diff --git a/.loopdeck/current-loop.md b/.loopdeck/current-loop.md index a910d2c..1dadb4b 100644 --- a/.loopdeck/current-loop.md +++ b/.loopdeck/current-loop.md @@ -1 +1 @@ -Selasar revamp — prd-rebrand-tokens Phase 1 (design tokens) complete: paper/ink/teak palette + font-display token + toggle verified \ No newline at end of file +Selasar revamp — prd-rebrand-tokens Phase 2 (rebrand copy audit) complete: full-repo audit recorded in PRD, tauri.conf.json/index.html renamed to Selasar, all in-app copy renamed; Phase 3 (visual pass) remains \ No newline at end of file diff --git a/.loopdeck/decisions.md b/.loopdeck/decisions.md index fb97589..636c001 100644 --- a/.loopdeck/decisions.md +++ b/.loopdeck/decisions.md @@ -175,3 +175,8 @@ _Older decisions archived to [decisions-archive.md](./decisions-archive.md)._ - **Status**: accepted - **Context**: The PRD criterion "apply `--font-display` to the wordmark, rail mark, and project-name treatments" had no literal rail-mark text — AppShell's brand tile is an icon-only gradient (Command icon, no wordmark text), and the run interview mapped "rail mark" to the sidebar subtitle. - **Consequences**: New `--font-display: ui-serif, Charter, "Iowan Old Style", "Palatino Linotype", Georgia, serif` token (Tailwind v4 `font-display` utility). Applied to the wordmark + subtitle in `AppShell.tsx`, and to project names at all 3 render sites: `ProjectList.tsx` row, `ProjectDetail.tsx` breadcrumb header, `ProjectDetail.tsx` tab-rail label. + +## 2026-08-05 — Selasar Phase-2 copy audit + rename: full-repo tagged list in the PRD, rename scope incl. bundle id +- **Status**: accepted +- **Context**: `prd-rebrand-tokens` Phase 2 (3 loops, one combined overnight run): audit every user-visible "LoopDeck" occurrence, then rename window title, wordmark, and in-app copy to "Selasar". The run interview resolved the PRD's open questions: rename the macOS bundle identifier too, and update Rust test assertions that assert on renamed copy. +- **Consequences**: Full-repo audit recorded in the PRD (`## Phase 2 Audit — "LoopDeck" occurrences`), every occurrence tagged user-visible / comment / test-assertion / left-intact. Renamed all user-visible copy + comments to "Selasar" (wordmark, error/empty/settings/import copy, agent initial prompts, chat truncation marker, Codex clientInfo title + turn errors, run-queue notification titles, schema/deny error strings, export header, 5 hook templates), updated test assertions + smoke-test-release.sh artifact names in lockstep, and changed the bundle `identifier` to `com.selasar.app`. Left untouched: `.loopdeck/` dir, `project.yaml` schema, `config.rs` `ProjectDirs::from("com","loopdeck","LoopDeck")`, log dir `~/Library/Logs/LoopDeck/`, all lowercase `loopdeck` identifiers, and docs/ (P2 goal, deferred). diff --git a/.loopdeck/loops.md b/.loopdeck/loops.md index 8416b86..68e1c78 100644 --- a/.loopdeck/loops.md +++ b/.loopdeck/loops.md @@ -3,8 +3,11 @@ ## Current - **Started**: 2026-08-05 -- **Goal**: `selasar-revamp` / `prd-rebrand-tokens` Phase 1 — Design tokens (the epic's first, gating PRD): replace `src/styles.css`'s light+dark token values with the paper/ink/teak palette, add a `--font-display` serif token, and verify the light/dark/system toggle against the new values. All three Phase-1 loops ran as one combined unattended overnight run; Phase 2 (rebrand copy audit) and Phase 3 (full visual pass) remain. +- **Goal**: `selasar-revamp` / `prd-rebrand-tokens` Phase 2 — Rebrand copy audit: grep the repo for user-visible "LoopDeck" occurrences and record the full list, rename `src-tauri/tauri.conf.json` productName/window title + `index.html` `
Scan a folder to discover repositories and create project memory, or start a - brand-new project from scratch. LoopDeck stores context inside each repository. + brand-new project from scratch. Selasar stores context inside each repository.
Something crashed while rendering the app. Your data is safe on disk — diff --git a/src/hooks/useStuckSessions.ts b/src/hooks/useStuckSessions.ts index c16de4e..b22d93c 100644 --- a/src/hooks/useStuckSessions.ts +++ b/src/hooks/useStuckSessions.ts @@ -21,7 +21,7 @@ const STUCK_TOAST_DURATION = Infinity; * `AskUserQuestion` prompts, manual tool approvals, AND plan approvals * (`ExitPlanMode`). * - * A LoopDeck-spawned agent parks one oneshot per pending prompt in + * A Selasar-spawned agent parks one oneshot per pending prompt in * `AppState.pending_answers` / `AppState.pending_permissions` / * `AppState.pending_plans`; the per-project cards (`AgentPanel`) only * reconcile their own project's slot when its tab mounts. So if the user is diff --git a/src/styles.css b/src/styles.css index 3a5fe37..a48b45f 100644 --- a/src/styles.css +++ b/src/styles.css @@ -172,7 +172,7 @@ } } -/* ── LoopDeck custom utilities ───────────────────────────────────────────── */ +/* ── Selasar custom utilities ───────────────────────────────────────────── */ @utility card-accent-top { position: relative; @@ -210,7 +210,7 @@ /* ── Syntax highlighting (rehype-highlight / highlight.js tokens) ───────────── Adaptive across light and dark mode using the OKLCH token palette — no - theme import needed, the colours below are tuned to feel native to LoopDeck + theme import needed, the colours below are tuned to feel native to Selasar in both schemes. Token names follow the highlight.js class convention. */ :root { diff --git a/src/types/index.ts b/src/types/index.ts index 5e2eab3..c0dc98e 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -134,7 +134,7 @@ export interface ConfidenceBreakdown { /** Summary of a project's Graphify knowledge graph. * `present: false` means no readable `graphify-out/graph.json` was found — - * the UI should hide the Graph tab rather than render empty stats. LoopDeck + * the UI should hide the Graph tab rather than render empty stats. Selasar * only reads Graphify's output and never runs it. */ export interface GraphifyStats { /** `false` when `graphify-out/graph.json` is missing or unparseable. */ @@ -431,7 +431,7 @@ export interface PinnedAnswer { * queued phase is still `pending`. */ export type InterviewStatus = "pending" | "answered" | "skipped"; -/** Queue-time consent for the whole run. LoopDeck never asks again once the +/** Queue-time consent for the whole run. Selasar never asks again once the * run starts. */ export interface RunConsent { draft_pr_authorized: boolean; @@ -841,7 +841,7 @@ export type ContentBlock = | { type: "tool_use"; name: string; input: string }; /** - * A permission decision made by the LoopDeck policy layer in response to a + * A permission decision made by the Selasar policy layer in response to a * Claude `control_request`. Ephemeral narration — not part of the persisted * transcript. * @@ -862,7 +862,7 @@ export interface PermissionDecision { input: string; /** `"pending"` (awaiting user), or an allow/deny verdict (resolved). */ decision: "allow" | "auto-allow" | "deny" | "pending"; - /** Why LoopDeck allowed/denied. Empty for pending and plain allows. */ + /** Why Selasar allowed/denied. Empty for pending and plain allows. */ reason: string; } diff --git a/templates/hooks/loopdeck-decisions-cap.py b/templates/hooks/loopdeck-decisions-cap.py index 1b75e3f..ba6daf9 100755 --- a/templates/hooks/loopdeck-decisions-cap.py +++ b/templates/hooks/loopdeck-decisions-cap.py @@ -1,11 +1,11 @@ #!/usr/bin/env python3 -"""LoopDeck PostToolUse hook — enforces the decisions.md live-entry cap. +"""Selasar PostToolUse hook — enforces the decisions.md live-entry cap. templates/skills/loopdeck-memory/SKILL.md documents a 15-live-entry cap on `.loopdeck/decisions.md` (overflow moves to `decisions-archive.md`), but that convention is "enforced by you, the writer, not by a parser" — it only works if every session remembers to archive on the write that crosses 15. This hook -makes it unconditional: after any Edit/Write/MultiEdit in a LoopDeck-tracked +makes it unconditional: after any Edit/Write/MultiEdit in a Selasar-tracked project, if decisions.md has grown past the cap, the oldest entries are moved to the archive automatically, no model turn required. @@ -69,7 +69,7 @@ def main(): "hookSpecificOutput": { "hookEventName": "PostToolUse", "additionalContext": ( - f"LoopDeck: auto-archived {overflow_count} decision(s) " + f"Selasar: auto-archived {overflow_count} decision(s) " f"to decisions-archive.md ({LIVE_CAP} live entries kept)." ), } diff --git a/templates/hooks/loopdeck-dirty-flag.py b/templates/hooks/loopdeck-dirty-flag.py index 142ea7a..dc7fda1 100755 --- a/templates/hooks/loopdeck-dirty-flag.py +++ b/templates/hooks/loopdeck-dirty-flag.py @@ -1,8 +1,8 @@ #!/usr/bin/env python3 -"""LoopDeck PreToolUse hook — marks the session as dirty on file changes. +"""Selasar PreToolUse hook — marks the session as dirty on file changes. Creates `.claude/.session-dirty` when an Edit / Write / MultiEdit / NotebookEdit -fires inside a LoopDeck-tracked project. The Stop hook +fires inside a Selasar-tracked project. The Stop hook (loopdeck-stop-hook.py) reads this flag to decide whether to emit the memory-update nudge, and loopdeck-memory-write.sh consumes (deletes) it. @@ -20,7 +20,7 @@ def main(): - # Only fire in LoopDeck-tracked projects. + # Only fire in Selasar-tracked projects. if not os.path.isdir(LOOPDECK_DIR): return 0 diff --git a/templates/hooks/loopdeck-memory-write.sh b/templates/hooks/loopdeck-memory-write.sh index 9853731..2b1c13d 100755 --- a/templates/hooks/loopdeck-memory-write.sh +++ b/templates/hooks/loopdeck-memory-write.sh @@ -1,9 +1,9 @@ #!/usr/bin/env bash -# LoopDeck memory auto-write helper (Approach B — shell fallback). +# Selasar memory auto-write helper (Approach B — shell fallback). # Called by the Stop hook to append a basic session summary to # .loopdeck/ files when the AI hasn't written them yet. # -# Gated by .loopdeck/ directory (only active in LoopDeck-tracked projects) +# Gated by .loopdeck/ directory (only active in Selasar-tracked projects) # and .claude/.session-dirty (only fires when file changes occurred). # # This is a mechanical fallback — the primary mechanism is @@ -20,7 +20,7 @@ emit_stop_response() { } trap emit_stop_response EXIT -# Gate: only fire in LoopDeck-tracked projects +# Gate: only fire in Selasar-tracked projects LOOPDECK_DIR=".loopdeck" if [ ! -d "$LOOPDECK_DIR" ]; then exit 0 @@ -65,7 +65,7 @@ if ! grep -q "^## $TODAY" "$DECISIONS_FILE"; then echo "" echo "## $TODAY — Session heartbeat" echo "- **Status**: proposed" - echo "- **Context**: AI session active on LoopDeck development." + echo "- **Context**: AI session active on Selasar development." echo "" } >> "$DECISIONS_FILE" fi diff --git a/templates/hooks/loopdeck-stop-hook.py b/templates/hooks/loopdeck-stop-hook.py index f5bc706..d177761 100755 --- a/templates/hooks/loopdeck-stop-hook.py +++ b/templates/hooks/loopdeck-stop-hook.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""LoopDeck Stop hook — append-only memory nudge (lean, no re-reads). +"""Selasar Stop hook — append-only memory nudge (lean, no re-reads). Design rules (learned the hard way — see decision 2026-07-19 "Stop hook re-injection caused runaway token usage"): @@ -7,7 +7,7 @@ 1. NEVER instruct the model to *read* loops.md / decisions.md. Those files can be large; forcing a re-read every turn is what burned ~30M tokens/hr. This nudge is ~3 lines and asks for an APPEND only. - 2. Gate on `.loopdeck/` (LoopDeck-tracked project) AND `.claude/.session-dirty` + 2. Gate on `.loopdeck/` (Selasar-tracked project) AND `.claude/.session-dirty` (file changes happened this turn). Without the dirty flag the hook is a no-op, so pure Q&A and read-only turns cost zero. 3. The dirty flag is created by loopdeck-dirty-flag.py (PreToolUse on @@ -21,13 +21,13 @@ # Short, append-only reminder. Deliberately does NOT say "read loops.md". REMINDER = ( - "LoopDeck: if you made an architectural decision or changed the active " + "Selasar: if you made an architectural decision or changed the active " "loop this turn, APPEND a one-paragraph entry to " ".loopdeck/decisions.md (## YYYY-MM-DD — Title) or update the Current " "section of .loopdeck/loops.md. Skip if this turn was read-only or Q&A." ) -# Only fire in LoopDeck-tracked projects that changed files this turn. +# Only fire in Selasar-tracked projects that changed files this turn. if not os.path.isdir(LOOPDECK_DIR) or not os.path.exists(DIRTY_FILE): msg = "" else: diff --git a/templates/hooks/orchestrator-start.py b/templates/hooks/orchestrator-start.py index 732c641..dedea18 100755 --- a/templates/hooks/orchestrator-start.py +++ b/templates/hooks/orchestrator-start.py @@ -1,10 +1,10 @@ #!/usr/bin/env python3 """ -LoopDeck orchestrator-start hook — PreToolUse on Skill(loopdeck:orchestrator). +Selasar orchestrator-start hook — PreToolUse on Skill(loopdeck:orchestrator). Writes .loopdeck/current-loop.md with a single task line (max 100 chars) before the orchestrator delegates to agents. -Gated by .loopdeck/ directory (only fires in LoopDeck-tracked projects). +Gated by .loopdeck/ directory (only fires in Selasar-tracked projects). """ import json import os @@ -30,7 +30,7 @@ def main(): pass_through() return 0 - # Gate: only fire in LoopDeck-tracked projects + # Gate: only fire in Selasar-tracked projects loopdeck_dir = ".loopdeck" if not os.path.isdir(loopdeck_dir): pass_through() @@ -55,7 +55,7 @@ def main(): with open(loopdeck_path, "w") as f: f.write(f"# Current Loop\n{task}\n") - additional_context = f"LoopDeck: .loopdeck/current-loop.md → {task}" + additional_context = f"Selasar: .loopdeck/current-loop.md → {task}" print( json.dumps({