@hanzlaa/rcode 4.7.1 → 4.7.3

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/AGENTS.md CHANGED
@@ -24,7 +24,7 @@ If a user says "just keep going" or "don't stop until done", that authorization
24
24
 
25
25
  - Follow [Conventional Commits](https://www.conventionalcommits.org/) format: `type(scope): subject`
26
26
  - Types allowed: `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore`, `perf`, `revert`
27
- - Scopes allowed: `agents`, `skills`, `workflows`, `templates`, `dashboard`, `docs`, `config`, `github`, `commands`, `memory`, `brand`, `cli`, `ci`, `release`, `meta`, `tasks`, `migrations`, `refs`, `state`, `hooks`, `install`, `parity`, `triggers`, `dogfood`, `namespace`, `planning`, `insights`, `help`, `roadmap`, `session`, `audits`, `execute`, `executor`, `plan`, `planner`, `readme`, `sync`, `sprint`, `agent-exp`, `extensibility`, `lens-audit`, `tiers`, `build`, `council`, `doctor`, `postinstall`, `progress`, `security`, `tools`, `uninstall`, `update`, `test`, `changelog`, `scopes`, `phases`, `references`, `kanban`, `orchestrator`, `orchpanel`, `status`, `bin`, `brain`, `dogfeed`, `new-project`, `package`, `rcode-tools`, `rihal-tools`, `team`, `usp`, `v4`, `observability`, `audit`, `agent-rules`, `cursor`, `i18n`, `phase`, `scaffold`, `campaign`, `ship`, `getting-started`, `do-router`, `milestone-health`, `modules`, `project-types`, `roadmapper`, `token`, plus numeric phase/sprint scopes (e.g. `docs(15)`, `feat(8.3)`)
27
+ - Scopes allowed: `agents`, `skills`, `workflows`, `templates`, `dashboard`, `docs`, `config`, `github`, `commands`, `memory`, `brand`, `cli`, `ci`, `release`, `meta`, `tasks`, `migrations`, `refs`, `state`, `hooks`, `init`, `install`, `parity`, `triggers`, `dogfood`, `namespace`, `planning`, `insights`, `help`, `roadmap`, `session`, `audits`, `execute`, `executor`, `plan`, `planner`, `readme`, `sync`, `sprint`, `agent-exp`, `extensibility`, `lens-audit`, `tiers`, `build`, `council`, `doctor`, `postinstall`, `progress`, `security`, `tools`, `uninstall`, `update`, `test`, `changelog`, `scopes`, `phases`, `references`, `kanban`, `orchestrator`, `orchpanel`, `status`, `bin`, `brain`, `dogfeed`, `new-project`, `package`, `rcode-tools`, `rihal-tools`, `team`, `usp`, `v4`, `observability`, `audit`, `agent-rules`, `cursor`, `i18n`, `phase`, `scaffold`, `campaign`, `ship`, `getting-started`, `do-router`, `milestone-health`, `modules`, `project-types`, `roadmapper`, `token`, plus numeric phase/sprint scopes (e.g. `docs(15)`, `feat(8.3)`)
28
28
  - Subject: lowercase first letter, imperative mood, no trailing period, under 72 chars
29
29
  - **NEVER add Claude/AI attribution to commit messages.** No "Generated with Claude Code", no "Co-Authored-By: Claude", no "🤖 Generated". The user does not want this.
30
30
  - **NEVER use `--no-verify`** to bypass hooks. If hooks fail, fix the underlying issue.
package/CONTRIBUTING.md CHANGED
@@ -286,6 +286,7 @@ We use [Conventional Commits](https://www.conventionalcommits.org/) format. The
286
286
  - `state` — `.rcode/state.json` and state-manipulation code paths
287
287
  - `refs` — files inside `rcode/references/`
288
288
  - `hooks` — `.claude/hooks/*` and install-time hook wiring
289
+ - `init` — `/rcode-init` command and init-time project bootstrap
289
290
  - `install` — installer flow, manifest, side-effects
290
291
  - `memory` — Memory Bank distillates and templates
291
292
  - `brand` — branding/voice across surfaces
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanzlaa/rcode",
3
- "version": "4.7.1",
3
+ "version": "4.7.3",
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": {
@@ -1,6 +1,15 @@
1
1
  ---
2
2
  name: rcode-do
3
- description: "[ROUTER] Interactive picker — describe what you want and rcode picks the command"
3
+ description: >-
4
+ [ROUTER] Interactive picker — describe what you want and rcode picks
5
+ the command. Activates whenever the user says "use rcode", "using
6
+ rcode", "rcode kar do", "rcode say kara do", "let rcode handle
7
+ this/it", "rcode this", or otherwise names rcode as the tool to use
8
+ for a task without naming a specific /rcode-* command — especially
9
+ when the request bundles multiple asks (e.g. "init a phase, build a
10
+ checklist, make a sprint"). Route through this picker instead of
11
+ hand-rolling files or Bash workarounds for what rcode already has a
12
+ command for.
4
13
  argument-hint: "[optional question or task description]"
5
14
  allowed-tools:
6
15
  - Read
@@ -79,6 +79,12 @@ Planner prompt:
79
79
  **Phase:** {phase_number}
80
80
  **Mode:** {standard | gap_closure | reviews}
81
81
 
82
+ ## Scope
83
+
84
+ Default: `phase` (one SPRINT.md, up to 8 stories — see Scope-Driven Sizing in your role instructions).
85
+
86
+ **Self-upgrade to `initiative` mid-decomposition** if, once you've read CONTEXT.md/ROADMAP.md and started breaking down the work, it splits into independent waves or work-streams (e.g. shared-primitive foundation → feature-local migrations → cleanup/tests) and total stories would exceed 8. When that happens, emit multiple SPRINT.md files (`{phase}-1-SPRINT.md`, `{phase}-2-SPRINT.md`, ...) in this same run instead of one oversized plan. Do not wait for rcode-sprint-checker's "scope exceeds context budget" rejection to force a resharding pass — that costs a full extra planner run. Decide the split now, while you're already looking at the file/story list.
87
+
82
88
  <files_to_read>
83
89
  - {state_path} (Project State)
84
90
  - {roadmap_path} (Roadmap)
@@ -17,6 +17,21 @@ import { Icon } from '../icons-client.js';
17
17
  import { TaskPipeline } from './TaskPipeline.js';
18
18
  import { openRunnerPicker } from './RunnerPicker.js';
19
19
 
20
+ // ---- Acceptance criteria: SPRINT.md stores this as "- line\n- line";
21
+ // rendering it as raw text collapses the newlines into one run-on line. ----
22
+ export function AcceptanceList({ text }) {
23
+ const lines = String(text || '')
24
+ .split('\n')
25
+ .map(l => l.replace(/^\s*[-*]\s*/, '').trim())
26
+ .filter(Boolean);
27
+ if (!lines.length) return null;
28
+ return html`
29
+ <ul class="task-actions-list">
30
+ ${lines.map((line, i) => html`<li key=${i} class="task-action-step">${line}</li>`)}
31
+ </ul>
32
+ `;
33
+ }
34
+
20
35
  // ---- Toast helper (shared by CmdHint copy action and any view) ----
21
36
  export function showToast(msg) {
22
37
  const el = document.getElementById('toast');
@@ -131,7 +146,11 @@ export function Breadcrumb({ items }) {
131
146
  * @param {{ cmd: string, desc: string }} props
132
147
  */
133
148
  export function CmdHint({ cmd, desc }) {
134
- function handleClick() {
149
+ function handleClick(e) {
150
+ // CmdHint often sits inside a clickable card row (SprintCard's empty
151
+ // state, etc.) — without this, copying the command also fires the
152
+ // row's own click (e.g. navigating away mid-copy).
153
+ if (e && e.stopPropagation) e.stopPropagation();
135
154
  navigator.clipboard.writeText(cmd)
136
155
  .then(() => showToast('Copied: ' + cmd))
137
156
  .catch(() => {
@@ -291,9 +310,7 @@ export function SprintCard({ sprint: s, S }) {
291
310
  </div>
292
311
  <div style="margin-top:6px;"><${ProgressBar} done=${done} total=${stories.length}/></div>
293
312
  ${stories.length === 0 ? html`
294
- <div class="empty-action" style="margin-top:var(--space-2);font-size:var(--text-xs);">
295
- No tasks — run <code>/rcode-plan ${phaseId}</code> to populate
296
- </div>
313
+ <${CmdHint} cmd=${'/rcode-plan ' + phaseId} desc="Populate this sprint with tasks"/>
297
314
  ` : null}
298
315
  ${s.started_at ? html`
299
316
  <div style="color:var(--text-muted);font-size:var(--text-xs);margin-top:4px;">
@@ -370,7 +387,12 @@ export function TaskCard({ task: t }) {
370
387
  <strong>Phase:</strong> P${t.phaseId}${t.phaseName ? ' — ' + t.phaseName : ''}
371
388
  </div>
372
389
  ` : null}
373
- ${t.acceptance ? html`<div class="task-detail-row"><strong>Acceptance:</strong> ${t.acceptance}</div>` : null}
390
+ ${t.acceptance ? html`
391
+ <div class="task-actions">
392
+ <div class="task-actions-title">Acceptance</div>
393
+ <${AcceptanceList} text=${t.acceptance}/>
394
+ </div>
395
+ ` : null}
374
396
  ${t.assignee ? html`<div class="task-detail-row"><strong>Assignee:</strong> ${t.assignee}</div>` : null}
375
397
  ${(t.actions && t.actions.length) ? html`
376
398
  <div class="task-actions">
@@ -9,7 +9,7 @@
9
9
 
10
10
  import { html } from '../preact.js';
11
11
  import { useStore } from '../store.js';
12
- import { pressable } from '../components/shared.js';
12
+ import { pressable, CmdHint } from '../components/shared.js';
13
13
  import { Icon } from '../icons-client.js';
14
14
 
15
15
  export function BacklogView() {
@@ -23,7 +23,7 @@ export function BacklogView() {
23
23
  ? html`
24
24
  <div class="empty">
25
25
  No phases waiting in the backlog.
26
- <div class="empty-action">Run /rcode-add-phase to queue up new work</div>
26
+ <${CmdHint} cmd="/rcode-add-phase" desc="Queue up new work"/>
27
27
  </div>
28
28
  `
29
29
  : html`
@@ -9,11 +9,11 @@
9
9
 
10
10
  import { html, useState, useCallback } from '../preact.js';
11
11
  import { useStore, refresh } from '../store.js';
12
- import { allTasks, currentPhaseName } from '../util.js';
12
+ import { allTasks, currentPhaseName, currentPhaseId } from '../util.js';
13
13
  import { stopStory, openOrchPanel, openTermPanel, setTaskStatus } from '../orchestrator.js';
14
14
  import { openFileViewer } from '../store.js';
15
15
  import { openRunnerPicker } from '../components/RunnerPicker.js';
16
- import { showToast } from '../components/shared.js';
16
+ import { showToast, CmdHint } from '../components/shared.js';
17
17
 
18
18
  // ---- Column descriptors ----
19
19
  const COLS = [
@@ -262,9 +262,11 @@ export function KanbanView() {
262
262
  ${' is active.'}
263
263
  </div>
264
264
  ` : null}
265
+ <${CmdHint}
266
+ cmd=${'/rcode-plan' + (currentPhaseId(currentPhase) ? ' ' + currentPhaseId(currentPhase) : '')}
267
+ desc="Generate sprint stories"/>
265
268
  <div class="empty-action">
266
- Run <code>/rcode-plan</code> to generate sprint stories, or browse
267
- planning docs in the <a href="#files">Files</a> view.
269
+ Or browse planning docs in the <a href="#files">Files</a> view.
268
270
  </div>
269
271
  </div>
270
272
  </div>
@@ -14,6 +14,7 @@
14
14
 
15
15
  import { html, useState, useEffect } from '../preact.js';
16
16
  import { FileReader } from '../components/FileReader.js';
17
+ import { CmdHint } from '../components/shared.js';
17
18
 
18
19
  // ---- Command hints accordion ----
19
20
  const MEMORY_HINTS = [
@@ -127,7 +128,7 @@ export function MemoryView() {
127
128
  <div class="empty">
128
129
  <h3 style="color:var(--rcode-gold);">Not initialised</h3>
129
130
  <p>The Memory Bank is rcode's structured project context.</p>
130
- <div class="empty-action">Run <code>/rcode-memory-init</code> to bootstrap</div>
131
+ <${CmdHint} cmd="/rcode-memory-init" desc="Bootstrap the Memory Bank"/>
131
132
  </div>
132
133
  </div>
133
134
  `;
@@ -11,7 +11,7 @@ import { html, useState } from '../preact.js';
11
11
  import { useStore } from '../store.js';
12
12
  import { pct, humanDate, phaseHints, chip, phaseMilestone } from '../util.js';
13
13
  import {
14
- Chip, ProgressBar, Breadcrumb, CmdHints, RunningBadge, SprintCard, PhaseCard,
14
+ Chip, ProgressBar, Breadcrumb, CmdHint, CmdHints, RunningBadge, SprintCard, PhaseCard,
15
15
  } from '../components/shared.js';
16
16
  import { openTermPanel, runningInPhase } from '../orchestrator.js';
17
17
  import { openFileViewer } from '../store.js';
@@ -118,7 +118,7 @@ function PhaseDetail({ phase: p, S }) {
118
118
  : html`
119
119
  <div class="empty">
120
120
  No sprints in this phase yet.
121
- <div class="empty-action">Run /rcode-plan to create sprints</div>
121
+ <${CmdHint} cmd=${'/rcode-plan ' + p.id} desc="Create sprints for this phase"/>
122
122
  </div>
123
123
  `}
124
124
  </div>
@@ -212,7 +212,7 @@ export function PhasesView({ subId, filters }) {
212
212
  : html`
213
213
  <div class="empty">
214
214
  No phases yet.
215
- <div class="empty-action">Run /rcode-new-project to start</div>
215
+ <${CmdHint} cmd="/rcode-new-project" desc="Design your first project"/>
216
216
  </div>
217
217
  `}
218
218
  </div>
@@ -10,9 +10,9 @@
10
10
 
11
11
  import { html, useState } from '../preact.js';
12
12
  import { useStore } from '../store.js';
13
- import { pct, humanDate, allSprints, sprintHints, chip, phaseMilestone } from '../util.js';
13
+ import { pct, humanDate, allSprints, sprintHints, chip, phaseMilestone, currentPhaseId } from '../util.js';
14
14
  import {
15
- Chip, ProgressBar, Breadcrumb, CmdHints, RunningBadge, SprintCard, TaskCard,
15
+ Chip, ProgressBar, Breadcrumb, CmdHint, CmdHints, RunningBadge, SprintCard, TaskCard, AcceptanceList,
16
16
  } from '../components/shared.js';
17
17
  import { openTermPanel, runningInSprint } from '../orchestrator.js';
18
18
  import { openFileViewer } from '../store.js';
@@ -105,7 +105,7 @@ function SprintDetail({ sprint: s, S }) {
105
105
  : html`
106
106
  <div class="empty">
107
107
  No tasks in this sprint yet.
108
- <div class="empty-action">Run /rcode-create-story to add tasks</div>
108
+ <${CmdHint} cmd=${'/rcode-create-story ' + s.id} desc="Add a task to this sprint"/>
109
109
  </div>
110
110
  `}
111
111
  </div>
@@ -115,8 +115,8 @@ function SprintDetail({ sprint: s, S }) {
115
115
  ${storiesWithAc.map(t => html`
116
116
  <div key=${t.id || t.title} class="item">
117
117
  <div class="item-title">${t.title}</div>
118
- <div style="color:var(--text-secondary);font-size:var(--text-sm);margin-top:4px;">
119
- ${t.acceptance}
118
+ <div style="margin-top:4px;">
119
+ <${AcceptanceList} text=${t.acceptance}/>
120
120
  </div>
121
121
  </div>
122
122
  `)}
@@ -210,7 +210,7 @@ export function SprintsView({ subId, filters }) {
210
210
  : html`
211
211
  <div class="empty">
212
212
  No sprints yet.
213
- <div class="empty-action">Run /rcode-plan to create sprints</div>
213
+ <${CmdHint} cmd=${'/rcode-plan' + (currentPhaseId(S.currentPhase) ? ' ' + currentPhaseId(S.currentPhase) : '')} desc="Plan sprints for the current phase"/>
214
214
  </div>
215
215
  `}
216
216
  </div>
@@ -9,7 +9,7 @@
9
9
  import { html, useState, useMemo } from '../preact.js';
10
10
  import { useStore } from '../store.js';
11
11
  import { allTasks, currentPhaseId } from '../util.js';
12
- import { CmdHints, TaskCard } from '../components/shared.js';
12
+ import { CmdHint, CmdHints, TaskCard } from '../components/shared.js';
13
13
 
14
14
  function TaskGrouped({ tasks }) {
15
15
  if (!tasks.length) return null;
@@ -137,9 +137,7 @@ export function TasksView() {
137
137
  : html`
138
138
  <div class="empty">
139
139
  No tasks yet.
140
- <div class="empty-action">
141
- Run <code>/rcode-plan${phaseHint}</code> to generate tasks for this project.
142
- </div>
140
+ <${CmdHint} cmd=${'/rcode-plan' + phaseHint} desc="Generate tasks for this project"/>
143
141
  </div>
144
142
  `}
145
143
  </div>
@@ -149,17 +149,20 @@ function buildPhaseTree(projectDir, rawPhases, listCached, overrides) {
149
149
  goal = (obj.trim().split('\n').map(s => s.trim()).filter(Boolean)[0] || '').slice(0, 160);
150
150
  }
151
151
 
152
- // Stories: one per <task> block; title from <title>.
152
+ // Stories: one per <task> block; title from the task's own title="..."
153
+ // attribute (current planner output), falling back to a legacy nested
154
+ // <title> child element for older SPRINT.md files.
153
155
  const stories = [];
154
156
  const taskRe = /<task\b([^>]*)>([\s\S]*?)<\/task>/g;
155
157
  let tm;
156
158
  while ((tm = taskRe.exec(text))) {
157
- const idM = tm[1].match(/id="([^"]+)"/);
158
- const titleM = tm[2].match(/<title>([\s\S]*?)<\/title>/);
159
+ const idM = tm[1].match(/id="([^"]+)"/);
160
+ const titleAttrM = tm[1].match(/title="([^"]*)"/);
161
+ const titleTagM = tm[2].match(/<title>([\s\S]*?)<\/title>/);
159
162
  const acM = tm[2].match(/<acceptance_criteria>\s*([\s\S]*?)\s*<\/acceptance_criteria>/);
160
163
  const story = {
161
164
  id: idM ? idM[1] : `${sid}-task-${stories.length + 1}`,
162
- title: titleM ? titleM[1].trim() : `Task ${stories.length + 1}`,
165
+ title: (titleAttrM && titleAttrM[1].trim()) || (titleTagM && titleTagM[1].trim()) || `Task ${stories.length + 1}`,
163
166
  status: phaseComplete ? 'done' : 'todo',
164
167
  };
165
168
  if (ov[story.id]) story.status = ov[story.id].status;