@hanzlaa/rcode 4.9.1 → 4.10.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanzlaa/rcode",
3
- "version": "4.9.1",
3
+ "version": "4.10.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": {
@@ -332,18 +332,37 @@ export function TaskCard({ task: t }) {
332
332
  const done = t.status === 'done' || t.status === 'completed';
333
333
  const running = isSessionRunning(t.id);
334
334
 
335
- // Build cmd hints for this task
335
+ // Build cmd hints for this task. rcode has two separate tracking pipelines
336
+ // that both use "sprint" terminology: phase -> SPRINT.md plan -> task
337
+ // (t.phaseId set; this is the real, execution-backed pipeline) vs.
338
+ // epic -> story (no t.phaseId; dev-story/create-story/verify-work). Using
339
+ // dev-story/create-story commands against a phase-pipeline task id (e.g.
340
+ // "1.1.2") doesn't parse — those commands only accept 2-part epic.story
341
+ // ids. Branch on t.phaseId so the hints (and the RunBtn below) actually
342
+ // resolve to a real command for whichever pipeline this task is from.
343
+ const isPhaseTask = !!t.phaseId;
344
+ const runCmd = isPhaseTask ? '/rcode-execute ' + t.phaseId : '/rcode-dev-story ' + t.id;
336
345
  const taskCmds = [];
337
346
  if (t.id) {
338
- if (!done) {
339
- taskCmds.push(['/rcode-dev-story ' + t.id, 'Implement this story']);
340
- taskCmds.push(['/rcode-create-story ' + (t.sprintId || ''), 'Add related story']);
347
+ if (isPhaseTask) {
348
+ if (!done) {
349
+ taskCmds.push(['/rcode-execute ' + t.phaseId, 'Execute phase ' + t.phaseId]);
350
+ } else {
351
+ taskCmds.push(['/rcode-verify-phase ' + t.phaseId, 'Verify phase ' + t.phaseId]);
352
+ taskCmds.push(['/rcode-review --phase ' + t.phaseId + ' --all', 'Review code for this phase']);
353
+ }
354
+ taskCmds.push(['/rcode-progress', 'Overall project status']);
341
355
  } else {
342
- taskCmds.push(['/rcode-verify-work ' + t.id, 'Verify this story']);
343
- taskCmds.push(['/rcode-review ' + t.id, 'Review code for this story']);
344
- }
345
- if (t.sprintId) {
346
- taskCmds.push(['/rcode-sprint-status ' + t.sprintId, 'Sprint ' + t.sprintId + ' status']);
356
+ if (!done) {
357
+ taskCmds.push(['/rcode-dev-story ' + t.id, 'Implement this story']);
358
+ taskCmds.push(['/rcode-create-story ' + (t.sprintId || ''), 'Add related story']);
359
+ } else {
360
+ taskCmds.push(['/rcode-verify-work ' + t.id, 'Verify this story']);
361
+ taskCmds.push(['/rcode-review ' + t.id, 'Review code for this story']);
362
+ }
363
+ if (t.sprintId) {
364
+ taskCmds.push(['/rcode-sprint-status ' + t.sprintId, 'Sprint ' + t.sprintId + ' status']);
365
+ }
347
366
  }
348
367
  }
349
368
 
@@ -357,7 +376,7 @@ export function TaskCard({ task: t }) {
357
376
  aria-expanded=${expanded}
358
377
  ...${pressable(() => setExpanded(e => !e))}>
359
378
  <div class="item-title" style=${done ? 'text-decoration:line-through' : ''}>
360
- ${t.id && !done ? html`<${RunBtn} storyId=${t.id} cmd=${'/rcode-dev-story ' + t.id} label=${'Story ' + t.id}/>` : null}
379
+ ${t.id && !done ? html`<${RunBtn} storyId=${t.id} cmd=${runCmd} label=${isPhaseTask ? 'Phase ' + t.phaseId : 'Story ' + t.id}/>` : null}
361
380
  ${t.file ? html`
362
381
  <button class="card-file-btn" title=${'View ' + t.file} onClick=${handleViewFile}>
363
382
  <${Icon} name="file-text" size=${11}/> File
@@ -195,7 +195,7 @@ function buildPhaseTree(projectDir, rawPhases, listCached, overrides) {
195
195
  // Status: a *-SUMMARY.md sibling means the sprint shipped.
196
196
  const hasSummary = files.includes(f.replace(/-SPRINT\.md$/i, '-SUMMARY.md'));
197
197
  const status = hasSummary ? 'complete'
198
- : (p.status === 'active' || p.status === 'in_progress') ? 'in_progress'
198
+ : toState(p.status) === 'active' ? 'in_progress'
199
199
  : 'planned';
200
200
 
201
201
  // Project-relative path to this sprint's SPRINT.md — same shape as the
@@ -383,7 +383,7 @@ function buildDashboard(state) {
383
383
  date: fmtISODate(p.completed || s.completed_at || p.created),
384
384
  file: s.file || null,
385
385
  });
386
- } else if (p.state === 'active') {
386
+ } else if (toState(p.status) === 'active') {
387
387
  // No per-task progress tracking exists — pct stays null and the UI
388
388
  // omits the percent pill rather than inventing a number.
389
389
  inProgressTasks.push({ title: st.title || st.id, pct: null, file: s.file || null });
@@ -393,10 +393,10 @@ function buildDashboard(state) {
393
393
  }
394
394
  // Fallbacks so the cards are never empty when stories are unregistered in state.json.
395
395
  if (!completedTasks.length) {
396
- phases.filter(p => p.state === 'done').slice(-6).forEach(p =>
396
+ phases.filter(p => toState(p.status) === 'done').slice(-6).forEach(p =>
397
397
  completedTasks.push({ title: p.name, date: fmtISODate(p.completed || p.created), file: null }));
398
398
  }
399
- if (!inProgressTasks.length && activePhase && activePhase.state === 'active') {
399
+ if (!inProgressTasks.length && activePhase && toState(activePhase.status) === 'active') {
400
400
  inProgressTasks.push({ title: activePhase.name, pct: null, file: null });
401
401
  }
402
402
  const tasks = {