@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,61 @@
1
+ import { emit, getGlobalOptions } from '../lib/output.js';
2
+ import { getRepoRoot } from '../lib/repo.js';
3
+ import { listSpecs } from '../lib/specs.js';
4
+ /** Canonicalize a status value for matching: lowercase and strip everything that is
5
+ * not a letter or digit. Makes `--status InProgress`, frontmatter `in_progress`,
6
+ * and legacy body prose like `🚧 In Progress (60% Complete)` all comparable. */
7
+ export function canonicalStatus(value) {
8
+ return value.toLowerCase().replace(/[^a-z0-9]+/g, '');
9
+ }
10
+ /** Prefix match on canonicalized status, both sides normalized. An empty filter
11
+ * matches nothing (a typo'd flag must not silently return the whole corpus). */
12
+ export function statusMatches(specStatus, filter) {
13
+ const target = canonicalStatus(filter);
14
+ if (target.length === 0)
15
+ return false;
16
+ return canonicalStatus(specStatus ?? '').startsWith(target);
17
+ }
18
+ export function registerList(program) {
19
+ program
20
+ .command('list')
21
+ .description('List specs filtered by core, status, or completeness. Supports --json on the subcommand.')
22
+ .option('--core <core>', 'Limit to one core')
23
+ .option('--status <status>', 'Filter by status — normalized prefix match (case/space/emoji-insensitive). Real values: specification, draft, in_progress, complete, blocked, deferred, archived')
24
+ .option('--include-archived', 'Include specs from specs/{core}/archive/', false)
25
+ .option('--missing-plan', 'Only specs with no PLAN.md', false)
26
+ .option('--missing-tasks', 'Only specs with no TASKS.md', false)
27
+ .option('--tag <tag>', 'Filter by tag (requires spec-index.json; falls back to unfiltered)')
28
+ .option('--json', 'Output JSON (also accepted as root-level flag)', false)
29
+ .action(async (options, cmd) => {
30
+ const global = getGlobalOptions(cmd);
31
+ if (options.json)
32
+ global.json = true;
33
+ const repoRoot = getRepoRoot(global.repoRoot);
34
+ let specs = listSpecs(repoRoot, options.core, { includeArchived: options.includeArchived });
35
+ if (options.status) {
36
+ specs = specs.filter((s) => statusMatches(s.status, String(options.status)));
37
+ }
38
+ if (options.missingPlan)
39
+ specs = specs.filter((s) => !s.hasPlan);
40
+ if (options.missingTasks)
41
+ specs = specs.filter((s) => !s.hasTasks);
42
+ const data = specs.map((s) => ({
43
+ id: s.id,
44
+ core: s.core,
45
+ status: s.status ?? 'unknown',
46
+ title: s.title ?? '',
47
+ file: s.path,
48
+ hasPlan: s.hasPlan,
49
+ hasTasks: s.hasTasks,
50
+ hasContext: s.hasContext,
51
+ archived: s.archived,
52
+ }));
53
+ const text = data.length === 0
54
+ ? 'list: no specs match'
55
+ : data
56
+ .map((s) => `${s.id.padEnd(10)} [${(s.status ?? '').padEnd(12)}]${s.archived ? ' 🗄️' : ''} plan=${s.hasPlan ? 'Y' : 'N'} tasks=${s.hasTasks ? 'Y' : 'N'} ${s.title}`)
57
+ .join('\n');
58
+ emit(global, { ok: true, data, text });
59
+ });
60
+ }
61
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerMetrics(program: Command): void;
@@ -0,0 +1,66 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { EVENTS_RELATIVE_PATH } from '../lib/events.js';
4
+ import { computeMetrics } from '../lib/metrics.js';
5
+ import { emit, getGlobalOptions } from '../lib/output.js';
6
+ import { getRepoRoot } from '../lib/repo.js';
7
+ import { withEventLog } from '../lib/with-event-log.js';
8
+ function loadEvents(path) {
9
+ if (!existsSync(path))
10
+ return [];
11
+ const text = readFileSync(path, 'utf8');
12
+ const out = [];
13
+ for (const line of text.split('\n')) {
14
+ const t = line.trim();
15
+ if (!t)
16
+ continue;
17
+ try {
18
+ out.push(JSON.parse(t));
19
+ }
20
+ catch {
21
+ // skip malformed line
22
+ }
23
+ }
24
+ return out;
25
+ }
26
+ export function registerMetrics(program) {
27
+ program
28
+ .command('metrics')
29
+ .description('Roll .claude/tmp/eos-spec-events.jsonl into per-command, per-model, and autonomy metrics.')
30
+ .option('--since <iso>', 'Only include events at or after this ISO8601 timestamp')
31
+ .option('--core <core>', 'Only include events for this core')
32
+ .action(withEventLog('metrics', async (options, cmd) => {
33
+ const global = getGlobalOptions(cmd);
34
+ const repoRoot = getRepoRoot(global.repoRoot);
35
+ const path = process.env.EOS_SPEC_EVENTS_PATH ?? join(repoRoot, EVENTS_RELATIVE_PATH);
36
+ const events = loadEvents(path);
37
+ const since = options.since ? new Date(options.since) : undefined;
38
+ const report = computeMetrics(events, { since, core: options.core });
39
+ const cmdRows = Object.entries(report.byCommand).map(([k, v]) => ` ${k.padEnd(16)} count=${String(v.count).padStart(4)} wall-clock=${(v.wallClockMs / 1000).toFixed(2)}s success=${(v.successRate * 100).toFixed(0)}%`);
40
+ const modelRows = Object.entries(report.byModel).map(([k, v]) => ` ${k.padEnd(32)} calls=${String(v.calls).padStart(3)} in=${v.tokensIn} out=${v.tokensOut} cost=${v.totalCostUsd === null ? '(unknown)' : `$${v.totalCostUsd.toFixed(4)}`}`);
41
+ const text = [
42
+ `Workflow metrics (since ${options.since ?? 'beginning'}, ${options.core ?? 'all'}):`,
43
+ '',
44
+ ' Commands',
45
+ ' ─────────────────────────────────────────────────────',
46
+ ...cmdRows,
47
+ '',
48
+ ' AI calls',
49
+ ' ─────────────────────────────────────────────────────',
50
+ ...(modelRows.length ? modelRows : [' (no AI calls in window)']),
51
+ '',
52
+ ' Autonomy estimate',
53
+ ' ─────────────────────────────────────────────────────',
54
+ ` Longest consecutive-success run: ${report.autonomy.longestRun}`,
55
+ ` Human touches (halts requiring intervention): ${report.autonomy.humanTouches}`,
56
+ ` Expected halts (governance gates fired): ${report.autonomy.byHaltCause.expectedHalts}`,
57
+ ` Unexpected halts (crashes / stalls): ${report.autonomy.byHaltCause.unexpectedHalts}`,
58
+ ...Object.entries(report.autonomy.byHaltCause.byCause).map(([cause, n]) => ` - ${cause}: ${n}`),
59
+ report.autonomy.lastHalt
60
+ ? ` Last halt: ${report.autonomy.lastHalt.command} (${report.autonomy.lastHalt.error ?? 'no error'})`
61
+ : ' No halts in window',
62
+ ].join('\n');
63
+ emit(global, { ok: true, data: report, text });
64
+ }));
65
+ }
66
+ //# sourceMappingURL=metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../src/commands/metrics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ import type { Command } from 'commander';
2
+ import { type BlockerRef, type Readiness } from '../lib/blockers.js';
3
+ import { type ActorType } from '../lib/pipeline-map.js';
4
+ import { type SessionState } from '../lib/session-state.js';
5
+ import { type SpecFile } from '../lib/specs.js';
6
+ export type NextAction = {
7
+ type: string;
8
+ specId: string;
9
+ reason: string;
10
+ actor: string;
11
+ actorType: ActorType;
12
+ invocation: string;
13
+ optional?: boolean;
14
+ /** Disagreement between pipeline_status and on-disk artifacts, if any. */
15
+ note?: string;
16
+ /** Set for the implement/complete tail. */
17
+ taskHint?: string;
18
+ };
19
+ /** Disagreement between later artifacts and the first incomplete required gate
20
+ * (e.g. tasks exist but validate-spec was never run). Optional and not-applicable
21
+ * transitions never count, so only real out-of-order gaps are flagged. */
22
+ export declare function computeOutOfOrder(spec: SpecFile): string | undefined;
23
+ /** Human-output blocker lines for `next --spec`: open blockers and unresolvable
24
+ * (likely typo'd) blocked_by references. Cleared (complete) blockers are omitted. */
25
+ export declare function formatSpecBlockers(blockers: BlockerRef[]): string[];
26
+ /** Assemble the `next --spec` human text: action, out-of-order warning, blocker
27
+ * lines, landscape advisory. The warning and blockers used to be JSON-only. */
28
+ export declare function buildSpecNextText(spec: SpecFile, action: NextAction, outOfOrder: string | undefined, blockers: BlockerRef[], advisory: string): string;
29
+ /** Pick the core-level next spec from a readiness-ordered list, honoring claims.
30
+ * Default: skip specs with an active claim. `--include-claimed`: keep them.
31
+ * `--claim`: atomically reserve the chosen spec inside the same lock so two
32
+ * concurrent core-picks in separate worktrees return distinct specs.
33
+ * Returns null when no eligible candidate remains. */
34
+ export declare function pickCorePick(repoRoot: string, ordered: Readiness[], opts: {
35
+ claim: boolean;
36
+ includeClaimed: boolean;
37
+ by?: string;
38
+ ttlMinutes?: number;
39
+ }): Readiness | null;
40
+ export declare function registerNext(program: Command): void;
41
+ /** Walk the SSOT pipeline; return the first applicable, not-done transition, else the implement/complete tail.
42
+ * An active session (STATE.md) on this spec short-circuits to resuming the in-progress task. */
43
+ export declare function recommendAction(spec: SpecFile, session?: SessionState | null, repoRoot?: string): NextAction;
44
+ /** True when TASKS.md carries at least one status marker we know how to read —
45
+ * a GitHub checkbox (`[ ]`/`[x]`) or a ballot-box glyph (☐/☑/☒). Used to
46
+ * distinguish "genuinely all complete" from "format we cannot parse". */
47
+ export declare function hasRecognizedTaskMarkers(text: string): boolean;
48
+ export declare function findIncompleteTaskHint(text: string): string | null;
@@ -0,0 +1,344 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { basename } from 'node:path';
3
+ import { computeReadiness, isCompleteStatus, isTerminal, orderByReadiness, unclearedBlockers, } from '../lib/blockers.js';
4
+ import { activeClaims, addClaim, DEFAULT_TTL_MINUTES, readClaims, withClaimLock } from '../lib/claims.js';
5
+ import { findExistingTableReferences } from '../lib/coherence.js';
6
+ import { ErrorCode, emit, getGlobalOptions } from '../lib/output.js';
7
+ import { computeStage, PIPELINE } from '../lib/pipeline-map.js';
8
+ import { getRepoRoot } from '../lib/repo.js';
9
+ import { readSessionState } from '../lib/session-state.js';
10
+ import { isClaimedCompleteUnverified } from '../lib/spec-debt.js';
11
+ import { diagnoseMissingSpec, findSpec, listSpecs, resolveArtifactPath } from '../lib/specs.js';
12
+ import { withEventLog } from '../lib/with-event-log.js';
13
+ /** Pipeline stages where a spec is still being shaped (pre-implementation), so an
14
+ * "already-implemented table" advisory is actionable rather than noise. */
15
+ const EARLY_STAGES = new Set([undefined, 'stub', 'clarified', 'validated']);
16
+ /** Build an advisory when an early-stage spec references tables that already exist
17
+ * in a migration — the signal that it may duplicate an existing feature. */
18
+ function landscapeAdvisory(repoRoot, spec) {
19
+ if (!EARLY_STAGES.has(spec.signals.pipelineStatus))
20
+ return '';
21
+ const existing = findExistingTableReferences(repoRoot, spec.id, spec.core);
22
+ if (existing.length === 0)
23
+ return '';
24
+ const shown = existing.slice(0, 5).map((e) => ` - ${e.table} (already in ${e.migration})`);
25
+ const more = existing.length > 5 ? `\n …and ${existing.length - 5} more` : '';
26
+ return `\n\n⚠ landscape: ${existing.length} referenced table(s) already exist in migrations — confirm you're EXTENDING the owning spec, not duplicating it:\n${shown.join('\n')}${more}`;
27
+ }
28
+ /** Disagreement between later artifacts and the first incomplete required gate
29
+ * (e.g. tasks exist but validate-spec was never run). Optional and not-applicable
30
+ * transitions never count, so only real out-of-order gaps are flagged. */
31
+ export function computeOutOfOrder(spec) {
32
+ const applicable = PIPELINE.filter((t) => !t.optional && !(t.regulatedOnly && !spec.signals.isRegulated));
33
+ const firstNotDone = applicable.findIndex((t) => !t.isDone(spec));
34
+ const laterDone = firstNotDone >= 0 ? applicable.slice(firstNotDone + 1).find((t) => t.isDone(spec)) : undefined;
35
+ return firstNotDone >= 0 && laterDone
36
+ ? `out-of-order: ${laterDone.id} artifact exists but ${applicable[firstNotDone].id} is incomplete`
37
+ : undefined;
38
+ }
39
+ /** Human-output blocker lines for `next --spec`: open blockers and unresolvable
40
+ * (likely typo'd) blocked_by references. Cleared (complete) blockers are omitted. */
41
+ export function formatSpecBlockers(blockers) {
42
+ const lines = [];
43
+ for (const b of blockers) {
44
+ if (b.state === 'open')
45
+ lines.push(` blocked by: ${b.id} (open)`);
46
+ if (b.state === 'unknown')
47
+ lines.push(` warning: blocked_by references unknown spec ID ${b.id} (typo?)`);
48
+ }
49
+ return lines;
50
+ }
51
+ /** Assemble the `next --spec` human text: action, out-of-order warning, blocker
52
+ * lines, landscape advisory. The warning and blockers used to be JSON-only. */
53
+ export function buildSpecNextText(spec, action, outOfOrder, blockers, advisory) {
54
+ const extras = [...(outOfOrder ? [` ⚠ ${outOfOrder}`] : []), ...formatSpecBlockers(blockers)];
55
+ return `${formatAction(spec.id, action)}${extras.length > 0 ? `\n${extras.join('\n')}` : ''}${advisory}`;
56
+ }
57
+ /** Pick the core-level next spec from a readiness-ordered list, honoring claims.
58
+ * Default: skip specs with an active claim. `--include-claimed`: keep them.
59
+ * `--claim`: atomically reserve the chosen spec inside the same lock so two
60
+ * concurrent core-picks in separate worktrees return distinct specs.
61
+ * Returns null when no eligible candidate remains. */
62
+ export function pickCorePick(repoRoot, ordered, opts) {
63
+ return withClaimLock(repoRoot, () => {
64
+ const claimed = new Set(activeClaims(readClaims(repoRoot), Date.now()).map((c) => c.id.toUpperCase()));
65
+ const eligible = opts.includeClaimed ? ordered : ordered.filter((r) => !claimed.has(r.spec.id.toUpperCase()));
66
+ const choice = eligible[0] ?? null;
67
+ if (choice && opts.claim) {
68
+ addClaim(repoRoot, choice.spec.id, {
69
+ by: opts.by ?? process.env.EOS_SPEC_CLAIMED_BY ?? basename(repoRoot),
70
+ ttlMinutes: opts.ttlMinutes ?? DEFAULT_TTL_MINUTES,
71
+ });
72
+ }
73
+ return choice;
74
+ });
75
+ }
76
+ export function registerNext(program) {
77
+ program
78
+ .command('next')
79
+ .description('Show the next recommended action for a spec or core (replaces ad-hoc whats-next chat command).')
80
+ .option('--core <core>', 'Limit to one core')
81
+ .option('--spec <id>', 'Single spec id (preferred)')
82
+ .option('--claim', 'Atomically reserve the returned core-pick (parallel-agent lease)', false)
83
+ .option('--include-claimed', 'Include specs already claimed by another worktree', false)
84
+ .action(withEventLog('next', async (options, cmd) => {
85
+ const global = getGlobalOptions(cmd);
86
+ const repoRoot = getRepoRoot(global.repoRoot);
87
+ const session = readSessionState(repoRoot);
88
+ if (options.spec) {
89
+ const spec = findSpec(repoRoot, options.spec);
90
+ if (!spec) {
91
+ const core = options.spec.split('-')[0]?.toLowerCase() ?? 'pf';
92
+ const diag = diagnoseMissingSpec(repoRoot, options.spec);
93
+ const text = diag.foundPath
94
+ ? `next: spec ${options.spec} is not navigable\nreason: ${diag.reason}\nfile: ${diag.foundPath}\nhint: move/rename it under specs/${core}/specs/ or specs/${core}/ux/ with a {CORE}-UX-{N} name, or add YAML frontmatter, then re-run`
95
+ : `next: spec ${options.spec} not found\nhint: run \`eos-spec precedent --core ${core} --topic "<feature>"\` to check archived prior art, then create-spec`;
96
+ emit(global, {
97
+ ok: false,
98
+ error: { code: ErrorCode.SPEC_NOT_FOUND, message: text },
99
+ data: null,
100
+ text,
101
+ });
102
+ }
103
+ const action = recommendAction(spec, session, repoRoot);
104
+ const outOfOrder = computeOutOfOrder(spec);
105
+ // Blockers resolve against the WHOLE corpus — a blocker may live in any core.
106
+ const [readiness] = computeReadiness([spec], listSpecs(repoRoot));
107
+ const claimedCompleteUnverified = isClaimedCompleteUnverified(repoRoot, spec.id);
108
+ const debtLine = claimedCompleteUnverified
109
+ ? `\n ⚠ verification-debt: claims complete but 0 @verifies-backed ACs — run \`npm run spec:check-debt\` / \`npm run spec:verify-acs -- --enforce --spec ${spec.id}\``
110
+ : '';
111
+ emit(global, {
112
+ ok: true,
113
+ data: {
114
+ specId: spec.id,
115
+ computedStage: computeStage(spec),
116
+ outOfOrder: outOfOrder ?? null,
117
+ blockers: readiness.blockers,
118
+ claimedCompleteButUnverified: claimedCompleteUnverified,
119
+ action,
120
+ },
121
+ text: `${buildSpecNextText(spec, action, outOfOrder, readiness.blockers, landscapeAdvisory(repoRoot, spec))}${debtLine}`,
122
+ });
123
+ }
124
+ const candidates = listSpecs(repoRoot, options.core).filter((s) => s.status && !isCompleteStatus(s.status) && !isTerminal(s));
125
+ if (candidates.length === 0) {
126
+ emit(global, {
127
+ ok: true,
128
+ data: { action: { type: 'noop', reason: 'all specs complete or no in-progress specs found' } },
129
+ text: `next: no in-progress specs found\nhint: run \`eos-spec precedent --core ${options.core ?? 'pf'} --topic "<feature>"\` to check archived prior art`,
130
+ });
131
+ }
132
+ // Blocker-aware pick: prefer specs whose `blocked_by` targets are all Complete.
133
+ // Resolve against the WHOLE corpus — a blocker clears only when Complete, and
134
+ // completed specs are excluded from `candidates`, so the corpus must be unfiltered
135
+ // (and blockers may live in any core regardless of the --core filter).
136
+ const corpus = listSpecs(repoRoot);
137
+ const ordered = orderByReadiness(candidates, corpus);
138
+ const choice = pickCorePick(repoRoot, ordered, {
139
+ claim: Boolean(options.claim),
140
+ includeClaimed: Boolean(options.includeClaimed),
141
+ });
142
+ if (!choice) {
143
+ emit(global, {
144
+ ok: true,
145
+ data: { action: { type: 'noop', reason: 'all in-progress specs are claimed by other worktrees' } },
146
+ text: `next: all ${candidates.length} in-progress spec(s) are claimed by other worktrees\nhint: pass --include-claimed to override, or wait for a claim to expire`,
147
+ });
148
+ }
149
+ const first = choice.spec;
150
+ const action = recommendAction(first, session, repoRoot);
151
+ const readyCount = ordered.filter((r) => r.ready).length;
152
+ if (!choice.ready) {
153
+ const open = unclearedBlockers(choice)
154
+ .map((b) => `${b.id} (${b.state})`)
155
+ .join(', ');
156
+ action.note = `blocked-by: ${open} — surfaced because no unblocked in-progress spec remains`;
157
+ }
158
+ emit(global, {
159
+ ok: true,
160
+ data: {
161
+ specId: first.id,
162
+ action,
163
+ totalInProgress: candidates.length,
164
+ readyCount,
165
+ ready: choice.ready,
166
+ blockers: choice.blockers,
167
+ claimed: Boolean(options.claim),
168
+ },
169
+ text: `${formatAction(first.id, action)}\n\n(${readyCount}/${candidates.length} in-progress spec(s) unblocked — pass --spec for a different one)`,
170
+ });
171
+ }));
172
+ }
173
+ /** Walk the SSOT pipeline; return the first applicable, not-done transition, else the implement/complete tail.
174
+ * An active session (STATE.md) on this spec short-circuits to resuming the in-progress task. */
175
+ export function recommendAction(spec, session, repoRoot) {
176
+ if (session && session.specId.toUpperCase() === spec.id.toUpperCase()) {
177
+ return {
178
+ type: 'implement',
179
+ specId: spec.id,
180
+ reason: `Session in progress on ${session.currentTask}.`,
181
+ actor: 'module-lifecycle skill',
182
+ actorType: 'skill',
183
+ invocation: `the module-lifecycle skill on ${spec.id} (resume at ${session.currentTask})`,
184
+ };
185
+ }
186
+ // Derived from artifacts only — mirror the same predicates the PIPELINE uses for isDone.
187
+ const reviewStagesDone = spec.signals.isRegulated ? spec.signals.hasComplianceSignoff : spec.signals.hasSpecReview;
188
+ if (reviewStagesDone && !spec.signals.hasUserStories && !spec.signals.hasAcceptanceCriteria) {
189
+ return {
190
+ type: 'backfill-frontmatter',
191
+ specId: spec.id,
192
+ reason: 'Spec passed review but has neither user stories nor acceptance_criteria — draft-acs and generate-tests both silently skip, so it would reach plan with no ACs.',
193
+ actor: 'backfill (ac-draft + backfill-status)',
194
+ actorType: 'command',
195
+ invocation: `the encore-spec-ac-draft skill on ${spec.id} (then npm run spec:backfill-status -- --spec ${spec.id})`,
196
+ };
197
+ }
198
+ for (const t of PIPELINE) {
199
+ if (t.optional)
200
+ continue; // advisories never block; surfaced separately
201
+ if (t.regulatedOnly && !spec.signals.isRegulated)
202
+ continue;
203
+ // Artifacts are the single source of truth. `pipeline_status` is derived/cached
204
+ // (see eos-spec reconcile) and is intentionally NOT consulted here.
205
+ if (t.isDone(spec))
206
+ continue;
207
+ return {
208
+ type: t.id,
209
+ specId: spec.id,
210
+ reason: t.reason,
211
+ actor: t.actor,
212
+ actorType: t.actorType,
213
+ invocation: t.invocation(spec.id),
214
+ };
215
+ }
216
+ return implementOrComplete(spec, repoRoot);
217
+ }
218
+ /** Task-level tail the pipeline-map does not model: drill into TASKS.md or mark
219
+ * complete. Implementation work routes to the module-lifecycle skill (Phase 8 —
220
+ * the live entry point; the old dedicated command was deleted from automation/),
221
+ * while the bookkeeping branches stay eos-spec CLI invocations. */
222
+ function implementOrComplete(spec, repoRoot) {
223
+ const cli = { specId: spec.id, actor: 'eos-spec CLI', actorType: 'command' };
224
+ if (!spec.hasTasks) {
225
+ return { ...cli, type: 'generate-tasks', reason: 'No TASKS.md yet.', invocation: `eos-spec tasks ${spec.id}` };
226
+ }
227
+ let text = null;
228
+ // Resolve the TASKS file folder-agnostically (C2). The old
229
+ // spec.path.replace(/\/specs\/[^/]+\.md$/, …) keyed on a literal `/specs/` segment and
230
+ // silently failed for UX specs under `specs/{core}/ux/`, making the tail read the spec
231
+ // BODY as if it were TASKS — the 46/84 UI-bearing-spec misroute this fixes.
232
+ const tasksPath = repoRoot ? resolveArtifactPath(repoRoot, spec.core, 'tasks', spec.id, 'TASKS') : null;
233
+ if (tasksPath) {
234
+ try {
235
+ text = readFileSync(tasksPath, 'utf8');
236
+ }
237
+ catch {
238
+ text = null;
239
+ }
240
+ }
241
+ if (text !== null) {
242
+ const hint = findIncompleteTaskHint(text);
243
+ if (hint) {
244
+ return {
245
+ specId: spec.id,
246
+ actor: 'module-lifecycle skill',
247
+ actorType: 'skill',
248
+ type: 'implement',
249
+ reason: 'Incomplete task found in TASKS.md',
250
+ invocation: `the module-lifecycle skill on ${spec.id}`,
251
+ taskHint: hint.slice(0, 120),
252
+ };
253
+ }
254
+ // Guard against the false "all complete" verdict: a TASKS.md with zero
255
+ // recognized status markers ([ ]/[x]/☐/☑) is unparseable, NOT done. Never
256
+ // recommend `complete --update-registry` (which marks the spec done in the
257
+ // registry) on a spec whose completion we cannot prove from artifacts.
258
+ if (!hasRecognizedTaskMarkers(text)) {
259
+ return {
260
+ ...cli,
261
+ type: 'verify-tasks',
262
+ reason: 'TASKS.md has no recognized task-status markers ([ ]/[x]/☐/☑) — completion cannot be derived from artifacts. Verify the task format before completing.',
263
+ invocation: `eos-spec status --spec ${spec.id} # then re-run \`eos-spec tasks ${spec.id} --force\` if the format is stale`,
264
+ };
265
+ }
266
+ }
267
+ // Verification tail (UI-bearing specs): tasks done is necessary, not
268
+ // sufficient — code-sourced docshots and a green browser auto-heal verdict
269
+ // are completion artifacts too (constitution §3.1: done = reachable
270
+ // capability, proven in the real browser and documented with real pixels).
271
+ if (spec.signals.isUiBearing && !spec.signals.hasDocshots) {
272
+ return {
273
+ specId: spec.id,
274
+ actor: 'encore-doc-screenshots skill',
275
+ actorType: 'skill',
276
+ type: 'capture-docshots',
277
+ reason: 'All tasks complete, but this UI-bearing spec has no docshot evidence — capture code-sourced screenshots before completing.',
278
+ invocation: `the encore-doc-screenshots skill on ${spec.id} (a tests/e2e/<core>/*-docs-shots.spec.ts writing docs/images/<area>/${spec.id.toLowerCase()}-*.png; verify with npm run docs:shots:check). No UI surface worth documenting? \`eos-spec signoff --type docshots --spec ${spec.id}\``,
279
+ };
280
+ }
281
+ // Submit→DB completion gate for create-wizards (Phase 3 / #1185): a render-only
282
+ // docshot/auto-heal can green-light a wizard whose submit path is broken (the
283
+ // GR-UX-10/05 gap). A kind:'create' wizard spec must have a passing submit→DB
284
+ // E2E before heal-verified/mark-complete. Config + non-wizard specs are exempt.
285
+ if (spec.signals.isCreateWizardSpec && !spec.signals.hasSubmitE2e) {
286
+ return {
287
+ specId: spec.id,
288
+ actor: 'submit→DB E2E (Playwright local lane)',
289
+ actorType: 'skill',
290
+ type: 'submit-e2e',
291
+ reason: 'This create-wizard has no submit→DB E2E — a render-only docshot/auto-heal can pass while the submit path is broken. Prove the wizard persists a row before completing.',
292
+ invocation: `add tests/e2e/${spec.core.toLowerCase()}/${spec.id.toLowerCase()}-local.spec.ts driving the wizard → submit → asserting the persisted row (exemplar: tests/e2e/gr/gr-ux-13-training-course-local.spec.ts); run \`npm run test:e2e:local\`. No submit path? \`eos-spec signoff --type submit-e2e-waived --spec ${spec.id}\``,
293
+ };
294
+ }
295
+ if (spec.signals.isUiBearing && !spec.signals.hasHealSignoff) {
296
+ return {
297
+ specId: spec.id,
298
+ actor: 'browser-autoheal skill',
299
+ actorType: 'skill',
300
+ type: 'browser-autoheal',
301
+ reason: 'All tasks complete, but no browser auto-heal verdict is recorded — drive the feature end-to-end with console/pageerror/network capture and fix to green.',
302
+ invocation: `the browser-autoheal skill on ${spec.id} (loop to HEAL_VERDICT=green), then \`eos-spec signoff --type heal-verified --spec ${spec.id}\``,
303
+ };
304
+ }
305
+ return {
306
+ ...cli,
307
+ type: 'mark-complete',
308
+ reason: 'All tasks appear complete.',
309
+ invocation: `eos-spec complete --spec ${spec.id} --update-registry` +
310
+ `\n ▸ before completing, prove the ACs: \`npm run spec:check-debt\` then ` +
311
+ `\`npm run spec:verify-acs -- --enforce --spec ${spec.id}\` (an AC is verified only on a real @verifies-backed test pass).`,
312
+ };
313
+ }
314
+ /** True when TASKS.md carries at least one status marker we know how to read —
315
+ * a GitHub checkbox (`[ ]`/`[x]`) or a ballot-box glyph (☐/☑/☒). Used to
316
+ * distinguish "genuinely all complete" from "format we cannot parse". */
317
+ export function hasRecognizedTaskMarkers(text) {
318
+ return /\[\s*[ xX]\s*\]/.test(text) || /[☐☑☒]/.test(text);
319
+ }
320
+ export function findIncompleteTaskHint(text) {
321
+ const headedTask = /^###\s+(T\d+[^\n]*)[\s\S]{0,240}?\*\*Status:\*\*\s*`?\[\s\]`?/m.exec(text);
322
+ if (headedTask?.[1])
323
+ return headedTask[1].trim();
324
+ const inlineTask = /^\s*-\s*\[\s\]\s+((?:T\d+|Task)[^\n]+)/m.exec(text);
325
+ if (inlineTask?.[1])
326
+ return inlineTask[1].trim();
327
+ // Table/glyph format (TASKS_TEMPLATE waves use markdown tables with a status
328
+ // cell): an open ballot-box glyph ☐ (U+2610) marks an incomplete row. Capture
329
+ // the first T-id on that line, else the line text, as the hint.
330
+ const glyphLine = /^.*☐.*$/m.exec(text);
331
+ if (glyphLine) {
332
+ const line = glyphLine[0];
333
+ const tid = /\bT\d+\b/.exec(line)?.[0];
334
+ return (tid ? `${tid} (incomplete)` : line.replace(/\|/g, ' ').replace(/\s+/g, ' ').trim()).slice(0, 120);
335
+ }
336
+ return null;
337
+ }
338
+ function formatAction(specId, action) {
339
+ const gate = action.actorType === 'human-gate' || action.actorType === 'agent' ? ' [human-gate]' : '';
340
+ const hint = action.taskHint ? `\n hint: ${action.taskHint}` : '';
341
+ const note = action.note ? `\n note: ${action.note}` : '';
342
+ return `next [${specId}] → ${action.type}${gate}: ${action.reason}\n ▶ run: ${action.invocation}${hint}${note}`;
343
+ }
344
+ //# sourceMappingURL=next.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"next.js","sourceRoot":"","sources":["../../src/commands/next.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,OAAO,EAEL,gBAAgB,EAChB,gBAAgB,EAChB,UAAU,EACV,gBAAgB,EAEhB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,mBAAmB,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC1G,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAkB,YAAY,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAqB,MAAM,yBAAyB,CAAC;AAC9E,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,SAAS,EAAE,mBAAmB,EAAiB,MAAM,iBAAiB,CAAC;AAC/G,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAExD;4EAC4E;AAC5E,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC;AAE5E;6EAC6E;AAC7E,SAAS,iBAAiB,CAAC,QAAgB,EAAE,IAAc;IACzD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC;QAAE,OAAO,EAAE,CAAC;IAC9D,MAAM,QAAQ,GAAG,2BAA2B,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3E,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACrC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,gBAAgB,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC;IAC5F,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,QAAQ,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/E,OAAO,oBAAoB,QAAQ,CAAC,MAAM,qHAAqH,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC;AAC3L,CAAC;AAgBD;;2EAE2E;AAC3E,MAAM,UAAU,iBAAiB,CAAC,IAAc;IAC9C,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,aAAa,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;IAC1G,MAAM,YAAY,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAClE,MAAM,SAAS,GAAG,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACjH,OAAO,YAAY,IAAI,CAAC,IAAI,SAAS;QACnC,CAAC,CAAC,iBAAiB,SAAS,CAAC,EAAE,wBAAwB,UAAU,CAAC,YAAY,CAAE,CAAC,EAAE,gBAAgB;QACnG,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC;AAED;sFACsF;AACtF,MAAM,UAAU,kBAAkB,CAAC,QAAsB;IACvD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;QACnE,IAAI,CAAC,CAAC,KAAK,KAAK,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,oDAAoD,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;IAC5G,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;gFACgF;AAChF,MAAM,UAAU,iBAAiB,CAC/B,IAAc,EACd,MAAkB,EAClB,UAA8B,EAC9B,QAAsB,EACtB,QAAgB;IAEhB,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,OAAO,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC/F,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,QAAQ,EAAE,CAAC;AAC3G,CAAC;AAED;;;;uDAIuD;AACvD,MAAM,UAAU,YAAY,CAC1B,QAAgB,EAChB,OAAoB,EACpB,IAAmF;IAEnF,OAAO,aAAa,CAAC,QAAQ,EAAE,GAAG,EAAE;QAClC,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QACvG,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAC9G,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;QACnC,IAAI,MAAM,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE;gBACjC,EAAE,EAAE,IAAI,CAAC,EAAE,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,QAAQ,CAAC,QAAQ,CAAC;gBACpE,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,mBAAmB;aACnD,CAAC,CAAC;QACL,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAgB;IAC3C,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,gGAAgG,CAAC;SAC7G,MAAM,CAAC,eAAe,EAAE,mBAAmB,CAAC;SAC5C,MAAM,CAAC,aAAa,EAAE,4BAA4B,CAAC;SACnD,MAAM,CAAC,SAAS,EAAE,kEAAkE,EAAE,KAAK,CAAC;SAC5F,MAAM,CAAC,mBAAmB,EAAE,mDAAmD,EAAE,KAAK,CAAC;SACvF,MAAM,CACL,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE;QAC1C,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAc,CAAC,CAAC;QAChD,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC9C,MAAM,OAAO,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAE3C,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;YAC9C,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,IAAI,CAAC;gBAC/D,MAAM,IAAI,GAAG,mBAAmB,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;gBACzD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS;oBACzB,CAAC,CAAC,cAAc,OAAO,CAAC,IAAI,8BAA8B,IAAI,CAAC,MAAM,WAAW,IAAI,CAAC,SAAS,sCAAsC,IAAI,oBAAoB,IAAI,sEAAsE;oBACtO,CAAC,CAAC,cAAc,OAAO,CAAC,IAAI,qDAAqD,IAAI,sEAAsE,CAAC;gBAC9J,IAAI,CAAC,MAAM,EAAE;oBACX,EAAE,EAAE,KAAK;oBACT,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,cAAc,EAAE,OAAO,EAAE,IAAI,EAAE;oBACxD,IAAI,EAAE,IAAI;oBACV,IAAI;iBACL,CAAC,CAAC;YACL,CAAC;YACD,MAAM,MAAM,GAAG,eAAe,CAAC,IAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;YACzD,MAAM,UAAU,GAAG,iBAAiB,CAAC,IAAK,CAAC,CAAC;YAC5C,8EAA8E;YAC9E,MAAM,CAAC,SAAS,CAAC,GAAG,gBAAgB,CAAC,CAAC,IAAK,CAAC,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;YACnE,MAAM,yBAAyB,GAAG,2BAA2B,CAAC,QAAQ,EAAE,IAAK,CAAC,EAAE,CAAC,CAAC;YAClF,MAAM,QAAQ,GAAG,yBAAyB;gBACxC,CAAC,CAAC,yJAAyJ,IAAK,CAAC,EAAE,IAAI;gBACvK,CAAC,CAAC,EAAE,CAAC;YACP,IAAI,CAAC,MAAM,EAAE;gBACX,EAAE,EAAE,IAAI;gBACR,IAAI,EAAE;oBACJ,MAAM,EAAE,IAAK,CAAC,EAAE;oBAChB,aAAa,EAAE,YAAY,CAAC,IAAK,CAAC;oBAClC,UAAU,EAAE,UAAU,IAAI,IAAI;oBAC9B,QAAQ,EAAE,SAAU,CAAC,QAAQ;oBAC7B,4BAA4B,EAAE,yBAAyB;oBACvD,MAAM;iBACP;gBACD,IAAI,EAAE,GAAG,iBAAiB,CAAC,IAAK,EAAE,MAAM,EAAE,UAAU,EAAE,SAAU,CAAC,QAAQ,EAAE,iBAAiB,CAAC,QAAQ,EAAE,IAAK,CAAC,CAAC,GAAG,QAAQ,EAAE;aAC5H,CAAC,CAAC;QACL,CAAC;QAED,MAAM,UAAU,GAAG,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,CACzD,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CACjE,CAAC;QACF,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,IAAI,CAAC,MAAM,EAAE;gBACX,EAAE,EAAE,IAAI;gBACR,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,kDAAkD,EAAE,EAAE;gBAC9F,IAAI,EAAE,2EAA2E,OAAO,CAAC,IAAI,IAAI,IAAI,oDAAoD;aAC1J,CAAC,CAAC;QACL,CAAC;QACD,gFAAgF;QAChF,8EAA8E;QAC9E,mFAAmF;QACnF,uEAAuE;QACvE,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,gBAAgB,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QACrD,MAAM,MAAM,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,EAAE;YAC7C,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC;YAC7B,cAAc,EAAE,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC;SAChD,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,IAAI,CAAC,MAAM,EAAE;gBACX,EAAE,EAAE,IAAI;gBACR,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,sDAAsD,EAAE,EAAE;gBAClG,IAAI,EAAE,aAAa,UAAU,CAAC,MAAM,8HAA8H;aACnK,CAAC,CAAC;QACL,CAAC;QACD,MAAM,KAAK,GAAG,MAAO,CAAC,IAAI,CAAC;QAC3B,MAAM,MAAM,GAAG,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QACzD,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;QACzD,IAAI,CAAC,MAAO,CAAC,KAAK,EAAE,CAAC;YACnB,MAAM,IAAI,GAAG,iBAAiB,CAAC,MAAO,CAAC;iBACpC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,KAAK,GAAG,CAAC;iBAClC,IAAI,CAAC,IAAI,CAAC,CAAC;YACd,MAAM,CAAC,IAAI,GAAG,eAAe,IAAI,2DAA2D,CAAC;QAC/F,CAAC;QACD,IAAI,CAAC,MAAM,EAAE;YACX,EAAE,EAAE,IAAI;YACR,IAAI,EAAE;gBACJ,MAAM,EAAE,KAAK,CAAC,EAAE;gBAChB,MAAM;gBACN,eAAe,EAAE,UAAU,CAAC,MAAM;gBAClC,UAAU;gBACV,KAAK,EAAE,MAAO,CAAC,KAAK;gBACpB,QAAQ,EAAE,MAAO,CAAC,QAAQ;gBAC1B,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC;aAChC;YACD,IAAI,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,CAAC,QAAQ,UAAU,IAAI,UAAU,CAAC,MAAM,mEAAmE;SAClJ,CAAC,CAAC;IACL,CAAC,CAAC,CACH,CAAC;AACN,CAAC;AAED;iGACiG;AACjG,MAAM,UAAU,eAAe,CAAC,IAAc,EAAE,OAA6B,EAAE,QAAiB;IAC9F,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;QACtE,OAAO;YACL,IAAI,EAAE,WAAW;YACjB,MAAM,EAAE,IAAI,CAAC,EAAE;YACf,MAAM,EAAE,0BAA0B,OAAO,CAAC,WAAW,GAAG;YACxD,KAAK,EAAE,wBAAwB;YAC/B,SAAS,EAAE,OAAO;YAClB,UAAU,EAAE,iCAAiC,IAAI,CAAC,EAAE,eAAe,OAAO,CAAC,WAAW,GAAG;SAC1F,CAAC;IACJ,CAAC;IACD,yFAAyF;IACzF,MAAM,gBAAgB,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC;IACnH,IAAI,gBAAgB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,qBAAqB,EAAE,CAAC;QAC5F,OAAO;YACL,IAAI,EAAE,sBAAsB;YAC5B,MAAM,EAAE,IAAI,CAAC,EAAE;YACf,MAAM,EACJ,gKAAgK;YAClK,KAAK,EAAE,uCAAuC;YAC9C,SAAS,EAAE,SAAsB;YACjC,UAAU,EAAE,qCAAqC,IAAI,CAAC,EAAE,iDAAiD,IAAI,CAAC,EAAE,GAAG;SACpH,CAAC;IACJ,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,CAAC,QAAQ;YAAE,SAAS,CAAC,8CAA8C;QACxE,IAAI,CAAC,CAAC,aAAa,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW;YAAE,SAAS;QAC3D,gFAAgF;QAChF,oEAAoE;QACpE,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;YAAE,SAAS;QAE7B,OAAO;YACL,IAAI,EAAE,CAAC,CAAC,EAAE;YACV,MAAM,EAAE,IAAI,CAAC,EAAE;YACf,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,UAAU,EAAE,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;SAClC,CAAC;IACJ,CAAC;IACD,OAAO,mBAAmB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC7C,CAAC;AAED;;;oEAGoE;AACpE,SAAS,mBAAmB,CAAC,IAAc,EAAE,QAAiB;IAC5D,MAAM,GAAG,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,SAAsB,EAAE,CAAC;IAC1F,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACnB,OAAO,EAAE,GAAG,GAAG,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAE,kBAAkB,EAAE,UAAU,EAAE,kBAAkB,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC;IACjH,CAAC;IACD,IAAI,IAAI,GAAkB,IAAI,CAAC;IAC/B,2DAA2D;IAC3D,uFAAuF;IACvF,uFAAuF;IACvF,4EAA4E;IAC5E,MAAM,SAAS,GAAG,QAAQ,CAAC,CAAC,CAAC,mBAAmB,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACxG,IAAI,SAAS,EAAE,CAAC;QACd,IAAI,CAAC;YACH,IAAI,GAAG,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QACzC,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,GAAG,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClB,MAAM,IAAI,GAAG,sBAAsB,CAAC,IAAI,CAAC,CAAC;QAC1C,IAAI,IAAI,EAAE,CAAC;YACT,OAAO;gBACL,MAAM,EAAE,IAAI,CAAC,EAAE;gBACf,KAAK,EAAE,wBAAwB;gBAC/B,SAAS,EAAE,OAAO;gBAClB,IAAI,EAAE,WAAW;gBACjB,MAAM,EAAE,mCAAmC;gBAC3C,UAAU,EAAE,iCAAiC,IAAI,CAAC,EAAE,EAAE;gBACtD,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;aAC7B,CAAC;QACJ,CAAC;QACD,uEAAuE;QACvE,0EAA0E;QAC1E,2EAA2E;QAC3E,uEAAuE;QACvE,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,EAAE,CAAC;YACpC,OAAO;gBACL,GAAG,GAAG;gBACN,IAAI,EAAE,cAAc;gBACpB,MAAM,EACJ,uJAAuJ;gBACzJ,UAAU,EAAE,0BAA0B,IAAI,CAAC,EAAE,oCAAoC,IAAI,CAAC,EAAE,mCAAmC;aAC5H,CAAC;QACJ,CAAC;IACH,CAAC;IACD,qEAAqE;IACrE,2EAA2E;IAC3E,oEAAoE;IACpE,2EAA2E;IAC3E,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;QAC1D,OAAO;YACL,MAAM,EAAE,IAAI,CAAC,EAAE;YACf,KAAK,EAAE,8BAA8B;YACrC,SAAS,EAAE,OAAoB;YAC/B,IAAI,EAAE,kBAAkB;YACxB,MAAM,EACJ,4HAA4H;YAC9H,UAAU,EAAE,uCAAuC,IAAI,CAAC,EAAE,wEAAwE,IAAI,CAAC,EAAE,CAAC,WAAW,EAAE,6HAA6H,IAAI,CAAC,EAAE,IAAI;SAChS,CAAC;IACJ,CAAC;IACD,gFAAgF;IAChF,8EAA8E;IAC9E,8EAA8E;IAC9E,gFAAgF;IAChF,IAAI,IAAI,CAAC,OAAO,CAAC,kBAAkB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC;QAClE,OAAO;YACL,MAAM,EAAE,IAAI,CAAC,EAAE;YACf,KAAK,EAAE,uCAAuC;YAC9C,SAAS,EAAE,OAAoB;YAC/B,IAAI,EAAE,YAAY;YAClB,MAAM,EACJ,wKAAwK;YAC1K,UAAU,EAAE,iBAAiB,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC,WAAW,EAAE,gPAAgP,IAAI,CAAC,EAAE,IAAI;SACzU,CAAC;IACJ,CAAC;IACD,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC;QAC7D,OAAO;YACL,MAAM,EAAE,IAAI,CAAC,EAAE;YACf,KAAK,EAAE,wBAAwB;YAC/B,SAAS,EAAE,OAAoB;YAC/B,IAAI,EAAE,kBAAkB;YACxB,MAAM,EACJ,0JAA0J;YAC5J,UAAU,EAAE,iCAAiC,IAAI,CAAC,EAAE,sFAAsF,IAAI,CAAC,EAAE,IAAI;SACtJ,CAAC;IACJ,CAAC;IACD,OAAO;QACL,GAAG,GAAG;QACN,IAAI,EAAE,eAAe;QACrB,MAAM,EAAE,4BAA4B;QACpC,UAAU,EACR,4BAA4B,IAAI,CAAC,EAAE,oBAAoB;YACvD,2EAA2E;YAC3E,iDAAiD,IAAI,CAAC,EAAE,mEAAmE;KAC9H,CAAC;AACJ,CAAC;AAED;;0EAE0E;AAC1E,MAAM,UAAU,wBAAwB,CAAC,IAAY;IACnD,OAAO,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,IAAY;IACjD,MAAM,UAAU,GAAG,gEAAgE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/F,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC;QAAE,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAEjD,MAAM,UAAU,GAAG,yCAAyC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxE,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC;QAAE,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAEjD,6EAA6E;IAC7E,8EAA8E;IAC9E,gEAAgE;IAChE,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxC,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAC1B,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC5G,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,YAAY,CAAC,MAAc,EAAE,MAAkB;IACtD,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,KAAK,YAAY,IAAI,MAAM,CAAC,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC;IACtG,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACnE,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3D,OAAO,SAAS,MAAM,OAAO,MAAM,CAAC,IAAI,GAAG,IAAI,KAAK,MAAM,CAAC,MAAM,cAAc,MAAM,CAAC,UAAU,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC;AACnH,CAAC"}
@@ -0,0 +1,66 @@
1
+ import type { Command } from 'commander';
2
+ type PrecedentSpecMatch = {
3
+ id: string;
4
+ core: string;
5
+ title: string;
6
+ status: string;
7
+ path: string;
8
+ archived: boolean;
9
+ archivedAt?: string;
10
+ /** Present on ranked --topic matches (precedent v2). */
11
+ score?: number;
12
+ matchedFields?: string[];
13
+ /** Present on --spec overlap matches: distinctive tables shared with the target (df ascending). */
14
+ sharedTables?: string[];
15
+ };
16
+ type PrecedentLineMatch = {
17
+ id?: string;
18
+ line: string;
19
+ };
20
+ export type MigrationCollision = {
21
+ table: string;
22
+ migration: string;
23
+ };
24
+ export type PrecedentReport = {
25
+ query: {
26
+ spec?: string;
27
+ topic?: string;
28
+ core?: string;
29
+ checkMigrations?: boolean;
30
+ all?: boolean;
31
+ };
32
+ warnings: string[];
33
+ active: PrecedentSpecMatch[];
34
+ archived: PrecedentSpecMatch[];
35
+ registry: PrecedentLineMatch[];
36
+ deferred: PrecedentLineMatch[];
37
+ bodyIdentifiers?: string[];
38
+ migrationCollisions?: MigrationCollision[];
39
+ };
40
+ /** Document-frequency cap for --spec overlap matching. Tables referenced by more specs
41
+ * than this are ubiquitous infrastructure (pf_module_permissions, pf_organizations,
42
+ * hr_employees, …) and say nothing about WHICH prior art is relevant, so they are
43
+ * zero-weighted for overlap matching only (HR-41 measured 90% of its 251 matches came
44
+ * solely from 4 such tables). Absolute floor of 30 with a 2.5%-of-corpus scale-up —
45
+ * the measured max df is ~15.8% of the corpus, so a relative threshold like
46
+ * 30%-of-corpus would never fire. */
47
+ export declare function thresholdForCorpus(corpusSize: number): number;
48
+ /** Backtick-quoted {core}_* identifiers referenced in a spec body. */
49
+ export declare function extractCoreIdentifiers(body: string, core: string): string[];
50
+ /** Backtick-quoted `{core}_*` identifiers for ANY known core prefix — a spec that
51
+ * touches another core's tables is exactly the precedent worth surfacing. */
52
+ export declare function extractKnownCoreIdentifiers(body: string, cores: string[]): string[];
53
+ /** Error text for a --core value outside the canonical core list; null when valid.
54
+ * A silently-accepted bogus core returns 0 matches with exit 0 — lethal for a
55
+ * HALT-to-review gate, so the command exits 1 instead. */
56
+ export declare function unknownCoreError(core: string, repoRoot: string): string | null;
57
+ export declare function registerPrecedent(program: Command): void;
58
+ export declare function buildPrecedentReport(repoRoot: string, query: {
59
+ spec?: string;
60
+ topic?: string;
61
+ core?: string;
62
+ checkMigrations?: boolean;
63
+ all?: boolean;
64
+ }): PrecedentReport;
65
+ export declare function formatPrecedentText(report: PrecedentReport): string;
66
+ export {};