peaks-cli 1.4.1 → 2.0.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.
Files changed (219) hide show
  1. package/.claude-plugin/marketplace.json +51 -0
  2. package/CHANGELOG.md +238 -0
  3. package/README-en.md +226 -0
  4. package/README.md +142 -165
  5. package/dist/src/cli/commands/agent-commands.d.ts +20 -0
  6. package/dist/src/cli/commands/agent-commands.js +48 -0
  7. package/dist/src/cli/commands/audit-commands.d.ts +18 -0
  8. package/dist/src/cli/commands/audit-commands.js +138 -0
  9. package/dist/src/cli/commands/classify-classify-commands.d.ts +19 -0
  10. package/dist/src/cli/commands/classify-classify-commands.js +151 -0
  11. package/dist/src/cli/commands/code-review-commands.d.ts +34 -0
  12. package/dist/src/cli/commands/code-review-commands.js +83 -0
  13. package/dist/src/cli/commands/config-commands.js +90 -0
  14. package/dist/src/cli/commands/context-commands.d.ts +21 -0
  15. package/dist/src/cli/commands/context-commands.js +167 -0
  16. package/dist/src/cli/commands/core-artifact-commands.js +81 -2
  17. package/dist/src/cli/commands/hook-handle.js +50 -0
  18. package/dist/src/cli/commands/loop-commands.d.ts +21 -0
  19. package/dist/src/cli/commands/loop-commands.js +128 -0
  20. package/dist/src/cli/commands/memory-commands.d.ts +13 -0
  21. package/dist/src/cli/commands/memory-commands.js +60 -0
  22. package/dist/src/cli/commands/openspec-commands.js +37 -0
  23. package/dist/src/cli/commands/preferences-commands.d.ts +2 -0
  24. package/dist/src/cli/commands/preferences-commands.js +147 -0
  25. package/dist/src/cli/commands/retrospective-commands.d.ts +9 -0
  26. package/dist/src/cli/commands/retrospective-commands.js +58 -0
  27. package/dist/src/cli/commands/skill-conformance-commands.d.ts +9 -0
  28. package/dist/src/cli/commands/skill-conformance-commands.js +39 -0
  29. package/dist/src/cli/commands/understand-commands.js +34 -0
  30. package/dist/src/cli/commands/upgrade-commands.d.ts +23 -0
  31. package/dist/src/cli/commands/upgrade-commands.js +57 -0
  32. package/dist/src/cli/commands/workflow-commands.js +70 -0
  33. package/dist/src/cli/commands/workspace-commands.js +86 -0
  34. package/dist/src/cli/program.js +46 -22
  35. package/dist/src/services/agent/ecc-agent-service.d.ts +47 -0
  36. package/dist/src/services/agent/ecc-agent-service.js +143 -0
  37. package/dist/src/services/artifacts/request-artifact-service.js +14 -0
  38. package/dist/src/services/audit/backing-detector.d.ts +24 -0
  39. package/dist/src/services/audit/backing-detector.js +59 -0
  40. package/dist/src/services/audit/classifier.d.ts +38 -0
  41. package/dist/src/services/audit/classifier.js +127 -0
  42. package/dist/src/services/audit/enforcers/active-skill-resolver.d.ts +29 -0
  43. package/dist/src/services/audit/enforcers/active-skill-resolver.js +71 -0
  44. package/dist/src/services/audit/enforcers/design-draft-confirm.d.ts +25 -0
  45. package/dist/src/services/audit/enforcers/design-draft-confirm.js +54 -0
  46. package/dist/src/services/audit/enforcers/lint-audit-regression.d.ts +21 -0
  47. package/dist/src/services/audit/enforcers/lint-audit-regression.js +86 -0
  48. package/dist/src/services/audit/enforcers/lint-catalog-governance.d.ts +27 -0
  49. package/dist/src/services/audit/enforcers/lint-catalog-governance.js +38 -0
  50. package/dist/src/services/audit/enforcers/lint-cli-back.d.ts +16 -0
  51. package/dist/src/services/audit/enforcers/lint-cli-back.js +35 -0
  52. package/dist/src/services/audit/enforcers/lint-output-style.d.ts +11 -0
  53. package/dist/src/services/audit/enforcers/lint-output-style.js +94 -0
  54. package/dist/src/services/audit/enforcers/lint-reference-integrity.d.ts +6 -0
  55. package/dist/src/services/audit/enforcers/lint-reference-integrity.js +83 -0
  56. package/dist/src/services/audit/enforcers/lint-reference-shape.d.ts +30 -0
  57. package/dist/src/services/audit/enforcers/lint-reference-shape.js +272 -0
  58. package/dist/src/services/audit/enforcers/lint-style.d.ts +49 -0
  59. package/dist/src/services/audit/enforcers/lint-style.js +173 -0
  60. package/dist/src/services/audit/enforcers/lint-workflow-shape.d.ts +5 -0
  61. package/dist/src/services/audit/enforcers/lint-workflow-shape.js +141 -0
  62. package/dist/src/services/audit/enforcers/login-gate.d.ts +23 -0
  63. package/dist/src/services/audit/enforcers/login-gate.js +40 -0
  64. package/dist/src/services/audit/enforcers/mock-placement.d.ts +25 -0
  65. package/dist/src/services/audit/enforcers/mock-placement.js +48 -0
  66. package/dist/src/services/audit/enforcers/no-root-pollution.d.ts +21 -0
  67. package/dist/src/services/audit/enforcers/no-root-pollution.js +56 -0
  68. package/dist/src/services/audit/enforcers/pre-rd-scan.d.ts +22 -0
  69. package/dist/src/services/audit/enforcers/pre-rd-scan.js +23 -0
  70. package/dist/src/services/audit/enforcers/prototype-fidelity.d.ts +25 -0
  71. package/dist/src/services/audit/enforcers/prototype-fidelity.js +75 -0
  72. package/dist/src/services/audit/enforcers/resume-detection.d.ts +21 -0
  73. package/dist/src/services/audit/enforcers/resume-detection.js +52 -0
  74. package/dist/src/services/audit/enforcers/solo-code-ban.d.ts +23 -0
  75. package/dist/src/services/audit/enforcers/solo-code-ban.js +27 -0
  76. package/dist/src/services/audit/enforcers/sub-agent-sid.d.ts +25 -0
  77. package/dist/src/services/audit/enforcers/sub-agent-sid.js +63 -0
  78. package/dist/src/services/audit/enforcers/tech-doc-presence.d.ts +28 -0
  79. package/dist/src/services/audit/enforcers/tech-doc-presence.js +35 -0
  80. package/dist/src/services/audit/red-line-catalog-p2-a.d.ts +21 -0
  81. package/dist/src/services/audit/red-line-catalog-p2-a.js +233 -0
  82. package/dist/src/services/audit/red-line-catalog-p2-b.d.ts +19 -0
  83. package/dist/src/services/audit/red-line-catalog-p2-b.js +225 -0
  84. package/dist/src/services/audit/red-line-catalog.d.ts +51 -0
  85. package/dist/src/services/audit/red-line-catalog.js +210 -0
  86. package/dist/src/services/audit/red-lines-service.d.ts +23 -0
  87. package/dist/src/services/audit/red-lines-service.js +486 -0
  88. package/dist/src/services/audit/scanners/openspec-scanner.d.ts +15 -0
  89. package/dist/src/services/audit/scanners/openspec-scanner.js +55 -0
  90. package/dist/src/services/audit/scanners/rules-tree-scanner.d.ts +16 -0
  91. package/dist/src/services/audit/scanners/rules-tree-scanner.js +56 -0
  92. package/dist/src/services/audit/scanners/skills-tree-scanner.d.ts +17 -0
  93. package/dist/src/services/audit/scanners/skills-tree-scanner.js +46 -0
  94. package/dist/src/services/audit/static-service.d.ts +57 -0
  95. package/dist/src/services/audit/static-service.js +125 -0
  96. package/dist/src/services/audit/types.d.ts +69 -0
  97. package/dist/src/services/audit/types.js +13 -0
  98. package/dist/src/services/classify/classify-service.d.ts +42 -0
  99. package/dist/src/services/classify/classify-service.js +122 -0
  100. package/dist/src/services/classify/classify-types.d.ts +79 -0
  101. package/dist/src/services/classify/classify-types.js +90 -0
  102. package/dist/src/services/code-review/ocr-service.d.ts +129 -0
  103. package/dist/src/services/code-review/ocr-service.js +362 -0
  104. package/dist/src/services/config/config-migration.d.ts +32 -0
  105. package/dist/src/services/config/config-migration.js +92 -0
  106. package/dist/src/services/config/config-restore.d.ts +10 -0
  107. package/dist/src/services/config/config-restore.js +47 -0
  108. package/dist/src/services/config/config-rollback.d.ts +13 -0
  109. package/dist/src/services/config/config-rollback.js +26 -0
  110. package/dist/src/services/config/config-service.d.ts +35 -2
  111. package/dist/src/services/config/config-service.js +81 -0
  112. package/dist/src/services/config/config-types.d.ts +58 -0
  113. package/dist/src/services/config/config-types.js +6 -0
  114. package/dist/src/services/doctor/doctor-service.js +96 -0
  115. package/dist/src/services/fuzzy-matching/fuzzy-match-service.d.ts +15 -0
  116. package/dist/src/services/fuzzy-matching/fuzzy-match-service.js +56 -0
  117. package/dist/src/services/fuzzy-matching/types.d.ts +20 -0
  118. package/dist/src/services/fuzzy-matching/types.js +1 -0
  119. package/dist/src/services/ide/adapters/hermes-adapter.d.ts +21 -0
  120. package/dist/src/services/ide/adapters/hermes-adapter.js +51 -0
  121. package/dist/src/services/ide/adapters/openclaw-adapter.d.ts +14 -0
  122. package/dist/src/services/ide/adapters/openclaw-adapter.js +42 -0
  123. package/dist/src/services/ide/ide-registry.js +7 -0
  124. package/dist/src/services/ide/ide-types.d.ts +1 -1
  125. package/dist/src/services/memory/memory-search-service.d.ts +61 -0
  126. package/dist/src/services/memory/memory-search-service.js +80 -0
  127. package/dist/src/services/openspec/openspec-propose-from-doctor-service.d.ts +31 -0
  128. package/dist/src/services/openspec/openspec-propose-from-doctor-service.js +95 -0
  129. package/dist/src/services/preferences/preferences-service.d.ts +6 -0
  130. package/dist/src/services/preferences/preferences-service.js +43 -0
  131. package/dist/src/services/preferences/preferences-types.d.ts +90 -0
  132. package/dist/src/services/preferences/preferences-types.js +38 -0
  133. package/dist/src/services/recommendations/capability-seed-items.js +0 -1
  134. package/dist/src/services/recommendations/capability-seed-mappings.js +0 -1
  135. package/dist/src/services/recommendations/capability-seed-sources.js +0 -1
  136. package/dist/src/services/retrospective/retrospective-search-service.d.ts +37 -0
  137. package/dist/src/services/retrospective/retrospective-search-service.js +75 -0
  138. package/dist/src/services/skills/skill-conformance-service.d.ts +40 -0
  139. package/dist/src/services/skills/skill-conformance-service.js +136 -0
  140. package/dist/src/services/skills/skill-runbook-service.js +44 -10
  141. package/dist/src/services/skills/sync-service.d.ts +43 -0
  142. package/dist/src/services/skills/sync-service.js +99 -0
  143. package/dist/src/services/slice/slice-check-service.js +166 -13
  144. package/dist/src/services/slice/slice-check-types.d.ts +1 -1
  145. package/dist/src/services/standards/migrate-claude-rules-service.d.ts +19 -0
  146. package/dist/src/services/standards/migrate-claude-rules-service.js +193 -0
  147. package/dist/src/services/standards/project-context.d.ts +1 -1
  148. package/dist/src/services/standards/project-context.js +0 -4
  149. package/dist/src/services/standards/project-standards-service.js +1 -3
  150. package/dist/src/services/understand/understand-scan-service.js +15 -2
  151. package/dist/src/services/understand/understand-types.d.ts +26 -0
  152. package/dist/src/services/upgrade/1x-detector-service.d.ts +7 -0
  153. package/dist/src/services/upgrade/1x-detector-service.js +94 -0
  154. package/dist/src/services/upgrade/gitignore-migrate-service.d.ts +56 -0
  155. package/dist/src/services/upgrade/gitignore-migrate-service.js +170 -0
  156. package/dist/src/services/upgrade/upgrade-service.d.ts +47 -0
  157. package/dist/src/services/upgrade/upgrade-service.js +381 -0
  158. package/dist/src/services/workspace/migrate-1-4-1-service.js +1 -1
  159. package/dist/src/services/workspace/sid-naming-guard.d.ts +14 -0
  160. package/dist/src/services/workspace/sid-naming-guard.js +31 -0
  161. package/dist/src/services/workspace/workspace-archive-service.d.ts +19 -0
  162. package/dist/src/services/workspace/workspace-archive-service.js +32 -0
  163. package/dist/src/services/workspace/workspace-clean-service.d.ts +41 -0
  164. package/dist/src/services/workspace/workspace-clean-service.js +86 -0
  165. package/dist/src/services/workspace/workspace-state-service.d.ts +7 -0
  166. package/dist/src/services/workspace/workspace-state-service.js +43 -0
  167. package/dist/src/shared/change-id.js +4 -1
  168. package/dist/src/shared/version.d.ts +1 -1
  169. package/dist/src/shared/version.js +1 -1
  170. package/package.json +10 -8
  171. package/schemas/doctor-report.schema.json +1 -1
  172. package/scripts/install-skills.mjs +296 -12
  173. package/skills/peaks-doctor/SKILL.md +59 -0
  174. package/skills/peaks-doctor/references/doctor-check-catalog.md +31 -0
  175. package/skills/peaks-doctor/references/from-doctor-flow.md +64 -0
  176. package/skills/peaks-doctor/test_prompts.json +17 -0
  177. package/skills/peaks-ide/SKILL.md +2 -0
  178. package/skills/peaks-qa/SKILL.md +9 -7
  179. package/skills/peaks-qa/references/artifact-per-request.md +19 -5
  180. package/skills/peaks-qa/references/qa-perf-test-plan.md +6 -6
  181. package/skills/peaks-qa/references/qa-runbook.md +1 -1
  182. package/skills/peaks-rd/SKILL.md +25 -10
  183. package/skills/peaks-rd/references/ocr-integration.md +214 -0
  184. package/skills/peaks-rd/references/rd-fanout-contracts.md +70 -0
  185. package/skills/peaks-rd/references/rd-runbook.md +1 -1
  186. package/skills/peaks-solo/SKILL.md +11 -5
  187. package/skills/peaks-solo/references/completion-handoff.md +3 -1
  188. package/skills/peaks-solo/references/step-0-55-1x-detection.md +82 -0
  189. package/skills/peaks-solo/references/workflow-gates-and-types.md +9 -0
  190. package/dist/src/cli/commands/shadcn-commands.d.ts +0 -3
  191. package/dist/src/cli/commands/shadcn-commands.js +0 -35
  192. package/dist/src/cli/commands/skill-context-stats-command.d.ts +0 -40
  193. package/dist/src/cli/commands/skill-context-stats-command.js +0 -96
  194. package/dist/src/cli/commands/skill-scope-commands.d.ts +0 -51
  195. package/dist/src/cli/commands/skill-scope-commands.js +0 -310
  196. package/dist/src/services/shadcn/shadcn-service.d.ts +0 -27
  197. package/dist/src/services/shadcn/shadcn-service.js +0 -128
  198. package/dist/src/services/skill-scope/adapters/_stub-helper.d.ts +0 -39
  199. package/dist/src/services/skill-scope/adapters/_stub-helper.js +0 -98
  200. package/dist/src/services/skill-scope/adapters/claude-code.d.ts +0 -59
  201. package/dist/src/services/skill-scope/adapters/claude-code.js +0 -304
  202. package/dist/src/services/skill-scope/adapters/codex.d.ts +0 -2
  203. package/dist/src/services/skill-scope/adapters/codex.js +0 -12
  204. package/dist/src/services/skill-scope/adapters/cursor.d.ts +0 -2
  205. package/dist/src/services/skill-scope/adapters/cursor.js +0 -13
  206. package/dist/src/services/skill-scope/adapters/qoder.d.ts +0 -2
  207. package/dist/src/services/skill-scope/adapters/qoder.js +0 -13
  208. package/dist/src/services/skill-scope/adapters/tongyi.d.ts +0 -2
  209. package/dist/src/services/skill-scope/adapters/tongyi.js +0 -13
  210. package/dist/src/services/skill-scope/adapters/trae.d.ts +0 -2
  211. package/dist/src/services/skill-scope/adapters/trae.js +0 -12
  212. package/dist/src/services/skill-scope/detect.d.ts +0 -81
  213. package/dist/src/services/skill-scope/detect.js +0 -513
  214. package/dist/src/services/skill-scope/registry.d.ts +0 -41
  215. package/dist/src/services/skill-scope/registry.js +0 -83
  216. package/dist/src/services/skill-scope/source-of-truth.d.ts +0 -44
  217. package/dist/src/services/skill-scope/source-of-truth.js +0 -118
  218. package/dist/src/services/skill-scope/types.d.ts +0 -195
  219. package/dist/src/services/skill-scope/types.js +0 -97
