yaml-flow 5.2.8 → 5.4.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.
- package/board-livecards-server-runtime.js +15 -66
- package/browser/board-livegraph-engine.js +4 -1
- package/browser/board-livegraph-engine.js.map +1 -1
- package/browser/card-compute.js +1 -1
- package/browser/live-cards.js +178 -144
- package/browser/live-cards.schema.json +1 -1
- package/dist/board-livegraph-runtime/index.cjs +4 -1
- package/dist/board-livegraph-runtime/index.cjs.map +1 -1
- package/dist/board-livegraph-runtime/index.js +4 -1
- package/dist/board-livegraph-runtime/index.js.map +1 -1
- package/dist/card-compute/index.cjs +5 -1
- package/dist/card-compute/index.cjs.map +1 -1
- package/dist/card-compute/index.js +5 -1
- package/dist/card-compute/index.js.map +1 -1
- package/dist/cli/board-live-cards-cli.cjs +2416 -2113
- package/dist/cli/board-live-cards-cli.cjs.map +1 -1
- package/dist/cli/board-live-cards-cli.d.cts +59 -113
- package/dist/cli/board-live-cards-cli.d.ts +59 -113
- package/dist/cli/board-live-cards-cli.js +2413 -2109
- package/dist/cli/board-live-cards-cli.js.map +1 -1
- package/dist/continuous-event-graph/index.cjs +4 -1
- package/dist/continuous-event-graph/index.cjs.map +1 -1
- package/dist/continuous-event-graph/index.js +4 -1
- package/dist/continuous-event-graph/index.js.map +1 -1
- package/dist/index.cjs +5 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker.js +4 -4
- package/examples/example-board/agent-instructions-cardlayout.md +28 -0
- package/examples/example-board/agent-instructions.md +4 -5
- package/examples/example-board/cards/card-rebalance-sim.json +13 -3
- package/examples/example-board/demo-server.js +77 -11
- package/examples/example-board/demo-shell-browser.html +4 -4
- package/examples/example-board/demo-shell-with-server.html +4 -4
- package/examples/example-board/demo-task-executor.js +22 -2
- package/package.json +1 -1
- package/schema/live-cards.schema.json +1 -1
|
@@ -79,14 +79,14 @@ function cliCommand() {
|
|
|
79
79
|
|
|
80
80
|
function runCli(args, capture = false) {
|
|
81
81
|
const { cmd, prefixArgs } = cliCommand();
|
|
82
|
+
const env = { ...process.env };
|
|
83
|
+
// This demo needs real worker dispatch; suppressing spawn keeps source/inference tasks in running state.
|
|
84
|
+
delete env.BOARD_LIVE_CARDS_NO_SPAWN;
|
|
82
85
|
const result = spawnSync(cmd, [...prefixArgs, ...args], {
|
|
83
86
|
stdio: capture ? 'pipe' : 'inherit',
|
|
84
87
|
shell: false,
|
|
85
88
|
windowsHide: true,
|
|
86
|
-
env
|
|
87
|
-
...process.env,
|
|
88
|
-
BOARD_LIVE_CARDS_NO_SPAWN: '1',
|
|
89
|
-
},
|
|
89
|
+
env,
|
|
90
90
|
encoding: capture ? 'utf-8' : undefined,
|
|
91
91
|
});
|
|
92
92
|
|
|
@@ -26,3 +26,31 @@
|
|
|
26
26
|
- `board.col` — Bootstrap 12-column span: `3`=quarter, `4`=third, `6`=half, `8`=two-thirds, `12`=full
|
|
27
27
|
- `board.order` — ascending integer, controls vertical sort in board view
|
|
28
28
|
- `canvas` — pixel coordinates/size for drag-layout (canvas mode). `h` must be tall enough for all rendered content — a card with metrics + a 4-row table typically needs 400–500px. Too small a height causes an in-card scrollbar; when in doubt, size generously.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## LLM View-Type Guidance (for `kind: "ref"`)
|
|
33
|
+
|
|
34
|
+
When a source uses Copilot/LLM and the card renders via a `ref` element, the model should emit a `_view` hint alongside the data.
|
|
35
|
+
|
|
36
|
+
- Keep `_view.kind` within the renderer whitelist only:
|
|
37
|
+
`table`, `editable-table`, `chart`, `metric`, `list`, `badge`, `text`, `narrative`, `markdown`, `form`, `filter`, `todo`, `alert`
|
|
38
|
+
- Default to `table` when uncertain.
|
|
39
|
+
- Use `editable-table` for user-adjustable tabular rows and include `data.writeTo` to a `card_data` path.
|
|
40
|
+
- Use `chart` only when one clear category/value mapping exists; include `data.chartType` and `data.columns: [labelField, valueField]`.
|
|
41
|
+
- Keep `_view.data` minimal. Static card JSON may override it for safety.
|
|
42
|
+
|
|
43
|
+
Recommended response shape:
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"<data_key>": [ ... ],
|
|
48
|
+
"_view": {
|
|
49
|
+
"kind": "editable-table",
|
|
50
|
+
"data": {
|
|
51
|
+
"writeTo": "card_data.<key>",
|
|
52
|
+
"columns": ["field1", "field2"]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
@@ -509,11 +509,10 @@ The optional `projections` map lets a source definition declare which upstream d
|
|
|
509
509
|
"outputFile": "quotes.json",
|
|
510
510
|
"projections": {
|
|
511
511
|
"holdings": "requires.holdings",
|
|
512
|
-
"
|
|
513
|
-
"threshold": "card_data.threshold"
|
|
512
|
+
"url_list": "requires.holdings.ticker.('https://query1.finance.yahoo.com/v8/finance/chart/' & $ & '?interval=1d&range=1d')"
|
|
514
513
|
},
|
|
515
|
-
"
|
|
516
|
-
"
|
|
514
|
+
"url-list": {
|
|
515
|
+
"cacheTimeout": 3600
|
|
517
516
|
}
|
|
518
517
|
}
|
|
519
518
|
]
|
|
@@ -538,7 +537,7 @@ node board-live-cards-cli.js describe-task-executor-capabilities --rg <boardDir>
|
|
|
538
537
|
```
|
|
539
538
|
|
|
540
539
|
This invokes the executor's `describe-capabilities` subcommand and prints its capabilities JSON to stdout. The output includes:
|
|
541
|
-
- **`sourceKinds`** — every source kind the executor handles (e.g. `mock`, `copilot`, `
|
|
540
|
+
- **`sourceKinds`** — every source kind the executor handles (e.g. `mock`, `copilot`, `workiq`, `url`, `url-list`), each with:
|
|
542
541
|
- `description` — what the kind does
|
|
543
542
|
- `inputSchema` — the exact `customFields` the executor expects on the source entry
|
|
544
543
|
- `outputShape` — the shape of the JSON written to `--out`
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"portfolio_action": "requires.portfolio_action"
|
|
20
20
|
},
|
|
21
21
|
"copilot": {
|
|
22
|
-
"prompt_template": "You are a portfolio rebalance advisor. Using the intelligence analysis and current holdings below, propose specific trades.\n\nCurrent holdings:\n{{holdings}}\nFields: ticker, quantity, cost_basis ($).\n\nPositions (with live prices):\n{{positions}}\nFields: ticker, quantity, cost_basis, price ($), value ($), gain_$, gain_%, chg_$, chg_pct.\n\nPortfolio intelligence:\n- Mix: {{portfolio_mix}}\n- Risks: {{portfolio_risks}}\n- Action signal: {{portfolio_action}}\n\nIMPORTANT OUTPUT RULES:\n- Return ONLY a valid JSON object. No markdown, no preamble, no trailing text.\n- Start with { and end with }.\n- proposed_trades must be an array of objects with EXACTLY these fields per entry:\n ticker (string), direction (\"reduce\" or \"increase\"), current_qty (number, current shares held), change (number, shares to trade), proposed_qty (number, resulting shares after trade), price (number, current price per share), trade_value (number, change * price rounded to 2 decimals), reason (string, one short sentence).\n- Include one entry per ticker you recommend changing. Do not include tickers with no change.\n\n{\n \"proposed_trades\": [\n {\"ticker\": \"AAPL\", \"direction\": \"reduce\", \"current_qty\": 15, \"change\": 5, \"proposed_qty\": 10, \"price\": 210.50, \"trade_value\": 1052.50, \"reason\": \"overweight at 41%, trim before earnings\"}\n ]\n}"
|
|
22
|
+
"prompt_template": "You are a portfolio rebalance advisor. Using the intelligence analysis and current holdings below, propose specific trades.\n\nCurrent holdings:\n{{holdings}}\nFields: ticker, quantity, cost_basis ($).\n\nPositions (with live prices):\n{{positions}}\nFields: ticker, quantity, cost_basis, price ($), value ($), gain_$, gain_%, chg_$, chg_pct.\n\nPortfolio intelligence:\n- Mix: {{portfolio_mix}}\n- Risks: {{portfolio_risks}}\n- Action signal: {{portfolio_action}}\n\n{{view_kind_guidance}}\n\n{{card_layout_guidance}}\n\nIMPORTANT OUTPUT RULES:\n- Return ONLY a valid JSON object. No markdown, no preamble, no trailing text.\n- Start with { and end with }.\n- proposed_trades must be an array of objects with EXACTLY these fields per entry:\n ticker (string), direction (\"reduce\" or \"increase\"), current_qty (number, current shares held), change (number, shares to trade), proposed_qty (number, resulting shares after trade), price (number, current price per share), trade_value (number, change * price rounded to 2 decimals), reason (string, one short sentence).\n- Include one entry per ticker you recommend changing. Do not include tickers with no change.\n- Include a top-level _view object for a ref element with this shape:\n { \"kind\": \"editable-table\"|\"table\"|\"chart\", \"data\": { ... } }\n- If kind is editable-table or table, include data.columns with the exact proposed_trades fields in desired order.\n- If kind is editable-table, also include data.writeTo = \"card_data.proposed_trades\".\n- If kind is chart, include data.chartType and data.columns as [\"ticker\", \"trade_value\"].\n- If unsure, choose editable-table.\n\n{\n \"proposed_trades\": [\n {\"ticker\": \"AAPL\", \"direction\": \"reduce\", \"current_qty\": 15, \"change\": 5, \"proposed_qty\": 10, \"price\": 210.50, \"trade_value\": 1052.50, \"reason\": \"overweight at 41%, trim before earnings\"}\n ],\n \"_view\": {\n \"kind\": \"editable-table\",\n \"data\": {\n \"writeTo\": \"card_data.proposed_trades\",\n \"columns\": [\"ticker\", \"direction\", \"current_qty\", \"change\", \"proposed_qty\", \"price\", \"trade_value\", \"reason\"]\n }\n }\n}"
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
],
|
|
@@ -29,10 +29,12 @@
|
|
|
29
29
|
"view": {
|
|
30
30
|
"elements": [
|
|
31
31
|
{
|
|
32
|
-
"kind": "
|
|
32
|
+
"kind": "ref",
|
|
33
33
|
"label": "Proposed Trades",
|
|
34
34
|
"data": {
|
|
35
35
|
"bind": "fetched_sources.rebalance.proposed_trades",
|
|
36
|
+
"viewBind": "fetched_sources.rebalance._view",
|
|
37
|
+
"fallbackKind": "editable-table",
|
|
36
38
|
"writeTo": "card_data.proposed_trades",
|
|
37
39
|
"columns": ["ticker", "direction", "current_qty", "change", "proposed_qty", "price", "trade_value", "reason"],
|
|
38
40
|
"schema": {
|
|
@@ -45,13 +47,21 @@
|
|
|
45
47
|
}
|
|
46
48
|
}
|
|
47
49
|
}
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"kind": "notes",
|
|
53
|
+
"label": "Notes",
|
|
54
|
+
"data": {
|
|
55
|
+
"bind": "card_data.notes",
|
|
56
|
+
"writeTo": "card_data.notes"
|
|
57
|
+
}
|
|
48
58
|
}
|
|
49
59
|
],
|
|
50
60
|
"layout": {
|
|
51
61
|
"board": { "col": 6, "order": 7 },
|
|
52
62
|
"canvas": { "x": 840, "y": 480, "w": 500, "h": 280 }
|
|
53
63
|
},
|
|
54
|
-
"features": { "refresh": true
|
|
64
|
+
"features": { "refresh": true }
|
|
55
65
|
},
|
|
56
66
|
"card_data": {}
|
|
57
67
|
}
|
|
@@ -126,13 +126,67 @@ function jsonReply(res, status, payload) {
|
|
|
126
126
|
res.end(body);
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
// Card preparation — host-level concern, not a reusable runtime concern.
|
|
131
|
+
// Copies source card JSON files into the runtime's tmpCardsDir and writes
|
|
132
|
+
// the concatenated copilot-instructions.md at the board setup root.
|
|
133
|
+
// The runtime's bootstrap operations assume cards are already in tmpCardsDir;
|
|
134
|
+
// the host (this file) decides how and when they get there.
|
|
135
|
+
// ---------------------------------------------------------------------------
|
|
136
|
+
|
|
137
|
+
const _demoPrepSetupDone = new Map(); // boardId → true
|
|
138
|
+
|
|
139
|
+
function isDemoSetupDone(boardId, service) {
|
|
140
|
+
return _demoPrepSetupDone.get(boardId) === true && fs.existsSync(service.tmpCardsDir);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function demoPrepSetup(boardId, service) {
|
|
144
|
+
const { tmpSurfaceDir, tmpCardsDir, cardsDir, gandalfCardsDir, tmpGandalfCardsDir, boardDir } = service;
|
|
145
|
+
|
|
146
|
+
fs.mkdirSync(tmpSurfaceDir, { recursive: true });
|
|
147
|
+
fs.rmSync(tmpCardsDir, { recursive: true, force: true });
|
|
148
|
+
fs.mkdirSync(tmpCardsDir, { recursive: true });
|
|
149
|
+
|
|
150
|
+
const entries = fs.readdirSync(cardsDir, { withFileTypes: true });
|
|
151
|
+
for (const entry of entries) {
|
|
152
|
+
if (!entry.isFile()) continue;
|
|
153
|
+
if (!entry.name.toLowerCase().endsWith('.json')) continue;
|
|
154
|
+
fs.copyFileSync(path.join(cardsDir, entry.name), path.join(tmpCardsDir, entry.name));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Copy gandalf-card templates if gandalfCardsDir is configured.
|
|
158
|
+
if (gandalfCardsDir && fs.existsSync(gandalfCardsDir)) {
|
|
159
|
+
fs.rmSync(tmpGandalfCardsDir, { recursive: true, force: true });
|
|
160
|
+
fs.mkdirSync(tmpGandalfCardsDir, { recursive: true });
|
|
161
|
+
for (const entry of fs.readdirSync(gandalfCardsDir, { withFileTypes: true })) {
|
|
162
|
+
if (!entry.isFile() || !entry.name.toLowerCase().endsWith('.json')) continue;
|
|
163
|
+
fs.copyFileSync(path.join(gandalfCardsDir, entry.name), path.join(tmpGandalfCardsDir, entry.name));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Concatenate agent-instructions*.md into copilot-instructions.md at boardSetupRoot.
|
|
168
|
+
const boardSetupRoot = path.dirname(boardDir);
|
|
169
|
+
const srcDir = path.dirname(cardsDir);
|
|
170
|
+
const agentInstructionFiles = ['agent-instructions.md', 'agent-instructions-cardlayout.md'];
|
|
171
|
+
const parts = [];
|
|
172
|
+
for (const fname of agentInstructionFiles) {
|
|
173
|
+
const fpath = path.join(srcDir, fname);
|
|
174
|
+
if (fs.existsSync(fpath)) parts.push(fs.readFileSync(fpath, 'utf-8').trimEnd());
|
|
175
|
+
}
|
|
176
|
+
if (parts.length > 0) {
|
|
177
|
+
fs.writeFileSync(path.join(boardSetupRoot, 'copilot-instructions.md'), parts.join('\n\n') + '\n', 'utf-8');
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
_demoPrepSetupDone.set(boardId, true);
|
|
181
|
+
}
|
|
182
|
+
|
|
129
183
|
async function handleDemoSetup(req, res, boardId) {
|
|
130
184
|
try {
|
|
131
|
-
const { service
|
|
185
|
+
const { service } = runtime.requireBoardService(boardId);
|
|
132
186
|
let setupPerformed = false;
|
|
133
187
|
|
|
134
|
-
if (!
|
|
135
|
-
service
|
|
188
|
+
if (!isDemoSetupDone(boardId, service)) {
|
|
189
|
+
demoPrepSetup(boardId, service);
|
|
136
190
|
setupPerformed = true;
|
|
137
191
|
}
|
|
138
192
|
|
|
@@ -168,26 +222,38 @@ async function handleWorkiqAsk(req, res) {
|
|
|
168
222
|
await new Promise((resolve) => {
|
|
169
223
|
let stdout = '';
|
|
170
224
|
let stderr = '';
|
|
225
|
+
let responded = false;
|
|
171
226
|
const child = spawn(process.execPath, [workiqJs, 'ask', '-q', query], {
|
|
172
227
|
stdio: ['inherit', 'pipe', 'pipe'],
|
|
173
228
|
});
|
|
174
229
|
child.stdout.on('data', chunk => { stdout += chunk; });
|
|
175
230
|
child.stderr.on('data', chunk => { stderr += chunk; });
|
|
176
231
|
child.on('error', (err) => {
|
|
177
|
-
|
|
232
|
+
if (!responded) {
|
|
233
|
+
responded = true;
|
|
234
|
+
clearTimeout(timeoutId);
|
|
235
|
+
jsonReply(res, 500, { error: `workiq spawn error: ${err.message}` });
|
|
236
|
+
}
|
|
178
237
|
resolve();
|
|
179
238
|
});
|
|
180
239
|
child.on('close', (code) => {
|
|
181
|
-
if (
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
240
|
+
if (!responded) {
|
|
241
|
+
responded = true;
|
|
242
|
+
clearTimeout(timeoutId);
|
|
243
|
+
if (code !== 0) {
|
|
244
|
+
jsonReply(res, 500, { error: `workiq exited ${code}`, stderr });
|
|
245
|
+
} else {
|
|
246
|
+
jsonReply(res, 200, { response: stdout });
|
|
247
|
+
}
|
|
185
248
|
}
|
|
186
249
|
resolve();
|
|
187
250
|
});
|
|
188
|
-
setTimeout(() => {
|
|
189
|
-
|
|
190
|
-
|
|
251
|
+
const timeoutId = setTimeout(() => {
|
|
252
|
+
if (!responded) {
|
|
253
|
+
responded = true;
|
|
254
|
+
child.kill();
|
|
255
|
+
jsonReply(res, 504, { error: 'workiq timed out after 60s' });
|
|
256
|
+
}
|
|
191
257
|
resolve();
|
|
192
258
|
}, 60_000);
|
|
193
259
|
});
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
<title>Example Board Demo (Browser Runtime)</title>
|
|
7
7
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" />
|
|
8
8
|
<script src="https://cdn.jsdelivr.net/npm/jsonata/jsonata.min.js"></script>
|
|
9
|
-
<script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.
|
|
10
|
-
<script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.
|
|
11
|
-
<script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.
|
|
9
|
+
<script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.4.0/browser/card-compute.js"></script>
|
|
10
|
+
<script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.4.0/browser/live-cards.js"></script>
|
|
11
|
+
<script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.4.0/browser/board-livegraph-engine.js"></script>
|
|
12
12
|
</head>
|
|
13
13
|
<body class="bg-light">
|
|
14
14
|
<div class="container-fluid py-3">
|
|
@@ -378,7 +378,7 @@
|
|
|
378
378
|
|
|
379
379
|
return {
|
|
380
380
|
fetchSource: async function (card, sourceDef) {
|
|
381
|
-
//
|
|
381
|
+
// mock source with mock="quotes" → return mock quote data
|
|
382
382
|
if (sourceDef && sourceDef.mock === 'quotes') return clone(quoteData);
|
|
383
383
|
// copilot source → return mock analysis object
|
|
384
384
|
if (sourceDef && sourceDef.copilot) return clone(mockAnalysis);
|
|
@@ -16,10 +16,10 @@
|
|
|
16
16
|
</style>
|
|
17
17
|
<script src="https://cdn.jsdelivr.net/npm/jsonata/jsonata.min.js"></script>
|
|
18
18
|
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
|
19
|
-
<script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.
|
|
20
|
-
<script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.
|
|
21
|
-
<script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.
|
|
22
|
-
<script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.
|
|
19
|
+
<script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.4.0/browser/card-compute.js"></script>
|
|
20
|
+
<script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.4.0/browser/live-cards.js"></script>
|
|
21
|
+
<script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.4.0/browser/board-livegraph-engine.js"></script>
|
|
22
|
+
<script src="https://cdn.jsdelivr.net/npm/yaml-flow@5.4.0/browser/board-livecards-runtime-client.js"></script>
|
|
23
23
|
</head>
|
|
24
24
|
<body class="bg-light">
|
|
25
25
|
<div class="container-fluid py-3">
|
|
@@ -45,8 +45,7 @@
|
|
|
45
45
|
* - { "url-list": { method?, headers?, cacheTimeout? } }
|
|
46
46
|
* → fan-out over _projections.url_list (string[]); returns array of responses.
|
|
47
47
|
* Build url_list in projections: e.g. `requires.holdings.ticker.('https://host/' & $ & '?q=1')`
|
|
48
|
-
*
|
|
49
|
-
* prefer url-list for new sources
|
|
48
|
+
* Prefer url-list for multi-URL fan-out sources.
|
|
50
49
|
* A real executor can also handle: graphapi, teams, mail, incidentdb, script, etc.
|
|
51
50
|
*
|
|
52
51
|
* url / url-list notes:
|
|
@@ -137,6 +136,26 @@ function interpolatePrompt(template, args) {
|
|
|
137
136
|
});
|
|
138
137
|
}
|
|
139
138
|
|
|
139
|
+
// Reusable prompt fragments available to all copilot source templates.
|
|
140
|
+
// Source definitions can interpolate them with {{view_kind_guidance}} and {{card_layout_guidance}}.
|
|
141
|
+
const COPILOT_PROMPT_CONTEXT = {
|
|
142
|
+
view_kind_guidance: [
|
|
143
|
+
'VIEW KIND GUIDANCE (for dynamic ref rendering):',
|
|
144
|
+
'- Return a _view object whenever your output data is meant for a ref element.',
|
|
145
|
+
'- Allowed _view.kind values only: table, editable-table, chart, metric, list, badge, text, narrative, markdown, form, filter, todo, alert.',
|
|
146
|
+
'- If uncertain, use "table".',
|
|
147
|
+
'- For array rows that users should edit, prefer "editable-table" and set _view.data.writeTo to a card_data path.',
|
|
148
|
+
'- For chart, set _view.data.chartType and _view.data.columns with [labelField, valueField].',
|
|
149
|
+
'- Keep _view.data minimal and valid JSON (no comments, no trailing text).',
|
|
150
|
+
].join('\n'),
|
|
151
|
+
card_layout_guidance: [
|
|
152
|
+
'CARD LAYOUT GUIDANCE:',
|
|
153
|
+
'- Prefer compact outputs that fit a card: one primary structure plus concise rationale text.',
|
|
154
|
+
'- Avoid repeating values already present in upstream inputs.',
|
|
155
|
+
'- If you produce both machine-readable and human-readable content, keep machine-readable fields top-level and concise prose in a separate field.',
|
|
156
|
+
].join('\n'),
|
|
157
|
+
};
|
|
158
|
+
|
|
140
159
|
/**
|
|
141
160
|
* Fetch a URL using the system curl binary (synchronous, no Node event-loop handles).
|
|
142
161
|
* Throws if curl exits non-zero (e.g. HTTP 4xx/5xx with -f, or network error).
|
|
@@ -167,6 +186,7 @@ function resolveCopilotPrompt(sourceDef) {
|
|
|
167
186
|
// evaluated by the engine from card_data/requires before invoking this executor.
|
|
168
187
|
// Explicit args defined on the source take highest precedence.
|
|
169
188
|
const interpolationContext = {
|
|
189
|
+
...COPILOT_PROMPT_CONTEXT,
|
|
170
190
|
...sourceDef._projections,
|
|
171
191
|
...args,
|
|
172
192
|
};
|
package/package.json
CHANGED
|
@@ -126,7 +126,7 @@
|
|
|
126
126
|
"kind": {
|
|
127
127
|
"enum": ["metric", "table", "editable-table", "chart", "form", "filter", "list",
|
|
128
128
|
"notes", "todo", "alert", "narrative", "badge", "text",
|
|
129
|
-
"markdown", "custom", "actions"]
|
|
129
|
+
"markdown", "ref", "custom", "actions"]
|
|
130
130
|
},
|
|
131
131
|
"label": { "type": "string", "description": "Heading above this element" },
|
|
132
132
|
"className": { "type": "string", "description": "Bootstrap grid class, e.g. 'col-12 col-md-6'" },
|