@encore-os/eos-spec 0.3.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 (256) hide show
  1. package/LICENSE +17 -0
  2. package/bin/check-dist-fresh.js +51 -0
  3. package/bin/eos-spec.js +7 -0
  4. package/dist/commands/ac-backfill.d.ts +31 -0
  5. package/dist/commands/ac-backfill.js +198 -0
  6. package/dist/commands/ac-backfill.js.map +1 -0
  7. package/dist/commands/archive.d.ts +2 -0
  8. package/dist/commands/archive.js +101 -0
  9. package/dist/commands/archive.js.map +1 -0
  10. package/dist/commands/audit.d.ts +30 -0
  11. package/dist/commands/audit.js +107 -0
  12. package/dist/commands/audit.js.map +1 -0
  13. package/dist/commands/backfill.d.ts +41 -0
  14. package/dist/commands/backfill.js +239 -0
  15. package/dist/commands/backfill.js.map +1 -0
  16. package/dist/commands/checkArtifacts.d.ts +2 -0
  17. package/dist/commands/checkArtifacts.js +48 -0
  18. package/dist/commands/checkArtifacts.js.map +1 -0
  19. package/dist/commands/checkPlacement.d.ts +2 -0
  20. package/dist/commands/checkPlacement.js +31 -0
  21. package/dist/commands/checkPlacement.js.map +1 -0
  22. package/dist/commands/claim.d.ts +4 -0
  23. package/dist/commands/claim.js +46 -0
  24. package/dist/commands/claim.js.map +1 -0
  25. package/dist/commands/complete.d.ts +2 -0
  26. package/dist/commands/complete.js +138 -0
  27. package/dist/commands/complete.js.map +1 -0
  28. package/dist/commands/conformance.d.ts +23 -0
  29. package/dist/commands/conformance.js +124 -0
  30. package/dist/commands/conformance.js.map +1 -0
  31. package/dist/commands/create.d.ts +6 -0
  32. package/dist/commands/create.js +277 -0
  33. package/dist/commands/create.js.map +1 -0
  34. package/dist/commands/deferred.d.ts +2 -0
  35. package/dist/commands/deferred.js +85 -0
  36. package/dist/commands/deferred.js.map +1 -0
  37. package/dist/commands/delta.d.ts +17 -0
  38. package/dist/commands/delta.js +292 -0
  39. package/dist/commands/delta.js.map +1 -0
  40. package/dist/commands/freshness.d.ts +13 -0
  41. package/dist/commands/freshness.js +72 -0
  42. package/dist/commands/freshness.js.map +1 -0
  43. package/dist/commands/funnel.d.ts +2 -0
  44. package/dist/commands/funnel.js +61 -0
  45. package/dist/commands/funnel.js.map +1 -0
  46. package/dist/commands/gen-tests.d.ts +2 -0
  47. package/dist/commands/gen-tests.js +53 -0
  48. package/dist/commands/gen-tests.js.map +1 -0
  49. package/dist/commands/init.d.ts +2 -0
  50. package/dist/commands/init.js +64 -0
  51. package/dist/commands/init.js.map +1 -0
  52. package/dist/commands/list.d.ts +9 -0
  53. package/dist/commands/list.js +61 -0
  54. package/dist/commands/list.js.map +1 -0
  55. package/dist/commands/metrics.d.ts +2 -0
  56. package/dist/commands/metrics.js +66 -0
  57. package/dist/commands/metrics.js.map +1 -0
  58. package/dist/commands/next.d.ts +48 -0
  59. package/dist/commands/next.js +344 -0
  60. package/dist/commands/next.js.map +1 -0
  61. package/dist/commands/precedent.d.ts +66 -0
  62. package/dist/commands/precedent.js +343 -0
  63. package/dist/commands/precedent.js.map +1 -0
  64. package/dist/commands/ready.d.ts +28 -0
  65. package/dist/commands/ready.js +147 -0
  66. package/dist/commands/ready.js.map +1 -0
  67. package/dist/commands/reconcile.d.ts +44 -0
  68. package/dist/commands/reconcile.js +187 -0
  69. package/dist/commands/reconcile.js.map +1 -0
  70. package/dist/commands/rollup.d.ts +2 -0
  71. package/dist/commands/rollup.js +43 -0
  72. package/dist/commands/rollup.js.map +1 -0
  73. package/dist/commands/scorecard.d.ts +11 -0
  74. package/dist/commands/scorecard.js +55 -0
  75. package/dist/commands/scorecard.js.map +1 -0
  76. package/dist/commands/signoff.d.ts +2 -0
  77. package/dist/commands/signoff.js +114 -0
  78. package/dist/commands/signoff.js.map +1 -0
  79. package/dist/commands/status.d.ts +2 -0
  80. package/dist/commands/status.js +100 -0
  81. package/dist/commands/status.js.map +1 -0
  82. package/dist/commands/tasks.d.ts +13 -0
  83. package/dist/commands/tasks.js +81 -0
  84. package/dist/commands/tasks.js.map +1 -0
  85. package/dist/commands/validate.d.ts +16 -0
  86. package/dist/commands/validate.js +89 -0
  87. package/dist/commands/validate.js.map +1 -0
  88. package/dist/commands/verify-acs.d.ts +15 -0
  89. package/dist/commands/verify-acs.js +196 -0
  90. package/dist/commands/verify-acs.js.map +1 -0
  91. package/dist/commands/verifyRollout.d.ts +2 -0
  92. package/dist/commands/verifyRollout.js +125 -0
  93. package/dist/commands/verifyRollout.js.map +1 -0
  94. package/dist/index.d.ts +21 -0
  95. package/dist/index.js +138 -0
  96. package/dist/index.js.map +1 -0
  97. package/dist/lib/ac-draft-prompt.d.ts +18 -0
  98. package/dist/lib/ac-draft-prompt.js +38 -0
  99. package/dist/lib/ac-draft-prompt.js.map +1 -0
  100. package/dist/lib/ac-response-parser.d.ts +18 -0
  101. package/dist/lib/ac-response-parser.js +57 -0
  102. package/dist/lib/ac-response-parser.js.map +1 -0
  103. package/dist/lib/ai-call.d.ts +13 -0
  104. package/dist/lib/ai-call.js +17 -0
  105. package/dist/lib/ai-call.js.map +1 -0
  106. package/dist/lib/archive.d.ts +21 -0
  107. package/dist/lib/archive.js +136 -0
  108. package/dist/lib/archive.js.map +1 -0
  109. package/dist/lib/artifact-integrity.d.ts +5 -0
  110. package/dist/lib/artifact-integrity.js +65 -0
  111. package/dist/lib/artifact-integrity.js.map +1 -0
  112. package/dist/lib/backfill-queue.d.ts +11 -0
  113. package/dist/lib/backfill-queue.js +14 -0
  114. package/dist/lib/backfill-queue.js.map +1 -0
  115. package/dist/lib/blockers.d.ts +66 -0
  116. package/dist/lib/blockers.js +103 -0
  117. package/dist/lib/blockers.js.map +1 -0
  118. package/dist/lib/claims.d.ts +39 -0
  119. package/dist/lib/claims.js +133 -0
  120. package/dist/lib/claims.js.map +1 -0
  121. package/dist/lib/classify-debt.d.ts +17 -0
  122. package/dist/lib/classify-debt.js +13 -0
  123. package/dist/lib/classify-debt.js.map +1 -0
  124. package/dist/lib/code-evidence.d.ts +35 -0
  125. package/dist/lib/code-evidence.js +171 -0
  126. package/dist/lib/code-evidence.js.map +1 -0
  127. package/dist/lib/coherence.d.ts +14 -0
  128. package/dist/lib/coherence.js +188 -0
  129. package/dist/lib/coherence.js.map +1 -0
  130. package/dist/lib/completion-gate.d.ts +17 -0
  131. package/dist/lib/completion-gate.js +28 -0
  132. package/dist/lib/completion-gate.js.map +1 -0
  133. package/dist/lib/compliance-signoff.d.ts +39 -0
  134. package/dist/lib/compliance-signoff.js +81 -0
  135. package/dist/lib/compliance-signoff.js.map +1 -0
  136. package/dist/lib/config.d.ts +63 -0
  137. package/dist/lib/config.js +40 -0
  138. package/dist/lib/config.js.map +1 -0
  139. package/dist/lib/cost.d.ts +12 -0
  140. package/dist/lib/cost.js +12 -0
  141. package/dist/lib/cost.js.map +1 -0
  142. package/dist/lib/debt-dashboard.d.ts +25 -0
  143. package/dist/lib/debt-dashboard.js +36 -0
  144. package/dist/lib/debt-dashboard.js.map +1 -0
  145. package/dist/lib/embedding-store.d.ts +103 -0
  146. package/dist/lib/embedding-store.js +133 -0
  147. package/dist/lib/embedding-store.js.map +1 -0
  148. package/dist/lib/embeddings-source.d.ts +36 -0
  149. package/dist/lib/embeddings-source.js +62 -0
  150. package/dist/lib/embeddings-source.js.map +1 -0
  151. package/dist/lib/enforcement-allowlist.d.ts +12 -0
  152. package/dist/lib/enforcement-allowlist.js +25 -0
  153. package/dist/lib/enforcement-allowlist.js.map +1 -0
  154. package/dist/lib/events.d.ts +47 -0
  155. package/dist/lib/events.js +75 -0
  156. package/dist/lib/events.js.map +1 -0
  157. package/dist/lib/exec.d.ts +8 -0
  158. package/dist/lib/exec.js +25 -0
  159. package/dist/lib/exec.js.map +1 -0
  160. package/dist/lib/frontmatter.d.ts +112 -0
  161. package/dist/lib/frontmatter.js +261 -0
  162. package/dist/lib/frontmatter.js.map +1 -0
  163. package/dist/lib/funnel.d.ts +22 -0
  164. package/dist/lib/funnel.js +41 -0
  165. package/dist/lib/funnel.js.map +1 -0
  166. package/dist/lib/git-mtime.d.ts +4 -0
  167. package/dist/lib/git-mtime.js +23 -0
  168. package/dist/lib/git-mtime.js.map +1 -0
  169. package/dist/lib/metrics.d.ts +42 -0
  170. package/dist/lib/metrics.js +92 -0
  171. package/dist/lib/metrics.js.map +1 -0
  172. package/dist/lib/migration-collision.d.ts +20 -0
  173. package/dist/lib/migration-collision.js +61 -0
  174. package/dist/lib/migration-collision.js.map +1 -0
  175. package/dist/lib/next-action.d.ts +44 -0
  176. package/dist/lib/next-action.js +138 -0
  177. package/dist/lib/next-action.js.map +1 -0
  178. package/dist/lib/ollama-embed.d.ts +21 -0
  179. package/dist/lib/ollama-embed.js +65 -0
  180. package/dist/lib/ollama-embed.js.map +1 -0
  181. package/dist/lib/output.d.ts +35 -0
  182. package/dist/lib/output.js +46 -0
  183. package/dist/lib/output.js.map +1 -0
  184. package/dist/lib/pipeline-config.d.ts +20 -0
  185. package/dist/lib/pipeline-config.js +208 -0
  186. package/dist/lib/pipeline-config.js.map +1 -0
  187. package/dist/lib/pipeline-map.d.ts +68 -0
  188. package/dist/lib/pipeline-map.js +256 -0
  189. package/dist/lib/pipeline-map.js.map +1 -0
  190. package/dist/lib/pipeline-schema.d.ts +48 -0
  191. package/dist/lib/pipeline-schema.js +22 -0
  192. package/dist/lib/pipeline-schema.js.map +1 -0
  193. package/dist/lib/placement.d.ts +6 -0
  194. package/dist/lib/placement.js +40 -0
  195. package/dist/lib/placement.js.map +1 -0
  196. package/dist/lib/precedent-search.d.ts +18 -0
  197. package/dist/lib/precedent-search.js +160 -0
  198. package/dist/lib/precedent-search.js.map +1 -0
  199. package/dist/lib/predicate-registry.d.ts +6 -0
  200. package/dist/lib/predicate-registry.js +40 -0
  201. package/dist/lib/predicate-registry.js.map +1 -0
  202. package/dist/lib/recall-cases.d.ts +15 -0
  203. package/dist/lib/recall-cases.js +39 -0
  204. package/dist/lib/recall-cases.js.map +1 -0
  205. package/dist/lib/repo.d.ts +20 -0
  206. package/dist/lib/repo.js +82 -0
  207. package/dist/lib/repo.js.map +1 -0
  208. package/dist/lib/requirements.d.ts +91 -0
  209. package/dist/lib/requirements.js +179 -0
  210. package/dist/lib/requirements.js.map +1 -0
  211. package/dist/lib/rollup.d.ts +24 -0
  212. package/dist/lib/rollup.js +34 -0
  213. package/dist/lib/rollup.js.map +1 -0
  214. package/dist/lib/scorecard-run.d.ts +6 -0
  215. package/dist/lib/scorecard-run.js +48 -0
  216. package/dist/lib/scorecard-run.js.map +1 -0
  217. package/dist/lib/scorecard.d.ts +69 -0
  218. package/dist/lib/scorecard.js +113 -0
  219. package/dist/lib/scorecard.js.map +1 -0
  220. package/dist/lib/semantic-search.d.ts +36 -0
  221. package/dist/lib/semantic-search.js +56 -0
  222. package/dist/lib/semantic-search.js.map +1 -0
  223. package/dist/lib/session-state.d.ts +8 -0
  224. package/dist/lib/session-state.js +25 -0
  225. package/dist/lib/session-state.js.map +1 -0
  226. package/dist/lib/spec-debt.d.ts +8 -0
  227. package/dist/lib/spec-debt.js +17 -0
  228. package/dist/lib/spec-debt.js.map +1 -0
  229. package/dist/lib/spec-pure.d.ts +59 -0
  230. package/dist/lib/spec-pure.js +215 -0
  231. package/dist/lib/spec-pure.js.map +1 -0
  232. package/dist/lib/specs.d.ts +148 -0
  233. package/dist/lib/specs.js +373 -0
  234. package/dist/lib/specs.js.map +1 -0
  235. package/dist/lib/test-generator.d.ts +5 -0
  236. package/dist/lib/test-generator.js +72 -0
  237. package/dist/lib/test-generator.js.map +1 -0
  238. package/dist/lib/user-stories.d.ts +6 -0
  239. package/dist/lib/user-stories.js +56 -0
  240. package/dist/lib/user-stories.js.map +1 -0
  241. package/dist/lib/verifies-scan.d.ts +9 -0
  242. package/dist/lib/verifies-scan.js +73 -0
  243. package/dist/lib/verifies-scan.js.map +1 -0
  244. package/dist/lib/verify-core.d.ts +23 -0
  245. package/dist/lib/verify-core.js +48 -0
  246. package/dist/lib/verify-core.js.map +1 -0
  247. package/dist/lib/with-event-log.d.ts +12 -0
  248. package/dist/lib/with-event-log.js +65 -0
  249. package/dist/lib/with-event-log.js.map +1 -0
  250. package/dist/lib/wizard-specs.d.ts +17 -0
  251. package/dist/lib/wizard-specs.js +34 -0
  252. package/dist/lib/wizard-specs.js.map +1 -0
  253. package/dist/pure.d.ts +19 -0
  254. package/dist/pure.js +31 -0
  255. package/dist/pure.js.map +1 -0
  256. package/package.json +69 -0
