yaml-flow 4.0.0 → 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 (95) hide show
  1. package/browser/board-livegraph-runtime.js +1453 -0
  2. package/browser/board-livegraph-runtime.js.map +1 -0
  3. package/browser/card-compute.js +36 -17
  4. package/browser/live-cards.js +848 -109
  5. package/browser/live-cards.schema.json +46 -21
  6. package/dist/board-livegraph-runtime/index.cjs +1448 -0
  7. package/dist/board-livegraph-runtime/index.cjs.map +1 -0
  8. package/dist/board-livegraph-runtime/index.d.cts +101 -0
  9. package/dist/board-livegraph-runtime/index.d.ts +101 -0
  10. package/dist/board-livegraph-runtime/index.js +1441 -0
  11. package/dist/board-livegraph-runtime/index.js.map +1 -0
  12. package/dist/card-compute/index.cjs +159 -44
  13. package/dist/card-compute/index.cjs.map +1 -1
  14. package/dist/card-compute/index.d.cts +36 -11
  15. package/dist/card-compute/index.d.ts +36 -11
  16. package/dist/card-compute/index.js +156 -44
  17. package/dist/card-compute/index.js.map +1 -1
  18. package/dist/cli/board-live-cards-cli.cjs +476 -105
  19. package/dist/cli/board-live-cards-cli.cjs.map +1 -1
  20. package/dist/cli/board-live-cards-cli.d.cts +8 -16
  21. package/dist/cli/board-live-cards-cli.d.ts +8 -16
  22. package/dist/cli/board-live-cards-cli.js +476 -106
  23. package/dist/cli/board-live-cards-cli.js.map +1 -1
  24. package/dist/continuous-event-graph/index.cjs +74 -33
  25. package/dist/continuous-event-graph/index.cjs.map +1 -1
  26. package/dist/continuous-event-graph/index.d.cts +7 -23
  27. package/dist/continuous-event-graph/index.d.ts +7 -23
  28. package/dist/continuous-event-graph/index.js +73 -32
  29. package/dist/continuous-event-graph/index.js.map +1 -1
  30. package/dist/index.cjs +1440 -56
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.d.cts +21 -3
  33. package/dist/index.d.ts +21 -3
  34. package/dist/index.js +1434 -56
  35. package/dist/index.js.map +1 -1
  36. package/dist/journal-DRfJiheM.d.cts +28 -0
  37. package/dist/journal-NLYuqege.d.ts +28 -0
  38. package/dist/{journal-B_2JnBMF.d.ts → live-cards-bridge-Or7fdEJV.d.ts} +5 -32
  39. package/dist/{journal-BJDjWb5Q.d.cts → live-cards-bridge-vGJ6tMzN.d.cts} +5 -32
  40. package/dist/schedule-CMcZe5Ny.d.ts +21 -0
  41. package/dist/schedule-CiucyCan.d.cts +21 -0
  42. package/examples/browser/boards/portfolio-tracker/cards/holdings-table.json +1 -1
  43. package/examples/browser/boards/portfolio-tracker/cards/portfolio-form.json +3 -3
  44. package/examples/browser/boards/portfolio-tracker/cards/portfolio-value.json +1 -1
  45. package/examples/browser/boards/portfolio-tracker/cards/price-fetch.json +3 -3
  46. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-task-executor.cjs +96 -0
  47. package/examples/browser/boards/portfolio-tracker/portfolio-tracker.js +33 -5
  48. package/examples/browser/livecards-browser/index.html +37 -684
  49. package/examples/cli/step-machine-cli/portfolio-tracker/cards/holdings-table.json +1 -1
  50. package/examples/cli/step-machine-cli/portfolio-tracker/cards/portfolio-form.json +3 -3
  51. package/examples/cli/step-machine-cli/portfolio-tracker/cards/portfolio-value.json +1 -1
  52. package/examples/cli/step-machine-cli/portfolio-tracker/cards/price-fetch.json +3 -3
  53. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/update-holdings-cli.js +2 -2
  54. package/examples/example-board/board.yaml +23 -0
  55. package/examples/example-board/bootstrap_payload.json +1 -0
  56. package/examples/example-board/cards/card-chain-region-alert.json +39 -0
  57. package/examples/example-board/cards/card-chain-region-totals.json +26 -0
  58. package/examples/example-board/cards/card-chain-top-region.json +24 -0
  59. package/examples/example-board/cards/card-ex-actions.json +32 -0
  60. package/examples/example-board/cards/card-ex-chart.json +30 -0
  61. package/examples/example-board/cards/card-ex-filter.json +36 -0
  62. package/examples/example-board/cards/card-ex-filtered-by-preference.json +59 -0
  63. package/examples/example-board/cards/card-ex-form.json +91 -0
  64. package/examples/example-board/cards/card-ex-list.json +22 -0
  65. package/examples/example-board/cards/card-ex-markdown.json +17 -0
  66. package/examples/example-board/cards/card-ex-metric.json +19 -0
  67. package/examples/example-board/cards/card-ex-narrative.json +36 -0
  68. package/examples/example-board/cards/card-ex-source-http.json +28 -0
  69. package/examples/example-board/cards/card-ex-source.json +21 -0
  70. package/examples/example-board/cards/card-ex-status.json +35 -0
  71. package/examples/example-board/cards/card-ex-table.json +30 -0
  72. package/examples/example-board/cards/card-ex-todo.json +29 -0
  73. package/examples/example-board/demo-chat-handler.js +69 -0
  74. package/examples/example-board/demo-server.js +87 -0
  75. package/examples/example-board/demo-shell-browser.html +806 -0
  76. package/examples/example-board/demo-shell-with-server.html +280 -0
  77. package/examples/example-board/demo-shell.html +62 -0
  78. package/examples/example-board/demo-task-executor.js +255 -0
  79. package/examples/example-board/mock.db +15 -0
  80. package/examples/example-board/reusable-board-runtime-client.js +265 -0
  81. package/examples/example-board/reusable-runtime-artifacts-adapter.js +233 -0
  82. package/examples/example-board/reusable-server-runtime.js +1284 -0
  83. package/examples/index.html +16 -9
  84. package/examples/npm-libs/continuous-event-graph/live-cards-board.ts +17 -17
  85. package/examples/npm-libs/continuous-event-graph/live-portfolio-dashboard.ts +23 -23
  86. package/examples/step-machine-cli/portfolio-tracker/cards/holdings-table.json +1 -1
  87. package/examples/step-machine-cli/portfolio-tracker/cards/portfolio-form.json +3 -3
  88. package/examples/step-machine-cli/portfolio-tracker/cards/portfolio-value.json +1 -1
  89. package/examples/step-machine-cli/portfolio-tracker/cards/price-fetch.json +1 -1
  90. package/examples/step-machine-cli/portfolio-tracker/portfolio-tracker-task-executor.cjs +96 -0
  91. package/package.json +16 -2
  92. package/schema/card-runtime.schema.json +25 -0
  93. package/schema/live-cards.schema.json +46 -21
  94. package/browser/ingest-board.js +0 -296
  95. package/examples/ingest.js +0 -733
