@hanzlaa/rcode 4.5.0 → 4.7.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.
- package/README.md +47 -14
- package/package.json +1 -1
- package/rcode/agents/rcode-mariam.md +6 -0
- package/rcode/agents/rcode-sadiq.md +6 -0
- package/rcode/agents/rcode-waleed.md +6 -0
- package/rcode/bin/rcode-hooks.cjs +41 -5
- package/rcode/skills/agents/mariam-marketing/SKILL.md +1 -0
- package/rcode/skills/agents/sadiq-analyst/SKILL.md +1 -0
- package/rcode/skills/agents/waleed-architect/SKILL.md +1 -0
- package/rcode/workflows/council.md +29 -1
- package/server/dashboard.js +6 -3
- package/server/lib/html/client/components/App.js +16 -2
- package/server/lib/html/client/components/OrchPanel.js +2 -2
- package/server/lib/html/client/components/PhaseGraph.js +20 -12
- package/server/lib/html/client/components/Sidebar.js +1 -0
- package/server/lib/html/client/components/Topbar.js +3 -3
- package/server/lib/html/client/components/XtermPanel.js +98 -23
- package/server/lib/html/client/components/dashboard/Blockers.js +3 -3
- package/server/lib/html/client/components/dashboard/CompletedTasks.js +4 -2
- package/server/lib/html/client/components/dashboard/InProgress.js +4 -3
- package/server/lib/html/client/components/dashboard/ProgressTimeline.js +11 -6
- package/server/lib/html/client/components/dashboard/RecentDecisions.js +4 -3
- package/server/lib/html/client/components/shared.js +111 -2
- package/server/lib/html/client/orchestrator.js +28 -15
- package/server/lib/html/client/store.js +47 -0
- package/server/lib/html/client/util.js +1 -22
- package/server/lib/html/client/views/BacklogView.js +44 -0
- package/server/lib/html/client/views/DecisionsView.js +4 -3
- package/server/lib/html/client/views/FilesView.js +47 -34
- package/server/lib/html/client/views/KanbanView.js +8 -0
- package/server/lib/html/client/views/OrchestrationView.js +247 -169
- package/server/lib/html/client/views/PhasesView.js +8 -3
- package/server/lib/html/client/views/SprintsView.js +9 -0
- package/server/lib/html/client.js +1 -0
- package/server/lib/html/css.js +692 -246
- package/server/lib/html/shell.js +9 -3
- package/server/lib/scanner.js +21 -6
- package/server/orchestrator.js +3 -4
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ pnpm dlx @hanzlaa/rcode install
|
|
|
23
23
|
[](https://github.com/hanzlahabib/rcode/actions/workflows/test.yml)
|
|
24
24
|
[](LICENSE)
|
|
25
25
|
|
|
26
|
-
Status: `@hanzlaa/rcode` v4.
|
|
26
|
+
Status: `@hanzlaa/rcode` v4.7.0 on npm. 45 agents · 117 commands · 129 workflows · **1 runtime dependency**. Test status tracked by CI badge above. Actively dogfooded on real projects every week.
|
|
27
27
|
|
|
28
28
|
---
|
|
29
29
|
|
|
@@ -49,7 +49,19 @@ If you're a solo dev or small team using Claude Code (or Cursor, Codex, VS Code)
|
|
|
49
49
|
|
|
50
50
|
<p align="center"><img src="brand/hero-org-in-folder.png" alt="rcode is an engineering org in a folder: agents, commands, workflows, and skills as plain markdown" width="760"></p>
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
In plain words: **rcode is a folder of instructions your AI already knows how to read.** No new app to install, no server to run, no separate "agent brain" — just files. Your IDE (Claude Code, Cursor, whichever) is already an agent; rcode just hands it a really good playbook and a notebook that never forgets.
|
|
53
|
+
|
|
54
|
+
```mermaid
|
|
55
|
+
flowchart LR
|
|
56
|
+
A["You type a command<br/>/rcode-plan"] --> B["rcode's files answer:<br/>what to do, in what order"]
|
|
57
|
+
B --> C["Your IDE's own agent<br/>does the actual work"]
|
|
58
|
+
C --> D["Result gets saved to<br/>.rcode/memory/"]
|
|
59
|
+
D -.->|"next session starts here"| A
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
That loop — command in, memory out, memory feeds the next command — is the whole idea. Everything else in this repo is detail on top of that loop.
|
|
63
|
+
|
|
64
|
+
Three layers make it up:
|
|
53
65
|
|
|
54
66
|
| Layer | What lives here | Example |
|
|
55
67
|
|-------|-----------------|---------|
|
|
@@ -63,15 +75,26 @@ Single agent navigates the structure. No LangChain, no AutoGen, no orchestrator
|
|
|
63
75
|
|
|
64
76
|
## Why I built it
|
|
65
77
|
|
|
66
|
-
I've shipped products solo for years and watched the same failure repeat in every project:
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
78
|
+
I've shipped products solo for years and watched the same failure repeat in every project. In one sentence: **the AI forgets everything the moment the chat window closes, so I kept re-explaining the same decisions forever.**
|
|
79
|
+
|
|
80
|
+
```mermaid
|
|
81
|
+
flowchart LR
|
|
82
|
+
subgraph without["😩 Without rcode"]
|
|
83
|
+
direction TB
|
|
84
|
+
w1["Session 1 — pick Postgres"] --> w2["Session 5 — agent forgot,<br/>suggests Mongo, you argue"]
|
|
85
|
+
w2 --> w3["Session 20 — you're pasting<br/>4K tokens of 'here's what<br/>we decided' every time"]
|
|
86
|
+
end
|
|
87
|
+
subgraph with["✅ With rcode"]
|
|
88
|
+
direction TB
|
|
89
|
+
r1["Session 1 — pick Postgres"] --> r2["Decision saved once to<br/>.rcode/memory/decisions.md"]
|
|
90
|
+
r2 --> r3["Session 20 — agent reads it<br/>automatically, no re-explaining"]
|
|
91
|
+
end
|
|
92
|
+
without ~~~ with
|
|
93
|
+
```
|
|
71
94
|
|
|
72
|
-
|
|
95
|
+
That's it. That's the whole pitch. **Write the decision down once, in a file. The agent reads the file. Done.**
|
|
73
96
|
|
|
74
|
-
|
|
97
|
+
The same problem shows up at team scale, just wearing a different costume: onboarding a new hire takes 30 minutes of Slack archaeology, a late requirement quietly shifts the goalposts with no record of why, and six months later nobody remembers why the MVP was built the way it was. rcode's fix is the same either way — write the context down where the agent (and the next human) will actually see it.
|
|
75
98
|
|
|
76
99
|
---
|
|
77
100
|
|
|
@@ -81,6 +104,7 @@ What you'll feel in week one:
|
|
|
81
104
|
|
|
82
105
|
- **No more re-explaining.** Decisions, blockers, conventions live in `.rcode/memory/` — agent reads them at session start automatically (~5K tokens, fully oriented).
|
|
83
106
|
- **Phased delivery without ceremony.** `/rcode-new-project` produces a roadmap with phases → sprints → tasks. `/rcode-plan` produces SPRINT.md files. `/rcode-execute` runs them with atomic commits. No Jira required.
|
|
107
|
+
- **No blank-page starts.** Already know you're building an API, a SaaS product, or a mobile app? `/rcode-from-template api-backend` seeds a real roadmap + requirements doc for that project type — edit it down instead of writing it up from nothing.
|
|
84
108
|
- **Specialist review on tap.** Want a Karpathy-style review of your last commit? `/rcode-review --karpathy`. Want a council debate on a decision? `/rcode-council should I rewrite auth?` — 5 agents answer in parallel, round 2 they challenge each other.
|
|
85
109
|
- **Intent guards.** Run the wrong command and get a one-line redirect, not a useless output.
|
|
86
110
|
- **Health check.** `rcode-tools health` returns JSON — milestone health, state snapshot, project status. Wire it into your dashboard.
|
|
@@ -159,12 +183,21 @@ pnpm dlx @hanzlaa/rcode install
|
|
|
159
183
|
|
|
160
184
|
### The full loop
|
|
161
185
|
|
|
186
|
+
Four commands cover most of a real week of work — decide, plan, build, check in:
|
|
187
|
+
|
|
188
|
+
```mermaid
|
|
189
|
+
flowchart LR
|
|
190
|
+
A["🗣️ /rcode-council<br/>should I rewrite auth?"] --> B["📋 /rcode-plan --research<br/>build a rental app"]
|
|
191
|
+
B --> C["⚙️ /rcode-execute<br/>PLAN.md"]
|
|
192
|
+
C --> D["📊 /rcode-status<br/>phases · decisions · blockers"]
|
|
162
193
|
```
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
194
|
+
|
|
195
|
+
| Command | What it does |
|
|
196
|
+
|---|---|
|
|
197
|
+
| `/rcode-council should I rewrite auth?` | 5 specialist agents debate it, 2 rounds — you get a decision, not a monologue |
|
|
198
|
+
| `/rcode-plan --research build a rental app` | A researcher grounds the plan in your real codebase, a checker verifies it before you build anything |
|
|
199
|
+
| `/rcode-execute .planning/plans/01/PLAN.md` | Runs the plan as atomic git commits, with pass/fail gates between steps |
|
|
200
|
+
| `/rcode-status` | One glance at phases, decisions, and blockers — no digging through chat history |
|
|
168
201
|
|
|
169
202
|
Full install flavors and IDE options: [`docs/install.md`](docs/install.md). Step-by-step first project: [`docs/getting-started.md`](docs/getting-started.md).
|
|
170
203
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanzlaa/rcode",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.7.0",
|
|
4
4
|
"description": "rcode — the AI team that never forgets. Persistent memory, specialist agents, and slash commands for AI IDEs. Works in Claude Code, Cursor, Gemini, VS Code, and Antigravity.",
|
|
5
5
|
"main": "cli/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -16,3 +16,9 @@ color: purple
|
|
|
16
16
|
@.rcode/references/agent-shared-rules.md
|
|
17
17
|
@.rcode/references/codebase-grounding.md
|
|
18
18
|
@.rcode/skills/agents/mariam-marketing/SKILL.md
|
|
19
|
+
|
|
20
|
+
## Grounding rule (mandatory)
|
|
21
|
+
|
|
22
|
+
Any pricing, fee, rate, market-size, or regulation claim MUST be verified with
|
|
23
|
+
WebSearch/WebFetch in-session, or explicitly tagged `[unverified — training data]`.
|
|
24
|
+
Do not present training-data numbers as current fact.
|
|
@@ -16,3 +16,9 @@ color: blue
|
|
|
16
16
|
@.rcode/references/agent-shared-rules.md
|
|
17
17
|
@.rcode/references/codebase-grounding.md
|
|
18
18
|
@.rcode/skills/agents/sadiq-analyst/SKILL.md
|
|
19
|
+
|
|
20
|
+
## Grounding rule (mandatory)
|
|
21
|
+
|
|
22
|
+
Any pricing, fee, rate, market-size, or regulation claim MUST be verified with
|
|
23
|
+
WebSearch/WebFetch in-session, or explicitly tagged `[unverified — training data]`.
|
|
24
|
+
Do not present training-data numbers as current fact.
|
|
@@ -18,3 +18,9 @@ color: green
|
|
|
18
18
|
@.rcode/references/codebase-grounding.md
|
|
19
19
|
@.rcode/references/karpathy-guidelines.md
|
|
20
20
|
@.rcode/skills/agents/waleed-architect/SKILL.md
|
|
21
|
+
|
|
22
|
+
## Grounding rule (mandatory)
|
|
23
|
+
|
|
24
|
+
Any pricing, fee, rate, market-size, or regulation claim MUST be verified with
|
|
25
|
+
WebSearch/WebFetch in-session, or explicitly tagged `[unverified — training data]`.
|
|
26
|
+
Do not present training-data numbers as current fact.
|
|
@@ -25,8 +25,43 @@ const fs = require('fs');
|
|
|
25
25
|
const os = require('os');
|
|
26
26
|
const path = require('path');
|
|
27
27
|
const { execSync, spawnSync } = require('child_process');
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Self-healing lib require (#960). When this file runs from an installed
|
|
31
|
+
* `.rcode/bin/` whose `lib/` is stale or partial (fresh git worktree, merge/
|
|
32
|
+
* pull that changed `rcode/bin/lib/` without a mirror sync), a hard require
|
|
33
|
+
* crashes EVERY hook — the user sees a SessionStart loader error and loses
|
|
34
|
+
* the status line entirely. Instead: on MODULE_NOT_FOUND, try healing from
|
|
35
|
+
* the in-repo source of truth (`rcode/bin/lib/<name>` relative to the project
|
|
36
|
+
* root that contains this `.rcode/`), retry once, and otherwise fail open so
|
|
37
|
+
* hooks degrade (no memory injection / drift check) rather than die.
|
|
38
|
+
*/
|
|
39
|
+
function requireLib(name) {
|
|
40
|
+
const local = path.join(__dirname, 'lib', name);
|
|
41
|
+
try { return require(local); } catch (err) {
|
|
42
|
+
if (err && err.code !== 'MODULE_NOT_FOUND') throw err;
|
|
43
|
+
try {
|
|
44
|
+
const src = path.join(__dirname, '..', '..', 'rcode', 'bin', 'lib', name);
|
|
45
|
+
if (fs.existsSync(src)) {
|
|
46
|
+
fs.mkdirSync(path.dirname(local), { recursive: true });
|
|
47
|
+
fs.copyFileSync(src, local);
|
|
48
|
+
return require(local);
|
|
49
|
+
}
|
|
50
|
+
} catch { /* healing is best-effort */ }
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const _stateReader = requireLib('state-reader.cjs') || {};
|
|
56
|
+
const resolveActivePhase = _stateReader.resolveActivePhase || (() => ({ activePhase: null, phaseLabel: null }));
|
|
57
|
+
const readSprintProgress = _stateReader.readSprintProgress || (() => ({ completedCount: 0, incompleteTasks: [] }));
|
|
58
|
+
const readRecentCommits = _stateReader.readRecentCommits || (() => []);
|
|
59
|
+
const readMilestoneHint = _stateReader.readMilestoneHint || (() => null);
|
|
60
|
+
|
|
61
|
+
const _memSelect = requireLib('memory-select.cjs') || {};
|
|
62
|
+
const selectMemoryChunks = _memSelect.selectMemoryChunks || (() => []);
|
|
63
|
+
const formatMemoryContext = _memSelect.formatMemoryContext || (() => '');
|
|
64
|
+
const hasMemory = _memSelect.hasMemory || (() => false);
|
|
30
65
|
|
|
31
66
|
// lib/memory-drift.cjs is optional at the module-load level: some hook-copy
|
|
32
67
|
// test fixtures deliberately stage a minimal bin/lib/ (only state-reader.cjs)
|
|
@@ -34,9 +69,10 @@ const { selectMemoryChunks, formatMemoryContext, hasMemory } = require('./lib/me
|
|
|
34
69
|
// require would crash every subcommand, not just `drift`/`post-commit`, so
|
|
35
70
|
// this loads lazily and fails open — same pattern as INTENT_TABLE below.
|
|
36
71
|
let checkDrift = null;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
72
|
+
{
|
|
73
|
+
const _drift = requireLib('memory-drift.cjs');
|
|
74
|
+
if (_drift) ({ checkDrift } = _drift);
|
|
75
|
+
}
|
|
40
76
|
|
|
41
77
|
/**
|
|
42
78
|
* Read and parse stdin JSON.
|
|
@@ -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
|
|
|
@@ -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
|
|
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
|
|
package/server/dashboard.js
CHANGED
|
@@ -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(
|
|
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
|
}
|
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
|
|
15
15
|
import { html, useState, useEffect, useRef, useCallback } from '../preact.js';
|
|
16
16
|
import { parseFilters } from '../filter-state.js';
|
|
17
|
-
import { getState, setState, subscribe, registerRefresh } from '../store.js';
|
|
17
|
+
import { getState, setState, subscribe, registerRefresh, closeFileViewer, closeDecisionViewer, closeBlockerViewer } from '../store.js';
|
|
18
|
+
import { FileReader } from './FileReader.js';
|
|
19
|
+
import { DecisionDrawer, BlockerDrawer } from './shared.js';
|
|
18
20
|
import { startSessionsPoll, refreshOrchToken } from '../orchestrator.js';
|
|
19
21
|
import { Sidebar } from './Sidebar.js';
|
|
20
22
|
import { Topbar } from './Topbar.js';
|
|
@@ -32,6 +34,7 @@ import { PhasesView } from '../views/PhasesView.js';
|
|
|
32
34
|
import { SprintsView } from '../views/SprintsView.js';
|
|
33
35
|
import { TasksView } from '../views/TasksView.js';
|
|
34
36
|
import { KanbanView } from '../views/KanbanView.js';
|
|
37
|
+
import { BacklogView } from '../views/BacklogView.js';
|
|
35
38
|
import { FilesView } from '../views/FilesView.js';
|
|
36
39
|
import { AgentsView } from '../views/AgentsView.js';
|
|
37
40
|
import { MemoryView } from '../views/MemoryView.js';
|
|
@@ -48,6 +51,7 @@ const PREACT_VIEWS = {
|
|
|
48
51
|
sprints: SprintsView,
|
|
49
52
|
tasks: TasksView,
|
|
50
53
|
kanban: KanbanView,
|
|
54
|
+
backlog: BacklogView,
|
|
51
55
|
files: FilesView,
|
|
52
56
|
agents: AgentsView,
|
|
53
57
|
memory: MemoryView,
|
|
@@ -213,6 +217,7 @@ export function App() {
|
|
|
213
217
|
timeline: d.timeline || null,
|
|
214
218
|
tasks: d.tasks || null,
|
|
215
219
|
health: d.health || null,
|
|
220
|
+
backlog: d.backlog || [],
|
|
216
221
|
});
|
|
217
222
|
if (newState.raw) {
|
|
218
223
|
Object.assign(patch, {
|
|
@@ -304,12 +309,21 @@ export function App() {
|
|
|
304
309
|
/>
|
|
305
310
|
</div>
|
|
306
311
|
|
|
307
|
-
<${XtermPanel} />
|
|
312
|
+
<${XtermPanel} suspend=${view === 'orchestration'} />
|
|
308
313
|
<${OrchPanel} />
|
|
309
314
|
<${BlockedToasts} />
|
|
310
315
|
<${RunnerPicker} />
|
|
311
316
|
<${RunConfirmDialog} pending=${storeState.runConfirm} />
|
|
312
317
|
<${CommandPalette} open=${paletteOpen} onClose=${() => setPaletteOpen(false)} />
|
|
318
|
+
${storeState.fileViewer && html`
|
|
319
|
+
<${FileReader}
|
|
320
|
+
path=${storeState.fileViewer.path}
|
|
321
|
+
title=${storeState.fileViewer.title}
|
|
322
|
+
onClose=${closeFileViewer}
|
|
323
|
+
/>
|
|
324
|
+
`}
|
|
325
|
+
<${DecisionDrawer} decision=${storeState.decisionViewer} onClose=${closeDecisionViewer} />
|
|
326
|
+
<${BlockerDrawer} blocker=${storeState.blockerViewer} onClose=${closeBlockerViewer} />
|
|
313
327
|
</div>
|
|
314
328
|
`;
|
|
315
329
|
}
|
|
@@ -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,
|
|
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
|
-
|
|
109
|
+
orchWs() + '/ws/' + encodeURIComponent(storyId) +
|
|
110
110
|
'?token=' + encodeURIComponent(tok)
|
|
111
111
|
);
|
|
112
112
|
_streams[storyId] = ws;
|
|
@@ -171,25 +171,33 @@ function Tooltip({ phase, nodePos, canvasW, canvasH }) {
|
|
|
171
171
|
`;
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
/**
|
|
174
|
+
/**
|
|
175
|
+
* Sequence row — the honest no-dependencies presentation. There is nothing
|
|
176
|
+
* to lay out as a DAG (no edges), so this doesn't pretend to be a graph: a
|
|
177
|
+
* connected left-to-right chain of small status pills in roadmap order,
|
|
178
|
+
* joined by arrows. Reads as "the order things ship in", not "broken nodes".
|
|
179
|
+
*/
|
|
175
180
|
function FlowRow({ phases }) {
|
|
176
181
|
return html`
|
|
177
|
-
<div class="pg-
|
|
178
|
-
|
|
182
|
+
<div class="pg-hint pg-hint-top">No cross-phase dependencies declared — phases shown in roadmap order.</div>
|
|
183
|
+
<div class="pg-seq">
|
|
184
|
+
${phases.map((p, i) => {
|
|
179
185
|
const kind = statusKind(p.status);
|
|
180
186
|
const sprints = (p.sprints || []).length;
|
|
181
187
|
return html`
|
|
182
|
-
<
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
188
|
+
<span key=${p.id} class="pg-seq-item">
|
|
189
|
+
<button type="button"
|
|
190
|
+
class=${'pg-seq-chip pg-' + kind}
|
|
191
|
+
title=${(p.name || '') + ' — ' + sprints + (sprints === 1 ? ' sprint' : ' sprints')}
|
|
192
|
+
onClick=${() => goToPhase(p.id)}>
|
|
193
|
+
<span class="pg-seq-id">P${p.id}</span>
|
|
194
|
+
<span class="pg-seq-name">${truncate(p.name, 22)}</span>
|
|
195
|
+
</button>
|
|
196
|
+
${i < phases.length - 1 ? html`<span class="pg-seq-arrow" aria-hidden="true">›</span>` : null}
|
|
197
|
+
</span>
|
|
189
198
|
`;
|
|
190
199
|
})}
|
|
191
200
|
</div>
|
|
192
|
-
<div class="pg-hint">No cross-phase dependencies declared — phases shown in roadmap order.</div>
|
|
193
201
|
`;
|
|
194
202
|
}
|
|
195
203
|
|
|
@@ -280,7 +288,7 @@ export function PhaseGraph({ phases }) {
|
|
|
280
288
|
return html`
|
|
281
289
|
<details class="pg-panel" open>
|
|
282
290
|
<summary>
|
|
283
|
-
<${Icon} name="layers" size=${14}/> Dependency Graph
|
|
291
|
+
<${Icon} name="layers" size=${14}/> ${hasDeps ? 'Dependency Graph' : 'Phases'}
|
|
284
292
|
<span class="pg-count">${list.length} ${list.length === 1 ? 'phase' : 'phases'}</span>
|
|
285
293
|
</summary>
|
|
286
294
|
<div class="pg-legend">
|
|
@@ -33,6 +33,7 @@ const NAV_LINKS = [
|
|
|
33
33
|
{ view: 'sprints', icon: 'zap', label: 'Sprints' },
|
|
34
34
|
{ view: 'tasks', icon: 'checkSquare', label: 'Tasks' },
|
|
35
35
|
{ view: 'kanban', icon: 'kanban', label: 'Kanban' },
|
|
36
|
+
{ view: 'backlog', icon: 'hourglass', label: 'Backlog' },
|
|
36
37
|
{ view: 'decisions', icon: 'scale', label: 'Decisions' },
|
|
37
38
|
{ view: 'files', icon: 'file-text', label: 'Files' },
|
|
38
39
|
{ view: 'agents', icon: 'users', label: 'Agents' },
|
|
@@ -92,10 +92,10 @@ export function Topbar({ projectName, updatedAgo, refreshing, onRefresh, onToggl
|
|
|
92
92
|
class="tb-btn tb-btn--icon"
|
|
93
93
|
type="button"
|
|
94
94
|
onClick=${onToggleTheme}
|
|
95
|
-
title=${'
|
|
96
|
-
aria-label="
|
|
95
|
+
title=${'Switch to ' + (themeLabel === 'light' ? 'dark' : 'light') + ' theme'}
|
|
96
|
+
aria-label="Toggle theme"
|
|
97
97
|
>
|
|
98
|
-
|
|
98
|
+
<${Icon} name=${themeLabel === 'light' ? 'moon' : 'sun'} size=${15} />
|
|
99
99
|
</button>
|
|
100
100
|
</div>
|
|
101
101
|
</header>
|