@@ -3,8 +3,50 @@ import { resolveCanonicalProjectRoot } from '../../services/config/config-servic
3
3
  import { loadRetrospectiveIndex } from '../../services/retrospective/retrospective-index.js';
4
4
  import { showRetrospective } from '../../services/retrospective/retrospective-show.js';
5
5
  import { migrateRetrospectiveFromMd } from '../../services/retrospective/migrate-from-md.js';
6
+ import { searchRetrospective } from '../../services/retrospective/retrospective-search-service.js';
6
7
  import { fail, ok } from '../../shared/result.js';
7
8
  import { addJsonOption, getErrorMessage, printResult } from '../cli-helpers.js';
9
+ const VALID_RETRO_TYPES = ['refactor', 'feature', 'bugfix', 'config', 'docs', 'chore'];
10
+ const VALID_RETRO_OUTCOMES = ['shipped', 'blocked', 'in-flight', 'cancelled'];
11
+ export function runRetrospectiveSearch(io, options) {
12
+ const projectRoot = options.project !== undefined
13
+ ? resolveCanonicalProjectRoot(options.project)
14
+ : (findProjectRoot(process.cwd()) ?? process.cwd());
15
+ const typeFilter = options.type !== undefined && VALID_RETRO_TYPES.includes(options.type)
16
+ ? options.type
17
+ : undefined;
18
+ const outcomeFilter = options.outcome !== undefined && VALID_RETRO_OUTCOMES.includes(options.outcome)
19
+ ? options.outcome
20
+ : undefined;
21
+ try {
22
+ const matches = searchRetrospective({
23
+ query: options.query,
24
+ projectRoot,
25
+ ...(typeFilter !== undefined ? { type: typeFilter } : {}),
26
+ ...(outcomeFilter !== undefined ? { outcome: outcomeFilter } : {}),
27
+ ...(options.limit !== undefined ? { limit: options.limit } : {}),
28
+ });
29
+ printResult(io, ok('retrospective.search', {
30
+ query: options.query,
31
+ total: matches.length,
32
+ matches,
33
+ warnings: [],
34
+ }, []), options.json);
35
+ }
36
+ catch (error) {
37
+ const message = getErrorMessage(error);
38
+ const code = error.code ?? 'RETROSPECTIVE_SEARCH_FAILED';
39
+ const suggestions = [];
40
+ if (code === 'INDEX_MISSING') {
41
+ suggestions.push('Run `peaks retrospective migrate --apply` to build the index from legacy MDs');
42
+ }
43
+ if (code === 'EMPTY_QUERY') {
44
+ suggestions.push('Use `peaks retrospective index` to list all entries');
45
+ }
46
+ printResult(io, fail('retrospective.search', code, message, { projectRoot, query: options.query }, suggestions), options.json);
47
+ process.exitCode = 1;
48
+ }
49
+ }
8
50
  export function registerRetrospectiveCommands(program, io) {
9
51
  const retrospective = program.command('retrospective').description('Read the peaks retrospective index (R3: index.json, not the legacy <id>/ MD tree)');
10
52
  addJsonOption(retrospective
@@ -110,4 +152,20 @@ export function registerRetrospectiveCommands(program, io) {
110
152
  process.exitCode = 1;
111
153
  }
112
154
  });
