yaml-flow 8.5.2 → 8.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/browser/asset-integrity.json +3 -3
  2. package/examples/board/demo-shell-with-server.html +2 -2
  3. package/examples/board/doc.html +2 -2
  4. package/examples/board/server/board-server.js +266 -5
  5. package/examples/board/server/board-worker/task-executor.js +166 -51
  6. package/examples/board/server/chat-flow/copilot-chat/assistant.js +25 -12
  7. package/examples/board/server/chat-flow/copilot-chat/probe.js +7 -0
  8. package/examples/board/server/chat-flow/copilot-chat/shared.js +97 -0
  9. package/examples/board/server/chat-flow/flow-steps.json +109 -51
  10. package/examples/board/server-config.json +1 -0
  11. package/examples/board/test/server-http-test.js +870 -67
  12. package/examples/board-local/demo-shell-localstorage.html +3 -3
  13. package/lib/{artifacts-store-lib-D-k-E8Vy.d.ts → artifacts-store-lib-C1rtrkxm.d.ts} +1 -1
  14. package/lib/{artifacts-store-lib-CVgtQrNZ.d.cts → artifacts-store-lib-CLOtsiav.d.cts} +1 -1
  15. package/lib/artifacts-store-public.cjs +1 -1
  16. package/lib/artifacts-store-public.d.cts +3 -3
  17. package/lib/artifacts-store-public.d.ts +3 -3
  18. package/lib/artifacts-store-public.js +1 -1
  19. package/lib/batch/index.cjs +1 -1
  20. package/lib/batch/index.js +1 -1
  21. package/lib/board-live-cards-mcp.cjs +1 -1
  22. package/lib/board-live-cards-mcp.d.cts +36 -16
  23. package/lib/board-live-cards-mcp.d.ts +36 -16
  24. package/lib/board-live-cards-mcp.js +1 -1
  25. package/lib/board-live-cards-node.cjs +8 -16
  26. package/lib/board-live-cards-node.d.cts +32 -12
  27. package/lib/board-live-cards-node.d.ts +32 -12
  28. package/lib/board-live-cards-node.js +8 -16
  29. package/lib/{board-live-cards-public-BGS22cMb.d.ts → board-live-cards-public-CBVjm327.d.ts} +59 -24
  30. package/lib/{board-live-cards-public-B13InXhC.d.cts → board-live-cards-public-CPJy-aGW.d.cts} +59 -24
  31. package/lib/board-live-cards-public.cjs +1 -2
  32. package/lib/board-live-cards-public.d.cts +2 -2
  33. package/lib/board-live-cards-public.d.ts +2 -2
  34. package/lib/board-live-cards-public.js +1 -2
  35. package/lib/board-live-cards-server-runtime.cjs +1 -7
  36. package/lib/board-live-cards-server-runtime.d.cts +5 -5
  37. package/lib/board-live-cards-server-runtime.d.ts +5 -5
  38. package/lib/board-live-cards-server-runtime.js +1 -7
  39. package/lib/board-livegraph-runtime/index.cjs +1 -2
  40. package/lib/board-livegraph-runtime/index.js +1 -2
  41. package/lib/board-worker-adapter.cjs +21 -7
  42. package/lib/board-worker-adapter.d.cts +17 -2
  43. package/lib/board-worker-adapter.d.ts +17 -2
  44. package/lib/board-worker-adapter.js +21 -7
  45. package/lib/card-compute/index.cjs +1 -9
  46. package/lib/card-compute/index.js +1 -9
  47. package/lib/card-store-public.cjs +1 -1
  48. package/lib/card-store-public.d.cts +2 -2
  49. package/lib/card-store-public.d.ts +2 -2
  50. package/lib/card-store-public.js +1 -1
  51. package/lib/card-validation.cjs +1 -9
  52. package/lib/card-validation.js +1 -9
  53. package/lib/{chat-storage-lib-CJn7a6OH.d.ts → chat-storage-lib-Bce-xx6l.d.ts} +1 -1
  54. package/lib/{chat-storage-lib-0imhRX3l.d.cts → chat-storage-lib-CKylihjm.d.cts} +1 -1
  55. package/lib/chat-store-public.cjs +1 -1
  56. package/lib/chat-store-public.d.cts +3 -3
  57. package/lib/chat-store-public.d.ts +3 -3
  58. package/lib/chat-store-public.js +1 -1
  59. package/lib/chunk-2MZUYY65.cjs +2 -0
  60. package/lib/chunk-5DB54ZX2.cjs +2 -0
  61. package/lib/chunk-5EA2ESS4.cjs +16 -0
  62. package/lib/chunk-6APH25VI.js +2 -0
  63. package/lib/chunk-76ON3V7R.js +2 -0
  64. package/lib/chunk-7BKNHFNH.js +2 -0
  65. package/lib/chunk-CWREBRXS.js +3 -0
  66. package/lib/chunk-DAXACY63.js +2 -0
  67. package/lib/chunk-FW4363Y4.js +2 -0
  68. package/lib/chunk-FZ2SBU5M.js +3 -0
  69. package/lib/chunk-G4XXRHL2.cjs +3 -0
  70. package/lib/chunk-GNFE24S7.cjs +2 -0
  71. package/lib/chunk-GYQXDNNI.cjs +2 -0
  72. package/lib/chunk-H5KD3JPY.cjs +2 -0
  73. package/lib/chunk-HLJH7LGW.js +16 -0
  74. package/lib/chunk-I4WH5U5D.cjs +2 -0
  75. package/lib/chunk-IXZG74EW.cjs +2 -0
  76. package/lib/chunk-JAL25FGA.cjs +2 -0
  77. package/lib/chunk-JM5EKT57.js +2 -0
  78. package/lib/chunk-JMDHDY6M.js +2 -0
  79. package/lib/chunk-KBELAKIY.js +2 -0
  80. package/lib/chunk-KHJABJ45.cjs +3 -0
  81. package/lib/chunk-KLRUISRY.cjs +2 -0
  82. package/lib/chunk-KNFFDVLD.cjs +2 -0
  83. package/lib/chunk-LBMEVV4U.js +2 -0
  84. package/lib/chunk-LDAP75GN.js +2 -0
  85. package/lib/chunk-LODXIALE.cjs +2 -0
  86. package/lib/chunk-LVNQCE5X.cjs +3 -0
  87. package/lib/chunk-M7EQRS6W.js +3 -0
  88. package/lib/chunk-MNEOJWPS.js +10 -0
  89. package/lib/chunk-NJJ7WEDT.cjs +2 -0
  90. package/lib/chunk-NMZ6XNLB.cjs +3 -0
  91. package/lib/chunk-OPNGCSXJ.js +2 -0
  92. package/lib/chunk-P64UKI3L.cjs +8 -0
  93. package/lib/chunk-P7ZCDICS.cjs +2 -0
  94. package/lib/chunk-Q6H7NINN.cjs +5 -0
  95. package/lib/chunk-Q6VSL327.js +8 -0
  96. package/lib/chunk-QWBNDVUA.js +5 -0
  97. package/lib/chunk-S6DRP2HX.cjs +2 -0
  98. package/lib/chunk-UJ7ZTV4J.cjs +10 -0
  99. package/lib/chunk-UVE65IPR.cjs +3 -0
  100. package/lib/chunk-VCCTAUIG.js +2 -0
  101. package/lib/chunk-VGT3TRQG.js +3 -0
  102. package/lib/chunk-VLBB3D6B.js +3 -0
  103. package/lib/chunk-WDPOGXTY.js +2 -0
  104. package/lib/chunk-X3LC4LII.js +2 -0
  105. package/lib/chunk-YGKDQLYP.js +2 -0
  106. package/lib/chunk-YMEIPKLW.cjs +2 -0
  107. package/lib/config/index.cjs +1 -1
  108. package/lib/config/index.js +1 -1
  109. package/lib/continuous-event-graph/index.cjs +1 -2
  110. package/lib/continuous-event-graph/index.js +1 -2
  111. package/lib/event-graph/index.cjs +1 -22
  112. package/lib/event-graph/index.js +1 -22
  113. package/lib/execution-refs.cjs +1 -2
  114. package/lib/execution-refs.d.cts +3 -2
  115. package/lib/execution-refs.d.ts +3 -2
  116. package/lib/execution-refs.js +1 -2
  117. package/lib/index.cjs +2 -24
  118. package/lib/index.d.cts +1 -1
  119. package/lib/index.d.ts +1 -1
  120. package/lib/index.js +2 -24
  121. package/lib/server-runtime/index.cjs +1 -7
  122. package/lib/server-runtime/index.d.cts +6 -6
  123. package/lib/server-runtime/index.d.ts +6 -6
  124. package/lib/server-runtime/index.js +1 -7
  125. package/lib/step-machine/index.cjs +1 -11
  126. package/lib/step-machine/index.js +1 -11
  127. package/lib/step-machine-public/index.cjs +1 -4
  128. package/lib/step-machine-public/index.d.cts +1 -1
  129. package/lib/step-machine-public/index.d.ts +1 -1
  130. package/lib/step-machine-public/index.js +1 -4
  131. package/lib/{storage-interface-B2WD9D5n.d.cts → storage-interface-Ct-C4tlz.d.cts} +28 -1
  132. package/lib/{storage-interface-B2WD9D5n.d.ts → storage-interface-Ct-C4tlz.d.ts} +28 -1
  133. package/lib/stores/index.cjs +1 -2
  134. package/lib/stores/index.d.cts +1 -1
  135. package/lib/stores/index.d.ts +1 -1
  136. package/lib/stores/index.js +1 -2
  137. package/lib/stores/kv.cjs +1 -2
  138. package/lib/stores/kv.d.cts +1 -1
  139. package/lib/stores/kv.d.ts +1 -1
  140. package/lib/stores/kv.js +1 -2
  141. package/lib/stores/memory.cjs +1 -1
  142. package/lib/stores/memory.js +1 -1
  143. package/lib/{types-30R357js.d.ts → types-BuK2UMxk.d.ts} +4 -4
  144. package/lib/{types-CIgsh56O.d.cts → types-DRl0Hy_p.d.cts} +4 -4
  145. package/package.json +2 -16
  146. package/cli/board-live-cards-lib-COi4bSpk.d.ts +0 -322
  147. package/cli/browser-api/board-live-cards-browser-adapter.d.ts +0 -36
  148. package/cli/browser-api/board-live-cards-browser-adapter.js +0 -4
  149. package/cli/browser-api/card-store-browser-api.d.ts +0 -25
  150. package/cli/browser-api/card-store-browser-api.js +0 -2
  151. package/cli/browser-api/jsonata-sync.cjs +0 -7623
  152. package/cli/bundled/artifacts-store-cli.mjs +0 -12
  153. package/cli/bundled/batch-runner-cli.mjs +0 -3
  154. package/cli/bundled/board-live-cards-cli.mjs +0 -29
  155. package/cli/bundled/card-store-cli.mjs +0 -154
  156. package/cli/bundled/chat-store-cli.mjs +0 -16
  157. package/cli/bundled/jsonata-sync.cjs +0 -7623
  158. package/cli/bundled/step-machine-cli.mjs +0 -150
  159. package/cli/execution-interface-BCIhu1gO.d.ts +0 -442
  160. package/cli/types-H3EMBPY2.d.ts +0 -398
  161. package/examples/board/server/README-mcp-api.md +0 -680
  162. package/examples/board/test/server-http-mcp-test.js +0 -1163
  163. package/lib/board-livegraph-runtime/jsonata-sync.cjs +0 -7623
  164. package/lib/card-compute/jsonata-sync.cjs +0 -7623
  165. package/lib/continuous-event-graph/jsonata-sync.cjs +0 -7623
  166. package/lib/server-runtime/jsonata-sync.cjs +0 -7623
