sitelooper 0.3.0

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 (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +625 -0
  3. package/bin/sitelooper.js +6 -0
  4. package/dist/agent/llm.js +460 -0
  5. package/dist/agent/llm.js.map +1 -0
  6. package/dist/agent/loop.js +870 -0
  7. package/dist/agent/loop.js.map +1 -0
  8. package/dist/agent/prompt.js +40 -0
  9. package/dist/agent/prompt.js.map +1 -0
  10. package/dist/agent/report.js +545 -0
  11. package/dist/agent/report.js.map +1 -0
  12. package/dist/agent/tools.js +1147 -0
  13. package/dist/agent/tools.js.map +1 -0
  14. package/dist/cli.js +1692 -0
  15. package/dist/cli.js.map +1 -0
  16. package/dist/daemon/browser.js +218 -0
  17. package/dist/daemon/browser.js.map +1 -0
  18. package/dist/daemon/codegen.js +241 -0
  19. package/dist/daemon/codegen.js.map +1 -0
  20. package/dist/daemon/dialogs.js +57 -0
  21. package/dist/daemon/dialogs.js.map +1 -0
  22. package/dist/daemon/diff.js +198 -0
  23. package/dist/daemon/diff.js.map +1 -0
  24. package/dist/daemon/fingerprint.js +98 -0
  25. package/dist/daemon/fingerprint.js.map +1 -0
  26. package/dist/daemon/inputs.js +134 -0
  27. package/dist/daemon/inputs.js.map +1 -0
  28. package/dist/daemon/recorder.js +1232 -0
  29. package/dist/daemon/recorder.js.map +1 -0
  30. package/dist/daemon/refs.js +194 -0
  31. package/dist/daemon/refs.js.map +1 -0
  32. package/dist/daemon/server.js +1724 -0
  33. package/dist/daemon/server.js.map +1 -0
  34. package/dist/daemon/state.js +239 -0
  35. package/dist/daemon/state.js.map +1 -0
  36. package/dist/doctor.js +90 -0
  37. package/dist/doctor.js.map +1 -0
  38. package/dist/shared/paths.js +80 -0
  39. package/dist/shared/paths.js.map +1 -0
  40. package/dist/shared/protocol.js +28 -0
  41. package/dist/shared/protocol.js.map +1 -0
  42. package/dist/shared/secrets.js +92 -0
  43. package/dist/shared/secrets.js.map +1 -0
  44. package/dist/shared/text.js +39 -0
  45. package/dist/shared/text.js.map +1 -0
  46. package/dist/skills/compile.js +1420 -0
  47. package/dist/skills/compile.js.map +1 -0
  48. package/dist/skills/components.js +456 -0
  49. package/dist/skills/components.js.map +1 -0
  50. package/dist/skills/flow.js +1041 -0
  51. package/dist/skills/flow.js.map +1 -0
  52. package/dist/skills/learn.js +406 -0
  53. package/dist/skills/learn.js.map +1 -0
  54. package/dist/skills/ledger.js +304 -0
  55. package/dist/skills/ledger.js.map +1 -0
  56. package/dist/skills/relabel.js +206 -0
  57. package/dist/skills/relabel.js.map +1 -0
  58. package/dist/skills/repair.js +570 -0
  59. package/dist/skills/repair.js.map +1 -0
  60. package/dist/skills/replay.js +1281 -0
  61. package/dist/skills/replay.js.map +1 -0
  62. package/dist/skills/store.js +147 -0
  63. package/dist/skills/store.js.map +1 -0
  64. package/dist/spec/check.js +428 -0
  65. package/dist/spec/check.js.map +1 -0
  66. package/dist/spec/diagnostics.js +58 -0
  67. package/dist/spec/diagnostics.js.map +1 -0
  68. package/dist/spec/emit.js +2084 -0
  69. package/dist/spec/emit.js.map +1 -0
  70. package/dist/spec/index.js +62 -0
  71. package/dist/spec/index.js.map +1 -0
  72. package/dist/spec/ir.js +216 -0
  73. package/dist/spec/ir.js.map +1 -0
  74. package/dist/spec/lift.js +162 -0
  75. package/dist/spec/lift.js.map +1 -0
  76. package/dist/spec/locators.js +270 -0
  77. package/dist/spec/locators.js.map +1 -0
  78. package/dist/spec/lower.js +124 -0
  79. package/dist/spec/lower.js.map +1 -0
  80. package/dist/spec/repair.js +657 -0
  81. package/dist/spec/repair.js.map +1 -0
  82. package/dist/spec/rerecord.js +169 -0
  83. package/dist/spec/rerecord.js.map +1 -0
  84. package/dist/spec/rethread.js +120 -0
  85. package/dist/spec/rethread.js.map +1 -0
  86. package/package.json +50 -0
  87. package/skills/sitelooper/SKILL.md +228 -0
@@ -0,0 +1,304 @@
1
+ /**
2
+ * The RunLedger: one registry for everything a RUN made, as opposed to what
3
+ * the app provides.
4
+ *
5
+ * Seven defects in six cloud takes were the same bug wearing different
6
+ * clothes — a value or a procedure from the recording run surviving into a
7
+ * replay: a read pinned to row 1 publishing a seed record's ref; a runid
8
+ * baked into a locator's hasText; a dashboard uid embedded 62 times in skill
9
+ * templates; a three-character record id below a minting floor. Each was
10
+ * fixed where it was found, and the next take produced a fresh instance,
11
+ * because the rule they all violate had no home: recognition was
12
+ * re-implemented per call site (three copies of the same length gate), and
13
+ * relied on text matching against whatever the current instruction happened
14
+ * to mention.
15
+ *
16
+ * This is that home. A value enters ONCE, with a Binding saying how a later
17
+ * run re-derives its own, and every producer asks the ledger rather than
18
+ * guessing. See PLAN-provenance.md.
19
+ */
20
+ /**
21
+ * Identifier-like: specific enough to be a REFERENCE rather than a word the
22
+ * app happens to use. A route word ("tickets", "dashboards") is a common
23
+ * lowercase noun; a minted id carries a digit, a separator, or the length of
24
+ * a generated uid.
25
+ *
26
+ * This is the ONE copy. It previously existed three times with two different
27
+ * length floors, which is why repair-desk's "t15" was banked by one caller
28
+ * and left literal by another.
29
+ */
30
+ /**
31
+ * A url part that is an identifier by POSITION, whatever its characters.
32
+ *
33
+ * identifierLike reads the value's shape, and a shape gate has a floor: odoo's
34
+ * database ids are short integers (`#id=44`), invisible to it — and through
35
+ * it, to the ledger, the leak guards, flow minting and compile slotting all at
36
+ * once. fwod27 is the bill: the recording's contact id 44 rode into a flow
37
+ * instruction as prose ("res.partner id 44"), no guard saw it, and both
38
+ * replays navigated to the recording's deleted record and halted at step 2.
39
+ *
40
+ * The url's own vocabulary settles what a shape cannot: a query/hash param
41
+ * NAMED id holds a record id. Only all-digit values qualify — a param named
42
+ * `id` carrying a word is some app's routing, not a record number.
43
+ *
44
+ * Exactly `id`, not `.*_id`. The wider match was speculation beyond the
45
+ * evidence (fwod27's leak was `#id=44`), and fwod29 showed what it costs:
46
+ * odoo's `menu_id=181` — a routing constant every run shares — banked as a
47
+ * run-made record id and flunked verify-artifacts' navigation check on a
48
+ * clean 8/8 sweep. An app calls its record pointer `id`; a `<thing>_id`
49
+ * param in a url is that thing's ADDRESS in the app's chrome.
50
+ */
51
+ export function idPositionPart(part) {
52
+ return part.label === 'q.id' && /^\d{1,10}$/.test(part.value);
53
+ }
54
+ export function identifierLike(value) {
55
+ if (value.length < MIN_ID_LEN)
56
+ return false;
57
+ // No minted id contains whitespace. Without this the `length >= 12` clause
58
+ // — which exists for digitless uids like "afwfbbc2of6rkf" — swallows
59
+ // ordinary prose: fwrd23l reported the app's validation heading "Ticket is
60
+ // not ready" as a value, it was banked as an identifier, and the export gate
61
+ // then refused a clean 37-minute run because a text locator legitimately
62
+ // matched the app's own error message.
63
+ if (/\s/.test(value))
64
+ return false;
65
+ // A hyphenated pair of words is a SLUG, not a minted id: grafana's
66
+ // "bench-service-health", atelyr's "project-manager". Those are route
67
+ // segments every run shares, and banking them made the export gate refuse a
68
+ // whole recording. A separator only makes a reference when a digit comes
69
+ // with it ("RD-1015", "fwrd24l-n1"); a digitless opaque token still
70
+ // qualifies on length alone, which is what grafana's "cfwcsdxqdjabkf" needs.
71
+ if (/[-_]/.test(value))
72
+ return /\d/.test(value);
73
+ return /\d/.test(value) || value.length >= 12;
74
+ }
75
+ /** Three, not four: repair-desk's record ids are "t15". */
76
+ const MIN_ID_LEN = 3;
77
+ const MAX_VALUE_LEN = 200;
78
+ /**
79
+ * A binding's stable identity, so a compiled param can name the ORIGIN of its
80
+ * value ("var:runid", "url:01-open:p1") and a later run resolve its own from
81
+ * the same origin. This is what lets a value cross an instruction boundary: a
82
+ * skill whose template never mentions the runid can still bind it, because the
83
+ * param points at where the value comes from rather than at a word to match.
84
+ */
85
+ export function bindingKey(b) {
86
+ switch (b.from) {
87
+ case 'var':
88
+ return `var:${b.name}`;
89
+ case 'input':
90
+ return 'input';
91
+ case 'url':
92
+ return `url:${b.step}:${b.label}`;
93
+ case 'output':
94
+ return `output:${b.step}:${b.name}${b.path ? `#${b.path}` : ''}`;
95
+ }
96
+ }
97
+ export class RunLedger {
98
+ entries = [];
99
+ /** Values already banked, so first appearance wins. */
100
+ seen = new Set();
101
+ instruction = 0;
102
+ step = 0;
103
+ /** Advance the cursor used to stamp `firstSeen`. */
104
+ beginInstruction(index) {
105
+ this.instruction = index;
106
+ this.step = 0;
107
+ }
108
+ beginStep(index) {
109
+ this.step = index;
110
+ }
111
+ /**
112
+ * Bank a value with its provenance. Returns the entry, or null when the
113
+ * value is unusable (too short, too long, already known). First appearance
114
+ * wins: the step that MINTED a value owns it, so later steps reference it
115
+ * rather than re-minting a duplicate.
116
+ */
117
+ add(value, binding, opts = {}) {
118
+ const v = String(value ?? '').trim();
119
+ // The length floor guards against banking junk from shape-guessing
120
+ // callers. A VOUCHED value has positional evidence instead (a `q.id` url
121
+ // part — see idPositionPart), and odoo's two-digit record ids are exactly
122
+ // what the floor was silently discarding: fwod27's contact id 44 never
123
+ // banked, so no guard downstream could see it leak.
124
+ if ((v.length < MIN_ID_LEN && !opts.vouched) || !v.length || v.length > MAX_VALUE_LEN || this.seen.has(v))
125
+ return null;
126
+ const entry = {
127
+ value: v,
128
+ binding,
129
+ kind: opts.kind ?? (identifierLike(v) ? 'identifier' : 'text'),
130
+ known: opts.known ?? binding.from === 'var',
131
+ firstSeen: { instruction: this.instruction, step: this.step },
132
+ };
133
+ this.seen.add(v);
134
+ this.entries.push(entry);
135
+ return entry;
136
+ }
137
+ /** Bank the identifier-like parts of a url the run just landed on. */
138
+ addUrlIds(url, step, parts) {
139
+ const out = [];
140
+ for (const part of parts) {
141
+ if (!identifierLike(part.value) && !idPositionPart(part))
142
+ continue;
143
+ // A pure-digit QUERY param the app does not call `id` is routing
144
+ // vocabulary, not a record: fwod29 banked odoo's `action=315` and
145
+ // `action=126` (window-action numbers, identical on every run) and the
146
+ // navigation check flagged 16 "leaks" on a clean sweep. A digit run in
147
+ // a PATH position (`/tickets/315`) still banks — there the position is
148
+ // the app saying "this is the record".
149
+ if (/^\d+$/.test(part.value) && part.label.startsWith('q.') && !idPositionPart(part))
150
+ continue;
151
+ const entry = this.add(part.value, { from: 'url', step, label: part.label }, { kind: 'identifier', known: true, vouched: idPositionPart(part) });
152
+ if (entry)
153
+ out.push(entry);
154
+ }
155
+ return out;
156
+ }
157
+ /** Every entry, oldest first. */
158
+ all() {
159
+ return [...this.entries];
160
+ }
161
+ has(value) {
162
+ return this.seen.has(String(value ?? '').trim());
163
+ }
164
+ /**
165
+ * THE predicate. Every producer that needs to know "does this string carry
166
+ * something this run made?" asks here — compile's slot discovery, the flow
167
+ * exporter's referencizing, the recorder's identity hints, the scanner.
168
+ *
169
+ * Longest first, so a value nested inside a longer one (a runid inside a
170
+ * part name) does not shadow the more specific match.
171
+ */
172
+ runValuesIn(text) {
173
+ const s = String(text ?? '');
174
+ if (!s)
175
+ return [];
176
+ return this.entries.filter((e) => occursAsToken(s, e.value)).sort((a, b) => b.value.length - a.value.length);
177
+ }
178
+ /** The values themselves, for callers that only need strings (identity hints). */
179
+ values(opts = {}) {
180
+ return this.entries.filter((e) => (opts.known === undefined ? true : e.known === opts.known)).map((e) => e.value);
181
+ }
182
+ }
183
+ /**
184
+ * Whole-token occurrence. Underscores bind — `o_form_view_group` is ONE
185
+ * identifier, so a value "form" must not match its middle (fwod5 shipped
186
+ * exactly that corruption) — while hyphens do not, since a runid prefix in
187
+ * "x7-bench-dashboard" is a reference worth threading.
188
+ */
189
+ export function occursAsToken(text, value) {
190
+ if (!value)
191
+ return false;
192
+ return new RegExp(`(?<![A-Za-z0-9_])${escapeRe(value)}(?![A-Za-z0-9_])`).test(text);
193
+ }
194
+ export function escapeRe(s) {
195
+ return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
196
+ }
197
+ /**
198
+ * Fields whose CONTRACT is to hold the recording run's value: a param's
199
+ * example, the provenance of the recording, a flow step's record of what it
200
+ * observed. They are documentation, never replayed, and exempting them is
201
+ * what keeps the scanner's output all signal.
202
+ *
203
+ * Deliberately NOT exempt, though both hold recorded text: `reportTemplate`
204
+ * (a tier-A replay synthesises its report from it, so an unslotted value is
205
+ * published as this run's answer) and `expect.urlPattern` (a replay checks
206
+ * the live url against it).
207
+ */
208
+ const EXEMPT = [/(^|\.)provenance(\.|$)/, /(^|\.)params\.[^.]+\.example$/, /(^|\.)derived\.[^.]+\.example$/, /(^|\.)recorded(\.|$)/, /(^|\.)stats(\.|$)/];
209
+ function exempt(path) {
210
+ return EXEMPT.some((re) => re.test(path));
211
+ }
212
+ /**
213
+ * Walk anything JSON-shaped and report every run value that survived
214
+ * unslotted. This is an INSTRUMENT before it is a guard: what it actually
215
+ * measures is ledger coverage, since a converter given a complete slot set is
216
+ * a total function. Every one of the seven known defects was a recognition
217
+ * gap, not a conversion error, and each cost a two-hour sweep plus a reading
218
+ * of the drift files to find. This finds them in milliseconds.
219
+ *
220
+ * It can only report values it knows about, so it can never prove absence —
221
+ * only ever "here are more".
222
+ */
223
+ export function scanForLeaks(artifact, ledger, where = '') {
224
+ const out = [];
225
+ const walk = (node, path) => {
226
+ if (exempt(path))
227
+ return;
228
+ if (typeof node === 'string') {
229
+ for (const entry of ledger.runValuesIn(node)) {
230
+ out.push({ where: path, value: entry.value, binding: entry.binding, kind: entry.kind, context: node.slice(0, 160) });
231
+ }
232
+ return;
233
+ }
234
+ if (Array.isArray(node)) {
235
+ node.forEach((v, i) => walk(v, `${path}[${i}]`));
236
+ return;
237
+ }
238
+ if (node && typeof node === 'object') {
239
+ for (const [k, v] of Object.entries(node))
240
+ walk(v, path ? `${path}.${k}` : k);
241
+ }
242
+ };
243
+ walk(artifact, where);
244
+ return out;
245
+ }
246
+ /** One line per leak, for a warning or a thrown error. */
247
+ export function describeLeaks(leaks) {
248
+ return leaks
249
+ .map((l) => ` ${l.where}: ${JSON.stringify(l.value)} (${l.binding.from}) in ${JSON.stringify(l.context)}`)
250
+ .join('\n');
251
+ }
252
+ /**
253
+ * Which leaks are fatal.
254
+ *
255
+ * A leak in a LOCATOR or a precondition acts on the wrong record silently:
256
+ * the step resolves, the run continues, and nothing in the output says the
257
+ * procedure moved. That is the failure this whole plan exists to stop, and it
258
+ * is worth refusing an export over.
259
+ *
260
+ * Everywhere else the leak announces itself. A stale `expect.urlPattern`
261
+ * fails its assertion loudly; a stale `reportTemplate` is caught at replay by
262
+ * synthesizeReport, which refuses to publish a value this run did not
263
+ * observe. Those stay warnings — blocking an export on a defect that is
264
+ * already contained would only teach people to pass a --force flag.
265
+ */
266
+ export function fatal(leak) {
267
+ // Only an IDENTIFIER. A run also reports text it merely observed — an error
268
+ // heading, a status word — and a locator matching the app's own copy is
269
+ // doing its job. Refusing an export over one of those trains people to
270
+ // force past the gate, which costs more than the leak it caught.
271
+ if (leak.kind !== 'identifier')
272
+ return false;
273
+ // ...and only in a LOCATOR, which is the silent case: the step resolves,
274
+ // the run continues, and nothing says the procedure moved record.
275
+ //
276
+ // A precondition is loud. A stale urlPattern or requireText makes the skill
277
+ // REFUSE — softUrlMatch may generalise it, requireText gates identity, and
278
+ // either way the step falls to recovery and says so. Grafana's dashboards
279
+ // put a minted uid in almost every precondition, so treating those as fatal
280
+ // refused whole recordings for a defect that announces itself.
281
+ //
282
+ // A NAVIGATION TARGET was fatal here for one release cycle and is not any
283
+ // more. The reasoning was sound -- fwgr11 went to
284
+ // `/d/<run-1-uid>/{{runid}}-bench-dashboard` and a url is a locator for a
285
+ // page -- but deciding it needs a judgement that cannot be made from one
286
+ // run. fwod19 refused a clean 6/6 recording over
287
+ //
288
+ // args.url: "123" in "http://127.0.0.1:8069/web#action=123&cids=1&menu_id=81"
289
+ //
290
+ // where 123 is Odoo's Discuss MENU id, present in the first post-login
291
+ // navigation and identical on every run. identifierLike("123") is true, so
292
+ // the ledger banked a permanent app constant as a record this run made, and
293
+ // the whole export died. No record-time discriminator survives contact with
294
+ // it: the navigation that reveals 123 is a click, and the step before it is
295
+ // the login fill, so neither "before the first mutation" nor "before the
296
+ // run typed anything" separates it from a real minted uid.
297
+ //
298
+ // So the rule moved to bench/verify-artifacts.mjs, where a false positive
299
+ // costs a look instead of a run. A gate may only enforce what a single run
300
+ // can actually establish; see PLAN-evidence-over-shape.md, which makes the
301
+ // deferred version -- run 1 proposes, run 2 decides -- stage 1.
302
+ return /(^|\.)locators(\.|\[)/.test(leak.where);
303
+ }
304
+ //# sourceMappingURL=ledger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ledger.js","sourceRoot":"","sources":["../../src/skills/ledger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,206 @@
1
+ export function relabelCases(entries) {
2
+ const out = [];
3
+ let index = 0;
4
+ let instruction = '';
5
+ for (const e of entries) {
6
+ if (e.k === 'instruction') {
7
+ index++;
8
+ instruction = e.text ?? '';
9
+ }
10
+ else if (e.k === 'report' && e.status === 'success' && Object.keys(e.values ?? {}).length) {
11
+ out.push({ index, instruction, values: { ...e.values }, ...(e.skill ? { skill: e.skill } : {}) });
12
+ }
13
+ }
14
+ return out;
15
+ }
16
+ const RENAME_TOOL = {
17
+ name: 'rename_values',
18
+ description: 'Submit the value renames for this session. Rename ONLY names that mislead or say nothing ' +
19
+ '(selector fragments like h1, role_radiogroup_aria_che, generic value/value_2, or a name that ' +
20
+ 'contradicts what the value is). Leave every adequate name alone — churn costs more than it buys.',
21
+ parameters: {
22
+ type: 'object',
23
+ required: ['renames'],
24
+ properties: {
25
+ renames: {
26
+ type: 'array',
27
+ items: {
28
+ type: 'object',
29
+ required: ['i', 'from', 'to'],
30
+ properties: {
31
+ i: { type: 'number', description: 'The instruction number the value belongs to.' },
32
+ from: { type: 'string', description: 'The current name, exactly as listed.' },
33
+ to: {
34
+ type: 'string',
35
+ description: 'The name a person would use: order_reference, unit_price, customer_name. snake_case.',
36
+ },
37
+ },
38
+ },
39
+ },
40
+ },
41
+ },
42
+ };
43
+ function relabelMessages(cases) {
44
+ const lines = cases.map((c) => `instruction ${c.index}: ${JSON.stringify(c.instruction)}\n values: ${JSON.stringify(c.values)}`);
45
+ return [
46
+ {
47
+ role: 'system',
48
+ content: 'A browser-automation session just finished recording. Each instruction below reported values read ' +
49
+ 'off the page, keyed by name. Later runs of this procedure address these values BY NAME, so a name ' +
50
+ 'must say what the value IS to someone who cannot see the page: a value the app minted as an order ' +
51
+ 'reference must be called order_reference, not h1 (the selector it was read from) and not value_2. ' +
52
+ 'You see the whole session, so use hindsight: if a later instruction uses a value, name it the way ' +
53
+ 'that instruction speaks about it. Call rename_values exactly once with every rename worth making — ' +
54
+ 'and no others.',
55
+ },
56
+ { role: 'user', content: lines.join('\n\n') },
57
+ ];
58
+ }
59
+ // snake_case is what the prompt asks for, but models also name values in
60
+ // camelCase and those names WORK — fwrd35's reports use totalPrice, partB.
61
+ // The validator's job is mechanical safety, not style: it must not refuse
62
+ // `partB -> partBName` while partB itself stands. Letters either case.
63
+ const NAME_RE = /^[a-zA-Z][a-zA-Z0-9_]{0,31}$/;
64
+ /**
65
+ * Validate a raw rename list into a plan. Anything mechanically unsafe is
66
+ * dropped, not repaired: a rename of a name that does not exist, to a name
67
+ * already taken in the same report, or to something that is not a
68
+ * snake_case word. Returns the plan and what was dropped (for the log).
69
+ */
70
+ export function validateRelabelPlan(raw, cases) {
71
+ const plan = new Map();
72
+ const dropped = [];
73
+ const byIndex = new Map(cases.map((c) => [c.index, c]));
74
+ const list = Array.isArray(raw?.renames) ? raw.renames : [];
75
+ for (const r of list) {
76
+ const { i, from, to } = (r ?? {});
77
+ const c = typeof i === 'number' ? byIndex.get(i) : undefined;
78
+ const oldName = typeof from === 'string' ? from : '';
79
+ const newName = typeof to === 'string' ? to.trim() : '';
80
+ const have = c
81
+ ? new Set([...Object.keys(c.values), ...Object.values(plan.get(c.index) ?? {})])
82
+ : new Set();
83
+ if (!c || !(oldName in c.values))
84
+ dropped.push(`i${String(i)}.${oldName}: no such value`);
85
+ else if (!NAME_RE.test(newName))
86
+ dropped.push(`i${c.index}.${oldName} -> ${JSON.stringify(newName)}: not a snake_case name`);
87
+ else if (newName === oldName)
88
+ continue;
89
+ else if (have.has(newName))
90
+ dropped.push(`i${c.index}.${oldName} -> ${newName}: name already taken`);
91
+ else {
92
+ const m = plan.get(c.index) ?? {};
93
+ m[oldName] = newName;
94
+ plan.set(c.index, m);
95
+ }
96
+ }
97
+ return { plan, dropped };
98
+ }
99
+ /**
100
+ * Ask the model for a plan. One call; a refusal or malformed answer is an
101
+ * empty plan. Pass a timeout signal: this runs inside the daemon's `stop`,
102
+ * and a slow model must cost the caller a bounded wait, never the export —
103
+ * fwod26's stop blew the CLI's 20s budget on exactly this call and the sweep
104
+ * skipped both replays believing the flow was never saved.
105
+ */
106
+ export async function requestRelabelPlan(provider, cases, opts = {}) {
107
+ if (!cases.length)
108
+ return { plan: new Map(), dropped: [] };
109
+ // effort low: the plan is one mechanical tool call, and at default effort a
110
+ // reasoning model can deliberate past the caller's whole timebox on a large
111
+ // session — fwgr19-n1 aborted at 100s with the request still pending, on
112
+ // the same model/endpoint where low effort answers in seconds (see
113
+ // CompleteOptions.effort for the measurement).
114
+ const done = await provider.complete(relabelMessages(cases), [RENAME_TOOL], { signal: opts.signal, effort: 'low' });
115
+ const call = (done.toolCalls ?? []).find((t) => t.name === 'rename_values');
116
+ return validateRelabelPlan(call?.args, cases);
117
+ }
118
+ /**
119
+ * Rename report value keys in the recorded entries, in place. Key order is
120
+ * preserved so the rewritten script diffs cleanly. Returns renames applied.
121
+ *
122
+ * Each renamed report also gets a `relabel` field recording old -> new — the
123
+ * durable trace, like `namingAsk`. The daemon runs detached with its stderr
124
+ * ignored, so fwod26's first live relabel was a black box: nothing anywhere
125
+ * said whether the pass ran, renamed, or failed. script.jsonl is the one
126
+ * artifact every run publishes; what the pass did belongs in it.
127
+ */
128
+ export function applyRelabelToEntries(entries, plan) {
129
+ let applied = 0;
130
+ let index = 0;
131
+ for (const e of entries) {
132
+ if (e.k === 'instruction')
133
+ index++;
134
+ else if (e.k === 'report' && plan.has(index)) {
135
+ const renames = plan.get(index);
136
+ const values = {};
137
+ const done = {};
138
+ for (const [k, v] of Object.entries(e.values ?? {})) {
139
+ const nk = renames[k] ?? k;
140
+ if (nk !== k) {
141
+ applied++;
142
+ done[k] = nk;
143
+ }
144
+ values[nk] = v;
145
+ }
146
+ e.values = values;
147
+ if (Object.keys(done).length)
148
+ e.relabel = done;
149
+ }
150
+ }
151
+ return applied;
152
+ }
153
+ /**
154
+ * Rename one session's compiled skills to agree with the renamed entries:
155
+ * read labels, reportTemplate keys, and `output:i<n>:<name>` param bindings.
156
+ * `skillIndex` says which instruction each skill (or segment chain) belongs
157
+ * to. Mutates; returns the ids of skills actually changed, for persisting.
158
+ */
159
+ export function applyRelabelToSkills(skills, plan, skillIndex) {
160
+ const changed = new Set();
161
+ for (const skill of skills) {
162
+ const index = skillIndex.get(skill.id);
163
+ const renames = index !== undefined ? plan.get(index) : undefined;
164
+ if (renames) {
165
+ const renameSteps = (steps) => {
166
+ for (const s of steps) {
167
+ if (s.label && renames[s.label]) {
168
+ s.label = renames[s.label];
169
+ changed.add(skill.id);
170
+ }
171
+ if (s.body)
172
+ renameSteps(s.body);
173
+ }
174
+ };
175
+ renameSteps(skill.steps);
176
+ if (skill.reportTemplate?.values) {
177
+ const values = {};
178
+ let touched = false;
179
+ for (const [k, v] of Object.entries(skill.reportTemplate.values)) {
180
+ const nk = renames[k] ?? k;
181
+ if (nk !== k)
182
+ touched = true;
183
+ values[nk] = v;
184
+ }
185
+ if (touched) {
186
+ skill.reportTemplate.values = values;
187
+ changed.add(skill.id);
188
+ }
189
+ }
190
+ }
191
+ // Bindings can point at ANY earlier instruction's output, so every skill
192
+ // is checked against the whole plan, not just its own instruction's part.
193
+ for (const param of Object.values(skill.params ?? {})) {
194
+ const m = param.binding?.match(/^output:i(\d+):([^#]+)(#.*)?$/);
195
+ if (!m)
196
+ continue;
197
+ const to = plan.get(Number(m[1]))?.[m[2]];
198
+ if (to) {
199
+ param.binding = `output:i${m[1]}:${to}${m[3] ?? ''}`;
200
+ changed.add(skill.id);
201
+ }
202
+ }
203
+ }
204
+ return [...changed];
205
+ }
206
+ //# sourceMappingURL=relabel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relabel.js","sourceRoot":"","sources":["../../src/skills/relabel.ts"],"names":[],"mappings":"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"}