@hanzlaa/rcode 4.4.4 → 4.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/AGENTS.md +11 -4
  2. package/CLAUDE.md +11 -4
  3. package/CONTRIBUTING.md +6 -1
  4. package/cli/doctor.js +122 -0
  5. package/cli/index.js +4 -0
  6. package/cli/install.js +8 -0
  7. package/cli/lib/namespace-migrate.cjs +216 -0
  8. package/cli/migrate-namespace.js +61 -0
  9. package/cli/update.js +19 -0
  10. package/dist/rcode.js +215 -208
  11. package/package.json +14 -12
  12. package/rcode/agents/rcode-mariam.md +6 -0
  13. package/rcode/agents/rcode-sadiq.md +6 -0
  14. package/rcode/agents/rcode-waleed.md +6 -0
  15. package/rcode/bin/lib/brain.cjs +353 -0
  16. package/rcode/bin/lib/gitignore.cjs +126 -0
  17. package/rcode/bin/lib/memory-drift.cjs +237 -0
  18. package/rcode/bin/lib/memory-select.cjs +263 -0
  19. package/rcode/bin/lib/progress.cjs +440 -0
  20. package/rcode/bin/lib/state-reader.cjs +127 -0
  21. package/rcode/bin/lib/summary.cjs +82 -0
  22. package/rcode/bin/rcode-hooks.cjs +230 -64
  23. package/rcode/bin/rcode-tools.cjs +106 -985
  24. package/rcode/data/intent-table.json +19 -19
  25. package/rcode/skills/actions/4-implementation/rcode-herdr-orchestration/templates/heartbeat.sh +0 -0
  26. package/rcode/skills/agents/mariam-marketing/SKILL.md +1 -0
  27. package/rcode/skills/agents/sadiq-analyst/SKILL.md +1 -0
  28. package/rcode/skills/agents/waleed-architect/SKILL.md +1 -0
  29. package/rcode/templates/memory/INDEX.md +6 -1
  30. package/rcode/templates/settings-hooks.json +12 -1
  31. package/rcode/workflows/council.md +29 -1
  32. package/rcode/workflows/do.md +2 -2
  33. package/rcode/workflows/enable-hooks.md +3 -2
  34. package/rcode/workflows/new-project-roadmap.md +2 -2
  35. package/server/dashboard.js +6 -3
  36. package/server/lib/html/client/components/App.js +1 -1
  37. package/server/lib/html/client/components/OrchPanel.js +2 -2
  38. package/server/lib/html/client/components/XtermPanel.js +98 -23
  39. package/server/lib/html/client/orchestrator.js +28 -15
  40. package/server/lib/html/client/views/OrchestrationView.js +247 -169
  41. package/server/lib/html/css.js +596 -227
  42. package/server/lib/html/shell.js +9 -3
  43. package/server/orchestrator.js +3 -4
