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,300 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * portfolio-tracker-server.js
4
+ *
5
+ * Minimal single-board HTTP server for the portfolio-tracker example.
6
+ * Uses createSingleBoardServerRuntime from yaml-flow/server-runtime.
7
+ *
8
+ * Cards are seeded inline on first start (if the card store is empty).
9
+ * Task executor: portfolio-tracker-fetch-prices.js (mock-quotes source kind).
10
+ *
11
+ * Usage:
12
+ * node portfolio-tracker-server.js [--port 7800] [--reset]
13
+ *
14
+ * Endpoints (all under /api/board):
15
+ * GET /api/board/init-board
16
+ * GET /api/board/sse
17
+ * GET /api/board/board-status
18
+ * PATCH /api/board/cards/:id
19
+ * POST /api/board/cards/:id/actions
20
+ */
21
+
22
+ import http from 'node:http';
23
+ import fs from 'node:fs';
24
+ import path from 'node:path';
25
+ import os from 'node:os';
26
+ import net from 'node:net';
27
+ import { spawn } from 'node:child_process';
28
+ import { fileURLToPath } from 'node:url';
29
+
30
+ import { createSingleBoardServerRuntime } from 'yaml-flow/server-runtime';
31
+ import {
32
+ createFsBoardPlatformAdapter,
33
+ parseRef,
34
+ serializeRef,
35
+ } from 'yaml-flow/board-live-cards-node';
36
+
37
+ const __filename = fileURLToPath(import.meta.url);
38
+ const __dirname = path.dirname(__filename);
39
+ const args = process.argv.slice(2);
40
+ const portIdx = args.indexOf('--port');
41
+ const PORT = portIdx >= 0 ? Number(args[portIdx + 1]) : 7800;
42
+ const RESET = args.includes('--reset');
43
+
44
+ // ── Paths ──────────────────────────────────────────────────────────────────────
45
+ const SETUP_DIR = path.join(os.tmpdir(), 'portfolio-tracker-server');
46
+ const RUNTIME_DIR = path.join(SETUP_DIR, 'runtime');
47
+ const CARDS_DIR = path.join(SETUP_DIR, 'cards');
48
+ const OUTPUTS_DIR = path.join(SETUP_DIR, 'outputs');
49
+ const FETCH_PRICES_JS = path.join(__dirname, 'portfolio-tracker-fetch-prices.js');
50
+
51
+ if (RESET && fs.existsSync(SETUP_DIR)) {
52
+ fs.rmSync(SETUP_DIR, { recursive: true, force: true });
53
+ console.log(`[portfolio-tracker-server] reset: wiped ${SETUP_DIR}`);
54
+ }
55
+ for (const d of [RUNTIME_DIR, CARDS_DIR, OUTPUTS_DIR]) {
56
+ fs.mkdirSync(d, { recursive: true });
57
+ }
58
+
59
+ // ── Card definitions ───────────────────────────────────────────────────────────
60
+ const INITIAL_HOLDINGS = [
61
+ { symbol: 'AAPL', qty: 50 },
62
+ { symbol: 'MSFT', qty: 30 },
63
+ ];
64
+
65
+ const INLINE_CARDS = [
66
+ {
67
+ id: 'portfolio-form',
68
+ meta: { title: 'Portfolio Holdings Form' },
69
+ provides: [{ bindTo: 'holdings', ref: 'card_data.holdings' }],
70
+ card_data: { holdings: INITIAL_HOLDINGS },
71
+ view: {
72
+ elements: [
73
+ { kind: 'table', label: 'Holdings',
74
+ data: { bind: 'card_data.holdings', columns: ['symbol', 'qty'] } },
75
+ ],
76
+ },
77
+ },
78
+ {
79
+ id: 'price-fetch',
80
+ meta: { title: 'Fetch Market Prices' },
81
+ requires: ['holdings'],
82
+ provides: [{ bindTo: 'prices', ref: 'computed_values.prices' }],
83
+ card_data: {},
84
+ compute: [
85
+ {
86
+ bindTo: 'prices',
87
+ expr: '$merge($map(requires.holdings, function($h){ { $h.symbol: 100 } }))',
88
+ },
89
+ ],
90
+ view: {
91
+ elements: [
92
+ { kind: 'table', label: 'Market Prices',
93
+ data: { bind: 'computed_values.prices' } },
94
+ ],
95
+ },
96
+ },
97
+ {
98
+ id: 'holdings-table',
99
+ meta: { title: 'Holdings Table' },
100
+ requires: ['holdings', 'prices'],
101
+ provides: [{ bindTo: 'table', ref: 'computed_values.table' }],
102
+ card_data: {},
103
+ compute: [{
104
+ bindTo: 'table',
105
+ expr: '{ "rows": $map(requires.holdings, function($h) { { "symbol": $h.symbol, "qty": $h.qty, "price": $lookup(requires.prices, $h.symbol), "value": $h.qty * $lookup(requires.prices, $h.symbol) } }) }',
106
+ }],
107
+ view: {
108
+ elements: [
109
+ { kind: 'table', label: 'Portfolio Positions',
110
+ data: { bind: 'computed_values.table.rows', columns: ['symbol', 'qty', 'price', 'value'] } },
111
+ ],
112
+ },
113
+ },
114
+ {
115
+ id: 'portfolio-value',
116
+ meta: { title: 'Portfolio Total Value' },
117
+ requires: ['table'],
118
+ provides: [{ bindTo: 'totalValue', ref: 'computed_values.totalValue' }],
119
+ card_data: {},
120
+ compute: [
121
+ { bindTo: 'totalValue', expr: '$sum(requires.table.rows.value)' },
122
+ ],
123
+ view: {
124
+ elements: [
125
+ { kind: 'metric', label: 'Total Portfolio Value',
126
+ data: { bind: 'computed_values.totalValue' } },
127
+ ],
128
+ },
129
+ },
130
+ ];
131
+
132
+ // ── Host adapters ──────────────────────────────────────────────────────────────
133
+ const NOTIFY_CHANNEL = `yaml-flow-pt-server-${process.pid}`;
134
+
135
+ function namedPipePath(name) {
136
+ if (process.platform === 'win32') return `\\\\.\\pipe\\${name}`;
137
+ return path.join(os.tmpdir(), `${name}.sock`);
138
+ }
139
+
140
+ function createNodeSpawnInvocationAdapter() {
141
+ return {
142
+ async invoke(ref, invokeArgs) {
143
+ if (ref.howToRun !== 'local-node') {
144
+ return { dispatched: false, error: `unsupported howToRun: ${ref.howToRun}` };
145
+ }
146
+ const whatToRun = String(ref.whatToRun || '');
147
+ let scriptPath = '';
148
+ if (whatToRun.startsWith('b64:')) {
149
+ try {
150
+ const parsed = parseRef(whatToRun);
151
+ if (parsed.kind === 'fs-path') scriptPath = parsed.value;
152
+ } catch {
153
+ scriptPath = '';
154
+ }
155
+ } else {
156
+ scriptPath = whatToRun;
157
+ }
158
+ if (!scriptPath) return { dispatched: false, error: 'no script path' };
159
+ const extra = Buffer.from(JSON.stringify(invokeArgs)).toString('base64');
160
+ try {
161
+ const proc = spawn(process.execPath, [
162
+ scriptPath,
163
+ '--boardId', String(invokeArgs.boardId || ''),
164
+ '--cardId', String(invokeArgs.cardId || ''),
165
+ '--extraEncJson', extra,
166
+ ], { stdio: 'ignore', windowsHide: true });
167
+ proc.unref();
168
+ return { dispatched: true };
169
+ } catch (err) {
170
+ return { dispatched: false, error: err?.message || String(err) };
171
+ }
172
+ },
173
+ };
174
+ }
175
+
176
+ function createNamedPipeNotificationTransport() {
177
+ return {
178
+ async subscribe(ref, onEvent) {
179
+ if (ref.kind !== 'named-pipe') return () => {};
180
+ const pipePath = ref.value;
181
+ if (process.platform !== 'win32' && fs.existsSync(pipePath)) {
182
+ try { fs.rmSync(pipePath, { force: true }); } catch { /* best-effort */ }
183
+ }
184
+ const server = net.createServer((socket) => {
185
+ let buf = '';
186
+ socket.on('data', (chunk) => {
187
+ buf += chunk.toString('utf-8');
188
+ while (true) {
189
+ const i = buf.indexOf('\n');
190
+ if (i < 0) break;
191
+ const line = buf.slice(0, i).trim();
192
+ buf = buf.slice(i + 1);
193
+ if (!line) continue;
194
+ try {
195
+ const msg = JSON.parse(line);
196
+ onEvent(msg?.notification ?? msg);
197
+ } catch { /* ignore malformed lines */ }
198
+ }
199
+ });
200
+ });
201
+ await new Promise((resolve, reject) => {
202
+ server.once('error', reject);
203
+ server.listen(pipePath, () => resolve());
204
+ });
205
+ return () => {
206
+ server.close();
207
+ if (process.platform !== 'win32') {
208
+ try { fs.rmSync(pipePath, { force: true }); } catch { /* best-effort */ }
209
+ }
210
+ };
211
+ },
212
+ };
213
+ }
214
+
215
+ // ── Board adapter ──────────────────────────────────────────────────────────────
216
+ // cliDir must point to the yaml-flow root so buildBoardCliInvocation finds
217
+ // board-live-cards-cli.js there (used to build selfRef for task executor callbacks).
218
+ // __dirname here is examples/browser/boards/portfolio-tracker — 4 levels up = yaml-flow root.
219
+ const YAML_FLOW_CLI_DIR = path.resolve(__dirname, '..', '..', '..', '..');
220
+ const baseRef = parseRef(serializeRef({ kind: 'fs-path', value: RUNTIME_DIR }));
221
+ const boardAdapter = createFsBoardPlatformAdapter(baseRef, YAML_FLOW_CLI_DIR, { notifyChannel: NOTIFY_CHANNEL });
222
+ // In the server context the drain loop is driven in-process.
223
+ boardAdapter.requestProcessAccumulated = () => {};
224
+
225
+ const cardStoreRef = serializeRef({ kind: 'fs-path', value: path.join(CARDS_DIR, 'cards') });
226
+ const outputsStoreRef = serializeRef({ kind: 'fs-path', value: path.join(OUTPUTS_DIR, '.outputs') });
227
+ const notifyRef = { kind: 'named-pipe', value: namedPipePath(NOTIFY_CHANNEL) };
228
+ const taskExecutorRef = {
229
+ howToRun: 'local-node',
230
+ whatToRun: serializeRef({ kind: 'fs-path', value: FETCH_PRICES_JS }),
231
+ meta: 'task-executor',
232
+ };
233
+
234
+ // ── Runtime ────────────────────────────────────────────────────────────────────
235
+ const runtime = createSingleBoardServerRuntime({
236
+ apiBasePath: '/api/board',
237
+ boardId: 'portfolio-tracker',
238
+ boards: [{
239
+ label: 'portfolio-tracker',
240
+ boardAdapter,
241
+ baseRef,
242
+ cardStoreRef,
243
+ outputsStoreRef,
244
+ notifyRef,
245
+ taskExecutorRef,
246
+ }],
247
+ invocationAdapter: createNodeSpawnInvocationAdapter(),
248
+ notificationTransport: createNamedPipeNotificationTransport(),
249
+ logger: { info: console.log, warn: console.warn, error: console.error },
250
+ serverUrl: `http://127.0.0.1:${PORT}`,
251
+ });
252
+
253
+ // ── Card store seeding ─────────────────────────────────────────────────────────
254
+ const existing = runtime.cardStore.get({});
255
+ const isEmpty = existing.status !== 'success' || !existing.data?.cards?.length;
256
+ if (isEmpty) {
257
+ runtime.cardStore.set({ body: INLINE_CARDS });
258
+ console.log(`[portfolio-tracker-server] seeded ${INLINE_CARDS.length} cards into card store`);
259
+ } else {
260
+ console.log(`[portfolio-tracker-server] card store already populated (${existing.data.cards.length} cards)`);
261
+ }
262
+
263
+ // ── HTTP server ────────────────────────────────────────────────────────────────
264
+ const CORS_HEADERS = {
265
+ 'Access-Control-Allow-Origin': '*',
266
+ 'Access-Control-Allow-Headers': 'content-type,x-file-name',
267
+ 'Access-Control-Allow-Methods': 'GET,POST,PATCH,OPTIONS',
268
+ };
269
+
270
+ const server = http.createServer((req, res) => {
271
+ const method = req.method || 'GET';
272
+ const url = new URL(req.url || '/', `http://127.0.0.1:${PORT}`);
273
+
274
+ if (method === 'OPTIONS') {
275
+ res.writeHead(204, CORS_HEADERS);
276
+ res.end();
277
+ return;
278
+ }
279
+
280
+ runtime.handleRuntimeApi(req, res, url).then((handled) => {
281
+ if (!handled) {
282
+ res.writeHead(404, { 'Content-Type': 'application/json' });
283
+ res.end(JSON.stringify({ error: 'Not found' }));
284
+ }
285
+ }).catch((err) => {
286
+ res.writeHead(500, { 'Content-Type': 'application/json' });
287
+ res.end(JSON.stringify({ error: String(err?.message || err) }));
288
+ });
289
+ });
290
+
291
+ server.listen(PORT, '127.0.0.1', () => {
292
+ console.log(`[portfolio-tracker-server] listening on http://127.0.0.1:${PORT}`);
293
+ console.log(`[portfolio-tracker-server] runtime dir: ${RUNTIME_DIR}`);
294
+ console.log(`[portfolio-tracker-server] endpoints:`);
295
+ console.log(` GET /api/board/init-board`);
296
+ console.log(` GET /api/board/sse`);
297
+ console.log(` GET /api/board/board-status`);
298
+ console.log(` PATCH /api/board/cards/:id`);
299
+ console.log(` POST /api/board/cards/:id/actions`);
300
+ });