yaml-flow 3.1.1 → 5.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 (194) hide show
  1. package/README.md +81 -20
  2. package/board-live-cards-cli.js +37 -0
  3. package/browser/board-livegraph-runtime.js +1453 -0
  4. package/browser/board-livegraph-runtime.js.map +1 -0
  5. package/browser/card-compute.js +153 -433
  6. package/browser/live-cards.js +868 -115
  7. package/browser/live-cards.schema.json +90 -83
  8. package/dist/board-livegraph-runtime/index.cjs +1448 -0
  9. package/dist/board-livegraph-runtime/index.cjs.map +1 -0
  10. package/dist/board-livegraph-runtime/index.d.cts +101 -0
  11. package/dist/board-livegraph-runtime/index.d.ts +101 -0
  12. package/dist/board-livegraph-runtime/index.js +1441 -0
  13. package/dist/board-livegraph-runtime/index.js.map +1 -0
  14. package/dist/card-compute/index.cjs +266 -431
  15. package/dist/card-compute/index.cjs.map +1 -1
  16. package/dist/card-compute/index.d.cts +77 -49
  17. package/dist/card-compute/index.d.ts +77 -49
  18. package/dist/card-compute/index.js +263 -432
  19. package/dist/card-compute/index.js.map +1 -1
  20. package/dist/cli/board-live-cards-cli.cjs +2750 -0
  21. package/dist/cli/board-live-cards-cli.cjs.map +1 -0
  22. package/dist/cli/board-live-cards-cli.d.cts +205 -0
  23. package/dist/cli/board-live-cards-cli.d.ts +205 -0
  24. package/dist/cli/board-live-cards-cli.js +2702 -0
  25. package/dist/cli/board-live-cards-cli.js.map +1 -0
  26. package/dist/{constants-B2zqu10b.d.ts → constants-DuzE5n03.d.ts} +2 -2
  27. package/dist/{constants-DJZU1pwJ.d.cts → constants-ozjf1Ejw.d.cts} +2 -2
  28. package/dist/continuous-event-graph/index.cjs +258 -464
  29. package/dist/continuous-event-graph/index.cjs.map +1 -1
  30. package/dist/continuous-event-graph/index.d.cts +18 -358
  31. package/dist/continuous-event-graph/index.d.ts +18 -358
  32. package/dist/continuous-event-graph/index.js +255 -464
  33. package/dist/continuous-event-graph/index.js.map +1 -1
  34. package/dist/event-graph/index.cjs +4 -4
  35. package/dist/event-graph/index.cjs.map +1 -1
  36. package/dist/event-graph/index.d.cts +5 -5
  37. package/dist/event-graph/index.d.ts +5 -5
  38. package/dist/event-graph/index.js +4 -4
  39. package/dist/event-graph/index.js.map +1 -1
  40. package/dist/index.cjs +1684 -555
  41. package/dist/index.cjs.map +1 -1
  42. package/dist/index.d.cts +26 -7
  43. package/dist/index.d.ts +26 -7
  44. package/dist/index.js +1678 -555
  45. package/dist/index.js.map +1 -1
  46. package/dist/inference/index.cjs +138 -19
  47. package/dist/inference/index.cjs.map +1 -1
  48. package/dist/inference/index.d.cts +2 -2
  49. package/dist/inference/index.d.ts +2 -2
  50. package/dist/inference/index.js +138 -19
  51. package/dist/inference/index.js.map +1 -1
  52. package/dist/journal-DRfJiheM.d.cts +28 -0
  53. package/dist/journal-NLYuqege.d.ts +28 -0
  54. package/dist/live-cards-bridge-Or7fdEJV.d.ts +316 -0
  55. package/dist/live-cards-bridge-vGJ6tMzN.d.cts +316 -0
  56. package/dist/schedule-CMcZe5Ny.d.ts +21 -0
  57. package/dist/schedule-CiucyCan.d.cts +21 -0
  58. package/dist/step-machine/index.cjs +18 -1
  59. package/dist/step-machine/index.cjs.map +1 -1
  60. package/dist/step-machine/index.d.cts +2 -2
  61. package/dist/step-machine/index.d.ts +2 -2
  62. package/dist/step-machine/index.js +18 -1
  63. package/dist/step-machine/index.js.map +1 -1
  64. package/dist/stores/file.d.cts +1 -1
  65. package/dist/stores/file.d.ts +1 -1
  66. package/dist/stores/index.d.cts +1 -1
  67. package/dist/stores/index.d.ts +1 -1
  68. package/dist/stores/localStorage.d.cts +1 -1
  69. package/dist/stores/localStorage.d.ts +1 -1
  70. package/dist/stores/memory.d.cts +1 -1
  71. package/dist/stores/memory.d.ts +1 -1
  72. package/dist/{types-BwvgvlOO.d.cts → types-BzLD8bjb.d.cts} +1 -1
  73. package/dist/{types-ClRA8hzC.d.ts → types-C2eJ7DAV.d.ts} +1 -1
  74. package/dist/{types-DEj7OakX.d.cts → types-CMFSIjpc.d.cts} +39 -4
  75. package/dist/{types-DEj7OakX.d.ts → types-CMFSIjpc.d.ts} +39 -4
  76. package/dist/{types-FZ_eyErS.d.cts → types-ycun84cq.d.cts} +1 -0
  77. package/dist/{types-FZ_eyErS.d.ts → types-ycun84cq.d.ts} +1 -0
  78. package/dist/{validate-DEZ2Ymdb.d.ts → validate-DJQTQ6bP.d.ts} +1 -1
  79. package/dist/{validate-DqKTZg_o.d.cts → validate-ke92Cleg.d.cts} +1 -1
  80. package/examples/browser/boards/portfolio-tracker/cards/holdings-table.json +22 -0
  81. package/examples/browser/boards/portfolio-tracker/cards/portfolio-form.json +16 -0
  82. package/examples/browser/boards/portfolio-tracker/cards/portfolio-value.json +15 -0
  83. package/examples/browser/boards/portfolio-tracker/cards/price-fetch.json +15 -0
  84. package/examples/browser/boards/portfolio-tracker/fetch-prices.js +43 -0
  85. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-task-executor.cjs +96 -0
  86. package/examples/browser/boards/portfolio-tracker/portfolio-tracker.bat +7 -0
  87. package/examples/browser/boards/portfolio-tracker/portfolio-tracker.js +217 -0
  88. package/examples/browser/livecards-browser/index.html +41 -0
  89. package/examples/browser/{index.html → step-machine-browser/index.html} +53 -53
  90. package/examples/cli/step-machine-cli/portfolio-tracker/cards/holdings-table.json +22 -0
  91. package/examples/cli/step-machine-cli/portfolio-tracker/cards/portfolio-form.json +43 -0
  92. package/examples/cli/step-machine-cli/portfolio-tracker/cards/portfolio-value.json +15 -0
  93. package/examples/cli/step-machine-cli/portfolio-tracker/cards/price-fetch.json +15 -0
  94. package/examples/cli/step-machine-cli/portfolio-tracker/fetch-prices.js +48 -0
  95. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/_board-cli.js +58 -0
  96. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/add-cards-cli.js +27 -0
  97. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/init-board-cli.js +25 -0
  98. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/reset-board-dir-cli.js +29 -0
  99. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/retrigger-cli.js +27 -0
  100. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/status-cli.js +25 -0
  101. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/update-holdings-cli.js +37 -0
  102. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/wait-completed-cli.js +53 -0
  103. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/write-prices-cli.js +35 -0
  104. package/examples/cli/step-machine-cli/portfolio-tracker/portfolio-tracker.flow.yaml +227 -0
  105. package/examples/cli/step-machine-cli/portfolio-tracker/portfolio-tracker.input.json +38 -0
  106. package/examples/cli/step-machine-cli/portfolio-tracker/run-portfolio-tracker.bat +29 -0
  107. package/examples/cli/step-machine-demo/jsonata-init-board-cli.js +36 -0
  108. package/examples/cli/step-machine-demo/jsonata-init-board.flow.yaml +30 -0
  109. package/examples/cli/step-machine-demo/one-step-cli-only.flow.yaml +19 -0
  110. package/examples/cli/step-machine-demo/step-cli-echo-y.js +15 -0
  111. package/examples/cli/step-machine-demo/step2-double-cli.js +39 -0
  112. package/examples/cli/step-machine-demo/two-step-math-handlers.js +32 -0
  113. package/examples/cli/step-machine-demo/two-step-math.flow.yaml +31 -0
  114. package/examples/cli/step-machine-demo/two-step-mixed-handlers.js +24 -0
  115. package/examples/cli/step-machine-demo/two-step-mixed.flow.yaml +35 -0
  116. package/examples/example-board/board.yaml +23 -0
  117. package/examples/example-board/bootstrap_payload.json +1 -0
  118. package/examples/example-board/cards/card-chain-region-alert.json +39 -0
  119. package/examples/example-board/cards/card-chain-region-totals.json +26 -0
  120. package/examples/example-board/cards/card-chain-top-region.json +24 -0
  121. package/examples/example-board/cards/card-ex-actions.json +32 -0
  122. package/examples/example-board/cards/card-ex-chart.json +30 -0
  123. package/examples/example-board/cards/card-ex-filter.json +36 -0
  124. package/examples/example-board/cards/card-ex-filtered-by-preference.json +59 -0
  125. package/examples/example-board/cards/card-ex-form.json +91 -0
  126. package/examples/example-board/cards/card-ex-list.json +22 -0
  127. package/examples/example-board/cards/card-ex-markdown.json +17 -0
  128. package/examples/example-board/cards/card-ex-metric.json +19 -0
  129. package/examples/example-board/cards/card-ex-narrative.json +36 -0
  130. package/examples/example-board/cards/card-ex-source-http.json +28 -0
  131. package/examples/example-board/cards/card-ex-source.json +21 -0
  132. package/examples/example-board/cards/card-ex-status.json +35 -0
  133. package/examples/example-board/cards/card-ex-table.json +30 -0
  134. package/examples/example-board/cards/card-ex-todo.json +29 -0
  135. package/examples/example-board/demo-chat-handler.js +69 -0
  136. package/examples/example-board/demo-server.js +87 -0
  137. package/examples/example-board/demo-shell-browser.html +806 -0
  138. package/examples/example-board/demo-shell-with-server.html +280 -0
  139. package/examples/example-board/demo-shell.html +62 -0
  140. package/examples/example-board/demo-task-executor.js +255 -0
  141. package/examples/example-board/mock.db +15 -0
  142. package/examples/example-board/reusable-board-runtime-client.js +265 -0
  143. package/examples/example-board/reusable-runtime-artifacts-adapter.js +233 -0
  144. package/examples/example-board/reusable-server-runtime.js +1284 -0
  145. package/examples/index.html +799 -0
  146. package/examples/{batch → npm-libs/batch}/batch-step-machine.ts +1 -1
  147. package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/live-cards-board.ts +18 -18
  148. package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/live-portfolio-dashboard.ts +24 -24
  149. package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/portfolio-tracker.ts +1 -1
  150. package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/reactive-monitoring.ts +1 -1
  151. package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/reactive-pipeline.ts +1 -1
  152. package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/soc-incident-board.ts +1 -1
  153. package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/stock-dashboard.ts +1 -1
  154. package/examples/{event-graph → npm-libs/event-graph}/ci-cd-pipeline.ts +1 -1
  155. package/examples/{event-graph → npm-libs/event-graph}/executor-diamond.ts +1 -1
  156. package/examples/{event-graph → npm-libs/event-graph}/executor-pipeline.ts +1 -1
  157. package/examples/{event-graph → npm-libs/event-graph}/research-pipeline.ts +1 -1
  158. package/examples/{graph-of-graphs → npm-libs/graph-of-graphs}/multi-stage-etl.ts +1 -1
  159. package/examples/{graph-of-graphs → npm-libs/graph-of-graphs}/url-processing-pipeline.ts +1 -1
  160. package/examples/{inference → npm-libs/inference}/azure-deployment.ts +1 -1
  161. package/examples/{inference → npm-libs/inference}/copilot-cli.ts +1 -1
  162. package/examples/{inference → npm-libs/inference}/data-pipeline.ts +1 -1
  163. package/examples/{inference → npm-libs/inference}/pluggable-adapters.ts +1 -1
  164. package/examples/{node → npm-libs/node}/ai-conversation.ts +1 -1
  165. package/examples/{node → npm-libs/node}/simple-greeting.ts +2 -2
  166. package/examples/step-machine-cli/portfolio-tracker/cards/holdings-table.json +22 -0
  167. package/examples/step-machine-cli/portfolio-tracker/cards/portfolio-form.json +43 -0
  168. package/examples/step-machine-cli/portfolio-tracker/cards/portfolio-value.json +15 -0
  169. package/examples/step-machine-cli/portfolio-tracker/cards/price-fetch.json +15 -0
  170. package/examples/step-machine-cli/portfolio-tracker/fetch-prices.js +48 -0
  171. package/examples/step-machine-cli/portfolio-tracker/handlers/_board-cli.js +58 -0
  172. package/examples/step-machine-cli/portfolio-tracker/handlers/add-cards-cli.js +27 -0
  173. package/examples/step-machine-cli/portfolio-tracker/handlers/init-board-cli.js +25 -0
  174. package/examples/step-machine-cli/portfolio-tracker/handlers/reset-board-dir-cli.js +29 -0
  175. package/examples/step-machine-cli/portfolio-tracker/handlers/retrigger-cli.js +27 -0
  176. package/examples/step-machine-cli/portfolio-tracker/handlers/status-cli.js +25 -0
  177. package/examples/step-machine-cli/portfolio-tracker/handlers/update-holdings-cli.js +37 -0
  178. package/examples/step-machine-cli/portfolio-tracker/handlers/wait-completed-cli.js +53 -0
  179. package/examples/step-machine-cli/portfolio-tracker/handlers/write-prices-cli.js +35 -0
  180. package/examples/step-machine-cli/portfolio-tracker/portfolio-tracker-task-executor.cjs +96 -0
  181. package/examples/step-machine-cli/portfolio-tracker/portfolio-tracker.flow.yaml +227 -0
  182. package/examples/step-machine-cli/portfolio-tracker/portfolio-tracker.input.json +38 -0
  183. package/examples/step-machine-cli/portfolio-tracker/run-portfolio-tracker.bat +29 -0
  184. package/package.json +27 -2
  185. package/schema/board-status.schema.json +118 -0
  186. package/schema/card-runtime.schema.json +25 -0
  187. package/schema/flow.schema.json +5 -0
  188. package/schema/live-cards.schema.json +90 -83
  189. package/step-machine-cli.js +674 -0
  190. package/browser/ingest-board.js +0 -296
  191. package/examples/ingest.js +0 -733
  192. /package/examples/{flows → npm-libs/flows}/ai-conversation.yaml +0 -0
  193. /package/examples/{flows → npm-libs/flows}/order-processing.yaml +0 -0
  194. /package/examples/{flows → npm-libs/flows}/simple-greeting.yaml +0 -0
