@planu/cli 5.7.4 → 5.7.6

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 (208) hide show
  1. package/CHANGELOG.md +85 -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-session-safeguard.sh +22 -15
  8. package/dist/config/official-sdd-tools.d.ts +1 -1
  9. package/dist/config/official-sdd-tools.js +11 -24
  10. package/dist/config/registries/hosts/codex.json +14 -30
  11. package/dist/config/registries/hosts/opencode.json +1 -6
  12. package/dist/config/registries/legacy-guidance.json +26 -0
  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 +1 -1
  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/lifecycle-gate.js +7 -4
  38. package/dist/engine/evidence-index/index-builder.js +21 -4
  39. package/dist/engine/execution/job-runtime.js +1 -1
  40. package/dist/engine/execution/package-handoff-job-executor.d.ts +22 -0
  41. package/dist/engine/execution/package-handoff-job-executor.js +490 -0
  42. package/dist/engine/execution/validate-job-executor.js +20 -8
  43. package/dist/engine/git/exec-git.d.ts +4 -0
  44. package/dist/engine/git/exec-git.js +14 -0
  45. package/dist/engine/handoff-artifacts/implementation-review-reader.js +15 -2
  46. package/dist/engine/handoff-artifacts/schemas.d.ts +2 -0
  47. package/dist/engine/handoff-artifacts/schemas.js +1 -0
  48. package/dist/engine/handoff-format.d.ts +36 -0
  49. package/dist/engine/handoff-format.js +314 -0
  50. package/dist/engine/handoff-packager.d.ts +5 -3
  51. package/dist/engine/handoff-packager.js +89 -32
  52. package/dist/engine/host-tool-filter.js +20 -49
  53. package/dist/engine/human-summary.js +14 -3
  54. package/dist/engine/implementation-contract/common.d.ts +8 -3
  55. package/dist/engine/implementation-contract/common.js +9 -6
  56. package/dist/engine/implementation-contract/evaluator.js +4 -6
  57. package/dist/engine/implementation-contract/renderer.js +18 -23
  58. package/dist/engine/project-health-checker.js +2 -2
  59. package/dist/engine/readiness-checker.js +27 -0
  60. package/dist/engine/reconcile/apply-changes.js +4 -0
  61. package/dist/engine/reconcile/propagate-mirrors.d.ts +3 -0
  62. package/dist/engine/reconcile/propagate-mirrors.js +311 -0
  63. package/dist/engine/self-healing/healer.js +12 -5
  64. package/dist/engine/self-healing/strategies/lint-fix.d.ts +1 -1
  65. package/dist/engine/self-healing/strategies/lint-fix.js +4 -1
  66. package/dist/engine/self-healing/strategies/test-fix.d.ts +4 -3
  67. package/dist/engine/self-healing/strategies/test-fix.js +32 -14
  68. package/dist/engine/self-healing/strategies/typescript-fix.d.ts +1 -1
  69. package/dist/engine/self-healing/strategies/typescript-fix.js +28 -10
  70. package/dist/engine/session/checkpoint-writer.js +8 -4
  71. package/dist/engine/session/session-tracker.d.ts +5 -16
  72. package/dist/engine/session/session-tracker.js +29 -26
  73. package/dist/engine/session-state/writer.js +3 -11
  74. package/dist/engine/skill-generator/workflow-skill-generator.d.ts +4 -2
  75. package/dist/engine/skill-generator/workflow-skill-generator.js +113 -38
  76. package/dist/engine/spec-format/bdd-parser.d.ts +1 -11
  77. package/dist/engine/spec-format/bdd-parser.js +40 -11
  78. package/dist/engine/spec-format/lean-spec-generator.js +30 -10
  79. package/dist/engine/spec-format/retired-scaffold.d.ts +3 -0
  80. package/dist/engine/spec-format/retired-scaffold.js +5 -0
  81. package/dist/engine/spec-format/technical-md-populator.d.ts +1 -0
  82. package/dist/engine/spec-format/technical-md-populator.js +27 -0
  83. package/dist/engine/spec-format/unified-spec-builder.d.ts +1 -0
  84. package/dist/engine/spec-format/unified-spec-builder.js +30 -20
  85. package/dist/engine/spec-grounding/contract.js +115 -1
  86. package/dist/engine/spec-migrator/fold-technical.js +60 -19
  87. package/dist/engine/spec-migrator/placeholder-technical.d.ts +2 -0
  88. package/dist/engine/spec-migrator/placeholder-technical.js +18 -0
  89. package/dist/engine/spec-quality/generic-output-gate.js +37 -3
  90. package/dist/engine/technical-enricher/index.js +4 -1
  91. package/dist/engine/type-safety-gate.js +3 -11
  92. package/dist/engine/universal-rules/catalog.js +0 -2
  93. package/dist/engine/universal-rules/rules/planu-workflow.js +1 -1
  94. package/dist/engine/validation/durable-validation.d.ts +3 -2
  95. package/dist/engine/validation/durable-validation.js +106 -40
  96. package/dist/engine/validation/validation-freshness.d.ts +3 -2
  97. package/dist/engine/validation/validation-freshness.js +22 -16
  98. package/dist/engine/validation/validation-worktree.js +34 -0
  99. package/dist/hosts/claude-code/ux/mcp-prompts.js +8 -8
  100. package/dist/index.js +3 -17
  101. package/dist/resources/process.js +38 -65
  102. package/dist/storage/session-state-store.js +2 -0
  103. package/dist/tools/challenge-spec/scenarios-utils.js +2 -2
  104. package/dist/tools/configure-checkpoint-policy.js +3 -3
  105. package/dist/tools/create-spec-helpers.js +2 -5
  106. package/dist/tools/create-spec.js +21 -4
  107. package/dist/tools/facilitate.js +3 -6
  108. package/dist/tools/git/branch-ops.js +16 -4
  109. package/dist/tools/github-release-handler.js +1 -20
  110. package/dist/tools/heal-spec-docs.js +1 -13
  111. package/dist/tools/init-project/agents-md-writer.js +6 -6
  112. package/dist/tools/init-project/claude-md-generator.d.ts +0 -1
  113. package/dist/tools/init-project/claude-md-generator.js +0 -35
  114. package/dist/tools/init-project/handler.js +24 -49
  115. package/dist/tools/init-project/legacy-guidance-scanner.d.ts +12 -0
  116. package/dist/tools/init-project/legacy-guidance-scanner.js +176 -0
  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 +21 -1
  120. package/dist/tools/init-project/portable-index-reconciler.js +66 -0
  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/jobs/handlers.d.ts +0 -6
  126. package/dist/tools/jobs/handlers.js +13 -40
  127. package/dist/tools/list-specs.js +6 -21
  128. package/dist/tools/package-handoff.d.ts +3 -2
  129. package/dist/tools/package-handoff.js +153 -427
  130. package/dist/tools/reconcile-session-safeguard-hook.js +22 -15
  131. package/dist/tools/register-sdd-tools.js +0 -23
  132. package/dist/tools/register-spec-tools/core-spec-tools.js +18 -27
  133. package/dist/tools/schemas/index.d.ts +1 -1
  134. package/dist/tools/schemas/index.js +1 -1
  135. package/dist/tools/schemas/output-schemas.d.ts +1 -18
  136. package/dist/tools/schemas/output-schemas.js +1 -11
  137. package/dist/tools/schemas/package-handoff-output-schema.d.ts +40 -0
  138. package/dist/tools/schemas/package-handoff-output-schema.js +68 -0
  139. package/dist/tools/schemas/validate-output-schema.d.ts +1 -2
  140. package/dist/tools/schemas/validate-output-schema.js +3 -2
  141. package/dist/tools/session-checkpoint.js +2 -2
  142. package/dist/tools/skill-registry/index.d.ts +0 -1
  143. package/dist/tools/skill-registry/index.js +0 -1
  144. package/dist/tools/sync-spec-state-handler.d.ts +2 -2
  145. package/dist/tools/sync-spec-state-handler.js +23 -3
  146. package/dist/tools/tool-registry/core-tools.js +1 -140
  147. package/dist/tools/tool-registry/group-infra.js +2 -39
  148. package/dist/tools/tool-registry/group-quality-compliance.js +9 -1
  149. package/dist/tools/update-status/batch.js +17 -0
  150. package/dist/tools/update-status/dod-gates.js +14 -1
  151. package/dist/tools/update-status/done-receipt-verifier.d.ts +22 -0
  152. package/dist/tools/update-status/done-receipt-verifier.js +56 -26
  153. package/dist/tools/update-status/evidence-gate.js +10 -21
  154. package/dist/tools/update-status/file-sync.d.ts +1 -0
  155. package/dist/tools/update-status/file-sync.js +6 -0
  156. package/dist/tools/update-status/index.d.ts +6 -0
  157. package/dist/tools/update-status/index.js +39 -44
  158. package/dist/tools/update-status-actions.js +2 -7
  159. package/dist/tools/validate.js +34 -28
  160. package/dist/transports/oauth-validator.js +12 -1
  161. package/dist/transports/transport-factory.d.ts +2 -1
  162. package/dist/transports/transport-factory.js +19 -0
  163. package/dist/types/common/primitives.d.ts +2 -0
  164. package/dist/types/durable-job.d.ts +45 -0
  165. package/dist/types/durable-validation.d.ts +1 -1
  166. package/dist/types/evidence-autofill.d.ts +13 -1
  167. package/dist/types/handoff-artifacts.d.ts +2 -1
  168. package/dist/types/index.d.ts +1 -0
  169. package/dist/types/index.js +1 -0
  170. package/dist/types/legacy-guidance.d.ts +20 -0
  171. package/dist/types/legacy-guidance.js +3 -0
  172. package/dist/types/readiness.d.ts +8 -1
  173. package/dist/types/reconcile.d.ts +6 -0
  174. package/dist/types/skill-registry.d.ts +26 -1
  175. package/dist/types/spec/core.d.ts +5 -0
  176. package/dist/types/spec/inputs.d.ts +2 -2
  177. package/dist/types/spec-format.d.ts +11 -1
  178. package/dist/types/spec-grounding.d.ts +12 -0
  179. package/dist/types/ssr-migration.d.ts +1 -1
  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
