yaml-flow 5.0.0 → 5.2.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 (105) hide show
  1. package/{examples/example-board/reusable-server-runtime.js → board-livecards-server-runtime.js} +103 -24
  2. package/{examples/example-board/reusable-board-runtime-client.js → browser/board-livecards-runtime-client.js} +6 -2
  3. package/browser/{board-livegraph-runtime.js → board-livegraph-engine.js} +212 -16
  4. package/browser/board-livegraph-engine.js.map +1 -0
  5. package/browser/live-cards.js +362 -38
  6. package/browser/live-cards.schema.json +20 -4
  7. package/dist/board-livegraph-runtime/index.cjs +210 -14
  8. package/dist/board-livegraph-runtime/index.cjs.map +1 -1
  9. package/dist/board-livegraph-runtime/index.d.cts +49 -5
  10. package/dist/board-livegraph-runtime/index.d.ts +49 -5
  11. package/dist/board-livegraph-runtime/index.js +209 -15
  12. package/dist/board-livegraph-runtime/index.js.map +1 -1
  13. package/dist/card-compute/index.cjs +63 -7
  14. package/dist/card-compute/index.cjs.map +1 -1
  15. package/dist/card-compute/index.d.cts +2 -2
  16. package/dist/card-compute/index.d.ts +2 -2
  17. package/dist/card-compute/index.js +63 -7
  18. package/dist/card-compute/index.js.map +1 -1
  19. package/dist/cli/board-live-cards-cli.cjs +664 -75
  20. package/dist/cli/board-live-cards-cli.cjs.map +1 -1
  21. package/dist/cli/board-live-cards-cli.d.cts +33 -5
  22. package/dist/cli/board-live-cards-cli.d.ts +33 -5
  23. package/dist/cli/board-live-cards-cli.js +661 -76
  24. package/dist/cli/board-live-cards-cli.js.map +1 -1
  25. package/dist/{constants-ozjf1Ejw.d.cts → constants-BzZUyYlp.d.cts} +1 -1
  26. package/dist/{constants-DuzE5n03.d.ts → constants-oCEbNpul.d.ts} +1 -1
  27. package/dist/continuous-event-graph/index.cjs +47 -14
  28. package/dist/continuous-event-graph/index.cjs.map +1 -1
  29. package/dist/continuous-event-graph/index.d.cts +9 -9
  30. package/dist/continuous-event-graph/index.d.ts +9 -9
  31. package/dist/continuous-event-graph/index.js +47 -14
  32. package/dist/continuous-event-graph/index.js.map +1 -1
  33. package/dist/event-graph/index.cjs +29 -12
  34. package/dist/event-graph/index.cjs.map +1 -1
  35. package/dist/event-graph/index.d.cts +5 -5
  36. package/dist/event-graph/index.d.ts +5 -5
  37. package/dist/event-graph/index.js +29 -12
  38. package/dist/event-graph/index.js.map +1 -1
  39. package/dist/index.cjs +93 -20
  40. package/dist/index.cjs.map +1 -1
  41. package/dist/index.d.cts +7 -7
  42. package/dist/index.d.ts +7 -7
  43. package/dist/index.js +93 -20
  44. package/dist/index.js.map +1 -1
  45. package/dist/inference/index.cjs +29 -12
  46. package/dist/inference/index.cjs.map +1 -1
  47. package/dist/inference/index.d.cts +2 -2
  48. package/dist/inference/index.d.ts +2 -2
  49. package/dist/inference/index.js +29 -12
  50. package/dist/inference/index.js.map +1 -1
  51. package/dist/{journal-NLYuqege.d.ts → journal-9HEgs7dU.d.ts} +1 -1
  52. package/dist/{journal-DRfJiheM.d.cts → journal-B-JCfQnh.d.cts} +1 -1
  53. package/dist/{live-cards-bridge-Or7fdEJV.d.ts → live-cards-bridge-CeNxiVcm.d.ts} +6 -2
  54. package/dist/{live-cards-bridge-vGJ6tMzN.d.cts → live-cards-bridge-z_rJCSbi.d.cts} +6 -2
  55. package/dist/{schedule-CMcZe5Ny.d.ts → schedule-Cszq9LYY.d.ts} +1 -1
  56. package/dist/{schedule-CiucyCan.d.cts → schedule-qWNL0RQh.d.cts} +1 -1
  57. package/dist/{types-CMFSIjpc.d.cts → types-BBhqYGhE.d.cts} +4 -0
  58. package/dist/{types-CMFSIjpc.d.ts → types-BBhqYGhE.d.ts} +4 -0
  59. package/dist/{types-BzLD8bjb.d.cts → types-CHSdoAAA.d.cts} +1 -1
  60. package/dist/{types-C2eJ7DAV.d.ts → types-CoW0gQl3.d.ts} +1 -1
  61. package/dist/{validate-DJQTQ6bP.d.ts → validate-BAVzUJWa.d.ts} +1 -1
  62. package/dist/{validate-ke92Cleg.d.cts → validate-Dbu7ygys.d.cts} +1 -1
  63. package/examples/browser/boards/portfolio-tracker/cards/portfolio-risk-assessment.json +28 -0
  64. package/examples/browser/boards/portfolio-tracker/cards/rebalancing-strategy.json +28 -0
  65. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-inference-adapter.js +187 -0
  66. package/examples/browser/boards/portfolio-tracker/portfolio-tracker.js +139 -5
  67. package/examples/example-board/agent-instructions-cardlayout.md +28 -0
  68. package/examples/example-board/agent-instructions.md +603 -0
  69. package/examples/example-board/cards/card-concentration.json +42 -0
  70. package/examples/example-board/cards/card-market-prices.json +51 -0
  71. package/examples/example-board/cards/card-portfolio-action.json +19 -0
  72. package/examples/example-board/cards/card-portfolio-risks.json +19 -0
  73. package/examples/example-board/cards/card-portfolio-value.json +62 -0
  74. package/examples/example-board/cards/card-portfolio.json +44 -0
  75. package/examples/example-board/demo-chat-handler.js +373 -33
  76. package/examples/example-board/demo-server-config.json +5 -0
  77. package/examples/example-board/demo-server.js +83 -7
  78. package/examples/example-board/demo-shell-browser.html +75 -207
  79. package/examples/example-board/demo-shell-with-server.html +14 -9
  80. package/examples/example-board/demo-shell.html +1 -1
  81. package/examples/example-board/demo-task-executor.js +259 -41
  82. package/package.json +6 -2
  83. package/schema/live-cards.schema.json +20 -4
  84. package/browser/board-livegraph-runtime.js.map +0 -1
  85. package/examples/example-board/board.yaml +0 -23
  86. package/examples/example-board/bootstrap_payload.json +0 -1
  87. package/examples/example-board/cards/card-chain-region-alert.json +0 -39
  88. package/examples/example-board/cards/card-chain-region-totals.json +0 -26
  89. package/examples/example-board/cards/card-chain-top-region.json +0 -24
  90. package/examples/example-board/cards/card-ex-actions.json +0 -32
  91. package/examples/example-board/cards/card-ex-chart.json +0 -30
  92. package/examples/example-board/cards/card-ex-filter.json +0 -36
  93. package/examples/example-board/cards/card-ex-filtered-by-preference.json +0 -59
  94. package/examples/example-board/cards/card-ex-form.json +0 -91
  95. package/examples/example-board/cards/card-ex-list.json +0 -22
  96. package/examples/example-board/cards/card-ex-markdown.json +0 -17
  97. package/examples/example-board/cards/card-ex-metric.json +0 -19
  98. package/examples/example-board/cards/card-ex-narrative.json +0 -36
  99. package/examples/example-board/cards/card-ex-source-http.json +0 -28
  100. package/examples/example-board/cards/card-ex-source.json +0 -21
  101. package/examples/example-board/cards/card-ex-status.json +0 -35
  102. package/examples/example-board/cards/card-ex-table.json +0 -30
  103. package/examples/example-board/cards/card-ex-todo.json +0 -29
  104. package/examples/example-board/mock.db +0 -15
  105. package/examples/example-board/reusable-runtime-artifacts-adapter.js +0 -233
