@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.
Files changed (166) hide show
  1. package/dist/config/license-plans.json +202 -196
  2. package/dist/engine/agent-orchestrator/coordinator-prompt.d.ts +3 -0
  3. package/dist/engine/agent-orchestrator/coordinator-prompt.d.ts.map +1 -0
  4. package/dist/engine/agent-orchestrator/coordinator-prompt.js +38 -0
  5. package/dist/engine/agent-orchestrator/coordinator-prompt.js.map +1 -0
  6. package/dist/engine/agent-orchestrator/execution-guide.d.ts +3 -0
  7. package/dist/engine/agent-orchestrator/execution-guide.d.ts.map +1 -0
  8. package/dist/engine/agent-orchestrator/execution-guide.js +59 -0
  9. package/dist/engine/agent-orchestrator/execution-guide.js.map +1 -0
  10. package/dist/engine/agent-orchestrator/file-partitioner.d.ts +7 -0
  11. package/dist/engine/agent-orchestrator/file-partitioner.d.ts.map +1 -0
  12. package/dist/engine/agent-orchestrator/file-partitioner.js +19 -0
  13. package/dist/engine/agent-orchestrator/file-partitioner.js.map +1 -0
  14. package/dist/engine/agent-orchestrator/index.d.ts +12 -0
  15. package/dist/engine/agent-orchestrator/index.d.ts.map +1 -0
  16. package/dist/engine/agent-orchestrator/index.js +131 -0
  17. package/dist/engine/agent-orchestrator/index.js.map +1 -0
  18. package/dist/engine/agent-orchestrator/spec-reader.d.ts +6 -0
  19. package/dist/engine/agent-orchestrator/spec-reader.d.ts.map +1 -0
  20. package/dist/engine/agent-orchestrator/spec-reader.js +20 -0
  21. package/dist/engine/agent-orchestrator/spec-reader.js.map +1 -0
  22. package/dist/engine/agent-orchestrator/specialist-prompt.d.ts +3 -0
  23. package/dist/engine/agent-orchestrator/specialist-prompt.d.ts.map +1 -0
  24. package/dist/engine/agent-orchestrator/specialist-prompt.js +56 -0
  25. package/dist/engine/agent-orchestrator/specialist-prompt.js.map +1 -0
  26. package/dist/engine/agent-orchestrator/verifier-prompt.d.ts +3 -0
  27. package/dist/engine/agent-orchestrator/verifier-prompt.d.ts.map +1 -0
  28. package/dist/engine/agent-orchestrator/verifier-prompt.js +69 -0
  29. package/dist/engine/agent-orchestrator/verifier-prompt.js.map +1 -0
  30. package/dist/engine/filesystem-watcher/index.d.ts +31 -0
  31. package/dist/engine/filesystem-watcher/index.d.ts.map +1 -0
  32. package/dist/engine/filesystem-watcher/index.js +101 -0
  33. package/dist/engine/filesystem-watcher/index.js.map +1 -0
  34. package/dist/engine/living-specs/criteria-matcher.d.ts +12 -0
  35. package/dist/engine/living-specs/criteria-matcher.d.ts.map +1 -0
  36. package/dist/engine/living-specs/criteria-matcher.js +105 -0
  37. package/dist/engine/living-specs/criteria-matcher.js.map +1 -0
  38. package/dist/engine/living-specs/file-scanner.d.ts +11 -0
  39. package/dist/engine/living-specs/file-scanner.d.ts.map +1 -0
  40. package/dist/engine/living-specs/file-scanner.js +56 -0
  41. package/dist/engine/living-specs/file-scanner.js.map +1 -0
  42. package/dist/engine/living-specs/index.d.ts +9 -0
  43. package/dist/engine/living-specs/index.d.ts.map +1 -0
  44. package/dist/engine/living-specs/index.js +137 -0
  45. package/dist/engine/living-specs/index.js.map +1 -0
  46. package/dist/engine/skills-evaluator/eval-store.d.ts +4 -0
  47. package/dist/engine/skills-evaluator/eval-store.d.ts.map +1 -0
  48. package/dist/engine/skills-evaluator/eval-store.js +22 -0
  49. package/dist/engine/skills-evaluator/eval-store.js.map +1 -0
  50. package/dist/engine/skills-evaluator/index.d.ts +5 -0
  51. package/dist/engine/skills-evaluator/index.d.ts.map +1 -0
  52. package/dist/engine/skills-evaluator/index.js +54 -0
  53. package/dist/engine/skills-evaluator/index.js.map +1 -0
  54. package/dist/engine/skills-evaluator/scenario-runner.d.ts +7 -0
  55. package/dist/engine/skills-evaluator/scenario-runner.d.ts.map +1 -0
  56. package/dist/engine/skills-evaluator/scenario-runner.js +44 -0
  57. package/dist/engine/skills-evaluator/scenario-runner.js.map +1 -0
  58. package/dist/engine/skills-evaluator/skill-reader.d.ts +8 -0
  59. package/dist/engine/skills-evaluator/skill-reader.d.ts.map +1 -0
  60. package/dist/engine/skills-evaluator/skill-reader.js +152 -0
  61. package/dist/engine/skills-evaluator/skill-reader.js.map +1 -0
  62. package/dist/engine/trial/index.d.ts +25 -0
  63. package/dist/engine/trial/index.d.ts.map +1 -0
  64. package/dist/engine/trial/index.js +125 -0
  65. package/dist/engine/trial/index.js.map +1 -0
  66. package/dist/engine/trial-engine.d.ts +2 -0
  67. package/dist/engine/trial-engine.d.ts.map +1 -0
  68. package/dist/engine/trial-engine.js +3 -0
  69. package/dist/engine/trial-engine.js.map +1 -0
  70. package/dist/engine/update-notifier.d.ts +2 -0
  71. package/dist/engine/update-notifier.d.ts.map +1 -1
  72. package/dist/engine/update-notifier.js +12 -0
  73. package/dist/engine/update-notifier.js.map +1 -1
  74. package/dist/index.js +10 -0
  75. package/dist/index.js.map +1 -1
  76. package/dist/storage/trial-store.d.ts +19 -0
  77. package/dist/storage/trial-store.d.ts.map +1 -0
  78. package/dist/storage/trial-store.js +50 -0
  79. package/dist/storage/trial-store.js.map +1 -0
  80. package/dist/tools/eval-skill-v2-handler.d.ts +3 -0
  81. package/dist/tools/eval-skill-v2-handler.d.ts.map +1 -0
  82. package/dist/tools/eval-skill-v2-handler.js +53 -0
  83. package/dist/tools/eval-skill-v2-handler.js.map +1 -0
  84. package/dist/tools/filesystem-hooks-handler.d.ts +8 -0
  85. package/dist/tools/filesystem-hooks-handler.d.ts.map +1 -0
  86. package/dist/tools/filesystem-hooks-handler.js +96 -0
  87. package/dist/tools/filesystem-hooks-handler.js.map +1 -0
  88. package/dist/tools/init-project/handler.js +1 -1
  89. package/dist/tools/init-project/handler.js.map +1 -1
  90. package/dist/tools/init-project/result-builder.d.ts +1 -1
  91. package/dist/tools/init-project/result-builder.d.ts.map +1 -1
  92. package/dist/tools/init-project/result-builder.js +10 -2
  93. package/dist/tools/init-project/result-builder.js.map +1 -1
  94. package/dist/tools/license-status.d.ts.map +1 -1
  95. package/dist/tools/license-status.js +20 -2
  96. package/dist/tools/license-status.js.map +1 -1
  97. package/dist/tools/orchestrate-agents-handler.d.ts +4 -0
  98. package/dist/tools/orchestrate-agents-handler.d.ts.map +1 -0
  99. package/dist/tools/orchestrate-agents-handler.js +70 -0
  100. package/dist/tools/orchestrate-agents-handler.js.map +1 -0
  101. package/dist/tools/reconcile-spec-living-handler.d.ts +6 -0
  102. package/dist/tools/reconcile-spec-living-handler.d.ts.map +1 -0
  103. package/dist/tools/reconcile-spec-living-handler.js +52 -0
  104. package/dist/tools/reconcile-spec-living-handler.js.map +1 -0
  105. package/dist/tools/register-filesystem-hooks-tools.d.ts +3 -0
  106. package/dist/tools/register-filesystem-hooks-tools.d.ts.map +1 -0
  107. package/dist/tools/register-filesystem-hooks-tools.js +85 -0
  108. package/dist/tools/register-filesystem-hooks-tools.js.map +1 -0
  109. package/dist/tools/register-living-specs-tools.d.ts +3 -0
  110. package/dist/tools/register-living-specs-tools.d.ts.map +1 -0
  111. package/dist/tools/register-living-specs-tools.js +24 -0
  112. package/dist/tools/register-living-specs-tools.js.map +1 -0
  113. package/dist/tools/register-skills-eval-tools.d.ts +3 -0
  114. package/dist/tools/register-skills-eval-tools.d.ts.map +1 -0
  115. package/dist/tools/register-skills-eval-tools.js +29 -0
  116. package/dist/tools/register-skills-eval-tools.js.map +1 -0
  117. package/dist/tools/register-spec-331-tools.d.ts +3 -0
  118. package/dist/tools/register-spec-331-tools.d.ts.map +1 -0
  119. package/dist/tools/register-spec-331-tools.js +37 -0
  120. package/dist/tools/register-spec-331-tools.js.map +1 -0
  121. package/dist/tools/register-trial-tools.d.ts +3 -0
  122. package/dist/tools/register-trial-tools.d.ts.map +1 -0
  123. package/dist/tools/register-trial-tools.js +16 -0
  124. package/dist/tools/register-trial-tools.js.map +1 -0
  125. package/dist/tools/safe-handler.d.ts +3 -0
  126. package/dist/tools/safe-handler.d.ts.map +1 -1
  127. package/dist/tools/safe-handler.js +24 -2
  128. package/dist/tools/safe-handler.js.map +1 -1
  129. package/dist/tools/status-handler.d.ts.map +1 -1
  130. package/dist/tools/status-handler.js +9 -2
  131. package/dist/tools/status-handler.js.map +1 -1
  132. package/dist/tools/trial-handler.d.ts +5 -0
  133. package/dist/tools/trial-handler.d.ts.map +1 -0
  134. package/dist/tools/trial-handler.js +51 -0
  135. package/dist/tools/trial-handler.js.map +1 -0
  136. package/dist/tools/update-status/side-effects.d.ts.map +1 -1
  137. package/dist/tools/update-status/side-effects.js +11 -0
  138. package/dist/tools/update-status/side-effects.js.map +1 -1
  139. package/dist/types/agent-orchestration.d.ts +54 -0
  140. package/dist/types/agent-orchestration.d.ts.map +1 -0
  141. package/dist/types/agent-orchestration.js +3 -0
  142. package/dist/types/agent-orchestration.js.map +1 -0
  143. package/dist/types/filesystem-hooks.d.ts +30 -0
  144. package/dist/types/filesystem-hooks.d.ts.map +1 -0
  145. package/dist/types/filesystem-hooks.js +3 -0
  146. package/dist/types/filesystem-hooks.js.map +1 -0
  147. package/dist/types/index.d.ts +5 -0
  148. package/dist/types/index.d.ts.map +1 -1
  149. package/dist/types/index.js +5 -0
  150. package/dist/types/index.js.map +1 -1
  151. package/dist/types/living-specs.d.ts +35 -0
  152. package/dist/types/living-specs.d.ts.map +1 -0
  153. package/dist/types/living-specs.js +3 -0
  154. package/dist/types/living-specs.js.map +1 -0
  155. package/dist/types/skills-evaluation.d.ts +38 -0
  156. package/dist/types/skills-evaluation.d.ts.map +1 -0
  157. package/dist/types/skills-evaluation.js +3 -0
  158. package/dist/types/skills-evaluation.js.map +1 -0
  159. package/dist/types/telemetry.d.ts +1 -1
  160. package/dist/types/telemetry.d.ts.map +1 -1
  161. package/dist/types/trial.d.ts +41 -0
  162. package/dist/types/trial.d.ts.map +1 -0
  163. package/dist/types/trial.js +3 -0
  164. package/dist/types/trial.js.map +1 -0
  165. package/package.json +1 -1
  166. 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":"AAAA,uFAAuF;AACvF,kEAAkE;AAClE,4EAA4E;AAI5E,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAI3D;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,IAAU,EACV,UAAkB,EAClB,WAAmB;IAEnB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;IAEnD,wEAAwE;IACxE,MAAM,WAAW,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IACtE,MAAM,gBAAgB,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;IAEhF,uDAAuD;IACvD,MAAM,QAAQ,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IAE9C,uEAAuE;IACvE,MAAM,QAAQ,GAAG,YAAY,CAAC,gBAAgB,CAAC,CAAC;IAEhD,oEAAoE;IACpE,MAAM,WAAW,GAAG,cAAc,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAEpD,cAAc;IACd,MAAM,KAAK,GAA4B,EAAE,CAAC;IAE1C,uBAAuB;IACvB,KAAK,CAAC,IAAI,CAAC;QACT,IAAI,EAAE,aAAa;QACnB,IAAI,EAAE,aAAa;QACnB,KAAK,EAAE,EAAE;QACT,IAAI,EAAE,CAAC;QACP,MAAM,EAAE,sBAAsB,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,gBAAgB,EAAE,KAAK,EAAE,CAAC;KAC/E,CAAC,CAAC;IAEH,kCAAkC;IAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,WAAW,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACnC,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QACpC,KAAK,CAAC,IAAI,CAAC;YACT,IAAI,EAAE,YAAY;YAClB,IAAI,EAAE,cAAc,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,KAAK,EAAE;YAC7C,KAAK;YACL,IAAI,EAAE,CAAC;YACP,MAAM,EAAE,qBAAqB,CAAC;gBAC5B,IAAI;gBACJ,WAAW;gBACX,KAAK,EAAE,CAAC,GAAG,CAAC;gBACZ,KAAK;gBACL,KAAK;gBACL,QAAQ;gBACR,gBAAgB,EAAE,KAAK;aACxB,CAAC;SACH,CAAC,CAAC;IACL,CAAC;IAED,oBAAoB;IACpB,KAAK,CAAC,IAAI,CAAC;QACT,IAAI,EAAE,UAAU;QAChB,IAAI,EAAE,UAAU;QAChB,KAAK,EAAE,QAAQ;QACf,IAAI,EAAE,CAAC;QACP,MAAM,EAAE,mBAAmB,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;KAC1D,CAAC,CAAC;IAEH,OAAO;QACL,MAAM,EAAE,IAAI,CAAC,EAAE;QACf,SAAS,EAAE,IAAI,CAAC,KAAK;QACrB,UAAU,EAAE,KAAK;QACjB,UAAU,EAAE,CAAC;QACb,KAAK;QACL,cAAc,EAAE,mBAAmB,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;KAC5D,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E,SAAS,eAAe,CAAC,WAAmB;IAC1C,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACtC,OAAO,KAAK;SACT,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;SACzC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,qBAAqB,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;SACvD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,YAAY,CAAC,gBAAwB;IAC5C,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,4DAA4D;QAC5D,OAAO,CAAC,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;IACjE,CAAC;IAED,MAAM,KAAK,GAAG,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,WAAW,GAAG,6DAA6D,CAAC;IAElF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,SAAS,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;YACtD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;gBACvD,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,CAAC,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;IACjE,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,WAAW,CAAC,KAAe,EAAE,KAAa;IACjD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,cAAc,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,CAAC;IAC3C,CAAC;IAED,wDAAwD;IACxD,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IACpE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;IACvC,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1C,CAAC;IAED,0BAA0B;IAC1B,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;SAC/B,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;SAChD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE/B,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACtB,IAAI,GAAG,EAAE,CAAC;QACR,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,cAAc,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,CAAC;AAC3C,CAAC;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Read a spec file's content.
3
+ * Returns empty string if the file does not exist or the path is empty.
4
+ */
5
+ export declare function readFileContent(filePath: string | undefined, projectPath: string): Promise<string>;
6
+ //# sourceMappingURL=spec-reader.d.ts.map
@@ -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,3 @@
1
+ import type { SpecialistPromptInput } from '../../types/agent-orchestration.js';
2
+ export declare function buildSpecialistPrompt(input: SpecialistPromptInput): string;
3
+ //# sourceMappingURL=specialist-prompt.d.ts.map
@@ -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,3 @@
1
+ import type { VerifierPromptInput } from '../../types/agent-orchestration.js';
2
+ export declare function buildVerifierPrompt(input: VerifierPromptInput): string;
3
+ //# sourceMappingURL=verifier-prompt.d.ts.map
@@ -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"}