yaml-flow 6.0.0 → 7.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 (162) hide show
  1. package/board-live-cards-cli.js +4 -4
  2. package/browser/asset-integrity.json +3 -3
  3. package/browser/board-livecards-client.js +2 -0
  4. package/browser/board-livecards-client.js.map +1 -0
  5. package/browser/board-livecards-localstorage.js +10 -0
  6. package/browser/board-livecards-localstorage.js.map +1 -0
  7. package/browser/board-livegraph-engine.js +2 -2
  8. package/browser/board-livegraph-engine.js.map +1 -1
  9. package/browser/card-compute.js +28 -28
  10. package/browser/compute-jsonata.js +5 -0
  11. package/browser/compute-jsonata.js.map +1 -0
  12. package/browser/live-cards.js +261 -150
  13. package/card-store.js +4 -4
  14. package/dist/{board-live-cards-public-CltXYgaY.d.cts → board-live-cards-public-CW5074xr.d.cts} +9 -5
  15. package/dist/{board-live-cards-public-f-E-FAyp.d.ts → board-live-cards-public-hnZo0mAf.d.ts} +9 -5
  16. package/dist/board-livegraph-runtime/index.cjs +2 -2
  17. package/dist/board-livegraph-runtime/index.cjs.map +1 -1
  18. package/dist/board-livegraph-runtime/index.d.cts +11 -9
  19. package/dist/board-livegraph-runtime/index.d.ts +11 -9
  20. package/dist/board-livegraph-runtime/index.js +2 -2
  21. package/dist/board-livegraph-runtime/index.js.map +1 -1
  22. package/dist/board-livegraph-runtime/jsonata-sync.cjs +37 -1
  23. package/dist/card-compute/index.cjs +4 -4
  24. package/dist/card-compute/index.cjs.map +1 -1
  25. package/dist/card-compute/index.d.cts +5 -1
  26. package/dist/card-compute/index.d.ts +5 -1
  27. package/dist/card-compute/index.js +4 -4
  28. package/dist/card-compute/index.js.map +1 -1
  29. package/dist/card-compute/jsonata-sync.cjs +37 -1
  30. package/dist/cli/browser-api/board-live-cards-browser-adapter.cjs +2 -1
  31. package/dist/cli/browser-api/board-live-cards-browser-adapter.cjs.map +1 -1
  32. package/dist/cli/browser-api/board-live-cards-browser-adapter.d.cts +27 -14
  33. package/dist/cli/browser-api/board-live-cards-browser-adapter.d.ts +27 -14
  34. package/dist/cli/browser-api/board-live-cards-browser-adapter.js +2 -1
  35. package/dist/cli/browser-api/board-live-cards-browser-adapter.js.map +1 -1
  36. package/dist/cli/browser-api/card-store-browser-api.cjs +1 -1
  37. package/dist/cli/browser-api/card-store-browser-api.cjs.map +1 -1
  38. package/dist/cli/browser-api/card-store-browser-api.js +1 -1
  39. package/dist/cli/browser-api/card-store-browser-api.js.map +1 -1
  40. package/dist/cli/browser-api/jsonata-sync.cjs +37 -1
  41. package/dist/cli/node/artifacts-store-cli.cjs +8 -8
  42. package/dist/cli/node/artifacts-store-cli.cjs.map +1 -1
  43. package/dist/cli/node/artifacts-store-cli.js +8 -8
  44. package/dist/cli/node/artifacts-store-cli.js.map +1 -1
  45. package/dist/cli/node/board-live-cards-cli.cjs +7 -7
  46. package/dist/cli/node/board-live-cards-cli.cjs.map +1 -1
  47. package/dist/cli/node/board-live-cards-cli.js +7 -7
  48. package/dist/cli/node/board-live-cards-cli.js.map +1 -1
  49. package/dist/cli/node/card-store-cli.cjs +5 -5
  50. package/dist/cli/node/card-store-cli.cjs.map +1 -1
  51. package/dist/cli/node/card-store-cli.js +5 -5
  52. package/dist/cli/node/card-store-cli.js.map +1 -1
  53. package/dist/cli/node/execution-adapter.cjs +3 -0
  54. package/dist/cli/node/execution-adapter.cjs.map +1 -0
  55. package/dist/cli/node/execution-adapter.d.cts +174 -0
  56. package/dist/cli/node/execution-adapter.d.ts +174 -0
  57. package/dist/cli/node/execution-adapter.js +3 -0
  58. package/dist/cli/node/execution-adapter.js.map +1 -0
  59. package/dist/cli/node/fs-board-adapter.cjs +7 -7
  60. package/dist/cli/node/fs-board-adapter.cjs.map +1 -1
  61. package/dist/cli/node/fs-board-adapter.d.cts +2 -2
  62. package/dist/cli/node/fs-board-adapter.d.ts +2 -2
  63. package/dist/cli/node/fs-board-adapter.js +7 -7
  64. package/dist/cli/node/fs-board-adapter.js.map +1 -1
  65. package/dist/cli/node/jsonata-sync.cjs +37 -1
  66. package/dist/cli/node/source-cli-task-executor.cjs +4 -4
  67. package/dist/cli/node/source-cli-task-executor.cjs.map +1 -1
  68. package/dist/cli/node/source-cli-task-executor.js +4 -4
  69. package/dist/cli/node/source-cli-task-executor.js.map +1 -1
  70. package/dist/continuous-event-graph/index.cjs +2 -2
  71. package/dist/continuous-event-graph/index.cjs.map +1 -1
  72. package/dist/continuous-event-graph/index.js +2 -2
  73. package/dist/continuous-event-graph/index.js.map +1 -1
  74. package/dist/continuous-event-graph/jsonata-sync.cjs +37 -1
  75. package/dist/execution-refs.cjs +2 -1
  76. package/dist/execution-refs.cjs.map +1 -1
  77. package/dist/execution-refs.d.cts +49 -11
  78. package/dist/execution-refs.d.ts +49 -11
  79. package/dist/execution-refs.js +2 -1
  80. package/dist/execution-refs.js.map +1 -1
  81. package/dist/index.cjs +10 -10
  82. package/dist/index.cjs.map +1 -1
  83. package/dist/index.js +10 -10
  84. package/dist/index.js.map +1 -1
  85. package/dist/jsonata-sync.cjs +37 -1
  86. package/dist/server-runtime/index.cjs +9 -0
  87. package/dist/server-runtime/index.cjs.map +1 -0
  88. package/dist/server-runtime/index.d.cts +31 -0
  89. package/dist/server-runtime/index.d.ts +31 -0
  90. package/dist/server-runtime/index.js +9 -0
  91. package/dist/server-runtime/index.js.map +1 -0
  92. package/dist/server-runtime/jsonata-sync.cjs +7623 -0
  93. package/dist/step-machine-public/index.cjs +2 -0
  94. package/dist/step-machine-public/index.cjs.map +1 -0
  95. package/dist/step-machine-public/index.d.cts +159 -0
  96. package/dist/step-machine-public/index.d.ts +159 -0
  97. package/dist/step-machine-public/index.js +2 -0
  98. package/dist/step-machine-public/index.js.map +1 -0
  99. package/dist/step-machine-public/jsonata-sync.cjs +7623 -0
  100. package/dist/storage-refs.cjs +2 -2
  101. package/dist/storage-refs.cjs.map +1 -1
  102. package/dist/storage-refs.d.cts +7 -6
  103. package/dist/storage-refs.d.ts +7 -6
  104. package/dist/storage-refs.js +2 -2
  105. package/dist/storage-refs.js.map +1 -1
  106. package/dist/types-B1ZRa4aI.d.ts +147 -0
  107. package/dist/types-BxEFcVK9.d.cts +147 -0
  108. package/examples/browser/boards/portfolio-tracker/portfolio-t4.js +9 -10
  109. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-http-test.js +357 -0
  110. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-public.js +9 -10
  111. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-server.js +300 -0
  112. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-server.py +617 -0
  113. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-sse-worker.js +48 -0
  114. package/examples/browser/boards/portfolio-tracker/portfolio-tracker.py +11 -10
  115. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/_board-cli.js +19 -4
  116. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/add-cards-cli.js +4 -8
  117. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/init-board-cli.js +6 -10
  118. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/poll-status-cli.js +8 -16
  119. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/reset-board-dir-cli.js +2 -6
  120. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/retrigger-cli.js +4 -8
  121. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/status-cli.js +3 -7
  122. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/update-holdings-cli.js +4 -8
  123. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/wait-completed-cli.js +7 -16
  124. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/write-prices-cli.js +2 -6
  125. package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/_board_pycli.py +13 -3
  126. package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/add-cards.py +2 -1
  127. package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/init-board.py +2 -1
  128. package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/poll-status.py +2 -1
  129. package/examples/cli/step-machine-cli/portfolio-tracker/portfolio-tracker.flow.yaml +20 -24
  130. package/examples/cli/step-machine-cli/portfolio-tracker/run-inline-python-demo-pycli.py +0 -3
  131. package/examples/cli/step-machine-demo/jsonata-init-board-cli.js +8 -13
  132. package/examples/cli/step-machine-demo/jsonata-init-board.flow.yaml +33 -9
  133. package/examples/cli/step-machine-demo/one-step-cli-only.flow.yaml +3 -1
  134. package/examples/cli/step-machine-demo/step2-double-cli.js +6 -12
  135. package/examples/cli/step-machine-demo/two-step-math.flow.yaml +66 -4
  136. package/examples/cli/step-machine-demo/two-step-mixed.flow.yaml +13 -5
  137. package/examples/example-board/cards/_index.json +47 -0
  138. package/examples/example-board/cards/card-market-prices.json +33 -9
  139. package/examples/example-board/cards/card-my-identity.json +30 -6
  140. package/examples/example-board/cards/card-portfolio-action.json +24 -6
  141. package/examples/example-board/cards/card-portfolio-intelligence.json +97 -0
  142. package/examples/example-board/cards/card-portfolio-risks.json +24 -6
  143. package/examples/example-board/cards/card-portfolio-value.json +38 -10
  144. package/examples/example-board/cards/card-portfolio.json +57 -13
  145. package/examples/example-board/cards/card-rebalance-impact.json +22 -6
  146. package/examples/example-board/cards/card-rebalance-sim.json +66 -15
  147. package/examples/example-board/demo-server.js +360 -69
  148. package/examples/example-board/demo-shell-localstorage.html +774 -0
  149. package/examples/example-board/demo-shell-with-server.html +18 -36
  150. package/examples/example-board/demo-shell.html +5 -4
  151. package/examples/example-board/demo-task-executor.js +217 -265
  152. package/package.json +15 -13
  153. package/step-machine-cli.js +43 -310
  154. package/board-livecards-server-runtime.js +0 -1513
  155. package/browser/board-livecards-runtime-client.js +0 -263
  156. package/dist/pycli/quickjs-board-runtime.global.js +0 -9
  157. package/dist/pycli/quickjs-board-runtime.global.js.map +0 -1
  158. package/dist/pycli/quickjs-step-machine-runtime.global.js +0 -5
  159. package/dist/pycli/quickjs-step-machine-runtime.global.js.map +0 -1
  160. package/examples/cli/step-machine-demo/two-step-math-handlers.js +0 -32
  161. package/examples/cli/step-machine-demo/two-step-mixed-handlers.js +0 -24
  162. package/examples/example-board/demo-shell-browser.html +0 -675
