@planu/cli 5.7.5 → 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 (196) hide show
  1. package/CHANGELOG.md +75 -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/server-instructions.js +0 -21
  13. package/dist/config/skill-templates/planu-context-assets.md +3 -6
  14. package/dist/config/skill-templates/planu-implement.md +2 -2
  15. package/dist/config/skill-templates/planu-multi-teammate-review.md +1 -1
  16. package/dist/config/skill-templates/planu-release.md +2 -7
  17. package/dist/config/skill-templates/planu-validate.md +3 -3
  18. package/dist/config/spec-templates/crud-rest-api/template.json +5 -1
  19. package/dist/config/spec-templates/file-upload-s3/template.json +5 -1
  20. package/dist/config/spec-templates/stripe-payments/template.json +5 -1
  21. package/dist/config/spec-templates/webhook-system/template.json +5 -1
  22. package/dist/config/subagent-templates/planu-challenger.md +4 -9
  23. package/dist/config/subagent-templates/planu-spec-implementer.md +2 -4
  24. package/dist/config/subagent-templates/planu-validator.md +5 -8
  25. package/dist/config/tool-groups.json +6 -144
  26. package/dist/engine/ambiguity-scorer.js +40 -1
  27. package/dist/engine/autopilot/bootstrap.js +1 -1
  28. package/dist/engine/code-impact-analyzer.js +2 -6
  29. package/dist/engine/context-orchestrator/index.js +2 -2
  30. package/dist/engine/convention-scanner/codebase-scanner.js +2 -2
  31. package/dist/engine/dogfooding/runtime-gap-detector.js +2 -2
  32. package/dist/engine/evidence-gates/artifact-reader.d.ts +1 -0
  33. package/dist/engine/evidence-gates/artifact-reader.js +1 -1
  34. package/dist/engine/evidence-gates/evidence-autofill.d.ts +13 -5
  35. package/dist/engine/evidence-gates/evidence-autofill.js +106 -43
  36. package/dist/engine/evidence-gates/lifecycle-gate.js +7 -4
  37. package/dist/engine/evidence-index/index-builder.js +21 -4
  38. package/dist/engine/execution/job-runtime.js +1 -1
  39. package/dist/engine/execution/package-handoff-job-executor.d.ts +22 -0
  40. package/dist/engine/execution/package-handoff-job-executor.js +490 -0
  41. package/dist/engine/execution/validate-job-executor.js +20 -8
  42. package/dist/engine/git/exec-git.d.ts +4 -0
  43. package/dist/engine/git/exec-git.js +14 -0
  44. package/dist/engine/handoff-artifacts/implementation-review-reader.js +15 -2
  45. package/dist/engine/handoff-artifacts/schemas.d.ts +2 -0
  46. package/dist/engine/handoff-artifacts/schemas.js +1 -0
  47. package/dist/engine/handoff-format.d.ts +36 -0
  48. package/dist/engine/handoff-format.js +314 -0
  49. package/dist/engine/handoff-packager.d.ts +5 -3
  50. package/dist/engine/handoff-packager.js +89 -32
  51. package/dist/engine/host-tool-filter.js +20 -49
  52. package/dist/engine/human-summary.js +14 -3
  53. package/dist/engine/implementation-contract/common.d.ts +8 -3
  54. package/dist/engine/implementation-contract/common.js +9 -6
  55. package/dist/engine/implementation-contract/evaluator.js +4 -6
  56. package/dist/engine/implementation-contract/renderer.js +18 -23
  57. package/dist/engine/project-health-checker.js +2 -2
  58. package/dist/engine/readiness-checker.js +27 -0
  59. package/dist/engine/reconcile/apply-changes.js +4 -0
  60. package/dist/engine/reconcile/propagate-mirrors.d.ts +3 -0
  61. package/dist/engine/reconcile/propagate-mirrors.js +311 -0
  62. package/dist/engine/self-healing/healer.js +12 -5
  63. package/dist/engine/self-healing/strategies/lint-fix.d.ts +1 -1
  64. package/dist/engine/self-healing/strategies/lint-fix.js +4 -1
  65. package/dist/engine/self-healing/strategies/test-fix.d.ts +4 -3
  66. package/dist/engine/self-healing/strategies/test-fix.js +32 -14
  67. package/dist/engine/self-healing/strategies/typescript-fix.d.ts +1 -1
  68. package/dist/engine/self-healing/strategies/typescript-fix.js +28 -10
  69. package/dist/engine/session/checkpoint-writer.js +8 -4
  70. package/dist/engine/session/session-tracker.d.ts +5 -16
  71. package/dist/engine/session/session-tracker.js +29 -26
  72. package/dist/engine/session-state/writer.js +3 -11
  73. package/dist/engine/skill-generator/workflow-skill-generator.d.ts +4 -2
  74. package/dist/engine/skill-generator/workflow-skill-generator.js +113 -38
  75. package/dist/engine/spec-format/bdd-parser.d.ts +1 -11
  76. package/dist/engine/spec-format/bdd-parser.js +40 -11
  77. package/dist/engine/spec-format/lean-spec-generator.js +30 -10
  78. package/dist/engine/spec-format/retired-scaffold.d.ts +3 -0
  79. package/dist/engine/spec-format/retired-scaffold.js +5 -0
  80. package/dist/engine/spec-format/technical-md-populator.d.ts +1 -0
  81. package/dist/engine/spec-format/technical-md-populator.js +27 -0
  82. package/dist/engine/spec-format/unified-spec-builder.d.ts +1 -0
  83. package/dist/engine/spec-format/unified-spec-builder.js +30 -20
  84. package/dist/engine/spec-grounding/contract.js +115 -1
  85. package/dist/engine/spec-quality/generic-output-gate.js +37 -3
  86. package/dist/engine/technical-enricher/index.js +4 -1
  87. package/dist/engine/type-safety-gate.js +3 -11
  88. package/dist/engine/universal-rules/catalog.js +0 -2
  89. package/dist/engine/universal-rules/rules/planu-workflow.js +1 -1
  90. package/dist/engine/validation/durable-validation.d.ts +3 -2
  91. package/dist/engine/validation/durable-validation.js +106 -40
  92. package/dist/engine/validation/validation-freshness.d.ts +3 -2
  93. package/dist/engine/validation/validation-freshness.js +22 -16
  94. package/dist/engine/validation/validation-worktree.js +34 -0
  95. package/dist/hosts/claude-code/ux/mcp-prompts.js +8 -8
  96. package/dist/index.js +3 -17
  97. package/dist/resources/process.js +38 -65
  98. package/dist/storage/session-state-store.js +2 -0
  99. package/dist/tools/challenge-spec/scenarios-utils.js +2 -2
  100. package/dist/tools/configure-checkpoint-policy.js +3 -3
  101. package/dist/tools/create-spec-helpers.js +2 -5
  102. package/dist/tools/create-spec.js +21 -4
  103. package/dist/tools/facilitate.js +3 -6
  104. package/dist/tools/git/branch-ops.js +16 -4
  105. package/dist/tools/github-release-handler.js +1 -20
  106. package/dist/tools/init-project/agents-md-writer.js +6 -6
  107. package/dist/tools/init-project/claude-md-generator.d.ts +0 -1
  108. package/dist/tools/init-project/claude-md-generator.js +0 -35
  109. package/dist/tools/init-project/handler.js +7 -5
  110. package/dist/tools/init-project/per-client-files-writer.js +5 -5
  111. package/dist/tools/init-project/planu-workflow-generator.js +2 -13
  112. package/dist/tools/init-project/portable-index-reconciler.d.ts +2 -1
  113. package/dist/tools/init-project/portable-index-reconciler.js +7 -2
  114. package/dist/tools/init-project/rules-generator.d.ts +0 -11
  115. package/dist/tools/init-project/rules-generator.js +4 -85
  116. package/dist/tools/init-project/scaffold-writer.d.ts +0 -1
  117. package/dist/tools/init-project/scaffold-writer.js +1 -12
  118. package/dist/tools/jobs/handlers.d.ts +0 -6
  119. package/dist/tools/jobs/handlers.js +13 -40
  120. package/dist/tools/list-specs.js +6 -21
  121. package/dist/tools/package-handoff.d.ts +3 -2
  122. package/dist/tools/package-handoff.js +153 -427
  123. package/dist/tools/reconcile-session-safeguard-hook.js +22 -15
  124. package/dist/tools/register-sdd-tools.js +0 -23
  125. package/dist/tools/register-spec-tools/core-spec-tools.js +18 -27
  126. package/dist/tools/schemas/index.d.ts +1 -1
  127. package/dist/tools/schemas/index.js +1 -1
  128. package/dist/tools/schemas/output-schemas.d.ts +1 -18
  129. package/dist/tools/schemas/output-schemas.js +1 -11
  130. package/dist/tools/schemas/package-handoff-output-schema.d.ts +40 -0
  131. package/dist/tools/schemas/package-handoff-output-schema.js +68 -0
  132. package/dist/tools/schemas/validate-output-schema.d.ts +1 -2
  133. package/dist/tools/schemas/validate-output-schema.js +3 -2
  134. package/dist/tools/session-checkpoint.js +2 -2
  135. package/dist/tools/skill-registry/index.d.ts +0 -1
  136. package/dist/tools/skill-registry/index.js +0 -1
  137. package/dist/tools/sync-spec-state-handler.d.ts +2 -2
  138. package/dist/tools/sync-spec-state-handler.js +23 -3
  139. package/dist/tools/tool-registry/core-tools.js +1 -140
  140. package/dist/tools/tool-registry/group-infra.js +2 -39
  141. package/dist/tools/tool-registry/group-quality-compliance.js +9 -1
  142. package/dist/tools/update-status/batch.js +17 -0
  143. package/dist/tools/update-status/dod-gates.js +14 -1
  144. package/dist/tools/update-status/done-receipt-verifier.d.ts +22 -0
  145. package/dist/tools/update-status/done-receipt-verifier.js +56 -26
  146. package/dist/tools/update-status/evidence-gate.js +10 -21
  147. package/dist/tools/update-status/file-sync.d.ts +1 -0
  148. package/dist/tools/update-status/file-sync.js +6 -0
  149. package/dist/tools/update-status/index.d.ts +6 -0
  150. package/dist/tools/update-status/index.js +39 -44
  151. package/dist/tools/update-status-actions.js +2 -7
  152. package/dist/tools/validate.js +34 -28
  153. package/dist/transports/oauth-validator.js +12 -1
  154. package/dist/transports/transport-factory.d.ts +2 -1
  155. package/dist/transports/transport-factory.js +19 -0
  156. package/dist/types/common/primitives.d.ts +2 -0
  157. package/dist/types/durable-job.d.ts +45 -0
  158. package/dist/types/durable-validation.d.ts +1 -1
  159. package/dist/types/evidence-autofill.d.ts +13 -1
  160. package/dist/types/handoff-artifacts.d.ts +2 -1
  161. package/dist/types/readiness.d.ts +8 -1
  162. package/dist/types/reconcile.d.ts +6 -0
  163. package/dist/types/skill-registry.d.ts +26 -1
  164. package/dist/types/spec/core.d.ts +5 -0
  165. package/dist/types/spec/inputs.d.ts +2 -2
  166. package/dist/types/spec-format.d.ts +11 -1
  167. package/dist/types/spec-grounding.d.ts +12 -0
  168. package/dist/types/transport.d.ts +1 -0
  169. package/dist/types/validation-receipt.d.ts +27 -0
  170. package/package.json +3 -2
  171. package/planu-plugin.json +13 -26
  172. package/src/i18n/messages/en.json +1 -1
  173. package/src/i18n/messages/es.json +1 -1
  174. package/src/i18n/messages/pt.json +1 -1
  175. package/dist/engine/skill-generator/conventions-hasher.d.ts +0 -7
  176. package/dist/engine/skill-generator/conventions-hasher.js +0 -24
  177. package/dist/engine/universal-rules/rules/agent-teams.d.ts +0 -3
  178. package/dist/engine/universal-rules/rules/agent-teams.js +0 -63
  179. package/dist/tools/clarify-requirements/multiple-choice.d.ts +0 -30
  180. package/dist/tools/clarify-requirements/multiple-choice.js +0 -306
  181. package/dist/tools/clarify-requirements/questions-context.d.ts +0 -9
  182. package/dist/tools/clarify-requirements/questions-context.js +0 -74
  183. package/dist/tools/clarify-requirements/questions.d.ts +0 -16
  184. package/dist/tools/clarify-requirements/questions.js +0 -96
  185. package/dist/tools/clarify-requirements.d.ts +0 -4
  186. package/dist/tools/clarify-requirements.js +0 -314
  187. package/dist/tools/code-graph-handler.d.ts +0 -6
  188. package/dist/tools/code-graph-handler.js +0 -72
  189. package/dist/tools/create-rule.d.ts +0 -4
  190. package/dist/tools/create-rule.js +0 -107
  191. package/dist/tools/feedback-handler.d.ts +0 -7
  192. package/dist/tools/feedback-handler.js +0 -150
  193. package/dist/tools/semantic-search-handler.d.ts +0 -7
  194. package/dist/tools/semantic-search-handler.js +0 -71
  195. package/dist/tools/skill-registry/search.d.ts +0 -11
  196. package/dist/tools/skill-registry/search.js +0 -159
