yaml-flow 5.4.2 → 6.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.
Files changed (199) hide show
  1. package/board-live-cards-cli.js +2 -2
  2. package/board-livecards-server-runtime.js +486 -547
  3. package/browser/asset-integrity.json +10 -0
  4. package/browser/board-livegraph-engine.js +2 -1676
  5. package/browser/board-livegraph-engine.js.map +1 -1
  6. package/browser/live-cards.js +347 -26
  7. package/browser/live-cards.schema.json +418 -132
  8. package/card-store.js +37 -0
  9. package/dist/batch/index.cjs +1 -108
  10. package/dist/batch/index.cjs.map +1 -1
  11. package/dist/batch/index.js +1 -106
  12. package/dist/batch/index.js.map +1 -1
  13. package/dist/board-live-cards-lib-Bg6EvCo5.d.cts +136 -0
  14. package/dist/board-live-cards-lib-jM2uYG1v.d.ts +136 -0
  15. package/dist/board-live-cards-public-CltXYgaY.d.cts +314 -0
  16. package/dist/board-live-cards-public-f-E-FAyp.d.ts +314 -0
  17. package/dist/board-livegraph-runtime/index.cjs +2 -1671
  18. package/dist/board-livegraph-runtime/index.cjs.map +1 -1
  19. package/dist/board-livegraph-runtime/index.d.cts +1 -2
  20. package/dist/board-livegraph-runtime/index.d.ts +1 -2
  21. package/dist/board-livegraph-runtime/index.js +2 -1662
  22. package/dist/board-livegraph-runtime/index.js.map +1 -1
  23. package/dist/board-livegraph-runtime/jsonata-sync.cjs +7587 -0
  24. package/dist/card-compute/index.cjs +9 -7159
  25. package/dist/card-compute/index.cjs.map +1 -1
  26. package/dist/card-compute/index.d.cts +22 -0
  27. package/dist/card-compute/index.d.ts +22 -0
  28. package/dist/card-compute/index.js +9 -7145
  29. package/dist/card-compute/index.js.map +1 -1
  30. package/dist/card-compute/jsonata-sync.cjs +7587 -0
  31. package/dist/cli/browser-api/board-live-cards-browser-adapter.cjs +2 -0
  32. package/dist/cli/browser-api/board-live-cards-browser-adapter.cjs.map +1 -0
  33. package/dist/cli/browser-api/board-live-cards-browser-adapter.d.cts +24 -0
  34. package/dist/cli/browser-api/board-live-cards-browser-adapter.d.ts +24 -0
  35. package/dist/cli/browser-api/board-live-cards-browser-adapter.js +2 -0
  36. package/dist/cli/browser-api/board-live-cards-browser-adapter.js.map +1 -0
  37. package/dist/cli/browser-api/card-store-browser-api.cjs +2 -0
  38. package/dist/cli/browser-api/card-store-browser-api.cjs.map +1 -0
  39. package/dist/cli/browser-api/card-store-browser-api.d.cts +26 -0
  40. package/dist/cli/browser-api/card-store-browser-api.d.ts +26 -0
  41. package/dist/cli/browser-api/card-store-browser-api.js +2 -0
  42. package/dist/cli/browser-api/card-store-browser-api.js.map +1 -0
  43. package/dist/cli/browser-api/jsonata-sync.cjs +7587 -0
  44. package/dist/cli/node/artifacts-store-cli.cjs +11 -0
  45. package/dist/cli/node/artifacts-store-cli.cjs.map +1 -0
  46. package/dist/cli/node/artifacts-store-cli.d.cts +8 -0
  47. package/dist/cli/node/artifacts-store-cli.d.ts +8 -0
  48. package/dist/cli/node/artifacts-store-cli.js +11 -0
  49. package/dist/cli/node/artifacts-store-cli.js.map +1 -0
  50. package/dist/cli/node/board-live-cards-cli.cjs +15 -0
  51. package/dist/cli/node/board-live-cards-cli.cjs.map +1 -0
  52. package/dist/cli/node/board-live-cards-cli.d.cts +20 -0
  53. package/dist/cli/node/board-live-cards-cli.d.ts +20 -0
  54. package/dist/cli/node/board-live-cards-cli.js +15 -0
  55. package/dist/cli/node/board-live-cards-cli.js.map +1 -0
  56. package/dist/cli/node/card-store-cli.cjs +8 -0
  57. package/dist/cli/node/card-store-cli.cjs.map +1 -0
  58. package/dist/cli/node/card-store-cli.d.cts +15 -0
  59. package/dist/cli/node/card-store-cli.d.ts +15 -0
  60. package/dist/cli/node/card-store-cli.js +8 -0
  61. package/dist/cli/node/card-store-cli.js.map +1 -0
  62. package/dist/cli/node/fs-board-adapter.cjs +14 -0
  63. package/dist/cli/node/fs-board-adapter.cjs.map +1 -0
  64. package/dist/cli/node/fs-board-adapter.d.cts +204 -0
  65. package/dist/cli/node/fs-board-adapter.d.ts +204 -0
  66. package/dist/cli/node/fs-board-adapter.js +14 -0
  67. package/dist/cli/node/fs-board-adapter.js.map +1 -0
  68. package/dist/cli/node/jsonata-sync.cjs +7587 -0
  69. package/dist/cli/node/source-cli-task-executor.cjs +11 -0
  70. package/dist/cli/node/source-cli-task-executor.cjs.map +1 -0
  71. package/dist/cli/node/source-cli-task-executor.d.cts +1 -0
  72. package/dist/cli/node/source-cli-task-executor.d.ts +1 -0
  73. package/dist/cli/node/source-cli-task-executor.js +11 -0
  74. package/dist/cli/node/source-cli-task-executor.js.map +1 -0
  75. package/dist/config/index.cjs +1 -79
  76. package/dist/config/index.cjs.map +1 -1
  77. package/dist/config/index.js +1 -76
  78. package/dist/config/index.js.map +1 -1
  79. package/dist/continuous-event-graph/index.cjs +2 -2129
  80. package/dist/continuous-event-graph/index.cjs.map +1 -1
  81. package/dist/continuous-event-graph/index.d.cts +81 -5
  82. package/dist/continuous-event-graph/index.d.ts +81 -5
  83. package/dist/continuous-event-graph/index.js +2 -2088
  84. package/dist/continuous-event-graph/index.js.map +1 -1
  85. package/dist/continuous-event-graph/jsonata-sync.cjs +7587 -0
  86. package/dist/event-graph/index.cjs +22 -8292
  87. package/dist/event-graph/index.cjs.map +1 -1
  88. package/dist/event-graph/index.js +22 -8237
  89. package/dist/event-graph/index.js.map +1 -1
  90. package/dist/execution-refs.cjs +2 -0
  91. package/dist/execution-refs.cjs.map +1 -0
  92. package/dist/execution-refs.d.cts +222 -0
  93. package/dist/execution-refs.d.ts +222 -0
  94. package/dist/execution-refs.js +2 -0
  95. package/dist/execution-refs.js.map +1 -0
  96. package/dist/index.cjs +29 -13221
  97. package/dist/index.cjs.map +1 -1
  98. package/dist/index.d.cts +2 -4
  99. package/dist/index.d.ts +2 -4
  100. package/dist/index.js +29 -13112
  101. package/dist/index.js.map +1 -1
  102. package/dist/inference/index.cjs +5 -617
  103. package/dist/inference/index.cjs.map +1 -1
  104. package/dist/inference/index.js +5 -610
  105. package/dist/inference/index.js.map +1 -1
  106. package/dist/jsonata-sync.cjs +7587 -0
  107. package/dist/{live-cards-bridge-x5XREkXm.d.cts → live-cards-bridge-BXbVTsna.d.cts} +27 -4
  108. package/dist/{live-cards-bridge-EQjytzI_.d.ts → live-cards-bridge-Ds28XR15.d.ts} +27 -4
  109. package/dist/pycli/quickjs-board-runtime.global.js +9 -0
  110. package/dist/pycli/quickjs-board-runtime.global.js.map +1 -0
  111. package/dist/pycli/quickjs-step-machine-runtime.global.js +5 -0
  112. package/dist/pycli/quickjs-step-machine-runtime.global.js.map +1 -0
  113. package/dist/step-machine/index.cjs +11 -7129
  114. package/dist/step-machine/index.cjs.map +1 -1
  115. package/dist/step-machine/index.js +11 -7113
  116. package/dist/step-machine/index.js.map +1 -1
  117. package/dist/storage-refs.cjs +10 -0
  118. package/dist/storage-refs.cjs.map +1 -0
  119. package/dist/storage-refs.d.cts +92 -0
  120. package/dist/storage-refs.d.ts +92 -0
  121. package/dist/storage-refs.js +10 -0
  122. package/dist/storage-refs.js.map +1 -0
  123. package/dist/stores/file.cjs +1 -114
  124. package/dist/stores/file.cjs.map +1 -1
  125. package/dist/stores/file.js +1 -112
  126. package/dist/stores/file.js.map +1 -1
  127. package/dist/stores/index.cjs +1 -231
  128. package/dist/stores/index.cjs.map +1 -1
  129. package/dist/stores/index.js +1 -227
  130. package/dist/stores/index.js.map +1 -1
  131. package/dist/stores/localStorage.cjs +1 -76
  132. package/dist/stores/localStorage.cjs.map +1 -1
  133. package/dist/stores/localStorage.js +1 -74
  134. package/dist/stores/localStorage.js.map +1 -1
  135. package/dist/stores/memory.cjs +1 -47
  136. package/dist/stores/memory.cjs.map +1 -1
  137. package/dist/stores/memory.js +1 -45
  138. package/dist/stores/memory.js.map +1 -1
  139. package/examples/browser/boards/portfolio-tracker/portfolio-t4.js +292 -0
  140. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-fetch-prices.js +218 -0
  141. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-fetch-prices.py +201 -0
  142. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-inference-adapter.js +25 -16
  143. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-public.js +553 -0
  144. package/examples/browser/boards/portfolio-tracker/portfolio-tracker.py +365 -0
  145. package/examples/cli/step-machine-cli/portfolio-tracker/--base-ref/.runtime-out +1 -0
  146. package/examples/cli/step-machine-cli/portfolio-tracker/--base-ref/board-graph.json +32 -0
  147. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/_board-cli.js +53 -1
  148. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/add-cards-cli.js +15 -6
  149. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/init-board-cli.js +6 -1
  150. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/poll-status-cli.js +57 -0
  151. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/retrigger-cli.js +1 -1
  152. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/status-cli.js +1 -1
  153. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/update-holdings-cli.js +7 -2
  154. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/wait-completed-cli.js +6 -2
  155. package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/_board_pycli.py +97 -0
  156. package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/add-cards.py +50 -0
  157. package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/init-board.py +44 -0
  158. package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/poll-status.py +70 -0
  159. package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/reset-board-dir.py +36 -0
  160. package/examples/cli/step-machine-cli/portfolio-tracker/inline-python-demo.flow.yaml +26 -0
  161. package/examples/cli/step-machine-cli/portfolio-tracker/inline-python-handlers.py +39 -0
  162. package/examples/cli/step-machine-cli/portfolio-tracker/portfolio-tracker-pycli.flow.yaml +80 -0
  163. package/examples/cli/step-machine-cli/portfolio-tracker/portfolio-tracker.flow.yaml +25 -172
  164. package/examples/cli/step-machine-cli/portfolio-tracker/portfolio-tracker.input.json +40 -34
  165. package/examples/cli/step-machine-cli/portfolio-tracker/run-inline-python-demo-pycli.py +46 -0
  166. package/examples/cli/step-machine-cli/portfolio-tracker/run-portfolio-tracker-pycli.py +77 -0
  167. package/examples/cli/step-machine-cli/portfolio-tracker/run-portfolio-tracker.bat +1 -2
  168. package/examples/example-board/agent-instructions.md +11 -5
  169. package/examples/example-board/demo-chat-handler.js +14 -4
  170. package/examples/example-board/demo-server-config.json +1 -0
  171. package/examples/example-board/demo-server.js +14 -7
  172. package/examples/example-board/demo-shell-browser.html +5 -4
  173. package/examples/example-board/demo-shell-with-server.html +6 -5
  174. package/examples/example-board/demo-task-executor.js +81 -35
  175. package/examples/index.html +0 -14
  176. package/examples/step-machine-cli/portfolio-tracker/handlers/_board-cli.js +0 -1
  177. package/examples/step-machine-cli/portfolio-tracker/run-portfolio-tracker.bat +1 -2
  178. package/package.json +39 -3
  179. package/schema/live-cards.schema.json +418 -132
  180. package/dist/cli/board-live-cards-cli.cjs +0 -10650
  181. package/dist/cli/board-live-cards-cli.cjs.map +0 -1
  182. package/dist/cli/board-live-cards-cli.d.cts +0 -179
  183. package/dist/cli/board-live-cards-cli.d.ts +0 -179
  184. package/dist/cli/board-live-cards-cli.js +0 -10598
  185. package/dist/cli/board-live-cards-cli.js.map +0 -1
  186. package/dist/journal-9HEgs7dU.d.ts +0 -28
  187. package/dist/journal-B-JCfQnh.d.cts +0 -28
  188. package/dist/schedule-Cszq9LYY.d.ts +0 -21
  189. package/dist/schedule-qWNL0RQh.d.cts +0 -21
  190. package/examples/browser/boards/portfolio-tracker/cards/holdings-table.json +0 -22
  191. package/examples/browser/boards/portfolio-tracker/cards/portfolio-form.json +0 -16
  192. package/examples/browser/boards/portfolio-tracker/cards/portfolio-risk-assessment.json +0 -28
  193. package/examples/browser/boards/portfolio-tracker/cards/portfolio-value.json +0 -15
  194. package/examples/browser/boards/portfolio-tracker/cards/price-fetch.json +0 -15
  195. package/examples/browser/boards/portfolio-tracker/cards/rebalancing-strategy.json +0 -28
  196. package/examples/browser/boards/portfolio-tracker/fetch-prices.js +0 -43
  197. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-task-executor.cjs +0 -96
  198. package/examples/browser/boards/portfolio-tracker/portfolio-tracker.bat +0 -7
  199. package/examples/browser/boards/portfolio-tracker/portfolio-tracker.js +0 -351