@@ -1,21 +1,45 @@
1
1
  id: jsonata-init-board-demo
2
2
  settings:
3
- start_step: t0_init_board
3
+ start_step: t0_prepare
4
4
  max_total_steps: 10
5
5
  timeout_ms: 30000
6
6
 
7
7
  steps:
8
- t0_init_board:
9
- description: Build board path with JSONata and invoke CLI with command templating
8
+ t0_prepare:
9
+ description: Build board path from runtime_root and board_name
10
10
  expects_data: [runtime_root, board_name]
11
+ produces_data: [BOARD_DIR]
12
+ handler:
13
+ type: compute-jsonata
14
+ expr:
15
+ - data.BOARD_DIR = expects_data.runtime_root & "/" & expects_data.board_name
16
+ - result = "success"
17
+ transitions:
18
+ success: t1_init_board
19
+ failure: failed_state
20
+
21
+ t1_init_board:
22
+ description: Invoke init-board CLI with BOARD_DIR
23
+ expects_data: [BOARD_DIR]
24
+ produces_data: [board_dir, message]
25
+ handler:
26
+ type: ref
27
+ howToRun: local-node
28
+ whatToRun: "::fs-path::./jsonata-init-board-cli.js"
29
+ transitions:
30
+ success: t2_map_output
31
+ failure: failed_state
32
+
33
+ t2_map_output:
34
+ description: Map CLI output to final field names
35
+ expects_data: [BOARD_DIR, message]
11
36
  produces_data: [board_dir, init_message]
