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
@@ -0,0 +1,366 @@
1
+ #!/usr/bin/env python3
2
+ """portfolio-tracker.py — E2E orchestrator for the portfolio board demo.
3
+
4
+ Black-box CLI client. All board and card-store operations are performed by
5
+ shelling out to board-live-cards-cli and card-store-cli. No env vars. No
6
+ fallbacks or defaults.
7
+ """
8
+
9
+ import copy
10
+ import base64
11
+ import json
12
+ import os
13
+ import shutil
14
+ import subprocess
15
+ import sys
16
+ import tempfile
17
+ import time
18
+ import argparse
19
+
20
+
21
+ def serialize_ref(ref: dict[str, str]) -> str:
22
+ payload = json.dumps({"kind": ref.get("kind", ""), "value": ref.get("value", "")}, separators=(",", ":")).encode("utf-8")
23
+ return "b64:" + base64.urlsafe_b64encode(payload).decode("ascii").rstrip("=")
24
+
25
+
26
+ _CLI_PARSER = argparse.ArgumentParser()
27
+ _MODE_GROUP = _CLI_PARSER.add_mutually_exclusive_group()
28
+ _MODE_GROUP.add_argument('--run-pycli', action='store_true', help='Use pycli for board/card operations (default)')
29
+ _MODE_GROUP.add_argument('--run-nodecli', action='store_true', help='Use node cli for board/card operations')
30
+ _CLI_ARGS = _CLI_PARSER.parse_args()
31
+ RUN_PYCLI = not _CLI_ARGS.run_nodecli
32
+
33
+ # ── Path resolution ────────────────────────────────────────────────────────────
34
+ _HERE = os.path.dirname(os.path.abspath(__file__))
35
+ _REPO_ROOT = os.path.normpath(os.path.join(_HERE, '..', '..', '..', '..'))
36
+
37
+ NODE = shutil.which('node')
38
+ if not NODE:
39
+ print('[ERROR] node not found on PATH', file=sys.stderr)
40
+ sys.exit(1)
41
+
42
+ BOARD_CLI = os.path.join(_REPO_ROOT, 'board-live-cards-cli.js')
43
+ CARD_STORE_CLI = os.path.join(_REPO_ROOT, 'card-store.js')
44
+ FETCH_PRICES_PY = os.path.join(_HERE, 'portfolio-tracker-fetch-prices.py')
45
+
46
+ PYTHON = shutil.which('python')
47
+ if not PYTHON:
48
+ print('[ERROR] python not found on PATH (required for portfolio-tracker-fetch-prices.py)', file=sys.stderr)
49
+ sys.exit(1)
50
+
51
+ PYTHON_RUNNER = sys.executable or PYTHON
52
+
53
+ BOARD_PYCLI = os.path.join(_REPO_ROOT, 'pycli', 'main', 'board_live_cards_pycli.py')
54
+ CARD_STORE_PYCLI = os.path.join(_REPO_ROOT, 'pycli', 'main', 'card_store_pycli.py')
55
+
56
+ if RUN_PYCLI:
57
+ if not os.path.exists(BOARD_PYCLI):
58
+ print(f'[ERROR] pycli entry not found: {BOARD_PYCLI}', file=sys.stderr)
59
+ sys.exit(1)
60
+ if not os.path.exists(CARD_STORE_PYCLI):
61
+ print(f'[ERROR] pycli entry not found: {CARD_STORE_PYCLI}', file=sys.stderr)
62
+ sys.exit(1)
63
+
64
+ if RUN_PYCLI:
65
+ ACTIVE_BOARD_BIN = [PYTHON_RUNNER, BOARD_PYCLI]
66
+ ACTIVE_CARD_STORE_BIN = [PYTHON_RUNNER, CARD_STORE_PYCLI]
67
+ ACTIVE_BOARD_SUFFIX = []
68
+ else:
69
+ ACTIVE_BOARD_BIN = [NODE, BOARD_CLI]
70
+ ACTIVE_CARD_STORE_BIN = [NODE, CARD_STORE_CLI]
71
+ ACTIVE_BOARD_SUFFIX = []
72
+
73
+ # ── Runtime directories (under os.tmpdir()/experiment/) ───────────────────────
74
+ _TMP_BASE = tempfile.mkdtemp(prefix='experiment-')
75
+ CARDSTORE_DIR = os.path.join(_TMP_BASE, 'cardstore')
76
+ BOARDRUNTIME_DIR = os.path.join(_TMP_BASE, 'boardruntime')
77
+ OUTPUTS_DIR = os.path.join(_TMP_BASE, 'outputs')
78
+
79
+ CARDSTORE_REF = serialize_ref({'kind': 'fs-path', 'value': CARDSTORE_DIR})
80
+ BOARDRUNTIME_REF = serialize_ref({'kind': 'fs-path', 'value': BOARDRUNTIME_DIR})
81
+ OUTPUTS_REF = serialize_ref({'kind': 'fs-path', 'value': OUTPUTS_DIR})
82
+
83
+ # ── Inline card definitions ────────────────────────────────────────────────────
84
+ CARD_PORTFOLIO_FORM = {
85
+ "id": "portfolio-form",
86
+ "meta": {"title": "Portfolio Holdings Form"},
87
+ "provides": [{"bindTo": "holdings", "ref": "card_data.holdings"}],
88
+ "card_data": {"holdings": []},
89
+ "view": {
90
+ "elements": [
91
+ {"kind": "table", "label": "Holdings",
92
+ "data": {"bind": "card_data.holdings", "columns": ["symbol", "qty"]}}
93
+ ]
94
+ }
95
+ }
96
+
97
+ CARD_PRICE_FETCH = {
98
+ "id": "price-fetch",
99
+ "meta": {"title": "Fetch Market Prices"},
100
+ "requires": ["holdings"],
101
+ "provides": [{"bindTo": "prices", "ref": "fetched_sources.prices"}],
102
+ "card_data": {},
103
+ "source_defs": [{
104
+ "kind": "mock-quotes",
105
+ "bindTo": "prices",
106
+ "outputFile": "prices.json",
107
+ "projections": {"tickers": "requires.holdings.symbol"}
108
+ }],
109
+ "view": {
110
+ "elements": [
111
+ {"kind": "table", "label": "Market Prices",
112
+ "data": {"bind": "fetched_sources.prices"}}
113
+ ]
114
+ }
115
+ }
116
+
117
+ CARD_HOLDINGS_TABLE = {
118
+ "id": "holdings-table",
119
+ "meta": {"title": "Holdings Table"},
120
+ "requires": ["holdings", "prices"],
121
+ "provides": [{"bindTo": "table", "ref": "computed_values.table"}],
122
+ "card_data": {},
123
+ "compute": [{
124
+ "bindTo": "table",
125
+ "expr": (
126
+ '{ "rows": $map(requires.holdings, function($h) { '
127
+ '{ "symbol": $h.symbol, "qty": $h.qty, '
128
+ '"price": $lookup(requires.prices, $h.symbol), '
129
+ '"value": $h.qty * $lookup(requires.prices, $h.symbol) } }) }'
130
+ )
131
+ }],
132
+ "view": {
133
+ "elements": [
134
+ {"kind": "table", "label": "Portfolio Positions",
135
+ "data": {"bind": "computed_values.table.rows",
136
+ "columns": ["symbol", "qty", "price", "value"]}}
137
+ ]
138
+ }
139
+ }
140
+
141
+ CARD_PORTFOLIO_VALUE = {
142
+ "id": "portfolio-value",
143
+ "meta": {"title": "Portfolio Total Value"},
144
+ "requires": ["table"],
145
+ "provides": [{"bindTo": "totalValue", "ref": "computed_values.totalValue"}],
146
+ "card_data": {},
147
+ "compute": [
148
+ {"bindTo": "totalValue", "expr": "$sum(requires.table.rows.value)"}
149
+ ],
150
+ "view": {
151
+ "elements": [
152
+ {"kind": "metric", "label": "Total Portfolio Value",
153
+ "data": {"bind": "computed_values.totalValue"}}
154
+ ]
155
+ }
156
+ }
157
+
158
+ # ── Helpers ────────────────────────────────────────────────────────────────────
159
+ def set_holdings(card_json: dict, holdings: dict) -> dict:
160
+ card = copy.deepcopy(card_json)
161
+ card["card_data"]["holdings"] = [
162
+ {"symbol": symbol, "qty": qty}
163
+ for symbol, qty in holdings.items()
164
+ ]
165
+ return card
166
+
167
+
168
+ def run_board(*args):
169
+ subprocess.run([*ACTIVE_BOARD_BIN, *args, *ACTIVE_BOARD_SUFFIX], check=True, shell=False)
170
+
171
+
172
+ def run_board_with_input(*args, input_json: str):
173
+ subprocess.run(
174
+ [*ACTIVE_BOARD_BIN, *args, *ACTIVE_BOARD_SUFFIX],
175
+ input=input_json, check=True, shell=False, text=True,
176
+ )
177
+
178
+
179
+ def run_board_capture(*args) -> str:
180
+ result = subprocess.run(
181
+ [*ACTIVE_BOARD_BIN, *args, *ACTIVE_BOARD_SUFFIX],
182
+ check=True, shell=False, capture_output=True, text=True,
183
+ )
184
+ return result.stdout
185
+
186
+
187
+ def run_card_store_set(card: dict):
188
+ subprocess.run(
189
+ [*ACTIVE_CARD_STORE_BIN, 'set', '--store-ref', CARDSTORE_REF],
190
+ input=json.dumps(card),
191
+ check=True,
192
+ shell=False,
193
+ text=True,
194
+ )
195
+
196
+
197
+ def read_json(path: str):
198
+ with open(path, encoding='utf-8') as f:
199
+ return json.load(f)
200
+
201
+
202
+ def wait_for_completed(label: str, timeout_s: float = 10.0, poll_s: float = 0.5):
203
+ required_names = {'portfolio-form', 'price-fetch', 'holdings-table', 'portfolio-value'}
204
+ deadline = time.monotonic() + timeout_s
205
+ while time.monotonic() < deadline:
206
+ raw = run_board_capture('status', '--base-ref', BOARDRUNTIME_REF)
207
+ data = json.loads(raw).get('data', {})
208
+ cards = data.get('cards', [])
209
+ completed = {c['name'] for c in cards if c.get('status') == 'completed'}
210
+ if required_names.issubset(completed):
211
+ print(f'[{label}] all cards completed.')
212
+ return
213
+ time.sleep(poll_s)
214
+ # timed out — print status and exit
215
+ raw = run_board_capture('status', '--base-ref', BOARDRUNTIME_REF)
216
+ print(f'[ERROR] {label}: timed out waiting for all cards to complete.', file=sys.stderr)
217
+ print(raw, file=sys.stderr)
218
+ sys.exit(1)
219
+
220
+
221
+ # ── T0a — Create runtime directories ──────────────────────────────────────────
222
+ print('\n=== T0a: Create runtime directories ===')
223
+ for d in (CARDSTORE_DIR, BOARDRUNTIME_DIR, OUTPUTS_DIR):
224
+ os.makedirs(d)
225
+ print(f' created: {d}')
226
+
227
+ # ── T0b — Init board ───────────────────────────────────────────────────────────
228
+ print('\n=== T0b: Init board ===')
229
+ _task_executor_body = json.dumps({
230
+ 'task-executor-ref': {
231
+ 'meta': 'task-executor',
232
+ 'howToRun': 'local-python',
233
+ 'whatToRun': serialize_ref({'kind': 'fs-path', 'value': FETCH_PRICES_PY}),
234
+ }
235
+ })
236
+ run_board_with_input(
237
+ 'init',
238
+ '--base-ref', BOARDRUNTIME_REF,
239
+ '--card-store-ref', CARDSTORE_REF,
240
+ '--outputs-store-ref', OUTPUTS_REF,
241
+ input_json=_task_executor_body,
242
+ )
243
+
244
+ # ── T0c — Set all cards into card store ────────────────────────────────────────
245
+ print('\n=== T0c: Set all cards into card store ===')
246
+ run_card_store_set(set_holdings(CARD_PORTFOLIO_FORM, {"AAPL": 50, "MSFT": 30}))
247
+ run_card_store_set(CARD_PRICE_FETCH)
248
+ run_card_store_set(CARD_HOLDINGS_TABLE)
249
+ run_card_store_set(CARD_PORTFOLIO_VALUE)
250
+
251
+ # ── T0d — Upsert cards to board ────────────────────────────────────────────────
252
+ print('\n=== T0d: Upsert cards to board ===')
253
+ for _card_id in ('portfolio-form', 'price-fetch', 'holdings-table', 'portfolio-value'):
254
+ run_board('upsert-card', '--base-ref', BOARDRUNTIME_REF, '--card-id', _card_id)
255
+
256
+ # ── T1 — Wait for all cards completed ──────────────────────────────────────────
257
+ print('\n=== T1: Wait for all cards completed ===')
258
+ wait_for_completed('T1')
259
+
260
+ _prices_path = os.path.join(OUTPUTS_DIR, 'data-objects', 'prices.json')
261
+ _prices_t1 = read_json(_prices_path)
262
+ assert isinstance(_prices_t1, dict) and len(_prices_t1) > 0, \
263
+ 'T1: prices.json is empty or not an object'
264
+ assert set(_prices_t1.keys()) == {'AAPL', 'MSFT'}, \
265
+ f'T1: expected keys {{AAPL, MSFT}}, got {set(_prices_t1.keys())}'
266
+ assert all(isinstance(v, (int, float)) for v in _prices_t1.values()), \
267
+ 'T1: all price values must be numbers'
268
+ print('[T1] assertion passed: prices.json has AAPL, MSFT with numeric values.')
269
+
270
+ # ── T2a — Update holdings (GOOG added) ────────────────────────────────────────
271
+ print('\n=== T2a: Update holdings (GOOG added) ===')
272
+ run_card_store_set(set_holdings(CARD_PORTFOLIO_FORM, {"AAPL": 50, "MSFT": 30, "GOOG": 100}))
273
+
274
+ # ── T2b — Upsert portfolio-form with --restart ─────────────────────────────────
275
+ print('\n=== T2b: Upsert portfolio-form --restart ===')
276
+ run_board('upsert-card', '--base-ref', BOARDRUNTIME_REF,
277
+ '--card-id', 'portfolio-form', '--restart')
278
+
279
+ # ── T2c — Wait and assert ──────────────────────────────────────────────────────
280
+ print('\n=== T2c: Wait for all cards completed ===')
281
+ wait_for_completed('T2c')
282
+
283
+ _prices_t2c = read_json(_prices_path)
284
+ assert set(_prices_t2c.keys()) == {'AAPL', 'MSFT', 'GOOG'}, \
285
+ f'T2c: expected keys {{AAPL, MSFT, GOOG}}, got {set(_prices_t2c.keys())}'
286
+
287
+ _ht_cv_path = os.path.join(OUTPUTS_DIR, 'cards', 'holdings-table', 'computed_values.json')
288
+ _ht_cv_t2c = read_json(_ht_cv_path)
289
+ assert len(_ht_cv_t2c['table']['rows']) == 3, \
290
+ f'T2c: expected 3 rows in holdings-table, got {len(_ht_cv_t2c["table"]["rows"])}'
291
+ print('[T2c] assertions passed: 3 tickers in prices, 3 rows in holdings-table.')
292
+
293
+ # ── T3 — Retrigger price-fetch, wait ──────────────────────────────────────────
294
+ print('\n=== T3: Retrigger price-fetch ===')
295
+ run_board('retrigger', '--base-ref', BOARDRUNTIME_REF, '--id', 'price-fetch')
296
+ wait_for_completed('T3')
297
+
298
+ _prices_t3 = read_json(_prices_path)
299
+ assert set(_prices_t3.keys()) == {'AAPL', 'MSFT', 'GOOG'}, \
300
+ f'T3: expected 3 tickers, got {set(_prices_t3.keys())}'
301
+ assert _prices_t3 != _prices_t2c, \
302
+ 'T3: prices must differ from T2c values after retrigger (random regeneration)'
303
+ print('[T3] assertions passed: 3 tickers, prices differ from T2c.')
304
+
305
+ # ── T4 — Rapid 5× portfolio-form updates (queue stress test) ──────────────────
306
+ print('\n=== T4: Rapid 5x portfolio-form updates ===')
307
+ for _holdings in [
308
+ {"AAPL": 50, "MSFT": 30, "GOOG": 100, "AMZN": 40}, # V3
309
+ {"AAPL": 45, "MSFT": 30, "GOOG": 110, "AMZN": 40, "TSLA": 60}, # V4
310
+ {"AAPL": 45, "MSFT": 30, "GOOG": 110, "AMZN": 100}, # V4a
311
+ {"AAPL": 45, "MSFT": 30, "GOOG": 110, "AMZN": 140, "TSLA": 60}, # V4b
312
+ {"AAPL": 40, "MSFT": 35, "GOOG": 120, "TSLA": 70}, # V5
313
+ ]:
314
+ run_card_store_set(set_holdings(CARD_PORTFOLIO_FORM, _holdings))
315
+ run_board('upsert-card', '--base-ref', BOARDRUNTIME_REF,
316
+ '--card-id', 'portfolio-form', '--restart')
317
+
318
+ wait_for_completed('T4')
319
+
320
+ _prices_t4 = read_json(_prices_path)
321
+ assert set(_prices_t4.keys()) == {'AAPL', 'MSFT', 'GOOG', 'TSLA'}, \
322
+ f'T4: expected keys {{AAPL, MSFT, GOOG, TSLA}}, got {set(_prices_t4.keys())}'
323
+ assert 'AMZN' not in _prices_t4, \
324
+ 'T4: AMZN must not be present (board must have settled on V5 holdings)'
325
+ print('[T4] assertions passed: V5 tickers only, AMZN absent.')
326
+
327
+ # ── T5 — Print final status and cross-check ────────────────────────────────────
328
+ print('\n=== T5: Print final status and cross-check ===')
329
+
330
+ # Step 1: Wait for all cards completed (stable state before any assertions)
331
+ wait_for_completed('T5')
332
+
333
+ # Step 2: Capture live CLI status
334
+ _cli_raw = run_board_capture('status', '--base-ref', BOARDRUNTIME_REF)
335
+ _cli_status = json.loads(_cli_raw)['data']
336
+
337
+ # Step 3: Read status.json from outputs store
338
+ _file_status = read_json(os.path.join(OUTPUTS_DIR, 'status.json'))
339
+
340
+ # Step 4: Cross-check CLI vs file status
341
+ assert json.dumps(_cli_status, sort_keys=True) == json.dumps(_file_status, sort_keys=True), \
342
+ 'T5: CLI status does not match status.json snapshot'
343
+ print('[T5] cross-check passed: CLI status matches status.json.')
344
+
345
+ # Step 5: Print holdings-table computed values
346
+ _ht_cv = read_json(_ht_cv_path)
347
+ print('\nFinal portfolio positions table:')
348
+ print(json.dumps(_ht_cv['table'], indent=2))
349
+
350
+ # Step 6: Totals cross-verify: holdings × prices == totalValue
351
+ V5_HOLDINGS = {"AAPL": 40, "MSFT": 35, "GOOG": 120, "TSLA": 70}
352
+ _prices_final = read_json(_prices_path)
353
+ _pv_cv = read_json(
354
+ os.path.join(OUTPUTS_DIR, 'cards', 'portfolio-value', 'computed_values.json')
355
+ )
356
+ _total_value = _pv_cv['totalValue']
357
+ _expected = sum(qty * _prices_final[sym] for sym, qty in V5_HOLDINGS.items())
358
+ assert round(_expected, 2) == round(_total_value, 2), \
359
+ f'T5: totals mismatch: expected={round(_expected, 2)}, got={round(_total_value, 2)}'
360
+ print(f'[T5] totals assertion passed: expected={round(_expected, 2)}, totalValue={round(_total_value, 2)}')
361
+
362
+ # Step 7: Print full CLI status
363
+ print('\nFinal board status:')
364
+ print(json.dumps(_cli_status, indent=2))
365
+
366
+ print('\n=== portfolio-tracker completed successfully ===')
@@ -0,0 +1,32 @@
1
+ {
2
+ "graph": {
3
+ "version": 1,
4
+ "config": {
5
+ "settings": {
6
+ "completion": "manual",
7
+ "refreshStrategy": "data-changed"
8
+ },
9
+ "tasks": {}
10
+ },
11
+ "state": {
12
+ "status": "running",
13
+ "tasks": {},
14
+ "availableOutputs": [],
15
+ "stuckDetection": {
16
+ "is_stuck": false,
17
+ "stuck_description": null,
18
+ "outputs_unresolvable": [],
19
+ "tasks_blocked": []
20
+ },
21
+ "lastUpdated": "2026-05-02T15:18:33.305Z",
22
+ "executionId": "live-1777735113305",
23
+ "executionConfig": {
24
+ "executionMode": "eligibility-mode",
25
+ "conflictStrategy": "alphabetical",
26
+ "completionStrategy": "manual"
27
+ }
28
+ },
29
+ "snapshotAt": "2026-05-02T15:18:33.305Z"
30
+ },
31
+ "lastDrainedJournalId": ""
32
+ }
@@ -6,17 +6,31 @@ const __filename = fileURLToPath(import.meta.url);
6
6
  const __dirname = path.dirname(__filename);