@@ -1,87 +1,87 @@
1
1
  [
2
2
  {
3
3
  "intent": "new-project",
4
- "keywords": ["set up a new project", "initialize a new project", "start a new project", "create a new project"],
4
+ "keywords": ["set up a new project", "initialize a new project", "start a new project", "create a new project", "naya project shuru karo", "naya project banao", "مشروع جديد", "ابدأ مشروع جديد"],
5
5
  "command": "/rcode-new-project"
6
6
  },
7
7
  {
8
8
  "intent": "map-codebase",
9
- "keywords": ["map the codebase", "map this codebase", "analyze the codebase", "analyse the codebase", "map existing codebase"],
9
+ "keywords": ["map the codebase", "map this codebase", "analyze the codebase", "analyse the codebase", "map existing codebase", "codebase samjhao", "code ka structure dikhao", "حلل الكود", "افهم هيكل المشروع"],
10
10
  "command": "/rcode-map-codebase"
11
11
  },
12
12
  {
13
13
  "intent": "debug",
14
- "keywords": ["bug", "getting an error", "throwing an error", "error in the", "fix the error", "debug this", "crash", "failure", "broken", "not working", "fails", "exception", "traceback"],
14
+ "keywords": ["bug", "getting an error", "throwing an error", "error in the", "fix the error", "debug this", "crash", "failure", "broken", "not working", "fails", "exception", "traceback", "kharab", "masla", "ye kaam nahi kar raha", "yeh kaam nahi kar raha", "error a raha hai", "theek karo", "khud se crash", "خطأ", "مشكلة", "لا يعمل", "أصلح الخطأ", "تعطل البرنامج"],
15
15
  "command": "/rcode-debug"
16
16
  },
17
17
  {
18
- "intent": "audit-karpathy",
19
- "keywords": ["audit", "review changes", "check my diff", "karpathy", "too complex", "complexity", "code review"],
20
- "command": "/rcode-review --karpathy"
18
+ "intent": "karpathy-audit",
19
+ "keywords": ["review changes", "check my diff", "karpathy", "too complex", "complexity", "diff check karo", "پیچیدہ کوڈ", "تحقق من التغييرات"],
20
+ "command": "/rcode-karpathy-audit"
21
21
  },
22
22
  {
23
23
  "intent": "lazy",
24
- "keywords": ["be lazy", "lazy mode", "simplest solution", "yagni", "over-engineered", "over-engineering", "kam code likho"],
24
+ "keywords": ["be lazy", "lazy mode", "simplest solution", "yagni", "over-engineered", "over-engineering", "kam code likho", "asaan tareeqa", "سهل الحل", "أبسط طريقة"],
25
25
  "command": "/rcode-lazy"
26
26
  },
27
27
  {
28
28
  "intent": "checkpoint",
29
- "keywords": ["checkpoint", "explain this diff", "human review", "walk through the change", "walk through this change"],
29
+ "keywords": ["checkpoint", "explain this diff", "human review", "walk through the change", "walk through this change", "diff samjhao", "اشرح هذا التغيير"],
30
30
  "command": "/rcode-checkpoint-preview"
31
31
  },
32
32
  {
33
33
  "intent": "brainstorm",
34
- "keywords": ["brainstorm", "generate ideas", "explore options", "what could we do", "ideate", "ideas for"],
34
+ "keywords": ["brainstorm", "generate ideas", "explore options", "what could we do", "ideate", "ideas for", "ideas do", "hum kya kar sakte hain", "أفكار", "ما الذي يمكننا فعله"],
35
35
  "command": "/rcode-brainstorm"
36
36
  },
37
37
  {
38
38
  "intent": "explore",
39
- "keywords": ["explore", "research phase", "do some research", "comparing", "investigate", "look into", "understand how"],
39
+ "keywords": ["explore", "research phase", "do some research", "comparing", "investigate", "look into", "understand how", "research karo", "pata karo", "ابحث عن", "قارن بين"],
40
40
  "command": "/rcode-research-phase"
41
41
  },
42
42
  {
43
43
  "intent": "discuss",
44
- "keywords": ["which one", "better ux", "how should", "still have confusion", "conflicting", "discuss the scope", "design this", "architect this"],
44
+ "keywords": ["which one", "better ux", "how should", "still have confusion", "conflicting", "discuss the scope", "design this", "architect this", "confusion hai", "kaunsa behtar hai", "أيهما أفضل", "لست متأكداً"],
45
45
  "command": "/rcode-discuss-phase"
46
46
  },
47
47
  {
48
48
  "intent": "add-phase",
49
- "keywords": ["refactor", "migration", "multi-file", "system redesign", "multi file", "large refactor", "architectural", "integration", "integrate"],
49
+ "keywords": ["refactor", "migration", "multi-file", "system redesign", "multi file", "large refactor", "architectural", "integration", "integrate", "poora refactor karo", "migration karna hai", "إعادة هيكلة", "ترحيل النظام"],
50
50
  "command": "/rcode-add-phase"
51
51
  },
52
52
  {
53
53
  "intent": "sprint-planning",
54
- "keywords": ["sprint planning", "plan the sprint", "next sprint", "what's in this sprint"],
54
+ "keywords": ["sprint planning", "plan the sprint", "next sprint", "what's in this sprint", "sprint plan karo", "تخطيط السبرنت"],
55
55
  "command": "/rcode-sprint-planning"
56
56
  },
57
57
  {
58
58
  "intent": "execute-sprint",
59
- "keywords": ["run the sprint", "start sprint", "execute sprint", "work on sprint"],
59
+ "keywords": ["run the sprint", "start sprint", "execute sprint", "work on sprint", "sprint chalao", "sprint shuru karo", "نفذ السبرنت", "ابدأ السبرنت"],
60
60
  "command": "/rcode-execute-sprint"
61
61
  },
62
62
  {
63
63
  "intent": "plan",
64
- "keywords": ["let's plan", "plan phase", "plan this", "let me plan", "planning phase", "create a plan", "please plan", "plan and think", "scope this", "scope the feature"],
64
+ "keywords": ["let's plan", "plan phase", "plan this", "let me plan", "planning phase", "create a plan", "please plan", "plan and think", "scope this", "scope the feature", "plan banao", "isko plan karo", "خطط لهذا", "أنشئ خطة"],
65
65
  "command": "/rcode-plan"
66
66
  },
67
67
  {
68
68
  "intent": "new-milestone",
69
- "keywords": ["create milestones", "plan milestones", "create roadmap", "break project into milestones", "new milestone", "what milestones"],
69
+ "keywords": ["create milestones", "plan milestones", "create roadmap", "break project into milestones", "new milestone", "what milestones", "milestones banao", "خطة الطريق", "مراحل المشروع"],
70
70
  "command": "/rcode-new-milestone"
71
71
  },
72
72
  {
73
73
  "intent": "epics-stories",
74
- "keywords": ["create epics", "user stories", "create stories", "epics and stories", "break into epics"],
74
+ "keywords": ["create epics", "user stories", "create stories", "epics and stories", "break into epics", "stories banao", "قصص المستخدم", "أنشئ ملاحم"],
75
75
  "command": "/rcode-create-epics-and-stories"
76
76
  },
77
77
  {
78
78
  "intent": "feature-drift",
79
- "keywords": ["out of date", "out-of-date", "verify docs", "audit feature docs", "fill out existing", "prd drift", "docs vs code"],
79
+ "keywords": ["out of date", "out-of-date", "verify docs", "audit feature docs", "fill out existing", "prd drift", "docs vs code", "docs purane hain", "الوثائق قديمة", "تحقق من التوثيق"],
80
80
  "command": "/rcode-feature-drift"
81
81
  },
82
82
  {
83
83
  "intent": "audit",
84
- "keywords": ["re-audit", "extend the audit", "fill out the", "expand the", "re audit"],
84
+ "keywords": ["re-audit", "extend the audit", "fill out the", "expand the", "re audit", "audit", "code review", "dobara audit karo", "audit karo", "code review karo", "دقق الكود", "مراجعة الكود", "راجع التغييرات"],
85
85
  "command": "/rcode-audit"
86
86
  }
87
87
  ]
