yaml-flow 6.0.0 → 7.1.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 (166) hide show
  1. package/board-live-cards-cli.js +4 -4
  2. package/browser/asset-integrity.json +3 -3
  3. package/browser/board-livecards-client.js +2 -0
  4. package/browser/board-livecards-client.js.map +1 -0
  5. package/browser/board-livecards-localstorage.js +10 -0
  6. package/browser/board-livecards-localstorage.js.map +1 -0
  7. package/browser/board-livegraph-engine.js +2 -2
  8. package/browser/board-livegraph-engine.js.map +1 -1
  9. package/browser/card-compute.js +28 -28
  10. package/browser/compute-jsonata.js +5 -0
  11. package/browser/compute-jsonata.js.map +1 -0
  12. package/browser/live-cards.js +264 -151
  13. package/card-store.js +4 -4
  14. package/dist/{board-live-cards-public-CltXYgaY.d.cts → board-live-cards-public-5n1-syA3.d.cts} +8 -5
  15. package/dist/{board-live-cards-public-f-E-FAyp.d.ts → board-live-cards-public-CK_J8uv0.d.ts} +8 -5
  16. package/dist/board-livegraph-runtime/index.cjs +2 -2
  17. package/dist/board-livegraph-runtime/index.cjs.map +1 -1
  18. package/dist/board-livegraph-runtime/index.d.cts +11 -9
  19. package/dist/board-livegraph-runtime/index.d.ts +11 -9
  20. package/dist/board-livegraph-runtime/index.js +2 -2
  21. package/dist/board-livegraph-runtime/index.js.map +1 -1
  22. package/dist/board-livegraph-runtime/jsonata-sync.cjs +37 -1
  23. package/dist/card-compute/index.cjs +4 -4
  24. package/dist/card-compute/index.cjs.map +1 -1
  25. package/dist/card-compute/index.d.cts +5 -1
  26. package/dist/card-compute/index.d.ts +5 -1
  27. package/dist/card-compute/index.js +4 -4
  28. package/dist/card-compute/index.js.map +1 -1
  29. package/dist/card-compute/jsonata-sync.cjs +37 -1
  30. package/dist/cli/browser-api/board-live-cards-browser-adapter.cjs +2 -1
  31. package/dist/cli/browser-api/board-live-cards-browser-adapter.cjs.map +1 -1
  32. package/dist/cli/browser-api/board-live-cards-browser-adapter.d.cts +27 -14
  33. package/dist/cli/browser-api/board-live-cards-browser-adapter.d.ts +27 -14
  34. package/dist/cli/browser-api/board-live-cards-browser-adapter.js +2 -1
  35. package/dist/cli/browser-api/board-live-cards-browser-adapter.js.map +1 -1
  36. package/dist/cli/browser-api/card-store-browser-api.cjs +1 -1
  37. package/dist/cli/browser-api/card-store-browser-api.cjs.map +1 -1
  38. package/dist/cli/browser-api/card-store-browser-api.js +1 -1
  39. package/dist/cli/browser-api/card-store-browser-api.js.map +1 -1
  40. package/dist/cli/browser-api/jsonata-sync.cjs +37 -1
  41. package/dist/cli/node/artifacts-store-cli.cjs +8 -8
  42. package/dist/cli/node/artifacts-store-cli.cjs.map +1 -1
  43. package/dist/cli/node/artifacts-store-cli.js +8 -8
  44. package/dist/cli/node/artifacts-store-cli.js.map +1 -1
  45. package/dist/cli/node/board-live-cards-cli.cjs +7 -7
  46. package/dist/cli/node/board-live-cards-cli.cjs.map +1 -1
  47. package/dist/cli/node/board-live-cards-cli.js +7 -7
  48. package/dist/cli/node/board-live-cards-cli.js.map +1 -1
  49. package/dist/cli/node/card-store-cli.cjs +5 -5
  50. package/dist/cli/node/card-store-cli.cjs.map +1 -1
  51. package/dist/cli/node/card-store-cli.js +5 -5
  52. package/dist/cli/node/card-store-cli.js.map +1 -1
  53. package/dist/cli/node/execution-adapter.cjs +3 -0
  54. package/dist/cli/node/execution-adapter.cjs.map +1 -0
  55. package/dist/cli/node/execution-adapter.d.cts +174 -0
  56. package/dist/cli/node/execution-adapter.d.ts +174 -0
  57. package/dist/cli/node/execution-adapter.js +3 -0
  58. package/dist/cli/node/execution-adapter.js.map +1 -0
  59. package/dist/cli/node/fs-board-adapter.cjs +7 -7
  60. package/dist/cli/node/fs-board-adapter.cjs.map +1 -1
  61. package/dist/cli/node/fs-board-adapter.d.cts +2 -2
  62. package/dist/cli/node/fs-board-adapter.d.ts +2 -2
  63. package/dist/cli/node/fs-board-adapter.js +7 -7
  64. package/dist/cli/node/fs-board-adapter.js.map +1 -1
  65. package/dist/cli/node/jsonata-sync.cjs +37 -1
  66. package/dist/cli/node/source-cli-task-executor.cjs +4 -4
  67. package/dist/cli/node/source-cli-task-executor.cjs.map +1 -1
  68. package/dist/cli/node/source-cli-task-executor.js +4 -4
  69. package/dist/cli/node/source-cli-task-executor.js.map +1 -1
  70. package/dist/continuous-event-graph/index.cjs +2 -2
  71. package/dist/continuous-event-graph/index.cjs.map +1 -1
  72. package/dist/continuous-event-graph/index.js +2 -2
  73. package/dist/continuous-event-graph/index.js.map +1 -1
  74. package/dist/continuous-event-graph/jsonata-sync.cjs +37 -1
  75. package/dist/execution-refs.cjs +2 -1
  76. package/dist/execution-refs.cjs.map +1 -1
  77. package/dist/execution-refs.d.cts +55 -12
  78. package/dist/execution-refs.d.ts +55 -12
  79. package/dist/execution-refs.js +2 -1
  80. package/dist/execution-refs.js.map +1 -1
  81. package/dist/index.cjs +10 -10
  82. package/dist/index.cjs.map +1 -1
  83. package/dist/index.js +10 -10
  84. package/dist/index.js.map +1 -1
  85. package/dist/jsonata-sync.cjs +37 -1
  86. package/dist/server-runtime/index.cjs +9 -0
  87. package/dist/server-runtime/index.cjs.map +1 -0
  88. package/dist/server-runtime/index.d.cts +31 -0
  89. package/dist/server-runtime/index.d.ts +31 -0
  90. package/dist/server-runtime/index.js +9 -0
  91. package/dist/server-runtime/index.js.map +1 -0
  92. package/dist/server-runtime/jsonata-sync.cjs +7623 -0
  93. package/dist/step-machine-public/index.cjs +3 -0
  94. package/dist/step-machine-public/index.cjs.map +1 -0
  95. package/dist/step-machine-public/index.d.cts +166 -0
  96. package/dist/step-machine-public/index.d.ts +166 -0
  97. package/dist/step-machine-public/index.js +3 -0
  98. package/dist/step-machine-public/index.js.map +1 -0
  99. package/dist/step-machine-public/jsonata-sync.cjs +7623 -0
  100. package/dist/storage-refs.cjs +2 -2
  101. package/dist/storage-refs.cjs.map +1 -1
  102. package/dist/storage-refs.d.cts +6 -6
  103. package/dist/storage-refs.d.ts +6 -6
  104. package/dist/storage-refs.js +2 -2
  105. package/dist/storage-refs.js.map +1 -1
  106. package/dist/types-CU3DjTKL.d.cts +147 -0
  107. package/dist/types-HGDTWIun.d.ts +147 -0
  108. package/examples/browser/boards/portfolio-tracker/portfolio-t4.js +9 -10
  109. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-http-test.js +370 -0
  110. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-http-test.py +398 -0
  111. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-public.js +9 -10
  112. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-server.js +300 -0
  113. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-server.py +617 -0
  114. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-sse-worker.js +48 -0
  115. package/examples/browser/boards/portfolio-tracker/portfolio-tracker.py +11 -10
  116. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/_board-cli.js +19 -4
  117. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/add-cards-cli.js +4 -8
  118. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/init-board-cli.js +6 -10
  119. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/poll-status-cli.js +8 -16
  120. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/reset-board-dir-cli.js +2 -6
  121. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/retrigger-cli.js +4 -8
  122. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/status-cli.js +3 -7
  123. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/update-holdings-cli.js +4 -8
  124. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/wait-completed-cli.js +7 -16
  125. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/write-prices-cli.js +2 -6
  126. package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/_board_pycli.py +13 -3
  127. package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/add-cards.py +2 -1
  128. package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/init-board.py +2 -1
  129. package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/poll-status.py +2 -1
  130. package/examples/cli/step-machine-cli/portfolio-tracker/portfolio-tracker.flow.yaml +20 -24
  131. package/examples/cli/step-machine-cli/portfolio-tracker/run-inline-python-demo-pycli.py +0 -3
  132. package/examples/cli/step-machine-demo/jsonata-init-board-cli.js +8 -13
  133. package/examples/cli/step-machine-demo/jsonata-init-board.flow.yaml +33 -9
  134. package/examples/cli/step-machine-demo/one-step-cli-only.flow.yaml +3 -1
  135. package/examples/cli/step-machine-demo/step2-double-cli.js +6 -12
  136. package/examples/cli/step-machine-demo/two-step-math.flow.yaml +66 -4
  137. package/examples/cli/step-machine-demo/two-step-mixed.flow.yaml +13 -5
  138. package/examples/example-board/agent-instructions.md +1 -1
  139. package/examples/example-board/cards/card-my-identity.json +30 -6
  140. package/examples/example-board/cards/card-portfolio-action.json +24 -6
  141. package/examples/example-board/cards/card-portfolio-intelligence.json +97 -0
  142. package/examples/example-board/cards/card-portfolio-risks.json +24 -6
  143. package/examples/example-board/cards/card-rebalance-impact.json +22 -6
  144. package/examples/example-board/cards/card-rebalance-sim.json +66 -15
  145. package/examples/example-board/cards/cardT-market-prices.json +80 -0
  146. package/examples/example-board/cards/{card-portfolio-value.json → cardT-portfolio-value.json} +38 -10
  147. package/examples/example-board/cards/cardT-portfolio.json +78 -0
  148. package/examples/example-board/demo-server-config.json +1 -1
  149. package/examples/example-board/demo-server.js +383 -69
  150. package/examples/example-board/demo-shell-localstorage.html +774 -0
  151. package/examples/example-board/demo-shell-with-server.html +18 -36
  152. package/examples/example-board/demo-shell.html +5 -4
  153. package/examples/example-board/demo-task-executor.js +213 -265
  154. package/package.json +15 -13
  155. package/step-machine-cli.js +43 -310
  156. package/board-livecards-server-runtime.js +0 -1513
  157. package/browser/board-livecards-runtime-client.js +0 -263
  158. package/dist/pycli/quickjs-board-runtime.global.js +0 -9
  159. package/dist/pycli/quickjs-board-runtime.global.js.map +0 -1
  160. package/dist/pycli/quickjs-step-machine-runtime.global.js +0 -5
  161. package/dist/pycli/quickjs-step-machine-runtime.global.js.map +0 -1
  162. package/examples/cli/step-machine-demo/two-step-math-handlers.js +0 -32
  163. package/examples/cli/step-machine-demo/two-step-mixed-handlers.js +0 -24
  164. package/examples/example-board/cards/card-market-prices.json +0 -56
  165. package/examples/example-board/cards/card-portfolio.json +0 -44
  166. package/examples/example-board/demo-shell-browser.html +0 -675
