@hanzlaa/rcode 4.1.0 → 4.1.2

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 (53) hide show
  1. package/AGENTS.md +1 -1
  2. package/CONTRIBUTING.md +3 -0
  3. package/README.md +3 -0
  4. package/cli/agent.js +3 -1
  5. package/cli/index.js +45 -0
  6. package/cli/install.js +59 -3
  7. package/cli/workflow.js +99 -0
  8. package/dist/rcode.js +215 -187
  9. package/package.json +1 -1
  10. package/rcode/bin/lib/config.cjs +3 -2
  11. package/rcode/bin/rcode-tools.cjs +23 -9
  12. package/rcode/commands/scaffold-project.md +2 -2
  13. package/rcode/skills/actions/2-plan/rcode-create-epics-and-stories/steps/step-04-final-validation.md +1 -1
  14. package/rcode/skills/actions/2-plan/rcode-create-milestone/steps/README.md +2 -2
  15. package/rcode/skills/actions/2-plan/rcode-create-milestone/steps/step-09-state-sync.md +1 -1
  16. package/rcode/skills/actions/3-solutioning/rcode-create-architecture/steps/step-01-init.md +1 -1
  17. package/rcode/skills/actions/3-solutioning/rcode-create-architecture/workflow.md +13 -1
  18. package/rcode/skills/actions/4-implementation/rcode-code-review/steps/step-02-review.md +1 -1
  19. package/rcode/skills/actions/4-implementation/rcode-git-flow/SKILL.md +1 -1
  20. package/rcode/skills/actions/4-implementation/rcode-herdr-orchestration/SKILL.md +5 -1
  21. package/rcode/skills/actions/4-implementation/rcode-retrospective/workflow.md +61 -246
  22. package/rcode/skills/actions/4-implementation/rcode-scaffold-project/SKILL.md +39 -12
  23. package/rcode/skills/actions/4-implementation/rcode-scaffold-project/steps/step-01-target.md +18 -3
  24. package/rcode/skills/actions/4-implementation/rcode-scaffold-project/steps/step-02-safety.md +27 -3
  25. package/rcode/skills/actions/4-implementation/rcode-scaffold-project/steps/step-03-brownfield.md +57 -0
  26. package/rcode/skills/actions/4-implementation/rcode-scaffold-project/steps/step-03-clone.md +4 -1
  27. package/rcode/skills/actions/4-implementation/rcode-scaffold-project/steps/step-04-post-setup.md +15 -1
  28. package/rcode/skills/actions/4-implementation/rcode-trim/SKILL.md +1 -1
  29. package/rcode/workflows/audit-milestone.md +1 -1
  30. package/rcode/workflows/audit.md +3 -0
  31. package/rcode/workflows/brainstorm.md +1 -1
  32. package/rcode/workflows/council.md +8 -1
  33. package/rcode/workflows/create-architecture.md +5 -1
  34. package/rcode/workflows/create-prd.md +5 -1
  35. package/rcode/workflows/dashboard.md +5 -2
  36. package/rcode/workflows/discuss-phase.md +4 -16
  37. package/rcode/workflows/execute-milestone.md +1 -1
  38. package/rcode/workflows/execute-regression-gates.md +3 -0
  39. package/rcode/workflows/execute-sprint.md +30 -2
  40. package/rcode/workflows/execute-waves.md +6 -0
  41. package/rcode/workflows/execute.md +13 -3
  42. package/rcode/workflows/new-milestone.md +2 -2
  43. package/rcode/workflows/new-project.md +4 -0
  44. package/rcode/workflows/plan-research-validation.md +1 -1
  45. package/rcode/workflows/plan-spawn-planner.md +2 -2
  46. package/rcode/workflows/plan.md +34 -15
  47. package/rcode/workflows/retrospective.md +5 -1
  48. package/rcode/workflows/review.md +2 -0
  49. package/rcode/workflows/scaffold-project.md +5 -1
  50. package/rcode/workflows/session-report.md +1 -1
  51. package/rcode/workflows/ship.md +39 -0
  52. package/rcode/workflows/sprint-planning.md +36 -5
  53. package/rcode/workflows/status.md +3 -3
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`, 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`, `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`, 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
@@ -349,6 +349,9 @@ We use [Conventional Commits](https://www.conventionalcommits.org/) format. The
349
349
  - `cursor` — Cursor IDE rules under `.cursor/rules/rcode/`
350
350
  - `i18n` — internationalization, brand strings, and user-visible copy
351
351
  - `phase` — phase-lifecycle changes (variable renames, phase-loop fixes); use numeric `<phase-id>` for in-phase commits
352
+ - `scaffold` — scaffold-project workflow changes
353
+ - `campaign` — fix-campaign orchestration tracking files
354
+ - `ship` — ship workflow changes
352
355
  - `<phase-id>` — numeric phase scope when committing inside a phase (e.g. `docs(15)`, `feat(8.3)`)
353
356
  - `<sprint-id>` — numeric sprint scope inside a phase (e.g. `feat(15.1)`)
354
357
 
package/README.md CHANGED
@@ -117,6 +117,9 @@ pnpm dlx @hanzlaa/rcode install
117
117
  /rcode-init
118
118
  ```
119
119
 
120
+ > **Don't have pnpm?** On Node 18+ / npm 11.x we recommend pnpm to avoid `npx` cache issues:
121
+ > `npm install -g pnpm`
122
+
120
123
  `/rcode-init` detects your project state (fresh / existing / returning) and routes to the right first action. For a greenfield project it auto-routes to `/rcode-new-project`.
121
124
 
122
125
  ### The full loop
package/cli/agent.js CHANGED
@@ -24,7 +24,9 @@ module.exports = function agent(args, { packageRoot }) {
24
24
  }
25
25
 
26
26
  const name = args[0];
27
- const agentName = `rcode-${name}`;
27
+ // Strip rcode- prefix if already provided so rcode agent rcode-executor works (#882)
28
+ const bare = name.startsWith('rcode-') ? name.slice('rcode-'.length) : name;
29
+ const agentName = `rcode-${bare}`;
28
30
 
29
31
  // Validate agent file exists
30
32
  const agentFile = path.join(agentDir, `${agentName}.md`);
package/cli/index.js CHANGED
@@ -33,6 +33,11 @@ const COMMANDS = {
33
33
  team: require('./team'),
34
34
  agent: require('./agent'),
35
35
  doctor: require('./doctor'),
36
+ workflow: require('./workflow'), // lifecycle bridge for non-Claude runtimes
37
+ // Thin lifecycle aliases — delegate to workflow show <name> (#883)
38
+ plan: (args, ctx) => lifecycleAlias('plan', args, ctx),
39
+ execute: (args, ctx) => lifecycleAlias('execute-sprint', args, ctx),
40
+ ship: (args, ctx) => lifecycleAlias('ship', args, ctx),
36
41
  'set-profile': require('./set-profile'),
37
42
  'set-mode': require('./set-mode'),
38
43
  config: require('./config'),
@@ -68,6 +73,25 @@ Usage:
68
73
  context Memory bank freshness (--check | --refresh | --install-hook)
69
74
  github-sync Sync .rcode/ phases/epics/stories to GitHub (dry-run default)
70
75
 
76
+ šŸ”„ LIFECYCLE (Codex / Copilot / Grok bridge)
77
+ plan Print the plan workflow (alias for workflow show plan)
78
+ execute Print the execute-sprint workflow
79
+ ship Print the ship workflow
80
+ workflow list List all lifecycle workflow names
81
+ workflow show <name> Print a workflow's full instructions to stdout
82
+ workflow show new-project → project setup + ROADMAP
83
+ workflow show create-prd → write / update the PRD
84
+ workflow show discuss-phase → gather phase context
85
+ workflow show plan → create a SPRINT plan
86
+ workflow show execute-sprint → execute a SPRINT
87
+ workflow show verify-phase → verify phase completion
88
+ workflow show retrospective → retrospective + velocity
89
+ workflow show ship → deploy / release workflow
90
+
91
+ Non-Claude agents: pipe to your agent instead of using slash commands.
92
+ Example: rcode plan | codex run -
93
+ Example: rcode workflow show plan | codex run -
94
+
71
95
  šŸ‘„ TEAM
72
96
  team List the team roster
73
97
  digest Print compact digests for all agents
@@ -75,6 +99,7 @@ Usage:
75
99
  rcode agent --list to see available agents
76
100
  show-model Show which model each agent uses in the current profile
77
101
  dashboard Start the Diwan view-only dashboard (port 7717)
102
+ Starts a view-only dashboard at http://localhost:7717. No write access.
78
103
  serve Alias for dashboard
79
104
 
80
105
  āš™ļø META
@@ -95,6 +120,26 @@ Documentation: https://github.com/hanzlahabib/rihal-code
95
120
  `.trim());
