yaml-flow 3.1.1 → 4.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 (148) hide show
  1. package/README.md +81 -20
  2. package/board-live-cards-cli.js +37 -0
  3. package/browser/card-compute.js +132 -431
  4. package/browser/live-cards.js +41 -27
  5. package/browser/live-cards.schema.json +59 -77
  6. package/dist/card-compute/index.cjs +135 -415
  7. package/dist/card-compute/index.cjs.map +1 -1
  8. package/dist/card-compute/index.d.cts +52 -49
  9. package/dist/card-compute/index.d.ts +52 -49
  10. package/dist/card-compute/index.js +134 -415
  11. package/dist/card-compute/index.js.map +1 -1
  12. package/dist/cli/board-live-cards-cli.cjs +2379 -0
  13. package/dist/cli/board-live-cards-cli.cjs.map +1 -0
  14. package/dist/cli/board-live-cards-cli.d.cts +213 -0
  15. package/dist/cli/board-live-cards-cli.d.ts +213 -0
  16. package/dist/cli/board-live-cards-cli.js +2332 -0
  17. package/dist/cli/board-live-cards-cli.js.map +1 -0
  18. package/dist/{constants-B2zqu10b.d.ts → constants-DuzE5n03.d.ts} +2 -2
  19. package/dist/{constants-DJZU1pwJ.d.cts → constants-ozjf1Ejw.d.cts} +2 -2
  20. package/dist/continuous-event-graph/index.cjs +201 -448
  21. package/dist/continuous-event-graph/index.cjs.map +1 -1
  22. package/dist/continuous-event-graph/index.d.cts +16 -340
  23. package/dist/continuous-event-graph/index.d.ts +16 -340
  24. package/dist/continuous-event-graph/index.js +198 -448
  25. package/dist/continuous-event-graph/index.js.map +1 -1
  26. package/dist/event-graph/index.cjs +4 -4
  27. package/dist/event-graph/index.cjs.map +1 -1
  28. package/dist/event-graph/index.d.cts +5 -5
  29. package/dist/event-graph/index.d.ts +5 -5
  30. package/dist/event-graph/index.js +4 -4
  31. package/dist/event-graph/index.js.map +1 -1
  32. package/dist/index.cjs +278 -533
  33. package/dist/index.cjs.map +1 -1
  34. package/dist/index.d.cts +8 -7
  35. package/dist/index.d.ts +8 -7
  36. package/dist/index.js +278 -533
  37. package/dist/index.js.map +1 -1
  38. package/dist/inference/index.cjs +138 -19
  39. package/dist/inference/index.cjs.map +1 -1
  40. package/dist/inference/index.d.cts +2 -2
  41. package/dist/inference/index.d.ts +2 -2
  42. package/dist/inference/index.js +138 -19
  43. package/dist/inference/index.js.map +1 -1
  44. package/dist/journal-BJDjWb5Q.d.cts +343 -0
  45. package/dist/journal-B_2JnBMF.d.ts +343 -0
  46. package/dist/step-machine/index.cjs +18 -1
  47. package/dist/step-machine/index.cjs.map +1 -1
  48. package/dist/step-machine/index.d.cts +2 -2
  49. package/dist/step-machine/index.d.ts +2 -2
  50. package/dist/step-machine/index.js +18 -1
  51. package/dist/step-machine/index.js.map +1 -1
  52. package/dist/stores/file.d.cts +1 -1
  53. package/dist/stores/file.d.ts +1 -1
  54. package/dist/stores/index.d.cts +1 -1
  55. package/dist/stores/index.d.ts +1 -1
  56. package/dist/stores/localStorage.d.cts +1 -1
  57. package/dist/stores/localStorage.d.ts +1 -1
  58. package/dist/stores/memory.d.cts +1 -1
  59. package/dist/stores/memory.d.ts +1 -1
  60. package/dist/{types-BwvgvlOO.d.cts → types-BzLD8bjb.d.cts} +1 -1
  61. package/dist/{types-ClRA8hzC.d.ts → types-C2eJ7DAV.d.ts} +1 -1
  62. package/dist/{types-DEj7OakX.d.cts → types-CMFSIjpc.d.cts} +39 -4
  63. package/dist/{types-DEj7OakX.d.ts → types-CMFSIjpc.d.ts} +39 -4
  64. package/dist/{types-FZ_eyErS.d.cts → types-ycun84cq.d.cts} +1 -0
  65. package/dist/{types-FZ_eyErS.d.ts → types-ycun84cq.d.ts} +1 -0
  66. package/dist/{validate-DEZ2Ymdb.d.ts → validate-DJQTQ6bP.d.ts} +1 -1
  67. package/dist/{validate-DqKTZg_o.d.cts → validate-ke92Cleg.d.cts} +1 -1
  68. package/examples/browser/boards/portfolio-tracker/cards/holdings-table.json +22 -0
  69. package/examples/browser/boards/portfolio-tracker/cards/portfolio-form.json +16 -0
  70. package/examples/browser/boards/portfolio-tracker/cards/portfolio-value.json +15 -0
  71. package/examples/browser/boards/portfolio-tracker/cards/price-fetch.json +15 -0
  72. package/examples/browser/boards/portfolio-tracker/fetch-prices.js +43 -0
  73. package/examples/browser/boards/portfolio-tracker/portfolio-tracker.bat +7 -0
  74. package/examples/browser/boards/portfolio-tracker/portfolio-tracker.js +189 -0
  75. package/examples/browser/livecards-browser/index.html +688 -0
  76. package/examples/browser/{index.html → step-machine-browser/index.html} +53 -53
  77. package/examples/cli/step-machine-cli/portfolio-tracker/cards/holdings-table.json +22 -0
  78. package/examples/cli/step-machine-cli/portfolio-tracker/cards/portfolio-form.json +43 -0
  79. package/examples/cli/step-machine-cli/portfolio-tracker/cards/portfolio-value.json +15 -0
  80. package/examples/cli/step-machine-cli/portfolio-tracker/cards/price-fetch.json +15 -0
  81. package/examples/cli/step-machine-cli/portfolio-tracker/fetch-prices.js +48 -0
  82. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/_board-cli.js +58 -0
  83. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/add-cards-cli.js +27 -0
  84. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/init-board-cli.js +25 -0
  85. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/reset-board-dir-cli.js +29 -0
  86. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/retrigger-cli.js +27 -0
  87. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/status-cli.js +25 -0
  88. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/update-holdings-cli.js +37 -0
  89. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/wait-completed-cli.js +53 -0
  90. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/write-prices-cli.js +35 -0
  91. package/examples/cli/step-machine-cli/portfolio-tracker/portfolio-tracker.flow.yaml +227 -0
  92. package/examples/cli/step-machine-cli/portfolio-tracker/portfolio-tracker.input.json +38 -0
  93. package/examples/cli/step-machine-cli/portfolio-tracker/run-portfolio-tracker.bat +29 -0
  94. package/examples/cli/step-machine-demo/jsonata-init-board-cli.js +36 -0
  95. package/examples/cli/step-machine-demo/jsonata-init-board.flow.yaml +30 -0
  96. package/examples/cli/step-machine-demo/one-step-cli-only.flow.yaml +19 -0
  97. package/examples/cli/step-machine-demo/step-cli-echo-y.js +15 -0
  98. package/examples/cli/step-machine-demo/step2-double-cli.js +39 -0
  99. package/examples/cli/step-machine-demo/two-step-math-handlers.js +32 -0
  100. package/examples/cli/step-machine-demo/two-step-math.flow.yaml +31 -0
  101. package/examples/cli/step-machine-demo/two-step-mixed-handlers.js +24 -0
  102. package/examples/cli/step-machine-demo/two-step-mixed.flow.yaml +35 -0
  103. package/examples/index.html +792 -0
  104. package/examples/{batch → npm-libs/batch}/batch-step-machine.ts +1 -1
  105. package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/live-cards-board.ts +1 -1
  106. package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/live-portfolio-dashboard.ts +1 -1
  107. package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/portfolio-tracker.ts +1 -1
  108. package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/reactive-monitoring.ts +1 -1
  109. package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/reactive-pipeline.ts +1 -1
  110. package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/soc-incident-board.ts +1 -1
  111. package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/stock-dashboard.ts +1 -1
  112. package/examples/{event-graph → npm-libs/event-graph}/ci-cd-pipeline.ts +1 -1
  113. package/examples/{event-graph → npm-libs/event-graph}/executor-diamond.ts +1 -1
  114. package/examples/{event-graph → npm-libs/event-graph}/executor-pipeline.ts +1 -1
  115. package/examples/{event-graph → npm-libs/event-graph}/research-pipeline.ts +1 -1
  116. package/examples/{graph-of-graphs → npm-libs/graph-of-graphs}/multi-stage-etl.ts +1 -1
  117. package/examples/{graph-of-graphs → npm-libs/graph-of-graphs}/url-processing-pipeline.ts +1 -1
  118. package/examples/{inference → npm-libs/inference}/azure-deployment.ts +1 -1
  119. package/examples/{inference → npm-libs/inference}/copilot-cli.ts +1 -1
  120. package/examples/{inference → npm-libs/inference}/data-pipeline.ts +1 -1
  121. package/examples/{inference → npm-libs/inference}/pluggable-adapters.ts +1 -1
  122. package/examples/{node → npm-libs/node}/ai-conversation.ts +1 -1
  123. package/examples/{node → npm-libs/node}/simple-greeting.ts +2 -2
  124. package/examples/step-machine-cli/portfolio-tracker/cards/holdings-table.json +22 -0
  125. package/examples/step-machine-cli/portfolio-tracker/cards/portfolio-form.json +43 -0
  126. package/examples/step-machine-cli/portfolio-tracker/cards/portfolio-value.json +15 -0
  127. package/examples/step-machine-cli/portfolio-tracker/cards/price-fetch.json +15 -0
  128. package/examples/step-machine-cli/portfolio-tracker/fetch-prices.js +48 -0
  129. package/examples/step-machine-cli/portfolio-tracker/handlers/_board-cli.js +58 -0
  130. package/examples/step-machine-cli/portfolio-tracker/handlers/add-cards-cli.js +27 -0
  131. package/examples/step-machine-cli/portfolio-tracker/handlers/init-board-cli.js +25 -0
  132. package/examples/step-machine-cli/portfolio-tracker/handlers/reset-board-dir-cli.js +29 -0
  133. package/examples/step-machine-cli/portfolio-tracker/handlers/retrigger-cli.js +27 -0
  134. package/examples/step-machine-cli/portfolio-tracker/handlers/status-cli.js +25 -0
  135. package/examples/step-machine-cli/portfolio-tracker/handlers/update-holdings-cli.js +37 -0
  136. package/examples/step-machine-cli/portfolio-tracker/handlers/wait-completed-cli.js +53 -0
  137. package/examples/step-machine-cli/portfolio-tracker/handlers/write-prices-cli.js +35 -0
  138. package/examples/step-machine-cli/portfolio-tracker/portfolio-tracker.flow.yaml +227 -0
  139. package/examples/step-machine-cli/portfolio-tracker/portfolio-tracker.input.json +38 -0
  140. package/examples/step-machine-cli/portfolio-tracker/run-portfolio-tracker.bat +29 -0
  141. package/package.json +12 -1
  142. package/schema/board-status.schema.json +118 -0
  143. package/schema/flow.schema.json +5 -0
  144. package/schema/live-cards.schema.json +59 -77
  145. package/step-machine-cli.js +674 -0
  146. /package/examples/{flows → npm-libs/flows}/ai-conversation.yaml +0 -0
  147. /package/examples/{flows → npm-libs/flows}/order-processing.yaml +0 -0
  148. /package/examples/{flows → npm-libs/flows}/simple-greeting.yaml +0 -0