@@ -1,17 +1,19 @@
1
1
  // live-cards.js — LiveCards v3: Node-based Board/Canvas engine
2
2
  //
3
3
  // Schema: Each node has { id } required; all else optional.
4
- // id, meta, card_data, requires, provides, source_defs, compute, view
5
- // Nodes with view render as cards; nodes with source_defs but no view render as source pills in canvas.
6
- // compute[] ordered array of { bindTo, expr } JSONata steps writes to node.computed_values (ephemeral)
7
- // source_defs[] open objects: only bindTo + outputFile matter to the engine; all other fields are
8
- // passed verbatim to the board's task-executor (--in JSON). Users define their own
9
- // shape (kind, url, mailbox, channel, model, ...) per executor.
10
- // requires[] — upstream node IDs; engine subscribes automatically
4
+ // id, meta, card_data, requires, provides, view
5
+ // Nodes with view render as cards; nodes with no view but with source_defs declared on the
6
+ // underlying card definition render as source pills in canvas mode (source_defs are runtime-only;
7
+ // they are not interpreted here).
8
+ // requires[] upstream provider tokens; engine subscribes automatically
11
9
  // provides[] — [{ bindTo, src }] explicit downstream token bindings
10
+ // computed_values — derived values produced by the runtime; rendered as-is, never recomputed here
11
+ //
12
+ // Rendering contract: this module renders derived state only. View bind paths resolve to one of
13
+ // card_data | requires | computed_values | runtime_state. Raw fetched-source payloads stay in the
14
+ // runtime and never reach the Board.
12
15
  //