96
121
  }
97
122
 
123
+ /**
124
+ * Lifecycle aliases (plan/execute/ship): show the workflow then print actionable
125
+ * next-step guidance so the user knows how to actually run it.
126
+ */
127
+ function lifecycleAlias(workflowName, args, ctx) {
128
+ require('./workflow')(['show', workflowName, ...args], ctx);
129
+
130
+ const hasAuto = args.includes('--auto') || args.includes('--run');
131
+
132
+ console.log('\n─────────────────────────────────────────────');
133
+ console.log(`ā–¶ To run: paste the above into Claude Code as /${workflowName === 'execute-sprint' ? 'rcode-execute-sprint' : `rcode-${workflowName}`}`);
134
+ console.log(' or pipe it directly: rcode ' + (workflowName === 'execute-sprint' ? 'execute' : workflowName) + ' | cld --model sonnet');
135
+
136
+ if (hasAuto) {
137
+ console.log('\n AUTO mode detected — in Claude Code run: /rcode-' +
138
+ (workflowName === 'execute-sprint' ? 'execute-sprint' : workflowName) +
139
+ ' --auto (applies yolo defaults, skips confirmation prompts)');
140
+ }
141
+ }
142
+
98
143
  /**
99
144
  * npm 10+ suppresses postinstall script output during global installs, so users
100
145
  * who run `npm install -g @hanzlaa/rcode` see only "added 1 package" with no
package/cli/install.js CHANGED
@@ -89,7 +89,7 @@ const SOURCE_ROOT = path.join(PACKAGE_ROOT, 'rcode');
89
89
  * detectIdeSignals, plus a row to runInstallWizard's multiselect — three
90
90
  * sites instead of ten.
91
91
  */