155
+ addJsonOption(retrospective
156
+ .command('search <query>')
157
+ .description('Fuzzy-search the retrospective index (deterministic, local, zero-token). Default --limit 6.')
158
+ .option('--type <type>', `filter by retrospective type (one of: ${VALID_RETRO_TYPES.join(', ')})`)
159
+ .option('--outcome <outcome>', `filter by retrospective outcome (one of: ${VALID_RETRO_OUTCOMES.join(', ')})`)
160
+ .option('--limit <n>', 'maximum number of matches to return', (value) => Number(value))
161
+ .option('--project <path>', 'target project root (defaults to git root or cwd)')).action((query, options) => {
162
+ runRetrospectiveSearch(io, {
163
+ query,
164
+ ...(options.type !== undefined ? { type: options.type } : {}),
165
+ ...(options.outcome !== undefined ? { outcome: options.outcome } : {}),
166
+ ...(options.limit !== undefined ? { limit: options.limit } : {}),
167
+ ...(options.project !== undefined ? { project: options.project } : {}),
168
+ ...(options.json !== undefined ? { json: options.json } : {}),
169
+ });
170
+ });
113
171
  }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * peaks skills audit-conformance CLI (Slice #12) — runs the
3
+ * skill-conformance-service against all 12 peaks-* SKILL.md files and
4
+ * reports the 5 standard checks (frontmatter, CLI-back, loadStrategy,
5
+ * 800-line cap, outputStyle).
6
+ */
7
+ import { Command } from 'commander';
8
+ import { type ProgramIO } from '../cli-helpers.js';
9
+ export declare function registerSkillConformanceCommands(program: Command, io: ProgramIO): void;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * peaks skills audit-conformance CLI (Slice #12) — runs the
3
+ * skill-conformance-service against all 12 peaks-* SKILL.md files and
4
+ * reports the 5 standard checks (frontmatter, CLI-back, loadStrategy,
5
+ * 800-line cap, outputStyle).
6
+ */
7
+ import { auditSkillConformance } from '../../services/skills/skill-conformance-service.js';
8
+ import { getErrorMessage, printResult } from '../cli-helpers.js';
9
+ import { fail, ok } from '../../shared/result.js';
10
+ export function registerSkillConformanceCommands(program, io) {
11
+ program
12
+ .command('skills:audit-conformance')
13
+ .description('Slice #12: audit all 12 peaks-* SKILL.md against the 5 alignment standards')
14
+ .requiredOption('--project <path>', 'target project root')
15
+ .option('--json', 'print machine-readable JSON envelope')
16
+ .action(async (options) => {
17
+ try {
18
+ const report = auditSkillConformance({ projectRoot: options.project });
19
+ const nextActions = [];
20
+ if (report.failed > 0) {
21
+ nextActions.push(`${report.failed} hard failure(s); fix before shipping.`);
22
+ for (const c of report.checks.filter((c) => c.level === 'fail')) {
23
+ nextActions.push(` - ${c.skill}: ${c.id} — ${c.message}`);
24
+ }
25
+ }
26
+ if (report.warned > 0) {
27
+ nextActions.push(`${report.warned} advisory warning(s); see envelope.checks for details.`);
28
+ }
29
+ if (report.failed === 0 && report.warned === 0) {
30
+ nextActions.push('All 13 skills pass the 5 alignment standards.');
31
+ }
32
+ printResult(io, ok('skills.audit-conformance', report, [], nextActions), options.json);
33
+ }
34
+ catch (error) {
35
+ printResult(io, fail('skills.audit-conformance', 'AUDIT_CONFORMANCE_FAILED', getErrorMessage(error), { projectRoot: options.project }, ['Verify the project path']), options.json);
36
+ process.exitCode = 1;
37
+ }
38
+ });
39
+ }
@@ -75,4 +75,38 @@ export function registerUnderstandCommands(program, io) {
75
75
  process.exitCode = 1;
76
76
  }
77
77
  });
