@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
@@ -0,0 +1,68 @@
1
+ import { z } from 'zod';
2
+ /** Exact public structured-output contract for the package_handoff MCP tool submission ack. */
3
+ export const PackageHandoffOutputSchema = {
4
+ schemaVersion: z.literal(1).describe('Ack schema version.'),
5
+ operationId: z
6
+ .string()
7
+ .min(1)
8
+ .max(128)
9
+ .describe('Deterministic durable job id, form handoff-<sha256 hex>.'),
10
+ projectId: z.string().min(1).max(128).describe('Canonical project identity.'),
11
+ workspaceId: z.string().min(1).max(128).describe('Durable job workspace scope.'),
12
+ state: z
13
+ .enum([
14
+ 'accepted',
15
+ 'running',
16
+ 'checkpointed',
17
+ 'completed',
18
+ 'failed',
19
+ 'cancelled',
20
+ 'dead-letter',
21
+ ])
22
+ .describe('Current durable job state at submission or reuse time.'),
23
+ submittedAt: z.iso.datetime().describe('When this job was first accepted.'),
24
+ attachedAt: z.iso.datetime().describe('When this request attached to the job.'),
25
+ reused: z
26
+ .boolean()
27
+ .describe('True when this request attached to an existing job instead of inserting a new one.'),
28
+ cursor: z
29
+ .string()
30
+ .regex(/^[a-f0-9]{64}$/)
31
+ .describe('Content-derived observation cursor.'),
32
+ queue: z.object({
33
+ status: z.enum(['active', 'queued', 'terminal']).describe('Queue lifecycle bucket.'),
34
+ position: z
35
+ .number()
36
+ .int()
37
+ .positive()
38
+ .nullable()
39
+ .describe('1-based queue position, null once terminal.'),
40
+ aheadCount: z
41
+ .number()
42
+ .int()
43
+ .nonnegative()
44
+ .describe('Jobs ahead of this one in the same scope.'),
45
+ capacity: z.number().int().positive().describe('Worker concurrency capacity for this scope.'),
46
+ remainingBudgetMs: z.number().int().nonnegative().describe('Remaining execution budget in ms.'),
47
+ }),
48
+ terminalStates: z
49
+ .tuple([
50
+ z.literal('completed'),
51
+ z.literal('failed'),
52
+ z.literal('cancelled'),
53
+ z.literal('dead-letter'),
54
+ ])
55
+ .describe('The states get_job should treat as terminal.'),
56
+ resultSchema: z
57
+ .literal('package-handoff-completion/v1')
58
+ .describe('Result payload schema id once completed.'),
59
+ observation: z.object({
60
+ get: z.literal('get_job').describe('Tool to poll for job progress and result.'),
61
+ restart: z.literal('restart_job').describe('Tool to reactivate a terminal-failed job.'),
62
+ }),
63
+ recoveryAction: z
64
+ .literal('restart_job')
65
+ .optional()
66
+ .describe('Present when the reused job ended terminal-failed/cancelled/dead-letter and needs restart_job.'),
67
+ };
68
+ //# sourceMappingURL=package-handoff-output-schema.js.map
@@ -252,6 +252,7 @@ export declare const ValidateOutputSchema: {
252
252
  }>;
253
253
  submittedAt: z.ZodISODateTime;
254
254
  attachedAt: z.ZodISODateTime;
255
+ reused: z.ZodBoolean;
255
256
  cursor: z.ZodString;