92
- const SUPPORTED_IDES = Object.freeze(['claude', 'cursor', 'gemini', 'vscode', 'antigravity', 'windsurf']);
92
+ const SUPPORTED_IDES = Object.freeze(['claude', 'cursor', 'gemini', 'vscode', 'antigravity', 'windsurf', 'codex']);
93
93
 
94
94
  /**
95
95
  * Resolve the stable on-disk location of this package so config.yaml
@@ -197,6 +197,9 @@ function parseArgs(argv) {
197
197
  silent: false,
198
198
  // noPrompt — skip all interactive prompts (used by postinstall auto-run)
199
199
  noPrompt: false,
200
+ // dry-run / list-files — preview paths that would be written, then exit
201
+ dryRun: false,
202
+ listFiles: false,
200
203
  };
201
204
  const positional = [];
202
205
  for (let i = 0; i < argv.length; i++) {
@@ -231,6 +234,8 @@ function parseArgs(argv) {
231
234
  else if (arg === '--global') opts.global = true;
232
235
  else if (arg === '--silent') opts.silent = true;
233
236
  else if (arg === '--no-prompt') opts.noPrompt = true;
237
+ else if (arg === '--dry-run') opts.dryRun = true;
238
+ else if (arg === '--list-files') opts.listFiles = true;
234
239
  else if (!arg.startsWith('--')) positional.push(arg);
235
240
  }
236
241
  if (positional[0]) {
@@ -372,7 +377,7 @@ function printInstallHeader(targetVersion) {
372
377
  * Returns a set like { claude: true, cursor: false, gemini: false }.
373
378
  */
