@planu/cli 4.11.2 → 4.11.4
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.
- package/CHANGELOG.md +14 -0
- package/dist/config/elicitation-questions.json +5 -17
- package/dist/engine/elicitation/question-generator.js +10 -3
- package/dist/engine/implementation-contract/evaluator.js +4 -1
- package/dist/engine/implementation-contract/renderer.js +17 -39
- package/dist/engine/lifecycle-hints.d.ts +1 -1
- package/dist/engine/lifecycle-hints.js +13 -29
- package/dist/engine/spec-format/lean-spec-generator.d.ts +2 -2
- package/dist/engine/spec-format/lean-spec-generator.js +9 -10
- package/dist/engine/spec-generator/fallback-generator.js +13 -20
- package/dist/engine/spec-grounding/contract.d.ts +5 -0
- package/dist/engine/spec-grounding/contract.js +10 -6
- package/dist/engine/spec-migrator/lean-migration.js +9 -16
- package/dist/engine/web-fetcher/stack-advisor.d.ts +2 -2
- package/dist/engine/web-fetcher/stack-advisor.js +78 -17
- package/dist/tools/challenge-spec/challenge-report.d.ts +16 -0
- package/dist/tools/challenge-spec/challenge-report.js +120 -0
- package/dist/tools/challenge-spec.js +13 -8
- package/dist/tools/clarify-requirements/multiple-choice.js +1 -1
- package/dist/tools/clarify-requirements/questions-context.js +11 -11
- package/dist/tools/clarify-requirements/questions.js +3 -23
- package/dist/tools/clarify-requirements.js +38 -0
- package/dist/tools/create-spec/autopilot-analyzer.d.ts +1 -1
- package/dist/tools/create-spec/autopilot-analyzer.js +29 -54
- package/dist/tools/create-spec/post-creation.js +23 -4
- package/dist/tools/create-spec.js +47 -144
- package/dist/tools/elicit-requirements-handler.js +20 -12
- package/dist/tools/register-spec-tools/core-spec-tools.js +11 -2
- package/dist/tools/suggest-stack.js +49 -13
- package/dist/tools/update-status/dod-gates.d.ts +8 -0
- package/dist/tools/update-status/dod-gates.js +68 -43
- package/dist/tools/update-status/index.js +109 -74
- package/dist/tools/update-status/qa-gate.js +26 -0
- package/dist/tools/update-status/transition-guard.d.ts +2 -2
- package/dist/tools/update-status/transition-guard.js +14 -7
- package/dist/tools/validate-lint.d.ts +1 -1
- package/dist/tools/validate-lint.js +39 -1
- package/dist/types/spec/core.d.ts +20 -0
- package/dist/types/spec/inputs.d.ts +1 -1
- package/dist/types/stack/index.d.ts +1 -1
- package/dist/types/stack/recommend.d.ts +10 -0
- package/package.json +9 -9
- package/planu-native.json +1 -1
- package/planu-plugin.json +1 -1
- package/dist/engine/elicitation/non-interactive-defaults.d.ts +0 -9
- package/dist/engine/elicitation/non-interactive-defaults.js +0 -28
- package/dist/tools/clarify-requirements/interview-mode.d.ts +0 -42
- package/dist/tools/clarify-requirements/interview-mode.js +0 -342
|
@@ -9,6 +9,9 @@ export async function checkQaGate(spec, projectPath, force) {
|
|
|
9
9
|
if (state?.lastResult?.passed === true) {
|
|
10
10
|
return null;
|
|
11
11
|
}
|
|
12
|
+
if (await hasPassedExternalQaEvidence(spec, projectPath)) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
12
15
|
let effectiveResult = state?.lastResult ?? null;
|
|
13
16
|
if (effectiveResult === null) {
|
|
14
17
|
const { runQaGate } = await import('../../engine/qa-gate.js');
|
|
@@ -47,4 +50,27 @@ export async function checkQaGate(spec, projectPath, force) {
|
|
|
47
50
|
},
|
|
48
51
|
};
|
|
49
52
|
}
|
|
53
|
+
async function hasPassedExternalQaEvidence(spec, projectPath) {
|
|
54
|
+
try {
|
|
55
|
+
const { readEvidenceArtifacts } = await import('../../engine/evidence-gates/artifact-reader.js');
|
|
56
|
+
const artifacts = await readEvidenceArtifacts({
|
|
57
|
+
spec,
|
|
58
|
+
projectId: spec.projectId,
|
|
59
|
+
specId: spec.id,
|
|
60
|
+
projectPath,
|
|
61
|
+
});
|
|
62
|
+
const rows = artifacts.traceabilityMatrix?.rows ?? [];
|
|
63
|
+
return rows.length > 0 && rows.every((row) => isPassedQaEvidence(row.validationEvidence));
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function isPassedQaEvidence(value) {
|
|
70
|
+
if (!value) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
return (/\b(?:pnpm\s+validate|pnpm\s+test|pnpm\s+typecheck)\b[\s\S]{0,120}\bpass(?:ed|ing)?\b/i.test(value) ||
|
|
74
|
+
/\bpass(?:ed|ing)?\b[\s\S]{0,120}\b(?:pnpm\s+validate|pnpm\s+test|pnpm\s+typecheck)\b/i.test(value));
|
|
75
|
+
}
|
|
50
76
|
//# sourceMappingURL=qa-gate.js.map
|
|
@@ -73,10 +73,10 @@ export declare function checkAmbiguityGate(spec: Spec, newStatus: SpecStatus): P
|
|
|
73
73
|
export declare function checkReadinessGate(spec: Spec, newStatus: SpecStatus, forceApprove: boolean | undefined): Promise<ReadinessGateOutput>;
|
|
74
74
|
/**
|
|
75
75
|
* SPEC-964: Challenge gate — block 'review' if challenge_spec was never run
|
|
76
|
-
* or
|
|
76
|
+
* or does not contain enough explicit resolution evidence.
|
|
77
77
|
*
|
|
78
78
|
* - Requires challengeReport to exist on the spec
|
|
79
|
-
* - Requires
|
|
79
|
+
* - Requires explicit mitigation/risk-acceptance evidence for up to the first 3 findings
|
|
80
80
|
* - High-risk specs (high/critical) require all 5 focus areas
|
|
81
81
|
*/
|
|
82
82
|
export declare function checkChallengeGate(spec: Spec, newStatus: SpecStatus): ToolResult | null;
|
|
@@ -9,6 +9,7 @@ import { validateEnglishOnlySpecText } from '../../engine/spec-language/english-
|
|
|
9
9
|
import { checkGroundedSpecContract } from '../../engine/spec-grounding/contract.js';
|
|
10
10
|
import { checkGenericSpecOutput } from '../../engine/spec-quality/generic-output-gate.js';
|
|
11
11
|
import { formatKeyValue } from '../output-formatter.js';
|
|
12
|
+
import { getResolvedChallengeEvidence, requiredResolvedChallenges, } from '../challenge-spec/challenge-report.js';
|
|
12
13
|
/**
|
|
13
14
|
* Valid state transitions for spec lifecycle.
|
|
14
15
|
* draft -> review -> approved -> implementing -> done
|
|
@@ -432,10 +433,10 @@ export async function checkReadinessGate(spec, newStatus, forceApprove) {
|
|
|
432
433
|
}
|
|
433
434
|
/**
|
|
434
435
|
* SPEC-964: Challenge gate — block 'review' if challenge_spec was never run
|
|
435
|
-
* or
|
|
436
|
+
* or does not contain enough explicit resolution evidence.
|
|
436
437
|
*
|
|
437
438
|
* - Requires challengeReport to exist on the spec
|
|
438
|
-
* - Requires
|
|
439
|
+
* - Requires explicit mitigation/risk-acceptance evidence for up to the first 3 findings
|
|
439
440
|
* - High-risk specs (high/critical) require all 5 focus areas
|
|
440
441
|
*/
|
|
441
442
|
export function checkChallengeGate(spec, newStatus) {
|
|
@@ -459,21 +460,27 @@ export function checkChallengeGate(spec, newStatus) {
|
|
|
459
460
|
},
|
|
460
461
|
};
|
|
461
462
|
}
|
|
462
|
-
|
|
463
|
+
const resolutionEvidence = getResolvedChallengeEvidence(report);
|
|
464
|
+
const addressedCount = resolutionEvidence.length;
|
|
465
|
+
const findingsCount = Array.isArray(report.findings)
|
|
466
|
+
? report.findings.length
|
|
467
|
+
: report.totalScenarios;
|
|
468
|
+
const requiredCount = requiredResolvedChallenges(findingsCount);
|
|
469
|
+
if (addressedCount < requiredCount) {
|
|
463
470
|
return {
|
|
464
471
|
content: [
|
|
465
472
|
{
|
|
466
473
|
type: 'text',
|
|
467
|
-
text: `Challenge gate blocked: only ${String(
|
|
474
|
+
text: `Challenge gate blocked: only ${String(addressedCount)} scenario(s) have explicit resolution evidence (minimum ${String(requiredCount)} required). Record mitigation or accepted-risk evidence for discovered findings before retrying.`,
|
|
468
475
|
},
|
|
469
476
|
],
|
|
470
477
|
isError: true,
|
|
471
478
|
structuredContent: {
|
|
472
479
|
error: 'CHALLENGE_GATE_BLOCKED',
|
|
473
480
|
code: 'INSUFFICIENT_CHALLENGES',
|
|
474
|
-
addressedCount
|
|
475
|
-
requiredCount
|
|
476
|
-
fixHint: `
|
|
481
|
+
addressedCount,
|
|
482
|
+
requiredCount,
|
|
483
|
+
fixHint: `Resolve challenge_spec findings with concrete evidence, then retry update_status(specId="${spec.id}", status="review").`,
|
|
477
484
|
},
|
|
478
485
|
};
|
|
479
486
|
}
|
|
@@ -3,6 +3,6 @@ interface LintCheckContext {
|
|
|
3
3
|
projectId?: string;
|
|
4
4
|
specId?: string;
|
|
5
5
|
}
|
|
6
|
-
export declare function runLintCheck(projectPath: string, lintCommand: string | null,
|
|
6
|
+
export declare function runLintCheck(projectPath: string, lintCommand: string | null, context?: LintCheckContext): LintCheckResult;
|
|
7
7
|
export {};
|
|
8
8
|
//# sourceMappingURL=validate-lint.d.ts.map
|
|
@@ -3,6 +3,7 @@ import { execFileSync } from 'node:child_process';
|
|
|
3
3
|
import { createHash } from 'node:crypto';
|
|
4
4
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
5
5
|
import { dirname, join } from 'node:path';
|
|
6
|
+
import { projectDataDir } from '../storage/base-store.js';
|
|
6
7
|
import { formatLintFailureDiagnostics, resolveProjectCommandPlan, runProjectCommandPlan, } from './validate-runtime.js';
|
|
7
8
|
/** Allowlist: alphanumerics, spaces, and safe shell chars. Rejects ; | $ ` & < > */
|
|
8
9
|
const SAFE_COMMAND_RE = /^[\w\s./:@~=-]+$/;
|
|
@@ -39,7 +40,7 @@ function parseLintIssueCount(output) {
|
|
|
39
40
|
}
|
|
40
41
|
return output.split('\n').filter((l) => l.trim().length > 0).length;
|
|
41
42
|
}
|
|
42
|
-
export function runLintCheck(projectPath, lintCommand,
|
|
43
|
+
export function runLintCheck(projectPath, lintCommand, context = {}) {
|
|
43
44
|
if (lintCommand !== null && !isSafeCommand(lintCommand)) {
|
|
44
45
|
console.warn(`[Planu] validate: lintCommand contains unsafe characters — skipping execution`);
|
|
45
46
|
return {
|
|
@@ -50,6 +51,10 @@ export function runLintCheck(projectPath, lintCommand, _context = {}) {
|
|
|
50
51
|
};
|
|
51
52
|
}
|
|
52
53
|
const command = lintCommand ?? 'pnpm lint';
|
|
54
|
+
const externalEvidence = readExternalPassedLintEvidence(context, command);
|
|
55
|
+
if (externalEvidence !== null) {
|
|
56
|
+
return externalEvidence;
|
|
57
|
+
}
|
|
53
58
|
const plan = resolveProjectCommandPlan(projectPath, command);
|
|
54
59
|
const fingerprint = calculateLintFingerprint(projectPath);
|
|
55
60
|
const cached = readPassedLintCache(projectPath, command, fingerprint);
|
|
@@ -77,6 +82,39 @@ export function runLintCheck(projectPath, lintCommand, _context = {}) {
|
|
|
77
82
|
return { passed: false, command, issueCount, output };
|
|
78
83
|
}
|
|
79
84
|
}
|
|
85
|
+
function readExternalPassedLintEvidence(context, command) {
|
|
86
|
+
if (!context.projectId || !context.specId) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
const path = join(projectDataDir(context.projectId), 'handoffs', context.specId, 'traceability-matrix.json');
|
|
91
|
+
if (!existsSync(path)) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
const parsed = JSON.parse(readFileSync(path, 'utf-8'));
|
|
95
|
+
const rows = Array.isArray(parsed.rows) ? parsed.rows : [];
|
|
96
|
+
if (rows.length === 0 ||
|
|
97
|
+
!rows.every((row) => isPassedFullValidationEvidence(row.validationEvidence))) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
passed: true,
|
|
102
|
+
command,
|
|
103
|
+
issueCount: 0,
|
|
104
|
+
output: `(reused external validation evidence from handoffs/${context.specId}/traceability-matrix.json)`,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function isPassedFullValidationEvidence(value) {
|
|
112
|
+
if (typeof value !== 'string') {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
return (/\bpnpm\s+validate\b[\s\S]{0,160}\bpass(?:ed|ing)?\b/i.test(value) ||
|
|
116
|
+
/\bpass(?:ed|ing)?\b[\s\S]{0,160}\bpnpm\s+validate\b/i.test(value));
|
|
117
|
+
}
|
|
80
118
|
function lintCheckTimeoutMs() {
|
|
81
119
|
const raw = process.env.PLANU_VALIDATE_LINT_TIMEOUT_MS;
|
|
82
120
|
if (raw === undefined || raw.trim() === '') {
|
|
@@ -112,6 +112,26 @@ export interface ChallengeReport {
|
|
|
112
112
|
overallRisk: 'low' | 'medium' | 'high' | 'critical';
|
|
113
113
|
/** Whether the challenge passed the mandatory gate. */
|
|
114
114
|
passed: boolean;
|
|
115
|
+
/** Findings discovered by the challenge run and their evidence-derived state. */
|
|
116
|
+
findings?: ChallengeFinding[];
|
|
117
|
+
/** Explicit mitigation or risk-acceptance evidence for resolved findings. */
|
|
118
|
+
resolutionEvidence?: ChallengeResolutionEvidence[];
|
|
119
|
+
}
|
|
120
|
+
export interface ChallengeFinding {
|
|
121
|
+
/** Exact scenario text emitted by challenge_spec. */
|
|
122
|
+
scenario: string;
|
|
123
|
+
/** Derived from matching explicit resolution evidence; discovery alone is never resolution. */
|
|
124
|
+
resolved: boolean;
|
|
125
|
+
}
|
|
126
|
+
export interface ChallengeResolutionEvidence {
|
|
127
|
+
/** Exact scenario text being resolved. */
|
|
128
|
+
scenario: string;
|
|
129
|
+
/** Whether the scenario was mitigated or explicitly accepted as a known risk. */
|
|
130
|
+
resolution: 'mitigated' | 'accepted';
|
|
131
|
+
/** Concrete proof or rationale supporting the resolution. */
|
|
132
|
+
evidence: string;
|
|
133
|
+
/** When the resolution was recorded. */
|
|
134
|
+
resolvedAt: string;
|
|
115
135
|
}
|
|
116
136
|
/** SPEC-630: Model and token budget derived from spec difficulty and devHours. */
|
|
117
137
|
export interface ModelBudget {
|
|
@@ -21,7 +21,7 @@ export interface CreateSpecInput {
|
|
|
21
21
|
* Required when the previous response contained interactiveQuestions[].
|
|
22
22
|
*/
|
|
23
23
|
clarificationAnswers?: Record<string, string>;
|
|
24
|
-
/**
|
|
24
|
+
/** Explicit user-confirmed out-of-scope items. Omitted values are not inferred. */
|
|
25
25
|
outOfScope?: string[];
|
|
26
26
|
/** SPEC-697: Spec ID for agent team findings synthesis path. Required with agentTeamFindings. */
|
|
27
27
|
specId?: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { StackRecommendation, SuggestStackResult, PackageRegistry, DependencyStatus, CheckVersionsResult, SkillFile, GenerateSkillResult, AgentConfig, SubAgentDefinition, GenerateSubAgentResult, GenerateRulesResult, SuggestStackInput, CheckVersionsInput, GenerateSkillInput, GenerateSubAgentInput, GenerateRulesInput, DetectAgentInput, DetectAgentResult, GenerateOrchestrationScriptInput, PlatformConfig, PlatformsConfig, RuleSection, LanguageSignature, FrameworkSignature, PackageManagerSignature, DatabaseSignature, StackSignatures, ArchPatternConfig, ArchPatternsFile, FrameworkConfig, AgentPlatformsConfig, } from './recommend.js';
|
|
1
|
+
export type { StackRecommendation, StackAdviceGrounding, SuggestStackResult, PackageRegistry, DependencyStatus, CheckVersionsResult, SkillFile, GenerateSkillResult, AgentConfig, SubAgentDefinition, GenerateSubAgentResult, GenerateRulesResult, SuggestStackInput, CheckVersionsInput, GenerateSkillInput, GenerateSubAgentInput, GenerateRulesInput, DetectAgentInput, DetectAgentResult, GenerateOrchestrationScriptInput, PlatformConfig, PlatformsConfig, RuleSection, LanguageSignature, FrameworkSignature, PackageManagerSignature, DatabaseSignature, StackSignatures, ArchPatternConfig, ArchPatternsFile, FrameworkConfig, AgentPlatformsConfig, } from './recommend.js';
|
|
2
2
|
export type { DependencyStatusCode, DepSeverity, AuditedDependency, StackHealthScore, StackAuditResult, RuntimeVersionStatus, StackAuditDelta, UpgradeRiskLevel, UpgradeBreakingChange, UpgradePlan, StackAuditConfig, ManifestData, AuditStackOptions, AuditStackInput, PlanUpgradeInput, VulnerableRange, KnownVulnerablePackage, } from './audit.js';
|
|
3
3
|
export type { DeprecationSeverity, DeprecationFinding, DeprecationReport, DeprecationPattern, DetectDeprecationsInput, } from './deprecation.js';
|
|
4
4
|
export type { HypermediaFramework, RenderingMode, TurboSubtype, HypermediaDetectionResult, TemplateEngineSignal, } from './hypermedia.js';
|
|
@@ -26,6 +26,16 @@ export interface SuggestStackResult {
|
|
|
26
26
|
lastChecked: string;
|
|
27
27
|
confidence?: 'high' | 'medium' | 'low';
|
|
28
28
|
}
|
|
29
|
+
export interface StackAdviceGrounding {
|
|
30
|
+
selectionStatus: 'unconfirmed' | 'partially-confirmed';
|
|
31
|
+
detectedEvidence: string[];
|
|
32
|
+
confirmedChoices: {
|
|
33
|
+
field: string;
|
|
34
|
+
value: string;
|
|
35
|
+
source: 'user_confirmation';
|
|
36
|
+
}[];
|
|
37
|
+
candidateNotice: string;
|
|
38
|
+
}
|
|
29
39
|
export type PackageRegistry = 'npm' | 'pypi' | 'crates' | 'go' | 'packagist' | 'pub' | 'nuget' | 'rubygems';
|
|
30
40
|
export interface DependencyStatus {
|
|
31
41
|
name: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@planu/cli",
|
|
3
|
-
"version": "4.11.
|
|
3
|
+
"version": "4.11.4",
|
|
4
4
|
"description": "Planu — MCP Server for Spec Driven Development with native Rust acceleration for hot paths. Cross-platform (Linux/macOS/Windows, x64/arm64, glibc/musl).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -34,14 +34,14 @@
|
|
|
34
34
|
"packageName": "@planu/core"
|
|
35
35
|
},
|
|
36
36
|
"optionalDependencies": {
|
|
37
|
-
"@planu/core-darwin-arm64": "4.11.
|
|
38
|
-
"@planu/core-darwin-x64": "4.11.
|
|
39
|
-
"@planu/core-linux-arm64-gnu": "4.11.
|
|
40
|
-
"@planu/core-linux-arm64-musl": "4.11.
|
|
41
|
-
"@planu/core-linux-x64-gnu": "4.11.
|
|
42
|
-
"@planu/core-linux-x64-musl": "4.11.
|
|
43
|
-
"@planu/core-win32-arm64-msvc": "4.11.
|
|
44
|
-
"@planu/core-win32-x64-msvc": "4.11.
|
|
37
|
+
"@planu/core-darwin-arm64": "4.11.4",
|
|
38
|
+
"@planu/core-darwin-x64": "4.11.4",
|
|
39
|
+
"@planu/core-linux-arm64-gnu": "4.11.4",
|
|
40
|
+
"@planu/core-linux-arm64-musl": "4.11.4",
|
|
41
|
+
"@planu/core-linux-x64-gnu": "4.11.4",
|
|
42
|
+
"@planu/core-linux-x64-musl": "4.11.4",
|
|
43
|
+
"@planu/core-win32-arm64-msvc": "4.11.4",
|
|
44
|
+
"@planu/core-win32-x64-msvc": "4.11.4"
|
|
45
45
|
},
|
|
46
46
|
"engines": {
|
|
47
47
|
"node": ">=24.0.0"
|
package/planu-native.json
CHANGED
package/planu-plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
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": "4.11.
|
|
5
|
+
"version": "4.11.4",
|
|
6
6
|
"icon": "assets/plugin/icon.svg",
|
|
7
7
|
"command": [
|
|
8
8
|
"npx",
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { ElicitRequirementsInput } from '../../types/spec-elicitation.js';
|
|
2
|
-
/** A flat map of question-id -> answer string, matching the shape of parseAnswers() output. */
|
|
3
|
-
export type ParsedAnswers = Record<string, string>;
|
|
4
|
-
/**
|
|
5
|
-
* Build default answers for an elicitation session without any user interaction.
|
|
6
|
-
* Called when mode === 'non-interactive' and answers is empty.
|
|
7
|
-
*/
|
|
8
|
-
export declare function buildDefaultAnswers(input: ElicitRequirementsInput): ParsedAnswers;
|
|
9
|
-
//# sourceMappingURL=non-interactive-defaults.d.ts.map
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
// engine/elicitation/non-interactive-defaults.ts — SPEC-724: Default answers for non-interactive mode.
|
|
2
|
-
// Synthesises a complete ParsedAnswers deterministically from ElicitRequirementsInput,
|
|
3
|
-
// reusing the hasDatabase / isApi heuristics already present in elicit-requirements-handler.ts.
|
|
4
|
-
/**
|
|
5
|
-
* Build default answers for an elicitation session without any user interaction.
|
|
6
|
-
* Called when mode === 'non-interactive' and answers is empty.
|
|
7
|
-
*/
|
|
8
|
-
export function buildDefaultAnswers(input) {
|
|
9
|
-
const desc = input.description.toLowerCase();
|
|
10
|
-
const title = input.title;
|
|
11
|
-
const hasDatabase = desc.includes('data') || desc.includes('store') || desc.includes('database');
|
|
12
|
-
const isApi = desc.includes('api') || desc.includes('endpoint');
|
|
13
|
-
const answers = {
|
|
14
|
-
users: `End users of the ${title} feature`,
|
|
15
|
-
success: `The ${title} feature works correctly and meets the described requirements`,
|
|
16
|
-
scope: input.description,
|
|
17
|
-
edge_cases: 'Handle empty states, invalid input, and network errors gracefully',
|
|
18
|
-
performance: 'Response time under 2 seconds for typical operations',
|
|
19
|
-
};
|
|
20
|
-
if (hasDatabase) {
|
|
21
|
-
answers.data = `Data for ${title} is persisted reliably with proper validation and error handling`;
|
|
22
|
-
}
|
|
23
|
-
if (isApi) {
|
|
24
|
-
answers.api_contract = `API endpoints for ${title} follow RESTful conventions with proper status codes`;
|
|
25
|
-
}
|
|
26
|
-
return answers;
|
|
27
|
-
}
|
|
28
|
-
//# sourceMappingURL=non-interactive-defaults.js.map
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
export type InterviewDimension = 'technical' | 'ux' | 'edge-cases' | 'tradeoffs' | 'security' | 'performance' | 'integration';
|
|
2
|
-
export interface CoverageMap {
|
|
3
|
-
technical: boolean;
|
|
4
|
-
ux: boolean;
|
|
5
|
-
'edge-cases': boolean;
|
|
6
|
-
tradeoffs: boolean;
|
|
7
|
-
security: boolean;
|
|
8
|
-
performance: boolean;
|
|
9
|
-
integration: boolean;
|
|
10
|
-
}
|
|
11
|
-
export interface InterviewState {
|
|
12
|
-
sessionId: string;
|
|
13
|
-
coverageMap: CoverageMap;
|
|
14
|
-
completionPercent: number;
|
|
15
|
-
accumulatedAnswers: Record<string, string>;
|
|
16
|
-
nextDimension: InterviewDimension | null;
|
|
17
|
-
ready: boolean;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Analyzes answers to update which dimensions are covered.
|
|
21
|
-
* Merges with an existing coverage map if provided.
|
|
22
|
-
*/
|
|
23
|
-
export declare function updateCoverageFromAnswers(answers: Record<string, string>, existing?: CoverageMap): CoverageMap;
|
|
24
|
-
/**
|
|
25
|
-
* Returns the lowest-priority uncovered dimension, or null if all are covered.
|
|
26
|
-
*/
|
|
27
|
-
export declare function pickNextDimension(coverage: CoverageMap): InterviewDimension | null;
|
|
28
|
-
/**
|
|
29
|
-
* Generates a targeted follow-up question for a specific dimension.
|
|
30
|
-
* Takes existing answers into account to avoid repeating covered ground.
|
|
31
|
-
*/
|
|
32
|
-
export declare function generateDimensionQuestion(dimension: InterviewDimension, topic: string, answers: Record<string, string>): string;
|
|
33
|
-
/**
|
|
34
|
-
* Computes completion percentage based on how many dimensions are covered (0–100).
|
|
35
|
-
*/
|
|
36
|
-
export declare function computeCompletion(coverage: CoverageMap): number;
|
|
37
|
-
/**
|
|
38
|
-
* Returns true if the topic is too simple for interview mode.
|
|
39
|
-
* Delegates to isShortTopic from questions.ts.
|
|
40
|
-
*/
|
|
41
|
-
export declare function shouldSkipInterview(topic: string): boolean;
|
|
42
|
-
//# sourceMappingURL=interview-mode.d.ts.map
|