@@ -88,6 +88,7 @@ Five named heuristics. Cite by name when reasoning:
88
88
  - **Never claim market readiness from < 4 disconfirmable signals.** Three customers is a focus group at best.
89
89
  - **Never write a launch plan** without a 90-day proof point AND the kill criterion.
90
90
  - **Never speculate on market data without WebSearch.** "unknown — would need 1 hour of research" is a valid answer.
91
+ - **Grounding rule (mandatory):** any pricing, fee, rate, market-size, or regulation claim MUST be verified with WebSearch/WebFetch in-session, or explicitly tagged `[unverified — training data]`.
91
92
  - **Never write PRDs / user stories / architecture decisions.** Stay in the GTM lane.
92
93
  - Brand consistency over clever campaigns
93
94
 
@@ -84,6 +84,7 @@ State the rule by name when refusing.
84
84
  - **Never accept urgency manufactured by sales pressure** without independent market signal. Get the LOI in writing first.
85
85
  - **Never make a strategic call under context-switch pressure.** If the user is tired or mid-fire, defer. Bad strategy at midnight is worse than no strategy.
86
86
  - **Never write code, PRDs, or research reports.** Strategy directors set bets and kill switches; that's the deliverable.
87
+ - **Grounding rule (mandatory):** any pricing, fee, rate, market-size, or regulation claim MUST be verified with WebSearch/WebFetch in-session, or explicitly tagged `[unverified — training data]`.
87
88
 
88
89
  ## In Round 2 (council follow-ups)
89
90
 
@@ -86,6 +86,7 @@ State the rule by name when refusing.
86
86
  - **Never propose "rewrite from scratch"** without a measurable pain point AND a parallel-run migration plan. Joel Spolsky test: if you can't write the migration plan in 200 words, the rewrite is wrong-shaped.
87
87
  - **Never recommend bleeding-edge tech** for systems with multi-year lifetime expectations. Beta dependencies are a Reversibility-test fail.
88
88
  - **Never write production code** in your responses. ADRs and decision matrices only. Code goes to Yousef / Hanzla / Omar / Haitham.
89
+ - **Grounding rule (mandatory):** any pricing, fee, rate, market-size, or regulation claim MUST be verified with WebSearch/WebFetch in-session, or explicitly tagged `[unverified — training data]`.
89
90
 
90
91
  ## Capabilities
91
92
 
@@ -1,6 +1,8 @@
1
1
  # Memory Bank — `{{PROJECT_NAME}}`
2
2
 
3
- > The Memory Bank is your project's persistent brain. AI agents read from here on every session. You write to it as work happens. Survives session resets, team changes, and AI memory limits.
3
+ > The Memory Bank is your project's persistent brain. Full read/write access is on-demand: run `/rcode-memory-init` to scaffold it, `/rcode-memory-update` after work happens, `/rcode-memory-distill` to regenerate the compressed distillates, and `/rcode-memory-audit` to check it for staleness. Ambient injection also runs automatically (#958): the `session-start` hook emits its usual one-line phase-status primer from `.rcode/state.json`, then — when this directory exists and has content — a relevance-ranked selector (`rcode/bin/lib/memory-select.cjs`) scores every file here against the current phase, git branch, and recently touched files, and injects the top-scoring excerpts as `additionalContext` within a ~1500-token budget (override via `.rcode/config.yaml`'s `memory_inject_budget`). The `pre-compact` hook does the same with a smaller ~600-token budget as part of its survival context. This keeps agents grounded in relevant memory without a human having to run a `/rcode-memory-*` command first — full manual review is still the way to go deep.
4
+ >
5
+ > A `post-commit` hook runs a lightweight drift check after every commit (#958): it compares `project/stack.md` and `project/decisions.md` claims against the last 10 commits and the current working tree — removed/added dependencies, referenced files/dirs that no longer exist, and an `INDEX.md` older than 30 days. If it finds anything, it nudges you toward `/rcode-memory-update` once per session. Run `rcode-hooks drift` (or `node .rcode/bin/rcode-hooks.cjs drift` if the CLI isn't on your PATH) anytime for the full report.
4
6
 
5
7
  **Last updated:** {{INIT_DATE}}
6
8
 
@@ -27,6 +29,8 @@
27
29
 
28
30
  ## Token budget guide
29
31
 
32
+ - **Ambient session-start injection** (~1.5K tokens, `memory_inject_budget`) — automatic, relevance-ranked, no command needed
33
+ - **Ambient pre-compact injection** (~600 tokens) — automatic survival context alongside `HANDOFF.json`
30
34
  - **`INDEX.md` only** (~500 tokens) — quick orientation
31
35
  - **`INDEX.md` + `distillates/project.distillate.md`** (~5K tokens) — standard session start
32
36
  - **Full `project/` directory** (~10–15K tokens) — deep planning
@@ -39,6 +43,7 @@
39
43
  - **`incidents/known-issues.md`** — add when a workaround ships, remove when a real fix lands
40
44
  - **`distillates/`** — regenerate via `/rcode-memory-distill` when source files change
41
45
  - **Whole bank** — audit via `/rcode-memory-audit` at every milestone close
46
+ - **Drift check** — runs automatically on every commit; run `rcode-hooks drift` manually anytime, or after a large dependency/refactor change
42
47
 
43
48
  ## Constraints
44
49
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "_comment": "pre-edit hook is currently advisory (logs warning, does not block). Full session-read tracking requires PostToolUse Read hook to write state file. Implemented in follow-up. prompt-router (UserPromptSubmit) is advisory — emits additionalContext to nudge toward the right rcode command; never blocks.",
2
+ "_comment": "pre-edit hook is currently advisory (logs warning, does not block). Full session-read tracking requires PostToolUse Read hook to write state file. Implemented in follow-up. prompt-router (UserPromptSubmit) is advisory — emits additionalContext to nudge toward the right rcode command; never blocks. session-start (SessionStart) emits a one-line project status primer at session open.",
3
3
  "hooks": {
4
4
  "PreToolUse": [
5
5
  {
@@ -85,6 +85,17 @@
85
85
  }
86
86
  ]
87
87
  }
88
+ ],
89
+ "SessionStart": [
90
+ {
91
+ "matcher": "",
92
+ "hooks": [
93
+ {
94
+ "type": "command",
95
+ "command": "node .rcode/bin/rcode-hooks.cjs session-start"
96
+ }
97
+ ]
98
+ }
88
99
  ]