256
257
  queue: z.ZodObject<{
257
258
  status: z.ZodEnum<{
@@ -268,8 +269,6 @@ export declare const ValidateOutputSchema: {
268
269
  resultSchema: z.ZodLiteral<"validate-completion/v1">;
269
270
  observation: z.ZodObject<{
270
271
  get: z.ZodLiteral<"get_job">;
271
- watch: z.ZodLiteral<"watch_job">;
272
- cancel: z.ZodLiteral<"cancel_job">;
273
272
  restart: z.ZodLiteral<"restart_job">;
274
273
  }, z.core.$strip>;
275
274
  };
@@ -197,6 +197,9 @@ export const ValidateOutputSchema = {
197
197
  state: z.enum(['accepted', 'running', 'checkpointed']),
198
198
  submittedAt: z.iso.datetime(),
199
199
  attachedAt: z.iso.datetime(),
200
+ reused: z
201
+ .boolean()
202
+ .describe('True when this request attached to an already-running validation job instead of dispatching new work.'),
200
203
  cursor: z.string().regex(/^[a-f0-9]{64}$/),
201
204
  queue: z.object({
202
205
  status: z.enum(['active', 'queued', 'terminal']),
@@ -214,8 +217,6 @@ export const ValidateOutputSchema = {
214
217
  resultSchema: z.literal('validate-completion/v1'),
215
218
  observation: z.object({
216
219
  get: z.literal('get_job'),
217
- watch: z.literal('watch_job'),
218
- cancel: z.literal('cancel_job'),
219
220
  restart: z.literal('restart_job'),
220
221
  }),
221
222
  };
@@ -1,5 +1,5 @@
1
1
  // tools/session-checkpoint.ts — Manual trigger for session checkpoint (SPEC-563).
2
- import { sessionTracker } from '../engine/session/session-tracker.js';
2
+ import { getSessionTracker } from '../engine/session/session-tracker.js';
3
3
  import { writeCheckpoint } from '../engine/session/checkpoint-writer.js';
4
4
  import { compactResult } from './output-formatter.js';
5
5
  /**
@@ -7,7 +7,7 @@ import { compactResult } from './output-formatter.js';
7
7
  * Writes a checkpoint immediately regardless of the call-count threshold.
8
8
  */
9
9
  export async function handleSessionCheckpoint(args) {
10
- const snapshot = sessionTracker.getSnapshot();
10
+ const snapshot = getSessionTracker(args.projectPath).getSnapshot();
11
11
  await writeCheckpoint(args.projectPath, snapshot);
12
12
  return compactResult(`Session checkpoint written to ${args.projectPath}/planu/.runtime/session-context.md\n` +
13
13
  `Calls recorded: ${String(snapshot.callCount)}, ` +
@@ -1,3 +1,2 @@
1
- export { handleSkillSearch } from './search.js';
2
1
  export { handleSkillInstall } from './install.js';
3
2
  //# sourceMappingURL=index.d.ts.map
@@ -1,4 +1,3 @@
1
1
  // tools/skill-registry/index.ts — Barrel for skill registry tool handlers (SPEC-150)
2
- export { handleSkillSearch } from './search.js';
3
2
  export { handleSkillInstall } from './install.js';
4
3
  //# sourceMappingURL=index.js.map
@@ -1,10 +1,10 @@
1
1
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
- import type { SyncReport } from '../types/index.js';
2
+ import type { SyncReport, SyncSpecStateOptions } from '../types/index.js';
3
3
  /**
4
4
  * Sync spec state for a single project.
5
5
  * Reads YAML frontmatter from spec.md files and reconciles divergences into the store.
6
6
  */
7
- export declare function syncSpecState(projectPath: string, projectId: string): Promise<SyncReport>;
7
+ export declare function syncSpecState(projectPath: string, projectId: string, options?: SyncSpecStateOptions): Promise<SyncReport>;
8
8
  /**
9
9
  * Startup sync: iterates all registered projects and calls syncSpecState for each.
10
10
  * Non-blocking — errors are logged but not propagated.
@@ -20,7 +20,8 @@ import { readFile, stat } from 'node:fs/promises';
20
20
  * Sync spec state for a single project.
21
21
  * Reads YAML frontmatter from spec.md files and reconciles divergences into the store.
22
22
  */
23
- export async function syncSpecState(projectPath, projectId) {
23
+ export async function syncSpecState(projectPath, projectId, options = {}) {
24
+ const { applyTransitions = true } = options;
24
25
  let dataEntries;
25
26
  try {
26
27
  const specs = await listSpecs(projectId);
@@ -109,6 +110,14 @@ export async function syncSpecState(projectPath, projectId) {
109
110
  report.synced += 1;
110
111
  continue;
111
112
  }
113
+ if (!applyTransitions) {
114
+ report.rejected.push({ specId, reason: refusalReason });
115
+ const idx = report.divergences.findIndex((d) => d.specId === specId);
116
+ if (idx !== -1) {
117
+ report.divergences.splice(idx, 1);
118
+ }
119
+ continue;
120
+ }
112
121
  try {
113
122
  const result = await handleUpdateStatus({
114
123
  specId,
@@ -205,13 +214,24 @@ export async function startupSync() {
205
214
  }
206
215
  await Promise.all(projects.map(async (project) => {
207
216
  try {
208
- await syncSpecState(project.path, project.hash);
217
+ const report = await syncSpecState(project.path, project.hash, {
218
+ applyTransitions: false,
219
+ });
220
+ if (report.rejected.length > 0) {
221
+ console.error(`[Planu] startupSync: ${project.path} has ${report.rejected.length} spec status divergence(s) reported read-only:`, report.rejected);
222
+ }
209
223
  }
210
224
  catch (err) {
211
225
  console.error(`[Planu] startupSync: failed to sync project ${project.path}:`, err);
212
226
  }
213
227
  try {
214
- await cleanEphemeralArtifacts({ projectPath: project.path, dryRun: false });
228
+ const cleanupResult = await cleanEphemeralArtifacts({
229
+ projectPath: project.path,
230
+ dryRun: true,
231
+ });
232
+ if (cleanupResult.wouldDelete.length > 0) {
233
+ console.error(`[Planu] startupSync: ${project.path} has ${cleanupResult.wouldDelete.length} ephemeral artifact(s) that would be deleted (run housekeeping-sweep to apply):`, cleanupResult.wouldDelete);
234
+ }
215
235
  }
216
236
  catch (err) {
217
237
  console.error(`[Planu] startupSync: failed to clean spec artifacts ${project.path}:`, err);
@@ -38,21 +38,25 @@ import { handleIdeConfig } from '../ide-config-handler.js';
38
38
  import { IdeTargetEnum, IdeConfigScopeEnum } from '../schemas/ide-config.js';
39
39
  import { handleReconcileSpecLiving } from '../reconcile-spec-living-handler.js';
40
40
  import { handleSecurityReport } from '../security-report-handler.js';
41
- import { handleFeedbackStatus, handleResolveFeedback, handleSubmitFeedback, handleSyncFeedback, handleTriageFeedback, } from '../feedback-handler.js';
42
41
  import { handleDogfoodWatch } from '../dogfood-watch.js';
43
42
  import { SecurityReportTimeRangeEnum, SecurityReportFormatEnum, } from '../schemas/runtime-security.js';
44
43
  import { RenderSpecForProviderInputSchema, handleRenderSpecForProvider, } from '../render-spec-for-provider.js';
45
44
  import { handleTriageRequest, TriageRequestInputSchema } from '../triage-request.js';
46
45
  import { handleStoragePaths } from '../storage-paths-handler.js';
47
46
  import { handleStorageExport, handleStorageImport } from '../storage-bundle-handler.js';
48
- import { handleCancelJob, handleGetJob, handleRestartJob, handleWatchJob, } from '../jobs/handlers.js';
47
+ import { handleGetJob, handleRestartJob } from '../jobs/handlers.js';
49
48
  // ── Registry ─────────────────────────────────────────────────────────────────
50
49
  const coreToolsRegistry = [
51
50
  {
52
51
  name: 'session_checkpoint',
53
52
  description: 'Persist a compact, bounded session checkpoint to planu/session-context.md for the next session.',
54
53
  schema: {
55
- projectPath: z.string().trim().min(1).max(4096),
54
+ projectPath: z
55
+ .string()
56
+ .trim()
57
+ .min(1)
58
+ .max(4096)
59
+ .describe('Absolute path to the project root. Max 4096 characters.'),
56
60
  },
57
61
  handler: handleSessionCheckpoint,
58
62
  annotations: {
@@ -67,9 +71,20 @@ const coreToolsRegistry = [
67
71
  name: 'get_job',
68
72
  description: 'Read the durable state and latest checkpoint or result for a local Planu job.',
69
73
  schema: {
70
- operationId: z.string().trim().min(1).max(128),
71
- projectId: z.string().trim().min(1).max(128),
72
- workspaceId: z.string().trim().min(1).max(128).optional(),
74
+ operationId: z
75
+ .string()
76
+ .trim()
77
+ .min(1)
78
+ .max(128)
79
+ .describe('Job operation ID. Max 128 characters.'),
80
+ projectId: z.string().trim().min(1).max(128).describe('Project ID hash. Max 128 characters.'),
81
+ workspaceId: z
82
+ .string()
83
+ .trim()
84
+ .min(1)
85
+ .max(128)
86
+ .optional()
87
+ .describe('Workspace ID. Max 128 characters.'),
73
88
  },
74
89
  handler: handleGetJob,
75
90
  annotations: {
@@ -81,55 +96,24 @@ const coreToolsRegistry = [
81
96
  wrap: 'safe',
82
97
  group: 'infrastructure',
83
98
  },
84
- {
85
- name: 'watch_job',
86
- description: 'Wait up to 30 seconds for a durable Planu job to change or reach a terminal state.',
87
- schema: {
88
- operationId: z.string().trim().min(1).max(128),
89
- projectId: z.string().trim().min(1).max(128),
90
- workspaceId: z.string().trim().min(1).max(128).optional(),
91
- afterCursor: z
92
- .string()
93
- .regex(/^[a-f0-9]{64}$/)
94
- .optional(),
95
- timeoutMs: z.number().int().min(0).max(30_000).optional(),
96
- },
97
- handler: handleWatchJob,
98
- annotations: {
99
- title: 'Watch Durable Job',
100
- readOnlyHint: true,
101
- destructiveHint: false,
102
- openWorldHint: false,
103
- },
104
- wrap: 'safe',
105
- group: 'infrastructure',
106
- },
107
- {
108
- name: 'cancel_job',
109
- description: 'Durably cancel a Planu job and fence any worker that still holds its former lease.',
110
- schema: {
111
- operationId: z.string().trim().min(1).max(128),
112
- projectId: z.string().trim().min(1).max(128),
113
- workspaceId: z.string().trim().min(1).max(128).optional(),
114
- },
115
- handler: handleCancelJob,
116
- annotations: {
117
- title: 'Cancel Durable Job',
118
- readOnlyHint: false,
119
- destructiveHint: true,
120
- idempotentHint: true,
121
- openWorldHint: false,
122
- },
123
- wrap: 'safe',
124
- group: 'infrastructure',
125
- },
126
99
  {
127
100
  name: 'restart_job',
128
101
  description: 'Restart a cancelled or failed durable job and schedule its typed executor.',
129
102
  schema: {
130
- operationId: z.string().trim().min(1).max(128),
131
- projectId: z.string().trim().min(1).max(128),
132
- workspaceId: z.string().trim().min(1).max(128).optional(),
103
+ operationId: z
104
+ .string()
105
+ .trim()
106
+ .min(1)
107
+ .max(128)
108
+ .describe('Job operation ID. Max 128 characters.'),
109
+ projectId: z.string().trim().min(1).max(128).describe('Project ID hash. Max 128 characters.'),
110
+ workspaceId: z
111
+ .string()
112
+ .trim()
113
+ .min(1)
114
+ .max(128)
115
+ .optional()
116
+ .describe('Workspace ID. Max 128 characters.'),
133
117
  },
134
118
  handler: handleRestartJob,
135
119
  annotations: {
@@ -300,12 +284,16 @@ const coreToolsRegistry = [
300
284
  name: 'planu_status',
301
285
  description: 'Get a compact world-snapshot of the current Planu project state in one call: active spec (in-progress), next recommended spec (highest-priority approved), queue count, git state (staged/modified files), and an actionable suggestion. Designed to return the full picture in ≤150 tokens.',
302
286
  schema: {
303
- projectPath: z.string().min(1).max(4096).describe('Absolute path to project root'),
287
+ projectPath: z
288
+ .string()
289
+ .min(1)
290
+ .max(4096)
291
+ .describe('Max 4096 characters. Absolute path to project root.'),
304
292
  projectId: z
305
293
  .string()
306
294
  .max(500)
307
295
  .optional()
308
- .describe('Project ID (optional — derived from projectPath if omitted)'),
296
+ .describe('Max 500 characters. Project ID (optional — derived from projectPath if omitted).'),
309
297
  },
310
298
  handler: async (args) => handlePlanStatus(args),
311
299
  annotations: { readOnlyHint: true },
@@ -587,17 +575,17 @@ const coreToolsRegistry = [
587
575
  description: z
588
576
  .string()
589
577
  .max(10_000)
590
- .describe('Free-form description: what you want to build, your problem, or your request'),
578
+ .describe('Max 10000 characters. Free-form description: what you want to build, your problem, or your request.'),
591
579
  projectId: z
592
580
  .string()
593
581
  .max(500)
594
582
  .optional()
595
- .describe('Project ID or project path (used for context loading and focus persistence)'),
583
+ .describe('Max 500 characters. Project ID or project path (used for context loading and focus persistence).'),
596
584
  sessionId: z
597
585
  .string()
598
586
  .max(500)
599
587
  .optional()
600
- .describe('Session ID (overrides projectId for focus tracking)'),
588
+ .describe('Max 500 characters. Session ID (overrides projectId for focus tracking).'),
601
589
  scenario: z
602
590
  .enum(['new_project', 'existing_project', 'concrete_problem'])
603
591
  .optional()
@@ -610,28 +598,44 @@ const coreToolsRegistry = [
610
598
  .string()
611
599
  .max(4096)
612
600
  .optional()
613
- .describe('Parent workspace path that should contain a new project folder'),
614
- appName: z.string().max(500).optional().describe('Human-readable new app name'),
601
+ .describe('Max 4096 characters. Parent workspace path that should contain a new project folder.'),
602
+ appName: z
603
+ .string()
604
+ .max(500)
605
+ .optional()
606
+ .describe('Max 500 characters. Human-readable new app name.'),
615
607
  appSlug: z
616
608
  .string()
617
609
  .max(200)
618
610
  .optional()
619
- .describe('Safe folder name for the new app; must not contain path separators'),
620
- projectType: z.string().max(500).optional().describe('Kind of project to create'),
621
- platform: z.string().max(500).optional().describe('Runtime or deployment platform'),
622
- language: z.string().max(500).optional().describe('User-confirmed programming language'),
611
+ .describe('Max 200 characters. Safe folder name for the new app; must not contain path separators.'),
612
+ projectType: z
613
+ .string()
614
+ .max(500)
615
+ .optional()
616
+ .describe('Max 500 characters. Kind of project to create.'),
617
+ platform: z
618
+ .string()
619
+ .max(500)
620
+ .optional()
621
+ .describe('Max 500 characters. Runtime or deployment platform.'),
622
+ language: z
623
+ .string()
624
+ .max(500)
625
+ .optional()
626
+ .describe('Max 500 characters. User-confirmed programming language.'),
623
627
  framework: z
624
628
  .string()
625
629
  .max(500)
626
630
  .nullable()
627
631
  .optional()
628
- .describe('User-confirmed framework, null for no framework'),
632
+ .describe('Max 500 characters. User-confirmed framework, null for no framework.'),
629
633
  database: z
630
634
  .string()
631
635
  .max(500)
632
636
  .nullable()
633
637
  .optional()
634
- .describe('User-confirmed database, null for no database'),
638
+ .describe('Max 500 characters. User-confirmed database, null for no database.'),
635
639
  createDirectory: z
636
640
  .boolean()
637
641
  .optional()
@@ -646,12 +650,12 @@ const coreToolsRegistry = [
646
650
  .min(0)
647
651
  .max(10)
648
652
  .optional()
649
- .describe('Current step index for new_project flow (0–2)'),
653
+ .describe('Maximum 10. Current step index for new_project flow (0–2).'),
650
654
  targetTool: z
651
655
  .string()
652
656
  .max(500)
653
657
  .optional()
654
- .describe('Planu tool name to check ambiguity for before calling it'),
658
+ .describe('Max 500 characters. Planu tool name to check ambiguity for before calling it.'),
655
659
  checkFocus: z
656
660
  .boolean()
657
661
  .optional()
@@ -660,12 +664,12 @@ const coreToolsRegistry = [
660
664
  .string()
661
665
  .max(10_000)
662
666
  .optional()
663
- .describe('Explicitly declare a new session objective'),
667
+ .describe('Max 10000 characters. Explicitly declare a new session objective.'),
664
668
  planContent: z
665
669
  .string()
666
670
  .max(10_000)
667
671
  .optional()
668
- .describe('Plan Mode output to convert into a spec. Paste the plan markdown here to extract ACs and route to create_spec.'),
672
+ .describe('Max 10000 characters. Plan Mode output to convert into a spec. Paste the plan markdown here to extract ACs and route to create_spec.'),
669
673
  },
670
674
  handler: (args) => handleFacilitate(args),
671
675
  annotations: { readOnlyHint: false },
@@ -899,102 +903,6 @@ const coreToolsRegistry = [
899
903
  wrap: 'tracked',
900
904
  group: 'core',
901
905
  },
902
- // ── feedback hub (SPEC-188, SPEC-1100) ───────────────────────────────────
903
- {
904
- name: 'submit_feedback',
905
- description: 'Submit user feedback or a bug report to Planu Feedback Hub. Always persists locally first, then attempts privacy-bounded remote registration with the central feedback intake.',
906
- schema: {
907
- type: z
908
- .enum(['bug', 'feature', 'suggestion', 'dx'])
909
- .describe('Feedback type: bug | feature | suggestion | dx'),
910
- title: z.string().min(1).max(200).describe('Short feedback title'),
911
- description: z.string().min(1).max(5000).describe('Detailed feedback description'),
912
- context: z
913
- .object({
914
- projectPath: z.string().max(4096).optional(),
915
- currentFile: z.string().max(4096).optional(),
916
- errorMessage: z.string().max(2000).optional(),
917
- stack: z.string().max(8000).optional(),
918
- })
919
- .optional()
920
- .describe('Optional local-only context; sensitive path fields are not sent remotely.'),
921
- },
922
- handler: async (args) => handleSubmitFeedback(args),
923
- annotations: {
924
- title: 'Submit Feedback',
925
- readOnlyHint: false,
926
- destructiveHint: false,
927
- openWorldHint: true,
928
- },
929
- wrap: 'tracked',
930
- group: 'feedback',
931
- },
932
- {
933
- name: 'triage_feedback',
934
- description: 'Group pending local feedback by similarity so maintainers can decide whether to create specs, merge duplicates, or dismiss items.',
935
- schema: {
936
- filter: z
937
- .enum(['bug', 'feature', 'suggestion', 'dx'])
938
- .optional()
939
- .describe('Optional feedback type filter'),
940
- },
941
- handler: async (args) => Promise.resolve(handleTriageFeedback(args)),
942
- annotations: { title: 'Triage Feedback', readOnlyHint: true },
943
- wrap: 'tracked',
944
- group: 'feedback',
945
- },
946
- {
947
- name: 'resolve_feedback',
948
- description: 'Mark a local feedback item as resolved and optionally link it to a Planu spec, PR URL, and resolution notes.',
949
- schema: {
950
- feedbackId: z.string().min(1).max(50).describe('Local feedback ID, e.g. FB-001'),
951
- specId: z.string().max(50).optional().describe('Optional linked Planu spec ID'),
952
- prUrl: z.url().optional().describe('Optional pull request URL'),
953
- notes: z.string().max(2000).optional().describe('Optional resolution notes'),
954
- },
955
- handler: async (args) => handleResolveFeedback(args),
956
- annotations: { title: 'Resolve Feedback', readOnlyHint: false, destructiveHint: false },
957
- wrap: 'tracked',
958
- group: 'feedback',
959
- },
960
- {
961
- name: 'sync_feedback',
962
- description: 'Retry remote Supabase registration for local feedback entries whose delivery is pending or failed. Does not accept remote row IDs or perform direct SQL/Data API writes.',
963
- schema: {
964
- projectPath: z.string().max(4096).optional().describe('Absolute path to project root'),
965
- includeSynced: z
966
- .boolean()
967
- .optional()
968
- .describe('When true, also reprocess entries already marked synced. Default false.'),
969
- limit: z
970
- .number()
971
- .int()
972
- .positive()
973
- .max(500)
974
- .optional()
975
- .describe('Maximum number of local entries to process.'),
976
- },
977
- handler: async (args) => handleSyncFeedback(args),
978
- annotations: {
979
- title: 'Sync Feedback',
980
- readOnlyHint: false,
981
- destructiveHint: false,
982
- openWorldHint: true,
983
- },
984
- wrap: 'tracked',
985
- group: 'feedback',
986
- },
987
- {
988
- name: 'feedback_status',
989
- description: 'Show aggregate local feedback totals and remote delivery health without exposing descriptions, file paths, user identifiers, or secrets.',
990
- schema: {
991
- projectPath: z.string().max(4096).optional().describe('Absolute path to project root'),
992
- },
993
- handler: async (args) => Promise.resolve(handleFeedbackStatus(args)),
994
- annotations: { title: 'Feedback Status', readOnlyHint: true },
995
- wrap: 'tracked',
996
- group: 'feedback',
997
- },
998
906
  {
999
907
  name: 'dogfood_watch',
1000
908
  description: 'Analyze recent local Planu runtime evidence and surface actionable dogfooding gaps such as repeated tool failures, persisted version drift, guard fallback leakage, and stale local compatibility mirrors.',
@@ -41,8 +41,8 @@ import { handleCheckSpecAccuracy } from '../check-spec-accuracy.js';
41
41
  import { handleUpdateRegistry } from '../update-registry.js';
42
42
  import { CheckSpecAccuracySchema, UpdateRegistrySchema } from '../schemas/registry.js';
43
43
  // ── Skill registry tools (register-skill-registry-tools.ts) ─────────────────
44
- import { SkillSearchInputSchema, SkillInstallInputSchema, } from '../schemas/skill-registry-schemas.js';
45
- import { handleSkillSearch, handleSkillInstall } from '../skill-registry/index.js';
44
+ import { SkillInstallInputSchema } from '../schemas/skill-registry-schemas.js';
45
+ import { handleSkillInstall } from '../skill-registry/index.js';
46
46
  // ── Well-known registry tools (register-well-known-tools.ts) ─────────────────
47
47
  import { handlePublishRegistry } from '../publish-registry.js';
48
48
  import { handleDiscoverRegistry } from '../discover-registry.js';
@@ -61,7 +61,6 @@ import { handleGenerateDocsSite } from '../generate-docs-site.js';
61
61
  // ── Memory config tools (register-memory-config-tools.ts) ────────────────────
62
62
  import { handleConfigureMemory, handleMemoryStatus } from '../memory-config-handler.js';
63
63
  // ── Code graph tools (SPEC-376 / SPEC-1060) ─────────────────────────────────
64
- import { handleConfigureCodeGraph, handleCodeGraphStatus } from '../code-graph-handler.js';
65
64
  // ── Onboarding tools (register-onboarding-tools.ts) ──────────────────────────
66
65
  import { handleStartOnboarding, handleGuidedTour, handleOnboardingChecklist, handleQuickStart, handleOnboardingProgress, } from '../onboarding-handler.js';
67
66
  // ── Docs registry tools (register-docs-registry-tools.ts) ────────────────────
@@ -562,18 +561,6 @@ export function registerInfraGroupTools(server) {
562
561
  annotations: { title: 'Update Framework Registry', destructiveHint: false },
563
562
  }, safeTracked('update_registry', async (args) => handleUpdateRegistry(args)));
564
563
  // ── Skill registry tools ───────────────────────────────────────────────────
565
- server.registerTool('skill_search', {
566
- description: 'Search for installable Claude skills across multiple registries (Anthropic, AgentSkill.sh, Skills.sh). ' +
567
- 'Filter by technology stack, restrict to a specific registry, or search all at once. ' +
568
- 'Returns ranked results with install commands ready to use.',
569
- inputSchema: {
570
- query: SkillSearchInputSchema.shape.query,
571
- registry: SkillSearchInputSchema.shape.registry,
572
- stack: SkillSearchInputSchema.shape.stack,
573
- limit: SkillSearchInputSchema.shape.limit,
574
- },
575
- annotations: { title: 'Skill Search', readOnlyHint: true },
576
- }, safeTracked('skill_search', async (args) => handleSkillSearch(args)));
577
564
  server.registerTool('skill_install', {
578
565
  description: "Install a skill from a registry into a project's .claude/skills/ directory. " +
579
566
  'Detects the source registry from the skill name prefix if not specified. ' +
@@ -780,30 +767,6 @@ export function registerInfraGroupTools(server) {
780
767
  projectPath: z.string().describe('Absolute path to the project root directory'),
781
768
  },
782
769
  }, safeGoverned('memory_status', async (args) => handleMemoryStatus(args)));
783
- // ── Code graph tools ──────────────────────────────────────────────────────
784
- server.registerTool('configure_code_graph', {
785
- description: 'Configure a local code graph MCP provider for the project. Supports Colby CodeGraph, CodeGraphContext, Pathfinder, and Axon. Writes the provider entry to .claude.json.',
786
- annotations: { title: 'Configure Code Graph', readOnlyHint: false },
787
- inputSchema: {
788
- projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root'),
789
- action: z
790
- .enum([
791
- 'setup-colby-codegraph',
792
- 'setup-codegraph-context',
793
- 'setup-pathfinder',
794
- 'setup-axon',
795
- 'status',
796
- ])
797
- .describe('setup-colby-codegraph: configure @colbymchenry/codegraph | setup-codegraph-context: configure CodeGraphContext | setup-pathfinder: configure Pathfinder | setup-axon: configure Axon | status: show current provider status'),
798
- },
799
- }, safeGoverned('configure_code_graph', async (args) => handleConfigureCodeGraph(args)));
800
- server.registerTool('code_graph_status', {
801
- description: 'Returns the current code graph MCP provider status from .claude.json, including the active provider if one is configured.',
802
- annotations: { title: 'Code Graph Status', readOnlyHint: true },
803
- inputSchema: {
804
- projectPath: z.string().min(1).max(4096).describe('Absolute path to the project root'),
805
- },
806
- }, safeGoverned('code_graph_status', async (args) => handleCodeGraphStatus(args)));
807
770
  // ── Onboarding tools ───────────────────────────────────────────────────────
808
771
  server.registerTool('start_onboarding', {
809
772
  description: 'Start interactive onboarding for a new project. Generates personalized recommendations based on your role, project type, and team size. Returns a markdown guide with next steps.',