daycare-cli 2026.2.26 → 2026.2.27
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/dist/engine/agents/agent.d.ts +2 -0
- package/dist/engine/agents/agent.d.ts.map +1 -1
- package/dist/engine/agents/agent.js +7 -3
- package/dist/engine/agents/agent.js.map +1 -1
- package/dist/engine/agents/agentSystem.d.ts +5 -0
- package/dist/engine/agents/agentSystem.d.ts.map +1 -1
- package/dist/engine/agents/agentSystem.js +16 -1
- package/dist/engine/agents/agentSystem.js.map +1 -1
- package/dist/engine/agents/agentSystem.spec.js +59 -0
- package/dist/engine/agents/agentSystem.spec.js.map +1 -1
- package/dist/engine/agents/ops/agentLoopRun.d.ts +0 -2
- package/dist/engine/agents/ops/agentLoopRun.d.ts.map +1 -1
- package/dist/engine/agents/ops/agentLoopRun.js +4 -7
- package/dist/engine/agents/ops/agentLoopRun.js.map +1 -1
- package/dist/engine/agents/ops/agentLoopRun.spec.js +21 -24
- package/dist/engine/agents/ops/agentLoopRun.spec.js.map +1 -1
- package/dist/engine/apps/appExecute.spec.js +2 -10
- package/dist/engine/apps/appExecute.spec.js.map +1 -1
- package/dist/engine/apps/appInstallToolBuild.js +1 -1
- package/dist/engine/apps/appInstallToolBuild.js.map +1 -1
- package/dist/engine/apps/appInstallToolBuild.spec.js +1 -5
- package/dist/engine/apps/appInstallToolBuild.spec.js.map +1 -1
- package/dist/engine/apps/appRuleToolBuild.spec.js +1 -5
- package/dist/engine/apps/appRuleToolBuild.spec.js.map +1 -1
- package/dist/engine/apps/appToolExecutorBuild.spec.js +1 -5
- package/dist/engine/apps/appToolExecutorBuild.spec.js.map +1 -1
- package/dist/engine/engine.d.ts.map +1 -1
- package/dist/engine/engine.js +10 -0
- package/dist/engine/engine.js.map +1 -1
- package/dist/engine/friends/usertagGenerate.d.ts +6 -0
- package/dist/engine/friends/usertagGenerate.d.ts.map +1 -0
- package/dist/engine/friends/usertagGenerate.js +311 -0
- package/dist/engine/friends/usertagGenerate.js.map +1 -0
- package/dist/engine/friends/usertagGenerate.spec.d.ts +2 -0
- package/dist/engine/friends/usertagGenerate.spec.d.ts.map +1 -0
- package/dist/engine/friends/usertagGenerate.spec.js +13 -0
- package/dist/engine/friends/usertagGenerate.spec.js.map +1 -0
- package/dist/engine/modules/executablePrompts/executablePromptExpand.spec.js +1 -5
- package/dist/engine/modules/executablePrompts/executablePromptExpand.spec.js.map +1 -1
- package/dist/engine/modules/monty/montyPythonTypeFromSchemaRuntime.spec.js +1 -5
- package/dist/engine/modules/monty/montyPythonTypeFromSchemaRuntime.spec.js.map +1 -1
- package/dist/engine/modules/rlm/rlmExecute.spec.js +1 -5
- package/dist/engine/modules/rlm/rlmExecute.spec.js.map +1 -1
- package/dist/engine/modules/rlm/rlmRestore.spec.js +1 -5
- package/dist/engine/modules/rlm/rlmRestore.spec.js.map +1 -1
- package/dist/engine/modules/rlm/rlmTool.spec.js +1 -5
- package/dist/engine/modules/rlm/rlmTool.spec.js.map +1 -1
- package/dist/engine/modules/say/sayFileResolve.d.ts +4 -5
- package/dist/engine/modules/say/sayFileResolve.d.ts.map +1 -1
- package/dist/engine/modules/say/sayFileResolve.js +24 -14
- package/dist/engine/modules/say/sayFileResolve.js.map +1 -1
- package/dist/engine/modules/say/sayFileResolve.spec.js +28 -29
- package/dist/engine/modules/say/sayFileResolve.spec.js.map +1 -1
- package/dist/engine/modules/toolResolver.spec.js +1 -5
- package/dist/engine/modules/toolResolver.spec.js.map +1 -1
- package/dist/engine/modules/tools/agentCompactTool.spec.js +1 -5
- package/dist/engine/modules/tools/agentCompactTool.spec.js.map +1 -1
- package/dist/engine/modules/tools/agentResetTool.spec.js +1 -5
- package/dist/engine/modules/tools/agentResetTool.spec.js.map +1 -1
- package/dist/engine/modules/tools/background.spec.js +3 -11
- package/dist/engine/modules/tools/background.spec.js.map +1 -1
- package/dist/engine/modules/tools/channelCreateTool.spec.js +1 -5
- package/dist/engine/modules/tools/channelCreateTool.spec.js.map +1 -1
- package/dist/engine/modules/tools/channelHistoryTool.spec.js +1 -5
- package/dist/engine/modules/tools/channelHistoryTool.spec.js.map +1 -1
- package/dist/engine/modules/tools/channelMemberTool.spec.js +1 -5
- package/dist/engine/modules/tools/channelMemberTool.spec.js.map +1 -1
- package/dist/engine/modules/tools/channelSendTool.spec.js +1 -5
- package/dist/engine/modules/tools/channelSendTool.spec.js.map +1 -1
- package/dist/engine/modules/tools/friendAddToolBuild.d.ts +7 -0
- package/dist/engine/modules/tools/friendAddToolBuild.d.ts.map +1 -0
- package/dist/engine/modules/tools/friendAddToolBuild.js +163 -0
- package/dist/engine/modules/tools/friendAddToolBuild.js.map +1 -0
- package/dist/engine/modules/tools/friendAddToolBuild.spec.d.ts +2 -0
- package/dist/engine/modules/tools/friendAddToolBuild.spec.d.ts.map +1 -0
- package/dist/engine/modules/tools/friendAddToolBuild.spec.js +151 -0
- package/dist/engine/modules/tools/friendAddToolBuild.spec.js.map +1 -0
- package/dist/engine/modules/tools/friendRemoveToolBuild.d.ts +7 -0
- package/dist/engine/modules/tools/friendRemoveToolBuild.d.ts.map +1 -0
- package/dist/engine/modules/tools/friendRemoveToolBuild.js +174 -0
- package/dist/engine/modules/tools/friendRemoveToolBuild.js.map +1 -0
- package/dist/engine/modules/tools/friendRemoveToolBuild.spec.d.ts +2 -0
- package/dist/engine/modules/tools/friendRemoveToolBuild.spec.d.ts.map +1 -0
- package/dist/engine/modules/tools/friendRemoveToolBuild.spec.js +172 -0
- package/dist/engine/modules/tools/friendRemoveToolBuild.spec.js.map +1 -0
- package/dist/engine/modules/tools/friendSendToolBuild.d.ts +7 -0
- package/dist/engine/modules/tools/friendSendToolBuild.d.ts.map +1 -0
- package/dist/engine/modules/tools/friendSendToolBuild.js +104 -0
- package/dist/engine/modules/tools/friendSendToolBuild.js.map +1 -0
- package/dist/engine/modules/tools/friendSendToolBuild.spec.d.ts +2 -0
- package/dist/engine/modules/tools/friendSendToolBuild.spec.d.ts.map +1 -0
- package/dist/engine/modules/tools/friendSendToolBuild.spec.js +120 -0
- package/dist/engine/modules/tools/friendSendToolBuild.spec.js.map +1 -0
- package/dist/engine/modules/tools/friendShareSubuserToolBuild.d.ts +7 -0
- package/dist/engine/modules/tools/friendShareSubuserToolBuild.d.ts.map +1 -0
- package/dist/engine/modules/tools/friendShareSubuserToolBuild.js +133 -0
- package/dist/engine/modules/tools/friendShareSubuserToolBuild.js.map +1 -0
- package/dist/engine/modules/tools/friendShareSubuserToolBuild.spec.d.ts +2 -0
- package/dist/engine/modules/tools/friendShareSubuserToolBuild.spec.d.ts.map +1 -0
- package/dist/engine/modules/tools/friendShareSubuserToolBuild.spec.js +119 -0
- package/dist/engine/modules/tools/friendShareSubuserToolBuild.spec.js.map +1 -0
- package/dist/engine/modules/tools/friendUnshareSubuserToolBuild.d.ts +7 -0
- package/dist/engine/modules/tools/friendUnshareSubuserToolBuild.d.ts.map +1 -0
- package/dist/engine/modules/tools/friendUnshareSubuserToolBuild.js +118 -0
- package/dist/engine/modules/tools/friendUnshareSubuserToolBuild.js.map +1 -0
- package/dist/engine/modules/tools/friendUnshareSubuserToolBuild.spec.d.ts +2 -0
- package/dist/engine/modules/tools/friendUnshareSubuserToolBuild.spec.d.ts.map +1 -0
- package/dist/engine/modules/tools/friendUnshareSubuserToolBuild.spec.js +100 -0
- package/dist/engine/modules/tools/friendUnshareSubuserToolBuild.spec.js.map +1 -0
- package/dist/engine/modules/tools/image-generation.d.ts.map +1 -1
- package/dist/engine/modules/tools/image-generation.js +26 -10
- package/dist/engine/modules/tools/image-generation.js.map +1 -1
- package/dist/engine/modules/tools/image-generation.spec.js +13 -10
- package/dist/engine/modules/tools/image-generation.spec.js.map +1 -1
- package/dist/engine/modules/tools/mermaid-png.d.ts.map +1 -1
- package/dist/engine/modules/tools/mermaid-png.js +16 -11
- package/dist/engine/modules/tools/mermaid-png.js.map +1 -1
- package/dist/engine/modules/tools/mermaid-png.spec.js +20 -24
- package/dist/engine/modules/tools/mermaid-png.spec.js.map +1 -1
- package/dist/engine/modules/tools/pdf-process.d.ts.map +1 -1
- package/dist/engine/modules/tools/pdf-process.js +10 -38
- package/dist/engine/modules/tools/pdf-process.js.map +1 -1
- package/dist/engine/modules/tools/pdf-process.spec.js +15 -5
- package/dist/engine/modules/tools/pdf-process.spec.js.map +1 -1
- package/dist/engine/modules/tools/permanentAgentToolBuild.spec.js +5 -13
- package/dist/engine/modules/tools/permanentAgentToolBuild.spec.js.map +1 -1
- package/dist/engine/modules/tools/send-file.d.ts.map +1 -1
- package/dist/engine/modules/tools/send-file.js +20 -11
- package/dist/engine/modules/tools/send-file.js.map +1 -1
- package/dist/engine/modules/tools/sendUserMessageTool.spec.js +1 -5
- package/dist/engine/modules/tools/sendUserMessageTool.spec.js.map +1 -1
- package/dist/engine/modules/tools/sessionHistoryToolBuild.spec.js +1 -2
- package/dist/engine/modules/tools/sessionHistoryToolBuild.spec.js.map +1 -1
- package/dist/engine/modules/tools/signal.spec.js +1 -5
- package/dist/engine/modules/tools/signal.spec.js.map +1 -1
- package/dist/engine/modules/tools/signalEventsCsvToolBuild.spec.js +1 -5
- package/dist/engine/modules/tools/signalEventsCsvToolBuild.spec.js.map +1 -1
- package/dist/engine/modules/tools/signalSubscribeToolBuild.spec.js +1 -5
- package/dist/engine/modules/tools/signalSubscribeToolBuild.spec.js.map +1 -1
- package/dist/engine/modules/tools/signalUnsubscribeToolBuild.spec.js +1 -5
- package/dist/engine/modules/tools/signalUnsubscribeToolBuild.spec.js.map +1 -1
- package/dist/engine/modules/tools/skillToolBuild.js +3 -3
- package/dist/engine/modules/tools/skillToolBuild.js.map +1 -1
- package/dist/engine/modules/tools/skillToolBuild.spec.js +12 -9
- package/dist/engine/modules/tools/skillToolBuild.spec.js.map +1 -1
- package/dist/engine/modules/tools/subuserConfigureToolBuild.spec.js +1 -2
- package/dist/engine/modules/tools/subuserConfigureToolBuild.spec.js.map +1 -1
- package/dist/engine/modules/tools/subuserCreateToolBuild.spec.js +1 -2
- package/dist/engine/modules/tools/subuserCreateToolBuild.spec.js.map +1 -1
- package/dist/engine/modules/tools/subuserListToolBuild.spec.js +1 -2
- package/dist/engine/modules/tools/subuserListToolBuild.spec.js.map +1 -1
- package/dist/engine/modules/tools/topologyToolBuild.d.ts.map +1 -1
- package/dist/engine/modules/tools/topologyToolBuild.js +111 -2
- package/dist/engine/modules/tools/topologyToolBuild.js.map +1 -1
- package/dist/engine/modules/tools/topologyToolBuild.spec.js +99 -2
- package/dist/engine/modules/tools/topologyToolBuild.spec.js.map +1 -1
- package/dist/engine/modules/tools/types.d.ts +3 -4
- package/dist/engine/modules/tools/types.d.ts.map +1 -1
- package/dist/plugins/dashboard/site/404.html +1 -1
- package/dist/plugins/dashboard/site/agent.html +1 -1
- package/dist/plugins/dashboard/site/agent.txt +1 -1
- package/dist/plugins/dashboard/site/agents.html +1 -1
- package/dist/plugins/dashboard/site/agents.txt +1 -1
- package/dist/plugins/dashboard/site/automations.html +1 -1
- package/dist/plugins/dashboard/site/automations.txt +1 -1
- package/dist/plugins/dashboard/site/connectors.html +1 -1
- package/dist/plugins/dashboard/site/connectors.txt +1 -1
- package/dist/plugins/dashboard/site/index.html +1 -1
- package/dist/plugins/dashboard/site/index.txt +1 -1
- package/dist/plugins/dashboard/site/memory.html +1 -1
- package/dist/plugins/dashboard/site/memory.txt +1 -1
- package/dist/plugins/dashboard/site/processes.html +1 -1
- package/dist/plugins/dashboard/site/processes.txt +1 -1
- package/dist/plugins/dashboard/site/providers.html +1 -1
- package/dist/plugins/dashboard/site/providers.txt +1 -1
- package/dist/plugins/dashboard/site/signals.html +1 -1
- package/dist/plugins/dashboard/site/signals.txt +1 -1
- package/dist/plugins/dashboard/site/telemetry.html +1 -1
- package/dist/plugins/dashboard/site/telemetry.txt +1 -1
- package/dist/plugins/dashboard/site/tools.html +1 -1
- package/dist/plugins/dashboard/site/tools.txt +1 -1
- package/dist/plugins/database/__tests__/plugin.spec.js +4 -2
- package/dist/plugins/database/__tests__/plugin.spec.js.map +1 -1
- package/dist/plugins/monty-python/tool.spec.js +1 -2
- package/dist/plugins/monty-python/tool.spec.js.map +1 -1
- package/dist/plugins/shell/processTools.js +1 -1
- package/dist/plugins/shell/processTools.js.map +1 -1
- package/dist/plugins/shell/processTools.spec.js +2 -3
- package/dist/plugins/shell/processTools.spec.js.map +1 -1
- package/dist/plugins/shell/tool.d.ts.map +1 -1
- package/dist/plugins/shell/tool.js +90 -486
- package/dist/plugins/shell/tool.js.map +1 -1
- package/dist/plugins/shell/tool.spec.js +11 -20
- package/dist/plugins/shell/tool.spec.js.map +1 -1
- package/dist/sandbox/sandbox.d.ts +26 -0
- package/dist/sandbox/sandbox.d.ts.map +1 -0
- package/dist/sandbox/sandbox.js +466 -0
- package/dist/sandbox/sandbox.js.map +1 -0
- package/dist/sandbox/sandbox.spec.d.ts +2 -0
- package/dist/sandbox/sandbox.spec.d.ts.map +1 -0
- package/dist/sandbox/sandbox.spec.js +167 -0
- package/dist/sandbox/sandbox.spec.js.map +1 -0
- package/dist/sandbox/sandboxCanRead.d.ts.map +1 -1
- package/dist/sandbox/sandboxCanRead.js +4 -8
- package/dist/sandbox/sandboxCanRead.js.map +1 -1
- package/dist/sandbox/sandboxCanRead.spec.js +17 -11
- package/dist/sandbox/sandboxCanRead.spec.js.map +1 -1
- package/dist/sandbox/sandboxFilesystemPolicyBuild.d.ts +1 -1
- package/dist/sandbox/sandboxFilesystemPolicyBuild.d.ts.map +1 -1
- package/dist/sandbox/sandboxFilesystemPolicyBuild.js +14 -6
- package/dist/sandbox/sandboxFilesystemPolicyBuild.js.map +1 -1
- package/dist/sandbox/sandboxFilesystemPolicyBuild.spec.js +7 -2
- package/dist/sandbox/sandboxFilesystemPolicyBuild.spec.js.map +1 -1
- package/dist/sandbox/sandboxReadDenyPathsBuild.d.ts +13 -0
- package/dist/sandbox/sandboxReadDenyPathsBuild.d.ts.map +1 -0
- package/dist/sandbox/sandboxReadDenyPathsBuild.js +28 -0
- package/dist/sandbox/sandboxReadDenyPathsBuild.js.map +1 -0
- package/dist/sandbox/sandboxReadDenyPathsBuild.spec.d.ts +2 -0
- package/dist/sandbox/sandboxReadDenyPathsBuild.spec.d.ts.map +1 -0
- package/dist/sandbox/sandboxReadDenyPathsBuild.spec.js +29 -0
- package/dist/sandbox/sandboxReadDenyPathsBuild.spec.js.map +1 -0
- package/dist/sandbox/sandboxTypes.d.ts +67 -0
- package/dist/sandbox/sandboxTypes.d.ts.map +1 -0
- package/dist/sandbox/sandboxTypes.js +2 -0
- package/dist/sandbox/sandboxTypes.js.map +1 -0
- package/dist/storage/agentsRepository.d.ts +1 -0
- package/dist/storage/agentsRepository.d.ts.map +1 -1
- package/dist/storage/agentsRepository.js +16 -0
- package/dist/storage/agentsRepository.js.map +1 -1
- package/dist/storage/agentsRepository.spec.js +45 -0
- package/dist/storage/agentsRepository.spec.js.map +1 -1
- package/dist/storage/connectionsRepository.d.ts +18 -0
- package/dist/storage/connectionsRepository.d.ts.map +1 -0
- package/dist/storage/connectionsRepository.js +163 -0
- package/dist/storage/connectionsRepository.js.map +1 -0
- package/dist/storage/connectionsRepository.spec.d.ts +2 -0
- package/dist/storage/connectionsRepository.spec.d.ts.map +1 -0
- package/dist/storage/connectionsRepository.spec.js +115 -0
- package/dist/storage/connectionsRepository.spec.js.map +1 -0
- package/dist/storage/databaseTypes.d.ts +19 -0
- package/dist/storage/databaseTypes.d.ts.map +1 -1
- package/dist/storage/migrations/20260222_add_usertag_connections.d.ts +7 -0
- package/dist/storage/migrations/20260222_add_usertag_connections.d.ts.map +1 -0
- package/dist/storage/migrations/20260222_add_usertag_connections.js +32 -0
- package/dist/storage/migrations/20260222_add_usertag_connections.js.map +1 -0
- package/dist/storage/migrations/20260222_add_usertag_connections.spec.d.ts +2 -0
- package/dist/storage/migrations/20260222_add_usertag_connections.spec.d.ts.map +1 -0
- package/dist/storage/migrations/20260222_add_usertag_connections.spec.js +55 -0
- package/dist/storage/migrations/20260222_add_usertag_connections.spec.js.map +1 -0
- package/dist/storage/migrations/_migrations.d.ts.map +1 -1
- package/dist/storage/migrations/_migrations.js +3 -1
- package/dist/storage/migrations/_migrations.js.map +1 -1
- package/dist/storage/storage.d.ts +3 -0
- package/dist/storage/storage.d.ts.map +1 -1
- package/dist/storage/storage.js +35 -3
- package/dist/storage/storage.js.map +1 -1
- package/dist/storage/storage.spec.js +1 -0
- package/dist/storage/storage.spec.js.map +1 -1
- package/dist/storage/usersRepository.d.ts +2 -0
- package/dist/storage/usersRepository.d.ts.map +1 -1
- package/dist/storage/usersRepository.js +43 -2
- package/dist/storage/usersRepository.js.map +1 -1
- package/dist/storage/usersRepository.spec.js +9 -2
- package/dist/storage/usersRepository.spec.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- /package/dist/plugins/dashboard/site/_next/static/{X_oqQhoSTmj1_qmNPx-r5 → Hr0soHgJ1L7WevXil6GIk}/_buildManifest.js +0 -0
- /package/dist/plugins/dashboard/site/_next/static/{X_oqQhoSTmj1_qmNPx-r5 → Hr0soHgJ1L7WevXil6GIk}/_ssgManifest.js +0 -0
|
@@ -1,25 +1,10 @@
|
|
|
1
|
-
import { promises as fs } from "node:fs";
|
|
2
|
-
import os from "node:os";
|
|
3
1
|
import path from "node:path";
|
|
4
2
|
import { Type } from "@sinclair/typebox";
|
|
5
3
|
import { toolExecutionResultOutcomeWithTyped, toolMessageTextExtract } from "../../engine/modules/tools/toolReturnOutcome.js";
|
|
6
|
-
import { resolveWorkspacePath } from "../../engine/permissions.js";
|
|
7
|
-
import { isWithinSecure, openSecure } from "../../sandbox/pathResolveSecure.js";
|
|
8
|
-
import { runInSandbox } from "../../sandbox/runtime.js";
|
|
9
|
-
import { sandboxAllowedDomainsResolve } from "../../sandbox/sandboxAllowedDomainsResolve.js";
|
|
10
|
-
import { sandboxAllowedDomainsValidate } from "../../sandbox/sandboxAllowedDomainsValidate.js";
|
|
11
|
-
import { sandboxCanRead } from "../../sandbox/sandboxCanRead.js";
|
|
12
|
-
import { sandboxCanWrite } from "../../sandbox/sandboxCanWrite.js";
|
|
13
|
-
import { sandboxFilesystemPolicyBuild } from "../../sandbox/sandboxFilesystemPolicyBuild.js";
|
|
14
|
-
import { envNormalize } from "../../util/envNormalize.js";
|
|
15
4
|
import { stringTruncateTail } from "../../utils/stringTruncateTail.js";
|
|
16
5
|
const READ_MAX_LINES = 2000;
|
|
17
6
|
const READ_MAX_BYTES = 50 * 1024;
|
|
18
|
-
const MAX_EXEC_BUFFER = 1_000_000;
|
|
19
7
|
const MAX_EXEC_STREAM_OUTPUT_CHARS = 8_000;
|
|
20
|
-
const DEFAULT_EXEC_TIMEOUT = 30_000;
|
|
21
|
-
const UNICODE_SPACES = /[\u00A0\u2000-\u200A\u202F\u205F\u3000]/g;
|
|
22
|
-
const NARROW_NO_BREAK_SPACE = "\u202F";
|
|
23
8
|
const editItemSchema = Type.Object({
|
|
24
9
|
search: Type.String({ minLength: 1 }),
|
|
25
10
|
replace: Type.String(),
|
|
@@ -45,7 +30,6 @@ const execSchema = Type.Object({
|
|
|
45
30
|
cwd: Type.Optional(Type.String({ minLength: 1 })),
|
|
46
31
|
timeoutMs: Type.Optional(Type.Number({ minimum: 100, maximum: 300_000 })),
|
|
47
32
|
env: Type.Optional(envSchema),
|
|
48
|
-
home: Type.Optional(Type.String({ minLength: 1 })),
|
|
49
33
|
packageManagers: Type.Optional(Type.Array(Type.Union([
|
|
50
34
|
Type.Literal("dart"),
|
|
51
35
|
Type.Literal("dotnet"),
|
|
@@ -86,13 +70,38 @@ export function buildWorkspaceReadTool() {
|
|
|
86
70
|
returns: shellReturns,
|
|
87
71
|
execute: async (args, toolContext, toolCall) => {
|
|
88
72
|
const payload = args;
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
73
|
+
const readResult = await toolContext.sandbox.read({
|
|
74
|
+
path: payload.path,
|
|
75
|
+
offset: payload.offset,
|
|
76
|
+
limit: payload.limit
|
|
77
|
+
});
|
|
78
|
+
if (readResult.type === "image") {
|
|
79
|
+
const text = `Read image file: ${readResult.displayPath} [${readResult.mimeType}]`;
|
|
80
|
+
const toolMessage = buildToolMessage(toolCall, text, false, {
|
|
81
|
+
action: "read",
|
|
82
|
+
path: readResult.displayPath,
|
|
83
|
+
bytes: readResult.bytes,
|
|
84
|
+
mimeType: readResult.mimeType
|
|
85
|
+
});
|
|
86
|
+
toolMessage.content = [
|
|
87
|
+
{ type: "text", text },
|
|
88
|
+
{ type: "image", data: readResult.content.toString("base64"), mimeType: readResult.mimeType }
|
|
89
|
+
];
|
|
90
|
+
return toolExecutionResultOutcomeWithTyped(toolMessage, shellResultBuild(toolMessage, "read"));
|
|
92
91
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
92
|
+
if (readResult.type !== "text") {
|
|
93
|
+
throw new Error("Path is not a text or image file.");
|
|
94
|
+
}
|
|
95
|
+
const toolMessage = buildToolMessage(toolCall, readResult.content, false, {
|
|
96
|
+
action: "read",
|
|
97
|
+
path: readResult.displayPath,
|
|
98
|
+
bytes: readResult.bytes,
|
|
99
|
+
truncated: readResult.truncated,
|
|
100
|
+
truncatedBy: readResult.truncatedBy,
|
|
101
|
+
offset: payload.offset ?? null,
|
|
102
|
+
limit: payload.limit ?? null
|
|
103
|
+
});
|
|
104
|
+
return toolExecutionResultOutcomeWithTyped(toolMessage, shellResultBuild(toolMessage, "read"));
|
|
96
105
|
}
|
|
97
106
|
};
|
|
98
107
|
}
|
|
@@ -106,13 +115,19 @@ export function buildWorkspaceWriteTool() {
|
|
|
106
115
|
returns: shellReturns,
|
|
107
116
|
execute: async (args, toolContext, toolCall) => {
|
|
108
117
|
const payload = args;
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const
|
|
115
|
-
|
|
118
|
+
const writeResult = await toolContext.sandbox.write({
|
|
119
|
+
path: payload.path,
|
|
120
|
+
content: payload.content,
|
|
121
|
+
append: payload.append ?? false
|
|
122
|
+
});
|
|
123
|
+
const text = `${payload.append ? "Appended" : "Wrote"} ${writeResult.bytes} bytes to ${writeResult.sandboxPath}.`;
|
|
124
|
+
const toolMessage = buildToolMessage(toolCall, text, false, {
|
|
125
|
+
action: "write",
|
|
126
|
+
path: writeResult.sandboxPath,
|
|
127
|
+
bytes: writeResult.bytes,
|
|
128
|
+
append: payload.append ?? false
|
|
129
|
+
});
|
|
130
|
+
return toolExecutionResultOutcomeWithTyped(toolMessage, shellResultBuild(toolMessage, "write"));
|
|
116
131
|
}
|
|
117
132
|
};
|
|
118
133
|
}
|
|
@@ -126,13 +141,33 @@ export function buildWorkspaceEditTool() {
|
|
|
126
141
|
returns: shellReturns,
|
|
127
142
|
execute: async (args, toolContext, toolCall) => {
|
|
128
143
|
const payload = args;
|
|
129
|
-
const workingDir = toolContext.permissions.workingDir;
|
|
130
|
-
if (!workingDir) {
|
|
131
|
-
throw new Error("Workspace is not configured.");
|
|
132
|
-
}
|
|
133
144
|
ensureAbsolutePath(payload.path);
|
|
134
|
-
const
|
|
135
|
-
|
|
145
|
+
const readResult = await toolContext.sandbox.read({ path: payload.path, raw: true });
|
|
146
|
+
if (readResult.type !== "text") {
|
|
147
|
+
throw new Error("Path is not a text file.");
|
|
148
|
+
}
|
|
149
|
+
let updated = readResult.content;
|
|
150
|
+
const counts = [];
|
|
151
|
+
for (const edit of payload.edits) {
|
|
152
|
+
const { next, count } = applyEdit(updated, edit);
|
|
153
|
+
if (count === 0) {
|
|
154
|
+
const preview = edit.search.length > 80 ? `${edit.search.slice(0, 77)}...` : edit.search;
|
|
155
|
+
throw new Error(`Edit not applied: "${preview}" not found.`);
|
|
156
|
+
}
|
|
157
|
+
counts.push(count);
|
|
158
|
+
updated = next;
|
|
159
|
+
}
|
|
160
|
+
await toolContext.sandbox.write({ path: payload.path, content: updated });
|
|
161
|
+
const summary = counts
|
|
162
|
+
.map((count, index) => `edit ${index + 1}: ${count} replacement${count === 1 ? "" : "s"}`)
|
|
163
|
+
.join(", ");
|
|
164
|
+
const text = `Updated ${readResult.displayPath} (${summary}).`;
|
|
165
|
+
const toolMessage = buildToolMessage(toolCall, text, false, {
|
|
166
|
+
action: "edit",
|
|
167
|
+
path: readResult.displayPath,
|
|
168
|
+
edits: counts
|
|
169
|
+
});
|
|
170
|
+
return toolExecutionResultOutcomeWithTyped(toolMessage, shellResultBuild(toolMessage, "edit"));
|
|
136
171
|
}
|
|
137
172
|
};
|
|
138
173
|
}
|
|
@@ -140,230 +175,34 @@ export function buildExecTool() {
|
|
|
140
175
|
return {
|
|
141
176
|
tool: {
|
|
142
177
|
name: "exec",
|
|
143
|
-
description: "Execute a shell command inside the agent workspace (or a subdirectory). The cwd, if provided, must
|
|
178
|
+
description: "Execute a shell command inside the agent workspace (or a subdirectory). The cwd, if provided, must resolve inside the workspace. Exec uses the caller's granted write directories and global read access with a protected deny-list. Optional packageManagers language presets auto-allow ecosystem hosts (dart/dotnet/go/java/node/php/python/ruby/rust). Optional allowedDomains enables outbound access to specific domains (supports subdomain wildcards like *.example.com, no global wildcard). Returns stdout/stderr and failure details.",
|
|
144
179
|
parameters: execSchema
|
|
145
180
|
},
|
|
146
181
|
returns: shellReturns,
|
|
147
182
|
execute: async (args, toolContext, toolCall) => {
|
|
148
183
|
const payload = args;
|
|
149
|
-
const workingDir = toolContext.
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
throw new Error(domainIssues.join(" "));
|
|
166
|
-
}
|
|
167
|
-
const envOverrides = envNormalize(payload.env);
|
|
168
|
-
const env = envOverrides ? { ...process.env, ...envOverrides } : process.env;
|
|
169
|
-
const timeout = payload.timeoutMs ?? DEFAULT_EXEC_TIMEOUT;
|
|
170
|
-
const sandboxConfig = buildSandboxConfig(permissions, allowedDomains);
|
|
171
|
-
try {
|
|
172
|
-
const result = await runInSandbox(payload.command, sandboxConfig, {
|
|
173
|
-
cwd,
|
|
174
|
-
env,
|
|
175
|
-
home,
|
|
176
|
-
timeoutMs: timeout,
|
|
177
|
-
maxBufferBytes: MAX_EXEC_BUFFER
|
|
178
|
-
});
|
|
179
|
-
const stdout = toText(result.stdout);
|
|
180
|
-
const stderr = toText(result.stderr);
|
|
181
|
-
const text = formatExecOutput(stdout, stderr, false);
|
|
182
|
-
const toolMessage = buildToolMessage(toolCall, text, false, {
|
|
183
|
-
cwd: path.relative(workingDir, cwd) || "."
|
|
184
|
-
});
|
|
185
|
-
return toolExecutionResultOutcomeWithTyped(toolMessage, shellResultBuild(toolMessage, "exec"));
|
|
186
|
-
}
|
|
187
|
-
catch (error) {
|
|
188
|
-
const execError = error;
|
|
189
|
-
const stdout = toText(execError.stdout);
|
|
190
|
-
const stderr = toText(execError.stderr);
|
|
191
|
-
const text = formatExecOutput(stdout, stderr, true);
|
|
192
|
-
const toolMessage = buildToolMessage(toolCall, text, true, {
|
|
193
|
-
cwd: path.relative(workingDir, cwd) || ".",
|
|
194
|
-
exitCode: execError.code ?? null,
|
|
195
|
-
signal: execError.signal ?? null
|
|
196
|
-
});
|
|
197
|
-
return toolExecutionResultOutcomeWithTyped(toolMessage, shellResultBuild(toolMessage, "exec"));
|
|
198
|
-
}
|
|
184
|
+
const workingDir = toolContext.sandbox.workingDir;
|
|
185
|
+
const result = await toolContext.sandbox.exec({
|
|
186
|
+
command: payload.command,
|
|
187
|
+
cwd: payload.cwd,
|
|
188
|
+
timeoutMs: payload.timeoutMs,
|
|
189
|
+
env: payload.env,
|
|
190
|
+
packageManagers: payload.packageManagers,
|
|
191
|
+
allowedDomains: payload.allowedDomains
|
|
192
|
+
});
|
|
193
|
+
const text = formatExecOutput(result.stdout, result.stderr, result.failed);
|
|
194
|
+
const toolMessage = buildToolMessage(toolCall, text, result.failed, {
|
|
195
|
+
cwd: path.relative(workingDir, result.cwd) || ".",
|
|
196
|
+
exitCode: result.exitCode,
|
|
197
|
+
signal: result.signal
|
|
198
|
+
});
|
|
199
|
+
return toolExecutionResultOutcomeWithTyped(toolMessage, shellResultBuild(toolMessage, "exec"));
|
|
199
200
|
}
|
|
200
201
|
};
|
|
201
202
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
*/
|
|
206
|
-
async function handleReadSecure(resolvedPath, requestedPath, offset, limit, workingDir, toolCall) {
|
|
207
|
-
// Use lstat to check file type without following symlinks
|
|
208
|
-
const stats = await fs.lstat(resolvedPath);
|
|
209
|
-
if (stats.isSymbolicLink()) {
|
|
210
|
-
throw new Error("Cannot read symbolic link directly.");
|
|
211
|
-
}
|
|
212
|
-
if (!stats.isFile()) {
|
|
213
|
-
throw new Error("Path is not a file.");
|
|
214
|
-
}
|
|
215
|
-
const displayPath = formatDisplayPath(workingDir, resolvedPath);
|
|
216
|
-
const mimeType = await detectSupportedImageMimeTypeFromFile(resolvedPath);
|
|
217
|
-
if (mimeType) {
|
|
218
|
-
const imageBuffer = await readBinaryFileSecure(resolvedPath);
|
|
219
|
-
const text = `Read image file: ${displayPath} [${mimeType}]`;
|
|
220
|
-
const toolMessage = buildToolMessage(toolCall, text, false, {
|
|
221
|
-
action: "read",
|
|
222
|
-
path: displayPath,
|
|
223
|
-
bytes: stats.size,
|
|
224
|
-
mimeType
|
|
225
|
-
});
|
|
226
|
-
toolMessage.content = [
|
|
227
|
-
{ type: "text", text },
|
|
228
|
-
{ type: "image", data: imageBuffer.toString("base64"), mimeType }
|
|
229
|
-
];
|
|
230
|
-
return toolExecutionResultOutcomeWithTyped(toolMessage, shellResultBuild(toolMessage, "read"));
|
|
231
|
-
}
|
|
232
|
-
const textContent = await readTextFileSecure(resolvedPath);
|
|
233
|
-
const allLines = textContent.split("\n");
|
|
234
|
-
const totalFileLines = allLines.length;
|
|
235
|
-
const startLine = offset ? Math.max(0, offset - 1) : 0;
|
|
236
|
-
const startLineDisplay = startLine + 1;
|
|
237
|
-
if (startLine >= allLines.length) {
|
|
238
|
-
throw new Error(`Offset ${offset} is beyond end of file (${allLines.length} lines total)`);
|
|
239
|
-
}
|
|
240
|
-
let selectedContent;
|
|
241
|
-
let userLimitedLines;
|
|
242
|
-
if (limit !== undefined) {
|
|
243
|
-
const endLine = Math.min(startLine + limit, allLines.length);
|
|
244
|
-
selectedContent = allLines.slice(startLine, endLine).join("\n");
|
|
245
|
-
userLimitedLines = endLine - startLine;
|
|
246
|
-
}
|
|
247
|
-
else {
|
|
248
|
-
selectedContent = allLines.slice(startLine).join("\n");
|
|
249
|
-
}
|
|
250
|
-
const truncation = truncateHead(selectedContent);
|
|
251
|
-
let outputText;
|
|
252
|
-
if (truncation.firstLineExceedsLimit) {
|
|
253
|
-
const firstLineSize = formatSize(Buffer.byteLength(allLines[startLine] ?? "", "utf8"));
|
|
254
|
-
outputText = `[Line ${startLineDisplay} is ${firstLineSize}, exceeds ${formatSize(READ_MAX_BYTES)} limit. Use bash: sed -n '${startLineDisplay}p' ${requestedPath} | head -c ${READ_MAX_BYTES}]`;
|
|
255
|
-
}
|
|
256
|
-
else if (truncation.truncated) {
|
|
257
|
-
const endLineDisplay = startLineDisplay + truncation.outputLines - 1;
|
|
258
|
-
const nextOffset = endLineDisplay + 1;
|
|
259
|
-
outputText = truncation.content;
|
|
260
|
-
if (truncation.truncatedBy === "lines") {
|
|
261
|
-
outputText += `\n\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines}. Use offset=${nextOffset} to continue.]`;
|
|
262
|
-
}
|
|
263
|
-
else {
|
|
264
|
-
outputText += `\n\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines} (${formatSize(READ_MAX_BYTES)} limit). Use offset=${nextOffset} to continue.]`;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
else if (userLimitedLines !== undefined && startLine + userLimitedLines < allLines.length) {
|
|
268
|
-
const remaining = allLines.length - (startLine + userLimitedLines);
|
|
269
|
-
const nextOffset = startLine + userLimitedLines + 1;
|
|
270
|
-
outputText = `${truncation.content}\n\n[${remaining} more lines in file. Use offset=${nextOffset} to continue.]`;
|
|
271
|
-
}
|
|
272
|
-
else {
|
|
273
|
-
outputText = truncation.content;
|
|
274
|
-
}
|
|
275
|
-
const toolMessage = buildToolMessage(toolCall, outputText, false, {
|
|
276
|
-
action: "read",
|
|
277
|
-
path: displayPath,
|
|
278
|
-
bytes: stats.size,
|
|
279
|
-
truncated: truncation.truncated,
|
|
280
|
-
truncatedBy: truncation.truncatedBy,
|
|
281
|
-
offset: offset ?? null,
|
|
282
|
-
limit: limit ?? null
|
|
283
|
-
});
|
|
284
|
-
return toolExecutionResultOutcomeWithTyped(toolMessage, shellResultBuild(toolMessage, "read"));
|
|
285
|
-
}
|
|
286
|
-
/**
|
|
287
|
-
* Secure write handler that prevents TOCTOU attacks.
|
|
288
|
-
* The path has already been securely resolved (symlinks followed, containment verified).
|
|
289
|
-
*/
|
|
290
|
-
async function handleWriteSecure(resolvedPath, content, append, workingDir, toolCall) {
|
|
291
|
-
await fs.mkdir(path.dirname(resolvedPath), { recursive: true });
|
|
292
|
-
// Check if target is a symlink before writing
|
|
293
|
-
try {
|
|
294
|
-
const stats = await fs.lstat(resolvedPath);
|
|
295
|
-
if (stats.isSymbolicLink()) {
|
|
296
|
-
throw new Error("Cannot write to symbolic link.");
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
catch (error) {
|
|
300
|
-
// File doesn't exist yet - OK for write operations
|
|
301
|
-
if (error.code !== "ENOENT") {
|
|
302
|
-
throw error;
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
// Use atomic file operations via file handle
|
|
306
|
-
const flags = append ? "a" : "w";
|
|
307
|
-
const handle = await fs.open(resolvedPath, flags);
|
|
308
|
-
try {
|
|
309
|
-
await handle.writeFile(content, "utf8");
|
|
310
|
-
}
|
|
311
|
-
finally {
|
|
312
|
-
await handle.close();
|
|
313
|
-
}
|
|
314
|
-
const bytes = Buffer.byteLength(content, "utf8");
|
|
315
|
-
const displayPath = formatDisplayPath(workingDir, resolvedPath);
|
|
316
|
-
const text = `${append ? "Appended" : "Wrote"} ${bytes} bytes to ${displayPath}.`;
|
|
317
|
-
const toolMessage = buildToolMessage(toolCall, text, false, {
|
|
318
|
-
action: "write",
|
|
319
|
-
path: displayPath,
|
|
320
|
-
bytes,
|
|
321
|
-
append
|
|
322
|
-
});
|
|
323
|
-
return toolExecutionResultOutcomeWithTyped(toolMessage, shellResultBuild(toolMessage, "write"));
|
|
324
|
-
}
|
|
325
|
-
/**
|
|
326
|
-
* Secure edit handler that prevents TOCTOU attacks.
|
|
327
|
-
* Uses file handle to ensure atomic read-modify-write operations.
|
|
328
|
-
*/
|
|
329
|
-
async function handleEditSecure(resolvedPath, edits, workingDir, toolCall) {
|
|
330
|
-
// Check if target is a symlink
|
|
331
|
-
const stats = await fs.lstat(resolvedPath);
|
|
332
|
-
if (stats.isSymbolicLink()) {
|
|
333
|
-
throw new Error("Cannot edit symbolic link.");
|
|
334
|
-
}
|
|
335
|
-
// Open with r+ for read-modify-write atomicity
|
|
336
|
-
const handle = await fs.open(resolvedPath, "r+");
|
|
337
|
-
try {
|
|
338
|
-
const original = await handle.readFile("utf8");
|
|
339
|
-
let updated = original;
|
|
340
|
-
const counts = [];
|
|
341
|
-
for (const edit of edits) {
|
|
342
|
-
const { next, count } = applyEdit(updated, edit);
|
|
343
|
-
if (count === 0) {
|
|
344
|
-
const preview = edit.search.length > 80 ? `${edit.search.slice(0, 77)}...` : edit.search;
|
|
345
|
-
throw new Error(`Edit not applied: "${preview}" not found.`);
|
|
346
|
-
}
|
|
347
|
-
counts.push(count);
|
|
348
|
-
updated = next;
|
|
349
|
-
}
|
|
350
|
-
// Truncate and write from beginning
|
|
351
|
-
await handle.truncate(0);
|
|
352
|
-
await handle.write(updated, 0, "utf8");
|
|
353
|
-
const displayPath = formatDisplayPath(workingDir, resolvedPath);
|
|
354
|
-
const summary = counts
|
|
355
|
-
.map((count, index) => `edit ${index + 1}: ${count} replacement${count === 1 ? "" : "s"}`)
|
|
356
|
-
.join(", ");
|
|
357
|
-
const text = `Updated ${displayPath} (${summary}).`;
|
|
358
|
-
const toolMessage = buildToolMessage(toolCall, text, false, {
|
|
359
|
-
action: "edit",
|
|
360
|
-
path: displayPath,
|
|
361
|
-
edits: counts
|
|
362
|
-
});
|
|
363
|
-
return toolExecutionResultOutcomeWithTyped(toolMessage, shellResultBuild(toolMessage, "edit"));
|
|
364
|
-
}
|
|
365
|
-
finally {
|
|
366
|
-
await handle.close();
|
|
203
|
+
function ensureAbsolutePath(target) {
|
|
204
|
+
if (!path.isAbsolute(target)) {
|
|
205
|
+
throw new Error("Path must be absolute.");
|
|
367
206
|
}
|
|
368
207
|
}
|
|
369
208
|
function applyEdit(input, edit) {
|
|
@@ -429,12 +268,6 @@ function detailNumberGet(details, key) {
|
|
|
429
268
|
const value = details[key];
|
|
430
269
|
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
431
270
|
}
|
|
432
|
-
function toText(value) {
|
|
433
|
-
if (!value) {
|
|
434
|
-
return "";
|
|
435
|
-
}
|
|
436
|
-
return typeof value === "string" ? value : value.toString("utf8");
|
|
437
|
-
}
|
|
438
271
|
export function formatExecOutput(stdout, stderr, failed) {
|
|
439
272
|
const parts = [];
|
|
440
273
|
const stdoutPart = formatExecStream("stdout", stdout);
|
|
@@ -457,233 +290,4 @@ function formatExecStream(stream, value) {
|
|
|
457
290
|
const text = stringTruncateTail(value.trimEnd(), MAX_EXEC_STREAM_OUTPUT_CHARS, stream);
|
|
458
291
|
return `${stream}:\n${text}`;
|
|
459
292
|
}
|
|
460
|
-
async function readTextFileSecure(resolvedPath) {
|
|
461
|
-
const handle = await openSecure(resolvedPath, "r");
|
|
462
|
-
try {
|
|
463
|
-
return await handle.readFile("utf8");
|
|
464
|
-
}
|
|
465
|
-
finally {
|
|
466
|
-
await handle.close();
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
async function readBinaryFileSecure(resolvedPath) {
|
|
470
|
-
const handle = await openSecure(resolvedPath, "r");
|
|
471
|
-
try {
|
|
472
|
-
return await handle.readFile();
|
|
473
|
-
}
|
|
474
|
-
finally {
|
|
475
|
-
await handle.close();
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
async function detectSupportedImageMimeTypeFromFile(resolvedPath) {
|
|
479
|
-
const handle = await openSecure(resolvedPath, "r");
|
|
480
|
-
try {
|
|
481
|
-
const header = Buffer.alloc(16);
|
|
482
|
-
const { bytesRead } = await handle.read(header, 0, header.length, 0);
|
|
483
|
-
if (bytesRead === 0) {
|
|
484
|
-
return null;
|
|
485
|
-
}
|
|
486
|
-
return detectSupportedImageMimeTypeFromHeader(header.subarray(0, bytesRead));
|
|
487
|
-
}
|
|
488
|
-
finally {
|
|
489
|
-
await handle.close();
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
function detectSupportedImageMimeTypeFromHeader(header) {
|
|
493
|
-
if (header.length >= 3 && header[0] === 0xff && header[1] === 0xd8 && header[2] === 0xff) {
|
|
494
|
-
return "image/jpeg";
|
|
495
|
-
}
|
|
496
|
-
if (header.length >= 8 &&
|
|
497
|
-
header[0] === 0x89 &&
|
|
498
|
-
header[1] === 0x50 &&
|
|
499
|
-
header[2] === 0x4e &&
|
|
500
|
-
header[3] === 0x47 &&
|
|
501
|
-
header[4] === 0x0d &&
|
|
502
|
-
header[5] === 0x0a &&
|
|
503
|
-
header[6] === 0x1a &&
|
|
504
|
-
header[7] === 0x0a) {
|
|
505
|
-
return "image/png";
|
|
506
|
-
}
|
|
507
|
-
if (header.length >= 6) {
|
|
508
|
-
const signature = header.subarray(0, 6).toString("ascii");
|
|
509
|
-
if (signature === "GIF87a" || signature === "GIF89a") {
|
|
510
|
-
return "image/gif";
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
if (header.length >= 12 &&
|
|
514
|
-
header.subarray(0, 4).toString("ascii") === "RIFF" &&
|
|
515
|
-
header.subarray(8, 12).toString("ascii") === "WEBP") {
|
|
516
|
-
return "image/webp";
|
|
517
|
-
}
|
|
518
|
-
return null;
|
|
519
|
-
}
|
|
520
|
-
function formatSize(bytes) {
|
|
521
|
-
if (bytes < 1024) {
|
|
522
|
-
return `${bytes}B`;
|
|
523
|
-
}
|
|
524
|
-
if (bytes < 1024 * 1024) {
|
|
525
|
-
return `${(bytes / 1024).toFixed(1)}KB`;
|
|
526
|
-
}
|
|
527
|
-
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
528
|
-
}
|
|
529
|
-
function truncateHead(content) {
|
|
530
|
-
const totalBytes = Buffer.byteLength(content, "utf8");
|
|
531
|
-
const lines = content.split("\n");
|
|
532
|
-
const totalLines = lines.length;
|
|
533
|
-
if (totalLines <= READ_MAX_LINES && totalBytes <= READ_MAX_BYTES) {
|
|
534
|
-
return {
|
|
535
|
-
content,
|
|
536
|
-
truncated: false,
|
|
537
|
-
truncatedBy: null,
|
|
538
|
-
totalLines,
|
|
539
|
-
totalBytes,
|
|
540
|
-
outputLines: totalLines,
|
|
541
|
-
outputBytes: totalBytes,
|
|
542
|
-
lastLinePartial: false,
|
|
543
|
-
firstLineExceedsLimit: false
|
|
544
|
-
};
|
|
545
|
-
}
|
|
546
|
-
const firstLineBytes = Buffer.byteLength(lines[0] ?? "", "utf8");
|
|
547
|
-
if (firstLineBytes > READ_MAX_BYTES) {
|
|
548
|
-
return {
|
|
549
|
-
content: "",
|
|
550
|
-
truncated: true,
|
|
551
|
-
truncatedBy: "bytes",
|
|
552
|
-
totalLines,
|
|
553
|
-
totalBytes,
|
|
554
|
-
outputLines: 0,
|
|
555
|
-
outputBytes: 0,
|
|
556
|
-
lastLinePartial: false,
|
|
557
|
-
firstLineExceedsLimit: true
|
|
558
|
-
};
|
|
559
|
-
}
|
|
560
|
-
const outputLines = [];
|
|
561
|
-
let outputBytes = 0;
|
|
562
|
-
let truncatedBy = "lines";
|
|
563
|
-
for (let index = 0; index < lines.length && index < READ_MAX_LINES; index++) {
|
|
564
|
-
const line = lines[index] ?? "";
|
|
565
|
-
const lineBytes = Buffer.byteLength(line, "utf8") + (index > 0 ? 1 : 0);
|
|
566
|
-
if (outputBytes + lineBytes > READ_MAX_BYTES) {
|
|
567
|
-
truncatedBy = "bytes";
|
|
568
|
-
break;
|
|
569
|
-
}
|
|
570
|
-
outputLines.push(line);
|
|
571
|
-
outputBytes += lineBytes;
|
|
572
|
-
}
|
|
573
|
-
if (outputLines.length >= READ_MAX_LINES && outputBytes <= READ_MAX_BYTES) {
|
|
574
|
-
truncatedBy = "lines";
|
|
575
|
-
}
|
|
576
|
-
const outputContent = outputLines.join("\n");
|
|
577
|
-
return {
|
|
578
|
-
content: outputContent,
|
|
579
|
-
truncated: true,
|
|
580
|
-
truncatedBy,
|
|
581
|
-
totalLines,
|
|
582
|
-
totalBytes,
|
|
583
|
-
outputLines: outputLines.length,
|
|
584
|
-
outputBytes: Buffer.byteLength(outputContent, "utf8"),
|
|
585
|
-
lastLinePartial: false,
|
|
586
|
-
firstLineExceedsLimit: false
|
|
587
|
-
};
|
|
588
|
-
}
|
|
589
|
-
function normalizeReadPathUnicodeSpaces(value) {
|
|
590
|
-
return value.replace(UNICODE_SPACES, " ");
|
|
591
|
-
}
|
|
592
|
-
function normalizeReadPathAtPrefix(value) {
|
|
593
|
-
return value.startsWith("@") ? value.slice(1) : value;
|
|
594
|
-
}
|
|
595
|
-
function normalizeReadPathInput(rawPath) {
|
|
596
|
-
const normalized = normalizeReadPathUnicodeSpaces(normalizeReadPathAtPrefix(rawPath));
|
|
597
|
-
if (normalized === "~") {
|
|
598
|
-
return os.homedir();
|
|
599
|
-
}
|
|
600
|
-
if (normalized.startsWith("~/")) {
|
|
601
|
-
return os.homedir() + normalized.slice(1);
|
|
602
|
-
}
|
|
603
|
-
return normalized;
|
|
604
|
-
}
|
|
605
|
-
async function pathExists(target) {
|
|
606
|
-
try {
|
|
607
|
-
await fs.access(target);
|
|
608
|
-
return true;
|
|
609
|
-
}
|
|
610
|
-
catch {
|
|
611
|
-
return false;
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
function readPathTryMacOSScreenshotVariant(target) {
|
|
615
|
-
return target.replace(/ (AM|PM)\./g, `${NARROW_NO_BREAK_SPACE}$1.`);
|
|
616
|
-
}
|
|
617
|
-
function readPathTryNfdVariant(target) {
|
|
618
|
-
return target.normalize("NFD");
|
|
619
|
-
}
|
|
620
|
-
function readPathTryCurlyQuoteVariant(target) {
|
|
621
|
-
return target.replace(/'/g, "\u2019");
|
|
622
|
-
}
|
|
623
|
-
/**
|
|
624
|
-
* Resolves a read path with compatibility fallbacks for common macOS screenshot naming variants.
|
|
625
|
-
*/
|
|
626
|
-
async function resolveReadInputPath(rawPath, workingDir) {
|
|
627
|
-
const normalized = normalizeReadPathInput(rawPath);
|
|
628
|
-
const resolved = path.isAbsolute(normalized) ? normalized : path.resolve(workingDir, normalized);
|
|
629
|
-
if (await pathExists(resolved)) {
|
|
630
|
-
return resolved;
|
|
631
|
-
}
|
|
632
|
-
const amPmVariant = readPathTryMacOSScreenshotVariant(resolved);
|
|
633
|
-
if (amPmVariant !== resolved && (await pathExists(amPmVariant))) {
|
|
634
|
-
return amPmVariant;
|
|
635
|
-
}
|
|
636
|
-
const nfdVariant = readPathTryNfdVariant(resolved);
|
|
637
|
-
if (nfdVariant !== resolved && (await pathExists(nfdVariant))) {
|
|
638
|
-
return nfdVariant;
|
|
639
|
-
}
|
|
640
|
-
const curlyVariant = readPathTryCurlyQuoteVariant(resolved);
|
|
641
|
-
if (curlyVariant !== resolved && (await pathExists(curlyVariant))) {
|
|
642
|
-
return curlyVariant;
|
|
643
|
-
}
|
|
644
|
-
const nfdCurlyVariant = readPathTryCurlyQuoteVariant(nfdVariant);
|
|
645
|
-
if (nfdCurlyVariant !== resolved && (await pathExists(nfdCurlyVariant))) {
|
|
646
|
-
return nfdCurlyVariant;
|
|
647
|
-
}
|
|
648
|
-
return resolved;
|
|
649
|
-
}
|
|
650
|
-
function ensureAbsolutePath(target) {
|
|
651
|
-
if (!path.isAbsolute(target)) {
|
|
652
|
-
throw new Error("Path must be absolute.");
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
async function resolveWritePathSecure(permissions, target) {
|
|
656
|
-
return sandboxCanWrite(permissions, target);
|
|
657
|
-
}
|
|
658
|
-
async function resolveReadPathSecure(permissions, target) {
|
|
659
|
-
return sandboxCanRead(permissions, target);
|
|
660
|
-
}
|
|
661
|
-
function formatDisplayPath(workingDir, target) {
|
|
662
|
-
if (isWithinSecure(workingDir, target)) {
|
|
663
|
-
return path.relative(workingDir, target) || ".";
|
|
664
|
-
}
|
|
665
|
-
return target;
|
|
666
|
-
}
|
|
667
|
-
function buildSandboxConfig(permissions, allowedDomains) {
|
|
668
|
-
const filesystem = sandboxFilesystemPolicyBuild({
|
|
669
|
-
writeDirs: permissions.writeDirs,
|
|
670
|
-
workingDir: permissions.workingDir
|
|
671
|
-
});
|
|
672
|
-
return {
|
|
673
|
-
filesystem,
|
|
674
|
-
network: {
|
|
675
|
-
allowedDomains,
|
|
676
|
-
deniedDomains: []
|
|
677
|
-
},
|
|
678
|
-
enableWeakerNestedSandbox: true
|
|
679
|
-
};
|
|
680
|
-
}
|
|
681
|
-
function resolveExecPermissions(currentPermissions) {
|
|
682
|
-
const readDirs = currentPermissions.readDirs ? [...currentPermissions.readDirs] : undefined;
|
|
683
|
-
return {
|
|
684
|
-
workingDir: currentPermissions.workingDir,
|
|
685
|
-
writeDirs: [...currentPermissions.writeDirs],
|
|
686
|
-
...(readDirs ? { readDirs } : {})
|
|
687
|
-
};
|
|
688
|
-
}
|
|
689
293
|
//# sourceMappingURL=tool.js.map
|