89
100
  }
90
101
  }
@@ -240,6 +240,16 @@ Do NOT skip this step. A council that answers market questions from training dat
240
240
  Constraints: <regulatory, geographic, or operational limits>
241
241
  ```
242
242
 
243
+ 3. **MANDATORY ARTIFACT GATE — write the Research context block to disk before spawning any panelist.** This file is the enforcement mechanism: its existence on disk is what proves live research ran, not just prose claiming it did.
244
+
245
+ ```bash
246
+ mkdir -p "{paths.sessions_dir}"
247
+ RESEARCH_FILE="{paths.sessions_dir}/$(date +%Y%m%d-%H%M%S)-research.md"
248
+ # Write the "Research context" block above (verbatim) to $RESEARCH_FILE
249
+ ```
250
+
251
+ Do NOT proceed to Step 3 (panel selection) until `$RESEARCH_FILE` exists on disk with the Research context block written into it. Step 4 (spawn) and Step 5 (synthesis) both depend on this file existing.
252
+
243
253
  Also run the minimal codebase scan (config.yaml + README only) so subagents know the team's current capabilities:
244
254
 
245
255
  ```bash
@@ -282,6 +292,8 @@ Use the AskUserQuestion tool (not raw stdin) for the confirmation.
282
292
 
283
293
  For each agent id in `panel`, build this prompt. **Before embedding, sanitize the question:** strip any literal `Task(`, `Agent(`, `subagent_type=`, or `system:` tokens that could be misinterpreted as tool calls by the sub-agent (replace with `[filtered]`). This is a low-severity guard — the user already has full access, but it prevents accidental or malicious prompt confusion.
284
294
 
295
+ **For research-typed questions (`market`/`discovery`/`greenfield`):** `{the summary block}` below MUST be the verbatim content of `$RESEARCH_FILE` written in Step 2's artifact gate — not a paraphrase, not a re-summary. Every panelist reads the same grounded facts.
296
+
285
297
  ```
286
298
  You are being spawned as part of a rcode council session.
287
299
 
@@ -289,7 +301,7 @@ You are being spawned as part of a rcode council session.
289
301
  {sanitized_question}
290
302
 
291
303
  ## Observed context
292
- {the summary block from Step 1 — codebase scan OR research context depending on question_type}
304
+ {the summary block from Step 1 — codebase scan OR the verbatim $RESEARCH_FILE content for research-typed questions}
293
305
 
294
306
  ## Session metadata
295
307
  - Project: {config.project_name}
@@ -384,6 +396,14 @@ to resolve or strategic ambiguity to explore.
384
396
 
385
397
  ## Step 5 — Present responses
386
398
 
399
+ **Grounding gate (research-typed questions only):** For `market`/`discovery`/`greenfield` questions, before printing anything else, verify `$RESEARCH_FILE` from Step 2 exists on disk (`test -f "$RESEARCH_FILE"`). If it is missing — the research pre-step was skipped or failed silently — open the verdict output (both compact and verbose modes) with this banner as the very first line, before the `COUNCIL VERDICT` header:
400
+
401
+ ```
402
+ ⚠ UNGROUNDED — answered from model knowledge, no live research ran
403
+ ```
404
+
405
+ Do NOT silently proceed as if research happened. This banner is mandatory whenever the file is missing for a research-typed question; it is never shown for `codebase`/`frontend`/`backend`/etc. questions where no research file is expected.
406
+
387
407
  Before saving any artifact, print the panel output inline. Two modes:
388
408
 
389
409
  ### Default mode (compact summary)
@@ -417,6 +437,9 @@ Format:
417
437
  **Orchestrator note**
418
438
  {max 2 sentences — sharpest remaining disagreement OR clearest convergent action}
419
439
 
440
+ **Data freshness**
441
+ {N} claims live-verified (sources: {comma-separated source names/URLs}) / {M} claims from model knowledge
442
+
420
443
  📄 Full transcripts: {artifact path}
421
444
  ```
422
445
 
