yaml-flow 7.0.0 → 7.1.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/browser/asset-integrity.json +1 -1
- package/browser/board-livecards-client.js +1 -1
- package/browser/board-livecards-client.js.map +1 -1
- package/browser/board-livecards-localstorage.js +5 -5
- package/browser/board-livecards-localstorage.js.map +1 -1
- package/browser/live-cards.js +3 -1
- package/dist/{board-live-cards-public-CW5074xr.d.cts → board-live-cards-public-5n1-syA3.d.cts} +1 -2
- package/dist/{board-live-cards-public-hnZo0mAf.d.ts → board-live-cards-public-CK_J8uv0.d.ts} +1 -2
- package/dist/cli/browser-api/board-live-cards-browser-adapter.cjs +2 -2
- package/dist/cli/browser-api/board-live-cards-browser-adapter.cjs.map +1 -1
- package/dist/cli/browser-api/board-live-cards-browser-adapter.d.cts +2 -2
- package/dist/cli/browser-api/board-live-cards-browser-adapter.d.ts +2 -2
- package/dist/cli/browser-api/board-live-cards-browser-adapter.js +2 -2
- package/dist/cli/browser-api/board-live-cards-browser-adapter.js.map +1 -1
- package/dist/cli/browser-api/card-store-browser-api.cjs.map +1 -1
- package/dist/cli/browser-api/card-store-browser-api.js.map +1 -1
- package/dist/cli/node/artifacts-store-cli.cjs +5 -5
- package/dist/cli/node/artifacts-store-cli.cjs.map +1 -1
- package/dist/cli/node/artifacts-store-cli.js +5 -5
- package/dist/cli/node/artifacts-store-cli.js.map +1 -1
- package/dist/cli/node/board-live-cards-cli.cjs +7 -7
- package/dist/cli/node/board-live-cards-cli.cjs.map +1 -1
- package/dist/cli/node/board-live-cards-cli.js +7 -7
- package/dist/cli/node/board-live-cards-cli.js.map +1 -1
- package/dist/cli/node/card-store-cli.cjs +4 -4
- package/dist/cli/node/card-store-cli.cjs.map +1 -1
- package/dist/cli/node/card-store-cli.js +4 -4
- package/dist/cli/node/card-store-cli.js.map +1 -1
- package/dist/cli/node/execution-adapter.cjs +1 -1
- package/dist/cli/node/execution-adapter.cjs.map +1 -1
- package/dist/cli/node/execution-adapter.js +1 -1
- package/dist/cli/node/execution-adapter.js.map +1 -1
- package/dist/cli/node/fs-board-adapter.cjs +7 -7
- package/dist/cli/node/fs-board-adapter.cjs.map +1 -1
- package/dist/cli/node/fs-board-adapter.d.cts +2 -2
- package/dist/cli/node/fs-board-adapter.d.ts +2 -2
- package/dist/cli/node/fs-board-adapter.js +7 -7
- package/dist/cli/node/fs-board-adapter.js.map +1 -1
- package/dist/cli/node/source-cli-task-executor.cjs +2 -2
- package/dist/cli/node/source-cli-task-executor.cjs.map +1 -1
- package/dist/cli/node/source-cli-task-executor.js +2 -2
- package/dist/cli/node/source-cli-task-executor.js.map +1 -1
- package/dist/execution-refs.cjs +2 -2
- package/dist/execution-refs.cjs.map +1 -1
- package/dist/execution-refs.d.cts +9 -4
- package/dist/execution-refs.d.ts +9 -4
- package/dist/execution-refs.js +2 -2
- package/dist/execution-refs.js.map +1 -1
- package/dist/server-runtime/index.cjs +4 -4
- package/dist/server-runtime/index.cjs.map +1 -1
- package/dist/server-runtime/index.d.cts +3 -3
- package/dist/server-runtime/index.d.ts +3 -3
- package/dist/server-runtime/index.js +4 -4
- package/dist/server-runtime/index.js.map +1 -1
- package/dist/step-machine-public/index.cjs +2 -1
- package/dist/step-machine-public/index.cjs.map +1 -1
- package/dist/step-machine-public/index.d.cts +7 -0
- package/dist/step-machine-public/index.d.ts +7 -0
- package/dist/step-machine-public/index.js +2 -1
- package/dist/step-machine-public/index.js.map +1 -1
- package/dist/storage-refs.cjs +2 -2
- package/dist/storage-refs.cjs.map +1 -1
- package/dist/storage-refs.d.cts +1 -2
- package/dist/storage-refs.d.ts +1 -2
- package/dist/storage-refs.js +2 -2
- package/dist/storage-refs.js.map +1 -1
- package/dist/{types-BxEFcVK9.d.cts → types-CU3DjTKL.d.cts} +1 -1
- package/dist/{types-B1ZRa4aI.d.ts → types-HGDTWIun.d.ts} +1 -1
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker-http-test.js +13 -0
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker-http-test.py +398 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/portfolio-tracker.flow.yaml +4 -4
- package/examples/cli/step-machine-demo/jsonata-init-board.flow.yaml +1 -1
- package/examples/cli/step-machine-demo/one-step-cli-only.flow.yaml +1 -1
- package/examples/cli/step-machine-demo/two-step-mixed.flow.yaml +1 -1
- package/examples/example-board/agent-instructions.md +1 -1
- package/examples/example-board/cards/{card-market-prices.json → cardT-market-prices.json} +2 -2
- package/examples/example-board/cards/{card-portfolio.json → cardT-portfolio.json} +3 -13
- package/examples/example-board/demo-server-config.json +1 -1
- package/examples/example-board/demo-server.js +48 -25
- package/examples/example-board/demo-shell-localstorage.html +3 -3
- package/examples/example-board/demo-shell-with-server.html +2 -2
- package/examples/example-board/demo-task-executor.js +4 -8
- package/package.json +2 -2
- package/step-machine-cli.js +1 -1
- package/examples/example-board/cards/_index.json +0 -47
- /package/examples/example-board/cards/{card-portfolio-value.json → cardT-portfolio-value.json} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/cli/common/storage-interface.ts","../../../src/cli/node/process-runner.ts","../../../src/cli/common/jsonata-loader.ts","../../../src/cli/common/args-massaging.ts","../../../src/cli/node/execution-adapter.ts"],"names":["REF_PREFIX","toBase64Url","raw","utf8","buf","base64","binary","byte","fromBase64Url","input","bytes","i","serializeRef","ref","parseRef","s","parsed","candidate","parseCommandSpec","command","args","rest","resolved","_resolveNode","parts","splitCommandLine","cmd","tokens","current","quote","ch","_needsWindowsShell","runSync","spec","options","cwd","env","timeoutMs","execFileSync","runAsync","callback","execFile","err","stdout","stderr","runDetached","spawn","buildBoardCliInvocation","cliDir","jsPath","tsPath","tsxMjs","tsxBin","tsx","createNodeCommandExecutor","rawCmd","rawArgs","_require","createRequire","_loadJsonata","jsonata","resolveArgsMassaging","argsMassaging","context","label","out","expr","msg","_requireJsonata","evalJsonata","evalJsonataString","result","resolveBuiltIn","whatToRun","name","h","m","resolveBaseInvocation","scriptPath","buildDefaultTaskExecutorArgv","extra","argv","buildDefaultTaskExecutorBody","buildLocalBaseSpec","_parseStdoutAsJson","trimmed","lines","last","invokeRefSync","massaged","baseSpec","stdinPayload","executor","e","status","detail","createExecutionAdapter","_invokeTaskExecutorHttp","baseArgs","callArgv","finalArgs","spawnSync","url","body","evaluated","response","text","responseJson","builtInSourceCliExecutorRef","builtInBoardCliRef","localNodeExecutorRef","dispatchTaskExecutorDetached"],"mappings":"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","file":"execution-adapter.js","sourcesContent":["/**\n * storage-interface.ts\n *\n * Three minimal storage primitives that together cover all persistence needs\n * of the board-live-cards system. Any backend (Node fs, CosmosDB, Azure Blob,\n * browser localStorage, in-memory test double) implements these three interfaces.\n *\n * The pure-logic stores in board-live-cards-all-stores.ts depend only on these\n * interfaces — never on Node built-ins.\n *\n * Blob — raw string content at a logical, backend-neutral key\n * Journal — append-only log with cursor-based reads\n * KV — key-value store with list/delete\n *\n * Mapping to existing storage adapters:\n *\n * CardStorageAdapter\n * inventory (cardId → { blobRef, checksum, fileMetadata? }) → KV\n * card JSON files → Blob\n * source output files → Blob\n *\n * JournalStorageAdapter → Journal (board-journal.jsonl)\n *\n * ExecutionRequestStore → KV (keyed by journalId, via createFsKvStorage)\n *\n * StateSnapshotStorageAdapter\n * board-graph.json (packed single JSON, written atomically) → Blob\n * per-card sidecars (cards/<id>/runtime, fetched-sources-manifest) → KV\n */\n\n// ============================================================================\n// Blob — raw content at an opaque key\n//\n// The key is backend-specific (file path, blob name, storage key).\n// Text helpers are always available. Binary helpers are optional so existing\n// backends can adopt incrementally.\n// ============================================================================\n\nexport interface BlobStat {\n key: string;\n size: number;\n updatedAt?: string;\n contentType?: string;\n}\n\nexport interface BlobStorage {\n /** Returns raw content string, or null if the blob does not exist. */\n read(key: string): string | null;\n\n /** Write content at key. Implementations should be atomic (write-rename). */\n write(key: string, content: string): void;\n\n /** Returns true if a blob exists at key. */\n exists(key: string): boolean;\n\n /** Delete the blob at key. No-op if it does not exist. */\n remove(key: string): void;\n\n /** Optional binary read for file-like artifacts. */\n readBytes?(key: string): Uint8Array | null;\n\n /** Optional binary write for file-like artifacts. */\n writeBytes?(key: string, content: Uint8Array): void;\n\n /** Optional key listing by prefix. */\n listKeys?(prefix?: string): string[];\n\n /** Optional metadata lookup. */\n stat?(key: string): BlobStat | null;\n}\n\n// ============================================================================\n// KindValueRef — backend-neutral typed reference\n//\n// A ref describes WHERE content lives without carrying the bytes.\n// Serialized on the CLI wire as: b64:<base64url({\"kind\":\"...\",\"value\":\"...\"})>\n// kind = 'fs-path': value is an absolute file path\n// Additional kinds (e.g. 'cosmos') are added in public-storage-adapter.ts as new backends are supported.\n// ============================================================================\n\nexport interface KindValueRef {\n readonly kind: string;\n readonly value: string;\n}\n\nconst REF_PREFIX = 'b64:';\n\nfunction toBase64Url(raw: string): string {\n const utf8 = new TextEncoder().encode(raw);\n const buf = (globalThis as { Buffer?: { from(data: Uint8Array): { toString(enc: string): string } } }).Buffer;\n let base64: string;\n if (buf) {\n base64 = buf.from(utf8).toString('base64');\n } else if (typeof btoa === 'function') {\n let binary = '';\n for (const byte of utf8) binary += String.fromCharCode(byte);\n base64 = btoa(binary);\n } else {\n throw new Error('No base64 encoder available in this runtime');\n }\n return base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/g, '');\n}\n\nfunction fromBase64Url(input: string): string {\n const base64 = input.replace(/-/g, '+').replace(/_/g, '/')\n + '='.repeat((4 - (input.length % 4)) % 4);\n const buf = (globalThis as { Buffer?: { from(data: string, enc: string): { toString(enc: string): string } } }).Buffer;\n if (buf) return buf.from(base64, 'base64').toString('utf8');\n if (typeof atob === 'function') {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i += 1) bytes[i] = binary.charCodeAt(i);\n return new TextDecoder().decode(bytes);\n }\n throw new Error('No base64 decoder available in this runtime');\n}\n\n/** Serialize a KindValueRef to the wire format: b64:<base64url(json)> */\nexport function serializeRef(ref: KindValueRef): string {\n return `${REF_PREFIX}${toBase64Url(JSON.stringify(ref))}`;\n}\n\n/** Parse a wire-format ref string (b64:<base64url(json)>) into a KindValueRef.\n * Also accepts the legacy ::fs-path::<path> format for backward compatibility. */\nexport function parseRef(s: string): KindValueRef {\n // Legacy format: ::fs-path::<path>\n if (s.startsWith('::fs-path::')) {\n return { kind: 'fs-path', value: s.slice('::fs-path::'.length) };\n }\n if (!s.startsWith(REF_PREFIX)) throw new Error(`Invalid ref format (expected ${REF_PREFIX}<base64url(json)>): ${s}`);\n let parsed: unknown;\n try {\n parsed = JSON.parse(fromBase64Url(s.slice(REF_PREFIX.length)));\n } catch {\n throw new Error(`Invalid ref format (malformed base64url/json): ${s}`);\n }\n if (!parsed || typeof parsed !== 'object') {\n throw new Error(`Invalid ref format (expected object payload): ${s}`);\n }\n const candidate = parsed as { kind?: unknown; value?: unknown };\n if (typeof candidate.kind !== 'string' || typeof candidate.value !== 'string') {\n throw new Error(`Invalid ref format (payload must contain string kind/value): ${s}`);\n }\n return { kind: candidate.kind, value: candidate.value };\n}\n\n// ============================================================================\n// Journal — append-only log, cursor-based reads\n//\n// Each entry has a string id (UUID or monotonic token) and an opaque payload.\n// Cursors are entry ids — readAfter returns entries strictly after that id.\n// A null/empty cursor means \"read from the beginning\".\n// ============================================================================\n\nexport interface JournalEntry {\n id: string;\n payload: unknown;\n}\n\nexport interface JournalReadResult {\n entries: JournalEntry[];\n /** The id of the last entry returned, suitable for use as the next cursor. */\n newCursor: string | null;\n}\n\nexport interface JournalStorage {\n /** Append an entry. The storage layer assigns the id. */\n append(payload: unknown): JournalEntry;\n\n /** Read ALL entries (for index rebuilds, full replay). */\n readAll(): JournalEntry[];\n\n /**\n * Read entries appended after the given cursor id.\n * If cursor is null/empty, returns all entries from the beginning.\n */\n readAfter(cursor: string | null): JournalReadResult;\n}\n\n// ============================================================================\n// KV — key-value store with list and delete\n//\n// Values are opaque unknown — callers own serialisation.\n// Keys are scoped by the adapter factory (e.g. a boardDir prefix is closed\n// over in the adapter, not passed per-call).\n// ============================================================================\n\nexport interface KVStorage {\n /** Returns the stored value, or null if the key does not exist. */\n read(key: string): unknown | null;\n\n /** Write value at key. Overwrites any existing value. */\n write(key: string, value: unknown): void;\n\n /** Delete the key. No-op if it does not exist. */\n delete(key: string): void;\n\n /**\n * List all keys, optionally filtered to those starting with prefix.\n * Order is implementation-defined.\n */\n listKeys(prefix?: string): string[];\n}\n\n// ============================================================================\n// JSONStorage — KV store with JSON-aware merge operations\n//\n// Backed by KVStorage under the hood. Adds deepMerge and shallowMerge so\n// callers never need to read-modify-write manually for partial updates.\n// ============================================================================\n\nexport interface JSONStorage {\n /** Returns the stored JSON value, or null if the key does not exist. */\n read(key: string): unknown | null;\n\n /**\n * Read a nested value inside the stored object using a dot-notation path.\n * e.g. get('myKey', 'a.b.c') returns the value at { a: { b: { c: ... } } }.\n * Returns null if the key does not exist or the path cannot be traversed.\n */\n get(key: string, jsonPath: string): unknown | null;\n\n /** Write value at key. Overwrites any existing value. */\n write(key: string, value: unknown): void;\n\n /** Delete the key. No-op if it does not exist. */\n delete(key: string): void;\n\n /** List all keys, optionally filtered by prefix. */\n listKeys(prefix?: string): string[];\n\n /**\n * Shallow-merge patch into the existing object at key.\n * Equivalent to: write(key, { ...read(key), ...patch })\n * Creates the key if it does not exist.\n */\n shallowMerge(key: string, patch: Record<string, unknown>): void;\n\n /**\n * Deep-merge patch into the existing object at key.\n * Recursively merges nested plain objects; arrays and primitives are replaced.\n * Creates the key if it does not exist.\n */\n deepMerge(key: string, patch: Record<string, unknown>): void;\n\n /**\n * Set a nested value inside the stored object using a dot-notation path.\n * e.g. patch('myKey', 'a.b.c', 42) sets { a: { b: { c: 42 } } } into the stored object.\n * Intermediate objects are created if absent. Arrays are not traversed — use integer\n * segments to index into them (e.g. 'items.0.name').\n * Creates the top-level key if it does not exist.\n */\n patch(key: string, jsonPath: string, value: unknown): void;\n}\n\n// ============================================================================\n// StorageProvider — aggregate of all three primitives\n//\n// Adapter factories receive a StorageProvider and close over any scope (e.g.\n// boardDir) themselves. This is the single injection point for swapping\n// backends (Node fs → CosmosDB, browser localStorage, test doubles, etc.).\n// ============================================================================\n\nexport interface StorageProvider {\n blob: BlobStorage;\n journal: JournalStorage;\n kv: KVStorage;\n}\n\n// ============================================================================\n// AtomicRelayLock — non-blocking try-acquire lock with relay-on-busy semantics\n//\n// This interface serves TWO tightly coupled purposes which are intentionally\n// unified into a single primitive:\n//\n// 1. ATOMICITY — ensures that a read-mutate-save cycle is executed by at\n// most one actor at a time, preventing concurrent actors from racing on\n// stale state and writing conflicting snapshots.\n//\n// 2. RELAY SIGNAL — when tryAcquire() returns null, the caller knows the\n// cycle is already in progress. Because the holder always reads fresh\n// state upon entry, it will pick up every change appended by the skipping\n// caller before the lock was attempted. The caller can therefore safely\n// exit — its work will be completed by the holder. This is the\n// \"relay baton\" pattern: the lock being held IS the in-progress signal.\n//\n// These two purposes are not an accidental overload — they are the same\n// invariant expressed at different scopes. Any backend implementation\n// (FS lockfile, Cosmos document lease, Azure entity lock, in-memory flag)\n// that satisfies \"at most one holder at a time\" automatically satisfies both.\n//\n// Contract:\n// - tryAcquire() is non-blocking. It never waits.\n// - Returns a release function on success, or null if already held.\n// - The release function must be called exactly once (use try/finally).\n// - Behaviour after calling release() more than once is undefined.\n// ============================================================================\n\nexport interface AtomicRelayLock {\n /**\n * Attempt to acquire the lock without blocking.\n * Returns a `release` function if successful, or `null` if the lock is\n * already held by another actor (relay: that actor will complete the work).\n */\n tryAcquire(): (() => void) | null;\n}\n\n/**\n * Execute `work` under an `AtomicRelayLock`.\n *\n * - If the lock is busy, returns false immediately (relay: the holder will\n * complete the work on behalf of this caller).\n * - If acquired, runs `work` exclusively, releases the lock, then calls\n * `continuation` if provided — allowing the caller to schedule the next\n * cycle (e.g. spawn a detached process) after the lock is free.\n * - Returns true if work ran.\n */\nexport async function withRelayLock(\n lock: AtomicRelayLock,\n work: () => Promise<void>,\n continuation?: () => void,\n): Promise<boolean> {\n const release = lock.tryAcquire();\n if (!release) return false; // relay: holder is already doing the work\n try {\n await work();\n } finally {\n release(); // release before continuation so it can immediately re-acquire\n }\n continuation?.();\n return true;\n}\n","/**\n * process-runner.ts — Single source of truth for child process execution.\n *\n * All CLI execution paths (task-executor, source.cli, inference-adapter,\n * detached background workers) route through these helpers.\n *\n * DESIGN:\n * - CommandSpec is the structured command form: { command, args, cwd, env, timeoutMs }\n * - runSync / runAsync use execFileSync / execFile (no ambient shell)\n * - runDetached handles OS differences in one place\n * - parseCommandSpec reads both legacy string form and new { command, args } form\n *\n * WHY NO SHELL BY DEFAULT:\n * - Shell interpretation is platform-dependent (cmd.exe vs /bin/sh vs bash)\n * - Shell parsing of argument strings is fragile and platform-fragile\n * - execFile / execFileSync avoids all quoting and escaping issues\n *\n * BACKWARD COMPAT:\n * - parseCommandSpec(\"node my-tool.js --flag\") → { command: process.execPath, args: ['my-tool.js', '--flag'] }\n * - Legacy .task-executor / .inference-adapter / source.cli string values still load correctly\n */\n\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport * as net from 'node:net';\nimport { fileURLToPath } from 'node:url';\nimport { execFileSync, execFile, spawn } from 'node:child_process';\nimport { randomUUID, createHash } from 'node:crypto';\n\nimport type { CommandSpec } from '../../continuous-event-graph/handlers.js';\nimport type { KindValueRef } from '../common/storage-interface.js';\nimport { serializeRef } from '../common/storage-interface.js';\nexport type { CommandSpec };\n\n// ============================================================================\n// makeBoardTempFilePath — board-scoped temp file path for external process handoff\n// ============================================================================\n\n/**\n * Return a unique file path under `<boardDir>/.tmp/` suitable for passing\n * to an external binary (task-executor, inference-adapter) as `--in`, `--out`,\n * or `--err` arguments.\n *\n * - Files are co-located with the board they belong to (not global os.tmpdir()).\n * - The `.tmp/` directory is created on demand.\n * - The file itself is NOT created here — the caller writes it before use.\n * - `ext` defaults to `.json`; use `.txt` for plain-text error files.\n */\nexport function makeBoardTempFilePath(boardDir: string, label: string, ext = '.json'): string {\n const tmpDir = path.join(boardDir, '.tmp');\n fs.mkdirSync(tmpDir, { recursive: true });\n return path.join(tmpDir, `${label}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}${ext}`);\n}\n\n/** Join path segments — thin wrapper so callers don't need to import node:path. */\nexport function joinPath(...segments: string[]): string { return path.join(...segments); }\n\n/** Resolve a path to absolute — thin wrapper so callers don't need to import node:path. */\nexport function resolvePath(...segments: string[]): string { return path.resolve(...segments); }\n\n/** Return the directory name of a path. */\nexport function dirnamePath(p: string): string { return path.dirname(p); }\n\n/** Return true if the path is absolute. */\nexport function isAbsolutePath(p: string): boolean { return path.isAbsolute(p); }\n\n/** Generate a new random UUID. */\nexport function genUUID(): string { return randomUUID(); }\n\n/** SHA-256 hex hash of a string. */\nexport function getHash(x: string): string { return createHash('sha256').update(x).digest('hex'); }\n\n/** Resolve the directory of an ESM module from its import.meta.url. */\nexport function resolveModuleDir(importMetaUrl: string): string { return path.dirname(fileURLToPath(importMetaUrl)); }\n\n// ============================================================================\n// parseCommandSpec — legacy string or structured CommandSpec → normalized form\n// ============================================================================\n\n/**\n * Parse a legacy string command or pass through a structured CommandSpec.\n *\n * - Legacy string: \"node script.js --flag value\"\n * → { command: process.execPath, args: ['script.js', '--flag', 'value'] }\n *\n * - Structured: { command: 'node', args: ['script.js', '--flag', 'value'] }\n * → { command: process.execPath, args: ['script.js', '--flag', 'value'] }\n *\n * After parsing, 'node'/'node.exe' is resolved to process.execPath, and bare\n * '.js'/'.mjs' paths are wrapped in a node invocation.\n */\nexport function parseCommandSpec(raw: string | CommandSpec): CommandSpec {\n if (typeof raw === 'object' && raw !== null) {\n const { command, args = [], ...rest } = raw;\n const resolved = _resolveNode(command, args);\n return { ...rest, command: resolved.command, args: resolved.args };\n }\n const parts = splitCommandLine(raw);\n if (parts.length === 0) throw new Error(`Empty command spec: ${JSON.stringify(raw)}`);\n return _resolveNode(parts[0], parts.slice(1));\n}\n\nfunction _resolveNode(cmd: string, args: string[]): { command: string; args: string[] } {\n if (/^(node|node\\.exe)$/i.test(cmd)) return { command: process.execPath, args };\n if (/\\.m?js$/i.test(cmd)) return { command: process.execPath, args: [cmd, ...args] };\n return { command: cmd, args };\n}\n\n// ============================================================================\n// splitCommandLine — shell-style string splitting (legacy compat only)\n// ============================================================================\n\n/**\n * Split a shell-style command string into tokens, respecting single/double quotes.\n * Used only for backward-compat parsing of legacy string-format config values.\n */\nexport function splitCommandLine(command: string): string[] {\n const tokens: string[] = [];\n let current = '';\n let quote: '\"' | '\\'' | null = null;\n\n for (const ch of command.trim()) {\n if (quote) {\n if (ch === quote) { quote = null; } else { current += ch; }\n continue;\n }\n if (ch === '\"' || ch === '\\'') { quote = ch; continue; }\n if (/\\s/.test(ch)) {\n if (current) { tokens.push(current); current = ''; }\n continue;\n }\n current += ch;\n }\n\n if (quote) throw new Error(`Unterminated quote in command: ${command}`);\n if (current) tokens.push(current);\n return tokens;\n}\n\n// ============================================================================\n// .cmd/.bat on Windows needs shell: true\n// ============================================================================\n\nfunction _needsWindowsShell(cmd: string): boolean {\n return process.platform === 'win32' && /\\.(cmd|bat)$/i.test(cmd);\n}\n\n// ============================================================================\n// runSync — synchronous process execution\n// ============================================================================\n\n/**\n * Run a command synchronously and return stdout as a string.\n * Uses execFileSync — no ambient shell. Safe on all platforms.\n */\nexport function runSync(spec: CommandSpec, options?: { encoding?: BufferEncoding; input?: string }): string {\n const { command, args = [], cwd, env, timeoutMs } = spec;\n const output = execFileSync(command, args, {\n shell: _needsWindowsShell(command),\n timeout: timeoutMs,\n encoding: options?.encoding ?? 'utf-8',\n cwd,\n windowsHide: true,\n env: env ? { ...process.env, ...env } : undefined,\n input: options?.input,\n });\n return output as string;\n}\n\n// ============================================================================\n// runAsync — async process execution with callback\n// ============================================================================\n\n/**\n * Run a command asynchronously, calling back with (err, stdout, stderr).\n * Uses execFile — no ambient shell. Safe on all platforms.\n */\nexport function runAsync(\n spec: CommandSpec,\n callback: (err: Error | null, stdout: string, stderr: string) => void,\n): void {\n const { command, args = [], cwd, env, timeoutMs = 30_000 } = spec;\n execFile(\n command,\n args,\n {\n shell: _needsWindowsShell(command),\n encoding: 'utf8',\n windowsHide: true,\n timeout: timeoutMs,\n maxBuffer: 10 * 1024 * 1024,\n cwd,\n env: env ? { ...process.env, ...env } : undefined,\n },\n (err, stdout, stderr) => callback(err ?? null, stdout, stderr),\n );\n}\n\n// ============================================================================\n// Git Bash detection (Windows only — needed for runDetached)\n// ============================================================================\n\nlet _gitBashPath: string | false | undefined;\nconst _GIT_BASH_CACHE = path.join(os.tmpdir(), '.board-live-cards-git-bash-cache.json');\n\nexport function findGitBash(): string | false {\n if (_gitBashPath !== undefined) return _gitBashPath;\n if (process.platform !== 'win32') return (_gitBashPath = false);\n\n try {\n const cached = JSON.parse(fs.readFileSync(_GIT_BASH_CACHE, 'utf8')) as { path: string | false };\n if (cached.path === false || (typeof cached.path === 'string' && fs.existsSync(cached.path))) {\n return (_gitBashPath = cached.path);\n }\n } catch { /* cache miss */ }\n\n const candidates: Array<string | undefined> = [\n process.env.SHELL,\n process.env.PROGRAMFILES\n ? path.join(process.env.PROGRAMFILES, 'Git', 'usr', 'bin', 'bash.exe')\n : undefined,\n process.env.PROGRAMFILES\n ? path.join(process.env.PROGRAMFILES, 'Git', 'bin', 'bash.exe')\n : undefined,\n process.env['PROGRAMFILES(X86)']\n ? path.join(process.env['PROGRAMFILES(X86)']!, 'Git', 'bin', 'bash.exe')\n : undefined,\n process.env.LOCALAPPDATA\n ? path.join(process.env.LOCALAPPDATA, 'Programs', 'Git', 'bin', 'bash.exe')\n : undefined,\n ];\n\n for (const c of candidates) {\n if (c && /bash(\\.exe)?$/i.test(c) && fs.existsSync(c)) {\n _gitBashPath = c;\n try { fs.writeFileSync(_GIT_BASH_CACHE, JSON.stringify({ path: c })); } catch { /* best-effort */ }\n return _gitBashPath;\n }\n }\n\n _gitBashPath = false;\n try { fs.writeFileSync(_GIT_BASH_CACHE, JSON.stringify({ path: false })); } catch { /* best-effort */ }\n return _gitBashPath;\n}\n\nfunction _shellQuote(s: string): string {\n return \"'\" + s.replace(/'/g, \"'\\\\''\") + \"'\";\n}\n\n// ============================================================================\n// runDetached — fire-and-forget background spawn\n// ============================================================================\n\n/**\n * Spawn a detached background process that survives parent exit.\n * Handles Windows (Git Bash / cmd /c start /b) and Linux/macOS transparently.\n */\nexport function runDetached(spec: CommandSpec): void {\n const { command, args = [] } = spec;\n\n if (process.platform === 'win32') {\n const child = spawn(command, args, {\n detached: true,\n stdio: 'ignore',\n windowsHide: true,\n shell: _needsWindowsShell(command),\n });\n child.unref();\n return;\n }\n\n const child = spawn(command, args, { detached: true, stdio: 'ignore' });\n child.unref();\n}\n\n// ============================================================================\n// buildBoardCliInvocation — resolve how to invoke board-live-cards-cli\n//\n// cliDir is the directory containing board-live-cards-cli.ts / .js.\n// Probe order: compiled .js → tsx dev → npx tsx fallback.\n// ============================================================================\n\n/**\n * Return { cmd, args } that invokes `board-live-cards-cli <command> [...args]`\n * in whatever environment is available (compiled dist, dev tsx, npx fallback).\n *\n * Pass `__dirname` (from the calling file's own directory) as `cliDir`.\n */\nexport function buildBoardCliInvocation(\n cliDir: string,\n command: string,\n args: string[],\n): { cmd: string; args: string[] } {\n const jsPath = path.join(cliDir, 'board-live-cards-cli.js');\n if (fs.existsSync(jsPath)) {\n return { cmd: process.execPath, args: [jsPath, command, ...args] };\n }\n\n const tsPath = path.join(cliDir, 'board-live-cards-cli.ts');\n const tsxMjs = path.join(cliDir, '..', '..', 'node_modules', 'tsx', 'dist', 'cli.mjs');\n const tsxBin = path.join(cliDir, '..', '..', 'node_modules', '.bin', 'tsx');\n const tsx = fs.existsSync(tsxMjs) ? tsxMjs : tsxBin;\n if (fs.existsSync(tsPath) && fs.existsSync(tsx)) {\n return { cmd: process.execPath, args: [tsx, tsPath, command, ...args] };\n }\n\n const npxCmd = process.platform === 'win32' ? 'npx.cmd' : 'npx';\n return { cmd: npxCmd, args: ['tsx', tsPath, command, ...args] };\n}\n\n// ============================================================================\n// requestProcessAccumulatedDetached — fire-and-forget dispatch of next drain pass\n// ============================================================================\n\n/**\n * Spawn a detached board-live-cards process-accumulated-events pass for the given board.\n */\nexport function requestProcessAccumulatedDetached(cliDir: string, baseRef: KindValueRef, notifyChannel?: string): void {\n const cliArgs = ['--base-ref', serializeRef(baseRef)];\n if (notifyChannel) cliArgs.push('--notify-channel', notifyChannel);\n const { cmd, args } = buildBoardCliInvocation(cliDir, 'process-accumulated-events', cliArgs);\n runDetached({ command: cmd, args });\n}\n\n// ============================================================================\n// Named-pipe event transport (cross-process board notifications)\n// ============================================================================\n\n/** Return canonical named-pipe/socket path for the given channel name. */\nexport function getNamedPipePath(pipeName: string): string {\n if (process.platform === 'win32') return `\\\\\\\\.\\\\pipe\\\\${pipeName}`;\n return path.join(os.tmpdir(), `${pipeName}.sock`);\n}\n\n/**\n * Publish a batch of JSON notifications as newline-delimited records to a named pipe.\n * Best-effort: if the pipe is unavailable, logs via onWarn and drops the batch.\n *\n * All payloads are concatenated into a single `socket.write()` call so the consumer\n * receives them atomically (no interleaving from other drain cycles).\n * Uses a per-pipeName persistent connection so ordering is preserved across calls.\n */\nconst _pipeClients = new Map<string, { socket: net.Socket; ready: boolean; queue: string[] }>();\n\nexport function publishJsonEventsToNamedPipe(\n pipeName: string,\n payloads: unknown[],\n onWarn?: (msg: string) => void,\n): void {\n if (payloads.length === 0) return;\n const chunk = payloads.map(p => JSON.stringify(p)).join('\\n') + '\\n';\n let entry = _pipeClients.get(pipeName);\n\n if (entry && !entry.socket.destroyed) {\n if (entry.ready) {\n entry.socket.write(chunk);\n } else {\n entry.queue.push(chunk);\n }\n return;\n }\n\n // Create a new persistent connection\n const pipePath = getNamedPipePath(pipeName);\n const socket = net.createConnection(pipePath);\n entry = { socket, ready: false, queue: [chunk] };\n _pipeClients.set(pipeName, entry);\n\n socket.on('connect', () => {\n entry!.ready = true;\n for (const queued of entry!.queue) socket.write(queued);\n entry!.queue.length = 0;\n });\n\n socket.on('error', (e) => {\n onWarn?.(`[named-pipe publish] ${pipePath}: ${e instanceof Error ? e.message : String(e)}`);\n _pipeClients.delete(pipeName);\n });\n\n socket.on('close', () => {\n _pipeClients.delete(pipeName);\n });\n}\n\n// ============================================================================\n// createNodeCommandExecutor — Node implementation of CommandExecutor\n//\n// Wraps runSync / runAsync / runDetached / parseCommandSpec / splitCommandLine\n// into a single injectable object. Pass to command handlers instead of the\n// individual execCommandSync / execCommandAsync / resolveCommandInvocation /\n// splitCommandLine / spawnDetachedCommand dep functions.\n// ============================================================================\n\nimport type { CommandExecutor, ExecOptions } from '../common/process-interface.js';\n\nexport function createNodeCommandExecutor(): CommandExecutor {\n return {\n executeSync(cmd: string, args: string[], options?: ExecOptions): string {\n return runSync(\n { command: cmd, args, cwd: options?.cwd, timeoutMs: options?.timeout, env: options?.env as Record<string, string> | undefined },\n { encoding: options?.encoding as BufferEncoding | undefined, input: options?.input },\n );\n },\n executeAsync(cmd: string, args: string[], callback: (err: Error | null, stdout: string, stderr: string) => void): void {\n runAsync({ command: cmd, args }, callback);\n },\n resolveInvocation(rawCmd: string, rawArgs: string[]): { cmd: string; args: string[] } {\n const spec = parseCommandSpec({ command: rawCmd, args: rawArgs });\n return { cmd: spec.command, args: spec.args ?? [] };\n },\n splitCommand: splitCommandLine,\n spawnDetached(cmd: string, args: string[]): void {\n runDetached({ command: cmd, args });\n },\n };\n}\n","/**\n * cli/common/jsonata-loader — synchronous jsonata wrapper.\n *\n * Mirrors the loader pattern used by card-compute. Uses createRequire so the\n * vendored CommonJS sync build can be loaded from ESM. The canonical source\n * file is `src/card-compute/jsonata-sync.cjs`; the tsup post-build hook copies\n * it next to every dist bundle that references it.\n */\n\nimport { createRequire } from 'module';\n\nconst _require = createRequire(import.meta.url);\n\nexport type JsonataExpression = {\n evaluate: (data: unknown) => unknown;\n};\n\n// Source path resolves via the file's location at src/cli/common/.\n// Dist path resolves via the post-build copy that places jsonata-sync.cjs\n// alongside the bundled output (handled by tsup's copyJsonataSyncToDistDirs).\nfunction _loadJsonata(): (expr: string) => JsonataExpression {\n // Try sibling first (dist layout). If that fails, fall back to the canonical\n // source location (used when running TypeScript directly under vitest/tsx).\n try {\n return _require('./jsonata-sync.cjs');\n } catch {\n return _require('../../card-compute/jsonata-sync.cjs');\n }\n}\n\nexport const jsonata: (expr: string) => JsonataExpression = _loadJsonata();\n","/**\n * cli/common/args-massaging — JSONata-based mapping from logical args to\n * transport-specific shape.\n *\n * `argsMassaging` is a property of `ExecutionRef`, so honoring it is the job\n * of every adapter (Node spawn, HTTP, Azure Function, etc.). This helper is\n * the shared pure-JSONata implementation reused by all adapters.\n *\n * Adapters call this as the first step inside their `invokeRefSync` /\n * `dispatchExecution` implementation, then perform their transport using\n * `cmdArgs` / `body` / `url`.\n */\n\nimport { jsonata } from './jsonata-loader.js';\nimport type { ArgsMassaging, OutputTransforms } from './execution-interface.js';\nimport type { NormalizedHandlerResult } from '../../step-machine-public/types.js';\n\nexport interface MassagedArgs {\n /** Resolved argv tail for local transports. */\n cmdArgs?: string[];\n /** Resolved request body for http transports (or stdin payload for local). */\n body?: unknown;\n /** Resolved final URL string for http transports. */\n url?: string;\n}\n\n/**\n * Evaluate `argsMassaging` against the supplied context.\n *\n * Throws with a label-tagged message if any expression fails. Adapters\n * should catch and convert to a normalized failure result.\n */\nexport function resolveArgsMassaging(\n argsMassaging: ArgsMassaging | undefined,\n context: Record<string, unknown>,\n label: string,\n): MassagedArgs {\n if (!argsMassaging || typeof argsMassaging !== 'object') return {};\n\n const out: MassagedArgs = {};\n\n if (Array.isArray(argsMassaging.cmdTemplate)) {\n const resolved: string[] = [];\n for (const expr of argsMassaging.cmdTemplate) {\n try {\n resolved.push(String(jsonata(expr).evaluate(context)));\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(\n `[${label}] argsMassaging.cmdTemplate failed on \"${expr}\": ${msg}`,\n );\n }\n }\n out.cmdArgs = resolved;\n }\n\n if (typeof argsMassaging.bodyTemplate === 'string') {\n try {\n out.body = jsonata(argsMassaging.bodyTemplate).evaluate(context);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(\n `[${label}] argsMassaging.bodyTemplate failed: ${msg}`,\n );\n }\n }\n\n if (typeof argsMassaging.urlTemplate === 'string') {\n try {\n out.url = String(jsonata(argsMassaging.urlTemplate).evaluate(context));\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(\n `[${label}] argsMassaging.urlTemplate failed: ${msg}`,\n );\n }\n }\n\n return out;\n}\n\n/**\n * Apply `outputTransforms` to a raw invoke result.\n *\n * Context for all expressions: `{ output }` where `output` is the raw\n * { result, data, error? } envelope from invokeRefSync.\n *\n * Returns a new NormalizedHandlerResult with overrides applied.\n * Throws with a label-tagged message if any expression fails.\n */\nexport function resolveOutputTransforms(\n transforms: OutputTransforms | undefined,\n raw: NormalizedHandlerResult,\n label: string,\n): NormalizedHandlerResult {\n if (!transforms || typeof transforms !== 'object') return raw;\n\n const ctx = { output: raw };\n let result = raw.result;\n let data = raw.data;\n let error = raw.error;\n\n if (typeof transforms.resultExpr === 'string') {\n try {\n const val = jsonata(transforms.resultExpr).evaluate(ctx);\n if (typeof val !== 'string' || !val.trim()) {\n throw new Error(`resultExpr did not produce a non-empty string (got ${JSON.stringify(val)})`);\n }\n result = val;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(`[${label}] outputTransforms.resultExpr failed: ${msg}`);\n }\n }\n\n if (typeof transforms.dataTemplate === 'string') {\n try {\n const val = jsonata(transforms.dataTemplate).evaluate(ctx);\n if (!val || typeof val !== 'object' || Array.isArray(val)) {\n throw new Error(`dataTemplate did not produce an object (got ${JSON.stringify(val)})`);\n }\n data = val as Record<string, unknown>;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(`[${label}] outputTransforms.dataTemplate failed: ${msg}`);\n }\n }\n\n if (typeof transforms.errorExpr === 'string') {\n try {\n const val = jsonata(transforms.errorExpr).evaluate(ctx);\n // $undefined() evaluates to undefined — clears the error field\n error = val != null ? String(val) : undefined;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(`[${label}] outputTransforms.errorExpr failed: ${msg}`);\n }\n }\n\n return error !== undefined\n ? { result, data, error }\n : { result, data };\n}\n","/**\n * execution-adapter.ts\n *\n * Node.js-specific adapter that resolves an ExecutionRef + logical args\n * into a physical invocation (process spawn, HTTP request, or built-in call).\n *\n * This is the platform layer that pairs with execution-interface.ts (pure types).\n * Import this only from Node contexts — not from browser bundles.\n *\n * ────────────────────────────────────────────────────────────────────────────\n * WELL-KNOWN INVOCATION KINDS\n * ────────────────────────────────────────────────────────────────────────────\n *\n * invokeTaskExecutor(ref, args)\n * Standard task-executor protocol.\n * Logical args: { subcommand, inRef, outRef, errRef?, extra? }\n * Default cmdTemplate (local): ['subcommand', '--in-ref', inRef, '--out-ref', outRef, '--err-ref', errRef]\n * Default body (http): { subcommand, inRef, outRef, errRef }\n *\n * invokeBoardCliCallback(ref, args)\n * Back-channel from a task-executor to the board CLI.\n * Logical args: { command, argv[] }\n * Resolves 'built-in' to the board CLI script alongside cliDir.\n *\n * ────────────────────────────────────────────────────────────────────────────\n * BUILT-IN RESOLUTION\n * ────────────────────────────────────────────────────────────────────────────\n *\n * howToRun: 'built-in' with whatToRun: 'b64:<base64url({\"kind\":\"built-in\",\"value\":\"source-cli-task-executor\"})>'\n * → resolves to node <cliDir>/source-cli-task-executor.js\n *\n * howToRun: 'built-in' with whatToRun: 'b64:<base64url({\"kind\":\"built-in\",\"value\":\"board-live-cards\"})>'\n * → resolves to node <cliDir>/board-live-cards-cli.js (via buildBoardCliInvocation)\n *\n * ────────────────────────────────────────────────────────────────────────────\n * argsMassaging EVALUATION\n * ────────────────────────────────────────────────────────────────────────────\n *\n * Each argsMassaging field is a JSONata expression evaluated against the\n * logical args object merged with { whatToRun } (the address from the ref).\n *\n * If argsMassaging is absent, the adapter uses its default mapping.\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { spawnSync } from 'node:child_process';\nimport { createRequire } from 'module';\nconst _requireJsonata = createRequire(import.meta.url);\nconst jsonata: (expr: string) => { evaluate: (data: unknown) => unknown } = _requireJsonata('../../card-compute/jsonata-sync.cjs');\nimport type { ExecutionRef, ExecutionResult } from '../common/execution-interface.js';\nimport { parseRef, serializeRef } from '../common/storage-interface.js';\nimport { buildBoardCliInvocation, runSync, runDetached } from './process-runner.js';\n\n// ============================================================================\n// Logical args shapes for well-known invocation kinds\n// ============================================================================\n\n/** Logical args for invokeTaskExecutor — standard task-executor protocol. */\nexport interface TaskExecutorArgs {\n /** Subcommand to dispatch: 'run-source-fetch' | 'validate-source-def' | 'describe-capabilities' | ... */\n subcommand: string;\n /** Input ref (b64:<base64url(json)> wire form) pointing to the task payload. */\n inRef?: string;\n /** Output ref (b64:<base64url(json)> wire form) where the executor writes its result. */\n outRef?: string;\n /** Error ref (b64:<base64url(json)> wire form) for structured error output. */\n errRef?: string;\n}\n\n/** Logical args for invokeBoardCliCallback — back-channel from executor to board. */\nexport interface BoardCliCallbackArgs {\n /** Board CLI subcommand to invoke (e.g. 'source-data-fetched', 'source-data-fetch-failure'). */\n command: string;\n /** Additional argv strings passed after the command. */\n argv: string[];\n}\n\n// ============================================================================\n// ExecutionAdapterOptions\n// ============================================================================\n\n/**\n * Options passed when constructing an execution adapter.\n * Provides the platform-specific context needed for built-in resolution.\n */\nexport interface ExecutionAdapterOptions {\n /**\n * Absolute path to the directory containing the compiled CLI files.\n * Required for resolving 'built-in' refs (e.g. source-cli-task-executor.js,\n * board-live-cards-cli.js).\n */\n cliDir: string;\n}\n\n// ============================================================================\n// JSONata evaluation helper\n// ============================================================================\n\n/**\n * Evaluate a single JSONata expression against a context object.\n * Returns the result as-is (string, object, array, etc.).\n */\nasync function evalJsonata(expr: string, context: Record<string, unknown>): Promise<unknown> {\n const compiled = jsonata(expr);\n return compiled.evaluate(context);\n}\n\n/**\n * Evaluate a JSONata expression and coerce the result to a string.\n * Throws if the result is not a string.\n */\nasync function evalJsonataString(expr: string, context: Record<string, unknown>): Promise<string> {\n const result = await evalJsonata(expr, context);\n if (typeof result !== 'string') {\n throw new Error(`argsMassaging expression did not produce a string: ${expr} → ${JSON.stringify(result)}`);\n }\n return result;\n}\n\n// ============================================================================\n// Built-in ref resolution\n// ============================================================================\n\n/**\n * Resolve a 'built-in' ExecutionRef to a concrete { command, args } invocation.\n * The whatToRun value names the built-in implementation.\n *\n * Supported built-in names:\n * source-cli-task-executor → node <cliDir>/source-cli-task-executor.js\n * board-live-cards → node <cliDir>/board-live-cards-cli.js (via buildBoardCliInvocation)\n */\nfunction resolveBuiltIn(whatToRun: string, cliDir: string): { command: string; args: string[] } {\n // whatToRun is a b64:<base64url(json)> ref — parse the value portion\n let name: string;\n try {\n name = parseRef(whatToRun).value;\n } catch {\n // fallback: treat as bare name\n name = whatToRun;\n }\n\n switch (name) {\n case 'source-cli-task-executor': {\n const jsPath = path.join(cliDir, 'source-cli-task-executor.js');\n if (fs.existsSync(jsPath)) {\n return { command: process.execPath, args: [jsPath] };\n }\n const tsPath = path.join(cliDir, 'source-cli-task-executor.ts');\n const tsxMjs = path.join(cliDir, '..', '..', 'node_modules', 'tsx', 'dist', 'cli.mjs');\n const tsxBin = path.join(cliDir, '..', '..', 'node_modules', '.bin', 'tsx');\n const tsx = fs.existsSync(tsxMjs) ? tsxMjs : tsxBin;\n if (fs.existsSync(tsPath) && fs.existsSync(tsx)) {\n return { command: process.execPath, args: [tsx, tsPath] };\n }\n return { command: process.execPath, args: [jsPath] }; // fallback — will fail with clear error\n }\n case 'board-live-cards': {\n const { cmd, args } = buildBoardCliInvocation(cliDir, '_', []);\n return { command: cmd, args };\n }\n default:\n throw new Error(`resolveBuiltIn: unknown built-in name \"${name}\". Supported: source-cli-task-executor, board-live-cards`);\n }\n}\n\n/**\n * Resolve an ExecutionRef's whatToRun + howToRun to a base { command, args }\n * for local transports, or a URL string for http transports.\n */\nfunction resolveBaseInvocation(\n ref: ExecutionRef,\n cliDir: string,\n): { command: string; baseArgs: string[] } {\n if (ref.howToRun === 'built-in') {\n const { command, args } = resolveBuiltIn(ref.whatToRun, cliDir);\n return { command, baseArgs: args };\n }\n\n // For local-* transports, parse the whatToRun as a storage ref or bare path\n let scriptPath: string;\n try {\n scriptPath = parseRef(ref.whatToRun).value;\n } catch {\n scriptPath = ref.whatToRun;\n }\n\n switch (ref.howToRun) {\n case 'local-node':\n return { command: process.execPath, baseArgs: [scriptPath] };\n case 'local-python': {\n const python = process.platform === 'win32' ? 'python' : 'python3';\n return { command: python, baseArgs: [scriptPath] };\n }\n case 'local-process':\n return { command: scriptPath, baseArgs: [] };\n default:\n throw new Error(`resolveBaseInvocation: howToRun \"${ref.howToRun}\" is not a local transport`);\n }\n}\n\n// ============================================================================\n// Default arg mappings per invocation kind\n// ============================================================================\n\n/**\n * Build the default argv for a task-executor invocation (local transports).\n * Protocol: <subcommand> [--in-ref <inRef>] [--out-ref <outRef>] [--err-ref <errRef>] [--extra <base64>]\n *\n * @param extra Opaque executor config from ExecutionRef.extra — base64-encoded before passing.\n */\nfunction buildDefaultTaskExecutorArgv(\n args: TaskExecutorArgs,\n extra?: Record<string, unknown>,\n): string[] {\n const argv: string[] = [args.subcommand];\n if (args.inRef) argv.push('--in-ref', args.inRef);\n if (args.outRef) argv.push('--out-ref', args.outRef);\n if (args.errRef) argv.push('--err-ref', args.errRef);\n if (extra) argv.push('--extra', Buffer.from(JSON.stringify(extra)).toString('base64'));\n return argv;\n}\n\n/**\n * Build the default HTTP body for a task-executor invocation.\n *\n * @param extra Opaque executor config from ExecutionRef.extra — passed as-is in the body.\n */\nfunction buildDefaultTaskExecutorBody(\n args: TaskExecutorArgs,\n extra?: Record<string, unknown>,\n): Record<string, unknown> {\n return {\n subcommand: args.subcommand,\n ...(args.inRef ? { inRef: args.inRef } : {}),\n ...(args.outRef ? { outRef: args.outRef } : {}),\n ...(args.errRef ? { errRef: args.errRef } : {}),\n ...(extra ? { extra } : {}),\n };\n}\n\n// ============================================================================\n// buildLocalBaseSpec — sync helper for callers that stay synchronous\n// ============================================================================\n\n/**\n * Resolve an ExecutionRef to its base { command, baseArgs } for local transports.\n *\n * Exported for callers that need to stay synchronous (e.g. validate-source-def,\n * describe-capabilities) and build their own final argv.\n * Does NOT evaluate argsMassaging — append custom argv after baseArgs.\n *\n * @example\n * const { command, baseArgs } = buildLocalBaseSpec(teRef, cliDir);\n * executor.executeSync(command, [...baseArgs, 'describe-capabilities'], { timeout: 10_000 });\n */\nexport function buildLocalBaseSpec(\n ref: ExecutionRef,\n cliDir: string,\n): { command: string; baseArgs: string[] } {\n return resolveBaseInvocation(ref, cliDir);\n}\n\n// ============================================================================\n// invokeRefSync — synchronous request/reply for ref-based invocations\n// ============================================================================\n\nimport { resolveArgsMassaging } from '../common/args-massaging.js';\nimport { createNodeCommandExecutor } from './process-runner.js';\n\n/** Normalized envelope returned by invokeRefSync. */\nexport interface InvokeRefResult {\n /** Outcome key — drives transitions in the step machine ('success' | 'failure' | custom). */\n result: string;\n /** Response payload as a record (always object-shaped; raw stdout wrapped under `stdout` if not JSON object). */\n data: Record<string, unknown>;\n /** Optional human-readable error detail. */\n error?: string;\n}\n\nexport interface InvokeRefSyncOptions {\n /** Directory used to resolve `built-in` refs (defaults to ref's cwd / process cwd). */\n cliDir?: string;\n /** Working directory for the spawned child (default: process cwd). */\n cwd?: string;\n /** Timeout in milliseconds (default: 30_000). */\n timeoutMs?: number;\n /** Label used in error messages (default: 'invokeRefSync'). */\n label?: string;\n}\n\nfunction _parseStdoutAsJson(stdout: string): unknown {\n const trimmed = stdout.trim();\n if (!trimmed) throw new Error('empty stdout');\n try {\n return JSON.parse(trimmed);\n } catch {\n const lines = trimmed.split(/\\r?\\n/).filter(Boolean);\n const last = lines[lines.length - 1];\n return JSON.parse(last);\n }\n}\n\n/**\n * Invoke an ExecutionRef synchronously with a request/reply contract.\n *\n * Used by:\n * - step-machine ref steps (each step's handler dispatches through here)\n * - any utility that needs sync request/reply against an ExecutionRef\n *\n * Behavior:\n * 1. Resolve `ref.argsMassaging` against `args` to get cmdArgs / body.\n * 2. Build the local base spec (node/python/process + script path).\n * 3. Spawn synchronously with `JSON.stringify(body ?? args)` on stdin.\n * 4. Map exit code into envelope:\n * exit 0 → { result: 'success', data: parsed-stdout-or-{stdout: raw} }\n * non-0 → { result: 'failure', data: { error: stderr-or-exit-detail } }\n *\n * The framework (engine) never inspects payload shape; it only routes on `result`.\n */\nexport function invokeRefSync(\n ref: ExecutionRef,\n args: Record<string, unknown>,\n options?: InvokeRefSyncOptions,\n): InvokeRefResult {\n const label = options?.label ?? 'invokeRefSync';\n const cliDir = options?.cliDir ?? options?.cwd ?? process.cwd();\n\n let massaged;\n try {\n massaged = resolveArgsMassaging(ref.argsMassaging, args, label);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return { result: 'failure', data: { error: msg } };\n }\n\n let baseSpec;\n try {\n baseSpec = buildLocalBaseSpec(ref, cliDir);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return { result: 'failure', data: { error: `[${label}] ref resolution failed: ${msg}` } };\n }\n\n const argv = [...baseSpec.baseArgs, ...(massaged.cmdArgs ?? [])];\n const stdinPayload = JSON.stringify(massaged.body ?? args);\n const executor = createNodeCommandExecutor();\n\n let stdout: string;\n try {\n stdout = executor.executeSync(baseSpec.command, argv, {\n timeout: options?.timeoutMs ?? 30_000,\n encoding: 'utf-8',\n cwd: options?.cwd,\n input: stdinPayload,\n });\n } catch (err) {\n // execFileSync throws on non-zero exit / spawn error / timeout.\n const e = err as NodeJS.ErrnoException & { stderr?: Buffer | string; status?: number | null };\n const stderr = (e.stderr ? String(e.stderr) : '').trim();\n const status = typeof e.status === 'number' ? e.status : 'unknown';\n const detail = stderr || e.message;\n return {\n result: 'failure',\n data: { error: `[${label}] ref exited with status ${status}${detail ? `: ${detail}` : ''}` },\n };\n }\n\n // Transport succeeded (exit 0). Wrap stdout as data unconditionally.\n try {\n const parsed = _parseStdoutAsJson(stdout);\n const data: Record<string, unknown> =\n parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : { stdout: parsed };\n return { result: 'success', data };\n } catch {\n return { result: 'success', data: { stdout: stdout.trim() } };\n }\n}\n\n// ============================================================================\n// createExecutionAdapter — factory\n// ============================================================================\n\nexport interface ExecutionAdapter {\n /**\n * Invoke a task-executor using the standard protocol.\n * Dispatches based on howToRun; applies argsMassaging if present, otherwise\n * uses the default task-executor protocol (--in-ref / --out-ref / --err-ref).\n */\n invokeTaskExecutor(ref: ExecutionRef, args: TaskExecutorArgs): Promise<ExecutionResult>;\n\n /**\n * Invoke the board CLI as a back-channel callback.\n * Used by task-executors to report source-data-fetched / source-data-fetch-failure.\n * Resolves 'built-in::board-live-cards' to the board CLI script alongside cliDir.\n */\n invokeBoardCliCallback(ref: ExecutionRef, args: BoardCliCallbackArgs): ExecutionResult;\n}\n\n/**\n * Create an ExecutionAdapter bound to a specific cliDir.\n *\n * @param options.cliDir Absolute path to the compiled CLI directory.\n * Used to resolve 'built-in' refs.\n */\nexport function createExecutionAdapter(options: ExecutionAdapterOptions): ExecutionAdapter {\n const { cliDir } = options;\n\n return {\n async invokeTaskExecutor(ref: ExecutionRef, args: TaskExecutorArgs): Promise<ExecutionResult> {\n const isHttp = ref.howToRun === 'http:post' || ref.howToRun === 'http:get';\n\n if (isHttp) {\n return _invokeTaskExecutorHttp(ref, args);\n }\n\n // Local transports: local-node, local-python, local-process, built-in\n const { command, baseArgs } = resolveBaseInvocation(ref, cliDir);\n\n let callArgv: string[];\n if (ref.argsMassaging?.cmdTemplate) {\n // Evaluate each JSONata expression in the template\n const context: Record<string, unknown> = { ...args, whatToRun: ref.whatToRun };\n const evaluated = await Promise.all(\n ref.argsMassaging.cmdTemplate.map(expr => evalJsonataString(expr, context)),\n );\n callArgv = evaluated;\n } else {\n callArgv = buildDefaultTaskExecutorArgv(args, ref.extra);\n }\n\n const finalArgs = [...baseArgs, ...callArgv];\n try {\n runSync({ command, args: finalArgs });\n return { status: 'success' };\n } catch (err) {\n return { status: 'error', error: err instanceof Error ? err.message : String(err) };\n }\n },\n\n invokeBoardCliCallback(ref: ExecutionRef, args: BoardCliCallbackArgs): ExecutionResult {\n // Resolve the board CLI invocation\n let cmd: string;\n let baseArgs: string[];\n\n if (ref.howToRun === 'built-in') {\n const resolved = buildBoardCliInvocation(cliDir, args.command, args.argv);\n // buildBoardCliInvocation already includes the command and argv\n const result = spawnSync(resolved.cmd, resolved.args, { encoding: 'utf-8', windowsHide: true });\n if (result.status !== 0) {\n return { status: 'error', error: `board CLI exited ${result.status}: ${result.stderr?.trim()}` };\n }\n return { status: 'success' };\n }\n\n ({ command: cmd, baseArgs } = resolveBaseInvocation(ref, cliDir));\n const result = spawnSync(cmd, [...baseArgs, args.command, ...args.argv], {\n encoding: 'utf-8',\n windowsHide: true,\n });\n if (result.status !== 0) {\n return { status: 'error', error: `board CLI exited ${result.status}: ${result.stderr?.trim()}` };\n }\n return { status: 'success' };\n },\n };\n}\n\n// ============================================================================\n// HTTP transport (async — used for http:post / http:get)\n// ============================================================================\n\nasync function _invokeTaskExecutorHttp(\n ref: ExecutionRef,\n args: TaskExecutorArgs,\n): Promise<ExecutionResult> {\n let url: string;\n let body: Record<string, unknown>;\n\n const context: Record<string, unknown> = { ...args, whatToRun: ref.whatToRun };\n\n if (ref.argsMassaging?.urlTemplate) {\n url = await evalJsonataString(ref.argsMassaging.urlTemplate, context);\n } else {\n // Default: use whatToRun as URL directly (strip b64 KindValueRef if present)\n try {\n url = parseRef(ref.whatToRun).value;\n } catch {\n url = ref.whatToRun;\n }\n }\n\n if (ref.argsMassaging?.bodyTemplate) {\n const evaluated = await evalJsonata(ref.argsMassaging.bodyTemplate, context);\n if (typeof evaluated !== 'object' || evaluated === null) {\n throw new Error(`bodyTemplate must produce an object, got: ${JSON.stringify(evaluated)}`);\n }\n body = evaluated as Record<string, unknown>;\n } else {\n body = buildDefaultTaskExecutorBody(args, ref.extra);\n }\n\n // Use native fetch (Node 18+)\n const response = await fetch(url, {\n method: ref.howToRun === 'http:get' ? 'GET' : 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n return { status: 'error', error: `HTTP ${response.status}: ${text}` };\n }\n\n const responseJson = await response.json().catch(() => null) as Record<string, unknown> | null;\n if (responseJson && typeof responseJson.status === 'string') {\n return responseJson as unknown as ExecutionResult;\n }\n return { status: 'success' };\n}\n\n// ============================================================================\n// Well-known ExecutionRef factories\n// ============================================================================\n\n/**\n * Create an ExecutionRef for the built-in source-cli task executor.\n * Resolves to node <cliDir>/source-cli-task-executor.js at runtime.\n */\nexport function builtInSourceCliExecutorRef(): ExecutionRef {\n return {\n meta: 'task-executor',\n howToRun: 'built-in',\n whatToRun: serializeRef({ kind: 'built-in', value: 'source-cli-task-executor' }),\n };\n}\n\n/**\n * Create an ExecutionRef for the board CLI callback back-channel.\n * Resolves to node <cliDir>/board-live-cards-cli.js at runtime.\n */\nexport function builtInBoardCliRef(): ExecutionRef {\n return {\n meta: 'board-live-cards',\n howToRun: 'built-in',\n whatToRun: serializeRef({ kind: 'built-in', value: 'board-live-cards' }),\n };\n}\n\n/**\n * Create an ExecutionRef for a local Node.js task executor script.\n *\n * @param scriptPath Absolute path to the executor .js file.\n */\nexport function localNodeExecutorRef(scriptPath: string): ExecutionRef {\n return {\n meta: 'task-executor',\n howToRun: 'local-node',\n whatToRun: serializeRef({ kind: 'fs-path', value: scriptPath }),\n };\n}\n\n// ============================================================================\n// Detached task-executor dispatch\n// ============================================================================\n\n/**\n * Dispatch a task-executor invocation as a detached background process.\n * Used by the board source-fetch dispatcher — fire-and-forget.\n *\n * For http transports, falls back to synchronous fetch (not truly detached).\n */\nexport function dispatchTaskExecutorDetached(\n ref: ExecutionRef,\n args: TaskExecutorArgs,\n cliDir: string,\n): void {\n const isHttp = ref.howToRun === 'http:post' || ref.howToRun === 'http:get';\n if (isHttp) {\n // For HTTP, we can't easily detach — fire async and ignore result\n void _invokeTaskExecutorHttp(ref, args).catch(err => {\n console.error(`[dispatchTaskExecutorDetached] HTTP dispatch failed: ${(err as Error).message}`);\n });\n return;\n }\n\n const { command, baseArgs } = resolveBaseInvocation(ref, cliDir);\n const callArgv = buildDefaultTaskExecutorArgv(args, ref.extra);\n runDetached({ command, args: [...baseArgs, ...callArgv] });\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/cli/common/storage-interface.ts","../../../src/cli/node/process-runner.ts","../../../src/cli/common/jsonata-loader.ts","../../../src/cli/common/args-massaging.ts","../../../src/cli/node/execution-adapter.ts"],"names":["REF_PREFIX","toBase64Url","raw","utf8","buf","base64","binary","byte","fromBase64Url","input","bytes","i","serializeRef","ref","parseRef","s","parsed","candidate","parseCommandSpec","command","args","rest","resolved","_resolveNode","parts","splitCommandLine","cmd","tokens","current","quote","ch","_needsWindowsShell","runSync","spec","options","cwd","env","timeoutMs","execFileSync","runAsync","callback","execFile","err","stdout","stderr","runDetached","spawn","buildBoardCliInvocation","cliDir","jsPath","tsPath","tsxMjs","tsxBin","tsx","createNodeCommandExecutor","rawCmd","rawArgs","_require","createRequire","_loadJsonata","jsonata","resolveArgsMassaging","argsMassaging","context","label","out","expr","msg","_requireJsonata","evalJsonata","evalJsonataString","result","resolveBuiltIn","whatToRun","name","h","m","resolveBaseInvocation","scriptPath","buildDefaultTaskExecutorArgv","extra","argv","buildDefaultTaskExecutorBody","buildLocalBaseSpec","_parseStdoutAsJson","trimmed","lines","last","invokeRefSync","massaged","baseSpec","stdinPayload","executor","e","status","detail","createExecutionAdapter","_invokeTaskExecutorHttp","baseArgs","callArgv","finalArgs","spawnSync","url","body","evaluated","response","text","responseJson","builtInSourceCliExecutorRef","builtInBoardCliRef","localNodeExecutorRef","dispatchTaskExecutorDetached"],"mappings":"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","file":"execution-adapter.js","sourcesContent":["/**\n * storage-interface.ts\n *\n * Three minimal storage primitives that together cover all persistence needs\n * of the board-live-cards system. Any backend (Node fs, CosmosDB, Azure Blob,\n * browser localStorage, in-memory test double) implements these three interfaces.\n *\n * The pure-logic stores in board-live-cards-all-stores.ts depend only on these\n * interfaces — never on Node built-ins.\n *\n * Blob — raw string content at a logical, backend-neutral key\n * Journal — append-only log with cursor-based reads\n * KV — key-value store with list/delete\n *\n * Mapping to existing storage adapters:\n *\n * CardStorageAdapter\n * inventory (cardId → { blobRef, checksum, fileMetadata? }) → KV\n * card JSON files → Blob\n * source output files → Blob\n *\n * JournalStorageAdapter → Journal (board-journal.jsonl)\n *\n * ExecutionRequestStore → KV (keyed by journalId, via createFsKvStorage)\n *\n * StateSnapshotStorageAdapter\n * board-graph.json (packed single JSON, written atomically) → Blob\n * per-card sidecars (cards/<id>/runtime, fetched-sources-manifest) → KV\n */\n\n// ============================================================================\n// Blob — raw content at an opaque key\n//\n// The key is backend-specific (file path, blob name, storage key).\n// Text helpers are always available. Binary helpers are optional so existing\n// backends can adopt incrementally.\n// ============================================================================\n\nexport interface BlobStat {\n key: string;\n size: number;\n updatedAt?: string;\n contentType?: string;\n}\n\nexport interface BlobStorage {\n /** Returns raw content string, or null if the blob does not exist. */\n read(key: string): string | null;\n\n /** Write content at key. Implementations should be atomic (write-rename). */\n write(key: string, content: string): void;\n\n /** Returns true if a blob exists at key. */\n exists(key: string): boolean;\n\n /** Delete the blob at key. No-op if it does not exist. */\n remove(key: string): void;\n\n /** Optional binary read for file-like artifacts. */\n readBytes?(key: string): Uint8Array | null;\n\n /** Optional binary write for file-like artifacts. */\n writeBytes?(key: string, content: Uint8Array): void;\n\n /** Optional key listing by prefix. */\n listKeys?(prefix?: string): string[];\n\n /** Optional metadata lookup. */\n stat?(key: string): BlobStat | null;\n}\n\n// ============================================================================\n// KindValueRef — backend-neutral typed reference\n//\n// A ref describes WHERE content lives without carrying the bytes.\n// Serialized on the CLI wire as: b64:<base64url({\"kind\":\"...\",\"value\":\"...\"})>\n// kind = 'fs-path': value is an absolute file path\n// Additional kinds (e.g. 'cosmos') are added in public-storage-adapter.ts as new backends are supported.\n// ============================================================================\n\nexport interface KindValueRef {\n readonly kind: string;\n readonly value: string;\n}\n\nconst REF_PREFIX = 'b64:';\n\nfunction toBase64Url(raw: string): string {\n const utf8 = new TextEncoder().encode(raw);\n const buf = (globalThis as { Buffer?: { from(data: Uint8Array): { toString(enc: string): string } } }).Buffer;\n let base64: string;\n if (buf) {\n base64 = buf.from(utf8).toString('base64');\n } else if (typeof btoa === 'function') {\n let binary = '';\n for (const byte of utf8) binary += String.fromCharCode(byte);\n base64 = btoa(binary);\n } else {\n throw new Error('No base64 encoder available in this runtime');\n }\n return base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/g, '');\n}\n\nfunction fromBase64Url(input: string): string {\n const base64 = input.replace(/-/g, '+').replace(/_/g, '/')\n + '='.repeat((4 - (input.length % 4)) % 4);\n const buf = (globalThis as { Buffer?: { from(data: string, enc: string): { toString(enc: string): string } } }).Buffer;\n if (buf) return buf.from(base64, 'base64').toString('utf8');\n if (typeof atob === 'function') {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i += 1) bytes[i] = binary.charCodeAt(i);\n return new TextDecoder().decode(bytes);\n }\n throw new Error('No base64 decoder available in this runtime');\n}\n\n/** Serialize a KindValueRef to the wire format: b64:<base64url(json)> */\nexport function serializeRef(ref: KindValueRef): string {\n return `${REF_PREFIX}${toBase64Url(JSON.stringify(ref))}`;\n}\n\n/** Parse a wire-format ref string (b64:<base64url(json)>) into a KindValueRef. */\nexport function parseRef(s: string): KindValueRef {\n if (!s.startsWith(REF_PREFIX)) throw new Error(`Invalid ref format (expected ${REF_PREFIX}<base64url(json)>): ${s}`);\n let parsed: unknown;\n try {\n parsed = JSON.parse(fromBase64Url(s.slice(REF_PREFIX.length)));\n } catch {\n throw new Error(`Invalid ref format (malformed base64url/json): ${s}`);\n }\n if (!parsed || typeof parsed !== 'object') {\n throw new Error(`Invalid ref format (expected object payload): ${s}`);\n }\n const candidate = parsed as { kind?: unknown; value?: unknown };\n if (typeof candidate.kind !== 'string' || typeof candidate.value !== 'string') {\n throw new Error(`Invalid ref format (payload must contain string kind/value): ${s}`);\n }\n return { kind: candidate.kind, value: candidate.value };\n}\n\n// ============================================================================\n// Journal — append-only log, cursor-based reads\n//\n// Each entry has a string id (UUID or monotonic token) and an opaque payload.\n// Cursors are entry ids — readAfter returns entries strictly after that id.\n// A null/empty cursor means \"read from the beginning\".\n// ============================================================================\n\nexport interface JournalEntry {\n id: string;\n payload: unknown;\n}\n\nexport interface JournalReadResult {\n entries: JournalEntry[];\n /** The id of the last entry returned, suitable for use as the next cursor. */\n newCursor: string | null;\n}\n\nexport interface JournalStorage {\n /** Append an entry. The storage layer assigns the id. */\n append(payload: unknown): JournalEntry;\n\n /** Read ALL entries (for index rebuilds, full replay). */\n readAll(): JournalEntry[];\n\n /**\n * Read entries appended after the given cursor id.\n * If cursor is null/empty, returns all entries from the beginning.\n */\n readAfter(cursor: string | null): JournalReadResult;\n}\n\n// ============================================================================\n// KV — key-value store with list and delete\n//\n// Values are opaque unknown — callers own serialisation.\n// Keys are scoped by the adapter factory (e.g. a boardDir prefix is closed\n// over in the adapter, not passed per-call).\n// ============================================================================\n\nexport interface KVStorage {\n /** Returns the stored value, or null if the key does not exist. */\n read(key: string): unknown | null;\n\n /** Write value at key. Overwrites any existing value. */\n write(key: string, value: unknown): void;\n\n /** Delete the key. No-op if it does not exist. */\n delete(key: string): void;\n\n /**\n * List all keys, optionally filtered to those starting with prefix.\n * Order is implementation-defined.\n */\n listKeys(prefix?: string): string[];\n}\n\n// ============================================================================\n// JSONStorage — KV store with JSON-aware merge operations\n//\n// Backed by KVStorage under the hood. Adds deepMerge and shallowMerge so\n// callers never need to read-modify-write manually for partial updates.\n// ============================================================================\n\nexport interface JSONStorage {\n /** Returns the stored JSON value, or null if the key does not exist. */\n read(key: string): unknown | null;\n\n /**\n * Read a nested value inside the stored object using a dot-notation path.\n * e.g. get('myKey', 'a.b.c') returns the value at { a: { b: { c: ... } } }.\n * Returns null if the key does not exist or the path cannot be traversed.\n */\n get(key: string, jsonPath: string): unknown | null;\n\n /** Write value at key. Overwrites any existing value. */\n write(key: string, value: unknown): void;\n\n /** Delete the key. No-op if it does not exist. */\n delete(key: string): void;\n\n /** List all keys, optionally filtered by prefix. */\n listKeys(prefix?: string): string[];\n\n /**\n * Shallow-merge patch into the existing object at key.\n * Equivalent to: write(key, { ...read(key), ...patch })\n * Creates the key if it does not exist.\n */\n shallowMerge(key: string, patch: Record<string, unknown>): void;\n\n /**\n * Deep-merge patch into the existing object at key.\n * Recursively merges nested plain objects; arrays and primitives are replaced.\n * Creates the key if it does not exist.\n */\n deepMerge(key: string, patch: Record<string, unknown>): void;\n\n /**\n * Set a nested value inside the stored object using a dot-notation path.\n * e.g. patch('myKey', 'a.b.c', 42) sets { a: { b: { c: 42 } } } into the stored object.\n * Intermediate objects are created if absent. Arrays are not traversed — use integer\n * segments to index into them (e.g. 'items.0.name').\n * Creates the top-level key if it does not exist.\n */\n patch(key: string, jsonPath: string, value: unknown): void;\n}\n\n// ============================================================================\n// StorageProvider — aggregate of all three primitives\n//\n// Adapter factories receive a StorageProvider and close over any scope (e.g.\n// boardDir) themselves. This is the single injection point for swapping\n// backends (Node fs → CosmosDB, browser localStorage, test doubles, etc.).\n// ============================================================================\n\nexport interface StorageProvider {\n blob: BlobStorage;\n journal: JournalStorage;\n kv: KVStorage;\n}\n\n// ============================================================================\n// AtomicRelayLock — non-blocking try-acquire lock with relay-on-busy semantics\n//\n// This interface serves TWO tightly coupled purposes which are intentionally\n// unified into a single primitive:\n//\n// 1. ATOMICITY — ensures that a read-mutate-save cycle is executed by at\n// most one actor at a time, preventing concurrent actors from racing on\n// stale state and writing conflicting snapshots.\n//\n// 2. RELAY SIGNAL — when tryAcquire() returns null, the caller knows the\n// cycle is already in progress. Because the holder always reads fresh\n// state upon entry, it will pick up every change appended by the skipping\n// caller before the lock was attempted. The caller can therefore safely\n// exit — its work will be completed by the holder. This is the\n// \"relay baton\" pattern: the lock being held IS the in-progress signal.\n//\n// These two purposes are not an accidental overload — they are the same\n// invariant expressed at different scopes. Any backend implementation\n// (FS lockfile, Cosmos document lease, Azure entity lock, in-memory flag)\n// that satisfies \"at most one holder at a time\" automatically satisfies both.\n//\n// Contract:\n// - tryAcquire() is non-blocking. It never waits.\n// - Returns a release function on success, or null if already held.\n// - The release function must be called exactly once (use try/finally).\n// - Behaviour after calling release() more than once is undefined.\n// ============================================================================\n\nexport interface AtomicRelayLock {\n /**\n * Attempt to acquire the lock without blocking.\n * Returns a `release` function if successful, or `null` if the lock is\n * already held by another actor (relay: that actor will complete the work).\n */\n tryAcquire(): (() => void) | null;\n}\n\n/**\n * Execute `work` under an `AtomicRelayLock`.\n *\n * - If the lock is busy, returns false immediately (relay: the holder will\n * complete the work on behalf of this caller).\n * - If acquired, runs `work` exclusively, releases the lock, then calls\n * `continuation` if provided — allowing the caller to schedule the next\n * cycle (e.g. spawn a detached process) after the lock is free.\n * - Returns true if work ran.\n */\nexport async function withRelayLock(\n lock: AtomicRelayLock,\n work: () => Promise<void>,\n continuation?: () => void,\n): Promise<boolean> {\n const release = lock.tryAcquire();\n if (!release) return false; // relay: holder is already doing the work\n try {\n await work();\n } finally {\n release(); // release before continuation so it can immediately re-acquire\n }\n continuation?.();\n return true;\n}\n","/**\n * process-runner.ts — Single source of truth for child process execution.\n *\n * All CLI execution paths (task-executor, source.cli, inference-adapter,\n * detached background workers) route through these helpers.\n *\n * DESIGN:\n * - CommandSpec is the structured command form: { command, args, cwd, env, timeoutMs }\n * - runSync / runAsync use execFileSync / execFile (no ambient shell)\n * - runDetached handles OS differences in one place\n * - parseCommandSpec reads both legacy string form and new { command, args } form\n *\n * WHY NO SHELL BY DEFAULT:\n * - Shell interpretation is platform-dependent (cmd.exe vs /bin/sh vs bash)\n * - Shell parsing of argument strings is fragile and platform-fragile\n * - execFile / execFileSync avoids all quoting and escaping issues\n *\n * BACKWARD COMPAT:\n * - parseCommandSpec(\"node my-tool.js --flag\") → { command: process.execPath, args: ['my-tool.js', '--flag'] }\n * - Legacy .task-executor / .inference-adapter / source.cli string values still load correctly\n */\n\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport * as net from 'node:net';\nimport { fileURLToPath } from 'node:url';\nimport { execFileSync, execFile, spawn } from 'node:child_process';\nimport { randomUUID, createHash } from 'node:crypto';\n\nimport type { CommandSpec } from '../../continuous-event-graph/handlers.js';\nimport type { KindValueRef } from '../common/storage-interface.js';\nimport { serializeRef } from '../common/storage-interface.js';\nexport type { CommandSpec };\n\n// ============================================================================\n// makeBoardTempFilePath — board-scoped temp file path for external process handoff\n// ============================================================================\n\n/**\n * Return a unique file path under `<boardDir>/.tmp/` suitable for passing\n * to an external binary (task-executor, inference-adapter) as `--in`, `--out`,\n * or `--err` arguments.\n *\n * - Files are co-located with the board they belong to (not global os.tmpdir()).\n * - The `.tmp/` directory is created on demand.\n * - The file itself is NOT created here — the caller writes it before use.\n * - `ext` defaults to `.json`; use `.txt` for plain-text error files.\n */\nexport function makeBoardTempFilePath(boardDir: string, label: string, ext = '.json'): string {\n const tmpDir = path.join(boardDir, '.tmp');\n fs.mkdirSync(tmpDir, { recursive: true });\n return path.join(tmpDir, `${label}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}${ext}`);\n}\n\n/** Join path segments — thin wrapper so callers don't need to import node:path. */\nexport function joinPath(...segments: string[]): string { return path.join(...segments); }\n\n/** Resolve a path to absolute — thin wrapper so callers don't need to import node:path. */\nexport function resolvePath(...segments: string[]): string { return path.resolve(...segments); }\n\n/** Return the directory name of a path. */\nexport function dirnamePath(p: string): string { return path.dirname(p); }\n\n/** Return true if the path is absolute. */\nexport function isAbsolutePath(p: string): boolean { return path.isAbsolute(p); }\n\n/** Generate a new random UUID. */\nexport function genUUID(): string { return randomUUID(); }\n\n/** SHA-256 hex hash of a string. */\nexport function getHash(x: string): string { return createHash('sha256').update(x).digest('hex'); }\n\n/** Resolve the directory of an ESM module from its import.meta.url. */\nexport function resolveModuleDir(importMetaUrl: string): string { return path.dirname(fileURLToPath(importMetaUrl)); }\n\n// ============================================================================\n// parseCommandSpec — legacy string or structured CommandSpec → normalized form\n// ============================================================================\n\n/**\n * Parse a legacy string command or pass through a structured CommandSpec.\n *\n * - Legacy string: \"node script.js --flag value\"\n * → { command: process.execPath, args: ['script.js', '--flag', 'value'] }\n *\n * - Structured: { command: 'node', args: ['script.js', '--flag', 'value'] }\n * → { command: process.execPath, args: ['script.js', '--flag', 'value'] }\n *\n * After parsing, 'node'/'node.exe' is resolved to process.execPath, and bare\n * '.js'/'.mjs' paths are wrapped in a node invocation.\n */\nexport function parseCommandSpec(raw: string | CommandSpec): CommandSpec {\n if (typeof raw === 'object' && raw !== null) {\n const { command, args = [], ...rest } = raw;\n const resolved = _resolveNode(command, args);\n return { ...rest, command: resolved.command, args: resolved.args };\n }\n const parts = splitCommandLine(raw);\n if (parts.length === 0) throw new Error(`Empty command spec: ${JSON.stringify(raw)}`);\n return _resolveNode(parts[0], parts.slice(1));\n}\n\nfunction _resolveNode(cmd: string, args: string[]): { command: string; args: string[] } {\n if (/^(node|node\\.exe)$/i.test(cmd)) return { command: process.execPath, args };\n if (/\\.m?js$/i.test(cmd)) return { command: process.execPath, args: [cmd, ...args] };\n return { command: cmd, args };\n}\n\n// ============================================================================\n// splitCommandLine — shell-style string splitting (legacy compat only)\n// ============================================================================\n\n/**\n * Split a shell-style command string into tokens, respecting single/double quotes.\n * Used only for backward-compat parsing of legacy string-format config values.\n */\nexport function splitCommandLine(command: string): string[] {\n const tokens: string[] = [];\n let current = '';\n let quote: '\"' | '\\'' | null = null;\n\n for (const ch of command.trim()) {\n if (quote) {\n if (ch === quote) { quote = null; } else { current += ch; }\n continue;\n }\n if (ch === '\"' || ch === '\\'') { quote = ch; continue; }\n if (/\\s/.test(ch)) {\n if (current) { tokens.push(current); current = ''; }\n continue;\n }\n current += ch;\n }\n\n if (quote) throw new Error(`Unterminated quote in command: ${command}`);\n if (current) tokens.push(current);\n return tokens;\n}\n\n// ============================================================================\n// .cmd/.bat on Windows needs shell: true\n// ============================================================================\n\nfunction _needsWindowsShell(cmd: string): boolean {\n return process.platform === 'win32' && /\\.(cmd|bat)$/i.test(cmd);\n}\n\n// ============================================================================\n// runSync — synchronous process execution\n// ============================================================================\n\n/**\n * Run a command synchronously and return stdout as a string.\n * Uses execFileSync — no ambient shell. Safe on all platforms.\n */\nexport function runSync(spec: CommandSpec, options?: { encoding?: BufferEncoding; input?: string }): string {\n const { command, args = [], cwd, env, timeoutMs } = spec;\n const output = execFileSync(command, args, {\n shell: _needsWindowsShell(command),\n timeout: timeoutMs,\n encoding: options?.encoding ?? 'utf-8',\n cwd,\n windowsHide: true,\n env: env ? { ...process.env, ...env } : undefined,\n input: options?.input,\n });\n return output as string;\n}\n\n// ============================================================================\n// runAsync — async process execution with callback\n// ============================================================================\n\n/**\n * Run a command asynchronously, calling back with (err, stdout, stderr).\n * Uses execFile — no ambient shell. Safe on all platforms.\n */\nexport function runAsync(\n spec: CommandSpec,\n callback: (err: Error | null, stdout: string, stderr: string) => void,\n): void {\n const { command, args = [], cwd, env, timeoutMs = 30_000 } = spec;\n execFile(\n command,\n args,\n {\n shell: _needsWindowsShell(command),\n encoding: 'utf8',\n windowsHide: true,\n timeout: timeoutMs,\n maxBuffer: 10 * 1024 * 1024,\n cwd,\n env: env ? { ...process.env, ...env } : undefined,\n },\n (err, stdout, stderr) => callback(err ?? null, stdout, stderr),\n );\n}\n\n// ============================================================================\n// Git Bash detection (Windows only — needed for runDetached)\n// ============================================================================\n\nlet _gitBashPath: string | false | undefined;\nconst _GIT_BASH_CACHE = path.join(os.tmpdir(), '.board-live-cards-git-bash-cache.json');\n\nexport function findGitBash(): string | false {\n if (_gitBashPath !== undefined) return _gitBashPath;\n if (process.platform !== 'win32') return (_gitBashPath = false);\n\n try {\n const cached = JSON.parse(fs.readFileSync(_GIT_BASH_CACHE, 'utf8')) as { path: string | false };\n if (cached.path === false || (typeof cached.path === 'string' && fs.existsSync(cached.path))) {\n return (_gitBashPath = cached.path);\n }\n } catch { /* cache miss */ }\n\n const candidates: Array<string | undefined> = [\n process.env.SHELL,\n process.env.PROGRAMFILES\n ? path.join(process.env.PROGRAMFILES, 'Git', 'usr', 'bin', 'bash.exe')\n : undefined,\n process.env.PROGRAMFILES\n ? path.join(process.env.PROGRAMFILES, 'Git', 'bin', 'bash.exe')\n : undefined,\n process.env['PROGRAMFILES(X86)']\n ? path.join(process.env['PROGRAMFILES(X86)']!, 'Git', 'bin', 'bash.exe')\n : undefined,\n process.env.LOCALAPPDATA\n ? path.join(process.env.LOCALAPPDATA, 'Programs', 'Git', 'bin', 'bash.exe')\n : undefined,\n ];\n\n for (const c of candidates) {\n if (c && /bash(\\.exe)?$/i.test(c) && fs.existsSync(c)) {\n _gitBashPath = c;\n try { fs.writeFileSync(_GIT_BASH_CACHE, JSON.stringify({ path: c })); } catch { /* best-effort */ }\n return _gitBashPath;\n }\n }\n\n _gitBashPath = false;\n try { fs.writeFileSync(_GIT_BASH_CACHE, JSON.stringify({ path: false })); } catch { /* best-effort */ }\n return _gitBashPath;\n}\n\nfunction _shellQuote(s: string): string {\n return \"'\" + s.replace(/'/g, \"'\\\\''\") + \"'\";\n}\n\n// ============================================================================\n// runDetached — fire-and-forget background spawn\n// ============================================================================\n\n/**\n * Spawn a detached background process that survives parent exit.\n * Handles Windows (Git Bash / cmd /c start /b) and Linux/macOS transparently.\n */\nexport function runDetached(spec: CommandSpec): void {\n const { command, args = [] } = spec;\n\n if (process.platform === 'win32') {\n const child = spawn(command, args, {\n detached: true,\n stdio: 'ignore',\n windowsHide: true,\n shell: _needsWindowsShell(command),\n });\n child.unref();\n return;\n }\n\n const child = spawn(command, args, { detached: true, stdio: 'ignore' });\n child.unref();\n}\n\n// ============================================================================\n// buildBoardCliInvocation — resolve how to invoke board-live-cards-cli\n//\n// cliDir is the directory containing board-live-cards-cli.ts / .js.\n// Probe order: compiled .js → tsx dev → npx tsx fallback.\n// ============================================================================\n\n/**\n * Return { cmd, args } that invokes `board-live-cards-cli <command> [...args]`\n * in whatever environment is available (compiled dist, dev tsx, npx fallback).\n *\n * Pass `__dirname` (from the calling file's own directory) as `cliDir`.\n */\nexport function buildBoardCliInvocation(\n cliDir: string,\n command: string,\n args: string[],\n): { cmd: string; args: string[] } {\n const jsPath = path.join(cliDir, 'board-live-cards-cli.js');\n if (fs.existsSync(jsPath)) {\n return { cmd: process.execPath, args: [jsPath, command, ...args] };\n }\n\n const tsPath = path.join(cliDir, 'board-live-cards-cli.ts');\n const tsxMjs = path.join(cliDir, '..', '..', 'node_modules', 'tsx', 'dist', 'cli.mjs');\n const tsxBin = path.join(cliDir, '..', '..', 'node_modules', '.bin', 'tsx');\n const tsx = fs.existsSync(tsxMjs) ? tsxMjs : tsxBin;\n if (fs.existsSync(tsPath) && fs.existsSync(tsx)) {\n return { cmd: process.execPath, args: [tsx, tsPath, command, ...args] };\n }\n\n const npxCmd = process.platform === 'win32' ? 'npx.cmd' : 'npx';\n return { cmd: npxCmd, args: ['tsx', tsPath, command, ...args] };\n}\n\n/**\n * Resolve a stable script path for callback-style invocations where the callee\n * only accepts `node <script> ...` (no separate runtime args like tsx).\n *\n * Prefer the repo wrapper when present because it can bridge src/dist modes.\n * Fall back to the compiled JS CLI entrypoint in cliDir when available.\n */\nexport function resolveBoardCliCallbackTarget(cliDir: string): string {\n // 3 levels up: dist/cli/node -> repo root (compiled mode)\n const repoBoardCliWrapper = path.join(cliDir, '..', '..', '..', 'board-live-cards-cli.js');\n if (fs.existsSync(repoBoardCliWrapper)) return repoBoardCliWrapper;\n\n // 2 levels up: tests/cli -> repo root (test/source mode)\n const repoBoardCliWrapper2 = path.join(cliDir, '..', '..', 'board-live-cards-cli.js');\n if (fs.existsSync(repoBoardCliWrapper2)) return repoBoardCliWrapper2;\n\n const jsPath = path.join(cliDir, 'board-live-cards-cli.js');\n if (fs.existsSync(jsPath)) return jsPath;\n\n throw new Error(\n `resolveBoardCliCallbackTarget: cannot find callback target in ${cliDir} ` +\n `(expected ../board-live-cards-cli.js wrapper or ${jsPath})`\n );\n}\n\n// ============================================================================\n// requestProcessAccumulatedDetached — fire-and-forget dispatch of next drain pass\n// ============================================================================\n\n/**\n * Spawn a detached board-live-cards process-accumulated-events pass for the given board.\n */\nexport function requestProcessAccumulatedDetached(cliDir: string, baseRef: KindValueRef, notifyChannel?: string): void {\n const cliArgs = ['--base-ref', serializeRef(baseRef)];\n if (notifyChannel) cliArgs.push('--notify-channel', notifyChannel);\n const { cmd, args } = buildBoardCliInvocation(cliDir, 'process-accumulated-events', cliArgs);\n runDetached({ command: cmd, args });\n}\n\n// ============================================================================\n// Named-pipe event transport (cross-process board notifications)\n// ============================================================================\n\n/** Return canonical named-pipe/socket path for the given channel name. */\nexport function getNamedPipePath(pipeName: string): string {\n if (process.platform === 'win32') return `\\\\\\\\.\\\\pipe\\\\${pipeName}`;\n return path.join(os.tmpdir(), `${pipeName}.sock`);\n}\n\n/**\n * Publish a batch of JSON notifications as newline-delimited records to a named pipe.\n * Best-effort: if the pipe is unavailable, logs via onWarn and drops the batch.\n *\n * All payloads are concatenated into a single `socket.write()` call so the consumer\n * receives them atomically (no interleaving from other drain cycles).\n * Uses a per-pipeName persistent connection so ordering is preserved across calls.\n */\nconst _pipeClients = new Map<string, { socket: net.Socket; ready: boolean; queue: string[] }>();\n\nexport function publishJsonEventsToNamedPipe(\n pipeName: string,\n payloads: unknown[],\n onWarn?: (msg: string) => void,\n): void {\n if (payloads.length === 0) return;\n const chunk = payloads.map(p => JSON.stringify(p)).join('\\n') + '\\n';\n let entry = _pipeClients.get(pipeName);\n\n if (entry && !entry.socket.destroyed) {\n if (entry.ready) {\n entry.socket.write(chunk);\n } else {\n entry.queue.push(chunk);\n }\n return;\n }\n\n // Create a new persistent connection\n const pipePath = getNamedPipePath(pipeName);\n const socket = net.createConnection(pipePath);\n entry = { socket, ready: false, queue: [chunk] };\n _pipeClients.set(pipeName, entry);\n\n socket.on('connect', () => {\n entry!.ready = true;\n for (const queued of entry!.queue) socket.write(queued);\n entry!.queue.length = 0;\n });\n\n socket.on('error', (e) => {\n onWarn?.(`[named-pipe publish] ${pipePath}: ${e instanceof Error ? e.message : String(e)}`);\n _pipeClients.delete(pipeName);\n });\n\n socket.on('close', () => {\n _pipeClients.delete(pipeName);\n });\n}\n\n// ============================================================================\n// createNodeCommandExecutor — Node implementation of CommandExecutor\n//\n// Wraps runSync / runAsync / runDetached / parseCommandSpec / splitCommandLine\n// into a single injectable object. Pass to command handlers instead of the\n// individual execCommandSync / execCommandAsync / resolveCommandInvocation /\n// splitCommandLine / spawnDetachedCommand dep functions.\n// ============================================================================\n\nimport type { CommandExecutor, ExecOptions } from '../common/process-interface.js';\n\nexport function createNodeCommandExecutor(): CommandExecutor {\n return {\n executeSync(cmd: string, args: string[], options?: ExecOptions): string {\n return runSync(\n { command: cmd, args, cwd: options?.cwd, timeoutMs: options?.timeout, env: options?.env as Record<string, string> | undefined },\n { encoding: options?.encoding as BufferEncoding | undefined, input: options?.input },\n );\n },\n executeAsync(cmd: string, args: string[], callback: (err: Error | null, stdout: string, stderr: string) => void): void {\n runAsync({ command: cmd, args }, callback);\n },\n resolveInvocation(rawCmd: string, rawArgs: string[]): { cmd: string; args: string[] } {\n const spec = parseCommandSpec({ command: rawCmd, args: rawArgs });\n return { cmd: spec.command, args: spec.args ?? [] };\n },\n splitCommand: splitCommandLine,\n spawnDetached(cmd: string, args: string[]): void {\n runDetached({ command: cmd, args });\n },\n };\n}\n","/**\n * cli/common/jsonata-loader — synchronous jsonata wrapper.\n *\n * Mirrors the loader pattern used by card-compute. Uses createRequire so the\n * vendored CommonJS sync build can be loaded from ESM. The canonical source\n * file is `src/card-compute/jsonata-sync.cjs`; the tsup post-build hook copies\n * it next to every dist bundle that references it.\n */\n\nimport { createRequire } from 'module';\n\nconst _require = createRequire(import.meta.url);\n\nexport type JsonataExpression = {\n evaluate: (data: unknown) => unknown;\n};\n\n// Source path resolves via the file's location at src/cli/common/.\n// Dist path resolves via the post-build copy that places jsonata-sync.cjs\n// alongside the bundled output (handled by tsup's copyJsonataSyncToDistDirs).\nfunction _loadJsonata(): (expr: string) => JsonataExpression {\n // Try sibling first (dist layout). If that fails, fall back to the canonical\n // source location (used when running TypeScript directly under vitest/tsx).\n try {\n return _require('./jsonata-sync.cjs');\n } catch {\n return _require('../../card-compute/jsonata-sync.cjs');\n }\n}\n\nexport const jsonata: (expr: string) => JsonataExpression = _loadJsonata();\n","/**\n * cli/common/args-massaging — JSONata-based mapping from logical args to\n * transport-specific shape.\n *\n * `argsMassaging` is a property of `ExecutionRef`, so honoring it is the job\n * of every adapter (Node spawn, HTTP, Azure Function, etc.). This helper is\n * the shared pure-JSONata implementation reused by all adapters.\n *\n * Adapters call this as the first step inside their `invokeRefSync` /\n * `dispatchExecution` implementation, then perform their transport using\n * `cmdArgs` / `body` / `url`.\n */\n\nimport { jsonata } from './jsonata-loader.js';\nimport type { ArgsMassaging, OutputTransforms } from './execution-interface.js';\nimport type { NormalizedHandlerResult } from '../../step-machine-public/types.js';\n\nexport interface MassagedArgs {\n /** Resolved argv tail for local transports. */\n cmdArgs?: string[];\n /** Resolved request body for http transports (or stdin payload for local). */\n body?: unknown;\n /** Resolved final URL string for http transports. */\n url?: string;\n}\n\n/**\n * Evaluate `argsMassaging` against the supplied context.\n *\n * Throws with a label-tagged message if any expression fails. Adapters\n * should catch and convert to a normalized failure result.\n */\nexport function resolveArgsMassaging(\n argsMassaging: ArgsMassaging | undefined,\n context: Record<string, unknown>,\n label: string,\n): MassagedArgs {\n if (!argsMassaging || typeof argsMassaging !== 'object') return {};\n\n const out: MassagedArgs = {};\n\n if (Array.isArray(argsMassaging.cmdTemplate)) {\n const resolved: string[] = [];\n for (const expr of argsMassaging.cmdTemplate) {\n try {\n resolved.push(String(jsonata(expr).evaluate(context)));\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(\n `[${label}] argsMassaging.cmdTemplate failed on \"${expr}\": ${msg}`,\n );\n }\n }\n out.cmdArgs = resolved;\n }\n\n if (typeof argsMassaging.bodyTemplate === 'string') {\n try {\n out.body = jsonata(argsMassaging.bodyTemplate).evaluate(context);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(\n `[${label}] argsMassaging.bodyTemplate failed: ${msg}`,\n );\n }\n }\n\n if (typeof argsMassaging.urlTemplate === 'string') {\n try {\n out.url = String(jsonata(argsMassaging.urlTemplate).evaluate(context));\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(\n `[${label}] argsMassaging.urlTemplate failed: ${msg}`,\n );\n }\n }\n\n return out;\n}\n\n/**\n * Apply `outputTransforms` to a raw invoke result.\n *\n * Context for all expressions: `{ output }` where `output` is the raw\n * { result, data, error? } envelope from invokeRefSync.\n *\n * Returns a new NormalizedHandlerResult with overrides applied.\n * Throws with a label-tagged message if any expression fails.\n */\nexport function resolveOutputTransforms(\n transforms: OutputTransforms | undefined,\n raw: NormalizedHandlerResult,\n label: string,\n): NormalizedHandlerResult {\n if (!transforms || typeof transforms !== 'object') return raw;\n\n const ctx = { output: raw };\n let result = raw.result;\n let data = raw.data;\n let error = raw.error;\n\n if (typeof transforms.resultExpr === 'string') {\n try {\n const val = jsonata(transforms.resultExpr).evaluate(ctx);\n if (typeof val !== 'string' || !val.trim()) {\n throw new Error(`resultExpr did not produce a non-empty string (got ${JSON.stringify(val)})`);\n }\n result = val;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(`[${label}] outputTransforms.resultExpr failed: ${msg}`);\n }\n }\n\n if (typeof transforms.dataTemplate === 'string') {\n try {\n const val = jsonata(transforms.dataTemplate).evaluate(ctx);\n if (!val || typeof val !== 'object' || Array.isArray(val)) {\n throw new Error(`dataTemplate did not produce an object (got ${JSON.stringify(val)})`);\n }\n data = val as Record<string, unknown>;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(`[${label}] outputTransforms.dataTemplate failed: ${msg}`);\n }\n }\n\n if (typeof transforms.errorExpr === 'string') {\n try {\n const val = jsonata(transforms.errorExpr).evaluate(ctx);\n // $undefined() evaluates to undefined — clears the error field\n error = val != null ? String(val) : undefined;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(`[${label}] outputTransforms.errorExpr failed: ${msg}`);\n }\n }\n\n return error !== undefined\n ? { result, data, error }\n : { result, data };\n}\n","/**\n * execution-adapter.ts\n *\n * Node.js-specific adapter that resolves an ExecutionRef + logical args\n * into a physical invocation (process spawn, HTTP request, or built-in call).\n *\n * This is the platform layer that pairs with execution-interface.ts (pure types).\n * Import this only from Node contexts — not from browser bundles.\n *\n * ────────────────────────────────────────────────────────────────────────────\n * WELL-KNOWN INVOCATION KINDS\n * ────────────────────────────────────────────────────────────────────────────\n *\n * invokeTaskExecutor(ref, args)\n * Standard task-executor protocol.\n * Logical args: { subcommand, inRef, outRef, errRef?, extra? }\n * Default cmdTemplate (local): ['subcommand', '--in-ref', inRef, '--out-ref', outRef, '--err-ref', errRef]\n * Default body (http): { subcommand, inRef, outRef, errRef }\n *\n * invokeBoardCliCallback(ref, args)\n * Back-channel from a task-executor to the board CLI.\n * Logical args: { command, argv[] }\n * Resolves 'built-in' to the board CLI script alongside cliDir.\n *\n * ────────────────────────────────────────────────────────────────────────────\n * BUILT-IN RESOLUTION\n * ────────────────────────────────────────────────────────────────────────────\n *\n * howToRun: 'built-in' with whatToRun: 'b64:<base64url({\"kind\":\"built-in\",\"value\":\"source-cli-task-executor\"})>'\n * → resolves to node <cliDir>/source-cli-task-executor.js\n *\n * howToRun: 'built-in' with whatToRun: 'b64:<base64url({\"kind\":\"built-in\",\"value\":\"board-live-cards\"})>'\n * → resolves to node <cliDir>/board-live-cards-cli.js (via buildBoardCliInvocation)\n *\n * ────────────────────────────────────────────────────────────────────────────\n * argsMassaging EVALUATION\n * ────────────────────────────────────────────────────────────────────────────\n *\n * Each argsMassaging field is a JSONata expression evaluated against the\n * logical args object merged with { whatToRun } (the address from the ref).\n *\n * If argsMassaging is absent, the adapter uses its default mapping.\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { spawnSync } from 'node:child_process';\nimport { createRequire } from 'module';\nconst _requireJsonata = createRequire(import.meta.url);\nconst jsonata: (expr: string) => { evaluate: (data: unknown) => unknown } = _requireJsonata('../../card-compute/jsonata-sync.cjs');\nimport type { ExecutionRef, ExecutionResult } from '../common/execution-interface.js';\nimport { parseRef, serializeRef } from '../common/storage-interface.js';\nimport { buildBoardCliInvocation, runSync, runDetached } from './process-runner.js';\n\n// ============================================================================\n// Logical args shapes for well-known invocation kinds\n// ============================================================================\n\n/** Logical args for invokeTaskExecutor — standard task-executor protocol. */\nexport interface TaskExecutorArgs {\n /** Subcommand to dispatch: 'run-source-fetch' | 'validate-source-def' | 'describe-capabilities' | ... */\n subcommand: string;\n /** Input ref (b64:<base64url(json)> wire form) pointing to the task payload. */\n inRef?: string;\n /** Output ref (b64:<base64url(json)> wire form) where the executor writes its result. */\n outRef?: string;\n /** Error ref (b64:<base64url(json)> wire form) for structured error output. */\n errRef?: string;\n}\n\n/** Logical args for invokeBoardCliCallback — back-channel from executor to board. */\nexport interface BoardCliCallbackArgs {\n /** Board CLI subcommand to invoke (e.g. 'source-data-fetched', 'source-data-fetch-failure'). */\n command: string;\n /** Additional argv strings passed after the command. */\n argv: string[];\n}\n\n// ============================================================================\n// ExecutionAdapterOptions\n// ============================================================================\n\n/**\n * Options passed when constructing an execution adapter.\n * Provides the platform-specific context needed for built-in resolution.\n */\nexport interface ExecutionAdapterOptions {\n /**\n * Absolute path to the directory containing the compiled CLI files.\n * Required for resolving 'built-in' refs (e.g. source-cli-task-executor.js,\n * board-live-cards-cli.js).\n */\n cliDir: string;\n}\n\n// ============================================================================\n// JSONata evaluation helper\n// ============================================================================\n\n/**\n * Evaluate a single JSONata expression against a context object.\n * Returns the result as-is (string, object, array, etc.).\n */\nasync function evalJsonata(expr: string, context: Record<string, unknown>): Promise<unknown> {\n const compiled = jsonata(expr);\n return compiled.evaluate(context);\n}\n\n/**\n * Evaluate a JSONata expression and coerce the result to a string.\n * Throws if the result is not a string.\n */\nasync function evalJsonataString(expr: string, context: Record<string, unknown>): Promise<string> {\n const result = await evalJsonata(expr, context);\n if (typeof result !== 'string') {\n throw new Error(`argsMassaging expression did not produce a string: ${expr} → ${JSON.stringify(result)}`);\n }\n return result;\n}\n\n// ============================================================================\n// Built-in ref resolution\n// ============================================================================\n\n/**\n * Resolve a 'built-in' ExecutionRef to a concrete { command, args } invocation.\n * The whatToRun value names the built-in implementation.\n *\n * Supported built-in names:\n * source-cli-task-executor → node <cliDir>/source-cli-task-executor.js\n * board-live-cards → node <cliDir>/board-live-cards-cli.js (via buildBoardCliInvocation)\n */\nfunction resolveBuiltIn(whatToRun: string | { kind: string; value: string }, cliDir: string): { command: string; args: string[] } {\n // whatToRun must be a b64 KindValueRef string or a plain-object ref\n const name = typeof whatToRun === 'object' ? whatToRun.value : parseRef(whatToRun).value;\n\n switch (name) {\n case 'source-cli-task-executor': {\n const jsPath = path.join(cliDir, 'source-cli-task-executor.js');\n if (fs.existsSync(jsPath)) {\n return { command: process.execPath, args: [jsPath] };\n }\n const tsPath = path.join(cliDir, 'source-cli-task-executor.ts');\n const tsxMjs = path.join(cliDir, '..', '..', 'node_modules', 'tsx', 'dist', 'cli.mjs');\n const tsxBin = path.join(cliDir, '..', '..', 'node_modules', '.bin', 'tsx');\n const tsx = fs.existsSync(tsxMjs) ? tsxMjs : tsxBin;\n if (fs.existsSync(tsPath) && fs.existsSync(tsx)) {\n return { command: process.execPath, args: [tsx, tsPath] };\n }\n return { command: process.execPath, args: [jsPath] }; // fallback — will fail with clear error\n }\n case 'board-live-cards': {\n const { cmd, args } = buildBoardCliInvocation(cliDir, '_', []);\n return { command: cmd, args };\n }\n default:\n throw new Error(`resolveBuiltIn: unknown built-in name \"${name}\". Supported: source-cli-task-executor, board-live-cards`);\n }\n}\n\n/**\n * Resolve an ExecutionRef's whatToRun + howToRun to a base { command, args }\n * for local transports, or a URL string for http transports.\n */\nfunction resolveBaseInvocation(\n ref: ExecutionRef,\n cliDir: string,\n): { command: string; baseArgs: string[] } {\n if (ref.howToRun === 'built-in') {\n const { command, args } = resolveBuiltIn(ref.whatToRun, cliDir);\n return { command, baseArgs: args };\n }\n\n // For local-* transports, resolve the whatToRun as a KindValueRef\n const scriptPath: string = typeof ref.whatToRun === 'object'\n ? ref.whatToRun.value\n : parseRef(ref.whatToRun).value;\n\n switch (ref.howToRun) {\n case 'local-node':\n return { command: process.execPath, baseArgs: [scriptPath] };\n case 'local-python': {\n const python = process.platform === 'win32' ? 'python' : 'python3';\n return { command: python, baseArgs: [scriptPath] };\n }\n case 'local-process':\n return { command: scriptPath, baseArgs: [] };\n default:\n throw new Error(`resolveBaseInvocation: howToRun \"${ref.howToRun}\" is not a local transport`);\n }\n}\n\n// ============================================================================\n// Default arg mappings per invocation kind\n// ============================================================================\n\n/**\n * Build the default argv for a task-executor invocation (local transports).\n * Protocol: <subcommand> [--in-ref <inRef>] [--out-ref <outRef>] [--err-ref <errRef>] [--extra <base64>]\n *\n * @param extra Opaque executor config from ExecutionRef.extra — base64-encoded before passing.\n */\nfunction buildDefaultTaskExecutorArgv(\n args: TaskExecutorArgs,\n extra?: Record<string, unknown>,\n): string[] {\n const argv: string[] = [args.subcommand];\n if (args.inRef) argv.push('--in-ref', args.inRef);\n if (args.outRef) argv.push('--out-ref', args.outRef);\n if (args.errRef) argv.push('--err-ref', args.errRef);\n if (extra) argv.push('--extra', Buffer.from(JSON.stringify(extra)).toString('base64'));\n return argv;\n}\n\n/**\n * Build the default HTTP body for a task-executor invocation.\n *\n * @param extra Opaque executor config from ExecutionRef.extra — passed as-is in the body.\n */\nfunction buildDefaultTaskExecutorBody(\n args: TaskExecutorArgs,\n extra?: Record<string, unknown>,\n): Record<string, unknown> {\n return {\n subcommand: args.subcommand,\n ...(args.inRef ? { inRef: args.inRef } : {}),\n ...(args.outRef ? { outRef: args.outRef } : {}),\n ...(args.errRef ? { errRef: args.errRef } : {}),\n ...(extra ? { extra } : {}),\n };\n}\n\n// ============================================================================\n// buildLocalBaseSpec — sync helper for callers that stay synchronous\n// ============================================================================\n\n/**\n * Resolve an ExecutionRef to its base { command, baseArgs } for local transports.\n *\n * Exported for callers that need to stay synchronous (e.g. validate-source-def,\n * describe-capabilities) and build their own final argv.\n * Does NOT evaluate argsMassaging — append custom argv after baseArgs.\n *\n * @example\n * const { command, baseArgs } = buildLocalBaseSpec(teRef, cliDir);\n * executor.executeSync(command, [...baseArgs, 'describe-capabilities'], { timeout: 10_000 });\n */\nexport function buildLocalBaseSpec(\n ref: ExecutionRef,\n cliDir: string,\n): { command: string; baseArgs: string[] } {\n return resolveBaseInvocation(ref, cliDir);\n}\n\n// ============================================================================\n// invokeRefSync — synchronous request/reply for ref-based invocations\n// ============================================================================\n\nimport { resolveArgsMassaging } from '../common/args-massaging.js';\nimport { createNodeCommandExecutor } from './process-runner.js';\n\n/** Normalized envelope returned by invokeRefSync. */\nexport interface InvokeRefResult {\n /** Outcome key — drives transitions in the step machine ('success' | 'failure' | custom). */\n result: string;\n /** Response payload as a record (always object-shaped; raw stdout wrapped under `stdout` if not JSON object). */\n data: Record<string, unknown>;\n /** Optional human-readable error detail. */\n error?: string;\n}\n\nexport interface InvokeRefSyncOptions {\n /** Directory used to resolve `built-in` refs (defaults to ref's cwd / process cwd). */\n cliDir?: string;\n /** Working directory for the spawned child (default: process cwd). */\n cwd?: string;\n /** Timeout in milliseconds (default: 30_000). */\n timeoutMs?: number;\n /** Label used in error messages (default: 'invokeRefSync'). */\n label?: string;\n}\n\nfunction _parseStdoutAsJson(stdout: string): unknown {\n const trimmed = stdout.trim();\n if (!trimmed) throw new Error('empty stdout');\n try {\n return JSON.parse(trimmed);\n } catch {\n const lines = trimmed.split(/\\r?\\n/).filter(Boolean);\n const last = lines[lines.length - 1];\n return JSON.parse(last);\n }\n}\n\n/**\n * Invoke an ExecutionRef synchronously with a request/reply contract.\n *\n * Used by:\n * - step-machine ref steps (each step's handler dispatches through here)\n * - any utility that needs sync request/reply against an ExecutionRef\n *\n * Behavior:\n * 1. Resolve `ref.argsMassaging` against `args` to get cmdArgs / body.\n * 2. Build the local base spec (node/python/process + script path).\n * 3. Spawn synchronously with `JSON.stringify(body ?? args)` on stdin.\n * 4. Map exit code into envelope:\n * exit 0 → { result: 'success', data: parsed-stdout-or-{stdout: raw} }\n * non-0 → { result: 'failure', data: { error: stderr-or-exit-detail } }\n *\n * The framework (engine) never inspects payload shape; it only routes on `result`.\n */\nexport function invokeRefSync(\n ref: ExecutionRef,\n args: Record<string, unknown>,\n options?: InvokeRefSyncOptions,\n): InvokeRefResult {\n const label = options?.label ?? 'invokeRefSync';\n const cliDir = options?.cliDir ?? options?.cwd ?? process.cwd();\n\n let massaged;\n try {\n massaged = resolveArgsMassaging(ref.argsMassaging, args, label);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return { result: 'failure', data: { error: msg } };\n }\n\n let baseSpec;\n try {\n baseSpec = buildLocalBaseSpec(ref, cliDir);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return { result: 'failure', data: { error: `[${label}] ref resolution failed: ${msg}` } };\n }\n\n const argv = [...baseSpec.baseArgs, ...(massaged.cmdArgs ?? [])];\n const stdinPayload = JSON.stringify(massaged.body ?? args);\n const executor = createNodeCommandExecutor();\n\n let stdout: string;\n try {\n stdout = executor.executeSync(baseSpec.command, argv, {\n timeout: options?.timeoutMs ?? 30_000,\n encoding: 'utf-8',\n cwd: options?.cwd,\n input: stdinPayload,\n });\n } catch (err) {\n // execFileSync throws on non-zero exit / spawn error / timeout.\n const e = err as NodeJS.ErrnoException & { stderr?: Buffer | string; status?: number | null };\n const stderr = (e.stderr ? String(e.stderr) : '').trim();\n const status = typeof e.status === 'number' ? e.status : 'unknown';\n const detail = stderr || e.message;\n return {\n result: 'failure',\n data: { error: `[${label}] ref exited with status ${status}${detail ? `: ${detail}` : ''}` },\n };\n }\n\n // Transport succeeded (exit 0). Wrap stdout as data unconditionally.\n try {\n const parsed = _parseStdoutAsJson(stdout);\n const data: Record<string, unknown> =\n parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : { stdout: parsed };\n return { result: 'success', data };\n } catch {\n return { result: 'success', data: { stdout: stdout.trim() } };\n }\n}\n\n// ============================================================================\n// createExecutionAdapter — factory\n// ============================================================================\n\nexport interface ExecutionAdapter {\n /**\n * Invoke a task-executor using the standard protocol.\n * Dispatches based on howToRun; applies argsMassaging if present, otherwise\n * uses the default task-executor protocol (--in-ref / --out-ref / --err-ref).\n */\n invokeTaskExecutor(ref: ExecutionRef, args: TaskExecutorArgs): Promise<ExecutionResult>;\n\n /**\n * Invoke the board CLI as a back-channel callback.\n * Used by task-executors to report source-data-fetched / source-data-fetch-failure.\n * Resolves 'built-in::board-live-cards' to the board CLI script alongside cliDir.\n */\n invokeBoardCliCallback(ref: ExecutionRef, args: BoardCliCallbackArgs): ExecutionResult;\n}\n\n/**\n * Create an ExecutionAdapter bound to a specific cliDir.\n *\n * @param options.cliDir Absolute path to the compiled CLI directory.\n * Used to resolve 'built-in' refs.\n */\nexport function createExecutionAdapter(options: ExecutionAdapterOptions): ExecutionAdapter {\n const { cliDir } = options;\n\n return {\n async invokeTaskExecutor(ref: ExecutionRef, args: TaskExecutorArgs): Promise<ExecutionResult> {\n const isHttp = ref.howToRun === 'http:post' || ref.howToRun === 'http:get';\n\n if (isHttp) {\n return _invokeTaskExecutorHttp(ref, args);\n }\n\n // Local transports: local-node, local-python, local-process, built-in\n const { command, baseArgs } = resolveBaseInvocation(ref, cliDir);\n\n let callArgv: string[];\n if (ref.argsMassaging?.cmdTemplate) {\n // Evaluate each JSONata expression in the template\n const context: Record<string, unknown> = { ...args, whatToRun: ref.whatToRun };\n const evaluated = await Promise.all(\n ref.argsMassaging.cmdTemplate.map(expr => evalJsonataString(expr, context)),\n );\n callArgv = evaluated;\n } else {\n callArgv = buildDefaultTaskExecutorArgv(args, ref.extra);\n }\n\n const finalArgs = [...baseArgs, ...callArgv];\n try {\n runSync({ command, args: finalArgs });\n return { status: 'success' };\n } catch (err) {\n return { status: 'error', error: err instanceof Error ? err.message : String(err) };\n }\n },\n\n invokeBoardCliCallback(ref: ExecutionRef, args: BoardCliCallbackArgs): ExecutionResult {\n // Resolve the board CLI invocation\n let cmd: string;\n let baseArgs: string[];\n\n if (ref.howToRun === 'built-in') {\n const resolved = buildBoardCliInvocation(cliDir, args.command, args.argv);\n // buildBoardCliInvocation already includes the command and argv\n const result = spawnSync(resolved.cmd, resolved.args, { encoding: 'utf-8', windowsHide: true });\n if (result.status !== 0) {\n return { status: 'error', error: `board CLI exited ${result.status}: ${result.stderr?.trim()}` };\n }\n return { status: 'success' };\n }\n\n ({ command: cmd, baseArgs } = resolveBaseInvocation(ref, cliDir));\n const result = spawnSync(cmd, [...baseArgs, args.command, ...args.argv], {\n encoding: 'utf-8',\n windowsHide: true,\n });\n if (result.status !== 0) {\n return { status: 'error', error: `board CLI exited ${result.status}: ${result.stderr?.trim()}` };\n }\n return { status: 'success' };\n },\n };\n}\n\n// ============================================================================\n// HTTP transport (async — used for http:post / http:get)\n// ============================================================================\n\nasync function _invokeTaskExecutorHttp(\n ref: ExecutionRef,\n args: TaskExecutorArgs,\n): Promise<ExecutionResult> {\n let url: string;\n let body: Record<string, unknown>;\n\n const context: Record<string, unknown> = { ...args, whatToRun: ref.whatToRun };\n\n if (ref.argsMassaging?.urlTemplate) {\n url = await evalJsonataString(ref.argsMassaging.urlTemplate, context);\n } else {\n // Resolve whatToRun as a KindValueRef (object or b64 string)\n url = typeof ref.whatToRun === 'object' ? ref.whatToRun.value : parseRef(ref.whatToRun).value;\n }\n\n if (ref.argsMassaging?.bodyTemplate) {\n const evaluated = await evalJsonata(ref.argsMassaging.bodyTemplate, context);\n if (typeof evaluated !== 'object' || evaluated === null) {\n throw new Error(`bodyTemplate must produce an object, got: ${JSON.stringify(evaluated)}`);\n }\n body = evaluated as Record<string, unknown>;\n } else {\n body = buildDefaultTaskExecutorBody(args, ref.extra);\n }\n\n // Use native fetch (Node 18+)\n const response = await fetch(url, {\n method: ref.howToRun === 'http:get' ? 'GET' : 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n return { status: 'error', error: `HTTP ${response.status}: ${text}` };\n }\n\n const responseJson = await response.json().catch(() => null) as Record<string, unknown> | null;\n if (responseJson && typeof responseJson.status === 'string') {\n return responseJson as unknown as ExecutionResult;\n }\n return { status: 'success' };\n}\n\n// ============================================================================\n// Well-known ExecutionRef factories\n// ============================================================================\n\n/**\n * Create an ExecutionRef for the built-in source-cli task executor.\n * Resolves to node <cliDir>/source-cli-task-executor.js at runtime.\n */\nexport function builtInSourceCliExecutorRef(): ExecutionRef {\n return {\n meta: 'task-executor',\n howToRun: 'built-in',\n whatToRun: serializeRef({ kind: 'built-in', value: 'source-cli-task-executor' }),\n };\n}\n\n/**\n * Create an ExecutionRef for the board CLI callback back-channel.\n * Resolves to node <cliDir>/board-live-cards-cli.js at runtime.\n */\nexport function builtInBoardCliRef(): ExecutionRef {\n return {\n meta: 'board-live-cards',\n howToRun: 'built-in',\n whatToRun: serializeRef({ kind: 'built-in', value: 'board-live-cards' }),\n };\n}\n\n/**\n * Create an ExecutionRef for a local Node.js task executor script.\n *\n * @param scriptPath Absolute path to the executor .js file.\n */\nexport function localNodeExecutorRef(scriptPath: string): ExecutionRef {\n return {\n meta: 'task-executor',\n howToRun: 'local-node',\n whatToRun: serializeRef({ kind: 'fs-path', value: scriptPath }),\n };\n}\n\n// ============================================================================\n// Detached task-executor dispatch\n// ============================================================================\n\n/**\n * Dispatch a task-executor invocation as a detached background process.\n * Used by the board source-fetch dispatcher — fire-and-forget.\n *\n * For http transports, falls back to synchronous fetch (not truly detached).\n */\nexport function dispatchTaskExecutorDetached(\n ref: ExecutionRef,\n args: TaskExecutorArgs,\n cliDir: string,\n): void {\n const isHttp = ref.howToRun === 'http:post' || ref.howToRun === 'http:get';\n if (isHttp) {\n // For HTTP, we can't easily detach — fire async and ignore result\n void _invokeTaskExecutorHttp(ref, args).catch(err => {\n console.error(`[dispatchTaskExecutorDetached] HTTP dispatch failed: ${(err as Error).message}`);\n });\n return;\n }\n\n const { command, baseArgs } = resolveBaseInvocation(ref, cliDir);\n const callArgv = buildDefaultTaskExecutorArgv(args, ref.extra);\n runDetached({ command, args: [...baseArgs, ...callArgv] });\n}\n"]}
|