@@ -0,0 +1,292 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { loadConfig } from '../lib/config.js';
3
+ import { runScript } from '../lib/exec.js';
4
+ import { ErrorCode, emit, getGlobalOptions } from '../lib/output.js';
5
+ import { getRepoRoot } from '../lib/repo.js';
6
+ import { findSpec } from '../lib/specs.js';
7
+ export function registerDelta(program) {
8
+ const deltaCmd = program
9
+ .command('delta')
10
+ .description('Manage OpenSpec-inspired change delta sections in enhancement specs.');
11
+ deltaCmd
12
+ .command('show')
13
+ .description('Display the Change Delta section from an enhancement spec.')
14
+ .requiredOption('--spec <id>', 'Enhancement spec id (e.g. CL-15-EN-01)')
15
+ .option('--format <fmt>', 'Output format: internal (default) or openspec', 'internal')
16
+ .action(async (options, cmd) => {
17
+ const global = getGlobalOptions(cmd.parent.parent);
18
+ const repoRoot = getRepoRoot(global.repoRoot);
19
+ const spec = findSpec(repoRoot, options.spec);
20
+ if (!spec) {
21
+ emit(global, {
22
+ ok: false,
23
+ error: { code: ErrorCode.SPEC_NOT_FOUND, message: `delta show: spec ${options.spec} not found` },
24
+ data: null,
25
+ text: `delta show: spec ${options.spec} not found`,
26
+ });
27
+ }
28
+ const content = readFileSync(spec.path, 'utf8');
29
+ const delta = parseDeltaSection(content);
30
+ if (!delta) {
31
+ emit(global, {
32
+ ok: false,
33
+ data: { specId: spec.id },
34
+ text: `delta show: no "## Change Delta" section found in ${spec.id}`,
35
+ });
36
+ }
37
+ if (options.format === 'openspec') {
38
+ emit(global, {
39
+ ok: true,
40
+ data: { specId: spec.id, format: 'openspec', delta },
41
+ text: formatOpenSpec(spec.id, delta),
42
+ });
43
+ }
44
+ emit(global, {
45
+ ok: true,
46
+ data: { specId: spec.id, format: 'internal', delta },
47
+ text: formatInternal(spec.id, delta),
48
+ });
49
+ });
50
+ deltaCmd
51
+ .command('validate')
52
+ .description('Validate the Change Delta section against config rules.')
53
+ .requiredOption('--spec <id>', 'Enhancement spec id')
54
+ .action(async (options, cmd) => {
55
+ const global = getGlobalOptions(cmd.parent.parent);
56
+ const repoRoot = getRepoRoot(global.repoRoot);
57
+ const spec = findSpec(repoRoot, options.spec);
58
+ if (!spec) {
59
+ emit(global, {
60
+ ok: false,
61
+ error: { code: ErrorCode.SPEC_NOT_FOUND, message: `delta validate: spec ${options.spec} not found` },
62
+ data: null,
63
+ text: `delta validate: spec ${options.spec} not found`,
64
+ });
65
+ }
66
+ const content = readFileSync(spec.path, 'utf8');
67
+ const delta = parseDeltaSection(content);
68
+ if (!delta) {
69
+ emit(global, {
70
+ ok: false,
71
+ data: { specId: spec.id, issues: ['No "## Change Delta" section found'] },
72
+ text: `delta validate: no Change Delta section in ${spec.id}`,
73
+ });
74
+ }
75
+ const config = loadConfig(repoRoot, global.config);
76
+ const issues = validateDelta(delta, config.delta_types);
77
+ emit(global, {
78
+ ok: issues.length === 0,
79
+ data: { specId: spec.id, issues, delta },
80
+ text: issues.length === 0
81
+ ? `delta validate: ${spec.id} OK`
82
+ : `delta validate: ${spec.id} — ${issues.length} issue(s)\n${issues.map((i) => ` - ${i}`).join('\n')}`,
83
+ exitCode: issues.length === 0 ? 0 : 1,
84
+ });
85
+ });
86
+ deltaCmd
87
+ .command('diff')
88
+ .description('Generate a Change Delta matrix from git diff between two refs.')
89
+ .requiredOption('--spec <id>', 'Spec ID for context')
90
+ .option('--from <ref>', 'Git ref to diff from (default: HEAD~1)', 'HEAD~1')
91
+ .option('--to <ref>', 'Git ref to diff to (default: HEAD)', 'HEAD')
92
+ .action(async (options, cmd) => {
93
+ const global = getGlobalOptions(cmd.parent.parent);
94
+ const repoRoot = getRepoRoot(global.repoRoot);
95
+ const spec = findSpec(repoRoot, options.spec);
96
+ if (!spec) {
97
+ emit(global, {
98
+ ok: false,
99
+ error: { code: ErrorCode.SPEC_NOT_FOUND, message: `delta diff: spec ${options.spec} not found` },
100
+ data: null,
101
+ text: `delta diff: spec ${options.spec} not found`,
102
+ });
103
+ }
104
+ const diffResult = runScript(['git', 'diff', '--name-status', `${options.from}...${options.to}`], repoRoot);
105
+ if (diffResult.exitCode !== 0) {
106
+ emit(global, {
107
+ ok: false,
108
+ data: { stderr: diffResult.stderr },
109
+ text: `delta diff: git diff failed\n${diffResult.stderr}`,
110
+ });
111
+ }
112
+ const matrix = classifyDiffLines(diffResult.stdout, spec.core);
113
+ emit(global, {
114
+ ok: true,
115
+ data: { specId: spec.id, from: options.from, to: options.to, matrix },
116
+ text: formatDiffMatrix(spec.id, options.from, options.to, matrix),
117
+ });
118
+ });
119
+ }
120
+ export function parseDeltaSection(content) {
121
+ const deltaMatch = /## Change Delta[^\n]*\n([\s\S]*?)(?=\n## |\n---\s*$|$)/.exec(content);
122
+ if (!deltaMatch)
123
+ return null;
124
+ const section = deltaMatch[1];
125
+ const typeMatch = /\*\*Type:\*\*\s*(.+)/i.exec(section) ?? /Type:\s*\[([xX ])\]\s*(\w+)/i.exec(section);
126
+ let type = null;
127
+ if (typeMatch) {
128
+ const checked = section.match(/\[\s*[xX]\s*\]\s*(\w+)/g);
129
+ if (checked && checked.length > 0) {
130
+ type = checked
131
+ .map((m) => {
132
+ const w = /\[\s*[xX]\s*\]\s*(\w+)/.exec(m);
133
+ return w?.[1]?.toLowerCase() ?? '';
134
+ })
135
+ .filter(Boolean)
136
+ .join(', ');
137
+ }
138
+ }
139
+ const rows = [];
140
+ const tableRegex = /\|\s*([^|]+?)\s*\|\s*([^|]*?)\s*\|\s*([^|]*?)\s*\|\s*([^|]*?)\s*\|/g;
141
+ let match;
142
+ let headerSkipped = false;
143
+ let separatorSkipped = false;
144
+ while ((match = tableRegex.exec(section)) !== null) {
145
+ const col1 = match[1].trim();
146
+ if (col1 === 'Section' || col1 === '---' || col1.startsWith('-')) {
147
+ if (!headerSkipped) {
148
+ headerSkipped = true;
149
+ continue;
150
+ }
151
+ if (!separatorSkipped) {
152
+ separatorSkipped = true;
153
+ continue;
154
+ }
155
+ }
156
+ if (col1.startsWith('-'))
157
+ continue;
158
+ rows.push({
159
+ section: col1,
160
+ adds: match[2].trim(),
161
+ changes: match[3].trim(),
162
+ removes: match[4].trim(),
163
+ });
164
+ }
165
+ const backwardMatch = /\*\*Backward compatibility:\*\*\s*(.+)/i.exec(section);
166
+ const consumersMatch = /\*\*Consumers affected:\*\*\s*(.+)/i.exec(section);
167
+ return {
168
+ type,
169
+ rows,
170
+ backwardCompatibility: backwardMatch?.[1]?.trim() ?? null,
171
+ consumersAffected: consumersMatch?.[1]?.trim() ?? null,
172
+ };
173
+ }
174
+ export function validateDelta(delta, allowedTypes) {
175
+ const issues = [];
176
+ if (!delta.type) {
177
+ issues.push(`No delta type checked (expected one of: ${allowedTypes.join(', ')})`);
178
+ }
179
+ else {
180
+ const types = delta.type.split(',').map((t) => t.trim());
181
+ for (const t of types) {
182
+ if (!allowedTypes.includes(t)) {
183
+ issues.push(`Unknown delta type "${t}" (allowed: ${allowedTypes.join(', ')})`);
184
+ }
185
+ }
186
+ }
187
+ const hasContent = delta.rows.some((r) => (r.adds && !r.adds.startsWith('_')) ||
188
+ (r.changes && !r.changes.startsWith('_')) ||
189
+ (r.removes && !r.removes.startsWith('_')));
190
+ if (!hasContent) {
191
+ issues.push('All delta rows are empty or placeholders — at least one row must be filled');
192
+ }
193
+ if (delta.type) {
194
+ const types = delta.type.split(',').map((t) => t.trim());
195
+ if (types.includes('breaking') || types.includes('deletion')) {
196
+ if (!delta.backwardCompatibility || delta.backwardCompatibility.toLowerCase().startsWith('yes')) {
197
+ issues.push('Breaking/deletion delta requires "Backward compatibility: No" with a migration path');
198
+ }
199
+ }
200
+ }
201
+ return issues;
202
+ }
203
+ function formatInternal(specId, delta) {
204
+ const lines = [`Change Delta for ${specId}:`, ` Type: ${delta.type ?? '(none)'}`];
205
+ if (delta.rows.length > 0) {
206
+ lines.push(' | Section | Adds | Changes | Removes |');
207
+ lines.push(' |---------|------|---------|---------|');
208
+ for (const r of delta.rows) {
209
+ lines.push(` | ${r.section} | ${r.adds} | ${r.changes} | ${r.removes} |`);
210
+ }
211
+ }
212
+ if (delta.backwardCompatibility)
213
+ lines.push(` Backward compatibility: ${delta.backwardCompatibility}`);
214
+ if (delta.consumersAffected)
215
+ lines.push(` Consumers affected: ${delta.consumersAffected}`);
216
+ return lines.join('\n');
217
+ }
218
+ function formatOpenSpec(specId, delta) {
219
+ const lines = [`# Change Delta for ${specId} (OpenSpec format)`, ''];
220
+ const added = delta.rows.filter((r) => r.adds && !r.adds.startsWith('_'));
221
+ const modified = delta.rows.filter((r) => r.changes && !r.changes.startsWith('_'));
222
+ const removed = delta.rows.filter((r) => r.removes && !r.removes.startsWith('_'));
223
+ if (added.length > 0) {
224
+ lines.push('## ADDED Requirements', '');
225
+ for (const r of added)
226
+ lines.push(`### Requirement: ${r.section}`, '', r.adds, '');
227
+ }
228
+ if (modified.length > 0) {
229
+ lines.push('## MODIFIED Requirements', '');
230
+ for (const r of modified)
231
+ lines.push(`### Requirement: ${r.section}`, '', r.changes, '');
232
+ }
233
+ if (removed.length > 0) {
234
+ lines.push('## REMOVED Requirements', '');
235
+ for (const r of removed)
236
+ lines.push(`### Requirement: ${r.section}`, '', r.removes, '');
237
+ }
238
+ return lines.join('\n');
239
+ }
240
+ function classifyDiffLines(diffOutput, _core) {
241
+ const result = { schema: [], permissions: [], api: [], ui: [] };
242
+ for (const line of diffOutput.split('\n')) {
243
+ if (!line.trim())
244
+ continue;
245
+ const parts = line.split('\t');
246
+ if (parts.length < 2)
247
+ continue;
248
+ const status = parts[0];
249
+ const file = parts[parts.length - 1];
250
+ const label = `${status}\t${file}`;
251
+ if (file.includes('migration') || file.includes('.sql') || file.endsWith('.schema.ts')) {
252
+ result.schema.push(label);
253
+ }
254
+ else if (file.includes('rls') || file.includes('policy') || file.includes('permission')) {
255
+ result.permissions.push(label);
256
+ }
257
+ else if (file.includes('/api/') || file.includes('edge-function') || file.includes('supabase/functions')) {
258
+ result.api.push(label);
259
+ }
260
+ else if (file.includes('/components/') || file.includes('/pages/') || file.endsWith('.tsx')) {
261
+ result.ui.push(label);
262
+ }
263
+ }
264
+ return result;
265
+ }
266
+ function formatDiffMatrix(specId, from, to, matrix) {
267
+ const lines = [`delta diff: ${specId} (${from}...${to})`, ''];
268
+ const sections = [
269
+ ['Schema (tables/columns)', matrix.schema],
270
+ ['Permissions / RLS', matrix.permissions],
271
+ ['API / events', matrix.api],
272
+ ['UI surfaces', matrix.ui],
273
+ ];
274
+ lines.push('| Section | Adds | Changes | Removes |');
275
+ lines.push('|---------|------|---------|---------|');
276
+ for (const [name, files] of sections) {
277
+ const adds = files.filter((f) => f.startsWith('A')).length;
278
+ const mods = files.filter((f) => f.startsWith('M')).length;
279
+ const dels = files.filter((f) => f.startsWith('D')).length;
280
+ lines.push(`| ${name} | ${adds || '-'} | ${mods || '-'} | ${dels || '-'} |`);
281
+ }
282
+ lines.push('', 'Files:');
283
+ for (const [name, files] of sections) {
284
+ if (files.length > 0) {
285
+ lines.push(` ${name}:`);
286
+ for (const f of files)
287
+ lines.push(` ${f}`);
288
+ }
289
+ }
290
+ return lines.join('\n');
291
+ }
292
+ //# sourceMappingURL=delta.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delta.js","sourceRoot":"","sources":["../../src/commands/delta.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { Command } from 'commander';
2
+ /**
3
+ * `eos-spec freshness` — semantic-precedent embedding freshness gate.
4
+ *
5
+ * Recomputes the corpus surface hash from the generated specs/spec-index.json and
6
+ * compares it to the committed embedding manifest. The committed vectors power the
7
+ * semantic precedent ranking AND the recall ratchet, so when the corpus drifts the
8
+ * vectors are stale and must be rebuilt. Exits non-zero on drift (or a missing
9
+ * manifest/index) so CI / pre-commit can block, with an actionable rebuild hint.
10
+ *
11
+ * Generate the (gitignored) spec-index.json first via your repo's spec-index step.
12
+ */
13
+ export declare function registerFreshness(program: Command): void;
@@ -0,0 +1,72 @@
1
+ import { embeddingsSourceFromConfig } from '../lib/embeddings-source.js';
2
+ import { ErrorCode, emit, getGlobalOptions } from '../lib/output.js';
3
+ import { getRepoRoot } from '../lib/repo.js';
4
+ const REBUILD_HINT = 'Rebuild the committed embedding vectors for the current corpus (your repo’s build:embeddings step).';
5
+ /**
6
+ * `eos-spec freshness` — semantic-precedent embedding freshness gate.
7
+ *
8
+ * Recomputes the corpus surface hash from the generated specs/spec-index.json and
9
+ * compares it to the committed embedding manifest. The committed vectors power the
10
+ * semantic precedent ranking AND the recall ratchet, so when the corpus drifts the
11
+ * vectors are stale and must be rebuilt. Exits non-zero on drift (or a missing
12
+ * manifest/index) so CI / pre-commit can block, with an actionable rebuild hint.
13
+ *
14
+ * Generate the (gitignored) spec-index.json first via your repo's spec-index step.
15
+ */
16
+ export function registerFreshness(program) {
17
+ program
18
+ .command('freshness')
19
+ .description('Check the committed semantic-precedent embeddings against the current spec corpus. Exits non-zero when the corpus has drifted (rebuild needed) or the manifest/index is missing. Generate specs/spec-index.json first.')
20
+ .action(async (_options, cmd) => {
21
+ const global = getGlobalOptions(cmd);
22
+ const repoRoot = getRepoRoot(global.repoRoot);
23
+ const result = embeddingsSourceFromConfig(repoRoot, global.config).checkFreshness();
24
+ if (result.fresh) {
25
+ emit(global, {
26
+ ok: true,
27
+ data: result,
28
+ text: `embeddings fresh — corpus surface hash matches the committed manifest (${result.currentHash.slice(0, 12)}…)`,
29
+ });
30
+ }
31
+ // Not fresh: distinguish the failure modes so the message is actionable.
32
+ if (result.reason === 'index-missing') {
33
+ emit(global, {
34
+ ok: false,
35
+ error: {
36
+ code: ErrorCode.IO_ERROR,
37
+ message: 'freshness: specs/spec-index.json not found — generate the spec index first',
38
+ },
39
+ data: result,
40
+ text: 'freshness: specs/spec-index.json not found — generate the spec index first.',
41
+ });
42
+ }
43
+ if (result.reason === 'manifest-missing') {
44
+ emit(global, {
45
+ ok: false,
46
+ error: {
47
+ code: ErrorCode.IO_ERROR,
48
+ message: `freshness: committed embedding manifest not found. ${REBUILD_HINT}`,
49
+ },
50
+ data: result,
51
+ text: `freshness: committed embedding manifest not found.\n${REBUILD_HINT}`,
52
+ });
53
+ }
54
+ emit(global, {
55
+ ok: false,
56
+ error: {
57
+ code: ErrorCode.VALIDATION_FAILED,
58
+ message: `freshness: spec corpus drifted from the committed embeddings (current ${result.currentHash.slice(0, 12)}… != committed ${(result.committedHash ?? '').slice(0, 12)}…). ${REBUILD_HINT}`,
59
+ },
60
+ data: result,
61
+ text: [
62
+ 'freshness: spec corpus has drifted from the committed semantic embeddings.',
63
+ ` current surface hash: ${result.currentHash}`,
64
+ ` committed surface hash: ${result.committedHash}`,
65
+ '',
66
+ 'The semantic precedent ranking + recall ratchet read these vectors, so they are stale.',
67
+ REBUILD_HINT,
68
+ ].join('\n'),
69
+ });
70
+ });
71
+ }
72
+ //# sourceMappingURL=freshness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"freshness.js","sourceRoot":"","sources":["../../src/commands/freshness.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;AACzE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,MAAM,YAAY,GAChB,qGAAqG,CAAC;AAExG;;;;;;;;;;GAUG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAgB;IAChD,OAAO;SACJ,OAAO,CAAC,WAAW,CAAC;SACpB,WAAW,CACV,wNAAwN,CACzN;SACA,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAE;QAC9B,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;QACrC,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAG,0BAA0B,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,cAAc,EAAE,CAAC;QAEpF,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,IAAI,CAAC,MAAM,EAAE;gBACX,EAAE,EAAE,IAAI;gBACR,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,0EAA0E,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI;aACpH,CAAC,CAAC;QACL,CAAC;QAED,yEAAyE;QACzE,IAAI,MAAM,CAAC,MAAM,KAAK,eAAe,EAAE,CAAC;YACtC,IAAI,CAAC,MAAM,EAAE;gBACX,EAAE,EAAE,KAAK;gBACT,KAAK,EAAE;oBACL,IAAI,EAAE,SAAS,CAAC,QAAQ;oBACxB,OAAO,EAAE,4EAA4E;iBACtF;gBACD,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,6EAA6E;aACpF,CAAC,CAAC;QACL,CAAC;QACD,IAAI,MAAM,CAAC,MAAM,KAAK,kBAAkB,EAAE,CAAC;YACzC,IAAI,CAAC,MAAM,EAAE;gBACX,EAAE,EAAE,KAAK;gBACT,KAAK,EAAE;oBACL,IAAI,EAAE,SAAS,CAAC,QAAQ;oBACxB,OAAO,EAAE,sDAAsD,YAAY,EAAE;iBAC9E;gBACD,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,uDAAuD,YAAY,EAAE;aAC5E,CAAC,CAAC;QACL,CAAC;QAED,IAAI,CAAC,MAAM,EAAE;YACX,EAAE,EAAE,KAAK;YACT,KAAK,EAAE;gBACL,IAAI,EAAE,SAAS,CAAC,iBAAiB;gBACjC,OAAO,EAAE,yEAAyE,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,MAAM,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,YAAY,EAAE;aAClM;YACD,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE;gBACJ,4EAA4E;gBAC5E,6BAA6B,MAAM,CAAC,WAAW,EAAE;gBACjD,6BAA6B,MAAM,CAAC,aAAa,EAAE;gBACnD,EAAE;gBACF,wFAAwF;gBACxF,YAAY;aACb,CAAC,IAAI,CAAC,IAAI,CAAC;SACb,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerFunnel(program: Command): void;
@@ -0,0 +1,61 @@
1
+ import { mkdirSync, writeFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { computeFunnel } from '../lib/funnel.js';
4
+ import { gitMtimes } from '../lib/git-mtime.js';
5
+ import { emit, getGlobalOptions } from '../lib/output.js';
6
+ import { getRepoRoot } from '../lib/repo.js';
7
+ import { listSpecs } from '../lib/specs.js';
8
+ import { withEventLog } from '../lib/with-event-log.js';
9
+ const STAGE_ORDER = [
10
+ 'stub',
11
+ 'clarified',
12
+ 'validated',
13
+ 'regulatory_grounded',
14
+ 'reviewed',
15
+ 'compliance_reviewed',
16
+ 'ux_reviewed',
17
+ 'planned',
18
+ 'tasks_generated',
19
+ ];
20
+ export function registerFunnel(program) {
21
+ program
22
+ .command('funnel')
23
+ .description('Per-core funnel: stages × AC coverage × stall detection. Derived from artifacts.')
24
+ .option('--core <core>', 'Limit to one core')
25
+ .option('--stall-days <n>', 'Stall threshold in days (default 30)', '30')
26
+ .option('--save', 'Write a dated snapshot to docs/reports/FUNNEL_HEALTH_<date>.md', false)
27
+ .action(withEventLog('funnel', async (options, cmd) => {
28
+ const global = getGlobalOptions(cmd);
29
+ const repoRoot = getRepoRoot(global.repoRoot);
30
+ const specs = listSpecs(repoRoot, options.core);
31
+ const mtimeBySpecPath = gitMtimes(repoRoot, specs.map((s) => s.path));
32
+ const report = computeFunnel({
33
+ specs,
34
+ mtimeBySpecPath,
35
+ stallDays: parseInt(options.stallDays, 10),
36
+ });
37
+ const stageLines = STAGE_ORDER.map((s) => ` ${s.padEnd(18)} ${report.byStage[s] ?? 0}`);
38
+ const text = [
39
+ `Funnel health (${options.core ?? 'all'}):`,
40
+ ' Stage count',
41
+ ' ────────────────────────',
42
+ ...stageLines,
43
+ '',
44
+ ` with user_stories : ${report.withStories}`,
45
+ ` with ACs : ${report.withACs}`,
46
+ ` storied-but-no-ACs : ${report.storiedButNoACs} ← AC-backfill target population`,
47
+ ` with seed fixtures : ${report.withSeedFixtures}`,
48
+ ` ACs-but-no-fixture : ${report.acsButNoSeedFixture} ← seed-fixture target population (generate-seed-fixtures)`,
49
+ ` stalls (>${options.stallDays}d): ${report.stalls}`,
50
+ ].join('\n');
51
+ if (options.save) {
52
+ const date = new Date().toISOString().slice(0, 10);
53
+ const dir = join(repoRoot, 'docs/reports');
54
+ mkdirSync(dir, { recursive: true });
55
+ const path = join(dir, `FUNNEL_HEALTH_${date}.md`);
56
+ writeFileSync(path, `# Funnel Health — ${date}\n\n\`\`\`\n${text}\n\`\`\`\n`, 'utf8');
57
+ }
58
+ emit(global, { ok: true, data: report, text });
59
+ }));
60
+ }
61
+ //# sourceMappingURL=funnel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"funnel.js","sourceRoot":"","sources":["../../src/commands/funnel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerGenTests(program: Command): void;
@@ -0,0 +1,53 @@
1
+ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import { readFrontmatter, setE2eTests } from '../lib/frontmatter.js';
4
+ import { emit, getGlobalOptions } from '../lib/output.js';
5
+ import { normalizeAcceptanceCriteria } from '../lib/requirements.js';
6
+ import { getRepoRoot } from '../lib/repo.js';
7
+ import { findSpec } from '../lib/specs.js';
8
+ import { classifyLane, generateTestContent, generatedRelPath } from '../lib/test-generator.js';
9
+ export function registerGenTests(program) {
10
+ program
11
+ .command('gen-tests')
12
+ .description('Generate a fixme-gated test skeleton (@verifies-stamped) from a spec’s acceptance_criteria. Dry-run unless --write.')
13
+ .requiredOption('--spec <id>', 'Spec id, e.g. WEB-05')
14
+ .option('--write', 'Write the generated file under e2e/generated/', false)
15
+ .option('--update-frontmatter', 'Also add the generated path to the spec’s e2e_tests:', false)
16
+ .option('--lane <lane>', 'Override the ui|integration heuristic')
17
+ .action((options, cmd) => {
18
+ const global = getGlobalOptions(cmd);
19
+ const repoRoot = getRepoRoot(global.repoRoot);
20
+ const spec = findSpec(repoRoot, options.spec);
21
+ if (!spec)
22
+ emit(global, { ok: false, data: {}, text: `gen-tests: spec not found: ${options.spec}`, exitCode: 1 });
23
+ const specText = readFileSync(spec.path, 'utf8');
24
+ const fm = readFrontmatter(specText);
25
+ const { acs } = normalizeAcceptanceCriteria(fm.acceptance_criteria);
26
+ const lane = options.lane === 'ui' || options.lane === 'integration' ? options.lane : classifyLane(acs);
27
+ const rel = generatedRelPath(spec.id, lane);
28
+ const content = generateTestContent(spec.id, spec.title ?? spec.id, acs, lane);
29
+ if (!options.write)
30
+ emit(global, {
31
+ ok: true,
32
+ data: { spec: spec.id, lane, path: rel, acCount: acs.length, dryRun: true },
33
+ text: `gen-tests: would write ${rel} (lane=${lane}, ${acs.length} AC) — pass --write`,
34
+ });
35
+ const abs = join(repoRoot, rel);
36
+ mkdirSync(dirname(abs), { recursive: true });
37
+ writeFileSync(abs, content);
38
+ if (options.updateFrontmatter)
39
+ writeFileSync(spec.path, setE2eTests(specText, rel));
40
+ emit(global, {
41
+ ok: true,
42
+ data: {
43
+ spec: spec.id,
44
+ lane,
45
+ path: rel,
46
+ acCount: acs.length,
47
+ frontmatterUpdated: Boolean(options.updateFrontmatter),
48
+ },
49
+ text: `gen-tests: wrote ${rel} (lane=${lane}, ${acs.length} AC)${options.updateFrontmatter ? ' + updated e2e_tests' : ''}`,
50
+ });
51
+ });
52
+ }
53
+ //# sourceMappingURL=gen-tests.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gen-tests.js","sourceRoot":"","sources":["../../src/commands/gen-tests.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerInit(program: Command): void;
@@ -0,0 +1,64 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { loadConfig } from '../lib/config.js';
4
+ import { runScript } from '../lib/exec.js';
5
+ import { emit, emitContinuing, getGlobalOptions } from '../lib/output.js';
6
+ import { getRepoRoot } from '../lib/repo.js';
7
+ export function registerInit(program) {
8
+ program
9
+ .command('init')
10
+ .description('Verify spec workflow is set up: required directories, scripts, and templates exist.')
11
+ .action(async (_options, cmd) => {
12
+ const global = getGlobalOptions(cmd);
13
+ const repoRoot = getRepoRoot(global.repoRoot);
14
+ const required = [
15
+ 'specs/SPEC_STATUS_REGISTRY.md',
16
+ 'scripts/audit/audit-spec-completion.js',
17
+ 'scripts/specs/sync-deferred-dashboard.ts',
18
+ 'specs/_templates/SPEC_GUIDE.md',
19
+ 'specs/_templates/TEMPLATE_INDEX.md',
20
+ ];
21
+ try {
22
+ const config = loadConfig(repoRoot, global.config);
23
+ const templatePaths = flattenTemplatePaths(config.templates);
24
+ required.push(...templatePaths);
25
+ }
26
+ catch {
27
+ required.push('specs/_templates/SPEC_TEMPLATE.md', 'specs/_templates/SPEC_TEMPLATE_LITE.md', 'specs/_templates/PLAN_TEMPLATE.md', 'specs/_templates/TASKS_TEMPLATE.md');
28
+ }
29
+ const unique = [...new Set(required)];
30
+ const missing = unique.filter((p) => !existsSync(join(repoRoot, p)));
31
+ if (missing.length === 0) {
32
+ const git = runScript(['git', 'rev-parse', '--show-toplevel'], repoRoot);
33
+ if (git.exitCode !== 0) {
34
+ emit(global, {
35
+ ok: false,
36
+ data: { reason: 'git not available', missing: [] },
37
+ text: 'init: git not available — required for repo-root resolution',
38
+ });
39
+ }
40
+ emit(global, {
41
+ ok: true,
42
+ data: { repoRoot, missing: [] },
43
+ text: `init: spec workflow ready (${repoRoot})`,
44
+ });
45
+ }
46
+ emitContinuing(global, 'init: missing required files:');
47
+ for (const m of missing)
48
+ emitContinuing(global, ` - ${m}`);
49
+ emit(global, { ok: false, data: { repoRoot, missing }, exitCode: 1 });
50
+ });
51
+ }
52
+ function flattenTemplatePaths(templates) {
53
+ const paths = [];
54
+ for (const val of Object.values(templates)) {
55
+ if (typeof val === 'string') {
56
+ paths.push(val);
57
+ }
58
+ else if (val && typeof val === 'object') {
59
+ paths.push(...Object.values(val));
60
+ }
61
+ }
62
+ return paths;
63
+ }
64
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { Command } from 'commander';
2
+ /** Canonicalize a status value for matching: lowercase and strip everything that is
3
+ * not a letter or digit. Makes `--status InProgress`, frontmatter `in_progress`,
4
+ * and legacy body prose like `🚧 In Progress (60% Complete)` all comparable. */
5
+ export declare function canonicalStatus(value: string): string;
6
+ /** Prefix match on canonicalized status, both sides normalized. An empty filter
7
+ * matches nothing (a typo'd flag must not silently return the whole corpus). */
8
+ export declare function statusMatches(specStatus: string | undefined, filter: string): boolean;
9
+ export declare function registerList(program: Command): void;