12
37
  handler:
13
- cli: node ./jsonata-init-board-cli.js "%%BOARD_DIR%%"
14
- input-transforms:
15
- BOARD_DIR: runtime_root & "/" & board_name
16
- output-transforms:
17
- board_dir: BOARD_DIR
18
- init_message: data.message
38
+ type: compute-jsonata
39
+ expr:
40
+ - data.board_dir = expects_data.BOARD_DIR
41
+ - data.init_message = expects_data.message
42
+ - result = "success"
19
43
  transitions:
20
44
  success: success_state
21
45
  failure: failed_state
@@ -6,7 +6,9 @@ steps:
6
6
  expects_data: [x]
7
7
  produces_data: [y]
8
8
  handler:
9
- cli: node ./step-cli-echo-y.js
9
+ type: ref
10
+ howToRun: local-node
11
+ whatToRun: "::fs-path::./step-cli-echo-y.js"
10
12
  transitions:
11
13
  success: success_state
12
14
  failure: failed_state
@@ -13,26 +13,20 @@ process.stdin.on('end', () => {
13
13
  const c = Number(input.c);
14
14
 
15
15
  if (!Number.isFinite(c)) {
16
- process.stdout.write(JSON.stringify({
17
- result: 'failure',
18
- error: 'step2_double requires numeric c',
19
- }));
20
- process.exit(0);
16
+ process.stderr.write('step2_double requires numeric c');
17
+ process.exit(1);
21
18
  return;
22
19
  }
23
20
 
24
21
  const d = c * 2;
25
22
  process.stdout.write(JSON.stringify({
26
- status: 'success',
27
- data: {
28
- a: 123,
29
- d,
30
- },
23
+ a: 123,
24
+ d,
31
25
  }));
32
26
  } catch (error) {
33
27
  const message = error instanceof Error ? error.message : String(error);
34
- process.stdout.write(JSON.stringify({ result: 'failure', error: message }));
35
- process.exit(0);
28
+ process.stderr.write(message);
29
+ process.exit(1);
36
30
  }
37
31
  });
