yaml-flow 3.1.1 → 5.0.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.
- package/README.md +81 -20
- package/board-live-cards-cli.js +37 -0
- package/browser/board-livegraph-runtime.js +1453 -0
- package/browser/board-livegraph-runtime.js.map +1 -0
- package/browser/card-compute.js +153 -433
- package/browser/live-cards.js +868 -115
- package/browser/live-cards.schema.json +90 -83
- package/dist/board-livegraph-runtime/index.cjs +1448 -0
- package/dist/board-livegraph-runtime/index.cjs.map +1 -0
- package/dist/board-livegraph-runtime/index.d.cts +101 -0
- package/dist/board-livegraph-runtime/index.d.ts +101 -0
- package/dist/board-livegraph-runtime/index.js +1441 -0
- package/dist/board-livegraph-runtime/index.js.map +1 -0
- package/dist/card-compute/index.cjs +266 -431
- package/dist/card-compute/index.cjs.map +1 -1
- package/dist/card-compute/index.d.cts +77 -49
- package/dist/card-compute/index.d.ts +77 -49
- package/dist/card-compute/index.js +263 -432
- package/dist/card-compute/index.js.map +1 -1
- package/dist/cli/board-live-cards-cli.cjs +2750 -0
- package/dist/cli/board-live-cards-cli.cjs.map +1 -0
- package/dist/cli/board-live-cards-cli.d.cts +205 -0
- package/dist/cli/board-live-cards-cli.d.ts +205 -0
- package/dist/cli/board-live-cards-cli.js +2702 -0
- package/dist/cli/board-live-cards-cli.js.map +1 -0
- package/dist/{constants-B2zqu10b.d.ts → constants-DuzE5n03.d.ts} +2 -2
- package/dist/{constants-DJZU1pwJ.d.cts → constants-ozjf1Ejw.d.cts} +2 -2
- package/dist/continuous-event-graph/index.cjs +258 -464
- package/dist/continuous-event-graph/index.cjs.map +1 -1
- package/dist/continuous-event-graph/index.d.cts +18 -358
- package/dist/continuous-event-graph/index.d.ts +18 -358
- package/dist/continuous-event-graph/index.js +255 -464
- package/dist/continuous-event-graph/index.js.map +1 -1
- package/dist/event-graph/index.cjs +4 -4
- package/dist/event-graph/index.cjs.map +1 -1
- package/dist/event-graph/index.d.cts +5 -5
- package/dist/event-graph/index.d.ts +5 -5
- package/dist/event-graph/index.js +4 -4
- package/dist/event-graph/index.js.map +1 -1
- package/dist/index.cjs +1684 -555
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +26 -7
- package/dist/index.d.ts +26 -7
- package/dist/index.js +1678 -555
- package/dist/index.js.map +1 -1
- package/dist/inference/index.cjs +138 -19
- package/dist/inference/index.cjs.map +1 -1
- package/dist/inference/index.d.cts +2 -2
- package/dist/inference/index.d.ts +2 -2
- package/dist/inference/index.js +138 -19
- package/dist/inference/index.js.map +1 -1
- package/dist/journal-DRfJiheM.d.cts +28 -0
- package/dist/journal-NLYuqege.d.ts +28 -0
- package/dist/live-cards-bridge-Or7fdEJV.d.ts +316 -0
- package/dist/live-cards-bridge-vGJ6tMzN.d.cts +316 -0
- package/dist/schedule-CMcZe5Ny.d.ts +21 -0
- package/dist/schedule-CiucyCan.d.cts +21 -0
- package/dist/step-machine/index.cjs +18 -1
- package/dist/step-machine/index.cjs.map +1 -1
- package/dist/step-machine/index.d.cts +2 -2
- package/dist/step-machine/index.d.ts +2 -2
- package/dist/step-machine/index.js +18 -1
- package/dist/step-machine/index.js.map +1 -1
- package/dist/stores/file.d.cts +1 -1
- package/dist/stores/file.d.ts +1 -1
- package/dist/stores/index.d.cts +1 -1
- package/dist/stores/index.d.ts +1 -1
- package/dist/stores/localStorage.d.cts +1 -1
- package/dist/stores/localStorage.d.ts +1 -1
- package/dist/stores/memory.d.cts +1 -1
- package/dist/stores/memory.d.ts +1 -1
- package/dist/{types-BwvgvlOO.d.cts → types-BzLD8bjb.d.cts} +1 -1
- package/dist/{types-ClRA8hzC.d.ts → types-C2eJ7DAV.d.ts} +1 -1
- package/dist/{types-DEj7OakX.d.cts → types-CMFSIjpc.d.cts} +39 -4
- package/dist/{types-DEj7OakX.d.ts → types-CMFSIjpc.d.ts} +39 -4
- package/dist/{types-FZ_eyErS.d.cts → types-ycun84cq.d.cts} +1 -0
- package/dist/{types-FZ_eyErS.d.ts → types-ycun84cq.d.ts} +1 -0
- package/dist/{validate-DEZ2Ymdb.d.ts → validate-DJQTQ6bP.d.ts} +1 -1
- package/dist/{validate-DqKTZg_o.d.cts → validate-ke92Cleg.d.cts} +1 -1
- package/examples/browser/boards/portfolio-tracker/cards/holdings-table.json +22 -0
- package/examples/browser/boards/portfolio-tracker/cards/portfolio-form.json +16 -0
- package/examples/browser/boards/portfolio-tracker/cards/portfolio-value.json +15 -0
- package/examples/browser/boards/portfolio-tracker/cards/price-fetch.json +15 -0
- package/examples/browser/boards/portfolio-tracker/fetch-prices.js +43 -0
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker-task-executor.cjs +96 -0
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker.bat +7 -0
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker.js +217 -0
- package/examples/browser/livecards-browser/index.html +41 -0
- package/examples/browser/{index.html → step-machine-browser/index.html} +53 -53
- package/examples/cli/step-machine-cli/portfolio-tracker/cards/holdings-table.json +22 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/cards/portfolio-form.json +43 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/cards/portfolio-value.json +15 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/cards/price-fetch.json +15 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/fetch-prices.js +48 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/_board-cli.js +58 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/add-cards-cli.js +27 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/init-board-cli.js +25 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/reset-board-dir-cli.js +29 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/retrigger-cli.js +27 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/status-cli.js +25 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/update-holdings-cli.js +37 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/wait-completed-cli.js +53 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/write-prices-cli.js +35 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/portfolio-tracker.flow.yaml +227 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/portfolio-tracker.input.json +38 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/run-portfolio-tracker.bat +29 -0
- package/examples/cli/step-machine-demo/jsonata-init-board-cli.js +36 -0
- package/examples/cli/step-machine-demo/jsonata-init-board.flow.yaml +30 -0
- package/examples/cli/step-machine-demo/one-step-cli-only.flow.yaml +19 -0
- package/examples/cli/step-machine-demo/step-cli-echo-y.js +15 -0
- package/examples/cli/step-machine-demo/step2-double-cli.js +39 -0
- package/examples/cli/step-machine-demo/two-step-math-handlers.js +32 -0
- package/examples/cli/step-machine-demo/two-step-math.flow.yaml +31 -0
- package/examples/cli/step-machine-demo/two-step-mixed-handlers.js +24 -0
- package/examples/cli/step-machine-demo/two-step-mixed.flow.yaml +35 -0
- package/examples/example-board/board.yaml +23 -0
- package/examples/example-board/bootstrap_payload.json +1 -0
- package/examples/example-board/cards/card-chain-region-alert.json +39 -0
- package/examples/example-board/cards/card-chain-region-totals.json +26 -0
- package/examples/example-board/cards/card-chain-top-region.json +24 -0
- package/examples/example-board/cards/card-ex-actions.json +32 -0
- package/examples/example-board/cards/card-ex-chart.json +30 -0
- package/examples/example-board/cards/card-ex-filter.json +36 -0
- package/examples/example-board/cards/card-ex-filtered-by-preference.json +59 -0
- package/examples/example-board/cards/card-ex-form.json +91 -0
- package/examples/example-board/cards/card-ex-list.json +22 -0
- package/examples/example-board/cards/card-ex-markdown.json +17 -0
- package/examples/example-board/cards/card-ex-metric.json +19 -0
- package/examples/example-board/cards/card-ex-narrative.json +36 -0
- package/examples/example-board/cards/card-ex-source-http.json +28 -0
- package/examples/example-board/cards/card-ex-source.json +21 -0
- package/examples/example-board/cards/card-ex-status.json +35 -0
- package/examples/example-board/cards/card-ex-table.json +30 -0
- package/examples/example-board/cards/card-ex-todo.json +29 -0
- package/examples/example-board/demo-chat-handler.js +69 -0
- package/examples/example-board/demo-server.js +87 -0
- package/examples/example-board/demo-shell-browser.html +806 -0
- package/examples/example-board/demo-shell-with-server.html +280 -0
- package/examples/example-board/demo-shell.html +62 -0
- package/examples/example-board/demo-task-executor.js +255 -0
- package/examples/example-board/mock.db +15 -0
- package/examples/example-board/reusable-board-runtime-client.js +265 -0
- package/examples/example-board/reusable-runtime-artifacts-adapter.js +233 -0
- package/examples/example-board/reusable-server-runtime.js +1284 -0
- package/examples/index.html +799 -0
- package/examples/{batch → npm-libs/batch}/batch-step-machine.ts +1 -1
- package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/live-cards-board.ts +18 -18
- package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/live-portfolio-dashboard.ts +24 -24
- package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/portfolio-tracker.ts +1 -1
- package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/reactive-monitoring.ts +1 -1
- package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/reactive-pipeline.ts +1 -1
- package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/soc-incident-board.ts +1 -1
- package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/stock-dashboard.ts +1 -1
- package/examples/{event-graph → npm-libs/event-graph}/ci-cd-pipeline.ts +1 -1
- package/examples/{event-graph → npm-libs/event-graph}/executor-diamond.ts +1 -1
- package/examples/{event-graph → npm-libs/event-graph}/executor-pipeline.ts +1 -1
- package/examples/{event-graph → npm-libs/event-graph}/research-pipeline.ts +1 -1
- package/examples/{graph-of-graphs → npm-libs/graph-of-graphs}/multi-stage-etl.ts +1 -1
- package/examples/{graph-of-graphs → npm-libs/graph-of-graphs}/url-processing-pipeline.ts +1 -1
- package/examples/{inference → npm-libs/inference}/azure-deployment.ts +1 -1
- package/examples/{inference → npm-libs/inference}/copilot-cli.ts +1 -1
- package/examples/{inference → npm-libs/inference}/data-pipeline.ts +1 -1
- package/examples/{inference → npm-libs/inference}/pluggable-adapters.ts +1 -1
- package/examples/{node → npm-libs/node}/ai-conversation.ts +1 -1
- package/examples/{node → npm-libs/node}/simple-greeting.ts +2 -2
- package/examples/step-machine-cli/portfolio-tracker/cards/holdings-table.json +22 -0
- package/examples/step-machine-cli/portfolio-tracker/cards/portfolio-form.json +43 -0
- package/examples/step-machine-cli/portfolio-tracker/cards/portfolio-value.json +15 -0
- package/examples/step-machine-cli/portfolio-tracker/cards/price-fetch.json +15 -0
- package/examples/step-machine-cli/portfolio-tracker/fetch-prices.js +48 -0
- package/examples/step-machine-cli/portfolio-tracker/handlers/_board-cli.js +58 -0
- package/examples/step-machine-cli/portfolio-tracker/handlers/add-cards-cli.js +27 -0
- package/examples/step-machine-cli/portfolio-tracker/handlers/init-board-cli.js +25 -0
- package/examples/step-machine-cli/portfolio-tracker/handlers/reset-board-dir-cli.js +29 -0
- package/examples/step-machine-cli/portfolio-tracker/handlers/retrigger-cli.js +27 -0
- package/examples/step-machine-cli/portfolio-tracker/handlers/status-cli.js +25 -0
- package/examples/step-machine-cli/portfolio-tracker/handlers/update-holdings-cli.js +37 -0
- package/examples/step-machine-cli/portfolio-tracker/handlers/wait-completed-cli.js +53 -0
- package/examples/step-machine-cli/portfolio-tracker/handlers/write-prices-cli.js +35 -0
- package/examples/step-machine-cli/portfolio-tracker/portfolio-tracker-task-executor.cjs +96 -0
- package/examples/step-machine-cli/portfolio-tracker/portfolio-tracker.flow.yaml +227 -0
- package/examples/step-machine-cli/portfolio-tracker/portfolio-tracker.input.json +38 -0
- package/examples/step-machine-cli/portfolio-tracker/run-portfolio-tracker.bat +29 -0
- package/package.json +27 -2
- package/schema/board-status.schema.json +118 -0
- package/schema/card-runtime.schema.json +25 -0
- package/schema/flow.schema.json +5 -0
- package/schema/live-cards.schema.json +90 -83
- package/step-machine-cli.js +674 -0
- package/browser/ingest-board.js +0 -296
- package/examples/ingest.js +0 -733
- /package/examples/{flows → npm-libs/flows}/ai-conversation.yaml +0 -0
- /package/examples/{flows → npm-libs/flows}/order-processing.yaml +0 -0
- /package/examples/{flows → npm-libs/flows}/simple-greeting.yaml +0 -0
package/dist/inference/index.js
CHANGED
|
@@ -174,37 +174,156 @@ function applyEvent(live, event) {
|
|
|
174
174
|
if ("executionId" in event && event.executionId && event.executionId !== state.executionId) {
|
|
175
175
|
return live;
|
|
176
176
|
}
|
|
177
|
-
let newState;
|
|
178
177
|
switch (event.type) {
|
|
178
|
+
// --- Execution state transitions ---
|
|
179
179
|
case "task-started":
|
|
180
|
-
|
|
181
|
-
break;
|
|
180
|
+
return { config, state: applyTaskStart(state, event.taskName) };
|
|
182
181
|
case "task-completed":
|
|
183
|
-
|
|
184
|
-
break;
|
|
182
|
+
return { config, state: applyTaskCompletion(state, config, event.taskName, event.result, event.dataHash, event.data) };
|
|
185
183
|
case "task-failed":
|
|
186
|
-
|
|
187
|
-
break;
|
|
184
|
+
return { config, state: applyTaskFailure(state, config, event.taskName, event.error) };
|
|
188
185
|
case "task-progress":
|
|
189
|
-
|
|
190
|
-
break;
|
|
186
|
+
return { config, state: applyTaskProgress(state, event.taskName, event.message, event.progress) };
|
|
191
187
|
case "task-restart":
|
|
192
|
-
|
|
193
|
-
break;
|
|
188
|
+
return { config, state: applyTaskRestart(state, event.taskName) };
|
|
194
189
|
case "inject-tokens":
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
190
|
+
return {
|
|
191
|
+
config,
|
|
192
|
+
state: {
|
|
193
|
+
...state,
|
|
194
|
+
availableOutputs: [.../* @__PURE__ */ new Set([...state.availableOutputs, ...event.tokens])],
|
|
195
|
+
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
196
|
+
}
|
|
199
197
|
};
|
|
200
|
-
break;
|
|
201
198
|
case "agent-action":
|
|
202
|
-
|
|
203
|
-
|
|
199
|
+
return { config, state: applyAgentAction(state, event.action) };
|
|
200
|
+
// --- Structural mutations ---
|
|
201
|
+
case "task-upsert":
|
|
202
|
+
return addNode(live, event.taskName, event.taskConfig);
|
|
203
|
+
case "task-removal":
|
|
204
|
+
return removeNode(live, event.taskName);
|
|
205
|
+
case "node-requires-add":
|
|
206
|
+
return addRequires(live, event.nodeName, event.tokens);
|
|
207
|
+
case "node-requires-remove":
|
|
208
|
+
return removeRequires(live, event.nodeName, event.tokens);
|
|
209
|
+
case "node-provides-add":
|
|
210
|
+
return addProvides(live, event.nodeName, event.tokens);
|
|
211
|
+
case "node-provides-remove":
|
|
212
|
+
return removeProvides(live, event.nodeName, event.tokens);
|
|
204
213
|
default:
|
|
205
214
|
return live;
|
|
206
215
|
}
|
|
207
|
-
|
|
216
|
+
}
|
|
217
|
+
function addNode(live, name, taskConfig) {
|
|
218
|
+
const exists = !!live.config.tasks[name];
|
|
219
|
+
return {
|
|
220
|
+
config: {
|
|
221
|
+
...live.config,
|
|
222
|
+
tasks: { ...live.config.tasks, [name]: taskConfig }
|
|
223
|
+
},
|
|
224
|
+
state: {
|
|
225
|
+
...live.state,
|
|
226
|
+
tasks: {
|
|
227
|
+
...live.state.tasks,
|
|
228
|
+
[name]: exists ? live.state.tasks[name] : createDefaultGraphEngineStore2()
|
|
229
|
+
},
|
|
230
|
+
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function removeNode(live, name) {
|
|
235
|
+
if (!live.config.tasks[name]) return live;
|
|
236
|
+
const { [name]: _removedConfig, ...remainingTasks } = live.config.tasks;
|
|
237
|
+
const { [name]: _removedState, ...remainingStates } = live.state.tasks;
|
|
238
|
+
return {
|
|
239
|
+
config: {
|
|
240
|
+
...live.config,
|
|
241
|
+
tasks: remainingTasks
|
|
242
|
+
},
|
|
243
|
+
state: {
|
|
244
|
+
...live.state,
|
|
245
|
+
tasks: remainingStates,
|
|
246
|
+
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
function addRequires(live, nodeName, tokens) {
|
|
251
|
+
const task = live.config.tasks[nodeName];
|
|
252
|
+
if (!task) return live;
|
|
253
|
+
const current = getRequires(task);
|
|
254
|
+
const toAdd = tokens.filter((t) => !current.includes(t));
|
|
255
|
+
if (toAdd.length === 0) return live;
|
|
256
|
+
return {
|
|
257
|
+
config: {
|
|
258
|
+
...live.config,
|
|
259
|
+
tasks: {
|
|
260
|
+
...live.config.tasks,
|
|
261
|
+
[nodeName]: { ...task, requires: [...current, ...toAdd] }
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
state: live.state
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
function removeRequires(live, nodeName, tokens) {
|
|
268
|
+
const task = live.config.tasks[nodeName];
|
|
269
|
+
if (!task) return live;
|
|
270
|
+
const current = getRequires(task);
|
|
271
|
+
const remaining = current.filter((t) => !tokens.includes(t));
|
|
272
|
+
if (remaining.length === current.length) return live;
|
|
273
|
+
return {
|
|
274
|
+
config: {
|
|
275
|
+
...live.config,
|
|
276
|
+
tasks: {
|
|
277
|
+
...live.config.tasks,
|
|
278
|
+
[nodeName]: { ...task, requires: remaining }
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
state: live.state
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
function addProvides(live, nodeName, tokens) {
|
|
285
|
+
const task = live.config.tasks[nodeName];
|
|
286
|
+
if (!task) return live;
|
|
287
|
+
const current = getProvides(task);
|
|
288
|
+
const toAdd = tokens.filter((t) => !current.includes(t));
|
|
289
|
+
if (toAdd.length === 0) return live;
|
|
290
|
+
return {
|
|
291
|
+
config: {
|
|
292
|
+
...live.config,
|
|
293
|
+
tasks: {
|
|
294
|
+
...live.config.tasks,
|
|
295
|
+
[nodeName]: { ...task, provides: [...current, ...toAdd] }
|
|
296
|
+
}
|
|
297
|
+
},
|
|
298
|
+
state: live.state
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
function removeProvides(live, nodeName, tokens) {
|
|
302
|
+
const task = live.config.tasks[nodeName];
|
|
303
|
+
if (!task) return live;
|
|
304
|
+
const current = getProvides(task);
|
|
305
|
+
const remaining = current.filter((t) => !tokens.includes(t));
|
|
306
|
+
if (remaining.length === current.length) return live;
|
|
307
|
+
return {
|
|
308
|
+
config: {
|
|
309
|
+
...live.config,
|
|
310
|
+
tasks: {
|
|
311
|
+
...live.config.tasks,
|
|
312
|
+
[nodeName]: { ...task, provides: remaining }
|
|
313
|
+
}
|
|
314
|
+
},
|
|
315
|
+
state: live.state
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
function createDefaultGraphEngineStore2() {
|
|
319
|
+
return {
|
|
320
|
+
status: "not-started",
|
|
321
|
+
executionCount: 0,
|
|
322
|
+
retryCount: 0,
|
|
323
|
+
lastEpoch: 0,
|
|
324
|
+
messages: [],
|
|
325
|
+
progress: null
|
|
326
|
+
};
|
|
208
327
|
}
|
|
209
328
|
function applyAgentAction(state, action) {
|
|
210
329
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/event-graph/graph-helpers.ts","../../src/event-graph/task-transitions.ts","../../src/continuous-event-graph/core.ts","../../src/inference/core.ts","../../src/inference/adapters.ts"],"names":["updatedTask"],"mappings":";;;AAcO,SAAS,YAAY,IAAA,EAAwC;AAClE,EAAA,IAAI,CAAC,IAAA,EAAM,OAAO,EAAC;AACnB,EAAA,IAAI,MAAM,OAAA,CAAQ,IAAA,CAAK,QAAQ,CAAA,SAAU,IAAA,CAAK,QAAA;AAC9C,EAAA,OAAO,EAAC;AACV;AAEO,SAAS,YAAY,IAAA,EAAwC;AAClE,EAAA,IAAI,CAAC,IAAA,EAAM,OAAO,EAAC;AACnB,EAAA,IAAI,MAAM,OAAA,CAAQ,IAAA,CAAK,QAAQ,CAAA,SAAU,IAAA,CAAK,QAAA;AAC9C,EAAA,OAAO,EAAC;AACV;AAEO,SAAS,YAAY,KAAA,EAAgD;AAC1E,EAAA,OAAO,KAAA,CAAM,SAAS,EAAC;AACzB;;;ACfO,SAAS,cAAA,CAAe,OAAuB,QAAA,EAAkC;AACtF,EAAA,MAAM,YAAA,GAAe,KAAA,CAAM,KAAA,CAAM,QAAQ,KAAK,6BAAA,EAA8B;AAE5E,EAAA,MAAM,WAAA,GAAgC;AAAA,IACpC,GAAG,YAAA;AAAA,IACH,MAAA,EAAQ,SAAA;AAAA,IACR,SAAA,EAAA,iBAAW,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,IAClC,WAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,IACpC,QAAA,EAAU,CAAA;AAAA,IACV,KAAA,EAAO;AAAA,GACT;AAEA,EAAA,OAAO;AAAA,IACL,GAAG,KAAA;AAAA,IACH,KAAA,EAAO,EAAE,GAAG,KAAA,CAAM,OAAO,CAAC,QAAQ,GAAG,WAAA,EAAY;AAAA,IACjD,WAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA;AAAY,GACtC;AACF;AAOO,SAAS,oBACd,KAAA,EACA,KAAA,EACA,QAAA,EACA,MAAA,EACA,UACA,IAAA,EACgB;AAChB,EAAA,MAAM,YAAA,GAAe,KAAA,CAAM,KAAA,CAAM,QAAQ,KAAK,6BAAA,EAA8B;AAC5E,EAAA,MAAM,UAAA,GAAa,KAAA,CAAM,KAAA,CAAM,QAAQ,CAAA;AACvC,EAAA,IAAI,CAAC,UAAA,EAAY;AACf,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,MAAA,EAAS,QAAQ,CAAA,oBAAA,CAAsB,CAAA;AAAA,EACzD;AAGA,EAAA,IAAI,YAAA;AACJ,EAAA,IAAI,UAAU,UAAA,CAAW,EAAA,IAAM,UAAA,CAAW,EAAA,CAAG,MAAM,CAAA,EAAG;AAEpD,IAAA,YAAA,GAAe,UAAA,CAAW,GAAG,MAAM,CAAA;AAAA,EACrC,CAAA,MAAO;AAEL,IAAA,YAAA,GAAe,YAAY,UAAU,CAAA;AAAA,EACvC;AAGA,EAAA,MAAM,kBAAA,GAA6C,EAAE,GAAG,YAAA,CAAa,kBAAA,EAAmB;AACxF,EAAA,MAAM,QAAA,GAAW,UAAA,CAAW,QAAA,IAAY,EAAC;AACzC,EAAA,KAAA,MAAW,SAAS,QAAA,EAAU;AAE5B,IAAA,KAAA,MAAW,CAAC,WAAW,WAAW,CAAA,IAAK,OAAO,OAAA,CAAQ,KAAA,CAAM,KAAK,CAAA,EAAG;AAClE,MAAA,IAAI,WAAA,CAAY,WAAW,CAAA,CAAE,QAAA,CAAS,KAAK,CAAA,EAAG;AAC5C,QAAA,MAAM,UAAA,GAAa,KAAA,CAAM,KAAA,CAAM,SAAS,CAAA;AACxC,QAAA,IAAI,YAAY,YAAA,EAAc;AAC5B,UAAA,kBAAA,CAAmB,KAAK,IAAI,UAAA,CAAW,YAAA;AAAA,QACzC;AACA,QAAA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,MAAM,WAAA,GAAgC;AAAA,IACpC,GAAG,YAAA;AAAA,IACH,MAAA,EAAQ,WAAA;AAAA,IACR,WAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,IACpC,WAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,IACpC,cAAA,EAAgB,aAAa,cAAA,GAAiB,CAAA;AAAA,IAC9C,SAAA,EAAW,aAAa,cAAA,GAAiB,CAAA;AAAA,IACzC,YAAA,EAAc,QAAA;AAAA,IACd,IAAA;AAAA,IACA,kBAAA;AAAA,IACA,KAAA,EAAO;AAAA,GACT;AAGA,EAAA,MAAM,UAAA,GAAa,CAAC,mBAAG,IAAI,GAAA,CAAI,CAAC,GAAG,KAAA,CAAM,gBAAA,EAAkB,GAAG,YAAY,CAAC,CAAC,CAAA;AAE5E,EAAA,OAAO;AAAA,IACL,GAAG,KAAA;AAAA,IACH,KAAA,EAAO,EAAE,GAAG,KAAA,CAAM,OAAO,CAAC,QAAQ,GAAG,WAAA,EAAY;AAAA,IACjD,gBAAA,EAAkB,UAAA;AAAA,IAClB,WAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA;AAAY,GACtC;AACF;AAOO,SAAS,gBAAA,CACd,KAAA,EACA,KAAA,EACA,QAAA,EACA,KAAA,EACgB;AAChB,EAAA,MAAM,YAAA,GAAe,KAAA,CAAM,KAAA,CAAM,QAAQ,KAAK,6BAAA,EAA8B;AAC5E,EAAA,MAAM,UAAA,GAAa,KAAA,CAAM,KAAA,CAAM,QAAQ,CAAA;AAGvC,EAAA,IAAI,YAAY,KAAA,EAAO;AACrB,IAAA,MAAM,UAAA,GAAa,aAAa,UAAA,GAAa,CAAA;AAC7C,IAAA,IAAI,UAAA,IAAc,UAAA,CAAW,KAAA,CAAM,YAAA,EAAc;AAE/C,MAAA,MAAMA,YAAAA,GAAgC;AAAA,QACpC,GAAG,YAAA;AAAA,QACH,MAAA,EAAQ,aAAA;AAAA,QACR,UAAA;AAAA,QACA,WAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,QACpC;AAAA,OACF;AACA,MAAA,OAAO;AAAA,QACL,GAAG,KAAA;AAAA,QACH,KAAA,EAAO,EAAE,GAAG,KAAA,CAAM,OAAO,CAAC,QAAQ,GAAGA,YAAAA,EAAY;AAAA,QACjD,WAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA;AAAY,OACtC;AAAA,IACF;AAAA,EACF;AAGA,EAAA,MAAM,WAAA,GAAgC;AAAA,IACpC,GAAG,YAAA;AAAA,IACH,MAAA,EAAQ,QAAA;AAAA,IACR,QAAA,EAAA,iBAAU,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,IACjC,WAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,IACpC,KAAA;AAAA,IACA,cAAA,EAAgB,aAAa,cAAA,GAAiB;AAAA,GAChD;AAGA,EAAA,IAAI,aAAa,KAAA,CAAM,gBAAA;AACvB,EAAA,IAAI,UAAA,EAAY,UAAA,IAAc,UAAA,CAAW,UAAA,CAAW,SAAS,CAAA,EAAG;AAC9D,IAAA,UAAA,GAAa,CAAC,mBAAG,IAAI,GAAA,CAAI,CAAC,GAAG,KAAA,CAAM,gBAAA,EAAkB,GAAG,UAAA,CAAW,UAAU,CAAC,CAAC,CAAA;AAAA,EACjF;AAGA,EAAA,IAAI,YAAY,eAAA,IAAmB,WAAA,CAAY,cAAA,IAAkB,UAAA,CAAW,gBAAgB,cAAA,EAAgB;AAC1G,IAAA,MAAM,WAAA,GAAc,WAAW,eAAA,CAAgB,QAAA;AAC/C,IAAA,UAAA,GAAa,CAAC,mBAAG,IAAI,GAAA,CAAI,CAAC,GAAG,UAAA,EAAY,GAAG,WAAW,CAAC,CAAC,CAAA;AAAA,EAC3D;AAEA,EAAA,OAAO;AAAA,IACL,GAAG,KAAA;AAAA,IACH,KAAA,EAAO,EAAE,GAAG,KAAA,CAAM,OAAO,CAAC,QAAQ,GAAG,WAAA,EAAY;AAAA,IACjD,gBAAA,EAAkB,UAAA;AAAA,IAClB,WAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA;AAAY,GACtC;AACF;AAKO,SAAS,iBAAA,CACd,KAAA,EACA,QAAA,EACA,OAAA,EACA,QAAA,EACgB;AAChB,EAAA,MAAM,YAAA,GAAe,KAAA,CAAM,KAAA,CAAM,QAAQ,KAAK,6BAAA,EAA8B;AAE5E,EAAA,MAAM,WAAA,GAAgC;AAAA,IACpC,GAAG,YAAA;AAAA,IACH,QAAA,EAAU,OAAO,QAAA,KAAa,QAAA,GAAW,WAAW,YAAA,CAAa,QAAA;AAAA,IACjE,QAAA,EAAU;AAAA,MACR,GAAI,YAAA,CAAa,QAAA,IAAY,EAAC;AAAA,MAC9B,GAAI,OAAA,GAAU,CAAC,EAAE,OAAA,EAAS,4BAAW,IAAI,IAAA,EAAK,EAAE,WAAA,IAAe,MAAA,EAAQ,YAAA,CAAa,MAAA,EAAQ,IAAI;AAAC,KACnG;AAAA,IACA,WAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA;AAAY,GACtC;AAEA,EAAA,OAAO;AAAA,IACL,GAAG,KAAA;AAAA,IACH,KAAA,EAAO,EAAE,GAAG,KAAA,CAAM,OAAO,CAAC,QAAQ,GAAG,WAAA,EAAY;AAAA,IACjD,WAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA;AAAY,GACtC;AACF;AASO,SAAS,gBAAA,CACd,OACA,QAAA,EACgB;AAChB,EAAA,MAAM,YAAA,GAAe,KAAA,CAAM,KAAA,CAAM,QAAQ,CAAA;AACzC,EAAA,IAAI,CAAC,cAAc,OAAO,KAAA;AAE1B,EAAA,MAAM,WAAA,GAAgC;AAAA,IACpC,GAAG,YAAA;AAAA,IACH,MAAA,EAAQ,aAAA;AAAA,IACR,SAAA,EAAW,MAAA;AAAA,IACX,WAAA,EAAa,MAAA;AAAA,IACb,QAAA,EAAU,MAAA;AAAA,IACV,KAAA,EAAO,MAAA;AAAA,IACP,IAAA,EAAM,MAAA;AAAA,IACN,QAAA,EAAU,IAAA;AAAA,IACV,WAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA;AAAY,GACtC;AAEA,EAAA,OAAO;AAAA,IACL,GAAG,KAAA;AAAA,IACH,KAAA,EAAO,EAAE,GAAG,KAAA,CAAM,OAAO,CAAC,QAAQ,GAAG,WAAA,EAAY;AAAA,IACjD,WAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA;AAAY,GACtC;AACF;AAEA,SAAS,6BAAA,GAAkD;AACzD,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,aAAA;AAAA,IACR,cAAA,EAAgB,CAAA;AAAA,IAChB,UAAA,EAAY,CAAA;AAAA,IACZ,SAAA,EAAW,CAAA;AAAA,IACX,UAAU,EAAC;AAAA,IACX,QAAA,EAAU;AAAA,GACZ;AACF;;;ACzKO,SAAS,UAAA,CAAW,MAAiB,KAAA,EAA8B;AACxE,EAAA,MAAM,EAAE,MAAA,EAAQ,KAAA,EAAM,GAAI,IAAA;AAG1B,EAAA,IAAI,iBAAiB,KAAA,IAAS,KAAA,CAAM,eAAe,KAAA,CAAM,WAAA,KAAgB,MAAM,WAAA,EAAa;AAC1F,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,IAAI,QAAA;AAEJ,EAAA,QAAQ,MAAM,IAAA;AAAM,IAClB,KAAK,cAAA;AACH,MAAA,QAAA,GAAW,cAAA,CAAe,KAAA,EAAO,KAAA,CAAM,QAAQ,CAAA;AAC/C,MAAA;AAAA,IAEF,KAAK,gBAAA;AACH,MAAA,QAAA,GAAW,mBAAA,CAAoB,KAAA,EAAO,MAAA,EAAQ,KAAA,CAAM,QAAA,EAAU,MAAM,MAAA,EAAQ,KAAA,CAAM,QAAA,EAAU,KAAA,CAAM,IAAI,CAAA;AACtG,MAAA;AAAA,IAEF,KAAK,aAAA;AACH,MAAA,QAAA,GAAW,iBAAiB,KAAA,EAAO,MAAA,EAAQ,KAAA,CAAM,QAAA,EAAU,MAAM,KAAK,CAAA;AACtE,MAAA;AAAA,IAEF,KAAK,eAAA;AACH,MAAA,QAAA,GAAW,kBAAkB,KAAA,EAAO,KAAA,CAAM,UAAU,KAAA,CAAM,OAAA,EAAS,MAAM,QAAQ,CAAA;AACjF,MAAA;AAAA,IAEF,KAAK,cAAA;AACH,MAAA,QAAA,GAAW,gBAAA,CAAiB,KAAA,EAAO,KAAA,CAAM,QAAQ,CAAA;AACjD,MAAA;AAAA,IAEF,KAAK,eAAA;AACH,MAAA,QAAA,GAAW;AAAA,QACT,GAAG,KAAA;AAAA,QACH,gBAAA,EAAkB,CAAC,mBAAG,IAAI,GAAA,CAAI,CAAC,GAAG,KAAA,CAAM,gBAAA,EAAkB,GAAG,KAAA,CAAM,MAAM,CAAC,CAAC,CAAA;AAAA,QAC3E,WAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA;AAAY,OACtC;AACA,MAAA;AAAA,IAEF,KAAK,cAAA;AACH,MAAA,QAAA,GAAW,gBAAA,CAAiB,KAAA,EAAO,KAAA,CAAM,MAAM,CAAA;AAC/C,MAAA;AAAA,IAEF;AACE,MAAA,OAAO,IAAA;AAAA;AAGX,EAAA,OAAO,EAAE,MAAA,EAAQ,KAAA,EAAO,QAAA,EAAS;AACnC;AA4VA,SAAS,gBAAA,CACP,OACA,MAAA,EACgB;AAChB,EAAA,MAAM,GAAA,GAAA,iBAAM,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AACnC,EAAA,QAAQ,MAAA;AAAQ,IACd,KAAK,MAAA;AACH,MAAA,OAAO,EAAE,GAAG,KAAA,EAAO,MAAA,EAAQ,SAAA,EAAW,aAAa,GAAA,EAAI;AAAA,IACzD,KAAK,OAAA;AACH,MAAA,OAAO,EAAE,GAAG,KAAA,EAAO,MAAA,EAAQ,QAAA,EAAU,aAAa,GAAA,EAAI;AAAA,IACxD,KAAK,QAAA;AACH,MAAA,OAAO,EAAE,GAAG,KAAA,EAAO,MAAA,EAAQ,SAAA,EAAW,aAAa,GAAA,EAAI;AAAA,IACzD;AACE,MAAA,OAAO,KAAA;AAAA;AAEb;;;AC/bA,IAAM,iBAAA,GAAoB,GAAA;AAE1B,IAAM,qBAAA,GAAwB,CAAA;;AAAA,+IAAA,CAAA;AAgBvB,SAAS,oBAAA,CACd,IAAA,EACA,OAAA,GAA4B,EAAC,EACrB;AACR,EAAA,MAAM,EAAE,KAAA,EAAO,OAAA,EAAS,YAAA,EAAa,GAAI,OAAA;AACzC,EAAA,MAAM,UAAA,GAAa,WAAA,CAAY,IAAA,CAAK,MAAM,CAAA;AAC1C,EAAA,MAAM,EAAE,OAAM,GAAI,IAAA;AAGlB,EAAA,MAAM,UAAA,GAAa,uBAAA,CAAwB,IAAA,EAAM,KAAK,CAAA;AAEtD,EAAA,IAAI,UAAA,CAAW,WAAW,CAAA,EAAG;AAC3B,IAAA,OAAO,EAAA;AAAA,EACT;AAEA,EAAA,MAAM,QAAkB,EAAC;AAGzB,EAAA,KAAA,CAAM,IAAA,CAAK,gBAAgB,qBAAqB,CAAA;AAChD,EAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AAGb,EAAA,KAAA,CAAM,KAAK,gBAAgB,CAAA;AAC3B,EAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,EAAA,KAAA,CAAM,IAAA,CAAK,CAAA,kBAAA,EAAqB,KAAA,CAAM,gBAAA,CAAiB,MAAA,GAAS,CAAA,GAAI,KAAA,CAAM,gBAAA,CAAiB,IAAA,CAAK,IAAI,CAAA,GAAI,QAAQ,CAAA,CAAE,CAAA;AAClH,EAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AAGb,EAAA,MAAM,cAAA,GAAiB,OAAO,OAAA,CAAQ,KAAA,CAAM,KAAK,CAAA,CAC9C,MAAA,CAAO,CAAC,CAAC,CAAA,EAAG,EAAE,CAAA,KAAM,EAAA,CAAG,WAAW,WAAW,CAAA,CAC7C,IAAI,CAAC,CAAC,IAAI,CAAA,KAAM,IAAI,CAAA;AACvB,EAAA,IAAI,cAAA,CAAe,SAAS,CAAA,EAAG;AAC7B,IAAA,KAAA,CAAM,KAAK,CAAA,iBAAA,EAAoB,cAAA,CAAe,IAAA,CAAK,IAAI,CAAC,CAAA,CAAE,CAAA;AAC1D,IAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AAAA,EACf;AAGA,EAAA,KAAA,CAAM,KAAK,qBAAqB,CAAA;AAChC,EAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AAEb,EAAA,KAAA,MAAW,YAAY,UAAA,EAAY;AACjC,IAAA,MAAM,UAAA,GAAa,WAAW,QAAQ,CAAA;AACtC,IAAA,MAAM,SAAA,GAAY,KAAA,CAAM,KAAA,CAAM,QAAQ,CAAA;AAEtC,IAAA,KAAA,CAAM,IAAA,CAAK,CAAA,IAAA,EAAO,QAAQ,CAAA,CAAE,CAAA;AAC5B,IAAA,IAAI,WAAW,WAAA,EAAa;AAC1B,MAAA,KAAA,CAAM,IAAA,CAAK,CAAA,aAAA,EAAgB,UAAA,CAAW,WAAW,CAAA,CAAE,CAAA;AAAA,IACrD;AAEA,IAAA,MAAM,QAAA,GAAW,YAAY,UAAU,CAAA;AACvC,IAAA,MAAM,QAAA,GAAW,YAAY,UAAU,CAAA;AACvC,IAAA,IAAI,QAAA,CAAS,MAAA,GAAS,CAAA,EAAG,KAAA,CAAM,IAAA,CAAK,aAAa,QAAA,CAAS,IAAA,CAAK,IAAI,CAAC,CAAA,CAAE,CAAA;AACtE,IAAA,IAAI,QAAA,CAAS,MAAA,GAAS,CAAA,EAAG,KAAA,CAAM,IAAA,CAAK,aAAa,QAAA,CAAS,IAAA,CAAK,IAAI,CAAC,CAAA,CAAE,CAAA;AACtE,IAAA,KAAA,CAAM,IAAA,CAAK,CAAA,gBAAA,EAAmB,SAAA,EAAW,MAAA,IAAU,aAAa,CAAA,CAAE,CAAA;AAGlE,IAAA,MAAM,QAAQ,UAAA,CAAW,SAAA;AACzB,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,IAAI,MAAM,QAAA,EAAU,KAAA,CAAM,KAAK,CAAA,qBAAA,EAAwB,KAAA,CAAM,QAAQ,CAAA,CAAE,CAAA;AACvE,MAAA,IAAI,KAAA,CAAM,QAAA,EAAU,MAAA,EAAQ,KAAA,CAAM,IAAA,CAAK,CAAA,UAAA,EAAa,KAAA,CAAM,QAAA,CAAS,IAAA,CAAK,IAAI,CAAC,CAAA,CAAE,CAAA;AAC/E,MAAA,IAAI,KAAA,CAAM,eAAA,EAAiB,MAAA,EAAQ,KAAA,CAAM,IAAA,CAAK,CAAA,kBAAA,EAAqB,KAAA,CAAM,eAAA,CAAgB,IAAA,CAAK,IAAI,CAAC,CAAA,CAAE,CAAA;AAAA,IACvG;AAEA,IAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AAAA,EACf;AAGA,EAAA,IAAI,OAAA,EAAS;AACX,IAAA,KAAA,CAAM,KAAK,kCAAkC,CAAA;AAC7C,IAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,IAAA,KAAA,CAAM,KAAK,OAAO,CAAA;AAClB,IAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AAAA,EACf;AAGA,EAAA,KAAA,CAAM,KAAK,oBAAoB,CAAA;AAC/B,EAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,EAAA,KAAA,CAAM,KAAK,2EAA2E,CAAA;AACtF,EAAA,KAAA,CAAM,KAAK,SAAS,CAAA;AACpB,EAAA,KAAA,CAAM,KAAK,GAAG,CAAA;AACd,EAAA,KAAA,CAAM,KAAK,KAAK,CAAA;AAChB,EAAA,KAAA,CAAM,KAAK,8BAA8B,CAAA;AACzC,EAAA,KAAA,CAAM,KAAK,+BAA+B,CAAA;AAC1C,EAAA,KAAA,CAAM,KAAK,gFAAgF,CAAA;AAC3F,EAAA,KAAA,CAAM,KAAK,KAAK,CAAA;AAChB,EAAA,KAAA,CAAM,KAAK,GAAG,CAAA;AACd,EAAA,KAAA,CAAM,KAAK,KAAK,CAAA;AAChB,EAAA,KAAA,CAAM,KAAK,EAAE,CAAA;AACb,EAAA,KAAA,CAAM,KAAK,QAAQ,CAAA;AACnB,EAAA,KAAA,CAAM,KAAK,0DAA0D,CAAA;AACrE,EAAA,KAAA,CAAM,KAAK,4EAA4E,CAAA;AACvF,EAAA,KAAA,CAAM,KAAK,8DAA8D,CAAA;AACzE,EAAA,KAAA,CAAM,KAAK,wEAAmE,CAAA;AAC9E,EAAA,KAAA,CAAM,KAAK,wDAAwD,CAAA;AAEnE,EAAA,OAAO,KAAA,CAAM,KAAK,IAAI,CAAA;AACxB;AAYA,eAAsB,gBAAA,CACpB,IAAA,EACA,OAAA,EACA,OAAA,GAA4B,EAAC,EACH;AAC1B,EAAkB,QAAQ,SAAA,IAAa;AACvC,EAAA,MAAM,aAAA,GAAgB,uBAAA,CAAwB,IAAA,EAAM,OAAA,CAAQ,KAAK,CAAA;AAGjE,EAAA,IAAI,aAAA,CAAc,WAAW,CAAA,EAAG;AAC9B,IAAA,OAAO,EAAE,WAAA,EAAa,EAAC,EAAG,UAAA,EAAY,IAAI,WAAA,EAAa,EAAA,EAAI,aAAA,EAAe,EAAC,EAAE;AAAA,EAC/E;AAEA,EAAA,MAAM,MAAA,GAAS,oBAAA,CAAqB,IAAA,EAAM,OAAO,CAAA;AACjD,EAAA,MAAM,WAAA,GAAc,MAAM,OAAA,CAAQ,OAAA,CAAQ,MAAM,CAAA;AAChD,EAAA,MAAM,WAAA,GAAc,sBAAA,CAAuB,WAAA,EAAa,aAAwB,CAAA;AAEhF,EAAA,OAAO;AAAA,IACL,WAAA;AAAA,IACA,UAAA,EAAY,MAAA;AAAA,IACZ,WAAA;AAAA,IACA;AAAA,GACF;AACF;AAeO,SAAS,eAAA,CACd,IAAA,EACA,MAAA,EACA,SAAA,GAAoB,iBAAA,EACT;AACX,EAAA,IAAI,OAAA,GAAU,IAAA;AAEd,EAAA,KAAA,MAAW,UAAA,IAAc,OAAO,WAAA,EAAa;AAC3C,IAAA,IAAI,UAAA,CAAW,aAAa,SAAA,EAAW;AAEvC,IAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,KAAA,CAAM,KAAA,CAAM,WAAW,QAAQ,CAAA;AACzD,IAAA,IAAI,CAAC,SAAA,EAAW;AAGhB,IAAA,IAAI,SAAA,CAAU,MAAA,KAAW,WAAA,IAAe,SAAA,CAAU,WAAW,SAAA,EAAW;AAGxE,IAAA,MAAM,GAAA,GAAA,iBAAM,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AACnC,IAAA,OAAA,GAAU,WAAW,OAAA,EAAS;AAAA,MAC5B,IAAA,EAAM,cAAA;AAAA,MACN,UAAU,UAAA,CAAW,QAAA;AAAA,MACrB,SAAA,EAAW;AAAA,KACZ,CAAA;AACD,IAAA,OAAA,GAAU,WAAW,OAAA,EAAS;AAAA,MAC5B,IAAA,EAAM,gBAAA;AAAA,MACN,UAAU,UAAA,CAAW,QAAA;AAAA,MACrB,SAAA,EAAW,GAAA;AAAA,MACX,MAAA,EAAQ;AAAA,KACT,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,OAAA;AACT;AAUA,eAAsB,aAAA,CACpB,IAAA,EACA,OAAA,EACA,OAAA,GAA4B,EAAC,EACC;AAC9B,EAAA,MAAM,SAAA,GAAY,QAAQ,SAAA,IAAa,iBAAA;AACvC,EAAA,MAAM,SAAA,GAAY,MAAM,gBAAA,CAAiB,IAAA,EAAM,SAAS,OAAO,CAAA;AAC/D,EAAA,MAAM,OAAA,GAAU,eAAA,CAAgB,IAAA,EAAM,SAAA,EAAW,SAAS,CAAA;AAE1D,EAAA,MAAM,UAAU,SAAA,CAAU,WAAA,CAAY,OAAO,CAAA,CAAA,KAAK,CAAA,CAAE,cAAc,SAAS,CAAA;AAC3E,EAAA,MAAM,UAAU,SAAA,CAAU,WAAA,CAAY,OAAO,CAAA,CAAA,KAAK,CAAA,CAAE,aAAa,SAAS,CAAA;AAE1E,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,OAAA;AAAA,IACN,SAAA;AAAA,IACA,OAAA;AAAA,IACA;AAAA,GACF;AACF;AAWA,SAAS,uBAAA,CAAwB,MAAiB,KAAA,EAA4B;AAC5E,EAAA,MAAM,UAAA,GAAa,WAAA,CAAY,IAAA,CAAK,MAAM,CAAA;AAC1C,EAAA,MAAM,EAAE,OAAM,GAAI,IAAA;AAElB,EAAA,MAAM,aAAuB,EAAC;AAE9B,EAAA,KAAA,MAAW,CAAC,IAAA,EAAM,MAAM,KAAK,MAAA,CAAO,OAAA,CAAQ,UAAU,CAAA,EAAG;AACvD,IAAA,MAAM,SAAA,GAAY,KAAA,CAAM,KAAA,CAAM,IAAI,CAAA;AAGlC,IAAA,IAAI,SAAA,EAAW,MAAA,KAAW,WAAA,IAAe,SAAA,EAAW,WAAW,SAAA,EAAW;AAE1E,IAAA,IAAI,KAAA,EAAO;AAET,MAAA,IAAI,MAAM,QAAA,CAAS,IAAI,CAAA,EAAG,UAAA,CAAW,KAAK,IAAI,CAAA;AAAA,IAChD,CAAA,MAAO;AAEL,MAAA,IAAI,MAAA,CAAO,SAAA,EAAW,cAAA,EAAgB,UAAA,CAAW,KAAK,IAAI,CAAA;AAAA,IAC5D;AAAA,EACF;AAEA,EAAA,OAAO,UAAA;AACT;AAMA,SAAS,sBAAA,CACP,WAAA,EACA,UAAA,EACA,UAAA,EACsB;AACtB,EAAA,MAAM,QAAA,GAAW,IAAI,GAAA,CAAI,UAAU,CAAA;AAEnC,EAAA,IAAI;AAEF,IAAA,MAAM,OAAA,GAAU,YAAY,WAAW,CAAA;AACvC,IAAA,IAAI,CAAC,OAAA,EAAS,OAAO,EAAC;AAEtB,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,OAAO,CAAA;AAGjC,IAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,SAAU,EAAC;AAEpC,IAAA,MAAM,cAAoC,EAAC;AAE3C,IAAA,KAAA,MAAW,QAAQ,MAAA,EAAQ;AAEzB,MAAA,IAAI,CAAC,IAAA,IAAQ,OAAO,IAAA,KAAS,QAAA,EAAU;AACvC,MAAA,IAAI,OAAO,IAAA,CAAK,QAAA,KAAa,QAAA,EAAU;AACvC,MAAA,IAAI,OAAO,IAAA,CAAK,UAAA,KAAe,QAAA,EAAU;AAGzC,MAAA,IAAI,CAAC,QAAA,CAAS,GAAA,CAAI,IAAA,CAAK,QAAQ,CAAA,EAAG;AAGlC,MAAA,MAAM,UAAA,GAAa,KAAK,GAAA,CAAI,CAAA,EAAG,KAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,UAAU,CAAC,CAAA;AAE3D,MAAA,WAAA,CAAY,IAAA,CAAK;AAAA,QACf,UAAU,IAAA,CAAK,QAAA;AAAA,QACf,UAAA;AAAA,QACA,WAAW,OAAO,IAAA,CAAK,SAAA,KAAc,QAAA,GAAW,KAAK,SAAA,GAAY,EAAA;AAAA,QACjE,eAAA,EAAiB;AAAA,OAClB,CAAA;AAAA,IACH;AAEA,IAAA,OAAO,WAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AAEN,IAAA,OAAO,EAAC;AAAA,EACV;AACF;AAMA,SAAS,YAAY,IAAA,EAA6B;AAChD,EAAA,IAAI,CAAC,IAAA,IAAQ,OAAO,IAAA,KAAS,UAAU,OAAO,IAAA;AAE9C,EAAA,MAAM,OAAA,GAAU,KAAK,IAAA,EAAK;AAG1B,EAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,KAAA,CAAM,uCAAuC,CAAA;AACxE,EAAA,IAAI,UAAA,EAAY,OAAO,UAAA,CAAW,CAAC,EAAE,IAAA,EAAK;AAG1C,EAAA,MAAM,YAAA,GAAe,OAAA,CAAQ,OAAA,CAAQ,GAAG,CAAA;AACxC,EAAA,MAAM,WAAA,GAAc,OAAA,CAAQ,WAAA,CAAY,GAAG,CAAA;AAC3C,EAAA,IAAI,YAAA,KAAiB,EAAA,IAAM,WAAA,GAAc,YAAA,EAAc;AACrD,IAAA,OAAO,OAAA,CAAQ,KAAA,CAAM,YAAA,EAAc,WAAA,GAAc,CAAC,CAAA;AAAA,EACpD;AAGA,EAAA,IAAI,OAAA,CAAQ,UAAA,CAAW,GAAG,CAAA,EAAG,OAAO,OAAA;AAEpC,EAAA,OAAO,IAAA;AACT;AC9RO,SAAS,iBAAiB,IAAA,EAA2C;AAC1E,EAAA,MAAM,OAAA,GAAU,KAAK,OAAA,IAAW,GAAA;AAEhC,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,CAAC,MAAA,KAAoC;AAC5C,MAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,QAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,CAAK,MAAM,CAAA;AAE7B,QAAA,MAAM,KAAA,GAAQ,QAAA;AAAA,UACZ,IAAA,CAAK,OAAA;AAAA,UACL,IAAA,CAAK,KAAA,GAAQ,IAAA,CAAK,IAAA,CAAK,EAAE,CAAA,GAAI,IAAA;AAAA,UAC7B;AAAA,YACE,OAAA;AAAA,YACA,KAAK,IAAA,CAAK,GAAA;AAAA,YACV,GAAA,EAAK,IAAA,CAAK,GAAA,GAAM,EAAE,GAAG,QAAQ,GAAA,EAAK,GAAG,IAAA,CAAK,GAAA,EAAI,GAAI,MAAA;AAAA,YAClD,SAAA,EAAW,KAAK,IAAA,GAAO;AAAA;AAAA,WACzB;AAAA,UACA,CAAC,KAAA,EAAO,MAAA,EAAQ,MAAA,KAAW;AACzB,YAAA,IAAI,KAAA,EAAO;AACT,cAAA,MAAA,CAAO,IAAI,KAAA;AAAA,gBACT,CAAA,oBAAA,EAAuB,KAAK,OAAO,CAAA,aAAA,EAAgB,MAAM,IAAA,IAAQ,OAAO,MACvE,MAAA,GAAS;AAAA,QAAA,EAAa,OAAO,KAAA,CAAM,CAAA,EAAG,GAAG,CAAC,KAAK,EAAA,CAAA,GAChD;AAAA,EAAK,MAAM,OAAO,CAAA;AAAA,eACnB,CAAA;AAAA,YACH,CAAA,MAAO;AACL,cAAA,OAAA,CAAQ,MAAM,CAAA;AAAA,YAChB;AAAA,UACF;AAAA,SACF;AAGA,QAAA,IAAI,IAAA,CAAK,KAAA,IAAS,KAAA,CAAM,KAAA,EAAO;AAC7B,UAAA,KAAA,CAAM,KAAA,CAAM,MAAM,MAAM,CAAA;AACxB,UAAA,KAAA,CAAM,MAAM,GAAA,EAAI;AAAA,QAClB;AAAA,MACF,CAAC,CAAA;AAAA,IACH;AAAA,GACF;AACF;AA2CO,SAAS,kBAAkB,IAAA,EAA4C;AAC5E,EAAA,MAAM,OAAA,GAAU,KAAK,OAAA,IAAW,GAAA;AAEhC,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,OAAO,MAAA,KAAoC;AAClD,MAAA,MAAM,IAAA,GAAO,KAAK,SAAA,GAAY,IAAA,CAAK,UAAU,MAAM,CAAA,GAAI,EAAE,MAAA,EAAO;AAEhE,MAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,MAAA,MAAM,QAAQ,UAAA,CAAW,MAAM,UAAA,CAAW,KAAA,IAAS,OAAO,CAAA;AAE1D,MAAA,IAAI;AACF,QAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,IAAA,CAAK,GAAA,EAAK;AAAA,UACrC,MAAA,EAAQ,MAAA;AAAA,UACR,OAAA,EAAS;AAAA,YACP,cAAA,EAAgB,kBAAA;AAAA,YAChB,GAAI,IAAA,CAAK,OAAA,IAAW;AAAC,WACvB;AAAA,UACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,IAAI,CAAA;AAAA,UACzB,QAAQ,UAAA,CAAW;AAAA,SACpB,CAAA;AAED,QAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,UAAA,MAAM,OAAO,MAAM,QAAA,CAAS,MAAK,CAAE,KAAA,CAAM,MAAM,EAAE,CAAA;AACjD,UAAA,MAAM,IAAI,KAAA,CAAM,CAAA,KAAA,EAAQ,QAAA,CAAS,MAAM,CAAA,EAAA,EAAK,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,GAAG,CAAC,CAAA,CAAE,CAAA;AAAA,QAClE;AAEA,QAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AAEjC,QAAA,IAAI,KAAK,eAAA,EAAiB;AACxB,UAAA,OAAO,IAAA,CAAK,gBAAgB,IAAI,CAAA;AAAA,QAClC;AAGA,QAAA,IAAI,OAAO,IAAA,CAAK,QAAA,KAAa,QAAA,SAAiB,IAAA,CAAK,QAAA;AACnD,QAAA,IAAI,OAAO,IAAA,CAAK,IAAA,KAAS,QAAA,SAAiB,IAAA,CAAK,IAAA;AAC/C,QAAA,IAAI,OAAO,IAAA,CAAK,OAAA,KAAY,QAAA,SAAiB,IAAA,CAAK,OAAA;AAClD,QAAA,OAAO,IAAA,CAAK,UAAU,IAAI,CAAA;AAAA,MAC5B,CAAA,SAAE;AACA,QAAA,YAAA,CAAa,KAAK,CAAA;AAAA,MACpB;AAAA,IACF;AAAA,GACF;AACF","file":"index.js","sourcesContent":["/**\n * Event Graph — Graph Helpers\n *\n * Pure functions for manipulating the requires/provides task dependency graph.\n * No I/O, no side effects.\n */\n\nimport type { GraphConfig, TaskConfig, GraphEngineStore, ExecutionState, RefreshStrategy } from './types.js';\nimport { TASK_STATUS } from './constants.js';\n\n// ============================================================================\n// Accessors — normalize requires/provides to always be arrays\n// ============================================================================\n\nexport function getProvides(task: TaskConfig | undefined): string[] {\n if (!task) return [];\n if (Array.isArray(task.provides)) return task.provides;\n return [];\n}\n\nexport function getRequires(task: TaskConfig | undefined): string[] {\n if (!task) return [];\n if (Array.isArray(task.requires)) return task.requires;\n return [];\n}\n\nexport function getAllTasks(graph: GraphConfig): Record<string, TaskConfig> {\n return graph.tasks ?? {};\n}\n\nexport function getTask(graph: GraphConfig, taskName: string): TaskConfig | undefined {\n return graph.tasks[taskName];\n}\n\nexport function hasTask(graph: GraphConfig, taskName: string): boolean {\n return taskName in graph.tasks;\n}\n\n// ============================================================================\n// Task State Predicates\n// ============================================================================\n\nexport function isNonActiveTask(taskState: GraphEngineStore | undefined): boolean {\n if (!taskState) return false;\n return taskState.status === TASK_STATUS.FAILED || taskState.status === TASK_STATUS.INACTIVATED;\n}\n\nexport function isTaskCompleted(taskState: GraphEngineStore | undefined): boolean {\n return taskState?.status === TASK_STATUS.COMPLETED;\n}\n\nexport function isTaskRunning(taskState: GraphEngineStore | undefined): boolean {\n return taskState?.status === TASK_STATUS.RUNNING;\n}\n\nexport function getRefreshStrategy(taskConfig: TaskConfig, graphSettings?: { refreshStrategy?: RefreshStrategy }): RefreshStrategy {\n return taskConfig.refreshStrategy ?? graphSettings?.refreshStrategy ?? 'data-changed';\n}\n\nexport function isRerunnable(taskConfig: TaskConfig, graphSettings?: { refreshStrategy?: RefreshStrategy }): boolean {\n return getRefreshStrategy(taskConfig, graphSettings) !== 'once';\n}\n\nexport function getMaxExecutions(taskConfig: TaskConfig): number | undefined {\n return taskConfig.maxExecutions;\n}\n\n// ============================================================================\n// Available Outputs Computation\n// ============================================================================\n\n/**\n * Dynamically compute available outputs from all completed tasks.\n * Tasks with strategies other than 'once' may have completed and reset.\n * Pure function.\n */\nexport function computeAvailableOutputs(\n graph: GraphConfig,\n taskStates: Record<string, GraphEngineStore>\n): string[] {\n const outputs: Set<string> = new Set();\n\n for (const [taskName, taskState] of Object.entries(taskStates)) {\n if (taskState.status === TASK_STATUS.COMPLETED) {\n const taskConfig = graph.tasks[taskName];\n if (taskConfig) {\n const provides = getProvides(taskConfig);\n provides.forEach(output => outputs.add(output));\n }\n }\n }\n\n return Array.from(outputs);\n}\n\n// ============================================================================\n// Conflict Detection\n// ============================================================================\n\n/**\n * Group candidate tasks by the outputs they provide.\n * Used to detect conflicts (multiple tasks providing the same output).\n */\nexport function groupTasksByProvides(\n candidateTaskNames: string[],\n tasks: Record<string, TaskConfig>\n): Record<string, string[]> {\n const outputGroups: Record<string, string[]> = {};\n\n candidateTaskNames.forEach(taskName => {\n const task = tasks[taskName];\n if (!task) return;\n const provides = getProvides(task);\n provides.forEach(output => {\n if (!outputGroups[output]) {\n outputGroups[output] = [];\n }\n outputGroups[output].push(taskName);\n });\n });\n\n return outputGroups;\n}\n\n/**\n * Check if a task's outputs conflict with other candidates.\n */\nexport function hasOutputConflict(\n taskName: string,\n taskProvides: string[],\n candidates: string[],\n tasks: Record<string, TaskConfig>\n): boolean {\n for (const otherName of candidates) {\n if (otherName === taskName) continue;\n const otherProvides = getProvides(tasks[otherName]);\n const overlapping = taskProvides.some(output => otherProvides.includes(output));\n if (overlapping) return true;\n }\n return false;\n}\n\n// ============================================================================\n// Immutable Graph Mutation\n// ============================================================================\n\nexport function addKeyToProvides(task: TaskConfig, key: string): TaskConfig {\n const current = getProvides(task);\n if (current.includes(key)) return task;\n return { ...task, provides: [...current, key] };\n}\n\nexport function removeKeyFromProvides(task: TaskConfig, key: string): TaskConfig {\n const current = getProvides(task);\n return { ...task, provides: current.filter(p => p !== key) };\n}\n\nexport function addKeyToRequires(task: TaskConfig, key: string): TaskConfig {\n const current = getRequires(task);\n if (current.includes(key)) return task;\n return { ...task, requires: [...current, key] };\n}\n\nexport function removeKeyFromRequires(task: TaskConfig, key: string): TaskConfig {\n const current = getRequires(task);\n return { ...task, requires: current.filter(r => r !== key) };\n}\n\n// ============================================================================\n// Dynamic Task Management\n// ============================================================================\n\n/**\n * Add a new task to a graph config. Returns a new GraphConfig (immutable).\n */\nexport function addDynamicTask(\n graph: GraphConfig,\n taskName: string,\n taskConfig: TaskConfig\n): GraphConfig {\n return {\n ...graph,\n tasks: {\n ...graph.tasks,\n [taskName]: taskConfig,\n },\n };\n}\n\n/**\n * Create default task state for a new task.\n */\nexport function createDefaultGraphEngineStore(): GraphEngineStore {\n return {\n status: 'not-started',\n executionCount: 0,\n retryCount: 0,\n lastEpoch: 0,\n messages: [],\n progress: null,\n };\n}\n\n/**\n * Create the initial execution state for a graph.\n */\nexport function createInitialExecutionState(\n graph: GraphConfig,\n executionId: string\n): ExecutionState {\n const tasks: Record<string, GraphEngineStore> = {};\n for (const taskName of Object.keys(graph.tasks)) {\n tasks[taskName] = createDefaultGraphEngineStore();\n }\n\n return {\n status: 'running',\n tasks,\n availableOutputs: [],\n stuckDetection: { is_stuck: false, stuck_description: null, outputs_unresolvable: [], tasks_blocked: [] },\n lastUpdated: new Date().toISOString(),\n executionId,\n executionConfig: {\n executionMode: graph.settings.execution_mode ?? 'eligibility-mode',\n conflictStrategy: graph.settings.conflict_strategy ?? 'alphabetical',\n completionStrategy: graph.settings.completion,\n },\n };\n}\n","/**\n * Event Graph — Task State Transitions\n *\n * Pure functions for applying task lifecycle events to execution state.\n * Each function: f(state, ...) → newState\n */\n\nimport type { ExecutionState, GraphEngineStore, GraphConfig } from './types.js';\nimport { getProvides } from './graph-helpers.js';\n\n/**\n * Apply task start to execution state. Pure function.\n */\nexport function applyTaskStart(state: ExecutionState, taskName: string): ExecutionState {\n const existingTask = state.tasks[taskName] ?? createDefaultGraphEngineStore();\n\n const updatedTask: GraphEngineStore = {\n ...existingTask,\n status: 'running',\n startedAt: new Date().toISOString(),\n lastUpdated: new Date().toISOString(),\n progress: 0,\n error: undefined,\n };\n\n return {\n ...state,\n tasks: { ...state.tasks, [taskName]: updatedTask },\n lastUpdated: new Date().toISOString(),\n };\n}\n\n/**\n * Apply task completion to execution state.\n * Handles: default provides, conditional provides (on), refresh strategy, data hash tracking.\n * Pure function.\n */\nexport function applyTaskCompletion(\n state: ExecutionState,\n graph: GraphConfig,\n taskName: string,\n result?: string,\n dataHash?: string,\n data?: Record<string, unknown>\n): ExecutionState {\n const existingTask = state.tasks[taskName] ?? createDefaultGraphEngineStore();\n const taskConfig = graph.tasks[taskName];\n if (!taskConfig) {\n throw new Error(`Task \"${taskName}\" not found in graph`);\n }\n\n // Determine which outputs to produce\n let outputTokens: string[];\n if (result && taskConfig.on && taskConfig.on[result]) {\n // Conditional routing — use the on[result] provides\n outputTokens = taskConfig.on[result];\n } else {\n // Default provides\n outputTokens = getProvides(taskConfig);\n }\n\n // Build lastConsumedHashes: snapshot the data hashes of all upstream tasks\n const lastConsumedHashes: Record<string, string> = { ...existingTask.lastConsumedHashes };\n const requires = taskConfig.requires ?? [];\n for (const token of requires) {\n // Find the task that provides this token and grab its hash\n for (const [otherName, otherConfig] of Object.entries(graph.tasks)) {\n if (getProvides(otherConfig).includes(token)) {\n const otherState = state.tasks[otherName];\n if (otherState?.lastDataHash) {\n lastConsumedHashes[token] = otherState.lastDataHash;\n }\n break;\n }\n }\n }\n\n const updatedTask: GraphEngineStore = {\n ...existingTask,\n status: 'completed',\n completedAt: new Date().toISOString(),\n lastUpdated: new Date().toISOString(),\n executionCount: existingTask.executionCount + 1,\n lastEpoch: existingTask.executionCount + 1,\n lastDataHash: dataHash,\n data,\n lastConsumedHashes,\n error: undefined,\n };\n\n // Merge new outputs with existing available outputs\n const newOutputs = [...new Set([...state.availableOutputs, ...outputTokens])];\n\n return {\n ...state,\n tasks: { ...state.tasks, [taskName]: updatedTask },\n availableOutputs: newOutputs,\n lastUpdated: new Date().toISOString(),\n };\n}\n\n/**\n * Apply task failure to execution state.\n * Handles: retry logic, on_failure token injection, circuit breaker.\n * Pure function.\n */\nexport function applyTaskFailure(\n state: ExecutionState,\n graph: GraphConfig,\n taskName: string,\n error: string\n): ExecutionState {\n const existingTask = state.tasks[taskName] ?? createDefaultGraphEngineStore();\n const taskConfig = graph.tasks[taskName];\n\n // Check retry\n if (taskConfig?.retry) {\n const retryCount = existingTask.retryCount + 1;\n if (retryCount <= taskConfig.retry.max_attempts) {\n // Retry — set back to not-started with incremented retry count\n const updatedTask: GraphEngineStore = {\n ...existingTask,\n status: 'not-started',\n retryCount,\n lastUpdated: new Date().toISOString(),\n error,\n };\n return {\n ...state,\n tasks: { ...state.tasks, [taskName]: updatedTask },\n lastUpdated: new Date().toISOString(),\n };\n }\n }\n\n // No more retries — mark as failed\n const updatedTask: GraphEngineStore = {\n ...existingTask,\n status: 'failed',\n failedAt: new Date().toISOString(),\n lastUpdated: new Date().toISOString(),\n error,\n executionCount: existingTask.executionCount + 1,\n };\n\n // Inject failure tokens if configured\n let newOutputs = state.availableOutputs;\n if (taskConfig?.on_failure && taskConfig.on_failure.length > 0) {\n newOutputs = [...new Set([...state.availableOutputs, ...taskConfig.on_failure])];\n }\n\n // Check circuit breaker\n if (taskConfig?.circuit_breaker && updatedTask.executionCount >= taskConfig.circuit_breaker.max_executions) {\n const breakTokens = taskConfig.circuit_breaker.on_break;\n newOutputs = [...new Set([...newOutputs, ...breakTokens])];\n }\n\n return {\n ...state,\n tasks: { ...state.tasks, [taskName]: updatedTask },\n availableOutputs: newOutputs,\n lastUpdated: new Date().toISOString(),\n };\n}\n\n/**\n * Apply task progress update. Pure function.\n */\nexport function applyTaskProgress(\n state: ExecutionState,\n taskName: string,\n message?: string,\n progress?: number\n): ExecutionState {\n const existingTask = state.tasks[taskName] ?? createDefaultGraphEngineStore();\n\n const updatedTask: GraphEngineStore = {\n ...existingTask,\n progress: typeof progress === 'number' ? progress : existingTask.progress,\n messages: [\n ...(existingTask.messages ?? []),\n ...(message ? [{ message, timestamp: new Date().toISOString(), status: existingTask.status }] : []),\n ],\n lastUpdated: new Date().toISOString(),\n };\n\n return {\n ...state,\n tasks: { ...state.tasks, [taskName]: updatedTask },\n lastUpdated: new Date().toISOString(),\n };\n}\n\n/**\n * Apply task restart to execution state.\n * Resets the task to not-started, preserving executionCount and lastEpoch\n * (history). Clears data, error, progress. The task becomes eligible for\n * scheduling again on the next drain cycle.\n * Pure function.\n */\nexport function applyTaskRestart(\n state: ExecutionState,\n taskName: string,\n): ExecutionState {\n const existingTask = state.tasks[taskName];\n if (!existingTask) return state;\n\n const updatedTask: GraphEngineStore = {\n ...existingTask,\n status: 'not-started',\n startedAt: undefined,\n completedAt: undefined,\n failedAt: undefined,\n error: undefined,\n data: undefined,\n progress: null,\n lastUpdated: new Date().toISOString(),\n };\n\n return {\n ...state,\n tasks: { ...state.tasks, [taskName]: updatedTask },\n lastUpdated: new Date().toISOString(),\n };\n}\n\nfunction createDefaultGraphEngineStore(): GraphEngineStore {\n return {\n status: 'not-started',\n executionCount: 0,\n retryCount: 0,\n lastEpoch: 0,\n messages: [],\n progress: null,\n };\n}\n","/**\n * Continuous Event Graph — Core\n *\n * All functions are pure: f(LiveGraph, input) → LiveGraph\n *\n * - createLiveGraph: bootstrap from a GraphConfig\n * - applyEvent: reduce an event (task-started, task-completed, etc.)\n * - addNode / removeNode: structural graph mutations\n * - addRequires / removeRequires / addProvides / removeProvides: wiring mutations\n */\n\nimport type { GraphConfig, TaskConfig, GraphEvent, LiveGraph, NodeInfo, LiveGraphSnapshot } from './types.js';\nimport type { ExecutionState, GraphEngineStore } from '../event-graph/types.js';\nimport { getProvides, getRequires } from '../event-graph/graph-helpers.js';\nimport {\n applyTaskStart,\n applyTaskCompletion,\n applyTaskFailure,\n applyTaskProgress,\n applyTaskRestart,\n} from '../event-graph/task-transitions.js';\n\n// ============================================================================\n// Create\n// ============================================================================\n\n/**\n * Create a LiveGraph from a GraphConfig.\n * Initialises execution state for all tasks in the config.\n */\nexport function createLiveGraph(config: GraphConfig, executionId?: string): LiveGraph {\n const id = executionId ?? `live-${Date.now()}`;\n const tasks: Record<string, GraphEngineStore> = {};\n\n for (const taskName of Object.keys(config.tasks)) {\n tasks[taskName] = createDefaultGraphEngineStore();\n }\n\n const state: ExecutionState = {\n status: 'running',\n tasks,\n availableOutputs: [],\n stuckDetection: { is_stuck: false, stuck_description: null, outputs_unresolvable: [], tasks_blocked: [] },\n lastUpdated: new Date().toISOString(),\n executionId: id,\n executionConfig: {\n executionMode: config.settings.execution_mode ?? 'eligibility-mode',\n conflictStrategy: config.settings.conflict_strategy ?? 'alphabetical',\n completionStrategy: config.settings.completion,\n },\n };\n\n return { config, state };\n}\n\n// ============================================================================\n// Event Reducer\n// ============================================================================\n\n/**\n * Apply an execution event to the LiveGraph, producing a new LiveGraph.\n * Events are the shared vocabulary: task-started, task-completed, task-failed,\n * task-progress, inject-tokens, agent-action.\n *\n * Config is NOT mutated by events — only state changes.\n */\nexport function applyEvent(live: LiveGraph, event: GraphEvent): LiveGraph {\n const { config, state } = live;\n\n // Ghost event filtering\n if ('executionId' in event && event.executionId && event.executionId !== state.executionId) {\n return live;\n }\n\n let newState: ExecutionState;\n\n switch (event.type) {\n case 'task-started':\n newState = applyTaskStart(state, event.taskName);\n break;\n\n case 'task-completed':\n newState = applyTaskCompletion(state, config, event.taskName, event.result, event.dataHash, event.data);\n break;\n\n case 'task-failed':\n newState = applyTaskFailure(state, config, event.taskName, event.error);\n break;\n\n case 'task-progress':\n newState = applyTaskProgress(state, event.taskName, event.message, event.progress);\n break;\n\n case 'task-restart':\n newState = applyTaskRestart(state, event.taskName);\n break;\n\n case 'inject-tokens':\n newState = {\n ...state,\n availableOutputs: [...new Set([...state.availableOutputs, ...event.tokens])],\n lastUpdated: new Date().toISOString(),\n };\n break;\n\n case 'agent-action':\n newState = applyAgentAction(state, event.action);\n break;\n\n default:\n return live;\n }\n\n return { config, state: newState };\n}\n\n/**\n * Apply multiple events atomically to a LiveGraph.\n * Events are reduced sequentially, but the caller only sees the final state.\n * Use this for batch processing (e.g. draining a journal of pending events).\n */\nexport function applyEvents(live: LiveGraph, events: GraphEvent[]): LiveGraph {\n return events.reduce((current, event) => applyEvent(current, event), live);\n}\n\n// ============================================================================\n// Graph Mutations — node-level\n// ============================================================================\n\n/**\n * Add a node (task) to the live graph. Updates both config and state atomically.\n * If the node already exists, returns the graph unchanged.\n */\nexport function addNode(live: LiveGraph, name: string, taskConfig: TaskConfig): LiveGraph {\n if (live.config.tasks[name]) return live;\n\n return {\n config: {\n ...live.config,\n tasks: { ...live.config.tasks, [name]: taskConfig },\n },\n state: {\n ...live.state,\n tasks: { ...live.state.tasks, [name]: createDefaultGraphEngineStore() },\n lastUpdated: new Date().toISOString(),\n },\n };\n}\n\n/**\n * Remove a node (task) from the live graph. Updates both config and state atomically.\n * If the node doesn't exist, returns the graph unchanged.\n * NOTE: Does not clean up references — other nodes' requires/provides are left intact.\n * The caller can use removeRequires() to clean up if needed.\n */\nexport function removeNode(live: LiveGraph, name: string): LiveGraph {\n if (!live.config.tasks[name]) return live;\n\n const { [name]: _removedConfig, ...remainingTasks } = live.config.tasks;\n const { [name]: _removedState, ...remainingStates } = live.state.tasks;\n\n return {\n config: {\n ...live.config,\n tasks: remainingTasks,\n },\n state: {\n ...live.state,\n tasks: remainingStates,\n lastUpdated: new Date().toISOString(),\n },\n };\n}\n\n// ============================================================================\n// Graph Mutations — wiring\n// ============================================================================\n\n/**\n * Add requires tokens to a node. If the node doesn't exist, returns unchanged.\n * Deduplicates — won't add tokens already in requires.\n */\nexport function addRequires(live: LiveGraph, nodeName: string, tokens: string[]): LiveGraph {\n const task = live.config.tasks[nodeName];\n if (!task) return live;\n\n const current = getRequires(task);\n const toAdd = tokens.filter(t => !current.includes(t));\n if (toAdd.length === 0) return live;\n\n return {\n config: {\n ...live.config,\n tasks: {\n ...live.config.tasks,\n [nodeName]: { ...task, requires: [...current, ...toAdd] },\n },\n },\n state: live.state,\n };\n}\n\n/**\n * Remove requires tokens from a node. If the node doesn't exist, returns unchanged.\n */\nexport function removeRequires(live: LiveGraph, nodeName: string, tokens: string[]): LiveGraph {\n const task = live.config.tasks[nodeName];\n if (!task) return live;\n\n const current = getRequires(task);\n const remaining = current.filter(t => !tokens.includes(t));\n if (remaining.length === current.length) return live;\n\n return {\n config: {\n ...live.config,\n tasks: {\n ...live.config.tasks,\n [nodeName]: { ...task, requires: remaining },\n },\n },\n state: live.state,\n };\n}\n\n/**\n * Add provides tokens to a node. If the node doesn't exist, returns unchanged.\n * Deduplicates — won't add tokens already in provides.\n */\nexport function addProvides(live: LiveGraph, nodeName: string, tokens: string[]): LiveGraph {\n const task = live.config.tasks[nodeName];\n if (!task) return live;\n\n const current = getProvides(task);\n const toAdd = tokens.filter(t => !current.includes(t));\n if (toAdd.length === 0) return live;\n\n return {\n config: {\n ...live.config,\n tasks: {\n ...live.config.tasks,\n [nodeName]: { ...task, provides: [...current, ...toAdd] },\n },\n },\n state: live.state,\n };\n}\n\n/**\n * Remove provides tokens from a node. If the node doesn't exist, returns unchanged.\n */\nexport function removeProvides(live: LiveGraph, nodeName: string, tokens: string[]): LiveGraph {\n const task = live.config.tasks[nodeName];\n if (!task) return live;\n\n const current = getProvides(task);\n const remaining = current.filter(t => !tokens.includes(t));\n if (remaining.length === current.length) return live;\n\n return {\n config: {\n ...live.config,\n tasks: {\n ...live.config.tasks,\n [nodeName]: { ...task, provides: remaining },\n },\n },\n state: live.state,\n };\n}\n\n// ============================================================================\n// Convenience — inject tokens via mutation (sugar over applyEvent)\n// ============================================================================\n\n/**\n * Inject tokens into the live graph's available outputs.\n * Equivalent to applyEvent(live, { type: 'inject-tokens', tokens, timestamp }).\n */\nexport function injectTokens(live: LiveGraph, tokens: string[]): LiveGraph {\n return applyEvent(live, {\n type: 'inject-tokens',\n tokens,\n timestamp: new Date().toISOString(),\n });\n}\n\n/**\n * Drain (remove) tokens from the live graph's available outputs.\n * Inverse of injectTokens — useful for expiring stale data or revoking signals.\n * Tokens that aren't currently available are silently ignored.\n * Pure function.\n */\nexport function drainTokens(live: LiveGraph, tokens: string[]): LiveGraph {\n const toRemove = new Set(tokens);\n const remaining = live.state.availableOutputs.filter(t => !toRemove.has(t));\n\n if (remaining.length === live.state.availableOutputs.length) return live;\n\n return {\n config: live.config,\n state: {\n ...live.state,\n availableOutputs: remaining,\n lastUpdated: new Date().toISOString(),\n },\n };\n}\n\n// ============================================================================\n// Node lifecycle\n// ============================================================================\n\n/**\n * Reset a node's state back to not-started, clearing error, retry count, progress.\n * Config is untouched. Useful when a failed task should be retried later.\n * If the node doesn't exist, returns unchanged.\n */\nexport function resetNode(live: LiveGraph, name: string): LiveGraph {\n if (!live.config.tasks[name] || !live.state.tasks[name]) return live;\n\n return {\n config: live.config,\n state: {\n ...live.state,\n tasks: {\n ...live.state.tasks,\n [name]: createDefaultGraphEngineStore(),\n },\n lastUpdated: new Date().toISOString(),\n },\n };\n}\n\n/**\n * Disable a node — sets its status to 'inactivated'.\n * The scheduler will skip inactivated tasks. Config is untouched.\n * If the node doesn't exist or is already inactivated, returns unchanged.\n */\nexport function disableNode(live: LiveGraph, name: string): LiveGraph {\n const taskState = live.state.tasks[name];\n if (!taskState || taskState.status === 'inactivated') return live;\n\n return {\n config: live.config,\n state: {\n ...live.state,\n tasks: {\n ...live.state.tasks,\n [name]: { ...taskState, status: 'inactivated', lastUpdated: new Date().toISOString() },\n },\n lastUpdated: new Date().toISOString(),\n },\n };\n}\n\n/**\n * Enable a previously-disabled node — sets its status back to 'not-started'.\n * Only acts on 'inactivated' nodes. If the node isn't inactivated, returns unchanged.\n */\nexport function enableNode(live: LiveGraph, name: string): LiveGraph {\n const taskState = live.state.tasks[name];\n if (!taskState || taskState.status !== 'inactivated') return live;\n\n return {\n config: live.config,\n state: {\n ...live.state,\n tasks: {\n ...live.state.tasks,\n [name]: { ...taskState, status: 'not-started', lastUpdated: new Date().toISOString() },\n },\n lastUpdated: new Date().toISOString(),\n },\n };\n}\n\n// ============================================================================\n// Read: getNode\n// ============================================================================\n\n/**\n * Get the config and state for a single node.\n * Returns undefined if the node doesn't exist.\n */\nexport function getNode(live: LiveGraph, name: string): NodeInfo | undefined {\n const config = live.config.tasks[name];\n if (!config) return undefined;\n const state = live.state.tasks[name] ?? createDefaultGraphEngineStore();\n return { name, config, state };\n}\n\n// ============================================================================\n// Persistence: snapshot / restore\n// ============================================================================\n\n/**\n * Serialize a LiveGraph to a plain JSON-safe object.\n * Can be persisted to disk, database, etc.\n */\nexport function snapshot(live: LiveGraph): LiveGraphSnapshot {\n return {\n version: 1,\n config: live.config,\n state: live.state,\n snapshotAt: new Date().toISOString(),\n };\n}\n\n/**\n * Restore a LiveGraph from a snapshot. Validates the shape.\n * Throws if the snapshot is invalid.\n */\nexport function restore(data: unknown): LiveGraph {\n if (!data || typeof data !== 'object') {\n throw new Error('Invalid snapshot: expected an object');\n }\n\n const snap = data as Record<string, unknown>;\n\n if (!snap.config || typeof snap.config !== 'object') {\n throw new Error('Invalid snapshot: missing or invalid \"config\"');\n }\n if (!snap.state || typeof snap.state !== 'object') {\n throw new Error('Invalid snapshot: missing or invalid \"state\"');\n }\n\n const config = snap.config as GraphConfig;\n const state = snap.state as ExecutionState;\n\n if (!config.settings || typeof config.settings !== 'object') {\n throw new Error('Invalid snapshot: config.settings missing');\n }\n if (!config.tasks || typeof config.tasks !== 'object') {\n throw new Error('Invalid snapshot: config.tasks missing');\n }\n if (!state.tasks || typeof state.tasks !== 'object') {\n throw new Error('Invalid snapshot: state.tasks missing');\n }\n if (!Array.isArray(state.availableOutputs)) {\n throw new Error('Invalid snapshot: state.availableOutputs must be an array');\n }\n\n return { config, state };\n}\n\n// ============================================================================\n// Internals\n// ============================================================================\n\nfunction createDefaultGraphEngineStore(): GraphEngineStore {\n return {\n status: 'not-started',\n executionCount: 0,\n retryCount: 0,\n lastEpoch: 0,\n messages: [],\n progress: null,\n };\n}\n\nfunction applyAgentAction(\n state: ExecutionState,\n action: 'start' | 'stop' | 'pause' | 'resume',\n): ExecutionState {\n const now = new Date().toISOString();\n switch (action) {\n case 'stop':\n return { ...state, status: 'stopped', lastUpdated: now };\n case 'pause':\n return { ...state, status: 'paused', lastUpdated: now };\n case 'resume':\n return { ...state, status: 'running', lastUpdated: now };\n default:\n return state;\n }\n}\n","/**\n * Inference — Core\n *\n * LLM inference layer for continuous-event-graph.\n * Pluggable adapter pattern: yaml-flow builds the prompt and parses the\n * response; the caller provides the LLM via an InferenceAdapter.\n *\n * Core pattern:\n * buildInferencePrompt(live) → prompt string (pure, sync)\n * inferCompletions(live, adapter, opts) → InferenceResult (async, calls LLM)\n * applyInferences(live, result, thresh) → LiveGraph (pure, sync)\n * inferAndApply(live, adapter, opts) → InferAndApplyResult (async, convenience)\n */\n\nimport type { LiveGraph } from '../continuous-event-graph/types.js';\nimport type {\n InferenceAdapter,\n InferenceOptions,\n InferenceResult,\n InferredCompletion,\n InferAndApplyResult,\n} from './types.js';\nimport { getAllTasks } from '../event-graph/graph-helpers.js';\nimport { getRequires, getProvides } from '../event-graph/graph-helpers.js';\nimport { applyEvent } from '../continuous-event-graph/core.js';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst DEFAULT_THRESHOLD = 0.5;\n\nconst DEFAULT_SYSTEM_PROMPT = `You are a workflow completion analyzer. Given a graph of tasks with their current states, evidence, and inference hints, determine which tasks appear to be completed based on the available evidence.\n\nFor each task you analyze, provide a JSON response. Be conservative — only mark tasks as completed when the evidence strongly supports it.`;\n\n// ============================================================================\n// buildInferencePrompt — pure, sync\n// ============================================================================\n\n/**\n * Build an LLM prompt from the current LiveGraph state.\n * Includes only nodes that are:\n * - Not yet completed\n * - Have `inference.autoDetectable` set to true (or are in scope)\n *\n * Pure function — no side effects.\n */\nexport function buildInferencePrompt(\n live: LiveGraph,\n options: InferenceOptions = {},\n): string {\n const { scope, context, systemPrompt } = options;\n const graphTasks = getAllTasks(live.config);\n const { state } = live;\n\n // Determine which nodes to analyze\n const candidates = getAnalyzableCandidates(live, scope);\n\n if (candidates.length === 0) {\n return '';\n }\n\n const lines: string[] = [];\n\n // System context\n lines.push(systemPrompt || DEFAULT_SYSTEM_PROMPT);\n lines.push('');\n\n // Graph overview\n lines.push('## Graph State');\n lines.push('');\n lines.push(`Available tokens: ${state.availableOutputs.length > 0 ? state.availableOutputs.join(', ') : '(none)'}`);\n lines.push('');\n\n // Completed tasks (for context)\n const completedTasks = Object.entries(state.tasks)\n .filter(([_, ts]) => ts.status === 'completed')\n .map(([name]) => name);\n if (completedTasks.length > 0) {\n lines.push(`Completed tasks: ${completedTasks.join(', ')}`);\n lines.push('');\n }\n\n // Candidate nodes\n lines.push('## Tasks to Analyze');\n lines.push('');\n\n for (const taskName of candidates) {\n const taskConfig = graphTasks[taskName];\n const taskState = state.tasks[taskName];\n\n lines.push(`### ${taskName}`);\n if (taskConfig.description) {\n lines.push(`Description: ${taskConfig.description}`);\n }\n\n const requires = getRequires(taskConfig);\n const provides = getProvides(taskConfig);\n if (requires.length > 0) lines.push(`Requires: ${requires.join(', ')}`);\n if (provides.length > 0) lines.push(`Provides: ${provides.join(', ')}`);\n lines.push(`Current status: ${taskState?.status || 'not-started'}`);\n\n // Inference hints\n const hints = taskConfig.inference;\n if (hints) {\n if (hints.criteria) lines.push(`Completion criteria: ${hints.criteria}`);\n if (hints.keywords?.length) lines.push(`Keywords: ${hints.keywords.join(', ')}`);\n if (hints.suggestedChecks?.length) lines.push(`Suggested checks: ${hints.suggestedChecks.join('; ')}`);\n }\n\n lines.push('');\n }\n\n // Additional evidence/context\n if (context) {\n lines.push('## Additional Context / Evidence');\n lines.push('');\n lines.push(context);\n lines.push('');\n }\n\n // Response format instructions\n lines.push('## Response Format');\n lines.push('');\n lines.push('Respond with a JSON array of objects, one per task you have evidence for:');\n lines.push('```json');\n lines.push('[');\n lines.push(' {');\n lines.push(' \"taskName\": \"task-name\",');\n lines.push(' \"confidence\": 0.0 to 1.0,');\n lines.push(' \"reasoning\": \"explanation of why you believe this task is complete or not\"');\n lines.push(' }');\n lines.push(']');\n lines.push('```');\n lines.push('');\n lines.push('Rules:');\n lines.push('- Only include tasks from the \"Tasks to Analyze\" section');\n lines.push('- confidence 0.0 = no evidence of completion, 1.0 = certain it is complete');\n lines.push('- If you have no evidence for a task, omit it from the array');\n lines.push('- Be conservative — require clear evidence before high confidence');\n lines.push('- Respond ONLY with the JSON array, no additional text');\n\n return lines.join('\\n');\n}\n\n// ============================================================================\n// inferCompletions — async, calls LLM\n// ============================================================================\n\n/**\n * Ask an LLM to analyze the current graph state and suggest completions.\n *\n * Builds a prompt from the LiveGraph, sends it through the adapter,\n * parses the structured response, and returns an InferenceResult.\n */\nexport async function inferCompletions(\n live: LiveGraph,\n adapter: InferenceAdapter,\n options: InferenceOptions = {},\n): Promise<InferenceResult> {\n const threshold = options.threshold ?? DEFAULT_THRESHOLD;\n const analyzedNodes = getAnalyzableCandidates(live, options.scope);\n\n // Nothing to analyze\n if (analyzedNodes.length === 0) {\n return { suggestions: [], promptUsed: '', rawResponse: '', analyzedNodes: [] };\n }\n\n const prompt = buildInferencePrompt(live, options);\n const rawResponse = await adapter.analyze(prompt);\n const suggestions = parseInferenceResponse(rawResponse, analyzedNodes, threshold);\n\n return {\n suggestions,\n promptUsed: prompt,\n rawResponse,\n analyzedNodes,\n };\n}\n\n// ============================================================================\n// applyInferences — pure, sync\n// ============================================================================\n\n/**\n * Apply inferred completions to a LiveGraph.\n * Only applies suggestions at or above the given confidence threshold.\n *\n * Under the hood, this fires `task-started` + `task-completed` events\n * for each accepted suggestion (if the task isn't already running/completed).\n *\n * Pure function — returns a new LiveGraph.\n */\nexport function applyInferences(\n live: LiveGraph,\n result: InferenceResult,\n threshold: number = DEFAULT_THRESHOLD,\n): LiveGraph {\n let current = live;\n\n for (const suggestion of result.suggestions) {\n if (suggestion.confidence < threshold) continue;\n\n const taskState = current.state.tasks[suggestion.taskName];\n if (!taskState) continue;\n\n // Skip already completed or running tasks\n if (taskState.status === 'completed' || taskState.status === 'running') continue;\n\n // Apply start + complete events\n const now = new Date().toISOString();\n current = applyEvent(current, {\n type: 'task-started',\n taskName: suggestion.taskName,\n timestamp: now,\n });\n current = applyEvent(current, {\n type: 'task-completed',\n taskName: suggestion.taskName,\n timestamp: now,\n result: 'llm-inferred',\n });\n }\n\n return current;\n}\n\n// ============================================================================\n// inferAndApply — async, convenience\n// ============================================================================\n\n/**\n * Convenience: infer completions and apply them in one step.\n * Returns the updated LiveGraph + full audit trail of what was inferred vs applied.\n */\nexport async function inferAndApply(\n live: LiveGraph,\n adapter: InferenceAdapter,\n options: InferenceOptions = {},\n): Promise<InferAndApplyResult> {\n const threshold = options.threshold ?? DEFAULT_THRESHOLD;\n const inference = await inferCompletions(live, adapter, options);\n const updated = applyInferences(live, inference, threshold);\n\n const applied = inference.suggestions.filter(s => s.confidence >= threshold);\n const skipped = inference.suggestions.filter(s => s.confidence < threshold);\n\n return {\n live: updated,\n inference,\n applied,\n skipped,\n };\n}\n\n// ============================================================================\n// Internals\n// ============================================================================\n\n/**\n * Determine which nodes should be analyzed.\n * - If scope is provided, use those (filtered to non-completed with hints)\n * - Otherwise, find all non-completed nodes with `inference.autoDetectable === true`\n */\nfunction getAnalyzableCandidates(live: LiveGraph, scope?: string[]): string[] {\n const graphTasks = getAllTasks(live.config);\n const { state } = live;\n\n const candidates: string[] = [];\n\n for (const [name, config] of Object.entries(graphTasks)) {\n const taskState = state.tasks[name];\n\n // Skip completed/running tasks\n if (taskState?.status === 'completed' || taskState?.status === 'running') continue;\n\n if (scope) {\n // If scope is provided, include if name is in scope\n if (scope.includes(name)) candidates.push(name);\n } else {\n // Otherwise, include only if autoDetectable\n if (config.inference?.autoDetectable) candidates.push(name);\n }\n }\n\n return candidates;\n}\n\n/**\n * Parse the LLM's raw response into structured InferredCompletion objects.\n * Handles edge cases: markdown fences, preamble text, malformed JSON.\n */\nfunction parseInferenceResponse(\n rawResponse: string,\n validNodes: string[],\n _threshold: number,\n): InferredCompletion[] {\n const validSet = new Set(validNodes);\n\n try {\n // Try to extract JSON from the response (handle markdown fences, preamble, etc.)\n const jsonStr = extractJson(rawResponse);\n if (!jsonStr) return [];\n\n const parsed = JSON.parse(jsonStr);\n\n // Must be an array\n if (!Array.isArray(parsed)) return [];\n\n const suggestions: InferredCompletion[] = [];\n\n for (const item of parsed) {\n // Validate shape\n if (!item || typeof item !== 'object') continue;\n if (typeof item.taskName !== 'string') continue;\n if (typeof item.confidence !== 'number') continue;\n\n // Must reference a valid node\n if (!validSet.has(item.taskName)) continue;\n\n // Clamp confidence to [0, 1]\n const confidence = Math.max(0, Math.min(1, item.confidence));\n\n suggestions.push({\n taskName: item.taskName,\n confidence,\n reasoning: typeof item.reasoning === 'string' ? item.reasoning : '',\n detectionMethod: 'llm-inferred',\n });\n }\n\n return suggestions;\n } catch {\n // JSON parse failed — return empty\n return [];\n }\n}\n\n/**\n * Extract JSON array from raw LLM text.\n * Handles: bare JSON, markdown-fenced JSON, preamble/postamble text.\n */\nfunction extractJson(text: string): string | null {\n if (!text || typeof text !== 'string') return null;\n\n const trimmed = text.trim();\n\n // Try 1: Markdown fence (```json ... ``` or ``` ... ```)\n const fenceMatch = trimmed.match(/```(?:json)?\\s*\\n?([\\s\\S]*?)\\n?\\s*```/);\n if (fenceMatch) return fenceMatch[1].trim();\n\n // Try 2: Find first [ ... last ]\n const firstBracket = trimmed.indexOf('[');\n const lastBracket = trimmed.lastIndexOf(']');\n if (firstBracket !== -1 && lastBracket > firstBracket) {\n return trimmed.slice(firstBracket, lastBracket + 1);\n }\n\n // Try 3: Maybe it's bare JSON\n if (trimmed.startsWith('[')) return trimmed;\n\n return null;\n}\n","/**\n * Inference — Built-in Adapter Factories\n *\n * Ready-made adapter constructors for common LLM interfaces.\n * Each returns an InferenceAdapter.\n *\n * CLI adapters spawn a child process and capture stdout.\n * HTTP adapters POST to an endpoint and read the response.\n */\n\nimport { execFile } from 'node:child_process';\nimport type { InferenceAdapter } from './types.js';\n\n// ============================================================================\n// CLI Adapter — execute any local command\n// ============================================================================\n\nexport interface CliAdapterOptions {\n /** The command to execute (e.g., 'gh', 'ollama', 'llm') */\n command: string;\n /**\n * Arguments builder: receives the prompt and returns the args array.\n * The prompt is passed as an argument — NOT via stdin — unless you override.\n *\n * @example gh copilot: (prompt) => ['copilot', 'suggest', '-t', 'shell', prompt]\n * @example ollama: (prompt) => ['run', 'llama3', prompt]\n * @example llm cli: (prompt) => ['--model', 'gpt-4o', prompt]\n */\n args: (prompt: string) => string[];\n /** Max execution time in ms (default: 60000) */\n timeout?: number;\n /** Working directory for the child process */\n cwd?: string;\n /** Environment variables to pass to the child process */\n env?: Record<string, string>;\n /**\n * If true, pass the prompt via stdin instead of as a CLI argument.\n * Useful for long prompts that exceed shell argument limits.\n * Default: false\n */\n stdin?: boolean;\n}\n\n/**\n * Create an InferenceAdapter that executes a local CLI command.\n * The prompt is passed as a CLI argument (or via stdin if opts.stdin=true).\n * stdout is captured as the LLM response.\n *\n * @example\n * // GitHub Copilot CLI\n * const adapter = createCliAdapter({\n * command: 'gh',\n * args: (prompt) => ['copilot', 'suggest', '-t', 'shell', prompt],\n * });\n *\n * @example\n * // Ollama (local LLM)\n * const adapter = createCliAdapter({\n * command: 'ollama',\n * args: (prompt) => ['run', 'llama3', prompt],\n * });\n *\n * @example\n * // Simon Willison's llm CLI\n * const adapter = createCliAdapter({\n * command: 'llm',\n * args: (prompt) => ['--model', 'gpt-4o', prompt],\n * });\n *\n * @example\n * // Any script (stdin mode for long prompts)\n * const adapter = createCliAdapter({\n * command: 'python',\n * args: () => ['my_llm_script.py'],\n * stdin: true,\n * });\n */\nexport function createCliAdapter(opts: CliAdapterOptions): InferenceAdapter {\n const timeout = opts.timeout ?? 60_000;\n\n return {\n analyze: (prompt: string): Promise<string> => {\n return new Promise((resolve, reject) => {\n const args = opts.args(prompt);\n\n const child = execFile(\n opts.command,\n opts.stdin ? opts.args('') : args,\n {\n timeout,\n cwd: opts.cwd,\n env: opts.env ? { ...process.env, ...opts.env } : undefined,\n maxBuffer: 10 * 1024 * 1024, // 10MB\n },\n (error, stdout, stderr) => {\n if (error) {\n reject(new Error(\n `CLI adapter failed: ${opts.command} exited with ${error.code ?? 'error'}` +\n (stderr ? `\\nstderr: ${stderr.slice(0, 500)}` : '') +\n `\\n${error.message}`,\n ));\n } else {\n resolve(stdout);\n }\n },\n );\n\n // If stdin mode, write the prompt to the child's stdin\n if (opts.stdin && child.stdin) {\n child.stdin.write(prompt);\n child.stdin.end();\n }\n });\n },\n };\n}\n\n// ============================================================================\n// HTTP Adapter — POST to any endpoint\n// ============================================================================\n\nexport interface HttpAdapterOptions {\n /** The endpoint URL to POST to */\n url: string;\n /** Additional headers (Authorization, etc.) */\n headers?: Record<string, string>;\n /**\n * Build the request body from the prompt.\n * Default: `{ prompt }`\n */\n buildBody?: (prompt: string) => unknown;\n /**\n * Extract the response text from the parsed JSON response.\n * Default: `(json) => json.response ?? json.text ?? json.content ?? JSON.stringify(json)`\n */\n extractResponse?: (json: Record<string, unknown>) => string;\n /** Request timeout in ms (default: 60000) */\n timeout?: number;\n}\n\n/**\n * Create an InferenceAdapter that POSTs to an HTTP endpoint.\n *\n * @example\n * // Ollama HTTP API\n * const adapter = createHttpAdapter({\n * url: 'http://localhost:11434/api/generate',\n * buildBody: (prompt) => ({ model: 'llama3', prompt, stream: false }),\n * extractResponse: (json) => json.response as string,\n * });\n *\n * @example\n * // Custom API with auth\n * const adapter = createHttpAdapter({\n * url: 'https://my-llm.example.com/analyze',\n * headers: { Authorization: `Bearer ${process.env.API_KEY}` },\n * });\n */\nexport function createHttpAdapter(opts: HttpAdapterOptions): InferenceAdapter {\n const timeout = opts.timeout ?? 60_000;\n\n return {\n analyze: async (prompt: string): Promise<string> => {\n const body = opts.buildBody ? opts.buildBody(prompt) : { prompt };\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(opts.url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(opts.headers ?? {}),\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n throw new Error(`HTTP ${response.status}: ${text.slice(0, 500)}`);\n }\n\n const json = await response.json() as Record<string, unknown>;\n\n if (opts.extractResponse) {\n return opts.extractResponse(json);\n }\n\n // Default extraction: try common response fields\n if (typeof json.response === 'string') return json.response;\n if (typeof json.text === 'string') return json.text;\n if (typeof json.content === 'string') return json.content;\n return JSON.stringify(json);\n } finally {\n clearTimeout(timer);\n }\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/event-graph/graph-helpers.ts","../../src/event-graph/task-transitions.ts","../../src/continuous-event-graph/core.ts","../../src/inference/core.ts","../../src/inference/adapters.ts"],"names":["updatedTask","createDefaultGraphEngineStore"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Event Graph — Graph Helpers\n *\n * Pure functions for manipulating the requires/provides task dependency graph.\n * No I/O, no side effects.\n */\n\nimport type { GraphConfig, TaskConfig, GraphEngineStore, ExecutionState, RefreshStrategy } from './types.js';\nimport { TASK_STATUS } from './constants.js';\n\n// ============================================================================\n// Accessors — normalize requires/provides to always be arrays\n// ============================================================================\n\nexport function getProvides(task: TaskConfig | undefined): string[] {\n if (!task) return [];\n if (Array.isArray(task.provides)) return task.provides;\n return [];\n}\n\nexport function getRequires(task: TaskConfig | undefined): string[] {\n if (!task) return [];\n if (Array.isArray(task.requires)) return task.requires;\n return [];\n}\n\nexport function getAllTasks(graph: GraphConfig): Record<string, TaskConfig> {\n return graph.tasks ?? {};\n}\n\nexport function getTask(graph: GraphConfig, taskName: string): TaskConfig | undefined {\n return graph.tasks[taskName];\n}\n\nexport function hasTask(graph: GraphConfig, taskName: string): boolean {\n return taskName in graph.tasks;\n}\n\n// ============================================================================\n// Task State Predicates\n// ============================================================================\n\nexport function isNonActiveTask(taskState: GraphEngineStore | undefined): boolean {\n if (!taskState) return false;\n return taskState.status === TASK_STATUS.FAILED || taskState.status === TASK_STATUS.INACTIVATED;\n}\n\nexport function isTaskCompleted(taskState: GraphEngineStore | undefined): boolean {\n return taskState?.status === TASK_STATUS.COMPLETED;\n}\n\nexport function isTaskRunning(taskState: GraphEngineStore | undefined): boolean {\n return taskState?.status === TASK_STATUS.RUNNING;\n}\n\nexport function getRefreshStrategy(taskConfig: TaskConfig, graphSettings?: { refreshStrategy?: RefreshStrategy }): RefreshStrategy {\n return taskConfig.refreshStrategy ?? graphSettings?.refreshStrategy ?? 'data-changed';\n}\n\nexport function isRerunnable(taskConfig: TaskConfig, graphSettings?: { refreshStrategy?: RefreshStrategy }): boolean {\n return getRefreshStrategy(taskConfig, graphSettings) !== 'once';\n}\n\nexport function getMaxExecutions(taskConfig: TaskConfig): number | undefined {\n return taskConfig.maxExecutions;\n}\n\n// ============================================================================\n// Available Outputs Computation\n// ============================================================================\n\n/**\n * Dynamically compute available outputs from all completed tasks.\n * Tasks with strategies other than 'once' may have completed and reset.\n * Pure function.\n */\nexport function computeAvailableOutputs(\n graph: GraphConfig,\n taskStates: Record<string, GraphEngineStore>\n): string[] {\n const outputs: Set<string> = new Set();\n\n for (const [taskName, taskState] of Object.entries(taskStates)) {\n if (taskState.status === TASK_STATUS.COMPLETED) {\n const taskConfig = graph.tasks[taskName];\n if (taskConfig) {\n const provides = getProvides(taskConfig);\n provides.forEach(output => outputs.add(output));\n }\n }\n }\n\n return Array.from(outputs);\n}\n\n// ============================================================================\n// Conflict Detection\n// ============================================================================\n\n/**\n * Group candidate tasks by the outputs they provide.\n * Used to detect conflicts (multiple tasks providing the same output).\n */\nexport function groupTasksByProvides(\n candidateTaskNames: string[],\n tasks: Record<string, TaskConfig>\n): Record<string, string[]> {\n const outputGroups: Record<string, string[]> = {};\n\n candidateTaskNames.forEach(taskName => {\n const task = tasks[taskName];\n if (!task) return;\n const provides = getProvides(task);\n provides.forEach(output => {\n if (!outputGroups[output]) {\n outputGroups[output] = [];\n }\n outputGroups[output].push(taskName);\n });\n });\n\n return outputGroups;\n}\n\n/**\n * Check if a task's outputs conflict with other candidates.\n */\nexport function hasOutputConflict(\n taskName: string,\n taskProvides: string[],\n candidates: string[],\n tasks: Record<string, TaskConfig>\n): boolean {\n for (const otherName of candidates) {\n if (otherName === taskName) continue;\n const otherProvides = getProvides(tasks[otherName]);\n const overlapping = taskProvides.some(output => otherProvides.includes(output));\n if (overlapping) return true;\n }\n return false;\n}\n\n// ============================================================================\n// Immutable Graph Mutation\n// ============================================================================\n\nexport function addKeyToProvides(task: TaskConfig, key: string): TaskConfig {\n const current = getProvides(task);\n if (current.includes(key)) return task;\n return { ...task, provides: [...current, key] };\n}\n\nexport function removeKeyFromProvides(task: TaskConfig, key: string): TaskConfig {\n const current = getProvides(task);\n return { ...task, provides: current.filter(p => p !== key) };\n}\n\nexport function addKeyToRequires(task: TaskConfig, key: string): TaskConfig {\n const current = getRequires(task);\n if (current.includes(key)) return task;\n return { ...task, requires: [...current, key] };\n}\n\nexport function removeKeyFromRequires(task: TaskConfig, key: string): TaskConfig {\n const current = getRequires(task);\n return { ...task, requires: current.filter(r => r !== key) };\n}\n\n// ============================================================================\n// Dynamic Task Management\n// ============================================================================\n\n/**\n * Add a new task to a graph config. Returns a new GraphConfig (immutable).\n */\nexport function addDynamicTask(\n graph: GraphConfig,\n taskName: string,\n taskConfig: TaskConfig\n): GraphConfig {\n return {\n ...graph,\n tasks: {\n ...graph.tasks,\n [taskName]: taskConfig,\n },\n };\n}\n\n/**\n * Create default task state for a new task.\n */\nexport function createDefaultGraphEngineStore(): GraphEngineStore {\n return {\n status: 'not-started',\n executionCount: 0,\n retryCount: 0,\n lastEpoch: 0,\n messages: [],\n progress: null,\n };\n}\n\n/**\n * Create the initial execution state for a graph.\n */\nexport function createInitialExecutionState(\n graph: GraphConfig,\n executionId: string\n): ExecutionState {\n const tasks: Record<string, GraphEngineStore> = {};\n for (const taskName of Object.keys(graph.tasks)) {\n tasks[taskName] = createDefaultGraphEngineStore();\n }\n\n return {\n status: 'running',\n tasks,\n availableOutputs: [],\n stuckDetection: { is_stuck: false, stuck_description: null, outputs_unresolvable: [], tasks_blocked: [] },\n lastUpdated: new Date().toISOString(),\n executionId,\n executionConfig: {\n executionMode: graph.settings.execution_mode ?? 'eligibility-mode',\n conflictStrategy: graph.settings.conflict_strategy ?? 'alphabetical',\n completionStrategy: graph.settings.completion,\n },\n };\n}\n","/**\n * Event Graph — Task State Transitions\n *\n * Pure functions for applying task lifecycle events to execution state.\n * Each function: f(state, ...) → newState\n */\n\nimport type { ExecutionState, GraphEngineStore, GraphConfig } from './types.js';\nimport { getProvides } from './graph-helpers.js';\n\n/**\n * Apply task start to execution state. Pure function.\n */\nexport function applyTaskStart(state: ExecutionState, taskName: string): ExecutionState {\n const existingTask = state.tasks[taskName] ?? createDefaultGraphEngineStore();\n\n const updatedTask: GraphEngineStore = {\n ...existingTask,\n status: 'running',\n startedAt: new Date().toISOString(),\n lastUpdated: new Date().toISOString(),\n progress: 0,\n error: undefined,\n };\n\n return {\n ...state,\n tasks: { ...state.tasks, [taskName]: updatedTask },\n lastUpdated: new Date().toISOString(),\n };\n}\n\n/**\n * Apply task completion to execution state.\n * Handles: default provides, conditional provides (on), refresh strategy, data hash tracking.\n * Pure function.\n */\nexport function applyTaskCompletion(\n state: ExecutionState,\n graph: GraphConfig,\n taskName: string,\n result?: string,\n dataHash?: string,\n data?: Record<string, unknown>\n): ExecutionState {\n const existingTask = state.tasks[taskName] ?? createDefaultGraphEngineStore();\n const taskConfig = graph.tasks[taskName];\n if (!taskConfig) {\n throw new Error(`Task \"${taskName}\" not found in graph`);\n }\n\n // Determine which outputs to produce\n let outputTokens: string[];\n if (result && taskConfig.on && taskConfig.on[result]) {\n // Conditional routing — use the on[result] provides\n outputTokens = taskConfig.on[result];\n } else {\n // Default provides\n outputTokens = getProvides(taskConfig);\n }\n\n // Build lastConsumedHashes: snapshot the data hashes of all upstream tasks\n const lastConsumedHashes: Record<string, string> = { ...existingTask.lastConsumedHashes };\n const requires = taskConfig.requires ?? [];\n for (const token of requires) {\n // Find the task that provides this token and grab its hash\n for (const [otherName, otherConfig] of Object.entries(graph.tasks)) {\n if (getProvides(otherConfig).includes(token)) {\n const otherState = state.tasks[otherName];\n if (otherState?.lastDataHash) {\n lastConsumedHashes[token] = otherState.lastDataHash;\n }\n break;\n }\n }\n }\n\n const updatedTask: GraphEngineStore = {\n ...existingTask,\n status: 'completed',\n completedAt: new Date().toISOString(),\n lastUpdated: new Date().toISOString(),\n executionCount: existingTask.executionCount + 1,\n lastEpoch: existingTask.executionCount + 1,\n lastDataHash: dataHash,\n data,\n lastConsumedHashes,\n error: undefined,\n };\n\n // Merge new outputs with existing available outputs\n const newOutputs = [...new Set([...state.availableOutputs, ...outputTokens])];\n\n return {\n ...state,\n tasks: { ...state.tasks, [taskName]: updatedTask },\n availableOutputs: newOutputs,\n lastUpdated: new Date().toISOString(),\n };\n}\n\n/**\n * Apply task failure to execution state.\n * Handles: retry logic, on_failure token injection, circuit breaker.\n * Pure function.\n */\nexport function applyTaskFailure(\n state: ExecutionState,\n graph: GraphConfig,\n taskName: string,\n error: string\n): ExecutionState {\n const existingTask = state.tasks[taskName] ?? createDefaultGraphEngineStore();\n const taskConfig = graph.tasks[taskName];\n\n // Check retry\n if (taskConfig?.retry) {\n const retryCount = existingTask.retryCount + 1;\n if (retryCount <= taskConfig.retry.max_attempts) {\n // Retry — set back to not-started with incremented retry count\n const updatedTask: GraphEngineStore = {\n ...existingTask,\n status: 'not-started',\n retryCount,\n lastUpdated: new Date().toISOString(),\n error,\n };\n return {\n ...state,\n tasks: { ...state.tasks, [taskName]: updatedTask },\n lastUpdated: new Date().toISOString(),\n };\n }\n }\n\n // No more retries — mark as failed\n const updatedTask: GraphEngineStore = {\n ...existingTask,\n status: 'failed',\n failedAt: new Date().toISOString(),\n lastUpdated: new Date().toISOString(),\n error,\n executionCount: existingTask.executionCount + 1,\n };\n\n // Inject failure tokens if configured\n let newOutputs = state.availableOutputs;\n if (taskConfig?.on_failure && taskConfig.on_failure.length > 0) {\n newOutputs = [...new Set([...state.availableOutputs, ...taskConfig.on_failure])];\n }\n\n // Check circuit breaker\n if (taskConfig?.circuit_breaker && updatedTask.executionCount >= taskConfig.circuit_breaker.max_executions) {\n const breakTokens = taskConfig.circuit_breaker.on_break;\n newOutputs = [...new Set([...newOutputs, ...breakTokens])];\n }\n\n return {\n ...state,\n tasks: { ...state.tasks, [taskName]: updatedTask },\n availableOutputs: newOutputs,\n lastUpdated: new Date().toISOString(),\n };\n}\n\n/**\n * Apply task progress update. Pure function.\n */\nexport function applyTaskProgress(\n state: ExecutionState,\n taskName: string,\n message?: string,\n progress?: number\n): ExecutionState {\n const existingTask = state.tasks[taskName] ?? createDefaultGraphEngineStore();\n\n const updatedTask: GraphEngineStore = {\n ...existingTask,\n progress: typeof progress === 'number' ? progress : existingTask.progress,\n messages: [\n ...(existingTask.messages ?? []),\n ...(message ? [{ message, timestamp: new Date().toISOString(), status: existingTask.status }] : []),\n ],\n lastUpdated: new Date().toISOString(),\n };\n\n return {\n ...state,\n tasks: { ...state.tasks, [taskName]: updatedTask },\n lastUpdated: new Date().toISOString(),\n };\n}\n\n/**\n * Apply task restart to execution state.\n * Resets the task to not-started, preserving executionCount and lastEpoch\n * (history). Clears data, error, progress. The task becomes eligible for\n * scheduling again on the next drain cycle.\n * Pure function.\n */\nexport function applyTaskRestart(\n state: ExecutionState,\n taskName: string,\n): ExecutionState {\n const existingTask = state.tasks[taskName];\n if (!existingTask) return state;\n\n const updatedTask: GraphEngineStore = {\n ...existingTask,\n status: 'not-started',\n startedAt: undefined,\n completedAt: undefined,\n failedAt: undefined,\n error: undefined,\n data: undefined,\n progress: null,\n lastUpdated: new Date().toISOString(),\n };\n\n return {\n ...state,\n tasks: { ...state.tasks, [taskName]: updatedTask },\n lastUpdated: new Date().toISOString(),\n };\n}\n\nfunction createDefaultGraphEngineStore(): GraphEngineStore {\n return {\n status: 'not-started',\n executionCount: 0,\n retryCount: 0,\n lastEpoch: 0,\n messages: [],\n progress: null,\n };\n}\n","/**\n * Continuous Event Graph — Core\n *\n * All functions are pure: f(LiveGraph, input) → LiveGraph\n *\n * - createLiveGraph: bootstrap from a GraphConfig\n * - applyEvent: reduce an event (task-started, task-completed, etc.)\n * - addNode / removeNode: structural graph mutations\n * - addRequires / removeRequires / addProvides / removeProvides: wiring mutations\n */\n\nimport type { GraphConfig, TaskConfig, GraphEvent, LiveGraph, NodeInfo, LiveGraphSnapshot } from './types.js';\nimport type { ExecutionState, GraphEngineStore } from '../event-graph/types.js';\nimport { getProvides, getRequires } from '../event-graph/graph-helpers.js';\nimport {\n applyTaskStart,\n applyTaskCompletion,\n applyTaskFailure,\n applyTaskProgress,\n applyTaskRestart,\n} from '../event-graph/task-transitions.js';\n\n// ============================================================================\n// Create\n// ============================================================================\n\n/**\n * Create a LiveGraph from a GraphConfig.\n * Initialises execution state for all tasks in the config.\n */\nexport function createLiveGraph(config: GraphConfig, executionId?: string): LiveGraph {\n const id = executionId ?? `live-${Date.now()}`;\n const tasks: Record<string, GraphEngineStore> = {};\n\n for (const taskName of Object.keys(config.tasks)) {\n tasks[taskName] = createDefaultGraphEngineStore();\n }\n\n const state: ExecutionState = {\n status: 'running',\n tasks,\n availableOutputs: [],\n stuckDetection: { is_stuck: false, stuck_description: null, outputs_unresolvable: [], tasks_blocked: [] },\n lastUpdated: new Date().toISOString(),\n executionId: id,\n executionConfig: {\n executionMode: config.settings.execution_mode ?? 'eligibility-mode',\n conflictStrategy: config.settings.conflict_strategy ?? 'alphabetical',\n completionStrategy: config.settings.completion,\n },\n };\n\n return { config, state };\n}\n\n// ============================================================================\n// Event Reducer\n// ============================================================================\n\n/**\n * Apply an event to the LiveGraph, producing a new LiveGraph.\n * Events are the shared vocabulary — both execution state transitions\n * (task-started, task-completed, etc.) and structural mutations\n * (task-upsert, task-removal, node-requires-add, etc.).\n *\n * Pure function: f(LiveGraph, GraphEvent) → LiveGraph\n */\nexport function applyEvent(live: LiveGraph, event: GraphEvent): LiveGraph {\n const { config, state } = live;\n\n // Ghost event filtering\n if ('executionId' in event && event.executionId && event.executionId !== state.executionId) {\n return live;\n }\n\n switch (event.type) {\n // --- Execution state transitions ---\n\n case 'task-started':\n return { config, state: applyTaskStart(state, event.taskName) };\n\n case 'task-completed':\n return { config, state: applyTaskCompletion(state, config, event.taskName, event.result, event.dataHash, event.data) };\n\n case 'task-failed':\n return { config, state: applyTaskFailure(state, config, event.taskName, event.error) };\n\n case 'task-progress':\n return { config, state: applyTaskProgress(state, event.taskName, event.message, event.progress) };\n\n case 'task-restart':\n return { config, state: applyTaskRestart(state, event.taskName) };\n\n case 'inject-tokens':\n return {\n config,\n state: {\n ...state,\n availableOutputs: [...new Set([...state.availableOutputs, ...event.tokens])],\n lastUpdated: new Date().toISOString(),\n },\n };\n\n case 'agent-action':\n return { config, state: applyAgentAction(state, event.action) };\n\n // --- Structural mutations ---\n\n case 'task-upsert':\n return addNode(live, event.taskName, event.taskConfig);\n\n case 'task-removal':\n return removeNode(live, event.taskName);\n\n case 'node-requires-add':\n return addRequires(live, event.nodeName, event.tokens);\n\n case 'node-requires-remove':\n return removeRequires(live, event.nodeName, event.tokens);\n\n case 'node-provides-add':\n return addProvides(live, event.nodeName, event.tokens);\n\n case 'node-provides-remove':\n return removeProvides(live, event.nodeName, event.tokens);\n\n default:\n return live;\n }\n}\n\n/**\n * Apply multiple events atomically to a LiveGraph.\n * Events are reduced sequentially, but the caller only sees the final state.\n * Use this for batch processing (e.g. draining a journal of pending events).\n */\nexport function applyEvents(live: LiveGraph, events: GraphEvent[]): LiveGraph {\n return events.reduce((current, event) => applyEvent(current, event), live);\n}\n\n// ============================================================================\n// Graph Mutations — node-level\n// ============================================================================\n\n/**\n * Upsert a node (task) in the live graph. Updates both config and state atomically.\n * If the node already exists, replaces its config but preserves its state.\n * If new, creates fresh default state.\n */\nexport function addNode(live: LiveGraph, name: string, taskConfig: TaskConfig): LiveGraph {\n const exists = !!live.config.tasks[name];\n return {\n config: {\n ...live.config,\n tasks: { ...live.config.tasks, [name]: taskConfig },\n },\n state: {\n ...live.state,\n tasks: {\n ...live.state.tasks,\n [name]: exists ? live.state.tasks[name] : createDefaultGraphEngineStore(),\n },\n lastUpdated: new Date().toISOString(),\n },\n };\n}\n\n/**\n * Remove a node (task) from the live graph. Updates both config and state atomically.\n * If the node doesn't exist, returns the graph unchanged.\n * NOTE: Does not clean up references — other nodes' requires/provides are left intact.\n * The caller can use removeRequires() to clean up if needed.\n */\nexport function removeNode(live: LiveGraph, name: string): LiveGraph {\n if (!live.config.tasks[name]) return live;\n\n const { [name]: _removedConfig, ...remainingTasks } = live.config.tasks;\n const { [name]: _removedState, ...remainingStates } = live.state.tasks;\n\n return {\n config: {\n ...live.config,\n tasks: remainingTasks,\n },\n state: {\n ...live.state,\n tasks: remainingStates,\n lastUpdated: new Date().toISOString(),\n },\n };\n}\n\n// ============================================================================\n// Graph Mutations — wiring\n// ============================================================================\n\n/**\n * Add requires tokens to a node. If the node doesn't exist, returns unchanged.\n * Deduplicates — won't add tokens already in requires.\n */\nexport function addRequires(live: LiveGraph, nodeName: string, tokens: string[]): LiveGraph {\n const task = live.config.tasks[nodeName];\n if (!task) return live;\n\n const current = getRequires(task);\n const toAdd = tokens.filter(t => !current.includes(t));\n if (toAdd.length === 0) return live;\n\n return {\n config: {\n ...live.config,\n tasks: {\n ...live.config.tasks,\n [nodeName]: { ...task, requires: [...current, ...toAdd] },\n },\n },\n state: live.state,\n };\n}\n\n/**\n * Remove requires tokens from a node. If the node doesn't exist, returns unchanged.\n */\nexport function removeRequires(live: LiveGraph, nodeName: string, tokens: string[]): LiveGraph {\n const task = live.config.tasks[nodeName];\n if (!task) return live;\n\n const current = getRequires(task);\n const remaining = current.filter(t => !tokens.includes(t));\n if (remaining.length === current.length) return live;\n\n return {\n config: {\n ...live.config,\n tasks: {\n ...live.config.tasks,\n [nodeName]: { ...task, requires: remaining },\n },\n },\n state: live.state,\n };\n}\n\n/**\n * Add provides tokens to a node. If the node doesn't exist, returns unchanged.\n * Deduplicates — won't add tokens already in provides.\n */\nexport function addProvides(live: LiveGraph, nodeName: string, tokens: string[]): LiveGraph {\n const task = live.config.tasks[nodeName];\n if (!task) return live;\n\n const current = getProvides(task);\n const toAdd = tokens.filter(t => !current.includes(t));\n if (toAdd.length === 0) return live;\n\n return {\n config: {\n ...live.config,\n tasks: {\n ...live.config.tasks,\n [nodeName]: { ...task, provides: [...current, ...toAdd] },\n },\n },\n state: live.state,\n };\n}\n\n/**\n * Remove provides tokens from a node. If the node doesn't exist, returns unchanged.\n */\nexport function removeProvides(live: LiveGraph, nodeName: string, tokens: string[]): LiveGraph {\n const task = live.config.tasks[nodeName];\n if (!task) return live;\n\n const current = getProvides(task);\n const remaining = current.filter(t => !tokens.includes(t));\n if (remaining.length === current.length) return live;\n\n return {\n config: {\n ...live.config,\n tasks: {\n ...live.config.tasks,\n [nodeName]: { ...task, provides: remaining },\n },\n },\n state: live.state,\n };\n}\n\n// ============================================================================\n// Convenience — inject tokens via mutation (sugar over applyEvent)\n// ============================================================================\n\n/**\n * Inject tokens into the live graph's available outputs.\n * Equivalent to applyEvent(live, { type: 'inject-tokens', tokens, timestamp }).\n */\nexport function injectTokens(live: LiveGraph, tokens: string[]): LiveGraph {\n return applyEvent(live, {\n type: 'inject-tokens',\n tokens,\n timestamp: new Date().toISOString(),\n });\n}\n\n/**\n * Drain (remove) tokens from the live graph's available outputs.\n * Inverse of injectTokens — useful for expiring stale data or revoking signals.\n * Tokens that aren't currently available are silently ignored.\n * Pure function.\n */\nexport function drainTokens(live: LiveGraph, tokens: string[]): LiveGraph {\n const toRemove = new Set(tokens);\n const remaining = live.state.availableOutputs.filter(t => !toRemove.has(t));\n\n if (remaining.length === live.state.availableOutputs.length) return live;\n\n return {\n config: live.config,\n state: {\n ...live.state,\n availableOutputs: remaining,\n lastUpdated: new Date().toISOString(),\n },\n };\n}\n\n// ============================================================================\n// Node lifecycle\n// ============================================================================\n\n/**\n * Reset a node's state back to not-started, clearing error, retry count, progress.\n * Config is untouched. Useful when a failed task should be retried later.\n * If the node doesn't exist, returns unchanged.\n */\nexport function resetNode(live: LiveGraph, name: string): LiveGraph {\n if (!live.config.tasks[name] || !live.state.tasks[name]) return live;\n\n return {\n config: live.config,\n state: {\n ...live.state,\n tasks: {\n ...live.state.tasks,\n [name]: createDefaultGraphEngineStore(),\n },\n lastUpdated: new Date().toISOString(),\n },\n };\n}\n\n/**\n * Disable a node — sets its status to 'inactivated'.\n * The scheduler will skip inactivated tasks. Config is untouched.\n * If the node doesn't exist or is already inactivated, returns unchanged.\n */\nexport function disableNode(live: LiveGraph, name: string): LiveGraph {\n const taskState = live.state.tasks[name];\n if (!taskState || taskState.status === 'inactivated') return live;\n\n return {\n config: live.config,\n state: {\n ...live.state,\n tasks: {\n ...live.state.tasks,\n [name]: { ...taskState, status: 'inactivated', lastUpdated: new Date().toISOString() },\n },\n lastUpdated: new Date().toISOString(),\n },\n };\n}\n\n/**\n * Enable a previously-disabled node — sets its status back to 'not-started'.\n * Only acts on 'inactivated' nodes. If the node isn't inactivated, returns unchanged.\n */\nexport function enableNode(live: LiveGraph, name: string): LiveGraph {\n const taskState = live.state.tasks[name];\n if (!taskState || taskState.status !== 'inactivated') return live;\n\n return {\n config: live.config,\n state: {\n ...live.state,\n tasks: {\n ...live.state.tasks,\n [name]: { ...taskState, status: 'not-started', lastUpdated: new Date().toISOString() },\n },\n lastUpdated: new Date().toISOString(),\n },\n };\n}\n\n// ============================================================================\n// Read: getNode\n// ============================================================================\n\n/**\n * Get the config and state for a single node.\n * Returns undefined if the node doesn't exist.\n */\nexport function getNode(live: LiveGraph, name: string): NodeInfo | undefined {\n const config = live.config.tasks[name];\n if (!config) return undefined;\n const state = live.state.tasks[name] ?? createDefaultGraphEngineStore();\n return { name, config, state };\n}\n\n// ============================================================================\n// Persistence: snapshot / restore\n// ============================================================================\n\n/**\n * Serialize a LiveGraph to a plain JSON-safe object.\n * Can be persisted to disk, database, etc.\n */\nexport function snapshot(live: LiveGraph): LiveGraphSnapshot {\n return {\n version: 1,\n config: live.config,\n state: live.state,\n snapshotAt: new Date().toISOString(),\n };\n}\n\n/**\n * Restore a LiveGraph from a snapshot. Validates the shape.\n * Throws if the snapshot is invalid.\n */\nexport function restore(data: unknown): LiveGraph {\n if (!data || typeof data !== 'object') {\n throw new Error('Invalid snapshot: expected an object');\n }\n\n const snap = data as Record<string, unknown>;\n\n if (!snap.config || typeof snap.config !== 'object') {\n throw new Error('Invalid snapshot: missing or invalid \"config\"');\n }\n if (!snap.state || typeof snap.state !== 'object') {\n throw new Error('Invalid snapshot: missing or invalid \"state\"');\n }\n\n const config = snap.config as GraphConfig;\n const state = snap.state as ExecutionState;\n\n if (!config.settings || typeof config.settings !== 'object') {\n throw new Error('Invalid snapshot: config.settings missing');\n }\n if (!config.tasks || typeof config.tasks !== 'object') {\n throw new Error('Invalid snapshot: config.tasks missing');\n }\n if (!state.tasks || typeof state.tasks !== 'object') {\n throw new Error('Invalid snapshot: state.tasks missing');\n }\n if (!Array.isArray(state.availableOutputs)) {\n throw new Error('Invalid snapshot: state.availableOutputs must be an array');\n }\n\n return { config, state };\n}\n\n// ============================================================================\n// Internals\n// ============================================================================\n\nfunction createDefaultGraphEngineStore(): GraphEngineStore {\n return {\n status: 'not-started',\n executionCount: 0,\n retryCount: 0,\n lastEpoch: 0,\n messages: [],\n progress: null,\n };\n}\n\nfunction applyAgentAction(\n state: ExecutionState,\n action: 'start' | 'stop' | 'pause' | 'resume',\n): ExecutionState {\n const now = new Date().toISOString();\n switch (action) {\n case 'stop':\n return { ...state, status: 'stopped', lastUpdated: now };\n case 'pause':\n return { ...state, status: 'paused', lastUpdated: now };\n case 'resume':\n return { ...state, status: 'running', lastUpdated: now };\n default:\n return state;\n }\n}\n","/**\n * Inference — Core\n *\n * LLM inference layer for continuous-event-graph.\n * Pluggable adapter pattern: yaml-flow builds the prompt and parses the\n * response; the caller provides the LLM via an InferenceAdapter.\n *\n * Core pattern:\n * buildInferencePrompt(live) → prompt string (pure, sync)\n * inferCompletions(live, adapter, opts) → InferenceResult (async, calls LLM)\n * applyInferences(live, result, thresh) → LiveGraph (pure, sync)\n * inferAndApply(live, adapter, opts) → InferAndApplyResult (async, convenience)\n */\n\nimport type { LiveGraph } from '../continuous-event-graph/types.js';\nimport type {\n InferenceAdapter,\n InferenceOptions,\n InferenceResult,\n InferredCompletion,\n InferAndApplyResult,\n} from './types.js';\nimport { getAllTasks } from '../event-graph/graph-helpers.js';\nimport { getRequires, getProvides } from '../event-graph/graph-helpers.js';\nimport { applyEvent } from '../continuous-event-graph/core.js';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst DEFAULT_THRESHOLD = 0.5;\n\nconst DEFAULT_SYSTEM_PROMPT = `You are a workflow completion analyzer. Given a graph of tasks with their current states, evidence, and inference hints, determine which tasks appear to be completed based on the available evidence.\n\nFor each task you analyze, provide a JSON response. Be conservative — only mark tasks as completed when the evidence strongly supports it.`;\n\n// ============================================================================\n// buildInferencePrompt — pure, sync\n// ============================================================================\n\n/**\n * Build an LLM prompt from the current LiveGraph state.\n * Includes only nodes that are:\n * - Not yet completed\n * - Have `inference.autoDetectable` set to true (or are in scope)\n *\n * Pure function — no side effects.\n */\nexport function buildInferencePrompt(\n live: LiveGraph,\n options: InferenceOptions = {},\n): string {\n const { scope, context, systemPrompt } = options;\n const graphTasks = getAllTasks(live.config);\n const { state } = live;\n\n // Determine which nodes to analyze\n const candidates = getAnalyzableCandidates(live, scope);\n\n if (candidates.length === 0) {\n return '';\n }\n\n const lines: string[] = [];\n\n // System context\n lines.push(systemPrompt || DEFAULT_SYSTEM_PROMPT);\n lines.push('');\n\n // Graph overview\n lines.push('## Graph State');\n lines.push('');\n lines.push(`Available tokens: ${state.availableOutputs.length > 0 ? state.availableOutputs.join(', ') : '(none)'}`);\n lines.push('');\n\n // Completed tasks (for context)\n const completedTasks = Object.entries(state.tasks)\n .filter(([_, ts]) => ts.status === 'completed')\n .map(([name]) => name);\n if (completedTasks.length > 0) {\n lines.push(`Completed tasks: ${completedTasks.join(', ')}`);\n lines.push('');\n }\n\n // Candidate nodes\n lines.push('## Tasks to Analyze');\n lines.push('');\n\n for (const taskName of candidates) {\n const taskConfig = graphTasks[taskName];\n const taskState = state.tasks[taskName];\n\n lines.push(`### ${taskName}`);\n if (taskConfig.description) {\n lines.push(`Description: ${taskConfig.description}`);\n }\n\n const requires = getRequires(taskConfig);\n const provides = getProvides(taskConfig);\n if (requires.length > 0) lines.push(`Requires: ${requires.join(', ')}`);\n if (provides.length > 0) lines.push(`Provides: ${provides.join(', ')}`);\n lines.push(`Current status: ${taskState?.status || 'not-started'}`);\n\n // Inference hints\n const hints = taskConfig.inference;\n if (hints) {\n if (hints.criteria) lines.push(`Completion criteria: ${hints.criteria}`);\n if (hints.keywords?.length) lines.push(`Keywords: ${hints.keywords.join(', ')}`);\n if (hints.suggestedChecks?.length) lines.push(`Suggested checks: ${hints.suggestedChecks.join('; ')}`);\n }\n\n lines.push('');\n }\n\n // Additional evidence/context\n if (context) {\n lines.push('## Additional Context / Evidence');\n lines.push('');\n lines.push(context);\n lines.push('');\n }\n\n // Response format instructions\n lines.push('## Response Format');\n lines.push('');\n lines.push('Respond with a JSON array of objects, one per task you have evidence for:');\n lines.push('```json');\n lines.push('[');\n lines.push(' {');\n lines.push(' \"taskName\": \"task-name\",');\n lines.push(' \"confidence\": 0.0 to 1.0,');\n lines.push(' \"reasoning\": \"explanation of why you believe this task is complete or not\"');\n lines.push(' }');\n lines.push(']');\n lines.push('```');\n lines.push('');\n lines.push('Rules:');\n lines.push('- Only include tasks from the \"Tasks to Analyze\" section');\n lines.push('- confidence 0.0 = no evidence of completion, 1.0 = certain it is complete');\n lines.push('- If you have no evidence for a task, omit it from the array');\n lines.push('- Be conservative — require clear evidence before high confidence');\n lines.push('- Respond ONLY with the JSON array, no additional text');\n\n return lines.join('\\n');\n}\n\n// ============================================================================\n// inferCompletions — async, calls LLM\n// ============================================================================\n\n/**\n * Ask an LLM to analyze the current graph state and suggest completions.\n *\n * Builds a prompt from the LiveGraph, sends it through the adapter,\n * parses the structured response, and returns an InferenceResult.\n */\nexport async function inferCompletions(\n live: LiveGraph,\n adapter: InferenceAdapter,\n options: InferenceOptions = {},\n): Promise<InferenceResult> {\n const threshold = options.threshold ?? DEFAULT_THRESHOLD;\n const analyzedNodes = getAnalyzableCandidates(live, options.scope);\n\n // Nothing to analyze\n if (analyzedNodes.length === 0) {\n return { suggestions: [], promptUsed: '', rawResponse: '', analyzedNodes: [] };\n }\n\n const prompt = buildInferencePrompt(live, options);\n const rawResponse = await adapter.analyze(prompt);\n const suggestions = parseInferenceResponse(rawResponse, analyzedNodes, threshold);\n\n return {\n suggestions,\n promptUsed: prompt,\n rawResponse,\n analyzedNodes,\n };\n}\n\n// ============================================================================\n// applyInferences — pure, sync\n// ============================================================================\n\n/**\n * Apply inferred completions to a LiveGraph.\n * Only applies suggestions at or above the given confidence threshold.\n *\n * Under the hood, this fires `task-started` + `task-completed` events\n * for each accepted suggestion (if the task isn't already running/completed).\n *\n * Pure function — returns a new LiveGraph.\n */\nexport function applyInferences(\n live: LiveGraph,\n result: InferenceResult,\n threshold: number = DEFAULT_THRESHOLD,\n): LiveGraph {\n let current = live;\n\n for (const suggestion of result.suggestions) {\n if (suggestion.confidence < threshold) continue;\n\n const taskState = current.state.tasks[suggestion.taskName];\n if (!taskState) continue;\n\n // Skip already completed or running tasks\n if (taskState.status === 'completed' || taskState.status === 'running') continue;\n\n // Apply start + complete events\n const now = new Date().toISOString();\n current = applyEvent(current, {\n type: 'task-started',\n taskName: suggestion.taskName,\n timestamp: now,\n });\n current = applyEvent(current, {\n type: 'task-completed',\n taskName: suggestion.taskName,\n timestamp: now,\n result: 'llm-inferred',\n });\n }\n\n return current;\n}\n\n// ============================================================================\n// inferAndApply — async, convenience\n// ============================================================================\n\n/**\n * Convenience: infer completions and apply them in one step.\n * Returns the updated LiveGraph + full audit trail of what was inferred vs applied.\n */\nexport async function inferAndApply(\n live: LiveGraph,\n adapter: InferenceAdapter,\n options: InferenceOptions = {},\n): Promise<InferAndApplyResult> {\n const threshold = options.threshold ?? DEFAULT_THRESHOLD;\n const inference = await inferCompletions(live, adapter, options);\n const updated = applyInferences(live, inference, threshold);\n\n const applied = inference.suggestions.filter(s => s.confidence >= threshold);\n const skipped = inference.suggestions.filter(s => s.confidence < threshold);\n\n return {\n live: updated,\n inference,\n applied,\n skipped,\n };\n}\n\n// ============================================================================\n// Internals\n// ============================================================================\n\n/**\n * Determine which nodes should be analyzed.\n * - If scope is provided, use those (filtered to non-completed with hints)\n * - Otherwise, find all non-completed nodes with `inference.autoDetectable === true`\n */\nfunction getAnalyzableCandidates(live: LiveGraph, scope?: string[]): string[] {\n const graphTasks = getAllTasks(live.config);\n const { state } = live;\n\n const candidates: string[] = [];\n\n for (const [name, config] of Object.entries(graphTasks)) {\n const taskState = state.tasks[name];\n\n // Skip completed/running tasks\n if (taskState?.status === 'completed' || taskState?.status === 'running') continue;\n\n if (scope) {\n // If scope is provided, include if name is in scope\n if (scope.includes(name)) candidates.push(name);\n } else {\n // Otherwise, include only if autoDetectable\n if (config.inference?.autoDetectable) candidates.push(name);\n }\n }\n\n return candidates;\n}\n\n/**\n * Parse the LLM's raw response into structured InferredCompletion objects.\n * Handles edge cases: markdown fences, preamble text, malformed JSON.\n */\nfunction parseInferenceResponse(\n rawResponse: string,\n validNodes: string[],\n _threshold: number,\n): InferredCompletion[] {\n const validSet = new Set(validNodes);\n\n try {\n // Try to extract JSON from the response (handle markdown fences, preamble, etc.)\n const jsonStr = extractJson(rawResponse);\n if (!jsonStr) return [];\n\n const parsed = JSON.parse(jsonStr);\n\n // Must be an array\n if (!Array.isArray(parsed)) return [];\n\n const suggestions: InferredCompletion[] = [];\n\n for (const item of parsed) {\n // Validate shape\n if (!item || typeof item !== 'object') continue;\n if (typeof item.taskName !== 'string') continue;\n if (typeof item.confidence !== 'number') continue;\n\n // Must reference a valid node\n if (!validSet.has(item.taskName)) continue;\n\n // Clamp confidence to [0, 1]\n const confidence = Math.max(0, Math.min(1, item.confidence));\n\n suggestions.push({\n taskName: item.taskName,\n confidence,\n reasoning: typeof item.reasoning === 'string' ? item.reasoning : '',\n detectionMethod: 'llm-inferred',\n });\n }\n\n return suggestions;\n } catch {\n // JSON parse failed — return empty\n return [];\n }\n}\n\n/**\n * Extract JSON array from raw LLM text.\n * Handles: bare JSON, markdown-fenced JSON, preamble/postamble text.\n */\nfunction extractJson(text: string): string | null {\n if (!text || typeof text !== 'string') return null;\n\n const trimmed = text.trim();\n\n // Try 1: Markdown fence (```json ... ``` or ``` ... ```)\n const fenceMatch = trimmed.match(/```(?:json)?\\s*\\n?([\\s\\S]*?)\\n?\\s*```/);\n if (fenceMatch) return fenceMatch[1].trim();\n\n // Try 2: Find first [ ... last ]\n const firstBracket = trimmed.indexOf('[');\n const lastBracket = trimmed.lastIndexOf(']');\n if (firstBracket !== -1 && lastBracket > firstBracket) {\n return trimmed.slice(firstBracket, lastBracket + 1);\n }\n\n // Try 3: Maybe it's bare JSON\n if (trimmed.startsWith('[')) return trimmed;\n\n return null;\n}\n","/**\n * Inference — Built-in Adapter Factories\n *\n * Ready-made adapter constructors for common LLM interfaces.\n * Each returns an InferenceAdapter.\n *\n * CLI adapters spawn a child process and capture stdout.\n * HTTP adapters POST to an endpoint and read the response.\n */\n\nimport { execFile } from 'node:child_process';\nimport type { InferenceAdapter } from './types.js';\n\n// ============================================================================\n// CLI Adapter — execute any local command\n// ============================================================================\n\nexport interface CliAdapterOptions {\n /** The command to execute (e.g., 'gh', 'ollama', 'llm') */\n command: string;\n /**\n * Arguments builder: receives the prompt and returns the args array.\n * The prompt is passed as an argument — NOT via stdin — unless you override.\n *\n * @example gh copilot: (prompt) => ['copilot', 'suggest', '-t', 'shell', prompt]\n * @example ollama: (prompt) => ['run', 'llama3', prompt]\n * @example llm cli: (prompt) => ['--model', 'gpt-4o', prompt]\n */\n args: (prompt: string) => string[];\n /** Max execution time in ms (default: 60000) */\n timeout?: number;\n /** Working directory for the child process */\n cwd?: string;\n /** Environment variables to pass to the child process */\n env?: Record<string, string>;\n /**\n * If true, pass the prompt via stdin instead of as a CLI argument.\n * Useful for long prompts that exceed shell argument limits.\n * Default: false\n */\n stdin?: boolean;\n}\n\n/**\n * Create an InferenceAdapter that executes a local CLI command.\n * The prompt is passed as a CLI argument (or via stdin if opts.stdin=true).\n * stdout is captured as the LLM response.\n *\n * @example\n * // GitHub Copilot CLI\n * const adapter = createCliAdapter({\n * command: 'gh',\n * args: (prompt) => ['copilot', 'suggest', '-t', 'shell', prompt],\n * });\n *\n * @example\n * // Ollama (local LLM)\n * const adapter = createCliAdapter({\n * command: 'ollama',\n * args: (prompt) => ['run', 'llama3', prompt],\n * });\n *\n * @example\n * // Simon Willison's llm CLI\n * const adapter = createCliAdapter({\n * command: 'llm',\n * args: (prompt) => ['--model', 'gpt-4o', prompt],\n * });\n *\n * @example\n * // Any script (stdin mode for long prompts)\n * const adapter = createCliAdapter({\n * command: 'python',\n * args: () => ['my_llm_script.py'],\n * stdin: true,\n * });\n */\nexport function createCliAdapter(opts: CliAdapterOptions): InferenceAdapter {\n const timeout = opts.timeout ?? 60_000;\n\n return {\n analyze: (prompt: string): Promise<string> => {\n return new Promise((resolve, reject) => {\n const args = opts.args(prompt);\n\n const child = execFile(\n opts.command,\n opts.stdin ? opts.args('') : args,\n {\n timeout,\n cwd: opts.cwd,\n env: opts.env ? { ...process.env, ...opts.env } : undefined,\n maxBuffer: 10 * 1024 * 1024, // 10MB\n },\n (error, stdout, stderr) => {\n if (error) {\n reject(new Error(\n `CLI adapter failed: ${opts.command} exited with ${error.code ?? 'error'}` +\n (stderr ? `\\nstderr: ${stderr.slice(0, 500)}` : '') +\n `\\n${error.message}`,\n ));\n } else {\n resolve(stdout);\n }\n },\n );\n\n // If stdin mode, write the prompt to the child's stdin\n if (opts.stdin && child.stdin) {\n child.stdin.write(prompt);\n child.stdin.end();\n }\n });\n },\n };\n}\n\n// ============================================================================\n// HTTP Adapter — POST to any endpoint\n// ============================================================================\n\nexport interface HttpAdapterOptions {\n /** The endpoint URL to POST to */\n url: string;\n /** Additional headers (Authorization, etc.) */\n headers?: Record<string, string>;\n /**\n * Build the request body from the prompt.\n * Default: `{ prompt }`\n */\n buildBody?: (prompt: string) => unknown;\n /**\n * Extract the response text from the parsed JSON response.\n * Default: `(json) => json.response ?? json.text ?? json.content ?? JSON.stringify(json)`\n */\n extractResponse?: (json: Record<string, unknown>) => string;\n /** Request timeout in ms (default: 60000) */\n timeout?: number;\n}\n\n/**\n * Create an InferenceAdapter that POSTs to an HTTP endpoint.\n *\n * @example\n * // Ollama HTTP API\n * const adapter = createHttpAdapter({\n * url: 'http://localhost:11434/api/generate',\n * buildBody: (prompt) => ({ model: 'llama3', prompt, stream: false }),\n * extractResponse: (json) => json.response as string,\n * });\n *\n * @example\n * // Custom API with auth\n * const adapter = createHttpAdapter({\n * url: 'https://my-llm.example.com/analyze',\n * headers: { Authorization: `Bearer ${process.env.API_KEY}` },\n * });\n */\nexport function createHttpAdapter(opts: HttpAdapterOptions): InferenceAdapter {\n const timeout = opts.timeout ?? 60_000;\n\n return {\n analyze: async (prompt: string): Promise<string> => {\n const body = opts.buildBody ? opts.buildBody(prompt) : { prompt };\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeout);\n\n try {\n const response = await fetch(opts.url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(opts.headers ?? {}),\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n throw new Error(`HTTP ${response.status}: ${text.slice(0, 500)}`);\n }\n\n const json = await response.json() as Record<string, unknown>;\n\n if (opts.extractResponse) {\n return opts.extractResponse(json);\n }\n\n // Default extraction: try common response fields\n if (typeof json.response === 'string') return json.response;\n if (typeof json.text === 'string') return json.text;\n if (typeof json.content === 'string') return json.content;\n return JSON.stringify(json);\n } finally {\n clearTimeout(timer);\n }\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { f as GraphEvent } from './types-CMFSIjpc.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Continuous Event Graph — Journal
|
|
5
|
+
*
|
|
6
|
+
* Append-only event log for the reactive layer.
|
|
7
|
+
* Handlers append events here; drain() reads and clears atomically.
|
|
8
|
+
*
|
|
9
|
+
* Adapter:
|
|
10
|
+
* - MemoryJournal: in-process array (default)
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
interface Journal {
|
|
14
|
+
/** Append an event to the journal. Safe to call from concurrent callbacks. */
|
|
15
|
+
append(event: GraphEvent): void;
|
|
16
|
+
/** Read all pending events and clear the journal atomically. */
|
|
17
|
+
drain(): GraphEvent[];
|
|
18
|
+
/** Number of pending events (for observability). */
|
|
19
|
+
readonly size: number;
|
|
20
|
+
}
|
|
21
|
+
declare class MemoryJournal implements Journal {
|
|
22
|
+
private buffer;
|
|
23
|
+
append(event: GraphEvent): void;
|
|
24
|
+
drain(): GraphEvent[];
|
|
25
|
+
get size(): number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export { type Journal as J, MemoryJournal as M };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { f as GraphEvent } from './types-CMFSIjpc.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Continuous Event Graph — Journal
|
|
5
|
+
*
|
|
6
|
+
* Append-only event log for the reactive layer.
|
|
7
|
+
* Handlers append events here; drain() reads and clears atomically.
|
|
8
|
+
*
|
|
9
|
+
* Adapter:
|
|
10
|
+
* - MemoryJournal: in-process array (default)
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
interface Journal {
|
|
14
|
+
/** Append an event to the journal. Safe to call from concurrent callbacks. */
|
|
15
|
+
append(event: GraphEvent): void;
|
|
16
|
+
/** Read all pending events and clear the journal atomically. */
|
|
17
|
+
drain(): GraphEvent[];
|
|
18
|
+
/** Number of pending events (for observability). */
|
|
19
|
+
readonly size: number;
|
|
20
|
+
}
|
|
21
|
+
declare class MemoryJournal implements Journal {
|
|
22
|
+
private buffer;
|
|
23
|
+
append(event: GraphEvent): void;
|
|
24
|
+
drain(): GraphEvent[];
|
|
25
|
+
get size(): number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export { type Journal as J, MemoryJournal as M };
|