13
16
  // Uses Bootstrap 5 for layout/forms, optional Chart.js for charts.
14
- // Uses CardCompute (card-compute.js) for declarative compute expressions.
15
17
  //
16
18
  // API:
17
19
  // const engine = LiveCard.init({ resolve, onPatch, onPatchState, onRefresh, onAction, getChatMessages, markdown, sanitize, chartLib });
@@ -24,8 +26,15 @@
24
26
  // engine.appendChatMessage(nodeId, role, text)
25
27
  // engine.registerRenderer(name, fn)
26
28
  //
27
- // const board = LiveCard.Board(engine, el, { nodes, positions?, mode, canvas })
28
- // board.setMode('board'|'canvas'), board.autoLayout(), board.add(node), board.remove(id)
29
+ // Reactive board (preferred): state in, view out. No destructive re-renders.
30
+ // const board = LiveCard.Board(engine, el, { initialState, getNodeIds, selectNode, mode?, canvas? });
31
+ // board.setState(nextState) — diff vs prev; per-node updates only
32
+ // board.destroy()
33
+ //
34
+ // Imperative core (advanced): direct node-list manipulation.
35
+ // const core = LiveCard.BoardCore(engine, el, { nodes, positions?, mode, canvas });
36
+ // core.add(node), core.remove(id), core.reorder(ids), core.updateNode(id, model)
37
+ // core.setMode('board'|'canvas'), core.setDevMode(flag), core.autoLayout(), core.clear(), core.destroy()
29
38
 
30
39
  // eslint-disable-next-line no-unused-vars