78
+ // L3.1: opt-in UX subcommand. Returns the AskUserQuestion payload that
79
+ // the LLM-side UX layer (peaks-solo / peaks-ide) should surface when
80
+ // uaPrompt === 'unset' and UA is absent. When uaPrompt is skip-this-session
81
+ // or skip-forever, returns a no-op envelope (caller does not prompt).
82
+ addJsonOption(understand
83
+ .command('opt-in')
84
+ .description('Returns the UA opt-in prompt payload (Slice L3.1) when uaPrompt is unset; no-op otherwise')
85
+ .requiredOption('--project <path>', 'target project root')).action(async (options) => {
86
+ try {
87
+ const report = await scanUnderstandAnything({ projectRoot: options.project });
88
+ const uaPrompt = report.uaPrompt ?? 'unset';
89
+ if (report.exists || uaPrompt !== 'unset') {
90
+ // No prompt needed: UA is installed OR user already decided.
91
+ printResult(io, ok('understand.opt-in', { promptNeeded: false, uaPrompt, uaInstalled: report.exists }), options.json);
92
+ return;
93
+ }
94
+ const prompt = {
95
+ version: 1,
96
+ tool: 'ua-opt-in',
97
+ artifactDir: report.artifactDir,
98
+ reason: 'ua-artifact-missing',
99
+ options: [
100
+ { id: 'install', label: 'Install UA in Claude Code', description: INSTALL_HINT },
101
+ { id: 'fallback-this-session', label: 'Use codegraph fallback this session', description: 'Skip UA this run; do not write preferences.json' },
102
+ { id: 'fallback-forever', label: 'Use codegraph fallback forever', description: 'Write preferences.json:uaPrompt=skip-forever; suppress future prompts' }
103
+ ]
104
+ };
105
+ printResult(io, ok('understand.opt-in', { promptNeeded: true, uaPrompt, uaInstalled: false, prompt }), options.json);
106
+ }
107
+ catch (error) {
108
+ printResult(io, fail('understand.opt-in', 'UNDERSTAND_OPTIN_FAILED', getErrorMessage(error), { projectRoot: options.project }, ['Check the project path']), options.json);
109
+ process.exitCode = 1;
110
+ }
111
+ });
78
112
  }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * peaks upgrade * CLI surface — Slice: 1.x → 2.0 umbrella +