package/planu-plugin.json CHANGED
@@ -2,44 +2,31 @@
2
2
  "name": "dev.planu.cli",
3
3
  "displayName": "Planu — Spec Driven Development",
4
4
  "description": "Manage software specs, estimations, and autonomous SDD workflows. Language-agnostic MCP server for Claude Code.",
5
- "version": "5.7.4",
5
+ "version": "5.7.6",
6
6
  "icon": "assets/plugin/icon.svg",
7
7
  "command": ["npx", "@planu/cli@latest"],
8
8
  "packageName": "@planu/cli",
9
9
  "capabilities": {
10
10
  "tools": [
11
- "planu_status",
12
- "session_checkpoint",
13
- "facilitate",
14
11
  "init_project",
15
- "clarify_requirements",
12
+ "facilitate",
16
13
  "create_spec",
17
14
  "list_specs",
18
- "challenge_spec",
19
- "check_readiness",
20
15
  "update_status",
21
16
  "update_status_batch",
22
- "request_changes",
23
- "estimate",
24
- "package_handoff",
25
17
  "validate",
26
- "get_job",
27
- "watch_job",
28
- "cancel_job",
29
- "restart_job",
30
- "reconcile_spec",
31
- "create_rule",
32
- "create_skill",
33
- "skill_search",
34
- "configure_code_graph",
35
- "code_graph_status",
36
- "submit_feedback",
37
- "triage_feedback",
38
- "resolve_feedback",
39
- "sync_feedback",
40
- "feedback_status",
18
+ "challenge_spec",
19
+ "check_readiness",
41
20
  "bump_spec_version",
42
- "migrate_legacy_spec"
21
+ "reconcile_spec",
22
+ "migrate_legacy_spec",
23
+ "package_handoff",
24
+ "planu_status",
25
+ "session_checkpoint",
26
+ "estimate",
27
+ "request_changes",
28
+ "get_job",
29
+ "restart_job"
43
30
  ],
44
31
  "resources": ["planu://specs/list", "planu://specs/{id}", "planu://project/status", "planu://roadmap"],
45
32
  "prompts": ["create-spec-from-idea", "review-spec-readiness", "generate-implementation-plan"],
@@ -307,7 +307,7 @@
307
307
  "description": "Check if a plan has enough detail to start building. Verifies that the description is complete, acceptance criteria are clear, and all dependencies are met. Tells you if the plan is ready or what is missing."
308
308
  },