@@ -1,58 +1,58 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en">
3
3
  <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>yaml-flow Browser Example</title>
7
- <style>
8
- * { box-sizing: border-box; }
9
- body {
10
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
11
- max-width: 800px;
12
- margin: 40px auto;
13
- padding: 20px;
14
- background: #f5f5f5;
15
- }
16
- h1 { color: #333; }
17
- .card {
18
- background: white;
19
- border-radius: 8px;
20
- padding: 20px;
21
- margin: 20px 0;
22
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
23
- }
24
- .step-list {
25
- display: flex;
26
- gap: 10px;
27
- flex-wrap: wrap;
28
- margin: 10px 0;
29
- }
30
- .step {
31
- padding: 8px 16px;
32
- border-radius: 20px;
33
- background: #e0e0e0;
34
- font-size: 14px;
35
- }
36
- .step.active {
37
- background: #2196F3;
38
- color: white;
39
- }
40
- .step.completed {
41
- background: #4CAF50;
42
- color: white;
43
- }
44
- button {
45
- background: #2196F3;
46
- color: white;
47
- border: none;
48
- padding: 12px 24px;
49
- border-radius: 6px;
50
- cursor: pointer;
51
- font-size: 16px;
52
- margin: 5px;
53
- }
54
- button:hover { background: #1976D2; }
55
- button:disabled { background: #ccc; cursor: not-allowed; }
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>Step Machine Browser Example — yaml-flow</title>
7
+ <style>
8
+ * { box-sizing: border-box; }
9
+ body {
10
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
11
+ max-width: 800px;
12
+ margin: 40px auto;
13
+ padding: 20px;
14
+ background: #f5f5f5;
15
+ }
16
+ h1 { color: #333; }
17
+ .card {
18
+ background: white;
19
+ border-radius: 8px;
20
+ padding: 20px;
21
+ margin: 20px 0;
22
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
23
+ }
24
+ .step-list {
25
+ display: flex;
26
+ gap: 10px;
27
+ flex-wrap: wrap;
28
+ margin: 10px 0;
29
+ }
30
+ .step {
31
+ padding: 8px 16px;
32
+ border-radius: 20px;
33
+ background: #e0e0e0;
34
+ font-size: 14px;
35
+ }
36
+ .step.active {
37
+ background: #2196F3;
38
+ color: white;
39
+ }
40
+ .step.completed {
41
+ background: #4CAF50;
42
+ color: white;
43
+ }
44
+ button {
45
+ background: #2196F3;
46
+ color: white;
47
+ border: none;
48
+ padding: 12px 24px;
49
+ border-radius: 6px;
50
+ cursor: pointer;
51
+ font-size: 16px;
52
+ margin: 5px;
53
+ }
54
+ button:hover { background: #1976D2; }
55
+ button:disabled { background: #ccc; cursor: not-allowed; }
56
56
  .log {
57
57
  background: #263238;
58
58
  color: #aed581;
@@ -83,7 +83,7 @@
83
83
  </style>
84
84
  </head>
85
85
  <body>
86
- <h1>🔄 yaml-flow Browser Demo</h1>
86
+ <h1>yaml-flow Step Machine Browser Example</h1>
87
87
 
88
88
  <div class="card">
89
89
  <h2>Simple Greeting Flow</h2>
@@ -0,0 +1,22 @@
1
+ {
2
+ "id": "holdings-table",
3
+ "meta": { "title": "Holdings Table" },
4
+ "requires": ["holdings", "prices"],
5
+ "provides": [{ "bindTo": "table", "src": "computed_values.table" }],
6
+ "state": {},
7
+ "compute": [
8
+ {
9
+ "bindTo": "table",
10
+ "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) } }) }"
11
+ }
12
+ ],
13
+ "view": {
14
+ "elements": [
15
+ {
16
+ "kind": "table",
17
+ "label": "Portfolio Positions",
18
+ "data": { "bind": "computed_values.table.rows", "columns": ["symbol", "qty", "price", "value"] }
19
+ }
20
+ ]
21
+ }
22
+ }
@@ -0,0 +1,43 @@
1
+ {
2
+ "id": "portfolio-form",
3
+ "meta": {
4
+ "title": "Portfolio Holdings Form"
5
+ },
6
+ "provides": [
7
+ {
8
+ "bindTo": "holdings",
9
+ "src": "state.holdings"
10
+ }
11
+ ],
12
+ "state": {
13
+ "holdings": [
14
+ {
15
+ "symbol": "AAPL",
16
+ "qty": 50
17
+ },
18
+ {
19
+ "symbol": "MSFT",
20
+ "qty": 30
21
+ },
22
+ {
23
+ "symbol": "GOOG",
24
+ "qty": 100
25
+ }
26
+ ]
27
+ },
28
+ "view": {
29
+ "elements": [
30
+ {
31
+ "kind": "table",
32
+ "label": "Holdings",
33
+ "data": {
34
+ "bind": "state.holdings",
35
+ "columns": [
36
+ "symbol",
37
+ "qty"
38
+ ]
39
+ }
40
+ }
41
+ ]
42
+ }
43
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "id": "portfolio-value",
3
+ "meta": { "title": "Portfolio Total Value" },
4
+ "requires": ["table"],
5
+ "provides": [{ "bindTo": "totalValue", "src": "computed_values.totalValue" }],
6
+ "state": {},
7
+ "compute": [
8
+ { "bindTo": "totalValue", "expr": "$sum(requires.table.rows.value)" }
9
+ ],
10
+ "view": {
11
+ "elements": [
12
+ { "kind": "metric", "label": "Total Portfolio Value", "data": { "bind": "computed_values.totalValue" } }
13
+ ]
14
+ }
15
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "id": "price-fetch",
3
+ "meta": { "title": "Fetch Market Prices" },
4
+ "requires": ["holdings"],
5
+ "provides": [{ "bindTo": "prices", "src": "sources.prices" }],
6
+ "state": {},
7
+ "sources": [
8
+ { "cli": "node ../fetch-prices.js --tmp-file-name tmp_file1", "bindTo": "prices", "outputFile": "prices.json" }
9
+ ],
10
+ "view": {
11
+ "elements": [
12
+ { "kind": "table", "label": "Market Prices", "data": { "bind": "sources.prices" } }
13
+ ]
14
+ }
15
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * fetch-prices.js
3
+ * Polls for tmp_file1 payload and outputs JSON to stdout once available.
4
+ */
5
+ import * as fs from 'node:fs';
6
+ import * as path from 'node:path';
7
+
8
+ function getArgValue(flagName) {
9
+ const idx = process.argv.indexOf(flagName);
10
+ if (idx < 0) return undefined;
11
+ return process.argv[idx + 1];
12
+ }
13
+
14
+ const envBoardDir = (process.env.BOARD_DIR ?? '').trim();
15
+ const tmpFileName = String(getArgValue('--tmp-file-name') ?? process.env.TMP_FILE_NAME ?? 'tmp_file1').trim();
16
+ const tmpFilePath = envBoardDir ? path.join(envBoardDir, tmpFileName) : '';
17
+
18
+ if (!tmpFilePath) {
19
+ console.error('BOARD_DIR environment variable is required for fetch-prices.js');
20
+ process.exit(1);
21
+ }
22
+
23
+ function getReadableTmpFile() {
24
+ if (!fs.existsSync(tmpFilePath)) return undefined;
25
+ const content = fs.readFileSync(tmpFilePath, 'utf-8').trim();
26
+ if (!content) return undefined;
27
+ return { tmpFile: tmpFilePath, content };
28
+ }
29
+
30
+ function waitForFile(timeoutMs = 120000) {
31
+ const started = Date.now();
32
+ const interval = setInterval(() => {
33
+ if (Date.now() - started > timeoutMs) {
34
+ clearInterval(interval);
35
+ console.error('Timed out waiting for tmp_file1 market prices input.');
36
+ process.exit(1);
37
+ }
38
+
39
+ const ready = getReadableTmpFile();
40
+ if (!ready) return;
41
+
42
+ clearInterval(interval);
43
+ fs.writeFileSync(ready.tmpFile, '', 'utf-8');
44
+ process.stdout.write(`${ready.content}\n`);
45
+ }, 250);
46
+ }
47
+
48
+ waitForFile();
@@ -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
+ }