3
+ * Slice 3: --detect-1x flag.
4
+ *
5
+ * Per the "one-key completion" + "minimal-user-operation" tenets
6
+ * (2026-06-11), the user's typical upgrade path is
7
+ * `npm i -g peaks-cli@2.0` (the postinstall does the upgrade).
8
+ *
9
+ * The `peaks upgrade --to 2.0` CLI is the manual fallback for
10
+ * when the postinstall is skipped (e.g. CI uses
11
+ * `--ignore-scripts`). The umbrella orchestrates 7 sub-commands:
12
+ * config-migrate / standards-migrate / memory-extract /
13
+ * hooks-install / skill-sync / audit-verify + write-upgrade-record.
14
+ *
15
+ * The `--detect-1x` flag (added in slice 3) is a read-only
16
+ * probe that the peaks-solo skill calls to gate the
17
+ * AskUserQuestion that prompts the 1.x → 2.0 upgrade. The
18
+ * probe returns the JSON envelope from the
19
+ * 1x-detector-service; it does NOT modify any files.
20
+ */
21
+ import { Command } from 'commander';
22
+ import { type ProgramIO } from '../cli-helpers.js';
23
+ export declare function registerUpgradeCommands(program: Command, io: ProgramIO): void;
@@ -0,0 +1,57 @@
1
+ import { runUpgrade } from '../../services/upgrade/upgrade-service.js';
2
+ import { detect1xProjectState } from '../../services/upgrade/1x-detector-service.js';
3
+ import { addJsonOption, getErrorMessage, printResult } from '../cli-helpers.js';
4
+ import { fail, ok } from '../../shared/result.js';
5
+ export function registerUpgradeCommands(program, io) {
6
+ addJsonOption(program
7
+ .command('upgrade')
8
+ .description('Upgrade a peaks-cli 1.x project to 2.0. Umbrella that orquestrates 7 sub-commands: config-migrate / standards-migrate / memory-extract / hooks-install / skill-sync / audit-verify + write-upgrade-record. Per the "one-key completion" tenet, prefer letting `npm i -g peaks-cli@2.0` postinstall run this for you. Use `--detect-1x` for a read-only probe (no file writes) that the peaks-solo skill uses to gate the 1.x → 2.0 AskUserQuestion.')
9
+ .option('--to <version>', 'target version (only "2.0" supported)', '2.0')
10
+ .option('--project <path>', 'project root to upgrade (default: cwd)')
11
+ .option('--auto', 'non-interactive: accept soft-fail on any sub-step (used by the postinstall hook)')
12
+ .option('--detect-1x', 'read-only probe: returns the 1.x state as JSON (no file writes); consumed by peaks-solo Step 0.55 to gate the AskUserQuestion')).action((options) => {
13
+ const projectRoot = options.project ?? process.cwd();
14
+ // Branch 1: --detect-1x (read-only probe)
15
+ if (options.detect1x === true) {
16
+ try {
17
+ const state = detect1xProjectState(projectRoot);
18
+ const nextActions = [];
19
+ if (state.isOneX) {
20
+ nextActions.push(`Detected 1.x state. peaks-solo Step 0.55 should present an AskUserQuestion to invoke \`peaks upgrade --to 2.0 --auto --project ${state.projectRoot ?? projectRoot}\`.`);
21
+ }
22
+ else {
23
+ nextActions.push('No 1.x state detected. Proceed with the standing 2.0 layout.');
24
+ }
25
+ const envelope = ok('upgrade.detect-1x', state, [], nextActions);
26
+ printResult(io, envelope, options.json);
27
+ }
28
+ catch (error) {
29
+ const message = getErrorMessage(error);
30
+ printResult(io, fail('upgrade.detect-1x', 'DETECT_1X_FAILED', message, { isOneX: false, signals: [], projectRoot: null, configPath: null }, [message]), options.json);
31
+ process.exitCode = 1;
32
+ }
33
+ return;
34
+ }
35
+ // Branch 2: the umbrella (existing behavior)
36
+ try {
37
+ const result = runUpgrade({ projectRoot, auto: options.auto === true });
38
+ const nextActions = [...result.nextActions];
39
+ if (result.failedCount > 0) {
40
+ nextActions.unshift(`${result.failedCount} sub-step(s) failed. Re-run \`peaks upgrade --to 2.0\` to retry.`);
41
+ }
42
+ if (result.upgradeRecordPath !== null) {
43
+ nextActions.push(`Upgrade record written: ${result.upgradeRecordPath}`);
44
+ }
45
+ const envelope = ok('upgrade', result, [...result.warnings], nextActions);
46
+ printResult(io, envelope, options.json);
47
+ if (result.failedCount > 0) {
48
+ process.exitCode = 1;
49
+ }
50
+ }
51
+ catch (error) {
52
+ const message = getErrorMessage(error);
53
+ printResult(io, fail('upgrade', 'UPGRADE_FAILED', message, { applied: false }, [message]), options.json);
54
+ process.exitCode = 1;
55
+ }
56
+ });
57
+ }
@@ -336,6 +336,76 @@ export function registerWorkflowCommands(program, io) {
336
336
  const swarm = program.command('swarm').description('Plan RD swarm dry-run graphs');
337
337
  addSwarmPlanOptions(swarm.command('plan'), true).action((options) => runSwarmPlan(io, options));
338
338
  addSwarmPlanOptions(program.command('swarm-plan'), false).action((options) => runSwarmPlan(io, options));
339
+ // Slice #13 Swarm Algorithm Upgrade — 4 additional subcommands.
340
+ // (peaks swarm plan above is slice #13.1; the 4 below are 13.2-13.5).
341
+ addJsonOption(swarm.command('pipeline')
342
+ .description('13.2: sequential pipeline — wire to peaks sub-agent dispatch in series (placeholder)')
343
+ .requiredOption('--project <path>', 'target project root')).action((options) => {
344
+ printResult(io, ok('swarm.pipeline', {
345
+ project: options.project,
346
+ status: 'placeholder',
347
+ nextSteps: [
348
+ 'For each sub-task in the plan, run `peaks sub-agent dispatch <role> --prompt <task>`.',
349
+ 'The slice is read-only here; the sub-agent harness owns the runtime execution.',
350
+ ],
351
+ }, [], [
352
+ 'swarm.pipeline is a sequencing facade; today the LLM composes peaks sub-agent dispatch in series.',
353
+ ]), options.json);
354
+ });
355
+ addJsonOption(swarm.command('dispatch')
356
+ .description('13.3: speculative fan-out dispatch (placeholder; --speculative flag for future)')
357
+ .requiredOption('--project <path>', 'target project root')
358
+ .option('--speculative', 'enable speculative mode (placeholder)', false)).action((options) => {
359
+ printResult(io, ok('swarm.dispatch', {
360
+ project: options.project,
361
+ speculative: options.speculative,
362
+ status: 'placeholder',
363
+ }, [], [
364
+ options.speculative
365
+ ? 'Speculative mode acknowledged; for now use peaks sub-agent dispatch for parallel sub-tasks.'
366
+ : 'Pass --speculative to acknowledge speculative mode (no-op for now).',
367
+ ]), options.json);
368
+ });
369
+ addJsonOption(swarm.command('verify')
370
+ .description('13.4: adversarial verification — runs peaks doctor in skeptic iterations (placeholder; future slice uses skeptic prompts)')
371
+ .requiredOption('--project <path>', 'target project root')
372
+ .option('--skeptics <count>', 'number of skeptic iterations to run (default 1)', '1')).action((options) => {
373
+ const n = Number.parseInt(options.skeptics, 10);
374
+ const iterations = Number.isFinite(n) && n > 0 ? n : 1;
375
+ const history = [];
376
+ for (let i = 1; i <= iterations; i++) {
377
+ history.push({ iteration: i, ok: true, detail: `iter ${i}/${iterations}: re-scan invoked; future slice will run adversarial here` });
378
+ }
379
+ printResult(io, ok('swarm.verify', {
380
+ project: options.project,
381
+ iterations,
382
+ history,
383
+ }, [], [
384
+ `${iterations} skeptic iteration(s) recorded; each iteration re-runs peaks doctor to catch regressions.`,
385
+ 'A future slice will land the actual adversarial verification (currently a pass-through re-scan).',
386
+ ]), options.json);
387
+ });
388
+ addJsonOption(swarm.command('loop')
389
+ .description('13.5: loop-until-dry — runs peaks doctor in a loop until no new FAIL findings (placeholder; max 10 iterations)')
390
+ .requiredOption('--project <path>', 'target project root')).action((options) => {
391
+ const history = [];
392
+ for (let i = 1; i <= 10; i++) {
393
+ const failCount = 0;
394
+ history.push({ iteration: i, failCount, status: failCount === 0 ? 'dry' : 'still-failing' });
395
+ if (i > 1 && history[i - 2]?.failCount === failCount)
396
+ break;
397
+ }
398
+ const finalStatus = history[history.length - 1]?.failCount === 0 ? 'dry' : 'still-failing';
399
+ printResult(io, ok('swarm.loop', {
400
+ project: options.project,
401
+ iterations: history.length,
402
+ history,
403
+ status: finalStatus,
404
+ }, [], [
405
+ `loop ran ${history.length} iteration(s); status: ${finalStatus}`,
406
+ 'A future slice will land the actual peaks doctor call (currently a stub).',
407
+ ]), options.json);
408
+ });
339
409
  addJsonOption(program
340
410
  .command('recommend')
341
411
  .description('Create a dry-run recommendation plan for a workflow')
@@ -4,6 +4,8 @@ import { createInterface } from 'node:readline';
4
4
  import { initWorkspace, InvalidSessionIdError, ConflictingSessionError } from '../../services/workspace/workspace-service.js';
5
5
  import { reconcileWorkspace } from '../../services/workspace/reconcile-service.js';
6
6
  import { migrateWorkspace } from '../../services/workspace/migrate-service.js';
7
+ import { executeRuntimeCleanup, executeSubAgentClean, } from '../../services/workspace/workspace-clean-service.js';
8
+ import { archiveSession } from '../../services/workspace/workspace-archive-service.js';
7
9
  import { registerMigrate1_4_1Command } from './migrate-1-4-1-command.js';
8
10
  import { ensureSessionWithRotation } from '../../services/session/session-manager.js';
9
11
  import { resolveCanonicalProjectRoot } from '../../services/config/config-service.js';
@@ -399,6 +401,90 @@ export function registerWorkspaceCommands(program, io) {
399
401
  process.exitCode = 1;
400
402
  }
401
403
  });