38
32
 
@@ -4,19 +4,81 @@ settings:
4
4
  max_total_steps: 10
5
5
  timeout_ms: 10000
6
6
 
7
+ # Demonstrates three compute-jsonata techniques:
8
+ # 1. Basic arithmetic with data.* output and explicit result=
9
+ # 2. Chained ternary with local $var binding ($c :=) — range classification and conditional routing
10
+ # 3. $lookup object-switch — route result directly from a map (see switch test in step-machine-cli.test.ts)
11
+ # NOTE: expr items containing ': ' or '{key: value}' must be single-quoted in YAML.
12
+
7
13
  steps:
8
14
  step1_add:
9
15
  description: Compute c = a + b
10
16
  expects_data: [a, b]
11
17
  produces_data: [c]
18
+ input_validations:
19
+ - $type(a) = "number"
20
+ - $type(b) = "number"
21
+ handler:
22
+ type: compute-jsonata
23
+ expr:
24
+ - data.c = expects_data.a + expects_data.b
25
+ - result = "success"
26
+ transitions:
27
+ success: step2_classify
28
+ failure: failed_state
29
+
30
+ step2_classify:
31
+ description: |
32
+ Classify c using an object-lookup switch.
33
+ Routes to low_track / mid_track / high_track based on magnitude.
34
+ expects_data: [c]
35
+ produces_data: [band]
36
+ handler:
37
+ type: compute-jsonata
38
+ expr:
39
+ - 'data.band = ($c := expects_data.c; $c < 10 ? "low" : $c < 100 ? "mid" : "high")'
40
+ - result = data.band
12
41
  transitions:
13
- success: step2_double
42
+ low: low_track
43
+ mid: mid_track
44
+ high: high_track
45
+ failure: failed_state
46
+
47
+ low_track:
48
+ description: Small result — multiply by 3
49
+ expects_data: [c]
50
+ produces_data: [d]
51
+ handler:
52
+ type: compute-jsonata
53
+ expr:
54
+ - data.d = expects_data.c * 3
55
+ - result = "success"
56
+ transitions:
57
+ success: success_state
58
+ failure: failed_state
59
+
60
+ mid_track:
61
+ description: Medium result — multiply by 2
62
+ expects_data: [c]
63
+ produces_data: [d]
64
+ handler:
65
+ type: compute-jsonata
66
+ expr:
67
+ - data.d = expects_data.c * 2
68
+ - result = "success"
69
+ transitions:
70
+ success: success_state
14
71
  failure: failed_state
15
72
 
16
- step2_double:
17
- description: Compute d = c * 2
73
+ high_track:
74
+ description: Large result keep as-is (already big enough)
18
75
  expects_data: [c]
19
76
  produces_data: [d]