@@ -0,0 +1,58 @@
1
+ import * as path from 'node:path';
2
+ import { spawnSync } from 'node:child_process';
3
+ import { fileURLToPath } from 'node:url';
4
+
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = path.dirname(__filename);
7
+ const repoRoot = path.resolve(__dirname, '..', '..', '..', '..');
8
+ const boardCliPath = path.join(repoRoot, 'board-live-cards-cli.js');
9
+
10
+ export function runBoardCli(args, options = {}) {
11
+ const { capture = false, cwd = process.cwd() } = options;
12
+ const result = spawnSync(process.execPath, [boardCliPath, ...args], {
13
+ cwd,
14
+ encoding: 'utf-8',
15
+ windowsHide: true,
16
+ stdio: capture ? 'pipe' : 'pipe',
17
+ env: {
18
+ ...process.env,
19
+ BOARD_LIVE_CARDS_NO_SPAWN: process.env.BOARD_LIVE_CARDS_NO_SPAWN ?? '1',
20
+ BOARD_DIR: process.env.BOARD_DIR ?? '',
21
+ },
22
+ });
23
+
24
+ if (result.error) {
25
+ throw new Error(`Failed to launch board-live-cards-cli: ${result.error.message}`);
26
+ }
27
+
28
+ if ((result.status ?? 1) !== 0) {
29
+ const stderr = (result.stderr ?? '').trim();
30
+ const stdout = (result.stdout ?? '').trim();
31
+ throw new Error(`board-live-cards-cli failed (${result.status}): ${stderr || stdout || 'no output'}`);
32
+ }
33
+
34
+ return capture ? (result.stdout ?? '') : '';
35
+ }
36
+
37
+ export async function readStdinJson() {
38
+ let raw = '';
39
+ process.stdin.setEncoding('utf-8');
40
+
41
+ for await (const chunk of process.stdin) {
42
+ raw += chunk;
43
+ }
44
+
45
+ if (!raw.trim()) {
46
+ return {};
47
+ }
48
+
49
+ return JSON.parse(raw);
50
+ }
51
+
52
+ export function writeResult(payload) {
53
+ process.stdout.write(JSON.stringify(payload));
54
+ }
55
+
56
+ export function writeFailure(message) {
57
+ writeResult({ result: 'failure', error: message });
58
+ }
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readStdinJson, runBoardCli, writeFailure, writeResult } from './_board-cli.js';
4
+
5
+ try {
6
+ const input = await readStdinJson();
7
+ const boardDir = String(input.BOARD_DIR ?? '').trim();
8
+ const cardsGlob = String(input.CARDS_GLOB ?? '').trim();
9
+
10
+ if (!boardDir || !cardsGlob) {
11
+ writeFailure('BOARD_DIR and CARDS_GLOB are required');
12
+ process.exit(0);
13
+ }
14
+
15
+ runBoardCli(['add-cards', '--rg', boardDir, '--card-glob', cardsGlob]);
16
+
17
+ writeResult({
18
+ result: 'success',
19
+ data: {
20
+ board_dir: boardDir,
21
+ cards_glob: cardsGlob,
22
+ },
23
+ });
24
+ } catch (error) {
25
+ const message = error instanceof Error ? error.message : String(error);
26
+ writeFailure(message);
27
+ }
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readStdinJson, runBoardCli, writeFailure, writeResult } from './_board-cli.js';
4
+
5
+ try {
6
+ const input = await readStdinJson();
7
+ const boardDir = String(input.BOARD_DIR ?? '').trim();
8
+
9
+ if (!boardDir) {
10
+ writeFailure('BOARD_DIR is required');
11
+ process.exit(0);
12
+ }
13
+
14
+ runBoardCli(['init', boardDir]);
15
+ writeResult({
16
+ result: 'success',
17
+ data: {
18
+ board_dir: boardDir,
19
+ message: `initialized ${boardDir}`,
20
+ },
21
+ });
22
+ } catch (error) {
23
+ const message = error instanceof Error ? error.message : String(error);
24
+ writeFailure(message);
25
+ }
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+
3
+ import * as fs from 'node:fs';
4
+ import * as path from 'node:path';
5
+ import { readStdinJson, writeFailure, writeResult } from './_board-cli.js';
6
+
7
+ try {
8
+ const input = await readStdinJson();
9
+ const boardDirInput = String(input.BOARD_DIR ?? '').trim();
10
+
11
+ if (!boardDirInput) {
12
+ writeFailure('BOARD_DIR is required');
13
+ process.exit(0);
14
+ }
15
+
16
+ const boardDir = path.resolve(boardDirInput);
17
+ fs.rmSync(boardDir, { recursive: true, force: true });
18
+
19
+ writeResult({
20
+ result: 'success',
21
+ data: {
22
+ board_dir: boardDir,
23
+ reset: true,
24
+ },
25
+ });
26
+ } catch (error) {
27
+ const message = error instanceof Error ? error.message : String(error);
28
+ writeFailure(message);
29
+ }
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readStdinJson, runBoardCli, writeFailure, writeResult } from './_board-cli.js';
4
+
5
+ try {
6
+ const input = await readStdinJson();
7
+ const boardDir = String(input.BOARD_DIR ?? '').trim();
8
+ const task = String(input.TASK ?? '').trim();
9
+
10
+ if (!boardDir || !task) {
11
+ writeFailure('BOARD_DIR and TASK are required');
12
+ process.exit(0);
13
+ }
14
+
15
+ runBoardCli(['retrigger', '--rg', boardDir, '--task', task]);
16
+
17
+ writeResult({
18
+ result: 'success',
19
+ data: {
20
+ task,
21
+ retriggered: true,
22
+ },
23
+ });
24
+ } catch (error) {
25
+ const message = error instanceof Error ? error.message : String(error);
26
+ writeFailure(message);
27
+ }
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readStdinJson, runBoardCli, writeFailure, writeResult } from './_board-cli.js';
4
+
5
+ try {
6
+ const input = await readStdinJson();
7
+ const boardDir = String(input.BOARD_DIR ?? '').trim();
8
+
9
+ if (!boardDir) {
10
+ writeFailure('BOARD_DIR is required');
11
+ process.exit(0);
12
+ }
13
+
14
+ const status = runBoardCli(['status', '--rg', boardDir], { capture: true });
15
+
16
+ writeResult({
17
+ result: 'success',
18
+ data: {
19
+ status,
20
+ },
21
+ });
22
+ } catch (error) {
23
+ const message = error instanceof Error ? error.message : String(error);
24
+ writeFailure(message);
25
+ }
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env node
2
+
3
+ import * as fs from 'node:fs';
4
+ import * as path from 'node:path';
5
+ import { readStdinJson, runBoardCli, writeFailure, writeResult } from './_board-cli.js';
6
+
7
+ try {
8
+ const input = await readStdinJson();
9
+ const boardDir = String(input.BOARD_DIR ?? '').trim();
10
+ const cardsDir = String(input.CARDS_DIR ?? '').trim();
11
+ const holdings = input.HOLDINGS;
12
+
13
+ if (!boardDir || !cardsDir || !Array.isArray(holdings)) {
14
+ writeFailure('BOARD_DIR, CARDS_DIR and HOLDINGS array are required');
15
+ process.exit(0);
16
+ }
17
+
18
+ const cardPath = path.join(cardsDir, 'portfolio-form.json');
19
+ const raw = fs.readFileSync(cardPath, 'utf-8');
20
+ const card = JSON.parse(raw);
21
+ card.state = card.state ?? {};
22
+ card.state.holdings = holdings;
23
+ fs.writeFileSync(cardPath, `${JSON.stringify(card, null, 2)}\n`, 'utf-8');
24
+
25
+ runBoardCli(['update-card', '--rg', boardDir, '--card-id', 'portfolio-form', '--restart']);
26
+
27
+ writeResult({
28
+ result: 'success',
29
+ data: {
30
+ saved: true,
31
+ holdings_count: holdings.length,
32
+ },
33
+ });
34
+ } catch (error) {
35
+ const message = error instanceof Error ? error.message : String(error);
36
+ writeFailure(message);
37
+ }
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readStdinJson, runBoardCli, 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 tasks = Array.isArray(input.COMPLETION_TASKS) ? input.COMPLETION_TASKS : [];
13
+ const label = String(input.LABEL ?? 'WAIT');
14
+ const timeoutMs = Number(input.TIMEOUT_MS ?? 30000);
15
+ const pollMs = Number(input.POLL_MS ?? 500);
16
+
17
+ if (!boardDir || tasks.length === 0) {
18
+ writeFailure('BOARD_DIR and COMPLETION_TASKS are required');
19
+ process.exit(0);
20
+ }
21
+
22
+ const started = Date.now();
23
+
24
+ while (Date.now() - started < timeoutMs) {
25
+ const status = runBoardCli(['status', '--rg', boardDir], { capture: true });
26
+ const complete = tasks.every((task) => new RegExp(`\\bcompleted\\s+${task}\\b`).test(status));
27
+
28
+ if (complete) {
29
+ writeResult({
30
+ result: 'success',
31
+ data: {
32
+ label,
33
+ completed: true,
34
+ },
35
+ });
36
+ process.exit(0);
37
+ }
38
+
39
+ await sleep(pollMs);
40
+ }
41
+
42
+ writeResult({
43
+ result: 'timeout',
44
+ data: {
45
+ label,
46
+ completed: false,
47
+ error: `${label}: timed out waiting for completion`,
48
+ },
49
+ });
50
+ } catch (error) {
51
+ const message = error instanceof Error ? error.message : String(error);
52
+ writeFailure(message);
53
+ }
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env node
2
+
3
+ import * as fs from 'node:fs';
4
+ import * as path from 'node:path';
5
+ import { readStdinJson, writeFailure, writeResult } from './_board-cli.js';
6
+
7
+ try {
8
+ const input = await readStdinJson();
9
+ const boardDirInput = String(input.BOARD_DIR ?? '').trim();
10
+ const tmpFileName = String(input.TMP_FILE_NAME ?? '').trim() || 'tmp_file1';
11
+ const prices = input.PRICES;
12
+
13
+ if (!boardDirInput || !prices || typeof prices !== 'object' || Array.isArray(prices)) {
14
+ writeFailure('BOARD_DIR and PRICES object are required');
15
+ process.exit(0);
16
+ }
17
+
18
+ const boardDir = path.resolve(boardDirInput);
19
+ const payload = JSON.stringify(prices);
20
+ const tmpFile = path.join(boardDir, tmpFileName);
21
+
22
+ fs.mkdirSync(path.dirname(tmpFile), { recursive: true });
23
+ fs.writeFileSync(tmpFile, payload, 'utf-8');
24
+
25
+ writeResult({
26
+ result: 'success',
27
+ data: {
28
+ wrote: true,
29
+ tmp_file: tmpFile,
30
+ },
31
+ });
32
+ } catch (error) {
33
+ const message = error instanceof Error ? error.message : String(error);
34
+ writeFailure(message);
35
+ }
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Portfolio Tracker Task-Executor
4
+ *
5
+ * Implements the run-source-fetch protocol for board-live-cards.
6
+ * This script acts as an external task-executor that can be registered via .task-executor file.
7
+ *
8
+ * Contract:
9
+ * portfolio-tracker-task-executor.js run-source-fetch --in <defFile> --out <resultFile> --err <errFile>
10
+ *
11
+ * Input (--in file):
12
+ * JSON source definition with { cli: "...", bindTo: "...", outputFile: "...", ... }
13
+ *
14
+ * Output (on success):
15
+ * --out file contains the execution result
16
+ * Exit code: 0
17
+ *
18
+ * Output (on error):
19
+ * --err file contains error message
20
+ * Exit code: 1
21
+ */
22
+
23
+ const fs = require('fs');
24
+ const path = require('path');
25
+ const { execSync } = require('child_process');
26
+
27
+ // Parse command line arguments
28
+ const args = process.argv.slice(2);
29
+ let subcommand = '';
30
+ let inFile = '';
31
+ let outFile = '';
32
+ let errFile = '';
33
+
34
+ for (let i = 0; i < args.length; i++) {
35
+ if (args[i] === 'run-source-fetch') {
36
+ subcommand = 'run-source-fetch';
37
+ } else if (args[i] === '--in' && i + 1 < args.length) {
38
+ inFile = args[i + 1];
39
+ } else if (args[i] === '--out' && i + 1 < args.length) {
40
+ outFile = args[i + 1];
41
+ } else if (args[i] === '--err' && i + 1 < args.length) {
42
+ errFile = args[i + 1];
43
+ }
44
+ }
45
+
46
+ if (subcommand !== 'run-source-fetch' || !inFile || !outFile || !errFile) {
47
+ console.error('Usage: portfolio-tracker-task-executor.js run-source-fetch --in <defFile> --out <resultFile> --err <errFile>');
48
+ process.exit(1);
49
+ }
50
+
51
+ try {
52
+ // 1. Read source definition from --in file
53
+ console.log(`[portfolio-tracker-task-executor] Reading source definition from ${inFile}`);
54
+ const sourceDefStr = fs.readFileSync(inFile, 'utf-8');
55
+ const sourceDef = JSON.parse(sourceDefStr);
56
+
57
+ // 2. Extract cli command from source definition
58
+ const { cli: sourceCliCommand } = sourceDef;
59
+ if (!sourceCliCommand) {
60
+ throw new Error('cli is required in source definition');
61
+ }
62
+
63
+ console.log(`[portfolio-tracker-task-executor] Executing: ${sourceCliCommand}`);
64
+
65
+ // 3. Execute source.cli synchronously and capture output
66
+ let output;
67
+ try {
68
+ output = execSync(sourceCliCommand, {
69
+ encoding: 'utf-8',
70
+ timeout: (sourceDef.timeout ?? 120) * 1000, // Convert to ms
71
+ cwd: sourceDef.cwd,
72
+ shell: true,
73
+ stdio: ['pipe', 'pipe', 'pipe'], // Capture stdout/stderr
74
+ });
75
+ } catch (execErr) {
76
+ // Even on error, try to use what output we got
77
+ output = execErr.stdout || '';
78
+ if (!output) {
79
+ throw new Error(`Command execution failed: ${execErr.message}`);
80
+ }
81
+ }
82
+
83
+ // 4. Write output to --out file
84
+ console.log(`[portfolio-tracker-task-executor] Writing result to ${outFile}`);
85
+ fs.writeFileSync(outFile, output.trim(), 'utf-8');
86
+
87
+ console.log(`[portfolio-tracker-task-executor] Success`);
88
+ process.exit(0);
89
+ } catch (error) {
90
+ // 3a. On error: write error message to --err file and exit non-zero
91
+ const errorMsg = error instanceof Error ? error.message : String(error);
92
+ console.error(`[portfolio-tracker-task-executor] Error:`, errorMsg);
93
+
94
+ fs.writeFileSync(errFile, errorMsg, 'utf-8');
95
+ process.exit(1);
96
+ }
@@ -0,0 +1,227 @@
1
+ id: portfolio-tracker-step-machine
2
+ handler_vars:
3
+ BOARDCLI_CMD: ../../../board-live-cards-cli.js
4
+ TMP_FILE_NAME: tmp_file1
5
+ settings:
6
+ start_step: t0_reset_board
7
+ max_total_steps: 150
8
+ timeout_ms: 300000
9
+
10
+ steps:
11
+ t0_reset_board:
12
+ description: Reset board runtime directory for idempotent reruns
13
+ expects_data: [runtime_root, board_name]
14
+ produces_data: [board_dir]
15
+ handler:
16
+ cli: node ./handlers/reset-board-dir-cli.js
17
+ input-transforms:
18
+ BOARD_DIR: runtime_root & "/" & board_name
19
+ output-transforms:
20
+ board_dir: data.board_dir
21
+ transitions:
22
+ success: t0_init_board
23
+ failure_transitions:
24
+ failure: failed_state
25
+
26
+ t0_init_board:
27
+ description: Initialize board runtime directory
28
+ expects_data: [board_dir]
29
+ produces_data: [board_dir]
30
+ handler:
31
+ cli: node %%BOARDCLI_CMD%% init "%%BOARD_DIR%%"
32
+ result-mode: exit-code
33
+ input-transforms:
34
+ BOARD_DIR: board_dir
35
+ output-transforms:
36
+ board_dir: BOARD_DIR
37
+ transitions:
38
+ success: t0_add_cards
39
+ failure_transitions:
40
+ failure: failed_state
41
+
42
+ t0_add_cards:
43
+ description: Add local portfolio cards
44
+ expects_data: [board_dir, cards_template_dir]
45
+ produces_data: [cards_dir]
46
+ handler:
47
+ cli: node %%BOARDCLI_CMD%% add-cards --rg "%%BOARD_DIR%%" --card-glob "%%CARDS_GLOB%%"
48
+ result-mode: exit-code
49
+ input-transforms:
50
+ BOARD_DIR: board_dir
51
+ CARDS_GLOB: cards_template_dir & "/*.json"
52
+ output-transforms:
53
+ cards_dir: cards_template_dir
54
+ transitions:
55
+ success: t1_write_prices
56
+ failure_transitions:
57
+ failure: failed_state
58
+
59
+ t1_write_prices:
60
+ description: Write baseline prices
61
+ expects_data: [board_dir, prices_t1]
62
+ produces_data: [prices_written_t1]
63
+ handler:
64
+ cli: node ./handlers/write-prices-cli.js
65
+ input-transforms:
66
+ BOARD_DIR: board_dir
67
+ TMP_FILE_NAME: TMP_FILE_NAME
68
+ PRICES: prices_t1
69
+ output-transforms:
70
+ prices_written_t1: data.wrote
71
+ transitions:
72
+ success: t1_wait
73
+ failure_transitions:
74
+ failure: failed_state
75
+
76
+ t1_wait:
77
+ description: Wait for cards to complete after T1
78
+ expects_data: [board_dir, completion_tasks]
79
+ produces_data: [t1_done]
80
+ handler:
81
+ cli: node ./handlers/wait-completed-cli.js
82
+ input-transforms:
83
+ BOARD_DIR: board_dir
84
+ COMPLETION_TASKS: completion_tasks
85
+ LABEL: "'T1'"
86
+ TIMEOUT_MS: "60000"
87
+ POLL_MS: "500"
88
+ output-transforms:
89
+ t1_done: data.completed
90
+ transitions:
91
+ success: t2_update_holdings
92
+ failure_transitions:
93
+ timeout: failed_state
94
+ failure: failed_state
95
+
96
+ t2_update_holdings:
97
+ description: Add GOOG position to holdings
98
+ expects_data: [board_dir, cards_dir, holdings_t2]
99
+ produces_data: [t2_holdings_saved]
100
+ handler:
101
+ cli: node ./handlers/update-holdings-cli.js
102
+ input-transforms:
103
+ BOARD_DIR: board_dir
104
+ CARDS_DIR: cards_dir
105
+ HOLDINGS: holdings_t2
106
+ output-transforms:
107
+ t2_holdings_saved: data.saved
108
+ transitions:
109
+ success: t2_write_prices
110
+ failure_transitions:
111
+ failure: failed_state
112
+
113
+ t2_write_prices:
114
+ description: Write prices after T2 holdings update
115
+ expects_data: [board_dir, prices_t2]
116
+ produces_data: [prices_written_t2]
117
+ handler:
118
+ cli: node ./handlers/write-prices-cli.js
119
+ input-transforms:
120
+ BOARD_DIR: board_dir
121
+ TMP_FILE_NAME: TMP_FILE_NAME
122
+ PRICES: prices_t2
123
+ output-transforms:
124
+ prices_written_t2: data.wrote
125
+ transitions:
126
+ success: t2_wait
127
+ failure_transitions:
128
+ failure: failed_state
129
+
130
+ t2_wait:
131
+ description: Wait for cards to complete after T2
132
+ expects_data: [board_dir, completion_tasks]
133
+ produces_data: [t2_done]
134
+ handler:
135
+ cli: node ./handlers/wait-completed-cli.js
136
+ input-transforms:
137
+ BOARD_DIR: board_dir
138
+ COMPLETION_TASKS: completion_tasks
139
+ LABEL: "'T2'"
140
+ TIMEOUT_MS: "60000"
141
+ POLL_MS: "500"
142
+ output-transforms:
143
+ t2_done: data.completed
144
+ transitions:
145
+ success: t3_retrigger
146
+ failure_transitions:
147
+ timeout: failed_state
148
+ failure: failed_state
149
+
150
+ t3_retrigger:
151
+ description: Retrigger price-fetch task
152
+ expects_data: [board_dir, price_fetch_task]
153
+ produces_data: [t3_retriggered]
154
+ handler:
155
+ cli: node %%BOARDCLI_CMD%% retrigger --rg "%%BOARD_DIR%%" --task "%%TASK%%"
156
+ result-mode: exit-code
157
+ input-transforms:
158
+ BOARD_DIR: board_dir
159
+ TASK: price_fetch_task
160
+ output-transforms:
161
+ t3_retriggered: true
162
+ transitions:
163
+ success: t3_write_prices
164
+ failure_transitions:
165
+ failure: failed_state
166
+
167
+ t3_write_prices:
168
+ description: Write final refreshed prices
169
+ expects_data: [board_dir, prices_t3]
170
+ produces_data: [prices_written_t3]
171
+ handler:
172
+ cli: node ./handlers/write-prices-cli.js
173
+ input-transforms:
174
+ BOARD_DIR: board_dir
175
+ TMP_FILE_NAME: TMP_FILE_NAME
176
+ PRICES: prices_t3
177
+ output-transforms:
178
+ prices_written_t3: data.wrote
179
+ transitions:
180
+ success: t3_wait
181
+ failure_transitions:
182
+ failure: failed_state
183
+
184
+ t3_wait:
185
+ description: Wait for cards to complete after T3
186
+ expects_data: [board_dir, completion_tasks]
187
+ produces_data: [t3_done]
188
+ handler:
189
+ cli: node ./handlers/wait-completed-cli.js
190
+ input-transforms:
191
+ BOARD_DIR: board_dir
192
+ COMPLETION_TASKS: completion_tasks
193
+ LABEL: "'T3'"
194
+ TIMEOUT_MS: "60000"
195
+ POLL_MS: "500"
196
+ output-transforms:
197
+ t3_done: data.completed
198
+ transitions:
199
+ success: t4_status
200
+ failure_transitions:
201
+ timeout: failed_state
202
+ failure: failed_state
203
+
204
+ t4_status:
205
+ description: Capture final board status
206
+ expects_data: [board_dir]
207
+ produces_data: [final_status]
208
+ handler:
209
+ cli: node %%BOARDCLI_CMD%% status --rg "%%BOARD_DIR%%"
210
+ result-mode: exit-code
211
+ input-transforms:
212
+ BOARD_DIR: board_dir
213
+ output-transforms:
214
+ final_status: stdout
215
+ transitions:
216
+ success: success_state
217
+ failure_transitions:
218
+ failure: failed_state
219
+
220
+ terminal_states:
221
+ success_state:
222
+ return_intent: success
223
+ return_artifacts: [board_dir, t1_done, t2_done, t3_done, final_status]
224
+
225
+ failed_state:
226
+ return_intent: failure
227
+ return_artifacts: [error, board_dir, final_status]
@@ -0,0 +1,38 @@
1
+ {
2
+ "runtime_root": "./runtime",
3
+ "board_name": "portfolio-tracker-board",
4
+ "cards_template_dir": "./cards",
5
+ "completion_tasks": [
6
+ "portfolio-form",
7
+ "price-fetch",
8
+ "holdings-table",
9
+ "portfolio-value"
10
+ ],
11
+ "price_fetch_task": "price-fetch",
12
+ "prices_t1": {
13
+ "AAPL": 198.5,
14
+ "MSFT": 425.3,
15
+ "GOOG": 178.9,
16
+ "AMZN": 192.4,
17
+ "TSLA": 168.75
18
+ },
19
+ "holdings_t2": [
20
+ { "symbol": "AAPL", "qty": 50 },
21
+ { "symbol": "MSFT", "qty": 30 },
22
+ { "symbol": "GOOG", "qty": 100 }
23
+ ],
24
+ "prices_t2": {
25
+ "AAPL": 198.5,
26
+ "MSFT": 425.3,
27
+ "GOOG": 178.9,
28
+ "AMZN": 192.4,
29
+ "TSLA": 168.75
30
+ },
31
+ "prices_t3": {
32
+ "AAPL": 205,
33
+ "MSFT": 425.3,
34
+ "GOOG": 178.9,
35
+ "AMZN": 192.4,
36
+ "TSLA": 168.75
37
+ }
38
+ }