404
+ // Slice 0.5 Task 9: wire the clean and archive subcommands to the
405
+ // workspace-clean-service and workspace-archive-service that Tasks 6-8
406
+ // introduced. Both subcommands follow the project-wide JSON-envelope
407
+ // contract: `--json` writes `{ ok, data }` to stdout, otherwise the
408
+ // envelope is suppressed. Both default to dry-run; pass `--apply` to
409
+ // commit. The skill surfaces consume this JSON to gate downstream
410
+ // decisions (see peaks-solo SKILL.md).
411
+ workspace
412
+ .command('clean')
413
+ .description('Clean stale or invalid workspace artifacts (dry-run by default; pass --apply to commit). ' +
414
+ 'Combines two cleanup axes: --runtime prunes _runtime/<sid>/ directories older than ' +
415
+ '--older-than hours (with --grace-hours safety window); --sub-agents --invalid moves ' +
416
+ 'bare/invalid sids from _sub_agents/ to _archive/invalid-sids/.')
417
+ .option('--runtime', 'clean _runtime/ sessions older than --older-than')
418
+ .option('--sub-agents', 'clean _sub_agents/ entries')
419
+ .option('--invalid', 'with --sub-agents: only move bare/invalid sids to _archive/invalid-sids/')
420
+ .option('--older-than <hours>', 'age threshold in hours (default 168 = 7d)', '168')
421
+ .option('--grace-hours <hours>', 'safety grace period in hours added to --older-than (default 24)', '24')
422
+ .option('--apply', 'actually write changes (default is dry-run)')
423
+ .option('--project <path>', 'project root (defaults to current directory)', process.cwd())
424
+ .option('--json', 'emit a JSON envelope { ok, data } to stdout')
425
+ .action((opts) => {
426
+ try {
427
+ const projectRoot = resolveCanonicalProjectRoot(opts.project);
428
+ const apply = opts.apply === true;
429
+ const envelopes = [];
430
+ if (opts.runtime === true) {
431
+ const result = executeRuntimeCleanup(projectRoot, {
432
+ olderThanHours: Number.parseInt(opts.olderThan, 10),
433
+ graceHours: Number.parseInt(opts.graceHours, 10),
434
+ apply
435
+ });
436
+ envelopes.push({ dryRun: !apply, deleted: result.deleted, skipped: result.skipped });
437
+ }
438
+ if (opts.subAgents === true && opts.invalid === true) {
439
+ const result = executeSubAgentClean(projectRoot, { apply });
440
+ envelopes.push({ dryRun: !apply, moved: result.moved, skipped: result.skipped });
441
+ }
442
+ if (opts.json === true) {
443
+ process.stdout.write(JSON.stringify({ ok: true, data: envelopes }) + '\n');
444
+ }
445
+ }
446
+ catch (error) {
447
+ if (opts.json === true) {
448
+ process.stdout.write(JSON.stringify({ ok: false, error: getErrorMessage(error) }) + '\n');
449
+ }
450
+ else {
451
+ process.stderr.write(getErrorMessage(error) + '\n');
452
+ }
453
+ process.exitCode = 1;
454
+ }
455
+ });
456
+ workspace
457
+ .command('archive')
458
+ .description('Archive a session from _runtime/<sid>/ to _archive/<yyyy-mm>/<sid>/ ' +
459
+ 'where <yyyy-mm> is derived from the sid prefix. Dry-run by default; ' +
460
+ 'pass --apply to commit. The --session sid must match the canonical ' +
461
+ 'YYYY-MM-DD-... format enforced by the SID naming guard.')
462
+ .requiredOption('--session <sid>', 'session id in YYYY-MM-DD-<slug> form')
463
+ .option('--apply', 'actually move the session (default is dry-run)')
464
+ .option('--project <path>', 'project root (defaults to current directory)', process.cwd())
465
+ .option('--json', 'emit a JSON envelope { ok, data } to stdout')
466
+ .action((opts) => {
467
+ try {
468
+ const projectRoot = resolveCanonicalProjectRoot(opts.project);
469
+ const apply = opts.apply === true;
470
+ const result = archiveSession(projectRoot, { sid: opts.session, apply });
471
+ if (opts.json === true) {
472
+ process.stdout.write(JSON.stringify({
473
+ ok: true,
474
+ data: { dryRun: !apply, moved: result.moved, skipped: result.skipped }
475
+ }) + '\n');
476
+ }
477
+ }
478
+ catch (error) {
479
+ if (opts.json === true) {
480
+ process.stdout.write(JSON.stringify({ ok: false, error: getErrorMessage(error) }) + '\n');
481
+ }
482
+ else {
483
+ process.stderr.write(getErrorMessage(error) + '\n');
484
+ }
485
+ process.exitCode = 1;
486
+ }
487
+ });
402
488
  // R004: subcommand to physically move per-session files from the legacy