7
7
  const repoRoot = path.resolve(__dirname, '..', '..', '..', '..', '..');
8
8
  const boardCliPath = path.join(repoRoot, 'board-live-cards-cli.js');
9
+ const cardStoreCliPath = path.join(repoRoot, 'card-store.js');
10
+
11
+ export function toFsRef(value) {
12
+ const payload = Buffer.from(JSON.stringify({ kind: 'fs-path', value }), 'utf-8').toString('base64url');
13
+ return `b64:${payload}`;
14
+ }
15
+
16
+ function normalizeRefArg(v) {
17
+ if (typeof v !== 'string') return v;
18
+ return v;
19
+ }
20
+
21
+ function normalizeArgs(args) {
22
+ return args.map((v) => normalizeRefArg(v));
23
+ }
9
24
 
10
25
  export function runBoardCli(args, options = {}) {
11
26
  const { capture = false, cwd = process.cwd() } = options;
12
- const result = spawnSync(process.execPath, [boardCliPath, ...args], {
27
+ const result = spawnSync(process.execPath, [boardCliPath, ...normalizeArgs(args)], {
13
28
  cwd,
14
29
  encoding: 'utf-8',
15
30
  windowsHide: true,
16
31
  stdio: capture ? 'pipe' : 'pipe',
17
32
  env: {
18
33
  ...process.env,
19
- BOARD_LIVE_CARDS_NO_SPAWN: process.env.BOARD_LIVE_CARDS_NO_SPAWN ?? '1',
20
34
  BOARD_DIR: process.env.BOARD_DIR ?? '',
21
35
  },
22
36
  });
@@ -34,6 +48,58 @@ export function runBoardCli(args, options = {}) {
34
48
  return capture ? (result.stdout ?? '') : '';
35
49
  }
36
50
 
51
+ /** Spawn CLI with JSON piped to stdin. */
52
+ export function runBoardCliWithInput(args, inputJson, options = {}) {
53
+ const { cwd = process.cwd() } = options;
54
+ const result = spawnSync(process.execPath, [boardCliPath, ...normalizeArgs(args)], {
55
+ input: inputJson,
56
+ cwd,
57
+ encoding: 'utf-8',
58
+ windowsHide: true,
59
+ stdio: ['pipe', 'pipe', 'pipe'],
60
+ env: {
61
+ ...process.env,
62
+ BOARD_DIR: process.env.BOARD_DIR ?? '',
63
+ },
64
+ });
65
+
66
+ if (result.error) {
67
+ throw new Error(`Failed to launch board-live-cards-cli: ${result.error.message}`);
68
+ }
69
+
70
+ if ((result.status ?? 1) !== 0) {
71
+ const stderr = (result.stderr ?? '').trim();
72
+ const stdout = (result.stdout ?? '').trim();
73
+ throw new Error(`board-live-cards-cli failed (${result.status}): ${stderr || stdout || 'no output'}`);
74
+ }
75
+
76
+ return result.stdout ?? '';
77
+ }
78
+
79
+ /** Spawn card-store-cli with JSON piped to stdin. */
80
+ export function runCardStoreCliWithInput(args, inputJson, options = {}) {
81
+ const { cwd = process.cwd() } = options;
82
+ const result = spawnSync(process.execPath, [cardStoreCliPath, ...normalizeArgs(args)], {
83
+ input: inputJson,
84
+ cwd,
85
+ encoding: 'utf-8',
86
+ windowsHide: true,
87
+ stdio: ['pipe', 'pipe', 'pipe'],
88
+ });
89
+
90
+ if (result.error) {
91
+ throw new Error(`Failed to launch card-store-cli: ${result.error.message}`);
92
+ }
93
+
94
+ if ((result.status ?? 1) !== 0) {
95
+ const stderr = (result.stderr ?? '').trim();
96
+ const stdout = (result.stdout ?? '').trim();
97
+ throw new Error(`card-store-cli failed (${result.status}): ${stderr || stdout || 'no output'}`);
98
+ }
99
+
100
+ return result.stdout ?? '';
101
+ }
102
+
37
103
  export async function readStdinJson() {
38
104
  let raw = '';
39
105
  process.stdin.setEncoding('utf-8');
@@ -54,5 +120,6 @@ export function writeResult(payload) {
54
120
  }
55
121
 
56
122
  export function writeFailure(message) {
57
- writeResult({ result: 'failure', error: message });
123
+ process.stderr.write(message);
124
+ process.exit(1);
58
125
  }
@@ -1,25 +1,30 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { readStdinJson, runBoardCli, writeFailure, writeResult } from './_board-cli.js';
3
+ import { readStdinJson, runBoardCli, runCardStoreCliWithInput, toFsRef, writeFailure, writeResult } from './_board-cli.js';
4
4
 
5
5
  try {
6
6
  const input = await readStdinJson();
7
7
  const boardDir = String(input.BOARD_DIR ?? '').trim();
8
- const cardsGlob = String(input.CARDS_GLOB ?? '').trim();
8
+ const cards = Array.isArray(input.CARDS) ? input.CARDS : [];
9
9
 
10
- if (!boardDir || !cardsGlob) {
11
- writeFailure('BOARD_DIR and CARDS_GLOB are required');
12
- process.exit(0);
10
+ if (!boardDir || cards.length === 0) {
11
+ writeFailure('BOARD_DIR and CARDS (array) are required');
13
12
  }
14
13
 
15
- runBoardCli(['upsert-card', '--rg', boardDir, '--card-glob', cardsGlob]);
14
+ const baseRef = toFsRef(boardDir);
15
+
16
+ // Write all cards to the card store in one call
17
+ runCardStoreCliWithInput(
18
+ ['set', '--store-ref', baseRef],
19
+ JSON.stringify(cards),
20
+ );
21
+
22
+ // Upsert all cards at once
23
+ runBoardCli(['upsert-card', '--base-ref', baseRef, '--all']);
16
24
 
17
25
  writeResult({
18
- result: 'success',
19
- data: {
20
- board_dir: boardDir,
21
- cards_glob: cardsGlob,
22
- },
26
+ board_dir: boardDir,
27
+ cards_added: cards.length,
23
28
  });
24
29
  } catch (error) {
25
30
  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
  try {
6
6
  const input = await readStdinJson();
@@ -8,16 +8,17 @@ try {
8
8
 
9
9
  if (!boardDir) {
10
10
  writeFailure('BOARD_DIR is required');
11
- process.exit(0);
12
11
  }
13
12
 
14
- runBoardCli(['init', boardDir]);
13
+ runBoardCli([
14
+ 'init',
15
+ '--base-ref', toFsRef(boardDir),
16
+ '--card-store-ref', toFsRef(boardDir),
17
+ '--outputs-store-ref', toFsRef(boardDir),
18
+ ]);
15
19
  writeResult({
16
- result: 'success',
17
- data: {
18
- board_dir: boardDir,
19
- message: `initialized ${boardDir}`,
20
- },
20
+ board_dir: boardDir,
21
+ message: `initialized ${boardDir}`,
21
22
  });
22
23
  } catch (error) {
23
24
  const message = error instanceof Error ? error.message : String(error);
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readStdinJson, runBoardCli, toFsRef, writeFailure, writeResult } from './_board-cli.js';
4
+
5
+ function sleep(ms) {
6
+ return new Promise((resolve) => setTimeout(resolve, ms));
7
+ }
8
+
9
+ try {
10
+ const input = await readStdinJson();
11
+ const boardDir = String(input.BOARD_DIR ?? '').trim();
12
+ const expectedCardCount = Number(input.EXPECTED_CARD_COUNT ?? 0);
13
+ const timeoutMs = Number(input.TIMEOUT_MS ?? 30000);
14
+ const pollMs = Number(input.POLL_MS ?? 500);
15
+
16
+ if (!boardDir || expectedCardCount <= 0) {
17
+ writeFailure('BOARD_DIR and EXPECTED_CARD_COUNT are required');
18
+ }
19
+
20
+ const started = Date.now();
21
+
22
+ while (Date.now() - started < timeoutMs) {
23
+ const statusJson = runBoardCli(['status', '--base-ref', toFsRef(boardDir)], { capture: true });
24
+ let cards = [];
25
+ try {
26
+ cards = JSON.parse(statusJson)?.data?.cards ?? [];
27
+ } catch { /* ignore parse errors */ }
28
+
29
+ const completedCount = cards.filter(c => c.status === 'completed').length;
30
+
31
+ if (cards.length >= expectedCardCount && completedCount >= expectedCardCount) {
32
+ writeResult({
33
+ all_completed: true,
34
+ card_count: cards.length,
35
+ completed_count: completedCount,
36
+ });
37
+ process.exit(0);
38
+ }
39
+
40
+ await sleep(pollMs);
41
+ }
42
+
43
+ // Timeout — exit non-zero
44
+ process.stderr.write(`timed out waiting for ${expectedCardCount} cards to complete`);
45
+ process.exit(1);
46
+ } catch (error) {
47
+ const message = error instanceof Error ? error.message : String(error);
48
+ writeFailure(message);
49
+ }
@@ -10,18 +10,14 @@ try {
10
10
 
11
11
  if (!boardDirInput) {
12
12
  writeFailure('BOARD_DIR is required');
13
- process.exit(0);
14
13
  }
15
14
 
16
15
  const boardDir = path.resolve(boardDirInput);
17
16
  fs.rmSync(boardDir, { recursive: true, force: true });
18
17
 
19
18
  writeResult({
20
- result: 'success',
21
- data: {
22
- board_dir: boardDir,
23
- reset: true,
24
- },
19
+ board_dir: boardDir,
20
+ reset: true,
25
21
  });
26
22
  } catch (error) {
27
23
  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
  try {
6
6
  const input = await readStdinJson();
@@ -9,17 +9,13 @@ try {
9
9
 
10
10
  if (!boardDir || !task) {
11
11
  writeFailure('BOARD_DIR and TASK are required');
12
- process.exit(0);
13
12
  }
14
13
 
15
- runBoardCli(['retrigger', '--rg', boardDir, '--task', task]);
14
+ runBoardCli(['retrigger', '--base-ref', toFsRef(boardDir), '--id', task]);
16
15
 
17
16
  writeResult({
18
- result: 'success',
19
- data: {
20
- task,
21
- retriggered: true,
22
- },
17
+ task,
18
+ retriggered: true,
23
19
  });
24
20
  } catch (error) {
25
21
  const message = error instanceof Error ? error.message : String(error);