309
309
  "package_handoff": {
310
- "description": "Create a complete instruction package so an AI agent can implement a feature. Includes the objective, acceptance criteria, file list, what is out of scope, and any constraints — everything the agent needs to get started."
310
+ "description": "Submit a durable job that builds a complete instruction package so an AI agent can implement a feature. Returns an acknowledgment immediately; poll get_job for the completed package (objective, acceptance criteria, file list, what is out of scope, and any constraints)."
311
311
  },
312
312
  "context_budget": {
313
313
  "description": "Manage context window budget and optimization — configure limits, save checkpoints, and get suggestions to reduce token usage.",
@@ -307,7 +307,7 @@
307
307
  "description": "Verificar si un plan tiene suficiente detalle para empezar a construir. Verifica que la descripción esté completa, los criterios de aceptación sean claros y todas las dependencias estén cumplidas. Te dice si el plan está listo o qué falta."
308
308
  },
309
309
  "package_handoff": {
310
- "description": "Crear un paquete completo de instrucciones para que un agente de IA implemente una feature. Incluye el objetivo, criterios de aceptación, lista de archivos, qué está fuera de scope y cualquier restricción — todo lo que el agente necesita para empezar."
310
+ "description": "Enviar un job durable que construye un paquete completo de instrucciones para que un agente de IA implemente una feature. Devuelve un acuse de recibo de inmediato; usa get_job para obtener el paquete completado (objetivo, criterios de aceptación, lista de archivos, qué está fuera de scope y cualquier restricción)."
311
311
  },
312
312
  "context_budget": {
313
313
  "description": "Gestionar el presupuesto de ventana de contexto y optimización — configurar límites, guardar checkpoints y obtener sugerencias para reducir uso de tokens.",
@@ -307,7 +307,7 @@
307
307
  "description": "Verificar se um plano tem detalhes suficientes para começar a construir. Verifica se a descrição está completa, se os critérios de aceitação estão claros e se todas as dependências estão atendidas. Te diz se o plano está pronto ou o que está faltando."
308
308
  },