@@ -425,6 +448,7 @@ Rules for compact mode:
425
448
  - Convergence table: 2-5 rows, only axes where panelists take a stance. Cells ≤ 6 words.
426
449
  - Round 2 deltas: ≤ 15 words each. "Held position" is a valid delta.
427
450
  - No section headers beyond the four above. No numbered story breakdowns. No tables from panelists verbatim.
451
+ - **Data freshness footer is mandatory on every synthesis**, not just research-typed questions. Count claims across all panelist responses: a claim is "live-verified" if it cites a source found via WebSearch/WebFetch in this session (Step 2's research file, or a panelist's own in-session lookup); everything else — including anything tagged `[unverified — training data]` by a panelist — counts toward "from model knowledge". For non-research question types with no external claims, use `0 claims live-verified / 0 from model knowledge — no external claims made`.
428
452
 
429
453
  ### Verbose mode (`--verbose` flag or `output.verbose: true` in config)
430
454
 
@@ -449,6 +473,8 @@ Print Round 1 (and Round 2 if ran) verbatim in panel order. Do NOT summarize.
449
473
 
450
474
  ---
451
475
  **Orchestrator Note:** {max 3 sentences}
476
+
477
+ **Data freshness:** {N} claims live-verified (sources) / {M} claims from model knowledge
452
478
  ```
453
479
 
454
480
  Before presenting, load the commit format reference:
@@ -575,6 +601,8 @@ node .rcode/bin/rcode-tools.cjs state record-session
575
601
  - [ ] Round 2 cross-talk executed (unless consensus or agent deferred)
576
602
  - [ ] Session artifact written to `.planning/council-sessions/council-{date}-{slug}.md`
577
603
  - [ ] State updated with session record and timestamp
604
+ - [ ] For research-typed questions (`market`/`discovery`/`greenfield`): `$RESEARCH_FILE` written before spawn, or ⚠ UNGROUNDED banner shown
605
+ - [ ] Data freshness footer included in synthesis output
578
606
 
579
607
  ## On Error
580
608
 
@@ -290,7 +290,7 @@ Evaluate `$QUESTION` against these routing rules. Apply the **first matching** r
290
290
  | A bug, error, crash, failure, or something broken | `/rcode-debug` | Needs systematic investigation |
291
291
  | Validate an idea, "working backwards", "press release", "PRFAQ", "is this worth building" | `/rcode-prfaq` | Stress-test concept before committing sprint capacity |
292
292
  | Brainstorm, generate ideas, "explore options", "what could we do" | `/rcode-brainstorm` | Structured ideation before planning |
293
- | Audit code quality, "review changes", "karpathy", "check my diff", "too complex" | `/rcode-review --karpathy` | 4-principle code audit against recent diff |
293
+ | "karpathy", "review changes", "check my diff", "too complex" — 4-principle code audit against a diff | `/rcode-karpathy-audit` | Runs the karpathy-audit workflow directly (review.md has no `--karpathy` flag) |
294
294
  | Make it simpler, "be lazy", "lazy mode", "simplest solution", "yagni", "over-engineered", "kam code likho" | `/rcode-lazy` | Generative simplicity lens — YAGNI before code is written (rcode-trim removes bloat after the fact) |
295
295
  | Walk through a change, "checkpoint", "explain this diff", "human review" | `/rcode-checkpoint-preview` | Human-in-the-loop diff walkthrough |
296
296
  | Exploring, researching, comparing, or "how does X work" | `/rcode-research-phase` | Domain research before planning |
@@ -317,7 +317,7 @@ Evaluate `$QUESTION` against these routing rules. Apply the **first matching** r
317
317
  | Adding tests, "write tests", "test coverage" | `/rcode-add-tests` | Test generation |
318
318
  | Completing a milestone, shipping, releasing | `/rcode-complete-milestone` | Milestone lifecycle |
319
319
  | Drift / out-of-date / "verify docs vs code" / "audit feature docs" / "fill out existing PRD/epics/stories" | `/rcode-feature-drift` | Detects PRD↔epics↔stories↔code drift; --fix patches trivial items |
320
- | General audit / re-audit / extend / fill out / expand an existing artifact | `/rcode-audit` | Unified audit entry — picks artifact type and re-runs |
320
+ | Bare "audit" / "code review" / re-audit / extend / fill out / expand an existing artifact | `/rcode-audit` | Unified audit entry — disambiguates plans/phase/milestone/UAT/code before dispatching |
321
321
  > **SEO route guard:** Skills in this block assume a project context exists (`.planning/PROJECT.md`). If absent, the `HAS_PRD` check in `<step name="check_project">` redirects to `/rcode-new-project`.
322
322
 
323
323
  | **— SEO / Content intent —** | | |
@@ -1,7 +1,7 @@
1
1
  # Workflow: rcode-enable-hooks
2
2
 
3
3
  <purpose>
4
- Merge rcode opt-in hooks from settings-hooks.json into .claude/settings.json. Creates settings.json if missing. Enables all 9 guardrails: pre-edit (read-before-edit check), pre-workflow (command hint), post-commit (format validation), bash-guard (blocks dangerous commands), pre-compact (refreshes HANDOFF.json before context compaction), stop-verify (syntax-checks files changed during the response), cost-track (logs measured token usage to .rcode/telemetry/cost.jsonl), compact-nudge (advises /rcode-trim or /clear after many edits), and prompt-router (proactive nudge toward the right rcode command for long-term memory consistency).
4
+ Merge rcode opt-in hooks from settings-hooks.json into .claude/settings.json. Creates settings.json if missing. Enables all 10 guardrails: pre-edit (read-before-edit check), pre-workflow (command hint), post-commit (format validation), bash-guard (blocks dangerous commands), pre-compact (refreshes HANDOFF.json before context compaction), stop-verify (syntax-checks files changed during the response), cost-track (logs measured token usage to .rcode/telemetry/cost.jsonl), compact-nudge (advises /rcode-trim or /clear after many edits), prompt-router (proactive nudge toward the right rcode command for long-term memory consistency), and session-start (SessionStart — one-line project status primer at session open).
5
5
  </purpose>
6
6
 
7
7
 
@@ -44,7 +44,7 @@ If `.claude/` directory does not exist, create it first.
44
44
 
45
45
  ## Step 3 — Merge hooks
46
46
 
47
- For each hook type (`PreToolUse`, `PostToolUse`, `PreCompact`, `Stop`, `UserPromptSubmit`):
47
+ For each hook type (`PreToolUse`, `PostToolUse`, `PreCompact`, `Stop`, `UserPromptSubmit`, `SessionStart`):
48
48
 
49
49
  - If the hook type does not exist in the current settings.json, add it.
50
50
  - If it exists, append the new matchers and hook commands (avoid duplicates by checking for exact command matches).
@@ -87,6 +87,7 @@ Enabled guardrails:
87
87
  • cost-track: Logs measured token usage to .rcode/telemetry/cost.jsonl
88
88
  • compact-nudge: Advises /rcode-trim or /clear after many edits
89
89
  • prompt-router: Nudges toward the matching /rcode-* command and /rcode-memory-update so work lands in .rcode/state.json (toggle via prompt_nudge in .rcode/config.yaml: every|once-per-intent|when-stale|off)
90
+ • session-start: Greets the session with one-line phase status and suggested next command
90
91
 
91
92
  To disable, remove the hooks section from .claude/settings.json or edit .rcode/templates/settings-hooks.json and re-run.
92
93
  ```