374
379
  function detectIdeSignals(target) {
375
- const signals = { claude: false, cursor: false, gemini: false, vscode: false, antigravity: false, windsurf: false };
380
+ const signals = { claude: false, cursor: false, gemini: false, vscode: false, antigravity: false, windsurf: false, codex: false };
376
381
  // 1. Project-local install dirs (strongest signal — they already use one)
377
382
  if (fs.existsSync(path.join(target, '.claude'))) signals.claude = true;
378
383
  if (fs.existsSync(path.join(target, '.cursor'))) signals.cursor = true;
@@ -396,6 +401,7 @@ function detectIdeSignals(target) {
396
401
  if (process.env.CLAUDECODE === '1' || process.env.CLAUDE_CODE_ENTRYPOINT) signals.claude = true;
397
402
  if (process.env.VSCODE_PID || /vscode/i.test(process.env.TERM_PROGRAM || '')) signals.vscode = true;
398
403
  if (/windsurf/i.test(process.env.TERM_PROGRAM || '')) signals.windsurf = true;
404
+ if (process.env.CODEX_ENV || /codex/i.test(process.env.TERM_PROGRAM || '')) signals.codex = true;
399
405
  return signals;
400
406
  }
401
407
 
@@ -442,6 +448,7 @@ async function resolveIde(opts) {
442
448
  options: [
443
449
  { value: 'claude', label: 'Claude Code', hint: signals.claude ? '(detected)' : undefined },
444
450
  { value: 'cursor', label: 'Cursor', hint: signals.cursor ? '(detected)' : undefined },
451
+ { value: 'codex', label: 'Codex (OpenAI CLI)', hint: signals.codex ? '(detected)' : '(uses AGENTS.md + workflow bridge)' },
445
452
  { value: 'gemini', label: 'Gemini CLI', hint: signals.gemini ? '(detected)' : '(beta — limited)' },
446
453
  { value: 'vscode', label: 'VS Code', hint: signals.vscode ? '(detected)' : '(via Continue / Copilot extensions)' },
447
454
  { value: 'antigravity', label: 'Antigravity', hint: '(experimental — installs to .antigravity/)' },
@@ -522,6 +529,8 @@ Options:
522
529
  --language <lang> set communication_language (default: English)
523
530
  --mode <guided|yolo> default mode (default: guided)
524
531
  --ide <name> target IDE (claude, cursor, gemini; default: claude)
532
+ --dry-run preview what would be written; exit without writing any files
533
+ --list-files alias for --dry-run
525
534
  --help this text
526
535
 
527
536
  Installs (IDE-specific):
@@ -601,6 +610,18 @@ function getPathsForIde(ide, target) {
601
610
  referencesDir: path.join(target, '.rcode', 'references'),
602
611
  binDir: path.join(target, '.rcode', 'bin'),
603
612
  };
613
+ case 'codex':
614
+ // OpenAI Codex CLI reads AGENTS.md from the project root (written by the
615
+ // claude/vscode install paths). We install agent + command files to .claude/
616
+ // so multi-IDE installs share files, and the rcode workflow bridge gives
617
+ // Codex access to lifecycle workflows via `rcode workflow show <name>` (#883).
618
+ return {
619
+ agentsDir: path.join(target, '.claude', 'agents'),
620
+ commandsDir: path.join(target, '.claude', 'commands'),
621
+ workflowsDir: path.join(target, '.rcode', 'workflows'),
622
+ referencesDir: path.join(target, '.rcode', 'references'),
623
+ binDir: path.join(target, '.rcode', 'bin'),
624
+ };
604
625
  default:
605
626
  throw new Error(`Unknown IDE: ${ide}. Supported: ${SUPPORTED_IDES.join(', ')}`);
606
627
  }
@@ -847,6 +868,7 @@ function ensureRcodeGitignore(target, options = {}) {
847
868
  '.rcode/brain/best-practices/',
848
869
  '',
849
870
  '# Runtime noise',
871
+ 'node_modules/',
850
872
  '.rcode/state.json.lock',
851
873
  '.planning/debug/',
852
874
  '.planning/_backup/',
@@ -1928,7 +1950,8 @@ async function installInner(opts) {
1928
1950
  console.error(' Currently supported:');
1929
1951
  console.error(' claude — Claude Code native (recommended)');
1930
1952
  console.error(' cursor — Cursor IDE');
1931
- console.error(' gemini — Gemini CLI');
1953
+ console.error(' codex — Codex CLI');
1954
+ console.error(' gemini — Gemini CLI (planned — not yet implemented)');
1932
1955
  console.error(' vscode — VS Code (with Claude Code / Continue / Copilot extension)');
1933
1956
  console.error(' windsurf — Windsurf (Codeium)');
1934
1957
  console.error(' antigravity — Antigravity (experimental)');
@@ -1945,6 +1968,11 @@ async function installInner(opts) {
1945
1968
  console.log(' ' + dim('VS Code → installing to .claude/ paths (read by Claude Code / Continue / Copilot extensions).'));
1946
1969
  }
1947
1970
 
1971
+ // Codex installs to .claude/ and AGENTS.md; lifecycle via rcode workflow bridge.
1972
+ if (opts.ides.includes('codex')) {
1973
+ console.log(' ' + dim('Codex → installing to .claude/ paths + AGENTS.md. Use `rcode workflow show <name>` to feed workflows to Codex.'));
1974
+ }
1975
+
1948
1976
  // Gemini IDE support deferred
1949
1977
  if (opts.ides.includes('gemini')) {
1950
1978
  console.log(`\nāš ļø Gemini CLI install not yet implemented\n`);
@@ -1993,6 +2021,15 @@ async function installInner(opts) {
1993
2021
  console.log(` Modules: ${opts.modules.join(', ')}`);
1994
2022
  }
1995
2023
 
2024
+ // Dry run / list-files — list paths that would be written and exit without writing
2025
+ if (opts.dryRun || opts.listFiles) {
2026
+ console.log('DRY RUN: the following paths would be written:');
2027
+ for (const entry of plan) {
2028
+ console.log(' + ' + entry.rel);
2029
+ }
2030
+ return 0;
2031
+ }
2032
+
1996
2033
  // Force-overwrite backup — closes #381. Without this, customized
1997
2034
  // .claude/agents/rcode-*.md and similar package-managed files were silently
1998
2035
  // clobbered with no recovery path. Now every --force-overwrite run creates
@@ -2666,6 +2703,24 @@ async function installInner(opts) {
2666
2703
  console.error('[install] installInner: failed to count installed agents/commands:', err?.message || err);
2667
2704
  }
2668
2705
 
2706
+ // Duplicate-namespace detection: warn when both rcode-* and rihal-* entries exist.
2707
+ // Having both doubles the roster size with near-identical content.
2708
+ try {
2709
+ const skillsDir = path.join(opts.target, '.rcode', 'skills');
2710
+ const claudeCommandsDir = path.join(opts.target, '.claude', 'commands');
2711
+ const dirsToCheck = [skillsDir, claudeCommandsDir];
2712
+ let hasRcode = false, hasRihal = false;
2713
+ for (const dir of dirsToCheck) {
2714
+ if (!fs.existsSync(dir)) continue;
2715
+ const entries = fs.readdirSync(dir);
2716
+ if (entries.some(e => e.startsWith('rcode-'))) hasRcode = true;
2717
+ if (entries.some(e => e.startsWith('rihal-'))) hasRihal = true;
2718
+ }
2719
+ if (hasRcode && hasRihal) {
2720
+ process.stderr.write(pc.yellow('WARNING: rcode-* and rihal-* namespaces both detected — consider removing one to reduce roster size.') + '\n');
2721
+ }
2722
+ } catch { /* non-fatal */ }
2723
+
2669
2724
  const version = readPackageVersion();
2670
2725
  console.log('');
2671
2726
  console.log(` ${bold('Version:')} ${pc.cyan('@hanzlaa/rcode@' + version)}`);
@@ -2914,6 +2969,7 @@ async function runInstallWizard(opts) {
2914
2969
  options: [
2915
2970
  { value: 'claude', label: 'Claude Code', hint: 'recommended' },
2916
2971
  { value: 'cursor', label: 'Cursor' },
2972
+ { value: 'codex', label: 'Codex (OpenAI CLI)', hint: 'AGENTS.md + workflow bridge' },
2917
2973
  { value: 'gemini', label: 'Gemini CLI', hint: 'coming soon' },
2918
2974
  { value: 'vscode', label: 'VS Code', hint: 'via Continue / Copilot extensions' },
2919
2975
  { value: 'antigravity', label: 'Antigravity', hint: 'experimental' },
@@ -0,0 +1,99 @@
1
+ /**
2
+ * rcode workflow [list|show <name>] — lifecycle bridge for non-Claude runtimes.
3
+ *
4
+ * Codex, Copilot, Grok, and other non-Claude agents cannot invoke slash
5
+ * commands directly. This command exposes rcode's lifecycle workflows as
6
+ * readable markdown so any agent can follow the same process:
7
+ *
8
+ * rcode workflow list → list available workflow names
9
+ * rcode workflow show <name> → print workflow markdown to stdout
10
+ * rcode workflow show plan → print the plan workflow
11
+ *
12
+ * An agent consuming `rcode workflow show <name>` should treat the output
13
+ * as its operative instructions for that lifecycle step (the same content
14
+ * Claude Code loads when a slash command fires).
15
+ */
16
+
17
+ const fs = require('fs');
18
+ const path = require('path');
19
+
20
+ // Canonical lifecycle order shown in help output
21
+ const LIFECYCLE_ORDER = [
22
+ 'new-project',
23
+ 'create-prd',
24
+ 'discuss-phase',
25
+ 'plan',
26
+ 'execute-sprint',
27
+ 'verify-phase',
28
+ 'retrospective',
29
+ 'ship',
30
+ ];
31
+
32
+ module.exports = function workflow(args, { packageRoot }) {
33
+ const workflowsDir = path.join(packageRoot, 'rcode', 'workflows');
34
+
35
+ const subcommand = args[0];
36
+
37
+ if (!subcommand || subcommand === 'list' || subcommand === '--list') {
38
+ return listWorkflows(workflowsDir);
39
+ }
40
+
41
+ if (subcommand === 'show' || subcommand === 'get' || subcommand === 'run') {
42
+ const name = args[1];
43
+ if (!name) {
44
+ console.error('Usage: rcode workflow show <name>');
45
+ console.error(' rcode workflow list');
46
+ process.exit(1);
47
+ }
48
+ return showWorkflow(workflowsDir, name);
49
+ }
50
+
51
+ // Treat bare `rcode workflow <name>` as show
52
+ return showWorkflow(workflowsDir, subcommand);
53
+ };
54
+
55
+ function listWorkflows(workflowsDir) {
56
+ const all = fs.readdirSync(workflowsDir)
57
+ .filter(f => f.endsWith('.md'))
58
+ .map(f => f.replace(/\.md$/, ''))
59
+ .sort();
60
+
61
+ // Show lifecycle commands first, then remaining alphabetically
62
+ const lifecycle = LIFECYCLE_ORDER.filter(n => all.includes(n));
63
+ const rest = all.filter(n => !LIFECYCLE_ORDER.includes(n));
64
+
65
+ console.log('šŸ•Œ rcode lifecycle workflows\n');
66
+ console.log('Core lifecycle (in order):');
67
+ lifecycle.forEach(n => console.log(` rcode workflow show ${n}`));
68
+ if (rest.length) {
69
+ console.log('\nOther workflows:');
70
+ rest.forEach(n => console.log(` rcode workflow show ${n}`));
71
+ }
72
+ console.log('\nUsage: rcode workflow show <name> — print the full workflow instructions');
73
+ }
74
+
75
+ function showWorkflow(workflowsDir, name) {
76
+ // Normalise: strip rcode- prefix so both `plan` and `rcode-plan` resolve (#883)
77
+ const bare = name.startsWith('rcode-') ? name.slice('rcode-'.length) : name;
78
+ const candidates = [
79
+ path.join(workflowsDir, `${bare}.md`),
80
+ path.join(workflowsDir, `${name}.md`),
81
+ ];
82
+
83
+ for (const p of candidates) {
84
+ if (fs.existsSync(p)) {
85
+ process.stdout.write(fs.readFileSync(p, 'utf8'));
86
+ return;
87
+ }
88
+ }
89
+
90
+ // Not found — list available and exit non-zero
91
+ const available = fs.readdirSync(workflowsDir)
92
+ .filter(f => f.endsWith('.md'))
93
+ .map(f => f.replace(/\.md$/, ''))
94
+ .sort()
95
+ .join(', ');
96
+ console.error(`Error: workflow '${name}' not found.`);
97
+ console.error(`Available: ${available}`);
98
+ process.exit(1);
99
+ }