@planu/cli 5.7.5 → 5.7.7

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 (210) hide show
  1. package/CHANGELOG.md +88 -0
  2. package/README.md +3 -3
  3. package/dist/.planu-build.json +1 -1
  4. package/dist/cli/commands/package-handoff.js +30 -5
  5. package/dist/config/compliance-profiles.json +36 -3
  6. package/dist/config/environment-schema.json +21 -0
  7. package/dist/config/hook-templates/planu-review-panel-trigger.sh +2 -3
  8. package/dist/config/hook-templates/planu-session-safeguard.sh +22 -15
  9. package/dist/config/official-sdd-tools.d.ts +1 -1
  10. package/dist/config/official-sdd-tools.js +11 -24
  11. package/dist/config/registries/hosts/codex.json +14 -30
  12. package/dist/config/registries/hosts/opencode.json +1 -6
  13. package/dist/config/server-instructions.js +0 -21
  14. package/dist/config/skill-templates/planu-context-assets.md +3 -6
  15. package/dist/config/skill-templates/planu-implement.md +2 -2
  16. package/dist/config/skill-templates/planu-multi-teammate-review.md +8 -12
  17. package/dist/config/skill-templates/planu-release.md +2 -7
  18. package/dist/config/skill-templates/planu-validate.md +3 -3
  19. package/dist/config/spec-templates/crud-rest-api/template.json +5 -1
  20. package/dist/config/spec-templates/file-upload-s3/template.json +5 -1
  21. package/dist/config/spec-templates/stripe-payments/template.json +5 -1
  22. package/dist/config/spec-templates/webhook-system/template.json +5 -1
  23. package/dist/config/subagent-templates/planu-challenger.md +4 -9
  24. package/dist/config/subagent-templates/planu-spec-implementer.md +2 -4
  25. package/dist/config/subagent-templates/planu-validator.md +5 -8
  26. package/dist/config/tool-groups.json +6 -144
  27. package/dist/engine/ambiguity-scorer.js +40 -1
  28. package/dist/engine/autopilot/bootstrap.js +1 -1
  29. package/dist/engine/code-impact-analyzer.js +2 -6
  30. package/dist/engine/context-orchestrator/index.js +2 -2
  31. package/dist/engine/convention-scanner/codebase-scanner.js +2 -2
  32. package/dist/engine/dogfooding/runtime-gap-detector.js +2 -2
  33. package/dist/engine/evidence-gates/artifact-reader.d.ts +1 -0
  34. package/dist/engine/evidence-gates/artifact-reader.js +1 -1
  35. package/dist/engine/evidence-gates/evidence-autofill.d.ts +13 -5
  36. package/dist/engine/evidence-gates/evidence-autofill.js +106 -43
  37. package/dist/engine/evidence-gates/evidence-skeletons.js +3 -1
  38. package/dist/engine/evidence-gates/lifecycle-gate.js +7 -4
  39. package/dist/engine/evidence-index/index-builder.js +21 -4
  40. package/dist/engine/execution/job-runtime.js +1 -1
  41. package/dist/engine/execution/package-handoff-job-executor.d.ts +22 -0
  42. package/dist/engine/execution/package-handoff-job-executor.js +490 -0
  43. package/dist/engine/execution/validate-job-executor.js +20 -8
  44. package/dist/engine/git/exec-git.d.ts +4 -0
  45. package/dist/engine/git/exec-git.js +14 -0
  46. package/dist/engine/handoff-artifacts/implementation-review-reader.js +15 -2
  47. package/dist/engine/handoff-artifacts/schemas.d.ts +2 -0
  48. package/dist/engine/handoff-artifacts/schemas.js +1 -0
  49. package/dist/engine/handoff-format.d.ts +36 -0
  50. package/dist/engine/handoff-format.js +314 -0
  51. package/dist/engine/handoff-packager.d.ts +5 -3
  52. package/dist/engine/handoff-packager.js +89 -32
  53. package/dist/engine/host-tool-filter.js +20 -49
  54. package/dist/engine/human-summary.js +14 -3
  55. package/dist/engine/implementation-contract/common.d.ts +8 -3
  56. package/dist/engine/implementation-contract/common.js +9 -6
  57. package/dist/engine/implementation-contract/evaluator.js +4 -6
  58. package/dist/engine/implementation-contract/renderer.js +18 -23
  59. package/dist/engine/project-health-checker.js +2 -2
  60. package/dist/engine/readiness-checker.js +43 -5
  61. package/dist/engine/reconcile/apply-changes.js +4 -0
  62. package/dist/engine/reconcile/propagate-mirrors.d.ts +3 -0
  63. package/dist/engine/reconcile/propagate-mirrors.js +311 -0
  64. package/dist/engine/self-healing/healer.js +12 -5
  65. package/dist/engine/self-healing/strategies/lint-fix.d.ts +1 -1
  66. package/dist/engine/self-healing/strategies/lint-fix.js +4 -1
  67. package/dist/engine/self-healing/strategies/test-fix.d.ts +4 -3
  68. package/dist/engine/self-healing/strategies/test-fix.js +32 -14
  69. package/dist/engine/self-healing/strategies/typescript-fix.d.ts +1 -1
  70. package/dist/engine/self-healing/strategies/typescript-fix.js +28 -10
  71. package/dist/engine/session/checkpoint-writer.js +8 -4
  72. package/dist/engine/session/session-tracker.d.ts +5 -16
  73. package/dist/engine/session/session-tracker.js +29 -26
  74. package/dist/engine/session-state/writer.js +3 -11
  75. package/dist/engine/skill-generator/workflow-skill-generator.d.ts +4 -2
  76. package/dist/engine/skill-generator/workflow-skill-generator.js +113 -38
  77. package/dist/engine/spec-format/bdd-parser.d.ts +1 -11
  78. package/dist/engine/spec-format/bdd-parser.js +40 -11
  79. package/dist/engine/spec-format/lean-spec-generator.js +32 -12
  80. package/dist/engine/spec-format/retired-scaffold.d.ts +3 -0
  81. package/dist/engine/spec-format/retired-scaffold.js +5 -0
  82. package/dist/engine/spec-format/technical-md-populator.d.ts +1 -0
  83. package/dist/engine/spec-format/technical-md-populator.js +27 -0
  84. package/dist/engine/spec-format/unified-spec-builder.d.ts +1 -0
  85. package/dist/engine/spec-format/unified-spec-builder.js +30 -20
  86. package/dist/engine/spec-grounding/contract.d.ts +3 -3
  87. package/dist/engine/spec-grounding/contract.js +65 -4
  88. package/dist/engine/spec-grounding/grounding-entry-parser.d.ts +5 -0
  89. package/dist/engine/spec-grounding/grounding-entry-parser.js +185 -0
  90. package/dist/engine/spec-quality/generic-output-gate.js +37 -3
  91. package/dist/engine/technical-enricher/index.js +4 -1
  92. package/dist/engine/type-safety-gate.js +3 -11
  93. package/dist/engine/universal-rules/catalog.js +0 -2
  94. package/dist/engine/universal-rules/rules/planu-workflow.js +1 -1
  95. package/dist/engine/validation/durable-validation.d.ts +3 -2
  96. package/dist/engine/validation/durable-validation.js +106 -40
  97. package/dist/engine/validation/validation-freshness.d.ts +3 -2
  98. package/dist/engine/validation/validation-freshness.js +22 -16
  99. package/dist/engine/validation/validation-worktree.js +34 -0
  100. package/dist/hosts/claude-code/ux/mcp-prompts.js +8 -8
  101. package/dist/index.js +3 -17
  102. package/dist/resources/process.js +38 -65
  103. package/dist/storage/session-state-store.js +2 -0
  104. package/dist/storage/spec-store.js +8 -1
  105. package/dist/tools/bump-spec-version.js +5 -5
  106. package/dist/tools/challenge-spec/scenarios-utils.js +2 -2
  107. package/dist/tools/configure-checkpoint-policy.js +3 -3
  108. package/dist/tools/create-spec-helpers.js +2 -5
  109. package/dist/tools/create-spec.js +21 -4
  110. package/dist/tools/facilitate.js +3 -6
  111. package/dist/tools/git/branch-ops.js +16 -4
  112. package/dist/tools/github-release-handler.js +1 -20
  113. package/dist/tools/init-project/agents-md-writer.js +6 -6
  114. package/dist/tools/init-project/claude-md-generator.d.ts +0 -1
  115. package/dist/tools/init-project/claude-md-generator.js +0 -35
  116. package/dist/tools/init-project/handler.js +7 -5
  117. package/dist/tools/init-project/per-client-files-writer.js +5 -5
  118. package/dist/tools/init-project/planu-workflow-generator.js +2 -13
  119. package/dist/tools/init-project/portable-index-reconciler.d.ts +2 -1
  120. package/dist/tools/init-project/portable-index-reconciler.js +7 -2
  121. package/dist/tools/init-project/rules-generator.d.ts +0 -11
  122. package/dist/tools/init-project/rules-generator.js +4 -85
  123. package/dist/tools/init-project/scaffold-writer.d.ts +0 -1
  124. package/dist/tools/init-project/scaffold-writer.js +1 -12
  125. package/dist/tools/init-project/skills-multi-teammate-review-writer.js +1 -1
  126. package/dist/tools/jobs/handlers.d.ts +0 -6
  127. package/dist/tools/jobs/handlers.js +13 -40
  128. package/dist/tools/list-specs.js +6 -21
  129. package/dist/tools/multi-teammate-review.js +1 -14
  130. package/dist/tools/package-handoff.d.ts +3 -2
  131. package/dist/tools/package-handoff.js +153 -427
  132. package/dist/tools/reconcile-session-safeguard-hook.js +22 -15
  133. package/dist/tools/register-platform-tools/design-stack-tools.js +3 -3
  134. package/dist/tools/register-sdd-tools.js +0 -23
  135. package/dist/tools/register-spec-tools/analysis-tools.js +22 -9
  136. package/dist/tools/register-spec-tools/core-spec-tools.js +115 -70
  137. package/dist/tools/schemas/index.d.ts +1 -1
  138. package/dist/tools/schemas/index.js +1 -1
  139. package/dist/tools/schemas/output-schemas.d.ts +1 -18
  140. package/dist/tools/schemas/output-schemas.js +1 -11
  141. package/dist/tools/schemas/package-handoff-output-schema.d.ts +40 -0
  142. package/dist/tools/schemas/package-handoff-output-schema.js +68 -0
  143. package/dist/tools/schemas/validate-output-schema.d.ts +1 -2
  144. package/dist/tools/schemas/validate-output-schema.js +3 -2
  145. package/dist/tools/session-checkpoint.js +2 -2
  146. package/dist/tools/skill-registry/index.d.ts +0 -1
  147. package/dist/tools/skill-registry/index.js +0 -1
  148. package/dist/tools/sync-spec-state-handler.d.ts +2 -2
  149. package/dist/tools/sync-spec-state-handler.js +23 -3
  150. package/dist/tools/tool-registry/core-tools.js +72 -164
  151. package/dist/tools/tool-registry/group-infra.js +2 -39
  152. package/dist/tools/tool-registry/group-quality-compliance.js +20 -15
  153. package/dist/tools/tool-registry-helpers.js +6 -2
  154. package/dist/tools/update-status/batch.js +17 -0
  155. package/dist/tools/update-status/dod-gates.js +14 -1
  156. package/dist/tools/update-status/done-receipt-verifier.d.ts +22 -0
  157. package/dist/tools/update-status/done-receipt-verifier.js +56 -26
  158. package/dist/tools/update-status/evidence-gate.js +10 -21
  159. package/dist/tools/update-status/file-sync.d.ts +1 -0
  160. package/dist/tools/update-status/file-sync.js +6 -0
  161. package/dist/tools/update-status/index.d.ts +6 -0
  162. package/dist/tools/update-status/index.js +39 -44
  163. package/dist/tools/update-status-actions.js +2 -7
  164. package/dist/tools/validate.js +34 -28
  165. package/dist/transports/oauth-validator.js +12 -1
  166. package/dist/transports/transport-factory.d.ts +2 -1
  167. package/dist/transports/transport-factory.js +19 -0
  168. package/dist/types/common/primitives.d.ts +2 -0
  169. package/dist/types/durable-job.d.ts +45 -0
  170. package/dist/types/durable-validation.d.ts +1 -1
  171. package/dist/types/evidence-autofill.d.ts +13 -1
  172. package/dist/types/handoff-artifacts.d.ts +2 -1
  173. package/dist/types/readiness.d.ts +8 -1
  174. package/dist/types/reconcile.d.ts +6 -0
  175. package/dist/types/skill-registry.d.ts +26 -1
  176. package/dist/types/spec/core.d.ts +5 -0
  177. package/dist/types/spec/inputs.d.ts +2 -2
  178. package/dist/types/spec-format.d.ts +11 -1
  179. package/dist/types/spec-grounding.d.ts +26 -0
  180. package/dist/types/transport.d.ts +1 -0
  181. package/dist/types/validation-receipt.d.ts +27 -0
  182. package/package.json +3 -2
  183. package/planu-plugin.json +13 -26
  184. package/src/i18n/messages/en.json +1 -1
  185. package/src/i18n/messages/es.json +1 -1
  186. package/src/i18n/messages/pt.json +1 -1
  187. package/dist/engine/skill-generator/conventions-hasher.d.ts +0 -7
  188. package/dist/engine/skill-generator/conventions-hasher.js +0 -24
  189. package/dist/engine/universal-rules/rules/agent-teams.d.ts +0 -3
  190. package/dist/engine/universal-rules/rules/agent-teams.js +0 -63
  191. package/dist/tools/clarify-requirements/multiple-choice.d.ts +0 -30
  192. package/dist/tools/clarify-requirements/multiple-choice.js +0 -306
  193. package/dist/tools/clarify-requirements/questions-context.d.ts +0 -9
  194. package/dist/tools/clarify-requirements/questions-context.js +0 -74
  195. package/dist/tools/clarify-requirements/questions.d.ts +0 -16
  196. package/dist/tools/clarify-requirements/questions.js +0 -96
  197. package/dist/tools/clarify-requirements.d.ts +0 -4
  198. package/dist/tools/clarify-requirements.js +0 -314
  199. package/dist/tools/code-graph-handler.d.ts +0 -6
  200. package/dist/tools/code-graph-handler.js +0 -72
  201. package/dist/tools/create-rule.d.ts +0 -4
  202. package/dist/tools/create-rule.js +0 -107
  203. package/dist/tools/feedback-handler.d.ts +0 -7
  204. package/dist/tools/feedback-handler.js +0 -150
  205. package/dist/tools/semantic-search-handler.d.ts +0 -7
  206. package/dist/tools/semantic-search-handler.js +0 -71
  207. package/dist/tools/skill-registry/search.d.ts +0 -11
  208. package/dist/tools/skill-registry/search.js +0 -159
  209. package/dist/tools/tool-registry/deprecated-stubs.d.ts +0 -19
  210. package/dist/tools/tool-registry/deprecated-stubs.js +0 -65