@@ -0,0 +1,36 @@
1
+ {
2
+ "id": "card-ex-narrative",
3
+ "meta": {
4
+ "title": "Sales Insight",
5
+ "tags": [],
6
+ "desc": "AI-generated narrative from Copilot source execution"
7
+ },
8
+ "requires": ["orders", "prices"],
9
+ "compute": [
10
+ {
11
+ "bindTo": "orderCount",
12
+ "expr": "$count(requires.orders)"
13
+ },
14
+ {
15
+ "bindTo": "totalRevenue",
16
+ "expr": "$sum(requires.orders.amount)"
17
+ }
18
+ ],
19
+ "sources": [
20
+ {
21
+ "bindTo": "raw",
22
+ "outputFile": "card-ex-narrative-raw.json",
23
+ "copilot": {
24
+ "prompt_template": "You are a concise sales analyst. Write 5-7 bullet points about business signals to monitor this week for a small B2B widget company. Keep it under 120 words."
25
+ }
26
+ }
27
+ ],
28
+ "view": {
29
+ "elements": [
30
+ { "kind": "narrative", "data": { "bind": "fetched_sources.raw" } }
31
+ ],
32
+ "layout": { "board": { "col": 6, "order": 10 }, "canvas": { "x": 600, "y": 800, "w": 350, "h": 250 } },
33
+ "features": { "refresh": true, "chat": true }
34
+ },
35
+ "card_data": {}
36
+ }
@@ -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
+ });