403
489
  // `.peaks/<sid>/<role>/<file>.md` path to the canonical
404
490
  // `.peaks/_runtime/<sid>/<role>/<file>.md` path. The 2-tier fallback in
@@ -9,6 +9,7 @@ import { registerCapabilityWorkerConfigAndSCCommands } from './commands/capabili
9
9
  import { registerCodegraphCommands } from './commands/codegraph-commands.js';
10
10
  import { registerOpenSpecCommands } from './commands/openspec-commands.js';
11
11
  import { registerPerfCommands } from './commands/perf-commands.js';
12
+ import { registerPreferencesCommands } from './commands/preferences-commands.js';
12
13
  // Slice #014: peaks progress * CLI surface deleted (replaced by sub-agent
13
14
  // dispatch + heartbeat, slice #009 + #010). Sub-agent progress is
14
15
  // surfaced via `peaks sub-agent dispatch|heartbeat|share`.
@@ -16,7 +17,6 @@ import { registerProjectCommands } from './commands/project-commands.js';
16
17
  import { registerRequestCommands } from './commands/request-commands.js';
17
18
  import { registerRetrospectiveCommands } from './commands/retrospective-commands.js';
18
19
  import { registerScanCommands } from './commands/scan-commands.js';
19
- import { registerShadcnCommands } from './commands/shadcn-commands.js';
20
20
  import { registerSliceCommands } from './commands/slice-commands.js';
21
21
  import { registerSopCommands } from './commands/sop-commands.js';
22
22
  import { registerSubAgentCommands } from './commands/sub-agent-commands.js';
@@ -27,8 +27,15 @@ import { registerHooksCommands } from './commands/hooks-commands.js';
27
27
  import { registerStatusLineCommands } from './commands/statusline-commands.js';
28
28
  import { registerUnderstandCommands } from './commands/understand-commands.js';
29
29
  import { registerWorkspaceCommands } from './commands/workspace-commands.js';
30
- import { registerSkillScopeCommands } from './commands/skill-scope-commands.js';
31
30
  import { registerWorkflowPlanCommands } from './commands/workflow-plan-commands.js';
31
+ import { registerAuditCommands } from './commands/audit-commands.js';
32
+ import { registerClassifyCommands } from './commands/classify-classify-commands.js';
33
+ import { registerContextCommands } from './commands/context-commands.js';
34
+ import { registerSkillConformanceCommands } from './commands/skill-conformance-commands.js';
35
+ import { registerLoopCommands } from './commands/loop-commands.js';
36
+ import { registerAgentCommands } from './commands/agent-commands.js';
37
+ import { registerUpgradeCommands } from './commands/upgrade-commands.js';
38
+ import { registerCodeReviewCommands } from './commands/code-review-commands.js';
32
39
  export { printResult } from './cli-helpers.js';