@@ -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
@@ -1,96 +0,0 @@
1
- /** Returns true if the topic has fewer than 3 words (extremely vague — meta-questions needed). */
2
- export function isShortTopic(topic) {
3
- return topic.trim().split(/\s+/).length < 3;
4
- }
5
- /** Generate meta-questions to scope a vague topic. */
6
- export function generateMetaQuestions() {
7
- return [
8
- {
9
- id: 'meta-1',
10
- question: 'Which change type best describes the request?',
11
- category: 'scope',
12
- importance: 'critical',
13
- suggestedAnswers: ['New feature', 'Improvement to existing feature', 'Bug fix', 'Refactor'],
14
- },
15
- {
16
- id: 'meta-2',
17
- question: 'What observable outcome must this work produce?',
18
- category: 'scope',
19
- importance: 'critical',
20
- },
21
- {
22
- id: 'meta-3',
23
- question: 'Which boundaries are explicitly in scope and out of scope?',
24
- category: 'scope',
25
- importance: 'critical',
26
- },
27
- ];
28
- }
29
- /**
30
- * Detect contradictions in a set of answers.
31
- * Returns an array of human-readable contradiction descriptions.
32
- */
33
- export function detectContradictions(answers) {
34
- const contradictions = [];
35
- const values = Object.values(answers).map((v) => v.toLowerCase());
36
- const joined = values.join(' ');
37
- // Heuristic: "fast" / "no cache"
38
- if ((joined.includes('fast') || joined.includes('performant') || joined.includes('low latency')) &&
39
- (joined.includes('no cache') ||
40
- joined.includes('without cache') ||
41
- joined.includes('sin cache'))) {
42
- contradictions.push('Performance requirement ("fast") may conflict with "no cache" — caching is a primary tool for low-latency responses.');
43
- }
44
- // Heuristic: "simple" / many features
45
- const featureKeywords = [
46
- 'real-time',
47
- 'realtime',
48
- 'offline',
49
- 'multi-tenant',
50
- 'i18n',
51
- 'analytics',
52
- 'notifications',
53
- ];
54
- const wantsSimple = joined.includes('simple') || joined.includes('minimal') || joined.includes('lightweight');
55
- const wantsComplex = featureKeywords.some((k) => joined.includes(k));
56
- if (wantsSimple && wantsComplex) {
57
- contradictions.push('Scope may be underestimated: "simple/minimal" combined with advanced features (real-time, offline, multi-tenant, etc.) typically results in a complex implementation.');
58
- }
59
- // Heuristic: deadline conflicts
60
- if ((joined.includes('urgent') || joined.includes('asap') || joined.includes('tomorrow')) &&
61
- (joined.includes('comprehensive') ||
62
- joined.includes('complete') ||
63
- joined.includes('all edge cases'))) {
64
- contradictions.push('Timeline conflict: "urgent/ASAP" deadline with "comprehensive/all edge cases" scope — consider scoping down to an MVP first.');
65
- }
66
- return contradictions;
67
- }
68
- /**
69
- * Build suggested answers for a question using project knowledge.
70
- */
71
- export function buildSuggestedAnswers(question, knowledge) {
72
- const lower = question.question.toLowerCase();
73
- // Database-related: suggest the project's database
74
- if (lower.includes('database') || lower.includes('table') || lower.includes('schema')) {
75
- if (knowledge && knowledge.database !== 'unknown') {
76
- return [
77
- `Yes, using project's ${knowledge.database} database`,
78
- 'No new tables needed',
79
- 'Needs new tables',
80
- 'Modifies existing tables',
81
- ];
82
- }
83
- }
84
- // Framework-related: suggest the project's framework
85
- if (lower.includes('framework') || lower.includes('pattern') || lower.includes('component')) {
86
- if (knowledge?.framework) {
87
- return [
88
- `Yes, reuse ${knowledge.framework} patterns`,
89
- 'New pattern needed',
90
- 'Mix of existing and new',
91
- ];
92
- }
93
- }
94
- return [];
95
- }
96
- //# sourceMappingURL=questions.js.map
@@ -1,4 +0,0 @@
1
- import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
- import type { ClarifyRequirementsInput, ToolResult } from '../types/index.js';
3
- export declare function handleClarifyRequirements(params: ClarifyRequirementsInput, server?: McpServer): Promise<ToolResult>;
4
- //# sourceMappingURL=clarify-requirements.d.ts.map