yaml-flow 5.0.0 → 5.2.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/{examples/example-board/reusable-server-runtime.js → board-livecards-server-runtime.js} +103 -24
- package/{examples/example-board/reusable-board-runtime-client.js → browser/board-livecards-runtime-client.js} +6 -2
- package/browser/{board-livegraph-runtime.js → board-livegraph-engine.js} +212 -16
- package/browser/board-livegraph-engine.js.map +1 -0
- package/browser/live-cards.js +362 -38
- package/browser/live-cards.schema.json +20 -4
- package/dist/board-livegraph-runtime/index.cjs +210 -14
- package/dist/board-livegraph-runtime/index.cjs.map +1 -1
- package/dist/board-livegraph-runtime/index.d.cts +49 -5
- package/dist/board-livegraph-runtime/index.d.ts +49 -5
- package/dist/board-livegraph-runtime/index.js +209 -15
- package/dist/board-livegraph-runtime/index.js.map +1 -1
- package/dist/card-compute/index.cjs +63 -7
- package/dist/card-compute/index.cjs.map +1 -1
- package/dist/card-compute/index.d.cts +2 -2
- package/dist/card-compute/index.d.ts +2 -2
- package/dist/card-compute/index.js +63 -7
- package/dist/card-compute/index.js.map +1 -1
- package/dist/cli/board-live-cards-cli.cjs +664 -75
- package/dist/cli/board-live-cards-cli.cjs.map +1 -1
- package/dist/cli/board-live-cards-cli.d.cts +33 -5
- package/dist/cli/board-live-cards-cli.d.ts +33 -5
- package/dist/cli/board-live-cards-cli.js +661 -76
- package/dist/cli/board-live-cards-cli.js.map +1 -1
- package/dist/{constants-ozjf1Ejw.d.cts → constants-BzZUyYlp.d.cts} +1 -1
- package/dist/{constants-DuzE5n03.d.ts → constants-oCEbNpul.d.ts} +1 -1
- package/dist/continuous-event-graph/index.cjs +47 -14
- package/dist/continuous-event-graph/index.cjs.map +1 -1
- package/dist/continuous-event-graph/index.d.cts +9 -9
- package/dist/continuous-event-graph/index.d.ts +9 -9
- package/dist/continuous-event-graph/index.js +47 -14
- package/dist/continuous-event-graph/index.js.map +1 -1
- package/dist/event-graph/index.cjs +29 -12
- package/dist/event-graph/index.cjs.map +1 -1
- package/dist/event-graph/index.d.cts +5 -5
- package/dist/event-graph/index.d.ts +5 -5
- package/dist/event-graph/index.js +29 -12
- package/dist/event-graph/index.js.map +1 -1
- package/dist/index.cjs +93 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -7
- package/dist/index.d.ts +7 -7
- package/dist/index.js +93 -20
- package/dist/index.js.map +1 -1
- package/dist/inference/index.cjs +29 -12
- package/dist/inference/index.cjs.map +1 -1
- package/dist/inference/index.d.cts +2 -2
- package/dist/inference/index.d.ts +2 -2
- package/dist/inference/index.js +29 -12
- package/dist/inference/index.js.map +1 -1
- package/dist/{journal-NLYuqege.d.ts → journal-9HEgs7dU.d.ts} +1 -1
- package/dist/{journal-DRfJiheM.d.cts → journal-B-JCfQnh.d.cts} +1 -1
- package/dist/{live-cards-bridge-Or7fdEJV.d.ts → live-cards-bridge-CeNxiVcm.d.ts} +6 -2
- package/dist/{live-cards-bridge-vGJ6tMzN.d.cts → live-cards-bridge-z_rJCSbi.d.cts} +6 -2
- package/dist/{schedule-CMcZe5Ny.d.ts → schedule-Cszq9LYY.d.ts} +1 -1
- package/dist/{schedule-CiucyCan.d.cts → schedule-qWNL0RQh.d.cts} +1 -1
- package/dist/{types-CMFSIjpc.d.cts → types-BBhqYGhE.d.cts} +4 -0
- package/dist/{types-CMFSIjpc.d.ts → types-BBhqYGhE.d.ts} +4 -0
- package/dist/{types-BzLD8bjb.d.cts → types-CHSdoAAA.d.cts} +1 -1
- package/dist/{types-C2eJ7DAV.d.ts → types-CoW0gQl3.d.ts} +1 -1
- package/dist/{validate-DJQTQ6bP.d.ts → validate-BAVzUJWa.d.ts} +1 -1
- package/dist/{validate-ke92Cleg.d.cts → validate-Dbu7ygys.d.cts} +1 -1
- package/examples/browser/boards/portfolio-tracker/cards/portfolio-risk-assessment.json +28 -0
- package/examples/browser/boards/portfolio-tracker/cards/rebalancing-strategy.json +28 -0
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker-inference-adapter.js +187 -0
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker.js +139 -5
- package/examples/example-board/agent-instructions-cardlayout.md +28 -0
- package/examples/example-board/agent-instructions.md +603 -0
- package/examples/example-board/cards/card-concentration.json +42 -0
- package/examples/example-board/cards/card-market-prices.json +51 -0
- package/examples/example-board/cards/card-portfolio-action.json +19 -0
- package/examples/example-board/cards/card-portfolio-risks.json +19 -0
- package/examples/example-board/cards/card-portfolio-value.json +62 -0
- package/examples/example-board/cards/card-portfolio.json +44 -0
- package/examples/example-board/demo-chat-handler.js +373 -33
- package/examples/example-board/demo-server-config.json +5 -0
- package/examples/example-board/demo-server.js +83 -7
- package/examples/example-board/demo-shell-browser.html +75 -207
- package/examples/example-board/demo-shell-with-server.html +14 -9
- package/examples/example-board/demo-shell.html +1 -1
- package/examples/example-board/demo-task-executor.js +259 -41
- package/package.json +6 -2
- package/schema/live-cards.schema.json +20 -4
- package/browser/board-livegraph-runtime.js.map +0 -1
- package/examples/example-board/board.yaml +0 -23
- package/examples/example-board/bootstrap_payload.json +0 -1
- package/examples/example-board/cards/card-chain-region-alert.json +0 -39
- package/examples/example-board/cards/card-chain-region-totals.json +0 -26
- package/examples/example-board/cards/card-chain-top-region.json +0 -24
- package/examples/example-board/cards/card-ex-actions.json +0 -32
- package/examples/example-board/cards/card-ex-chart.json +0 -30
- package/examples/example-board/cards/card-ex-filter.json +0 -36
- package/examples/example-board/cards/card-ex-filtered-by-preference.json +0 -59
- package/examples/example-board/cards/card-ex-form.json +0 -91
- package/examples/example-board/cards/card-ex-list.json +0 -22
- package/examples/example-board/cards/card-ex-markdown.json +0 -17
- package/examples/example-board/cards/card-ex-metric.json +0 -19
- package/examples/example-board/cards/card-ex-narrative.json +0 -36
- package/examples/example-board/cards/card-ex-source-http.json +0 -28
- package/examples/example-board/cards/card-ex-source.json +0 -21
- package/examples/example-board/cards/card-ex-status.json +0 -35
- package/examples/example-board/cards/card-ex-table.json +0 -30
- package/examples/example-board/cards/card-ex-todo.json +0 -29
- package/examples/example-board/mock.db +0 -15
- package/examples/example-board/reusable-runtime-artifacts-adapter.js +0 -233
|
@@ -73,15 +73,30 @@ function groupTasksByProvides(candidateTaskNames, tasks) {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
// src/event-graph/task-transitions.ts
|
|
76
|
-
function applyTaskStart(state, taskName) {
|
|
76
|
+
function applyTaskStart(state, taskName, graph) {
|
|
77
77
|
const existingTask = state.tasks[taskName] ?? createDefaultGraphEngineStore();
|
|
78
|
+
const startConsumedHashes = {};
|
|
79
|
+
if (graph) {
|
|
80
|
+
const taskConfig = graph.tasks[taskName];
|
|
81
|
+
const requires = getRequires(taskConfig);
|
|
82
|
+
for (const token of requires) {
|
|
83
|
+
for (const [otherName, otherConfig] of Object.entries(graph.tasks)) {
|
|
84
|
+
if (getProvides(otherConfig).includes(token)) {
|
|
85
|
+
const otherState = state.tasks[otherName];
|
|
86
|
+
if (otherState?.lastDataHash) startConsumedHashes[token] = otherState.lastDataHash;
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
78
92
|
const updatedTask = {
|
|
79
93
|
...existingTask,
|
|
80
94
|
status: "running",
|
|
81
95
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
82
96
|
lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
83
97
|
progress: 0,
|
|
84
|
-
error: void 0
|
|
98
|
+
error: void 0,
|
|
99
|
+
startConsumedHashes
|
|
85
100
|
};
|
|
86
101
|
return {
|
|
87
102
|
...state,
|
|
@@ -101,16 +116,18 @@ function applyTaskCompletion(state, graph, taskName, result, dataHash, data) {
|
|
|
101
116
|
} else {
|
|
102
117
|
outputTokens = getProvides(taskConfig);
|
|
103
118
|
}
|
|
104
|
-
const lastConsumedHashes = { ...existingTask.lastConsumedHashes };
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
for (const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
119
|
+
const lastConsumedHashes = existingTask.startConsumedHashes ? { ...existingTask.startConsumedHashes } : { ...existingTask.lastConsumedHashes };
|
|
120
|
+
if (!existingTask.startConsumedHashes) {
|
|
121
|
+
const requires = taskConfig.requires ?? [];
|
|
122
|
+
for (const token of requires) {
|
|
123
|
+
for (const [otherName, otherConfig] of Object.entries(graph.tasks)) {
|
|
124
|
+
if (getProvides(otherConfig).includes(token)) {
|
|
125
|
+
const otherState = state.tasks[otherName];
|
|
126
|
+
if (otherState?.lastDataHash) {
|
|
127
|
+
lastConsumedHashes[token] = otherState.lastDataHash;
|
|
128
|
+
}
|
|
129
|
+
break;
|
|
112
130
|
}
|
|
113
|
-
break;
|
|
114
131
|
}
|
|
115
132
|
}
|
|
116
133
|
}
|
|
@@ -255,7 +272,7 @@ function applyEvent(live, event) {
|
|
|
255
272
|
switch (event.type) {
|
|
256
273
|
// --- Execution state transitions ---
|
|
257
274
|
case "task-started":
|
|
258
|
-
return { config, state: applyTaskStart(state, event.taskName) };
|
|
275
|
+
return { config, state: applyTaskStart(state, event.taskName, config) };
|
|
259
276
|
case "task-completed":
|
|
260
277
|
return { config, state: applyTaskCompletion(state, config, event.taskName, event.result, event.dataHash, event.data) };
|
|
261
278
|
case "task-failed":
|
|
@@ -1083,13 +1100,29 @@ function validateNode(node) {
|
|
|
1083
1100
|
if (!Array.isArray(n.sources)) {
|
|
1084
1101
|
errors.push("sources: must be an array");
|
|
1085
1102
|
} else {
|
|
1103
|
+
const bindTos = /* @__PURE__ */ new Set();
|
|
1104
|
+
const outputFiles = /* @__PURE__ */ new Set();
|
|
1086
1105
|
n.sources.forEach((src, i) => {
|
|
1087
1106
|
if (!src || typeof src !== "object" || Array.isArray(src)) {
|
|
1088
1107
|
errors.push(`sources[${i}]: must be an object`);
|
|
1089
1108
|
} else {
|
|
1090
1109
|
const s = src;
|
|
1091
|
-
if (typeof s.bindTo !== "string" || !s.bindTo)
|
|
1092
|
-
|
|
1110
|
+
if (typeof s.bindTo !== "string" || !s.bindTo) {
|
|
1111
|
+
errors.push(`sources[${i}]: missing required "bindTo" property`);
|
|
1112
|
+
} else {
|
|
1113
|
+
if (bindTos.has(s.bindTo)) {
|
|
1114
|
+
errors.push(`sources[${i}]: bindTo "${s.bindTo}" is not unique across sources`);
|
|
1115
|
+
}
|
|
1116
|
+
bindTos.add(s.bindTo);
|
|
1117
|
+
}
|
|
1118
|
+
if (typeof s.outputFile !== "string" || !s.outputFile) {
|
|
1119
|
+
errors.push(`sources[${i}]: missing required "outputFile" property`);
|
|
1120
|
+
} else {
|
|
1121
|
+
if (outputFiles.has(s.outputFile)) {
|
|
1122
|
+
errors.push(`sources[${i}]: outputFile "${s.outputFile}" is not unique across sources`);
|
|
1123
|
+
}
|
|
1124
|
+
outputFiles.add(s.outputFile);
|
|
1125
|
+
}
|
|
1093
1126
|
if (s.optionalForCompletionGating != null && typeof s.optionalForCompletionGating !== "boolean") {
|
|
1094
1127
|
errors.push(`sources[${i}]: optionalForCompletionGating must be a boolean`);
|
|
1095
1128
|
}
|
|
@@ -1147,12 +1180,15 @@ var CardCompute = {
|
|
|
1147
1180
|
var BOARD_FILE = "board-graph.json";
|
|
1148
1181
|
var JOURNAL_FILE = "board-journal.jsonl";
|
|
1149
1182
|
var TASK_EXECUTOR_LOG_FILE = "task-executor.jsonl";
|
|
1183
|
+
var INFERENCE_ADAPTER_LOG_FILE = "inference-adapter.jsonl";
|
|
1150
1184
|
var INVENTORY_FILE = "cards-inventory.jsonl";
|
|
1151
1185
|
var RUNTIME_OUT_FILE = ".runtime-out";
|
|
1152
1186
|
var DEFAULT_RUNTIME_OUT_DIR = "runtime-out";
|
|
1153
1187
|
var RUNTIME_STATUS_FILE = "board-livegraph-status.json";
|
|
1154
1188
|
var RUNTIME_CARDS_DIR = "cards";
|
|
1155
1189
|
var RUNTIME_DATA_OBJECTS_DIR = "data-objects";
|
|
1190
|
+
var INFERENCE_ADAPTER_FILE = ".inference-adapter";
|
|
1191
|
+
var DEFAULT_TASK_COMPLETION_RULE = "all_required_sources_fetched";
|
|
1156
1192
|
var EMPTY_CONFIG = { settings: { completion: "manual", refreshStrategy: "data-changed" }, tasks: {} };
|
|
1157
1193
|
var BoardJournal = class {
|
|
1158
1194
|
journalPath;
|
|
@@ -1360,6 +1396,39 @@ function decodeSourceToken(token) {
|
|
|
1360
1396
|
return null;
|
|
1361
1397
|
}
|
|
1362
1398
|
}
|
|
1399
|
+
function markRequested(entry, requestedAt) {
|
|
1400
|
+
entry.lastRequestedAt = requestedAt;
|
|
1401
|
+
}
|
|
1402
|
+
function markFetchFailed(entry, reason) {
|
|
1403
|
+
entry.lastError = reason;
|
|
1404
|
+
delete entry.lastFetchedAt;
|
|
1405
|
+
}
|
|
1406
|
+
function markFetchCompleted(entry, fetchedAt) {
|
|
1407
|
+
entry.lastFetchedAt = fetchedAt;
|
|
1408
|
+
delete entry.lastError;
|
|
1409
|
+
}
|
|
1410
|
+
function isSourceInFlight(entry) {
|
|
1411
|
+
if (!entry?.lastRequestedAt) return false;
|
|
1412
|
+
return !entry.lastFetchedAt || entry.lastFetchedAt < entry.lastRequestedAt;
|
|
1413
|
+
}
|
|
1414
|
+
function decideSourceAction(entry, queueRequestedAt) {
|
|
1415
|
+
if (!entry?.lastRequestedAt) return "dispatch";
|
|
1416
|
+
const inFlight = isSourceInFlight(entry);
|
|
1417
|
+
if (inFlight) return "in-flight";
|
|
1418
|
+
if (!entry.lastFetchedAt) return "dispatch";
|
|
1419
|
+
if (entry.lastFetchedAt < queueRequestedAt) return "dispatch";
|
|
1420
|
+
return "idle";
|
|
1421
|
+
}
|
|
1422
|
+
function nextEntryAfterFetchDelivery(entry, fetchedAt) {
|
|
1423
|
+
const next = { ...entry };
|
|
1424
|
+
markFetchCompleted(next, fetchedAt);
|
|
1425
|
+
return next;
|
|
1426
|
+
}
|
|
1427
|
+
function nextEntryAfterFetchFailure(entry, reason) {
|
|
1428
|
+
const next = { ...entry };
|
|
1429
|
+
markFetchFailed(next, reason);
|
|
1430
|
+
return next;
|
|
1431
|
+
}
|
|
1363
1432
|
function runtimePath(boardDir, cardId) {
|
|
1364
1433
|
return path.join(boardDir, `${cardId}.runtime.json`);
|
|
1365
1434
|
}
|
|
@@ -1514,6 +1583,15 @@ function splitCommandLine(command) {
|
|
|
1514
1583
|
if (current) tokens.push(current);
|
|
1515
1584
|
return tokens;
|
|
1516
1585
|
}
|
|
1586
|
+
function resolveCommandInvocation(rawCmd, rawArgs) {
|
|
1587
|
+
if (/^(node|node\.exe)$/i.test(rawCmd)) {
|
|
1588
|
+
return { cmd: process.execPath, args: rawArgs };
|
|
1589
|
+
}
|
|
1590
|
+
if (/\.m?js$/i.test(rawCmd)) {
|
|
1591
|
+
return { cmd: process.execPath, args: [rawCmd, ...rawArgs] };
|
|
1592
|
+
}
|
|
1593
|
+
return { cmd: rawCmd, args: rawArgs };
|
|
1594
|
+
}
|
|
1517
1595
|
function spawnDetachedProcessAccumulatedWorker(boardDir) {
|
|
1518
1596
|
const { cmd, args: cliArgs } = getCliInvocation("process-accumulated-events", ["--rg", boardDir, "--inline-loop"]);
|
|
1519
1597
|
try {
|
|
@@ -1589,7 +1667,18 @@ function getCliInvocation(command, args) {
|
|
|
1589
1667
|
return { cmd: npxCmd, args: ["tsx", tsPath, command, ...args] };
|
|
1590
1668
|
}
|
|
1591
1669
|
function invokeRunSources(boardDir, cardPath, callbackToken, callback) {
|
|
1592
|
-
const
|
|
1670
|
+
const args = ["--card", cardPath, "--token", callbackToken, "--rg", boardDir];
|
|
1671
|
+
const { cmd, args: cmdArgs } = getCliInvocation("run-sources-internal", args);
|
|
1672
|
+
try {
|
|
1673
|
+
spawnDetachedCommand(cmd, cmdArgs);
|
|
1674
|
+
callback(null);
|
|
1675
|
+
} catch (err) {
|
|
1676
|
+
callback(err instanceof Error ? err : new Error(String(err)));
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
function invokeRunInference(boardDir, cardId, inputFile, callbackToken, checksum, callback) {
|
|
1680
|
+
const inferenceToken = encodeSourceToken({ cbk: callbackToken, rg: boardDir, cid: cardId, b: "", d: "", cs: checksum });
|
|
1681
|
+
const { cmd, args } = getCliInvocation("run-inference-internal", ["--in", inputFile, "--token", inferenceToken]);
|
|
1593
1682
|
try {
|
|
1594
1683
|
spawnDetachedCommand(cmd, args);
|
|
1595
1684
|
callback(null);
|
|
@@ -1597,10 +1686,11 @@ function invokeRunSources(boardDir, cardPath, callbackToken, callback) {
|
|
|
1597
1686
|
callback(err instanceof Error ? err : new Error(String(err)));
|
|
1598
1687
|
}
|
|
1599
1688
|
}
|
|
1600
|
-
function appendTaskExecutorLog(boardDir, hydratedSource) {
|
|
1689
|
+
function appendTaskExecutorLog(boardDir, hydratedSource, mode) {
|
|
1601
1690
|
try {
|
|
1602
1691
|
const entry = {
|
|
1603
1692
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1693
|
+
mode,
|
|
1604
1694
|
hydratedSource
|
|
1605
1695
|
};
|
|
1606
1696
|
fs.appendFileSync(path.join(boardDir, TASK_EXECUTOR_LOG_FILE), JSON.stringify(entry) + "\n", "utf-8");
|
|
@@ -1608,6 +1698,18 @@ function appendTaskExecutorLog(boardDir, hydratedSource) {
|
|
|
1608
1698
|
console.error(`[task-executor-log] append failed: ${logErr instanceof Error ? logErr.message : String(logErr)}`);
|
|
1609
1699
|
}
|
|
1610
1700
|
}
|
|
1701
|
+
function appendInferenceAdapterLog(boardDir, cardId, payload) {
|
|
1702
|
+
try {
|
|
1703
|
+
const entry = {
|
|
1704
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1705
|
+
cardId,
|
|
1706
|
+
payload
|
|
1707
|
+
};
|
|
1708
|
+
fs.appendFileSync(path.join(boardDir, INFERENCE_ADAPTER_LOG_FILE), JSON.stringify(entry) + "\n", "utf-8");
|
|
1709
|
+
} catch (logErr) {
|
|
1710
|
+
console.error(`[inference-adapter-log] append failed: ${logErr instanceof Error ? logErr.message : String(logErr)}`);
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1611
1713
|
function invokeSourceDataFetched(sourceToken, tmpFile, callback) {
|
|
1612
1714
|
const { cmd, args } = getCliInvocation("source-data-fetched", ["--tmp", tmpFile, "--token", sourceToken]);
|
|
1613
1715
|
execCommandAsync(cmd, args, (err, stdout, stderr) => {
|
|
@@ -1636,22 +1738,33 @@ function createBoardReactiveGraph(boardDir) {
|
|
|
1636
1738
|
const requiredSources = allSources.filter((s) => s.optionalForCompletionGating !== true);
|
|
1637
1739
|
const runtime = readRuntimeState(boardDir, cardId);
|
|
1638
1740
|
let runtimeDirty = false;
|
|
1741
|
+
const currentExecutionCount = input.taskState?.executionCount ?? 0;
|
|
1742
|
+
if (typeof runtime._lastExecutionCount === "number" && runtime._lastExecutionCount !== currentExecutionCount) {
|
|
1743
|
+
runtime._sources = {};
|
|
1744
|
+
runtime._inferenceEntry = void 0;
|
|
1745
|
+
}
|
|
1746
|
+
if (runtime._lastExecutionCount !== currentExecutionCount) {
|
|
1747
|
+
runtime._lastExecutionCount = currentExecutionCount;
|
|
1748
|
+
runtimeDirty = true;
|
|
1749
|
+
}
|
|
1639
1750
|
if (input.update) {
|
|
1640
1751
|
const u = input.update;
|
|
1641
|
-
const
|
|
1642
|
-
if (
|
|
1643
|
-
|
|
1644
|
-
runtime._sources[
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1752
|
+
const outputFile = u.outputFile;
|
|
1753
|
+
if (outputFile) {
|
|
1754
|
+
if (!runtime._sources[outputFile]) runtime._sources[outputFile] = {};
|
|
1755
|
+
const entry = runtime._sources[outputFile];
|
|
1756
|
+
if (u.failure) {
|
|
1757
|
+
runtime._sources[outputFile] = nextEntryAfterFetchFailure(entry, u.reason ?? "unknown");
|
|
1758
|
+
runtimeDirty = true;
|
|
1759
|
+
} else {
|
|
1760
|
+
runtime._sources[outputFile] = nextEntryAfterFetchDelivery(
|
|
1761
|
+
entry,
|
|
1762
|
+
u.fetchedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
1763
|
+
);
|
|
1764
|
+
runtimeDirty = true;
|
|
1765
|
+
}
|
|
1766
|
+
if (runtimeDirty) writeRuntimeState(boardDir, cardId, runtime);
|
|
1653
1767
|
}
|
|
1654
|
-
if (runtimeDirty) writeRuntimeState(boardDir, cardId, runtime);
|
|
1655
1768
|
}
|
|
1656
1769
|
const sourcesData = {};
|
|
1657
1770
|
for (const src of allSources) {
|
|
@@ -1693,40 +1806,57 @@ function createBoardReactiveGraph(boardDir) {
|
|
|
1693
1806
|
card_id: cardId,
|
|
1694
1807
|
computed_values: computeNode.computed_values ?? {}
|
|
1695
1808
|
});
|
|
1809
|
+
const enrichedCard = { ...card };
|
|
1810
|
+
const enrichedSources = CardCompute.enrichSources(
|
|
1811
|
+
Array.isArray(card.sources) ? card.sources : void 0,
|
|
1812
|
+
{
|
|
1813
|
+
requires,
|
|
1814
|
+
sourcesData,
|
|
1815
|
+
computed_values: computeNode.computed_values
|
|
1816
|
+
}
|
|
1817
|
+
);
|
|
1818
|
+
const sourceCwd = path.dirname(cardPath);
|
|
1819
|
+
enrichedCard.sources = Array.isArray(enrichedSources) ? enrichedSources.map((src) => ({
|
|
1820
|
+
...src,
|
|
1821
|
+
cwd: typeof src.cwd === "string" && src.cwd ? src.cwd : sourceCwd,
|
|
1822
|
+
boardDir: typeof src.boardDir === "string" && src.boardDir ? src.boardDir : boardDir
|
|
1823
|
+
})) : enrichedSources;
|
|
1824
|
+
const enrichedByOutput = /* @__PURE__ */ new Map();
|
|
1825
|
+
for (const src of Array.isArray(enrichedCard.sources) ? enrichedCard.sources : []) {
|
|
1826
|
+
const outputFile = src.outputFile;
|
|
1827
|
+
if (typeof outputFile === "string" && outputFile) {
|
|
1828
|
+
enrichedByOutput.set(outputFile, src);
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1696
1831
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1832
|
+
const runQueuedAt = input.update ? void 0 : now;
|
|
1697
1833
|
const undeliveredRequired = requiredSources.filter((s) => {
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
if (!
|
|
1701
|
-
|
|
1702
|
-
|
|
1834
|
+
const outputFile = s.outputFile;
|
|
1835
|
+
if (typeof outputFile !== "string" || !outputFile) return true;
|
|
1836
|
+
if (!runtime._sources[outputFile]) runtime._sources[outputFile] = {};
|
|
1837
|
+
const entry = runtime._sources[outputFile];
|
|
1838
|
+
if (runQueuedAt) {
|
|
1839
|
+
entry.queueRequestedAt = runQueuedAt;
|
|
1840
|
+
runtimeDirty = true;
|
|
1841
|
+
}
|
|
1842
|
+
const qrt = entry.queueRequestedAt ?? entry.lastRequestedAt ?? now;
|
|
1843
|
+
const action = decideSourceAction(entry, qrt);
|
|
1844
|
+
if (action === "in-flight") return false;
|
|
1845
|
+
return action === "dispatch";
|
|
1703
1846
|
});
|
|
1847
|
+
if (runtimeDirty) writeRuntimeState(boardDir, cardId, runtime);
|
|
1704
1848
|
if (undeliveredRequired.length > 0) {
|
|
1705
1849
|
let stampedAny = false;
|
|
1706
1850
|
for (const src of undeliveredRequired) {
|
|
1707
|
-
const
|
|
1708
|
-
if (
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1851
|
+
const outputFile = src.outputFile;
|
|
1852
|
+
if (typeof outputFile !== "string" || !outputFile) continue;
|
|
1853
|
+
const entry = runtime._sources[outputFile] ?? {};
|
|
1854
|
+
markRequested(entry, now);
|
|
1855
|
+
runtime._sources[outputFile] = entry;
|
|
1856
|
+
stampedAny = true;
|
|
1713
1857
|
}
|
|
1714
1858
|
if (stampedAny) writeRuntimeState(boardDir, cardId, runtime);
|
|
1715
|
-
|
|
1716
|
-
const enrichedSources = CardCompute.enrichSources(
|
|
1717
|
-
Array.isArray(card.sources) ? card.sources : void 0,
|
|
1718
|
-
{
|
|
1719
|
-
requires,
|
|
1720
|
-
sourcesData,
|
|
1721
|
-
computed_values: computeNode.computed_values
|
|
1722
|
-
}
|
|
1723
|
-
);
|
|
1724
|
-
const sourceCwd = path.dirname(cardPath);
|
|
1725
|
-
enrichedCard.sources = Array.isArray(enrichedSources) ? enrichedSources.map((src) => ({
|
|
1726
|
-
...src,
|
|
1727
|
-
cwd: typeof src.cwd === "string" && src.cwd ? src.cwd : sourceCwd,
|
|
1728
|
-
boardDir: typeof src.boardDir === "string" && src.boardDir ? src.boardDir : boardDir
|
|
1729
|
-
})) : enrichedSources;
|
|
1859
|
+
if (!stampedAny) return "task-initiated";
|
|
1730
1860
|
const enrichedCardPath = path.join(os.tmpdir(), `card-enriched-${cardId}-${Date.now()}.json`);
|
|
1731
1861
|
fs.writeFileSync(enrichedCardPath, JSON.stringify(enrichedCard, null, 2), "utf-8");
|
|
1732
1862
|
invokeRunSources(boardDir, enrichedCardPath, input.callbackToken, (err) => {
|
|
@@ -1745,10 +1875,79 @@ function createBoardReactiveGraph(boardDir) {
|
|
|
1745
1875
|
for (const { bindTo, src } of providesBindings) {
|
|
1746
1876
|
data[bindTo] = CardCompute.resolve(computeNode, src);
|
|
1747
1877
|
}
|
|
1878
|
+
const completionRule = typeof card.when_is_task_completed === "string" && card.when_is_task_completed.trim() ? card.when_is_task_completed.trim() : DEFAULT_TASK_COMPLETION_RULE;
|
|
1879
|
+
const cardData = card.card_data;
|
|
1880
|
+
const llmCompletion = cardData?.llm_task_completion_inference ?? {};
|
|
1881
|
+
const isLlmTaskCompleted = llmCompletion.isTaskCompleted === true;
|
|
1882
|
+
const inferenceEntry = runtime._inferenceEntry ?? {};
|
|
1883
|
+
const inferenceRequestedAt = typeof inferenceEntry.lastRequestedAt === "string" ? inferenceEntry.lastRequestedAt : void 0;
|
|
1884
|
+
const inferenceCompletedAt = typeof llmCompletion.inferenceCompletedAt === "string" ? llmCompletion.inferenceCompletedAt : void 0;
|
|
1885
|
+
const inferencePending = !!inferenceRequestedAt && (!inferenceCompletedAt || inferenceCompletedAt < inferenceRequestedAt);
|
|
1886
|
+
const latestRequiredSourceFetchedAt = requiredSources.reduce((latest, src) => {
|
|
1887
|
+
const fetchedAt = runtime._sources[src.outputFile]?.lastFetchedAt;
|
|
1888
|
+
if (typeof fetchedAt !== "string") return latest;
|
|
1889
|
+
if (!latest || fetchedAt > latest) return fetchedAt;
|
|
1890
|
+
return latest;
|
|
1891
|
+
}, void 0);
|
|
1892
|
+
const shouldRequestInference = !inferenceRequestedAt || !inferenceCompletedAt || !!latestRequiredSourceFetchedAt && latestRequiredSourceFetchedAt > inferenceCompletedAt;
|
|
1893
|
+
if (completionRule !== DEFAULT_TASK_COMPLETION_RULE) {
|
|
1894
|
+
if (isLlmTaskCompleted) ; else if (inferencePending) {
|
|
1895
|
+
return "task-initiated";
|
|
1896
|
+
} else if (!shouldRequestInference) {
|
|
1897
|
+
return "task-initiated";
|
|
1898
|
+
} else {
|
|
1899
|
+
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
1900
|
+
const inferencePayload = {
|
|
1901
|
+
cardId,
|
|
1902
|
+
taskName: input.nodeId,
|
|
1903
|
+
completionRule,
|
|
1904
|
+
context: {
|
|
1905
|
+
requires,
|
|
1906
|
+
sourcesData,
|
|
1907
|
+
computed_values: computeNode.computed_values ?? {},
|
|
1908
|
+
provides: data,
|
|
1909
|
+
card_data: computeNode.card_data ?? {}
|
|
1910
|
+
}
|
|
1911
|
+
};
|
|
1912
|
+
if (runQueuedAt) {
|
|
1913
|
+
inferenceEntry.queueRequestedAt = runQueuedAt;
|
|
1914
|
+
runtimeDirty = true;
|
|
1915
|
+
}
|
|
1916
|
+
const inferenceQrt = inferenceEntry.queueRequestedAt ?? inferenceEntry.lastRequestedAt ?? now2;
|
|
1917
|
+
const inferenceAction = decideSourceAction(inferenceEntry, inferenceQrt);
|
|
1918
|
+
if (inferenceAction === "in-flight") {
|
|
1919
|
+
runtime._inferenceEntry = inferenceEntry;
|
|
1920
|
+
if (runtimeDirty) writeRuntimeState(boardDir, cardId, runtime);
|
|
1921
|
+
return "task-initiated";
|
|
1922
|
+
}
|
|
1923
|
+
if (inferenceAction === "idle") {
|
|
1924
|
+
return "task-initiated";
|
|
1925
|
+
}
|
|
1926
|
+
const inferenceInFile = path.join(os.tmpdir(), `card-inference-${cardId}-${Date.now()}.json`);
|
|
1927
|
+
fs.writeFileSync(inferenceInFile, JSON.stringify(inferencePayload, null, 2), "utf-8");
|
|
1928
|
+
appendInferenceAdapterLog(boardDir, cardId, inferencePayload);
|
|
1929
|
+
markRequested(inferenceEntry, now2);
|
|
1930
|
+
runtime._inferenceEntry = inferenceEntry;
|
|
1931
|
+
runtimeDirty = true;
|
|
1932
|
+
invokeRunInference(boardDir, cardId, inferenceInFile, input.callbackToken, void 0, (err) => {
|
|
1933
|
+
if (err) {
|
|
1934
|
+
console.error(`[card-handler] ${input.nodeId}:`, err.message);
|
|
1935
|
+
const failedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1936
|
+
appendEventToJournal(boardDir, {
|
|
1937
|
+
type: "task-failed",
|
|
1938
|
+
taskName: input.nodeId,
|
|
1939
|
+
error: err.message,
|
|
1940
|
+
timestamp: failedAt
|
|
1941
|
+
});
|
|
1942
|
+
}
|
|
1943
|
+
});
|
|
1944
|
+
return "task-initiated";
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1748
1947
|
writeRuntimeDataObjects(boardDir, data);
|
|
1749
1948
|
const undeliveredOptional = allSources.filter((s) => {
|
|
1750
|
-
if (s.optionalForCompletionGating !== true
|
|
1751
|
-
const entry = runtime._sources[s.
|
|
1949
|
+
if (s.optionalForCompletionGating !== true) return false;
|
|
1950
|
+
const entry = runtime._sources[s.outputFile];
|
|
1752
1951
|
if (!entry?.lastRequestedAt) return true;
|
|
1753
1952
|
if (!entry.lastFetchedAt) return true;
|
|
1754
1953
|
return entry.lastFetchedAt <= entry.lastRequestedAt;
|
|
@@ -1842,16 +2041,18 @@ function cmdAddCards(args) {
|
|
|
1842
2041
|
function cmdInit(args) {
|
|
1843
2042
|
const dir = args[0];
|
|
1844
2043
|
if (!dir) {
|
|
1845
|
-
throw new Error("Usage: board-live-cards init <dir> [--task-executor <script>] [--chat-handler <script>] [--runtime-out <dir>]");
|
|
2044
|
+
throw new Error("Usage: board-live-cards init <dir> [--task-executor <script>] [--chat-handler <script>] [--inference-adapter <script>] [--runtime-out <dir>]");
|
|
1846
2045
|
}
|
|
1847
2046
|
const teIdx = args.indexOf("--task-executor");
|
|
1848
2047
|
const taskExecutor = teIdx !== -1 ? args[teIdx + 1] : void 0;
|
|
1849
2048
|
const chIdx = args.indexOf("--chat-handler");
|
|
1850
2049
|
const chatHandler = chIdx !== -1 ? args[chIdx + 1] : void 0;
|
|
2050
|
+
const iaIdx = args.indexOf("--inference-adapter");
|
|
2051
|
+
const inferenceAdapter = iaIdx !== -1 ? args[iaIdx + 1] : void 0;
|
|
1851
2052
|
const roIdx = args.indexOf("--runtime-out");
|
|
1852
2053
|
const runtimeOut = roIdx !== -1 ? args[roIdx + 1] : void 0;
|
|
1853
2054
|
if (roIdx !== -1 && !runtimeOut) {
|
|
1854
|
-
throw new Error("Usage: board-live-cards init <dir> [--task-executor <script>] [--chat-handler <script>] [--runtime-out <dir>]");
|
|
2055
|
+
throw new Error("Usage: board-live-cards init <dir> [--task-executor <script>] [--chat-handler <script>] [--inference-adapter <script>] [--runtime-out <dir>]");
|
|
1855
2056
|
}
|
|
1856
2057
|
const result = initBoard(dir);
|
|
1857
2058
|
if (taskExecutor) {
|
|
@@ -1860,6 +2061,9 @@ function cmdInit(args) {
|
|
|
1860
2061
|
if (chatHandler) {
|
|
1861
2062
|
fs.writeFileSync(path.join(dir, ".chat-handler"), chatHandler, "utf-8");
|
|
1862
2063
|
}
|
|
2064
|
+
if (inferenceAdapter) {
|
|
2065
|
+
fs.writeFileSync(path.join(dir, INFERENCE_ADAPTER_FILE), inferenceAdapter, "utf-8");
|
|
2066
|
+
}
|
|
1863
2067
|
const runtimeOutDir = configureRuntimeOutDir(dir, runtimeOut);
|
|
1864
2068
|
const live = loadBoard(dir);
|
|
1865
2069
|
writeJsonAtomic(resolveStatusSnapshotPath(dir), buildBoardStatusObject(dir, live));
|
|
@@ -2095,7 +2299,7 @@ function cmdSourceDataFetched(args) {
|
|
|
2095
2299
|
console.error("Invalid source token");
|
|
2096
2300
|
process.exit(1);
|
|
2097
2301
|
}
|
|
2098
|
-
const { cbk, rg, cid, b, d } = payload;
|
|
2302
|
+
const { cbk, rg, cid, b, d, cs } = payload;
|
|
2099
2303
|
const destPath = path.join(rg, d);
|
|
2100
2304
|
fs.mkdirSync(path.dirname(destPath), { recursive: true });
|
|
2101
2305
|
fs.renameSync(tmpFile, destPath);
|
|
@@ -2109,7 +2313,7 @@ function cmdSourceDataFetched(args) {
|
|
|
2109
2313
|
appendEventToJournal(rg, {
|
|
2110
2314
|
type: "task-progress",
|
|
2111
2315
|
taskName: cbkDecoded.taskName,
|
|
2112
|
-
update: { bindTo: b, fetchedAt,
|
|
2316
|
+
update: { bindTo: b, outputFile: d, fetchedAt, sourceChecksum: cs },
|
|
2113
2317
|
timestamp: fetchedAt
|
|
2114
2318
|
});
|
|
2115
2319
|
void processAccumulatedEventsInfinitePass(rg);
|
|
@@ -2128,7 +2332,7 @@ function cmdSourceDataFetchFailure(args) {
|
|
|
2128
2332
|
console.error("Invalid source token");
|
|
2129
2333
|
process.exit(1);
|
|
2130
2334
|
}
|
|
2131
|
-
const { cbk, rg, cid, b } = payload;
|
|
2335
|
+
const { cbk, rg, cid, b, d, cs } = payload;
|
|
2132
2336
|
console.log(`[source-data-fetch-failure] ${cid}.${b}: ${reason}`);
|
|
2133
2337
|
const cbkDecoded = decodeCallbackToken2(cbk);
|
|
2134
2338
|
if (!cbkDecoded) {
|
|
@@ -2139,7 +2343,7 @@ function cmdSourceDataFetchFailure(args) {
|
|
|
2139
2343
|
appendEventToJournal(rg, {
|
|
2140
2344
|
type: "task-progress",
|
|
2141
2345
|
taskName: cbkDecoded.taskName,
|
|
2142
|
-
update: { bindTo: b, failure: true, reason },
|
|
2346
|
+
update: { bindTo: b, outputFile: d, failure: true, reason, sourceChecksum: cs },
|
|
2143
2347
|
timestamp
|
|
2144
2348
|
});
|
|
2145
2349
|
void processAccumulatedEventsInfinitePass(rg);
|
|
@@ -2148,11 +2352,14 @@ function cmdRunSources(args) {
|
|
|
2148
2352
|
const cardIdx = args.indexOf("--card");
|
|
2149
2353
|
const tokenIdx = args.indexOf("--token");
|
|
2150
2354
|
const rgIdx = args.indexOf("--rg");
|
|
2355
|
+
const sourceChecksumsIdx = args.indexOf("--source-checksums");
|
|
2151
2356
|
const cardFilePath = cardIdx !== -1 ? args[cardIdx + 1] : void 0;
|
|
2152
2357
|
const callbackToken = tokenIdx !== -1 ? args[tokenIdx + 1] : void 0;
|
|
2153
2358
|
const boardDir = rgIdx !== -1 ? args[rgIdx + 1] : void 0;
|
|
2359
|
+
const sourceChecksumsJson = sourceChecksumsIdx !== -1 ? args[sourceChecksumsIdx + 1] : void 0;
|
|
2360
|
+
const sourceChecksums = sourceChecksumsJson ? JSON.parse(sourceChecksumsJson) : void 0;
|
|
2154
2361
|
if (!cardFilePath || !callbackToken || !boardDir) {
|
|
2155
|
-
console.error("Usage: board-live-cards run-sources-internal --card <path> --token <token> --rg <dir>");
|
|
2362
|
+
console.error("Usage: board-live-cards run-sources-internal --card <path> --token <token> --rg <dir> [--source-checksums <json>]");
|
|
2156
2363
|
process.exit(1);
|
|
2157
2364
|
}
|
|
2158
2365
|
const card = JSON.parse(fs.readFileSync(cardFilePath, "utf-8"));
|
|
@@ -2166,12 +2373,14 @@ function cmdRunSources(args) {
|
|
|
2166
2373
|
const executorFile = path.join(boardDir, ".task-executor");
|
|
2167
2374
|
const taskExecutor = fs.existsSync(executorFile) ? fs.readFileSync(executorFile, "utf-8").trim() : void 0;
|
|
2168
2375
|
function runSource(src) {
|
|
2376
|
+
const sourceChecksumForInvoke = src.outputFile ? sourceChecksums?.[src.outputFile] : void 0;
|
|
2169
2377
|
const sourceToken = encodeSourceToken({
|
|
2170
2378
|
cbk: callbackToken,
|
|
2171
2379
|
rg: boardDir,
|
|
2172
2380
|
cid: card.id,
|
|
2173
2381
|
b: src.bindTo,
|
|
2174
|
-
d: src.outputFile ?? ""
|
|
2382
|
+
d: src.outputFile ?? "",
|
|
2383
|
+
cs: sourceChecksumForInvoke
|
|
2175
2384
|
});
|
|
2176
2385
|
function reportFailure(reason) {
|
|
2177
2386
|
invokeSourceDataFetchFailure(sourceToken, reason, (err) => {
|
|
@@ -2195,7 +2404,7 @@ function cmdRunSources(args) {
|
|
|
2195
2404
|
cwd: typeof src.cwd === "string" && src.cwd ? src.cwd : path.dirname(cardFilePath || ""),
|
|
2196
2405
|
boardDir: typeof src.boardDir === "string" && src.boardDir ? src.boardDir : boardDir
|
|
2197
2406
|
};
|
|
2198
|
-
appendTaskExecutorLog(boardDir, sourceForExecutor);
|
|
2407
|
+
appendTaskExecutorLog(boardDir, sourceForExecutor, "external-task-executor");
|
|
2199
2408
|
fs.writeFileSync(inFile, JSON.stringify(sourceForExecutor, null, 2), "utf-8");
|
|
2200
2409
|
console.log(`[run-sources-internal] task-executor: ${taskExecutor} run-source-fetch --in ${inFile} --out ${outFile2} --err ${errFile}`);
|
|
2201
2410
|
try {
|
|
@@ -2233,6 +2442,12 @@ function cmdRunSources(args) {
|
|
|
2233
2442
|
const timeout = src.timeout ?? 12e4;
|
|
2234
2443
|
const sourceCwd = typeof src.cwd === "string" ? src.cwd : path.dirname(cardFilePath || "");
|
|
2235
2444
|
const sourceBoardDir = typeof src.boardDir === "string" ? src.boardDir : boardDir;
|
|
2445
|
+
const sourceForBuiltInExecutor = {
|
|
2446
|
+
...src,
|
|
2447
|
+
cwd: sourceCwd,
|
|
2448
|
+
boardDir: sourceBoardDir
|
|
2449
|
+
};
|
|
2450
|
+
appendTaskExecutorLog(boardDir, sourceForBuiltInExecutor, "built-in-run-source-fetch");
|
|
2236
2451
|
const cmdParts = splitCommandLine(src.cli);
|
|
2237
2452
|
if (cmdParts.length === 0) {
|
|
2238
2453
|
const errMsg = "source.cli command is empty";
|
|
@@ -2241,8 +2456,7 @@ function cmdRunSources(args) {
|
|
|
2241
2456
|
return;
|
|
2242
2457
|
}
|
|
2243
2458
|
const rawCmd = cmdParts[0];
|
|
2244
|
-
const cmd =
|
|
2245
|
-
const cliArgs = cmdParts.slice(1);
|
|
2459
|
+
const { cmd, args: cliArgs } = resolveCommandInvocation(rawCmd, cmdParts.slice(1));
|
|
2246
2460
|
let stdout;
|
|
2247
2461
|
try {
|
|
2248
2462
|
stdout = execCommandSync(cmd, cliArgs, {
|
|
@@ -2269,6 +2483,181 @@ function cmdRunSources(args) {
|
|
|
2269
2483
|
runSource(src);
|
|
2270
2484
|
}
|
|
2271
2485
|
}
|
|
2486
|
+
function cmdTaskProgress(args) {
|
|
2487
|
+
const rgIdx = args.indexOf("--rg");
|
|
2488
|
+
const tokenIdx = args.indexOf("--token");
|
|
2489
|
+
const updateIdx = args.indexOf("--update");
|
|
2490
|
+
const dir = rgIdx !== -1 ? args[rgIdx + 1] : void 0;
|
|
2491
|
+
const token = tokenIdx !== -1 ? args[tokenIdx + 1] : void 0;
|
|
2492
|
+
const updateJson = updateIdx !== -1 ? args[updateIdx + 1] : "{}";
|
|
2493
|
+
if (!dir || !token) {
|
|
2494
|
+
console.error("Usage: board-live-cards task-progress --rg <dir> --token <token> [--update <json>]");
|
|
2495
|
+
process.exit(1);
|
|
2496
|
+
}
|
|
2497
|
+
const decoded = decodeCallbackToken2(token);
|
|
2498
|
+
if (!decoded) {
|
|
2499
|
+
console.error("Invalid callback token");
|
|
2500
|
+
process.exit(1);
|
|
2501
|
+
}
|
|
2502
|
+
const update = updateJson ? JSON.parse(updateJson) : {};
|
|
2503
|
+
appendEventToJournal(dir, {
|
|
2504
|
+
type: "task-progress",
|
|
2505
|
+
taskName: decoded.taskName,
|
|
2506
|
+
update,
|
|
2507
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2508
|
+
});
|
|
2509
|
+
void processAccumulatedEventsInfinitePass(dir);
|
|
2510
|
+
}
|
|
2511
|
+
function cmdRunInference(args) {
|
|
2512
|
+
const inIdx = args.indexOf("--in");
|
|
2513
|
+
const tokenIdx = args.indexOf("--token");
|
|
2514
|
+
const inFile = inIdx !== -1 ? args[inIdx + 1] : void 0;
|
|
2515
|
+
const inferenceToken = tokenIdx !== -1 ? args[tokenIdx + 1] : void 0;
|
|
2516
|
+
if (!inFile || !inferenceToken) {
|
|
2517
|
+
console.error("Usage: board-live-cards run-inference-internal --in <input.json> --token <inference-token>");
|
|
2518
|
+
process.exit(1);
|
|
2519
|
+
}
|
|
2520
|
+
const decodedToken = decodeSourceToken(inferenceToken);
|
|
2521
|
+
if (!decodedToken) {
|
|
2522
|
+
console.error("Invalid inference token");
|
|
2523
|
+
process.exit(1);
|
|
2524
|
+
}
|
|
2525
|
+
const callbackToken = decodedToken.cbk;
|
|
2526
|
+
const boardDir = decodedToken.rg;
|
|
2527
|
+
const cbkDecoded = decodeCallbackToken2(callbackToken);
|
|
2528
|
+
if (!cbkDecoded) {
|
|
2529
|
+
console.error("Invalid callback token embedded in inference token");
|
|
2530
|
+
process.exit(1);
|
|
2531
|
+
}
|
|
2532
|
+
function spawnInferenceDone(tmpFile) {
|
|
2533
|
+
const { cmd, args: cliArgs } = getCliInvocation("inference-done", ["--tmp", tmpFile, "--token", inferenceToken]);
|
|
2534
|
+
spawnDetachedCommand(cmd, cliArgs);
|
|
2535
|
+
}
|
|
2536
|
+
function spawnInferenceDoneError(reason) {
|
|
2537
|
+
const tmpFile = path.join(os.tmpdir(), `card-inference-err-${Date.now()}.json`);
|
|
2538
|
+
fs.writeFileSync(tmpFile, JSON.stringify({ isTaskCompleted: false, reason }), "utf-8");
|
|
2539
|
+
spawnInferenceDone(tmpFile);
|
|
2540
|
+
}
|
|
2541
|
+
if (!fs.existsSync(inFile)) {
|
|
2542
|
+
spawnInferenceDoneError(`inference input not found: ${inFile}`);
|
|
2543
|
+
return;
|
|
2544
|
+
}
|
|
2545
|
+
const adapterFile = path.join(boardDir, INFERENCE_ADAPTER_FILE);
|
|
2546
|
+
const inferenceAdapter = fs.existsSync(adapterFile) ? fs.readFileSync(adapterFile, "utf-8").trim() : void 0;
|
|
2547
|
+
if (!inferenceAdapter) {
|
|
2548
|
+
spawnInferenceDoneError(`inference adapter is not configured (${INFERENCE_ADAPTER_FILE})`);
|
|
2549
|
+
return;
|
|
2550
|
+
}
|
|
2551
|
+
const outFile = path.join(os.tmpdir(), `card-inference-out-${Date.now()}.json`);
|
|
2552
|
+
const errFile = path.join(os.tmpdir(), `card-inference-err-${Date.now()}.txt`);
|
|
2553
|
+
const adapterParts = splitCommandLine(inferenceAdapter);
|
|
2554
|
+
if (adapterParts.length === 0) {
|
|
2555
|
+
spawnInferenceDoneError("inference adapter command is empty");
|
|
2556
|
+
return;
|
|
2557
|
+
}
|
|
2558
|
+
const adapterRawCmd = adapterParts[0];
|
|
2559
|
+
const adapterRawArgs = adapterParts.slice(1);
|
|
2560
|
+
const { cmd: adapterCmd, args: adapterArgsPrefix } = resolveCommandInvocation(adapterRawCmd, adapterRawArgs);
|
|
2561
|
+
const adapterArgs = [...adapterArgsPrefix, "run-inference", "--in", inFile, "--out", outFile, "--err", errFile];
|
|
2562
|
+
try {
|
|
2563
|
+
execCommandSync(adapterCmd, adapterArgs, {
|
|
2564
|
+
shell: false,
|
|
2565
|
+
timeout: 12e4,
|
|
2566
|
+
cwd: boardDir,
|
|
2567
|
+
env: {
|
|
2568
|
+
...process.env,
|
|
2569
|
+
BOARD_DIR: boardDir
|
|
2570
|
+
}
|
|
2571
|
+
});
|
|
2572
|
+
} catch (err) {
|
|
2573
|
+
const reason = err.message ?? String(err);
|
|
2574
|
+
spawnInferenceDoneError(reason);
|
|
2575
|
+
return;
|
|
2576
|
+
}
|
|
2577
|
+
if (!fs.existsSync(outFile)) {
|
|
2578
|
+
const errMsg = fs.existsSync(errFile) ? fs.readFileSync(errFile, "utf-8").trim() : "inference adapter produced no output file";
|
|
2579
|
+
spawnInferenceDoneError(errMsg);
|
|
2580
|
+
return;
|
|
2581
|
+
}
|
|
2582
|
+
spawnInferenceDone(outFile);
|
|
2583
|
+
}
|
|
2584
|
+
function cmdInferenceDone(args) {
|
|
2585
|
+
const tmpIdx = args.indexOf("--tmp");
|
|
2586
|
+
const tokenIdx = args.indexOf("--token");
|
|
2587
|
+
const tmpFile = tmpIdx !== -1 ? args[tmpIdx + 1] : void 0;
|
|
2588
|
+
const inferenceToken = tokenIdx !== -1 ? args[tokenIdx + 1] : void 0;
|
|
2589
|
+
if (!tmpFile || !inferenceToken) {
|
|
2590
|
+
console.error("Usage: board-live-cards inference-done --tmp <result.json> --token <inference-token>");
|
|
2591
|
+
process.exit(1);
|
|
2592
|
+
}
|
|
2593
|
+
const decodedToken = decodeSourceToken(inferenceToken);
|
|
2594
|
+
if (!decodedToken) {
|
|
2595
|
+
console.error("Invalid inference token");
|
|
2596
|
+
process.exit(1);
|
|
2597
|
+
}
|
|
2598
|
+
const { cbk: callbackToken, rg: dir, cs: inputChecksum } = decodedToken;
|
|
2599
|
+
const decoded = decodeCallbackToken2(callbackToken);
|
|
2600
|
+
if (!decoded) {
|
|
2601
|
+
console.error("Invalid callback token embedded in inference token");
|
|
2602
|
+
process.exit(1);
|
|
2603
|
+
}
|
|
2604
|
+
const taskName = decoded.taskName;
|
|
2605
|
+
const cardPath = lookupCardPath(dir, taskName);
|
|
2606
|
+
if (!cardPath) {
|
|
2607
|
+
console.error(`Card file for task "${taskName}" not found in inventory`);
|
|
2608
|
+
process.exit(1);
|
|
2609
|
+
}
|
|
2610
|
+
let result = {};
|
|
2611
|
+
if (fs.existsSync(tmpFile)) {
|
|
2612
|
+
try {
|
|
2613
|
+
result = JSON.parse(fs.readFileSync(tmpFile, "utf-8").trim());
|
|
2614
|
+
} catch (err) {
|
|
2615
|
+
result = { isTaskCompleted: false, reason: `failed to parse inference result: ${err instanceof Error ? err.message : String(err)}` };
|
|
2616
|
+
}
|
|
2617
|
+
try {
|
|
2618
|
+
fs.unlinkSync(tmpFile);
|
|
2619
|
+
} catch {
|
|
2620
|
+
}
|
|
2621
|
+
} else {
|
|
2622
|
+
result = { isTaskCompleted: false, reason: `inference result file not found: ${tmpFile}` };
|
|
2623
|
+
}
|
|
2624
|
+
const isTaskCompletedFlag = result.isTaskCompleted === true;
|
|
2625
|
+
const inferenceCompletedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2626
|
+
const card = JSON.parse(fs.readFileSync(cardPath, "utf-8"));
|
|
2627
|
+
if (!card.card_data) card.card_data = {};
|
|
2628
|
+
const cardData = card.card_data;
|
|
2629
|
+
const existingInference = cardData.llm_task_completion_inference && typeof cardData.llm_task_completion_inference === "object" ? cardData.llm_task_completion_inference : {};
|
|
2630
|
+
cardData.llm_task_completion_inference = {
|
|
2631
|
+
...existingInference,
|
|
2632
|
+
isTaskCompleted: isTaskCompletedFlag,
|
|
2633
|
+
reason: typeof result.reason === "string" ? result.reason : "",
|
|
2634
|
+
evidence: typeof result.evidence === "string" ? result.evidence : "",
|
|
2635
|
+
inferenceCompletedAt
|
|
2636
|
+
};
|
|
2637
|
+
fs.writeFileSync(cardPath, JSON.stringify(card, null, 2), "utf-8");
|
|
2638
|
+
const runtimePath2 = path.join(dir, `${taskName}.runtime.json`);
|
|
2639
|
+
let runtime = { _sources: {} };
|
|
2640
|
+
if (fs.existsSync(runtimePath2)) {
|
|
2641
|
+
try {
|
|
2642
|
+
runtime = JSON.parse(fs.readFileSync(runtimePath2, "utf-8"));
|
|
2643
|
+
} catch {
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2646
|
+
const inferenceEntry = runtime._inferenceEntry ?? {};
|
|
2647
|
+
runtime._inferenceEntry = nextEntryAfterFetchDelivery(inferenceEntry, inferenceCompletedAt);
|
|
2648
|
+
fs.writeFileSync(runtimePath2, JSON.stringify(runtime, null, 2), "utf-8");
|
|
2649
|
+
appendEventToJournal(dir, {
|
|
2650
|
+
type: "task-progress",
|
|
2651
|
+
taskName,
|
|
2652
|
+
update: {
|
|
2653
|
+
kind: "inference-done",
|
|
2654
|
+
isTaskCompleted: isTaskCompletedFlag,
|
|
2655
|
+
inputChecksum
|
|
2656
|
+
},
|
|
2657
|
+
timestamp: inferenceCompletedAt
|
|
2658
|
+
});
|
|
2659
|
+
void processAccumulatedEventsInfinitePass(dir);
|
|
2660
|
+
}
|
|
2272
2661
|
function cmdRunSourceFetch(args) {
|
|
2273
2662
|
const inIdx = args.indexOf("--in");
|
|
2274
2663
|
const outIdx = args.indexOf("--out");
|
|
@@ -2314,8 +2703,7 @@ function cmdRunSourceFetch(args) {
|
|
|
2314
2703
|
process.exit(1);
|
|
2315
2704
|
}
|
|
2316
2705
|
const rawCmd = cmdParts[0];
|
|
2317
|
-
const cmd =
|
|
2318
|
-
const cliArgs = cmdParts.slice(1);
|
|
2706
|
+
const { cmd, args: cliArgs } = resolveCommandInvocation(rawCmd, cmdParts.slice(1));
|
|
2319
2707
|
let stdout;
|
|
2320
2708
|
try {
|
|
2321
2709
|
stdout = execCommandSync(cmd, cliArgs, {
|
|
@@ -2547,20 +2935,183 @@ async function cli(argv) {
|
|
|
2547
2935
|
return cmdTaskCompleted(rest);
|
|
2548
2936
|
case "task-failed":
|
|
2549
2937
|
return cmdTaskFailed(rest);
|
|
2938
|
+
case "task-progress":
|
|
2939
|
+
return cmdTaskProgress(rest);
|
|
2550
2940
|
case "source-data-fetched":
|
|
2551
2941
|
return cmdSourceDataFetched(rest);
|
|
2552
2942
|
case "source-data-fetch-failure":
|
|
2553
2943
|
return cmdSourceDataFetchFailure(rest);
|
|
2554
2944
|
case "run-sources-internal":
|
|
2555
2945
|
return cmdRunSources(rest);
|
|
2946
|
+
case "run-inference-internal":
|
|
2947
|
+
return cmdRunInference(rest);
|
|
2948
|
+
case "inference-done":
|
|
2949
|
+
return cmdInferenceDone(rest);
|
|
2556
2950
|
case "run-source-fetch":
|
|
2557
2951
|
return cmdRunSourceFetch(rest);
|
|
2952
|
+
case "probe-source":
|
|
2953
|
+
return await cmdProbeSource(rest);
|
|
2558
2954
|
case "process-accumulated-events":
|
|
2559
2955
|
return await cmdTryDrain(rest);
|
|
2560
2956
|
default:
|
|
2561
2957
|
throw new Error(`Unknown command: ${cmd ?? "(none)"}`);
|
|
2562
2958
|
}
|
|
2563
2959
|
}
|
|
2960
|
+
async function cmdProbeSource(args) {
|
|
2961
|
+
const cardIdx = args.indexOf("--card");
|
|
2962
|
+
const sourceIdxArg = args.indexOf("--source-idx");
|
|
2963
|
+
const sourceBindArg = args.indexOf("--source-bind");
|
|
2964
|
+
const mockReqIdx = args.indexOf("--mock-requires");
|
|
2965
|
+
const rgIdx = args.indexOf("--rg");
|
|
2966
|
+
const outIdx = args.indexOf("--out");
|
|
2967
|
+
const cardFilePath = cardIdx !== -1 ? args[cardIdx + 1] : void 0;
|
|
2968
|
+
const sourceIdxVal = sourceIdxArg !== -1 ? parseInt(args[sourceIdxArg + 1], 10) : 0;
|
|
2969
|
+
const sourceBindVal = sourceBindArg !== -1 ? args[sourceBindArg + 1] : void 0;
|
|
2970
|
+
const mockReqRaw = mockReqIdx !== -1 ? args[mockReqIdx + 1] : void 0;
|
|
2971
|
+
const boardDirArg = rgIdx !== -1 ? args[rgIdx + 1] : void 0;
|
|
2972
|
+
const outFile = outIdx !== -1 ? args[outIdx + 1] : void 0;
|
|
2973
|
+
if (!cardFilePath) {
|
|
2974
|
+
console.error("Usage: board-live-cards probe-source --card <card.json> [--source-idx <n>] [--source-bind <name>] [--mock-requires <json>] [--rg <boardDir>] [--out <result.json>]");
|
|
2975
|
+
process.exit(1);
|
|
2976
|
+
}
|
|
2977
|
+
let card;
|
|
2978
|
+
try {
|
|
2979
|
+
card = JSON.parse(fs.readFileSync(path.resolve(cardFilePath), "utf-8"));
|
|
2980
|
+
} catch (e) {
|
|
2981
|
+
console.error(`[probe-source] Cannot read card: ${e.message}`);
|
|
2982
|
+
process.exit(1);
|
|
2983
|
+
}
|
|
2984
|
+
const sources = card.sources ?? [];
|
|
2985
|
+
if (sources.length === 0) {
|
|
2986
|
+
console.error(`[probe-source] Card "${card.id}" has no sources`);
|
|
2987
|
+
process.exit(1);
|
|
2988
|
+
}
|
|
2989
|
+
let sourceIdx;
|
|
2990
|
+
if (sourceBindVal) {
|
|
2991
|
+
sourceIdx = sources.findIndex((s) => s.bindTo === sourceBindVal);
|
|
2992
|
+
if (sourceIdx === -1) {
|
|
2993
|
+
console.error(`[probe-source] No source with bindTo="${sourceBindVal}" in card "${card.id}"`);
|
|
2994
|
+
process.exit(1);
|
|
2995
|
+
}
|
|
2996
|
+
} else {
|
|
2997
|
+
sourceIdx = sourceIdxVal;
|
|
2998
|
+
if (isNaN(sourceIdx) || sourceIdx < 0 || sourceIdx >= sources.length) {
|
|
2999
|
+
console.error(`[probe-source] --source-idx ${sourceIdxVal} out of range (card has ${sources.length} source(s))`);
|
|
3000
|
+
process.exit(1);
|
|
3001
|
+
}
|
|
3002
|
+
}
|
|
3003
|
+
const sourceDef = sources[sourceIdx];
|
|
3004
|
+
const cardDir = path.resolve(path.dirname(cardFilePath));
|
|
3005
|
+
const boardDir = boardDirArg ? path.resolve(boardDirArg) : cardDir;
|
|
3006
|
+
let mockRequires = {};
|
|
3007
|
+
if (mockReqRaw) {
|
|
3008
|
+
const raw = mockReqRaw.startsWith("@") ? fs.readFileSync(path.resolve(mockReqRaw.slice(1)), "utf-8") : mockReqRaw;
|
|
3009
|
+
try {
|
|
3010
|
+
mockRequires = JSON.parse(raw);
|
|
3011
|
+
} catch (e) {
|
|
3012
|
+
console.error(`[probe-source] --mock-requires is not valid JSON: ${e.message}`);
|
|
3013
|
+
process.exit(1);
|
|
3014
|
+
}
|
|
3015
|
+
}
|
|
3016
|
+
const executorFile = path.join(boardDir, ".task-executor");
|
|
3017
|
+
const taskExecutor = fs.existsSync(executorFile) ? fs.readFileSync(executorFile, "utf-8").trim() : void 0;
|
|
3018
|
+
const inPayload = {
|
|
3019
|
+
...sourceDef,
|
|
3020
|
+
cwd: typeof sourceDef.cwd === "string" && sourceDef.cwd ? sourceDef.cwd : cardDir,
|
|
3021
|
+
boardDir: typeof sourceDef.boardDir === "string" && sourceDef.boardDir ? sourceDef.boardDir : boardDir,
|
|
3022
|
+
_requires: mockRequires,
|
|
3023
|
+
_sourcesData: {},
|
|
3024
|
+
_computed_values: {}
|
|
3025
|
+
};
|
|
3026
|
+
const sourceKind = sourceDef.chartApi ? "chartApi" : sourceDef.http ? "http" : sourceDef.copilot || sourceDef.prompt_template ? "copilot" : sourceDef.cli ? "cli" : "mock";
|
|
3027
|
+
console.log(`[probe-source] card: ${card.id}`);
|
|
3028
|
+
console.log(`[probe-source] source[${sourceIdx}]: bindTo="${sourceDef.bindTo}" kind=${sourceKind}`);
|
|
3029
|
+
console.log(`[probe-source] _requires: ${JSON.stringify(mockRequires)}`);
|
|
3030
|
+
console.log(`[probe-source] executor: ${taskExecutor ?? "built-in (source.cli only)"}`);
|
|
3031
|
+
console.log(`[probe-source] running fetch...`);
|
|
3032
|
+
const ts = Date.now();
|
|
3033
|
+
const inFile = path.join(os.tmpdir(), `probe-in-${sourceDef.bindTo}-${ts}.json`);
|
|
3034
|
+
const tmpOut = path.join(os.tmpdir(), `probe-out-${sourceDef.bindTo}-${ts}.json`);
|
|
3035
|
+
const errFile = path.join(os.tmpdir(), `probe-err-${sourceDef.bindTo}-${ts}.txt`);
|
|
3036
|
+
fs.writeFileSync(inFile, JSON.stringify(inPayload, null, 2), "utf-8");
|
|
3037
|
+
let passed = false;
|
|
3038
|
+
let errorMsg;
|
|
3039
|
+
let resultRaw;
|
|
3040
|
+
try {
|
|
3041
|
+
if (taskExecutor) {
|
|
3042
|
+
execCommandSync(taskExecutor, ["run-source-fetch", "--in", inFile, "--out", tmpOut, "--err", errFile], {
|
|
3043
|
+
shell: true,
|
|
3044
|
+
timeout: sourceDef.timeout ?? 3e4
|
|
3045
|
+
});
|
|
3046
|
+
} else {
|
|
3047
|
+
if (!inPayload.cli) {
|
|
3048
|
+
throw new Error("No task-executor registered and source has no cli field \u2014 cannot probe with built-in executor");
|
|
3049
|
+
}
|
|
3050
|
+
const cmdParts = splitCommandLine(inPayload.cli);
|
|
3051
|
+
const rawCmd = cmdParts[0];
|
|
3052
|
+
const { cmd, args: cliArgs } = resolveCommandInvocation(rawCmd, cmdParts.slice(1));
|
|
3053
|
+
const stdout = execCommandSync(cmd, cliArgs, {
|
|
3054
|
+
shell: false,
|
|
3055
|
+
encoding: "utf-8",
|
|
3056
|
+
timeout: sourceDef.timeout ?? 3e4,
|
|
3057
|
+
cwd: inPayload.cwd
|
|
3058
|
+
});
|
|
3059
|
+
fs.writeFileSync(tmpOut, stdout.trim(), "utf-8");
|
|
3060
|
+
}
|
|
3061
|
+
passed = fs.existsSync(tmpOut);
|
|
3062
|
+
if (passed) {
|
|
3063
|
+
resultRaw = fs.readFileSync(tmpOut, "utf-8");
|
|
3064
|
+
} else {
|
|
3065
|
+
errorMsg = fs.existsSync(errFile) ? fs.readFileSync(errFile, "utf-8").trim() : "executor produced no output file";
|
|
3066
|
+
}
|
|
3067
|
+
} catch (e) {
|
|
3068
|
+
errorMsg = e.message ?? String(e);
|
|
3069
|
+
if (!errorMsg && fs.existsSync(errFile)) {
|
|
3070
|
+
errorMsg = fs.readFileSync(errFile, "utf-8").trim();
|
|
3071
|
+
}
|
|
3072
|
+
}
|
|
3073
|
+
for (const f of [inFile, errFile]) {
|
|
3074
|
+
try {
|
|
3075
|
+
fs.unlinkSync(f);
|
|
3076
|
+
} catch {
|
|
3077
|
+
}
|
|
3078
|
+
}
|
|
3079
|
+
if (passed && resultRaw !== void 0) {
|
|
3080
|
+
const resultSize = resultRaw.length;
|
|
3081
|
+
const sample = resultRaw.slice(0, 300);
|
|
3082
|
+
console.log(`[probe-source] STATUS: PROBE_PASS`);
|
|
3083
|
+
console.log(`[probe-source] result size: ${resultSize} bytes`);
|
|
3084
|
+
console.log(`[probe-source] sample: ${sample}${resultSize > 300 ? "..." : ""}`);
|
|
3085
|
+
if (outFile) {
|
|
3086
|
+
fs.writeFileSync(path.resolve(outFile), resultRaw);
|
|
3087
|
+
console.log(`[probe-source] result written to: ${outFile}`);
|
|
3088
|
+
} else {
|
|
3089
|
+
try {
|
|
3090
|
+
fs.unlinkSync(tmpOut);
|
|
3091
|
+
} catch {
|
|
3092
|
+
}
|
|
3093
|
+
}
|
|
3094
|
+
} else {
|
|
3095
|
+
console.log(`[probe-source] STATUS: PROBE_FAIL`);
|
|
3096
|
+
if (errorMsg) console.log(`[probe-source] error: ${errorMsg}`);
|
|
3097
|
+
try {
|
|
3098
|
+
if (fs.existsSync(tmpOut)) fs.unlinkSync(tmpOut);
|
|
3099
|
+
} catch {
|
|
3100
|
+
}
|
|
3101
|
+
}
|
|
3102
|
+
const summary = {
|
|
3103
|
+
status: passed ? "PROBE_PASS" : "PROBE_FAIL",
|
|
3104
|
+
cardId: card.id,
|
|
3105
|
+
sourceIdx,
|
|
3106
|
+
bindTo: sourceDef.bindTo,
|
|
3107
|
+
sourceKind,
|
|
3108
|
+
mockRequiresKeys: Object.keys(mockRequires),
|
|
3109
|
+
resultSizeBytes: resultRaw !== void 0 ? resultRaw.length : 0,
|
|
3110
|
+
error: errorMsg ?? void 0
|
|
3111
|
+
};
|
|
3112
|
+
console.log(`[probe-source:result] ${JSON.stringify(summary)}`);
|
|
3113
|
+
process.exit(passed ? 0 : 1);
|
|
3114
|
+
}
|
|
2564
3115
|
function cmdHelp() {
|
|
2565
3116
|
console.log(`
|
|
2566
3117
|
board-live-cards-cli \u2014 LiveCards board CLI
|
|
@@ -2569,14 +3120,16 @@ USAGE
|
|
|
2569
3120
|
board-live-cards-cli <command> [options]
|
|
2570
3121
|
|
|
2571
3122
|
BOARD MANAGEMENT
|
|
2572
|
-
init <dir> [--task-executor <script>] [--runtime-out <dir>]
|
|
3123
|
+
init <dir> [--task-executor <script>] [--chat-handler <script>] [--inference-adapter <script>] [--runtime-out <dir>]
|
|
2573
3124
|
Create a new board in <dir>.
|
|
2574
3125
|
If --task-executor is given, writes <dir>/.task-executor with the script path.
|
|
3126
|
+
If --chat-handler is given, writes <dir>/.chat-handler with the script path.
|
|
3127
|
+
If --inference-adapter is given, writes <dir>/.inference-adapter with the script path.
|
|
2575
3128
|
Writes <dir>/.runtime-out (default: <dir>/runtime-out).
|
|
2576
3129
|
Published runtime files:
|
|
2577
3130
|
<runtime-out>/board-livegraph-status.json
|
|
2578
3131
|
<runtime-out>/cards/<card-id>.computed.json
|
|
2579
|
-
Re-running init on an existing board is safe;
|
|
3132
|
+
Re-running init on an existing board is safe; handler registrations are updated.
|
|
2580
3133
|
|
|
2581
3134
|
status --rg <dir> [--json]
|
|
2582
3135
|
Read and print the published status snapshot from <runtime-out>/board-livegraph-status.json.
|
|
@@ -2616,13 +3169,16 @@ TASK CALLBACKS (called by task executor scripts)
|
|
|
2616
3169
|
task-failed --token <callbackToken> [--error <message>]
|
|
2617
3170
|
Signal task failure with an optional error message.
|
|
2618
3171
|
|
|
3172
|
+
task-progress --rg <dir> --token <callbackToken> [--update <json>]
|
|
3173
|
+
Signal task progress with optional update payload (for waiting on more evidence, etc.).
|
|
3174
|
+
|
|
2619
3175
|
SOURCE CALLBACKS (called internally by run-sources-internal)
|
|
2620
3176
|
source-data-fetched --tmp <file> --token <sourceToken>
|
|
2621
3177
|
Atomically rename <file> into the outputFile destination and record delivery
|
|
2622
|
-
|
|
3178
|
+
via journal events. Appends a task-progress event to re-invoke the card handler.
|
|
2623
3179
|
|
|
2624
3180
|
source-data-fetch-failure --token <sourceToken> [--reason <message>]
|
|
2625
|
-
Record a source fetch failure
|
|
3181
|
+
Record a source fetch failure via journal events and append a task-progress event.
|
|
2626
3182
|
|
|
2627
3183
|
INTERNAL COMMANDS
|
|
2628
3184
|
process-accumulated-events --rg <dir>
|
|
@@ -2637,7 +3193,7 @@ INTERNAL COMMANDS
|
|
|
2637
3193
|
3) lock stays healthy,
|
|
2638
3194
|
4) event production eventually quiesces.
|
|
2639
3195
|
|
|
2640
|
-
run-sources-internal
|
|
3196
|
+
run-sources-internal --card <card.json> --token <callbackToken> --rg <dir>
|
|
2641
3197
|
Execute all source[] entries for a card, then report delivery or failure.
|
|
2642
3198
|
(Internal command \u2014 invoked by the card-handler. Not intended for direct use.)
|
|
2643
3199
|
|
|
@@ -2650,6 +3206,34 @@ INTERNAL COMMANDS
|
|
|
2650
3206
|
Execute a source definition. Board-live-cards reads source.cli and executes it.
|
|
2651
3207
|
Writes result to --out. Presence of --out after exit indicates success.
|
|
2652
3208
|
|
|
3209
|
+
probe-source --card <card.json> [--source-idx <n>] [--source-bind <name>]
|
|
3210
|
+
[--mock-requires <json>] [--rg <boardDir>] [--out <result.json>]
|
|
3211
|
+
Validate that a card source can be fetched successfully.
|
|
3212
|
+
Reads the card file, extracts the chosen source (default: index 0), builds the
|
|
3213
|
+
run-source-fetch --in payload with the supplied _requires data, invokes the
|
|
3214
|
+
registered task-executor (or built-in executor for source.cli), and reports pass/fail.
|
|
3215
|
+
--mock-requires: JSON string (or @file.json) providing the _requires token values
|
|
3216
|
+
the source needs. Craft the minimal payload that exercises the
|
|
3217
|
+
source \u2014 e.g. '{"holdings":[{"ticker":"AAPL","quantity":10}]}'.
|
|
3218
|
+
If omitted, _requires is passed as empty ({}).
|
|
3219
|
+
--source-idx: 0-based index into card.sources[]. Default: 0.
|
|
3220
|
+
--source-bind: Select source by its bindTo name instead of index.
|
|
3221
|
+
--rg: Board directory used to find .task-executor. Defaults to the
|
|
3222
|
+
directory containing the card file.
|
|
3223
|
+
--out: Optional path to write the raw fetch result JSON.
|
|
3224
|
+
Prints a structured report ending with a [probe-source:result] JSON line.
|
|
3225
|
+
Exits 0 on PROBE_PASS, 1 on PROBE_FAIL.
|
|
3226
|
+
|
|
3227
|
+
run-inference-internal --in <input.json> --token <inferenceToken>
|
|
3228
|
+
Execute inference via registered .inference-adapter and forward result to inference-done.
|
|
3229
|
+
inferenceToken encodes boardDir (rg), cardId (cid), callbackToken (cbk), checksum (cs).
|
|
3230
|
+
(Internal command \u2014 invoked by the card-handler when custom completion rule is used.)
|
|
3231
|
+
|
|
3232
|
+
inference-done --tmp <result.json> --token <inferenceToken>
|
|
3233
|
+
Persist llm_task_completion_inference on the card and append a task-progress event.
|
|
3234
|
+
Reads boardDir/callbackToken/checksum from decoded inferenceToken; deletes --tmp file after reading.
|
|
3235
|
+
(Internal command \u2014 invoked by run-inference-internal.)
|
|
3236
|
+
|
|
2653
3237
|
RUN-SOURCE-FETCH PROTOCOL
|
|
2654
3238
|
External task-executors implement:
|
|
2655
3239
|
<executor> run-source-fetch --in <source.json> --out <result.json> [--err <error.txt>]
|
|
@@ -2686,6 +3270,7 @@ EXAMPLES
|
|
|
2686
3270
|
board-live-cards-cli add-cards --rg ./my-board --card cards/prices.json
|
|
2687
3271
|
board-live-cards-cli status --rg ./my-board
|
|
2688
3272
|
board-live-cards-cli retrigger --rg ./my-board --task price-fetch
|
|
3273
|
+
board-live-cards-cli probe-source --card cards/card-market-prices.json --source-idx 0 --rg ./my-board --mock-requires '{"holdings":[{"ticker":"AAPL","quantity":10}]}'
|
|
2689
3274
|
`.trimStart());
|
|
2690
3275
|
}
|
|
2691
3276
|
var isMain = process.argv[1] && path.resolve(process.argv[1]) === path.resolve(new URL(import.meta.url).pathname.replace(/^\/([A-Z]:)/, "$1"));
|
|
@@ -2697,6 +3282,6 @@ if (isMain) {
|
|
|
2697
3282
|
});
|
|
2698
3283
|
}
|
|
2699
3284
|
|
|
2700
|
-
export { BoardJournal, appendCardInventory, appendEventToJournal, buildCardInventoryIndex, cli, createBoardReactiveGraph, decodeSourceToken, encodeSourceToken, getUndrainedEntries, initBoard, liveCardToTaskConfig, loadBoard, loadBoardEnvelope, lookupCardPath, processAccumulatedEvents, processAccumulatedEventsForced, processAccumulatedEventsInfinitePass, readCardInventory, saveBoard, withBoardLock };
|
|
3285
|
+
export { BoardJournal, appendCardInventory, appendEventToJournal, buildCardInventoryIndex, cli, createBoardReactiveGraph, decideSourceAction, decodeSourceToken, encodeSourceToken, getUndrainedEntries, initBoard, isSourceInFlight, liveCardToTaskConfig, loadBoard, loadBoardEnvelope, lookupCardPath, nextEntryAfterFetchDelivery, nextEntryAfterFetchFailure, processAccumulatedEvents, processAccumulatedEventsForced, processAccumulatedEventsInfinitePass, readCardInventory, saveBoard, withBoardLock };
|
|
2701
3286
|
//# sourceMappingURL=board-live-cards-cli.js.map
|
|
2702
3287
|
//# sourceMappingURL=board-live-cards-cli.js.map
|