yaml-flow 5.4.2 → 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.
- package/board-live-cards-cli.js +6 -6
- package/browser/asset-integrity.json +10 -0
- package/browser/board-livecards-client.js +2 -0
- package/browser/board-livecards-client.js.map +1 -0
- package/browser/board-livecards-localstorage.js +10 -0
- package/browser/board-livecards-localstorage.js.map +1 -0
- package/browser/board-livegraph-engine.js +2 -1676
- package/browser/board-livegraph-engine.js.map +1 -1
- package/browser/card-compute.js +28 -28
- package/browser/compute-jsonata.js +5 -0
- package/browser/compute-jsonata.js.map +1 -0
- package/browser/live-cards.js +561 -129
- package/browser/live-cards.schema.json +418 -132
- package/card-store.js +37 -0
- package/dist/batch/index.cjs +1 -108
- package/dist/batch/index.cjs.map +1 -1
- package/dist/batch/index.js +1 -106
- package/dist/batch/index.js.map +1 -1
- package/dist/board-live-cards-lib-Bg6EvCo5.d.cts +136 -0
- package/dist/board-live-cards-lib-jM2uYG1v.d.ts +136 -0
- package/dist/board-live-cards-public-CW5074xr.d.cts +318 -0
- package/dist/board-live-cards-public-hnZo0mAf.d.ts +318 -0
- package/dist/board-livegraph-runtime/index.cjs +2 -1671
- package/dist/board-livegraph-runtime/index.cjs.map +1 -1
- package/dist/board-livegraph-runtime/index.d.cts +12 -11
- package/dist/board-livegraph-runtime/index.d.ts +12 -11
- package/dist/board-livegraph-runtime/index.js +2 -1662
- package/dist/board-livegraph-runtime/index.js.map +1 -1
- package/dist/board-livegraph-runtime/jsonata-sync.cjs +7623 -0
- package/dist/card-compute/index.cjs +9 -7159
- package/dist/card-compute/index.cjs.map +1 -1
- package/dist/card-compute/index.d.cts +27 -1
- package/dist/card-compute/index.d.ts +27 -1
- package/dist/card-compute/index.js +9 -7145
- package/dist/card-compute/index.js.map +1 -1
- package/dist/card-compute/jsonata-sync.cjs +7623 -0
- package/dist/cli/browser-api/board-live-cards-browser-adapter.cjs +3 -0
- package/dist/cli/browser-api/board-live-cards-browser-adapter.cjs.map +1 -0
- package/dist/cli/browser-api/board-live-cards-browser-adapter.d.cts +37 -0
- package/dist/cli/browser-api/board-live-cards-browser-adapter.d.ts +37 -0
- package/dist/cli/browser-api/board-live-cards-browser-adapter.js +3 -0
- package/dist/cli/browser-api/board-live-cards-browser-adapter.js.map +1 -0
- package/dist/cli/browser-api/card-store-browser-api.cjs +2 -0
- package/dist/cli/browser-api/card-store-browser-api.cjs.map +1 -0
- package/dist/cli/browser-api/card-store-browser-api.d.cts +26 -0
- package/dist/cli/browser-api/card-store-browser-api.d.ts +26 -0
- package/dist/cli/browser-api/card-store-browser-api.js +2 -0
- package/dist/cli/browser-api/card-store-browser-api.js.map +1 -0
- package/dist/cli/browser-api/jsonata-sync.cjs +7623 -0
- package/dist/cli/node/artifacts-store-cli.cjs +11 -0
- package/dist/cli/node/artifacts-store-cli.cjs.map +1 -0
- package/dist/cli/node/artifacts-store-cli.d.cts +8 -0
- package/dist/cli/node/artifacts-store-cli.d.ts +8 -0
- package/dist/cli/node/artifacts-store-cli.js +11 -0
- package/dist/cli/node/artifacts-store-cli.js.map +1 -0
- package/dist/cli/node/board-live-cards-cli.cjs +15 -0
- package/dist/cli/node/board-live-cards-cli.cjs.map +1 -0
- package/dist/cli/node/board-live-cards-cli.d.cts +20 -0
- package/dist/cli/node/board-live-cards-cli.d.ts +20 -0
- package/dist/cli/node/board-live-cards-cli.js +15 -0
- package/dist/cli/node/board-live-cards-cli.js.map +1 -0
- package/dist/cli/node/card-store-cli.cjs +8 -0
- package/dist/cli/node/card-store-cli.cjs.map +1 -0
- package/dist/cli/node/card-store-cli.d.cts +15 -0
- package/dist/cli/node/card-store-cli.d.ts +15 -0
- package/dist/cli/node/card-store-cli.js +8 -0
- package/dist/cli/node/card-store-cli.js.map +1 -0
- package/dist/cli/node/execution-adapter.cjs +3 -0
- package/dist/cli/node/execution-adapter.cjs.map +1 -0
- package/dist/cli/node/execution-adapter.d.cts +174 -0
- package/dist/cli/node/execution-adapter.d.ts +174 -0
- package/dist/cli/node/execution-adapter.js +3 -0
- package/dist/cli/node/execution-adapter.js.map +1 -0
- package/dist/cli/node/fs-board-adapter.cjs +14 -0
- package/dist/cli/node/fs-board-adapter.cjs.map +1 -0
- package/dist/cli/node/fs-board-adapter.d.cts +204 -0
- package/dist/cli/node/fs-board-adapter.d.ts +204 -0
- package/dist/cli/node/fs-board-adapter.js +14 -0
- package/dist/cli/node/fs-board-adapter.js.map +1 -0
- package/dist/cli/node/jsonata-sync.cjs +7623 -0
- package/dist/cli/node/source-cli-task-executor.cjs +11 -0
- package/dist/cli/node/source-cli-task-executor.cjs.map +1 -0
- package/dist/cli/node/source-cli-task-executor.d.cts +1 -0
- package/dist/cli/node/source-cli-task-executor.d.ts +1 -0
- package/dist/cli/node/source-cli-task-executor.js +11 -0
- package/dist/cli/node/source-cli-task-executor.js.map +1 -0
- package/dist/config/index.cjs +1 -79
- package/dist/config/index.cjs.map +1 -1
- package/dist/config/index.js +1 -76
- package/dist/config/index.js.map +1 -1
- package/dist/continuous-event-graph/index.cjs +2 -2129
- package/dist/continuous-event-graph/index.cjs.map +1 -1
- package/dist/continuous-event-graph/index.d.cts +81 -5
- package/dist/continuous-event-graph/index.d.ts +81 -5
- package/dist/continuous-event-graph/index.js +2 -2088
- package/dist/continuous-event-graph/index.js.map +1 -1
- package/dist/continuous-event-graph/jsonata-sync.cjs +7623 -0
- package/dist/event-graph/index.cjs +22 -8292
- package/dist/event-graph/index.cjs.map +1 -1
- package/dist/event-graph/index.js +22 -8237
- package/dist/event-graph/index.js.map +1 -1
- package/dist/execution-refs.cjs +3 -0
- package/dist/execution-refs.cjs.map +1 -0
- package/dist/execution-refs.d.cts +260 -0
- package/dist/execution-refs.d.ts +260 -0
- package/dist/execution-refs.js +3 -0
- package/dist/execution-refs.js.map +1 -0
- package/dist/index.cjs +29 -13221
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -4
- package/dist/index.d.ts +2 -4
- package/dist/index.js +29 -13112
- package/dist/index.js.map +1 -1
- package/dist/inference/index.cjs +5 -617
- package/dist/inference/index.cjs.map +1 -1
- package/dist/inference/index.js +5 -610
- package/dist/inference/index.js.map +1 -1
- package/dist/jsonata-sync.cjs +7623 -0
- package/dist/{live-cards-bridge-x5XREkXm.d.cts → live-cards-bridge-BXbVTsna.d.cts} +27 -4
- package/dist/{live-cards-bridge-EQjytzI_.d.ts → live-cards-bridge-Ds28XR15.d.ts} +27 -4
- package/dist/server-runtime/index.cjs +9 -0
- package/dist/server-runtime/index.cjs.map +1 -0
- package/dist/server-runtime/index.d.cts +31 -0
- package/dist/server-runtime/index.d.ts +31 -0
- package/dist/server-runtime/index.js +9 -0
- package/dist/server-runtime/index.js.map +1 -0
- package/dist/server-runtime/jsonata-sync.cjs +7623 -0
- package/dist/step-machine/index.cjs +11 -7129
- package/dist/step-machine/index.cjs.map +1 -1
- package/dist/step-machine/index.js +11 -7113
- package/dist/step-machine/index.js.map +1 -1
- package/dist/step-machine-public/index.cjs +2 -0
- package/dist/step-machine-public/index.cjs.map +1 -0
- package/dist/step-machine-public/index.d.cts +159 -0
- package/dist/step-machine-public/index.d.ts +159 -0
- package/dist/step-machine-public/index.js +2 -0
- package/dist/step-machine-public/index.js.map +1 -0
- package/dist/step-machine-public/jsonata-sync.cjs +7623 -0
- package/dist/storage-refs.cjs +10 -0
- package/dist/storage-refs.cjs.map +1 -0
- package/dist/storage-refs.d.cts +93 -0
- package/dist/storage-refs.d.ts +93 -0
- package/dist/storage-refs.js +10 -0
- package/dist/storage-refs.js.map +1 -0
- package/dist/stores/file.cjs +1 -114
- package/dist/stores/file.cjs.map +1 -1
- package/dist/stores/file.js +1 -112
- package/dist/stores/file.js.map +1 -1
- package/dist/stores/index.cjs +1 -231
- package/dist/stores/index.cjs.map +1 -1
- package/dist/stores/index.js +1 -227
- package/dist/stores/index.js.map +1 -1
- package/dist/stores/localStorage.cjs +1 -76
- package/dist/stores/localStorage.cjs.map +1 -1
- package/dist/stores/localStorage.js +1 -74
- package/dist/stores/localStorage.js.map +1 -1
- package/dist/stores/memory.cjs +1 -47
- package/dist/stores/memory.cjs.map +1 -1
- package/dist/stores/memory.js +1 -45
- package/dist/stores/memory.js.map +1 -1
- package/dist/types-B1ZRa4aI.d.ts +147 -0
- package/dist/types-BxEFcVK9.d.cts +147 -0
- package/examples/browser/boards/portfolio-tracker/portfolio-t4.js +291 -0
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker-fetch-prices.js +218 -0
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker-fetch-prices.py +201 -0
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker-http-test.js +357 -0
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker-inference-adapter.js +25 -16
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker-public.js +552 -0
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker-server.js +300 -0
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker-server.py +617 -0
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker-sse-worker.js +48 -0
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker.py +366 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/--base-ref/.runtime-out +1 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/--base-ref/board-graph.json +32 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/_board-cli.js +70 -3
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/add-cards-cli.js +16 -11
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/init-board-cli.js +9 -8
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/poll-status-cli.js +49 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/reset-board-dir-cli.js +2 -6
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/retrigger-cli.js +4 -8
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/status-cli.js +3 -7
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/update-holdings-cli.js +9 -8
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/wait-completed-cli.js +12 -17
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/write-prices-cli.js +2 -6
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/_board_pycli.py +107 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/add-cards.py +51 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/init-board.py +45 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/poll-status.py +71 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/reset-board-dir.py +36 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/inline-python-demo.flow.yaml +26 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/inline-python-handlers.py +39 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/portfolio-tracker-pycli.flow.yaml +80 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/portfolio-tracker.flow.yaml +36 -187
- package/examples/cli/step-machine-cli/portfolio-tracker/portfolio-tracker.input.json +40 -34
- package/examples/cli/step-machine-cli/portfolio-tracker/run-inline-python-demo-pycli.py +43 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/run-portfolio-tracker-pycli.py +77 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/run-portfolio-tracker.bat +1 -2
- package/examples/cli/step-machine-demo/jsonata-init-board-cli.js +8 -13
- package/examples/cli/step-machine-demo/jsonata-init-board.flow.yaml +33 -9
- package/examples/cli/step-machine-demo/one-step-cli-only.flow.yaml +3 -1
- package/examples/cli/step-machine-demo/step2-double-cli.js +6 -12
- package/examples/cli/step-machine-demo/two-step-math.flow.yaml +66 -4
- package/examples/cli/step-machine-demo/two-step-mixed.flow.yaml +13 -5
- package/examples/example-board/agent-instructions.md +11 -5
- package/examples/example-board/cards/_index.json +47 -0
- package/examples/example-board/cards/card-market-prices.json +33 -9
- package/examples/example-board/cards/card-my-identity.json +30 -6
- package/examples/example-board/cards/card-portfolio-action.json +24 -6
- package/examples/example-board/cards/card-portfolio-intelligence.json +97 -0
- package/examples/example-board/cards/card-portfolio-risks.json +24 -6
- package/examples/example-board/cards/card-portfolio-value.json +38 -10
- package/examples/example-board/cards/card-portfolio.json +57 -13
- package/examples/example-board/cards/card-rebalance-impact.json +22 -6
- package/examples/example-board/cards/card-rebalance-sim.json +66 -15
- package/examples/example-board/demo-chat-handler.js +14 -4
- package/examples/example-board/demo-server-config.json +1 -0
- package/examples/example-board/demo-server.js +366 -68
- package/examples/example-board/demo-shell-localstorage.html +774 -0
- package/examples/example-board/demo-shell-with-server.html +20 -37
- package/examples/example-board/demo-shell.html +5 -4
- package/examples/example-board/demo-task-executor.js +273 -275
- package/examples/index.html +0 -14
- package/examples/step-machine-cli/portfolio-tracker/handlers/_board-cli.js +0 -1
- package/examples/step-machine-cli/portfolio-tracker/run-portfolio-tracker.bat +1 -2
- package/package.json +46 -8
- package/schema/live-cards.schema.json +418 -132
- package/step-machine-cli.js +43 -310
- package/board-livecards-server-runtime.js +0 -1574
- package/browser/board-livecards-runtime-client.js +0 -263
- package/dist/cli/board-live-cards-cli.cjs +0 -10650
- package/dist/cli/board-live-cards-cli.cjs.map +0 -1
- package/dist/cli/board-live-cards-cli.d.cts +0 -179
- package/dist/cli/board-live-cards-cli.d.ts +0 -179
- package/dist/cli/board-live-cards-cli.js +0 -10598
- package/dist/cli/board-live-cards-cli.js.map +0 -1
- package/dist/journal-9HEgs7dU.d.ts +0 -28
- package/dist/journal-B-JCfQnh.d.cts +0 -28
- package/dist/schedule-Cszq9LYY.d.ts +0 -21
- package/dist/schedule-qWNL0RQh.d.cts +0 -21
- package/examples/browser/boards/portfolio-tracker/cards/holdings-table.json +0 -22
- package/examples/browser/boards/portfolio-tracker/cards/portfolio-form.json +0 -16
- package/examples/browser/boards/portfolio-tracker/cards/portfolio-risk-assessment.json +0 -28
- package/examples/browser/boards/portfolio-tracker/cards/portfolio-value.json +0 -15
- package/examples/browser/boards/portfolio-tracker/cards/price-fetch.json +0 -15
- package/examples/browser/boards/portfolio-tracker/cards/rebalancing-strategy.json +0 -28
- package/examples/browser/boards/portfolio-tracker/fetch-prices.js +0 -43
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker-task-executor.cjs +0 -96
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker.bat +0 -7
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker.js +0 -351
- package/examples/cli/step-machine-demo/two-step-math-handlers.js +0 -32
- package/examples/cli/step-machine-demo/two-step-mixed-handlers.js +0 -24
- package/examples/example-board/demo-shell-browser.html +0 -674
|
@@ -32,7 +32,10 @@
|
|
|
32
32
|
* "boardId": "<board id>", // e.g. "default"
|
|
33
33
|
* "boardRuntimeDir": "<relative>", // e.g. "runtime"
|
|
34
34
|
* "runtimeStatusDir": "<relative>", // e.g. "runtime-out"
|
|
35
|
-
* "cardsDir": "<relative>"
|
|
35
|
+
* "cardsDir": "<relative>", // e.g. "surface/tmp-cards"
|
|
36
|
+
* "serverUrl": "<base url>", // optional; e.g. "http://127.0.0.1:7799"
|
|
37
|
+
* "boardLiveCardsCliJs":"<abs path>", // optional; path to board-live-cards-cli.js
|
|
38
|
+
* "stepMachineCliPath":"<abs path>" // optional; path to step-machine-cli.js
|
|
36
39
|
* }
|
|
37
40
|
*
|
|
38
41
|
* Supported source kinds (based on custom fields in --in):
|
|
@@ -55,11 +58,15 @@
|
|
|
55
58
|
import fs from 'node:fs';
|
|
56
59
|
import path from 'node:path';
|
|
57
60
|
import os from 'node:os';
|
|
58
|
-
import crypto from 'node:crypto';
|
|
59
61
|
import { execFileSync } from 'node:child_process';
|
|
60
|
-
import { fileURLToPath } from 'node:url';
|
|
62
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
63
|
+
import { parseRef, blobStorageForRef, reportComplete, reportFailed } from 'yaml-flow/storage-refs';
|
|
64
|
+
import { loadStepFlow, createStepMachine, MemoryStore } from '../../dist/index.js';
|
|
65
|
+
import { buildStepHandlersForFlow } from '../../dist/step-machine-public/index.js';
|
|
66
|
+
import { invokeRefSync } from '../../dist/cli/node/execution-adapter.js';
|
|
61
67
|
|
|
62
68
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
69
|
+
const SOURCE_DEF_FLOWS_FILE = path.join(__dirname, 'source_def_flows.json');
|
|
63
70
|
|
|
64
71
|
// ---------------------------------------------------------------------------
|
|
65
72
|
// Mock data — used when a source has { mock: "key" }.
|
|
@@ -79,50 +86,6 @@ const MOCK_DB = {
|
|
|
79
86
|
},
|
|
80
87
|
};
|
|
81
88
|
|
|
82
|
-
// ---------------------------------------------------------------------------
|
|
83
|
-
// Simple file cache for url / url-list results.
|
|
84
|
-
// Stored in os.tmpdir()/demo-executor-cache/<hash>.json
|
|
85
|
-
// ---------------------------------------------------------------------------
|
|
86
|
-
const CACHE_DIR = path.join(os.tmpdir(), 'demo-executor-cache');
|
|
87
|
-
const CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour
|
|
88
|
-
|
|
89
|
-
function cacheKey(str) {
|
|
90
|
-
return crypto.createHash('sha1').update(str).digest('hex');
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function readCache(key, ttlMs = CACHE_TTL_MS) {
|
|
94
|
-
const file = path.join(CACHE_DIR, `${key}.json`);
|
|
95
|
-
try {
|
|
96
|
-
const stat = fs.statSync(file);
|
|
97
|
-
if (Date.now() - stat.mtimeMs < ttlMs) {
|
|
98
|
-
return JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
99
|
-
}
|
|
100
|
-
} catch {}
|
|
101
|
-
return null;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Shared single-URL fetch helper used by both url and url-list.
|
|
105
|
-
// cacheTimeoutSec: override TTL in seconds (null → use CACHE_TTL_MS default).
|
|
106
|
-
function doFetchApi(url, method, headers, cacheTimeoutSec, errFile) {
|
|
107
|
-
const ttlMs = cacheTimeoutSec != null ? cacheTimeoutSec * 1000 : CACHE_TTL_MS;
|
|
108
|
-
const k = cacheKey(`url:${method}:${url}`);
|
|
109
|
-
const cached = readCache(k, ttlMs);
|
|
110
|
-
if (cached) {
|
|
111
|
-
console.warn(`[demo-task-executor] url: cache hit for ${url}`);
|
|
112
|
-
return cached;
|
|
113
|
-
}
|
|
114
|
-
const data = curlFetchJson(url, method, headers);
|
|
115
|
-
writeCache(k, data);
|
|
116
|
-
return data;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function writeCache(key, value) {
|
|
120
|
-
try {
|
|
121
|
-
fs.mkdirSync(CACHE_DIR, { recursive: true });
|
|
122
|
-
fs.writeFileSync(path.join(CACHE_DIR, `${key}.json`), JSON.stringify(value));
|
|
123
|
-
} catch {}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
89
|
function readJson(filePath) {
|
|
127
90
|
return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
128
91
|
}
|
|
@@ -156,26 +119,6 @@ const COPILOT_PROMPT_CONTEXT = {
|
|
|
156
119
|
].join('\n'),
|
|
157
120
|
};
|
|
158
121
|
|
|
159
|
-
/**
|
|
160
|
-
* Fetch a URL using the system curl binary (synchronous, no Node event-loop handles).
|
|
161
|
-
* Throws if curl exits non-zero (e.g. HTTP 4xx/5xx with -f, or network error).
|
|
162
|
-
*/
|
|
163
|
-
function curlFetchJson(url, method, headers) {
|
|
164
|
-
const bin = process.platform === 'win32' ? 'curl.exe' : 'curl';
|
|
165
|
-
// -s : silent (no progress bar)
|
|
166
|
-
// -S : show errors despite -s
|
|
167
|
-
// -f : fail (non-zero exit) on HTTP 4xx/5xx
|
|
168
|
-
// -L : follow redirects
|
|
169
|
-
// --max-time 10 : hard timeout
|
|
170
|
-
const args = ['-s', '-S', '-f', '-L', '--max-time', '10', '-X', method];
|
|
171
|
-
for (const [k, v] of Object.entries(headers)) {
|
|
172
|
-
args.push('-H', `${k}: ${v}`);
|
|
173
|
-
}
|
|
174
|
-
args.push(url);
|
|
175
|
-
const raw = execFileSync(bin, args, { encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024 });
|
|
176
|
-
return JSON.parse(raw);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
122
|
function resolveCopilotPrompt(sourceDef) {
|
|
180
123
|
const cfg = sourceDef?.copilot && typeof sourceDef.copilot === 'object' ? sourceDef.copilot : {};
|
|
181
124
|
const template = cfg.prompt_template ?? sourceDef.prompt_template;
|
|
@@ -245,6 +188,7 @@ function runCopilotViaWrapper(prompt, sourceDef, wrapperOutFile, sessionDir, cwd
|
|
|
245
188
|
encoding: 'utf-8',
|
|
246
189
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
247
190
|
maxBuffer: 10 * 1024 * 1024,
|
|
191
|
+
windowsHide: true,
|
|
248
192
|
});
|
|
249
193
|
} finally {
|
|
250
194
|
try { fs.unlinkSync(promptFile); } catch {}
|
|
@@ -264,205 +208,260 @@ function fail(msg, errFile) {
|
|
|
264
208
|
process.exit(1);
|
|
265
209
|
}
|
|
266
210
|
|
|
267
|
-
function
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
const errFile = errIdx !== -1 ? argv[errIdx + 1] : undefined;
|
|
275
|
-
const extraB64 = extraIdx !== -1 ? argv[extraIdx + 1] : undefined;
|
|
211
|
+
function loadSourceDefFlowsConfig() {
|
|
212
|
+
try {
|
|
213
|
+
return readJson(SOURCE_DEF_FLOWS_FILE);
|
|
214
|
+
} catch (err) {
|
|
215
|
+
fail(`Cannot read source flow registry at ${SOURCE_DEF_FLOWS_FILE}: ${String(err && err.message || err)}`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
276
218
|
|
|
277
|
-
|
|
278
|
-
if (
|
|
279
|
-
|
|
280
|
-
|
|
219
|
+
function matchesDetectRule(sourceDef, detect) {
|
|
220
|
+
if (!detect || typeof detect !== 'object') return false;
|
|
221
|
+
if (typeof detect.field === 'string') {
|
|
222
|
+
return sourceDef[detect.field] !== undefined;
|
|
223
|
+
}
|
|
224
|
+
if (Array.isArray(detect.anyOfFields)) {
|
|
225
|
+
return detect.anyOfFields.some((field) => sourceDef[field] !== undefined);
|
|
281
226
|
}
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
282
229
|
|
|
283
|
-
|
|
284
|
-
|
|
230
|
+
function resolveSourceKind(sourceDef, registry) {
|
|
231
|
+
const kinds = registry?.kinds && typeof registry.kinds === 'object' ? registry.kinds : {};
|
|
232
|
+
const order = Array.isArray(registry?.resolveOrder) ? registry.resolveOrder : Object.keys(kinds);
|
|
233
|
+
const matched = [];
|
|
234
|
+
for (const kind of order) {
|
|
235
|
+
const spec = kinds[kind];
|
|
236
|
+
if (!spec) continue;
|
|
237
|
+
if (matchesDetectRule(sourceDef, spec.detect)) {
|
|
238
|
+
matched.push(kind);
|
|
239
|
+
}
|
|
285
240
|
}
|
|
286
241
|
|
|
287
|
-
if (
|
|
288
|
-
|
|
242
|
+
if (matched.length === 0) {
|
|
243
|
+
const knownKinds = Object.keys(kinds);
|
|
244
|
+
throw new Error(`No recognised source kind. Known kinds: ${knownKinds.join(', ')}`);
|
|
289
245
|
}
|
|
246
|
+
if (matched.length > 1) {
|
|
247
|
+
throw new Error(`Multiple source kinds specified: [${matched.join(', ')}]. Use exactly one.`);
|
|
248
|
+
}
|
|
249
|
+
return matched[0];
|
|
250
|
+
}
|
|
290
251
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
if (sourceDef.tickersFrom) {
|
|
313
|
-
const dotIdx = sourceDef.tickersFrom.indexOf('.');
|
|
314
|
-
if (dotIdx > 0) {
|
|
315
|
-
const refKey = sourceDef.tickersFrom.slice(0, dotIdx);
|
|
316
|
-
const fieldName = sourceDef.tickersFrom.slice(dotIdx + 1);
|
|
317
|
-
const arr = sourceDef._projections?.[refKey];
|
|
318
|
-
if (Array.isArray(arr)) {
|
|
319
|
-
fetchArgs.tickers = arr.map(h => h[fieldName]).filter(Boolean).join(',');
|
|
320
|
-
}
|
|
321
|
-
}
|
|
252
|
+
async function executeStepMachineSourceFlow(context) {
|
|
253
|
+
const { kind, registry } = context;
|
|
254
|
+
const spec = registry?.kinds?.[kind];
|
|
255
|
+
if (!spec) {
|
|
256
|
+
throw new Error(`Missing flow registration for kind: ${kind}`);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const flowRef = spec.flow;
|
|
260
|
+
if (typeof flowRef !== 'string' || flowRef.length === 0) {
|
|
261
|
+
throw new Error(`Invalid or missing flow for kind: ${kind}`);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const flowPath = path.resolve(__dirname, flowRef);
|
|
265
|
+
const flow = await loadStepFlow(flowPath);
|
|
266
|
+
|
|
267
|
+
const invokeHttpRef = async (ref, args) => {
|
|
268
|
+
let rawUrl = ref.whatToRun;
|
|
269
|
+
try {
|
|
270
|
+
rawUrl = parseRef(ref.whatToRun).value;
|
|
271
|
+
} catch {
|
|
272
|
+
// Keep raw value when whatToRun is already a URL.
|
|
322
273
|
}
|
|
323
|
-
|
|
324
|
-
|
|
274
|
+
|
|
275
|
+
const base = String(args?.extra?.serverUrl || 'http://127.0.0.1:7799').replace(/\/$/, '');
|
|
276
|
+
const resolvedUrl = /^https?:\/\//i.test(rawUrl)
|
|
277
|
+
? rawUrl
|
|
278
|
+
: `${base}${rawUrl.startsWith('/') ? '' : '/'}${rawUrl}`;
|
|
279
|
+
|
|
280
|
+
let body = args;
|
|
281
|
+
const workiqCfg = args?.sourceDef?.workiq;
|
|
282
|
+
if (workiqCfg && typeof workiqCfg === 'object' && typeof workiqCfg.query_template === 'string') {
|
|
283
|
+
const interpolationContext = {
|
|
284
|
+
...(args?.sourceDef?._projections || {}),
|
|
285
|
+
...(workiqCfg.args || {}),
|
|
286
|
+
};
|
|
287
|
+
body = {
|
|
288
|
+
query: interpolatePrompt(workiqCfg.query_template, interpolationContext),
|
|
289
|
+
};
|
|
325
290
|
}
|
|
326
|
-
|
|
327
|
-
const
|
|
291
|
+
|
|
292
|
+
const method = ref.howToRun === 'http:get' ? 'GET' : 'POST';
|
|
293
|
+
const response = await fetch(resolvedUrl, {
|
|
294
|
+
method,
|
|
295
|
+
headers: { 'Content-Type': 'application/json' },
|
|
296
|
+
...(method === 'POST' ? { body: JSON.stringify(body) } : {}),
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
const text = await response.text();
|
|
300
|
+
let parsed;
|
|
328
301
|
try {
|
|
329
|
-
|
|
330
|
-
} catch
|
|
331
|
-
|
|
302
|
+
parsed = text ? JSON.parse(text) : {};
|
|
303
|
+
} catch {
|
|
304
|
+
parsed = { response: text };
|
|
332
305
|
}
|
|
333
306
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
// url_list must be a string[] pre-resolved in _projections.url_list.
|
|
338
|
-
// cacheTimeout: seconds to cache each individual response.
|
|
339
|
-
// ---------------------------------------------------------------------------
|
|
340
|
-
const cfg = sourceDef['url-list'];
|
|
341
|
-
const method = (cfg.method || 'GET').toUpperCase();
|
|
342
|
-
const headers = { ...(cfg.headers || {}) };
|
|
343
|
-
const cacheTimeoutSec = cfg.cacheTimeout != null ? Number(cfg.cacheTimeout) : null;
|
|
344
|
-
|
|
345
|
-
const urlList = Array.isArray(sourceDef._projections?.url_list)
|
|
346
|
-
? sourceDef._projections.url_list : null;
|
|
347
|
-
|
|
348
|
-
if (!urlList || urlList.length === 0) {
|
|
349
|
-
fail('url-list: _projections.url_list must be a non-empty string array', errFile);
|
|
307
|
+
if (!response.ok) {
|
|
308
|
+
const msg = typeof parsed?.error === 'string' ? parsed.error : `HTTP ${response.status}`;
|
|
309
|
+
return { result: 'failure', data: { error: msg }, error: msg };
|
|
350
310
|
}
|
|
351
311
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
try {
|
|
355
|
-
results.push(doFetchApi(u, method, headers, cacheTimeoutSec, errFile));
|
|
356
|
-
} catch (err) {
|
|
357
|
-
fail(`url-list fetch failed for ${u}: ${err.message}`, errFile);
|
|
358
|
-
}
|
|
312
|
+
if (typeof parsed?.error === 'string') {
|
|
313
|
+
return { result: 'failure', data: { error: parsed.error }, error: parsed.error };
|
|
359
314
|
}
|
|
360
|
-
resultValue = results;
|
|
361
315
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
316
|
+
return {
|
|
317
|
+
result: 'success',
|
|
318
|
+
data: {
|
|
319
|
+
resultValue: Object.prototype.hasOwnProperty.call(parsed, 'response') ? parsed.response : parsed,
|
|
320
|
+
},
|
|
321
|
+
};
|
|
322
|
+
};
|
|
367
323
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
// On Windows, delegate entirely to copilot_wrapper.bat which handles:
|
|
372
|
-
// - session management (--resume UUID for multi-turn continuity)
|
|
373
|
-
// - noise/footer stripping, JSON extraction, agentic retry on bad shape
|
|
374
|
-
// On non-Windows, fall back to a basic direct invocation (no retry).
|
|
375
|
-
const wrapperPath = path.join(__dirname, 'scripts', 'copilot_wrapper.bat');
|
|
376
|
-
const useWrapper = process.platform === 'win32' && fs.existsSync(wrapperPath);
|
|
377
|
-
|
|
378
|
-
if (useWrapper) {
|
|
379
|
-
// Session dir is stable across refreshes so --resume continues the conversation.
|
|
380
|
-
const sessionDir = path.join(
|
|
381
|
-
extra.boardSetupRoot || os.tmpdir(),
|
|
382
|
-
'copilot-sessions',
|
|
383
|
-
String(sourceDef.bindTo || 'default').replace(/[^a-zA-Z0-9_-]/g, '_'),
|
|
384
|
-
);
|
|
385
|
-
const wrapperOutFile = outFile + '.wrapper-out.json';
|
|
386
|
-
try {
|
|
387
|
-
resultValue = runCopilotViaWrapper(prompt, sourceDef, wrapperOutFile, sessionDir, copilotCwd);
|
|
388
|
-
} catch (err) {
|
|
389
|
-
fail(`copilot invocation failed: ${String(err && err.message || err)}`, errFile);
|
|
390
|
-
} finally {
|
|
391
|
-
try { fs.unlinkSync(wrapperOutFile); } catch {}
|
|
392
|
-
}
|
|
393
|
-
} else {
|
|
394
|
-
// Non-Windows fallback: call copilot directly via cmd.exe and do basic JSON extraction.
|
|
395
|
-
let rawOutput = '';
|
|
396
|
-
try {
|
|
397
|
-
rawOutput = execFileSync('cmd.exe', ['/d', '/c', 'copilot --allow-all'], {
|
|
398
|
-
input: String(prompt),
|
|
399
|
-
encoding: 'utf-8',
|
|
400
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
401
|
-
maxBuffer: 10 * 1024 * 1024,
|
|
402
|
-
...(copilotCwd ? { cwd: copilotCwd } : {}),
|
|
403
|
-
});
|
|
404
|
-
} catch (err) {
|
|
405
|
-
fail(`copilot invocation failed: ${String(err && err.message || err)}`, errFile);
|
|
406
|
-
}
|
|
407
|
-
// Basic JSON extraction: find first { or [ in output
|
|
408
|
-
const firstBrace = rawOutput.indexOf('{');
|
|
409
|
-
const firstBracket = rawOutput.indexOf('[');
|
|
410
|
-
const jsonStart = (firstBrace === -1) ? firstBracket
|
|
411
|
-
: (firstBracket === -1) ? firstBrace
|
|
412
|
-
: Math.min(firstBrace, firstBracket);
|
|
413
|
-
if (jsonStart !== -1) {
|
|
414
|
-
try {
|
|
415
|
-
const parsed = JSON.parse(rawOutput.slice(jsonStart));
|
|
416
|
-
resultValue = (parsed && typeof parsed === 'object') ? parsed : rawOutput;
|
|
417
|
-
} catch {
|
|
418
|
-
resultValue = rawOutput;
|
|
419
|
-
}
|
|
420
|
-
} else {
|
|
421
|
-
resultValue = rawOutput;
|
|
422
|
-
}
|
|
324
|
+
const invoke = async (ref, args) => {
|
|
325
|
+
if (ref.howToRun === 'http:post' || ref.howToRun === 'http:get') {
|
|
326
|
+
return invokeHttpRef(ref, args);
|
|
423
327
|
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
328
|
+
if (ref.howToRun === 'demo-local-module') {
|
|
329
|
+
const modulePath = path.resolve(__dirname, ref.whatToRun);
|
|
330
|
+
const mod = await import(pathToFileURL(modulePath).href);
|
|
331
|
+
if (typeof mod.execute !== 'function') {
|
|
332
|
+
throw new Error(`Flow module ${ref.whatToRun} must export execute(context)`);
|
|
333
|
+
}
|
|
334
|
+
return mod.execute(args);
|
|
428
335
|
}
|
|
429
|
-
|
|
430
|
-
|
|
336
|
+
return invokeRefSync(ref, args, { cliDir: __dirname, cwd: process.cwd() });
|
|
337
|
+
};
|
|
431
338
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
339
|
+
const handlers = buildStepHandlersForFlow(flow, { invoke });
|
|
340
|
+
const machine = createStepMachine(flow, handlers, { store: new MemoryStore() });
|
|
341
|
+
const run = await machine.run({
|
|
342
|
+
...context,
|
|
343
|
+
promptContext: COPILOT_PROMPT_CONTEXT,
|
|
344
|
+
executorDir: __dirname,
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
if (run.status !== 'completed') {
|
|
348
|
+
const reason = run.error?.message ?? run.intent ?? run.status;
|
|
349
|
+
throw new Error(`flow execution failed: ${reason}`);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if (run.intent !== 'success') {
|
|
353
|
+
const reason = typeof run.data?.error === 'string' ? run.data.error : `flow returned intent: ${run.intent}`;
|
|
354
|
+
throw new Error(reason);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return {
|
|
358
|
+
resultValue: run.data?.resultValue,
|
|
359
|
+
wroteOutputDirectly: !!run.data?.wroteOutputDirectly,
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
async function runSourceFetchSubcommand(argv) {
|
|
364
|
+
const inIdx = argv.indexOf('--in-ref');
|
|
365
|
+
const outIdx = argv.indexOf('--out-ref');
|
|
366
|
+
const errIdx = argv.indexOf('--err-ref');
|
|
367
|
+
const extraIdx = argv.indexOf('--extra');
|
|
368
|
+
const inRefStr = inIdx !== -1 ? argv[inIdx + 1] : undefined;
|
|
369
|
+
const outRefStr = outIdx !== -1 ? argv[outIdx + 1] : undefined;
|
|
370
|
+
const errRefStr = errIdx !== -1 ? argv[errIdx + 1] : undefined;
|
|
371
|
+
const extraB64 = extraIdx !== -1 ? argv[extraIdx + 1] : undefined;
|
|
372
|
+
|
|
373
|
+
let extra = {};
|
|
374
|
+
if (extraB64) {
|
|
375
|
+
try { extra = JSON.parse(Buffer.from(extraB64, 'base64').toString('utf-8')); }
|
|
376
|
+
catch { console.warn('[demo-task-executor] bad --extra base64, ignoring'); }
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (!inRefStr || !outRefStr) {
|
|
380
|
+
fail('Usage: run-source-fetch --in-ref <b64:<base64url(json)>> --out-ref <b64:<base64url(json)>> [--err-ref <b64:<base64url(json)>>]');
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
let inRef, outRef, errRef;
|
|
384
|
+
try {
|
|
385
|
+
inRef = parseRef(inRefStr);
|
|
386
|
+
outRef = parseRef(outRefStr);
|
|
387
|
+
if (errRefStr) errRef = parseRef(errRefStr);
|
|
388
|
+
} catch (e) {
|
|
389
|
+
fail(`invalid ref argument: ${e.message}`);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const inStorage = blobStorageForRef(inRef);
|
|
393
|
+
const outStorage = blobStorageForRef(outRef);
|
|
394
|
+
const errStorage = errRef ? blobStorageForRef(errRef) : undefined;
|
|
395
|
+
|
|
396
|
+
// Local error reporter — writes to errStorage and calls back to board if callback present.
|
|
397
|
+
const failRef = (msg, callback) => {
|
|
398
|
+
if (errStorage && errRef) { try { errStorage.write(errRef.value, msg); } catch {} }
|
|
399
|
+
console.error(`[demo-task-executor] ${msg}`);
|
|
400
|
+
if (callback) { try { reportFailed(callback, msg); } catch {} }
|
|
401
|
+
process.exit(1);
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
const rawIn = inStorage.read(inRef.value);
|
|
405
|
+
if (rawIn === null) {
|
|
406
|
+
failRef(`Input not found: ${inRefStr}`);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Payload may be { source_def, callback } (new protocol) or raw source def (legacy).
|
|
410
|
+
let envelope;
|
|
411
|
+
try {
|
|
412
|
+
envelope = JSON.parse(rawIn);
|
|
413
|
+
} catch (err) {
|
|
414
|
+
failRef(`Cannot parse input: ${String(err && err.message || err)}`);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const callback = envelope.source_def ? envelope.callback : undefined;
|
|
418
|
+
let sourceDef;
|
|
419
|
+
try {
|
|
420
|
+
sourceDef = envelope.source_def ?? envelope;
|
|
421
|
+
} catch (err) {
|
|
422
|
+
failRef(`Cannot resolve source_def: ${String(err && err.message || err)}`, callback);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const registry = loadSourceDefFlowsConfig();
|
|
426
|
+
let kind;
|
|
427
|
+
try {
|
|
428
|
+
kind = resolveSourceKind(sourceDef, registry);
|
|
429
|
+
} catch (err) {
|
|
430
|
+
failRef(String(err && err.message || err), callback);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
let flowResult;
|
|
434
|
+
try {
|
|
435
|
+
flowResult = await executeStepMachineSourceFlow({
|
|
436
|
+
kind,
|
|
437
|
+
registry,
|
|
438
|
+
sourceDef,
|
|
439
|
+
extra,
|
|
440
|
+
inRef,
|
|
441
|
+
outRef,
|
|
442
|
+
errRef,
|
|
443
|
+
mockDb: MOCK_DB,
|
|
444
|
+
});
|
|
445
|
+
} catch (err) {
|
|
446
|
+
const detail = (err && (err.stderr || err.stdout)) ? `\n${err.stderr || err.stdout}`.trimEnd() : '';
|
|
447
|
+
failRef(`${kind} invocation failed: ${String(err && err.message || err)}${detail}`, callback);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
if (!flowResult?.wroteOutputDirectly) {
|
|
436
451
|
try {
|
|
437
|
-
|
|
438
|
-
encoding: 'utf-8',
|
|
439
|
-
stdio: ['inherit', 'pipe', 'pipe'],
|
|
440
|
-
maxBuffer: 10 * 1024 * 1024,
|
|
441
|
-
env: {
|
|
442
|
-
...process.env,
|
|
443
|
-
WORKIQ_QUERY: query,
|
|
444
|
-
...(extra.serverUrl ? { WORKIQ_SERVER_URL: extra.serverUrl } : {}),
|
|
445
|
-
},
|
|
446
|
-
});
|
|
447
|
-
return; // wrapper wrote directly to outFile
|
|
452
|
+
outStorage.write(outRef.value, JSON.stringify(flowResult?.resultValue, null, 2));
|
|
448
453
|
} catch (err) {
|
|
449
|
-
|
|
454
|
+
failRef(`Cannot write output: ${String(err && err.message || err)}`, callback);
|
|
450
455
|
}
|
|
451
|
-
} else if (sourceDef.mock) {
|
|
452
|
-
// MOCK_DB lookup — data hardcoded at the top of this file
|
|
453
|
-
resultValue = MOCK_DB[sourceDef.mock];
|
|
454
|
-
if (resultValue === undefined) {
|
|
455
|
-
fail(`Key "${sourceDef.mock}" not found in MOCK_DB`, errFile);
|
|
456
|
-
}
|
|
457
|
-
} else {
|
|
458
|
-
fail('Source definition has no recognised kind (url, url-list, copilot, workiq, mock)', errFile);
|
|
459
456
|
}
|
|
460
457
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
458
|
+
if (callback) {
|
|
459
|
+
try {
|
|
460
|
+
reportComplete(callback, outRef);
|
|
461
|
+
} catch (err) {
|
|
462
|
+
console.error(`[demo-task-executor] reportComplete failed: ${String(err && err.message || err)}`);
|
|
463
|
+
process.exit(1);
|
|
464
|
+
}
|
|
466
465
|
}
|
|
467
466
|
|
|
468
467
|
}
|
|
@@ -493,30 +492,16 @@ function validateSourceDefSubcommand(argv) {
|
|
|
493
492
|
}
|
|
494
493
|
|
|
495
494
|
const errors = [];
|
|
495
|
+
const registry = loadSourceDefFlowsConfig();
|
|
496
496
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
const kindCount = [hasUrl, hasUrlList, hasCopilot || hasPromptTemplate, hasWorkiq, hasMock].filter(Boolean).length;
|
|
506
|
-
|
|
507
|
-
if (kindCount === 0) {
|
|
508
|
-
errors.push('No recognised source kind (url, url-list, copilot, workiq, mock). Add one of these fields.');
|
|
509
|
-
} else if (kindCount > 1) {
|
|
510
|
-
const kinds = [];
|
|
511
|
-
if (hasUrl) kinds.push('url');
|
|
512
|
-
if (hasUrlList) kinds.push('url-list');
|
|
513
|
-
if (hasCopilot || hasPromptTemplate) kinds.push('copilot');
|
|
514
|
-
if (hasWorkiq) kinds.push('workiq');
|
|
515
|
-
if (hasMock) kinds.push('mock');
|
|
516
|
-
errors.push(`Multiple source kinds specified: [${kinds.join(', ')}]. Use exactly one.`);
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
if (hasUrl) {
|
|
497
|
+
let kind = '';
|
|
498
|
+
try {
|
|
499
|
+
kind = resolveSourceKind(sourceDef, registry);
|
|
500
|
+
} catch (err) {
|
|
501
|
+
errors.push(String(err && err.message || err));
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
if (kind === 'url') {
|
|
520
505
|
if (typeof sourceDef['url'] !== 'object') {
|
|
521
506
|
errors.push('url must be an object.');
|
|
522
507
|
} else if (!sourceDef['url'].url || typeof sourceDef['url'].url !== 'string') {
|
|
@@ -524,24 +509,24 @@ function validateSourceDefSubcommand(argv) {
|
|
|
524
509
|
}
|
|
525
510
|
}
|
|
526
511
|
|
|
527
|
-
if (
|
|
512
|
+
if (kind === 'url-list') {
|
|
528
513
|
if (typeof sourceDef['url-list'] !== 'object') {
|
|
529
514
|
errors.push('url-list must be an object.');
|
|
530
515
|
}
|
|
531
516
|
// url_list is supplied via _projections at runtime — no static validation needed.
|
|
532
517
|
}
|
|
533
518
|
|
|
534
|
-
if (
|
|
519
|
+
if (kind === 'copilot') {
|
|
535
520
|
if (typeof sourceDef.copilot !== 'object') {
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
if (!sourceDef.copilot.prompt_template && !hasPromptTemplate) {
|
|
539
|
-
errors.push('copilot.prompt_template is required (or use top-level prompt_template).');
|
|
521
|
+
if (typeof sourceDef.prompt_template !== 'string') {
|
|
522
|
+
errors.push('copilot must be an object when prompt_template is not provided at top level.');
|
|
540
523
|
}
|
|
524
|
+
} else if (!sourceDef.copilot.prompt_template && typeof sourceDef.prompt_template !== 'string') {
|
|
525
|
+
errors.push('copilot.prompt_template is required (or use top-level prompt_template).');
|
|
541
526
|
}
|
|
542
527
|
}
|
|
543
528
|
|
|
544
|
-
if (
|
|
529
|
+
if (kind === 'workiq') {
|
|
545
530
|
if (typeof sourceDef.workiq !== 'object') {
|
|
546
531
|
errors.push('workiq must be an object.');
|
|
547
532
|
} else if (!sourceDef.workiq.query_template || typeof sourceDef.workiq.query_template !== 'string') {
|
|
@@ -549,7 +534,7 @@ function validateSourceDefSubcommand(argv) {
|
|
|
549
534
|
}
|
|
550
535
|
}
|
|
551
536
|
|
|
552
|
-
if (
|
|
537
|
+
if (kind === 'mock') {
|
|
553
538
|
if (typeof sourceDef.mock !== 'string') {
|
|
554
539
|
errors.push('mock must be a string key.');
|
|
555
540
|
}
|
|
@@ -650,21 +635,34 @@ const CAPABILITIES = {
|
|
|
650
635
|
runtimeStatusDir: { type: 'string', description: 'Relative path to runtime-out dir.' },
|
|
651
636
|
cardsDir: { type: 'string', description: 'Relative path to cards dir.' },
|
|
652
637
|
serverUrl: { type: 'string', description: 'Base URL of the hosting server (e.g. http://127.0.0.1:7799). Used by source kinds that call server-side proxy endpoints.' },
|
|
638
|
+
boardLiveCardsCliJs: { type: 'string', description: 'Absolute path to board-live-cards-cli.js when configured by the runtime.' },
|
|
639
|
+
stepMachineCliPath: { type: 'string', description: 'Absolute path to step-machine-cli.js when configured by the runtime.' },
|
|
653
640
|
},
|
|
654
641
|
},
|
|
655
642
|
};
|
|
656
643
|
|
|
657
644
|
function describeCapabilities() {
|
|
658
|
-
|
|
645
|
+
const registry = loadSourceDefFlowsConfig();
|
|
646
|
+
const merged = {
|
|
647
|
+
...CAPABILITIES,
|
|
648
|
+
sourceKinds: Object.fromEntries(
|
|
649
|
+
Object.entries(registry?.kinds || {}).map(([kind, spec]) => {
|
|
650
|
+
const existing = CAPABILITIES.sourceKinds[kind] || {};
|
|
651
|
+
const manifest = spec?.manifest && typeof spec.manifest === 'object' ? spec.manifest : {};
|
|
652
|
+
return [kind, { ...existing, ...manifest }];
|
|
653
|
+
}),
|
|
654
|
+
),
|
|
655
|
+
};
|
|
656
|
+
console.log(JSON.stringify(merged, null, 2));
|
|
659
657
|
}
|
|
660
658
|
|
|
661
659
|
async function main() {
|
|
662
660
|
const sub = process.argv[2];
|
|
663
661
|
if (sub === 'run-source-fetch') {
|
|
664
|
-
runSourceFetchSubcommand(process.argv.slice(3));
|
|
662
|
+
await runSourceFetchSubcommand(process.argv.slice(3));
|
|
665
663
|
return;
|
|
666
664
|
}
|
|
667
|
-
if (sub === 'describe-capabilities') {
|
|
665
|
+
if (sub === 'describe' || sub === 'describe-capabilities') {
|
|
668
666
|
describeCapabilities();
|
|
669
667
|
return;
|
|
670
668
|
}
|