human-to-code 0.1.27 → 0.1.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Readme.md +56 -36
- package/dist/agents/direct/file-memory.d.ts.map +1 -1
- package/dist/agents/direct/file-memory.js +70 -1
- package/dist/agents/direct/file-memory.js.map +1 -1
- package/dist/agents/direct/generation-client.d.ts +10 -0
- package/dist/agents/direct/generation-client.d.ts.map +1 -1
- package/dist/agents/direct/generation-client.js +19 -0
- package/dist/agents/direct/generation-client.js.map +1 -1
- package/dist/agents/direct/index.d.ts +3 -0
- package/dist/agents/direct/index.d.ts.map +1 -1
- package/dist/agents/direct/index.js +3 -0
- package/dist/agents/direct/index.js.map +1 -1
- package/dist/agents/direct/presentation.d.ts +20 -0
- package/dist/agents/direct/presentation.d.ts.map +1 -1
- package/dist/agents/direct/presentation.js +33 -3
- package/dist/agents/direct/presentation.js.map +1 -1
- package/dist/agents/direct/project-blueprint.d.ts +29 -0
- package/dist/agents/direct/project-blueprint.d.ts.map +1 -0
- package/dist/agents/direct/project-blueprint.js +170 -0
- package/dist/agents/direct/project-blueprint.js.map +1 -0
- package/dist/agents/direct/project-contracts.d.ts +34 -0
- package/dist/agents/direct/project-contracts.d.ts.map +1 -1
- package/dist/agents/direct/project-contracts.js +59 -42
- package/dist/agents/direct/project-contracts.js.map +1 -1
- package/dist/agents/direct/project-memory.d.ts +6 -0
- package/dist/agents/direct/project-memory.d.ts.map +1 -1
- package/dist/agents/direct/project-memory.js +20 -0
- package/dist/agents/direct/project-memory.js.map +1 -1
- package/dist/agents/direct/reference-validation.d.ts +55 -0
- package/dist/agents/direct/reference-validation.d.ts.map +1 -0
- package/dist/agents/direct/reference-validation.js +415 -0
- package/dist/agents/direct/reference-validation.js.map +1 -0
- package/dist/agents/direct/types.d.ts +45 -0
- package/dist/agents/direct/types.d.ts.map +1 -1
- package/dist/agents/direct/unit-todos.d.ts +51 -0
- package/dist/agents/direct/unit-todos.d.ts.map +1 -0
- package/dist/agents/direct/unit-todos.js +223 -0
- package/dist/agents/direct/unit-todos.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +147 -10
- package/dist/cli.js.map +1 -1
- package/dist/config/config.d.ts +22 -1
- package/dist/config/config.d.ts.map +1 -1
- package/dist/config/config.js +40 -6
- package/dist/config/config.js.map +1 -1
- package/dist/prompts/direct-blueprint.d.ts +19 -0
- package/dist/prompts/direct-blueprint.d.ts.map +1 -0
- package/dist/prompts/direct-blueprint.js +49 -0
- package/dist/prompts/direct-blueprint.js.map +1 -0
- package/dist/prompts/direct-conversion.d.ts +8 -0
- package/dist/prompts/direct-conversion.d.ts.map +1 -1
- package/dist/prompts/direct-conversion.js +26 -0
- package/dist/prompts/direct-conversion.js.map +1 -1
- package/dist/prompts/direct-todos.d.ts +17 -0
- package/dist/prompts/direct-todos.d.ts.map +1 -0
- package/dist/prompts/direct-todos.js +43 -0
- package/dist/prompts/direct-todos.js.map +1 -0
- package/dist/prompts/index.d.ts +2 -0
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/index.js +2 -0
- package/dist/prompts/index.js.map +1 -1
- package/dist/providers/provider.d.ts.map +1 -1
- package/dist/providers/provider.js +3 -1
- package/dist/providers/provider.js.map +1 -1
- package/docs/ARCHITECTURE.md +23 -6
- package/docs/CONFIGURATION.md +251 -0
- package/docs/MODULES.md +5 -2
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unit-todos.d.ts","sourceRoot":"","sources":["../../../src/agents/direct/unit-todos.ts"],"names":[],"mappings":"AAeA,OAAO,EAA8B,KAAK,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAGlG,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,uBAAuB,CAAC;IAC9B,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,mBAAmB,CAAC;CAC/B;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,yEAAyE;IACzE,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,uEAAuE;IACvE,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,2EAA2E;IAC3E,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAOD,mFAAmF;AACnF,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAuB/C;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,YAAY,CA4ClG;AAyCD;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,SAAS,QAAQ,EAAE,EAC1B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,GACX,YAAY,CAad;AAED,yDAAyD;AACzD,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,SAAS,QAAQ,EAAE,EAC1B,QAAQ,EAAE,YAAY,GACrB,MAAM,EAAE,CAQV;AAED,oEAAoE;AACpE,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,GAAG,MAAM,CAOjE;AA0BD,MAAM,WAAW,kBAAkB;IACjC,2EAA2E;IAC3E,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,8CAA8C;IAC9C,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,2HAA2H;AAC3H,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,kBAAkB,CAOpB;AAED,oGAAoG;AACpG,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,kBAAkB,GAAG,OAAO,CAEzE"}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-unit planning and the guard that makes a second coding pass safe.
|
|
3
|
+
*
|
|
4
|
+
* A todo list is agreed for one target before it is written, then a
|
|
5
|
+
* deterministic coverage check looks for the artifacts that list promised. Only
|
|
6
|
+
* a real coverage gap triggers a refinement request, and the refinement is
|
|
7
|
+
* accepted only if it keeps everything the previous pass produced — the
|
|
8
|
+
* regression ratchet. That inverts the usual risk of re-emitting a whole file:
|
|
9
|
+
* a model that drops most of a stylesheet loses its own output, not the run's.
|
|
10
|
+
*
|
|
11
|
+
* Coverage means "the named artifact appears in the output", never "the
|
|
12
|
+
* requirement is implemented" and never verification.
|
|
13
|
+
*/
|
|
14
|
+
import { extname } from "node:path";
|
|
15
|
+
import { extractStaticFileMemory } from "../../pipeline/file-memory.js";
|
|
16
|
+
import { BLUEPRINT_VOCABULARY_KINDS } from "./project-blueprint.js";
|
|
17
|
+
import { cssFacts, htmlFacts, javaScriptFacts } from "./project-contracts.js";
|
|
18
|
+
const MAX_TODOS = 24;
|
|
19
|
+
const MAX_EXPECTED_NAMES = 8;
|
|
20
|
+
const MAX_REQUIREMENT_CHARS = 240;
|
|
21
|
+
const ID_PATTERN = /^T[0-9]{1,2}$/u;
|
|
22
|
+
const NAME_PATTERN = /^[A-Za-z_$][A-Za-z0-9_$:.\-/]{0,119}$/u;
|
|
23
|
+
/** A refinement may not shrink a file below this fraction of the previous pass. */
|
|
24
|
+
export const MIN_REFINEMENT_LENGTH_RATIO = 0.6;
|
|
25
|
+
const HTML_EXTENSIONS = new Set([".html", ".htm"]);
|
|
26
|
+
const SCRIPT_EXTENSIONS = new Set([".js", ".jsx", ".mjs", ".cjs", ".ts", ".tsx", ".mts", ".cts"]);
|
|
27
|
+
function oneLine(value, limit) {
|
|
28
|
+
const clean = value
|
|
29
|
+
.replace(/[\u0000-\u0008\u000b-\u001f\u007f]/gu, " ")
|
|
30
|
+
.replace(/\s+/gu, " ")
|
|
31
|
+
.trim();
|
|
32
|
+
return clean.length <= limit ? clean : `${clean.slice(0, Math.max(0, limit - 1))}…`;
|
|
33
|
+
}
|
|
34
|
+
function ownKeys(value, expected) {
|
|
35
|
+
const actual = Object.keys(value).sort();
|
|
36
|
+
const wanted = [...expected].sort();
|
|
37
|
+
return actual.length === wanted.length && actual.every((key, index) => key === wanted[index]);
|
|
38
|
+
}
|
|
39
|
+
function object(value) {
|
|
40
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Strictly validate a todo list. When `allowedNames` is supplied, an expectation
|
|
44
|
+
* naming something outside the agreed vocabulary is dropped rather than
|
|
45
|
+
* rejected: the requirement text is still useful, and a stray name must never
|
|
46
|
+
* become a new instruction.
|
|
47
|
+
*/
|
|
48
|
+
export function parseUnitTodoList(output, allowedNames) {
|
|
49
|
+
let parsed;
|
|
50
|
+
try {
|
|
51
|
+
parsed = JSON.parse(output);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
throw new Error("Todo list is not valid JSON.");
|
|
55
|
+
}
|
|
56
|
+
if (!object(parsed) || !ownKeys(parsed, ["todos"])) {
|
|
57
|
+
throw new Error("Todo list must contain exactly todos.");
|
|
58
|
+
}
|
|
59
|
+
if (!Array.isArray(parsed.todos) || parsed.todos.length === 0 || parsed.todos.length > MAX_TODOS) {
|
|
60
|
+
throw new Error(`Todo list must be an array with 1-${MAX_TODOS} entries.`);
|
|
61
|
+
}
|
|
62
|
+
const seen = new Set();
|
|
63
|
+
const todos = parsed.todos.map((value, index) => {
|
|
64
|
+
if (!object(value) || (!ownKeys(value, ["id", "requirement"]) && !ownKeys(value, ["expects", "id", "requirement"]))) {
|
|
65
|
+
throw new Error(`Todo ${index} has unknown or missing fields.`);
|
|
66
|
+
}
|
|
67
|
+
if (typeof value.id !== "string" || !ID_PATTERN.test(value.id)) {
|
|
68
|
+
throw new Error(`Todo ${index} has an invalid id.`);
|
|
69
|
+
}
|
|
70
|
+
if (seen.has(value.id))
|
|
71
|
+
throw new Error(`Todo list repeats the id ${value.id}.`);
|
|
72
|
+
seen.add(value.id);
|
|
73
|
+
if (typeof value.requirement !== "string")
|
|
74
|
+
throw new Error(`Todo ${index} has an invalid requirement.`);
|
|
75
|
+
const requirement = oneLine(value.requirement, MAX_REQUIREMENT_CHARS);
|
|
76
|
+
if (requirement.length === 0)
|
|
77
|
+
throw new Error(`Todo ${index} has an empty requirement.`);
|
|
78
|
+
if (value.expects === undefined)
|
|
79
|
+
return { id: value.id, requirement };
|
|
80
|
+
if (!object(value.expects) || !ownKeys(value.expects, ["kind", "names"])) {
|
|
81
|
+
throw new Error(`Todo ${index} has an invalid expects object.`);
|
|
82
|
+
}
|
|
83
|
+
const { kind, names } = value.expects;
|
|
84
|
+
if (typeof kind !== "string" || !BLUEPRINT_VOCABULARY_KINDS.includes(kind)) {
|
|
85
|
+
throw new Error(`Todo ${index} expects an unknown kind.`);
|
|
86
|
+
}
|
|
87
|
+
if (!Array.isArray(names) || names.length === 0 || names.length > MAX_EXPECTED_NAMES) {
|
|
88
|
+
throw new Error(`Todo ${index} must expect 1-${MAX_EXPECTED_NAMES} names.`);
|
|
89
|
+
}
|
|
90
|
+
const cleaned = names.filter((name) => typeof name === "string" && NAME_PATTERN.test(name) && (allowedNames === undefined || allowedNames.has(name)));
|
|
91
|
+
if (cleaned.length === 0)
|
|
92
|
+
return { id: value.id, requirement };
|
|
93
|
+
return { id: value.id, requirement, expects: { kind, names: [...new Set(cleaned)] } };
|
|
94
|
+
});
|
|
95
|
+
return { todos };
|
|
96
|
+
}
|
|
97
|
+
/** Names a candidate demonstrably contains, by the file's own syntax. */
|
|
98
|
+
function presentNames(targetPath, code) {
|
|
99
|
+
const extension = extname(targetPath).toLowerCase();
|
|
100
|
+
const present = new Set();
|
|
101
|
+
const add = (values) => {
|
|
102
|
+
for (const value of values)
|
|
103
|
+
if (value.length > 0)
|
|
104
|
+
present.add(value);
|
|
105
|
+
};
|
|
106
|
+
if (HTML_EXTENSIONS.has(extension)) {
|
|
107
|
+
const facts = htmlFacts(code);
|
|
108
|
+
add(facts.classes);
|
|
109
|
+
add(facts.ids);
|
|
110
|
+
add(facts.handlerCalls);
|
|
111
|
+
add(facts.elements);
|
|
112
|
+
}
|
|
113
|
+
else if (extension === ".css") {
|
|
114
|
+
const facts = cssFacts(code);
|
|
115
|
+
add(facts.customProperties);
|
|
116
|
+
add(facts.selectors.map((selector) => selector.trim()));
|
|
117
|
+
for (const selector of facts.selectors) {
|
|
118
|
+
add((selector.match(/[.#][A-Za-z0-9_-]+/gu) ?? []).map((token) => token.slice(1)));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
else if (SCRIPT_EXTENSIONS.has(extension)) {
|
|
122
|
+
const facts = javaScriptFacts(code);
|
|
123
|
+
add(facts.toggledClasses);
|
|
124
|
+
add(facts.selectors);
|
|
125
|
+
for (const selector of facts.selectors) {
|
|
126
|
+
add((selector.match(/[.#][A-Za-z0-9_-]+/gu) ?? []).map((token) => token.slice(1)));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
for (const entry of extractStaticFileMemory(targetPath, code)) {
|
|
130
|
+
add((entry.code.match(/[A-Za-z_$][A-Za-z0-9_$]*/gu) ?? []).slice(0, 8));
|
|
131
|
+
}
|
|
132
|
+
return present;
|
|
133
|
+
}
|
|
134
|
+
function mentionsName(code, name) {
|
|
135
|
+
const escaped = name.replace(/[.*+?^${}()|[\]\\/-]/gu, "\\$&");
|
|
136
|
+
return new RegExp(`(?:^|[^A-Za-z0-9_$-])${escaped}(?:[^A-Za-z0-9_$-]|$)`, "u").test(code);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Deterministically check which todos left a trace in the candidate. No model
|
|
140
|
+
* request, no execution. Generous on purpose: a false "addressed" only skips a
|
|
141
|
+
* refinement, while a false "unaddressed" would spend a request for nothing.
|
|
142
|
+
*/
|
|
143
|
+
export function todoCoverage(todos, targetPath, code) {
|
|
144
|
+
const present = presentNames(targetPath, code);
|
|
145
|
+
const coverage = { addressed: [], unaddressed: [], unverifiable: [] };
|
|
146
|
+
for (const todo of todos) {
|
|
147
|
+
if (todo.expects === undefined) {
|
|
148
|
+
coverage.unverifiable.push(todo.id);
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
const missing = todo.expects.names.filter((name) => !present.has(name) && !mentionsName(code, name));
|
|
152
|
+
if (missing.length === 0)
|
|
153
|
+
coverage.addressed.push(todo.id);
|
|
154
|
+
else
|
|
155
|
+
coverage.unaddressed.push(todo.id);
|
|
156
|
+
}
|
|
157
|
+
return coverage;
|
|
158
|
+
}
|
|
159
|
+
/** Render unaddressed todos for a refinement request. */
|
|
160
|
+
export function unaddressedRequirements(todos, coverage) {
|
|
161
|
+
const byId = new Map(todos.map((todo) => [todo.id, todo]));
|
|
162
|
+
return coverage.unaddressed.flatMap((id) => {
|
|
163
|
+
const todo = byId.get(id);
|
|
164
|
+
if (todo === undefined)
|
|
165
|
+
return [];
|
|
166
|
+
const names = todo.expects === undefined ? "" : ` (expected ${todo.expects.kind}: ${todo.expects.names.join(", ")})`;
|
|
167
|
+
return [`${todo.id}: ${todo.requirement}${names}`];
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
/** Render a todo list into the block the coding prompt receives. */
|
|
171
|
+
export function renderTodoList(todos) {
|
|
172
|
+
return todos.map((todo) => {
|
|
173
|
+
const names = todo.expects === undefined
|
|
174
|
+
? ""
|
|
175
|
+
: ` [must produce ${todo.expects.kind}: ${todo.expects.names.join(", ")}]`;
|
|
176
|
+
return `${todo.id}. ${todo.requirement}${names}`;
|
|
177
|
+
}).join("\n");
|
|
178
|
+
}
|
|
179
|
+
/** Countable artifacts a refinement is not allowed to lose. */
|
|
180
|
+
function ratchetSet(targetPath, code) {
|
|
181
|
+
const extension = extname(targetPath).toLowerCase();
|
|
182
|
+
const values = new Set();
|
|
183
|
+
if (HTML_EXTENSIONS.has(extension)) {
|
|
184
|
+
const facts = htmlFacts(code);
|
|
185
|
+
for (const value of facts.ids)
|
|
186
|
+
values.add(`id:${value}`);
|
|
187
|
+
for (const value of facts.classes)
|
|
188
|
+
values.add(`class:${value}`);
|
|
189
|
+
}
|
|
190
|
+
else if (extension === ".css") {
|
|
191
|
+
const facts = cssFacts(code);
|
|
192
|
+
for (const value of facts.selectors)
|
|
193
|
+
values.add(`selector:${value.trim()}`);
|
|
194
|
+
for (const value of facts.customProperties)
|
|
195
|
+
values.add(`var:${value}`);
|
|
196
|
+
}
|
|
197
|
+
else if (SCRIPT_EXTENSIONS.has(extension)) {
|
|
198
|
+
const facts = javaScriptFacts(code);
|
|
199
|
+
for (const value of facts.selectors)
|
|
200
|
+
values.add(`selector:${value}`);
|
|
201
|
+
for (const value of facts.modules)
|
|
202
|
+
values.add(`module:${value}`);
|
|
203
|
+
}
|
|
204
|
+
for (const entry of extractStaticFileMemory(targetPath, code)) {
|
|
205
|
+
values.add(`declaration:${entry.code.trim()}`);
|
|
206
|
+
}
|
|
207
|
+
values.delete("");
|
|
208
|
+
return values;
|
|
209
|
+
}
|
|
210
|
+
/** Compare two passes over the same target. Empty `lost` plus an acceptable ratio means the refinement kept everything. */
|
|
211
|
+
export function contractRegression(targetPath, previous, next) {
|
|
212
|
+
const before = ratchetSet(targetPath, previous);
|
|
213
|
+
const after = ratchetSet(targetPath, next);
|
|
214
|
+
const lost = [...before].filter((value) => !after.has(value));
|
|
215
|
+
const previousLength = previous.trim().length;
|
|
216
|
+
const shrinkRatio = previousLength === 0 ? 1 : next.trim().length / previousLength;
|
|
217
|
+
return { lost, shrinkRatio };
|
|
218
|
+
}
|
|
219
|
+
/** The ratchet: a refinement is only accepted when it is a strict improvement in coverage terms. */
|
|
220
|
+
export function acceptsRefinement(regression) {
|
|
221
|
+
return regression.lost.length === 0 && regression.shrinkRatio >= MIN_REFINEMENT_LENGTH_RATIO;
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=unit-todos.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unit-todos.js","sourceRoot":"","sources":["../../../src/agents/direct/unit-todos.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AACxE,OAAO,EAAE,0BAA0B,EAAgC,MAAM,wBAAwB,CAAC;AAClG,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AA0B9E,MAAM,SAAS,GAAG,EAAE,CAAC;AACrB,MAAM,kBAAkB,GAAG,CAAC,CAAC;AAC7B,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAClC,MAAM,UAAU,GAAG,gBAAgB,CAAC;AACpC,MAAM,YAAY,GAAG,wCAAwC,CAAC;AAC9D,mFAAmF;AACnF,MAAM,CAAC,MAAM,2BAA2B,GAAG,GAAG,CAAC;AAE/C,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;AACnD,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAElG,SAAS,OAAO,CAAC,KAAa,EAAE,KAAa;IAC3C,MAAM,KAAK,GAAG,KAAK;SAChB,OAAO,CAAC,sCAAsC,EAAE,GAAG,CAAC;SACpD,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC;SACrB,IAAI,EAAE,CAAC;IACV,OAAO,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;AACtF,CAAC;AAED,SAAS,OAAO,CAAC,KAA8B,EAAE,QAA2B;IAC1E,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;IACzC,MAAM,MAAM,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;IACpC,OAAO,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AAChG,CAAC;AAED,SAAS,MAAM,CAAC,KAAc;IAC5B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAc,EAAE,YAAkC;IAClF,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAClD,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;QACjG,MAAM,IAAI,KAAK,CAAC,qCAAqC,SAAS,WAAW,CAAC,CAAC;IAC7E,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,KAAK,GAAe,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;QAC1D,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,SAAS,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;YACpH,MAAM,IAAI,KAAK,CAAC,QAAQ,KAAK,iCAAiC,CAAC,CAAC;QAClE,CAAC;QACD,IAAI,OAAO,KAAK,CAAC,EAAE,KAAK,QAAQ,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;YAC/D,MAAM,IAAI,KAAK,CAAC,QAAQ,KAAK,qBAAqB,CAAC,CAAC;QACtD,CAAC;QACD,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;QACjF,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACnB,IAAI,OAAO,KAAK,CAAC,WAAW,KAAK,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,QAAQ,KAAK,8BAA8B,CAAC,CAAC;QACxG,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,qBAAqB,CAAC,CAAC;QACtE,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,QAAQ,KAAK,4BAA4B,CAAC,CAAC;QAEzF,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,WAAW,EAAE,CAAC;QACtE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;YACzE,MAAM,IAAI,KAAK,CAAC,QAAQ,KAAK,iCAAiC,CAAC,CAAC;QAClE,CAAC;QACD,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC;QACtC,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,0BAA0B,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3E,MAAM,IAAI,KAAK,CAAC,QAAQ,KAAK,2BAA2B,CAAC,CAAC;QAC5D,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,kBAAkB,EAAE,CAAC;YACrF,MAAM,IAAI,KAAK,CAAC,QAAQ,KAAK,kBAAkB,kBAAkB,SAAS,CAAC,CAAC;QAC9E,CAAC;QACD,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CACpD,OAAO,IAAI,KAAK,QAAQ,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,KAAK,SAAS,IAAI,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjH,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,WAAW,EAAE,CAAC;QAC/D,OAAO,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC;IACxF,CAAC,CAAC,CAAC;IACH,OAAO,EAAE,KAAK,EAAE,CAAC;AACnB,CAAC;AAED,yEAAyE;AACzE,SAAS,YAAY,CAAC,UAAkB,EAAE,IAAY;IACpD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,CAAC;IACpD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,MAAM,GAAG,GAAG,CAAC,MAAwB,EAAQ,EAAE;QAC7C,KAAK,MAAM,KAAK,IAAI,MAAM;YAAE,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;gBAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACvE,CAAC,CAAC;IACF,IAAI,eAAe,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;QACnC,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAC9B,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACnB,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACf,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QACxB,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACtB,CAAC;SAAM,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC7B,GAAG,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;QAC5B,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACxD,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;YACvC,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,sBAAsB,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACrF,CAAC;IACH,CAAC;SAAM,IAAI,iBAAiB,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;QAC5C,MAAM,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;QACpC,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QAC1B,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACrB,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;YACvC,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,sBAAsB,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACrF,CAAC;IACH,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,uBAAuB,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC;QAC9D,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,4BAA4B,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,YAAY,CAAC,IAAY,EAAE,IAAY;IAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,wBAAwB,EAAE,MAAM,CAAC,CAAC;IAC/D,OAAO,IAAI,MAAM,CAAC,wBAAwB,OAAO,uBAAuB,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC5F,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAC1B,KAA0B,EAC1B,UAAkB,EAClB,IAAY;IAEZ,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAiB,EAAE,SAAS,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC;IACpF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAC/B,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACpC,SAAS;QACX,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QACrG,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;;YACtD,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,uBAAuB,CACrC,KAA0B,EAC1B,QAAsB;IAEtB,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IAC3D,OAAO,QAAQ,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE;QACzC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC1B,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,cAAc,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;QACrH,OAAO,CAAC,GAAG,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,WAAW,GAAG,KAAK,EAAE,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;AACL,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,cAAc,CAAC,KAA0B;IACvD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACxB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,KAAK,SAAS;YACtC,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,kBAAkB,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;QAC7E,OAAO,GAAG,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,WAAW,GAAG,KAAK,EAAE,CAAC;IACnD,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,+DAA+D;AAC/D,SAAS,UAAU,CAAC,UAAkB,EAAE,IAAY;IAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,CAAC;IACpD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;IACjC,IAAI,eAAe,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;QACnC,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAC9B,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,GAAG;YAAE,MAAM,CAAC,GAAG,CAAC,MAAM,KAAK,EAAE,CAAC,CAAC;QACzD,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,OAAO;YAAE,MAAM,CAAC,GAAG,CAAC,SAAS,KAAK,EAAE,CAAC,CAAC;IAClE,CAAC;SAAM,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC7B,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,SAAS;YAAE,MAAM,CAAC,GAAG,CAAC,YAAY,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC5E,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,gBAAgB;YAAE,MAAM,CAAC,GAAG,CAAC,OAAO,KAAK,EAAE,CAAC,CAAC;IACzE,CAAC;SAAM,IAAI,iBAAiB,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;QAC5C,MAAM,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;QACpC,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,SAAS;YAAE,MAAM,CAAC,GAAG,CAAC,YAAY,KAAK,EAAE,CAAC,CAAC;QACrE,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,OAAO;YAAE,MAAM,CAAC,GAAG,CAAC,UAAU,KAAK,EAAE,CAAC,CAAC;IACnE,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,uBAAuB,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC;QAC9D,MAAM,CAAC,GAAG,CAAC,eAAe,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACjD,CAAC;IACD,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAClB,OAAO,MAAM,CAAC;AAChB,CAAC;AASD,2HAA2H;AAC3H,MAAM,UAAU,kBAAkB,CAChC,UAAkB,EAClB,QAAgB,EAChB,IAAY;IAEZ,MAAM,MAAM,GAAG,UAAU,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG,UAAU,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IAC3C,MAAM,IAAI,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;IAC9D,MAAM,cAAc,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC;IAC9C,MAAM,WAAW,GAAG,cAAc,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,cAAc,CAAC;IACnF,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;AAC/B,CAAC;AAED,oGAAoG;AACpG,MAAM,UAAU,iBAAiB,CAAC,UAA8B;IAC9D,OAAO,UAAU,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,UAAU,CAAC,WAAW,IAAI,2BAA2B,CAAC;AAC/F,CAAC"}
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,sGAAsG;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,sGAAsG;AA2jCtG,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAiFzD"}
|
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/** Production CLI: analyze -> reviewed contract -> grounded patch -> validation -> explicit apply. */
|
|
3
3
|
import { constants as fsConstants, realpathSync } from "node:fs";
|
|
4
4
|
import { copyFile, lstat, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
5
|
-
import { dirname, relative, resolve, sep } from "node:path";
|
|
5
|
+
import { dirname, extname, relative, resolve, sep } from "node:path";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
7
|
import { parseArgs } from "node:util";
|
|
8
8
|
import { analyzeProject } from "./analysis/analyzer.js";
|
|
@@ -14,7 +14,7 @@ import { PlanningError, contractPathForSource, createDraftContract, loadReviewed
|
|
|
14
14
|
import { ProviderError } from "./providers/provider.js";
|
|
15
15
|
import { createOllamaProvider, createOpenAIProvider } from "./providers/providers.js";
|
|
16
16
|
import { RunStore } from "./pipeline/run-store.js";
|
|
17
|
-
import { applyWholeFileBatch, applyUnit, buildProjectMemory, conditionalRequestAllowance, discoverDirectUnits, generateConversionUnits, generateCode, generateIntegrationAudit, generateIntegrationRepairCode, generateRepairCode, reconcileGeneratedIntegrations, renderReceipt, validateCandidateProject, validateGeneratedUnit, } from "./agents/direct/index.js";
|
|
17
|
+
import { applyWholeFileBatch, applyUnit, buildProjectMemory, collectReferenceFindings, conditionalRequestAllowance, plannedRequestCounts, discoverDirectUnits, generateBlueprint, generateConversionUnits, generateCode, generateIntegrationAudit, generateIntegrationRepairCode, generateRepairCode, generateUnitTodos, parseProjectBlueprint, parseUnitTodoList, reconcileGeneratedIntegrations, REFERENCE_EXTENSIONS, renderBlueprintFor, renderReceipt, validateCandidateProject, validateGeneratedUnit, } from "./agents/direct/index.js";
|
|
18
18
|
import { applyVerifiedRun, buildContextPreview, generateRun, resolveWorkspaceConfig, rollbackAppliedRun, validateStoredRun, } from "./agents/guided/index.js";
|
|
19
19
|
const HELP = `human-to-code — reviewed, grounded, isolated human-to-code compiler agent
|
|
20
20
|
|
|
@@ -480,7 +480,10 @@ async function buildCommand(cli, rootInput) {
|
|
|
480
480
|
provider: providerName,
|
|
481
481
|
model,
|
|
482
482
|
context: "project-memory-v1",
|
|
483
|
+
// `requests` keeps its established meaning — the planned minimum — so an
|
|
484
|
+
// existing consumer is not silently redefined. The breakdown is additive.
|
|
483
485
|
requests: units.length,
|
|
486
|
+
plannedRequests: plannedRequestCounts(units, effective.direct.planning),
|
|
484
487
|
...(conditionalRequests !== undefined ? {
|
|
485
488
|
additionalRequests: {
|
|
486
489
|
conditional: true,
|
|
@@ -505,6 +508,7 @@ async function buildCommand(cli, rootInput) {
|
|
|
505
508
|
else {
|
|
506
509
|
output(renderReceipt(units, providerName, model, languages, {
|
|
507
510
|
reconcileIntegrations: effective.direct.reconcileIntegrations,
|
|
511
|
+
planning: effective.direct.planning,
|
|
508
512
|
}), false);
|
|
509
513
|
for (const notice of discovery.notices)
|
|
510
514
|
output(` ! ${notice.message}`, false);
|
|
@@ -537,9 +541,8 @@ async function buildCommand(cli, rootInput) {
|
|
|
537
541
|
excludedPaths: effective.privacy.excludedPaths,
|
|
538
542
|
maxFileBytes: effective.privacy.maxFileBytes,
|
|
539
543
|
});
|
|
540
|
-
// Default engine: deterministic per-
|
|
541
|
-
//
|
|
542
|
-
// failing never aborts the others.
|
|
544
|
+
// Default engine: deterministic per-target generation, optionally preceded by
|
|
545
|
+
// a shared planning pass. One target failing never aborts the others.
|
|
543
546
|
const describeUnit = (unit) => unit.kind === "file"
|
|
544
547
|
? `${unit.sourcePath} → ${unit.outputPath}`
|
|
545
548
|
: `${unit.sourcePath} (inline @human, line ${unit.line ?? "?"})`;
|
|
@@ -552,6 +555,12 @@ async function buildCommand(cli, rootInput) {
|
|
|
552
555
|
const retry = event.attempt > 1 ? ` (retry ${event.attempt - 1})` : "";
|
|
553
556
|
spinner.label(`generating ${describeUnit(event.unit)}${retry}`);
|
|
554
557
|
}
|
|
558
|
+
else if (event.kind === "plan") {
|
|
559
|
+
spinner.label(`planning ${describeUnit(event.unit)}`);
|
|
560
|
+
}
|
|
561
|
+
else if (event.kind === "refine") {
|
|
562
|
+
spinner.label(`completing ${describeUnit(event.unit)} (${event.unaddressed} unaddressed item(s))`);
|
|
563
|
+
}
|
|
555
564
|
else if (event.kind === "skip") {
|
|
556
565
|
spinner.note(` ⊘ skipped ${describeUnit(event.unit)}: ${event.reason}`);
|
|
557
566
|
}
|
|
@@ -559,6 +568,68 @@ async function buildCommand(cli, rootInput) {
|
|
|
559
568
|
: undefined;
|
|
560
569
|
if (interactive)
|
|
561
570
|
output(`\nConverting ${units.length} item(s) with ${model}…`, false);
|
|
571
|
+
const planning = effective.direct.planning;
|
|
572
|
+
const requestOptions = {
|
|
573
|
+
provider: providerName,
|
|
574
|
+
model,
|
|
575
|
+
...(baseUrl ? { baseUrl } : {}),
|
|
576
|
+
...(apiKey ? { apiKey } : {}),
|
|
577
|
+
};
|
|
578
|
+
// One shared planning request, before any file is generated. Each target is
|
|
579
|
+
// generated in isolation afterwards, so this is the only chance for them to
|
|
580
|
+
// agree on names. Best-effort: a failure loses the shared contract, never the
|
|
581
|
+
// run.
|
|
582
|
+
const plannedTargets = projectMemory.plannedTargets;
|
|
583
|
+
let blueprint;
|
|
584
|
+
let blueprintRequests = 0;
|
|
585
|
+
let blueprintNotice;
|
|
586
|
+
if (planning.enabled && planning.projectBlueprint && plannedTargets.length >= 2) {
|
|
587
|
+
if (interactive)
|
|
588
|
+
spinner.label(`agreeing a shared contract across ${plannedTargets.length} file(s)`);
|
|
589
|
+
blueprintRequests = 1;
|
|
590
|
+
try {
|
|
591
|
+
const raw = await generateBlueprint({
|
|
592
|
+
targets: plannedTargets.map((target) => ({
|
|
593
|
+
path: target.path,
|
|
594
|
+
language: target.language,
|
|
595
|
+
instruction: target.purposes.join(" | "),
|
|
596
|
+
})),
|
|
597
|
+
currentTree: discovery.scannedPaths.slice(0, 72),
|
|
598
|
+
}, { ...requestOptions, language });
|
|
599
|
+
blueprint = parseProjectBlueprint(raw, new Set(plannedTargets.map((target) => target.path)));
|
|
600
|
+
projectMemory.adoptBlueprint(blueprint);
|
|
601
|
+
}
|
|
602
|
+
catch (error) {
|
|
603
|
+
blueprintNotice = `shared contract unavailable (${error instanceof Error ? error.message : String(error)});`
|
|
604
|
+
+ " files were generated without it";
|
|
605
|
+
if (interactive)
|
|
606
|
+
spinner.note(` ! ${blueprintNotice}`);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
// One todo request per unit, when its kind is enabled. Returning undefined
|
|
610
|
+
// leaves that unit on the single-pass path.
|
|
611
|
+
const planningOutcomes = [];
|
|
612
|
+
const todoEnabled = (unit) => planning.enabled && (unit.kind === "file" ? planning.fileTodo : planning.markerTodo);
|
|
613
|
+
const planningEnabledFor = planning.enabled && (planning.fileTodo || planning.markerTodo)
|
|
614
|
+
? async (unit, context) => {
|
|
615
|
+
if (!todoEnabled(unit))
|
|
616
|
+
return undefined;
|
|
617
|
+
const target = unit.kind === "file" ? unit.outputPath : unit.sourcePath;
|
|
618
|
+
const raw = await generateUnitTodos({
|
|
619
|
+
targetPath: target,
|
|
620
|
+
instruction: unit.prompt,
|
|
621
|
+
inline: unit.kind === "inline",
|
|
622
|
+
...(blueprint ? { blueprint: renderBlueprintFor(blueprint, target) } : {}),
|
|
623
|
+
...(context.projectMemory ? { projectMemory: context.projectMemory } : {}),
|
|
624
|
+
}, { ...requestOptions, language: unit.language ?? language, targetPath: target });
|
|
625
|
+
// Deliberately unconstrained by the shared vocabulary: a todo may also
|
|
626
|
+
// expect target-local artifacts the blueprint has no reason to name
|
|
627
|
+
// (a @media block, a local helper). Injection safety comes from the
|
|
628
|
+
// name charset in the parser, and cross-file drift is caught
|
|
629
|
+
// deterministically by reference checking, not by dropping coverage.
|
|
630
|
+
return parseUnitTodoList(raw);
|
|
631
|
+
}
|
|
632
|
+
: undefined;
|
|
562
633
|
let generated;
|
|
563
634
|
try {
|
|
564
635
|
generated = await generateConversionUnits(units, (unit, context) => {
|
|
@@ -567,11 +638,8 @@ async function buildCommand(cli, rootInput) {
|
|
|
567
638
|
}
|
|
568
639
|
return generateCode(unit.prompt, {
|
|
569
640
|
language: unit.language ?? language,
|
|
570
|
-
|
|
571
|
-
model,
|
|
641
|
+
...requestOptions,
|
|
572
642
|
targetPath: unit.kind === "file" ? unit.outputPath : unit.sourcePath,
|
|
573
|
-
...(baseUrl ? { baseUrl } : {}),
|
|
574
|
-
...(apiKey ? { apiKey } : {}),
|
|
575
643
|
...context,
|
|
576
644
|
});
|
|
577
645
|
}, {
|
|
@@ -579,6 +647,9 @@ async function buildCommand(cli, rootInput) {
|
|
|
579
647
|
validate: validateGeneratedUnit,
|
|
580
648
|
projectMemory,
|
|
581
649
|
contextCharBudget,
|
|
650
|
+
maxCodingPasses: planning.enabled ? planning.maxCodingPassesPerUnit : 1,
|
|
651
|
+
...(planningEnabledFor !== undefined ? { plan: planningEnabledFor } : {}),
|
|
652
|
+
onPlanningOutcome: (outcome) => planningOutcomes.push(outcome),
|
|
582
653
|
...(onProgress ? { onProgress } : {}),
|
|
583
654
|
});
|
|
584
655
|
}
|
|
@@ -592,6 +663,44 @@ async function buildCommand(cli, rootInput) {
|
|
|
592
663
|
}
|
|
593
664
|
// Optional and off by default. ProjectMemory supplies language-aware
|
|
594
665
|
// relationships; this orchestrator remains cross-language and performs a
|
|
666
|
+
// Deterministic cross-file reference checking. No model request: the same
|
|
667
|
+
// static extractors ProjectMemory uses are cross-referenced across the
|
|
668
|
+
// candidate web files. This is reference checking, not verification.
|
|
669
|
+
let referenceFindings = [];
|
|
670
|
+
if (effective.direct.crossFileChecks) {
|
|
671
|
+
if (interactive)
|
|
672
|
+
spinner.label("cross-checking generated references");
|
|
673
|
+
const referenceFiles = [];
|
|
674
|
+
const seenReferencePaths = new Set();
|
|
675
|
+
for (const item of generated) {
|
|
676
|
+
if (item.error !== undefined || item.code.trim().length === 0)
|
|
677
|
+
continue;
|
|
678
|
+
const target = item.unit.kind === "file" ? item.unit.outputPath : item.unit.sourcePath;
|
|
679
|
+
if (!REFERENCE_EXTENSIONS.has(extname(target).toLowerCase()) || seenReferencePaths.has(target))
|
|
680
|
+
continue;
|
|
681
|
+
seenReferencePaths.add(target);
|
|
682
|
+
referenceFiles.push({ path: target, content: item.code, generated: true });
|
|
683
|
+
}
|
|
684
|
+
// Untouched project files provide the other half of every cross-reference.
|
|
685
|
+
for (const path of discovery.scannedPaths) {
|
|
686
|
+
if (seenReferencePaths.has(path) || !REFERENCE_EXTENSIONS.has(extname(path).toLowerCase()))
|
|
687
|
+
continue;
|
|
688
|
+
try {
|
|
689
|
+
const content = await readFile(resolve(root, path), "utf8");
|
|
690
|
+
seenReferencePaths.add(path);
|
|
691
|
+
referenceFiles.push({ path, content, generated: false });
|
|
692
|
+
}
|
|
693
|
+
catch {
|
|
694
|
+
continue;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
referenceFindings = collectReferenceFindings(referenceFiles);
|
|
698
|
+
if (interactive) {
|
|
699
|
+
for (const finding of referenceFindings) {
|
|
700
|
+
spinner.note(` ${finding.severity === "blocking" ? "✖" : "!"} ${finding.code}: ${finding.detail}`);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
}
|
|
595
704
|
// bounded audit -> target repair -> verification cycle over generated groups.
|
|
596
705
|
let integrationAuditRequests = 0;
|
|
597
706
|
let integrationRepairRequests = 0;
|
|
@@ -788,12 +897,33 @@ async function buildCommand(cli, rootInput) {
|
|
|
788
897
|
}
|
|
789
898
|
}
|
|
790
899
|
const seconds = Math.round((Date.now() - started) / 1000);
|
|
900
|
+
const todoRequests = planningOutcomes.reduce((total, outcome) => total + outcome.todoRequests, 0);
|
|
901
|
+
const codingRequests = planningOutcomes.reduce((total, outcome) => total + outcome.codingRequests, 0);
|
|
902
|
+
const refinementsRejected = planningOutcomes.filter((outcome) => outcome.refinementRejected !== undefined);
|
|
791
903
|
if (cli.json) {
|
|
792
904
|
output({
|
|
793
905
|
status: written.length === 0 && skipped.length > 0 ? "FAILED" : "DONE",
|
|
794
906
|
engine: "simple",
|
|
795
907
|
written,
|
|
796
908
|
skipped,
|
|
909
|
+
blueprintRequests,
|
|
910
|
+
...(blueprintNotice !== undefined ? { blueprintNotice } : {}),
|
|
911
|
+
todoRequests,
|
|
912
|
+
codingRequests,
|
|
913
|
+
...(refinementsRejected.length > 0 ? {
|
|
914
|
+
refinementsRejected: refinementsRejected.map((outcome) => ({
|
|
915
|
+
target: outcome.unit.kind === "file" ? outcome.unit.outputPath : outcome.unit.sourcePath,
|
|
916
|
+
reason: outcome.refinementRejected,
|
|
917
|
+
})),
|
|
918
|
+
} : {}),
|
|
919
|
+
...(effective.direct.crossFileChecks ? {
|
|
920
|
+
referenceFindings: referenceFindings.map((finding) => ({
|
|
921
|
+
code: finding.code,
|
|
922
|
+
severity: finding.severity,
|
|
923
|
+
path: finding.path,
|
|
924
|
+
detail: finding.detail,
|
|
925
|
+
})),
|
|
926
|
+
} : {}),
|
|
797
927
|
...(effective.direct.reconcileIntegrations ? {
|
|
798
928
|
integrationAuditRequests,
|
|
799
929
|
integrationRepairRequests,
|
|
@@ -808,7 +938,14 @@ async function buildCommand(cli, rootInput) {
|
|
|
808
938
|
? `, ${integrationAuditRequests} integration audit request(s), ${integrationRepairRequests} integration repair request(s)`
|
|
809
939
|
: "";
|
|
810
940
|
const repairs = repairRequests > 0 ? `, ${repairRequests} bounded repair request(s)` : "";
|
|
811
|
-
|
|
941
|
+
const planned = blueprintRequests + todoRequests > 0
|
|
942
|
+
? `, ${blueprintRequests} blueprint and ${todoRequests} todo request(s)`
|
|
943
|
+
: "";
|
|
944
|
+
output(`\nDone in ${seconds}s. ${written.length} written${skipped.length > 0 ? `, ${skipped.length} skipped` : ""}${planned}${integrations}${repairs}.`, false);
|
|
945
|
+
for (const outcome of refinementsRejected) {
|
|
946
|
+
const target = outcome.unit.kind === "file" ? outcome.unit.outputPath : outcome.unit.sourcePath;
|
|
947
|
+
output(` ! ${target}: ${outcome.refinementRejected}`, false);
|
|
948
|
+
}
|
|
812
949
|
}
|
|
813
950
|
return written.length === 0 && skipped.length > 0 ? 5 : 0;
|
|
814
951
|
}
|