yaml-flow 7.0.0 → 8.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 (393) hide show
  1. package/browser/asset-integrity.json +8 -4
  2. package/browser/board-livecards-client.js +1 -1
  3. package/browser/board-livecards-localstorage.js +5 -5
  4. package/browser/live-cards.js +19 -3307
  5. package/cli/board-live-cards-lib-tjYsPt5U.d.ts +321 -0
  6. package/{dist/cli → cli}/browser-api/board-live-cards-browser-adapter.d.ts +3 -5
  7. package/cli/browser-api/board-live-cards-browser-adapter.js +3 -0
  8. package/{dist/cli → cli}/browser-api/card-store-browser-api.d.ts +1 -2
  9. package/{dist/cli → cli}/browser-api/card-store-browser-api.js +1 -1
  10. package/cli/execution-interface-C_A6WCiK.d.ts +284 -0
  11. package/cli/node/artifacts-store-cli.js +11 -0
  12. package/cli/node/batch-runner-cli.js +3 -0
  13. package/cli/node/board-live-cards-cli.js +15 -0
  14. package/cli/node/card-store-cli.js +8 -0
  15. package/{dist/cli → cli}/node/execution-adapter.d.ts +3 -3
  16. package/cli/node/execution-adapter.js +3 -0
  17. package/{dist/cli → cli}/node/fs-board-adapter.d.ts +24 -11
  18. package/cli/node/fs-board-adapter.js +14 -0
  19. package/{dist/cli → cli}/node/source-cli-task-executor.js +2 -2
  20. package/cli/node/step-machine-cli.d.ts +7 -0
  21. package/cli/node/step-machine-cli.js +5 -0
  22. package/{dist/board-live-cards-public-CW5074xr.d.cts → cli/types-CziUxkiv.d.ts} +69 -7
  23. package/examples/board/.demo-setup/run-1778643703151-3360-dopnpv/board-default/gandalf-runtime/.config/card-store-ref.json +1 -0
  24. package/examples/board/.demo-setup/run-1778643703151-3360-dopnpv/board-default/gandalf-runtime/.config/chat-handler.json +1 -0
  25. package/examples/board/.demo-setup/run-1778643703151-3360-dopnpv/board-default/gandalf-runtime/.config/outputs-store-ref.json +1 -0
  26. package/examples/board/.demo-setup/run-1778643703151-3360-dopnpv/board-default/gandalf-runtime/.config/task-executor.json +1 -0
  27. package/examples/board/.demo-setup/run-1778643703151-3360-dopnpv/board-default/gandalf-runtime/.state-snapshot/board/graph.json +29 -0
  28. package/examples/board/.demo-setup/run-1778643703151-3360-dopnpv/board-default/gandalf-runtime/.state-snapshot/board/lastJournalProcessedId.json +1 -0
  29. package/examples/board/.demo-setup/run-1778643703151-3360-dopnpv/board-default/gandalf-runtime-out/.outputs/status.json +25 -0
  30. package/examples/board/.demo-setup/run-1778643703151-3360-dopnpv/board-default/runtime-out/.outputs/cards/card-market-prices/computed_values.json +67 -0
  31. package/examples/board/.demo-setup/run-1778643703151-3360-dopnpv/board-default/runtime-out/.outputs/cards/card-portfolio/computed_values.json +1 -0
  32. package/examples/board/.demo-setup/run-1778643703151-3360-dopnpv/board-default/runtime-out/.outputs/cards/card-portfolio-value/computed_values.json +52 -0
  33. package/examples/board/.demo-setup/run-1778643703151-3360-dopnpv/board-default/runtime-out/.outputs/data-objects/holdings.json +22 -0
  34. package/examples/board/.demo-setup/run-1778643703151-3360-dopnpv/board-default/runtime-out/.outputs/data-objects/positions.json +46 -0
  35. package/examples/board/.demo-setup/run-1778643703151-3360-dopnpv/board-default/runtime-out/.outputs/data-objects/quotes.json +35 -0
  36. package/examples/board/.demo-setup/run-1778643703151-3360-dopnpv/board-default/runtime-out/.outputs/status.json +113 -0
  37. package/examples/{example-board/cards/card-market-prices.json → board/cards/cardT-market-prices.json} +2 -2
  38. package/examples/{example-board/cards/card-portfolio.json → board/cards/cardT-portfolio.json} +3 -13
  39. package/examples/{example-board → board}/demo-server-config.json +0 -1
  40. package/examples/{example-board → board}/demo-server.js +70 -72
  41. package/examples/{example-board → board}/demo-shell-with-server.html +3 -3
  42. package/examples/{example-board → board}/demo-task-executor.js +75 -32
  43. package/examples/board/gandalf-cards/card-source-kinds.json +36 -0
  44. package/examples/board/gandalf-cards/cards/_index.json +7 -0
  45. package/examples/board/gandalf-cards/cards/card-source-kinds.json +64 -0
  46. package/examples/board/source-def-flows/copilot.flow.json +33 -0
  47. package/examples/board/source-def-flows/mock.flow.json +35 -0
  48. package/examples/board/source-def-flows/url-list.flow.json +33 -0
  49. package/examples/board/source-def-flows/url.flow.json +33 -0
  50. package/examples/board/source-def-flows/workiq.flow.json +34 -0
  51. package/examples/board/source-def-handlers/copilot-source-handler.js +141 -0
  52. package/examples/board/source-def-handlers/http-source-handler.js +145 -0
  53. package/examples/board/source_def_flows.json +249 -0
  54. package/examples/board/test/demo-http-test.js +317 -0
  55. package/examples/{example-board → board-local}/demo-shell-localstorage.html +4 -4
  56. package/examples/{browser/boards/portfolio-tracker → portfolio-tracker/handlers}/portfolio-tracker-fetch-prices.js +1 -1
  57. package/examples/{browser/boards/portfolio-tracker/portfolio-tracker-public.js → portfolio-tracker/portfolio-tracker.js} +11 -14
  58. package/examples/{browser/boards/portfolio-tracker → portfolio-tracker/test}/portfolio-t4.js +32 -50
  59. package/lib/artifacts-store-lib-public-BABrgFkV.d.ts +119 -0
  60. package/lib/artifacts-store-lib-public-DGa8BpJT.d.cts +119 -0
  61. package/lib/artifacts-store-public.cjs +2 -0
  62. package/lib/artifacts-store-public.d.cts +5 -0
  63. package/lib/artifacts-store-public.d.ts +5 -0
  64. package/lib/artifacts-store-public.js +2 -0
  65. package/lib/board-live-cards-node.cjs +14 -0
  66. package/{dist/cli/node/execution-adapter.d.cts → lib/board-live-cards-node.d.cts} +45 -85
  67. package/lib/board-live-cards-node.d.ts +134 -0
  68. package/lib/board-live-cards-node.js +14 -0
  69. package/lib/board-live-cards-public-BnmRAbQV.d.cts +383 -0
  70. package/{dist/board-live-cards-public-hnZo0mAf.d.ts → lib/board-live-cards-public-CsmYrvpd.d.ts} +142 -77
  71. package/lib/board-live-cards-public.cjs +3 -0
  72. package/lib/board-live-cards-public.d.cts +4 -0
  73. package/lib/board-live-cards-public.d.ts +4 -0
  74. package/lib/board-live-cards-public.js +3 -0
  75. package/lib/board-live-cards-server-runtime.cjs +9 -0
  76. package/lib/board-live-cards-server-runtime.d.cts +6 -0
  77. package/lib/board-live-cards-server-runtime.d.ts +6 -0
  78. package/lib/board-live-cards-server-runtime.js +9 -0
  79. package/lib/board-livegraph-runtime/index.cjs +3 -0
  80. package/{dist → lib}/board-livegraph-runtime/index.d.cts +1 -2
  81. package/{dist → lib}/board-livegraph-runtime/index.d.ts +1 -2
  82. package/lib/board-livegraph-runtime/index.js +3 -0
  83. package/lib/board-worker-adapter.cjs +10 -0
  84. package/{dist/storage-refs.d.cts → lib/board-worker-adapter.d.cts} +5 -5
  85. package/{dist/storage-refs.d.ts → lib/board-worker-adapter.d.ts} +5 -5
  86. package/lib/board-worker-adapter.js +10 -0
  87. package/{dist → lib}/card-compute/index.cjs +1 -1
  88. package/{dist → lib}/card-compute/index.js +1 -1
  89. package/lib/card-store-public.cjs +2 -0
  90. package/lib/card-store-public.d.cts +61 -0
  91. package/lib/card-store-public.d.ts +61 -0
  92. package/lib/card-store-public.js +2 -0
  93. package/lib/card-validation.cjs +10 -0
  94. package/lib/card-validation.d.cts +35 -0
  95. package/lib/card-validation.d.ts +35 -0
  96. package/lib/card-validation.js +10 -0
  97. package/{dist/constants-oCEbNpul.d.ts → lib/constants-BPVLb3Es.d.ts} +1 -1
  98. package/{dist/constants-BzZUyYlp.d.cts → lib/constants-DXxsRN9y.d.cts} +1 -1
  99. package/{dist → lib}/continuous-event-graph/index.cjs +2 -2
  100. package/{dist → lib}/continuous-event-graph/index.d.cts +3 -5
  101. package/{dist → lib}/continuous-event-graph/index.d.ts +3 -5
  102. package/{dist → lib}/continuous-event-graph/index.js +2 -2
  103. package/{dist → lib}/event-graph/index.d.cts +2 -2
  104. package/{dist → lib}/event-graph/index.d.ts +2 -2
  105. package/lib/execution-refs.cjs +3 -0
  106. package/{dist → lib}/execution-refs.d.cts +38 -14
  107. package/{dist → lib}/execution-refs.d.ts +38 -14
  108. package/lib/execution-refs.js +3 -0
  109. package/lib/index.cjs +25 -0
  110. package/{dist → lib}/index.d.cts +7 -8
  111. package/{dist → lib}/index.d.ts +7 -8
  112. package/lib/index.js +25 -0
  113. package/{dist/live-cards-bridge-BXbVTsna.d.cts → lib/live-cards-bridge-DC_ZU0eS.d.ts} +134 -3
  114. package/{dist/live-cards-bridge-Ds28XR15.d.ts → lib/live-cards-bridge-b25aAVvE.d.cts} +134 -3
  115. package/lib/loader-CuuLjxVA.d.cts +42 -0
  116. package/lib/loader-Zborm2pq.d.ts +42 -0
  117. package/lib/server-runtime/index.cjs +9 -0
  118. package/{dist → lib}/server-runtime/index.d.cts +4 -4
  119. package/{dist → lib}/server-runtime/index.d.ts +4 -4
  120. package/lib/server-runtime/index.js +9 -0
  121. package/lib/step-machine/index.d.cts +64 -0
  122. package/lib/step-machine/index.d.ts +64 -0
  123. package/lib/step-machine-public/index.cjs +5 -0
  124. package/{dist → lib}/step-machine-public/index.d.cts +21 -1
  125. package/{dist → lib}/step-machine-public/index.d.ts +21 -1
  126. package/lib/step-machine-public/index.js +5 -0
  127. package/lib/storage-interface-BhAON-gW.d.cts +84 -0
  128. package/lib/storage-interface-BhAON-gW.d.ts +84 -0
  129. package/lib/stores/index.cjs +3 -0
  130. package/lib/stores/index.d.cts +4 -0
  131. package/lib/stores/index.d.ts +4 -0
  132. package/lib/stores/index.js +3 -0
  133. package/lib/stores/kv.cjs +3 -0
  134. package/lib/stores/kv.d.cts +32 -0
  135. package/lib/stores/kv.d.ts +32 -0
  136. package/lib/stores/kv.js +3 -0
  137. package/{dist → lib}/stores/memory.d.cts +1 -1
  138. package/{dist → lib}/stores/memory.d.ts +1 -1
  139. package/{dist/types-B1ZRa4aI.d.ts → lib/types-CBxkYuLY.d.ts} +2 -1
  140. package/{dist/types-ycun84cq.d.cts → lib/types-DQ1bKuB1.d.cts} +11 -0
  141. package/{dist/types-ycun84cq.d.ts → lib/types-DQ1bKuB1.d.ts} +11 -0
  142. package/{dist/types-BxEFcVK9.d.cts → lib/types-DkFvgxwq.d.cts} +2 -1
  143. package/package.json +79 -119
  144. package/board-live-cards-cli.js +0 -37
  145. package/browser/board-livecards-client.js.map +0 -1
  146. package/browser/board-livecards-localstorage.js.map +0 -1
  147. package/browser/board-livegraph-engine.js +0 -3
  148. package/browser/board-livegraph-engine.js.map +0 -1
  149. package/browser/card-compute.js +0 -266
  150. package/browser/compute-jsonata.js.map +0 -1
  151. package/card-store.js +0 -37
  152. package/dist/batch/index.cjs.map +0 -1
  153. package/dist/batch/index.js.map +0 -1
  154. package/dist/board-live-cards-lib-Bg6EvCo5.d.cts +0 -136
  155. package/dist/board-live-cards-lib-jM2uYG1v.d.ts +0 -136
  156. package/dist/board-livegraph-runtime/index.cjs +0 -3
  157. package/dist/board-livegraph-runtime/index.cjs.map +0 -1
  158. package/dist/board-livegraph-runtime/index.js +0 -3
  159. package/dist/board-livegraph-runtime/index.js.map +0 -1
  160. package/dist/card-compute/index.cjs.map +0 -1
  161. package/dist/card-compute/index.js.map +0 -1
  162. package/dist/cli/browser-api/board-live-cards-browser-adapter.cjs +0 -3
  163. package/dist/cli/browser-api/board-live-cards-browser-adapter.cjs.map +0 -1
  164. package/dist/cli/browser-api/board-live-cards-browser-adapter.d.cts +0 -37
  165. package/dist/cli/browser-api/board-live-cards-browser-adapter.js +0 -3
  166. package/dist/cli/browser-api/board-live-cards-browser-adapter.js.map +0 -1
  167. package/dist/cli/browser-api/card-store-browser-api.cjs +0 -2
  168. package/dist/cli/browser-api/card-store-browser-api.cjs.map +0 -1
  169. package/dist/cli/browser-api/card-store-browser-api.d.cts +0 -26
  170. package/dist/cli/browser-api/card-store-browser-api.js.map +0 -1
  171. package/dist/cli/node/artifacts-store-cli.cjs +0 -11
  172. package/dist/cli/node/artifacts-store-cli.cjs.map +0 -1
  173. package/dist/cli/node/artifacts-store-cli.d.cts +0 -8
  174. package/dist/cli/node/artifacts-store-cli.js +0 -11
  175. package/dist/cli/node/artifacts-store-cli.js.map +0 -1
  176. package/dist/cli/node/board-live-cards-cli.cjs +0 -15
  177. package/dist/cli/node/board-live-cards-cli.cjs.map +0 -1
  178. package/dist/cli/node/board-live-cards-cli.d.cts +0 -20
  179. package/dist/cli/node/board-live-cards-cli.js +0 -15
  180. package/dist/cli/node/board-live-cards-cli.js.map +0 -1
  181. package/dist/cli/node/card-store-cli.cjs +0 -8
  182. package/dist/cli/node/card-store-cli.cjs.map +0 -1
  183. package/dist/cli/node/card-store-cli.d.cts +0 -15
  184. package/dist/cli/node/card-store-cli.js +0 -8
  185. package/dist/cli/node/card-store-cli.js.map +0 -1
  186. package/dist/cli/node/execution-adapter.cjs +0 -3
  187. package/dist/cli/node/execution-adapter.cjs.map +0 -1
  188. package/dist/cli/node/execution-adapter.js +0 -3
  189. package/dist/cli/node/execution-adapter.js.map +0 -1
  190. package/dist/cli/node/fs-board-adapter.cjs +0 -14
  191. package/dist/cli/node/fs-board-adapter.cjs.map +0 -1
  192. package/dist/cli/node/fs-board-adapter.d.cts +0 -204
  193. package/dist/cli/node/fs-board-adapter.js +0 -14
  194. package/dist/cli/node/fs-board-adapter.js.map +0 -1
  195. package/dist/cli/node/source-cli-task-executor.cjs +0 -11
  196. package/dist/cli/node/source-cli-task-executor.cjs.map +0 -1
  197. package/dist/cli/node/source-cli-task-executor.js.map +0 -1
  198. package/dist/config/index.cjs.map +0 -1
  199. package/dist/config/index.js.map +0 -1
  200. package/dist/continuous-event-graph/index.cjs.map +0 -1
  201. package/dist/continuous-event-graph/index.js.map +0 -1
  202. package/dist/event-graph/index.cjs.map +0 -1
  203. package/dist/event-graph/index.js.map +0 -1
  204. package/dist/execution-refs.cjs +0 -3
  205. package/dist/execution-refs.cjs.map +0 -1
  206. package/dist/execution-refs.js +0 -3
  207. package/dist/execution-refs.js.map +0 -1
  208. package/dist/index.cjs +0 -30
  209. package/dist/index.cjs.map +0 -1
  210. package/dist/index.js +0 -30
  211. package/dist/index.js.map +0 -1
  212. package/dist/inference/index.cjs +0 -7
  213. package/dist/inference/index.cjs.map +0 -1
  214. package/dist/inference/index.d.cts +0 -229
  215. package/dist/inference/index.d.ts +0 -229
  216. package/dist/inference/index.js +0 -7
  217. package/dist/inference/index.js.map +0 -1
  218. package/dist/server-runtime/index.cjs +0 -9
  219. package/dist/server-runtime/index.cjs.map +0 -1
  220. package/dist/server-runtime/index.js +0 -9
  221. package/dist/server-runtime/index.js.map +0 -1
  222. package/dist/step-machine/index.cjs.map +0 -1
  223. package/dist/step-machine/index.d.cts +0 -102
  224. package/dist/step-machine/index.d.ts +0 -102
  225. package/dist/step-machine/index.js.map +0 -1
  226. package/dist/step-machine-public/index.cjs +0 -2
  227. package/dist/step-machine-public/index.cjs.map +0 -1
  228. package/dist/step-machine-public/index.js +0 -2
  229. package/dist/step-machine-public/index.js.map +0 -1
  230. package/dist/storage-refs.cjs +0 -10
  231. package/dist/storage-refs.cjs.map +0 -1
  232. package/dist/storage-refs.js +0 -10
  233. package/dist/storage-refs.js.map +0 -1
  234. package/dist/stores/file.cjs +0 -2
  235. package/dist/stores/file.cjs.map +0 -1
  236. package/dist/stores/file.d.cts +0 -36
  237. package/dist/stores/file.d.ts +0 -36
  238. package/dist/stores/file.js +0 -2
  239. package/dist/stores/file.js.map +0 -1
  240. package/dist/stores/index.cjs +0 -2
  241. package/dist/stores/index.cjs.map +0 -1
  242. package/dist/stores/index.d.cts +0 -4
  243. package/dist/stores/index.d.ts +0 -4
  244. package/dist/stores/index.js +0 -2
  245. package/dist/stores/index.js.map +0 -1
  246. package/dist/stores/localStorage.cjs +0 -2
  247. package/dist/stores/localStorage.cjs.map +0 -1
  248. package/dist/stores/localStorage.d.cts +0 -34
  249. package/dist/stores/localStorage.d.ts +0 -34
  250. package/dist/stores/localStorage.js +0 -2
  251. package/dist/stores/localStorage.js.map +0 -1
  252. package/dist/stores/memory.cjs.map +0 -1
  253. package/dist/stores/memory.js.map +0 -1
  254. package/dist/types-CHSdoAAA.d.cts +0 -135
  255. package/dist/types-CoW0gQl3.d.ts +0 -135
  256. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-fetch-prices.py +0 -201
  257. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-http-test.js +0 -357
  258. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-inference-adapter.js +0 -196
  259. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-server.js +0 -300
  260. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-server.py +0 -617
  261. package/examples/browser/boards/portfolio-tracker/portfolio-tracker.py +0 -366
  262. package/examples/browser/livecards-browser/index.html +0 -41
  263. package/examples/browser/step-machine-browser/index.html +0 -367
  264. package/examples/cli/step-machine-cli/portfolio-tracker/--base-ref/.runtime-out +0 -1
  265. package/examples/cli/step-machine-cli/portfolio-tracker/--base-ref/board-graph.json +0 -32
  266. package/examples/cli/step-machine-cli/portfolio-tracker/cards/holdings-table.json +0 -22
  267. package/examples/cli/step-machine-cli/portfolio-tracker/cards/portfolio-form.json +0 -43
  268. package/examples/cli/step-machine-cli/portfolio-tracker/cards/portfolio-value.json +0 -15
  269. package/examples/cli/step-machine-cli/portfolio-tracker/cards/price-fetch.json +0 -15
  270. package/examples/cli/step-machine-cli/portfolio-tracker/fetch-prices.js +0 -48
  271. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/_board-cli.js +0 -125
  272. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/add-cards-cli.js +0 -32
  273. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/init-board-cli.js +0 -26
  274. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/poll-status-cli.js +0 -49
  275. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/reset-board-dir-cli.js +0 -25
  276. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/retrigger-cli.js +0 -23
  277. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/status-cli.js +0 -21
  278. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/update-holdings-cli.js +0 -38
  279. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/wait-completed-cli.js +0 -48
  280. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/write-prices-cli.js +0 -31
  281. package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/_board_pycli.py +0 -107
  282. package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/add-cards.py +0 -51
  283. package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/init-board.py +0 -45
  284. package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/poll-status.py +0 -71
  285. package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/reset-board-dir.py +0 -36
  286. package/examples/cli/step-machine-cli/portfolio-tracker/inline-python-demo.flow.yaml +0 -26
  287. package/examples/cli/step-machine-cli/portfolio-tracker/inline-python-handlers.py +0 -39
  288. package/examples/cli/step-machine-cli/portfolio-tracker/portfolio-tracker-pycli.flow.yaml +0 -80
  289. package/examples/cli/step-machine-cli/portfolio-tracker/portfolio-tracker.flow.yaml +0 -76
  290. package/examples/cli/step-machine-cli/portfolio-tracker/portfolio-tracker.input.json +0 -44
  291. package/examples/cli/step-machine-cli/portfolio-tracker/run-inline-python-demo-pycli.py +0 -43
  292. package/examples/cli/step-machine-cli/portfolio-tracker/run-portfolio-tracker-pycli.py +0 -77
  293. package/examples/cli/step-machine-cli/portfolio-tracker/run-portfolio-tracker.bat +0 -28
  294. package/examples/cli/step-machine-demo/jsonata-init-board-cli.js +0 -31
  295. package/examples/cli/step-machine-demo/jsonata-init-board.flow.yaml +0 -54
  296. package/examples/cli/step-machine-demo/one-step-cli-only.flow.yaml +0 -21
  297. package/examples/cli/step-machine-demo/step-cli-echo-y.js +0 -15
  298. package/examples/cli/step-machine-demo/step2-double-cli.js +0 -33
  299. package/examples/cli/step-machine-demo/two-step-math.flow.yaml +0 -93
  300. package/examples/cli/step-machine-demo/two-step-mixed.flow.yaml +0 -43
  301. package/examples/example-board/agent-instructions-cardlayout.md +0 -56
  302. package/examples/example-board/agent-instructions.md +0 -834
  303. package/examples/example-board/cards/_index.json +0 -47
  304. package/examples/example-board/demo-shell.html +0 -63
  305. package/examples/index.html +0 -785
  306. package/examples/npm-libs/batch/batch-step-machine.ts +0 -121
  307. package/examples/npm-libs/continuous-event-graph/live-cards-board.ts +0 -215
  308. package/examples/npm-libs/continuous-event-graph/live-portfolio-dashboard.ts +0 -555
  309. package/examples/npm-libs/continuous-event-graph/portfolio-tracker.ts +0 -287
  310. package/examples/npm-libs/continuous-event-graph/reactive-monitoring.ts +0 -265
  311. package/examples/npm-libs/continuous-event-graph/reactive-pipeline.ts +0 -168
  312. package/examples/npm-libs/continuous-event-graph/soc-incident-board.ts +0 -287
  313. package/examples/npm-libs/continuous-event-graph/stock-dashboard.ts +0 -229
  314. package/examples/npm-libs/event-graph/ci-cd-pipeline.ts +0 -243
  315. package/examples/npm-libs/event-graph/executor-diamond.ts +0 -165
  316. package/examples/npm-libs/event-graph/executor-pipeline.ts +0 -161
  317. package/examples/npm-libs/event-graph/research-pipeline.ts +0 -137
  318. package/examples/npm-libs/flows/ai-conversation.yaml +0 -116
  319. package/examples/npm-libs/flows/order-processing.yaml +0 -143
  320. package/examples/npm-libs/flows/simple-greeting.yaml +0 -54
  321. package/examples/npm-libs/graph-of-graphs/multi-stage-etl.ts +0 -307
  322. package/examples/npm-libs/graph-of-graphs/url-processing-pipeline.ts +0 -254
  323. package/examples/npm-libs/inference/azure-deployment.ts +0 -149
  324. package/examples/npm-libs/inference/copilot-cli.ts +0 -138
  325. package/examples/npm-libs/inference/data-pipeline.ts +0 -145
  326. package/examples/npm-libs/inference/pluggable-adapters.ts +0 -254
  327. package/examples/npm-libs/node/ai-conversation.ts +0 -195
  328. package/examples/npm-libs/node/simple-greeting.ts +0 -101
  329. package/examples/step-machine-cli/portfolio-tracker/cards/holdings-table.json +0 -22
  330. package/examples/step-machine-cli/portfolio-tracker/cards/portfolio-form.json +0 -43
  331. package/examples/step-machine-cli/portfolio-tracker/cards/portfolio-value.json +0 -15
  332. package/examples/step-machine-cli/portfolio-tracker/cards/price-fetch.json +0 -15
  333. package/examples/step-machine-cli/portfolio-tracker/fetch-prices.js +0 -48
  334. package/examples/step-machine-cli/portfolio-tracker/handlers/_board-cli.js +0 -57
  335. package/examples/step-machine-cli/portfolio-tracker/handlers/add-cards-cli.js +0 -27
  336. package/examples/step-machine-cli/portfolio-tracker/handlers/init-board-cli.js +0 -25
  337. package/examples/step-machine-cli/portfolio-tracker/handlers/reset-board-dir-cli.js +0 -29
  338. package/examples/step-machine-cli/portfolio-tracker/handlers/retrigger-cli.js +0 -27
  339. package/examples/step-machine-cli/portfolio-tracker/handlers/status-cli.js +0 -25
  340. package/examples/step-machine-cli/portfolio-tracker/handlers/update-holdings-cli.js +0 -37
  341. package/examples/step-machine-cli/portfolio-tracker/handlers/wait-completed-cli.js +0 -53
  342. package/examples/step-machine-cli/portfolio-tracker/handlers/write-prices-cli.js +0 -35
  343. package/examples/step-machine-cli/portfolio-tracker/portfolio-tracker-task-executor.cjs +0 -96
  344. package/examples/step-machine-cli/portfolio-tracker/portfolio-tracker.flow.yaml +0 -227
  345. package/examples/step-machine-cli/portfolio-tracker/portfolio-tracker.input.json +0 -38
  346. package/examples/step-machine-cli/portfolio-tracker/run-portfolio-tracker.bat +0 -28
  347. package/step-machine-cli.js +0 -407
  348. /package/{dist/board-livegraph-runtime → cli/browser-api}/jsonata-sync.cjs +0 -0
  349. /package/{dist/cli → cli}/node/artifacts-store-cli.d.ts +0 -0
  350. /package/{dist/cli/node/source-cli-task-executor.d.cts → cli/node/batch-runner-cli.d.ts} +0 -0
  351. /package/{dist/cli → cli}/node/board-live-cards-cli.d.ts +0 -0
  352. /package/{dist/cli → cli}/node/card-store-cli.d.ts +0 -0
  353. /package/{dist/card-compute → cli/node}/jsonata-sync.cjs +0 -0
  354. /package/{dist/cli → cli}/node/source-cli-task-executor.d.ts +0 -0
  355. /package/examples/{example-board → board}/cards/card-concentration.json +0 -0
  356. /package/examples/{example-board → board}/cards/card-my-identity.json +0 -0
  357. /package/examples/{example-board → board}/cards/card-portfolio-action.json +0 -0
  358. /package/examples/{example-board → board}/cards/card-portfolio-intelligence.json +0 -0
  359. /package/examples/{example-board → board}/cards/card-portfolio-risks.json +0 -0
  360. /package/examples/{example-board → board}/cards/card-rebalance-impact.json +0 -0
  361. /package/examples/{example-board → board}/cards/card-rebalance-sim.json +0 -0
  362. /package/examples/{example-board/cards/card-portfolio-value.json → board/cards/cardT-portfolio-value.json} +0 -0
  363. /package/examples/{example-board → board}/demo-chat-handler.js +0 -0
  364. /package/examples/{example-board → board}/scripts/copilot_wrapper.bat +0 -0
  365. /package/examples/{example-board → board}/scripts/copilot_wrapper_helper.ps1 +0 -0
  366. /package/examples/{example-board → board}/scripts/workiq_wrapper.mjs +0 -0
  367. /package/examples/{browser/boards/portfolio-tracker → board/test}/portfolio-tracker-sse-worker.js +0 -0
  368. /package/{dist → lib}/batch/index.cjs +0 -0
  369. /package/{dist → lib}/batch/index.d.cts +0 -0
  370. /package/{dist → lib}/batch/index.d.ts +0 -0
  371. /package/{dist → lib}/batch/index.js +0 -0
  372. /package/{dist/cli/browser-api → lib/board-livegraph-runtime}/jsonata-sync.cjs +0 -0
  373. /package/{dist → lib}/card-compute/index.d.cts +0 -0
  374. /package/{dist → lib}/card-compute/index.d.ts +0 -0
  375. /package/{dist/cli/node → lib/card-compute}/jsonata-sync.cjs +0 -0
  376. /package/{dist → lib}/config/index.cjs +0 -0
  377. /package/{dist → lib}/config/index.d.cts +0 -0
  378. /package/{dist → lib}/config/index.d.ts +0 -0
  379. /package/{dist → lib}/config/index.js +0 -0
  380. /package/{dist → lib}/continuous-event-graph/jsonata-sync.cjs +0 -0
  381. /package/{dist → lib}/event-graph/index.cjs +0 -0
  382. /package/{dist → lib}/event-graph/index.js +0 -0
  383. /package/{dist → lib}/jsonata-sync.cjs +0 -0
  384. /package/{dist → lib}/server-runtime/jsonata-sync.cjs +0 -0
  385. /package/{dist → lib}/step-machine/index.cjs +0 -0
  386. /package/{dist → lib}/step-machine/index.js +0 -0
  387. /package/{dist → lib}/step-machine-public/jsonata-sync.cjs +0 -0
  388. /package/{dist → lib}/stores/memory.cjs +0 -0
  389. /package/{dist → lib}/stores/memory.js +0 -0
  390. /package/{dist → lib}/types-BBhqYGhE.d.cts +0 -0
  391. /package/{dist → lib}/types-BBhqYGhE.d.ts +0 -0
  392. /package/{dist → lib}/validate-BAVzUJWa.d.ts +0 -0
  393. /package/{dist → lib}/validate-Dbu7ygys.d.cts +0 -0
