@specverse/engines 6.42.3 → 6.53.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 (119) hide show
  1. package/dist/ai/analyse-runner.d.ts.map +1 -1
  2. package/dist/ai/analyse-runner.js +53 -1
  3. package/dist/ai/analyse-runner.js.map +1 -1
  4. package/dist/ai/prompt-runner.d.ts +39 -1
  5. package/dist/ai/prompt-runner.d.ts.map +1 -1
  6. package/dist/ai/prompt-runner.js +44 -3
  7. package/dist/ai/prompt-runner.js.map +1 -1
  8. package/dist/ai/providers/claude-cli.d.ts.map +1 -1
  9. package/dist/ai/providers/claude-cli.js +8 -1
  10. package/dist/ai/providers/claude-cli.js.map +1 -1
  11. package/dist/ai/skill-loader.d.ts +50 -0
  12. package/dist/ai/skill-loader.d.ts.map +1 -0
  13. package/dist/ai/skill-loader.js +96 -0
  14. package/dist/ai/skill-loader.js.map +1 -0
  15. package/dist/analyse-prepass/adapters/index.d.ts +2 -0
  16. package/dist/analyse-prepass/adapters/index.d.ts.map +1 -1
  17. package/dist/analyse-prepass/adapters/index.js +2 -0
  18. package/dist/analyse-prepass/adapters/index.js.map +1 -1
  19. package/dist/analyse-prepass/adapters/module-functions.d.ts +95 -0
  20. package/dist/analyse-prepass/adapters/module-functions.d.ts.map +1 -0
  21. package/dist/analyse-prepass/adapters/module-functions.js +358 -0
  22. package/dist/analyse-prepass/adapters/module-functions.js.map +1 -0
  23. package/dist/analyse-prepass/adapters/naming-convention-fks.d.ts +90 -0
  24. package/dist/analyse-prepass/adapters/naming-convention-fks.d.ts.map +1 -0
  25. package/dist/analyse-prepass/adapters/naming-convention-fks.js +181 -0
  26. package/dist/analyse-prepass/adapters/naming-convention-fks.js.map +1 -0
  27. package/dist/analyse-prepass/index.d.ts +8 -0
  28. package/dist/analyse-prepass/index.d.ts.map +1 -1
  29. package/dist/analyse-prepass/index.js +130 -0
  30. package/dist/analyse-prepass/index.js.map +1 -1
  31. package/dist/libs/instance-factories/cli/templates/commander/cli-entry-generator.js +11 -12
  32. package/dist/libs/instance-factories/cli/templates/commander/command-generator.js +2 -2
  33. package/dist/libs/instance-factories/services/templates/prisma/behavior-generator.js +24 -2
  34. package/dist/libs/instance-factories/services/templates/prisma/controller-generator.js +28 -20
  35. package/dist/normalise/index.d.ts +14 -0
  36. package/dist/normalise/index.d.ts.map +1 -0
  37. package/dist/normalise/index.js +14 -0
  38. package/dist/normalise/index.js.map +1 -0
  39. package/dist/normalise/load-overrides.d.ts +43 -0
  40. package/dist/normalise/load-overrides.d.ts.map +1 -0
  41. package/dist/normalise/load-overrides.js +121 -0
  42. package/dist/normalise/load-overrides.js.map +1 -0
  43. package/dist/normalise/normalise-rules.d.ts +181 -0
  44. package/dist/normalise/normalise-rules.d.ts.map +1 -0
  45. package/dist/normalise/normalise-rules.js +79 -0
  46. package/dist/normalise/normalise-rules.js.map +1 -0
  47. package/dist/normalise/rules/cluster-module-functions.d.ts +31 -0
  48. package/dist/normalise/rules/cluster-module-functions.d.ts.map +1 -0
  49. package/dist/normalise/rules/cluster-module-functions.js +238 -0
  50. package/dist/normalise/rules/cluster-module-functions.js.map +1 -0
  51. package/dist/normalise/rules/crud-into-curved.d.ts +117 -0
  52. package/dist/normalise/rules/crud-into-curved.d.ts.map +1 -0
  53. package/dist/normalise/rules/crud-into-curved.js +303 -0
  54. package/dist/normalise/rules/crud-into-curved.js.map +1 -0
  55. package/dist/normalise/rules/drop-trivial-passthrough.d.ts +92 -0
  56. package/dist/normalise/rules/drop-trivial-passthrough.d.ts.map +1 -0
  57. package/dist/normalise/rules/drop-trivial-passthrough.js +217 -0
  58. package/dist/normalise/rules/drop-trivial-passthrough.js.map +1 -0
  59. package/dist/normalise/runner.d.ts +58 -0
  60. package/dist/normalise/runner.d.ts.map +1 -0
  61. package/dist/normalise/runner.js +114 -0
  62. package/dist/normalise/runner.js.map +1 -0
  63. package/dist/parser/import-resolver/resolver.js +1 -1
  64. package/dist/parser/import-resolver/resolver.js.map +1 -1
  65. package/dist/realize/engines/typescript-engine.js +1 -1
  66. package/dist/realize/engines/typescript-engine.js.map +1 -1
  67. package/dist/realize/index.d.ts.map +1 -1
  68. package/dist/realize/index.js +142 -90
  69. package/dist/realize/index.js.map +1 -1
  70. package/dist/realize/library/library.js +1 -1
  71. package/dist/realize/library/library.js.map +1 -1
  72. package/dist/realize/library/resolver.d.ts.map +1 -1
  73. package/dist/realize/library/resolver.js +14 -1
  74. package/dist/realize/library/resolver.js.map +1 -1
  75. package/dist/realize/owner-emit-shared.d.ts +114 -0
  76. package/dist/realize/owner-emit-shared.d.ts.map +1 -0
  77. package/dist/realize/owner-emit-shared.js +227 -0
  78. package/dist/realize/owner-emit-shared.js.map +1 -0
  79. package/dist/realize/per-owner-emit.d.ts +1 -58
  80. package/dist/realize/per-owner-emit.d.ts.map +1 -1
  81. package/dist/realize/per-owner-emit.js +45 -209
  82. package/dist/realize/per-owner-emit.js.map +1 -1
  83. package/dist/realize/per-owner-runner.d.ts +1 -2
  84. package/dist/realize/per-owner-runner.d.ts.map +1 -1
  85. package/dist/realize/per-owner-runner.js +1 -1
  86. package/dist/realize/per-owner-runner.js.map +1 -1
  87. package/dist/realize/post-emit-verify/feedback-runner.d.ts +84 -0
  88. package/dist/realize/post-emit-verify/feedback-runner.d.ts.map +1 -0
  89. package/dist/realize/post-emit-verify/feedback-runner.js +177 -0
  90. package/dist/realize/post-emit-verify/feedback-runner.js.map +1 -0
  91. package/dist/realize/post-emit-verify/index.d.ts +17 -0
  92. package/dist/realize/post-emit-verify/index.d.ts.map +1 -0
  93. package/dist/realize/post-emit-verify/index.js +16 -0
  94. package/dist/realize/post-emit-verify/index.js.map +1 -0
  95. package/dist/realize/post-emit-verify/reemit.d.ts +61 -0
  96. package/dist/realize/post-emit-verify/reemit.d.ts.map +1 -0
  97. package/dist/realize/post-emit-verify/reemit.js +122 -0
  98. package/dist/realize/post-emit-verify/reemit.js.map +1 -0
  99. package/dist/realize/post-emit-verify/types.d.ts +138 -0
  100. package/dist/realize/post-emit-verify/types.d.ts.map +1 -0
  101. package/dist/realize/post-emit-verify/types.js +28 -0
  102. package/dist/realize/post-emit-verify/types.js.map +1 -0
  103. package/dist/realize/post-emit-verify/verifier-manifest.d.ts +29 -0
  104. package/dist/realize/post-emit-verify/verifier-manifest.d.ts.map +1 -0
  105. package/dist/realize/post-emit-verify/verifier-manifest.js +55 -0
  106. package/dist/realize/post-emit-verify/verifier-manifest.js.map +1 -0
  107. package/dist/realize/post-emit-verify/verifiers/tsc.d.ts +24 -0
  108. package/dist/realize/post-emit-verify/verifiers/tsc.d.ts.map +1 -0
  109. package/dist/realize/post-emit-verify/verifiers/tsc.js +148 -0
  110. package/dist/realize/post-emit-verify/verifiers/tsc.js.map +1 -0
  111. package/dist/realize/realize-rules.d.ts +113 -0
  112. package/dist/realize/realize-rules.d.ts.map +1 -0
  113. package/dist/realize/realize-rules.js +271 -0
  114. package/dist/realize/realize-rules.js.map +1 -0
  115. package/libs/instance-factories/cli/templates/commander/cli-entry-generator.ts +11 -12
  116. package/libs/instance-factories/cli/templates/commander/command-generator.ts +2 -2
  117. package/libs/instance-factories/services/templates/prisma/behavior-generator.ts +62 -2
  118. package/libs/instance-factories/services/templates/prisma/controller-generator.ts +42 -20
  119. package/package.json +9 -1
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Post-emit feedback runner.
3
+ *
4
+ * After all per-owner emits complete, this orchestrator:
5
+ * 1. Runs all applicable verifiers against the realized output
6
+ * 2. Groups errors by source file → owning entity
7
+ * 3. For each owner with errors, asks the caller to re-emit the
8
+ * file via the provided `reemit` callback (with errors + previous
9
+ * content as context — the caller builds the LLM prompt)
10
+ * 4. Re-runs verifiers + records per-pass deltas
11
+ * 5. Bounded retries (default 1 pass)
12
+ *
13
+ * The runner is intentionally framework-agnostic: it does NOT call any
14
+ * specific LLM provider or import the per-owner-emit module. The
15
+ * caller wires `reemit` to whatever re-emission path makes sense for
16
+ * the project. This keeps the runner testable in isolation and
17
+ * forward-compatible with future re-emit strategies.
18
+ *
19
+ * Rollback policy: if a re-emit INCREASES error count for that file,
20
+ * the runner rolls back to the previous content. The LLM doesn't get
21
+ * to make things worse.
22
+ */
23
+ import { readFileSync, writeFileSync } from 'fs';
24
+ import { join } from 'path';
25
+ import { runAllVerifiers } from './verifier-manifest.js';
26
+ /**
27
+ * Default file→owner mapping for the SpecVerse TypeScript layout:
28
+ * `backend/src/behaviors/<Owner>.ai.ts` → `<Owner>`
29
+ * `<anything>/<Owner>.ai.ts` → `<Owner>` (relaxed fallback)
30
+ * Returns null for files that don't match.
31
+ */
32
+ export function defaultMapFileToOwner(file) {
33
+ const m = /(?:^|\/)([A-Za-z_][\w-]*)\.ai\.ts$/.exec(file);
34
+ return m ? m[1] : null;
35
+ }
36
+ /**
37
+ * Group verifier errors by file (preserving error order within each
38
+ * file). Files with no errors are absent from the map.
39
+ */
40
+ function groupErrorsByFile(errors) {
41
+ const out = new Map();
42
+ for (const e of errors) {
43
+ let bucket = out.get(e.file);
44
+ if (!bucket) {
45
+ bucket = [];
46
+ out.set(e.file, bucket);
47
+ }
48
+ bucket.push(e);
49
+ }
50
+ return out;
51
+ }
52
+ /**
53
+ * Sum the error count for a specific file across a result set.
54
+ */
55
+ function errorCountForFile(errors, file) {
56
+ let n = 0;
57
+ for (const e of errors)
58
+ if (e.file === file)
59
+ n++;
60
+ return n;
61
+ }
62
+ export async function runPostEmitFeedback(ctx, reemit, options = {}) {
63
+ const maxPasses = options.maxPasses ?? 1;
64
+ const maxFilesPerPass = options.maxFilesPerPass ?? 20;
65
+ const mapFileToOwner = options.mapFileToOwner ?? defaultMapFileToOwner;
66
+ const passes = [];
67
+ const verifierNotes = [];
68
+ // Initial verifier pass.
69
+ let currentResults = await runAllVerifiers(ctx);
70
+ for (const r of currentResults) {
71
+ if (r.notes.length > 0)
72
+ verifierNotes.push({ verifierId: r.verifierId, notes: r.notes });
73
+ }
74
+ const initialErrors = currentResults.flatMap((r) => r.errors);
75
+ let currentErrors = initialErrors;
76
+ for (let pass = 1; pass <= maxPasses; pass++) {
77
+ const errorsBefore = currentErrors.length;
78
+ if (errorsBefore === 0)
79
+ break;
80
+ const byFile = groupErrorsByFile(currentErrors);
81
+ const passResult = {
82
+ passNumber: pass,
83
+ errorsBefore,
84
+ errorsAfter: errorsBefore,
85
+ ownersAttempted: 0,
86
+ ownersImproved: 0,
87
+ ownersUnchanged: 0,
88
+ ownersRolledBack: 0,
89
+ ownersUnmappable: 0,
90
+ ownersReemitFailed: 0,
91
+ ownersOverBudget: 0,
92
+ };
93
+ // Per-file backup so we can roll back if the LLM makes it worse.
94
+ const backups = new Map();
95
+ // Apply the per-pass file budget. Iteration order over Map mirrors
96
+ // insertion order — which mirrors verifier emit order — so the
97
+ // first N files are deterministic across runs.
98
+ const fileEntries = [...byFile.entries()];
99
+ const allowed = fileEntries.slice(0, maxFilesPerPass);
100
+ const overBudget = fileEntries.slice(maxFilesPerPass);
101
+ passResult.ownersOverBudget = overBudget.length;
102
+ for (const [file, fileErrors] of allowed) {
103
+ const ownerName = mapFileToOwner(file);
104
+ if (!ownerName) {
105
+ passResult.ownersUnmappable++;
106
+ continue;
107
+ }
108
+ const absFile = join(ctx.outputDir, file);
109
+ let previousContent;
110
+ try {
111
+ previousContent = readFileSync(absFile, 'utf8');
112
+ }
113
+ catch {
114
+ passResult.ownersReemitFailed++;
115
+ continue;
116
+ }
117
+ passResult.ownersAttempted++;
118
+ const newContent = await reemit({
119
+ ownerName,
120
+ file,
121
+ errors: fileErrors,
122
+ previousContent,
123
+ });
124
+ if (!newContent) {
125
+ passResult.ownersReemitFailed++;
126
+ continue;
127
+ }
128
+ backups.set(file, previousContent);
129
+ writeFileSync(absFile, newContent);
130
+ }
131
+ // Re-run verifiers, then compare per-file error counts.
132
+ const newResults = await runAllVerifiers(ctx);
133
+ let newErrors = newResults.flatMap((r) => r.errors);
134
+ // Rollback pass: any file whose error count INCREASED gets restored.
135
+ // Only consider files we actually attempted (within the budget).
136
+ const filesToRestore = [];
137
+ for (const [file, fileErrors] of allowed) {
138
+ const before = fileErrors.length;
139
+ const after = errorCountForFile(newErrors, file);
140
+ if (after > before && backups.has(file)) {
141
+ filesToRestore.push(file);
142
+ passResult.ownersRolledBack++;
143
+ }
144
+ else if (after < before) {
145
+ passResult.ownersImproved++;
146
+ }
147
+ else if (after === before && after > 0) {
148
+ passResult.ownersUnchanged++;
149
+ }
150
+ }
151
+ if (filesToRestore.length > 0) {
152
+ for (const file of filesToRestore) {
153
+ const absFile = join(ctx.outputDir, file);
154
+ writeFileSync(absFile, backups.get(file));
155
+ }
156
+ // Re-run verifiers one more time so the reported `errorsAfter`
157
+ // reflects the post-rollback state.
158
+ const finalResults = await runAllVerifiers(ctx);
159
+ newErrors = finalResults.flatMap((r) => r.errors);
160
+ }
161
+ passResult.errorsAfter = newErrors.length;
162
+ passes.push(passResult);
163
+ currentResults = newResults;
164
+ currentErrors = newErrors;
165
+ // Early exit: if a pass produced no improvement, more passes
166
+ // unlikely to help.
167
+ if (passResult.errorsAfter >= passResult.errorsBefore)
168
+ break;
169
+ }
170
+ return {
171
+ initialErrors,
172
+ finalErrors: currentErrors,
173
+ passes,
174
+ verifierNotes,
175
+ };
176
+ }
177
+ //# sourceMappingURL=feedback-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feedback-runner.js","sourceRoot":"","sources":["../../../src/realize/post-emit-verify/feedback-runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @specverse/engines/realize/post-emit-verify — post-emit verification
3
+ * + feedback runner.
4
+ *
5
+ * Generic framework for running compile / lint / typecheck verifiers
6
+ * on the realized output and feeding errors back to the LLM for a
7
+ * surgical fix pass.
8
+ *
9
+ * See `specverse-self/docs/proposals/...` (TBD) for the design rationale
10
+ * + empirical evidence from idle-meta 2026-05-13.
11
+ */
12
+ export { type PostEmitVerifier, type VerifyContext, type VerifyError, type VerifyResult, type OwnerMapping, } from './types.js';
13
+ export { VERIFIERS, runAllVerifiers, findVerifier, } from './verifier-manifest.js';
14
+ export { runPostEmitFeedback, defaultMapFileToOwner, type Reemit, type ReemitRequest, type FeedbackRunOptions, type FeedbackRunResult, type PassResult, } from './feedback-runner.js';
15
+ export { TSC_VERIFIER } from './verifiers/tsc.js';
16
+ export { buildLlmReemit, formatFeedbackPrompt, type BuildReemitOptions, } from './reemit.js';
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/realize/post-emit-verify/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,YAAY,GAClB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,SAAS,EACT,eAAe,EACf,YAAY,GACb,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,KAAK,MAAM,EACX,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,UAAU,GAChB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,KAAK,kBAAkB,GACxB,MAAM,aAAa,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @specverse/engines/realize/post-emit-verify — post-emit verification
3
+ * + feedback runner.
4
+ *
5
+ * Generic framework for running compile / lint / typecheck verifiers
6
+ * on the realized output and feeding errors back to the LLM for a
7
+ * surgical fix pass.
8
+ *
9
+ * See `specverse-self/docs/proposals/...` (TBD) for the design rationale
10
+ * + empirical evidence from idle-meta 2026-05-13.
11
+ */
12
+ export { VERIFIERS, runAllVerifiers, findVerifier, } from './verifier-manifest.js';
13
+ export { runPostEmitFeedback, defaultMapFileToOwner, } from './feedback-runner.js';
14
+ export { TSC_VERIFIER } from './verifiers/tsc.js';
15
+ export { buildLlmReemit, formatFeedbackPrompt, } from './reemit.js';
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/realize/post-emit-verify/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAUH,OAAO,EACL,SAAS,EACT,eAAe,EACf,YAAY,GACb,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,mBAAmB,EACnB,qBAAqB,GAMtB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EACL,cAAc,EACd,oBAAoB,GAErB,MAAM,aAAa,CAAC"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Default `Reemit` implementation — builds a feedback prompt from
3
+ * verifier errors + previous file content and calls the LLM to
4
+ * re-emit a single file.
5
+ *
6
+ * The realize-emit skill (at ~/.claude/skills/realize-emit/) is
7
+ * auto-loaded by claude-cli when its description matches the prompt
8
+ * shape — that carries all the per-owner emission conventions
9
+ * (typing rules, _input convention, γ-stub shape, etc.) so the
10
+ * feedback re-emit benefits from the same guidance as the original
11
+ * emission.
12
+ *
13
+ * The prompt is intentionally minimal:
14
+ * - Errors (verifier-formatted)
15
+ * - Previous file content
16
+ * - A request to re-emit
17
+ *
18
+ * Future iterations may augment with AVAILABLE SPEC SURFACE (cross-
19
+ * service signatures) when the errors are arity-shape — empirically,
20
+ * the skill + basic prompt suffices for most null-safety / type
21
+ * mismatch / unused-decl cases.
22
+ */
23
+ import type { LanguageModel } from 'ai';
24
+ import type { Reemit, ReemitRequest } from './feedback-runner.js';
25
+ export interface BuildReemitOptions {
26
+ /** LLM model — same shared model used by per-owner-emit. */
27
+ model: LanguageModel;
28
+ /** Max retries per file when the LLM produces empty / unparseable
29
+ * output. Default 1. */
30
+ maxAttempts?: number;
31
+ /** Per-call timeout. Default 3min — feedback re-emits are typically
32
+ * faster than fresh emissions because the LLM has the previous
33
+ * content to anchor on. */
34
+ timeoutMs?: number;
35
+ /**
36
+ * Skills whose content should be inlined into the system prompt for
37
+ * non-claude-cli providers. claude-cli auto-loads skills via
38
+ * filesystem-based resolution; other providers (`openai-compatible`,
39
+ * `anthropic`, `stub`) need explicit inlining of the skill content.
40
+ *
41
+ * Defaults to `['realize-emit']` — the realize-emit skill carries the
42
+ * per-owner emission CONSTRAINTS / GUIDANCE / EXAMPLE that's directly
43
+ * relevant to the feedback re-emit task (typing conventions, _input
44
+ * convention, γ-stub shape).
45
+ */
46
+ skills?: string[];
47
+ }
48
+ /**
49
+ * Build a `Reemit` callback that uses the provided LLM model.
50
+ *
51
+ * The returned closure can be passed straight to `runPostEmitFeedback`.
52
+ */
53
+ export declare function buildLlmReemit(options: BuildReemitOptions): Reemit;
54
+ /**
55
+ * Format the feedback prompt body. Caller's LLM provider (e.g.
56
+ * claude-cli) loads the realize-emit skill as system context.
57
+ *
58
+ * Exported for tests + so callers can override the prompt shape.
59
+ */
60
+ export declare function formatFeedbackPrompt(req: ReemitRequest): string;
61
+ //# sourceMappingURL=reemit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reemit.d.ts","sourceRoot":"","sources":["../../../src/realize/post-emit-verify/reemit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AAGxC,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGlE,MAAM,WAAW,kBAAkB;IACjC,4DAA4D;IAC5D,KAAK,EAAE,aAAa,CAAC;IACrB;6BACyB;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;gCAE4B;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;;;;OAUG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,CA4ClE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAqB/D"}
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Default `Reemit` implementation — builds a feedback prompt from
3
+ * verifier errors + previous file content and calls the LLM to
4
+ * re-emit a single file.
5
+ *
6
+ * The realize-emit skill (at ~/.claude/skills/realize-emit/) is
7
+ * auto-loaded by claude-cli when its description matches the prompt
8
+ * shape — that carries all the per-owner emission conventions
9
+ * (typing rules, _input convention, γ-stub shape, etc.) so the
10
+ * feedback re-emit benefits from the same guidance as the original
11
+ * emission.
12
+ *
13
+ * The prompt is intentionally minimal:
14
+ * - Errors (verifier-formatted)
15
+ * - Previous file content
16
+ * - A request to re-emit
17
+ *
18
+ * Future iterations may augment with AVAILABLE SPEC SURFACE (cross-
19
+ * service signatures) when the errors are arity-shape — empirically,
20
+ * the skill + basic prompt suffices for most null-safety / type
21
+ * mismatch / unused-decl cases.
22
+ */
23
+ import { generateText } from 'ai';
24
+ import { assembleSystemWithSkills } from '../../ai/prompt-runner.js';
25
+ import { resolveProviderId } from '../../ai/model-resolver.js';
26
+ /**
27
+ * Build a `Reemit` callback that uses the provided LLM model.
28
+ *
29
+ * The returned closure can be passed straight to `runPostEmitFeedback`.
30
+ */
31
+ export function buildLlmReemit(options) {
32
+ const maxAttempts = options.maxAttempts ?? 1;
33
+ const timeoutMs = options.timeoutMs ?? 3 * 60_000;
34
+ const skills = options.skills ?? ['realize-emit'];
35
+ // Provider-aware skill inlining: claude-cli auto-loads skills via the
36
+ // CLI's filesystem resolution; everyone else needs the skill content
37
+ // prepended to the system prompt. Compute once at build time — the
38
+ // provider can't change mid-loop.
39
+ const providerId = resolveProviderId();
40
+ const systemPrompt = assembleSystemWithSkills('', providerId, skills);
41
+ return async (req) => {
42
+ const prompt = formatFeedbackPrompt(req);
43
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
44
+ try {
45
+ const result = await Promise.race([
46
+ generateText({
47
+ model: options.model,
48
+ prompt,
49
+ // For non-claude-cli providers, `systemPrompt` carries the
50
+ // skill content; for claude-cli it's empty and the CLI
51
+ // auto-loads.
52
+ ...(systemPrompt ? { system: systemPrompt } : {}),
53
+ }),
54
+ new Promise((_, reject) => setTimeout(() => reject(new Error('reemit timeout')), timeoutMs)),
55
+ ]);
56
+ const extracted = extractTypeScriptBlock(result.text ?? '');
57
+ if (!extracted) {
58
+ if (attempt + 1 < maxAttempts)
59
+ continue;
60
+ return null;
61
+ }
62
+ return extracted;
63
+ }
64
+ catch (err) {
65
+ if (attempt + 1 < maxAttempts)
66
+ continue;
67
+ return null;
68
+ }
69
+ }
70
+ return null;
71
+ };
72
+ }
73
+ /**
74
+ * Format the feedback prompt body. Caller's LLM provider (e.g.
75
+ * claude-cli) loads the realize-emit skill as system context.
76
+ *
77
+ * Exported for tests + so callers can override the prompt shape.
78
+ */
79
+ export function formatFeedbackPrompt(req) {
80
+ const errorLines = req.errors
81
+ .map(formatError)
82
+ .join('\n');
83
+ return [
84
+ `Re-emit the entire contents of \`${req.file}\`.`,
85
+ '',
86
+ `Your previous emission had the following compile / lint errors:`,
87
+ '',
88
+ errorLines,
89
+ '',
90
+ `Previous file content (re-emit this with the errors fixed):`,
91
+ '',
92
+ '```typescript',
93
+ req.previousContent,
94
+ '```',
95
+ '',
96
+ `Fix the errors and emit the ENTIRE updated file inside one \`\`\`typescript code block.`,
97
+ `Do not change any logic beyond what's needed to fix the errors.`,
98
+ ].join('\n');
99
+ }
100
+ function formatError(e) {
101
+ const pos = e.line !== undefined
102
+ ? `:${e.line}${e.col !== undefined ? `:${e.col}` : ''}`
103
+ : '';
104
+ return ` ${e.file}${pos} [${e.code}] ${e.message}`;
105
+ }
106
+ /**
107
+ * Pull the TypeScript code out of the LLM response. Matches the
108
+ * canonical ```typescript ... ``` block; falls back to ``` ... ``` if
109
+ * the LLM omitted the language tag.
110
+ */
111
+ function extractTypeScriptBlock(text) {
112
+ if (!text)
113
+ return null;
114
+ const tsMatch = /```typescript\s*\n([\s\S]*?)\n```/.exec(text);
115
+ if (tsMatch)
116
+ return tsMatch[1];
117
+ const anyMatch = /```\s*\n([\s\S]*?)\n```/.exec(text);
118
+ if (anyMatch)
119
+ return anyMatch[1];
120
+ return null;
121
+ }
122
+ //# sourceMappingURL=reemit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reemit.js","sourceRoot":"","sources":["../../../src/realize/post-emit-verify/reemit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Post-emit verification framework — generic interface.
3
+ *
4
+ * SpecVerse realize emits one or more LLM-authored source files per
5
+ * owner (e.g. `backend/src/behaviors/<Owner>.ai.ts` for the TypeScript
6
+ * stack). LLM emissions sometimes carry compile errors / lint issues
7
+ * that don't show up at per-rule validation time (the realize-rules
8
+ * manifest catches forbidden APIs, missing `.js` extensions, etc., but
9
+ * not type mismatches or runtime semantics).
10
+ *
11
+ * A `PostEmitVerifier` runs AFTER all owners have emitted, on the
12
+ * fully-realized output tree. It produces structured errors that the
13
+ * feedback runner uses to drive a per-file re-emit pass.
14
+ *
15
+ * The interface is intentionally language-agnostic. The first
16
+ * implementation is `tsc` for TypeScript stacks; future verifiers can
17
+ * target Python (`mypy`/`ruff`), Go (`go vet`), Java (`mvn compile`),
18
+ * Rust (`cargo check`), etc. Each verifier knows whether it `applies`
19
+ * given the realized target (the manifest's stack tells you).
20
+ *
21
+ * Empirical motivation: 2026-05-13 idle-meta realize at engines 6.50.1
22
+ * produced 48 backend tsc errors. Two hand-crafted feedback prompts
23
+ * (AuthController.ai.ts + FormatNumberService.ai.ts) reduced this to
24
+ * 37 errors with zero regressions. Extrapolation: a full feedback
25
+ * sweep brings idle-meta from ~48 → ~5-10 errors per realize.
26
+ */
27
+ /**
28
+ * Single error reported by a verifier. Position-optional (some
29
+ * verifiers — Go vet, formatters — emit errors without precise
30
+ * line/col).
31
+ */
32
+ export interface VerifyError {
33
+ /** Path to the source file, relative to the realized output dir. */
34
+ file: string;
35
+ line?: number;
36
+ col?: number;
37
+ /** Verifier-specific code, e.g. "TS2554", "py:E501", "go:S1000". */
38
+ code: string;
39
+ /** Human-readable description, suitable for inclusion in a feedback
40
+ * prompt. Verifier-specific; the framework doesn't interpret it. */
41
+ message: string;
42
+ severity: 'error' | 'warning';
43
+ }
44
+ /**
45
+ * Result of running a single verifier on the realized output.
46
+ */
47
+ export interface VerifyResult {
48
+ /** Verifier id (matches `PostEmitVerifier.id`). */
49
+ verifierId: string;
50
+ /** Wall-time. Useful for tuning verifier order + budget. */
51
+ durationMs: number;
52
+ /** Whether the verifier ran successfully. False indicates a tool-level
53
+ * failure (tsc not installed, npm install needed first, etc.) — the
54
+ * feedback runner SKIPS the verifier when not ok, not when errors > 0. */
55
+ ok: boolean;
56
+ errors: VerifyError[];
57
+ /** Non-fatal warnings from the verifier itself (separate from
58
+ * per-error severity), e.g. "tsc emitted 200 errors but we truncated
59
+ * to 100". */
60
+ notes: string[];
61
+ }
62
+ /**
63
+ * Context passed to verifiers — describes the realize target so each
64
+ * verifier can decide whether it `applies`.
65
+ *
66
+ * Minimal for now; extends as new verifiers need additional signal.
67
+ */
68
+ export interface VerifyContext {
69
+ /** Absolute path to the realized output root (the dir that contains
70
+ * e.g. `backend/`, `frontend/`, `tests/`). */
71
+ outputDir: string;
72
+ /** Realize target tag, e.g. 'typescript', 'python', 'go'. Set by the
73
+ * realize pipeline based on the manifest's primary stack. */
74
+ targetLanguage?: string;
75
+ /** Optional: explicit subpath within outputDir to verify. tsc would
76
+ * typically scope to `backend/`. Defaults to outputDir itself. */
77
+ subpath?: string;
78
+ /**
79
+ * When true (the default), verifiers MAY run dependency installation
80
+ * (`npm install` / `pip install` / etc.) before running their actual
81
+ * checks. Required for the in-pipeline `spv realize` invocation:
82
+ * realize emits a scaffolded project but doesn't install deps, so
83
+ * tsc/mypy/etc. wouldn't otherwise be available.
84
+ *
85
+ * Set to false in test harnesses or when the caller has already
86
+ * installed deps. Each verifier decides whether to honour the hint —
87
+ * a stub-only verifier might ignore it.
88
+ */
89
+ autoInstall?: boolean;
90
+ }
91
+ /**
92
+ * A verifier runs a quality check on the realized output. Each
93
+ * verifier is independent — the framework collects results from
94
+ * applicable verifiers, then the feedback runner decides what to do.
95
+ *
96
+ * Implementations must NOT throw on tool-level failures; return
97
+ * `{ ok: false, errors: [], notes: ['…'] }` instead. The framework
98
+ * surfaces notes to the user; throws crash the realize pipeline.
99
+ */
100
+ export interface PostEmitVerifier {
101
+ /** Stable identifier — kebab-case. e.g. 'tsc', 'mypy', 'go-vet'. */
102
+ id: string;
103
+ /** Human-readable name for logs and audit. */
104
+ name: string;
105
+ /**
106
+ * Whether this verifier runs unless explicitly disabled. Mature
107
+ * stable verifiers ship `enabledByDefault: true` (tsc); experimental
108
+ * or third-party verifiers ship `false` to require an opt-in via
109
+ * `SPECVERSE_REALIZE_POST_VERIFY_ENABLE=<id>,<id>` env (future).
110
+ *
111
+ * Optional for backwards compatibility — missing field is treated
112
+ * as `true` (the original behavior).
113
+ */
114
+ enabledByDefault?: boolean;
115
+ /** Predicate: does this verifier apply to the given context? */
116
+ applies: (ctx: VerifyContext) => boolean;
117
+ /** Run the verifier. MUST NOT throw on tool failure (return ok:false). */
118
+ verify: (ctx: VerifyContext) => Promise<VerifyResult>;
119
+ }
120
+ /**
121
+ * After all verifiers have run, the feedback runner needs to map
122
+ * each errored file to its owning spec entity (e.g.
123
+ * `backend/src/behaviors/AuthController.ai.ts` → ownerName=AuthController).
124
+ *
125
+ * Each verifier MAY contribute a mapping hint via `mapFileToOwner`,
126
+ * but the framework falls back to a generic regex
127
+ * (`behaviors/(.+)\\.ai\\.ts$` for TypeScript). Verifiers for other
128
+ * stacks would override the mapping.
129
+ */
130
+ export interface OwnerMapping {
131
+ /** Source file path (relative to outputDir). */
132
+ file: string;
133
+ /** Inferred owner name. null if the file can't be mapped (e.g.
134
+ * shared infrastructure files generated by the framework, not by
135
+ * per-owner LLM emit — those should NOT receive feedback re-emits). */
136
+ ownerName: string | null;
137
+ }
138
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/realize/post-emit-verify/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAC;IACb;yEACqE;IACrE,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,UAAU,EAAE,MAAM,CAAC;IACnB;;+EAE2E;IAC3E,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB;;mBAEe;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B;mDAC+C;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB;kEAC8D;IAC9D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;uEACmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;;;;OAUG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,gBAAgB;IAC/B,oEAAoE;IACpE,EAAE,EAAE,MAAM,CAAC;IACX,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;;OAQG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,gEAAgE;IAChE,OAAO,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC;IACzC,0EAA0E;IAC1E,MAAM,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;CACvD;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,YAAY;IAC3B,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb;;4EAEwE;IACxE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Post-emit verification framework — generic interface.
3
+ *
4
+ * SpecVerse realize emits one or more LLM-authored source files per
5
+ * owner (e.g. `backend/src/behaviors/<Owner>.ai.ts` for the TypeScript
6
+ * stack). LLM emissions sometimes carry compile errors / lint issues
7
+ * that don't show up at per-rule validation time (the realize-rules
8
+ * manifest catches forbidden APIs, missing `.js` extensions, etc., but
9
+ * not type mismatches or runtime semantics).
10
+ *
11
+ * A `PostEmitVerifier` runs AFTER all owners have emitted, on the
12
+ * fully-realized output tree. It produces structured errors that the
13
+ * feedback runner uses to drive a per-file re-emit pass.
14
+ *
15
+ * The interface is intentionally language-agnostic. The first
16
+ * implementation is `tsc` for TypeScript stacks; future verifiers can
17
+ * target Python (`mypy`/`ruff`), Go (`go vet`), Java (`mvn compile`),
18
+ * Rust (`cargo check`), etc. Each verifier knows whether it `applies`
19
+ * given the realized target (the manifest's stack tells you).
20
+ *
21
+ * Empirical motivation: 2026-05-13 idle-meta realize at engines 6.50.1
22
+ * produced 48 backend tsc errors. Two hand-crafted feedback prompts
23
+ * (AuthController.ai.ts + FormatNumberService.ai.ts) reduced this to
24
+ * 37 errors with zero regressions. Extrapolation: a full feedback
25
+ * sweep brings idle-meta from ~48 → ~5-10 errors per realize.
26
+ */
27
+ export {};
28
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/realize/post-emit-verify/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Post-emit verifier manifest — single source of truth for which
3
+ * verifiers ship with the realize pipeline.
4
+ *
5
+ * Adding a new verifier: append to VERIFIERS, then it auto-runs on
6
+ * matching realize targets via `applies`.
7
+ */
8
+ import type { PostEmitVerifier, VerifyContext, VerifyResult } from './types.js';
9
+ export declare const VERIFIERS: PostEmitVerifier[];
10
+ /**
11
+ * Run all applicable verifiers against the realized output. Verifiers
12
+ * run in series (most are heavyweight enough that parallel doesn't
13
+ * help much, and series gives predictable log output). Each verifier's
14
+ * tool-level failures are isolated — one failure doesn't stop the
15
+ * others.
16
+ *
17
+ * Verifier filtering order:
18
+ * 1. `enabledByDefault === false` AND id NOT in `enabledOverrides` → SKIP
19
+ * 2. `applies(ctx)` returns false → SKIP
20
+ * 3. Otherwise → run
21
+ *
22
+ * Missing `enabledByDefault` field is treated as `true` (backwards-
23
+ * compatible default). The `enabledOverrides` parameter lets callers
24
+ * opt-in to experimental verifiers at run-time without changing the
25
+ * manifest.
26
+ */
27
+ export declare function runAllVerifiers(ctx: VerifyContext, enabledOverrides?: Set<string>): Promise<VerifyResult[]>;
28
+ export declare function findVerifier(id: string): PostEmitVerifier | undefined;
29
+ //# sourceMappingURL=verifier-manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verifier-manifest.d.ts","sourceRoot":"","sources":["../../../src/realize/post-emit-verify/verifier-manifest.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAGhF,eAAO,MAAM,SAAS,EAAE,gBAAgB,EAOvC,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,aAAa,EAClB,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAC7B,OAAO,CAAC,YAAY,EAAE,CAAC,CAqBzB;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAErE"}