309
309
  "package_handoff": {
310
- "description": "Criar um pacote completo de instruções para um agente de IA implementar uma feature. Inclui o objetivo, critérios de aceitação, lista de arquivos, o que está fora do escopo e quaisquer restrições — tudo que o agente precisa para começar."
310
+ "description": "Enviar um job durável que constrói um pacote completo de instruções para um agente de IA implementar uma feature. Retorna uma confirmação imediatamente; use get_job para obter o pacote concluído (objetivo, critérios de aceitação, lista de arquivos, o que está fora do escopo e quaisquer restrições)."
311
311
  },
312
312
  "context_budget": {
313
313
  "description": "Gerenciar o orçamento da janela de contexto e otimização — configurar limites, salvar checkpoints e obter sugestões para reduzir uso de tokens.",
@@ -1,7 +0,0 @@
1
- import type { ProjectKnowledge } from '../../types/index.js';
2
- /**
3
- * Hash the subset of ProjectKnowledge fields that affect skill content.
4
- * Returns a short hex string suitable for embedding in a comment marker.
5
- */
6
- export declare function hashConventions(knowledge: ProjectKnowledge): string;
7
- //# sourceMappingURL=conventions-hasher.d.ts.map
@@ -1,24 +0,0 @@
1
- // src/engine/skill-generator/conventions-hasher.ts — SPEC-685
2
- // Computes a stable hash of the ProjectKnowledge fields that affect skill content.
3
- // Used for idempotency: only regenerate skills when conventions actually changed.
4
- import { createHash } from 'node:crypto';
5
- function extractConventions(knowledge) {
6
- return {
7
- packageManager: knowledge.packageManager,
8
- testCommand: knowledge.testCommand,
9
- buildCommand: knowledge.buildCommand,
10
- lintCommand: knowledge.lintCommand,
11
- language: knowledge.language,
12
- framework: knowledge.framework,
13
- };
14
- }
15
- /**
16
- * Hash the subset of ProjectKnowledge fields that affect skill content.
17
- * Returns a short hex string suitable for embedding in a comment marker.
18
- */
19
- export function hashConventions(knowledge) {
20
- const subset = extractConventions(knowledge);
21
- const json = JSON.stringify(subset);
22
- return createHash('sha256').update(json).digest('hex').slice(0, 16);
23
- }
24
- //# sourceMappingURL=conventions-hasher.js.map
@@ -1,3 +0,0 @@
1
- import type { UniversalRule } from '../../../types/universal-rules/index.js';
2
- export declare const agentTeamsRule: UniversalRule;
3
- //# sourceMappingURL=agent-teams.d.ts.map
@@ -1,63 +0,0 @@
1
- function buildBody() {
2
- return `# Agent Teams (MANDATORY when 3+ specs in parallel)
3
-
4
- This rule file is auto-generated by Planu \`init_project\`. Do not edit manually — re-run \`init_project\` to update.
5
-
6
- ## When to Use Agent Teams
7
-
8
- Use Agent Teams when ALL of the following apply:
9
- - 3+ independent specs are ready to implement simultaneously
10
- - Estimated total effort > 8h
11
- - Specs touch different modules/packages (clear file ownership boundaries)
12
- - Monorepo or multi-layer architecture with well-defined interfaces
13
-
14
- ## File Ownership (MANDATORY)
15
-
16
- **Two teammates MUST NEVER modify the same file.** This is non-negotiable.
17
-
18
- - \`plan_team_distribution\` auto-assigns exclusive file ownership per agent
19
- - Review the distribution before spawning — resolve any conflicts first
20
- - If two specs require the same shared file, implement them sequentially, not in parallel
21
-
22
- ## Workflow
23
-
24
- \`\`\`
25
- 1. plan_team_distribution # input: spec IDs → output: file ownership map
26
- 2. generate_teammate_prompt # input: teammate assignment → output: isolated prompt
27
- 3. spawn N agents # claude -p "<prompt>" for each teammate (run in parallel)
28
- 4. validate_team_results # input: projectPath → verifies merged code integrity
29
- \`\`\`
30
-
31
- ## Available Team Patterns
32
-
33
- - **implement-and-test** — one agent implements, another writes tests (zero shared files)
34
- - **full-stack** — frontend and backend agents with a contract-first API boundary
35
- - **research-then-build** — researcher gathers context first, builder implements after
36
- - **parallel-specs** — N agents implement N fully independent specs simultaneously
37
-
38
- ## Quick Reference
39
-
40
- | Goal | Tool |
41
- |------|------|
42
- | Plan team distribution | \`plan_team_distribution\` with spec IDs array |
43
- | Get teammate context | \`generate_teammate_prompt\` with assignment object |
44
- | Validate merged result | \`validate_team_results\` after all agents complete |
45
-
46
- ## Prohibited Patterns
47
-
48
- - NEVER spawn teammates without running \`plan_team_distribution\` first
49
- - NEVER assign the same file to two different teammates
50
- - NEVER skip \`validate_team_results\` after parallel implementation
51
- - NEVER use Agent Teams for 1-2 specs — sequential is faster and safer
52
- `;
53
- }
54
- export const agentTeamsRule = {
55
- id: 'agent-teams',
56
- name: 'Agent Teams',
57
- description: 'Mandatory rules for parallel spec implementation using Agent Teams.',
58
- category: 'workflow',
59
- applicableHosts: ['all'],
60
- defaultEnabled: true,
61
- buildContent: (_host) => buildBody(),
62
- };
63
- //# sourceMappingURL=agent-teams.js.map
@@ -1,30 +0,0 @@
1
- import type { ClarificationQuestion } from '../../types/index.js';
2
- /** Detected stack info from package files in the project directory. */
3
- export interface ClarifyStackDetectionResult {
4
- framework: string | null;
5
- language: string | null;
6
- database: string | null;
7
- /** Raw names found in package.json dependencies */
8
- detectedLibs: string[];
9
- }
10
- /**
11
- * Detect the project stack by reading package.json and/or requirements.txt
12
- * from the given project path.
13
- */
14
- export declare function detectStack(projectPath: string): Promise<ClarifyStackDetectionResult>;
15
- /**
16
- * Returns true if the question should be skipped because the stack already
17
- * provides a definitive answer.
18
- */
19
- export declare function shouldSkipQuestion(question: ClarificationQuestion, stack: ClarifyStackDetectionResult): boolean;
20
- /**
21
- * Attaches structured `options[]` to a question based on its content.
22
- * Each question gets 3-8 concrete choices + 'Other: ___' fallback.
23
- */
24
- export declare function attachOptions(question: ClarificationQuestion): ClarificationQuestion;
25
- /**
26
- * Builds a `suggestedDescription` string from accumulated answers.
27
- * The returned string is suitable for passing directly to create_spec.
28
- */
29
- export declare function buildSuggestedDescription(topic: string, answers: Record<string, string>, questions: ClarificationQuestion[]): string;
30
- //# sourceMappingURL=multiple-choice.d.ts.map
@@ -1,306 +0,0 @@
1
- import { technologyValue } from '../../engine/technology-registry.js';
2
- // tools/clarify-requirements/multiple-choice.ts — SPEC-337
3
- // Structured multiple-choice options for clarify_requirements interview mode.
4
- // Provides: per-question options[], stack detection, suggestedDescription builder.
5
- import { readFile } from 'node:fs/promises';
6
- import { join } from 'node:path';
7
- const OPTIONS_CATALOG = {
8
- stack_frontend: [
9
- technologyValue('technology-next-js-30b7f8'),
10
- technologyValue('technology-remix-f84ed4'),
11
- technologyValue('technology-nuxt-e88c87'),
12
- technologyValue('technology-sveltekit-b62200'),
13
- technologyValue('technology-astro-c490cc'),
14
- 'Vite + React',
15
- technologyValue('technology-angular-e79052'),
16
- 'Other: ___',
17
- ],
18
- stack_backend: [
19
- technologyValue('technology-express-572a14'),
20
- technologyValue('technology-fastify-ed8050'),
21
- technologyValue('technology-nestjs-58b822'),
22
- 'Hono',
23
- technologyValue('technology-fastapi-2dd9eb'),
24
- technologyValue('technology-django-4445d9'),
25
- technologyValue('technology-spring-boot-8d9a80'),
26
- 'Other: ___',
27
- ],
28
- stack_database: [
29
- 'PostgreSQL',
30
- 'MySQL',
31
- 'SQLite',
32
- 'MongoDB',
33
- technologyValue('technology-redis-a7f641'),
34
- technologyValue('technology-supabase-fe7ceb'),
35
- 'PlanetScale',
36
- 'Other: ___',
37
- ],
38
- stack_language: [
39
- technologyValue('technology-typescript-ed0504'),
40
- 'JavaScript',
41
- 'Python',
42
- 'Go',
43
- 'Java',
44
- 'Rust',
45
- 'Other: ___',
46
- ],
47
- auth_method: [
48
- 'Email + password',
49
- 'Google OAuth',
50
- 'GitHub OAuth',
51
- 'Magic link',
52
- 'JWT (custom)',
53
- 'Session-based',
54
- 'API key',
55
- 'Other: ___',
56
- ],
57
- scope_type: ['New feature', 'Improvement to existing', 'Bug fix', 'Refactor', 'Other: ___'],
58
- user_type: ['End user', 'Admin', 'Developer / internal', 'All users', 'Other: ___'],
59
- mvp_scope: [
60
- 'Core happy path only',
61
- 'Happy path + error handling',
62
- 'Full feature with edge cases',
63
- 'MVP first, iterate later',
64
- 'Other: ___',
65
- ],
66
- performance_target: [
67
- '< 100ms (real-time)',
68
- '< 500ms (interactive)',
69
- '< 2s (acceptable)',
70
- 'No strict SLA',
71
- 'Other: ___',
72
- ],
73
- ui_mockup: [
74
- 'Yes, Figma mockup available',
75
- 'Rough sketch only',
76
- 'No mockup — describe in text',
77
- 'Other: ___',
78
- ],
79
- login_method: [
80
- 'Email/password',
81
- 'Google',
82
- 'Apple',
83
- 'Magic link',
84
- 'GitHub',
85
- 'SSO / SAML',
86
- 'Other: ___',
87
- ],
88
- };
89
- /**
90
- * Detect the project stack by reading package.json and/or requirements.txt
91
- * from the given project path.
92
- */
93
- export async function detectStack(projectPath) {
94
- const result = {
95
- framework: null,
96
- language: null,
97
- database: null,
98
- detectedLibs: [],
99
- };
100
- try {
101
- const pkgRaw = await readFile(join(projectPath, 'package.json'), 'utf-8');
102
- const pkg = JSON.parse(pkgRaw);
103
- const allDeps = {
104
- ...(pkg.dependencies ?? {}),
105
- ...(pkg.devDependencies ?? {}),
106
- };
107
- const libs = Object.keys(allDeps);
108
- result.detectedLibs = libs;
109
- // Framework detection
110
- if (libs.includes('next')) {
111
- result.framework = technologyValue('technology-next-js-30b7f8');
112
- }
113
- else if (libs.includes('@remix-run/react') || libs.includes('@remix-run/node')) {
114
- result.framework = technologyValue('technology-remix-f84ed4');
115
- }
116
- else if (libs.includes(technologyValue('technology-nuxt-22c407'))) {
117
- result.framework = technologyValue('technology-nuxt-e88c87');
118
- }
119
- else if (libs.includes('@sveltejs/kit')) {
120
- result.framework = technologyValue('technology-sveltekit-b62200');
121
- }
122
- else if (libs.includes(technologyValue('technology-astro-23661e'))) {
123
- result.framework = technologyValue('technology-astro-c490cc');
124
- }
125
- else if (libs.includes(technologyValue('technology-fastify-cbe57e'))) {
126
- result.framework = technologyValue('technology-fastify-ed8050');
127
- }
128
- else if (libs.includes('@nestjs/core')) {
129
- result.framework = technologyValue('technology-nestjs-58b822');
130
- }
131
- else if (libs.includes(technologyValue('technology-express-008231'))) {
132
- result.framework = technologyValue('technology-express-572a14');
133
- }
134
- else if (libs.includes('hono')) {
135
- result.framework = 'Hono';
136
- }
137
- // Language (TypeScript presence)
138
- if (libs.includes(technologyValue('technology-typescript-969545')) ||
139
- libs.includes('ts-node') ||
140
- libs.includes('tsx')) {
141
- result.language = technologyValue('technology-typescript-ed0504');
142
- }
143
- else {
144
- result.language = 'JavaScript';
145
- }
146
- // Database detection
147
- if (libs.includes('pg') || libs.includes('postgres')) {
148
- result.database = 'PostgreSQL';
149
- }
150
- else if (libs.includes('mysql2') || libs.includes('mysql')) {
151
- result.database = 'MySQL';
152
- }
153
- else if (libs.includes('better-sqlite3') || libs.includes('sqlite3')) {
154
- result.database = 'SQLite';
155
- }
156
- else if (libs.includes(technologyValue('technology-mongoose-4e1812')) ||
157
- libs.includes('mongodb')) {
158
- result.database = 'MongoDB';
159
- }
160
- else if (libs.includes('@supabase/supabase-js')) {
161
- result.database = technologyValue('technology-supabase-fe7ceb');
162
- }
163
- else if (libs.includes('ioredis') ||
164
- libs.includes(technologyValue('technology-redis-34fb46'))) {
165
- result.database = technologyValue('technology-redis-a7f641');
166
- }
167
- }
168
- catch {
169
- // No package.json — try requirements.txt for Python
170
- try {
171
- const reqRaw = await readFile(join(projectPath, 'requirements.txt'), 'utf-8');
172
- const lines = reqRaw
173
- .split('\n')
174
- .map((l) => (l.split('=')[0] ?? l).split('>')[0]?.split('<')[0]?.trim().toLowerCase() ?? '');
175
- result.detectedLibs = lines.filter(Boolean);
176
- if (lines.includes(technologyValue('technology-django-7d8a08')) ||
177
- lines.includes('django-rest-framework')) {
178
- result.framework = technologyValue('technology-django-4445d9');
179
- result.language = 'Python';
180
- }
181
- else if (lines.includes(technologyValue('technology-fastapi-6aee0e'))) {
182
- result.framework = technologyValue('technology-fastapi-2dd9eb');
183
- result.language = 'Python';
184
- }
185
- else if (lines.includes(technologyValue('technology-flask-b87aa5'))) {
186
- result.framework = technologyValue('technology-flask-c08622');
187
- result.language = 'Python';
188
- }
189
- else {
190
- result.language = 'Python';
191
- }
192
- if (lines.includes('psycopg2') || lines.includes('psycopg2-binary')) {
193
- result.database = 'PostgreSQL';
194
- }
195
- else if (lines.includes('pymysql') || lines.includes('mysql-connector-python')) {
196
- result.database = 'MySQL';
197
- }
198
- else if (lines.includes('motor') || lines.includes('pymongo')) {
199
- result.database = 'MongoDB';
200
- }
201
- }
202
- catch {
203
- // No manifest files found — detection yields nulls
204
- }
205
- }
206
- return result;
207
- }
208
- /**
209
- * Returns true if the question should be skipped because the stack already
210
- * provides a definitive answer.
211
- */
212
- export function shouldSkipQuestion(question, stack) {
213
- const lower = question.question.toLowerCase();
214
- if ((lower.includes('stack') || lower.includes('framework') || lower.includes('language')) &&
215
- (stack.framework !== null || stack.language !== null)) {
216
- return true;
217
- }
218
- if (lower.includes('database') && stack.database !== null) {
219
- return true;
220
- }
221
- return false;
222
- }
223
- /**
224
- * Resolves option list from a catalog key.
225
- */
226
- function resolveOptions(key) {
227
- return OPTIONS_CATALOG[key];
228
- }
229
- /**
230
- * Attaches structured `options[]` to a question based on its content.
231
- * Each question gets 3-8 concrete choices + 'Other: ___' fallback.
232
- */
233
- export function attachOptions(question) {
234
- const lower = question.question.toLowerCase();
235
- let options;
236
- if (lower.includes('login') || lower.includes('sign in') || lower.includes('sign up')) {
237
- options = resolveOptions('login_method');
238
- }
239
- else if (lower.includes('auth')) {
240
- options = resolveOptions('auth_method');
241
- }
242
- else if (lower.includes('frontend') || lower.includes('ui framework')) {
243
- options = resolveOptions('stack_frontend');
244
- }
245
- else if (lower.includes('backend') || lower.includes('server framework')) {
246
- options = resolveOptions('stack_backend');
247
- }
248
- else if (lower.includes('database') || lower.includes('db')) {
249
- options = resolveOptions('stack_database');
250
- }
251
- else if (lower.includes('stack') || lower.includes('framework') || lower.includes('language')) {
252
- options = resolveOptions('stack_language');
253
- }
254
- else if (lower.includes('new feature') ||
255
- lower.includes('improvement') ||
256
- lower.includes('feature or')) {
257
- options = resolveOptions('scope_type');
258
- }
259
- else if (lower.includes('user') &&
260
- (lower.includes('who') || lower.includes('primary') || lower.includes('persona'))) {
261
- options = resolveOptions('user_type');
262
- }
263
- else if (lower.includes('must-have') ||
264
- lower.includes('minimum viable') ||
265
- lower.includes('mvp') ||
266
- lower.includes('first version')) {
267
- options = resolveOptions('mvp_scope');
268
- }
269
- else if (lower.includes('performance') ||
270
- lower.includes('response time') ||
271
- lower.includes('latency')) {
272
- options = resolveOptions('performance_target');
273
- }
274
- else if (lower.includes('mockup') ||
275
- lower.includes('design') ||
276
- lower.includes('reference design')) {
277
- options = resolveOptions('ui_mockup');
278
- }
279
- else if (lower.includes('scope') && lower.includes('done')) {
280
- options = resolveOptions('mvp_scope');
281
- }
282
- if (options === undefined) {
283
- return question;
284
- }
285
- return { ...question, options };
286
- }
287
- /**
288
- * Builds a `suggestedDescription` string from accumulated answers.
289
- * The returned string is suitable for passing directly to create_spec.
290
- */
291
- export function buildSuggestedDescription(topic, answers, questions) {
292
- const parts = [`Topic: ${topic}.`];
293
- for (const q of questions) {
294
- const answer = answers[q.id];
295
- if (answer === undefined || answer.trim() === '') {
296
- continue;
297
- }
298
- const trimmedAnswer = answer.trim();
299
- const shortQuestion = q.question
300
- .replace(/^(What|Who|Is|Are|Does|Do|How|Which)\s+/i, '')
301
- .replace(/\?$/, '');
302
- parts.push(`${shortQuestion}: ${trimmedAnswer}.`);
303
- }
304
- return parts.join(' ');
305
- }
306
- //# sourceMappingURL=multiple-choice.js.map
@@ -1,9 +0,0 @@
1
- import type { ClarificationQuestion } from '../../types/index.js';
2
- import type { knowledgeStore } from '../../storage/index.js';
3
- /**
4
- * Generate minimal clarification questions based on the topic.
5
- * Philosophy: Planu facilitates — only ask what's truly needed.
6
- * Technical details are inferred from project context, not asked.
7
- */
8
- export declare function generateQuestions(topic: string, _context: string | undefined, knowledge: Awaited<ReturnType<typeof knowledgeStore.getKnowledge>>, maxQuestions: number): ClarificationQuestion[];
9
- //# sourceMappingURL=questions-context.d.ts.map
@@ -1,74 +0,0 @@
1
- import { buildSuggestedAnswers } from './questions.js';
2
- /**
3
- * Generate minimal clarification questions based on the topic.
4
- * Philosophy: Planu facilitates — only ask what's truly needed.
5
- * Technical details are inferred from project context, not asked.
6
- */
7
- export function generateQuestions(topic, _context, knowledge, maxQuestions) {
8
- const questions = [];
9
- let idx = 0;
10
- const nextId = () => `q-${++idx}`;
11
- // === Core question: What do you want? (always relevant) ===
12
- questions.push({
13
- id: nextId(),
14
- question: `What observable behavior or result should "${topic}" produce?`,
15
- category: 'scope',
16
- importance: 'critical',
17
- });
18
- // === Scope question: What's the MVP? ===
19
- questions.push({
20
- id: nextId(),
21
- question: `What are the must-have features for a first version?`,
22
- category: 'requirements',
23
- importance: 'critical',
24
- });
25
- // === Acceptance: What does done look like? ===
26
- questions.push({
27
- id: nextId(),
28
- question: `Which explicit observations or checks will prove that "${topic}" is done?`,
29
- category: 'acceptance',
30
- importance: 'critical',
31
- });
32
- // === Context-specific (only if topic mentions specific domains) ===
33
- // Auth related — only ask which method, nothing else
34
- if (hasAffirmedTerm(topic, /\b(?:auth|authentication|login|register|password)\b/i)) {
35
- questions.push({
36
- id: nextId(),
37
- question: `What login methods? (email/password, Google, Apple, magic link, etc.)`,
38
- category: 'requirements',
39
- importance: 'helpful',
40
- });
41
- }
42
- // UI related — only ask if there are mockups
43
- if (hasAffirmedTerm(topic, /\b(?:ui|page|screen|dashboard)\b/i)) {
44
- questions.push({
45
- id: nextId(),
46
- question: `Are there mockups or a reference design to follow?`,
47
- category: 'requirements',
48
- importance: 'helpful',
49
- });
50
- }
51
- // Trim to maxQuestions, prioritizing by importance
52
- const priorityOrder = [
53
- 'critical',
54
- 'helpful',
55
- 'nice-to-have',
56
- ];
57
- const sorted = questions.sort((a, b) => {
58
- return priorityOrder.indexOf(a.importance) - priorityOrder.indexOf(b.importance);
59
- });
60
- const sliced = sorted.slice(0, maxQuestions);
61
- // Add context-aware suggestedAnswers to each question
62
- return sliced.map((q) => ({
63
- ...q,
64
- suggestedAnswers: buildSuggestedAnswers(q, knowledge),
65
- }));
66
- }
67
- const NEGATION_RE = /\b(?:no|not|never|without|exclude|excluding|forbid|forbidden|remove|avoid|must not|should not|do not|does not|don't|doesn't|out[- ]of[- ]scope)\b/i;
68
- function hasAffirmedTerm(text, pattern) {
69
- return text.split(/(?:\r?\n|[.;!?]+)/).some((segment) => {
70
- const match = new RegExp(pattern.source, pattern.flags.replace('g', '')).exec(segment);
71
- return match !== null && !NEGATION_RE.test(segment.slice(0, match.index));
72
- });
73
- }
74
- //# sourceMappingURL=questions-context.js.map
@@ -1,16 +0,0 @@
1
- import type { ClarificationQuestion } from '../../types/index.js';
2
- import type { knowledgeStore } from '../../storage/index.js';
3
- /** Returns true if the topic has fewer than 3 words (extremely vague — meta-questions needed). */
4
- export declare function isShortTopic(topic: string): boolean;
5
- /** Generate meta-questions to scope a vague topic. */
6
- export declare function generateMetaQuestions(): ClarificationQuestion[];
7
- /**
8
- * Detect contradictions in a set of answers.
9
- * Returns an array of human-readable contradiction descriptions.
10
- */
11
- export declare function detectContradictions(answers: Record<string, string>): string[];
12
- /**
13
- * Build suggested answers for a question using project knowledge.
14
- */
15
- export declare function buildSuggestedAnswers(question: ClarificationQuestion, knowledge: Awaited<ReturnType<typeof knowledgeStore.getKnowledge>>): string[];
16
- //# sourceMappingURL=questions.d.ts.map