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
@@ -7,7 +7,7 @@
7
7
  * - Progress tracking
8
8
  * - Mixed success/failure handling
9
9
  *
10
- * Run with: npx tsx examples/batch/batch-step-machine.ts
10
+ * Run with: npx tsx examples/npm-libs/batch/batch-step-machine.ts
11
11
  */
12
12
 
13
13
  import { batch } from '../../src/batch/index.js';
@@ -16,7 +16,7 @@
16
16
  * - LiveBoard overload — board.id, board.settings forwarded to GraphConfig
17
17
  * - validateReactiveGraph on the resulting graph
18
18
  *
19
- * Run with: npx tsx examples/continuous-event-graph/live-cards-board.ts
19
+ * Run with: npx tsx examples/npm-libs/continuous-event-graph/live-cards-board.ts
20
20
  */
21
21
 
22
22
  import {
@@ -22,7 +22,7 @@
22
22
  * Dynamically added: allocation-chart, risk-score, daily-pnl,
23
23
  * value-alert, summary, correlation, combined-view
24
24
  *
25
- * Run with: npx tsx examples/continuous-event-graph/live-portfolio-dashboard.ts
25
+ * Run with: npx tsx examples/npm-libs/continuous-event-graph/live-portfolio-dashboard.ts
26
26
  */
27
27
 
28
28
  import * as fs from 'node:fs';
@@ -29,7 +29,7 @@
29
29
  * T3: Force price refresh without form change → retrigger('price-fetch')
30
30
  * T4: Quiescent
31
31
  *
32
- * Run with: npx tsx examples/continuous-event-graph/portfolio-tracker.ts
32
+ * Run with: npx tsx examples/npm-libs/continuous-event-graph/portfolio-tracker.ts
33
33
  */
34
34
 
35
35
  import type { GraphConfig } from '../../src/event-graph/types.js';
@@ -15,7 +15,7 @@
15
15
  * Scenario: A monitoring system that collects metrics, evaluates alerts,
16
16
  * and dynamically adds notification channels at runtime.
17
17
  *
18
- * Run with: npx tsx examples/continuous-event-graph/reactive-monitoring.ts
18
+ * Run with: npx tsx examples/npm-libs/continuous-event-graph/reactive-monitoring.ts
19
19
  */
20
20
 
21
21
  import {
@@ -9,7 +9,7 @@
9
9
  * - validateLiveGraph for runtime state-consistency checks
10
10
  * - validateReactiveGraph for handler/dispatch checks
11
11
  *
12
- * Run with: npx tsx examples/continuous-event-graph/reactive-pipeline.ts
12
+ * Run with: npx tsx examples/npm-libs/continuous-event-graph/reactive-pipeline.ts
13
13
  */
14
14
 
15
15
  import {
@@ -31,7 +31,7 @@
31
31
  * T1: New intel arrives → retrigger threat-intel → data-changed cascade
32
32
  * create-ticket skipped (once) — slack re-fires
33
33
  *
34
- * Run with: npx tsx examples/continuous-event-graph/soc-incident-board.ts
34
+ * Run with: npx tsx examples/npm-libs/continuous-event-graph/soc-incident-board.ts
35
35
  */
36
36
 
37
37
  import type { GraphConfig } from '../../src/event-graph/types.js';
@@ -10,7 +10,7 @@
10
10
  * - Scheduling adapts as the graph evolves
11
11
  * - Snapshots allow persistence and restore
12
12
  *
13
- * Run with: npx tsx examples/continuous-event-graph/stock-dashboard.ts
13
+ * Run with: npx tsx examples/npm-libs/continuous-event-graph/stock-dashboard.ts
14
14
  */
15
15
 
16
16
  import {
@@ -8,7 +8,7 @@
8
8
  * - Retry configuration
9
9
  * - Stuck detection
10
10
  *
11
- * Run with: npx tsx examples/event-graph/ci-cd-pipeline.ts
11
+ * Run with: npx tsx examples/npm-libs/event-graph/ci-cd-pipeline.ts
12
12
  */
13
13
 
14
14
  import {
@@ -12,7 +12,7 @@
12
12
  * |
13
13
  * report
14
14
  *
15
- * Run with: npx tsx examples/event-graph/executor-diamond.ts
15
+ * Run with: npx tsx examples/npm-libs/event-graph/executor-diamond.ts
16
16
  */
17
17
 
18
18
  import {
@@ -11,7 +11,7 @@
11
11
  *
12
12
  * Contrast with reactive-pipeline.ts where the graph drives itself.
13
13
  *
14
- * Run with: npx tsx examples/event-graph/executor-pipeline.ts
14
+ * Run with: npx tsx examples/npm-libs/event-graph/executor-pipeline.ts
15
15
  */
16
16
 
17
17
  import {
@@ -6,7 +6,7 @@
6
6
  * - Goal-based completion
7
7
  * - The standard next() / apply() driver loop
8
8
  *
9
- * Run with: npx tsx examples/event-graph/research-pipeline.ts
9
+ * Run with: npx tsx examples/npm-libs/event-graph/research-pipeline.ts
10
10
  */
11
11
 
12
12
  import {
@@ -21,7 +21,7 @@
21
21
  * Inner transform flow (step-machine, per record):
22
22
  * parse → validate → normalize → enrich → (accept | reject)
23
23
  *
24
- * Run with: npx tsx examples/graph-of-graphs/multi-stage-etl.ts
24
+ * Run with: npx tsx examples/npm-libs/graph-of-graphs/multi-stage-etl.ts
25
25
  */
26
26
 
27
27
  import {
@@ -19,7 +19,7 @@
19
19
  * - resolveConfigTemplates() for DRY task configs
20
20
  * - Parallel fan-out inside inner graph
21
21
  *
22
- * Run with: npx tsx examples/graph-of-graphs/url-processing-pipeline.ts
22
+ * Run with: npx tsx examples/npm-libs/graph-of-graphs/url-processing-pipeline.ts
23
23
  */
24
24
 
25
25
  import {
@@ -5,7 +5,7 @@
5
5
  * The graph has 3 checkpoints. After deployment, the LLM analyzes
6
6
  * logs and determines what's complete.
7
7
  *
8
- * Run with: npx tsx examples/inference/azure-deployment.ts
8
+ * Run with: npx tsx examples/npm-libs/inference/azure-deployment.ts
9
9
  */
10
10
 
11
11
  import {
@@ -8,7 +8,7 @@
8
8
  * - GitHub Copilot CLI installed (comes with VS Code / GitHub Copilot extension)
9
9
  * - `copilot` available on PATH
10
10
  *
11
- * Run with: npx tsx examples/inference/copilot-cli.ts
11
+ * Run with: npx tsx examples/npm-libs/inference/copilot-cli.ts
12
12
  */
13
13
 
14
14
  import { createLiveGraph, schedule } from '../../src/continuous-event-graph/index.js';
@@ -4,7 +4,7 @@
4
4
  * Demonstrates iterative inference — run the LLM multiple times as
5
5
  * new evidence arrives. Each round may unlock more tasks.
6
6
  *
7
- * Run with: npx tsx examples/inference/data-pipeline.ts
7
+ * Run with: npx tsx examples/npm-libs/inference/data-pipeline.ts
8
8
  */
9
9
 
10
10
  import {
@@ -4,7 +4,7 @@
4
4
  * Shows how to create adapters for different LLM providers.
5
5
  * Each adapter implements InferenceAdapter.analyze(prompt) → string.
6
6
  *
7
- * Run with: npx tsx examples/inference/pluggable-adapters.ts
7
+ * Run with: npx tsx examples/npm-libs/inference/pluggable-adapters.ts
8
8
  */
9
9
 
10
10
  import {
@@ -7,7 +7,7 @@
7
7
  * - Circuit breakers
8
8
  * - Event handling
9
9
  *
10
- * Run with: npx ts-node examples/node/ai-conversation.ts
10
+ * Run with: npx ts-node examples/npm-libs/node/ai-conversation.ts
11
11
  */
12
12
 
13
13
  import { createEngine, loadFlow, MemoryStore } from '../../src/index.js';
@@ -3,8 +3,8 @@
3
3
  *
4
4
  * Demonstrates basic usage with file-based persistence.
5
5
  *
6
- * Run with: npx ts-node examples/node/simple-greeting.ts
7
- * Or after build: node examples/node/simple-greeting.js
6
+ * Run with: npx ts-node examples/npm-libs/node/simple-greeting.ts
7
+ * Or after build: node examples/npm-libs/node/simple-greeting.js
8
8
  */
9
9
 
10
10
  import { createEngine, loadFlow, FileStore } from '../../src/index.js';
@@ -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
+ }