@@ -1,10 +1,10 @@
1
1
  {
2
- "generatedAt": "2026-05-28T18:29:20.093Z",
2
+ "generatedAt": "2026-05-31T10:04:54.839Z",
3
3
  "algorithm": "sha256",
4
4
  "files": {
5
5
  "browser/board-livecards-localstorage.js": {
6
- "sha256": "sha256-ukHGdsDK8ytpOVMNh82v3OUUtYThohkEWbgGlROvO6s=",
7
- "bytes": 144037
6
+ "sha256": "sha256-ZsTMRbMZNr915issy2horB25TVTwUCI35oGGZ8vWF7k=",
7
+ "bytes": 153257
8
8
  },
9
9
  "browser/live-cards.schema.json": {
10
10
  "sha256": "sha256-F5nfqDzZ5L3p0lLTMxGt4YtMa2sVzdNPh8sbQ8OiXHE=",
@@ -19,8 +19,8 @@
19
19
  <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
20
20
  <script src="https://cdn.jsdelivr.net/npm/dompurify/dist/purify.min.js"></script>
21
21
  <script src="https://cdn.jsdelivr.net/npm/leader-line/leader-line.min.js"></script>
22
- <script src="https://cdn.jsdelivr.net/npm/yaml-flow@8.5.2/browser/live-cards.js"></script>
23
- <script src="https://cdn.jsdelivr.net/npm/yaml-flow@8.5.2/browser/board-livecards-client.js"></script>
22
+ <script src="https://cdn.jsdelivr.net/npm/yaml-flow@8.6.1/browser/live-cards.js"></script>
23
+ <script src="https://cdn.jsdelivr.net/npm/yaml-flow@8.6.1/browser/board-livecards-client.js"></script>
24
24
  </head>
25
25
  <body class="bg-light">
26
26
  <div class="container-fluid py-3">
@@ -37,8 +37,8 @@
37
37
  <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
38
38
  <script src="https://cdn.jsdelivr.net/npm/dompurify/dist/purify.min.js"></script>
39
39
  <script src="https://cdn.jsdelivr.net/npm/leader-line/leader-line.min.js"></script>
40
- <script src="https://cdn.jsdelivr.net/npm/yaml-flow@8.5.2/browser/live-cards.js"></script>
41
- <script src="https://cdn.jsdelivr.net/npm/yaml-flow@8.5.2/browser/board-livecards-client.js"></script>
40
+ <script src="https://cdn.jsdelivr.net/npm/yaml-flow@8.6.1/browser/live-cards.js"></script>
41
+ <script src="https://cdn.jsdelivr.net/npm/yaml-flow@8.6.1/browser/board-livecards-client.js"></script>
42
42
  </head>
43
43
  <body class="bg-light">
44
44
  <div class="container-fluid py-3">
@@ -6,7 +6,7 @@ import path from 'node:path';
6
6
  import net from 'node:net';
7
7
  import os from 'node:os';
8
8
  import { spawn } from 'node:child_process';
9
- import { fileURLToPath } from 'node:url';
9
+ import { fileURLToPath, pathToFileURL } from 'node:url';
10
10
 
11
11
  import {
12
12
  createMultiBoardServerRuntime,
@@ -23,8 +23,11 @@ import {
23
23
  evaluateArgsMassaging,
24
24
  invokeExecutionRef,
25
25
  parseRef,
26
+ registerInProcessExecutionHandler,
27
+ startBoardWorkerQueueRunner,
26
28
  serializeRef,
27
29
  } from 'yaml-flow/board-live-cards-node';
30
+ import { registerInProcessBoardWorkerCallback } from 'yaml-flow/board-worker-adapter';
28
31
  import {
29
32
  createStepMachineChatFlowRunner,
30
33
  } from 'yaml-flow/step-machine-public';
@@ -141,6 +144,17 @@ const configuredChatFlowTimeoutMs = normalizeTimeoutMs(serverConfig.chatFlowTime
141
144
  const configuredInvokeRefTimeoutMs = normalizeTimeoutMs(serverConfig.chatInvokeRefTimeoutMs, 300000);
142
145
  const configuredCopilotTimeoutMs = normalizeTimeoutMs(serverConfig.chatCopilotTimeoutMs, 300000);
143
146
 
147
+ function normalizeBoardWorkerTransport(value) {
148
+ const normalized = String(value || '').trim().toLowerCase();
149
+ if (normalized === 'http') return 'http';
150
+ if (normalized === 'queue') return 'queue';
151
+ return 'in-process-loop';
152
+ }
153
+
154
+ const configuredBoardWorkerTransport = normalizeBoardWorkerTransport(
155
+ process.env.DEMO_TASK_EXECUTOR_TRANSPORT || serverConfig.taskExecutorTransport || 'in-process-loop',
156
+ );
157
+
144
158
  // Resolve top-level config defaults (used as fallbacks for per-board config)
145
159
  const configuredTaskExecutorPath = resolveFromConfig(serverConfig.taskExecutorPath);
146
160
  const configuredChatHandlerPath = resolveFromConfig(serverConfig.chatHandlerPath);
@@ -167,6 +181,7 @@ const PORT = Number(process.env.DEMO_SERVER_PORT || serverConfig.port || 7799);
167
181
  const cardsPatternArgIndex = cliArgs.indexOf('--cards-pattern');
168
182
  const cliCardsPattern = cardsPatternArgIndex !== -1 ? cliArgs[cardsPatternArgIndex + 1] : null;
169
183
  const selectedCardsPattern = (process.env.DEMO_CARDS_PATTERN || cliCardsPattern || '').trim() || null;
184
+ const enableTestReq = /^(1|true|yes|on)$/i.test((process.env.BOARD_SERVER_ENABLE_TEST_REQ || '').trim());
170
185
 
171
186
  const CORS_HEADERS = {
172
187
  'Access-Control-Allow-Origin': '*',
@@ -229,6 +244,107 @@ function makeExecutionRef(scriptPath, extra) {
229
244
  };
230
245
  }
231
246
 
247
+ function makeLocalTaskExecutorRef(scriptPath, extra) {
248
+ if (!scriptPath) return undefined;
249
+ const resolved = path.isAbsolute(scriptPath) ? scriptPath : path.resolve(process.cwd(), scriptPath);
250
+ return {
251
+ meta: 'task-executor',
252
+ howToRun: 'local-node',
253
+ whatToRun: serializeRef({ kind: 'fs-path', value: resolved }),
254
+ ...(extra !== undefined ? { extra } : {}),
255
+ };
256
+ }
257
+
258
+ function isHostedTaskExecutorRef(ref) {
259
+ return ref?.howToRun === 'queue-storage'
260
+ || ref?.howToRun === 'in-process-loop'
261
+ || ref?.howToRun === 'http:post'
262
+ || ref?.howToRun === 'http:get';
263
+ }
264
+
265
+ function makeHostedBoardWorkerRef(boardId, taskExecPath, transport, executionExtra) {
266
+ if (!taskExecPath) return undefined;
267
+ if (transport === 'in-process-loop') {
268
+ return {
269
+ meta: 'task-executor',
270
+ howToRun: 'in-process-loop',
271
+ whatToRun: serializeRef({ kind: 'in-process-loop', value: `board:${boardId}:board-worker` }),
272
+ };
273
+ }
274
+ if (transport === 'http') {
275
+ return {
276
+ meta: 'task-executor',
277
+ howToRun: 'http:post',
278
+ whatToRun: serializeRef({
279
+ kind: 'http-url',
280
+ value: `${String(executionExtra.serverUrl || '').replace(/\/+$/, '')}/api/board-worker`,
281
+ }),
282
+ extra: { boardId },
283
+ };
284
+ }
285
+ if (transport === 'queue') {
286
+ return {
287
+ meta: 'task-executor',
288
+ howToRun: 'queue-storage',
289
+ whatToRun: serializeRef({ kind: 'queue-storage', value: `board:${boardId}:board-worker` }),
290
+ extra: { boardId },
291
+ };
292
+ }
293
+ throw new Error(`Unsupported board-worker transport for demo host: ${transport}`);
294
+ }
295
+
296
+ function makeBoardWorkerCallbackSelfRef(serverUrl, boardApiBasePath, transport, boardId) {
297
+ if (transport === 'in-process-loop' || transport === 'queue') {
298
+ return {
299
+ meta: 'board-live-cards',
300
+ howToRun: 'in-process-loop',
301
+ whatToRun: serializeRef({ kind: 'in-process-loop', value: `board:${boardId}:board-worker-callback` }),
302
+ };
303
+ }
304
+ const normalizedServerUrl = typeof serverUrl === 'string' ? serverUrl.trim().replace(/\/+$/, '') : '';
305
+ const normalizedApiBasePath = typeof boardApiBasePath === 'string' ? boardApiBasePath.trim().replace(/\/+$/, '') : '';
306
+ if (!normalizedServerUrl || !normalizedApiBasePath) return undefined;
307
+ return {
308
+ meta: 'board-live-cards',
309
+ howToRun: 'http:post',
310
+ whatToRun: serializeRef({
311
+ kind: 'http-url',
312
+ value: `${normalizedServerUrl}${normalizedApiBasePath}/callback/board-worker`,
313
+ }),
314
+ };
315
+ }
316
+
317
+ async function readJsonRequest(req) {
318
+ const parts = [];
319
+ for await (const chunk of req) parts.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
320
+ const raw = Buffer.concat(parts).toString('utf-8').trim();
321
+ return raw ? JSON.parse(raw) : {};
322
+ }
323
+
324
+ const boardWorkerModuleCache = new Map();
325
+
326
+ async function loadBoardWorkerModule(taskExecPath) {
327
+ const resolved = path.isAbsolute(taskExecPath) ? taskExecPath : path.resolve(BOARD_ROOT, taskExecPath);
328
+ if (!boardWorkerModuleCache.has(resolved)) {
329
+ boardWorkerModuleCache.set(resolved, import(pathToFileURL(resolved).href));
330
+ }
331
+ return boardWorkerModuleCache.get(resolved);
332
+ }
333
+
334
+ function createHostedBoardWorkerDispatcher(boardId, taskExecPath) {
335
+ if (!taskExecPath) return null;
336
+ return async (request) => {
337
+ const mod = await loadBoardWorkerModule(taskExecPath);
338
+ if (typeof mod.executeBoardWorkerRequest === 'function') {
339
+ return await mod.executeBoardWorkerRequest(request);
340
+ }
341
+ if (typeof mod.executeTaskExecutorRequest === 'function') {
342
+ return await mod.executeTaskExecutorRequest(request);
343
+ }
344
+ throw new Error(`Hosted board worker for board ${boardId} must export executeBoardWorkerRequest(request)`);
345
+ };
346
+ }
347
+
232
348
  function createNamedPipeNotificationTransport() {
233
349
  return {
234
350
  async subscribe(ref, onEvent) {
@@ -283,6 +399,9 @@ const apiBasePath = '/api/boards';
283
399
  const invocationAdapter = createNodeSpawnInvocationAdapter();
284
400
  const notificationTransport = createNamedPipeNotificationTransport();
285
401
  const logger = { info: console.log, warn: console.warn, error: console.error };
402
+ const hostedBoardWorkerDispatchers = new Map();
403
+ const hostedBoardWorkerQueueStops = new Map();
404
+ const hostedBoardChatStorages = new Map();
286
405
 
287
406
  // Map config keys to board entries for the factory
288
407
  const boardConfigEntries = serverConfig.boards ? Object.entries(serverConfig.boards) : [];
@@ -301,8 +420,24 @@ function buildBoardContextConfig(label, boardDir, taskExecPath, chatHandlerFlow,
301
420
 
302
421
  const notifyChannel = `yaml-flow-server-${label}-${boardId}-${process.pid}`;
303
422
  const baseRef = parseRef(serializeRef({ kind: 'fs-path', value: boardDir }));
304
- const boardAdapter = createFsBoardPlatformAdapter(baseRef, { notifyChannel });
305
- const nonCoreAdapter = createFsBoardNonCorePlatformAdapter(baseRef, { notifyChannel });
423
+ const boardWorkerTransport = normalizeBoardWorkerTransport(executionExtra.taskExecutorTransport);
424
+ const callbackSelfRef = makeBoardWorkerCallbackSelfRef(executionExtra.serverUrl, executionExtra.apiBasePath, boardWorkerTransport, boardId);
425
+ const boardAdapter = createFsBoardPlatformAdapter(baseRef, {
426
+ notifyChannel,
427
+ ...(callbackSelfRef ? { selfRef: callbackSelfRef } : {}),
428
+ });
429
+ const nonCoreAdapter = createFsBoardNonCorePlatformAdapter(baseRef, {
430
+ notifyChannel,
431
+ ...(callbackSelfRef ? { selfRef: callbackSelfRef } : {}),
432
+ });
433
+ const localSyncTaskExecutorRef = makeLocalTaskExecutorRef(taskExecPath, executionExtra);
434
+ if (localSyncTaskExecutorRef) {
435
+ const invokeExecutor = nonCoreAdapter.invokeExecutor.bind(nonCoreAdapter);
436
+ nonCoreAdapter.invokeExecutor = (ref, subcommand, execOpts) => {
437
+ const syncRef = isHostedTaskExecutorRef(ref) ? localSyncTaskExecutorRef : ref;
438
+ return invokeExecutor(syncRef, subcommand, execOpts);
439
+ };
440
+ }
306
441
  boardAdapter.requestProcessAccumulated = () => {};
307
442
  nonCoreAdapter.requestProcessAccumulated = () => {};
308
443
 
@@ -325,7 +460,7 @@ function buildBoardContextConfig(label, boardDir, taskExecPath, chatHandlerFlow,
325
460
  scratchStoreRef,
326
461
  archiveStoreRef,
327
462
  notifyRef: { kind: 'named-pipe', value: namedPipePath(notifyChannel) },
328
- taskExecutorRef: makeExecutionRef(taskExecPath, executionExtra),
463
+ taskExecutorRef: makeHostedBoardWorkerRef(boardId, taskExecPath, boardWorkerTransport, executionExtra),
329
464
  chatHandlerFlow,
330
465
  inferenceAdapterRef: makeExecutionRef(infAdapterPath),
331
466
  };
@@ -401,6 +536,7 @@ const runtime = createMultiBoardServerRuntime({
401
536
  );
402
537
  const infAdapterPath = resolveFromConfig(regular.inferenceAdapterPath) || (entry?.inferenceAdapterPath || configuredInferenceAdapterPath);
403
538
  const stepMachinePath = resolveFromConfig(regular.stepMachineCliPath || cfg?.stepMachineCliPath) || (entry?.stepMachineCliPath || configuredStepMachineCliPath);
539
+ const boardWorkerTransport = normalizeBoardWorkerTransport(regular.taskExecutorTransport || entry?.taskExecutorTransport || configuredBoardWorkerTransport);
404
540
  const chatInvokeRefTimeoutMs = configuredInvokeRefTimeoutMs;
405
541
  const chatCopilotTimeoutMs = configuredCopilotTimeoutMs;
406
542
 
@@ -436,6 +572,7 @@ const runtime = createMultiBoardServerRuntime({
436
572
  chatFlowRoot,
437
573
  apiBasePath: `${apiBasePath}/${boardId}`,
438
574
  serverUrl: `http://127.0.0.1:${PORT}`,
575
+ taskExecutorTransport: boardWorkerTransport,
439
576
  chatCopilotTimeoutMs,
440
577
  ...(stepMachinePath ? { stepMachineCliPath: stepMachinePath } : {}),
441
578
  };
@@ -446,6 +583,7 @@ const runtime = createMultiBoardServerRuntime({
446
583
  demoPrepSetup({ cardsDir, boardDir });
447
584
 
448
585
  const chatStorage = createFsBoardChatStorage(boardDir);
586
+ hostedBoardChatStorages.set(boardId, chatStorage);
449
587
 
450
588
  const singleBoardRuntime = createSingleBoardServerRuntime({
451
589
  apiBasePath: `${apiBasePath}/${boardId}`,
@@ -470,6 +608,44 @@ const runtime = createMultiBoardServerRuntime({
470
608
  },
471
609
  });
472
610
 
611
+ const hostedBoardWorkerDispatch = createHostedBoardWorkerDispatcher(boardId, taskExecPath);
612
+ if (hostedBoardWorkerDispatch) {
613
+ hostedBoardWorkerDispatchers.set(boardId, hostedBoardWorkerDispatch);
614
+ }
615
+ const previousQueueStop = hostedBoardWorkerQueueStops.get(boardId);
616
+ if (previousQueueStop) {
617
+ previousQueueStop();
618
+ hostedBoardWorkerQueueStops.delete(boardId);
619
+ }
620
+ if (boardWorkerTransport === 'in-process-loop' && hostedBoardWorkerDispatch) {
621
+ registerInProcessExecutionHandler(`board:${boardId}:board-worker`, async (_ref, args) => {
622
+ void hostedBoardWorkerDispatch(args).catch((err) => {
623
+ logger.error(`[board-server] in-process board-worker failed for ${boardId}: ${String(err && err.message || err)}`);
624
+ });
625
+ return { result: 'success', data: { dispatched: true } };
626
+ });
627
+ }
628
+ if ((boardWorkerTransport === 'in-process-loop' || boardWorkerTransport === 'queue') && hostedBoardWorkerDispatch) {
629
+ registerInProcessBoardWorkerCallback(`board:${boardId}:board-worker-callback`, (payload) => {
630
+ if (payload.outcome === 'success') {
631
+ return singleBoardRuntime.reportSourceFetched(payload.token, String(payload.ref || ''));
632
+ }
633
+ return singleBoardRuntime.reportSourceFetchFailure(payload.token, String(payload.reason || 'unknown'));
634
+ });
635
+ }
636
+ if (boardWorkerTransport === 'queue' && hostedBoardWorkerDispatch) {
637
+ const stopQueueRunner = startBoardWorkerQueueRunner({
638
+ workerStore: baseCfg.boardAdapter.boardWorkerStore(),
639
+ executeBoardWorkerRequest: hostedBoardWorkerDispatch,
640
+ onError: (error, lease) => {
641
+ logger.error(
642
+ `[board-server] queued board-worker failed for ${boardId} (attempt ${lease.attempt}): ${String(error && error.message || error)}`,
643
+ );
644
+ },
645
+ });
646
+ hostedBoardWorkerQueueStops.set(boardId, stopQueueRunner);
647
+ }
648
+
473
649
  // Seed card store from source cardsDir if empty
474
650
  const existing = singleBoardRuntime.cardStore.get({});
475
651
  const isEmpty = existing.status !== 'success' || !existing.data?.cards?.length;
@@ -509,7 +685,7 @@ function jsonReply(res, status, payload) {
509
685
  res.end(body);
510
686
  }
511
687
 
512
- const server = http.createServer((req, res) => {
688
+ const server = http.createServer(async (req, res) => {
513
689
  const method = req.method || 'GET';
514
690
  const url = new URL(req.url || '/', 'http://localhost');
515
691
  const pathname = url.pathname;
@@ -520,6 +696,87 @@ const server = http.createServer((req, res) => {
520
696
  return;
521
697
  }
522
698
 
699
+ const testSystemChatMatch = pathname.match(/^\/test-req\/boards\/([^/]+)\/chat\/system-message$/);
700
+ if (method === 'POST' && testSystemChatMatch) {
701
+ if (!enableTestReq) {
702
+ jsonReply(res, 404, { error: 'Not found' });
703
+ return;
704
+ }
705
+
706
+ try {
707
+ const boardId = decodeURIComponent(testSystemChatMatch[1]);
708
+ runtime.requireBoardService(boardId);
709
+ const chatStorage = hostedBoardChatStorages.get(boardId);
710
+ if (!chatStorage) {
711
+ jsonReply(res, 409, { error: `No hosted chat storage configured for board: ${boardId}` });
712
+ return;
713
+ }
714
+
715
+ const body = await readJsonRequest(req);
716
+ const cardId = typeof body?.cardId === 'string' ? body.cardId.trim() : '';
717
+ const text = typeof body?.text === 'string' ? body.text : '';
718
+ const turn = typeof body?.turn === 'string' ? body.turn : '';
719
+ const files = Array.isArray(body?.files) ? body.files : [];
720
+
721
+ if (!cardId) {
722
+ jsonReply(res, 400, { error: 'cardId is required' });
723
+ return;
724
+ }
725
+ if (typeof body?.text !== 'string') {
726
+ jsonReply(res, 400, { error: 'text is required' });
727
+ return;
728
+ }
729
+
730
+ const id = chatStorage.append(cardId, 'system', text, files, turn);
731
+ jsonReply(res, 200, {
732
+ status: 'success',
733
+ data: {
734
+ id,
735
+ boardId,
736
+ cardId,
737
+ role: 'system',
738
+ text,
739
+ turn,
740
+ files,
741
+ },
742
+ });
743
+ return;
744
+ } catch (err) {
745
+ jsonReply(res, 404, { error: String(err && err.message || err) });
746
+ return;
747
+ }
748
+ }
749
+
750
+ if (method === 'POST' && pathname === '/api/board-worker') {
751
+ try {
752
+ const body = await readJsonRequest(req);
753
+ const boardId = typeof body?.extra?.boardId === 'string' ? body.extra.boardId.trim() : '';
754
+ if (!boardId) {
755
+ jsonReply(res, 400, { error: 'boardId is required in request.extra.boardId' });
756
+ return;
757
+ }
758
+ runtime.requireBoardService(boardId);
759
+ const dispatcher = hostedBoardWorkerDispatchers.get(boardId);
760
+ if (!dispatcher) {
761
+ jsonReply(res, 409, { error: `No hosted board-worker configured for board: ${boardId}` });
762
+ return;
763
+ }
764
+ if (body?.source_def) {
765
+ void dispatcher(body).catch((err) => {
766
+ logger.error(`[board-server] hosted board-worker failed for ${boardId}: ${String(err && err.message || err)}`);
767
+ });
768
+ jsonReply(res, 202, { status: 'success', dispatched: true });
769
+ return;
770
+ }
771
+ const workerResult = await dispatcher(body);
772
+ jsonReply(res, 200, workerResult ?? { status: 'success', data: {} });
773
+ return;
774
+ } catch (err) {
775
+ jsonReply(res, 404, { error: String(err && err.message || err) });
776
+ return;
777
+ }
778
+ }
779
+
523
780
  // All other /api/boards routes are handled by the platform-free runtime
524
781
  runtime.handleApi(req, res, url).then((handled) => {
525
782
  if (!handled) {
@@ -546,4 +803,8 @@ server.listen(PORT, '127.0.0.1', () => {
546
803
  console.log(` GET ${apiBasePath}/:boardId/cards/:id/chats`);
547
804
  console.log(` POST ${apiBasePath}/:boardId/cards/:id/chats/subscribe-sse`);
548
805
  console.log(` POST ${apiBasePath}/:boardId/cards/:id/chats/unsubscribe-sse`);
806
+ console.log(' POST /api/board-worker');
807
+ if (enableTestReq) {
808
+ console.log(' POST /test-req/boards/:boardId/chat/system-message');
809
+ }
549
810
  });