@@ -302,12 +302,12 @@ Use AskUserQuestion:
302
302
  node .rcode/bin/rcode-tools.cjs generate-claude-md
303
303
  ```
304
304
 
305
- This ensures new projects get the default rcode workflow-enforcement guidance and current project context in `CLAUDE.md`.
305
+ This ensures new projects get the default rcode workflow-enforcement guidance and current project context in `CLAUDE.md` and `AGENTS.md` (the cross-tool standard read by Codex, Cursor, Windsurf, Antigravity, and Gemini). `AGENTS.md` is only written when absent — an install-managed roster section is preserved.
306
306
 
307
307
  **Commit roadmap (after approval or auto mode):**
308
308
 
309
309
  ```bash
310
- node .rcode/bin/rcode-tools.cjs commit "docs: create roadmap ([N] phases)" --files .planning/ROADMAP.md .planning/STATE.md .planning/REQUIREMENTS.md CLAUDE.md
310
+ node .rcode/bin/rcode-tools.cjs commit "docs: create roadmap ([N] phases)" --files .planning/ROADMAP.md .planning/STATE.md .planning/REQUIREMENTS.md CLAUDE.md AGENTS.md
311
311
  ```
312
312
 
313
313
  ## 9. Done
@@ -36,6 +36,9 @@ const { renderHtml } = require('./lib/html/shell');
36
36
 
37
37
  // ---------- Configuration ----------
38
38
  const PORT = parseInt(process.env.PORT || '7717', 10);
39
+ // #969 — the orchestrator's actual port, injected into the client so it never
40
+ // has to hardcode 7718. Defaults match orchestrator.js's own default.
41
+ const ORCH_PORT = parseInt(process.env.ORCH_PORT || '7718', 10);
39
42
  const RCODE_DIR = process.env.RCODE_DIR || path.join(process.cwd(), '.rcode');
40
43
  const PROJECT_ROOT = path.dirname(RCODE_DIR);
41
44
  // Fallback root for agent prompts when rcode is installed as a package (not run
@@ -147,7 +150,7 @@ function handleRequest(req, res) {
147
150
  return;
148
151
  }
149
152
  res.writeHead(200, { 'Content-Type': 'application/json' });
150
- res.end(JSON.stringify({ token: ORCH_TOKEN }));
153
+ res.end(JSON.stringify({ token: ORCH_TOKEN, orchPort: ORCH_PORT }));
151
154
  return;
152
155
  }
153
156
 
@@ -178,7 +181,7 @@ function handleRequest(req, res) {
178
181
 
179
182
  if (url === '/' || url === '/index.html') {
180
183
  const state = scanState(RCODE_DIR);
181
- const html = renderHtml(state, ORCH_TOKEN);
184
+ const html = renderHtml(state, ORCH_TOKEN, ORCH_PORT);
182
185
  res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8', 'Cache-Control': 'no-cache' });
183
186
  res.end(html);
184
187
  return;
@@ -257,7 +260,7 @@ function spawnOrchestrator() {
257
260
  console.error('[orch] spawn error:', err.message);
258
261
  _orchProc = null;
259
262
  });
260
- console.log('[orch] orchestrator started (port 7718)');
263
+ console.log(`[orch] orchestrator started (port ${ORCH_PORT})`);
261
264
  } catch (err) {
262
265
  console.error('[orch] failed to start:', err.message);
263
266
  }
@@ -304,7 +304,7 @@ export function App() {
304
304
  />
305
305
  </div>
306
306
 
307
- <${XtermPanel} />
307
+ <${XtermPanel} suspend=${view === 'orchestration'} />
308
308
  <${OrchPanel} />
309
309
  <${BlockedToasts} />
310
310
  <${RunnerPicker} />
@@ -15,7 +15,7 @@
15
15
 
16
16
  import { html, useState, useEffect, useRef, useCallback } from '../preact.js';
17
17
  import { useStore, setState } from '../store.js';
18
- import { orchToken, stopSession, cleanSessions, ORCH_WS } from '../orchestrator.js';
18
+ import { orchToken, stopSession, cleanSessions, orchWs } from '../orchestrator.js';
19
19
  import { showToast } from './shared.js';
20
20
  import { Icon } from '../icons-client.js';
21
21
 
@@ -106,7 +106,7 @@ export function OrchPanel() {
106
106
  return;
107
107
  }
108
108
  const ws = new WebSocket(
109
- ORCH_WS + '/ws/' + encodeURIComponent(storyId) +
109
+ orchWs() + '/ws/' + encodeURIComponent(storyId) +
110
110
  '?token=' + encodeURIComponent(tok)
111
111
  );
112
112
  _streams[storyId] = ws;
@@ -9,18 +9,34 @@
9
9
  *
10
10
  * Store field: state.terminal = { open, storyId, title, minimized, fullscreen }
11
11
  * Setting state.terminal via orchestrator.js triggers this component.
12
+ *
13
+ * Two mount points, one singleton terminal:
14
+ * - App.js mounts one instance as a floating overlay (backdrop + sliding
15
+ * panel + minimized pill) on every view.
16
+ * - OrchestrationView.js mounts a second instance with `docked=true` to
17
+ * embed the SAME xterm.js Terminal inline in its right column.
18
+ * Only one instance may touch the DOM at a time — App.js passes
19
+ * `suspend=${view === 'orchestration'}` so its overlay instance goes fully
20
+ * inert (renders null, effects no-op) while Orchestration's docked instance
21
+ * is mounted. `ensureTerm()` reparents the shared xterm DOM node into
22
+ * whichever container asks for it, so the buffer/connection survive the
23
+ * hand-off in both directions.
12
24
  */
13
25
 
14
26
  import { html, useEffect, useRef, useCallback } from '../preact.js';
15
27
  import { useStore, setState } from '../store.js';
16
- import { orchToken, stopSession, ORCH_WS } from '../orchestrator.js';
28
+ import { orchToken, stopSession, orchWs } from '../orchestrator.js';
17
29
 
18
30
  // ── Internal state (module-scoped, one panel at a time) ──────────────────────
19
- // These refs are NOT component state because the xterm instance must persist
20
- // across panel open/close cycles and Preact re-renders.
21
- let _term = null;
22
- let _termFit = null;
23
- let _termWs = null;
31
+ // These are NOT component state because the xterm instance (and the story it
32
+ // is currently connected to) must persist across panel open/close cycles,
33
+ // Preact re-renders, and — now — across the two XtermPanel mount points
34
+ // (floating overlay vs. docked). Component-local refs would not be shared
35
+ // between those two instances.
36
+ let _term = null;
37
+ let _termFit = null;
38
+ let _termWs = null;
39
+ let _currentStory = null;
24
40
 
25
41
  function setStatus(dotStatus) {
26
42
  // Propagate connection status via a store signal so the pill/header can react
@@ -34,9 +50,23 @@ function _resize() {
34
50
  }
35
51
  }
36
52
 
37
- /** Build the xterm instance exactly once; attach to `containerEl`. */
53
+ /**
54
+ * Build the xterm instance exactly once; attach to `containerEl`.
55
+ * If the instance already exists but lives under a DIFFERENT container
56
+ * (e.g. the overlay panel had it, and the docked panel is now asking), move
57
+ * its root DOM node into `containerEl` instead of no-oping. xterm.js's root
58
+ * element is a plain DOM node — reparenting it is safe and preserves the
59
+ * scrollback buffer and any live WebSocket connection.
60
+ */
38
61
  function ensureTerm(containerEl) {
39
- if (_term || typeof Terminal === 'undefined') return;
62
+ if (_term) {
63
+ if (_term.element && _term.element.parentElement !== containerEl) {
64
+ containerEl.appendChild(_term.element);
65
+ if (_termFit) { try { _termFit.fit(); } catch (_e) {} }
66
+ }
67
+ return;
68
+ }
69
+ if (typeof Terminal === 'undefined') return;
40
70
  _term = new Terminal({
41
71
  theme: {
42
72
  background: '#0c0c0e', foreground: '#c9d1d9',
@@ -74,7 +104,7 @@ function connectWs(storyId) {
74
104
  return;
75
105
  }
76
106
  setStatus('connecting');
77
- const url = ORCH_WS + '/ws/' + encodeURIComponent(storyId) + '?token=' + encodeURIComponent(tok);
107
+ const url = orchWs() + '/ws/' + encodeURIComponent(storyId) + '?token=' + encodeURIComponent(tok);
78
108
  const ws = new WebSocket(url);
79
109
  _termWs = ws;
80
110
 
@@ -98,10 +128,9 @@ function connectWs(storyId) {
98
128
 
99
129
  // ── Component ─────────────────────────────────────────────────────────────────
100
130
 
101
- export function XtermPanel() {
131
+ export function XtermPanel({ docked = false, suspend = false } = {}) {
102
132
  const { terminal, termStatus } = useStore();
103
133
  const containerRef = useRef(null);
104
- const currentStoryRef = useRef(null);
105
134
 
106
135
  const t = terminal || {};
107
136
  const open = !!t.open;
@@ -110,28 +139,37 @@ export function XtermPanel() {
110
139
  const storyId = t.storyId || '';
111
140
  const title = t.title || 'Terminal';
112
141
 
113
- // Build xterm instance on first open; reconnect when storyId changes.
114
- // The resize listener is registered here (not inside ensureTerm) so the
115
- // cleanup return can mirror it on unmount.
142
+ // Build/attach the xterm instance on open; (re)connect only when the
143
+ // focused storyId actually changes. `_currentStory` is module-scoped (not
144
+ // a per-instance ref) so that handing the terminal off between the
145
+ // floating overlay and the docked panel — same storyId, different
146
+ // container — reparents via ensureTerm() without tearing down the
147
+ // connection or clearing the buffer. `suspend` is in the dep array so the
148
+ // OTHER (un-suspending) instance re-runs this effect and reclaims the
149
+ // terminal DOM node when the user navigates away from Orchestration.
116
150
  useEffect(() => {
117
- if (!open || !containerRef.current) return;
151
+ if (suspend || !open || !containerRef.current) return;
118
152
  ensureTerm(containerRef.current);
119
- if (_term) { _term.clear(); _resize(); }
120
- if (storyId && storyId !== currentStoryRef.current) {
121
- currentStoryRef.current = storyId;
153
+ const isNewSession = storyId && storyId !== _currentStory;
154
+ if (isNewSession) {
155
+ _currentStory = storyId;
156
+ if (_term) _term.clear();
122
157
  connectWs(storyId);
123
158
  }
159
+ _resize();
124
160
  window.addEventListener('resize', _resize);
125
161
  return () => window.removeEventListener('resize', _resize);
126
- }, [open, storyId]);
162
+ }, [open, storyId, suspend]);
127
163
 
128
164
  // Resize when entering/leaving fullscreen or on open
129
165
  useEffect(() => {
130
- if (open) { setTimeout(_resize, 50); }
131
- }, [open, fullscreen]);
166
+ if (!suspend && open) { setTimeout(_resize, 50); }
167
+ }, [open, fullscreen, suspend]);
132
168
 
133
- // Escape key closes
169
+ // Escape key closes (docked panel has no "close" concept — it just shows
170
+ // the empty state when store.terminal is cleared elsewhere)
134
171
  useEffect(() => {
172
+ if (suspend || docked) return;
135
173
  function onKey(e) {
136
174
  if (e.key === 'Escape' && open && !minimized) {
137
175
  setState({ terminal: { ...t, open: false } });
@@ -139,9 +177,11 @@ export function XtermPanel() {
139
177
  }
140
178
  window.addEventListener('keydown', onKey);
141
179
  return () => window.removeEventListener('keydown', onKey);
142
- }, [open, minimized, t]);
180
+ }, [open, minimized, t, suspend, docked]);
143
181
 
144
182
  const dotCls = 'term-status-dot ' + (termStatus || '');
183
+ // Statuses that mean "output is actively streaming" for the docked live pulse.
184
+ const isLive = open && ['running', 'connecting', 'blocked', 'waiting'].includes(termStatus);
145
185
 
146
186
  // ── Actions ──
147
187
  const handleMinimize = useCallback(() => {
@@ -167,6 +207,41 @@ export function XtermPanel() {
167
207
  setTimeout(_resize, 50);
168
208
  }, [t, fullscreen]);
169
209
 
210
+ // Fully inert while the sibling instance owns the terminal DOM — no
211
+ // backdrop, no panel, no pill, nothing rendered at all.
212
+ if (suspend) return null;
213
+
214
+ // ── Docked render (Orchestration view's right column) ──
215
+ if (docked) {
216
+ return html`
217
+ <div class="orch-term-dock">
218
+ <div class="orch-term-dock-header">
219
+ <span class="orch-term-dot red"></span>
220
+ <span class="orch-term-dot amber"></span>
221
+ <span class="orch-term-dot green"></span>
222
+ <span class="orch-term-dock-label">xterm${open ? ' · ' + title : ''}</span>
223
+ ${isLive ? html`
224
+ <span class="orch-term-dock-live">
225
+ <span class="orch-term-dock-live-dot"></span>live
226
+ </span>
227
+ ` : null}
228
+ ${open ? html`
229
+ <button class="orch-term-dock-stop" onClick=${handleStop} title="End the agent session">Stop</button>
230
+ ` : null}
231
+ </div>
232
+ <div class="orch-term-dock-body">
233
+ ${open
234
+ ? html`<div ref=${containerRef} class="orch-term-dock-container"></div>`
235
+ : html`
236
+ <div class="orch-term-dock-empty">
237
+ No active execution. Select a command from the Runner picker to begin.
238
+ </div>
239
+ `}
240
+ </div>
241
+ </div>
242
+ `;
243
+ }
244
+
170
245
  // ── Pill (minimized state) ──
171
246
  const pill = html`
172
247
  <div