@@ -138,6 +138,15 @@ export function createMultiBoardServerRuntime(options = {}) {
138
138
  const defaultTaskExecutorPath = typeof entry.taskExecutorPath === 'string'
139
139
  ? entry.taskExecutorPath
140
140
  : options.defaultTaskExecutorPath;
141
+ const defaultStepMachineCliPath = typeof entry.stepMachineCliPath === 'string'
142
+ ? entry.stepMachineCliPath
143
+ : options.defaultStepMachineCliPath;
144
+ const defaultChatHandlerPath = typeof entry.chatHandlerPath === 'string'
145
+ ? entry.chatHandlerPath
146
+ : options.defaultChatHandlerPath;
147
+ const defaultInferenceAdapterPath = typeof entry.inferenceAdapterPath === 'string'
148
+ ? entry.inferenceAdapterPath
149
+ : options.defaultInferenceAdapterPath;
141
150
 
142
151
  const service = createExampleBoardServerRuntime({
143
152
  apiBasePath: `${apiBasePath}/${boardId}`,
@@ -148,6 +157,10 @@ export function createMultiBoardServerRuntime(options = {}) {
148
157
  tmpSurfaceDir: path.join(boardRoot, 'surface'),
149
158
  runtimeOutDir: path.join(boardRoot, 'runtime-out'),
150
159
  defaultTaskExecutorPath,
160
+ defaultStepMachineCliPath,
161
+ defaultChatHandlerPath,
162
+ defaultInferenceAdapterPath,
163
+ boardLiveCardsCliJs: options.boardLiveCardsCliJs,
151
164
  });
152
165
 
153
166
  boardServiceCache.set(boardId, service);
@@ -197,6 +210,10 @@ export function createMultiBoardServerRuntime(options = {}) {
197
210
  const label = typeof body.label === 'string' && body.label.trim() ? body.label.trim() : id;
198
211
  const entry = { id, label };
199
212
  if (typeof body.cardsDir === 'string') entry.cardsDir = body.cardsDir;
213
+ if (typeof body.stepMachineCliPath === 'string') entry.stepMachineCliPath = body.stepMachineCliPath;
214
+ if (typeof body.taskExecutorPath === 'string') entry.taskExecutorPath = body.taskExecutorPath;
215
+ if (typeof body.chatHandlerPath === 'string') entry.chatHandlerPath = body.chatHandlerPath;
216
+ if (typeof body.inferenceAdapterPath === 'string') entry.inferenceAdapterPath = body.inferenceAdapterPath;
200
217
  config.boards.push(entry);
201
218
  writeBoardsConfig(config);
202
219
 
@@ -245,27 +262,17 @@ export function createMultiBoardServerRuntime(options = {}) {
245
262
  return false;
246
263
  }
247
264
 
248
- // Exposed for host transport layers to execute demo-setup for a specific board.
249
- function performDemoSetup(boardId, reset = false) {
265
+ // Exposed so host layers (e.g. demo-server) can reach a board's service and root path.
266
+ // Throws a 404 error if the board is not registered.
267
+ function requireBoardService(boardId) {
250
268
  const config = readBoardsConfig();
251
269
  if (!config.boards.some((b) => b.id === boardId)) {
252
270
  const err = new Error(`Board "${boardId}" not registered`);
253
271
  err.statusCode = 404;
254
272
  throw err;
255
273
  }
256
-
257
- const service = getBoardService(boardId);
258
- let setupPerformed = false;
259
-
260
- if (reset) {
261
- service.demoPrepSetup();
262
- setupPerformed = true;
263
- } else if (!fs.existsSync(service.tmpCardsDir)) {
264
- service.ensureDemoSetup();
265
- setupPerformed = true;
266
- }
267
-
268
- return { ok: true, setupPerformed, reset, tmpCardsDir: service.tmpCardsDir };
274
+ const boardRoot = path.join(setupDir, `board-${boardId}`);
275
+ return { service: getBoardService(boardId), boardRoot };
269
276
  }
270
277
 
271
278
  return {
@@ -277,7 +284,7 @@ export function createMultiBoardServerRuntime(options = {}) {
277
284
  handleBoardsRegistryApi,
278
285
  handleBoardApi,
279
286
  handleApi,
280
- performDemoSetup,
287
+ requireBoardService,
281
288
  };
282
289
  }
283
290
 
@@ -310,6 +317,30 @@ export function createExampleBoardServerRuntime(options = {}) {
310
317
  ? options.defaultTaskExecutorPath
311
318
  : path.resolve(process.cwd(), options.defaultTaskExecutorPath))
312
319
  : null;
320
+ const configuredStepMachineCliPath = typeof options.defaultStepMachineCliPath === 'string'
321
+ && options.defaultStepMachineCliPath.trim()
322
+ ? (path.isAbsolute(options.defaultStepMachineCliPath)
323
+ ? options.defaultStepMachineCliPath
324
+ : path.resolve(process.cwd(), options.defaultStepMachineCliPath))
325
+ : null;
326
+ const configuredBoardLiveCardsCliJs = typeof options.boardLiveCardsCliJs === 'string'
327
+ && options.boardLiveCardsCliJs.trim()
328
+ ? (path.isAbsolute(options.boardLiveCardsCliJs)
329
+ ? options.boardLiveCardsCliJs
330
+ : path.resolve(process.cwd(), options.boardLiveCardsCliJs))
331
+ : null;
332
+ const configuredChatHandlerPath = typeof options.defaultChatHandlerPath === 'string'
333
+ && options.defaultChatHandlerPath.trim()
334
+ ? (path.isAbsolute(options.defaultChatHandlerPath)
335
+ ? options.defaultChatHandlerPath
336
+ : path.resolve(process.cwd(), options.defaultChatHandlerPath))
337
+ : null;
338
+ const configuredInferenceAdapterPath = typeof options.defaultInferenceAdapterPath === 'string'
339
+ && options.defaultInferenceAdapterPath.trim()
340
+ ? (path.isAbsolute(options.defaultInferenceAdapterPath)
341
+ ? options.defaultInferenceAdapterPath
342
+ : path.resolve(process.cwd(), options.defaultInferenceAdapterPath))
343
+ : null;
313
344
 
314
345
  const statusSnapshotFile = path.join(runtimeOutDir, 'board-livegraph-status.json');
315
346
  const boardFile = path.join(boardDir, 'board-graph.json');
@@ -318,6 +349,8 @@ export function createExampleBoardServerRuntime(options = {}) {
318
349
  let didDemoSetup = false;
319
350
 
320
351
  function resolveCliJsPath() {
352
+ if (configuredBoardLiveCardsCliJs && fs.existsSync(configuredBoardLiveCardsCliJs)) return configuredBoardLiveCardsCliJs;
353
+
321
354
  const envOverride = process.env.BOARD_LIVE_CARDS_CLI_JS;
322
355
  if (envOverride && fs.existsSync(envOverride)) return envOverride;
323
356
 
@@ -341,6 +374,10 @@ export function createExampleBoardServerRuntime(options = {}) {
341
374
 
342
375
  const cliJs = resolveCliJsPath();
343
376
 
377
+ if (!process.env.DEMO_STEP_MACHINE_CLI_PATH && configuredStepMachineCliPath && fs.existsSync(configuredStepMachineCliPath)) {
378
+ process.env.DEMO_STEP_MACHINE_CLI_PATH = configuredStepMachineCliPath;
379
+ }
380
+
344
381
  function ensureCardStorageDirs(cardId) {
345
382
  const safeCardId = String(cardId || '').replace(/[^a-zA-Z0-9_-]/g, '_') || 'unknown-card';
346
383
  const cardDir = path.join(tmpCardsDir, safeCardId);
@@ -417,7 +454,7 @@ export function createExampleBoardServerRuntime(options = {}) {
417
454
  function ensureBuilt() {
418
455
  if (!cliJs || !fs.existsSync(cliJs)) {
419
456
  throw new Error(
420
- 'Unable to locate board-live-cards CLI. Set BOARD_LIVE_CARDS_CLI_JS or install yaml-flow in this project.'
457
+ 'Unable to locate board-live-cards CLI. Set boardLiveCardsCliJs option, BOARD_LIVE_CARDS_CLI_JS, or install yaml-flow in this project.'
421
458
  );
422
459
  }
423
460
  }
@@ -631,29 +668,70 @@ export function createExampleBoardServerRuntime(options = {}) {
631
668
  return resolved;
632
669
  }
633
670
 
634
- function initBoard(taskExecutorPathParam) {
671
+ function resolveChatHandlerPath(chatHandlerPathParam) {
672
+ const raw = typeof chatHandlerPathParam === 'string' ? chatHandlerPathParam.trim() : '';
673
+ const resolved = raw
674
+ ? (path.isAbsolute(raw) ? raw : path.resolve(__dirname, raw))
675
+ : configuredChatHandlerPath;
676
+ if (!resolved) return null;
677
+ if (!fs.existsSync(resolved)) {
678
+ const err = new Error(`Chat handler script not found: ${resolved}`);
679
+ err.statusCode = 400;
680
+ throw err;
681
+ }
682
+ return resolved;
683
+ }
684
+
685
+ function resolveInferenceAdapterPath(inferenceAdapterPathParam) {
686
+ const raw = typeof inferenceAdapterPathParam === 'string' ? inferenceAdapterPathParam.trim() : '';
687
+ const resolved = raw
688
+ ? (path.isAbsolute(raw) ? raw : path.resolve(__dirname, raw))
689
+ : configuredInferenceAdapterPath;
690
+ if (!resolved) return null;
691
+ if (!fs.existsSync(resolved)) {
692
+ const err = new Error(`Inference adapter script not found: ${resolved}`);
693
+ err.statusCode = 400;
694
+ throw err;
695
+ }
696
+ return resolved;
697
+ }
698
+
699
+ function initBoard(taskExecutorPathParam, chatHandlerPathParam, inferenceAdapterPathParam) {
635
700
  fs.mkdirSync(boardDir, { recursive: true });
636
701
 
637
702
  const taskExecutorPath = resolveTaskExecutorPath(taskExecutorPathParam);
703
+ const chatHandlerPath = resolveChatHandlerPath(chatHandlerPathParam);
704
+ const inferenceAdapterPath = resolveInferenceAdapterPath(inferenceAdapterPathParam);
638
705
  const taskExecutorCmd = `${shellQuote(process.execPath)} ${shellQuote(taskExecutorPath)}`;
706
+ const chatHandlerCmd = chatHandlerPath
707
+ ? `${shellQuote(process.execPath)} ${shellQuote(chatHandlerPath)}`
708
+ : null;
709
+ const inferenceAdapterCmd = inferenceAdapterPath
710
+ ? `${shellQuote(process.execPath)} ${shellQuote(inferenceAdapterPath)}`
711
+ : null;
712
+
713
+ const initArgs = ['init', boardDir, '--task-executor', taskExecutorCmd];
714
+ if (chatHandlerCmd) initArgs.push('--chat-handler', chatHandlerCmd);
715
+ if (inferenceAdapterCmd) initArgs.push('--inference-adapter', inferenceAdapterCmd);
716
+ initArgs.push('--runtime-out', runtimeOutDir);
639
717
 
640
718
  try {
641
- runCli(['init', boardDir, '--task-executor', taskExecutorCmd, '--runtime-out', runtimeOutDir]);
719
+ runCli(initArgs);
642
720
  } catch (err) {
643
721
  const msg = String((err && err.message) || err);
644
722
  if (!msg.includes('no valid board-graph.json')) throw err;
645
723
 
646
724
  clearDirContents(boardDir);
647
725
  fs.mkdirSync(boardDir, { recursive: true });
648
- runCli(['init', boardDir, '--task-executor', taskExecutorCmd, '--runtime-out', runtimeOutDir]);
726
+ runCli(initArgs);
649
727
  }
650
728
  }
651
729
 
652
- function initBoardAndSetup(taskExecutorPathParam) {
730
+ function initBoardAndSetup(taskExecutorPathParam, chatHandlerPathParam, inferenceAdapterPathParam) {
653
731
  ensureDemoSetup();
654
732
 
655
733
  if (!fs.existsSync(boardFile)) {
656
- initBoard(taskExecutorPathParam);
734
+ initBoard(taskExecutorPathParam, chatHandlerPathParam, inferenceAdapterPathParam);
657
735
  }
658
736
 
659
737
  const expectedCardsRoot = path.resolve(tmpCardsDir);
@@ -665,7 +743,7 @@ export function createExampleBoardServerRuntime(options = {}) {
665
743
 
666
744
  if (hasStaleMapping) {
667
745
  clearDirContents(boardDir);
668
- initBoard(taskExecutorPathParam);
746
+ initBoard(taskExecutorPathParam, chatHandlerPathParam, inferenceAdapterPathParam);
669
747
  }
670
748
  }
671
749
 
@@ -1095,7 +1173,8 @@ export function createExampleBoardServerRuntime(options = {}) {
1095
1173
  try {
1096
1174
  if (method === 'GET' && p === `${apiBasePath}/init-board`) {
1097
1175
  const taskExecutorPathParam = url.searchParams.get('taskExecutorPath') || '';
1098
- initBoardAndSetup(taskExecutorPathParam);
1176
+ const chatHandlerPathParam = url.searchParams.get('chatHandlerPath') || '';
1177
+ initBoardAndSetup(taskExecutorPathParam, chatHandlerPathParam);
1099
1178
  json(res, 200, buildPublishedRuntimePayload());
1100
1179
  return true;
1101
1180
  }
@@ -19,13 +19,14 @@
19
19
 
20
20
  const fetchServer = options.fetchServer;
21
21
  const boardPaths = options.boardPaths;
22
- const buildLiveCardModelsFromArtifacts = options.buildLiveCardModelsFromArtifacts;
22
+ const buildLiveCardModelsFromArtifacts = options.buildLiveCardModelsFromArtifacts
23
+ || (typeof window !== 'undefined' && window.BoardLiveGraph && window.BoardLiveGraph.buildLiveCardModelsFromArtifacts);
23
24
  const getServerOrigin = options.getServerOrigin;
24
25
 
25
26
  if (typeof fetchServer !== 'function') throw new Error('options.fetchServer is required');
26
27
  if (typeof boardPaths !== 'function') throw new Error('options.boardPaths is required');
27
28
  if (typeof buildLiveCardModelsFromArtifacts !== 'function') {
28
- throw new Error('options.buildLiveCardModelsFromArtifacts is required');
29
+ throw new Error('options.buildLiveCardModelsFromArtifacts is required (or load board-livegraph-engine.js first)');
29
30
  }
30
31
  if (typeof getServerOrigin !== 'function') throw new Error('options.getServerOrigin is required');
31
32
 
@@ -155,6 +156,9 @@
155
156
 
156
157
  const engine = LiveCard.init({
157
158
  resolve: (id) => nodesById[id],
159
+ markdown: (typeof marked !== 'undefined')
160
+ ? (text) => marked.parse(text)
161
+ : null,
158
162
  onPatchState: async (id, patch) => {
159
163
  await fetchServer(paths.patchCard(id), {
160
164
  method: 'PATCH',
@@ -140,13 +140,29 @@ var BoardLiveGraph = (function (exports) {
140
140
  if (!Array.isArray(n.sources)) {
141
141
  errors.push("sources: must be an array");
142
142
  } else {
143
+ const bindTos = /* @__PURE__ */ new Set();
144
+ const outputFiles = /* @__PURE__ */ new Set();
143
145
  n.sources.forEach((src, i) => {
144
146
  if (!src || typeof src !== "object" || Array.isArray(src)) {
145
147
  errors.push(`sources[${i}]: must be an object`);
146
148
  } else {
147
149
  const s = src;
148
- if (typeof s.bindTo !== "string" || !s.bindTo) errors.push(`sources[${i}]: missing required "bindTo" property`);
149
- if (s.outputFile != null && typeof s.outputFile !== "string") errors.push(`sources[${i}]: outputFile must be a string`);
150
+ if (typeof s.bindTo !== "string" || !s.bindTo) {
151
+ errors.push(`sources[${i}]: missing required "bindTo" property`);
152
+ } else {
153
+ if (bindTos.has(s.bindTo)) {
154
+ errors.push(`sources[${i}]: bindTo "${s.bindTo}" is not unique across sources`);
155
+ }
156
+ bindTos.add(s.bindTo);
157
+ }
158
+ if (typeof s.outputFile !== "string" || !s.outputFile) {
159
+ errors.push(`sources[${i}]: missing required "outputFile" property`);
160
+ } else {
161
+ if (outputFiles.has(s.outputFile)) {
162
+ errors.push(`sources[${i}]: outputFile "${s.outputFile}" is not unique across sources`);
163
+ }
164
+ outputFiles.add(s.outputFile);
165
+ }
150
166
  if (s.optionalForCompletionGating != null && typeof s.optionalForCompletionGating !== "boolean") {
151
167
  errors.push(`sources[${i}]: optionalForCompletionGating must be a boolean`);
152
168
  }
@@ -262,15 +278,30 @@ var BoardLiveGraph = (function (exports) {
262
278
  }
263
279
 
264
280
  // src/event-graph/task-transitions.ts
265
- function applyTaskStart(state, taskName) {
281
+ function applyTaskStart(state, taskName, graph) {
266
282
  const existingTask = state.tasks[taskName] ?? createDefaultGraphEngineStore();
283
+ const startConsumedHashes = {};
284
+ if (graph) {
285
+ const taskConfig = graph.tasks[taskName];
286
+ const requires = getRequires(taskConfig);
287
+ for (const token of requires) {
288
+ for (const [otherName, otherConfig] of Object.entries(graph.tasks)) {
289
+ if (getProvides(otherConfig).includes(token)) {
290
+ const otherState = state.tasks[otherName];
291
+ if (otherState?.lastDataHash) startConsumedHashes[token] = otherState.lastDataHash;
292
+ break;
293
+ }
294
+ }
295
+ }
296
+ }
267
297
  const updatedTask = {
268
298
  ...existingTask,
269
299
  status: "running",
270
300
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
271
301
  lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
272
302
  progress: 0,
273
- error: void 0
303
+ error: void 0,
304
+ startConsumedHashes
274
305
  };
275
306
  return {
276
307
  ...state,
@@ -290,16 +321,18 @@ var BoardLiveGraph = (function (exports) {
290
321
  } else {
291
322
  outputTokens = getProvides(taskConfig);
292
323
  }
293
- const lastConsumedHashes = { ...existingTask.lastConsumedHashes };
294
- const requires = taskConfig.requires ?? [];
295
- for (const token of requires) {
296
- for (const [otherName, otherConfig] of Object.entries(graph.tasks)) {
297
- if (getProvides(otherConfig).includes(token)) {
298
- const otherState = state.tasks[otherName];
299
- if (otherState?.lastDataHash) {
300
- lastConsumedHashes[token] = otherState.lastDataHash;
324
+ const lastConsumedHashes = existingTask.startConsumedHashes ? { ...existingTask.startConsumedHashes } : { ...existingTask.lastConsumedHashes };
325
+ if (!existingTask.startConsumedHashes) {
326
+ const requires = taskConfig.requires ?? [];
327
+ for (const token of requires) {
328
+ for (const [otherName, otherConfig] of Object.entries(graph.tasks)) {
329
+ if (getProvides(otherConfig).includes(token)) {
330
+ const otherState = state.tasks[otherName];
331
+ if (otherState?.lastDataHash) {
332
+ lastConsumedHashes[token] = otherState.lastDataHash;
333
+ }
334
+ break;
301
335
  }
302
- break;
303
336
  }
304
337
  }
305
338
  }
@@ -444,7 +477,7 @@ var BoardLiveGraph = (function (exports) {
444
477
  switch (event.type) {
445
478
  // --- Execution state transitions ---
446
479
  case "task-started":
447
- return { config, state: applyTaskStart(state, event.taskName) };
480
+ return { config, state: applyTaskStart(state, event.taskName, config) };
448
481
  case "task-completed":
449
482
  return { config, state: applyTaskCompletion(state, config, event.taskName, event.result, event.dataHash, event.data) };
450
483
  case "task-failed":
@@ -1442,12 +1475,175 @@ var BoardLiveGraph = (function (exports) {
1442
1475
  };
1443
1476
  return runtime;
1444
1477
  }
1478
+ function taskStatusToCardStatus(taskStatus) {
1479
+ if (taskStatus === "running" || taskStatus === "in-progress") return "loading";
1480
+ if (taskStatus === "failed") return "error";
1481
+ if (taskStatus === "completed") return "fresh";
1482
+ return "fresh";
1483
+ }
1484
+ function cardStatusToTaskStatus(cardStatus) {
1485
+ if (cardStatus === "loading") return "in-progress";
1486
+ if (cardStatus === "error") return "failed";
1487
+ if (cardStatus === "stale") return "pending";
1488
+ if (cardStatus === "fresh") return "completed";
1489
+ return "pending";
1490
+ }
1491
+ function normalizeCardRuntimeArtifact(cardId, artifact) {
1492
+ const safe = artifact && typeof artifact === "object" && !Array.isArray(artifact) ? artifact : {};
1493
+ return {
1494
+ schema_version: safe.schema_version || "v1",
1495
+ card_id: typeof safe.card_id === "string" ? safe.card_id : cardId,
1496
+ card_data: safe.card_data && typeof safe.card_data === "object" && !Array.isArray(safe.card_data) ? structuredClone(safe.card_data) : {},
1497
+ computed_values: safe.computed_values && typeof safe.computed_values === "object" && !Array.isArray(safe.computed_values) ? structuredClone(safe.computed_values) : {},
1498
+ fetched_sources: safe.fetched_sources && typeof safe.fetched_sources === "object" && !Array.isArray(safe.fetched_sources) ? structuredClone(safe.fetched_sources) : {},
1499
+ requires: safe.requires && typeof safe.requires === "object" && !Array.isArray(safe.requires) ? structuredClone(safe.requires) : {}
1500
+ };
1501
+ }
1502
+ function buildLiveCardModelsFromArtifacts(payload) {
1503
+ if (!payload || typeof payload !== "object") throw new Error("payload must be an object");
1504
+ const cardDefinitions = Array.isArray(payload.cardDefinitions) ? payload.cardDefinitions : [];
1505
+ const statusSnapshot = payload.statusSnapshot && typeof payload.statusSnapshot === "object" ? payload.statusSnapshot : {};
1506
+ const cardRuntimeById = payload.cardRuntimeById && typeof payload.cardRuntimeById === "object" ? payload.cardRuntimeById : {};
1507
+ const dataObjectsByToken = payload.dataObjectsByToken && typeof payload.dataObjectsByToken === "object" ? payload.dataObjectsByToken : {};
1508
+ const statusCards = Array.isArray(statusSnapshot.cards) ? statusSnapshot.cards : [];
1509
+ const statusById = new Map(statusCards.map((c) => [c.name, c]));
1510
+ return cardDefinitions.map((cardDefinition) => {
1511
+ const card = structuredClone(cardDefinition);
1512
+ const cardId = card.id;
1513
+ if (!cardId) throw new Error("cardDefinitions entry missing id");
1514
+ const statusCard = statusById.get(cardId);
1515
+ const runtimeArtifact = normalizeCardRuntimeArtifact(cardId, cardRuntimeById[cardId]);
1516
+ const baseCardData = card.card_data && typeof card.card_data === "object" && !Array.isArray(card.card_data) ? card.card_data : {};
1517
+ const card_data = {
1518
+ ...baseCardData,
1519
+ ...runtimeArtifact.card_data || {},
1520
+ status: taskStatusToCardStatus(statusCard?.status),
1521
+ lastRun: statusCard?.runtime?.last_transition_at ?? null
1522
+ };
1523
+ if (statusCard?.error?.message) card_data["error"] = statusCard.error.message;
1524
+ const runtime_state = statusCard ? {
1525
+ task_status: statusCard.status ?? null,
1526
+ card_status: taskStatusToCardStatus(statusCard.status),
1527
+ runtime: structuredClone(statusCard.runtime ?? {}),
1528
+ error: statusCard.error ? structuredClone(statusCard.error) : null,
1529
+ blocked_by: Array.isArray(statusCard.blocked_by) ? structuredClone(statusCard.blocked_by) : [],
1530
+ requires_missing: Array.isArray(statusCard.requires_missing) ? structuredClone(statusCard.requires_missing) : []
1531
+ } : {
1532
+ task_status: null,
1533
+ card_status: card_data["status"] ?? "fresh",
1534
+ runtime: { last_transition_at: card_data["lastRun"] ?? null },
1535
+ error: card_data["error"] ? { message: card_data["error"] } : null,
1536
+ blocked_by: [],
1537
+ requires_missing: []
1538
+ };
1539
+ const requiresTokens = Array.isArray(card.requires) ? card.requires : [];
1540
+ const requires = {};
1541
+ for (const token of requiresTokens) {
1542
+ if (Object.prototype.hasOwnProperty.call(dataObjectsByToken, token)) {
1543
+ requires[token] = structuredClone(dataObjectsByToken[token]);
1544
+ }
1545
+ }
1546
+ return {
1547
+ id: cardId,
1548
+ card,
1549
+ card_data,
1550
+ fetched_sources: runtimeArtifact.fetched_sources,
1551
+ requires,
1552
+ computed_values: runtimeArtifact.computed_values,
1553
+ runtime_state
1554
+ };
1555
+ });
1556
+ }
1557
+ function buildBrowserArtifactsFromRuntime({
1558
+ boardPath,
1559
+ cardDefinitions,
1560
+ runtimeModels,
1561
+ graphState
1562
+ }) {
1563
+ const safeCardDefs = Array.isArray(cardDefinitions) ? cardDefinitions : [];
1564
+ const safeModels = Array.isArray(runtimeModels) ? runtimeModels : [];
1565
+ const runtimeModelById = new Map(safeModels.map((m) => [m.id, m]));
1566
+ const graphStateAny = graphState;
1567
+ const taskStates = graphStateAny.state?.tasks ?? {};
1568
+ const cardRuntimeById = {};
1569
+ for (const model of safeModels) {
1570
+ if (!model?.id) continue;
1571
+ cardRuntimeById[model.id] = {
1572
+ schema_version: "v1",
1573
+ card_id: model.id,
1574
+ card_data: structuredClone(model.card_data ?? {}),
1575
+ computed_values: structuredClone(model.computed_values ?? {}),
1576
+ fetched_sources: structuredClone(model.fetched_sources ?? {}),
1577
+ requires: structuredClone(model.requires ?? {})
1578
+ };
1579
+ }
1580
+ const dataObjectsByToken = {};
1581
+ for (const taskName of Object.keys(taskStates)) {
1582
+ const providesData = taskStates[taskName]?.data?.provides_data;
1583
+ if (providesData && typeof providesData === "object") {
1584
+ for (const token of Object.keys(providesData)) {
1585
+ dataObjectsByToken[token] = structuredClone(providesData[token]);
1586
+ }
1587
+ }
1588
+ }
1589
+ const statusCards = safeCardDefs.map((cardDef) => {
1590
+ const model = runtimeModelById.get(cardDef.id) ?? {};
1591
+ const taskState = taskStates[cardDef.id];
1592
+ const taskStatus = typeof taskState?.status === "string" ? taskState.status : cardStatusToTaskStatus(model.card_data?.["status"]);
1593
+ const errorMessage = typeof taskState?.error === "string" ? taskState.error : typeof model.card_data?.["error"] === "string" ? model.card_data["error"] : null;
1594
+ return {
1595
+ name: cardDef.id,
1596
+ status: taskStatus,
1597
+ ...errorMessage ? { error: { message: errorMessage, code: "TASK_FAILED", at: taskState?.failedAt ?? null, source: "browser-runtime" } } : {},
1598
+ requires: Array.isArray(cardDef.requires) ? cardDef.requires : [],
1599
+ requires_satisfied: [],
1600
+ requires_missing: [],
1601
+ provides_declared: Array.isArray(cardDef.provides) ? cardDef.provides.map((e) => e.bindTo) : [cardDef.id],
1602
+ provides_runtime: Object.keys(taskState?.data?.provides_data ?? {}).sort(),
1603
+ blocked_by: [],
1604
+ unblocks: [],
1605
+ runtime: {
1606
+ attempt_count: taskState?.executionCount ?? 0,
1607
+ restart_count: taskState?.retryCount ?? 0,
1608
+ in_progress_since: taskStatus === "in-progress" ? taskState?.startedAt ?? null : null,
1609
+ last_transition_at: taskState?.lastUpdated ?? model.card_data?.["lastRun"] ?? null,
1610
+ last_completed_at: taskState?.completedAt ?? null,
1611
+ last_restarted_at: taskState?.startedAt ?? null,
1612
+ status_age_ms: null
1613
+ }
1614
+ };
1615
+ });
1616
+ return {
1617
+ cardDefinitions: structuredClone(safeCardDefs),
1618
+ cardRuntimeById,
1619
+ dataObjectsByToken,
1620
+ statusSnapshot: {
1621
+ schema_version: "v1",
1622
+ meta: { board: { path: boardPath ?? "browser-runtime" } },
1623
+ summary: {
1624
+ card_count: statusCards.length,
1625
+ completed: statusCards.filter((c) => c.status === "completed").length,
1626
+ eligible: 0,
1627
+ pending: statusCards.filter((c) => c.status === "pending").length,
1628
+ blocked: 0,
1629
+ unresolved: 0,
1630
+ failed: statusCards.filter((c) => c.status === "failed").length,
1631
+ in_progress: statusCards.filter((c) => c.status === "in-progress").length,
1632
+ orphan_cards: 0,
1633
+ topology: { edge_count: 0, max_fan_out_card: null, max_fan_out: 0 }
1634
+ },
1635
+ cards: statusCards
1636
+ }
1637
+ };
1638
+ }
1445
1639
 
1446
1640
  exports.LocalStorageService = LocalStorageService;
1641
+ exports.buildBrowserArtifactsFromRuntime = buildBrowserArtifactsFromRuntime;
1642
+ exports.buildLiveCardModelsFromArtifacts = buildLiveCardModelsFromArtifacts;
1447
1643
  exports.createBoardLiveGraphRuntime = createBoardLiveGraphRuntime;
1448
1644
 
1449
1645
  return exports;
1450
1646
 
1451
1647
  })({});
1452
- //# sourceMappingURL=board-livegraph-runtime.js.map
1453
- //# sourceMappingURL=board-livegraph-runtime.js.map
1648
+ //# sourceMappingURL=board-livegraph-engine.js.map
1649
+ //# sourceMappingURL=board-livegraph-engine.js.map