shadow-claw 1.34.5 → 1.35.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/.well-known/mcp/server-card.json +1 -1
- package/.well-known/mcp.json +1 -1
- package/README.md +5 -1
- package/dist/cli/chunk-BCLxzLO92.js +5 -0
- package/dist/cli/chunk-BHNCi3ui2.js +1 -0
- package/dist/cli/chunk-BMPhLSn8.js +1 -0
- package/dist/cli/chunk-BMW6QB5-2.js +27 -0
- package/dist/cli/chunk-BQCWtrzh.js +1 -0
- package/dist/cli/chunk-BQCWtrzh2.js +1 -0
- package/dist/cli/chunk-BdJUjMuz.js +1 -0
- package/dist/cli/chunk-C47WdxKx2.js +1 -0
- package/dist/cli/{chunk-D9dku_3t.js → chunk-CAqvQuGr.js} +1 -1
- package/dist/cli/{chunk-DoVxObGa2.js → chunk-CHzhUS1N2.js} +1 -1
- package/dist/cli/chunk-CUMlq7Jw2.js +263 -0
- package/dist/cli/chunk-CXi9LU9e2.js +110 -0
- package/dist/cli/chunk-ChefnX-r.js +110 -0
- package/dist/cli/{chunk-zvi71-77.js → chunk-D3JxbzjI2.js} +15 -15
- package/dist/cli/chunk-D7VYMl092.js +1 -0
- package/dist/cli/chunk-DNIduiJ82.js +91 -0
- package/dist/cli/{chunk-C4UfzPK4.js → chunk-DTbrldk_.js} +1 -1
- package/dist/cli/chunk-DZ8YBXax.js +969 -0
- package/dist/cli/chunk-DduRvw8B2.js +1 -0
- package/dist/cli/chunk-DnYxGjdu2.js +1 -0
- package/dist/cli/chunk-Ea7nXmgb2.js +1 -0
- package/dist/cli/{chunk-BRiGkTIi.js → chunk-EohNY8vW.js} +1 -1
- package/dist/cli/chunk-LIIpZlwP2.js +1 -0
- package/dist/cli/chunk-LIJZHJml2.js +1 -0
- package/dist/cli/chunk-MHBh2BgF2.js +91 -0
- package/dist/cli/{chunk-BQ7lHA7c.js → chunk-SKgLGyTY.js} +1 -1
- package/dist/cli/chunk-kcJSXcbq2.js +1 -0
- package/dist/cli/cli.js +12 -11
- package/dist/headless-agent.js +191 -187
- package/dist/lib/components/index.js +21 -21
- package/dist/lib/components/settings/shadow-claw-channel-config.js +1 -1
- package/dist/lib/components/settings/shadow-claw-control-plane.js +1 -1
- package/dist/lib/components/settings/shadow-claw-git.js +1 -1
- package/dist/lib/components/settings/shadow-claw-llm.js +1 -1
- package/dist/lib/components/settings/shadow-claw-networking.js +1 -1
- package/dist/lib/components/settings/shadow-claw-notifications.js +1 -1
- package/dist/lib/components/settings/shadow-claw-peerjs.js +1 -1
- package/dist/lib/components/settings/shadow-claw-storage.js +1 -1
- package/dist/lib/components/settings/shadow-claw-task-server.js +1 -1
- package/dist/lib/components/settings/shadow-claw-webvm.js +1 -1
- package/dist/lib/components/shadow-claw-channel-config.js +1 -1
- package/dist/lib/components/shadow-claw-channels.js +1 -1
- package/dist/lib/components/shadow-claw-chat.js +1 -1
- package/dist/lib/components/shadow-claw-control-plane.js +1 -1
- package/dist/lib/components/shadow-claw-conversations.js +1 -1
- package/dist/lib/components/shadow-claw-file-viewer.js +1 -1
- package/dist/lib/components/shadow-claw-files.js +1 -1
- package/dist/lib/components/shadow-claw-git.js +1 -1
- package/dist/lib/components/shadow-claw-llm.js +1 -1
- package/dist/lib/components/shadow-claw-networking.js +1 -1
- package/dist/lib/components/shadow-claw-notifications.js +1 -1
- package/dist/lib/components/shadow-claw-pages.js +1 -1
- package/dist/lib/components/shadow-claw-peerjs.js +1 -1
- package/dist/lib/components/shadow-claw-settings.js +1 -1
- package/dist/lib/components/shadow-claw-storage.js +1 -1
- package/dist/lib/components/shadow-claw-task-server.js +1 -1
- package/dist/lib/components/shadow-claw-tasks.js +1 -1
- package/dist/lib/components/shadow-claw-terminal.js +1 -1
- package/dist/lib/components/shadow-claw-tools.js +1 -1
- package/dist/lib/components/shadow-claw-webvm.js +1 -1
- package/dist/lib/components/shadow-claw.js +1 -1
- package/dist/lib/{configurePeerJs-DSRcNp3v.js → configurePeerJs-CdPzmpyI.js} +2 -2
- package/dist/lib/{configurePeerJs-DSRcNp3v.js.map → configurePeerJs-CdPzmpyI.js.map} +1 -1
- package/dist/lib/index.js +21 -21
- package/dist/lib/{initControlPlane-CWfE_Oan.js → initControlPlane-BLymRW34.js} +7 -7
- package/dist/lib/{initControlPlane-CWfE_Oan.js.map → initControlPlane-BLymRW34.js.map} +1 -1
- package/dist/lib/{orchestrator-BEUug1TW.js → orchestrator-DZkhJj7f.js} +13 -2
- package/dist/lib/{orchestrator-BEUug1TW.js.map → orchestrator-DZkhJj7f.js.map} +1 -1
- package/dist/lib/{orchestrator-CGUzfGbE.js → orchestrator-ZsQTRknI.js} +5 -5
- package/dist/lib/{orchestrator-CGUzfGbE.js.map → orchestrator-ZsQTRknI.js.map} +1 -1
- package/dist/lib/{peerjs-BSD88rT3.js → peerjs-CJYfnR5V.js} +3 -3
- package/dist/lib/{peerjs-BSD88rT3.js.map → peerjs-CJYfnR5V.js.map} +1 -1
- package/dist/lib/{push-client-CC3qifgc.js → push-client-C9hIPqLZ.js} +2 -2
- package/dist/lib/{push-client-CC3qifgc.js.map → push-client-C9hIPqLZ.js.map} +1 -1
- package/dist/lib/{shadow-claw-BWS-UVnE.js → shadow-claw-8qL2-QoK.js} +4 -4
- package/dist/lib/{shadow-claw-BWS-UVnE.js.map → shadow-claw-8qL2-QoK.js.map} +1 -1
- package/dist/lib/{shadow-claw-channel-config-DwMn3nFJ.js → shadow-claw-channel-config-CvnbqGBy.js} +3 -3
- package/dist/lib/{shadow-claw-channel-config-DwMn3nFJ.js.map → shadow-claw-channel-config-CvnbqGBy.js.map} +1 -1
- package/dist/lib/{shadow-claw-channels-BdE4cUlx.js → shadow-claw-channels-CkCvjWn1.js} +2 -2
- package/dist/lib/{shadow-claw-channels-BdE4cUlx.js.map → shadow-claw-channels-CkCvjWn1.js.map} +1 -1
- package/dist/lib/{shadow-claw-chat-DqaMoE9C.js → shadow-claw-chat-B1YEHKN3.js} +3 -3
- package/dist/lib/{shadow-claw-chat-DqaMoE9C.js.map → shadow-claw-chat-B1YEHKN3.js.map} +1 -1
- package/dist/lib/{shadow-claw-control-plane-D3DUDO29.js → shadow-claw-control-plane-jjo789IE.js} +6 -6
- package/dist/lib/{shadow-claw-control-plane-D3DUDO29.js.map → shadow-claw-control-plane-jjo789IE.js.map} +1 -1
- package/dist/lib/{shadow-claw-conversations-XT-OXogj.js → shadow-claw-conversations-MMT7wYH3.js} +2 -2
- package/dist/lib/{shadow-claw-conversations-XT-OXogj.js.map → shadow-claw-conversations-MMT7wYH3.js.map} +1 -1
- package/dist/lib/{shadow-claw-file-viewer-DJqxyd97.js → shadow-claw-file-viewer-qSkD1RQK.js} +2 -2
- package/dist/lib/{shadow-claw-file-viewer-DJqxyd97.js.map → shadow-claw-file-viewer-qSkD1RQK.js.map} +1 -1
- package/dist/lib/{shadow-claw-files-CUEJlA1o.js → shadow-claw-files-Cg8ycQ_N.js} +2 -2
- package/dist/lib/{shadow-claw-files-CUEJlA1o.js.map → shadow-claw-files-Cg8ycQ_N.js.map} +1 -1
- package/dist/lib/{shadow-claw-git-D_iVcb86.js → shadow-claw-git-gaClz-ZC.js} +3 -3
- package/dist/lib/{shadow-claw-git-D_iVcb86.js.map → shadow-claw-git-gaClz-ZC.js.map} +1 -1
- package/dist/lib/{shadow-claw-llm-C2msAsyU.js → shadow-claw-llm-DyOz0qzT.js} +2 -2
- package/dist/lib/{shadow-claw-llm-C2msAsyU.js.map → shadow-claw-llm-DyOz0qzT.js.map} +1 -1
- package/dist/lib/{shadow-claw-networking-D2NvodC-.js → shadow-claw-networking-B2xx0UUR.js} +2 -2
- package/dist/lib/{shadow-claw-networking-D2NvodC-.js.map → shadow-claw-networking-B2xx0UUR.js.map} +1 -1
- package/dist/lib/{shadow-claw-notifications-BcvVn_vu.js → shadow-claw-notifications-BjKfZy0k.js} +2 -2
- package/dist/lib/{shadow-claw-notifications-BcvVn_vu.js.map → shadow-claw-notifications-BjKfZy0k.js.map} +1 -1
- package/dist/lib/{shadow-claw-pages-CTMXRhEX.js → shadow-claw-pages-CJ2tsMtL.js} +2 -2
- package/dist/lib/{shadow-claw-pages-CTMXRhEX.js.map → shadow-claw-pages-CJ2tsMtL.js.map} +1 -1
- package/dist/lib/{shadow-claw-peerjs-C2YvypqM.js → shadow-claw-peerjs-CazCkXQ1.js} +3 -3
- package/dist/lib/{shadow-claw-peerjs-C2YvypqM.js.map → shadow-claw-peerjs-CazCkXQ1.js.map} +1 -1
- package/dist/lib/{shadow-claw-settings-B0hiDwEt.js → shadow-claw-settings-qro6pO9I.js} +2 -2
- package/dist/lib/{shadow-claw-settings-B0hiDwEt.js.map → shadow-claw-settings-qro6pO9I.js.map} +1 -1
- package/dist/lib/{shadow-claw-storage-Dt4yg4Q4.js → shadow-claw-storage-ewDdvCGa.js} +2 -2
- package/dist/lib/{shadow-claw-storage-Dt4yg4Q4.js.map → shadow-claw-storage-ewDdvCGa.js.map} +1 -1
- package/dist/lib/{shadow-claw-task-server-B2gbZaz4.js → shadow-claw-task-server-DpqQcNIs.js} +2 -2
- package/dist/lib/{shadow-claw-task-server-B2gbZaz4.js.map → shadow-claw-task-server-DpqQcNIs.js.map} +1 -1
- package/dist/lib/{shadow-claw-tasks-Bxq-niuM.js → shadow-claw-tasks-B2fMF4qE.js} +2 -2
- package/dist/lib/{shadow-claw-tasks-Bxq-niuM.js.map → shadow-claw-tasks-B2fMF4qE.js.map} +1 -1
- package/dist/lib/{shadow-claw-terminal-BfbW3xtg.js → shadow-claw-terminal-B25kQJC3.js} +2 -2
- package/dist/lib/{shadow-claw-terminal-BfbW3xtg.js.map → shadow-claw-terminal-B25kQJC3.js.map} +1 -1
- package/dist/lib/{shadow-claw-tools-BNSAaK0Y.js → shadow-claw-tools-B0y8JzoA.js} +10 -3
- package/dist/lib/{shadow-claw-tools-BNSAaK0Y.js.map → shadow-claw-tools-B0y8JzoA.js.map} +1 -1
- package/dist/lib/{shadow-claw-webvm-Dc2KmEXq.js → shadow-claw-webvm-CoCedIza.js} +2 -2
- package/dist/lib/{shadow-claw-webvm-Dc2KmEXq.js.map → shadow-claw-webvm-CoCedIza.js.map} +1 -1
- package/dist/lib/{syncWebMcpRegistration-BIL83P0Q.js → syncWebMcpRegistration-JKLALq4e.js} +2 -2
- package/dist/lib/{syncWebMcpRegistration-BIL83P0Q.js.map → syncWebMcpRegistration-JKLALq4e.js.map} +1 -1
- package/dist/lib/worker/utils/sandboxedEval.d.ts +8 -0
- package/dist/public/.well-known/mcp/server-card.json +1 -1
- package/dist/public/.well-known/mcp.json +1 -1
- package/dist/public/AGENTS.md +1 -1
- package/dist/public/README.md +5 -1
- package/dist/public/agent.worker.js +1 -1
- package/dist/public/components/shadow-claw-tools/shadow-claw-tools.html +1 -1
- package/dist/public/{configurePeerJs-B925t9C7.js → configurePeerJs-BrHeJGw1.js} +1 -1
- package/dist/public/docs/decisions/headless-cli-agent-participant.md +1 -1
- package/dist/public/docs/example/article/index.html +1 -1
- package/dist/public/docs/publishing/index.html +1 -1
- package/dist/public/docs/skill-creator/index.html +1 -1
- package/dist/public/docs/subsystems/cli.md +33 -23
- package/dist/public/docs/subsystems/skills.md +17 -0
- package/dist/public/docs/subsystems/tools.md +1 -1
- package/dist/public/e2e/README.md +2 -2
- package/dist/public/{e2e-bridge-CE1xleGn.js → e2e-bridge-D_lyH__p.js} +1 -1
- package/dist/public/{executeTool-DtTrsZHV.js → executeTool-b6DnRhcv.js} +2 -1
- package/dist/public/{file-viewer-LEEStSq-.js → file-viewer-CKrQoxZi.js} +1 -1
- package/dist/public/index.html +1 -1
- package/dist/public/index.js +1 -1
- package/dist/public/{initControlPlane-e2JgxXEb.js → initControlPlane-Dn-XFuxg.js} +1 -1
- package/dist/public/llms.txt +2 -0
- package/dist/public/main/index.html +1 -1
- package/dist/public/main/memory/index.html +1 -1
- package/dist/public/{orchestrator-Baif6kmu.js → orchestrator-0BnBtxHO.js} +3 -2
- package/dist/public/{orchestrator-TndREZPL.js → orchestrator-C3GKZriH.js} +1 -1
- package/dist/public/{peerjs-DE6WF3h2.js → peerjs-CgfLEp2N.js} +1 -1
- package/dist/public/{push-client-B_IkTpNm.js → push-client-D6DLiY1s.js} +1 -1
- package/dist/public/service-worker.js +1 -1
- package/dist/public/{shadow-claw-channels-BCGz36Zl.js → shadow-claw-channels-DSijinZ9.js} +1 -1
- package/dist/public/{shadow-claw-chat-H9U9jbqD.js → shadow-claw-chat-BeHlAjnA.js} +1 -1
- package/dist/public/{shadow-claw-control-plane-CeKh64s2.js → shadow-claw-control-plane-BfF_AZSg.js} +2 -2
- package/dist/public/{shadow-claw-conversations-C26t1HXN.js → shadow-claw-conversations-Bb_2bVLJ.js} +1 -1
- package/dist/public/{shadow-claw-DBeXILmk.js → shadow-claw-f71DlRdV.js} +2 -2
- package/dist/public/{shadow-claw-file-viewer-DWUoTjkr.js → shadow-claw-file-viewer-B67000Mm.js} +1 -1
- package/dist/public/{shadow-claw-files-BQ8DSX-z.js → shadow-claw-files-DeZZYt01.js} +1 -1
- package/dist/public/{shadow-claw-git-CIXyISw-.js → shadow-claw-git-Ccy25LuW.js} +2 -2
- package/dist/public/{shadow-claw-llm-D_GpOSZE.js → shadow-claw-llm-XjYcTlXT.js} +1 -1
- package/dist/public/{shadow-claw-networking-BYp5K3B7.js → shadow-claw-networking-efXQtydQ.js} +1 -1
- package/dist/public/{shadow-claw-notifications-ZiXmPweY.js → shadow-claw-notifications-Cq2ZSeJa.js} +1 -1
- package/dist/public/{shadow-claw-pages-BHXwf3BD.js → shadow-claw-pages-BVFNSSb1.js} +1 -1
- package/dist/public/{shadow-claw-settings-BfvDvt9c.js → shadow-claw-settings-B3sHxPh9.js} +2 -2
- package/dist/public/{shadow-claw-storage-Bvn85DII.js → shadow-claw-storage-DNdlzCgC.js} +1 -1
- package/dist/public/{shadow-claw-task-server-DZL_d8FC.js → shadow-claw-task-server-BJq0rpju.js} +1 -1
- package/dist/public/{shadow-claw-tasks-Cy8jzd8q.js → shadow-claw-tasks-CkF1uMeZ.js} +1 -1
- package/dist/public/{shadow-claw-terminal-BgEXr82T.js → shadow-claw-terminal-CnHhcpA-.js} +1 -1
- package/dist/public/{shadow-claw-tools-BjnssRSi.js → shadow-claw-tools-iw0fljud.js} +8 -1
- package/dist/public/{shadow-claw-webvm-tZ1VDoVA.js → shadow-claw-webvm-Bliu4V__.js} +1 -1
- package/dist/public/{syncWebMcpRegistration-CLMvJ4kV.js → syncWebMcpRegistration-D91usEMu.js} +1 -1
- package/package.json +1 -1
- package/src/cli/cli.ts +26 -2
- package/src/cli/commands/agent.test.ts +421 -0
- package/src/cli/commands/agent.ts +270 -20
- package/src/components/shadow-claw-tools/shadow-claw-tools.html +7 -0
- package/src/worker/headless-agent.ts +14 -0
- package/src/worker/headless-types.ts +39 -0
- package/src/worker/utils/native-eval-executor.test.ts +36 -0
- package/src/worker/utils/native-eval-executor.ts +58 -0
- package/src/worker/utils/sandboxedEval.ts +36 -0
- package/dist/cli/chunk-1BmpU7jO2.js +0 -1
- package/dist/cli/chunk-54Euq8Ji2.js +0 -1
- package/dist/cli/chunk-BTitwCgT2.js +0 -88
- package/dist/cli/chunk-Bjh76Dai.js +0 -1081
- package/dist/cli/chunk-C2HeZQ6K.js +0 -1
- package/dist/cli/chunk-CxdpafWg.js +0 -1
- package/dist/cli/chunk-DEy72ZNV2.js +0 -88
- package/dist/cli/chunk-Da1BZyqf.js +0 -1
- package/dist/cli/chunk-FHsJD-Sf2.js +0 -27
- package/dist/cli/chunk-aWgoVB7x2.js +0 -1
- package/dist/cli/chunk-hOceZVB92.js +0 -371
- package/dist/cli/chunk-pwNc6VtC2.js +0 -1
|
@@ -21,6 +21,8 @@ import type {
|
|
|
21
21
|
AgentRunResult,
|
|
22
22
|
AgentModelOptions,
|
|
23
23
|
AgentModelResult,
|
|
24
|
+
AgentImportOptions,
|
|
25
|
+
AgentImportResult,
|
|
24
26
|
} from "../../worker/headless-types.js";
|
|
25
27
|
|
|
26
28
|
import { bootstrapHeadlessAgent } from "./agent-bootstrap.js";
|
|
@@ -254,6 +256,8 @@ export async function runAgentTools(
|
|
|
254
256
|
options: AgentToolsOptions & Record<string, any> = {},
|
|
255
257
|
): Promise<any> {
|
|
256
258
|
const { db, core } = await bootstrapHeadlessAgent(options);
|
|
259
|
+
const groupId =
|
|
260
|
+
options.group || core.DEFAULT_SERVER_GROUP_ID || DEFAULT_SERVER_GROUP_ID;
|
|
257
261
|
|
|
258
262
|
let profileToolNames: Set<string> | null = null;
|
|
259
263
|
if (options.toolsProfile || options.profile) {
|
|
@@ -283,7 +287,21 @@ export async function runAgentTools(
|
|
|
283
287
|
}
|
|
284
288
|
}
|
|
285
289
|
|
|
286
|
-
const
|
|
290
|
+
const allTools = [...(core.TOOL_DEFINITIONS || [])];
|
|
291
|
+
if (typeof core.loadDeclarativeTools === "function") {
|
|
292
|
+
try {
|
|
293
|
+
const decl = await core.loadDeclarativeTools(db, groupId);
|
|
294
|
+
if (decl && Array.isArray(decl.tools)) {
|
|
295
|
+
for (const dt of decl.tools) {
|
|
296
|
+
if (!allTools.some((t) => t.name === dt.name)) {
|
|
297
|
+
allTools.push(dt);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
} catch {}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const tools = allTools.map((def) => ({
|
|
287
305
|
name: def.name,
|
|
288
306
|
description: def.description,
|
|
289
307
|
headlessSafe: !BROWSER_ONLY_TOOLS.has(def.name),
|
|
@@ -310,11 +328,14 @@ export async function runAgentTool(
|
|
|
310
328
|
options.group || core.DEFAULT_SERVER_GROUP_ID || DEFAULT_SERVER_GROUP_ID;
|
|
311
329
|
|
|
312
330
|
// Find tool in built-in TOOL_DEFINITIONS or declarative tools
|
|
313
|
-
let toolDef = (core.TOOL_DEFINITIONS || []).find(
|
|
331
|
+
let toolDef = (core.TOOL_DEFINITIONS || []).find(
|
|
332
|
+
(t: any) => t.name === toolName,
|
|
333
|
+
);
|
|
334
|
+
|
|
314
335
|
if (!toolDef && typeof core.loadDeclarativeTools === "function") {
|
|
315
336
|
try {
|
|
316
337
|
const decl = await core.loadDeclarativeTools(db, groupId);
|
|
317
|
-
toolDef = decl.tools.find((t) => t.name === toolName);
|
|
338
|
+
toolDef = decl.tools.find((t: any) => t.name === toolName);
|
|
318
339
|
} catch {}
|
|
319
340
|
}
|
|
320
341
|
|
|
@@ -370,12 +391,10 @@ export async function runAgentTool(
|
|
|
370
391
|
|
|
371
392
|
let invokeContext: any = undefined;
|
|
372
393
|
try {
|
|
373
|
-
const resolved = await resolveAgentProvider(
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
options,
|
|
378
|
-
);
|
|
394
|
+
const resolved = await resolveAgentProvider(db, core, workspaceDir, {
|
|
395
|
+
...options,
|
|
396
|
+
interactive: false,
|
|
397
|
+
});
|
|
379
398
|
invokeContext = {
|
|
380
399
|
db,
|
|
381
400
|
provider: resolved.providerId,
|
|
@@ -471,7 +490,7 @@ export async function runAgentSkill(
|
|
|
471
490
|
skill.execution?.type === "tools" &&
|
|
472
491
|
Array.isArray(skill.execution.tools)
|
|
473
492
|
) {
|
|
474
|
-
const normalizedTools = skill.execution.tools.map((t) => ({
|
|
493
|
+
const normalizedTools = skill.execution.tools.map((t: any) => ({
|
|
475
494
|
name: t.name || t.tool,
|
|
476
495
|
input: t.input || t.arguments || {},
|
|
477
496
|
suppressOutput: t.suppressOutput,
|
|
@@ -565,7 +584,8 @@ export async function resolveAgentProvider(
|
|
|
565
584
|
process.env.CI &&
|
|
566
585
|
!["0", "false"].includes(process.env.CI.toLowerCase()),
|
|
567
586
|
);
|
|
568
|
-
const isInteractive =
|
|
587
|
+
const isInteractive =
|
|
588
|
+
isTTY && !isCI && !options.quiet && options.interactive !== false;
|
|
569
589
|
|
|
570
590
|
if (!providerId) {
|
|
571
591
|
if (isInteractive) {
|
|
@@ -726,7 +746,7 @@ export async function resolveAgentProvider(
|
|
|
726
746
|
const processSigintListener = () => handleSigint();
|
|
727
747
|
process.on("SIGINT", processSigintListener);
|
|
728
748
|
|
|
729
|
-
const dataListener = (chunk) => {
|
|
749
|
+
const dataListener = (chunk: any) => {
|
|
730
750
|
const str =
|
|
731
751
|
typeof chunk === "string" ? chunk : chunk.toString("binary");
|
|
732
752
|
if (str.includes("\x03") || str.includes("\x04")) {
|
|
@@ -883,11 +903,13 @@ async function resolveToolsAndProfile(
|
|
|
883
903
|
? options.tools
|
|
884
904
|
: String(options.tools).split(",")
|
|
885
905
|
)
|
|
886
|
-
.map((t) => String(t).trim())
|
|
906
|
+
.map((t: unknown) => String(t).trim())
|
|
887
907
|
.filter(Boolean);
|
|
888
908
|
|
|
889
909
|
enabledTools = requestedNames
|
|
890
|
-
.map((name
|
|
910
|
+
.map((name: unknown) =>
|
|
911
|
+
allAvailableTools.find((t) => t.name === String(name)),
|
|
912
|
+
)
|
|
891
913
|
.filter(Boolean);
|
|
892
914
|
return { enabledTools, profileSystemPromptOverride };
|
|
893
915
|
}
|
|
@@ -1098,7 +1120,7 @@ export async function runAgentRun(
|
|
|
1098
1120
|
let hasStreamedChunks = false;
|
|
1099
1121
|
const pendingWrites: Promise<void>[] = [];
|
|
1100
1122
|
|
|
1101
|
-
core.setPostHandler(async (message) => {
|
|
1123
|
+
core.setPostHandler(async (message: any) => {
|
|
1102
1124
|
switch (message.type) {
|
|
1103
1125
|
case "streaming-start":
|
|
1104
1126
|
hasStreamedChunks = true;
|
|
@@ -1197,15 +1219,15 @@ export async function runAgentRun(
|
|
|
1197
1219
|
groupId: taskGroupId,
|
|
1198
1220
|
db,
|
|
1199
1221
|
})
|
|
1200
|
-
.then((res) => {
|
|
1201
|
-
const resolvers = globalThis.pendingNativeAiResolvers;
|
|
1222
|
+
.then((res: unknown) => {
|
|
1223
|
+
const resolvers = (globalThis as any).pendingNativeAiResolvers;
|
|
1202
1224
|
if (resolvers && resolvers[id]) {
|
|
1203
1225
|
resolvers[id].resolve(res);
|
|
1204
1226
|
delete resolvers[id];
|
|
1205
1227
|
}
|
|
1206
1228
|
})
|
|
1207
|
-
.catch((err) => {
|
|
1208
|
-
const resolvers = globalThis.pendingNativeAiResolvers;
|
|
1229
|
+
.catch((err: unknown) => {
|
|
1230
|
+
const resolvers = (globalThis as any).pendingNativeAiResolvers;
|
|
1209
1231
|
if (resolvers && resolvers[id]) {
|
|
1210
1232
|
resolvers[id].reject(err);
|
|
1211
1233
|
delete resolvers[id];
|
|
@@ -1601,6 +1623,218 @@ export async function runAgentModel(
|
|
|
1601
1623
|
return { success: false, error: errorMsg };
|
|
1602
1624
|
}
|
|
1603
1625
|
|
|
1626
|
+
/**
|
|
1627
|
+
* Import tools, skills, and companion scripts from a remote discovery manifest or site URL.
|
|
1628
|
+
* @param {string} urlOrSite
|
|
1629
|
+
* @param {import("../../src/worker/headless-types.js").AgentImportOptions} [options]
|
|
1630
|
+
* @returns {Promise<import("../../src/worker/headless-types.js").AgentImportResult>}
|
|
1631
|
+
*/
|
|
1632
|
+
export async function runAgentImport(
|
|
1633
|
+
urlOrSite: string,
|
|
1634
|
+
options: AgentImportOptions & Record<string, any> = {},
|
|
1635
|
+
): Promise<AgentImportResult> {
|
|
1636
|
+
const trimmedUrl = (urlOrSite || "").trim();
|
|
1637
|
+
if (!trimmedUrl) {
|
|
1638
|
+
const errorMsg =
|
|
1639
|
+
"Error: Discovery URL or site URL required. Usage: shadow-claw agent import <url> [options]";
|
|
1640
|
+
if (!options.quiet) {
|
|
1641
|
+
console.error(errorMsg);
|
|
1642
|
+
}
|
|
1643
|
+
process.exitCode = 1;
|
|
1644
|
+
return { success: false, error: errorMsg };
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
const { db, core } = await bootstrapHeadlessAgent(options);
|
|
1648
|
+
const groupId =
|
|
1649
|
+
options.group || core.DEFAULT_SERVER_GROUP_ID || DEFAULT_SERVER_GROUP_ID;
|
|
1650
|
+
|
|
1651
|
+
const fetchDiscoveryManifest =
|
|
1652
|
+
core.fetchDiscoveryManifest ||
|
|
1653
|
+
(await import("../../subsystems/tools/remote/discovery.js"))
|
|
1654
|
+
.fetchDiscoveryManifest;
|
|
1655
|
+
const importRemoteArtifacts =
|
|
1656
|
+
core.importRemoteArtifacts ||
|
|
1657
|
+
(await import("../../subsystems/tools/remote/importArtifacts.js"))
|
|
1658
|
+
.importRemoteArtifacts;
|
|
1659
|
+
|
|
1660
|
+
const fetchFn = options.fetchFn || globalThis.fetch;
|
|
1661
|
+
|
|
1662
|
+
if (!options.quiet) {
|
|
1663
|
+
console.log(`Fetching discovery manifest from ${trimmedUrl}...`);
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
let resolvedManifest: any;
|
|
1667
|
+
try {
|
|
1668
|
+
resolvedManifest = await fetchDiscoveryManifest(trimmedUrl, fetchFn);
|
|
1669
|
+
} catch (err: any) {
|
|
1670
|
+
const errorMsg = `Failed to fetch discovery manifest: ${err instanceof Error ? err.message : String(err)}`;
|
|
1671
|
+
if (!options.quiet) {
|
|
1672
|
+
console.error(`Error: ${errorMsg}`);
|
|
1673
|
+
}
|
|
1674
|
+
process.exitCode = 1;
|
|
1675
|
+
return { success: false, error: errorMsg };
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
const { manifest, siteUrl, manifestUrl } = resolvedManifest;
|
|
1679
|
+
|
|
1680
|
+
const manifestTools = manifest.tools || [];
|
|
1681
|
+
const manifestSkills = manifest.skills || [];
|
|
1682
|
+
const manifestScripts = manifest.scripts || [];
|
|
1683
|
+
|
|
1684
|
+
if (!options.quiet) {
|
|
1685
|
+
console.log(
|
|
1686
|
+
`Discovered: ${manifest.name || "Remote Site"} (${manifestSkills.length} skill${manifestSkills.length === 1 ? "" : "s"}, ${manifestTools.length} tool${manifestTools.length === 1 ? "" : "s"}, ${manifestScripts.length} script${manifestScripts.length === 1 ? "" : "s"})`,
|
|
1687
|
+
);
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
const allToolNames = manifestTools.map((t: any) => t.name);
|
|
1691
|
+
const allSkillNames = manifestSkills.map((s: any) => s.name);
|
|
1692
|
+
const allScriptNames = manifestScripts.map((s: any) => s.name);
|
|
1693
|
+
|
|
1694
|
+
let toolNames: string[];
|
|
1695
|
+
let skillNames: string[];
|
|
1696
|
+
let scriptNames: string[];
|
|
1697
|
+
|
|
1698
|
+
const hasExplicitFilter = Boolean(
|
|
1699
|
+
options.tools || options.skills || options.scripts,
|
|
1700
|
+
);
|
|
1701
|
+
|
|
1702
|
+
if (hasExplicitFilter && !options.all) {
|
|
1703
|
+
const parseList = (val: any) => {
|
|
1704
|
+
if (!val) return [];
|
|
1705
|
+
if (Array.isArray(val))
|
|
1706
|
+
return val.map((v) => String(v).trim()).filter(Boolean);
|
|
1707
|
+
return String(val)
|
|
1708
|
+
.split(",")
|
|
1709
|
+
.map((v) => v.trim())
|
|
1710
|
+
.filter(Boolean);
|
|
1711
|
+
};
|
|
1712
|
+
toolNames = parseList(options.tools);
|
|
1713
|
+
skillNames = parseList(options.skills);
|
|
1714
|
+
scriptNames = parseList(options.scripts);
|
|
1715
|
+
} else {
|
|
1716
|
+
toolNames = allToolNames;
|
|
1717
|
+
skillNames = allSkillNames;
|
|
1718
|
+
scriptNames = allScriptNames;
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1721
|
+
const autoEnable = options.autoEnable !== false;
|
|
1722
|
+
const overwrite = Boolean(options.overwrite);
|
|
1723
|
+
|
|
1724
|
+
let importResult: any;
|
|
1725
|
+
try {
|
|
1726
|
+
importResult = await importRemoteArtifacts(
|
|
1727
|
+
db,
|
|
1728
|
+
groupId,
|
|
1729
|
+
manifest,
|
|
1730
|
+
{ toolNames, skillNames, scriptNames },
|
|
1731
|
+
{
|
|
1732
|
+
autoEnable,
|
|
1733
|
+
overwrite,
|
|
1734
|
+
fetchFn,
|
|
1735
|
+
siteSlug: options.siteSlug,
|
|
1736
|
+
targetSubdir: options.targetSubdir,
|
|
1737
|
+
},
|
|
1738
|
+
);
|
|
1739
|
+
} catch (err: any) {
|
|
1740
|
+
const errorMsg = `Import failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
1741
|
+
if (!options.quiet) {
|
|
1742
|
+
console.error(`Error: ${errorMsg}`);
|
|
1743
|
+
}
|
|
1744
|
+
process.exitCode = 1;
|
|
1745
|
+
return { success: false, error: errorMsg };
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
const importedTools = importResult.tools.filter(
|
|
1749
|
+
(t: any) => t.status === "imported",
|
|
1750
|
+
);
|
|
1751
|
+
const importedSkills = importResult.skills.filter(
|
|
1752
|
+
(s: any) => s.status === "imported",
|
|
1753
|
+
);
|
|
1754
|
+
const importedScripts = importResult.scripts.filter(
|
|
1755
|
+
(sc: any) => sc.status === "imported",
|
|
1756
|
+
);
|
|
1757
|
+
|
|
1758
|
+
const skippedTools = importResult.tools.filter(
|
|
1759
|
+
(t: any) => t.status === "skipped",
|
|
1760
|
+
);
|
|
1761
|
+
const skippedSkills = importResult.skills.filter(
|
|
1762
|
+
(s: any) => s.status === "skipped",
|
|
1763
|
+
);
|
|
1764
|
+
const skippedScripts = importResult.scripts.filter(
|
|
1765
|
+
(sc: any) => sc.status === "skipped",
|
|
1766
|
+
);
|
|
1767
|
+
|
|
1768
|
+
const failedTools = importResult.tools.filter(
|
|
1769
|
+
(t: any) => t.status === "failed",
|
|
1770
|
+
);
|
|
1771
|
+
const failedSkills = importResult.skills.filter(
|
|
1772
|
+
(s: any) => s.status === "failed",
|
|
1773
|
+
);
|
|
1774
|
+
const failedScripts = importResult.scripts.filter(
|
|
1775
|
+
(sc: any) => sc.status === "failed",
|
|
1776
|
+
);
|
|
1777
|
+
|
|
1778
|
+
const importedCount =
|
|
1779
|
+
importedTools.length + importedSkills.length + importedScripts.length;
|
|
1780
|
+
const skippedCount =
|
|
1781
|
+
skippedTools.length + skippedSkills.length + skippedScripts.length;
|
|
1782
|
+
const failedCount =
|
|
1783
|
+
failedTools.length + failedSkills.length + failedScripts.length;
|
|
1784
|
+
|
|
1785
|
+
if (!options.quiet) {
|
|
1786
|
+
console.log("\nImporting artifacts:");
|
|
1787
|
+
for (const item of [
|
|
1788
|
+
...importResult.tools,
|
|
1789
|
+
...importResult.skills,
|
|
1790
|
+
...importResult.scripts,
|
|
1791
|
+
]) {
|
|
1792
|
+
const type = importResult.tools.includes(item)
|
|
1793
|
+
? "tool"
|
|
1794
|
+
: importResult.skills.includes(item)
|
|
1795
|
+
? "skill"
|
|
1796
|
+
: "script";
|
|
1797
|
+
if (item.status === "imported") {
|
|
1798
|
+
console.log(` [${type}] ${item.name} -> ${item.path} (imported)`);
|
|
1799
|
+
} else if (item.status === "skipped") {
|
|
1800
|
+
console.log(
|
|
1801
|
+
` [${type}] ${item.name} -> ${item.path} (skipped, already exists - use --overwrite to replace)`,
|
|
1802
|
+
);
|
|
1803
|
+
} else {
|
|
1804
|
+
console.log(
|
|
1805
|
+
` [${type}] ${item.name} (failed: ${item.error || "unknown error"})`,
|
|
1806
|
+
);
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1810
|
+
if (failedCount > 0) {
|
|
1811
|
+
console.log(
|
|
1812
|
+
`\nCompleted with ${failedCount} error${failedCount === 1 ? "" : "s"}. Successfully imported ${importedCount} items, ${skippedCount} skipped.`,
|
|
1813
|
+
);
|
|
1814
|
+
} else {
|
|
1815
|
+
console.log(
|
|
1816
|
+
`\nSuccessfully imported ${importedCount} item${importedCount === 1 ? "" : "s"} (${importedTools.length} tool${importedTools.length === 1 ? "" : "s"}, ${importedSkills.length} skill${importedSkills.length === 1 ? "" : "s"}, ${importedScripts.length} script${importedScripts.length === 1 ? "" : "s"}).`,
|
|
1817
|
+
);
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
const success = failedCount === 0 || importedCount > 0;
|
|
1822
|
+
if (!success) {
|
|
1823
|
+
process.exitCode = 1;
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
return {
|
|
1827
|
+
success,
|
|
1828
|
+
manifest,
|
|
1829
|
+
siteUrl,
|
|
1830
|
+
manifestUrl,
|
|
1831
|
+
result: importResult,
|
|
1832
|
+
importedCount,
|
|
1833
|
+
skippedCount,
|
|
1834
|
+
failedCount,
|
|
1835
|
+
};
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1604
1838
|
/**
|
|
1605
1839
|
* Main dispatcher for the `agent` command group.
|
|
1606
1840
|
*/
|
|
@@ -1714,9 +1948,25 @@ export async function runAgentCommand(
|
|
|
1714
1948
|
return await runAgentModel(subaction, modelId, actualOptions);
|
|
1715
1949
|
}
|
|
1716
1950
|
|
|
1951
|
+
case "import": {
|
|
1952
|
+
const url = actualArgs[0];
|
|
1953
|
+
if (!url) {
|
|
1954
|
+
console.error(
|
|
1955
|
+
"Error: Discovery URL or site URL required. Usage: shadow-claw agent import <url> [options]",
|
|
1956
|
+
);
|
|
1957
|
+
process.exitCode = 1;
|
|
1958
|
+
return {
|
|
1959
|
+
success: false,
|
|
1960
|
+
error:
|
|
1961
|
+
"Discovery URL or site URL required. Usage: shadow-claw agent import <url> [options]",
|
|
1962
|
+
};
|
|
1963
|
+
}
|
|
1964
|
+
return await runAgentImport(url, actualOptions);
|
|
1965
|
+
}
|
|
1966
|
+
|
|
1717
1967
|
default: {
|
|
1718
1968
|
console.log(
|
|
1719
|
-
"Usage: shadow-claw agent <init|model|skills|tools|tool|skill|run> [args...]",
|
|
1969
|
+
"Usage: shadow-claw agent <init|model|skills|tools|tool|skill|import|run> [args...]",
|
|
1720
1970
|
);
|
|
1721
1971
|
}
|
|
1722
1972
|
}
|
|
@@ -544,6 +544,13 @@
|
|
|
544
544
|
>
|
|
545
545
|
🌱 Block Garden Knowledge Hub
|
|
546
546
|
</button>
|
|
547
|
+
<button
|
|
548
|
+
class="tools__preset-btn"
|
|
549
|
+
data-url="https://xt-ml.github.io/shadow-claw-agent-cli-weather"
|
|
550
|
+
type="button"
|
|
551
|
+
>
|
|
552
|
+
🌦️ Weather Agent (Open-Meteo)
|
|
553
|
+
</button>
|
|
547
554
|
</div>
|
|
548
555
|
</div>
|
|
549
556
|
|
|
@@ -12,11 +12,14 @@ import {
|
|
|
12
12
|
} from "./utils/handleInvoke.js";
|
|
13
13
|
import { executeNodeTransformersCompletion } from "./tools/node-transformers-executor.js";
|
|
14
14
|
import { executeNodeLlamafileCompletion } from "./tools/node-llamafile-executor.js";
|
|
15
|
+
import { setHeadlessEvalExecutor } from "./utils/sandboxedEval.js";
|
|
16
|
+
import { nativeEvalExecutor } from "./utils/native-eval-executor.js";
|
|
15
17
|
|
|
16
18
|
// Automatically wire native OS process execution for headless CLI agent
|
|
17
19
|
setHeadlessBashExecutor(nativeBashExecutor);
|
|
18
20
|
setNodeTransformersCompletionExecutor(executeNodeTransformersCompletion);
|
|
19
21
|
setNodeLlamafileCompletionExecutor(executeNodeLlamafileCompletion);
|
|
22
|
+
setHeadlessEvalExecutor(nativeEvalExecutor);
|
|
20
23
|
|
|
21
24
|
export { executeTool } from "./utils/executeTool.js";
|
|
22
25
|
export { executeToolChain } from "./utils/toolChain.js";
|
|
@@ -52,6 +55,16 @@ export {
|
|
|
52
55
|
export { TOOL_DEFINITIONS } from "../subsystems/tools/index.js";
|
|
53
56
|
export { DEFAULT_BUILTIN_PROFILE } from "../subsystems/tools/builtin-profiles.js";
|
|
54
57
|
export { loadDeclarativeTools } from "../subsystems/tools/declarative.js";
|
|
58
|
+
export {
|
|
59
|
+
resolveDiscoveryUrl,
|
|
60
|
+
fetchDiscoveryManifest,
|
|
61
|
+
} from "../subsystems/tools/remote/discovery.js";
|
|
62
|
+
export {
|
|
63
|
+
importRemoteArtifacts,
|
|
64
|
+
importRemoteTool,
|
|
65
|
+
importRemoteSkill,
|
|
66
|
+
importRemoteScript,
|
|
67
|
+
} from "../subsystems/tools/remote/importArtifacts.js";
|
|
55
68
|
export {
|
|
56
69
|
getProvider,
|
|
57
70
|
getDefaultProvider,
|
|
@@ -81,4 +94,5 @@ export { executeNodeTransformersCompletion } from "./tools/node-transformers-exe
|
|
|
81
94
|
export { createTransformersRuntimeService } from "../server/services/transformers-runtime.js";
|
|
82
95
|
export { cleanupAllLlamafileProcesses } from "../server/services/llamafile-manager.js";
|
|
83
96
|
export { nativeBashExecutor, setHeadlessBashExecutor };
|
|
97
|
+
export { nativeEvalExecutor, setHeadlessEvalExecutor };
|
|
84
98
|
export type * from "./headless-types.js";
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import type { ShadowClawDatabase } from "../db/types.js";
|
|
7
|
+
import type { ImportResult } from "../subsystems/tools/remote/types.js";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Dedicated agent configuration section in shadow-claw.config.json.
|
|
@@ -235,3 +236,41 @@ export interface AgentModelResult {
|
|
|
235
236
|
error?: string;
|
|
236
237
|
[key: string]: unknown;
|
|
237
238
|
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Options for runAgentImport.
|
|
242
|
+
*/
|
|
243
|
+
export interface AgentImportOptions {
|
|
244
|
+
workspace?: string;
|
|
245
|
+
group?: string;
|
|
246
|
+
databaseDir?: string;
|
|
247
|
+
cacheDir?: string;
|
|
248
|
+
tools?: string | string[];
|
|
249
|
+
skills?: string | string[];
|
|
250
|
+
scripts?: string | string[];
|
|
251
|
+
all?: boolean;
|
|
252
|
+
overwrite?: boolean;
|
|
253
|
+
autoEnable?: boolean;
|
|
254
|
+
targetSubdir?: string;
|
|
255
|
+
siteSlug?: string;
|
|
256
|
+
quiet?: boolean;
|
|
257
|
+
verbose?: boolean;
|
|
258
|
+
fetchFn?: typeof fetch;
|
|
259
|
+
[key: string]: unknown;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Result returned by runAgentImport.
|
|
264
|
+
*/
|
|
265
|
+
export interface AgentImportResult {
|
|
266
|
+
success: boolean;
|
|
267
|
+
manifest?: unknown;
|
|
268
|
+
siteUrl?: string;
|
|
269
|
+
manifestUrl?: string;
|
|
270
|
+
result?: ImportResult;
|
|
271
|
+
importedCount?: number;
|
|
272
|
+
skippedCount?: number;
|
|
273
|
+
failedCount?: number;
|
|
274
|
+
error?: string;
|
|
275
|
+
[key: string]: unknown;
|
|
276
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { nativeEvalExecutor } from "./native-eval-executor.js";
|
|
2
|
+
import { sandboxedEval, setHeadlessEvalExecutor } from "./sandboxedEval.js";
|
|
3
|
+
|
|
4
|
+
describe("nativeEvalExecutor", () => {
|
|
5
|
+
it("evaluates javascript expressions in node:vm", async () => {
|
|
6
|
+
const res = await nativeEvalExecutor("return 2 + 2;", 5000, false);
|
|
7
|
+
expect(res).toEqual({ ok: true, value: 4 });
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it("handles injected $PIPE_DATA and data parameter", async () => {
|
|
11
|
+
const res = await nativeEvalExecutor(
|
|
12
|
+
"const d = JSON.parse(data); return d.val * 3;",
|
|
13
|
+
5000,
|
|
14
|
+
false,
|
|
15
|
+
JSON.stringify({ val: 10 }),
|
|
16
|
+
);
|
|
17
|
+
expect(res).toEqual({ ok: true, value: 30 });
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("integrates with sandboxedEval when Worker is undefined", async () => {
|
|
21
|
+
setHeadlessEvalExecutor(nativeEvalExecutor);
|
|
22
|
+
const origWorker = (globalThis as any).Worker;
|
|
23
|
+
try {
|
|
24
|
+
delete (globalThis as any).Worker;
|
|
25
|
+
const res = await sandboxedEval("return 100 * 2;");
|
|
26
|
+
expect(res).toEqual({ ok: true, value: 200 });
|
|
27
|
+
} finally {
|
|
28
|
+
(globalThis as any).Worker = origWorker;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("handles evaluation timeout gracefully", async () => {
|
|
33
|
+
const res = await nativeEvalExecutor("while(true) {}", 50, false);
|
|
34
|
+
expect(res.ok).toBe(false);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { runInNewContext } from "node:vm";
|
|
2
|
+
import type { HeadlessEvalExecutor } from "./sandboxedEval.js";
|
|
3
|
+
import { setHeadlessEvalExecutor } from "./sandboxedEval.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Native Node.js node:vm executor for headless CLI / server mode.
|
|
7
|
+
*/
|
|
8
|
+
export const nativeEvalExecutor: HeadlessEvalExecutor = async (
|
|
9
|
+
code,
|
|
10
|
+
timeoutMs,
|
|
11
|
+
allowFullInternetAccess = false,
|
|
12
|
+
data,
|
|
13
|
+
) => {
|
|
14
|
+
try {
|
|
15
|
+
const sandbox: any = {
|
|
16
|
+
console,
|
|
17
|
+
URL,
|
|
18
|
+
TextEncoder,
|
|
19
|
+
TextDecoder,
|
|
20
|
+
JSON,
|
|
21
|
+
Math,
|
|
22
|
+
Date,
|
|
23
|
+
parseInt,
|
|
24
|
+
parseFloat,
|
|
25
|
+
encodeURIComponent,
|
|
26
|
+
decodeURIComponent,
|
|
27
|
+
setTimeout,
|
|
28
|
+
clearTimeout,
|
|
29
|
+
data: data ?? "",
|
|
30
|
+
$PIPE_DATA: data ?? "",
|
|
31
|
+
fetch: allowFullInternetAccess ? globalThis.fetch : undefined,
|
|
32
|
+
};
|
|
33
|
+
const wrappedCode = `(async () => {
|
|
34
|
+
"use strict";
|
|
35
|
+
${code}
|
|
36
|
+
})()`;
|
|
37
|
+
const result = await Promise.race([
|
|
38
|
+
runInNewContext(wrappedCode, sandbox, { timeout: timeoutMs }),
|
|
39
|
+
new Promise((_, reject) =>
|
|
40
|
+
setTimeout(
|
|
41
|
+
() =>
|
|
42
|
+
reject(new Error(`Execution timed out after ${timeoutMs / 1000}s`)),
|
|
43
|
+
timeoutMs,
|
|
44
|
+
),
|
|
45
|
+
),
|
|
46
|
+
]);
|
|
47
|
+
return { ok: true, value: result };
|
|
48
|
+
} catch (err: any) {
|
|
49
|
+
return {
|
|
50
|
+
ok: false,
|
|
51
|
+
error: err && err.message ? err.message : String(err),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// Register with sandboxedEval when loaded
|
|
57
|
+
setHeadlessEvalExecutor(nativeEvalExecutor);
|
|
58
|
+
(globalThis as any).__headlessEvalExecutor = nativeEvalExecutor;
|
|
@@ -87,6 +87,21 @@ function getBlockedGlobals(allowFullInternetAccess: boolean): string[] {
|
|
|
87
87
|
return [...BASE_BLOCKED_GLOBALS, "fetch"];
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
export type HeadlessEvalExecutor = (
|
|
91
|
+
code: string,
|
|
92
|
+
timeoutMs: number,
|
|
93
|
+
allowFullInternetAccess: boolean,
|
|
94
|
+
data?: string,
|
|
95
|
+
) => Promise<{ ok: true; value: unknown } | { ok: false; error: string }>;
|
|
96
|
+
|
|
97
|
+
let _headlessEvalExecutor: HeadlessEvalExecutor | null = null;
|
|
98
|
+
|
|
99
|
+
export function setHeadlessEvalExecutor(
|
|
100
|
+
executor: HeadlessEvalExecutor | null,
|
|
101
|
+
): void {
|
|
102
|
+
_headlessEvalExecutor = executor;
|
|
103
|
+
}
|
|
104
|
+
|
|
90
105
|
/**
|
|
91
106
|
* Execute user-supplied JavaScript in a sandboxed, timeout-enforced context.
|
|
92
107
|
*/
|
|
@@ -96,6 +111,26 @@ export async function sandboxedEval(
|
|
|
96
111
|
allowFullInternetAccess: boolean = false,
|
|
97
112
|
data?: string,
|
|
98
113
|
): Promise<{ ok: true; value: unknown } | { ok: false; error: string }> {
|
|
114
|
+
if (typeof Worker === "undefined") {
|
|
115
|
+
if (_headlessEvalExecutor) {
|
|
116
|
+
return _headlessEvalExecutor(
|
|
117
|
+
code,
|
|
118
|
+
timeoutMs,
|
|
119
|
+
allowFullInternetAccess,
|
|
120
|
+
data,
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
const globalExecutor = (globalThis as any).__headlessEvalExecutor;
|
|
124
|
+
if (typeof globalExecutor === "function") {
|
|
125
|
+
return globalExecutor(code, timeoutMs, allowFullInternetAccess, data);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
ok: false,
|
|
130
|
+
error: "Web Workers are not supported in this environment.",
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
99
134
|
// Build the worker source inline via a Blob URL
|
|
100
135
|
const workerSource = buildWorkerSource(code, allowFullInternetAccess, data);
|
|
101
136
|
const blob = new Blob([workerSource], { type: "application/javascript" });
|
|
@@ -266,6 +301,7 @@ const restoreGlobals = applyGlobalShadows();
|
|
|
266
301
|
const Function = undefined;
|
|
267
302
|
${allowFullInternetAccess ? "" : "const fetch = undefined;"}
|
|
268
303
|
const $PIPE_DATA = ${JSON.stringify(data ?? "")};
|
|
304
|
+
const data = $PIPE_DATA;
|
|
269
305
|
|
|
270
306
|
${code}
|
|
271
307
|
})();
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as e}from"./chunk-hOceZVB92.js";export{e as orchestratorStore};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{n as e}from"./chunk-zvi71-77.js";export{e as executeNativeAiTask};
|