@@ -67,17 +67,17 @@ export function registerDesignStackTools(server) {
67
67
  description: t('tools.challenge_spec.description'),
68
68
  annotations: { readOnlyHint: true },
69
69
  inputSchema: {
70
- specId: SpecIdSchema.describe('Spec ID to challenge'),
70
+ specId: SpecIdSchema.describe('Spec ID to challenge. Must match pattern ^SPEC-\\d+$, max 50 characters.'),
71
71
  projectId: z
72
72
  .string()
73
73
  .max(500)
74
74
  .optional()
75
- .describe('Project ID hash. Prefer projectPath — stays correct after context compaction.'),
75
+ .describe('Project ID hash. Prefer projectPath — stays correct after context compaction. Max 500 characters.'),
76
76
  projectPath: z
77
77
  .string()
78
78
  .max(4096)
79
79
  .optional()
80
- .describe('Absolute path to project root. Derives projectId automatically — always correct even after context compaction.'),
80
+ .describe('Max 4096 characters. Absolute path to project root. Derives projectId automatically — always correct even after context compaction.'),
81
81
  focus: z
82
82
  .array(ChallengeSpecFocusEnum)
83
83
  .max(100)
@@ -9,7 +9,6 @@ import { registerDesignStackTools } from './register-platform-tools/design-stack
9
9
  import { registerQualityComplianceGroupTools } from './tool-registry/group-quality-compliance.js';
10
10
  import { registerInfraGroupTools } from './tool-registry/group-infra.js';
11
11
  import { safe } from './safe-handler.js';
12
- import { handleCreateRule } from './create-rule.js';
13
12
  import { handleCreateSkill } from './create-skill.js';
14
13
  import { handleReconcileUniversalRules } from './reconcile-universal-rules.js';
15
14
  import { registerBumpSpecVersionTool } from './bump-spec-version.js';
@@ -43,28 +42,6 @@ function registerOnly(server, names, register) {
43
42
  register(scopedServer);
44
43
  }
45
44
  function registerUniversalRulesTools(s) {
46
- s.registerTool('create_rule', {
47
- description: 'Create a host-aware rule file for a Planu project. For Claude Code, writes to `.claude/rules/{name}.md`. For Codex, inserts a delimited block in `AGENTS.md`. For Gemini, inserts a delimited block in `.gemini/conventions.md`. Use host: "auto" to detect the current host automatically.',
48
- inputSchema: {
49
- projectPath: z
50
- .string()
51
- .describe('Absolute path to the project root where the rule will be written'),
52
- name: z
53
- .string()
54
- .min(1)
55
- .describe('Rule identifier — kebab-case, no extension (e.g. "team-style").'),
56
- content: z.string().min(1).describe('Markdown body of the rule (no frontmatter required)'),
57
- host: z
58
- .enum(['claude-code', 'codex', 'gemini', 'auto'])
59
- .default('auto')
60
- .describe('Target host or auto-detection.'),
61
- overwriteExisting: z
62
- .boolean()
63
- .optional()
64
- .describe('When true, overwrite an existing file with different content.'),
65
- },
66
- annotations: { readOnlyHint: false, destructiveHint: false, title: 'Create Rule' },
67
- }, safe((args) => handleCreateRule(args)));
68
45
  s.registerTool('create_skill', {
69
46
  description: 'Create a host-aware skill for a Planu project. For Claude Code, writes to `.claude/skills/{name}/SKILL.md`. For Codex, inserts a skill block in `AGENTS.md`. For Gemini, writes to `.gemini/skills/{name}.md`. Use host: "auto" to detect the current host automatically.',
70
47
  inputSchema: {
@@ -26,7 +26,7 @@ export const DeclaredDriftInputSchema = z.object({
26
26
  .string()
27
27
  .min(100)
28
28
  .max(10_000)
29
- .describe('Why the implementation drifted from the approved architectural premise. Minimum 100 characters — becomes the reconciliation transition reason.'),
29
+ .describe('Min 100, max 10000 characters. Why the implementation drifted from the approved architectural premise — becomes the reconciliation transition reason.'),
30
30
  });
31
31
  import { handleSsrBackMigration } from '../ssr-back-migration.js';
32
32
  import { registerMigrateLegacySpecTool } from '../migrate-legacy-spec.js';
@@ -115,13 +115,17 @@ export function registerAnalysisTools(server) {
115
115
  server.registerTool('reconcile_spec', {
116
116
  description: t('tools.reconcile_spec.description'),
117
117
  inputSchema: {
118
- specId: SpecIdSchema.describe('Spec ID to reconcile'),
119
- projectId: z.string().max(500).optional().describe('Project ID hash. Prefer projectPath.'),
118
+ specId: SpecIdSchema.describe('Spec ID to reconcile. Must match pattern ^SPEC-\\d+$, max 50 characters.'),
119
+ projectId: z
120
+ .string()
121
+ .max(500)
122
+ .optional()
123
+ .describe('Project ID hash. Prefer projectPath. Max 500 characters.'),
120
124
  projectPath: z
121
125
  .string()
122
126
  .max(4096)
123
127
  .optional()
124
- .describe('Absolute path to project root. Derives projectId automatically.'),
128
+ .describe('Absolute path to project root. Derives projectId automatically. Max 4096 characters.'),
125
129
  autoDetect: z
126
130
  .boolean()
127
131
  .optional()
@@ -132,11 +136,20 @@ export function registerAnalysisTools(server) {
132
136
  .describe('Enable living spec mode: compare acceptance criteria against codebase, auto-mark criteria as met/pending/drift, update the ## Progress section of spec.md (default: false)'),
133
137
  changes: z
134
138
  .array(z.object({
135
- section: z.string().max(500),
136
- originalValue: z.string().max(10_000),
137
- newValue: z.string().max(10_000),
138
- reason: z.string().max(10_000),
139
- approved: z.boolean(),
139
+ section: z
140
+ .string()
141
+ .max(500)
142
+ .describe('Max 500 characters. Spec section the change applies to.'),
143
+ originalValue: z
144
+ .string()
145
+ .max(10_000)
146
+ .describe('Max 10000 characters. Current text being replaced.'),
147
+ newValue: z.string().max(10_000).describe('Max 10000 characters. Replacement text.'),
148
+ reason: z
149
+ .string()
150
+ .max(10_000)
151
+ .describe('Max 10000 characters. Why the change is needed.'),
152
+ approved: z.boolean().describe('Whether the user approved this change.'),
140
153
  }))
141
154
  .max(1000)
142
155
  .optional()
@@ -7,7 +7,6 @@ import { handleSetLocale } from '../set-locale.js';
7
7
  import { handleInitProject } from '../init-project.js';
8
8
  import { handleSetWorkMode } from '../set-work-mode-handler.js';
9
9
  import { handleInitConstitution } from '../init-constitution.js';
10
- import { handleClarifyRequirements } from '../clarify-requirements.js';
11
10
  import { handleCreateSpec } from '../create-spec.js';
12
11
  import { handleListSpecs } from '../list-specs.js';
13
12
  import { handleUpdateStatus } from '../update-status.js';
@@ -19,7 +18,10 @@ import { handleTypeSafetyGate } from '../type-safety-gate.js';
19
18
  import { runWithTrustedLocalMcpContext } from '../../engine/lifecycle-reconciliation.js';
20
19
  /** init_project inputSchema — extracted to keep registerCoreSpecTools within line budget. */
21
20
  const INIT_PROJECT_INPUT_SCHEMA = {
22
- projectPath: z.string().max(4096).describe('Absolute path to the project root'),
21
+ projectPath: z
22
+ .string()
23
+ .max(4096)
24
+ .describe('Absolute path to the project root. Max 4096 characters.'),
23
25
  mode: z
24
26
  .enum(['existing_project', 'new_project'])
25
27
  .optional()
@@ -28,18 +30,40 @@ const INIT_PROJECT_INPUT_SCHEMA = {
28
30
  .string()
29
31
  .max(4096)
30
32
  .optional()
31
- .describe('Parent workspace path for explicit new_project onboarding'),
32
- appName: z.string().max(500).optional().describe('Human-readable app name for new_project'),
33
+ .describe('Parent workspace path for explicit new_project onboarding. Max 4096 characters.'),
34
+ appName: z
35
+ .string()
36
+ .max(500)
37
+ .optional()
38
+ .describe('Human-readable app name for new_project. Max 500 characters.'),
33
39
  appSlug: z
34
40
  .string()
35
41
  .max(200)
36
42
  .optional()
37
- .describe('Safe folder slug for new_project; must not contain path separators'),
38
- projectType: z.string().max(500).optional().describe('Type of project being initialized'),
39
- platform: z.string().max(500).optional().describe('Runtime/deployment platform'),
40
- language: z.string().max(500).optional().describe('User-confirmed language'),
41
- framework: z.string().max(500).nullable().optional().describe('User-confirmed framework'),
42
- database: z.string().max(500).nullable().optional().describe('User-confirmed database'),
43
+ .describe('Safe folder slug for new_project; must not contain path separators. Max 200 characters.'),
44
+ projectType: z
45
+ .string()
46
+ .max(500)
47
+ .optional()
48
+ .describe('Type of project being initialized. Max 500 characters.'),
49
+ platform: z
50
+ .string()
51
+ .max(500)
52
+ .optional()
53
+ .describe('Runtime/deployment platform. Max 500 characters.'),
54
+ language: z.string().max(500).optional().describe('User-confirmed language. Max 500 characters.'),
55
+ framework: z
56
+ .string()
57
+ .max(500)
58
+ .nullable()
59
+ .optional()
60
+ .describe('Max 500 characters. User-confirmed framework.'),
61
+ database: z
62
+ .string()
63
+ .max(500)
64
+ .nullable()
65
+ .optional()
66
+ .describe('Max 500 characters. User-confirmed database.'),
43
67
  createDirectory: z
44
68
  .boolean()
45
69
  .optional()
@@ -159,37 +183,15 @@ export function registerCoreSpecTools(server) {
159
183
  .describe('Manual principles to include'),
160
184
  },
161
185
  }, safeTracked('init_constitution', async (args) => handleInitConstitution(args)));
162
- // 4. clarify_requirements
163
- server.registerTool('clarify_requirements', {
164
- description: t('tools.clarify_requirements.description'),
165
- inputSchema: {
166
- projectId: z.string().max(500).describe('Project ID'),
167
- topic: z.string().max(500).describe('The topic or feature to clarify'),
168
- context: z
169
- .string()
170
- .max(10_000)
171
- .optional()
172
- .describe('Additional context about the requirement'),
173
- maxQuestions: z
174
- .number()
175
- .optional()
176
- .describe('Maximum number of questions to generate (default: 5)'),
177
- sessionId: z
178
- .string()
179
- .max(500)
180
- .optional()
181
- .describe('Existing clarification session to resume with user-confirmed answers.'),
182
- answers: z
183
- .record(z.string(), z.string())
184
- .optional()
185
- .describe('Explicit user-confirmed answers keyed by clarification question ID.'),
186
- },
187
- }, safeTracked('clarify_requirements', async (args) => handleClarifyRequirements(args, server)));
188
186
  // 5. create_spec
189
187
  server.registerTool('create_spec', {
190
188
  description: t('tools.create_spec.description'),
191
189
  inputSchema: {
192
- title: z.string().min(1).max(500).describe('Title of the spec / user story'),
190
+ title: z
191
+ .string()
192
+ .min(1)
193
+ .max(500)
194
+ .describe('Title of the spec / user story. Max 500 characters.'),
193
195
  description: z
194
196
  .string()
195
197
  .max(10_000)
@@ -203,21 +205,25 @@ export function registerCoreSpecTools(server) {
203
205
  .max(128)
204
206
  .regex(/^[A-Za-z0-9._:-]+$/)
205
207
  .optional()
206
- .describe('Stable caller key. Retries return the exact committed create_spec result.'),
208
+ .describe('Must match pattern ^[A-Za-z0-9._:-]+$, max 128 characters. Stable caller key retries return the exact committed create_spec result.'),
207
209
  projectPath: z
208
210
  .string()
209
211
  .max(4096)
210
212
  .optional()
211
- .describe('Absolute path to the project root. Auto-detected from git root when omitted.'),
213
+ .describe('Max 4096 characters. Absolute path to the project root. Auto-detected from git root when omitted.'),
212
214
  type: SpecTypeEnum.optional().describe('Spec type (default: feature)'),
213
215
  scope: SpecScopeEnum.optional().describe('Spec scope (default: feature)'),
214
216
  target: SpecTargetEnum.optional().describe('Target area: frontend, backend, shared, fullstack, infrastructure, database'),
215
- tags: z.array(z.string().max(500)).max(100).optional().describe('Tags for categorization'),
217
+ tags: z
218
+ .array(z.string().max(500))
219
+ .max(100)
220
+ .optional()
221
+ .describe('Tags for categorization. Each tag max 500 characters.'),
216
222
  feature: z
217
223
  .string()
218
224
  .max(500)
219
225
  .optional()
220
- .describe('Feature group tag (e.g. "Authentication", "Billing"). Added to tags for categorization. Flat structure — no subdirectories created.'),
226
+ .describe('Max 500 characters. Feature group tag (e.g. "Authentication", "Billing"). Added to tags for categorization. Flat structure — no subdirectories created.'),
221
227
  acFormat: SpecAcFormatEnum.optional().describe('SPEC-224: Format for acceptance criteria in spec.md. ' +
222
228
  'checkbox (default) — markdown checkboxes (- [ ] criterion). ' +
223
229
  'bdd — Gherkin Given-When-Then scenarios for BDD workflows.'),
@@ -269,12 +275,12 @@ export function registerCoreSpecTools(server) {
269
275
  .string()
270
276
  .max(500)
271
277
  .optional()
272
- .describe('Project ID (hash). Prefer projectPath if unknown.'),
278
+ .describe('Max 500 characters. Project ID (hash). Prefer projectPath if unknown.'),
273
279
  projectPath: z
274
280
  .string()
275
281
  .max(4096)
276
282
  .optional()
277
- .describe('Absolute path to the project root. Used to derive projectId automatically.'),
283
+ .describe('Max 4096 characters. Absolute path to the project root. Used to derive projectId automatically.'),
278
284
  status: SpecStatusEnum.optional().describe('Filter by spec status'),
279
285
  type: SpecTypeEnum.optional().describe('Filter by spec type'),
280
286
  detail: z
@@ -302,28 +308,28 @@ export function registerCoreSpecTools(server) {
302
308
  server.registerTool('update_status', {
303
309
  description: t('tools.update_status.description'),
304
310
  inputSchema: {
305
- specId: SpecIdSchema.describe('Spec ID to update'),
311
+ specId: SpecIdSchema.describe('Spec ID to update. Must match pattern ^SPEC-\\d+$ (e.g. SPEC-042), max 50 characters.'),
306
312
  projectId: z
307
313
  .string()
308
314
  .max(500)
309
315
  .optional()
310
- .describe('Project ID (hash). Prefer projectPath if unknown.'),
316
+ .describe('Project ID (hash). Prefer projectPath if unknown. Max 500 characters.'),
311
317
  projectPath: z
312
318
  .string()
313
319
  .max(4096)
314
320
  .optional()
315
- .describe('Absolute path to the project root. Used to derive projectId automatically.'),
321
+ .describe('Absolute path to the project root. Used to derive projectId automatically. Max 4096 characters.'),
316
322
  status: SpecStatusEnum.describe('New status'),
317
323
  sessionId: z
318
324
  .string()
319
325
  .max(500)
320
326
  .optional()
321
- .describe('Agent/session ID performing this lifecycle transition.'),
327
+ .describe('Agent/session ID performing this lifecycle transition. Max 500 characters.'),
322
328
  modelId: z
323
329
  .string()
324
330
  .max(500)
325
331
  .optional()
326
- .describe('Concrete model ID used for this transition. Can satisfy SDD model-routing evidence when it maps to the required tier.'),
332
+ .describe('Max 500 characters. Concrete model ID used for this transition. Can satisfy SDD model-routing evidence when it maps to the required tier.'),
327
333
  modelTierUsed: z
328
334
  .enum(['max', 'implementation', 'review'])
329
335
  .optional()
@@ -332,27 +338,27 @@ export function registerCoreSpecTools(server) {
332
338
  .string()
333
339
  .max(500)
334
340
  .optional()
335
- .describe('SHA-256 hash of the persisted context package used to prove context continuity across agents.'),
341
+ .describe('Max 500 characters. SHA-256 hash of the persisted context package used to prove context continuity across agents.'),
336
342
  handoffPath: z
337
343
  .string()
338
344
  .max(4096)
339
345
  .optional()
340
- .describe('Path to the persisted handoff package generated by package_handoff. Required for implementing/done unless handoffArtifactId is provided.'),
346
+ .describe('Max 4096 characters. Path to the persisted handoff package generated by package_handoff. Required for implementing/done unless handoffArtifactId is provided.'),
341
347
  handoffArtifactId: z
342
348
  .string()
343
349
  .max(500)
344
350
  .optional()
345
- .describe('External handoff artifact ID when the host stores handoff evidence outside the filesystem.'),
351
+ .describe('Max 500 characters. External handoff artifact ID when the host stores handoff evidence outside the filesystem.'),
346
352
  reviewedBy: z
347
353
  .string()
348
354
  .max(500)
349
355
  .optional()
350
- .describe('Reviewer identity/evidence required before status=done.'),
356
+ .describe('Reviewer identity/evidence required before status=done. Max 500 characters.'),
351
357
  arbitratedBy: z
352
358
  .string()
353
359
  .max(500)
354
360
  .optional()
355
- .describe('Arbiter identity/evidence required before status=done.'),
361
+ .describe('Arbiter identity/evidence required before status=done. Max 500 characters.'),
356
362
  reconcileRequired: z
357
363
  .boolean()
358
364
  .optional()
@@ -366,8 +372,16 @@ export function registerCoreSpecTools(server) {
366
372
  apiCostUsd: z.number().min(0).optional(),
367
373
  humanCostUsd: z.number().min(0).optional(),
368
374
  totalCostUsd: z.number().min(0).optional(),
369
- completedAt: z.string().max(500).optional(),
370
- notes: z.string().max(10_000).optional(),
375
+ completedAt: z
376
+ .string()
377
+ .max(500)
378
+ .optional()
379
+ .describe('ISO timestamp. Max 500 characters.'),
380
+ notes: z
381
+ .string()
382
+ .max(10_000)
383
+ .optional()
384
+ .describe('Free-text notes. Max 10000 characters.'),
371
385
  })
372
386
  .optional()
373
387
  .describe('Actual metrics for status = done. All fields optional (SPEC-1356): missing numeric fields default to 0, completedAt/notes are auto-filled when omitted.'),
@@ -375,7 +389,7 @@ export function registerCoreSpecTools(server) {
375
389
  .string()
376
390
  .max(10_000)
377
391
  .optional()
378
- .describe('Feedback or observations when sending a spec back (e.g., review→draft). Stored in the spec for the implementer to address.'),
392
+ .describe('Max 10000 characters. Feedback or observations when sending a spec back (e.g., review→draft). Stored in the spec for the implementer to address.'),
379
393
  force: z
380
394
  .boolean()
381
395
  .optional()
@@ -388,7 +402,7 @@ export function registerCoreSpecTools(server) {
388
402
  .string()
389
403
  .max(2000)
390
404
  .optional()
391
- .describe('SPEC-721: Required when forceStatus=true. ≥100 characters explaining why validate gate is bypassed.'),
405
+ .describe('SPEC-721: Required when forceStatus=true. ≥100 and <=2000 characters explaining why validate gate is bypassed.'),
392
406
  dry_run: z
393
407
  .boolean()
394
408
  .optional()
@@ -397,18 +411,24 @@ export function registerCoreSpecTools(server) {
397
411
  .string()
398
412
  .max(2000)
399
413
  .optional()
400
- .describe('SPEC-733: Required for reverse transitions (done→implementing, discarded→draft). Must be ≥30 chars explaining why the spec is being reopened.'),
414
+ .describe('Must be ≥30 and <=2000 chars. SPEC-733: Required for reverse transitions (done→implementing, discarded→draft), explaining why the spec is being reopened.'),
401
415
  reconciliationRequestId: z
402
416
  .string()
403
417
  .regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u)
404
418
  .optional()
405
- .describe('Trusted local MCP only: lowercase UUID idempotency key for implementing to review reconciliation.'),
406
- expectedImplementingTransitionId: z.string().max(500).optional(),
419
+ .describe('Must match pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$ (lowercase UUID). ' +
420
+ 'Trusted local MCP only: idempotency key for implementing to review reconciliation.'),
421
+ expectedImplementingTransitionId: z
422
+ .string()
423
+ .max(500)
424
+ .optional()
425
+ .describe('Max 500 characters. Idempotency guard: the transitionId returned by the prior implementing transition.'),
407
426
  implementationReviewDigest: z
408
427
  .string()
409
428
  .regex(/^sha256:[a-f0-9]{64}$/u)
410
429
  .optional()
411
- .describe('SHA-256 of the exact validation-report.json bytes. Required implementation evidence for status=done; for status=review it is valid only inside the complete trusted local-MCP reconciliation tuple.'),
430
+ .describe('Must match pattern ^sha256:[a-f0-9]{64}$ the literal prefix "sha256:" followed by 64 lowercase hex characters. ' +
431
+ 'SHA-256 of the exact validation-report.json bytes. Required implementation evidence for status=done; for status=review it is valid only inside the complete trusted local-MCP reconciliation tuple.'),
412
432
  forceApprove: z
413
433
  .boolean()
414
434
  .optional()
@@ -418,28 +438,53 @@ export function registerCoreSpecTools(server) {
418
438
  server.registerTool('update_status_batch', {
419
439
  description: 'Batch update many specs to the same status in one MCP execution. Uses the same transition rules as update_status and reports updated/skipped/failed per spec.',
420
440
  inputSchema: {
421
- specIds: z.array(SpecIdSchema).min(1).describe('Spec IDs to update'),
422
- projectId: z.string().max(500).optional().describe('Project ID, if known'),
441
+ specIds: z
442
+ .array(SpecIdSchema)
443
+ .min(1)
444
+ .describe('Spec IDs to update. Each must match pattern ^SPEC-\\d+$, max 50 characters.'),
445
+ projectId: z
446
+ .string()
447
+ .max(500)
448
+ .optional()
449
+ .describe('Project ID, if known. Max 500 characters.'),
423
450
  projectPath: z
424
451
  .string()
425
452
  .max(4096)
426
453
  .optional()
427
- .describe('Absolute project root. Preferred when projectId is unknown.'),
454
+ .describe('Absolute project root. Preferred when projectId is unknown. Max 4096 characters.'),
428
455
  status: SpecStatusEnum.exclude(['done']).describe('New status for all specs. Batch supports draft, review, approved, implementing, and discarded; close done specs individually with full evidence.'),
429
456
  dryRun: z.boolean().optional().describe('Preview the batch without mutating any spec.'),
430
457
  reviewNotes: z
431
458
  .string()
432
459
  .max(10_000)
433
460
  .optional()
434
- .describe('Optional notes for each transition.'),
461
+ .describe('Optional notes for each transition. Max 10000 characters.'),
462
+ evidence: z
463
+ .record(z.string(), z.object({
464
+ modelTierUsed: z
465
+ .enum(['max', 'implementation', 'review'])
466
+ .optional()
467
+ .describe('Model tier used for this spec.'),
468
+ modelId: z.string().optional().describe('Model ID used for this spec.'),
469
+ contextHash: z.string().optional().describe('Context hash for this spec.'),
470
+ handoffPath: z.string().optional().describe('Handoff artifact path for this spec.'),
471
+ handoffArtifactId: z
472
+ .string()
473
+ .optional()
474
+ .describe('Handoff artifact ID for this spec.'),
475
+ reviewedBy: z.string().optional().describe('Reviewer identity for this spec.'),
476
+ arbitratedBy: z.string().optional().describe('Arbitrator identity for this spec.'),
477
+ }))
478
+ .optional()
479
+ .describe('Per-spec model-routing evidence keyed by spec ID. Required for status approved or implementing: each entry supplies modelTierUsed, modelId, contextHash and handoffPath for that spec.'),
435
480
  },
436
481
  }, safeTracked('update_status_batch', async (args) => handleUpdateStatusBatch(args)));
437
482
  // 8. estimate
438
483
  server.registerTool('estimate', {
439
484
  description: t('tools.estimate.description'),
440
485
  inputSchema: {
441
- specId: SpecIdSchema.describe('Spec ID to estimate'),
442
- projectId: z.string().max(500).describe('Project ID'),
486
+ specId: SpecIdSchema.describe('Spec ID to estimate. Must match pattern ^SPEC-\\d+$ (e.g. SPEC-042), max 50 characters.'),
487
+ projectId: z.string().max(500).describe('Project ID. Max 500 characters.'),
443
488
  },
444
489
  outputSchema: EstimateOutputSchema,
445
490
  }, safeTracked('estimate', async (args) => handleEstimate(args)));
@@ -459,7 +504,7 @@ export function registerCoreSpecTools(server) {
459
504
  server.registerTool('validate', {
460
505
  description: t('tools.validate.description'),
461
506
  inputSchema: {
462
- specId: SpecIdSchema.describe('Spec ID to validate'),
507
+ specId: SpecIdSchema.describe('Spec ID to validate. Must match pattern ^SPEC-\\d+$ (e.g. SPEC-042), max 50 characters.'),
463
508
  mode: z
464
509
  .literal('submit')
465
510
  .default('submit')
@@ -468,12 +513,12 @@ export function registerCoreSpecTools(server) {
468
513
  .string()
469
514
  .max(500)
470
515
  .optional()
471
- .describe('Project ID hash. Prefer projectPath — stays correct after context compaction.'),
516
+ .describe('Project ID hash. Prefer projectPath — stays correct after context compaction. Max 500 characters.'),
472
517
  projectPath: z
473
518
  .string()
474
519
  .max(4096)
475
520
  .optional()
476
- .describe('Absolute path to project root. Derives projectId automatically — always correct even after context compaction.'),
521
+ .describe('Max 4096 characters. Absolute path to project root. Derives projectId automatically — always correct even after context compaction.'),
477
522
  },
478
523
  outputSchema: ValidateOutputSchema,
479
524
  annotations: {
@@ -16,7 +16,7 @@ export { TokenIntelligencePeriodEnum, TokenIntelligenceGroupByEnum, TokenIntelli
16
16
  export { ProjectGraphActionEnum, ProjectGraphQueryKindEnum } from './project-graph.js';
17
17
  export { ConfigureLLMProvidersActionEnum, LoadBalancingStrategyEnum, } from './llm-provider-schemas.js';
18
18
  export { PluginActionEnum } from './plugins-schemas.js';
19
- export { ListSpecsOutputSchema, EstimateOutputSchema, ValidateOutputSchema, CheckReadinessOutputSchema, } from './output-schemas.js';
19
+ export { ListSpecsOutputSchema, EstimateOutputSchema, ValidateOutputSchema, CheckReadinessOutputSchema, PackageHandoffOutputSchema, } from './output-schemas.js';
20
20
  export { CreatePRFromSpecSchema, PRStatusSchema, ReviewPRSchema, CreateReleaseSchema, GenerateChangelogSchema, } from './github.js';
21
21
  export { SkillSearchInputSchema, SkillInstallInputSchema } from './skill-registry-schemas.js';
22
22
  export { EcosystemStatusInputSchema } from './ecosystem-schemas.js';
@@ -17,7 +17,7 @@ export { TokenIntelligencePeriodEnum, TokenIntelligenceGroupByEnum, TokenIntelli
17
17
  export { ProjectGraphActionEnum, ProjectGraphQueryKindEnum } from './project-graph.js';
18
18
  export { ConfigureLLMProvidersActionEnum, LoadBalancingStrategyEnum, } from './llm-provider-schemas.js';
19
19
  export { PluginActionEnum } from './plugins-schemas.js';
20
- export { ListSpecsOutputSchema, EstimateOutputSchema, ValidateOutputSchema, CheckReadinessOutputSchema, } from './output-schemas.js';
20
+ export { ListSpecsOutputSchema, EstimateOutputSchema, ValidateOutputSchema, CheckReadinessOutputSchema, PackageHandoffOutputSchema, } from './output-schemas.js';
21
21
  export { CreatePRFromSpecSchema, PRStatusSchema, ReviewPRSchema, CreateReleaseSchema, GenerateChangelogSchema, } from './github.js';
22
22
  export { SkillSearchInputSchema, SkillInstallInputSchema } from './skill-registry-schemas.js';
23
23
  export { EcosystemStatusInputSchema } from './ecosystem-schemas.js';
@@ -33,16 +33,7 @@ export declare const ListSpecsOutputSchema: {
33
33
  totalReviewHours: z.ZodNumber;
34
34
  totalCostUsd: z.ZodNumber;
35
35
  }, z.core.$strip>;
36
- teamSuggestion: z.ZodNullable<z.ZodObject<{
37
- recommended: z.ZodBoolean;
38
- reason: z.ZodString;
39
- templateId: z.ZodString;
40
- teamSize: z.ZodNumber;
41
- specs: z.ZodArray<z.ZodString>;
42
- toolCalls: z.ZodArray<z.ZodString>;
43
- }, z.core.$strip>>;
44
36
  message: z.ZodString;
45
- teamDistributionHint: z.ZodOptional<z.ZodString>;
46
37
  humanSummary: z.ZodOptional<z.ZodString>;
47
38
  branchInfo: z.ZodOptional<z.ZodObject<{
48
39
  current: z.ZodString;
@@ -126,16 +117,7 @@ export declare const ListSpecsOutputObjectSchema: z.ZodObject<{
126
117
  totalReviewHours: z.ZodNumber;
127
118
  totalCostUsd: z.ZodNumber;
128
119
  }, z.core.$strip>;
129
- teamSuggestion: z.ZodNullable<z.ZodObject<{
130
- recommended: z.ZodBoolean;
131
- reason: z.ZodString;
132
- templateId: z.ZodString;
133
- teamSize: z.ZodNumber;
134
- specs: z.ZodArray<z.ZodString>;
135
- toolCalls: z.ZodArray<z.ZodString>;
136
- }, z.core.$strip>>;
137
120
  message: z.ZodString;
138
- teamDistributionHint: z.ZodOptional<z.ZodString>;
139
121
  humanSummary: z.ZodOptional<z.ZodString>;
140
122
  branchInfo: z.ZodOptional<z.ZodObject<{
141
123
  current: z.ZodString;
@@ -217,6 +199,7 @@ export declare const EstimateOutputSchema: {
217
199
  calibrationApplied: z.ZodOptional<z.ZodNullable<z.ZodString>>;
218
200
  };
219
201
  export { ValidateCompletionOutputSchema, ValidateOutputSchema } from './validate-output-schema.js';
202
+ export { PackageHandoffOutputSchema } from './package-handoff-output-schema.js';
220
203
  export declare const CheckReadinessOutputSchema: {
221
204
  specId: z.ZodString;
222
205
  score: z.ZodNumber;
@@ -39,18 +39,7 @@ export const ListSpecsOutputSchema = {
39
39
  totalReviewHours: z.number(),
40
40
  totalCostUsd: z.number(),
41
41
  }),
42
- teamSuggestion: z
43
- .object({
44
- recommended: z.boolean(),
45
- reason: z.string(),
46
- templateId: z.string(),
47
- teamSize: z.number(),
48
- specs: z.array(z.string()),
49
- toolCalls: z.array(z.string()),
50
- })
51
- .nullable(),
52
42
  message: z.string(),
53
- teamDistributionHint: z.string().optional(),
54
43
  humanSummary: z.string().optional(),
55
44
  branchInfo: z
56
45
  .object({
@@ -142,6 +131,7 @@ export const EstimateOutputSchema = {
142
131
  };
143
132
  // ── validate ────────────────────────────────────────────────────────────────
144
133
  export { ValidateCompletionOutputSchema, ValidateOutputSchema } from './validate-output-schema.js';
134
+ export { PackageHandoffOutputSchema } from './package-handoff-output-schema.js';
145
135
  // ── check_readiness ─────────────────────────────────────────────────────────
146
136
  export const CheckReadinessOutputSchema = {
147
137
  specId: z.string(),
@@ -0,0 +1,40 @@
1
+ import { z } from 'zod';
2
+ /** Exact public structured-output contract for the package_handoff MCP tool submission ack. */
3
+ export declare const PackageHandoffOutputSchema: {
4
+ schemaVersion: z.ZodLiteral<1>;
5
+ operationId: z.ZodString;
6
+ projectId: z.ZodString;
7
+ workspaceId: z.ZodString;
8
+ state: z.ZodEnum<{
9
+ accepted: "accepted";
10
+ cancelled: "cancelled";
11
+ checkpointed: "checkpointed";
12
+ completed: "completed";
13
+ "dead-letter": "dead-letter";
14
+ failed: "failed";
15
+ running: "running";
16
+ }>;
17
+ submittedAt: z.ZodISODateTime;
18
+ attachedAt: z.ZodISODateTime;
19
+ reused: z.ZodBoolean;
20
+ cursor: z.ZodString;
21
+ queue: z.ZodObject<{
22
+ status: z.ZodEnum<{
23
+ active: "active";
24
+ queued: "queued";
25
+ terminal: "terminal";
26
+ }>;
27
+ position: z.ZodNullable<z.ZodNumber>;
28
+ aheadCount: z.ZodNumber;
29
+ capacity: z.ZodNumber;
30
+ remainingBudgetMs: z.ZodNumber;
31
+ }, z.core.$strip>;
32
+ terminalStates: z.ZodTuple<[z.ZodLiteral<"completed">, z.ZodLiteral<"failed">, z.ZodLiteral<"cancelled">, z.ZodLiteral<"dead-letter">], null>;
33
+ resultSchema: z.ZodLiteral<"package-handoff-completion/v1">;
34
+ observation: z.ZodObject<{
35
+ get: z.ZodLiteral<"get_job">;
36
+ restart: z.ZodLiteral<"restart_job">;
37
+ }, z.core.$strip>;
38
+ recoveryAction: z.ZodOptional<z.ZodLiteral<"restart_job">>;
39
+ };
40
+ //# sourceMappingURL=package-handoff-output-schema.d.ts.map