77
+ handler:
78
+ type: compute-jsonata
79
+ expr:
80
+ - data.d = expects_data.c
81
+ - result = "success"
20
82
  transitions:
21
83
  success: success_state
22
84
  failure: failed_state
@@ -24,7 +86,7 @@ steps:
24
86
  terminal_states:
25
87
  success_state:
26
88
  return_intent: success
27
- return_artifacts: [a, b, c, d]
89
+ return_artifacts: [a, b, c, band, d]
28
90
 
29
91
  failed_state:
30
92
  return_intent: failure
@@ -6,21 +6,29 @@ settings:
6
6
 
7
7
  steps:
8
8
  step1_add:
9
- description: Inline handler computes c = a + b
9
+ description: Compute step computes c = a + b
10
10
  expects_data: [a, b]
11
- produces_data: [c, e]
11
+ produces_data: [c]
12
+ input_validations:
13
+ - $type(a) = "number"
14
+ - $type(b) = "number"
12
15
  handler:
13
- inline: step1_add
16
+ type: compute-jsonata
17
+ expr:
18
+ - data.c = expects_data.a + expects_data.b
19
+ - result = "success"
14
20
  transitions:
15
21
  success: step2_double
16
22
  failure: failed_state
17
23
 
18
24
  step2_double:
19
- description: CLI handler computes d = c * 2
25
+ description: Ref handler computes d = c * 2
20
26
  expects_data: [c]
21
27
  produces_data: [d, e]
22
28
  handler:
23
- cli: node ./step2-double-cli.js
29
+ type: ref
30
+ howToRun: local-node
31
+ whatToRun: "::fs-path::./step2-double-cli.js"
24
32
  transitions:
25
33
  success: success_state
26
34
  failure: failed_state
@@ -0,0 +1,47 @@
1
+ {
2
+ "card-portfolio-intelligence": {
3
+ "key": "card-portfolio-intelligence",
4
+ "checksum": "card-portfolio-intelligence",
5
+ "updatedAt": "2026-05-10T09:38:02.181Z"
6
+ },
7
+ "card-market-prices": {
8
+ "key": "card-market-prices",
9
+ "checksum": "card-market-prices",
10
+ "updatedAt": "2026-05-10T09:38:02.161Z"
11
+ },
12
+ "card-my-identity": {
13
+ "key": "card-my-identity",
14
+ "checksum": "card-my-identity",
15
+ "updatedAt": "2026-05-10T09:38:02.168Z"
16
+ },
17
+ "card-portfolio-action": {
18
+ "key": "card-portfolio-action",
19
+ "checksum": "card-portfolio-action",
20
+ "updatedAt": "2026-05-10T09:38:02.174Z"
21
+ },
22
+ "card-portfolio-risks": {
23
+ "key": "card-portfolio-risks",
24
+ "checksum": "card-portfolio-risks",
25
+ "updatedAt": "2026-05-10T09:38:02.187Z"
26
+ },
27
+ "card-portfolio-value": {
28
+ "key": "card-portfolio-value",
29
+ "checksum": "card-portfolio-value",
30
+ "updatedAt": "2026-05-10T09:38:02.195Z"
31
+ },
32
+ "card-portfolio": {
33
+ "key": "card-portfolio",
34
+ "checksum": "card-portfolio",
35
+ "updatedAt": "2026-05-10T09:38:02.201Z"
36
+ },
37
+ "card-rebalance-impact": {
38
+ "key": "card-rebalance-impact",
39
+ "checksum": "card-rebalance-impact",
40
+ "updatedAt": "2026-05-10T09:38:02.208Z"
41
+ },
42
+ "card-rebalance-sim": {
43
+ "key": "card-rebalance-sim",
44
+ "checksum": "card-rebalance-sim",
45
+ "updatedAt": "2026-05-10T09:38:02.214Z"
46
+ }
47
+ }
@@ -2,10 +2,15 @@
2
2
  "id": "card-market-prices",
3
3
  "meta": {
4
4
  "title": "Market Prices",
5
- "tags": ["prices", "market"],
5
+ "tags": [
6
+ "prices",
7
+ "market"
8
+ ],
6
9
  "desc": "Fetches live prices for portfolio tickers. Publishes enriched quote data for downstream portfolio value calculations."
7
10
  },
