yaml-flow 5.4.2 → 7.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 (252) hide show
  1. package/board-live-cards-cli.js +6 -6
  2. package/browser/asset-integrity.json +10 -0
  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 -1676
  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 +561 -129
  13. package/browser/live-cards.schema.json +418 -132
  14. package/card-store.js +37 -0
  15. package/dist/batch/index.cjs +1 -108
  16. package/dist/batch/index.cjs.map +1 -1
  17. package/dist/batch/index.js +1 -106
  18. package/dist/batch/index.js.map +1 -1
  19. package/dist/board-live-cards-lib-Bg6EvCo5.d.cts +136 -0
  20. package/dist/board-live-cards-lib-jM2uYG1v.d.ts +136 -0
  21. package/dist/board-live-cards-public-CW5074xr.d.cts +318 -0
  22. package/dist/board-live-cards-public-hnZo0mAf.d.ts +318 -0
  23. package/dist/board-livegraph-runtime/index.cjs +2 -1671
  24. package/dist/board-livegraph-runtime/index.cjs.map +1 -1
  25. package/dist/board-livegraph-runtime/index.d.cts +12 -11
  26. package/dist/board-livegraph-runtime/index.d.ts +12 -11
  27. package/dist/board-livegraph-runtime/index.js +2 -1662
  28. package/dist/board-livegraph-runtime/index.js.map +1 -1
  29. package/dist/board-livegraph-runtime/jsonata-sync.cjs +7623 -0
  30. package/dist/card-compute/index.cjs +9 -7159
  31. package/dist/card-compute/index.cjs.map +1 -1
  32. package/dist/card-compute/index.d.cts +27 -1
  33. package/dist/card-compute/index.d.ts +27 -1
  34. package/dist/card-compute/index.js +9 -7145
  35. package/dist/card-compute/index.js.map +1 -1
  36. package/dist/card-compute/jsonata-sync.cjs +7623 -0
  37. package/dist/cli/browser-api/board-live-cards-browser-adapter.cjs +3 -0
  38. package/dist/cli/browser-api/board-live-cards-browser-adapter.cjs.map +1 -0
  39. package/dist/cli/browser-api/board-live-cards-browser-adapter.d.cts +37 -0
  40. package/dist/cli/browser-api/board-live-cards-browser-adapter.d.ts +37 -0
  41. package/dist/cli/browser-api/board-live-cards-browser-adapter.js +3 -0
  42. package/dist/cli/browser-api/board-live-cards-browser-adapter.js.map +1 -0
  43. package/dist/cli/browser-api/card-store-browser-api.cjs +2 -0
  44. package/dist/cli/browser-api/card-store-browser-api.cjs.map +1 -0
  45. package/dist/cli/browser-api/card-store-browser-api.d.cts +26 -0
  46. package/dist/cli/browser-api/card-store-browser-api.d.ts +26 -0
  47. package/dist/cli/browser-api/card-store-browser-api.js +2 -0
  48. package/dist/cli/browser-api/card-store-browser-api.js.map +1 -0
  49. package/dist/cli/browser-api/jsonata-sync.cjs +7623 -0
  50. package/dist/cli/node/artifacts-store-cli.cjs +11 -0
  51. package/dist/cli/node/artifacts-store-cli.cjs.map +1 -0
  52. package/dist/cli/node/artifacts-store-cli.d.cts +8 -0
  53. package/dist/cli/node/artifacts-store-cli.d.ts +8 -0
  54. package/dist/cli/node/artifacts-store-cli.js +11 -0
  55. package/dist/cli/node/artifacts-store-cli.js.map +1 -0
  56. package/dist/cli/node/board-live-cards-cli.cjs +15 -0
  57. package/dist/cli/node/board-live-cards-cli.cjs.map +1 -0
  58. package/dist/cli/node/board-live-cards-cli.d.cts +20 -0
  59. package/dist/cli/node/board-live-cards-cli.d.ts +20 -0
  60. package/dist/cli/node/board-live-cards-cli.js +15 -0
  61. package/dist/cli/node/board-live-cards-cli.js.map +1 -0
  62. package/dist/cli/node/card-store-cli.cjs +8 -0
  63. package/dist/cli/node/card-store-cli.cjs.map +1 -0
  64. package/dist/cli/node/card-store-cli.d.cts +15 -0
  65. package/dist/cli/node/card-store-cli.d.ts +15 -0
  66. package/dist/cli/node/card-store-cli.js +8 -0
  67. package/dist/cli/node/card-store-cli.js.map +1 -0
  68. package/dist/cli/node/execution-adapter.cjs +3 -0
  69. package/dist/cli/node/execution-adapter.cjs.map +1 -0
  70. package/dist/cli/node/execution-adapter.d.cts +174 -0
  71. package/dist/cli/node/execution-adapter.d.ts +174 -0
  72. package/dist/cli/node/execution-adapter.js +3 -0
  73. package/dist/cli/node/execution-adapter.js.map +1 -0
  74. package/dist/cli/node/fs-board-adapter.cjs +14 -0
  75. package/dist/cli/node/fs-board-adapter.cjs.map +1 -0
  76. package/dist/cli/node/fs-board-adapter.d.cts +204 -0
  77. package/dist/cli/node/fs-board-adapter.d.ts +204 -0
  78. package/dist/cli/node/fs-board-adapter.js +14 -0
  79. package/dist/cli/node/fs-board-adapter.js.map +1 -0
  80. package/dist/cli/node/jsonata-sync.cjs +7623 -0
  81. package/dist/cli/node/source-cli-task-executor.cjs +11 -0
  82. package/dist/cli/node/source-cli-task-executor.cjs.map +1 -0
  83. package/dist/cli/node/source-cli-task-executor.d.cts +1 -0
  84. package/dist/cli/node/source-cli-task-executor.d.ts +1 -0
  85. package/dist/cli/node/source-cli-task-executor.js +11 -0
  86. package/dist/cli/node/source-cli-task-executor.js.map +1 -0
  87. package/dist/config/index.cjs +1 -79
  88. package/dist/config/index.cjs.map +1 -1
  89. package/dist/config/index.js +1 -76
  90. package/dist/config/index.js.map +1 -1
  91. package/dist/continuous-event-graph/index.cjs +2 -2129
  92. package/dist/continuous-event-graph/index.cjs.map +1 -1
  93. package/dist/continuous-event-graph/index.d.cts +81 -5
  94. package/dist/continuous-event-graph/index.d.ts +81 -5
  95. package/dist/continuous-event-graph/index.js +2 -2088
  96. package/dist/continuous-event-graph/index.js.map +1 -1
  97. package/dist/continuous-event-graph/jsonata-sync.cjs +7623 -0
  98. package/dist/event-graph/index.cjs +22 -8292
  99. package/dist/event-graph/index.cjs.map +1 -1
  100. package/dist/event-graph/index.js +22 -8237
  101. package/dist/event-graph/index.js.map +1 -1
  102. package/dist/execution-refs.cjs +3 -0
  103. package/dist/execution-refs.cjs.map +1 -0
  104. package/dist/execution-refs.d.cts +260 -0
  105. package/dist/execution-refs.d.ts +260 -0
  106. package/dist/execution-refs.js +3 -0
  107. package/dist/execution-refs.js.map +1 -0
  108. package/dist/index.cjs +29 -13221
  109. package/dist/index.cjs.map +1 -1
  110. package/dist/index.d.cts +2 -4
  111. package/dist/index.d.ts +2 -4
  112. package/dist/index.js +29 -13112
  113. package/dist/index.js.map +1 -1
  114. package/dist/inference/index.cjs +5 -617
  115. package/dist/inference/index.cjs.map +1 -1
  116. package/dist/inference/index.js +5 -610
  117. package/dist/inference/index.js.map +1 -1
  118. package/dist/jsonata-sync.cjs +7623 -0
  119. package/dist/{live-cards-bridge-x5XREkXm.d.cts → live-cards-bridge-BXbVTsna.d.cts} +27 -4
  120. package/dist/{live-cards-bridge-EQjytzI_.d.ts → live-cards-bridge-Ds28XR15.d.ts} +27 -4
  121. package/dist/server-runtime/index.cjs +9 -0
  122. package/dist/server-runtime/index.cjs.map +1 -0
  123. package/dist/server-runtime/index.d.cts +31 -0
  124. package/dist/server-runtime/index.d.ts +31 -0
  125. package/dist/server-runtime/index.js +9 -0
  126. package/dist/server-runtime/index.js.map +1 -0
  127. package/dist/server-runtime/jsonata-sync.cjs +7623 -0
  128. package/dist/step-machine/index.cjs +11 -7129
  129. package/dist/step-machine/index.cjs.map +1 -1
  130. package/dist/step-machine/index.js +11 -7113
  131. package/dist/step-machine/index.js.map +1 -1
  132. package/dist/step-machine-public/index.cjs +2 -0
  133. package/dist/step-machine-public/index.cjs.map +1 -0
  134. package/dist/step-machine-public/index.d.cts +159 -0
  135. package/dist/step-machine-public/index.d.ts +159 -0
  136. package/dist/step-machine-public/index.js +2 -0
  137. package/dist/step-machine-public/index.js.map +1 -0
  138. package/dist/step-machine-public/jsonata-sync.cjs +7623 -0
  139. package/dist/storage-refs.cjs +10 -0
  140. package/dist/storage-refs.cjs.map +1 -0
  141. package/dist/storage-refs.d.cts +93 -0
  142. package/dist/storage-refs.d.ts +93 -0
  143. package/dist/storage-refs.js +10 -0
  144. package/dist/storage-refs.js.map +1 -0
  145. package/dist/stores/file.cjs +1 -114
  146. package/dist/stores/file.cjs.map +1 -1
  147. package/dist/stores/file.js +1 -112
  148. package/dist/stores/file.js.map +1 -1
  149. package/dist/stores/index.cjs +1 -231
  150. package/dist/stores/index.cjs.map +1 -1
  151. package/dist/stores/index.js +1 -227
  152. package/dist/stores/index.js.map +1 -1
  153. package/dist/stores/localStorage.cjs +1 -76
  154. package/dist/stores/localStorage.cjs.map +1 -1
  155. package/dist/stores/localStorage.js +1 -74
  156. package/dist/stores/localStorage.js.map +1 -1
  157. package/dist/stores/memory.cjs +1 -47
  158. package/dist/stores/memory.cjs.map +1 -1
  159. package/dist/stores/memory.js +1 -45
  160. package/dist/stores/memory.js.map +1 -1
  161. package/dist/types-B1ZRa4aI.d.ts +147 -0
  162. package/dist/types-BxEFcVK9.d.cts +147 -0
  163. package/examples/browser/boards/portfolio-tracker/portfolio-t4.js +291 -0
  164. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-fetch-prices.js +218 -0
  165. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-fetch-prices.py +201 -0
  166. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-http-test.js +357 -0
  167. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-inference-adapter.js +25 -16
  168. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-public.js +552 -0
  169. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-server.js +300 -0
  170. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-server.py +617 -0
  171. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-sse-worker.js +48 -0
  172. package/examples/browser/boards/portfolio-tracker/portfolio-tracker.py +366 -0
  173. package/examples/cli/step-machine-cli/portfolio-tracker/--base-ref/.runtime-out +1 -0
  174. package/examples/cli/step-machine-cli/portfolio-tracker/--base-ref/board-graph.json +32 -0
  175. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/_board-cli.js +70 -3
  176. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/add-cards-cli.js +16 -11
  177. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/init-board-cli.js +9 -8
  178. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/poll-status-cli.js +49 -0
  179. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/reset-board-dir-cli.js +2 -6
  180. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/retrigger-cli.js +4 -8
  181. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/status-cli.js +3 -7
  182. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/update-holdings-cli.js +9 -8
  183. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/wait-completed-cli.js +12 -17
  184. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/write-prices-cli.js +2 -6
  185. package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/_board_pycli.py +107 -0
  186. package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/add-cards.py +51 -0
  187. package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/init-board.py +45 -0
  188. package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/poll-status.py +71 -0
  189. package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/reset-board-dir.py +36 -0
  190. package/examples/cli/step-machine-cli/portfolio-tracker/inline-python-demo.flow.yaml +26 -0
  191. package/examples/cli/step-machine-cli/portfolio-tracker/inline-python-handlers.py +39 -0
  192. package/examples/cli/step-machine-cli/portfolio-tracker/portfolio-tracker-pycli.flow.yaml +80 -0
  193. package/examples/cli/step-machine-cli/portfolio-tracker/portfolio-tracker.flow.yaml +36 -187
  194. package/examples/cli/step-machine-cli/portfolio-tracker/portfolio-tracker.input.json +40 -34
  195. package/examples/cli/step-machine-cli/portfolio-tracker/run-inline-python-demo-pycli.py +43 -0
  196. package/examples/cli/step-machine-cli/portfolio-tracker/run-portfolio-tracker-pycli.py +77 -0
  197. package/examples/cli/step-machine-cli/portfolio-tracker/run-portfolio-tracker.bat +1 -2
  198. package/examples/cli/step-machine-demo/jsonata-init-board-cli.js +8 -13
  199. package/examples/cli/step-machine-demo/jsonata-init-board.flow.yaml +33 -9
  200. package/examples/cli/step-machine-demo/one-step-cli-only.flow.yaml +3 -1
  201. package/examples/cli/step-machine-demo/step2-double-cli.js +6 -12
  202. package/examples/cli/step-machine-demo/two-step-math.flow.yaml +66 -4
  203. package/examples/cli/step-machine-demo/two-step-mixed.flow.yaml +13 -5
  204. package/examples/example-board/agent-instructions.md +11 -5
  205. package/examples/example-board/cards/_index.json +47 -0
  206. package/examples/example-board/cards/card-market-prices.json +33 -9
  207. package/examples/example-board/cards/card-my-identity.json +30 -6
  208. package/examples/example-board/cards/card-portfolio-action.json +24 -6
  209. package/examples/example-board/cards/card-portfolio-intelligence.json +97 -0
  210. package/examples/example-board/cards/card-portfolio-risks.json +24 -6
  211. package/examples/example-board/cards/card-portfolio-value.json +38 -10
  212. package/examples/example-board/cards/card-portfolio.json +57 -13
  213. package/examples/example-board/cards/card-rebalance-impact.json +22 -6
  214. package/examples/example-board/cards/card-rebalance-sim.json +66 -15
  215. package/examples/example-board/demo-chat-handler.js +14 -4
  216. package/examples/example-board/demo-server-config.json +1 -0
  217. package/examples/example-board/demo-server.js +366 -68
  218. package/examples/example-board/demo-shell-localstorage.html +774 -0
  219. package/examples/example-board/demo-shell-with-server.html +20 -37
  220. package/examples/example-board/demo-shell.html +5 -4
  221. package/examples/example-board/demo-task-executor.js +273 -275
  222. package/examples/index.html +0 -14
  223. package/examples/step-machine-cli/portfolio-tracker/handlers/_board-cli.js +0 -1
  224. package/examples/step-machine-cli/portfolio-tracker/run-portfolio-tracker.bat +1 -2
  225. package/package.json +46 -8
  226. package/schema/live-cards.schema.json +418 -132
  227. package/step-machine-cli.js +43 -310
  228. package/board-livecards-server-runtime.js +0 -1574
  229. package/browser/board-livecards-runtime-client.js +0 -263
  230. package/dist/cli/board-live-cards-cli.cjs +0 -10650
  231. package/dist/cli/board-live-cards-cli.cjs.map +0 -1
  232. package/dist/cli/board-live-cards-cli.d.cts +0 -179
  233. package/dist/cli/board-live-cards-cli.d.ts +0 -179
  234. package/dist/cli/board-live-cards-cli.js +0 -10598
  235. package/dist/cli/board-live-cards-cli.js.map +0 -1
  236. package/dist/journal-9HEgs7dU.d.ts +0 -28
  237. package/dist/journal-B-JCfQnh.d.cts +0 -28
  238. package/dist/schedule-Cszq9LYY.d.ts +0 -21
  239. package/dist/schedule-qWNL0RQh.d.cts +0 -21
  240. package/examples/browser/boards/portfolio-tracker/cards/holdings-table.json +0 -22
  241. package/examples/browser/boards/portfolio-tracker/cards/portfolio-form.json +0 -16
  242. package/examples/browser/boards/portfolio-tracker/cards/portfolio-risk-assessment.json +0 -28
  243. package/examples/browser/boards/portfolio-tracker/cards/portfolio-value.json +0 -15
  244. package/examples/browser/boards/portfolio-tracker/cards/price-fetch.json +0 -15
  245. package/examples/browser/boards/portfolio-tracker/cards/rebalancing-strategy.json +0 -28
  246. package/examples/browser/boards/portfolio-tracker/fetch-prices.js +0 -43
  247. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-task-executor.cjs +0 -96
  248. package/examples/browser/boards/portfolio-tracker/portfolio-tracker.bat +0 -7
  249. package/examples/browser/boards/portfolio-tracker/portfolio-tracker.js +0 -351
  250. package/examples/cli/step-machine-demo/two-step-math-handlers.js +0 -32
  251. package/examples/cli/step-machine-demo/two-step-mixed-handlers.js +0 -24
  252. package/examples/example-board/demo-shell-browser.html +0 -674
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { readStdinJson, runBoardCli, writeFailure, writeResult } from './_board-cli.js';
3
+ import { readStdinJson, runBoardCli, toFsRef, writeFailure, writeResult } from './_board-cli.js';
4
4
 