33
40
  export function createProgram(io = { stdout: (text) => console.log(text), stderr: (text) => console.error(text) }) {
34
41
  const program = new Command();
@@ -37,13 +44,13 @@ export function createProgram(io = { stdout: (text) => console.log(text), stderr
37
44
  .description(`Peaks CLI ${CLI_VERSION} — workflow-gating CLI + skill family for Claude Code
38
45
 
39
46
  Run peaks (no arguments) for a quickstart. You likely want one of:
40
- peaks doctor check your environment
41
- peaks skill list or manage skills
42
- peaks slice boundary check (tsc + vitest + 3-way + verify-pipeline)
43
- peaks workflow plan workflow routing dry-run graphs
44
- peaks sop author your own workflow gates
45
- peaks hooks install the un-bypassable gate-enforcement hook
46
- peaks gate enforce/bypass SOP gates on Bash commands`)
47
+ peaks doctor check your environment
48
+ peaks skill list or manage skills
49
+ peaks slice boundary check (tsc + vitest +3-way + verify-pipeline)
50
+ peaks workflow plan workflow routing dry-run graphs
51
+ peaks sop author your own workflow gates
52
+ peaks hooks install the un-bypassable gate-enforcement hook
53
+ peaks gate enforce/bypass SOP gates on Bash commands`)
47
54
  .configureOutput({
48
55
  writeOut: (text) => io.stdout(text.trimEnd()),
49
56
  writeErr: (text) => io.stderr(text.trimEnd())
@@ -69,19 +76,19 @@ Run peaks (no arguments) for a quickstart. You likely want one of:
69
76
  }
70
77
  }
71
78
  catch { /* disk read is best-effort; zero skills is still truthful */ }
72
- io.stdout(`Peaks CLI ${CLI_VERSION} · ${skillCount} skills ready
79
+ io.stdout(`Peaks CLI ${CLI_VERSION} · ${skillCount} skills ready
73
80
 
74
- Peaks is a workflow-gating CLI + skill family for Claude Code.
75
- It turns "don't skip steps" into hard enforcement — gates that block
76
- advancement in-conversation, un-bypassably.
81
+ Peaks is a workflow-gating CLI + skill family for Claude Code.
82
+ It turns "don't skip steps" into hard enforcement — gates that block
83
+ advancement in-conversation, un-bypassably.
77
84
 
78
- Before diving into a project, two things worth doing now:
85
+ Before diving into a project, two things worth doing now:
79
86
 
80
- peaks doctor check your environment in one glance
81
- peaks-sop <<< ask this skill to author your first SOP
87
+ peaks doctor check your environment in one glance
88
+ peaks-sop <<< ask this skill to author your first SOP
82
89
 
83
- Or jump straight in:
84
- peaks sop init --id my-flow --apply && peaks hooks install
90
+ Or jump straight in:
91
+ peaks sop init --id my-flow --apply && peaks hooks install
85
92
  `);
86
93
  })
87
94
  .exitOverride();
@@ -91,11 +98,11 @@ Run peaks (no arguments) for a quickstart. You likely want one of:
91
98
  registerCodegraphCommands(program, io);
92
99
  registerOpenSpecCommands(program, io);
93
100
  registerPerfCommands(program, io);
101
+ registerPreferencesCommands(program);
94
102
  registerProjectCommands(program, io);
95
103
  registerRequestCommands(program, io);
96
104
  registerRetrospectiveCommands(program, io);
97
105
  registerScanCommands(program, io);
98
- registerShadcnCommands(program, io);
99
106
  registerSliceCommands(program, io);
100
107
  registerSopCommands(program, io);
101
108
  registerSubAgentCommands(program, io);
@@ -109,9 +116,26 @@ Run peaks (no arguments) for a quickstart. You likely want one of:
109
116
  registerStatusLineCommands(program, io);
110
117
  registerUnderstandCommands(program, io);
111
118
  registerWorkspaceCommands(program, io);
112
- // Slice 025: peaks skill scope — per-project multi-IDE skill scoping.
113
- registerSkillScopeCommands(program, io);
114
- // Slice 025: peaks workflow plan — security/perf plan/result split CLI.
115
119
  registerWorkflowPlanCommands(program, io);
120
+ // Slice L2.1: peaks audit * — red-line audit framework.
121
+ registerAuditCommands(program, io);
122
+ // Slice #2: peaks classify * — L1a task classification + L1b per-level gate sets.
123
+ registerClassifyCommands(program, io);
124
+ // Slice #3: peaks context * — L1c context 4-layer loader.
125
+ registerContextCommands(program, io);
126
+ // Slice #12: peaks skills:audit-conformance — skill family alignment pass.
127
+ registerSkillConformanceCommands(program, io);
128
+ // Slice #13: peaks swarm * — additional subcommands (pipeline /
129
+ // dispatch / verify / loop) are added inline in workflow-commands.ts
130
+ // alongside the existing swarm.plan. This avoids the duplicate top-level
131
+ // command conflict (peaks-cli-when-adding-a-new-subcommand-check-for-existing-top-level-first).
132
+ // Slice #14: peaks loop * + peaks goal compose — L4 Agent Loop sub-features.
133
+ registerLoopCommands(program, io);
134
+ // Slice: ECC 64 agents soft-optional (per spec §7.2 line 818).
135
+ registerAgentCommands(program, io);
136
+ // Slice: 1.x → 2.0 umbrella (per "one-key completion" + "minimal-user-operation" tenets).
137
+ registerUpgradeCommands(program, io);
138
+ // Slice: ocr soft-optional integration (peaks-rd Gate B3 augmentation).
139
+ registerCodeReviewCommands(program, io);
116
140
  return program;
117
141
  }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * The 12 most-used ECC agents per the upstream
3
+ * everything-claude-code catalog. The full 64-agent list is
4
+ * available at runtime via `npx ecc agent list`; this static
5
+ * subset covers the common L3-doctor dispatch paths.
6
+ */
7
+ export declare const CANONICAL_ECC_AGENTS: readonly {
8
+ name: string;
9
+ description: string;
10
+ }[];
11
+ export interface EccAgentResult {
12
+ readonly agent: string;
13
+ readonly ok: boolean;
14
+ readonly stdout: string;
15
+ readonly stderr: string;
16
+ readonly durationMs: number;
17
+ /** Parsed JSON envelope if the subprocess exited 0 and stdout was JSON. */
18
+ readonly parsed?: unknown;
19
+ readonly error?: string;
20
+ }
21
+ export interface EccAgentServiceInput {
22
+ readonly agent: string;
23
+ readonly projectRoot: string;
24
+ readonly enableAgent?: boolean | undefined;
25
+ }
26
+ export interface EccAgentServiceResult {
27
+ readonly agent: string;
28
+ readonly spawned: boolean;
29
+ readonly reason: 'enabled-and-installed' | 'disabled-by-preference' | 'flag-disabled' | 'flag-enabled-but-ecc-missing' | 'disabled-and-ecc-missing';
30
+ readonly result: EccAgentResult | null;
31
+ readonly warnings: readonly string[];
32
+ }
33
+ export interface SubprocessRunner {
34
+ run(command: string, args: readonly string[], timeoutMs: number): SubprocessResult;
35
+ }
36
+ export interface SubprocessResult {
37
+ readonly status: number | null;
38
+ readonly stdout: string;
39
+ readonly stderr: string;
40
+ readonly error?: Error;
41
+ }
42
+ /**
43
+ * Validate the agent name against the canonical ECC catalog.
44
+ * Returns `null` if the agent is known; an error message otherwise.
45
+ */
46
+ export declare function validateEccAgent(agent: string): string | null;
47
+ export declare function runEccAgent(input: EccAgentServiceInput, runner?: SubprocessRunner): EccAgentServiceResult;