8
- "requires": ["holdings"],
11
+ "requires": [
12
+ "holdings"
13
+ ],
9
14
  "source_defs": [
10
15
  {
11
16
  "bindTo": "quotes",
@@ -24,7 +29,7 @@
24
29
  "compute": [
25
30
  {
26
31
  "bindTo": "normalizedQuotes",
27
- "expr": "{ \"quoteResponse\": { \"result\": $map(fetched_sources.quotes, function($r) { $r.chart.result[0].meta.{ \"symbol\": symbol, \"shortName\": longName, \"regularMarketPrice\": regularMarketPrice, \"regularMarketChange\": regularMarketChange, \"regularMarketChangePercent\": regularMarketChangePercent } }), \"error\": null } }"
32
+ "expr": "{ \"quoteResponse\": { \"result\": $map(fetched_sources.quotes, function($r) { ($m := $r.chart.result[0].meta; $prev := $m.chartPreviousClose; $chg := $m.regularMarketPrice - $prev; { \"symbol\": $m.symbol, \"shortName\": $m.shortName ? $m.shortName : $m.longName, \"regularMarketPrice\": $m.regularMarketPrice, \"regularMarketChange\": $chg, \"regularMarketChangePercent\": $chg / $prev * 100 }) }), \"error\": null } }"
28
33
  },
29
34
  {
30
35
  "bindTo": "prices",
@@ -32,7 +37,10 @@
32
37
  }
33
38
  ],
34
39
  "provides": [
35
- { "bindTo": "quotes", "ref": "computed_values.normalizedQuotes" }
40
+ {
41
+ "bindTo": "quotes",
42
+ "ref": "computed_values.normalizedQuotes"
43
+ }
36
44
  ],
37
45
  "view": {
38
46
  "elements": [
@@ -41,16 +49,32 @@
41
49
  "label": "Prices",
42
50
  "data": {
43
51
  "bind": "computed_values.prices",
44
- "columns": ["ticker", "name", "price", "change", "chg_pct"],
52
+ "columns": [
53
+ "ticker",
54
+ "name",
55
+ "price",
56
+ "change",
57
+ "chg_pct"
58
+ ],
45
59
  "sortable": true
46
60
  }
47
61
  }
48
62
  ],
49
63
  "layout": {
50
- "board": { "col": 4, "order": 2 },
51
- "canvas": { "x": 400, "y": 50, "w": 400, "h": 340 }
64
+ "board": {
65
+ "col": 4,
66
+ "order": 2
67
+ },
68
+ "canvas": {
69
+ "x": 400,
70
+ "y": 50,
71
+ "w": 400,
72
+ "h": 340
73
+ }
52
74
  },
53
- "features": { "refresh": true }
75
+ "features": {
76
+ "refresh": true
77
+ }
54
78
  },
55
79
  "card_data": {}
56
- }
80
+ }
@@ -2,7 +2,10 @@
2
2
  "id": "card-my-identity",
3
3
  "meta": {
4
4
  "title": "My Identity",
5
- "tags": ["m365", "workiq"],
5
+ "tags": [
6
+ "m365",
7
+ "workiq"
8
+ ],
6
9
  "desc": "Displays your M365 display name via WorkIQ (Microsoft 365 Copilot)."
7
10
  },
8
11
  "source_defs": [
@@ -14,15 +17,36 @@
14
17
  }
15
18
  }
16
19
  ],
20
+ "compute": [
21
+ {
22
+ "bindTo": "identity",
23
+ "expr": "fetched_sources.identity"
24
+ }
25
+ ],
17
26
  "view": {
18
27
  "elements": [
19
- { "kind": "markdown", "data": { "bind": "fetched_sources.identity" } }
28
+ {
29
+ "kind": "markdown",
30
+ "data": {
31
+ "bind": "computed_values.identity"
32
+ }
33
+ }
20
34
  ],
21
35
  "layout": {
22
- "board": { "col": 4, "order": 10 },
23
- "canvas": { "x": 50, "y": 450, "w": 420, "h": 260 }
36
+ "board": {
37
+ "col": 4,
38
+ "order": 10
39
+ },
40
+ "canvas": {
41
+ "x": 50,
42
+ "y": 450,
43
+ "w": 420,
44
+ "h": 260
45
+ }
24
46
  },
25
- "features": { "refresh": true }
47
+ "features": {
48
+ "refresh": true
49
+ }
26
50
  },
27
51
  "card_data": {}
28
- }
52
+ }
@@ -2,18 +2,36 @@
2
2
  "id": "card-portfolio-action",