@@ -1,617 +0,0 @@
1
- #!/usr/bin/env python3
2
- """portfolio-tracker-server.py
3
-
4
- Python port of portfolio-tracker-server.js.
5
-
6
- Minimal single-board HTTP server for the portfolio-tracker example.
7
- Uses create_single_board_server_runtime from py-server-runtime.
8
-
9
- Cards are seeded inline on first start (if the card store is empty).
10
- Task executor: portfolio-tracker-fetch-prices.py (mock-quotes source kind).
11
-
12
- Notification flow: a background polling thread (2-second interval) calls
13
- board.process_accumulated_events() using the server adapter, which has its
14
- publish_board_change_notifications hook wired (by the runtime) to broadcast
15
- SSE frames to connected clients. This bridges pycli task-executor callbacks
16
- (which run in subprocesses with a no-op publish) to SSE clients.
17
-
18
- Usage:
19
- python portfolio-tracker-server.py [--port 7801] [--reset]
20
-
21
- Endpoints (all under /api/board):
22
- GET /api/board/init-board
23
- GET /api/board/sse
24
- GET /api/board/board-status
25
- PATCH /api/board/cards/:id
26
- POST /api/board/cards/:id/actions
27
- """
28
- from __future__ import annotations
29
-
30
- import argparse
31
- import http.server
32
- import json
33
- import os
34
- import select
35
- import shutil
36
- import sys
37
- import tempfile
38
- import threading
39
- import time
40
- import uuid
41
- from pathlib import Path
42
- from typing import Any, Dict, List, Optional
43
- from urllib.parse import urlparse, parse_qs, unquote
44
-
45
- # ── Path resolution ────────────────────────────────────────────────────────────
46
-
47
- _HERE = os.path.dirname(os.path.abspath(__file__))
48
- _REPO_ROOT = os.path.normpath(os.path.join(_HERE, '..', '..', '..', '..'))
49
- _PYCLI_ROOT = os.path.join(_REPO_ROOT, 'pycli')
50
- if _PYCLI_ROOT not in sys.path:
51
- sys.path.insert(0, _PYCLI_ROOT)
52
-
53
- _PY_SERVER_RUNTIME_DIR = os.path.join(_PYCLI_ROOT, 'py-server-runtime')
54
- if _PY_SERVER_RUNTIME_DIR not in sys.path:
55
- sys.path.insert(0, _PY_SERVER_RUNTIME_DIR)
56
-
57
- from index import create_single_board_server_runtime # noqa: E402
58
-
59
- _PYCLI_SUB = os.path.join(_PYCLI_ROOT, 'sub')
60
- if _PYCLI_SUB not in sys.path:
61
- sys.path.insert(0, _PYCLI_SUB)
62
-
63
- from board_live_cards_adapters import ( # noqa: E402
64
- ExecutionRef,
65
- FsKvStorage,
66
- FsBlobStorage,
67
- FsJournalStorageAdapter,
68
- FileAtomicRelayLock,
69
- compute_stable_json_hash,
70
- dispatch_execution as _dispatch_execution_impl,
71
- )
72
- from pylib.cli.storage_interface import parse_ref, serialize_ref # noqa: E402
73
- from pylib.cli.board_live_cards_public import create_board_live_cards_public # noqa: E402
74
-
75
- # ── CLI args ───────────────────────────────────────────────────────────────────
76
-
77
- _parser = argparse.ArgumentParser()
78
- _parser.add_argument('--port', type=int, default=7801)
79
- _parser.add_argument('--reset', action='store_true')
80
- _args = _parser.parse_args()
81
-
82
- PORT = _args.port
83
- RESET = _args.reset
84
-
85
- # ── Paths ──────────────────────────────────────────────────────────────────────
86
-
87
- SETUP_DIR = os.path.join(tempfile.gettempdir(), 'portfolio-tracker-py-server')
88
- RUNTIME_DIR = os.path.join(SETUP_DIR, 'runtime')
89
- CARDS_DIR = os.path.join(SETUP_DIR, 'cards')
90
- OUTPUTS_DIR = os.path.join(SETUP_DIR, 'outputs')
91
- FETCH_PRICES_PY = os.path.join(_HERE, 'portfolio-tracker-fetch-prices.py')
92
-
93
- if RESET and os.path.exists(SETUP_DIR):
94
- shutil.rmtree(SETUP_DIR, ignore_errors=True)
95
- print(f'[portfolio-tracker-server.py] reset: wiped {SETUP_DIR}')
96
-
97
- for _d in [RUNTIME_DIR, CARDS_DIR, OUTPUTS_DIR]:
98
- os.makedirs(_d, exist_ok=True)
99
-
100
- # ── Inline card definitions ────────────────────────────────────────────────────
101
-
102
- INLINE_CARDS: List[Dict[str, Any]] = [
103
- {
104
- 'id': 'portfolio-form',
105
- 'meta': {'title': 'Portfolio Holdings Form'},
106
- 'provides': [{'bindTo': 'holdings', 'ref': 'card_data.holdings'}],
107
- 'card_data': {'holdings': [{'symbol': 'AAPL', 'qty': 50}, {'symbol': 'MSFT', 'qty': 30}]},
108
- 'view': {
109
- 'elements': [
110
- {'kind': 'table', 'label': 'Holdings',
111
- 'data': {'bind': 'card_data.holdings', 'columns': ['symbol', 'qty']}},
112
- ],
113
- },
114
- },
115
- {
116
- 'id': 'price-fetch',
117
- 'meta': {'title': 'Fetch Market Prices'},
118
- 'requires': ['holdings'],
119
- 'provides': [{'bindTo': 'prices', 'ref': 'fetched_sources.prices'}],
120
- 'card_data': {},
121
- 'source_defs': [{
122
- 'kind': 'mock-quotes',
123
- 'bindTo': 'prices',
124
- 'outputFile': 'prices.json',
125
- 'projections': {'tickers': '$append([], requires.holdings.symbol)'},
126
- }],
127
- 'view': {
128
- 'elements': [
129
- {'kind': 'table', 'label': 'Market Prices', 'data': {'bind': 'fetched_sources.prices'}},
130
- ],
131
- },
132
- },
133
- {
134
- 'id': 'holdings-table',
135
- 'meta': {'title': 'Holdings Table'},
136
- 'requires': ['holdings', 'prices'],
137
- 'provides': [{'bindTo': 'table', 'ref': 'computed_values.table'}],
138
- 'card_data': {},
139
- 'compute': [{
140
- 'bindTo': 'table',
141
- 'expr': ('{ "rows": $map(requires.holdings, function($h) {'
142
- ' { "symbol": $h.symbol, "qty": $h.qty,'
143
- ' "price": $lookup(requires.prices, $h.symbol),'
144
- ' "value": $h.qty * $lookup(requires.prices, $h.symbol) } }) }'),
145
- }],
146
- 'view': {
147
- 'elements': [
148
- {'kind': 'table', 'label': 'Portfolio Positions',
149
- 'data': {'bind': 'computed_values.table.rows', 'columns': ['symbol', 'qty', 'price', 'value']}},
150
- ],
151
- },
152
- },
153
- {
154
- 'id': 'portfolio-value',
155
- 'meta': {'title': 'Portfolio Total Value'},
156
- 'requires': ['table'],
157
- 'provides': [{'bindTo': 'totalValue', 'ref': 'computed_values.totalValue'}],
158
- 'card_data': {},
159
- 'compute': [{'bindTo': 'totalValue', 'expr': '$sum(requires.table.rows.value)'}],
160
- 'view': {
161
- 'elements': [
162
- {'kind': 'metric', 'label': 'Total Portfolio Value',
163
- 'data': {'bind': 'computed_values.totalValue'}},
164
- ],
165
- },
166
- },
167
- ]
168
-
169
- # ── FS adapter helpers ─────────────────────────────────────────────────────────
170
-
171
- def _make_kv(root: str):
172
- kv = FsKvStorage(root)
173
- class _KV:
174
- def read(self, key): return kv.read(key)
175
- def write(self, key, value): kv.write(key, value)
176
- def delete(self, key): kv.delete(key)
177
- def list_keys(self, prefix=None): return kv.list_keys(prefix)
178
- return _KV()
179
-
180
-
181
- def _make_blob(root: str):
182
- blob = FsBlobStorage(root)
183
- class _Blob:
184
- def read(self, key): return blob.read(key)
185
- def write(self, key, content): blob.write(key, content)
186
- def exists(self, key): return blob.exists(key)
187
- def remove(self, key): blob.remove(key)
188
- def list_keys(self, prefix: str = '') -> List[str]:
189
- root_path = Path(root)
190
- if not root_path.is_dir():
191
- return []
192
- results = []
193
- for p in root_path.rglob('*'):
194
- if p.is_file():
195
- rel = p.relative_to(root_path).as_posix()
196
- if not prefix or rel.startswith(prefix):
197
- results.append(rel)
198
- return sorted(results)
199
- return _Blob()
200
-
201
-
202
- def _make_journal(scope: str):
203
- j = FsJournalStorageAdapter(scope)
204
- class _Journal:
205
- def read_all_entries(self): return j.read_all_entries()
206
- def append_entry(self, entry): j.append_entry(entry)
207
- def generate_id(self): return j.generate_id()
208
- return _Journal()
209
-
210
-
211
- def _make_lock(lock_path: str):
212
- lk = FileAtomicRelayLock(lock_path)
213
- class _Lock:
214
- def try_acquire(self): return lk.try_acquire()
215
- return _Lock()
216
-
217
-
218
- def create_fs_board_platform_adapter(base_ref: Dict[str, str]):
219
- """FS-backed board platform adapter for the server context."""
220
- scope = base_ref['value']
221
-
222
- class _Adapter:
223
- def kv_storage(self, namespace: str):
224
- root = os.path.join(scope, f'.{namespace}') if namespace else scope
225
- return _make_kv(root)
226
-
227
- def kv_storage_for_ref(self, ref: str):
228
- return _make_kv(parse_ref(ref)['value'])
229
-
230
- def blob_storage(self, namespace: str):
231
- root = os.path.join(scope, namespace) if namespace else scope
232
- return _make_blob(root)
233
-
234
- def journal_adapter(self):
235
- return _make_journal(scope)
236
-
237
- @property
238
- def lock(self):
239
- return _make_lock(os.path.join(scope, '.board.lock'))
240
-
241
- @property
242
- def self_ref(self) -> Dict[str, Any]:
243
- return {
244
- 'meta': 'board-live-cards',
245
- 'howToRun': 'local-python',
246
- 'whatToRun': serialize_ref({'kind': 'fs-path', 'value': os.path.join(_PYCLI_ROOT, 'main', 'board_live_cards_pycli.py')}),
247
- }
248
-
249
- def dispatch_execution(self, ref: Dict[str, Any], args: Dict[str, Any]) -> Dict[str, Any]:
250
- """Dispatch a source-fetch task executor subprocess."""
251
- exec_ref = ExecutionRef(
252
- meta=ref.get('meta'),
253
- howToRun=ref.get('howToRun', ''),
254
- whatToRun=ref.get('whatToRun', ''),
255
- )
256
- label = (args.get('source_def') or {}).get('bindTo') or uuid.uuid4().hex[:8]
257
- tmp_dir = os.path.join(scope, '.tmp')
258
- os.makedirs(tmp_dir, exist_ok=True)
259
- in_file = os.path.join(tmp_dir, f'exec-in-{label}.json')
260
- out_file = os.path.join(tmp_dir, f'exec-out-{label}.json')
261
- err_file = os.path.join(tmp_dir, f'exec-err-{label}.txt')
262
- with open(in_file, 'w', encoding='utf-8') as f:
263
- json.dump(args, f, indent=2)
264
- return _dispatch_execution_impl(exec_ref, {
265
- 'subcommand': 'run-source-fetch',
266
- 'inRef': serialize_ref({'kind': 'fs-path', 'value': in_file}),
267
- 'outRef': serialize_ref({'kind': 'fs-path', 'value': out_file}),
268
- 'errRef': serialize_ref({'kind': 'fs-path', 'value': err_file}),
269
- }, cwd=scope, detached=True)
270
-
271
- def resolve_blob(self, ref: Dict[str, str]) -> str:
272
- if ref.get('kind') == 'fs-path':
273
- with open(ref['value'], 'r', encoding='utf-8') as f:
274
- return f.read()
275
- raise ValueError(f'resolveBlob: unsupported kind: {ref.get("kind")}')
276
-
277
- def hash_fn(self, value: Any) -> str:
278
- return compute_stable_json_hash(value)
279
-
280
- def gen_id(self) -> str:
281
- return uuid.uuid4().hex[:32]
282
-
283
- def request_process_accumulated(self) -> None:
284
- # No-op: the polling thread below drives drain in the server process
285
- # every 2 seconds using this same adapter (with the runtime-hooked publish).
286
- pass
287
-
288
- def publish_board_change_notifications(self, notifications) -> None:
289
- pass # Overridden by the runtime to broadcast to SSE clients
290
-
291
- return _Adapter()
292
-
293
-
294
- def create_invocation_adapter():
295
- """Generic invocation adapter (for chat handlers etc — not used by portfolio-tracker)."""
296
- class _Adapter:
297
- def invoke(self, ref: Dict[str, Any], args: Dict[str, Any]) -> Dict[str, Any]:
298
- how = ref.get('howToRun', '')
299
- what = str(ref.get('whatToRun') or '')
300
- if what.startswith('b64:'):
301
- try:
302
- parsed = parse_ref(what)
303
- script_path = parsed.get('value') if parsed.get('kind') == 'fs-path' else ''
304
- except Exception:
305
- script_path = ''
306
- else:
307
- script_path = what
308
- if not script_path:
309
- return {'dispatched': False, 'error': f'no script path: {what}'}
310
- if how == 'local-python':
311
- interpreter = sys.executable
312
- elif how == 'local-node':
313
- interpreter = shutil.which('node') or 'node'
314
- else:
315
- return {'dispatched': False, 'error': f'unsupported howToRun: {how}'}
316
- import base64
317
- import subprocess
318
- extra = base64.b64encode(json.dumps(args).encode('utf-8')).decode('ascii')
319
- cmd = [interpreter, script_path,
320
- '--boardId', str(args.get('boardId') or ''),
321
- '--cardId', str(args.get('cardId') or ''),
322
- '--extraEncJson', extra]
323
- try:
324
- if sys.platform == 'win32':
325
- subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
326
- creationflags=0x08000000)
327
- else:
328
- subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
329
- start_new_session=True)
330
- return {'dispatched': True}
331
- except Exception as e:
332
- return {'dispatched': False, 'error': str(e)}
333
- return _Adapter()
334
-
335
-
336
- # ── Board adapter & runtime ────────────────────────────────────────────────────
337
-
338
- base_ref = parse_ref(serialize_ref({'kind': 'fs-path', 'value': RUNTIME_DIR}))
339
- board_adapter = create_fs_board_platform_adapter(base_ref)
340
- card_store_ref = serialize_ref({'kind': 'fs-path', 'value': os.path.join(CARDS_DIR, 'cards')})
341
- outputs_store_ref = serialize_ref({'kind': 'fs-path', 'value': os.path.join(OUTPUTS_DIR, '.outputs')})
342
- task_executor_ref = {
343
- 'howToRun': 'local-python',
344
- 'whatToRun': serialize_ref({'kind': 'fs-path', 'value': FETCH_PRICES_PY}),
345
- 'meta': 'task-executor',
346
- }
347
-
348
- _logger = type('L', (), {
349
- 'info': staticmethod(lambda msg, *a: print(f'[portfolio-tracker-server.py] {msg}', *a)),
350
- 'warn': staticmethod(lambda msg, *a: print(f'[portfolio-tracker-server.py][WARN] {msg}', *a)),
351
- 'error': staticmethod(lambda msg, *a: print(f'[portfolio-tracker-server.py][ERROR] {msg}', *a)),
352
- })()
353
-
354
- runtime = create_single_board_server_runtime({
355
- 'api_base_path': '/api/board',
356
- 'board_id': 'portfolio-tracker',
357
- 'boards': [{
358
- 'label': 'portfolio-tracker',
359
- 'board_adapter': board_adapter,
360
- 'base_ref': base_ref,
361
- 'card_store_ref': card_store_ref,
362
- 'outputs_store_ref': outputs_store_ref,
363
- 'task_executor_ref': task_executor_ref,
364
- }],
365
- 'invocation_adapter': create_invocation_adapter(),
366
- 'logger': _logger,
367
- 'server_url': f'http://127.0.0.1:{PORT}',
368
- })
369
-
370
- # ── Card store seeding ─────────────────────────────────────────────────────────
371
-
372
- _existing = runtime.card_store.get({})
373
- _is_empty = _existing.get('status') != 'success' or not _existing.get('data', {}).get('cards')
374
- if _is_empty:
375
- runtime.card_store.set({'body': INLINE_CARDS})
376
- print(f'[portfolio-tracker-server.py] seeded {len(INLINE_CARDS)} cards')
377
- else:
378
- print(f'[portfolio-tracker-server.py] card store already populated '
379
- f'({len(_existing["data"]["cards"])} cards)')
380
-
381
- # ── Polling drain thread ───────────────────────────────────────────────────────
382
- #
383
- # board_adapter.publish_board_change_notifications is now the runtime's SSE broadcast
384
- # hook (set during create_single_board_server_runtime above).
385
- #
386
- # When portfolio-tracker-fetch-prices.py (the task executor) completes, it calls
387
- # back via pycli (board_live_cards_pycli.py source-data-fetched). That subprocess
388
- # uses NativeBoardPlatformAdapter whose publish_board_change_notifications is a no-op.
389
- # The polling thread below creates a fresh board with the server's board_adapter and
390
- # calls process_accumulated_events(), which reads the FS journal written by the pycli
391
- # subprocess and broadcasts the results to SSE clients within ~2 seconds.
392
-
393
- def _poll_drain() -> None:
394
- while True:
395
- time.sleep(2)
396
- try:
397
- poll_board = create_board_live_cards_public(base_ref, board_adapter)
398
- poll_board.process_accumulated_events({})
399
- publish = getattr(board_adapter, 'publish_board_change_notifications', None)
400
- if callable(publish):
401
- notifications: List[Dict[str, Any]] = []
402
- status_result = poll_board.status({})
403
- if status_result.get('status') == 'success' and status_result.get('data') is not None:
404
- notifications.append({'kind': 'status', 'status': status_result['data']})
405
- data_result = poll_board.get_all_outputs_data_objects({})
406
- if data_result.get('status') == 'success' and isinstance(data_result.get('data'), dict):
407
- for token, payload in data_result['data'].items():
408
- if token:
409
- notifications.append({'kind': 'data_object', 'key': token, 'payload': payload})
410
- cv_result = poll_board.get_all_outputs_computed_values({})
411
- if cv_result.get('status') == 'success' and isinstance(cv_result.get('data'), dict):
412
- for card_id, values in cv_result['data'].items():
413
- if card_id:
414
- notifications.append({'kind': 'computed_values', 'cardId': card_id, 'values': values})
415
- if notifications:
416
- publish(notifications)
417
- except Exception:
418
- pass
419
-
420
-
421
- _poll_thread = threading.Thread(target=_poll_drain, daemon=True, name='poll-drain')
422
- _poll_thread.start()
423
-
424
- # ── HTTP server ────────────────────────────────────────────────────────────────
425
-
426
- CORS_HEADERS = {
427
- 'Access-Control-Allow-Origin': '*',
428
- 'Access-Control-Allow-Headers': 'content-type,x-file-name',
429
- 'Access-Control-Allow-Methods': 'GET,POST,PATCH,OPTIONS',
430
- }
431
-
432
-
433
- class ParsedUrl:
434
- def __init__(self, url_str: str):
435
- parsed = urlparse(url_str)
436
- self.path = parsed.path
437
- qs = parse_qs(parsed.query, keep_blank_values=True)
438
- self.query_params = {k: v[0] for k, v in qs.items()}
439
-
440
-
441
- class RequestAdapter:
442
- def __init__(self, handler: http.server.BaseHTTPRequestHandler, body: bytes):
443
- self._handler = handler
444
- self._body = body
445
-
446
- @property
447
- def method(self) -> str:
448
- return self._handler.command
449
-
450
- @property
451
- def path(self) -> str:
452
- return urlparse(self._handler.path).path
453
-
454
- @property
455
- def headers(self) -> Dict[str, str]:
456
- return {k.lower(): v for k, v in self._handler.headers.items()}
457
-
458
- @property
459
- def query_params(self) -> Dict[str, str]:
460
- qs = parse_qs(urlparse(self._handler.path).query, keep_blank_values=True)
461
- return {k: v[0] for k, v in qs.items()}
462
-
463
- def read_body(self) -> bytes:
464
- return self._body
465
-
466
-
467
- class ResponseAdapter:
468
- """Adapts http.server to the py-server-runtime response protocol.
469
-
470
- For SSE connections the caller must invoke wait_for_close() after
471
- handle_runtime_api returns so that the thread stays alive (and the
472
- TCP connection stays open) until the client disconnects.
473
- Writes from other threads (notification broadcasts) are protected by
474
- a per-connection lock.
475
- """
476
-
477
- def __init__(self, handler: http.server.BaseHTTPRequestHandler):
478
- self._handler = handler
479
- self._headers_sent = False
480
- self._status = 200
481
- self._headers: Dict[str, str] = {}
482
- self._is_sse = False
483
- self._write_lock = threading.Lock()
484
-
485
- def write_head(self, status_code: int, headers: Optional[Dict[str, str]] = None) -> None:
486
- self._status = status_code
487
- if headers:
488
- self._headers.update(headers)
489
- ct = (headers or {}).get('Content-Type', '')
490
- if ct.startswith('text/event-stream'):
491
- self._is_sse = True
492
-
493
- def _send_headers_locked(self) -> None:
494
- if self._headers_sent:
495
- return
496
- self._headers_sent = True
497
- self._handler.send_response(self._status)
498
- for k, v in self._headers.items():
499
- self._handler.send_header(k, str(v))
500
- self._handler.end_headers()
501
-
502
- def write(self, data) -> None:
503
- with self._write_lock:
504
- self._send_headers_locked()
505
- raw = data.encode('utf-8') if isinstance(data, str) else data
506
- try:
507
- self._handler.wfile.write(raw)
508
- self._handler.wfile.flush()
509
- except Exception:
510
- pass # Client disconnected; broadcast will remove us from sse_clients
511
-
512
- def end(self, data=None) -> None:
513
- with self._write_lock:
514
- self._send_headers_locked()
515
- if data:
516
- raw = data.encode('utf-8') if isinstance(data, str) else data
517
- try:
518
- self._handler.wfile.write(raw)
519
- self._handler.wfile.flush()
520
- except Exception:
521
- pass
522
-
523
- def wait_for_close(self) -> None:
524
- """Block the SSE-connection thread until the client disconnects."""
525
- conn = self._handler.connection
526
- try:
527
- while True:
528
- try:
529
- r, _, e = select.select([conn], [], [conn], 1.0)
530
- except Exception:
531
- break
532
- if e:
533
- break
534
- if r:
535
- try:
536
- data = conn.recv(16)
537
- if not data:
538
- break
539
- except Exception:
540
- break
541
- except Exception:
542
- pass
543
-
544
-
545
- class _ThreadedServer(http.server.ThreadingHTTPServer):
546
- daemon_threads = True
547
-
548
-
549
- class _Handler(http.server.BaseHTTPRequestHandler):
550
- def log_message(self, fmt, *args): # type: ignore[override]
551
- pass # suppress per-request access log
552
-
553
- def do_OPTIONS(self) -> None:
554
- self.send_response(204)
555
- for k, v in CORS_HEADERS.items():
556
- self.send_header(k, v)
557
- self.end_headers()
558
-
559
- def do_GET(self) -> None:
560
- self._handle()
561
-
562
- def do_POST(self) -> None:
563
- self._handle()
564
-
565
- def do_PATCH(self) -> None:
566
- self._handle()
567
-
568
- def _handle(self) -> None:
569
- content_length = int(self.headers.get('content-length') or 0)
570
- body = self.rfile.read(content_length) if content_length > 0 else b''
571
-
572
- req = RequestAdapter(self, body)
573
- res = ResponseAdapter(self)
574
- parsed = ParsedUrl(self.path)
575
-
576
- try:
577
- handled = runtime.handle_runtime_api(req, res, parsed)
578
- except Exception as exc:
579
- self.send_response(500)
580
- self.send_header('Content-Type', 'application/json')
581
- self.end_headers()
582
- self.wfile.write(json.dumps({'error': str(exc)}).encode('utf-8'))
583
- return
584
-
585
- if not handled:
586
- self.send_response(404)
587
- self.send_header('Content-Type', 'application/json')
588
- self.end_headers()
589
- self.wfile.write(b'{"error":"Not found"}')
590
- return
591
-
592
- if res._is_sse:
593
- # Keep the thread alive (and the TCP connection open) until the client
594
- # disconnects. Other threads write SSE frames via res.write() under the
595
- # per-connection lock above.
596
- res.wait_for_close()
597
-
598
-
599
- def main() -> None:
600
- server = _ThreadedServer(('127.0.0.1', PORT), _Handler)
601
- print(f'[portfolio-tracker-server.py] listening on http://127.0.0.1:{PORT}')
602
- print(f'[portfolio-tracker-server.py] runtime dir: {RUNTIME_DIR}')
603
- print('[portfolio-tracker-server.py] endpoints:')
604
- print(' GET /api/board/init-board')
605
- print(' GET /api/board/sse')
606
- print(' GET /api/board/board-status')
607
- print(' PATCH /api/board/cards/:id')
608
- print(' POST /api/board/cards/:id/actions')
609
- try:
610
- server.serve_forever()
611
- except KeyboardInterrupt:
612
- print('\n[portfolio-tracker-server.py] shutting down')
613
- server.shutdown()
614
-
615
-
616
- if __name__ == '__main__':
617
- main()