@planu/cli 0.99.0 → 1.0.1
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/dist/config/license-plans.json +202 -196
- package/dist/engine/agent-orchestrator/coordinator-prompt.d.ts +3 -0
- package/dist/engine/agent-orchestrator/coordinator-prompt.d.ts.map +1 -0
- package/dist/engine/agent-orchestrator/coordinator-prompt.js +38 -0
- package/dist/engine/agent-orchestrator/coordinator-prompt.js.map +1 -0
- package/dist/engine/agent-orchestrator/execution-guide.d.ts +3 -0
- package/dist/engine/agent-orchestrator/execution-guide.d.ts.map +1 -0
- package/dist/engine/agent-orchestrator/execution-guide.js +59 -0
- package/dist/engine/agent-orchestrator/execution-guide.js.map +1 -0
- package/dist/engine/agent-orchestrator/file-partitioner.d.ts +7 -0
- package/dist/engine/agent-orchestrator/file-partitioner.d.ts.map +1 -0
- package/dist/engine/agent-orchestrator/file-partitioner.js +19 -0
- package/dist/engine/agent-orchestrator/file-partitioner.js.map +1 -0
- package/dist/engine/agent-orchestrator/index.d.ts +12 -0
- package/dist/engine/agent-orchestrator/index.d.ts.map +1 -0
- package/dist/engine/agent-orchestrator/index.js +131 -0
- package/dist/engine/agent-orchestrator/index.js.map +1 -0
- package/dist/engine/agent-orchestrator/spec-reader.d.ts +6 -0
- package/dist/engine/agent-orchestrator/spec-reader.d.ts.map +1 -0
- package/dist/engine/agent-orchestrator/spec-reader.js +20 -0
- package/dist/engine/agent-orchestrator/spec-reader.js.map +1 -0
- package/dist/engine/agent-orchestrator/specialist-prompt.d.ts +3 -0
- package/dist/engine/agent-orchestrator/specialist-prompt.d.ts.map +1 -0
- package/dist/engine/agent-orchestrator/specialist-prompt.js +56 -0
- package/dist/engine/agent-orchestrator/specialist-prompt.js.map +1 -0
- package/dist/engine/agent-orchestrator/verifier-prompt.d.ts +3 -0
- package/dist/engine/agent-orchestrator/verifier-prompt.d.ts.map +1 -0
- package/dist/engine/agent-orchestrator/verifier-prompt.js +69 -0
- package/dist/engine/agent-orchestrator/verifier-prompt.js.map +1 -0
- package/dist/engine/filesystem-watcher/index.d.ts +31 -0
- package/dist/engine/filesystem-watcher/index.d.ts.map +1 -0
- package/dist/engine/filesystem-watcher/index.js +101 -0
- package/dist/engine/filesystem-watcher/index.js.map +1 -0
- package/dist/engine/living-specs/criteria-matcher.d.ts +12 -0
- package/dist/engine/living-specs/criteria-matcher.d.ts.map +1 -0
- package/dist/engine/living-specs/criteria-matcher.js +105 -0
- package/dist/engine/living-specs/criteria-matcher.js.map +1 -0
- package/dist/engine/living-specs/file-scanner.d.ts +11 -0
- package/dist/engine/living-specs/file-scanner.d.ts.map +1 -0
- package/dist/engine/living-specs/file-scanner.js +56 -0
- package/dist/engine/living-specs/file-scanner.js.map +1 -0
- package/dist/engine/living-specs/index.d.ts +9 -0
- package/dist/engine/living-specs/index.d.ts.map +1 -0
- package/dist/engine/living-specs/index.js +137 -0
- package/dist/engine/living-specs/index.js.map +1 -0
- package/dist/engine/skills-evaluator/eval-store.d.ts +4 -0
- package/dist/engine/skills-evaluator/eval-store.d.ts.map +1 -0
- package/dist/engine/skills-evaluator/eval-store.js +22 -0
- package/dist/engine/skills-evaluator/eval-store.js.map +1 -0
- package/dist/engine/skills-evaluator/index.d.ts +5 -0
- package/dist/engine/skills-evaluator/index.d.ts.map +1 -0
- package/dist/engine/skills-evaluator/index.js +54 -0
- package/dist/engine/skills-evaluator/index.js.map +1 -0
- package/dist/engine/skills-evaluator/scenario-runner.d.ts +7 -0
- package/dist/engine/skills-evaluator/scenario-runner.d.ts.map +1 -0
- package/dist/engine/skills-evaluator/scenario-runner.js +44 -0
- package/dist/engine/skills-evaluator/scenario-runner.js.map +1 -0
- package/dist/engine/skills-evaluator/skill-reader.d.ts +8 -0
- package/dist/engine/skills-evaluator/skill-reader.d.ts.map +1 -0
- package/dist/engine/skills-evaluator/skill-reader.js +152 -0
- package/dist/engine/skills-evaluator/skill-reader.js.map +1 -0
- package/dist/engine/trial/index.d.ts +25 -0
- package/dist/engine/trial/index.d.ts.map +1 -0
- package/dist/engine/trial/index.js +125 -0
- package/dist/engine/trial/index.js.map +1 -0
- package/dist/engine/trial-engine.d.ts +2 -0
- package/dist/engine/trial-engine.d.ts.map +1 -0
- package/dist/engine/trial-engine.js +3 -0
- package/dist/engine/trial-engine.js.map +1 -0
- package/dist/engine/update-notifier.d.ts +2 -0
- package/dist/engine/update-notifier.d.ts.map +1 -1
- package/dist/engine/update-notifier.js +12 -0
- package/dist/engine/update-notifier.js.map +1 -1
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/storage/trial-store.d.ts +19 -0
- package/dist/storage/trial-store.d.ts.map +1 -0
- package/dist/storage/trial-store.js +50 -0
- package/dist/storage/trial-store.js.map +1 -0
- package/dist/tools/eval-skill-v2-handler.d.ts +3 -0
- package/dist/tools/eval-skill-v2-handler.d.ts.map +1 -0
- package/dist/tools/eval-skill-v2-handler.js +53 -0
- package/dist/tools/eval-skill-v2-handler.js.map +1 -0
- package/dist/tools/filesystem-hooks-handler.d.ts +8 -0
- package/dist/tools/filesystem-hooks-handler.d.ts.map +1 -0
- package/dist/tools/filesystem-hooks-handler.js +96 -0
- package/dist/tools/filesystem-hooks-handler.js.map +1 -0
- package/dist/tools/init-project/handler.js +1 -1
- package/dist/tools/init-project/handler.js.map +1 -1
- package/dist/tools/init-project/result-builder.d.ts +1 -1
- package/dist/tools/init-project/result-builder.d.ts.map +1 -1
- package/dist/tools/init-project/result-builder.js +10 -2
- package/dist/tools/init-project/result-builder.js.map +1 -1
- package/dist/tools/license-status.d.ts.map +1 -1
- package/dist/tools/license-status.js +20 -2
- package/dist/tools/license-status.js.map +1 -1
- package/dist/tools/orchestrate-agents-handler.d.ts +4 -0
- package/dist/tools/orchestrate-agents-handler.d.ts.map +1 -0
- package/dist/tools/orchestrate-agents-handler.js +70 -0
- package/dist/tools/orchestrate-agents-handler.js.map +1 -0
- package/dist/tools/reconcile-spec-living-handler.d.ts +6 -0
- package/dist/tools/reconcile-spec-living-handler.d.ts.map +1 -0
- package/dist/tools/reconcile-spec-living-handler.js +52 -0
- package/dist/tools/reconcile-spec-living-handler.js.map +1 -0
- package/dist/tools/register-filesystem-hooks-tools.d.ts +3 -0
- package/dist/tools/register-filesystem-hooks-tools.d.ts.map +1 -0
- package/dist/tools/register-filesystem-hooks-tools.js +85 -0
- package/dist/tools/register-filesystem-hooks-tools.js.map +1 -0
- package/dist/tools/register-living-specs-tools.d.ts +3 -0
- package/dist/tools/register-living-specs-tools.d.ts.map +1 -0
- package/dist/tools/register-living-specs-tools.js +24 -0
- package/dist/tools/register-living-specs-tools.js.map +1 -0
- package/dist/tools/register-skills-eval-tools.d.ts +3 -0
- package/dist/tools/register-skills-eval-tools.d.ts.map +1 -0
- package/dist/tools/register-skills-eval-tools.js +29 -0
- package/dist/tools/register-skills-eval-tools.js.map +1 -0
- package/dist/tools/register-spec-331-tools.d.ts +3 -0
- package/dist/tools/register-spec-331-tools.d.ts.map +1 -0
- package/dist/tools/register-spec-331-tools.js +37 -0
- package/dist/tools/register-spec-331-tools.js.map +1 -0
- package/dist/tools/register-trial-tools.d.ts +3 -0
- package/dist/tools/register-trial-tools.d.ts.map +1 -0
- package/dist/tools/register-trial-tools.js +16 -0
- package/dist/tools/register-trial-tools.js.map +1 -0
- package/dist/tools/safe-handler.d.ts +3 -0
- package/dist/tools/safe-handler.d.ts.map +1 -1
- package/dist/tools/safe-handler.js +24 -2
- package/dist/tools/safe-handler.js.map +1 -1
- package/dist/tools/status-handler.d.ts.map +1 -1
- package/dist/tools/status-handler.js +9 -2
- package/dist/tools/status-handler.js.map +1 -1
- package/dist/tools/trial-handler.d.ts +5 -0
- package/dist/tools/trial-handler.d.ts.map +1 -0
- package/dist/tools/trial-handler.js +51 -0
- package/dist/tools/trial-handler.js.map +1 -0
- package/dist/tools/update-status/side-effects.d.ts.map +1 -1
- package/dist/tools/update-status/side-effects.js +11 -0
- package/dist/tools/update-status/side-effects.js.map +1 -1
- package/dist/types/agent-orchestration.d.ts +54 -0
- package/dist/types/agent-orchestration.d.ts.map +1 -0
- package/dist/types/agent-orchestration.js +3 -0
- package/dist/types/agent-orchestration.js.map +1 -0
- package/dist/types/filesystem-hooks.d.ts +30 -0
- package/dist/types/filesystem-hooks.d.ts.map +1 -0
- package/dist/types/filesystem-hooks.js +3 -0
- package/dist/types/filesystem-hooks.js.map +1 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/living-specs.d.ts +35 -0
- package/dist/types/living-specs.d.ts.map +1 -0
- package/dist/types/living-specs.js +3 -0
- package/dist/types/living-specs.js.map +1 -0
- package/dist/types/skills-evaluation.d.ts +38 -0
- package/dist/types/skills-evaluation.d.ts.map +1 -0
- package/dist/types/skills-evaluation.js +3 -0
- package/dist/types/skills-evaluation.js.map +1 -0
- package/dist/types/telemetry.d.ts +1 -1
- package/dist/types/telemetry.d.ts.map +1 -1
- package/dist/types/trial.d.ts +41 -0
- package/dist/types/trial.d.ts.map +1 -0
- package/dist/types/trial.js +3 -0
- package/dist/types/trial.js.map +1 -0
- package/package.json +1 -1
- package/src/config/license-plans.json +202 -196
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// engine/agent-orchestrator/index.ts — SPEC-331: Declarative Multi-Agent Orchestration
|
|
2
|
+
// Generates a structured OrchestrationPlan from an approved spec.
|
|
3
|
+
// Pure: no network calls; reads spec data already passed in by the handler.
|
|
4
|
+
import { readFileContent } from './spec-reader.js';
|
|
5
|
+
import { partitionFiles } from './file-partitioner.js';
|
|
6
|
+
import { buildCoordinatorPrompt } from './coordinator-prompt.js';
|
|
7
|
+
import { buildSpecialistPrompt } from './specialist-prompt.js';
|
|
8
|
+
import { buildVerifierPrompt } from './verifier-prompt.js';
|
|
9
|
+
import { buildExecutionGuide } from './execution-guide.js';
|
|
10
|
+
/**
|
|
11
|
+
* Generate a declarative multi-agent orchestration plan from a spec.
|
|
12
|
+
*
|
|
13
|
+
* @param spec - Spec metadata from spec-store
|
|
14
|
+
* @param agentCount - Number of specialist agents (2–8)
|
|
15
|
+
* @param projectPath - Absolute path to the project root
|
|
16
|
+
*/
|
|
17
|
+
export async function generateOrchestrationPlan(spec, agentCount, projectPath) {
|
|
18
|
+
const count = Math.max(2, Math.min(8, agentCount));
|
|
19
|
+
// Read spec markdown content (acceptance criteria, technical file list)
|
|
20
|
+
const specContent = await readFileContent(spec.specPath, projectPath);
|
|
21
|
+
const technicalContent = await readFileContent(spec.technicalPath, projectPath);
|
|
22
|
+
// Extract acceptance criteria lines from spec markdown
|
|
23
|
+
const criteria = extractCriteria(specContent);
|
|
24
|
+
// Extract file list from technical.md (or fall back to logical layers)
|
|
25
|
+
const allFiles = extractFiles(technicalContent);
|
|
26
|
+
// Partition files across N specialist workstreams (non-overlapping)
|
|
27
|
+
const workstreams = partitionFiles(allFiles, count);
|
|
28
|
+
// Build roles
|
|
29
|
+
const roles = [];
|
|
30
|
+
// Wave 1 — Coordinator
|
|
31
|
+
roles.push({
|
|
32
|
+
role: 'coordinator',
|
|
33
|
+
name: 'Coordinator',
|
|
34
|
+
files: [],
|
|
35
|
+
wave: 1,
|
|
36
|
+
prompt: buildCoordinatorPrompt({ spec, specContent, technicalContent, count }),
|
|
37
|
+
});
|
|
38
|
+
// Wave 2 — Specialists (parallel)
|
|
39
|
+
for (let i = 0; i < count; i++) {
|
|
40
|
+
const files = workstreams[i] ?? [];
|
|
41
|
+
const label = deriveLabel(files, i);
|
|
42
|
+
roles.push({
|
|
43
|
+
role: 'specialist',
|
|
44
|
+
name: `Specialist-${String(i + 1)}: ${label}`,
|
|
45
|
+
files,
|
|
46
|
+
wave: 2,
|
|
47
|
+
prompt: buildSpecialistPrompt({
|
|
48
|
+
spec,
|
|
49
|
+
specContent,
|
|
50
|
+
index: i + 1,
|
|
51
|
+
label,
|
|
52
|
+
files,
|
|
53
|
+
criteria,
|
|
54
|
+
totalSpecialists: count,
|
|
55
|
+
}),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
// Wave 3 — Verifier
|
|
59
|
+
roles.push({
|
|
60
|
+
role: 'verifier',
|
|
61
|
+
name: 'Verifier',
|
|
62
|
+
files: allFiles,
|
|
63
|
+
wave: 3,
|
|
64
|
+
prompt: buildVerifierPrompt({ spec, criteria, allFiles }),
|
|
65
|
+
});
|
|
66
|
+
return {
|
|
67
|
+
specId: spec.id,
|
|
68
|
+
specTitle: spec.title,
|
|
69
|
+
agentCount: count,
|
|
70
|
+
totalWaves: 3,
|
|
71
|
+
roles,
|
|
72
|
+
executionGuide: buildExecutionGuide({ spec, count, roles }),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
// Internal helpers
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
function extractCriteria(specContent) {
|
|
79
|
+
const lines = specContent.split('\n');
|
|
80
|
+
return lines
|
|
81
|
+
.filter((l) => /^\s*-\s*\[[ x]\]/.test(l))
|
|
82
|
+
.map((l) => l.replace(/^\s*-\s*\[[ x]\]\s*/, '').trim())
|
|
83
|
+
.filter((l) => l.length > 0);
|
|
84
|
+
}
|
|
85
|
+
function extractFiles(technicalContent) {
|
|
86
|
+
if (!technicalContent) {
|
|
87
|
+
// Fallback to logical layers when no technical.md available
|
|
88
|
+
return ['src/storage/', 'src/engine/', 'src/tools/', 'tests/'];
|
|
89
|
+
}
|
|
90
|
+
const lines = technicalContent.split('\n');
|
|
91
|
+
const files = [];
|
|
92
|
+
const filePattern = /`([^`]+\.[a-zA-Z]+)`|^\s*[-*]\s+(src\/[^\s]+|tests\/[^\s]+)/;
|
|
93
|
+
for (const line of lines) {
|
|
94
|
+
const match = filePattern.exec(line);
|
|
95
|
+
if (match) {
|
|
96
|
+
const candidate = (match[1] ?? match[2] ?? '').trim();
|
|
97
|
+
if (candidate.length > 0 && !files.includes(candidate)) {
|
|
98
|
+
files.push(candidate);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (files.length === 0) {
|
|
103
|
+
return ['src/storage/', 'src/engine/', 'src/tools/', 'tests/'];
|
|
104
|
+
}
|
|
105
|
+
return files;
|
|
106
|
+
}
|
|
107
|
+
function deriveLabel(files, index) {
|
|
108
|
+
if (files.length === 0) {
|
|
109
|
+
return `Workstream ${String(index + 1)}`;
|
|
110
|
+
}
|
|
111
|
+
// Heuristic: derive label from most common path segment
|
|
112
|
+
const segments = files.flatMap((f) => f.split('/').filter(Boolean));
|
|
113
|
+
const freq = new Map();
|
|
114
|
+
for (const seg of segments) {
|
|
115
|
+
freq.set(seg, (freq.get(seg) ?? 0) + 1);
|
|
116
|
+
}
|
|
117
|
+
// Ignore generic segments
|
|
118
|
+
const ignored = new Set(['src', 'tests', 'ts', 'js', 'index']);
|
|
119
|
+
const ranked = [...freq.entries()]
|
|
120
|
+
.filter(([k]) => !ignored.has(k) && k.length > 2)
|
|
121
|
+
.sort((a, b) => b[1] - a[1]);
|
|
122
|
+
const top = ranked[0];
|
|
123
|
+
if (top) {
|
|
124
|
+
return capitalize(top[0]);
|
|
125
|
+
}
|
|
126
|
+
return `Workstream ${String(index + 1)}`;
|
|
127
|
+
}
|
|
128
|
+
function capitalize(s) {
|
|
129
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/engine/agent-orchestrator/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec-reader.d.ts","sourceRoot":"","sources":["../../../src/engine/agent-orchestrator/spec-reader.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC,CAWjB"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// engine/agent-orchestrator/spec-reader.ts — Read spec file content from disk
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
/**
|
|
5
|
+
* Read a spec file's content.
|
|
6
|
+
* Returns empty string if the file does not exist or the path is empty.
|
|
7
|
+
*/
|
|
8
|
+
export async function readFileContent(filePath, projectPath) {
|
|
9
|
+
if (!filePath) {
|
|
10
|
+
return '';
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
const absolute = filePath.startsWith('/') ? filePath : resolve(projectPath, filePath);
|
|
14
|
+
return await readFile(absolute, 'utf-8');
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return '';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=spec-reader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec-reader.js","sourceRoot":"","sources":["../../../src/engine/agent-orchestrator/spec-reader.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAA4B,EAC5B,WAAmB;IAEnB,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QACtF,OAAO,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"specialist-prompt.d.ts","sourceRoot":"","sources":["../../../src/engine/agent-orchestrator/specialist-prompt.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAEhF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,qBAAqB,GAAG,MAAM,CA0D1E"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// engine/agent-orchestrator/specialist-prompt.ts — Build specialist agent prompts
|
|
2
|
+
export function buildSpecialistPrompt(input) {
|
|
3
|
+
const { spec, index, label, files, criteria, totalSpecialists } = input;
|
|
4
|
+
const fileList = files.length > 0
|
|
5
|
+
? files.map((f) => ` - \`${f}\``).join('\n')
|
|
6
|
+
: ' - (See Coordinator workstream breakdown for your assigned files)';
|
|
7
|
+
const criteriaSection = criteria.length > 0
|
|
8
|
+
? criteria.map((c) => `- [ ] ${c}`).join('\n')
|
|
9
|
+
: '- [ ] (Refer to spec.md for your assigned acceptance criteria)';
|
|
10
|
+
return `# Specialist-${String(index)} Agent: ${label} — ${spec.id}: ${spec.title}
|
|
11
|
+
|
|
12
|
+
## Your Role
|
|
13
|
+
You are **Specialist-${String(index)} (${label})** for implementing SPEC **${spec.id}**.
|
|
14
|
+
You work in parallel with ${String(totalSpecialists - 1)} other Specialist(s). Each specialist has exclusive file ownership — you must NOT modify files outside your list.
|
|
15
|
+
|
|
16
|
+
## Model Recommendation
|
|
17
|
+
Use **claude-sonnet** for implementation tasks.
|
|
18
|
+
|
|
19
|
+
## Your Exclusive File Ownership
|
|
20
|
+
${fileList}
|
|
21
|
+
|
|
22
|
+
Do NOT create or modify files outside this list. If you discover a shared dependency, coordinate with the Coordinator's workstream breakdown.
|
|
23
|
+
|
|
24
|
+
## Acceptance Criteria (full list — implement the ones in your workstream)
|
|
25
|
+
${criteriaSection}
|
|
26
|
+
|
|
27
|
+
## Spec Context
|
|
28
|
+
**ID:** ${spec.id}
|
|
29
|
+
**Title:** ${spec.title}
|
|
30
|
+
**Status:** ${spec.status}
|
|
31
|
+
**Risk:** ${spec.risk}
|
|
32
|
+
|
|
33
|
+
## Implementation Instructions
|
|
34
|
+
1. Read the Coordinator's workstream breakdown to understand your exact assigned criteria
|
|
35
|
+
2. Implement ONLY the files in your ownership list above
|
|
36
|
+
3. Write tests alongside implementation (same branch of work)
|
|
37
|
+
4. Follow existing codebase conventions: TypeScript strict mode, ES modules, explicit return types
|
|
38
|
+
5. Use \`import type\` for type-only imports
|
|
39
|
+
6. All types must be defined in \`src/types/\` (not alongside implementation)
|
|
40
|
+
7. Run \`pnpm typecheck && pnpm lint\` before finishing
|
|
41
|
+
|
|
42
|
+
## Success Criteria
|
|
43
|
+
- All acceptance criteria assigned to you are implemented and tested
|
|
44
|
+
- \`pnpm typecheck\` passes with 0 errors
|
|
45
|
+
- \`pnpm lint\` passes with 0 warnings
|
|
46
|
+
- No files modified outside your exclusive ownership list
|
|
47
|
+
- Code coverage for your files ≥ 95%
|
|
48
|
+
|
|
49
|
+
## Output When Done
|
|
50
|
+
Report back:
|
|
51
|
+
1. Files created/modified
|
|
52
|
+
2. Acceptance criteria implemented (checked off)
|
|
53
|
+
3. Any open questions or blockers for the Verifier
|
|
54
|
+
`;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=specialist-prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"specialist-prompt.js","sourceRoot":"","sources":["../../../src/engine/agent-orchestrator/specialist-prompt.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAIlF,MAAM,UAAU,qBAAqB,CAAC,KAA4B;IAChE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,GAAG,KAAK,CAAC;IAExE,MAAM,QAAQ,GACZ,KAAK,CAAC,MAAM,GAAG,CAAC;QACd,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QAC7C,CAAC,CAAC,oEAAoE,CAAC;IAE3E,MAAM,eAAe,GACnB,QAAQ,CAAC,MAAM,GAAG,CAAC;QACjB,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QAC9C,CAAC,CAAC,gEAAgE,CAAC;IAEvE,OAAO,gBAAgB,MAAM,CAAC,KAAK,CAAC,WAAW,KAAK,MAAM,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,KAAK;;;uBAG3D,MAAM,CAAC,KAAK,CAAC,KAAK,KAAK,+BAA+B,IAAI,CAAC,EAAE;4BACxD,MAAM,CAAC,gBAAgB,GAAG,CAAC,CAAC;;;;;;EAMtD,QAAQ;;;;;EAKR,eAAe;;;UAGP,IAAI,CAAC,EAAE;aACJ,IAAI,CAAC,KAAK;cACT,IAAI,CAAC,MAAM;YACb,IAAI,CAAC,IAAI;;;;;;;;;;;;;;;;;;;;;;;CAuBpB,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verifier-prompt.d.ts","sourceRoot":"","sources":["../../../src/engine/agent-orchestrator/verifier-prompt.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAE9E,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM,CAuEtE"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// engine/agent-orchestrator/verifier-prompt.ts — Build verifier agent prompt
|
|
2
|
+
export function buildVerifierPrompt(input) {
|
|
3
|
+
const { spec, criteria, allFiles } = input;
|
|
4
|
+
const criteriaList = criteria.length > 0
|
|
5
|
+
? criteria.map((c) => `- [ ] ${c}`).join('\n')
|
|
6
|
+
: '- [ ] (Read spec.md acceptance criteria section)';
|
|
7
|
+
/* v8 ignore next 3 */
|
|
8
|
+
const fileList = allFiles.length > 0
|
|
9
|
+
? allFiles.map((f) => ` - \`${f}\``).join('\n')
|
|
10
|
+
: ' - (Scan the full project for changes related to this spec)';
|
|
11
|
+
return `# Verifier Agent — ${spec.id}: ${spec.title}
|
|
12
|
+
|
|
13
|
+
## Your Role
|
|
14
|
+
You are the **Verifier** for SPEC **${spec.id}**. You run AFTER all Specialist agents have completed. Your job is to validate that EVERY acceptance criterion has been correctly implemented.
|
|
15
|
+
|
|
16
|
+
## Model Recommendation
|
|
17
|
+
Use **claude-opus** for deep validation and cross-cutting analysis.
|
|
18
|
+
|
|
19
|
+
## Spec Reference
|
|
20
|
+
**ID:** ${spec.id}
|
|
21
|
+
**Title:** ${spec.title}
|
|
22
|
+
**Status:** ${spec.status}
|
|
23
|
+
|
|
24
|
+
## All Acceptance Criteria to Verify
|
|
25
|
+
${criteriaList}
|
|
26
|
+
|
|
27
|
+
## Files to Inspect
|
|
28
|
+
${fileList}
|
|
29
|
+
|
|
30
|
+
## Verification Instructions
|
|
31
|
+
For each acceptance criterion:
|
|
32
|
+
1. Find the implementation in the codebase
|
|
33
|
+
2. Confirm the behavior matches what the criterion specifies
|
|
34
|
+
3. Check edge cases: error paths, empty inputs, boundary values
|
|
35
|
+
4. Verify tests exist and actually cover the criterion
|
|
36
|
+
5. Run \`pnpm typecheck && pnpm lint && pnpm test:coverage\` and confirm all pass
|
|
37
|
+
|
|
38
|
+
## Cross-Cutting Checks
|
|
39
|
+
- No file ownership violations (each specialist only touched their assigned files)
|
|
40
|
+
- No circular imports introduced
|
|
41
|
+
- Type definitions are in \`src/types/\` (not in engine/tools files)
|
|
42
|
+
- All public functions have explicit return types
|
|
43
|
+
- No \`any\` types introduced
|
|
44
|
+
|
|
45
|
+
## Output Report (REQUIRED)
|
|
46
|
+
Produce a Verification Report:
|
|
47
|
+
\`\`\`
|
|
48
|
+
## Verification Report — ${spec.id}
|
|
49
|
+
|
|
50
|
+
### ✅ Criteria Met
|
|
51
|
+
(list each passing criterion with file reference)
|
|
52
|
+
|
|
53
|
+
### ❌ Criteria Missing or Incorrect
|
|
54
|
+
(list each failing criterion with explanation)
|
|
55
|
+
|
|
56
|
+
### Test Coverage
|
|
57
|
+
(summarize coverage results)
|
|
58
|
+
|
|
59
|
+
### Decision: PASS / FAIL
|
|
60
|
+
(if FAIL, list exact actions needed before marking spec done)
|
|
61
|
+
\`\`\`
|
|
62
|
+
|
|
63
|
+
## Success Criteria
|
|
64
|
+
- All acceptance criteria are implemented and verifiably working
|
|
65
|
+
- \`pnpm test:coverage\` passes with coverage ≥ 95%
|
|
66
|
+
- Verification Report is produced with PASS/FAIL decision
|
|
67
|
+
`;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=verifier-prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verifier-prompt.js","sourceRoot":"","sources":["../../../src/engine/agent-orchestrator/verifier-prompt.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAI7E,MAAM,UAAU,mBAAmB,CAAC,KAA0B;IAC5D,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IAE3C,MAAM,YAAY,GAChB,QAAQ,CAAC,MAAM,GAAG,CAAC;QACjB,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QAC9C,CAAC,CAAC,kDAAkD,CAAC;IAEzD,sBAAsB;IACtB,MAAM,QAAQ,GACZ,QAAQ,CAAC,MAAM,GAAG,CAAC;QACjB,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QAChD,CAAC,CAAC,8DAA8D,CAAC;IAErE,OAAO,sBAAsB,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,KAAK;;;sCAGf,IAAI,CAAC,EAAE;;;;;;UAMnC,IAAI,CAAC,EAAE;aACJ,IAAI,CAAC,KAAK;cACT,IAAI,CAAC,MAAM;;;EAGvB,YAAY;;;EAGZ,QAAQ;;;;;;;;;;;;;;;;;;;;2BAoBiB,IAAI,CAAC,EAAE;;;;;;;;;;;;;;;;;;;CAmBjC,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { FsHookConfig, FsHooksConfig, FsHookTriggerEvent, FsHookResult } from '../../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Returns the default hooks configuration (disabled with no hooks).
|
|
4
|
+
*/
|
|
5
|
+
export declare function getDefaultHooksConfig(): FsHooksConfig;
|
|
6
|
+
/**
|
|
7
|
+
* Loads the hooks configuration from `.planu/hooks.json` in the given project path.
|
|
8
|
+
* Returns the default config if the file does not exist.
|
|
9
|
+
*/
|
|
10
|
+
export declare function loadHooksConfig(projectPath: string): Promise<FsHooksConfig>;
|
|
11
|
+
/**
|
|
12
|
+
* Saves the hooks configuration to `.planu/hooks.json` in the given project path.
|
|
13
|
+
* Creates the `.planu` directory if it does not exist.
|
|
14
|
+
*/
|
|
15
|
+
export declare function saveHooksConfig(projectPath: string, config: FsHooksConfig): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Returns true if `filePath` matches the given glob `pattern`.
|
|
18
|
+
* Supports `**` and `*` wildcards.
|
|
19
|
+
*/
|
|
20
|
+
export declare function matchesPattern(filePath: string, pattern: string): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Builds a trigger event for a filesystem hook match.
|
|
23
|
+
*/
|
|
24
|
+
export declare function buildTriggerEvent(event: FsHookConfig['event'], filePath: string, hook: FsHookConfig): FsHookTriggerEvent;
|
|
25
|
+
/**
|
|
26
|
+
* Finds all hooks in `config` that match the given event and file path,
|
|
27
|
+
* and returns the result with triggered events.
|
|
28
|
+
* Does NOT call any tools — pure logic only.
|
|
29
|
+
*/
|
|
30
|
+
export declare function processFileEvent(event: 'on_save' | 'on_create' | 'on_delete', filePath: string, config: FsHooksConfig): FsHookResult;
|
|
31
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/engine/filesystem-watcher/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACb,kBAAkB,EAClB,YAAY,EACb,MAAM,sBAAsB,CAAC;AAI9B;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,aAAa,CAErD;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAQjF;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAK/F;AAsBD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAGzE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,YAAY,CAAC,OAAO,CAAC,EAC5B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,YAAY,GACjB,kBAAkB,CAQpB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,SAAS,GAAG,WAAW,GAAG,WAAW,EAC5C,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,aAAa,GACpB,YAAY,CAuBd"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// engine/filesystem-watcher/index.ts — SPEC-329: Filesystem watcher engine
|
|
2
|
+
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
const HOOKS_FILE = '.planu/hooks.json';
|
|
5
|
+
/**
|
|
6
|
+
* Returns the default hooks configuration (disabled with no hooks).
|
|
7
|
+
*/
|
|
8
|
+
export function getDefaultHooksConfig() {
|
|
9
|
+
return { enabled: false, hooks: [] };
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Loads the hooks configuration from `.planu/hooks.json` in the given project path.
|
|
13
|
+
* Returns the default config if the file does not exist.
|
|
14
|
+
*/
|
|
15
|
+
export async function loadHooksConfig(projectPath) {
|
|
16
|
+
const filePath = join(projectPath, HOOKS_FILE);
|
|
17
|
+
try {
|
|
18
|
+
const raw = await readFile(filePath, 'utf-8');
|
|
19
|
+
return JSON.parse(raw);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return getDefaultHooksConfig();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Saves the hooks configuration to `.planu/hooks.json` in the given project path.
|
|
27
|
+
* Creates the `.planu` directory if it does not exist.
|
|
28
|
+
*/
|
|
29
|
+
export async function saveHooksConfig(projectPath, config) {
|
|
30
|
+
const dir = join(projectPath, '.planu');
|
|
31
|
+
await mkdir(dir, { recursive: true });
|
|
32
|
+
const filePath = join(projectPath, HOOKS_FILE);
|
|
33
|
+
await writeFile(filePath, JSON.stringify(config, null, 2), 'utf-8');
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Converts a glob pattern to a RegExp.
|
|
37
|
+
* Supports `**` (any path segments) and `*` (any characters within a segment).
|
|
38
|
+
* Strategy: split on `*` boundaries to escape non-wildcard parts separately.
|
|
39
|
+
*/
|
|
40
|
+
function patternToRegex(pattern) {
|
|
41
|
+
// Split by ** first, then by *
|
|
42
|
+
const parts = pattern.split('**');
|
|
43
|
+
const regexStr = parts
|
|
44
|
+
.map((part) => {
|
|
45
|
+
// Within each ** segment, handle single *
|
|
46
|
+
return part
|
|
47
|
+
.split('*')
|
|
48
|
+
.map((segment) => segment.replace(/[.+^${}()|[\]\\]/g, '\\$&'))
|
|
49
|
+
.join('[^/]*');
|
|
50
|
+
})
|
|
51
|
+
.join('.*');
|
|
52
|
+
return new RegExp(`^${regexStr}$`);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Returns true if `filePath` matches the given glob `pattern`.
|
|
56
|
+
* Supports `**` and `*` wildcards.
|
|
57
|
+
*/
|
|
58
|
+
export function matchesPattern(filePath, pattern) {
|
|
59
|
+
const regex = patternToRegex(pattern);
|
|
60
|
+
return regex.test(filePath);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Builds a trigger event for a filesystem hook match.
|
|
64
|
+
*/
|
|
65
|
+
export function buildTriggerEvent(event, filePath, hook) {
|
|
66
|
+
return {
|
|
67
|
+
event,
|
|
68
|
+
filePath,
|
|
69
|
+
timestamp: new Date().toISOString(),
|
|
70
|
+
matchedPattern: hook.pattern,
|
|
71
|
+
tool: hook.tool,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Finds all hooks in `config` that match the given event and file path,
|
|
76
|
+
* and returns the result with triggered events.
|
|
77
|
+
* Does NOT call any tools — pure logic only.
|
|
78
|
+
*/
|
|
79
|
+
export function processFileEvent(event, filePath, config) {
|
|
80
|
+
if (!config.enabled) {
|
|
81
|
+
return { triggered: 0, events: [], errors: [] };
|
|
82
|
+
}
|
|
83
|
+
const events = [];
|
|
84
|
+
const errors = [];
|
|
85
|
+
for (const hook of config.hooks) {
|
|
86
|
+
if (hook.event !== event) {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
if (matchesPattern(filePath, hook.pattern)) {
|
|
91
|
+
events.push(buildTriggerEvent(event, filePath, hook));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
96
|
+
errors.push(`Pattern "${hook.pattern}" error: ${msg}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return { triggered: events.length, events, errors };
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/engine/filesystem-watcher/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { LivingSpecFileResult, LivingSpecCriteriaMatch } from '../../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Extract criteria lines from spec.md content.
|
|
4
|
+
* Returns the text after the `- [ ] ` or `- [x] ` prefix.
|
|
5
|
+
*/
|
|
6
|
+
export declare function extractCriteriaLines(specMdContent: string): string[];
|
|
7
|
+
/**
|
|
8
|
+
* Match each criterion against the scanned file results.
|
|
9
|
+
* A criterion is "met" if at least one keyword is found in any file export or path.
|
|
10
|
+
*/
|
|
11
|
+
export declare function matchCriteria(criteriaLines: string[], fileResults: LivingSpecFileResult[]): LivingSpecCriteriaMatch[];
|
|
12
|
+
//# sourceMappingURL=criteria-matcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"criteria-matcher.d.ts","sourceRoot":"","sources":["../../../src/engine/living-specs/criteria-matcher.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AA0C1F;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,CAapE;AAiCD;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,aAAa,EAAE,MAAM,EAAE,EACvB,WAAW,EAAE,oBAAoB,EAAE,GAClC,uBAAuB,EAAE,CAc3B"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
const CRITERIA_LINE_REGEX = /^- \[[ x]\] (.+)$/;
|
|
2
|
+
const STOP_WORDS = new Set([
|
|
3
|
+
'that',
|
|
4
|
+
'this',
|
|
5
|
+
'with',
|
|
6
|
+
'from',
|
|
7
|
+
'have',
|
|
8
|
+
'been',
|
|
9
|
+
'will',
|
|
10
|
+
'should',
|
|
11
|
+
'must',
|
|
12
|
+
'when',
|
|
13
|
+
'then',
|
|
14
|
+
'each',
|
|
15
|
+
'they',
|
|
16
|
+
'their',
|
|
17
|
+
'there',
|
|
18
|
+
'where',
|
|
19
|
+
'which',
|
|
20
|
+
'while',
|
|
21
|
+
'about',
|
|
22
|
+
'after',
|
|
23
|
+
'before',
|
|
24
|
+
'below',
|
|
25
|
+
'above',
|
|
26
|
+
'given',
|
|
27
|
+
'other',
|
|
28
|
+
'more',
|
|
29
|
+
'into',
|
|
30
|
+
'only',
|
|
31
|
+
'also',
|
|
32
|
+
'both',
|
|
33
|
+
'such',
|
|
34
|
+
'some',
|
|
35
|
+
'than',
|
|
36
|
+
'over',
|
|
37
|
+
'under',
|
|
38
|
+
]);
|
|
39
|
+
/**
|
|
40
|
+
* Extract criteria lines from spec.md content.
|
|
41
|
+
* Returns the text after the `- [ ] ` or `- [x] ` prefix.
|
|
42
|
+
*/
|
|
43
|
+
export function extractCriteriaLines(specMdContent) {
|
|
44
|
+
const lines = specMdContent.split('\n');
|
|
45
|
+
const result = [];
|
|
46
|
+
for (const line of lines) {
|
|
47
|
+
const match = CRITERIA_LINE_REGEX.exec(line.trimEnd());
|
|
48
|
+
if (match !== null) {
|
|
49
|
+
const text = match[1];
|
|
50
|
+
if (text !== undefined && text.trim().length > 0) {
|
|
51
|
+
result.push(text.trim());
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Extract meaningful keywords from a criterion string.
|
|
59
|
+
* Words must be longer than 4 chars and not in the stop-words list.
|
|
60
|
+
*/
|
|
61
|
+
function extractKeywords(criterion) {
|
|
62
|
+
return criterion
|
|
63
|
+
.toLowerCase()
|
|
64
|
+
.split(/\W+/)
|
|
65
|
+
.filter((word) => word.length > 4 && !STOP_WORDS.has(word));
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Check if any export name or file path contains a given keyword.
|
|
69
|
+
*/
|
|
70
|
+
function findKeywordInFiles(keyword, fileResults) {
|
|
71
|
+
for (const file of fileResults) {
|
|
72
|
+
if (!file.exists) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (file.path.toLowerCase().includes(keyword)) {
|
|
76
|
+
return file.path;
|
|
77
|
+
}
|
|
78
|
+
for (const exportName of file.exportsFound) {
|
|
79
|
+
if (exportName.toLowerCase().includes(keyword)) {
|
|
80
|
+
return file.path;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Match each criterion against the scanned file results.
|
|
88
|
+
* A criterion is "met" if at least one keyword is found in any file export or path.
|
|
89
|
+
*/
|
|
90
|
+
export function matchCriteria(criteriaLines, fileResults) {
|
|
91
|
+
return criteriaLines.map((criterion) => {
|
|
92
|
+
const keywords = extractKeywords(criterion);
|
|
93
|
+
if (keywords.length === 0) {
|
|
94
|
+
return { criterion, met: false, evidence: 'No match' };
|
|
95
|
+
}
|
|
96
|
+
for (const keyword of keywords) {
|
|
97
|
+
const foundIn = findKeywordInFiles(keyword, fileResults);
|
|
98
|
+
if (foundIn !== null) {
|
|
99
|
+
return { criterion, met: true, evidence: `Found in ${foundIn}` };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return { criterion, met: false, evidence: 'No match' };
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=criteria-matcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"criteria-matcher.js","sourceRoot":"","sources":["../../../src/engine/living-specs/criteria-matcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { LivingSpecFileResult } from '../../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Scan a single file: check existence, count lines, extract exports.
|
|
4
|
+
*/
|
|
5
|
+
export declare function scanFile(filePath: string): Promise<LivingSpecFileResult>;
|
|
6
|
+
/**
|
|
7
|
+
* Extract all file paths referenced in technical.md content (src/ and tests/ paths).
|
|
8
|
+
* Deduplicates results.
|
|
9
|
+
*/
|
|
10
|
+
export declare function extractFilePaths(technicalMdContent: string): string[];
|
|
11
|
+
//# sourceMappingURL=file-scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-scanner.d.ts","sourceRoot":"","sources":["../../../src/engine/living-specs/file-scanner.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAKjE;;GAEG;AACH,wBAAsB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAe9E;AAkBD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,kBAAkB,EAAE,MAAM,GAAG,MAAM,EAAE,CAWrE"}
|