3
3
  "meta": {
4
4
  "title": "Action Signal",
5
- "tags": ["portfolio", "action"],
5
+ "tags": [
6
+ "portfolio",
7
+ "action"
8
+ ],
6
9
  "desc": "Actionable recommendation sourced from Portfolio Intelligence."
7
10
  },
8
- "requires": ["portfolio_action"],
11
+ "requires": [
12
+ "portfolio_action"
13
+ ],
9
14
  "view": {
10
15
  "elements": [
11
- { "kind": "markdown", "data": { "bind": "requires.portfolio_action" } }
16
+ {
17
+ "kind": "markdown",
18
+ "data": {
19
+ "bind": "requires.portfolio_action"
20
+ }
21
+ }
12
22
  ],
13
23
  "layout": {
14
- "board": { "col": 4, "order": 6 },
15
- "canvas": { "x": 1660, "y": 50, "w": 300, "h": 160 }
24
+ "board": {
25
+ "col": 4,
26
+ "order": 6
27
+ },
28
+ "canvas": {
29
+ "x": 1660,
30
+ "y": 50,
31
+ "w": 300,
32
+ "h": 160
33
+ }
16
34
  }
17
35
  },
18
36
  "card_data": {}
19
- }
37
+ }
@@ -0,0 +1,97 @@
1
+ {
2
+ "id": "card-portfolio-intelligence",
3
+ "meta": {
4
+ "title": "Portfolio Intelligence",
5
+ "tags": [
6
+ "portfolio",
7
+ "analysis"
8
+ ],
9
+ "desc": "AI analysis of portfolio mix and P&L. Publishes structured insights as tokens for downstream risk and action cards."
10
+ },
11
+ "requires": [
12
+ "positions"
13
+ ],
14
+ "source_defs": [
15
+ {
16
+ "bindTo": "analysis",
17
+ "outputFile": "card-concentration-analysis.json",
18
+ "projections": {
19
+ "positions": "requires.positions"
20
+ },
21
+ "copilot": {
22
+ "prompt_template": "You are a concise equity analyst. Use web search to get today's news and upcoming events for each ticker before answering.\n\nPortfolio positions:\n{{positions}}\n\nFields: ticker, quantity, cost_basis ($), price ($), value ($), gain_$ (unrealised P&L), gain_% (unrealised return), chg_$ (today's position P&L $), chg_pct (today's % move).\n\nIMPORTANT OUTPUT RULES:\n- Return ONLY a valid JSON object. No markdown code fences, no preamble, no trailing text.\n- Start your response with { and end with }.\n- No emojis anywhere.\n- Each value is a Markdown string using - bullet points. No sub-headings inside values.\n- Maximum 40 words per section.\n\n{\n \"mix\": \"- <dominant holding ticker, % of total, and whether that is a risk>\\n- <sector clustering in one line>\",\n \"pnl\": \"- Best: <ticker> +X% (+$Y)\\n- Worst: <ticker> +X% (+$Y)\",\n \"risks\": \"- <TICKER>: <one specific current risk with event name or date>\\n- <TICKER>: ...\\n- (one bullet per position from today's news)\",\n \"action\": \"- <one sentence: specific action and reason grounded in today's market>\"\n}"
23
+ }
24
+ }
25
+ ],
26
+ "compute": [
27
+ {
28
+ "bindTo": "mix",
29
+ "expr": "fetched_sources.analysis.mix"
30
+ },
31
+ {
32
+ "bindTo": "pnl",
33
+ "expr": "fetched_sources.analysis.pnl"
34
+ },
35
+ {
36
+ "bindTo": "risks",
37
+ "expr": "fetched_sources.analysis.risks"
38
+ },
39
+ {
40
+ "bindTo": "action",
41
+ "expr": "fetched_sources.analysis.action"
42
+ }
43
+ ],
44
+ "provides": [
45
+ {
46
+ "bindTo": "portfolio_mix",
47
+ "ref": "computed_values.mix"
48
+ },
49
+ {
50
+ "bindTo": "portfolio_pnl",
51
+ "ref": "computed_values.pnl"
52
+ },
53
+ {
54
+ "bindTo": "portfolio_risks",
55
+ "ref": "computed_values.risks"
56
+ },
57
+ {
58
+ "bindTo": "portfolio_action",
59
+ "ref": "computed_values.action"
60
+ }
61
+ ],
62
+ "view": {
63
+ "elements": [
64
+ {
65
+ "kind": "markdown",
66
+ "label": "Mix",
67
+ "data": {
68
+ "bind": "computed_values.mix"
69
+ }
70
+ },
71
+ {
72
+ "kind": "markdown",
73
+ "label": "P&L",
74
+ "data": {
75
+ "bind": "computed_values.pnl"
76
+ }
77
+ }
78
+ ],
79
+ "layout": {
80
+ "board": {
81
+ "col": 3,
82
+ "order": 4
83
+ },
84
+ "canvas": {
85
+ "x": 1300,
86
+ "y": 50,
87
+ "w": 340,
88
+ "h": 200
89
+ }
90
+ },
91
+ "features": {
92
+ "refresh": true,
93
+ "chat": true
94
+ }
95
+ },
96
+ "card_data": {}
97
+ }
@@ -2,18 +2,36 @@
2
2
  "id": "card-portfolio-risks",
