roadmapsmith 0.9.29 → 0.9.31

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/bin/cli.js CHANGED
@@ -19,21 +19,27 @@ const { buildZeroModeConfigPatch, buildZeroModeDefaults, collectZeroModeAnswers,
19
19
  function printHelp() {
20
20
  console.log([
21
21
  'Usage:',
22
+ ' Canonical commands:',
22
23
  ' roadmapsmith zero [--project-root <path>] [--config <path>]',
23
- ' roadmapsmith maintain [--project-root <path>] [--config <path>] [--roadmap-file <path>] [--full-regen]',
24
- ' roadmapsmith /roadmap',
25
- ' roadmapsmith /roadmap <action>',
26
- ' roadmapsmith /roadmap-zero | /roadmap-maintain | /roadmap-status | /roadmap-init | /roadmap-generate | /roadmap-validate | /roadmap-update | /roadmap-audit | /roadmap-setup',
27
- ' roadmapsmith /road <action> # deprecated compatibility alias',
28
- ' roadmapsmith /roadmap-sync <action> # deprecated legacy compatibility root',
29
- ' roadmapsmith init [--roadmap-file <path>] [--agents-file <path>] [--dry-run]',
24
+ ' roadmapsmith maintain [--project-root <path>] [--config <path>] [--roadmap-file <path>] [--full-regen] [--refresh-annotations]',
25
+ ' roadmapsmith status [--roadmap-file <path>] [--project-root <path>] [--config <path>] [--json]',
26
+ ' roadmapsmith validate [--roadmap-file <path>] [--project-root <path>] [--config <path>] [--task <id|text>] [--json] [--strict]',
27
+ ' roadmapsmith update [--task <stable-id> --evidence <text>] [--roadmap-file <path>] [--project-root <path>] [--config <path>] [--dry-run]',
30
28
  ' roadmapsmith setup [--project-root <path>] [--config <path>] [--editor vscode] [--hosts <codex,claude>] [--dry-run]',
29
+ '',
30
+ ' Advanced commands:',
31
+ ' roadmapsmith init [--roadmap-file <path>] [--agents-file <path>] [--dry-run]',
31
32
  ' roadmapsmith generate [--project-root <path>] [--config <path>] [--roadmap-file <path>] [--dry-run] [--audit] [--full-regen]',
32
- ' roadmapsmith sync [--roadmap-file <path>] [--project-root <path>] [--config <path>] [--dry-run] [--audit]',
33
- ' roadmapsmith update --task <stable-id> --evidence <text> [--roadmap-file <path>] [--project-root <path>] [--config <path>] [--dry-run]',
34
- ' roadmapsmith validate [--roadmap-file <path>] [--project-root <path>] [--config <path>] [--task <id|text>] [--json]',
35
- ' roadmapsmith status [--roadmap-file <path>] [--project-root <path>] [--config <path>] [--json]',
36
- ' roadmapsmith doctor [--roadmap-file <path>] [--project-root <path>] [--config <path>] [--json] # compatibility alias'
33
+ ' roadmapsmith sync [--roadmap-file <path>] [--project-root <path>] [--config <path>] [--dry-run] [--audit] [--refresh-annotations]',
34
+ ' roadmapsmith /roadmap',
35
+ ' roadmapsmith /roadmap <action>',
36
+ ' roadmapsmith /roadmap-zero | /roadmap-maintain | /roadmap-status | /roadmap-validate | /roadmap-update | /roadmap-setup | /roadmap-init | /roadmap-generate | /roadmap-audit',
37
+ '',
38
+ ' Compatibility notes:',
39
+ ' roadmapsmith doctor [--json] # compatibility alias for status',
40
+ ' roadmapsmith regenerate # deprecated alias for generate --full-regen',
41
+ ' roadmapsmith /road <action> # deprecated compatibility alias',
42
+ ' roadmapsmith /roadmap-sync <action> # deprecated legacy compatibility root'
37
43
  ].join('\n'));
38
44
  }
39
45
 
@@ -81,6 +87,23 @@ function printAudit(audit) {
81
87
  }
82
88
  }
83
89
 