5
5
  try {
6
6
  const input = await readStdinJson();
@@ -8,16 +8,12 @@ try {
8
8
 
9
9
  if (!boardDir) {
10
10
  writeFailure('BOARD_DIR is required');
11
- process.exit(0);
12
11
  }
13
12
 
14
- const status = runBoardCli(['status', '--rg', boardDir], { capture: true });
13
+ const status = runBoardCli(['status', '--base-ref', toFsRef(boardDir)], { capture: true });
15
14
 
16
15
  writeResult({
17
- result: 'success',
18
- data: {
19
- status,
20
- },
16
+ status,
21
17
  });
22
18
  } catch (error) {
23
19
  const message = error instanceof Error ? error.message : String(error);
@@ -2,7 +2,7 @@
2
2
 
3
3
  import * as fs from 'node:fs';
4
4
  import * as path from 'node:path';
5
- import { readStdinJson, runBoardCli, writeFailure, writeResult } from './_board-cli.js';
5
+ import { readStdinJson, runBoardCli, runCardStoreCliWithInput, toFsRef, writeFailure, writeResult } from './_board-cli.js';
6
6
 
7
7
  try {
8
8
  const input = await readStdinJson();
@@ -12,7 +12,6 @@ try {
12
12
 
13
13
  if (!boardDir || !cardsDir || !Array.isArray(holdings)) {
14
14
  writeFailure('BOARD_DIR, CARDS_DIR and HOLDINGS array are required');
15
- process.exit(0);
16
15
  }
17
16
 
18
17
  const cardPath = path.join(cardsDir, 'portfolio-form.json');
@@ -22,14 +21,16 @@ try {
22
21
  card.card_data.holdings = holdings;
23
22
  fs.writeFileSync(cardPath, `${JSON.stringify(card, null, 2)}\n`, 'utf-8');
24
23
 
25
- runBoardCli(['upsert-card', '--rg', boardDir, '--card', cardPath, '--restart']);
24
+ const baseRef = toFsRef(boardDir);
25
+ runCardStoreCliWithInput(
26
+ ['set', '--store-ref', baseRef],
27
+ JSON.stringify(card),
28
+ );
29
+ runBoardCli(['upsert-card', '--base-ref', baseRef, '--card-id', card.id, '--restart']);
26
30
 
27
31
  writeResult({
28
- result: 'success',
29
- data: {
30
- saved: true,
31
- holdings_count: holdings.length,
32
- },
32
+ saved: true,
33
+ holdings_count: holdings.length,
33
34
  });
34
35
  } catch (error) {
35
36
  const message = error instanceof Error ? error.message : String(error);
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { readStdinJson, runBoardCli, writeFailure, writeResult } from './_board-cli.js';
3
+ import { readStdinJson, runBoardCli, toFsRef, writeFailure, writeResult } from './_board-cli.js';
4
4
 
5
5
  function sleep(ms) {
6
6
  return new Promise((resolve) => setTimeout(resolve, ms));
@@ -16,22 +16,22 @@ try {
16
16
 
17
17
  if (!boardDir || tasks.length === 0) {
18
18
  writeFailure('BOARD_DIR and COMPLETION_TASKS are required');
19
- process.exit(0);
20
19
  }
21
20
 
22
21
  const started = Date.now();
23
22
 
24
23
  while (Date.now() - started < timeoutMs) {
25
- const status = runBoardCli(['status', '--rg', boardDir], { capture: true });
26
- const complete = tasks.every((task) => new RegExp(`\\bcompleted\\s+${task}\\b`).test(status));
24
+ const statusJson = runBoardCli(['status', '--base-ref', toFsRef(boardDir)], { capture: true });
25
+ let cards = [];
26
+ try {
27
+ cards = JSON.parse(statusJson)?.data?.cards ?? [];
28
+ } catch { /* ignore parse errors */ }
29
+ const complete = tasks.every((task) => cards.some(c => c.name === task && c.status === 'completed'));
27
30
 
28
31
  if (complete) {
29
32
  writeResult({
30
- result: 'success',
31
- data: {
32
- label,
33
- completed: true,
34
- },
33
+ label,
34
+ completed: true,
35
35
  });
36
36
  process.exit(0);
37
37
  }
@@ -39,14 +39,9 @@ try {
39
39
  await sleep(pollMs);
40
40
  }
41
41
 
42
- writeResult({
43
- result: 'timeout',
44
- data: {
45
- label,
46
- completed: false,
47
- error: `${label}: timed out waiting for completion`,
48
- },
49
- });
42
+ // Timeout — exit non-zero
43
+ process.stderr.write(`${label}: timed out waiting for completion`);
44
+ process.exit(1);
50
45
  } catch (error) {
51
46
  const message = error instanceof Error ? error.message : String(error);
52
47
  writeFailure(message);
@@ -12,7 +12,6 @@ try {
12
12
 
13
13
  if (!boardDirInput || !prices || typeof prices !== 'object' || Array.isArray(prices)) {
14
14
  writeFailure('BOARD_DIR and PRICES object are required');
15
- process.exit(0);
16
15
  }
17
16
 
18
17
  const boardDir = path.resolve(boardDirInput);
@@ -23,11 +22,8 @@ try {
23
22
  fs.writeFileSync(tmpFile, payload, 'utf-8');
24
23
 
25
24
  writeResult({
26
- result: 'success',
27
- data: {
28
- wrote: true,
29
- tmp_file: tmpFile,
30
- },
25
+ wrote: true,
26
+ tmp_file: tmpFile,
31
27
  });
32
28
  } catch (error) {
33
29
  const message = error instanceof Error ? error.message : String(error);
@@ -0,0 +1,107 @@
1
+ """Shared helpers for step-machine portfolio-tracker pycli handlers.
2
+
3
+ Each handler reads a JSON object from stdin and writes a JSON object to stdout.
4
+ Result schema: {"result": "success" | "failure" | "timeout", "data"?: {...}, "error"?: "..."}
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import json
9
+ import base64
10
+ import os
11
+ import subprocess
12
+ import sys
13
+ from pathlib import Path
14
+ from typing import Any
15
+
16
+ # Repo root layout (standalone or source tree):
17
+ # <root>/pycli/main/board_live_cards_pycli.py
18
+ # <root>/pycli/main/card_store_pycli.py
19
+ # <root>/dist/pycli/quickjs-board-runtime.global.js
20
+ _HERE = Path(__file__).resolve().parent
21
+ _REPO_ROOT = _HERE.parents[4]
22
+
23
+ BOARD_PYCLI = _REPO_ROOT / "pycli" / "main" / "board_live_cards_pycli.py"
24
+ CARD_STORE_PYCLI = _REPO_ROOT / "pycli" / "main" / "card_store_pycli.py"
25
+ QUICKJS_BUNDLE = _REPO_ROOT / "dist" / "pycli" / "quickjs-board-runtime.global.js"
26
+
27
+
28
+ def read_stdin_json() -> dict[str, Any]:
29
+ raw = sys.stdin.read()
30
+ if not raw.strip():
31
+ return {}
32
+ return json.loads(raw)
33
+
34
+
35
+ def write_result(payload: dict[str, Any]) -> None:
36
+ sys.stdout.write(json.dumps(payload, ensure_ascii=True))
37
+ sys.stdout.flush()
38
+
39
+
40
+ def write_failure(message: str) -> None:
41
+ write_result({"result": "failure", "error": message})
42
+
43
+
44
+ def _hidden_kwargs() -> dict[str, Any]:
45
+ kwargs: dict[str, Any] = {}
46
+ if os.name == "nt":
47
+ startupinfo = subprocess.STARTUPINFO()
48
+ startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
49
+ kwargs["startupinfo"] = startupinfo
50
+ kwargs["creationflags"] = subprocess.CREATE_NO_WINDOW
51
+ return kwargs
52
+
53
+
54
+ def to_fs_ref(value: str) -> str:
55
+ payload = json.dumps({"kind": "fs-path", "value": value}, separators=(",", ":")).encode("utf-8")
56
+ return "b64:" + base64.urlsafe_b64encode(payload).decode("ascii").rstrip("=")
57
+
58
+
59
+ def _normalize_args(args: list[str]) -> list[str]:
60
+ return list(args)
61
+
62
+
63
+ def run_board_pycli(args: list[str], *, capture: bool = False) -> str:
64
+ cmd = [sys.executable, str(BOARD_PYCLI), *_normalize_args(args), "--bundle", str(QUICKJS_BUNDLE)]
65
+ proc = subprocess.run(
66
+ cmd,
67
+ capture_output=True,
68
+ text=True,
69
+ check=False,
70
+ **_hidden_kwargs(),
71
+ )
72
+ if proc.returncode != 0:
73
+ msg = (proc.stderr or proc.stdout or "no output").strip()
74
+ raise RuntimeError(f"board_live_cards_pycli failed ({proc.returncode}): {msg}")
75
+ return proc.stdout if capture else ""
76
+
77
+
78
+ def run_board_pycli_with_input(args: list[str], input_json: str) -> str:
79
+ cmd = [sys.executable, str(BOARD_PYCLI), *_normalize_args(args), "--bundle", str(QUICKJS_BUNDLE)]
80
+ proc = subprocess.run(
81
+ cmd,
82
+ input=input_json,
83
+ capture_output=True,
84
+ text=True,
85
+ check=False,
86
+ **_hidden_kwargs(),
87
+ )
88
+ if proc.returncode != 0:
89
+ msg = (proc.stderr or proc.stdout or "no output").strip()
90
+ raise RuntimeError(f"board_live_cards_pycli failed ({proc.returncode}): {msg}")
91
+ return proc.stdout
92
+
93
+
94
+ def run_card_store_pycli_with_input(args: list[str], input_json: str) -> str:
95
+ cmd = [sys.executable, str(CARD_STORE_PYCLI), *_normalize_args(args)]
96
+ proc = subprocess.run(
97
+ cmd,
98
+ input=input_json,
99
+ capture_output=True,
100
+ text=True,
101
+ check=False,
102
+ **_hidden_kwargs(),
103
+ )
104
+ if proc.returncode != 0:
105
+ msg = (proc.stderr or proc.stdout or "no output").strip()
106
+ raise RuntimeError(f"card_store_pycli failed ({proc.returncode}): {msg}")
107
+ return proc.stdout
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env python3
2
+ """Write all cards to card-store and upsert them onto the board (pycli)."""
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ sys.path.insert(0, str(Path(__file__).resolve().parent))
10
+ from _board_pycli import ( # noqa: E402
11
+ read_stdin_json,
12
+ run_board_pycli,
13
+ run_card_store_pycli_with_input,
14
+ to_fs_ref,
15
+ write_failure,
16
+ write_result,
17
+ )
18
+
19
+
20
+ def main() -> int:
21
+ try:
22
+ payload = read_stdin_json()
23
+ board_dir = str(payload.get("BOARD_DIR", "")).strip()
24
+ cards = payload.get("CARDS")
25
+ if not isinstance(cards, list):
26
+ cards = []
27
+
28
+ if not board_dir or not cards:
29
+ write_failure("BOARD_DIR and CARDS (array) are required")
30
+ return 0
31
+
32
+ base_ref = to_fs_ref(board_dir)
33
+
34
+ run_card_store_pycli_with_input(
35
+ ["set", "--store-ref", base_ref],
36
+ json.dumps(cards, ensure_ascii=True),
37
+ )
38
+ run_board_pycli(["upsert-card", "--base-ref", base_ref, "--all"])
39
+
40
+ write_result({
41
+ "result": "success",
42
+ "data": {"board_dir": board_dir, "count": len(cards)},
43
+ })
44
+ return 0
45
+ except Exception as exc:
46
+ write_failure(str(exc))
47
+ return 0
48
+
49
+
50
+ if __name__ == "__main__":
51
+ raise SystemExit(main())
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env python3
2
+ """Initialize the board with card-store and outputs-store refs (pycli)."""
3
+ from __future__ import annotations
4
+
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ sys.path.insert(0, str(Path(__file__).resolve().parent))
9
+ from _board_pycli import ( # noqa: E402
10
+ read_stdin_json,
11
+ run_board_pycli,
12
+ to_fs_ref,
13
+ write_failure,
14
+ write_result,
15
+ )
16
+
17
+
18
+ def main() -> int:
19
+ try:
20
+ payload = read_stdin_json()
21
+ board_dir = str(payload.get("BOARD_DIR", "")).strip()
22
+ if not board_dir:
23
+ write_failure("BOARD_DIR is required")
24
+ return 0
25
+
26
+ base_ref = to_fs_ref(board_dir)
27
+ run_board_pycli([
28
+ "init",
29
+ "--base-ref", base_ref,
30
+ "--card-store-ref", base_ref,
31
+ "--outputs-store-ref", base_ref,
32
+ ])
33
+
34
+ write_result({
35
+ "result": "success",
36
+ "data": {"board_dir": board_dir, "message": f"initialized {board_dir}"},
37
+ })
38
+ return 0
39
+ except Exception as exc:
40
+ write_failure(str(exc))
41
+ return 0
42
+
43
+
44
+ if __name__ == "__main__":
45
+ raise SystemExit(main())
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env python3
2
+ """Poll board status until all expected cards reach `completed` (pycli)."""
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import sys
7
+ import time
8
+ from pathlib import Path
9
+
10
+ sys.path.insert(0, str(Path(__file__).resolve().parent))
11
+ from _board_pycli import ( # noqa: E402
12
+ read_stdin_json,
13
+ run_board_pycli,
14
+ to_fs_ref,
15
+ write_failure,
16
+ write_result,
17
+ )
18
+
19
+
20
+ def main() -> int:
21
+ try:
22
+ payload = read_stdin_json()
23
+ board_dir = str(payload.get("BOARD_DIR", "")).strip()
24
+ expected = int(payload.get("EXPECTED_CARD_COUNT") or 0)
25
+ timeout_ms = int(payload.get("TIMEOUT_MS") or 30_000)
26
+ poll_ms = int(payload.get("POLL_MS") or 500)
27
+
28
+ if not board_dir or expected <= 0:
29
+ write_failure("BOARD_DIR and EXPECTED_CARD_COUNT are required")
30
+ return 0
31
+
32
+ base_ref = to_fs_ref(board_dir)
33
+ deadline = time.monotonic() + (timeout_ms / 1000)
34
+
35
+ while time.monotonic() < deadline:
36
+ raw = run_board_pycli(["status", "--base-ref", base_ref], capture=True)
37
+ cards = []
38
+ try:
39
+ cards = json.loads(raw).get("data", {}).get("cards", []) or []
40
+ except Exception:
41
+ cards = []
42
+
43
+ completed = [c for c in cards if c.get("status") == "completed"]
44
+ if len(cards) >= expected and len(completed) >= expected:
45
+ write_result({
46
+ "result": "success",
47
+ "data": {
48
+ "completed": True,
49
+ "card_count": len(cards),
50
+ "completed_count": len(completed),
51
+ },
52
+ })
53
+ return 0
54
+
55
+ time.sleep(poll_ms / 1000)
56
+
57
+ write_result({
58
+ "result": "timeout",
59
+ "data": {
60
+ "completed": False,
61
+ "error": f"timed out waiting for {expected} cards to complete",
62
+ },
63
+ })
64
+ return 0
65
+ except Exception as exc:
66
+ write_failure(str(exc))
67
+ return 0
68
+
69
+
70
+ if __name__ == "__main__":
71
+ raise SystemExit(main())
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env python3
2
+ """Reset (rm -rf) the board runtime directory."""
3
+ from __future__ import annotations
4
+
5
+ import shutil
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ sys.path.insert(0, str(Path(__file__).resolve().parent))
10
+ from _board_pycli import read_stdin_json, write_failure, write_result # noqa: E402
11
+
12
+
13
+ def main() -> int:
14
+ try:
15
+ payload = read_stdin_json()
16
+ board_dir_input = str(payload.get("BOARD_DIR", "")).strip()
17
+ if not board_dir_input:
18
+ write_failure("BOARD_DIR is required")
19
+ return 0
20
+
21
+ board_dir = Path(board_dir_input).resolve()
22
+ if board_dir.exists():
23
+ shutil.rmtree(board_dir, ignore_errors=True)
24
+
25
+ write_result({
26
+ "result": "success",
27
+ "data": {"board_dir": str(board_dir), "reset": True},
28
+ })
29
+ return 0
30
+ except Exception as exc:
31
+ write_failure(str(exc))
32
+ return 0
33
+
34
+
35
+ if __name__ == "__main__":
36
+ raise SystemExit(main())
@@ -0,0 +1,26 @@
1
+ id: inline-python-demo
2
+ settings:
3
+ start_step: greet
4
+ max_total_steps: 5
5
+
6
+ steps:
7
+ greet:
8
+ description: Build a greeting message using Python inline handler
9
+ handler:
10
+ inline: greet_user
11
+ transitions:
12
+ success: add
13
+
14
+ add:
15
+ description: Add two numbers with Python inline handler
16
+ expects_data: [a, b]
17
+ produces_data: [total]
18
+ handler:
19
+ inline: add_numbers
20
+ transitions:
21
+ success: done
22
+
23
+ terminal_states:
24
+ done:
25
+ return_intent: success
26
+ return_artifacts: [message, total]
@@ -0,0 +1,39 @@
1
+ from __future__ import annotations
2
+
3
+
4
+ def greet_user(input_obj, ctx=None):
5
+ payload = input_obj if isinstance(input_obj, dict) else {}
6
+ name = payload.get("name", "world")
7
+ return {
8
+ "result": "success",
9
+ "data": {
10
+ "message": f"Hello, {name}!",
11
+ },
12
+ }
13
+
14
+
15
+ def add_numbers(input_obj, ctx=None):
16
+ payload = input_obj if isinstance(input_obj, dict) else {}
17
+ a = payload.get("a", 0)
18
+ b = payload.get("b", 0)
19
+ try:
20
+ total = float(a) + float(b)
21
+ except Exception:
22
+ return {
23
+ "result": "failure",
24
+ "data": {"error": f"Cannot add values: a={a!r}, b={b!r}"},
25
+ }
26
+
27
+ if total.is_integer():
28
+ total = int(total)
29
+
30
+ return {
31
+ "result": "success",
32
+ "data": {"total": total},
33
+ }
34
+
35
+
36
+ handlers = {
37
+ "greet_user": greet_user,
38
+ "add_numbers": add_numbers,
39
+ }
@@ -0,0 +1,80 @@
1
+ id: portfolio-tracker-step-machine-pycli
2
+ settings:
3
+ start_step: t0_reset_board
4
+ max_total_steps: 30
5
+ timeout_ms: 120000
6
+
7
+ steps:
8
+ t0_reset_board:
9
+ description: Reset board runtime directory for idempotent reruns
10
+ expects_data: [runtime_root, board_name]
11
+ produces_data: [board_dir]
12
+ handler:
13
+ cli: python ./handlers-py/reset-board-dir.py
14
+ input-transforms:
15
+ BOARD_DIR: runtime_root & "/" & board_name
16
+ output-transforms:
17
+ board_dir: data.board_dir
18
+ transitions:
19
+ success: t0_init_board
20
+ failure_transitions:
21
+ failure: failed_state
22
+
23
+ t0_init_board:
24
+ description: Initialize board with card-store and outputs-store refs (pycli)
25
+ expects_data: [board_dir]
26
+ produces_data: [board_dir]
27
+ handler:
28
+ cli: python ./handlers-py/init-board.py
29
+ input-transforms:
30
+ BOARD_DIR: board_dir
31
+ output-transforms:
32
+ board_dir: data.board_dir
33
+ transitions:
34
+ success: t1_add_cards
35
+ failure_transitions:
36
+ failure: failed_state
37
+
38
+ t1_add_cards:
39
+ description: Add cards via card-store set and upsert-card --all (pycli)
40
+ expects_data: [board_dir, cards]
41
+ produces_data: [cards_added]
42
+ handler:
43
+ cli: python ./handlers-py/add-cards.py
44
+ input-transforms:
45
+ BOARD_DIR: board_dir
46
+ CARDS: cards
47
+ output-transforms:
48
+ cards_added: data.count
49
+ transitions:
50
+ success: t2_poll_status
51
+ failure_transitions:
52
+ failure: failed_state
53
+
54
+ t2_poll_status:
55
+ description: Poll board status until all cards are completed (pycli)
56
+ expects_data: [board_dir, expected_card_count]
57
+ produces_data: [all_completed]
58
+ handler:
59
+ cli: python ./handlers-py/poll-status.py
60
+ input-transforms:
61
+ BOARD_DIR: board_dir
62
+ EXPECTED_CARD_COUNT: expected_card_count
63
+ TIMEOUT_MS: "30000"
64
+ POLL_MS: "500"
65
+ output-transforms:
66
+ all_completed: data.completed
67
+ transitions:
68
+ success: success_state
69
+ failure_transitions:
70
+ timeout: failed_state
71
+ failure: failed_state
72
+
73
+ terminal_states:
74
+ success_state:
75
+ return_intent: success
76
+ return_artifacts: [board_dir, cards_added, all_completed]
77
+
78
+ failed_state:
79
+ return_intent: failure
80
+ return_artifacts: [error, board_dir]