3
3
  "meta": {
4
4
  "title": "Risk Watch",
5
- "tags": ["portfolio", "risk"],
5
+ "tags": [
6
+ "portfolio",
7
+ "risk"
8
+ ],
6
9
  "desc": "Per-ticker risk signals sourced from Portfolio Intelligence."
7
10
  },
8
- "requires": ["portfolio_risks"],
11
+ "requires": [
12
+ "portfolio_risks"
13
+ ],
9
14
  "view": {
10
15
  "elements": [
11
- { "kind": "markdown", "data": { "bind": "requires.portfolio_risks" } }
16
+ {
17
+ "kind": "markdown",
18
+ "data": {
19
+ "bind": "requires.portfolio_risks"
20
+ }
21
+ }
12
22
  ],
13
23
  "layout": {
14
- "board": { "col": 3, "order": 5 },
15
- "canvas": { "x": 1300, "y": 270, "w": 340, "h": 220 }
24
+ "board": {
25
+ "col": 3,
26
+ "order": 5
27
+ },
28
+ "canvas": {
29
+ "x": 1300,
30
+ "y": 270,
31
+ "w": 340,
32
+ "h": 220
33
+ }
16
34
  }
17
35
  },
18
36
  "card_data": {}
19
- }
37
+ }
@@ -2,12 +2,21 @@
2
2
  "id": "card-portfolio-value",
3
3
  "meta": {
4
4
  "title": "Portfolio Value",
5
- "tags": ["portfolio", "value"],
5
+ "tags": [
6
+ "portfolio",
7
+ "value"
8
+ ],
6
9
  "desc": "Computes total portfolio value, gainers/losers summary, and per-position P&L from holdings and live market quotes."
7
10
  },
8
- "requires": ["holdings", "quotes"],
11
+ "requires": [
12
+ "holdings",
13
+ "quotes"
14
+ ],
9
15
  "provides": [
10
- { "bindTo": "positions", "ref": "computed_values.positions" }
16
+ {
17
+ "bindTo": "positions",
18
+ "ref": "computed_values.positions"
19
+ }
11
20
  ],
12
21
  "compute": [
13
22
  {
@@ -36,27 +45,46 @@
36
45
  {
37
46
  "kind": "metric",
38
47
  "label": "Portfolio Value ($)",
39
- "data": { "bind": "computed_values.totalValue" }
48
+ "data": {
49
+ "bind": "computed_values.totalValue"
50
+ }
40
51
  },
41
52
  {
42
53
  "kind": "text",
43
- "data": { "bind": "computed_values.gainersLosers" }
54
+ "data": {
55
+ "bind": "computed_values.gainersLosers"
56
+ }
44
57
  },
45
58
  {
46
59
  "kind": "table",
47
60
  "label": "Positions",
48
61
  "data": {
49
62
  "bind": "computed_values.positions",
50
- "columns": ["ticker", "value", "gain_$", "gain_%"],
63
+ "columns": [
64
+ "ticker",
65
+ "value",
66
+ "gain_$",
67
+ "gain_%"
68
+ ],
51
69
  "sortable": true
52
70
  }
53
71
  }
54
72
  ],
55
73
  "layout": {
56
- "board": { "col": 4, "order": 3 },
57
- "canvas": { "x": 840, "y": 50, "w": 420, "h": 380 }
74
+ "board": {
75
+ "col": 4,
76
+ "order": 3
77
+ },
78
+ "canvas": {
79
+ "x": 840,
80
+ "y": 50,
81
+ "w": 420,
82
+ "h": 380
83
+ }
58
84
  },
59
- "features": { "chat": true }
85
+ "features": {
86
+ "chat": true
87
+ }
60
88
  },
61
89
  "card_data": {}
62
- }
90
+ }