@@ -1,2089 +1,3 @@
1
- import { exec } from 'child_process';
2
- import jsonata2 from 'jsonata';
3
- import 'ajv-formats';
4
-
5
- // src/event-graph/constants.ts
6
- var TASK_STATUS = {
7
- NOT_STARTED: "not-started",
8
- RUNNING: "running",
9
- COMPLETED: "completed",
10
- FAILED: "failed",
11
- INACTIVATED: "inactivated"
12
- };
13
-
14
- // src/event-graph/graph-helpers.ts
15
- function getProvides(task) {
16
- if (!task) return [];
17
- if (Array.isArray(task.provides)) return task.provides;
18
- return [];
19
- }
20
- function getRequires(task) {
21
- if (!task) return [];
22
- if (Array.isArray(task.requires)) return task.requires;
23
- return [];
24
- }
25
- function getAllTasks(graph) {
26
- return graph.tasks ?? {};
27
- }
28
- function isNonActiveTask(taskState) {
29
- if (!taskState) return false;
30
- return taskState.status === TASK_STATUS.FAILED || taskState.status === TASK_STATUS.INACTIVATED;
31
- }
32
- function getRefreshStrategy(taskConfig, graphSettings) {
33
- return taskConfig.refreshStrategy ?? graphSettings?.refreshStrategy ?? "data-changed";
34
- }
35
- function getMaxExecutions(taskConfig) {
36
- return taskConfig.maxExecutions;
37
- }
38
- function computeAvailableOutputs(graph, taskStates) {
39
- const outputs = /* @__PURE__ */ new Set();
40
- for (const [taskName, taskState] of Object.entries(taskStates)) {
41
- if (taskState.status === TASK_STATUS.COMPLETED) {
42
- const taskConfig = graph.tasks[taskName];
43
- if (taskConfig) {
44
- const provides = getProvides(taskConfig);
45
- provides.forEach((output) => outputs.add(output));
46
- }
47
- }
48
- }
49
- return Array.from(outputs);
50
- }
51
- function groupTasksByProvides(candidateTaskNames, tasks) {
52
- const outputGroups = {};
53
- candidateTaskNames.forEach((taskName) => {
54
- const task = tasks[taskName];
55
- if (!task) return;
56
- const provides = getProvides(task);
57
- provides.forEach((output) => {
58
- if (!outputGroups[output]) {
59
- outputGroups[output] = [];
60
- }
61
- outputGroups[output].push(taskName);
62
- });
63
- });
64
- return outputGroups;
65
- }
66
-
67
- // src/event-graph/task-transitions.ts
68
- function applyTaskStart(state, taskName, graph) {
69
- const existingTask = state.tasks[taskName] ?? createDefaultGraphEngineStore();
70
- const startConsumedHashes = {};
71
- if (graph) {
72
- const taskConfig = graph.tasks[taskName];
73
- const requires = getRequires(taskConfig);
74
- for (const token of requires) {
75
- for (const [otherName, otherConfig] of Object.entries(graph.tasks)) {
76
- if (getProvides(otherConfig).includes(token)) {
77
- const otherState = state.tasks[otherName];
78
- if (otherState?.lastDataHash) startConsumedHashes[token] = otherState.lastDataHash;
79
- break;
80
- }
81
- }
82
- }
83
- }
84
- const updatedTask = {
85
- ...existingTask,
86
- status: "running",
87
- startedAt: (/* @__PURE__ */ new Date()).toISOString(),
88
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
89
- progress: 0,
90
- error: void 0,
91
- startConsumedHashes
92
- };
93
- return {
94
- ...state,
95
- tasks: { ...state.tasks, [taskName]: updatedTask },
96
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
97
- };
98
- }
99
- function applyTaskCompletion(state, graph, taskName, result, dataHash, data) {
100
- const existingTask = state.tasks[taskName] ?? createDefaultGraphEngineStore();
101
- const taskConfig = graph.tasks[taskName];
102
- if (!taskConfig) {
103
- throw new Error(`Task "${taskName}" not found in graph`);
104
- }
105
- let outputTokens;
106
- if (result && taskConfig.on && taskConfig.on[result]) {
107
- outputTokens = taskConfig.on[result];
108
- } else {
109
- outputTokens = getProvides(taskConfig);
110
- }
111
- const lastConsumedHashes = existingTask.startConsumedHashes ? { ...existingTask.startConsumedHashes } : { ...existingTask.lastConsumedHashes };
112
- if (!existingTask.startConsumedHashes) {
113
- const requires = taskConfig.requires ?? [];
114
- for (const token of requires) {
115
- for (const [otherName, otherConfig] of Object.entries(graph.tasks)) {
116
- if (getProvides(otherConfig).includes(token)) {
117
- const otherState = state.tasks[otherName];
118
- if (otherState?.lastDataHash) {
119
- lastConsumedHashes[token] = otherState.lastDataHash;
120
- }
121
- break;
122
- }
123
- }
124
- }
125
- }
126
- const updatedTask = {
127
- ...existingTask,
128
- status: "completed",
129
- completedAt: (/* @__PURE__ */ new Date()).toISOString(),
130
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
131
- executionCount: existingTask.executionCount + 1,
132
- lastEpoch: existingTask.executionCount + 1,
133
- lastDataHash: dataHash,
134
- data,
135
- lastConsumedHashes,
136
- error: void 0
137
- };
138
- const newOutputs = [.../* @__PURE__ */ new Set([...state.availableOutputs, ...outputTokens])];
139
- return {
140
- ...state,
141
- tasks: { ...state.tasks, [taskName]: updatedTask },
142
- availableOutputs: newOutputs,
143
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
144
- };
145
- }
146
- function applyTaskFailure(state, graph, taskName, error) {
147
- const existingTask = state.tasks[taskName] ?? createDefaultGraphEngineStore();
148
- const taskConfig = graph.tasks[taskName];
149
- if (taskConfig?.retry) {
150
- const retryCount = existingTask.retryCount + 1;
151
- if (retryCount <= taskConfig.retry.max_attempts) {
152
- const updatedTask2 = {
153
- ...existingTask,
154
- status: "not-started",
155
- retryCount,
156
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
157
- error
158
- };
159
- return {
160
- ...state,
161
- tasks: { ...state.tasks, [taskName]: updatedTask2 },
162
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
163
- };
164
- }
165
- }
166
- const updatedTask = {
167
- ...existingTask,
168
- status: "failed",
169
- failedAt: (/* @__PURE__ */ new Date()).toISOString(),
170
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
171
- error,
172
- executionCount: existingTask.executionCount + 1
173
- };
174
- let newOutputs = state.availableOutputs;
175
- if (taskConfig?.on_failure && taskConfig.on_failure.length > 0) {
176
- newOutputs = [.../* @__PURE__ */ new Set([...state.availableOutputs, ...taskConfig.on_failure])];
177
- }
178
- if (taskConfig?.circuit_breaker && updatedTask.executionCount >= taskConfig.circuit_breaker.max_executions) {
179
- const breakTokens = taskConfig.circuit_breaker.on_break;
180
- newOutputs = [.../* @__PURE__ */ new Set([...newOutputs, ...breakTokens])];
181
- }
182
- return {
183
- ...state,
184
- tasks: { ...state.tasks, [taskName]: updatedTask },
185
- availableOutputs: newOutputs,
186
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
187
- };
188
- }
189
- function applyTaskProgress(state, taskName, message, progress) {
190
- const existingTask = state.tasks[taskName] ?? createDefaultGraphEngineStore();
191
- const updatedTask = {
192
- ...existingTask,
193
- progress: typeof progress === "number" ? progress : existingTask.progress,
194
- messages: [
195
- ...existingTask.messages ?? [],
196
- ...message ? [{ message, timestamp: (/* @__PURE__ */ new Date()).toISOString(), status: existingTask.status }] : []
197
- ],
198
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
199
- };
200
- return {
201
- ...state,
202
- tasks: { ...state.tasks, [taskName]: updatedTask },
203
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
204
- };
205
- }
206
- function applyTaskRestart(state, taskName) {
207
- const existingTask = state.tasks[taskName];
208
- if (!existingTask) return state;
209
- const updatedTask = {
210
- ...existingTask,
211
- status: "not-started",
212
- startedAt: void 0,
213
- completedAt: void 0,
214
- failedAt: void 0,
215
- error: void 0,
216
- data: void 0,
217
- progress: null,
218
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
219
- };
220
- return {
221
- ...state,
222
- tasks: { ...state.tasks, [taskName]: updatedTask },
223
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
224
- };
225
- }
226
- function createDefaultGraphEngineStore() {
227
- return {
228
- status: "not-started",
229
- executionCount: 0,
230
- retryCount: 0,
231
- lastEpoch: 0,
232
- messages: [],
233
- progress: null
234
- };
235
- }
236
-
237
- // src/continuous-event-graph/core.ts
238
- function createLiveGraph(config, executionId) {
239
- const id = executionId ?? `live-${Date.now()}`;
240
- const tasks = {};
241
- for (const taskName of Object.keys(config.tasks)) {
242
- tasks[taskName] = createDefaultGraphEngineStore2();
243
- }
244
- const state = {
245
- status: "running",
246
- tasks,
247
- availableOutputs: [],
248
- stuckDetection: { is_stuck: false, stuck_description: null, outputs_unresolvable: [], tasks_blocked: [] },
249
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
250
- executionId: id,
251
- executionConfig: {
252
- executionMode: config.settings.execution_mode ?? "eligibility-mode",
253
- conflictStrategy: config.settings.conflict_strategy ?? "alphabetical",
254
- completionStrategy: config.settings.completion
255
- }
256
- };
257
- return { config, state };
258
- }
259
- function applyEvent(live, event) {
260
- const { config, state } = live;
261
- if ("executionId" in event && event.executionId && event.executionId !== state.executionId) {
262
- return live;
263
- }
264
- switch (event.type) {
265
- // --- Execution state transitions ---
266
- case "task-started":
267
- return { config, state: applyTaskStart(state, event.taskName, config) };
268
- case "task-completed":
269
- return { config, state: applyTaskCompletion(state, config, event.taskName, event.result, event.dataHash, event.data) };
270
- case "task-failed":
271
- return { config, state: applyTaskFailure(state, config, event.taskName, event.error) };
272
- case "task-progress":
273
- return { config, state: applyTaskProgress(state, event.taskName, event.message, event.progress) };
274
- case "task-restart":
275
- return { config, state: applyTaskRestart(state, event.taskName) };
276
- case "inject-tokens":
277
- return {
278
- config,
279
- state: {
280
- ...state,
281
- availableOutputs: [.../* @__PURE__ */ new Set([...state.availableOutputs, ...event.tokens])],
282
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
283
- }
284
- };
285
- case "agent-action":
286
- return { config, state: applyAgentAction(state, event.action) };
287
- // --- Structural mutations ---
288
- case "task-upsert":
289
- return addNode(live, event.taskName, event.taskConfig);
290
- case "task-removal":
291
- return removeNode(live, event.taskName);
292
- case "node-requires-add":
293
- return addRequires(live, event.nodeName, event.tokens);
294
- case "node-requires-remove":
295
- return removeRequires(live, event.nodeName, event.tokens);
296
- case "node-provides-add":
297
- return addProvides(live, event.nodeName, event.tokens);
298
- case "node-provides-remove":
299
- return removeProvides(live, event.nodeName, event.tokens);
300
- default:
301
- return live;
302
- }
303
- }
304
- function applyEvents(live, events) {
305
- return events.reduce((current, event) => applyEvent(current, event), live);
306
- }
307
- function addNode(live, name, taskConfig) {
308
- const exists = !!live.config.tasks[name];
309
- return {
310
- config: {
311
- ...live.config,
312
- tasks: { ...live.config.tasks, [name]: taskConfig }
313
- },
314
- state: {
315
- ...live.state,
316
- tasks: {
317
- ...live.state.tasks,
318
- [name]: exists ? live.state.tasks[name] : createDefaultGraphEngineStore2()
319
- },
320
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
321
- }
322
- };
323
- }
324
- function removeNode(live, name) {
325
- if (!live.config.tasks[name]) return live;
326
- const { [name]: _removedConfig, ...remainingTasks } = live.config.tasks;
327
- const { [name]: _removedState, ...remainingStates } = live.state.tasks;
328
- return {
329
- config: {
330
- ...live.config,
331
- tasks: remainingTasks
332
- },
333
- state: {
334
- ...live.state,
335
- tasks: remainingStates,
336
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
337
- }
338
- };
339
- }
340
- function addRequires(live, nodeName, tokens) {
341
- const task = live.config.tasks[nodeName];
342
- if (!task) return live;
343
- const current = getRequires(task);
344
- const toAdd = tokens.filter((t) => !current.includes(t));
345
- if (toAdd.length === 0) return live;
346
- return {
347
- config: {
348
- ...live.config,
349
- tasks: {
350
- ...live.config.tasks,
351
- [nodeName]: { ...task, requires: [...current, ...toAdd] }
352
- }
353
- },
354
- state: live.state
355
- };
356
- }
357
- function removeRequires(live, nodeName, tokens) {
358
- const task = live.config.tasks[nodeName];
359
- if (!task) return live;
360
- const current = getRequires(task);
361
- const remaining = current.filter((t) => !tokens.includes(t));
362
- if (remaining.length === current.length) return live;
363
- return {
364
- config: {
365
- ...live.config,
366
- tasks: {
367
- ...live.config.tasks,
368
- [nodeName]: { ...task, requires: remaining }
369
- }
370
- },
371
- state: live.state
372
- };
373
- }
374
- function addProvides(live, nodeName, tokens) {
375
- const task = live.config.tasks[nodeName];
376
- if (!task) return live;
377
- const current = getProvides(task);
378
- const toAdd = tokens.filter((t) => !current.includes(t));
379
- if (toAdd.length === 0) return live;
380
- return {
381
- config: {
382
- ...live.config,
383
- tasks: {
384
- ...live.config.tasks,
385
- [nodeName]: { ...task, provides: [...current, ...toAdd] }
386
- }
387
- },
388
- state: live.state
389
- };
390
- }
391
- function removeProvides(live, nodeName, tokens) {
392
- const task = live.config.tasks[nodeName];
393
- if (!task) return live;
394
- const current = getProvides(task);
395
- const remaining = current.filter((t) => !tokens.includes(t));
396
- if (remaining.length === current.length) return live;
397
- return {
398
- config: {
399
- ...live.config,
400
- tasks: {
401
- ...live.config.tasks,
402
- [nodeName]: { ...task, provides: remaining }
403
- }
404
- },
405
- state: live.state
406
- };
407
- }
408
- function injectTokens(live, tokens) {
409
- return applyEvent(live, {
410
- type: "inject-tokens",
411
- tokens,
412
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
413
- });
414
- }
415
- function drainTokens(live, tokens) {
416
- const toRemove = new Set(tokens);
417
- const remaining = live.state.availableOutputs.filter((t) => !toRemove.has(t));
418
- if (remaining.length === live.state.availableOutputs.length) return live;
419
- return {
420
- config: live.config,
421
- state: {
422
- ...live.state,
423
- availableOutputs: remaining,
424
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
425
- }
426
- };
427
- }
428
- function resetNode(live, name) {
429
- if (!live.config.tasks[name] || !live.state.tasks[name]) return live;
430
- return {
431
- config: live.config,
432
- state: {
433
- ...live.state,
434
- tasks: {
435
- ...live.state.tasks,
436
- [name]: createDefaultGraphEngineStore2()
437
- },
438
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
439
- }
440
- };
441
- }
442
- function disableNode(live, name) {
443
- const taskState = live.state.tasks[name];
444
- if (!taskState || taskState.status === "inactivated") return live;
445
- return {
446
- config: live.config,
447
- state: {
448
- ...live.state,
449
- tasks: {
450
- ...live.state.tasks,
451
- [name]: { ...taskState, status: "inactivated", lastUpdated: (/* @__PURE__ */ new Date()).toISOString() }
452
- },
453
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
454
- }
455
- };
456
- }
457
- function enableNode(live, name) {
458
- const taskState = live.state.tasks[name];
459
- if (!taskState || taskState.status !== "inactivated") return live;
460
- return {
461
- config: live.config,
462
- state: {
463
- ...live.state,
464
- tasks: {
465
- ...live.state.tasks,
466
- [name]: { ...taskState, status: "not-started", lastUpdated: (/* @__PURE__ */ new Date()).toISOString() }
467
- },
468
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
469
- }
470
- };
471
- }
472
- function getNode(live, name) {
473
- const config = live.config.tasks[name];
474
- if (!config) return void 0;
475
- const state = live.state.tasks[name] ?? createDefaultGraphEngineStore2();
476
- return { name, config, state };
477
- }
478
- function snapshot(live) {
479
- return {
480
- version: 1,
481
- config: live.config,
482
- state: live.state,
483
- snapshotAt: (/* @__PURE__ */ new Date()).toISOString()
484
- };
485
- }
486
- function restore(data) {
487
- if (!data || typeof data !== "object") {
488
- throw new Error("Invalid snapshot: expected an object");
489
- }
490
- const snap = data;
491
- if (!snap.config || typeof snap.config !== "object") {
492
- throw new Error('Invalid snapshot: missing or invalid "config"');
493
- }
494
- if (!snap.state || typeof snap.state !== "object") {
495
- throw new Error('Invalid snapshot: missing or invalid "state"');
496
- }
497
- const config = snap.config;
498
- const state = snap.state;
499
- if (!config.settings || typeof config.settings !== "object") {
500
- throw new Error("Invalid snapshot: config.settings missing");
501
- }
502
- if (!config.tasks || typeof config.tasks !== "object") {
503
- throw new Error("Invalid snapshot: config.tasks missing");
504
- }
505
- if (!state.tasks || typeof state.tasks !== "object") {
506
- throw new Error("Invalid snapshot: state.tasks missing");
507
- }
508
- if (!Array.isArray(state.availableOutputs)) {
509
- throw new Error("Invalid snapshot: state.availableOutputs must be an array");
510
- }
511
- return { config, state };
512
- }
513
- function createDefaultGraphEngineStore2() {
514
- return {
515
- status: "not-started",
516
- executionCount: 0,
517
- retryCount: 0,
518
- lastEpoch: 0,
519
- messages: [],
520
- progress: null
521
- };
522
- }
523
- function applyAgentAction(state, action) {
524
- const now = (/* @__PURE__ */ new Date()).toISOString();
525
- switch (action) {
526
- case "stop":
527
- return { ...state, status: "stopped", lastUpdated: now };
528
- case "pause":
529
- return { ...state, status: "paused", lastUpdated: now };
530
- case "resume":
531
- return { ...state, status: "running", lastUpdated: now };
532
- default:
533
- return state;
534
- }
535
- }
536
-
537
- // src/continuous-event-graph/schedule.ts
538
- function schedule(live) {
539
- const { config, state } = live;
540
- const graphTasks = getAllTasks(config);
541
- const taskNames = Object.keys(graphTasks);
542
- if (taskNames.length === 0) {
543
- return { eligible: [], pending: [], unresolved: [], blocked: [], conflicts: {} };
544
- }
545
- const producerMap = buildProducerMap(graphTasks);
546
- const computedOutputs = computeAvailableOutputs(config, state.tasks);
547
- const availableOutputs = /* @__PURE__ */ new Set([...computedOutputs, ...state.availableOutputs]);
548
- const eligible = [];
549
- const pending = [];
550
- const unresolved = [];
551
- const blocked = [];
552
- for (const [taskName, taskConfig] of Object.entries(graphTasks)) {
553
- const taskState = state.tasks[taskName];
554
- const strategy = getRefreshStrategy(taskConfig, config.settings);
555
- const rerunnable = strategy !== "once";
556
- if (taskState?.status === TASK_STATUS.RUNNING || isNonActiveTask(taskState)) {
557
- continue;
558
- }
559
- const maxExec = getMaxExecutions(taskConfig);
560
- if (maxExec !== void 0 && taskState && taskState.executionCount >= maxExec) {
561
- continue;
562
- }
563
- if (taskConfig.circuit_breaker && taskState && taskState.executionCount >= taskConfig.circuit_breaker.max_executions) {
564
- continue;
565
- }
566
- if (!rerunnable && taskState?.status === TASK_STATUS.COMPLETED) {
567
- continue;
568
- }
569
- if (rerunnable && taskState?.status === TASK_STATUS.COMPLETED) {
570
- const requires2 = getRequires(taskConfig);
571
- let shouldSkip = false;
572
- switch (strategy) {
573
- case "data-changed": {
574
- if (requires2.length > 0) {
575
- const hasChangedData = requires2.some((req) => {
576
- for (const [otherName, otherConfig] of Object.entries(graphTasks)) {
577
- if (getProvides(otherConfig).includes(req)) {
578
- const otherState = state.tasks[otherName];
579
- if (!otherState) continue;
580
- const consumed = taskState.lastConsumedHashes?.[req];
581
- if (otherState.lastDataHash == null) {
582
- return otherState.executionCount > taskState.lastEpoch;
583
- }
584
- return otherState.lastDataHash !== consumed;
585
- }
586
- }
587
- return false;
588
- });
589
- if (!hasChangedData) shouldSkip = true;
590
- } else {
591
- shouldSkip = true;
592
- }
593
- break;
594
- }
595
- case "epoch-changed": {
596
- if (requires2.length > 0) {
597
- const hasRefreshed = requires2.some((req) => {
598
- for (const [otherName, otherConfig] of Object.entries(graphTasks)) {
599
- if (getProvides(otherConfig).includes(req)) {
600
- const otherState = state.tasks[otherName];
601
- if (otherState && otherState.executionCount > taskState.lastEpoch) return true;
602
- }
603
- }
604
- return false;
605
- });
606
- if (!hasRefreshed) shouldSkip = true;
607
- } else {
608
- shouldSkip = true;
609
- }
610
- break;
611
- }
612
- case "time-based": {
613
- const interval = taskConfig.refreshInterval ?? 0;
614
- if (interval <= 0) {
615
- shouldSkip = true;
616
- break;
617
- }
618
- const completedAt = taskState.completedAt;
619
- if (!completedAt) {
620
- shouldSkip = true;
621
- break;
622
- }
623
- const elapsedSec = (Date.now() - Date.parse(completedAt)) / 1e3;
624
- if (elapsedSec < interval) shouldSkip = true;
625
- break;
626
- }
627
- case "manual":
628
- shouldSkip = true;
629
- break;
630
- }
631
- if (shouldSkip) continue;
632
- }
633
- const requires = getRequires(taskConfig);
634
- if (requires.length === 0) {
635
- eligible.push(taskName);
636
- continue;
637
- }
638
- const missingTokens = [];
639
- const pendingTokens = [];
640
- const failedTokenInfo = [];
641
- for (const token of requires) {
642
- if (availableOutputs.has(token)) continue;
643
- const producers = producerMap[token] || [];
644
- if (producers.length === 0) {
645
- missingTokens.push(token);
646
- } else {
647
- const allFailed = producers.every((p) => isNonActiveTask(state.tasks[p]));
648
- if (allFailed) {
649
- failedTokenInfo.push({ token, failedProducer: producers[0] });
650
- } else {
651
- pendingTokens.push(token);
652
- }
653
- }
654
- }
655
- if (missingTokens.length > 0) {
656
- unresolved.push({ taskName, missingTokens });
657
- } else if (failedTokenInfo.length > 0) {
658
- blocked.push({
659
- taskName,
660
- failedTokens: failedTokenInfo.map((f) => f.token),
661
- failedProducers: [...new Set(failedTokenInfo.map((f) => f.failedProducer))]
662
- });
663
- } else if (pendingTokens.length > 0) {
664
- pending.push({ taskName, waitingOn: pendingTokens });
665
- } else {
666
- eligible.push(taskName);
667
- }
668
- }
669
- const conflicts = {};
670
- if (eligible.length > 1) {
671
- const outputGroups = groupTasksByProvides(eligible, graphTasks);
672
- for (const [outputKey, groupTasks] of Object.entries(outputGroups)) {
673
- if (groupTasks.length > 1) {
674
- conflicts[outputKey] = groupTasks;
675
- }
676
- }
677
- }
678
- return { eligible, pending, unresolved, blocked, conflicts };
679
- }
680
- function buildProducerMap(tasks) {
681
- const map = {};
682
- for (const [name, config] of Object.entries(tasks)) {
683
- for (const token of getProvides(config)) {
684
- if (!map[token]) map[token] = [];
685
- map[token].push(name);
686
- }
687
- if (config.on) {
688
- for (const tokens of Object.values(config.on)) {
689
- for (const token of tokens) {
690
- if (!map[token]) map[token] = [];
691
- if (!map[token].includes(name)) map[token].push(name);
692
- }
693
- }
694
- }
695
- if (config.on_failure) {
696
- for (const token of config.on_failure) {
697
- if (!map[token]) map[token] = [];
698
- if (!map[token].includes(name)) map[token].push(name);
699
- }
700
- }
701
- }
702
- return map;
703
- }
704
-
705
- // src/continuous-event-graph/inspect.ts
706
- function inspect(live) {
707
- const { config, state } = live;
708
- const graphTasks = getAllTasks(config);
709
- const taskNames = Object.keys(graphTasks);
710
- let running = 0, completed = 0, failed = 0, waiting = 0, notStarted = 0, disabled = 0;
711
- for (const taskName of taskNames) {
712
- const ts = state.tasks[taskName];
713
- if (!ts || ts.status === TASK_STATUS.NOT_STARTED) {
714
- notStarted++;
715
- } else {
716
- switch (ts.status) {
717
- case TASK_STATUS.RUNNING:
718
- running++;
719
- break;
720
- case TASK_STATUS.COMPLETED:
721
- completed++;
722
- break;
723
- case TASK_STATUS.FAILED:
724
- failed++;
725
- break;
726
- case "inactivated":
727
- disabled++;
728
- break;
729
- default:
730
- waiting++;
731
- }
732
- }
733
- }
734
- const producerMap = {};
735
- for (const [name, taskConfig] of Object.entries(graphTasks)) {
736
- for (const token of getProvides(taskConfig)) {
737
- if (!producerMap[token]) producerMap[token] = [];
738
- producerMap[token].push(name);
739
- }
740
- if (taskConfig.on) {
741
- for (const tokens of Object.values(taskConfig.on)) {
742
- for (const token of tokens) {
743
- if (!producerMap[token]) producerMap[token] = [];
744
- if (!producerMap[token].includes(name)) producerMap[token].push(name);
745
- }
746
- }
747
- }
748
- if (taskConfig.on_failure) {
749
- for (const token of taskConfig.on_failure) {
750
- if (!producerMap[token]) producerMap[token] = [];
751
- if (!producerMap[token].includes(name)) producerMap[token].push(name);
752
- }
753
- }
754
- }
755
- const openDeps = /* @__PURE__ */ new Set();
756
- let unresolvedCount = 0;
757
- let blockedCount = 0;
758
- for (const [taskName, taskConfig] of Object.entries(graphTasks)) {
759
- const ts = state.tasks[taskName];
760
- if (ts?.status === TASK_STATUS.COMPLETED || ts?.status === TASK_STATUS.RUNNING) continue;
761
- let hasOpen = false;
762
- let hasBlocked = false;
763
- for (const token of getRequires(taskConfig)) {
764
- const producers = producerMap[token] || [];
765
- if (producers.length === 0) {
766
- openDeps.add(token);
767
- hasOpen = true;
768
- } else {
769
- const allFailed = producers.every((p) => {
770
- const ps = state.tasks[p];
771
- return ps?.status === TASK_STATUS.FAILED || ps?.status === "inactivated";
772
- });
773
- if (allFailed) hasBlocked = true;
774
- }
775
- }
776
- if (hasOpen) unresolvedCount++;
777
- if (hasBlocked && !hasOpen) blockedCount++;
778
- }
779
- const conflictTokens = [];
780
- for (const [token, producers] of Object.entries(producerMap)) {
781
- if (producers.length > 1) conflictTokens.push(token);
782
- }
783
- const deps = buildTaskDeps(graphTasks, producerMap);
784
- const cycles = detectCycles(taskNames, deps);
785
- return {
786
- totalNodes: taskNames.length,
787
- running,
788
- completed,
789
- failed,
790
- waiting,
791
- notStarted,
792
- disabled,
793
- unresolvedCount,
794
- blockedCount,
795
- openDependencies: [...openDeps],
796
- cycles,
797
- conflictTokens
798
- };
799
- }
800
- function buildTaskDeps(tasks, producerMap) {
801
- const deps = {};
802
- for (const [name, config] of Object.entries(tasks)) {
803
- deps[name] = /* @__PURE__ */ new Set();
804
- for (const token of getRequires(config)) {
805
- for (const producer of producerMap[token] || []) {
806
- if (producer !== name) deps[name].add(producer);
807
- }
808
- }
809
- }
810
- return deps;
811
- }
812
- function detectCycles(taskNames, deps) {
813
- const WHITE = 0, GRAY = 1, BLACK = 2;
814
- const color = {};
815
- const parent = {};
816
- const cycles = [];
817
- for (const name of taskNames) {
818
- color[name] = WHITE;
819
- parent[name] = null;
820
- }
821
- function dfs(node) {
822
- color[node] = GRAY;
823
- for (const dep of deps[node] || []) {
824
- if (color[dep] === GRAY) {
825
- const cycle = [dep];
826
- let cur = node;
827
- while (cur !== dep) {
828
- cycle.push(cur);
829
- cur = parent[cur];
830
- }
831
- cycle.push(dep);
832
- cycle.reverse();
833
- cycles.push(cycle);
834
- } else if (color[dep] === WHITE) {
835
- parent[dep] = node;
836
- dfs(dep);
837
- }
838
- }
839
- color[node] = BLACK;
840
- }
841
- for (const name of taskNames) {
842
- if (color[name] === WHITE) dfs(name);
843
- }
844
- return cycles;
845
- }
846
- function buildProducerMap2(tasks) {
847
- const map = {};
848
- for (const [name, config] of Object.entries(tasks)) {
849
- for (const token of getProvides(config)) {
850
- if (!map[token]) map[token] = [];
851
- map[token].push(name);
852
- }
853
- if (config.on) {
854
- for (const tokens of Object.values(config.on)) {
855
- for (const token of tokens) {
856
- if (!map[token]) map[token] = [];
857
- if (!map[token].includes(name)) map[token].push(name);
858
- }
859
- }
860
- }
861
- if (config.on_failure) {
862
- for (const token of config.on_failure) {
863
- if (!map[token]) map[token] = [];
864
- if (!map[token].includes(name)) map[token].push(name);
865
- }
866
- }
867
- }
868
- return map;
869
- }
870
- function getUnreachableTokens(live) {
871
- const { config, state } = live;
872
- const graphTasks = getAllTasks(config);
873
- const producerMap = buildProducerMap2(graphTasks);
874
- const available = /* @__PURE__ */ new Set([...state.availableOutputs]);
875
- for (const [taskName, taskState] of Object.entries(state.tasks)) {
876
- if (taskState.status === "completed") {
877
- const tc = graphTasks[taskName];
878
- if (tc) getProvides(tc).forEach((t) => available.add(t));
879
- }
880
- }
881
- const allRequired = /* @__PURE__ */ new Set();
882
- for (const taskConfig of Object.values(graphTasks)) {
883
- for (const token of getRequires(taskConfig)) {
884
- allRequired.add(token);
885
- }
886
- }
887
- const unreachable = /* @__PURE__ */ new Set();
888
- const unreachableNodes = /* @__PURE__ */ new Set();
889
- for (const token of allRequired) {
890
- if (available.has(token)) continue;
891
- const producers = producerMap[token] || [];
892
- if (producers.length === 0) {
893
- unreachable.add(token);
894
- }
895
- }
896
- let changed = true;
897
- while (changed) {
898
- changed = false;
899
- for (const [name, taskConfig] of Object.entries(graphTasks)) {
900
- if (unreachableNodes.has(name)) continue;
901
- const ts = state.tasks[name];
902
- if (ts?.status === "completed") continue;
903
- const isNonActive = isNonActiveTask(ts);
904
- const requires = getRequires(taskConfig);
905
- const hasUnreachableDep = requires.some((t) => unreachable.has(t));
906
- if (isNonActive || hasUnreachableDep) {
907
- if (!unreachableNodes.has(name)) {
908
- unreachableNodes.add(name);
909
- changed = true;
910
- }
911
- }
912
- }
913
- for (const token of allRequired) {
914
- if (unreachable.has(token) || available.has(token)) continue;
915
- const producers = producerMap[token] || [];
916
- const allProducersUnreachable = producers.length > 0 && producers.every((p) => unreachableNodes.has(p) || isNonActiveTask(state.tasks[p]));
917
- if (producers.length === 0 || allProducersUnreachable) {
918
- if (!unreachable.has(token)) {
919
- unreachable.add(token);
920
- changed = true;
921
- }
922
- }
923
- }
924
- }
925
- const tokens = [];
926
- for (const token of unreachable) {
927
- const producers = producerMap[token] || [];
928
- let reason;
929
- if (producers.length === 0) {
930
- reason = "no-producer";
931
- } else {
932
- const allFailed = producers.every((p) => isNonActiveTask(state.tasks[p]));
933
- reason = allFailed ? "all-producers-failed" : "transitive";
934
- }
935
- tokens.push({ token, reason, producers });
936
- }
937
- return { tokens };
938
- }
939
- function getUnreachableNodes(live) {
940
- const { config, state } = live;
941
- const graphTasks = getAllTasks(config);
942
- const { tokens: unreachableTokens } = getUnreachableTokens(live);
943
- const unreachableTokenSet = new Set(unreachableTokens.map((t) => t.token));
944
- const nodes = [];
945
- for (const [name, taskConfig] of Object.entries(graphTasks)) {
946
- const ts = state.tasks[name];
947
- if (ts?.status === "completed") continue;
948
- const requires = getRequires(taskConfig);
949
- const missingTokens = requires.filter((t) => unreachableTokenSet.has(t));
950
- if (missingTokens.length > 0) {
951
- nodes.push({ nodeName: name, missingTokens });
952
- } else if (isNonActiveTask(ts)) {
953
- nodes.push({ nodeName: name, missingTokens: [] });
954
- }
955
- }
956
- return { nodes };
957
- }
958
- function getUpstream(live, nodeName) {
959
- const graphTasks = getAllTasks(live.config);
960
- if (!graphTasks[nodeName]) return { nodeName, nodes: [], tokens: [] };
961
- const producerMap = buildProducerMap2(graphTasks);
962
- const visited = /* @__PURE__ */ new Set();
963
- const tokenSet = /* @__PURE__ */ new Set();
964
- const nodeEntries = /* @__PURE__ */ new Map();
965
- function walk(current) {
966
- const taskConfig = graphTasks[current];
967
- if (!taskConfig) return;
968
- for (const token of getRequires(taskConfig)) {
969
- const producers = producerMap[token] || [];
970
- for (const producer of producers) {
971
- if (producer === nodeName) continue;
972
- tokenSet.add(token);
973
- if (!nodeEntries.has(producer)) nodeEntries.set(producer, /* @__PURE__ */ new Set());
974
- nodeEntries.get(producer).add(token);
975
- if (!visited.has(producer)) {
976
- visited.add(producer);
977
- walk(producer);
978
- }
979
- }
980
- }
981
- }
982
- walk(nodeName);
983
- const nodes = [...nodeEntries.entries()].map(([name, tokens]) => ({
984
- nodeName: name,
985
- providesTokens: [...tokens]
986
- }));
987
- return { nodeName, nodes, tokens: [...tokenSet] };
988
- }
989
- function getDownstream(live, nodeName) {
990
- const graphTasks = getAllTasks(live.config);
991
- if (!graphTasks[nodeName]) return { nodeName, nodes: [], tokens: [] };
992
- const consumerMap = {};
993
- for (const [name, config] of Object.entries(graphTasks)) {
994
- for (const token of getRequires(config)) {
995
- if (!consumerMap[token]) consumerMap[token] = [];
996
- consumerMap[token].push(name);
997
- }
998
- }
999
- const visited = /* @__PURE__ */ new Set();
1000
- const tokenSet = /* @__PURE__ */ new Set();
1001
- const nodeEntries = /* @__PURE__ */ new Map();
1002
- function walk(current) {
1003
- const taskConfig = graphTasks[current];
1004
- if (!taskConfig) return;
1005
- for (const token of getProvides(taskConfig)) {
1006
- const consumers = consumerMap[token] || [];
1007
- for (const consumer of consumers) {
1008
- if (consumer === nodeName) continue;
1009
- tokenSet.add(token);
1010
- if (!nodeEntries.has(consumer)) nodeEntries.set(consumer, /* @__PURE__ */ new Set());
1011
- nodeEntries.get(consumer).add(token);
1012
- if (!visited.has(consumer)) {
1013
- visited.add(consumer);
1014
- walk(consumer);
1015
- }
1016
- }
1017
- }
1018
- }
1019
- walk(nodeName);
1020
- const nodes = [...nodeEntries.entries()].map(([name, tokens]) => ({
1021
- nodeName: name,
1022
- requiresTokens: [...tokens]
1023
- }));
1024
- return { nodeName, nodes, tokens: [...tokenSet] };
1025
- }
1026
-
1027
- // src/continuous-event-graph/journal.ts
1028
- var MemoryJournal = class {
1029
- buffer = [];
1030
- append(event) {
1031
- this.buffer.push(event);
1032
- }
1033
- drain() {
1034
- const events = this.buffer;
1035
- this.buffer = [];
1036
- return events;
1037
- }
1038
- get size() {
1039
- return this.buffer.length;
1040
- }
1041
- };
1042
-
1043
- // src/continuous-event-graph/reactive.ts
1044
- function computeDataHash(data) {
1045
- const json = stableStringify(data);
1046
- return fnv1a64Hex(json);
1047
- }
1048
- function stableStringify(value) {
1049
- if (value === null || value === void 0 || typeof value !== "object") {
1050
- return JSON.stringify(value);
1051
- }
1052
- if (Array.isArray(value)) {
1053
- return "[" + value.map(stableStringify).join(",") + "]";
1054
- }
1055
- const obj = value;
1056
- const keys = Object.keys(obj).sort();
1057
- return "{" + keys.map((k) => JSON.stringify(k) + ":" + stableStringify(obj[k])).join(",") + "}";
1058
- }
1059
- function fnv1a64Hex(input) {
1060
- let hash = 0xcbf29ce484222325n;
1061
- const prime = 0x100000001b3n;
1062
- const mod = 0xffffffffffffffffn;
1063
- for (let i = 0; i < input.length; i++) {
1064
- hash ^= BigInt(input.charCodeAt(i));
1065
- hash = hash * prime & mod;
1066
- }
1067
- return hash.toString(16).padStart(16, "0");
1068
- }
1069
- function base64UrlEncode(input) {
1070
- if (typeof Buffer !== "undefined") {
1071
- return Buffer.from(input, "utf8").toString("base64url");
1072
- }
1073
- if (typeof btoa === "function") {
1074
- const bytes = new TextEncoder().encode(input);
1075
- let binary = "";
1076
- for (const b of bytes) binary += String.fromCharCode(b);
1077
- return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
1078
- }
1079
- throw new Error("No base64 encoder available in this runtime");
1080
- }
1081
- function base64UrlDecode(input) {
1082
- if (typeof Buffer !== "undefined") {
1083
- return Buffer.from(input, "base64url").toString("utf8");
1084
- }
1085
- if (typeof atob === "function") {
1086
- const base64 = input.replace(/-/g, "+").replace(/_/g, "/");
1087
- const padded = base64 + "=".repeat((4 - base64.length % 4) % 4);
1088
- const binary = atob(padded);
1089
- const bytes = new Uint8Array(binary.length);
1090
- for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
1091
- return new TextDecoder().decode(bytes);
1092
- }
1093
- throw new Error("No base64 decoder available in this runtime");
1094
- }
1095
- function encodeCallbackToken(taskName) {
1096
- const payload = JSON.stringify({ t: taskName, n: Date.now().toString(36) + Math.random().toString(36).slice(2, 6) });
1097
- return base64UrlEncode(payload);
1098
- }
1099
- function decodeCallbackToken(token) {
1100
- try {
1101
- const payload = JSON.parse(base64UrlDecode(token));
1102
- if (typeof payload?.t === "string") return { taskName: payload.t };
1103
- return null;
1104
- } catch {
1105
- return null;
1106
- }
1107
- }
1108
- function createReactiveGraph(configOrLive, options, executionId) {
1109
- const {
1110
- handlers: initialHandlers,
1111
- onDrain
1112
- } = options;
1113
- const inputQueue = new MemoryJournal();
1114
- let live = "state" in configOrLive && "config" in configOrLive ? configOrLive : createLiveGraph(configOrLive, executionId);
1115
- let disposed = false;
1116
- const pendingHandlers = /* @__PURE__ */ new Set();
1117
- const handlers = new Map(Object.entries(initialHandlers));
1118
- const internalJournal = new MemoryJournal();
1119
- let draining = false;
1120
- let drainQueued = false;
1121
- function drain() {
1122
- if (disposed) return;
1123
- if (draining) {
1124
- drainQueued = true;
1125
- return;
1126
- }
1127
- draining = true;
1128
- try {
1129
- do {
1130
- drainQueued = false;
1131
- drainOnce();
1132
- } while (drainQueued);
1133
- } finally {
1134
- draining = false;
1135
- }
1136
- }
1137
- function drainOnce() {
1138
- const internalEvents = internalJournal.drain();
1139
- const inputEvents = inputQueue.drain();
1140
- const events = [...internalEvents, ...inputEvents];
1141
- if (events.length > 0) {
1142
- live = applyEvents(live, events);
1143
- }
1144
- const result = schedule(live);
1145
- if (events.length > 0) {
1146
- onDrain?.(events, live, result);
1147
- }
1148
- for (const taskName of result.eligible) {
1149
- dispatchTask(taskName);
1150
- }
1151
- for (const event of events) {
1152
- if (event.type === "task-progress") {
1153
- const { taskName, update } = event;
1154
- const taskConfig = live.config.tasks[taskName];
1155
- if (!taskConfig) continue;
1156
- const taskState = live.state.tasks[taskName];
1157
- if (!taskState || taskState.status !== "running") continue;
1158
- const callbackToken = encodeCallbackToken(taskName);
1159
- const p = runPipeline(taskName, callbackToken, update).catch((error) => {
1160
- if (disposed) return;
1161
- internalJournal.append({
1162
- type: "task-failed",
1163
- taskName,
1164
- error: error.message ?? String(error),
1165
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
1166
- });
1167
- drain();
1168
- }).finally(() => {
1169
- pendingHandlers.delete(p);
1170
- });
1171
- pendingHandlers.add(p);
1172
- }
1173
- }
1174
- }
1175
- function resolveUpstreamState(taskName) {
1176
- const taskConfig = live.config.tasks[taskName];
1177
- const requires = taskConfig.requires ?? [];
1178
- const tokenToTask = /* @__PURE__ */ new Map();
1179
- for (const [name, cfg] of Object.entries(live.config.tasks)) {
1180
- for (const token of cfg.provides ?? []) {
1181
- tokenToTask.set(token, name);
1182
- }
1183
- }
1184
- const state = {};
1185
- for (const token of requires) {
1186
- const producerTask = tokenToTask.get(token);
1187
- if (producerTask) {
1188
- state[token] = live.state.tasks[producerTask]?.data;
1189
- } else {
1190
- state[token] = void 0;
1191
- }
1192
- }
1193
- return state;
1194
- }
1195
- async function runPipeline(taskName, callbackToken, update) {
1196
- const taskConfig = live.config.tasks[taskName];
1197
- const handlerNames = taskConfig.taskHandlers ?? [];
1198
- const upstreamState = resolveUpstreamState(taskName);
1199
- for (const handlerName of handlerNames) {
1200
- const handler = handlers.get(handlerName);
1201
- if (!handler) {
1202
- throw new Error(`Handler '${handlerName}' not found in registry (task '${taskName}')`);
1203
- }
1204
- const input = {
1205
- nodeId: taskName,
1206
- state: upstreamState,
1207
- taskState: live.state.tasks[taskName],
1208
- config: taskConfig,
1209
- callbackToken,
1210
- update
1211
- };
1212
- const status = await handler(input);
1213
- if (status === "task-initiate-failure") {
1214
- throw new Error(`Handler '${handlerName}' returned task-initiate-failure (task '${taskName}')`);
1215
- }
1216
- }
1217
- }
1218
- function dispatchTask(taskName) {
1219
- const taskConfig = live.config.tasks[taskName];
1220
- const handlerNames = taskConfig?.taskHandlers;
1221
- if (!handlerNames || handlerNames.length === 0) {
1222
- return;
1223
- }
1224
- internalJournal.append({
1225
- type: "task-started",
1226
- taskName,
1227
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
1228
- });
1229
- drain();
1230
- const callbackToken = encodeCallbackToken(taskName);
1231
- const p = runPipeline(taskName, callbackToken).catch((error) => {
1232
- if (disposed) return;
1233
- internalJournal.append({
1234
- type: "task-failed",
1235
- taskName,
1236
- error: error.message ?? String(error),
1237
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
1238
- });
1239
- drain();
1240
- }).finally(() => {
1241
- pendingHandlers.delete(p);
1242
- });
1243
- pendingHandlers.add(p);
1244
- }
1245
- return {
1246
- push(event) {
1247
- if (disposed) return;
1248
- if (event.type === "task-completed" && event.data && !event.dataHash) {
1249
- event = { ...event, dataHash: computeDataHash(event.data) };
1250
- }
1251
- inputQueue.append(event);
1252
- drain();
1253
- },
1254
- pushAll(events) {
1255
- if (disposed) return;
1256
- for (const event of events) {
1257
- if (event.type === "task-completed" && event.data && !event.dataHash) {
1258
- inputQueue.append({ ...event, dataHash: computeDataHash(event.data) });
1259
- } else {
1260
- inputQueue.append(event);
1261
- }
1262
- }
1263
- drain();
1264
- },
1265
- resolveCallback(callbackToken, data, errors) {
1266
- if (disposed) return;
1267
- const decoded = decodeCallbackToken(callbackToken);
1268
- if (!decoded) return;
1269
- const { taskName } = decoded;
1270
- if (!live.config.tasks[taskName]) return;
1271
- if (errors && errors.length > 0) {
1272
- inputQueue.append({
1273
- type: "task-failed",
1274
- taskName,
1275
- error: errors.join("; "),
1276
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
1277
- });
1278
- } else {
1279
- const dataHash = data && Object.keys(data).length > 0 ? computeDataHash(data) : void 0;
1280
- inputQueue.append({
1281
- type: "task-completed",
1282
- taskName,
1283
- data,
1284
- dataHash,
1285
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
1286
- });
1287
- }
1288
- drain();
1289
- },
1290
- addNode(name, taskConfig) {
1291
- if (disposed) return;
1292
- inputQueue.append({ type: "task-upsert", taskName: name, taskConfig, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
1293
- drain();
1294
- },
1295
- removeNode(name) {
1296
- if (disposed) return;
1297
- inputQueue.append({ type: "task-removal", taskName: name, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
1298
- drain();
1299
- },
1300
- addRequires(nodeName, tokens) {
1301
- if (disposed) return;
1302
- inputQueue.append({ type: "node-requires-add", nodeName, tokens, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
1303
- drain();
1304
- },
1305
- removeRequires(nodeName, tokens) {
1306
- if (disposed) return;
1307
- inputQueue.append({ type: "node-requires-remove", nodeName, tokens, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
1308
- drain();
1309
- },
1310
- addProvides(nodeName, tokens) {
1311
- if (disposed) return;
1312
- inputQueue.append({ type: "node-provides-add", nodeName, tokens, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
1313
- drain();
1314
- },
1315
- removeProvides(nodeName, tokens) {
1316
- if (disposed) return;
1317
- inputQueue.append({ type: "node-provides-remove", nodeName, tokens, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
1318
- drain();
1319
- },
1320
- registerHandler(name, fn) {
1321
- handlers.set(name, fn);
1322
- },
1323
- unregisterHandler(name) {
1324
- handlers.delete(name);
1325
- },
1326
- retrigger(taskName) {
1327
- if (disposed) return;
1328
- if (!live.config.tasks[taskName]) return;
1329
- inputQueue.append({
1330
- type: "task-restart",
1331
- taskName,
1332
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
1333
- });
1334
- drain();
1335
- },
1336
- retriggerAll(taskNames) {
1337
- if (disposed) return;
1338
- for (const name of taskNames) {
1339
- if (!live.config.tasks[name]) continue;
1340
- inputQueue.append({
1341
- type: "task-restart",
1342
- taskName: name,
1343
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
1344
- });
1345
- }
1346
- drain();
1347
- },
1348
- snapshot() {
1349
- return snapshot(live);
1350
- },
1351
- getState() {
1352
- return live;
1353
- },
1354
- getSchedule() {
1355
- return schedule(live);
1356
- },
1357
- async dispose(options2) {
1358
- if (options2?.wait && pendingHandlers.size > 0) {
1359
- await Promise.allSettled([...pendingHandlers]);
1360
- }
1361
- disposed = true;
1362
- }
1363
- };
1364
- }
1365
-
1366
- // src/continuous-event-graph/validate.ts
1367
- function validateLiveGraph(live) {
1368
- const issues = [];
1369
- const { config, state } = live;
1370
- const tasks = getAllTasks(config);
1371
- const taskNames = Object.keys(tasks);
1372
- for (const name of taskNames) {
1373
- if (!state.tasks[name]) {
1374
- issues.push({
1375
- severity: "error",
1376
- code: "MISSING_STATE",
1377
- message: `Task "${name}" exists in config but has no state entry`,
1378
- tasks: [name]
1379
- });
1380
- }
1381
- }
1382
- for (const name of Object.keys(state.tasks)) {
1383
- if (!tasks[name]) {
1384
- issues.push({
1385
- severity: "warning",
1386
- code: "ORPHAN_STATE",
1387
- message: `State entry "${name}" has no corresponding task config`,
1388
- tasks: [name]
1389
- });
1390
- }
1391
- }
1392
- for (const name of taskNames) {
1393
- const ts = state.tasks[name];
1394
- if (!ts) continue;
1395
- if (ts.status === TASK_STATUS.RUNNING && !ts.startedAt) {
1396
- issues.push({
1397
- severity: "warning",
1398
- code: "RUNNING_WITHOUT_START",
1399
- message: `Task "${name}" is running but has no startedAt timestamp`,
1400
- tasks: [name]
1401
- });
1402
- }
1403
- if (ts.status === TASK_STATUS.COMPLETED && !ts.completedAt) {
1404
- issues.push({
1405
- severity: "warning",
1406
- code: "COMPLETED_WITHOUT_TIMESTAMP",
1407
- message: `Task "${name}" is completed but has no completedAt timestamp`,
1408
- tasks: [name]
1409
- });
1410
- }
1411
- if (ts.status === TASK_STATUS.FAILED) {
1412
- if (!ts.failedAt) {
1413
- issues.push({
1414
- severity: "warning",
1415
- code: "FAILED_WITHOUT_INFO",
1416
- message: `Task "${name}" is failed but has no failedAt timestamp`,
1417
- tasks: [name]
1418
- });
1419
- }
1420
- if (!ts.error) {
1421
- issues.push({
1422
- severity: "info",
1423
- code: "FAILED_WITHOUT_INFO",
1424
- message: `Task "${name}" is failed but has no error message`,
1425
- tasks: [name]
1426
- });
1427
- }
1428
- }
1429
- }
1430
- const expectedOutputs = /* @__PURE__ */ new Set();
1431
- for (const name of taskNames) {
1432
- const ts = state.tasks[name];
1433
- if (ts?.status === TASK_STATUS.COMPLETED) {
1434
- for (const token of getProvides(tasks[name])) {
1435
- expectedOutputs.add(token);
1436
- }
1437
- }
1438
- }
1439
- const actualOutputs = new Set(state.availableOutputs);
1440
- const allProducible = /* @__PURE__ */ new Set();
1441
- for (const taskConfig of Object.values(tasks)) {
1442
- for (const t of getProvides(taskConfig)) allProducible.add(t);
1443
- if (taskConfig.on) {
1444
- for (const tokens of Object.values(taskConfig.on)) {
1445
- for (const t of tokens) allProducible.add(t);
1446
- }
1447
- }
1448
- if (taskConfig.on_failure) {
1449
- for (const t of taskConfig.on_failure) allProducible.add(t);
1450
- }
1451
- }
1452
- for (const token of actualOutputs) {
1453
- if (!expectedOutputs.has(token) && !allProducible.has(token)) {
1454
- issues.push({
1455
- severity: "info",
1456
- code: "INJECTED_TOKEN",
1457
- message: `Token "${token}" is available but no task in the graph can produce it (likely injected)`,
1458
- tokens: [token]
1459
- });
1460
- }
1461
- }
1462
- for (const token of expectedOutputs) {
1463
- if (!actualOutputs.has(token)) {
1464
- issues.push({
1465
- severity: "warning",
1466
- code: "MISSING_OUTPUT",
1467
- message: `Token "${token}" should be available (its producer completed) but is not in availableOutputs`,
1468
- tokens: [token]
1469
- });
1470
- }
1471
- }
1472
- for (const name of taskNames) {
1473
- const ts = state.tasks[name];
1474
- if (!ts) continue;
1475
- if (ts.executionCount < 0) {
1476
- issues.push({
1477
- severity: "error",
1478
- code: "INVALID_EXECUTION_COUNT",
1479
- message: `Task "${name}" has negative execution count: ${ts.executionCount}`,
1480
- tasks: [name]
1481
- });
1482
- }
1483
- const maxExec = tasks[name].maxExecutions;
1484
- if (maxExec !== void 0 && ts.executionCount > maxExec) {
1485
- issues.push({
1486
- severity: "error",
1487
- code: "EXCEEDED_MAX_EXECUTIONS",
1488
- message: `Task "${name}" executed ${ts.executionCount} times, exceeding maxExecutions of ${maxExec}`,
1489
- tasks: [name]
1490
- });
1491
- }
1492
- }
1493
- return buildResult(issues);
1494
- }
1495
- function validateReactiveGraph(input) {
1496
- const { graph, handlers } = input;
1497
- const live = graph.getState();
1498
- const issues = [];
1499
- const tasks = getAllTasks(live.config);
1500
- const taskNames = Object.keys(tasks);
1501
- const handlerNames = new Set(Object.keys(handlers));
1502
- const referencedHandlers = /* @__PURE__ */ new Set();
1503
- for (const name of taskNames) {
1504
- const taskHandlers = tasks[name].taskHandlers;
1505
- if (taskHandlers) {
1506
- for (const h of taskHandlers) {
1507
- referencedHandlers.add(h);
1508
- }
1509
- }
1510
- }
1511
- for (const name of taskNames) {
1512
- const taskHandlers = tasks[name].taskHandlers;
1513
- if (!taskHandlers) continue;
1514
- for (const h of taskHandlers) {
1515
- if (!handlers[h]) {
1516
- issues.push({
1517
- severity: "error",
1518
- code: "MISSING_HANDLER",
1519
- message: `Task "${name}" references handler "${h}" but it is not in the registry`,
1520
- tasks: [name]
1521
- });
1522
- }
1523
- }
1524
- }
1525
- for (const name of handlerNames) {
1526
- if (!referencedHandlers.has(name)) {
1527
- issues.push({
1528
- severity: "warning",
1529
- code: "ORPHAN_HANDLER",
1530
- message: `Handler "${name}" is registered but not referenced by any task's taskHandlers`,
1531
- tasks: [name]
1532
- });
1533
- }
1534
- }
1535
- const liveResult = validateLiveGraph(live);
1536
- issues.push(...liveResult.issues);
1537
- return buildResult(issues);
1538
- }
1539
- function buildResult(issues) {
1540
- const errors = issues.filter((i) => i.severity === "error");
1541
- const warnings = issues.filter((i) => i.severity === "warning");
1542
- return {
1543
- valid: errors.length === 0,
1544
- issues,
1545
- errors,
1546
- warnings
1547
- };
1548
- }
1549
-
1550
- // src/continuous-event-graph/mutate.ts
1551
- function mutateGraph(live, mutations) {
1552
- let current = live;
1553
- for (const mutation of mutations) {
1554
- current = applySingleMutation(current, mutation);
1555
- }
1556
- return current;
1557
- }
1558
- function applySingleMutation(live, mutation) {
1559
- switch (mutation.type) {
1560
- case "add-node":
1561
- return addNode(live, mutation.name, mutation.config);
1562
- case "remove-node":
1563
- return removeNode(live, mutation.name);
1564
- case "add-requires":
1565
- return addRequires(live, mutation.taskName, mutation.tokens);
1566
- case "remove-requires":
1567
- return removeRequires(live, mutation.taskName, mutation.tokens);
1568
- case "add-provides":
1569
- return addProvides(live, mutation.taskName, mutation.tokens);
1570
- case "remove-provides":
1571
- return removeProvides(live, mutation.taskName, mutation.tokens);
1572
- case "inject-tokens":
1573
- return injectTokens(live, mutation.tokens);
1574
- case "drain-tokens":
1575
- return drainTokens(live, mutation.tokens);
1576
- case "reset-node":
1577
- return resetNode(live, mutation.name);
1578
- case "disable-node":
1579
- return disableNode(live, mutation.name);
1580
- case "enable-node":
1581
- return enableNode(live, mutation.name);
1582
- case "apply-events":
1583
- return applyEvents(live, mutation.events);
1584
- default:
1585
- throw new Error(`Unknown mutation type: ${mutation.type}`);
1586
- }
1587
- }
1588
- function createCallbackHandler(fn, getResolve) {
1589
- return async (input) => {
1590
- const { callbackToken } = input;
1591
- Promise.resolve(fn(input)).then((data) => getResolve()(callbackToken, data)).catch((err) => getResolve()(callbackToken, {}, [err instanceof Error ? err.message : String(err)]));
1592
- return "task-initiated";
1593
- };
1594
- }
1595
- function createFireAndForgetHandler(fn, getResolve) {
1596
- return async (input) => {
1597
- const { callbackToken } = input;
1598
- Promise.resolve(fn(input)).then(() => getResolve()(callbackToken, {})).catch(() => getResolve()(callbackToken, {}));
1599
- return "task-initiated";
1600
- };
1601
- }
1602
- function createShellHandler(options) {
1603
- const {
1604
- command: commandTemplate,
1605
- cwd,
1606
- env,
1607
- timeoutMs = 3e4,
1608
- exitCodeMap,
1609
- captureOutput = false,
1610
- getResolve
1611
- } = options;
1612
- return async (input) => {
1613
- const { callbackToken, nodeId } = input;
1614
- const command = commandTemplate.replace(/\$\{taskName\}/g, nodeId);
1615
- exec(
1616
- command,
1617
- {
1618
- cwd,
1619
- env: env ? { ...process.env, ...env } : void 0,
1620
- timeout: timeoutMs,
1621
- maxBuffer: 10 * 1024 * 1024
1622
- // 10MB
1623
- },
1624
- (error, stdout, stderr) => {
1625
- const exitCode = error?.code ?? (error ? 1 : 0);
1626
- if (exitCode !== 0 && !exitCodeMap?.[exitCode]) {
1627
- getResolve()(callbackToken, {}, [`Command exited with code ${exitCode}: ${stderr || error?.message}`]);
1628
- return;
1629
- }
1630
- const data = {};
1631
- if (captureOutput) {
1632
- data.stdout = stdout;
1633
- data.stderr = stderr;
1634
- data.exitCode = exitCode;
1635
- }
1636
- getResolve()(callbackToken, data);
1637
- }
1638
- );
1639
- return "task-initiated";
1640
- };
1641
- }
1642
- function detectRuntime(scriptPath) {
1643
- if (scriptPath.endsWith(".js") || scriptPath.endsWith(".mjs") || scriptPath.endsWith(".ts")) return "node";
1644
- if (scriptPath.endsWith(".py")) return "python3";
1645
- if (scriptPath.endsWith(".sh")) return "bash";
1646
- return "bash";
1647
- }
1648
- function createScriptHandler(options) {
1649
- const {
1650
- scriptPath,
1651
- runtime,
1652
- args = [],
1653
- cwd,
1654
- timeoutMs = 6e4,
1655
- captureOutput = false,
1656
- getResolve
1657
- } = options;
1658
- const resolvedRuntime = runtime ?? detectRuntime(scriptPath);
1659
- const shellArgs = [ctx_taskName_placeholder, ...args].join(" ");
1660
- const command = `${resolvedRuntime} ${scriptPath} ${shellArgs}`;
1661
- return createShellHandler({
1662
- command: command.replace(ctx_taskName_placeholder, "${taskName}"),
1663
- cwd,
1664
- timeoutMs,
1665
- captureOutput,
1666
- getResolve
1667
- });
1668
- }
1669
- var ctx_taskName_placeholder = "__TASK_NAME__";
1670
- function createWebhookHandler(options) {
1671
- const {
1672
- url: urlTemplate,
1673
- method = "POST",
1674
- headers = {},
1675
- timeoutMs = 3e4,
1676
- failOnNon2xx = true,
1677
- getResolve
1678
- } = options;
1679
- return async (input) => {
1680
- const { callbackToken, nodeId, config } = input;
1681
- const url = urlTemplate.replace(/\$\{taskName\}/g, nodeId);
1682
- const body = JSON.stringify({
1683
- taskName: nodeId,
1684
- callbackToken,
1685
- config
1686
- });
1687
- const controller = new AbortController();
1688
- const timer = setTimeout(() => controller.abort(), timeoutMs);
1689
- fetch(url, {
1690
- method,
1691
- headers: { "Content-Type": "application/json", ...headers },
1692
- body,
1693
- signal: controller.signal
1694
- }).then(async (response) => {
1695
- clearTimeout(timer);
1696
- if (failOnNon2xx && !response.ok) {
1697
- const text = await response.text().catch(() => "");
1698
- getResolve()(callbackToken, {}, [`HTTP ${response.status}: ${text}`]);
1699
- return;
1700
- }
1701
- const data = await response.json().catch(() => ({}));
1702
- getResolve()(callbackToken, data);
1703
- }).catch((err) => {
1704
- clearTimeout(timer);
1705
- getResolve()(callbackToken, {}, [err instanceof Error ? err.message : String(err)]);
1706
- });
1707
- return "task-initiated";
1708
- };
1709
- }
1710
- function createNoopHandler(getResolve, staticData) {
1711
- return async (input) => {
1712
- getResolve()(input.callbackToken, staticData ?? {});
1713
- return "task-initiated";
1714
- };
1715
- }
1716
-
1717
- // src/card-compute/index.ts
1718
- function deepGet(obj, path) {
1719
- if (!path || !obj) return void 0;
1720
- const parts = path.split(".");
1721
- let cur = obj;
1722
- for (let i = 0; i < parts.length; i++) {
1723
- if (cur == null) return void 0;
1724
- cur = cur[parts[i]];
1725
- }
1726
- return cur;
1727
- }
1728
- function deepSet(obj, path, value) {
1729
- const parts = path.split(".");
1730
- let cur = obj;
1731
- for (let i = 0; i < parts.length - 1; i++) {
1732
- if (cur[parts[i]] == null || typeof cur[parts[i]] !== "object") cur[parts[i]] = {};
1733
- cur = cur[parts[i]];
1734
- }
1735
- cur[parts[parts.length - 1]] = value;
1736
- }
1737
- async function run(node, options) {
1738
- if (!node?.compute?.length) return node;
1739
- if (!node.card_data) node.card_data = {};
1740
- node.computed_values = {};
1741
- node._sourcesData = options?.sourcesData ?? {};
1742
- const ctx = {
1743
- card_data: node.card_data,
1744
- requires: node.requires ?? {},
1745
- fetched_sources: node._sourcesData,
1746
- computed_values: node.computed_values
1747
- };
1748
- for (const step of node.compute) {
1749
- try {
1750
- const val = await jsonata2(step.expr).evaluate(ctx);
1751
- deepSet(node.computed_values, step.bindTo, val);
1752
- ctx.computed_values = node.computed_values;
1753
- } catch (err) {
1754
- console.error(`CardCompute.run error on "${node.id ?? "?"}.${step.bindTo}":`, err);
1755
- }
1756
- }
1757
- return node;
1758
- }
1759
- async function evalExpr(expr, node) {
1760
- const ctx = {
1761
- card_data: node.card_data ?? {},
1762
- requires: node.requires ?? {},
1763
- fetched_sources: node._sourcesData ?? {},
1764
- computed_values: node.computed_values ?? {}
1765
- };
1766
- return jsonata2(expr).evaluate(ctx);
1767
- }
1768
- function resolve(node, path) {
1769
- if (path.startsWith("fetched_sources.")) {
1770
- return deepGet(node._sourcesData ?? {}, path.slice("fetched_sources.".length));
1771
- }
1772
- return deepGet(node, path);
1773
- }
1774
- var VALID_ELEMENT_KINDS = /* @__PURE__ */ new Set([
1775
- "metric",
1776
- "table",
1777
- "editable-table",
1778
- "chart",
1779
- "form",
1780
- "filter",
1781
- "list",
1782
- "notes",
1783
- "todo",
1784
- "alert",
1785
- "narrative",
1786
- "badge",
1787
- "text",
1788
- "markdown",
1789
- "ref",
1790
- "custom",
1791
- "actions"
1792
- ]);
1793
- var ALLOWED_KEYS = /* @__PURE__ */ new Set(["id", "meta", "requires", "provides", "view", "card_data", "compute", "source_defs"]);
1794
- function validateNode(node) {
1795
- const errors = [];
1796
- if (!node || typeof node !== "object" || Array.isArray(node)) {
1797
- return { ok: false, errors: ["Node must be a non-null object"] };
1798
- }
1799
- const n = node;
1800
- if (typeof n.id !== "string" || !n.id) errors.push("id: required, must be a non-empty string");
1801
- for (const key of Object.keys(n)) {
1802
- if (!ALLOWED_KEYS.has(key)) errors.push(`Unknown top-level key: "${key}"`);
1803
- }
1804
- if (n.card_data == null || typeof n.card_data !== "object" || Array.isArray(n.card_data)) {
1805
- errors.push("card_data: required, must be an object");
1806
- }
1807
- if (n.meta != null) {
1808
- if (typeof n.meta !== "object" || Array.isArray(n.meta)) {
1809
- errors.push("meta: must be an object");
1810
- } else {
1811
- const meta = n.meta;
1812
- if (meta.title != null && typeof meta.title !== "string") errors.push("meta.title: must be a string");
1813
- if (meta.tags != null && !Array.isArray(meta.tags)) errors.push("meta.tags: must be an array");
1814
- }
1815
- }
1816
- if (n.requires != null && !Array.isArray(n.requires)) errors.push("requires: must be an array of strings");
1817
- if (n.provides != null) {
1818
- if (!Array.isArray(n.provides)) {
1819
- errors.push("provides: must be an array of { bindTo, ref } bindings");
1820
- } else {
1821
- n.provides.forEach((p, i) => {
1822
- if (!p || typeof p !== "object" || Array.isArray(p)) {
1823
- errors.push(`provides[${i}]: must be an object with bindTo and ref`);
1824
- } else {
1825
- const b = p;
1826
- if (typeof b.bindTo !== "string" || !b.bindTo) errors.push(`provides[${i}]: missing required "bindTo" string`);
1827
- if (typeof b.ref !== "string" || !b.ref) errors.push(`provides[${i}]: missing required "ref" string`);
1828
- }
1829
- });
1830
- }
1831
- }
1832
- if (n.compute != null) {
1833
- if (!Array.isArray(n.compute)) {
1834
- errors.push("compute: must be an array of compute steps");
1835
- } else {
1836
- n.compute.forEach((step, i) => {
1837
- if (!step || typeof step !== "object" || Array.isArray(step)) {
1838
- errors.push(`compute[${i}]: must be a compute step object`);
1839
- } else {
1840
- const s = step;
1841
- if (typeof s.bindTo !== "string" || !s.bindTo) errors.push(`compute[${i}]: missing required "bindTo" property`);
1842
- if (typeof s.expr !== "string" || !s.expr) errors.push(`compute[${i}]: missing required "expr" string (JSONata expression)`);
1843
- }
1844
- });
1845
- }
1846
- }
1847
- if (n.source_defs != null) {
1848
- if (!Array.isArray(n.source_defs)) {
1849
- errors.push("source_defs: must be an array");
1850
- } else {
1851
- const bindTos = /* @__PURE__ */ new Set();
1852
- const outputFiles = /* @__PURE__ */ new Set();
1853
- n.source_defs.forEach((src, i) => {
1854
- if (!src || typeof src !== "object" || Array.isArray(src)) {
1855
- errors.push(`source_defs[${i}]: must be an object`);
1856
- } else {
1857
- const s = src;
1858
- if (typeof s.bindTo !== "string" || !s.bindTo) {
1859
- errors.push(`source_defs[${i}]: missing required "bindTo" property`);
1860
- } else {
1861
- if (bindTos.has(s.bindTo)) {
1862
- errors.push(`source_defs[${i}]: bindTo "${s.bindTo}" is not unique across source_defs`);
1863
- }
1864
- bindTos.add(s.bindTo);
1865
- }
1866
- if (typeof s.outputFile !== "string" || !s.outputFile) {
1867
- errors.push(`source_defs[${i}]: missing required "outputFile" property`);
1868
- } else {
1869
- if (outputFiles.has(s.outputFile)) {
1870
- errors.push(`source_defs[${i}]: outputFile "${s.outputFile}" is not unique across source_defs`);
1871
- }
1872
- outputFiles.add(s.outputFile);
1873
- }
1874
- if (s.optionalForCompletionGating != null && typeof s.optionalForCompletionGating !== "boolean") {
1875
- errors.push(`source_defs[${i}]: optionalForCompletionGating must be a boolean`);
1876
- }
1877
- }
1878
- });
1879
- }
1880
- }
1881
- if (n.view != null) {
1882
- if (typeof n.view !== "object" || Array.isArray(n.view)) {
1883
- errors.push("view: must be an object");
1884
- } else {
1885
- const view = n.view;
1886
- if (!Array.isArray(view.elements) || view.elements.length === 0) {
1887
- errors.push("view.elements: required, must be a non-empty array");
1888
- } else {
1889
- view.elements.forEach((elem, i) => {
1890
- if (!elem || typeof elem !== "object") {
1891
- errors.push(`view.elements[${i}]: must be an object`);
1892
- return;
1893
- }
1894
- if (!elem.kind || typeof elem.kind !== "string") {
1895
- errors.push(`view.elements[${i}].kind: required, must be a string`);
1896
- } else if (!VALID_ELEMENT_KINDS.has(elem.kind)) {
1897
- errors.push(`view.elements[${i}].kind: unknown kind "${elem.kind}". Valid: ${[...VALID_ELEMENT_KINDS].join(", ")}`);
1898
- }
1899
- if (elem.data != null && (typeof elem.data !== "object" || Array.isArray(elem.data))) {
1900
- errors.push(`view.elements[${i}].data: must be an object`);
1901
- }
1902
- });
1903
- }
1904
- if (view.layout != null && (typeof view.layout !== "object" || Array.isArray(view.layout))) errors.push("view.layout: must be an object");
1905
- if (view.features != null && (typeof view.features !== "object" || Array.isArray(view.features))) errors.push("view.features: must be an object");
1906
- }
1907
- }
1908
- return { ok: errors.length === 0, errors };
1909
- }
1910
- async function enrichSources(source_defs, context) {
1911
- if (!source_defs || source_defs.length === 0) return [];
1912
- const evalCtx = {
1913
- card_data: context.card_data ?? {},
1914
- requires: context.requires ?? {}
1915
- };
1916
- return Promise.all(
1917
- source_defs.map(async (src) => {
1918
- const _projections = {};
1919
- if (src.projections && typeof src.projections === "object" && !Array.isArray(src.projections)) {
1920
- for (const [key, expr] of Object.entries(src.projections)) {
1921
- if (typeof expr === "string" && expr.trim().length > 0) {
1922
- try {
1923
- _projections[key] = await jsonata2(expr).evaluate(evalCtx);
1924
- } catch {
1925
- _projections[key] = void 0;
1926
- }
1927
- }
1928
- }
1929
- }
1930
- return { ...src, _projections };
1931
- })
1932
- );
1933
- }
1934
- var CardCompute = {
1935
- run,
1936
- eval: evalExpr,
1937
- resolve,
1938
- validate: validateNode,
1939
- enrichSources
1940
- };
1941
-
1942
- // src/continuous-event-graph/live-cards-bridge.ts
1943
- function liveCardsToReactiveGraph(input, options = {}) {
1944
- let cards;
1945
- let boardSettings = {};
1946
- let boardId;
1947
- if (!Array.isArray(input) && "nodes" in input) {
1948
- const board = input;
1949
- cards = board.nodes;
1950
- boardId = board.id;
1951
- boardSettings = board.settings ?? {};
1952
- } else {
1953
- cards = input;
1954
- }
1955
- const {
1956
- sourceHandlers = {},
1957
- defaultSourceHandler,
1958
- cardHandlers = {},
1959
- reactiveOptions = {},
1960
- graphSettings = {},
1961
- executionId
1962
- } = options;
1963
- const cardMap = /* @__PURE__ */ new Map();
1964
- for (const card of cards) {
1965
- if (cardMap.has(card.id)) {
1966
- throw new Error(`Duplicate card ID: "${card.id}"`);
1967
- }
1968
- cardMap.set(card.id, card);
1969
- }
1970
- const sharedState = options.sharedState ?? /* @__PURE__ */ new Map();
1971
- const tasks = {};
1972
- const allTokens = /* @__PURE__ */ new Set();
1973
- const tokenToCardId = /* @__PURE__ */ new Map();
1974
- for (const card of cards) {
1975
- for (const binding of card.provides ?? [{ bindTo: card.id, ref: "card_data" }]) {
1976
- allTokens.add(binding.bindTo);
1977
- tokenToCardId.set(binding.bindTo, card.id);
1978
- }
1979
- }
1980
- for (const card of cards) {
1981
- const requires = card.requires ?? [];
1982
- for (const req of requires) {
1983
- if (!allTokens.has(req)) {
1984
- throw new Error(`Card "${card.id}" requires "${req}" but no card provides that token`);
1985
- }
1986
- }
1987
- tasks[card.id] = {
1988
- requires: requires.length > 0 ? requires : void 0,
1989
- provides: (card.provides ?? [{ bindTo: card.id, ref: "card_data" }]).map((p) => p.bindTo),
1990
- taskHandlers: [card.id],
1991
- description: card.meta?.title ?? card.id
1992
- };
1993
- }
1994
- const config = {
1995
- id: boardId ?? `live-cards-${Date.now()}`,
1996
- settings: {
1997
- completion: "manual",
1998
- execution_mode: "eligibility-mode",
1999
- ...boardSettings,
2000
- ...graphSettings
2001
- },
2002
- tasks
2003
- };
2004
- const handlers = {};
2005
- let graphRef = null;
2006
- const getResolve = () => (token, data, errors) => {
2007
- graphRef.resolveCallback(token, data, errors);
2008
- };
2009
- for (const card of cards) {
2010
- if (card.source_defs && card.source_defs.length > 0) {
2011
- handlers[card.id] = buildSourceHandler(card, sourceHandlers, defaultSourceHandler, sharedState, getResolve);
2012
- } else {
2013
- handlers[card.id] = buildCardHandler(card, cardHandlers, sharedState, cardMap, tokenToCardId, getResolve);
2014
- }
2015
- }
2016
- const graph = createReactiveGraph(
2017
- config,
2018
- {
2019
- ...reactiveOptions,
2020
- handlers
2021
- },
2022
- executionId
2023
- );
2024
- graphRef = graph;
2025
- return { graph, config, handlers, cards: cardMap, sharedState };
2026
- }
2027
- function buildSourceHandler(card, sourceHandlers, defaultSourceHandler, sharedState, getResolve) {
2028
- if (sourceHandlers[card.id]) {
2029
- const userHandler = sourceHandlers[card.id];
2030
- return async (input) => {
2031
- return userHandler(input);
2032
- };
2033
- }
2034
- if (defaultSourceHandler) {
2035
- const factoryHandler = defaultSourceHandler(card);
2036
- return async (input) => {
2037
- return factoryHandler(input);
2038
- };
2039
- }
2040
- return async (input) => {
2041
- const data = { ...card.card_data };
2042
- sharedState.set(card.id, data);
2043
- getResolve()(input.callbackToken, data);
2044
- return "task-initiated";
2045
- };
2046
- }
2047
- function buildCardHandler(card, cardHandlers, sharedState, _cardMap, tokenToCardId, getResolve) {
2048
- if (cardHandlers[card.id]) {
2049
- const userHandler = cardHandlers[card.id];
2050
- return async (input) => {
2051
- return userHandler(input);
2052
- };
2053
- }
2054
- return async (input) => {
2055
- const requiresData = {};
2056
- const requires = card.requires ?? [];
2057
- for (const token of requires) {
2058
- const producerId = tokenToCardId.get(token) ?? token;
2059
- const upstreamState = sharedState.get(producerId);
2060
- if (upstreamState) {
2061
- requiresData[token] = upstreamState[token] ?? upstreamState;
2062
- }
2063
- }
2064
- const computeNode = {
2065
- id: card.id,
2066
- card_data: { ...card.card_data },
2067
- requires: requiresData,
2068
- compute: card.compute
2069
- };
2070
- await CardCompute.run(computeNode);
2071
- let resultData;
2072
- if (card.provides && card.provides.length > 0) {
2073
- resultData = {};
2074
- for (const { bindTo, ref } of card.provides) {
2075
- resultData[bindTo] = CardCompute.resolve(computeNode, ref);
2076
- }
2077
- } else {
2078
- resultData = { ...computeNode.card_data, ...computeNode.computed_values };
2079
- }
2080
- const resultState = { ...computeNode.card_data, ...computeNode.computed_values };
2081
- sharedState.set(card.id, resultState);
2082
- getResolve()(input.callbackToken, resultData);
2083
- return "task-initiated";
2084
- };
2085
- }
2086
-
2087
- export { MemoryJournal, addNode, addProvides, addRequires, applyEvent, applyEvents, computeDataHash, createCallbackHandler, createFireAndForgetHandler, createLiveGraph, createNoopHandler, createReactiveGraph, createScriptHandler, createShellHandler, createWebhookHandler, disableNode, drainTokens, enableNode, getDownstream, getNode, getUnreachableNodes, getUnreachableTokens, getUpstream, injectTokens, inspect, liveCardsToReactiveGraph, mutateGraph, removeNode, removeProvides, removeRequires, resetNode, restore, schedule, snapshot, validateLiveGraph, validateReactiveGraph };
2088
- //# sourceMappingURL=index.js.map
1
+ import {exec,execFile}from'child_process';import W from'jsonata';import {createRequire}from'module';import'ajv-formats';var w={NOT_STARTED:"not-started",RUNNING:"running",COMPLETED:"completed",FAILED:"failed",INACTIVATED:"inactivated"};function C(e){return e?Array.isArray(e.provides)?e.provides:[]:[]}function O(e){return e?Array.isArray(e.requires)?e.requires:[]:[]}function A(e){return e.tasks??{}}function I(e){return e?e.status===w.FAILED||e.status===w.INACTIVATED:false}function oe(e,t){return e.refreshStrategy??t?.refreshStrategy??"data-changed"}function ae(e){return e.maxExecutions}function ie(e,t){let r=new Set;for(let[n,s]of Object.entries(t))if(s.status===w.COMPLETED){let o=e.tasks[n];o&&C(o).forEach(u=>r.add(u));}return Array.from(r)}function ce(e,t){let r={};return e.forEach(n=>{let s=t[n];if(!s)return;C(s).forEach(a=>{r[a]||(r[a]=[]),r[a].push(n);});}),r}function ue(e,t,r){let n=e.tasks[t]??D(),s={};if(r){let a=r.tasks[t],u=O(a);for(let l of u)for(let[i,d]of Object.entries(r.tasks))if(C(d).includes(l)){let c=e.tasks[i];c?.lastDataHash&&(s[l]=c.lastDataHash);break}}let o={...n,status:"running",startedAt:new Date().toISOString(),lastUpdated:new Date().toISOString(),progress:0,error:void 0,startConsumedHashes:s};return {...e,tasks:{...e.tasks,[t]:o},lastUpdated:new Date().toISOString()}}function de(e,t,r,n,s,o){let a=e.tasks[r]??D(),u=t.tasks[r];if(!u)throw new Error(`Task "${r}" not found in graph`);let l;n&&u.on&&u.on[n]?l=u.on[n]:l=C(u);let i=a.startConsumedHashes?{...a.startConsumedHashes}:{...a.lastConsumedHashes};if(!a.startConsumedHashes){let g=u.requires??[];for(let f of g)for(let[v,m]of Object.entries(t.tasks))if(C(m).includes(f)){let R=e.tasks[v];R?.lastDataHash&&(i[f]=R.lastDataHash);break}}let d={...a,status:"completed",completedAt:new Date().toISOString(),lastUpdated:new Date().toISOString(),executionCount:a.executionCount+1,lastEpoch:a.executionCount+1,lastDataHash:s,data:o,lastConsumedHashes:i,error:void 0},c=[...new Set([...e.availableOutputs,...l])];return {...e,tasks:{...e.tasks,[r]:d},availableOutputs:c,lastUpdated:new Date().toISOString()}}function pe(e,t,r,n){let s=e.tasks[r]??D(),o=t.tasks[r];if(o?.retry){let l=s.retryCount+1;if(l<=o.retry.max_attempts){let i={...s,status:"not-started",retryCount:l,lastUpdated:new Date().toISOString(),error:n};return {...e,tasks:{...e.tasks,[r]:i},lastUpdated:new Date().toISOString()}}}let a={...s,status:"failed",failedAt:new Date().toISOString(),lastUpdated:new Date().toISOString(),error:n,executionCount:s.executionCount+1},u=e.availableOutputs;if(o?.on_failure&&o.on_failure.length>0&&(u=[...new Set([...e.availableOutputs,...o.on_failure])]),o?.circuit_breaker&&a.executionCount>=o.circuit_breaker.max_executions){let l=o.circuit_breaker.on_break;u=[...new Set([...u,...l])];}return {...e,tasks:{...e.tasks,[r]:a},availableOutputs:u,lastUpdated:new Date().toISOString()}}function fe(e,t,r,n){let s=e.tasks[t]??D(),o={...s,progress:typeof n=="number"?n:s.progress,messages:[...s.messages??[],...r?[{message:r,timestamp:new Date().toISOString(),status:s.status}]:[]],lastUpdated:new Date().toISOString()};return {...e,tasks:{...e.tasks,[t]:o},lastUpdated:new Date().toISOString()}}function le(e,t){let r=e.tasks[t];if(!r)return e;let n={...r,status:"not-started",startedAt:void 0,completedAt:void 0,failedAt:void 0,error:void 0,data:void 0,progress:null,lastUpdated:new Date().toISOString()};return {...e,tasks:{...e.tasks,[t]:n},lastUpdated:new Date().toISOString()}}function D(){return {status:"not-started",executionCount:0,retryCount:0,lastEpoch:0,messages:[],progress:null}}function J(e,t){let r=t??`live-${Date.now()}`,n={};for(let o of Object.keys(e.tasks))n[o]=K();let s={status:"running",tasks:n,availableOutputs:[],stuckDetection:{is_stuck:false,stuck_description:null,outputs_unresolvable:[],tasks_blocked:[]},lastUpdated:new Date().toISOString(),executionId:r,executionConfig:{executionMode:e.settings.execution_mode??"eligibility-mode",conflictStrategy:e.settings.conflict_strategy??"alphabetical",completionStrategy:e.settings.completion}};return {config:e,state:s}}function Y(e,t){let{config:r,state:n}=e;if("executionId"in t&&t.executionId&&t.executionId!==n.executionId)return e;switch(t.type){case "task-started":return {config:r,state:ue(n,t.taskName,r)};case "task-completed":return {config:r,state:de(n,r,t.taskName,t.result,t.dataHash,t.data)};case "task-failed":return {config:r,state:pe(n,r,t.taskName,t.error)};case "task-progress":return {config:r,state:fe(n,t.taskName,t.message,t.progress)};case "task-restart":return {config:r,state:le(n,t.taskName)};case "inject-tokens":return {config:r,state:{...n,availableOutputs:[...new Set([...n.availableOutputs,...t.tokens])],lastUpdated:new Date().toISOString()}};case "agent-action":return {config:r,state:Ee(n,t.action)};case "task-upsert":return P(e,t.taskName,t.taskConfig);case "task-removal":return M(e,t.taskName);case "node-requires-add":return q(e,t.nodeName,t.tokens);case "node-requires-remove":return F(e,t.nodeName,t.tokens);case "node-provides-add":return $(e,t.nodeName,t.tokens);case "node-provides-remove":return U(e,t.nodeName,t.tokens);default:return e}}function L(e,t){return t.reduce((r,n)=>Y(r,n),e)}function P(e,t,r){let n=!!e.config.tasks[t];return {config:{...e.config,tasks:{...e.config.tasks,[t]:r}},state:{...e.state,tasks:{...e.state.tasks,[t]:n?e.state.tasks[t]:K()},lastUpdated:new Date().toISOString()}}}function M(e,t){if(!e.config.tasks[t])return e;let{[t]:r,...n}=e.config.tasks,{[t]:s,...o}=e.state.tasks;return {config:{...e.config,tasks:n},state:{...e.state,tasks:o,lastUpdated:new Date().toISOString()}}}function q(e,t,r){let n=e.config.tasks[t];if(!n)return e;let s=O(n),o=r.filter(a=>!s.includes(a));return o.length===0?e:{config:{...e.config,tasks:{...e.config.tasks,[t]:{...n,requires:[...s,...o]}}},state:e.state}}function F(e,t,r){let n=e.config.tasks[t];if(!n)return e;let s=O(n),o=s.filter(a=>!r.includes(a));return o.length===s.length?e:{config:{...e.config,tasks:{...e.config.tasks,[t]:{...n,requires:o}}},state:e.state}}function $(e,t,r){let n=e.config.tasks[t];if(!n)return e;let s=C(n),o=r.filter(a=>!s.includes(a));return o.length===0?e:{config:{...e.config,tasks:{...e.config.tasks,[t]:{...n,provides:[...s,...o]}}},state:e.state}}function U(e,t,r){let n=e.config.tasks[t];if(!n)return e;let s=C(n),o=s.filter(a=>!r.includes(a));return o.length===s.length?e:{config:{...e.config,tasks:{...e.config.tasks,[t]:{...n,provides:o}}},state:e.state}}function X(e,t){return Y(e,{type:"inject-tokens",tokens:t,timestamp:new Date().toISOString()})}function z(e,t){let r=new Set(t),n=e.state.availableOutputs.filter(s=>!r.has(s));return n.length===e.state.availableOutputs.length?e:{config:e.config,state:{...e.state,availableOutputs:n,lastUpdated:new Date().toISOString()}}}function Q(e,t){return !e.config.tasks[t]||!e.state.tasks[t]?e:{config:e.config,state:{...e.state,tasks:{...e.state.tasks,[t]:K()},lastUpdated:new Date().toISOString()}}}function Z(e,t){let r=e.state.tasks[t];return !r||r.status==="inactivated"?e:{config:e.config,state:{...e.state,tasks:{...e.state.tasks,[t]:{...r,status:"inactivated",lastUpdated:new Date().toISOString()}},lastUpdated:new Date().toISOString()}}}function ee(e,t){let r=e.state.tasks[t];return !r||r.status!=="inactivated"?e:{config:e.config,state:{...e.state,tasks:{...e.state.tasks,[t]:{...r,status:"not-started",lastUpdated:new Date().toISOString()}},lastUpdated:new Date().toISOString()}}}function Ce(e,t){let r=e.config.tasks[t];if(!r)return;let n=e.state.tasks[t]??K();return {name:t,config:r,state:n}}function te(e){return {version:1,config:e.config,state:e.state,snapshotAt:new Date().toISOString()}}function xe(e){if(!e||typeof e!="object")throw new Error("Invalid snapshot: expected an object");let t=e;if(!t.config||typeof t.config!="object")throw new Error('Invalid snapshot: missing or invalid "config"');if(!t.state||typeof t.state!="object")throw new Error('Invalid snapshot: missing or invalid "state"');let r=t.config,n=t.state;if(!r.settings||typeof r.settings!="object")throw new Error("Invalid snapshot: config.settings missing");if(!r.tasks||typeof r.tasks!="object")throw new Error("Invalid snapshot: config.tasks missing");if(!n.tasks||typeof n.tasks!="object")throw new Error("Invalid snapshot: state.tasks missing");if(!Array.isArray(n.availableOutputs))throw new Error("Invalid snapshot: state.availableOutputs must be an array");return {config:r,state:n}}function K(){return {status:"not-started",executionCount:0,retryCount:0,lastEpoch:0,messages:[],progress:null}}function Ee(e,t){let r=new Date().toISOString();switch(t){case "stop":return {...e,status:"stopped",lastUpdated:r};case "pause":return {...e,status:"paused",lastUpdated:r};case "resume":return {...e,status:"running",lastUpdated:r};default:return e}}function V(e){let{config:t,state:r}=e,n=A(t);if(Object.keys(n).length===0)return {eligible:[],pending:[],unresolved:[],blocked:[],conflicts:{}};let o=Oe(n),a=ie(t,r.tasks),u=new Set([...a,...r.availableOutputs]),l=[],i=[],d=[],c=[];for(let[f,v]of Object.entries(n)){let m=r.tasks[f],R=oe(v,t.settings),x=R!=="once";if(m?.status===w.RUNNING||I(m))continue;let p=ae(v);if(p!==void 0&&m&&m.executionCount>=p||v.circuit_breaker&&m&&m.executionCount>=v.circuit_breaker.max_executions||!x&&m?.status===w.COMPLETED)continue;if(x&&m?.status===w.COMPLETED){let y=O(v),S=false;switch(R){case "data-changed":{y.length>0&&y.some(E=>{for(let[G,j]of Object.entries(n))if(C(j).includes(E)){let N=r.tasks[G];if(!N)continue;let we=m.lastConsumedHashes?.[E];return N.lastDataHash==null?N.executionCount>m.lastEpoch:N.lastDataHash!==we}return false})||(S=true);break}case "epoch-changed":{y.length>0&&y.some(E=>{for(let[G,j]of Object.entries(n))if(C(j).includes(E)){let N=r.tasks[G];if(N&&N.executionCount>m.lastEpoch)return true}return false})||(S=true);break}case "time-based":{let _=v.refreshInterval??0;if(_<=0){S=true;break}let E=m.completedAt;if(!E){S=true;break}(Date.now()-Date.parse(E))/1e3<_&&(S=true);break}case "manual":S=true;break}if(S)continue}let h=O(v);if(h.length===0){l.push(f);continue}let b=[],k=[],T=[];for(let y of h){if(u.has(y))continue;let S=o[y]||[];S.length===0?b.push(y):S.every(E=>I(r.tasks[E]))?T.push({token:y,failedProducer:S[0]}):k.push(y);}b.length>0?d.push({taskName:f,missingTokens:b}):T.length>0?c.push({taskName:f,failedTokens:T.map(y=>y.token),failedProducers:[...new Set(T.map(y=>y.failedProducer))]}):k.length>0?i.push({taskName:f,waitingOn:k}):l.push(f);}let g={};if(l.length>1){let f=ce(l,n);for(let[v,m]of Object.entries(f))m.length>1&&(g[v]=m);}return {eligible:l,pending:i,unresolved:d,blocked:c,conflicts:g}}function Oe(e){let t={};for(let[r,n]of Object.entries(e)){for(let s of C(n))t[s]||(t[s]=[]),t[s].push(r);if(n.on)for(let s of Object.values(n.on))for(let o of s)t[o]||(t[o]=[]),t[o].includes(r)||t[o].push(r);if(n.on_failure)for(let s of n.on_failure)t[s]||(t[s]=[]),t[s].includes(r)||t[s].push(r);}return t}function _e(e){let{config:t,state:r}=e,n=A(t),s=Object.keys(n),o=0,a=0,u=0,l=0,i=0,d=0;for(let p of s){let h=r.tasks[p];if(!h||h.status===w.NOT_STARTED)i++;else switch(h.status){case w.RUNNING:o++;break;case w.COMPLETED:a++;break;case w.FAILED:u++;break;case "inactivated":d++;break;default:l++;}}let c={};for(let[p,h]of Object.entries(n)){for(let b of C(h))c[b]||(c[b]=[]),c[b].push(p);if(h.on)for(let b of Object.values(h.on))for(let k of b)c[k]||(c[k]=[]),c[k].includes(p)||c[k].push(p);if(h.on_failure)for(let b of h.on_failure)c[b]||(c[b]=[]),c[b].includes(p)||c[b].push(p);}let g=new Set,f=0,v=0;for(let[p,h]of Object.entries(n)){let b=r.tasks[p];if(b?.status===w.COMPLETED||b?.status===w.RUNNING)continue;let k=false,T=false;for(let y of O(h)){let S=c[y]||[];S.length===0?(g.add(y),k=true):S.every(E=>{let G=r.tasks[E];return G?.status===w.FAILED||G?.status==="inactivated"})&&(T=true);}k&&f++,T&&!k&&v++;}let m=[];for(let[p,h]of Object.entries(c))h.length>1&&m.push(p);let R=Ae(n,c),x=Ge(s,R);return {totalNodes:s.length,running:o,completed:a,failed:u,waiting:l,notStarted:i,disabled:d,unresolvedCount:f,blockedCount:v,openDependencies:[...g],cycles:x,conflictTokens:m}}function Ae(e,t){let r={};for(let[n,s]of Object.entries(e)){r[n]=new Set;for(let o of O(s))for(let a of t[o]||[])a!==n&&r[n].add(a);}return r}function Ge(e,t){let o={},a={},u=[];for(let i of e)o[i]=0,a[i]=null;function l(i){o[i]=1;for(let d of t[i]||[])if(o[d]===1){let c=[d],g=i;for(;g!==d;)c.push(g),g=a[g];c.push(d),c.reverse(),u.push(c);}else o[d]===0&&(a[d]=i,l(d));o[i]=2;}for(let i of e)o[i]===0&&l(i);return u}function ge(e){let t={};for(let[r,n]of Object.entries(e)){for(let s of C(n))t[s]||(t[s]=[]),t[s].push(r);if(n.on)for(let s of Object.values(n.on))for(let o of s)t[o]||(t[o]=[]),t[o].includes(r)||t[o].push(r);if(n.on_failure)for(let s of n.on_failure)t[s]||(t[s]=[]),t[s].includes(r)||t[s].push(r);}return t}function ke(e){let{config:t,state:r}=e,n=A(t),s=ge(n),o=new Set([...r.availableOutputs]);for(let[c,g]of Object.entries(r.tasks))if(g.status==="completed"){let f=n[c];f&&C(f).forEach(v=>o.add(v));}let a=new Set;for(let c of Object.values(n))for(let g of O(c))a.add(g);let u=new Set,l=new Set;for(let c of a){if(o.has(c))continue;(s[c]||[]).length===0&&u.add(c);}let i=true;for(;i;){i=false;for(let[c,g]of Object.entries(n)){if(l.has(c))continue;let f=r.tasks[c];if(f?.status==="completed")continue;let v=I(f),R=O(g).some(x=>u.has(x));(v||R)&&(l.has(c)||(l.add(c),i=true));}for(let c of a){if(u.has(c)||o.has(c))continue;let g=s[c]||[],f=g.length>0&&g.every(v=>l.has(v)||I(r.tasks[v]));(g.length===0||f)&&(u.has(c)||(u.add(c),i=true));}}let d=[];for(let c of u){let g=s[c]||[],f;g.length===0?f="no-producer":f=g.every(m=>I(r.tasks[m]))?"all-producers-failed":"transitive",d.push({token:c,reason:f,producers:g});}return {tokens:d}}function Ne(e){let{config:t,state:r}=e,n=A(t),{tokens:s}=ke(e),o=new Set(s.map(u=>u.token)),a=[];for(let[u,l]of Object.entries(n)){let i=r.tasks[u];if(i?.status==="completed")continue;let c=O(l).filter(g=>o.has(g));c.length>0?a.push({nodeName:u,missingTokens:c}):I(i)&&a.push({nodeName:u,missingTokens:[]});}return {nodes:a}}function Ie(e,t){let r=A(e.config);if(!r[t])return {nodeName:t,nodes:[],tokens:[]};let n=ge(r),s=new Set,o=new Set,a=new Map;function u(i){let d=r[i];if(d)for(let c of O(d)){let g=n[c]||[];for(let f of g)f!==t&&(o.add(c),a.has(f)||a.set(f,new Set),a.get(f).add(c),s.has(f)||(s.add(f),u(f)));}}u(t);let l=[...a.entries()].map(([i,d])=>({nodeName:i,providesTokens:[...d]}));return {nodeName:t,nodes:l,tokens:[...o]}}function je(e,t){let r=A(e.config);if(!r[t])return {nodeName:t,nodes:[],tokens:[]};let n={};for(let[i,d]of Object.entries(r))for(let c of O(d))n[c]||(n[c]=[]),n[c].push(i);let s=new Set,o=new Set,a=new Map;function u(i){let d=r[i];if(d)for(let c of C(d)){let g=n[c]||[];for(let f of g)f!==t&&(o.add(c),a.has(f)||a.set(f,new Set),a.get(f).add(c),s.has(f)||(s.add(f),u(f)));}}u(t);let l=[...a.entries()].map(([i,d])=>({nodeName:i,requiresTokens:[...d]}));return {nodeName:t,nodes:l,tokens:[...o]}}var H=class{buffer=[];append(t){this.buffer.push(t);}drain(){let t=this.buffer;return this.buffer=[],t}get size(){return this.buffer.length}};function B(e){let t=ne(e);return He(t)}function ne(e){if(e==null||typeof e!="object")return JSON.stringify(e);if(Array.isArray(e))return "["+e.map(ne).join(",")+"]";let t=e;return "{"+Object.keys(t).sort().map(n=>JSON.stringify(n)+":"+ne(t[n])).join(",")+"}"}function He(e){let t=0xcbf29ce484222325n,r=0x100000001b3n,n=0xffffffffffffffffn;for(let s=0;s<e.length;s++)t^=BigInt(e.charCodeAt(s)),t=t*r&n;return t.toString(16).padStart(16,"0")}function Le(e){if(typeof Buffer<"u")return Buffer.from(e,"utf8").toString("base64url");if(typeof btoa=="function"){let t=new TextEncoder().encode(e),r="";for(let n of t)r+=String.fromCharCode(n);return btoa(r).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}throw new Error("No base64 encoder available in this runtime")}function De(e){if(typeof Buffer<"u")return Buffer.from(e,"base64url").toString("utf8");if(typeof atob=="function"){let t=e.replace(/-/g,"+").replace(/_/g,"/"),r=t+"=".repeat((4-t.length%4)%4),n=atob(r),s=new Uint8Array(n.length);for(let o=0;o<n.length;o++)s[o]=n.charCodeAt(o);return new TextDecoder().decode(s)}throw new Error("No base64 decoder available in this runtime")}function he(e){let t=JSON.stringify({t:e,n:Date.now().toString(36)+Math.random().toString(36).slice(2,6)});return Le(t)}function Pe(e){try{let t=JSON.parse(De(e));return typeof t?.t=="string"?{taskName:t.t}:null}catch{return null}}function re(e,t,r){let{handlers:n,onDrain:s}=t,o=new H,a="state"in e&&"config"in e?e:J(e,r),u=false,l=new Set,i=new Map(Object.entries(n)),d=new H,c=false,g=false;function f(){if(!u){if(c){g=true;return}c=true;try{do g=!1,v();while(g)}finally{c=false;}}}function v(){let p=d.drain(),h=o.drain(),b=[...p,...h];b.length>0&&(a=L(a,b));let k=V(a);b.length>0&&s?.(b,a,k);for(let T of k.eligible)x(T);for(let T of b)if(T.type==="task-progress"){let{taskName:y,update:S}=T;if(!a.config.tasks[y])continue;let E=a.state.tasks[y];if(!E||E.status!=="running")continue;let G=he(y),j=R(y,G,S).catch(N=>{u||(d.append({type:"task-failed",taskName:y,error:N.message??String(N),timestamp:new Date().toISOString()}),f());}).finally(()=>{l.delete(j);});l.add(j);}}function m(p){let b=a.config.tasks[p].requires??[],k=new Map;for(let[y,S]of Object.entries(a.config.tasks))for(let _ of S.provides??[])k.set(_,y);let T={};for(let y of b){let S=k.get(y);S?T[y]=a.state.tasks[S]?.data:T[y]=void 0;}return T}async function R(p,h,b){let k=a.config.tasks[p],T=k.taskHandlers??[],y=m(p);for(let S of T){let _=i.get(S);if(!_)throw new Error(`Handler '${S}' not found in registry (task '${p}')`);let E={nodeId:p,state:y,taskState:a.state.tasks[p],config:k,callbackToken:h,update:b};if(await _(E)==="task-initiate-failure")throw new Error(`Handler '${S}' returned task-initiate-failure (task '${p}')`)}}function x(p){let b=a.config.tasks[p]?.taskHandlers;if(!b||b.length===0)return;d.append({type:"task-started",taskName:p,timestamp:new Date().toISOString()}),f();let k=he(p),T=R(p,k).catch(y=>{u||(d.append({type:"task-failed",taskName:p,error:y.message??String(y),timestamp:new Date().toISOString()}),f());}).finally(()=>{l.delete(T);});l.add(T);}return {push(p){u||(p.type==="task-completed"&&p.data&&!p.dataHash&&(p={...p,dataHash:B(p.data)}),o.append(p),f());},pushAll(p){if(!u){for(let h of p)h.type==="task-completed"&&h.data&&!h.dataHash?o.append({...h,dataHash:B(h.data)}):o.append(h);f();}},resolveCallback(p,h,b){if(u)return;let k=Pe(p);if(!k)return;let{taskName:T}=k;if(a.config.tasks[T]){if(b&&b.length>0)o.append({type:"task-failed",taskName:T,error:b.join("; "),timestamp:new Date().toISOString()});else {let y=h&&Object.keys(h).length>0?B(h):void 0;o.append({type:"task-completed",taskName:T,data:h,dataHash:y,timestamp:new Date().toISOString()});}f();}},addNode(p,h){u||(o.append({type:"task-upsert",taskName:p,taskConfig:h,timestamp:new Date().toISOString()}),f());},removeNode(p){u||(o.append({type:"task-removal",taskName:p,timestamp:new Date().toISOString()}),f());},addRequires(p,h){u||(o.append({type:"node-requires-add",nodeName:p,tokens:h,timestamp:new Date().toISOString()}),f());},removeRequires(p,h){u||(o.append({type:"node-requires-remove",nodeName:p,tokens:h,timestamp:new Date().toISOString()}),f());},addProvides(p,h){u||(o.append({type:"node-provides-add",nodeName:p,tokens:h,timestamp:new Date().toISOString()}),f());},removeProvides(p,h){u||(o.append({type:"node-provides-remove",nodeName:p,tokens:h,timestamp:new Date().toISOString()}),f());},registerHandler(p,h){i.set(p,h);},unregisterHandler(p){i.delete(p);},retrigger(p){u||a.config.tasks[p]&&(o.append({type:"task-restart",taskName:p,timestamp:new Date().toISOString()}),f());},retriggerAll(p){if(!u){for(let h of p)a.config.tasks[h]&&o.append({type:"task-restart",taskName:h,timestamp:new Date().toISOString()});f();}},snapshot(){return te(a)},getState(){return a},getSchedule(){return V(a)},async waitForHandlers(){l.size>0&&await Promise.allSettled([...l]);},async dispose(p){p?.wait&&l.size>0&&await Promise.allSettled([...l]),u=true;}}}function me(e){let t=[],{config:r,state:n}=e,s=A(r),o=Object.keys(s);for(let i of o)n.tasks[i]||t.push({severity:"error",code:"MISSING_STATE",message:`Task "${i}" exists in config but has no state entry`,tasks:[i]});for(let i of Object.keys(n.tasks))s[i]||t.push({severity:"warning",code:"ORPHAN_STATE",message:`State entry "${i}" has no corresponding task config`,tasks:[i]});for(let i of o){let d=n.tasks[i];d&&(d.status===w.RUNNING&&!d.startedAt&&t.push({severity:"warning",code:"RUNNING_WITHOUT_START",message:`Task "${i}" is running but has no startedAt timestamp`,tasks:[i]}),d.status===w.COMPLETED&&!d.completedAt&&t.push({severity:"warning",code:"COMPLETED_WITHOUT_TIMESTAMP",message:`Task "${i}" is completed but has no completedAt timestamp`,tasks:[i]}),d.status===w.FAILED&&(d.failedAt||t.push({severity:"warning",code:"FAILED_WITHOUT_INFO",message:`Task "${i}" is failed but has no failedAt timestamp`,tasks:[i]}),d.error||t.push({severity:"info",code:"FAILED_WITHOUT_INFO",message:`Task "${i}" is failed but has no error message`,tasks:[i]})));}let a=new Set;for(let i of o)if(n.tasks[i]?.status===w.COMPLETED)for(let c of C(s[i]))a.add(c);let u=new Set(n.availableOutputs),l=new Set;for(let i of Object.values(s)){for(let d of C(i))l.add(d);if(i.on)for(let d of Object.values(i.on))for(let c of d)l.add(c);if(i.on_failure)for(let d of i.on_failure)l.add(d);}for(let i of u)!a.has(i)&&!l.has(i)&&t.push({severity:"info",code:"INJECTED_TOKEN",message:`Token "${i}" is available but no task in the graph can produce it (likely injected)`,tokens:[i]});for(let i of a)u.has(i)||t.push({severity:"warning",code:"MISSING_OUTPUT",message:`Token "${i}" should be available (its producer completed) but is not in availableOutputs`,tokens:[i]});for(let i of o){let d=n.tasks[i];if(!d)continue;d.executionCount<0&&t.push({severity:"error",code:"INVALID_EXECUTION_COUNT",message:`Task "${i}" has negative execution count: ${d.executionCount}`,tasks:[i]});let c=s[i].maxExecutions;c!==void 0&&d.executionCount>c&&t.push({severity:"error",code:"EXCEEDED_MAX_EXECUTIONS",message:`Task "${i}" executed ${d.executionCount} times, exceeding maxExecutions of ${c}`,tasks:[i]});}return ve(t)}function Me(e){let{graph:t,handlers:r}=e,n=t.getState(),s=[],o=A(n.config),a=Object.keys(o),u=new Set(Object.keys(r)),l=new Set;for(let d of a){let c=o[d].taskHandlers;if(c)for(let g of c)l.add(g);}for(let d of a){let c=o[d].taskHandlers;if(c)for(let g of c)r[g]||s.push({severity:"error",code:"MISSING_HANDLER",message:`Task "${d}" references handler "${g}" but it is not in the registry`,tasks:[d]});}for(let d of u)l.has(d)||s.push({severity:"warning",code:"ORPHAN_HANDLER",message:`Handler "${d}" is registered but not referenced by any task's taskHandlers`,tasks:[d]});let i=me(n);return s.push(...i.issues),ve(s)}function ve(e){let t=e.filter(n=>n.severity==="error"),r=e.filter(n=>n.severity==="warning");return {valid:t.length===0,issues:e,errors:t,warnings:r}}function qe(e,t){let r=e;for(let n of t)r=Fe(r,n);return r}function Fe(e,t){switch(t.type){case "add-node":return P(e,t.name,t.config);case "remove-node":return M(e,t.name);case "add-requires":return q(e,t.taskName,t.tokens);case "remove-requires":return F(e,t.taskName,t.tokens);case "add-provides":return $(e,t.taskName,t.tokens);case "remove-provides":return U(e,t.taskName,t.tokens);case "inject-tokens":return X(e,t.tokens);case "drain-tokens":return z(e,t.tokens);case "reset-node":return Q(e,t.name);case "disable-node":return Z(e,t.name);case "enable-node":return ee(e,t.name);case "apply-events":return L(e,t.events);default:throw new Error(`Unknown mutation type: ${t.type}`)}}function Ke(e,t){return async r=>{let{callbackToken:n}=r;return Promise.resolve(e(r)).then(s=>t()(n,s)).catch(s=>t()(n,{},[s instanceof Error?s.message:String(s)])),"task-initiated"}}function Ve(e,t){return async r=>{let{callbackToken:n}=r;return Promise.resolve(e(r)).then(()=>t()(n,{})).catch(()=>t()(n,{})),"task-initiated"}}function Be(e){let{command:t,cwd:r,env:n,timeoutMs:s=3e4,exitCodeMap:o,captureOutput:a=false,getResolve:u}=e;return async l=>{let{callbackToken:i,nodeId:d}=l,c=t.replace(/\$\{taskName\}/g,d);return exec(c,{cwd:r,env:n?{...process.env,...n}:void 0,timeout:s,maxBuffer:10*1024*1024},(g,f,v)=>{let m=g?.code??(g?1:0);if(m!==0&&!o?.[m]){u()(i,{},[`Command exited with code ${m}: ${v||g?.message}`]);return}let R={};a&&(R.stdout=f,R.stderr=v,R.exitCode=m),u()(i,R);}),"task-initiated"}}function ye(e){let{command:t,args:r=[],cwd:n,env:s,timeoutMs:o=3e4,exitCodeMap:a,captureOutput:u=false,getResolve:l}=e;return async i=>{let{callbackToken:d,nodeId:c}=i,g=t.replace(/\$\{taskName\}/g,c),f=r.map(v=>v.replace(/\$\{taskName\}/g,c));return execFile(g,f,{cwd:n,env:s?{...process.env,...s}:void 0,timeout:o,maxBuffer:10*1024*1024,encoding:"utf8",windowsHide:true},(v,m,R)=>{let x=v?.code??(v?1:0);if(x!==0&&!a?.[x]){l()(d,{},[`Process exited with code ${x}: ${R||v?.message}`]);return}let p={};u&&(p.stdout=m,p.stderr=R,p.exitCode=x),l()(d,p);}),"task-initiated"}}function We(e){return e.endsWith(".js")||e.endsWith(".mjs")||e.endsWith(".ts")?"node":e.endsWith(".py")?"python3":(e.endsWith(".sh"),"bash")}function Je(e){let{scriptPath:t,runtime:r,args:n=[],cwd:s,timeoutMs:o=6e4,captureOutput:a=false,getResolve:u}=e,l=r??We(t),i=l==="node"?process.execPath:l;return ye({command:i,args:[t,"${taskName}",...n],cwd:s,timeoutMs:o,captureOutput:a,getResolve:u})}function Ye(e){let{url:t,method:r="POST",headers:n={},timeoutMs:s=3e4,failOnNon2xx:o=true,getResolve:a}=e;return async u=>{let{callbackToken:l,nodeId:i,config:d}=u,c=t.replace(/\$\{taskName\}/g,i),g=JSON.stringify({taskName:i,callbackToken:l,config:d}),f=new AbortController,v=setTimeout(()=>f.abort(),s);return fetch(c,{method:r,headers:{"Content-Type":"application/json",...n},body:g,signal:f.signal}).then(async m=>{if(clearTimeout(v),o&&!m.ok){let x=await m.text().catch(()=>"");a()(l,{},[`HTTP ${m.status}: ${x}`]);return}let R=await m.json().catch(()=>({}));a()(l,R);}).catch(m=>{clearTimeout(v),a()(l,{},[m instanceof Error?m.message:String(m)]);}),"task-initiated"}}function Xe(e,t){return async r=>(e()(r.callbackToken,t??{}),"task-initiated")}var Qe=createRequire(import.meta.url),Se=Qe("./jsonata-sync.cjs")??W;function be(e,t){if(!t||!e)return;let r=t.split("."),n=e;for(let s=0;s<r.length;s++){if(n==null)return;n=n[r[s]];}return n}function Re(e,t,r){let n=t.split("."),s=e;for(let o=0;o<n.length-1;o++)(s[n[o]]==null||typeof s[n[o]]!="object")&&(s[n[o]]={}),s=s[n[o]];s[n[n.length-1]]=r;}async function Ze(e,t){if(!e?.compute?.length)return e;e.card_data||(e.card_data={}),e.computed_values={},e._sourcesData=t?.sourcesData??{};let r={card_data:e.card_data,requires:e.requires??{},fetched_sources:e._sourcesData,computed_values:e.computed_values};for(let n of e.compute)try{let s=await W(n.expr).evaluate(r);Re(e.computed_values,n.bindTo,s),r.computed_values=e.computed_values;}catch(s){console.error(`CardCompute.run error on "${e.id??"?"}.${n.bindTo}":`,s);}return e}function et(e,t){if(!e?.compute?.length)return {ok:true,node:e};e.card_data||(e.card_data={}),e.computed_values={},e._sourcesData=t?.sourcesData??{};let r={card_data:e.card_data,requires:e.requires??{},fetched_sources:e._sourcesData,computed_values:e.computed_values};for(let n of e.compute)try{let s=Se(n.expr).evaluate(r);Re(e.computed_values,n.bindTo,s),r.computed_values=e.computed_values;}catch(s){console.error(`CardCompute.runSync error on "${e.id??"?"}.${n.bindTo}":`,s);}return {ok:true,node:e}}async function tt(e,t){let r={card_data:t.card_data??{},requires:t.requires??{},fetched_sources:t._sourcesData??{},computed_values:t.computed_values??{}};return W(e).evaluate(r)}function nt(e,t){return t.startsWith("fetched_sources.")?be(e._sourcesData??{},t.slice(16)):be(e,t)}var Te=new Set(["metric","table","editable-table","chart","form","filter","list","notes","todo","alert","narrative","badge","text","markdown","ref","custom","actions"]),rt=new Set(["id","meta","requires","provides","view","card_data","compute","source_defs"]);function st(e){let t=[];if(!e||typeof e!="object"||Array.isArray(e))return {ok:false,errors:["Node must be a non-null object"]};let r=e;(typeof r.id!="string"||!r.id)&&t.push("id: required, must be a non-empty string");for(let n of Object.keys(r))rt.has(n)||t.push(`Unknown top-level key: "${n}"`);if((r.card_data==null||typeof r.card_data!="object"||Array.isArray(r.card_data))&&t.push("card_data: required, must be an object"),r.meta!=null)if(typeof r.meta!="object"||Array.isArray(r.meta))t.push("meta: must be an object");else {let n=r.meta;n.title!=null&&typeof n.title!="string"&&t.push("meta.title: must be a string"),n.tags!=null&&!Array.isArray(n.tags)&&t.push("meta.tags: must be an array");}if(r.requires!=null&&!Array.isArray(r.requires)&&t.push("requires: must be an array of strings"),r.provides!=null&&(Array.isArray(r.provides)?r.provides.forEach((n,s)=>{if(!n||typeof n!="object"||Array.isArray(n))t.push(`provides[${s}]: must be an object with bindTo and ref`);else {let o=n;(typeof o.bindTo!="string"||!o.bindTo)&&t.push(`provides[${s}]: missing required "bindTo" string`),(typeof o.ref!="string"||!o.ref)&&t.push(`provides[${s}]: missing required "ref" string`);}}):t.push("provides: must be an array of { bindTo, ref } bindings")),r.compute!=null&&(Array.isArray(r.compute)?r.compute.forEach((n,s)=>{if(!n||typeof n!="object"||Array.isArray(n))t.push(`compute[${s}]: must be a compute step object`);else {let o=n;(typeof o.bindTo!="string"||!o.bindTo)&&t.push(`compute[${s}]: missing required "bindTo" property`),(typeof o.expr!="string"||!o.expr)&&t.push(`compute[${s}]: missing required "expr" string (JSONata expression)`);}}):t.push("compute: must be an array of compute steps")),r.source_defs!=null)if(!Array.isArray(r.source_defs))t.push("source_defs: must be an array");else {let n=new Set,s=new Set;r.source_defs.forEach((o,a)=>{if(!o||typeof o!="object"||Array.isArray(o))t.push(`source_defs[${a}]: must be an object`);else {let u=o;typeof u.bindTo!="string"||!u.bindTo?t.push(`source_defs[${a}]: missing required "bindTo" property`):(n.has(u.bindTo)&&t.push(`source_defs[${a}]: bindTo "${u.bindTo}" is not unique across source_defs`),n.add(u.bindTo)),typeof u.outputFile!="string"||!u.outputFile?t.push(`source_defs[${a}]: missing required "outputFile" property`):(s.has(u.outputFile)&&t.push(`source_defs[${a}]: outputFile "${u.outputFile}" is not unique across source_defs`),s.add(u.outputFile)),u.optionalForCompletionGating!=null&&typeof u.optionalForCompletionGating!="boolean"&&t.push(`source_defs[${a}]: optionalForCompletionGating must be a boolean`);}});}if(r.view!=null)if(typeof r.view!="object"||Array.isArray(r.view))t.push("view: must be an object");else {let n=r.view;!Array.isArray(n.elements)||n.elements.length===0?t.push("view.elements: required, must be a non-empty array"):n.elements.forEach((s,o)=>{if(!s||typeof s!="object"){t.push(`view.elements[${o}]: must be an object`);return}!s.kind||typeof s.kind!="string"?t.push(`view.elements[${o}].kind: required, must be a string`):Te.has(s.kind)||t.push(`view.elements[${o}].kind: unknown kind "${s.kind}". Valid: ${[...Te].join(", ")}`),s.data!=null&&(typeof s.data!="object"||Array.isArray(s.data))&&t.push(`view.elements[${o}].data: must be an object`);}),n.layout!=null&&(typeof n.layout!="object"||Array.isArray(n.layout))&&t.push("view.layout: must be an object"),n.features!=null&&(typeof n.features!="object"||Array.isArray(n.features))&&t.push("view.features: must be an object");}return {ok:t.length===0,errors:t}}async function ot(e,t){if(!e||e.length===0)return [];let r={card_data:t.card_data??{},requires:t.requires??{}};return Promise.all(e.map(async n=>{let s={};if(n.projections&&typeof n.projections=="object"&&!Array.isArray(n.projections)){for(let[o,a]of Object.entries(n.projections))if(typeof a=="string"&&a.trim().length>0)try{s[o]=await W(a).evaluate(r);}catch{s[o]=void 0;}}return {...n,_projections:s}}))}function at(e,t){if(!e||e.length===0)return [];let r={card_data:t.card_data??{},requires:t.requires??{}};return e.map(n=>{let s={};if(n.projections&&typeof n.projections=="object"&&!Array.isArray(n.projections)){for(let[o,a]of Object.entries(n.projections))if(typeof a=="string"&&a.trim().length>0)try{s[o]=Se(a).evaluate(r);}catch{s[o]=void 0;}}return {...n,_projections:s}})}var se={run:Ze,runSync:et,eval:tt,resolve:nt,validate:st,enrichSources:ot,enrichSourcesSync:at};function it(e,t={}){let r,n={},s;if(!Array.isArray(e)&&"nodes"in e){let k=e;r=k.nodes,s=k.id,n=k.settings??{};}else r=e;let{sourceHandlers:o={},defaultSourceHandler:a,cardHandlers:u={},reactiveOptions:l={},graphSettings:i={},executionId:d}=t,c=new Map;for(let k of r){if(c.has(k.id))throw new Error(`Duplicate card ID: "${k.id}"`);c.set(k.id,k);}let g=t.sharedState??new Map,f={},v=new Set,m=new Map;for(let k of r)for(let T of k.provides??[{bindTo:k.id,ref:"card_data"}])v.add(T.bindTo),m.set(T.bindTo,k.id);for(let k of r){let T=k.requires??[];for(let y of T)if(!v.has(y))throw new Error(`Card "${k.id}" requires "${y}" but no card provides that token`);f[k.id]={requires:T.length>0?T:void 0,provides:(k.provides??[{bindTo:k.id,ref:"card_data"}]).map(y=>y.bindTo),taskHandlers:[k.id],description:k.meta?.title??k.id};}let R={id:s??`live-cards-${Date.now()}`,settings:{completion:"manual",execution_mode:"eligibility-mode",...n,...i},tasks:f},x={},p=null,h=()=>(k,T,y)=>{p.resolveCallback(k,T,y);};for(let k of r)k.source_defs&&k.source_defs.length>0?x[k.id]=ct(k,o,a,g,h):x[k.id]=ut(k,u,g,c,m,h);let b=re(R,{...l,handlers:x},d);return p=b,{graph:b,config:R,handlers:x,cards:c,sharedState:g}}function ct(e,t,r,n,s){if(t[e.id]){let o=t[e.id];return async a=>o(a)}if(r){let o=r(e);return async a=>o(a)}return async o=>{let a={...e.card_data};return n.set(e.id,a),s()(o.callbackToken,a),"task-initiated"}}function ut(e,t,r,n,s,o){if(t[e.id]){let a=t[e.id];return async u=>a(u)}return async a=>{let u={},l=e.requires??[];for(let g of l){let f=s.get(g)??g,v=r.get(f);v&&(u[g]=v[g]??v);}let i={id:e.id,card_data:{...e.card_data},requires:u,compute:e.compute};await se.run(i);let d;if(e.provides&&e.provides.length>0){d={};for(let{bindTo:g,ref:f}of e.provides)d[g]=se.resolve(i,f);}else d={...i.card_data,...i.computed_values};let c={...i.card_data,...i.computed_values};return r.set(e.id,c),o()(a.callbackToken,d),"task-initiated"}}
2
+ export{H as MemoryJournal,P as addNode,$ as addProvides,q as addRequires,Y as applyEvent,L as applyEvents,B as computeDataHash,Ke as createCallbackHandler,Ve as createFireAndForgetHandler,J as createLiveGraph,Xe as createNoopHandler,ye as createProcessHandler,re as createReactiveGraph,Je as createScriptHandler,Be as createShellHandler,Ye as createWebhookHandler,Z as disableNode,z as drainTokens,ee as enableNode,je as getDownstream,Ce as getNode,Ne as getUnreachableNodes,ke as getUnreachableTokens,Ie as getUpstream,X as injectTokens,_e as inspect,it as liveCardsToReactiveGraph,qe as mutateGraph,M as removeNode,U as removeProvides,F as removeRequires,Q as resetNode,xe as restore,V as schedule,te as snapshot,me as validateLiveGraph,Me as validateReactiveGraph};//# sourceMappingURL=index.js.map
2089
3
  //# sourceMappingURL=index.js.map