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,270 @@
1
+ import { specOf } from '../skills/replay.js';
2
+ import { VOLATILE_TOKEN_SHAPE, WILDCARD, volatileMatcher } from '../shared/text.js';
3
+ const SLOT = /\{\{([vd]\d+)\}\}/;
4
+ const SLOT_G = new RegExp(SLOT.source, 'g');
5
+ const defaultSlot = (s) => '${p.' + s + '}';
6
+ /** The escapes a single-quoted and a template literal share. */
7
+ function escapeFor(text) {
8
+ return text
9
+ .replace(/\\/g, '\\\\')
10
+ .replace(/\n/g, '\\n')
11
+ .replace(/\r/g, '\\r')
12
+ .replace(/\t/g, '\\t')
13
+ .replace(/\u2028/g, '\\u2028')
14
+ .replace(/\u2029/g, '\\u2029');
15
+ }
16
+ /** A JS single-quoted string literal for `text`. */
17
+ function quote(text) {
18
+ return `'${escapeFor(text).replace(/'/g, "\\'")}'`;
19
+ }
20
+ /** Literal text inside a template literal: a backtick or a `${` would end it or open a hole. */
21
+ function escapeTemplate(text) {
22
+ return escapeFor(text).replace(/`/g, '\\`').replace(/\$\{/g, '\\${');
23
+ }
24
+ /** JS string source for recorded text: a single-quoted literal, or a template literal when it
25
+ * carries {{slots}}. */
26
+ export function stringSource(text, o = {}) {
27
+ if (!SLOT.test(text))
28
+ return quote(text);
29
+ const slot = o.slot ?? defaultSlot;
30
+ // split() with one capture group alternates literal, slot name, literal...
31
+ const body = text
32
+ .split(SLOT_G)
33
+ .map((p, i) => (i % 2 ? slot(p) : escapeTemplate(p)))
34
+ .join('');
35
+ return `\`${body}\``;
36
+ }
37
+ // The \u0001 delimiters keep a sentinel's digits from fusing with neighbouring
38
+ // text into a clock or date token, and escapeRe leaves all three characters
39
+ // alone, so the sentinel comes back out of the pattern intact.
40
+ const SENTINEL = (i) => `\u0001${i}\u0001`;
41
+ const SENTINEL_G = /\u0001(\d+)\u0001/g;
42
+ /**
43
+ * The pieces of the RegExp `volatileMatcher` would build, with the slots
44
+ * pulled back out - or null when it would return a plain string.
45
+ *
46
+ * Built by asking volatileMatcher itself rather than restating its token
47
+ * shape here: each slot is swapped for a sentinel that survives its escaping
48
+ * untouched, and the sentinels are cut back out of the resulting `source`.
49
+ * Duplicating the wildcard pattern would let the two drift, and the whole
50
+ * point of this module is that they cannot.
51
+ *
52
+ * Volatility is judged with the slots still unbound, because a parameter is
53
+ * unknown at compile time: a date arriving through `{{v1}}` stays an exact
54
+ * match in the spec where replay would have wildcarded it. Stricter, never
55
+ * looser - a spec that quietly matched another day's row would be a lie.
56
+ */
57
+ function matcherPieces(text) {
58
+ const names = [];
59
+ const probe = text.replace(SLOT_G, (_m, name) => {
60
+ names.push(name);
61
+ return SENTINEL(names.length - 1);
62
+ });
63
+ const matcher = volatileMatcher(probe);
64
+ if (typeof matcher === 'string')
65
+ return null;
66
+ const pieces = [];
67
+ let last = 0;
68
+ for (const m of matcher.source.matchAll(SENTINEL_G)) {
69
+ const at = m.index ?? 0;
70
+ if (at > last)
71
+ pieces.push({ lit: matcher.source.slice(last, at) });
72
+ pieces.push({ slot: names[Number(m[1])] });
73
+ last = at + m[0].length;
74
+ }
75
+ if (last < matcher.source.length)
76
+ pieces.push({ lit: matcher.source.slice(last) });
77
+ return pieces;
78
+ }
79
+ /** The expression inside a slot's interpolation, so it can be wrapped in escapeRe(). */
80
+ function slotExpr(name, o) {
81
+ const rendered = (o.slot ?? defaultSlot)(name);
82
+ return /^\$\{[\s\S]*\}$/.test(rendered) ? rendered.slice(2, -1) : null;
83
+ }
84
+ /** Source for the matcher makeLocator would build: stringSource, or a RegExp literal when
85
+ * volatileMatcher would return a RegExp (mirror its construction exactly; slots inside a
86
+ * regex become `${escapeRe(p.vN)}` via new RegExp(...) source). */
87
+ export function matcherSource(text, o = {}) {
88
+ const pieces = matcherPieces(text);
89
+ if (!pieces)
90
+ return stringSource(text, o);
91
+ if (!pieces.some((p) => 'slot' in p)) {
92
+ const source = pieces.map((p) => p.lit).join('');
93
+ // A literal keeps the generated file readable, and RegExp.source is
94
+ // already literal-safe - it escapes the slashes that would end one, which
95
+ // is why nothing is escaped again here. Only a line terminator has no
96
+ // literal form, so that case goes through new RegExp.
97
+ return /[\n\r\u2028\u2029]/.test(source) ? `new RegExp(${quote(source)})` : `/${source}/`;
98
+ }
99
+ // escapeRe is inlined into the generated file: a bound parameter is DATA, so
100
+ // its own regex metacharacters must not become pattern - which is exactly
101
+ // what volatileMatcher does to the recorded text before splicing in the
102
+ // wildcards.
103
+ const body = pieces
104
+ .map((p) => {
105
+ if ('lit' in p)
106
+ return escapeTemplate(p.lit);
107
+ const expr = slotExpr(p.slot, o);
108
+ // A caller whose slot renderer is not an interpolation owns its own
109
+ // escaping; there is no expression here to wrap.
110
+ return expr === null ? (o.slot ?? defaultSlot)(p.slot) : '${escapeRe(' + expr + ')}';
111
+ })
112
+ .join('');
113
+ return `new RegExp(\`${body}\`)`;
114
+ }
115
+ /** Regex SOURCE for one piece of recorded text: literals escaped, slots spliced in as
116
+ * `${escapeRe(p.vN)}` (a bound parameter is DATA, so its own metacharacters must not
117
+ * become pattern), all of it safe to sit inside a template literal. */
118
+ function patternBody(text, o) {
119
+ return text
120
+ .split(SLOT_G)
121
+ .map((p, i) => {
122
+ if (i % 2 === 0)
123
+ return escapeTemplate(reEscape(p));
124
+ const expr = slotExpr(p, o);
125
+ return expr === null ? (o.slot ?? defaultSlot)(p) : '${escapeRe(' + expr + ')}';
126
+ })
127
+ .join('');
128
+ }
129
+ const reEscape = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
130
+ /**
131
+ * Source for a matcher over a recorded PAGE LINE - one whose volatile tokens the
132
+ * STORE already replaced with `{{*}}` (maskVolatile), unlike a locator name, which
133
+ * arrives verbatim and is masked here by `matcherSource`/`volatileMatcher`.
134
+ *
135
+ * Rendered as the literal string it looks like, `{{*}}` can never match anything:
136
+ * kanboard's `textbox "{{*}} {{*}}"` (a due-date field the app names after the
137
+ * current date and time) failed on every replay of the compiled spec. So each
138
+ * wildcard becomes the token shape it stood for - NOT `.*`. The mask is only ever
139
+ * applied to a clock or calendar token, so the token shape is exactly what was
140
+ * masked out, and it is what `volatileMatcher` would have produced from the
141
+ * unmasked line; `.*` would let `textbox "Due date"` satisfy an assertion recorded
142
+ * for a dated field, which is an assertion looser than the evidence behind it.
143
+ *
144
+ * `anchor` mirrors the caller's `exact`: a presence check is a substring match
145
+ * (Playwright ignores `exact` for a RegExp name, so the anchoring has to carry it),
146
+ * while the already-in-effect guard reads presence as a reason NOT to act and must
147
+ * stay line-exact. Null when the text is nothing BUT wildcards: that names no
148
+ * element at all, and the caller leaves it as an observation.
149
+ */
150
+ export function maskedMatcherSource(text, o = {}) {
151
+ if (!text.includes(WILDCARD))
152
+ return matcherSource(text, o);
153
+ const parts = text.split(WILDCARD);
154
+ if (!parts.some((p) => p.trim()))
155
+ return null;
156
+ // The shape goes through escapeTemplate too: it is regex source living inside
157
+ // a template literal, and `\d` there is just "d".
158
+ const body = parts.map((p) => patternBody(p, o)).join(escapeTemplate(VOLATILE_TOKEN_SHAPE));
159
+ return `new RegExp(\`${o.anchor ? `^${body}$` : body}\`)`;
160
+ }
161
+ /** Playwright Locator expression for ONE candidate, mirroring makeLocator kind by kind
162
+ * (testid -> getByTestId / [attr="v"], role -> getByRole(role,{name,exact:true}), label,
163
+ * placeholder, text -> getByText(..,{exact:true}), id/css -> locator(sel), scoped ->
164
+ * locator(container,{hasText}).locator(sel), nth -> .nth(n)). Returns null for 'point'
165
+ * (not expressible without a runtime). */
166
+ export function candidateSource(c, o = {}) {
167
+ const page = o.page ?? 'page';
168
+ let src;
169
+ switch (c.kind) {
170
+ case 'testid':
171
+ src =
172
+ c.attr === 'data-testid'
173
+ ? `${page}.getByTestId(${stringSource(c.value, o)})`
174
+ : `${page}.locator(${stringSource(`[${c.attr}=${JSON.stringify(c.value)}]`, o)})`;
175
+ break;
176
+ case 'role':
177
+ src = `${page}.getByRole(${quote(c.role)}, { name: ${matcherSource(c.name, o)}, exact: true })`;
178
+ break;
179
+ case 'label':
180
+ src = `${page}.getByLabel(${matcherSource(c.label, o)})`;
181
+ break;
182
+ case 'placeholder':
183
+ src = `${page}.getByPlaceholder(${matcherSource(c.placeholder, o)})`;
184
+ break;
185
+ case 'text':
186
+ src = `${page}.getByText(${matcherSource(c.text, o)}, { exact: true })`;
187
+ break;
188
+ case 'id':
189
+ case 'css':
190
+ src = `${page}.locator(${stringSource(c.selector, o)})`;
191
+ break;
192
+ case 'scoped':
193
+ // hasText stays a plain substring match on the container, exactly as
194
+ // makeLocator passes it: the recorded value names the RECORD.
195
+ src = `${page}.locator(${stringSource(c.container, o)}, { hasText: ${stringSource(c.hasText, o)} })`;
196
+ if (c.selector)
197
+ src += `.locator(${stringSource(c.selector, o)})`;
198
+ break;
199
+ case 'point':
200
+ // markPoint tags the element under the recorded coordinates at replay
201
+ // time; a plain spec has nothing to tag, so the candidate is dropped
202
+ // rather than approximated into a selector that names a position.
203
+ return null;
204
+ }
205
+ return c.nth !== undefined ? `${src}.nth(${c.nth})` : src;
206
+ }
207
+ /** The whole chain as ONE expression: candidates ordered by specOf (identity, handles,
208
+ * path), joined with .or(), point dropped. When the chain carries identity (a scoped
209
+ * candidate with hasText), every non-identity candidate is guarded with
210
+ * .filter({ hasText }) so a fallback cannot land on another record - mirrors
211
+ * ResolvePolicy.requireIdentity. Returns the source, the candidates that could not be
212
+ * expressed, and the hasText guards applied. Multi-line pretty form: one candidate per
213
+ * line, `.or(` continuation lines indented by `indent`. */
214
+ /** The chain as an ordered list of expressions, best first, with the identity guards applied. */
215
+ export function candidateSources(chain, o = {}) {
216
+ const spec = specOf(chain);
217
+ const ordered = [...spec.identity, ...spec.handles, ...spec.path];
218
+ const scoped = spec.identity;
219
+ const guards = [...new Set(scoped.map((c) => c.hasText).filter(Boolean))];
220
+ const dropped = [];
221
+ const applied = new Set();
222
+ const sources = [];
223
+ for (const c of ordered) {
224
+ let src = candidateSource(c, o);
225
+ if (src === null) {
226
+ dropped.push(c);
227
+ continue;
228
+ }
229
+ if (c.kind !== 'scoped') {
230
+ // requireIdentity's rule: a value the candidate already carries needs no
231
+ // guard, everything else must still land on a node bearing the record's
232
+ // text. Unlike replay there is no exemption for the primary - a spec
233
+ // re-resolves nothing and has no recovery to fail over to, so a fallback
234
+ // that would silently work ANOTHER record must instead match nothing and
235
+ // let the step fail loudly.
236
+ const expr = JSON.stringify(c);
237
+ for (const g of guards.filter((v) => !expr.includes(v))) {
238
+ src += `.filter({ hasText: ${stringSource(g, o)} })`;
239
+ applied.add(g);
240
+ }
241
+ }
242
+ // A recorded chain routinely names the same element twice - an `id`
243
+ // candidate and the `css` candidate built from the same selector - and
244
+ // two identical expressions are two identical resolutions: no extra
245
+ // coverage, one more line for a reviewer to read past.
246
+ if (!sources.includes(src))
247
+ sources.push(src);
248
+ }
249
+ return { sources, dropped, identity: [...applied] };
250
+ }
251
+ /** The whole chain as ONE expression: candidates ordered by specOf (identity, handles,
252
+ * path), joined with .or(), point dropped. When the chain carries identity (a scoped
253
+ * candidate with hasText), every non-identity candidate is guarded with
254
+ * .filter({ hasText }) so a fallback cannot land on another record - mirrors
255
+ * ResolvePolicy.requireIdentity. Returns the source, the candidates that could not be
256
+ * expressed, and the hasText guards applied. Multi-line pretty form: one candidate per
257
+ * line, `.or(` continuation lines indented by `indent`.
258
+ *
259
+ * `.or()` is a UNION, so this expresses "any of these", not "the first of
260
+ * these that names exactly one element". That is right for a presence check
261
+ * and wrong for an action - see the emitter's `pick` helper.
262
+ */
263
+ export function chainSource(chain, o = {}) {
264
+ const indent = o.indent ?? ' ';
265
+ const { sources, dropped, identity } = candidateSources(chain, o);
266
+ const source = sources.length ? sources[0] + sources.slice(1).map((p) => `
267
+ ${indent}.or(${p})`).join('') : '';
268
+ return { source, dropped, identity };
269
+ }
270
+ //# sourceMappingURL=locators.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locators.js","sourceRoot":"","sources":["../../src/spec/locators.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Rebuild one segment as a `Skill`.
3
+ *
4
+ * `id` and the procedure fields (template/params/preconditions/steps/derived)
5
+ * are copied straight from the segment — those are exactly what `toSegment`
6
+ * (ir.ts) kept, so copying them back is the whole round trip. Everything else
7
+ * is bookkeeping `toSegment` deliberately drops and this function has to
8
+ * invent: zeroed stats (a compiled spec carries no replay history), no
9
+ * fingerprint (the emitted spec never had one to begin with — a live DOM
10
+ * count vector needs a runtime, not a JSON literal), and a synthetic
11
+ * provenance naming the spec as its own source rather than a recording
12
+ * session.
13
+ *
14
+ * `seq` is set only when the step's procedure has more than one segment: a
15
+ * single-segment skill in the wild never carries `seq` (see `Skill.seq` and
16
+ * `chainOf` in ir.ts, which treats an absent `seq` as "this skill is its own
17
+ * one-member chain"), and giving every skill a `seq` here would desync from
18
+ * that. The chain id is the step's FIRST segment's id — stable, unique to
19
+ * this step (segment ids are unique across a store), and exactly what
20
+ * `chainOf` needs to find every member back by filtering the origin's skills
21
+ * on `seq.chain`.
22
+ */
23
+ function toSkill(spec, step, seg, index, total, now) {
24
+ const skill = {
25
+ id: seg.id,
26
+ origin: spec.origin,
27
+ template: seg.template,
28
+ params: seg.params,
29
+ preconditions: seg.preconditions.requireText
30
+ ? { urlPattern: seg.preconditions.urlPattern, requireText: seg.preconditions.requireText }
31
+ : { urlPattern: seg.preconditions.urlPattern },
32
+ steps: seg.steps,
33
+ stats: { uses: 0, successes: 0, partial: 0, created: now, failedAtStep: {}, fallthroughs: 0 },
34
+ status: 'validated',
35
+ provenance: { session: `spec:${spec.name}`, instruction: step.instruction, created: now },
36
+ };
37
+ if (seg.derived)
38
+ skill.derived = seg.derived;
39
+ // The goal and the report template it needs travel together, and both are
40
+ // part of the procedure rather than bookkeeping: a repair that lowered a
41
+ // spec, replayed it and re-emitted would otherwise drop the "already
42
+ // satisfied" guard on the way through.
43
+ if (seg.goal)
44
+ skill.goal = seg.goal;
45
+ if (seg.report)
46
+ skill.reportTemplate = seg.report;
47
+ if (total > 1)
48
+ skill.seq = { chain: step.segments[0].id, index, of: total };
49
+ return skill;
50
+ }
51
+ /**
52
+ * Rebuild one `FlowStep`. `skill` points at the first segment's id (index 0)
53
+ * — matching `Skill.seq`'s own doc: "Matching/selection always starts at
54
+ * index 0" — and `chainOf` walks the rest of the chain from there. A step
55
+ * whose spec carried no segments (no converged procedure — `flowToSpec`
56
+ * still exports the shape and warns) gets no `skill` at all, same as a Flow
57
+ * step that never had one.
58
+ *
59
+ * `recorded` and `outputEvidence` are cross-run evidence `SpecStep` never
60
+ * carried in the first place (ir.ts's `SpecStep` has no field for them), so
61
+ * they come back empty/absent rather than fabricated — an empty `recorded`
62
+ * is indistinguishable, to every consumer, from "this run observed nothing
63
+ * yet", which is the truth for a freshly staged spec.
64
+ */
65
+ function toFlowStep(spec, step, now, skills) {
66
+ const segSkills = step.segments.map((seg, i) => toSkill(spec, step, seg, i, step.segments.length, now));
67
+ skills.push(...segSkills);
68
+ const flowStep = {
69
+ id: step.id,
70
+ instruction: step.instruction,
71
+ params: step.params,
72
+ outputs: step.outputs,
73
+ recorded: {},
74
+ };
75
+ if (segSkills.length)
76
+ flowStep.skill = segSkills[0].id;
77
+ return flowStep;
78
+ }
79
+ /**
80
+ * A lifted spec as the Flow + Skill[] the replay/repair code understands.
81
+ *
82
+ * Segments become skills that keep their ids, seq (chain = the flow step's
83
+ * first segment id, index/of from position), preconditions (no fingerprint),
84
+ * steps, derived, params; stats start at zero, status 'validated' (a
85
+ * compiled spec is by definition converged), provenance from the spec.
86
+ *
87
+ * Mirrors `flowToSpec`'s own ordering exactly (same per-step segment order,
88
+ * same chain-id choice) so that `flowToSpec(specToFlow(spec).flow, store)`
89
+ * reproduces `spec` once the returned skills are in a store `flowToSpec` can
90
+ * read — see `stageForReplay`, and PLAN-self-updating-spec.md's round-trip
91
+ * invariant.
92
+ */
93
+ export function specToFlow(spec) {
94
+ const now = new Date().toISOString();
95
+ const skills = [];
96
+ const steps = spec.steps.map((step) => toFlowStep(spec, step, now, skills));
97
+ const flow = {
98
+ name: spec.name,
99
+ origin: spec.origin,
100
+ startUrl: spec.startUrl,
101
+ vars: spec.vars,
102
+ steps,
103
+ provenance: { session: `spec:${spec.name}`, created: now },
104
+ };
105
+ return { flow, skills };
106
+ }
107
+ /**
108
+ * Write the skills into a store (an isolated temp store is the normal use)
109
+ * and return the flow, ready for `run`.
110
+ *
111
+ * A compiled spec has no store of its own — the spec IS the store, frozen —
112
+ * so `repair` cannot just point the existing replay/repair machinery at
113
+ * `~/.sitelooper/skills` (that store may not even have this origin, or may
114
+ * have moved on since the spec was emitted). Staging into a scratch
115
+ * `SkillStore` gives that machinery the on-disk shape it already expects
116
+ * without teaching it a second, spec-native code path.
117
+ */
118
+ export function stageForReplay(spec, store) {
119
+ const { flow, skills } = specToFlow(spec);
120
+ for (const skill of skills)
121
+ store.put(skill);
122
+ return flow;
123
+ }
124
+ //# sourceMappingURL=lower.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lower.js","sourceRoot":"","sources":["../../src/spec/lower.ts"],"names":[],"mappings":"AAkBA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,SAAS,OAAO,CAAC,IAAc,EAAE,IAAc,EAAE,GAAgB,EAAE,KAAa,EAAE,KAAa,EAAE,GAAW;IAC1G,MAAM,KAAK,GAAU;QACnB,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,aAAa,EAAE,GAAG,CAAC,aAAa,CAAC,WAAW;YAC1C,CAAC,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,aAAa,CAAC,UAAU,EAAE,WAAW,EAAE,GAAG,CAAC,aAAa,CAAC,WAAW,EAAE;YAC1F,CAAC,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,aAAa,CAAC,UAAU,EAAE;QAChD,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE;QAC7F,MAAM,EAAE,WAAW;QACnB,UAAU,EAAE,EAAE,OAAO,EAAE,QAAQ,IAAI,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,GAAG,EAAE;KAC1F,CAAC;IACF,IAAI,GAAG,CAAC,OAAO;QAAE,KAAK,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;IAC7C,0EAA0E;IAC1E,yEAAyE;IACzE,qEAAqE;IACrE,uCAAuC;IACvC,IAAI,GAAG,CAAC,IAAI;QAAE,KAAK,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;IACpC,IAAI,GAAG,CAAC,MAAM;QAAE,KAAK,CAAC,cAAc,GAAG,GAAG,CAAC,MAAM,CAAC;IAClD,IAAI,KAAK,GAAG,CAAC;QAAE,KAAK,CAAC,GAAG,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;IAC5E,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,SAAS,UAAU,CAAC,IAAc,EAAE,IAAc,EAAE,GAAW,EAAE,MAAe;IAC9E,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IACxG,MAAM,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC;IAC1B,MAAM,QAAQ,GAAa;QACzB,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,QAAQ,EAAE,EAAE;KACb,CAAC;IACF,IAAI,SAAS,CAAC,MAAM;QAAE,QAAQ,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACvD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,UAAU,CAAC,IAAc;IACvC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,MAAM,MAAM,GAAY,EAAE,CAAC;IAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;IAC5E,MAAM,IAAI,GAAS;QACjB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,KAAK;QACL,UAAU,EAAE,EAAE,OAAO,EAAE,QAAQ,IAAI,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE;KAC3D,CAAC;IACF,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAC1B,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAAC,IAAc,EAAE,KAAiB;IAC9D,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAC1C,KAAK,MAAM,KAAK,IAAI,MAAM;QAAE,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC7C,OAAO,IAAI,CAAC;AACd,CAAC"}