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,28 @@
1
+ {
2
+ "id": "card-ex-source-http",
3
+ "meta": {
4
+ "title": "Product Prices",
5
+ "tags": ["data", "linked"],
6
+ "desc": "Fetches pricing for products derived from upstream order data"
7
+ },
8
+ "requires": ["orders"],
9
+ "provides": [{ "bindTo": "prices", "src": "fetched_sources.raw" }],
10
+ "sources": [{
11
+ "bindTo": "raw",
12
+ "outputFile": "card-ex-source-http-raw.json",
13
+ "mock": "prices"
14
+ }],
15
+ "compute": [
16
+ {
17
+ "bindTo": "PRODUCT_LIST",
18
+ "expr": "$join($distinct(requires.orders.product), ',')"
19
+ }
20
+ ],
21
+ "view": {
22
+ "elements": [
23
+ { "kind": "table", "data": { "bind": "fetched_sources.raw", "columns": ["product", "price", "currency"], "sortable": true } }
24
+ ],
25
+ "layout": { "board": { "col": 6, "order": 2 }, "canvas": { "x": 450, "y": 50, "w": 350, "h": 220 } }
26
+ },
27
+ "card_data": {}
28
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "id": "card-ex-source",
3
+ "meta": {
4
+ "title": "Order Data",
5
+ "tags": ["data"],
6
+ "desc": "Root data source — fetches order records via a script"
7
+ },
8
+ "provides": [{ "bindTo": "orders", "src": "fetched_sources.raw" }],
9
+ "sources": [{
10
+ "bindTo": "raw",
11
+ "outputFile": "card-ex-source-raw.json",
12
+ "mock": "orders"
13
+ }],
14
+ "view": {
15
+ "elements": [
16
+ { "kind": "table", "data": { "bind": "fetched_sources.raw", "columns": ["id", "product", "quantity", "amount", "region"], "maxRows": 10 } }
17
+ ],
18
+ "layout": { "board": { "col": 6, "order": 1 }, "canvas": { "x": 50, "y": 50, "w": 350, "h": 220 } }
19
+ },
20
+ "card_data": {}
21
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ "id": "card-ex-status",
3
+ "meta": {
4
+ "title": "Revenue Health",
5
+ "tags": [],
6
+ "desc": "Status badge with threshold logic — JSONata ternary for green/amber/red"
7
+ },
8
+ "requires": ["orders"],
9
+ "compute": [
10
+ { "bindTo": "totalRevenue", "expr": "$sum(requires.orders.amount)" },
11
+ { "bindTo": "orderCount", "expr": "$count(requires.orders)" },
12
+ {
13
+ "bindTo": "health",
14
+ "expr": "computed_values.totalRevenue > 100000 ? { 'label': 'Healthy', 'value': computed_values.totalRevenue, 'orders': computed_values.orderCount } : computed_values.totalRevenue > 50000 ? { 'label': 'Moderate', 'value': computed_values.totalRevenue, 'orders': computed_values.orderCount } : { 'label': 'Low', 'value': computed_values.totalRevenue, 'orders': computed_values.orderCount }"
15
+ }
16
+ ],
17
+ "view": {
18
+ "elements": [
19
+ {
20
+ "kind": "badge",
21
+ "data": {
22
+ "bind": "computed_values.health.label",
23
+ "colorMap": { "Healthy": "success", "Moderate": "warning", "Low": "danger" }
24
+ }
25
+ },
26
+ {
27
+ "kind": "metric",
28
+ "label": "Revenue",
29
+ "data": { "bind": "computed_values.health.value" }
30
+ }
31
+ ],
32
+ "layout": { "board": { "col": 3, "order": 8 }, "canvas": { "x": 450, "y": 530, "w": 200, "h": 170 } }
33
+ },
34
+ "card_data": {}
35
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "id": "card-ex-table",
3
+ "meta": {
4
+ "title": "Order Details",
5
+ "tags": [],
6
+ "desc": "Filtered and sorted table — combines source data with user filter selections"
7
+ },
8
+ "requires": ["orders", "selections"],
9
+ "compute": [
10
+ {
11
+ "bindTo": "filtered",
12
+ "expr": "[$filter(requires.orders, function($v){ ($exists(requires.selections.region) ? $v.region = requires.selections.region : true) and ($exists(requires.selections.product) ? $v.product = requires.selections.product : true) })^(>amount)#$i[$i<20]]"
13
+ }
14
+ ],
15
+ "view": {
16
+ "elements": [
17
+ {
18
+ "kind": "table",
19
+ "data": {
20
+ "bind": "computed_values.filtered",
21
+ "columns": ["id", "product", "quantity", "amount", "region"],
22
+ "sortable": true,
23
+ "maxRows": 20
24
+ }
25
+ }
26
+ ],
27
+ "layout": { "board": { "col": 8, "order": 7 }, "canvas": { "x": 50, "y": 800, "w": 500, "h": 250 } }
28
+ },
29
+ "card_data": {}
30
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "id": "card-ex-todo",
3
+ "meta": {
4
+ "title": "Action Items",
5
+ "tags": [],
6
+ "desc": "Interactive todo list — persistent user input via writeTo"
7
+ },
8
+ "view": {
9
+ "elements": [
10
+ {
11
+ "kind": "todo",
12
+ "label": "Tasks",
13
+ "data": {
14
+ "bind": "card_data.items",
15
+ "writeTo": "card_data.items",
16
+ "placeholder": "No tasks yet — add one above"
17
+ }
18
+ }
19
+ ],
20
+ "layout": { "board": { "col": 4, "order": 11 }, "canvas": { "x": 700, "y": 320, "w": 260, "h": 180 } }
21
+ },
22
+ "card_data": {
23
+ "items": [
24
+ { "text": "Set up task-executor for your data sources", "done": false },
25
+ { "text": "Configure board.yaml connections", "done": false },
26
+ { "text": "Run board-live-cards-cli init", "done": false }
27
+ ]
28
+ }
29
+ }
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env node
2
+ // demo-chat-handler.js — Echo chat handler for demo/example boards.
3
+ //
4
+ // Invoked by reusable-server-runtime after a user chat message is persisted,
5
+ // when a .chat-handler file is present in the board runtime directory.
6
+ //
7
+ // Invocation contract:
8
+ // node demo-chat-handler.js --boardId <id> --cardId <id> --extra <json>
9
+ //
10
+ // --extra JSON shape: { chatDir: "<abs path>", boardDir: "<abs path>", lastChatFile: "<filename>" }
11
+ //
12
+ // This demo handler:
13
+ // 1. Reads the content of the last chat file (the user message just written).
14
+ // 2. Computes the next serial by incrementing the leading number from lastChatFile.
15
+ // 3. Writes <nextSerial>-assistant.txt to chatDir with: "Echoing <original content>"
16
+
17
+ import * as fs from 'node:fs';
18
+ import * as path from 'node:path';
19
+
20
+ const args = process.argv.slice(2);
21
+
22
+ function getArg(name) {
23
+ const idx = args.indexOf(name);
24
+ return idx !== -1 && args[idx + 1] !== undefined ? args[idx + 1] : null;
25
+ }
26
+
27
+ const boardId = getArg('--boardId') || '';
28
+ const cardId = getArg('--cardId') || '';
29
+ const extraStr = getArg('--extraEncJson') || '';
30
+
31
+ let extra = {};
32
+ try {
33
+ extra = JSON.parse(Buffer.from(extraStr, 'base64').toString('utf-8'));
34
+ } catch {
35
+ console.error('[demo-chat-handler] could not parse --extra JSON');
36
+ process.exit(0);
37
+ }
38
+
39
+ const { chatDir, lastChatFile } = extra;
40
+
41
+ if (!chatDir || !lastChatFile) {
42
+ console.error('[demo-chat-handler] --extra must contain chatDir and lastChatFile');
43
+ process.exit(0);
44
+ }
45
+
46
+ // Read the user message from the last chat file.
47
+ const lastChatPath = path.join(chatDir, lastChatFile);
48
+ let content = '';
49
+ try {
50
+ content = fs.readFileSync(lastChatPath, 'utf-8').trim();
51
+ } catch (err) {
52
+ console.error(`[demo-chat-handler] could not read ${lastChatPath}: ${err.message}`);
53
+ process.exit(0);
54
+ }
55
+
56
+ // Derive next serial by incrementing the leading digits in lastChatFile.
57
+ // e.g. "007_user.txt" → 7 → next = 8 → "008-assistant.txt"
58
+ const serialMatch = String(lastChatFile).match(/^(\d+)/);
59
+ const nextSerial = serialMatch ? parseInt(serialMatch[1], 10) + 1 : 1;
60
+ const nextName = `${String(nextSerial).padStart(3, '0')}-assistant.txt`;
61
+ const nextPath = path.join(chatDir, nextName);
62
+
63
+ try {
64
+ fs.writeFileSync(nextPath, `Echoing ${content}\n`, 'utf-8');
65
+ console.log(`[demo-chat-handler] boardId="${boardId}" cardId="${cardId}" wrote echo → ${nextPath}`);
66
+ } catch (err) {
67
+ console.error(`[demo-chat-handler] write failed: ${err.message}`);
68
+ process.exit(0);
69
+ }
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env node
2
+
3
+ import http from 'node:http';
4
+ import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ import {
8
+ createMultiBoardServerRuntime,
9
+ createRuntimeRequestDispatcher,
10
+ isRuntimeRoute,
11
+ } from './reusable-server-runtime.js';
12
+
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = path.dirname(__filename);
15
+
16
+ const PORT = Number(process.env.DEMO_SERVER_PORT || 7799);
17
+ const CORS_HEADERS = {
18
+ 'Access-Control-Allow-Origin': '*',
19
+ 'Access-Control-Allow-Headers': 'content-type,x-file-name',
20
+ 'Access-Control-Allow-Methods': 'GET,POST,PATCH,OPTIONS',
21
+ };
22
+
23
+ const runtime = createMultiBoardServerRuntime({
24
+ apiBasePath: '/api/boards',
25
+ defaultTaskExecutorPath: process.env.DEMO_TASK_EXECUTOR_PATH || path.join(__dirname, 'demo-task-executor.js'),
26
+ });
27
+
28
+ const dispatch = createRuntimeRequestDispatcher(runtime);
29
+
30
+ // Board-id segment regex: /api/boards/:boardId/...
31
+ const BOARD_SEG_RE = /^\/api\/boards\/([^/]+)\/(.+)$/;
32
+
33
+ function jsonReply(res, status, payload) {
34
+ const body = JSON.stringify(payload);
35
+ res.writeHead(status, { ...CORS_HEADERS, 'Content-Type': 'application/json; charset=utf-8' });
36
+ res.end(body);
37
+ }
38
+
39
+ async function handleDemoSetup(req, res, boardId) {
40
+ const url = new URL(req.url, 'http://localhost');
41
+ const reset = String(url.searchParams.get('reset') || '').toLowerCase() === 'true';
42
+ try {
43
+ const result = runtime.performDemoSetup(boardId, reset);
44
+ jsonReply(res, 200, result);
45
+ } catch (err) {
46
+ jsonReply(res, err.statusCode || 500, { error: String((err && err.message) || err) });
47
+ }
48
+ }
49
+
50
+ const server = http.createServer((req, res) => {
51
+ const method = req.method || 'GET';
52
+ const pathname = new URL(req.url || '/', 'http://localhost').pathname;
53
+
54
+ if (method === 'OPTIONS') {
55
+ res.writeHead(204, CORS_HEADERS);
56
+ res.end();
57
+ return;
58
+ }
59
+
60
+ // Route: demo-setup is handled here in demo-server (host concern)
61
+ const boardSegMatch = pathname.match(BOARD_SEG_RE);
62
+ if (boardSegMatch && boardSegMatch[2] === 'demo-setup') {
63
+ void handleDemoSetup(req, res, boardSegMatch[1]);
64
+ return;
65
+ }
66
+
67
+ // All other /api/boards routes are handled by the reusable runtime
68
+ void dispatch(req, res);
69
+ });
70
+
71
+ server.listen(PORT, '127.0.0.1', () => {
72
+ console.log(`[demo-server] listening on http://127.0.0.1:${PORT}`);
73
+ console.log(`[demo-server] setup dir: ${runtime.setupDir}`);
74
+ console.log(`[demo-server] boards config: ${runtime.setupDir}/boards-config.json`);
75
+ console.log('[demo-server] endpoints:');
76
+ console.log(` GET ${runtime.apiBasePath} <- list boards`);
77
+ console.log(` POST ${runtime.apiBasePath} {id, label?} <- register board`);
78
+ console.log(` GET ${runtime.apiBasePath}/:boardId/demo-setup`);
79
+ console.log(` GET ${runtime.apiBasePath}/:boardId/bootstrap`);
80
+ console.log(` GET ${runtime.apiBasePath}/:boardId/sse`);
81
+ console.log(` GET ${runtime.apiBasePath}/:boardId/board-status`);
82
+ console.log(` PATCH ${runtime.apiBasePath}/:boardId/cards/:id`);
83
+ console.log(` POST ${runtime.apiBasePath}/:boardId/cards/:id/actions`);
84
+ console.log(` POST ${runtime.apiBasePath}/:boardId/cards/:id/files`);
85
+ console.log(` GET ${runtime.apiBasePath}/:boardId/cards/:id/files/:idx`);
86
+ console.log(` GET ${runtime.apiBasePath}/:boardId/cards/:id/chats`);
87
+ });