31
40
  var LiveCard = (function () {
@@ -230,6 +239,30 @@ var LiveCard = (function () {
230
239
  const _formState = {}; // stateKey → { baseValues, journal }
231
240
  const _notesState = {}; // stateKey → { baseContent, journal|null }
232
241
  const _todoState = {}; // stateKey → { currentState, pending } for todo dirty tracking
242
+
243
+ /**
244
+ * Overlay a "Saving…" spinner over `el` while a patch is in-flight.
245
+ * The overlay is removed automatically on the next SSE re-render because
246
+ * every editable renderer does `el.innerHTML = …` on refresh.
247
+ */
248
+ function _showSavingOverlay(el) {
249
+ // Ensure the container is a positioned ancestor so the overlay can fill it.
250
+ if (getComputedStyle(el).position === 'static') el.style.position = 'relative';
251
+ const overlay = document.createElement('div');
252
+ overlay.className = 'lc-saving-overlay';
253
+ overlay.setAttribute('aria-live', 'polite');
254
+ overlay.style.cssText = [
255
+ 'position:absolute', 'inset:0',
256
+ 'background:rgba(255,255,255,0.78)',
257
+ 'display:flex', 'align-items:center', 'justify-content:center',
258
+ 'gap:0.5rem', 'z-index:20', 'border-radius:inherit',
259
+ 'pointer-events:all', // blocks all clicks on underlying inputs
260
+ ].join(';');
261
+ overlay.innerHTML =
262
+ '<span class="spinner-border spinner-border-sm text-primary" role="status" aria-hidden="true"></span>' +
263
+ '<span class="text-primary fw-medium small">Saving…</span>';
264
+ el.appendChild(overlay);
265
+ }
233
266
  const _renderers = {}; // kind → fn
234
267
  const _nodeEls = {}; // nodeId → { container, resultEl, uid }
235
268
  const _chatModal = {
@@ -275,11 +308,6 @@ var LiveCard = (function () {
275
308
  return _cleanup[id];
276
309
  }
277
310
 
278
- function _runCompute() {
279
- // Runtime payload is authoritative; UI never recomputes derived values.
280
- return Promise.resolve();
281
- }
282
-
283
311
  function _ensureChatModal() {
284
312
  if (_chatModal.backdrop) return;
285
313
 
@@ -767,11 +795,9 @@ var LiveCard = (function () {
767
795
  const ns = {
768
796
  card: node && node.card ? node.card : {},
769
797
  card_data: node && node.card_data ? node.card_data : {},
770
- fetched_sources: node && node.fetched_sources ? node.fetched_sources : {},
771
798
  requires: node && node.requires ? node.requires : {},
772
799
  computed_values: node && node.computed_values ? node.computed_values : {},
773
800
  runtime_state: node && node.runtime_state ? node.runtime_state : {},
774
- data_objects: node && node.data_objects ? node.data_objects : {},
775
801
  };
776
802
 
777
803
  if (!Object.prototype.hasOwnProperty.call(ns, root)) return undefined;
@@ -1181,6 +1207,7 @@ var LiveCard = (function () {
1181
1207
  const nextValues = getEffectiveValues();
1182
1208
  cfg.onPatchState(node.id, { fieldValues: nextValues });
1183
1209
  btn.textContent = 'Saving...';
1210
+ _showSavingOverlay(el);
1184
1211
  }, { signal });
1185
1212
 
1186
1213
  discardBtn.addEventListener('click', () => {
@@ -1257,8 +1284,11 @@ var LiveCard = (function () {
1257
1284
 
1258
1285
  saveBtn.addEventListener('click', () => {
1259
1286
  const nextValue = textarea.value;
1260
- cfg.onPatchState(node.id, { notes: nextValue });
1287
+ // Wrap in a named key so spread into card_data gives card_data.notes = "..."
1288
+ // (same dict pattern as form/filter; writeTo is not required).
1289
+ cfg.onPatchState(node.id, { fieldValues: { notes: nextValue } });
1261
1290
  saveBtn.textContent = 'Saving...';
1291
+ _showSavingOverlay(el);
1262
1292
  }, { signal });
1263
1293
 
1264
1294
  discardBtn.addEventListener('click', () => {
@@ -1343,6 +1373,7 @@ var LiveCard = (function () {
1343
1373
  cfg.onPatchState(node.id, { fieldValues: rows });
1344
1374
  const saveBtn = el.querySelector('.lc-et-save');
1345
1375
  if (saveBtn) saveBtn.textContent = 'Saving...';
1376
+ _showSavingOverlay(el);
1346
1377
  }
1347
1378
 
1348
1379
  function commitDiscard() {
@@ -1961,11 +1992,11 @@ var LiveCard = (function () {
1961
1992
  //
1962
1993
  // Usage:
1963
1994
  // { "kind": "ref",
1964
- // "data": { "bind": "fetched_sources.rebalance.proposed_trades",
1995
+ // "data": { "bind": "computed_values.proposed_trades",
1965
1996
  // "viewBind": "card_data.display_mode",
1966
1997
  // "fallbackKind": "table" } }
1967
1998
  //
1968
- // viewBind can point to any namespace: card_data, fetched_sources, requires, computed_values.
1999
+ // viewBind can point to any namespace: card_data, requires, computed_values, runtime_state.
1969
2000
  // If the resolved view object contains a "bind" sub-path, that overrides data.bind.
1970
2001
  const _REF_KIND_WHITELIST = new Set([
1971
2002
  'table','editable-table','chart','metric','list','badge',
@@ -2180,7 +2211,7 @@ var LiveCard = (function () {
2180
2211
  if (node.card_data && node.card_data.status === 'error' && node.card_data.error) {
2181
2212
  resultEl.innerHTML = `<div class="text-danger small fw-semibold">Refresh failed</div><pre class="text-muted small mt-1" style="white-space:pre-wrap">${_esc(node.card_data.error)}</pre>`;
2182
2213
  } else {
2183
- _runCompute(node).then(function () { _renderElements(node, resultEl); });
2214
+ _renderElements(node, resultEl);
2184
2215
  }
2185
2216
 
2186
2217
  // ---- Wire refresh ----
@@ -2275,7 +2306,7 @@ var LiveCard = (function () {
2275
2306
  if (node.card_data.status === 'error' && node.card_data.error) {
2276
2307
  info.resultEl.innerHTML = `<div class="text-danger small fw-semibold">Refresh failed</div><pre class="text-muted small mt-1" style="white-space:pre-wrap">${_esc(node.card_data.error)}</pre>`;
2277
2308
  } else {
2278
- _runCompute(node).then(function () { _renderElements(node, info.resultEl); });
2309
+ _renderElements(node, info.resultEl);
2279
2310
  }
2280
2311
  }
2281
2312
 
@@ -2354,10 +2385,11 @@ var LiveCard = (function () {
2354
2385
  }
2355
2386
 
2356
2387
  // ===========================================================================
2357
- // Board — grid (board) and DAG (canvas) modes
2388
+ // BoardCoreimperative grid (board) and DAG (canvas) modes.
2389
+ // Most callers should use Board (reactive wrapper) instead.
2358
2390
  // ===========================================================================
2359
2391
 
2360
- function Board(engine, containerEl, opts) {
2392
+ function BoardCore(engine, containerEl, opts) {
2361
2393
  opts = opts || {};
2362
2394
  const mode = { current: opts.mode || 'board' };
2363
2395
  const devMode = { current: opts.devMode || false };
@@ -2409,20 +2441,18 @@ var LiveCard = (function () {
2409
2441
 
2410
2442
  const canvasEl = document.createElement('div');
2411
2443
  canvasEl.className = 'lc-canvas';
2412
- const canvasHeight = co.height || '600px';
2413
- const canvasOverflow = co.overflow || 'auto';
2414
- canvasEl.style.cssText = 'position:relative;overflow:' + canvasOverflow + ';width:100%;height:' + canvasHeight + ';';
2444
+ canvasEl.style.cssText = 'position:relative;overflow:auto;width:100%;';
2415
2445
  const canvasInner = document.createElement('div');
2416
2446
  canvasInner.className = 'lc-canvas-inner';
2417
- canvasInner.style.cssText = 'position:absolute;top:0;left:0;transform-origin:0 0;';
2447
+ canvasInner.style.cssText = 'position:relative;transform-origin:0 0;min-width:100%;min-height:100%;';
2418
2448
  canvasEl.appendChild(canvasInner);
2419
2449
 
2420
2450
  // SVG overlay for edges
2421
2451
  const svgEl = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
2422
2452
  svgEl.setAttribute('class', 'lc-canvas-edges');
2423
- svgEl.style.cssText = 'position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;overflow:visible;';
2453
+ svgEl.style.cssText = 'position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;overflow:hidden;z-index:0;';
2424
2454
  const defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
2425
- defs.innerHTML = '<marker id="lc-arrow" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse"><path d="M 0 0 L 10 5 L 0 10 z" fill="var(--bs-secondary,#6c757d)"/></marker>';
2455
+ defs.innerHTML = '<marker id="lc-arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M 0 1 L 8 5 L 0 9 z" fill="rgba(108,117,125,0.55)"/></marker>';
2426
2456
  svgEl.appendChild(defs);
2427
2457
  canvasInner.appendChild(svgEl);
2428
2458
 
@@ -2433,13 +2463,13 @@ var LiveCard = (function () {
2433
2463
  s.textContent = `
2434
2464
  .lc-canvas-card { position:absolute; min-width:${cvs.minWidth}px; cursor:grab; user-select:none; z-index:1; }
2435
2465
  .lc-canvas-card.lc-dragging { cursor:grabbing; z-index:10; box-shadow:0 8px 24px rgba(0,0,0,0.18)!important; }
2436
- .lc-canvas-card .card-body { overflow:auto; }
2466
+ .lc-canvas-card .card-body { overflow:hidden; }
2437
2467
  .lc-canvas-card.lc-resizing { cursor:nwse-resize; z-index:10; }
2438
2468
  .lc-resize-handle { position:absolute; bottom:0; right:0; width:14px; height:14px; cursor:nwse-resize; z-index:2; opacity:0.4; transition:opacity .15s; }
2439
2469
  .lc-resize-handle:hover { opacity:1; }
2440
2470
  .lc-resize-handle::after { content:''; position:absolute; bottom:3px; right:3px; width:8px; height:8px; border-right:2px solid var(--bs-secondary,#6c757d); border-bottom:2px solid var(--bs-secondary,#6c757d); }
2441
- .lc-canvas-edges path.lc-edge-path { stroke:var(--bs-secondary,#6c757d); stroke-width:1.5; stroke-dasharray:6 4; animation:lc-edge-flow 0.6s linear infinite; }
2442
- .lc-canvas-edges line { stroke:var(--bs-secondary,#6c757d); stroke-width:1.5; }
2471
+ .lc-canvas-edges path.lc-edge-path { stroke:rgba(100,140,200,0.5); stroke-width:2; fill:none; stroke-linecap:round; }
2472
+ .lc-canvas-edges line { stroke:rgba(100,140,200,0.4); stroke-width:2; }
2443
2473
  @keyframes lc-edge-flow { to { stroke-dashoffset:-10; } }
2444
2474
  .lc-source-node { position:absolute; cursor:grab; user-select:none; z-index:1; }
2445
2475
  .lc-source-node.lc-dragging { cursor:grabbing; z-index:10; }
@@ -2545,32 +2575,9 @@ var LiveCard = (function () {
2545
2575
 
2546
2576
  const cardSection = document.createElement('div');
2547
2577
  cardSection.className = 'mb-4';
2548
- cardSection.innerHTML = '<h6 class="fw-semibold mb-2">Card Object (Editable)</h6>';
2549
-
2550
- const editableCardObject = JSON.parse(JSON.stringify((node && node.card) ? node.card : {}));
2551
-
2552
- const editor = document.createElement('textarea');
2553
- editor.className = 'form-control form-control-sm font-monospace';
2554
- editor.rows = 16;
2555
- editor.style.whiteSpace = 'pre';
2556
- editor.value = JSON.stringify(editableCardObject, null, 2);
2557
-
2558
- const editorHint = document.createElement('div');
2559
- editorHint.className = 'small text-muted mt-2';
2560
- editorHint.textContent = 'Edit JSON and click Submit to apply updates to this card.';
2561
-
2562
- const editorError = document.createElement('div');
2563
- editorError.className = 'small text-danger mt-1 d-none';
2564
-
2565
- const submitBtn = document.createElement('button');
2566
- submitBtn.type = 'button';
2567
- submitBtn.className = 'btn btn-primary btn-sm mb-2';
2568
- submitBtn.textContent = 'Submit';
2569
-
2570
- cardSection.appendChild(submitBtn);
2571
- cardSection.appendChild(editor);
2572
- cardSection.appendChild(editorHint);
2573
- cardSection.appendChild(editorError);
2578
+ cardSection.innerHTML = '<h6 class="fw-semibold mb-2">Card Definition (Read-only)</h6>';
2579
+ const cardDef = (node && node.card) ? node.card : {};
2580
+ cardSection.innerHTML += `<pre style="background: #f5f5f5; padding: 10px; border-radius: 4px; overflow-x: auto; font-size: 12px; white-space: pre-wrap; word-wrap: break-word;">${_esc(JSON.stringify(cardDef, null, 2))}</pre>`;
2574
2581
  body.appendChild(cardSection);
2575
2582
 
2576
2583
  const computedSection = document.createElement('div');
@@ -2580,13 +2587,6 @@ var LiveCard = (function () {
2580
2587
  computedSection.innerHTML += `<pre style="background: #f5f5f5; padding: 10px; border-radius: 4px; overflow-x: auto; font-size: 12px; white-space: pre-wrap; word-wrap: break-word;">${_esc(JSON.stringify(computedValues, null, 2))}</pre>`;
2581
2588
  body.appendChild(computedSection);
2582
2589
 
2583
- const sourcesSection = document.createElement('div');
2584
- sourcesSection.className = 'mb-4';
2585
- sourcesSection.innerHTML = '<h6 class="fw-semibold mb-2">Fetched Sources (Read-only)</h6>';
2586
- const sourcesData = node.fetched_sources || {};
2587
- sourcesSection.innerHTML += `<pre style="background: #f5f5f5; padding: 10px; border-radius: 4px; overflow-x: auto; font-size: 12px; white-space: pre-wrap; word-wrap: break-word;">${_esc(JSON.stringify(sourcesData, null, 2))}</pre>`;
2588
- body.appendChild(sourcesSection);
2589
-
2590
2590
  const requiresSection = document.createElement('div');
2591
2591
  requiresSection.className = 'mb-4';
2592
2592
  requiresSection.innerHTML = '<h6 class="fw-semibold mb-2">Requires (Read-only)</h6>';
@@ -2609,43 +2609,6 @@ var LiveCard = (function () {
2609
2609
  closeBtn.textContent = 'Close';
2610
2610
  closeBtn.addEventListener('click', closeModal);
2611
2611
 
2612
- submitBtn.addEventListener('click', function () {
2613
- editorError.classList.add('d-none');
2614
- editorError.textContent = '';
2615
- try {
2616
- const parsed = JSON.parse(editor.value);
2617
- if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
2618
- throw new Error('Card Object must be a JSON object.');
2619
- }
2620
- if (parsed.id && parsed.id !== node.id) {
2621
- throw new Error('Changing card id is not supported in the inspector.');
2622
- }
2623
-
2624
- const fixedId = node.id;
2625
- const preservedRuntime = {
2626
- card_data: node.card_data,
2627
- fetched_sources: node.fetched_sources,
2628
- requires: node.requires,
2629
- computed_values: node.computed_values,
2630
- runtime_state: node.runtime_state,
2631
- data_objects: node.data_objects,
2632
- };
2633
- node.card = parsed;
2634
- node.id = fixedId;
2635
- Object.assign(node, preservedRuntime);
2636
-
2637
- engine.notify(node.id, { inspector: 'card-object-updated' });
2638
- _render();
2639
-
2640
- submitBtn.textContent = '✓ Saved';
2641
- setTimeout(function () { submitBtn.textContent = 'Submit'; }, 1200);
2642
- closeModal();
2643
- } catch (err) {
2644
- editorError.textContent = 'Invalid JSON: ' + String((err && err.message) || err);
2645
- editorError.classList.remove('d-none');
2646
- }
2647
- });
2648
-
2649
2612
  footer.appendChild(closeBtn);
2650
2613
  content.appendChild(header);
2651
2614
  content.appendChild(body);
@@ -2796,8 +2759,23 @@ var LiveCard = (function () {
2796
2759
 
2797
2760
  // ---- Board mode ----
2798
2761
 
2762
+ // Compute canvas inner size from card positions + padding
2763
+ function _fitCanvasToContent() {
2764
+ var pad = 100;
2765
+ var maxR = 0, maxB = 0;
2766
+ canvasInner.querySelectorAll('.lc-canvas-card,.lc-source-node').forEach(function(el) {
2767
+ var r = el.offsetLeft + el.offsetWidth;
2768
+ var b = el.offsetTop + el.offsetHeight;
2769
+ if (r > maxR) maxR = r;
2770
+ if (b > maxB) maxB = b;
2771
+ });
2772
+ canvasInner.style.width = (maxR + pad) + 'px';
2773
+ canvasInner.style.height = (maxB + pad) + 'px';
2774
+ }
2775
+
2799
2776
  function _renderBoard() {
2800
2777
  _destroyEdges();
2778
+ document.body.style.overflow = '';
2801
2779
  root.innerHTML = '';
2802
2780
  root.appendChild(gridEl);
2803
2781
  gridEl.innerHTML = '';
@@ -2836,13 +2814,13 @@ var LiveCard = (function () {
2836
2814
  */
2837
2815
  function _updateTokenAvailability() {
2838
2816
  var tokenMap = _buildTokenMap();
2839
- // Determine which nodes "have data" (non-empty card_data or fetched_sources, or status=fresh/completed)
2817
+ // A node "has data" when card_data or computed_values is non-empty, or status is fresh/completed.
2840
2818
  var nodeHasData = {};
2841
2819
  nodeList.forEach(function(node) {
2842
2820
  var cd = node.card_data || (node.card && node.card.card_data);
2843
- var fs = node.fetched_sources;
2821
+ var cv = node.computed_values;
2844
2822
  var status = cd && cd.status;
2845
- var hasOutput = (cd && Object.keys(cd).length > 0) || (fs && Object.keys(fs).length > 0);
2823
+ var hasOutput = (cd && Object.keys(cd).length > 0) || (cv && Object.keys(cv).length > 0);
2846
2824
  nodeHasData[node.id] = hasOutput || status === 'fresh' || status === 'completed';
2847
2825
  });
2848
2826
 
@@ -2881,41 +2859,7 @@ var LiveCard = (function () {
2881
2859
  // Build token → provider nodeId map
2882
2860
  var tokenMap = _buildTokenMap();
2883
2861
 
2884
- // For each consumer node, for each required token, draw edge from
2885
- // the provider's "provides" badge → the consumer's "requires" badge.
2886
- if (typeof LeaderLine !== 'undefined') {
2887
- nodeList.forEach(function(node) {
2888
- var tgtInfo = nodeMap[node.id];
2889
- if (!tgtInfo || !tgtInfo.colEl) return;
2890
- _getRequires(node).forEach(function(token) {
2891
- var srcId = tokenMap[token];
2892
- if (!srcId) return;
2893
- var srcInfo = nodeMap[srcId];
2894
- if (!srcInfo || !srcInfo.colEl) return;
2895
- // Find the specific gem elements for this token
2896
- var srcGem = srcInfo.colEl.querySelector('.lc-token-gem-provides[data-token="' + token + '"]');
2897
- var tgtGem = tgtInfo.colEl.querySelector('.lc-token-gem-requires[data-token="' + token + '"]');
2898
- var startEl = srcGem || srcInfo.colEl;
2899
- var endEl = tgtGem || tgtInfo.colEl;
2900
- try {
2901
- var lineOpts = {
2902
- color: edgeCfg.color,
2903
- size: edgeCfg.size,
2904
- endPlug: edgeCfg.endPlug,
2905
- startSocket: srcGem ? 'bottom' : 'right',
2906
- endSocket: tgtGem ? 'top' : 'left',
2907
- };
2908
- if (edgeCfg.dash) {
2909
- lineOpts.dash = edgeCfg.animation ? { animation: true } : true;
2910
- }
2911
- _edges.push(new LeaderLine(startEl, endEl, lineOpts));
2912
- } catch(e) { /* skip edge on error */ }
2913
- });
2914
- });
2915
- return;
2916
- }
2917
-
2918
- // SVG fallback — connect badge-to-badge with curved paths
2862
+ // SVG edges rendered behind cards (z-index:0) for a clean look
2919
2863
  nodeList.forEach(function(node) {
2920
2864
  var tgtInfo = nodeMap[node.id];
2921
2865
  if (!tgtInfo || !tgtInfo.colEl) return;
@@ -2947,8 +2891,26 @@ var LiveCard = (function () {
2947
2891
  tx = tEl.offsetLeft + tEl.offsetWidth / 2;
2948
2892
  ty = tEl.offsetTop;
2949
2893
  }
2950
- var cpOffset = Math.min(Math.abs(ty - sy) * 0.5, 80);
2951
- var d = 'M ' + sx + ' ' + sy + ' C ' + sx + ' ' + (sy + cpOffset) + ', ' + tx + ' ' + (ty - cpOffset) + ', ' + tx + ' ' + ty;
2894
+ // Route bezier curves around cards offset control points outward
2895
+ var dx = tx - sx;
2896
+ var dy = ty - sy;
2897
+ var dist = Math.sqrt(dx * dx + dy * dy);
2898
+ var cpLen = Math.max(40, Math.min(dist * 0.4, 120));
2899
+ // Determine if src is roughly above, below, left, or right of target
2900
+ var absDx = Math.abs(dx);
2901
+ var absDy = Math.abs(dy);
2902
+ var cp1x, cp1y, cp2x, cp2y;
2903
+ if (absDy > absDx * 0.4) {
2904
+ // Mostly vertical — curve control points go straight down/up
2905
+ cp1x = sx; cp1y = sy + cpLen;
2906
+ cp2x = tx; cp2y = ty - cpLen;
2907
+ } else {
2908
+ // Mostly horizontal — swing control points outward to avoid overlapping cards
2909
+ var sideSign = dx > 0 ? 1 : -1;
2910
+ cp1x = sx + sideSign * cpLen; cp1y = sy + cpLen * 0.5;
2911
+ cp2x = tx - sideSign * cpLen; cp2y = ty - cpLen * 0.5;
2912
+ }
2913
+ var d = 'M ' + sx + ' ' + sy + ' C ' + cp1x + ' ' + cp1y + ', ' + cp2x + ' ' + cp2y + ', ' + tx + ' ' + ty;
2952
2914
  var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
2953
2915
  path.setAttribute('d', d);
2954
2916
  path.setAttribute('fill', 'none');
@@ -2999,6 +2961,7 @@ var LiveCard = (function () {
2999
2961
  node.card.view.layout.canvas.y = y;
3000
2962
  }
3001
2963
  engine.notify(node.id);
2964
+ _fitCanvasToContent();
3002
2965
  if (_edges.length) _repositionEdges();
3003
2966
  else _drawEdges();
3004
2967
  }, { signal });
@@ -3057,6 +3020,7 @@ var LiveCard = (function () {
3057
3020
  node.card.view.layout.canvas.h = sh;
3058
3021
  }
3059
3022
  engine.notify(node.id);
3023
+ _fitCanvasToContent();
3060
3024
  if (_edges.length) _repositionEdges();
3061
3025
  else _drawEdges();
3062
3026
  }, { signal });
@@ -3064,8 +3028,12 @@ var LiveCard = (function () {
3064
3028
 
3065
3029
  function _renderCanvas() {
3066
3030
  _destroyEdges();
3031
+ document.body.style.overflow = 'hidden';
3067
3032
  root.innerHTML = '';
3068
3033
  root.appendChild(canvasEl);
3034
+ // Fill remaining viewport height
3035
+ var top = canvasEl.getBoundingClientRect().top;
3036
+ canvasEl.style.height = co.height || ('calc(100vh - ' + top + 'px)');
3069
3037
  canvasInner.querySelectorAll('.lc-canvas-card,.lc-source-node').forEach(el => el.remove());
3070
3038
  svgEl.querySelectorAll('line,path').forEach(function(el) { el.remove(); });
3071
3039
  _initPositions();
@@ -3109,12 +3077,11 @@ var LiveCard = (function () {
3109
3077
 
3110
3078
  _updateTokenAvailability();
3111
3079
 
3112
- // Draw edges use rAF for LeaderLine so elements are laid out first
3113
- if (typeof LeaderLine !== 'undefined') {
3114
- requestAnimationFrame(function() { _drawEdges(); });
3115
- } else {
3080
+ // Fit canvas to content then draw edges
3081
+ requestAnimationFrame(function() {
3082
+ _fitCanvasToContent();
3116
3083
  _drawEdges();
3117
- }
3084
+ });
3118
3085
 
3119
3086
  // Reposition LeaderLine edges on scroll
3120
3087
  canvasEl.addEventListener('scroll', function() { _repositionEdges(); }, { signal, passive: true });
@@ -3226,7 +3193,41 @@ var LiveCard = (function () {
3226
3193
  _render();
3227
3194
  }
3228
3195
 
3229
- function refresh() { _render(); }
3196
+ /**
3197
+ * Per-node update: replace runtime fields on the existing node object in place
3198
+ * and re-render only that node's body. Outer wrapper is rebuilt to pick up
3199
+ * status/badges, but the surrounding column element is reused so layout is stable.
3200
+ * Editable element state is preserved via journal overlays keyed by nodeId:bindPath.
3201
+ */
3202
+ function updateNode(id, model) {
3203
+ const entry = nodeMap[id];
3204
+ if (!entry) throw new Error('updateNode: unknown node id ' + id);
3205
+ const node = entry.node;
3206
+ if (model && typeof model === 'object') {
3207
+ if (model.card !== undefined) node.card = model.card;
3208
+ if (model.card_data !== undefined) node.card_data = model.card_data;
3209
+ if (model.requires !== undefined) node.requires = model.requires;
3210
+ if (model.computed_values !== undefined) node.computed_values = model.computed_values;
3211
+ if (model.runtime_state !== undefined) node.runtime_state = model.runtime_state;
3212
+ }
3213
+ engine.destroy(id);
3214
+ if (mode.current === 'board') {
3215
+ const colEl = entry.colEl;
3216
+ colEl.innerHTML = '';
3217
+ const built = _buildCardWrapper(node);
3218
+ colEl.appendChild(built.wrap);
3219
+ nodeMap[id] = { node, colEl, bodyEl: built.body };
3220
+ engine.render(node, built.body, { showChat });
3221
+ } else {
3222
+ const el = entry.colEl;
3223
+ el.innerHTML = '';
3224
+ const built = _buildCardWrapper(node);
3225
+ while (built.wrap.firstChild) el.appendChild(built.wrap.firstChild);
3226
+ nodeMap[id] = { node, colEl: el, bodyEl: built.body };
3227
+ engine.render(node, built.body, { showChat: false });
3228
+ }
3229
+ _updateTokenAvailability();
3230
+ }
3230
3231
 
3231
3232
  function clear() {
3232
3233
  _destroyEdges();
@@ -3250,6 +3251,7 @@ var LiveCard = (function () {
3250
3251
 
3251
3252
  function destroy() {
3252
3253
  _destroyEdges();
3254
+ document.body.style.overflow = '';
3253
3255
  ac.abort();
3254
3256
  engine.destroyAll();
3255
3257
  nodeList.length = 0;
@@ -3268,7 +3270,7 @@ var LiveCard = (function () {
3268
3270
  add,
3269
3271
  remove,
3270
3272
  reorder,
3271
- refresh,
3273
+ updateNode,
3272
3274
  clear,
3273
3275
  setMode,
3274
3276
  setDevMode,
@@ -3281,9 +3283,120 @@ var LiveCard = (function () {
3281
3283
  };
3282
3284
  }
3283
3285
 
3286
+ // ===========================================================================
3287
+ // Board — reactive host. State in, view out. No destructive re-renders.
3288
+ // ===========================================================================
3289
+
3290
+ function Board(engine, containerEl, opts) {
3291
+ opts = opts || {};
3292
+ const initialState = opts.initialState;
3293
+ const getNodeIds = opts.getNodeIds;
3294
+ const selectNode = opts.selectNode;
3295
+ if (typeof getNodeIds !== 'function' || typeof selectNode !== 'function') {
3296
+ throw new Error('LiveCard.Board requires getNodeIds and selectNode functions');
3297
+ }
3298
+
3299
+ let state = initialState;
3300
+ const prevModelsById = {};
3301
+ const prevFingerprintsById = {};
3302
+
3303
+ function _stableStringify(v) {
3304
+ if (v == null || typeof v !== 'object') return JSON.stringify(v);
3305
+ if (Array.isArray(v)) return '[' + v.map(_stableStringify).join(',') + ']';
3306
+ const keys = Object.keys(v).sort();
3307
+ return '{' + keys.map(k => JSON.stringify(k) + ':' + _stableStringify(v[k])).join(',') + '}';
3308
+ }
3309
+
3310
+ function _modelFingerprint(model) {
3311
+ if (!model || typeof model !== 'object') return 'null';
3312
+ return _stableStringify({
3313
+ card: model.card,
3314
+ card_data: model.card_data,
3315
+ requires: model.requires,
3316
+ computed_values: model.computed_values,
3317
+ runtime_state: model.runtime_state,
3318
+ });
3319
+ }
3320
+
3321
+ const initialIds = getNodeIds(state);
3322
+ const initialNodes = initialIds.map(id => {
3323
+ const m = selectNode(state, id);
3324
+ prevModelsById[id] = m;
3325
+ prevFingerprintsById[id] = _modelFingerprint(m);
3326
+ return m;
3327
+ });
3328
+
3329
+ const coreOpts = {};
3330
+ Object.keys(opts).forEach(k => {
3331
+ if (k === 'initialState' || k === 'getNodeIds' || k === 'selectNode' || k === 'nodes') return;
3332
+ coreOpts[k] = opts[k];
3333
+ });
3334
+ coreOpts.nodes = initialNodes;
3335
+
3336
+ const core = BoardCore(engine, containerEl, coreOpts);
3337
+
3338
+ function _changed(prevFingerprint, nextFingerprint) {
3339
+ return prevFingerprint !== nextFingerprint;
3340
+ }
3341
+
3342
+ function setState(nextStateOrUpdater) {
3343
+ const nextState = (typeof nextStateOrUpdater === 'function')
3344
+ ? nextStateOrUpdater(state)
3345
+ : nextStateOrUpdater;
3346
+ if (nextState === undefined) return;
3347
+
3348
+ state = nextState;
3349
+ const nextIds = getNodeIds(state);
3350
+ const nextSet = new Set(nextIds);
3351
+
3352
+ // Removals
3353
+ Object.keys(prevModelsById).forEach(id => {
3354
+ if (!nextSet.has(id)) {
3355
+ core.remove(id);
3356
+ delete prevModelsById[id];
3357
+ delete prevFingerprintsById[id];
3358
+ }
3359
+ });
3360
+
3361
+ // Additions and per-node updates
3362
+ nextIds.forEach(id => {
3363
+ const next = selectNode(state, id);
3364
+ const prev = prevModelsById[id];
3365
+ const nextFingerprint = _modelFingerprint(next);
3366
+ const prevFingerprint = prevFingerprintsById[id];
3367
+ if (!prev) {
3368
+ core.add(next);
3369
+ } else if (_changed(prevFingerprint, nextFingerprint)) {
3370
+ core.updateNode(id, next);
3371
+ }
3372
+ prevModelsById[id] = next;
3373
+ prevFingerprintsById[id] = nextFingerprint;
3374
+ });
3375
+
3376
+ // Reorder if id sequence differs
3377
+ const currentOrder = core.nodes.map(n => n.id);
3378
+ const orderDiffers = nextIds.length !== currentOrder.length
3379
+ || nextIds.some((id, i) => id !== currentOrder[i]);
3380
+ if (orderDiffers) core.reorder(nextIds);
3381
+ }
3382
+
3383
+ function destroy() {
3384
+ Object.keys(prevModelsById).forEach(k => delete prevModelsById[k]);
3385
+ Object.keys(prevFingerprintsById).forEach(k => delete prevFingerprintsById[k]);
3386
+ core.destroy();
3387
+ }
3388
+
3389
+ return {
3390
+ setState,
3391
+ destroy,
3392
+ core,
3393
+ get state() { return state; },
3394
+ };
3395
+ }
3396
+
3284
3397
  // ===========================================================================
3285
3398
  // Module export
3286
3399
  // ===========================================================================
3287
3400
 
3288
- return { init, Board };
3401
+ return { init, Board, BoardCore };
3289
3402
  })();
package/card-store.js CHANGED
@@ -10,10 +10,7 @@ const distCli = path.join(__dirname, 'dist', 'cli', 'node', 'card-store-cli.js')
10
10
  const srcCli = path.join(__dirname, 'src', 'cli', 'node', 'card-store-cli.ts');
11
11
  const tsxCli = path.join(__dirname, 'node_modules', 'tsx', 'dist', 'cli.mjs');
12
12
 
13
- if (fs.existsSync(distCli)) {
14
- const { cli } = await import(pathToFileUrl(distCli).href);
15
- await cli(process.argv.slice(2));
16
- } else if (fs.existsSync(srcCli)) {
13
+ if (fs.existsSync(srcCli)) {
17
14
  const result = spawnSync(process.execPath, [tsxCli, srcCli, ...process.argv.slice(2)], {
18
15
  stdio: 'inherit',
19
16
  shell: false,
@@ -26,6 +23,9 @@ if (fs.existsSync(distCli)) {
26
23
  }
27
24
 
28
25
  process.exit(result.status ?? 0);
26
+ } else if (fs.existsSync(distCli)) {
27
+ const { cli } = await import(pathToFileUrl(distCli).href);
28
+ await cli(process.argv.slice(2));
29
29
  } else {
30
30
  console.error('[card-store] Could not find dist or src CLI entrypoint.');
31
31
  process.exit(1);