90
+ function printReadinessSummary(summary) {
91
+ if (!summary || typeof summary !== 'object') {
92
+ return;
93
+ }
94
+
95
+ console.log('\nStructured readiness summary:');
96
+ console.log(`- Workspace readiness: ${summary.workspaceReady ? 'ready' : 'needs setup'}`);
97
+ console.log(`- Codex readiness: ${summary.codexReady ? 'ready' : 'needs setup'}`);
98
+ console.log(`- Claude readiness: ${summary.claudeReady ? 'ready' : 'needs setup'}`);
99
+ console.log(`- Canonical native surfaces: ${summary.canonicalSurfaceReady ? 'ready' : 'needs attention'}`);
100
+ if (Array.isArray(summary.advancedSurfaceWarnings) && summary.advancedSurfaceWarnings.length > 0) {
101
+ summary.advancedSurfaceWarnings.forEach((warning) => {
102
+ console.log(`- Advanced warning: ${warning}`);
103
+ });
104
+ }
105
+ }
106
+
84
107
  function formatSurfaceLabel(surfaceKey) {
85
108
  return surfaceKey
86
109
  .replace(/([A-Z])/g, ' $1')
@@ -203,7 +226,8 @@ function runSyncCommand(projectRoot, config, flags, options = {}) {
203
226
  const validationContext = buildValidationContext(projectRoot, config, loadPlugins(projectRoot, config.plugins));
204
227
  const results = validateTasks(syncTasks, validationContext, config, validationContext.plugins);
205
228
  applyMinimumConfidence(results, config.validation?.minimumConfidence);
206
- const next = applySync(content, syncTasks, results);
229
+ const forceRefresh = isEnabled(flags['refresh-annotations']);
230
+ const next = applySync(content, syncTasks, results, { forceRefresh });
207
231
  const dryRun = isEnabled(flags['dry-run']);
208
232
  const writeResult = writeText(roadmapFile, next, { dryRun });
209
233
 
@@ -307,13 +331,18 @@ function printHumanStatus(payload) {
307
331
  if (!payload.vscode.tasks.ready && payload.vscode.tasks.missingLabels.length > 0) {
308
332
  console.log(`Missing VS Code tasks: ${payload.vscode.tasks.missingLabels.join(', ')}`);
309
333
  }
334
+ if (Array.isArray(payload.vscode.tasks.missingAdvancedLabels) && payload.vscode.tasks.missingAdvancedLabels.length > 0) {
335
+ console.log(`Missing advanced VS Code tasks: ${payload.vscode.tasks.missingAdvancedLabels.join(', ')}`);
336
+ }
310
337
  if (!payload.vscode.wrappers.ready) {
311
338
  console.log(`Missing task wrapper files: ${payload.vscode.wrappers.missingPaths.join(', ')}`);
312
339
  }
313
340
  console.log(`Codex readiness: ${payload.hosts.codex.ready ? 'ready' : 'needs setup'} (${payload.hosts.codex.message})`);
314
341
  console.log(`Claude readiness: ${payload.hosts.claude.ready ? 'ready' : 'needs setup'} (${payload.hosts.claude.message})`);
342
+ printReadinessSummary(payload.summary);
315
343
  printNativeSurfaceStatus(payload.surfaces);
316
- console.log('\nRecommended entrypoints: roadmapsmith zero (empty repo), roadmapsmith maintain (existing repo).');
344
+ console.log('\nRecommended entrypoints: roadmapsmith zero (empty repo), roadmapsmith maintain (existing repo), roadmapsmith update (canonical checklist refresh/task completion).');
345
+ console.log('Compatibility note: roadmapsmith doctor mirrors this payload for existing automation.');
317
346
  if (!payload.cli.ready) {
318
347
  console.log('\nInstalling the skill alone does not expose the CLI in VS Code. Install the CLI and rerun roadmapsmith setup.');
319
348
  }
@@ -422,8 +451,6 @@ async function run() {
422
451
  if (slashAction.id === 'audit') {
423
452
  flags.audit = true;
424
453
  effectiveCommand = 'sync';
425
- } else if (slashAction.id === 'sync' && String(command).trim().toLowerCase() === '/roadmap-update') {
426
- effectiveCommand = 'update';
427
454
  } else {
428
455
  effectiveCommand = slashAction.id;
429
456
  }
@@ -458,6 +485,7 @@ async function run() {
458
485
  if (effectiveCommand === 'regenerate') {
459
486
  const projectRoot = path.resolve(String(flags['project-root'] || process.cwd()));
460
487
  const config = loadConfig({ projectRoot, configPath: flags.config });
488
+ process.stderr.write('The regenerate command is deprecated. Use generate --full-regen for the public destructive rebuild path.\n');
461
489
  runRegenerateCommand(projectRoot, config, flags);
462
490
  return;
463
491
  }
@@ -510,7 +538,9 @@ async function run() {
510
538
 
511
539
  const parsedRoadmap = parseRoadmap(content);
512
540
  const tasks = maybeFilterTasks(parsedRoadmap.tasks, flags.task);
513
- const validationContext = buildValidationContext(projectRoot, config, loadPlugins(projectRoot, config.plugins));
541
+ const validationContext = buildValidationContext(projectRoot, config, loadPlugins(projectRoot, config.plugins), {
542
+ strictValidation: isEnabled(flags.strict)
543
+ });
514
544
  const results = validateTasks(tasks, validationContext, config, validationContext.plugins);
515
545
 
516
546
  const minRank = CONFIDENCE_RANK[config.validation && config.validation.minimumConfidence] ?? 0;
@@ -606,6 +636,9 @@ async function run() {
606
636
  logError(`[fail] VS Code tasks incomplete: missing ${hostStatus.vscode.tasks.missingLabels.join(', ') || 'managed labels'}`);
607
637
  ok = false;
608
638
  }
639
+ if (Array.isArray(hostStatus.vscode.tasks.missingAdvancedLabels) && hostStatus.vscode.tasks.missingAdvancedLabels.length > 0) {
640
+ log(`[warn] Advanced VS Code tasks missing: ${hostStatus.vscode.tasks.missingAdvancedLabels.join(', ')}`);
641
+ }
609
642
 
610
643
  if (hostStatus.runtime.ready) {
611
644
  log(`[ok] Node runtime: ${hostStatus.runtime.kind}${hostStatus.runtime.path ? ` (${hostStatus.runtime.path})` : ''}`);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "roadmapsmith",
3
- "version": "0.9.29",
4
- "description": "One-command evidence-backed ROADMAP.md generator and sync tool for AI coding agents, with shared RoadmapSmith plugin skills for Codex and Claude plus the roadmapsmith status readiness surface.",
3
+ "version": "0.9.31",
4
+ "description": "Evidence-backed ROADMAP.md workflows for AI coding agents, with canonical RoadmapSmith status and maintain surfaces plus advanced sync/generate tools and legacy compatibility aliases.",
5
5
  "main": "src/index.js",
6
6
  "bin": {
7
7
  "roadmapsmith": "bin/cli.js"
@@ -17,3 +17,4 @@ Use this command when the repository already has code, tests, docs, or an existi
17
17
  4. Mention that maintain runs preserve-first generate, sync, and audit in one invocation.
18
18
  5. After a successful maintain cycle, do not propose generate, sync, or audit separately unless the user needs manual control or inspection.
19
19
  6. Mention that `roadmapsmith maintain --full-regen` or `roadmapsmith generate --full-regen` is the explicit destructive rebuild path when the user truly wants a full managed-block replacement.
20
+ 7. When the user wants stale or outdated warning annotations to be recomputed from scratch (including annotations that were written by a prior maintain run or an external agent), use `roadmapsmith maintain --refresh-annotations`. This forces all existing warning text to be replaced with the current deterministic result rather than preserved. It is distinct from `--full-regen` (which rebuilds the managed block structure) — `--refresh-annotations` only affects warning annotations on still-failing tasks.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: roadmap-status
3
- description: Inspect RoadmapSmith readiness through doctor JSON and summarize the result.
3
+ description: Inspect RoadmapSmith readiness through status JSON and summarize the result.
4
4
  ---
5
5
 
6
6
  # RoadmapSmith Status
@@ -10,8 +10,9 @@ Use this command to inspect whether the shared bundle, native host surfaces, CLI
10
10
  ## Required behavior
11
11
 
12
12
  1. Prefer the local engine inside this repository:
13
- - `node roadmap-skill/bin/cli.js doctor --json --project-root .`
14
- - on this Windows machine, prefer `C:\Program Files\nodejs\node.exe roadmap-skill/bin/cli.js doctor --json --project-root .` if `node` is not in PATH
15
- 2. Otherwise prefer `roadmapsmith doctor --json --project-root .`. If its global shim cannot resolve `node`, use `& "C:\Program Files\nodejs\node.exe" "$env:APPDATA\npm\node_modules\roadmapsmith\bin\cli.js" doctor --json --project-root .`.
16
- 3. Parse and summarize the JSON output in plain language.
17
- 4. Explicitly call out missing commands or duplicate `/roadmap-sync` registration when doctor reports them.
13
+ - `node roadmap-skill/bin/cli.js status --json --project-root .`
14
+ - on this Windows machine, prefer `C:\Program Files\nodejs\node.exe roadmap-skill/bin/cli.js status --json --project-root .` if `node` is not in PATH
15
+ 2. Otherwise prefer `roadmapsmith status --json --project-root .`. If its global shim cannot resolve `node`, use `& "C:\Program Files\nodejs\node.exe" "$env:APPDATA\npm\node_modules\roadmapsmith\bin\cli.js" status --json --project-root .`.
16
+ 3. Treat `roadmapsmith doctor --json` as compatibility-only output for existing automation, not as the primary recommendation.
17
+ 4. Parse and summarize the JSON output in plain language.
18
+ 5. Explicitly call out missing canonical commands, duplicate legacy `/roadmap-sync` registration, and any missing advanced VS Code labels as warnings rather than canonical-readiness failures.
@@ -5,14 +5,14 @@ description: Apply evidence-backed checklist sync or complete one task with veri
5
5
 
6
6
  # RoadmapSmith Update
7
7
 
8
- Use this command when the user wants the direct sync surface without routing through the legacy `/roadmap-sync <action>` root.
8
+ Use this command when the user wants the canonical public `update` surface without routing through the legacy `/roadmap-sync <action>` root.
9
9
 
10
10
  ## Required behavior
11
11
 
12
12
  1. Prefer the local engine inside this repository:
13
13
  - `node roadmap-skill/bin/cli.js update --project-root .`
14
14
  - on this Windows machine, prefer `C:\Program Files\nodejs\node.exe roadmap-skill/bin/cli.js update --project-root .` if `node` is not in PATH
15
- 2. Otherwise prefer `roadmapsmith update --project-root .`. If that global shim fails because `node` is not in PATH, run `& "C:\Program Files\nodejs\node.exe" "$env:APPDATA\npm\node_modules\roadmapsmith\bin\cli.js" update --project-root .`.
16
- 3. Explain that `/roadmap-update` is the visible namespaced sync command, while `/roadmap-sync <action>` remains legacy compatibility.
17
- 4. Keep the evidence-backed sync semantics unchanged: no-argument update syncs the roadmap from repository evidence; it is not a full regeneration path.
15
+ 2. Otherwise prefer `roadmapsmith update --project-root .`. If its global shim fails because `node` is not in PATH, run `& "C:\Program Files\nodejs\node.exe" "$env:APPDATA\npm\node_modules\roadmapsmith\bin\cli.js" update --project-root .`.
16
+ 3. Explain that `/roadmap-update` is the visible namespaced command for the public `update` family, while `/roadmap-sync <action>` remains deprecated compatibility only.
17
+ 4. Keep the evidence-backed refresh semantics unchanged: no-argument `update` syncs the roadmap from repository evidence, and `sync` remains the advanced CLI alias for that same mutating refresh path. It is not a full regeneration path and not an independent audit engine.
18
18
  5. To complete one task, run `roadmapsmith update --task <stable-id> --evidence "<single-line evidence>"`. It writes only after the supplied evidence validates at high confidence; use `--dry-run` to preview it.
package/skills.json CHANGED
@@ -21,74 +21,74 @@
21
21
  "command": "npx skills add PapiScholz/roadmapsmith --skill '*' -a claude-code",
22
22
  "source": "PapiScholz/roadmapsmith",
23
23
  "skill": "*",
24
- "notes": "Recommended Claude Code install path for native GUI slash commands like /roadmap, /roadmap-zero, /roadmap-maintain, /roadmap-status, /roadmap-init, /roadmap-generate, /roadmap-validate, /roadmap-update, /roadmap-audit, and /roadmap-setup. DEPRECATED: /roadmap-sync remains only as a compatibility root for existing automation; use /roadmap-maintain or /roadmap-update for new workflows. Install the roadmapsmith CLI separately for actual command execution; roadmapsmith status is the visible readiness command and roadmapsmith doctor remains a compatibility alias. Then run /reload-skills and, if applicable, /reload-plugins. Codex native plugin installs use the repo/package .codex-plugin surface instead of this Claude-specific skills CLI path."
24
+ "notes": "Recommended Claude Code install path for native GUI slash commands. Canonical surfaces: /roadmap, /roadmap-zero, /roadmap-maintain, /roadmap-status, /roadmap-validate, /roadmap-update, /roadmap-setup. The public CLI update family covers both checklist refresh and verified single-task completion; sync remains the advanced alias for the mutating refresh path. Advanced surfaces: /roadmap-init, /roadmap-generate, /roadmap-audit. DEPRECATED: /roadmap-sync remains only as a compatibility root for existing automation; use /roadmap-maintain or /roadmap-update for new workflows. Install the roadmapsmith CLI separately for actual command execution; roadmapsmith status is the public readiness command and roadmapsmith doctor remains a compatibility alias. Then run /reload-skills and, if applicable, /reload-plugins. Codex native plugin installs use the repo/package .codex-plugin surface instead of this Claude-specific skills CLI path."
25
25
  },
26
26
  "skills": [
27
27
  {
28
28
  "name": "roadmap",
29
29
  "path": "skills/roadmap",
30
30
  "description": "Native slash palette for RoadmapSmith commands and recommended entrypoints across supported hosts.",
31
- "version": "0.9.29"
31
+ "version": "0.9.31"
32
32
  },
33
33
  {
34
34
  "name": "roadmap-zero",
35
35
  "path": "skills/roadmap-zero",
36
36
  "description": "Native slash entrypoint for the one-command Zero Mode CLI workflow.",
37
- "version": "0.9.29"
37
+ "version": "0.9.31"
38
38
  },
39
39
  {
40
40
  "name": "roadmap-maintain",
41
41
  "path": "skills/roadmap-maintain",
42
42
  "description": "Native slash entrypoint for the preserve-first generate + sync + audit flow.",
43
- "version": "0.9.29"
43
+ "version": "0.9.31"
44
44
  },
45
45
  {
46
46
  "name": "roadmap-status",
47
47
  "path": "skills/roadmap-status",
48
48
  "description": "Native slash readiness check grounded in roadmapsmith status JSON.",
49
- "version": "0.9.29"
49
+ "version": "0.9.31"
50
50
  },
51
51
  {
52
52
  "name": "roadmap-init",
53
53
  "path": "skills/roadmap-init",
54
54
  "description": "Native slash entrypoint for creating ROADMAP.md and AGENTS.md.",
55
- "version": "0.9.29"
55
+ "version": "0.9.31"
56
56
  },
57
57
  {
58
58
  "name": "roadmap-generate",
59
59
  "path": "skills/roadmap-generate",
60
60
  "description": "Native slash entrypoint for managed roadmap updates that require --full-regen before destructive replacement.",
61
- "version": "0.9.29"
61
+ "version": "0.9.31"
62
62
  },
63
63
  {
64
64
  "name": "roadmap-validate",
65
65
  "path": "skills/roadmap-validate",
66
66
  "description": "Native slash entrypoint for evidence-backed roadmap validation.",
67
- "version": "0.9.29"
67
+ "version": "0.9.31"
68
68
  },
69
69
  {
70
70
  "name": "roadmap-update",
71
71
  "path": "skills/roadmap-update",
72
72
  "description": "Native slash entrypoint for evidence-backed sync and verified single-task completion.",
73
- "version": "0.9.29"
73
+ "version": "0.9.31"
74
74
  },
75
75
  {
76
76
  "name": "roadmap-sync",
77
77
  "path": "skills/roadmap-sync",
78
78
  "description": "DEPRECATED legacy compatibility root; use roadmap-maintain or roadmap-update.",
79
- "version": "0.9.29"
79
+ "version": "0.9.31"
80
80
  },
81
81
  {
82
82
  "name": "roadmap-audit",
83
83
  "path": "skills/roadmap-audit",
84
- "description": "Native slash entrypoint for the current sync-plus-audit workflow.",
85
- "version": "0.9.29"
84
+ "description": "Native slash entrypoint for the advanced sync-plus-audit mutating summary workflow.",
85
+ "version": "0.9.31"
86
86
  },
87
87
  {
88
88
  "name": "roadmap-setup",
89
89
  "path": "skills/roadmap-setup",
90
90
  "description": "Native slash entrypoint for generating RoadmapSmith host integration files.",
91
- "version": "0.9.29"
91
+ "version": "0.9.31"
92
92
  }
93
93
  ]
94
94
  }
package/src/host.js CHANGED
@@ -4,7 +4,14 @@ const fs = require('fs');
4
4
  const os = require('os');
5
5
  const path = require('path');
6
6
  const { readTextIfExists, writeText } = require('./io');
7
- const { getHostNativeSkillNames, getHostNativeSlashCommands, getSlashActionSpecs } = require('./slash');
7
+ const {
8
+ getAdvancedHostNativeSlashCommands,
9
+ getCanonicalHostNativeSlashCommands,
10
+ getCompatibilityHostNativeSlashCommands,
11
+ getHostNativeSkillNames,
12
+ getHostNativeSlashCommands,
13
+ getSlashActionSpecs
14
+ } = require('./slash');
8
15
 
9
16
  const SUPPORTED_EDITORS = new Set(['vscode']);
10
17
  const SUPPORTED_HOSTS = new Set(['codex', 'claude']);
@@ -13,18 +20,25 @@ const REPO_ROOT = path.resolve(PACKAGE_ROOT, '..');
13
20
  const VSCODE_LAUNCHER_RELATIVE_PATH = '.vscode/roadmapsmith-launcher.js';
14
21
  const WINDOWS_TASK_WRAPPER_RELATIVE_PATH = '.vscode/roadmapsmith-task.cmd';
15
22
  const POSIX_TASK_WRAPPER_RELATIVE_PATH = '.vscode/roadmapsmith-task.sh';
16
- const ROADMAPSMITH_TASK_LABELS = [
23
+ const ROADMAPSMITH_CANONICAL_TASK_LABELS = [
17
24
  'RoadmapSmith: Zero Mode',
18
25
  'RoadmapSmith: Maintain',
19
26
  'RoadmapSmith: Status',
27
+ 'RoadmapSmith: Validate',
28
+ 'RoadmapSmith: Update',
29
+ 'RoadmapSmith: Refresh Setup'
30
+ ];
31
+ const ROADMAPSMITH_ADVANCED_TASK_LABELS = [
20
32
  'RoadmapSmith: Explain Workflow',
21
33
  'RoadmapSmith: Init',
22
34
  'RoadmapSmith: Generate',
23
- 'RoadmapSmith: Validate',
24
35
  'RoadmapSmith: Sync',
25
36
  'RoadmapSmith: Sync Dry Run',
26
- 'RoadmapSmith: Sync Audit',
27
- 'RoadmapSmith: Refresh Setup'
37
+ 'RoadmapSmith: Sync Audit'
38
+ ];
39
+ const ROADMAPSMITH_TASK_LABELS = [
40
+ ...ROADMAPSMITH_CANONICAL_TASK_LABELS,
41
+ ...ROADMAPSMITH_ADVANCED_TASK_LABELS
28
42
  ];
29
43
  const CLAUDE_HOOK_COMMAND = 'node .claude/hooks/roadmap-sync.js';
30
44
  const CLAUDE_HOOK_RELATIVE_PATH = '.claude/hooks/roadmap-sync.js';
@@ -32,6 +46,9 @@ const ROADMAPSMITH_PLUGIN_NAME = 'roadmapsmith';
32
46
  const LEGACY_ROADMAP_SYNC_SKILL_NAME = 'roadmap-sync';
33
47
  const EXPECTED_NATIVE_SKILL_NAMES = Object.freeze(getHostNativeSkillNames());
34
48
  const EXPECTED_NATIVE_SLASH_COMMANDS = Object.freeze(getHostNativeSlashCommands());
49
+ const EXPECTED_CANONICAL_NATIVE_SLASH_COMMANDS = Object.freeze(getCanonicalHostNativeSlashCommands());
50
+ const EXPECTED_ADVANCED_NATIVE_SLASH_COMMANDS = Object.freeze(getAdvancedHostNativeSlashCommands());
51
+ const EXPECTED_COMPATIBILITY_NATIVE_SLASH_COMMANDS = Object.freeze(getCompatibilityHostNativeSlashCommands());
35
52
  const BUNDLE_ROOT_CANDIDATES = Object.freeze([
36
53
  { kind: 'package', root: PACKAGE_ROOT },
37
54
  { kind: 'repo', root: REPO_ROOT }
@@ -294,14 +311,15 @@ function createManagedTasks() {
294
311
  createTask('zero', 'RoadmapSmith: Zero Mode', 'Run the Zero Mode interview and generate the first roadmap in one command.'),
295
312
  createTask('maintain', 'RoadmapSmith: Maintain', 'Run the preserve-first existing-repo flow: generate, sync, and audit in one command.'),
296
313
  createTask('status', 'RoadmapSmith: Status', 'Inspect readiness and learn the slash entrypoints like /roadmap, /roadmap-update, and legacy /roadmap-sync <action>.'),
314
+ createTask('validate', 'RoadmapSmith: Validate', 'Inspect per-task evidence status as JSON.'),
315
+ createTask('update', 'RoadmapSmith: Update', 'Apply evidence-backed checklist refresh or complete one task with verified evidence.'),
316
+ createTask('setup', 'RoadmapSmith: Refresh Setup', 'Reapply RoadmapSmith VS Code and host integration files.'),
297
317
  createTask('explain', 'RoadmapSmith: Explain Workflow', 'Explain how zero, maintain, the skill, setup, slash routing, and VS Code tasks work together.'),
298
318
  createTask('init', 'RoadmapSmith: Init', 'Create ROADMAP.md and AGENTS.md when they are missing.'),
299
319
  createTask('generate', 'RoadmapSmith: Generate', 'Update ROADMAP.md and refuse destructive replacement unless rerun with --full-regen.'),
300
- createTask('validate', 'RoadmapSmith: Validate', 'Inspect per-task evidence status as JSON.'),
301
320
  createTask('sync', 'RoadmapSmith: Sync', 'Apply evidence-backed checklist sync to ROADMAP.md.'),
302
321
  createTask('sync-dry-run', 'RoadmapSmith: Sync Dry Run', 'Preview the next roadmap sync without writing files.'),
303
- createTask('sync-audit', 'RoadmapSmith: Sync Audit', 'Run sync and print the post-sync mismatch summary.'),
304
- createTask('setup', 'RoadmapSmith: Refresh Setup', 'Reapply RoadmapSmith VS Code and host integration files.')
322
+ createTask('sync-audit', 'RoadmapSmith: Sync Audit', 'Run sync and print the post-sync mismatch summary.')
305
323
  ];
306
324
  }
307
325
 
@@ -568,7 +586,7 @@ function inspectSharedBundleSurface() {
568
586
  ? skillsManifest.skills.map((skill) => skill && skill.name).filter(Boolean)
569
587
  : [];
570
588
  const availableCommands = declaredSkillNames.map((name) => `/${name}`);
571
- const missingCommands = EXPECTED_NATIVE_SLASH_COMMANDS.filter((command) => !availableCommands.includes(command));
589
+ const missingCommands = EXPECTED_CANONICAL_NATIVE_SLASH_COMMANDS.filter((command) => !availableCommands.includes(command));
572
590
 
573
591
  return {
574
592
  kind: bundleSurface.kind,
@@ -586,7 +604,9 @@ function inspectSharedBundleSurface() {
586
604
  hasCodexPluginManifest: bundleSurface.hasCodexPluginManifest
587
605
  },
588
606
  declaredSkillNames,
589
- expectedCommands: EXPECTED_NATIVE_SLASH_COMMANDS.slice(),
607
+ expectedCommands: EXPECTED_CANONICAL_NATIVE_SLASH_COMMANDS.slice(),
608
+ advancedCommands: EXPECTED_ADVANCED_NATIVE_SLASH_COMMANDS.slice(),
609
+ compatibilityCommands: EXPECTED_COMPATIBILITY_NATIVE_SLASH_COMMANDS.slice(),
590
610
  availableCommands,
591
611
  missingCommands
592
612
  };
@@ -635,7 +655,7 @@ function inspectCodexPluginState(projectRoot, options = {}) {
635
655
  ? options.codexCommandPath
636
656
  : findCommandPath('codex', env);
637
657
  const legacySkill = inspectLegacyRoadmapSyncSkill(options, env);
638
- const expectedCommands = EXPECTED_NATIVE_SLASH_COMMANDS.slice();
658
+ const expectedCommands = EXPECTED_CANONICAL_NATIVE_SLASH_COMMANDS.slice();
639
659
  const missingCommands = expectedCommands.slice();
640
660
  const baseState = {
641
661
  commandPath: codexCommandPath,
@@ -708,13 +728,15 @@ function inspectCodexPluginState(projectRoot, options = {}) {
708
728
  plugin,
709
729
  marketplace,
710
730
  expectedCommands,
731
+ advancedCommands: EXPECTED_ADVANCED_NATIVE_SLASH_COMMANDS.slice(),
732
+ compatibilityCommands: EXPECTED_COMPATIBILITY_NATIVE_SLASH_COMMANDS.slice(),
711
733
  availableCommands: expectedCommands,
712
734
  missingCommands: [],
713
735
  duplicates,
714
- ready: duplicates.length === 0,
736
+ ready: true,
715
737
  source: `${plugin.pluginId || plugin.name}${plugin.marketplaceName ? ` (${plugin.marketplaceName})` : ''}`,
716
738
  message: duplicates.length > 0
717
- ? 'RoadmapSmith is installed in Codex, but /roadmap-sync is duplicated by the legacy ~/.agents/skills install.'
739
+ ? 'RoadmapSmith is installed in Codex. The legacy ~/.agents/skills install still duplicates /roadmap-sync, but the canonical native surface is healthy.'
718
740
  : 'RoadmapSmith is installed and enabled in Codex. Interactive slash-menu visibility still needs manual host verification.',
719
741
  legacySkill
720
742
  };
@@ -783,14 +805,23 @@ function renderVsCodeLauncher() {
783
805
  '}',
784
806
  '',
785
807
  'function getNamespacedDirectSlash(actionId) {',
786
- ' return actionId === \'sync\' ? \'/roadmap-update\' : `/roadmap-${actionId}`;',
808
+ ' return `/roadmap-${actionId}`;',
787
809
  '}',
788
810
  '',
789
811
  'const DIRECT_HOST_NATIVE_ALIAS_TO_ACTION = Object.fromEntries(',
790
812
  ' SLASH_ACTIONS.map((action) => [getNamespacedDirectSlash(action.id), action.id])',
791
813
  ');',
792
814
  'const DIRECT_DEPRECATED_CLI_ALIAS_TO_ACTION = Object.fromEntries(',
793
- ' SLASH_ACTIONS.map((action) => [`/${action.id}`, action.id])',
815
+ ' SLASH_ACTIONS.flatMap((action) => {',
816
+ ' const aliases = Array.isArray(action.aliases) ? action.aliases : [];',
817
+ ' return [action.id, ...aliases].map((alias) => [`/${alias}`, action.id]);',
818
+ ' })',
819
+ ');',
820
+ 'const ACTION_ALIAS_TO_ID = Object.fromEntries(',
821
+ ' SLASH_ACTIONS.flatMap((action) => {',
822
+ ' const aliases = Array.isArray(action.aliases) ? action.aliases : [];',
823
+ ' return [action.id, ...aliases].map((alias) => [alias, action.id]);',
824
+ ' })',
794
825
  ');',
795
826
  '',
796
827
  'function normalizeActionId(value) {',
@@ -798,19 +829,28 @@ function renderVsCodeLauncher() {
798
829
  ' if (normalized.startsWith(\'roadmap-\')) {',
799
830
  ' normalized = normalized.slice(\'roadmap-\'.length);',
800
831
  ' }',
801
- ' if (normalized === \'update\') {',
802
- ' normalized = \'sync\';',
803
- ' }',
804
832
  ' return normalized;',
805
833
  '}',
806
834
  '',
835
+ 'function canonicalizeActionId(value) {',
836
+ ' const normalized = normalizeActionId(value);',
837
+ ' return ACTION_ALIAS_TO_ID[normalized] || normalized;',
838
+ '}',
839
+ '',
840
+ 'function actionSearchTerms(action) {',
841
+ ' return [action.id, ...(Array.isArray(action.aliases) ? action.aliases : [])];',
842
+ '}',
843
+ '',
807
844
  'function getSlashSuggestions(query) {',
808
845
  ' const normalized = normalizeActionId(query);',
809
846
  ' if (!normalized) {',
810
847
  ' return SLASH_ACTIONS.slice();',
811
848
  ' }',
812
- ' const startsWithMatches = SLASH_ACTIONS.filter((action) => action.id.startsWith(normalized));',
813
- ' const containsMatches = SLASH_ACTIONS.filter((action) => !action.id.startsWith(normalized) && action.id.includes(normalized));',
849
+ ' const startsWithMatches = SLASH_ACTIONS.filter((action) => actionSearchTerms(action).some((term) => term.startsWith(normalized)));',
850
+ ' const containsMatches = SLASH_ACTIONS.filter((action) => {',
851
+ ' return !actionSearchTerms(action).some((term) => term.startsWith(normalized))',
852
+ ' && actionSearchTerms(action).some((term) => term.includes(normalized));',
853
+ ' });',
814
854
  ' return [...startsWithMatches, ...containsMatches];',
815
855
  '}',
816
856
  '',
@@ -857,7 +897,7 @@ function renderVsCodeLauncher() {
857
897
  '}',
858
898
  '',
859
899
  'function getSlashAction(actionId) {',
860
- ' const normalized = normalizeActionId(actionId);',
900
+ ' const normalized = canonicalizeActionId(actionId);',
861
901
  ' return SLASH_ACTIONS.find((action) => action.id === normalized) || null;',
862
902
  '}',
863
903
  '',
@@ -921,13 +961,13 @@ function renderVsCodeLauncher() {
921
961
  'function explain() {',
922
962
  ' console.log(\'RoadmapSmith layers:\\n\');',
923
963
  ' console.log(\'1. The roadmap-sync skill guides the agent. It does not add VS Code buttons or install the CLI.\');',
924
- ' console.log(\'2. The roadmapsmith CLI executes zero/maintain plus init/generate/validate/sync/setup/status, with doctor kept as a compatibility alias and --full-regen reserved for destructive replacement.\');',
964
+ ' console.log(\'2. The roadmapsmith CLI executes zero/maintain plus the canonical update family, with sync kept as the advanced alias for manual refresh and doctor kept as a compatibility alias.\');',
925
965
  ' console.log(\'3. roadmapsmith setup makes the CLI visible in VS Code through tasks and optional Claude hook wiring.\\n\');',
926
966
  ' console.log(\'Typical VS Code workflow:\');',
927
967
  ' console.log(\'- Run "RoadmapSmith: Status" to inspect readiness.\');',
928
968
  ' console.log(\'- For empty repos, run "RoadmapSmith: Zero Mode" or use "/roadmap zero".\');',
929
969
  ' console.log(\'- For existing repos, run "RoadmapSmith: Maintain" or use "/roadmap maintain".\');',
930
- ' console.log(\'- Use Init, Generate, Validate, and Sync when you want manual control.\\n\');',
970
+ ' console.log(\'- Use Update for the public checklist-refresh/task-completion family, and use Init, Generate, Validate, and Sync when you want manual control.\\n\');',
931
971
  ' console.log(\'If you installed only the skill, install the CLI as well and then run "RoadmapSmith: Refresh Setup".\');',
932
972
  '}',
933
973
  '',
@@ -954,6 +994,16 @@ function renderVsCodeLauncher() {
954
994
  ' }',
955
995
  ' console.log(`Codex readiness: ${payload.hosts.codex.ready ? \'ready\' : \'needs setup\'} (${payload.hosts.codex.message})`);',
956
996
  ' console.log(`Claude readiness: ${payload.hosts.claude.ready ? \'ready\' : \'needs setup\'} (${payload.hosts.claude.message})`);',
997
+ ' if (payload.summary) {',
998
+ ' console.log(\'\\nStructured readiness summary:\');',
999
+ ' console.log(`- Workspace readiness: ${payload.summary.workspaceReady ? \'ready\' : \'needs setup\'}`);',
1000
+ ' console.log(`- Codex readiness: ${payload.summary.codexReady ? \'ready\' : \'needs setup\'}`);',
1001
+ ' console.log(`- Claude readiness: ${payload.summary.claudeReady ? \'ready\' : \'needs setup\'}`);',
1002
+ ' console.log(`- Canonical native surfaces: ${payload.summary.canonicalSurfaceReady ? \'ready\' : \'needs attention\'}`);',
1003
+ ' if (Array.isArray(payload.summary.advancedSurfaceWarnings)) {',
1004
+ ' payload.summary.advancedSurfaceWarnings.forEach((warning) => console.log(`- Advanced warning: ${warning}`));',
1005
+ ' }',
1006
+ ' }',
957
1007
  ' if (payload.surfaces && typeof payload.surfaces === \'object\') {',
958
1008
  ' console.log(\'\\nNative slash surfaces:\');',
959
1009
  ' Object.entries(payload.surfaces).forEach(([surfaceKey, surface]) => {',
@@ -976,7 +1026,8 @@ function renderVsCodeLauncher() {
976
1026
  ' if (!payload.runtime.ready) {',
977
1027
  ' console.log(\'\\nThe VS Code task runtime is missing. Install Node.js or set ROADMAPSMITH_NODE, then rerun "RoadmapSmith: Status".\');',
978
1028
  ' }',
979
- ' console.log(\'\\nRecommended entrypoints: roadmapsmith zero, roadmapsmith maintain\');',
1029
+ ' console.log(\'\\nRecommended entrypoints: roadmapsmith zero, roadmapsmith maintain, roadmapsmith update\');',
1030
+ ' console.log(\'Compatibility note: roadmapsmith doctor mirrors this payload for existing automation.\');',
980
1031
  ' console.log(\'Slash entrypoints: /roadmap, /roadmap-zero, /roadmap-maintain, /roadmap-status, /roadmap-init, /roadmap-generate, /roadmap-validate, /roadmap-update, /roadmap-audit, /roadmap-setup, plus legacy /roadmap-sync <action>.\');',
981
1032
  '}',
982
1033
  '',
@@ -1041,6 +1092,7 @@ function renderVsCodeLauncher() {
1041
1092
  ' maintain: [\'maintain\', \'--project-root\', PROJECT_ROOT],',
1042
1093
  ' init: [\'init\'],',
1043
1094
  ' generate: [\'generate\', \'--project-root\', PROJECT_ROOT],',
1095
+ ' update: [\'update\', \'--project-root\', PROJECT_ROOT],',
1044
1096
  ' validate: [\'validate\', \'--json\', \'--project-root\', PROJECT_ROOT],',
1045
1097
  ' sync: [\'sync\', \'--project-root\', PROJECT_ROOT],',
1046
1098
  ' audit: [\'sync\', \'--audit\', \'--project-root\', PROJECT_ROOT],',
@@ -1228,10 +1280,12 @@ function inspectVsCodeTasks(projectRoot) {
1228
1280
  tasks: {
1229
1281
  path: tasksPath,
1230
1282
  exists: tasksConfig != null,
1231
- ready: ROADMAPSMITH_TASK_LABELS.every((label) => presentLabels.includes(label)) && fs.existsSync(launcherPath) && wrapperEntries.every((entry) => entry.exists),
1232
- expectedLabels: ROADMAPSMITH_TASK_LABELS.slice(),
1283
+ ready: ROADMAPSMITH_CANONICAL_TASK_LABELS.every((label) => presentLabels.includes(label)) && fs.existsSync(launcherPath) && wrapperEntries.every((entry) => entry.exists),
1284
+ expectedLabels: ROADMAPSMITH_CANONICAL_TASK_LABELS.slice(),
1285
+ advancedLabels: ROADMAPSMITH_ADVANCED_TASK_LABELS.slice(),
1233
1286
  presentLabels: presentManagedLabels,
1234
- missingLabels: ROADMAPSMITH_TASK_LABELS.filter((label) => !presentLabels.includes(label))
1287
+ missingLabels: ROADMAPSMITH_CANONICAL_TASK_LABELS.filter((label) => !presentLabels.includes(label)),
1288
+ missingAdvancedLabels: ROADMAPSMITH_ADVANCED_TASK_LABELS.filter((label) => !presentLabels.includes(label))
1235
1289
  }
1236
1290
  };
1237
1291
  }
@@ -1359,14 +1413,29 @@ function inspectHostSetup(projectRoot, options = {}) {
1359
1413
  ? 'Claude PostToolUse hook is configured'
1360
1414
  : 'Run roadmapsmith setup with the claude host and verify node is available to Claude'
1361
1415
  }
1416
+ },
1417
+ summary: {
1418
+ workspaceReady: cli.ready && runtime.ready && vscode.tasks.ready && Boolean(roadmapFile && fs.existsSync(roadmapFile)) && Boolean(agentsFile && fs.existsSync(agentsFile)),
1419
+ codexReady,
1420
+ claudeReady: cli.ready && claude.ready,
1421
+ canonicalSurfaceReady: bundle.ready && vscode.tasks.ready,
1422
+ advancedSurfaceWarnings: [
1423
+ ...vscode.tasks.missingAdvancedLabels.map((label) => `Missing advanced VS Code task: ${label}`),
1424
+ ...EXPECTED_ADVANCED_NATIVE_SLASH_COMMANDS.filter((command) => !bundle.advancedCommands.includes(command)).map((command) => `Missing advanced bundle slash command: ${command}`)
1425
+ ]
1362
1426
  }
1363
1427
  };
1364
1428
  }
1365
1429
 
1366
1430
  module.exports = {
1367
1431
  CLAUDE_HOOK_COMMAND,
1432
+ EXPECTED_ADVANCED_NATIVE_SLASH_COMMANDS,
1433
+ EXPECTED_CANONICAL_NATIVE_SLASH_COMMANDS,
1434
+ EXPECTED_COMPATIBILITY_NATIVE_SLASH_COMMANDS,
1368
1435
  EXPECTED_NATIVE_SKILL_NAMES,
1369
1436
  EXPECTED_NATIVE_SLASH_COMMANDS,
1437
+ ROADMAPSMITH_ADVANCED_TASK_LABELS,
1438
+ ROADMAPSMITH_CANONICAL_TASK_LABELS,
1370
1439
  ROADMAPSMITH_TASK_LABELS,
1371
1440
  applySetupFiles,
1372
1441
  assertSupportedEditor,
package/src/reasons.js ADDED
@@ -0,0 +1,28 @@
1
+ 'use strict';
2
+
3
+ // Low-specificity reason strings produced by the deterministic validator for
4
+ // policy-level failures. These messages carry no file- or symbol-specific
5
+ // information and should not overwrite more informative existing annotations
6
+ // that a prior run or a human/agent authored.
7
+ const LOW_SPECIFICITY_REASONS = new Set([
8
+ 'validation failed',
9
+ 'implementation task requires deterministic Verify metadata or explicit Evidence to be marked complete',
10
+ 'implementation task requires Evidence line or high-confidence evidence (code + test) to be marked complete',
11
+ ]);
12
+
13
+ /**
14
+ * Returns true when `reason` is a low-specificity policy message — one that carries
15
+ * no file- or symbol-specific diagnostic value and should not be used to overwrite
16
+ * a more informative existing annotation.
17
+ *
18
+ * Input should be a normalized reason string (⚠️ prefix and warning prefixes already
19
+ * stripped, as produced by normalizeWarningReason in src/sync/index.js).
20
+ *
21
+ * @param {string} reason
22
+ * @returns {boolean}
23
+ */
24
+ function isLowSpecificityReason(reason) {
25
+ return LOW_SPECIFICITY_REASONS.has(String(reason || '').trim());
26
+ }
27
+
28
+ module.exports = { LOW_SPECIFICITY_REASONS, isLowSpecificityReason };