@gajae-code/coding-agent 0.18.7 → 0.18.9
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/CHANGELOG.md +377 -1
- package/dist/types/async/endpoint-id.d.ts +16 -0
- package/dist/types/async/job-manager.d.ts +1 -1
- package/dist/types/async/support.d.ts +0 -14
- package/dist/types/capability/mcp.d.ts +2 -0
- package/dist/types/capability/skill.d.ts +2 -0
- package/dist/types/capability/types.d.ts +2 -0
- package/dist/types/cli/public-command-errors.d.ts +3 -1
- package/dist/types/cli/setup-cli.d.ts +1 -1
- package/dist/types/commands/deep-interview.d.ts +3 -0
- package/dist/types/commands/mcp-serve.d.ts +4 -0
- package/dist/types/config/autorouting-tier-map.d.ts +348 -9
- package/dist/types/config/file-lock.d.ts +1 -0
- package/dist/types/config/model-bindings-applier.d.ts +2 -0
- package/dist/types/config/model-profile-activation.d.ts +11 -3
- package/dist/types/config/model-registry.d.ts +4 -9
- package/dist/types/config/skill-settings-defaults.d.ts +2 -0
- package/dist/types/cursor-delete-path.d.ts +1 -0
- package/dist/types/cursor-mcp-name.d.ts +8 -0
- package/dist/types/customization/inventory.d.ts +2 -0
- package/dist/types/debug/report-bundle-parent.d.ts +2 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/stream.d.ts +1 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/version-manager.d.ts +31 -0
- package/dist/types/defaults/gjc-skills.generated.d.ts +5 -6
- package/dist/types/discovery/helpers.d.ts +6 -1
- package/dist/types/discovery/mcp-json.d.ts +1 -0
- package/dist/types/eval/py/kernel.d.ts +18 -0
- package/dist/types/export/html/css-color.d.ts +2 -0
- package/dist/types/export/html/html-export-destination.d.ts +2 -0
- package/dist/types/export/html/template.generated.d.ts +1 -1
- package/dist/types/extensibility/extensions/function-hooks-internal.d.ts +5 -0
- package/dist/types/extensibility/extensions/types.d.ts +7 -0
- package/dist/types/extensibility/gjc-plugins/runtime-adapters.d.ts +14 -1
- package/dist/types/extensibility/plugins/marketplace/cache.d.ts +2 -0
- package/dist/types/extensibility/plugins/plugin-link-path.d.ts +2 -0
- package/dist/types/extensibility/runtime-skill-discovery.d.ts +3 -1
- package/dist/types/extensibility/skill-management.d.ts +4 -1
- package/dist/types/extensibility/skills.d.ts +2 -0
- package/dist/types/gjc-runtime/deep-interview-crystallize.d.ts +74 -0
- package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +11 -0
- package/dist/types/gjc-runtime/gc-runtime.d.ts +5 -0
- package/dist/types/gjc-runtime/psmux-detect.d.ts +3 -3
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +0 -5
- package/dist/types/gjc-runtime/sidecar-bootstrap-env.d.ts +6 -0
- package/dist/types/gjc-runtime/state-argv.d.ts +1 -1
- package/dist/types/gjc-runtime/state-migrations.d.ts +8 -0
- package/dist/types/gjc-runtime/state-runtime.d.ts +95 -0
- package/dist/types/gjc-runtime/state-writer.d.ts +14 -1
- package/dist/types/gjc-runtime/tmux-common.d.ts +8 -5
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +8 -0
- package/dist/types/internal-urls/skill-path.d.ts +1 -0
- package/dist/types/lsp/config.d.ts +8 -5
- package/dist/types/lsp/workspace-path.d.ts +1 -0
- package/dist/types/modes/acp/acp-agent.d.ts +7 -0
- package/dist/types/modes/components/custom-editor.d.ts +6 -0
- package/dist/types/modes/components/customization/customization-dashboard.d.ts +1 -0
- package/dist/types/modes/components/extensions/state-manager.d.ts +4 -3
- package/dist/types/modes/controllers/input-controller.d.ts +9 -0
- package/dist/types/modes/interactive-mode.d.ts +1 -0
- package/dist/types/modes/utils/interrupt-ownership.d.ts +3 -0
- package/dist/types/modes/utils/keybinding-matchers.d.ts +1 -0
- package/dist/types/modes/utils/macos-option-forwarding.d.ts +17 -0
- package/dist/types/progress/collect-project-progress.d.ts +38 -0
- package/dist/types/progress/progress-contract.d.ts +154 -0
- package/dist/types/progress/progress-snapshot.d.ts +11 -0
- package/dist/types/progress/project-progress.d.ts +141 -0
- package/dist/types/progress/render-progress.d.ts +28 -0
- package/dist/types/runtime-mcp/manager.d.ts +2 -1
- package/dist/types/runtime-mcp/mcp-redirect.d.ts +9 -0
- package/dist/types/runtime-mcp/oauth-public-url.d.ts +3 -0
- package/dist/types/runtime-mcp/plugin-network-boundary.d.ts +1 -0
- package/dist/types/runtime-mcp/project-host-values.d.ts +27 -0
- package/dist/types/runtime-mcp/smithery-registry.d.ts +24 -0
- package/dist/types/runtime-mcp/types.d.ts +6 -0
- package/dist/types/sdk/acp/adapter.d.ts +1 -1
- package/dist/types/sdk/broker/broker-exit.d.ts +6 -2
- package/dist/types/sdk/broker/broker.d.ts +24 -2
- package/dist/types/sdk/broker/doctor-restart.d.ts +5 -0
- package/dist/types/sdk/broker/ensure.d.ts +14 -1
- package/dist/types/sdk/broker/session-index.d.ts +12 -6
- package/dist/types/sdk/bus/index.d.ts +12 -1
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +6 -1
- package/dist/types/sdk/client/client.d.ts +2 -0
- package/dist/types/sdk/host/query/handlers.d.ts +3 -0
- package/dist/types/sdk/index.d.ts +1 -0
- package/dist/types/sdk/router/session-router.d.ts +2 -0
- package/dist/types/sdk/session-list.d.ts +1 -1
- package/dist/types/sdk/session.d.ts +8 -0
- package/dist/types/session/agent-session.d.ts +38 -9
- package/dist/types/session/artifacts.d.ts +2 -2
- package/dist/types/session/internal/managed-gc-retirement-codec.d.ts +32 -0
- package/dist/types/session/internal/managed-session-scope.d.ts +79 -2
- package/dist/types/session/internal/managed-session-storage.d.ts +26 -1
- package/dist/types/session/internal/managed-task-owner-cleanup.d.ts +62 -0
- package/dist/types/session/internal/task-artifact-owner-access.d.ts +2 -0
- package/dist/types/session/internal/task-artifact-owner-transcript.d.ts +9 -1
- package/dist/types/session/session-manager.d.ts +31 -5
- package/dist/types/session/session-retirement.d.ts +31 -7
- package/dist/types/session/session-storage.d.ts +69 -2
- package/dist/types/session/task-artifact-owner-codec.d.ts +2 -0
- package/dist/types/setup/credential-auto-import.d.ts +1 -1
- package/dist/types/setup/credential-import.d.ts +6 -4
- package/dist/types/skill-state/active-state.d.ts +38 -0
- package/dist/types/skill-state/workflow-mutation-guard.d.ts +3 -0
- package/dist/types/slash-commands/helpers/progress-report.d.ts +8 -0
- package/dist/types/task/executor.d.ts +3 -0
- package/dist/types/task/isolation-dir.d.ts +26 -0
- package/dist/types/tools/ast-edit-write-path.d.ts +13 -0
- package/dist/types/tools/bash-skill-urls.d.ts +1 -1
- package/dist/types/tools/browser/cdp-url.d.ts +2 -0
- package/dist/types/tools/github-side-effect.d.ts +22 -0
- package/dist/types/tools/index.d.ts +3 -0
- package/dist/types/tools/monitor-mutation.d.ts +9 -0
- package/dist/types/tools/python.d.ts +9 -1
- package/dist/types/tools/recipe/recipe-guard.d.ts +7 -0
- package/dist/types/tools/restricted-cwd.d.ts +1 -0
- package/dist/types/tools/todo-write.d.ts +6 -0
- package/dist/types/utils/tools-checksum.d.ts +7 -0
- package/package.json +7 -7
- package/scripts/generate-sdk-operation-inventory.ts +21 -0
- package/scripts/verify-managed-empty-stop.ts +28 -0
- package/src/async/endpoint-id.ts +26 -0
- package/src/async/job-manager.ts +247 -132
- package/src/async/support.ts +0 -25
- package/src/capability/index.ts +15 -0
- package/src/capability/mcp.ts +2 -0
- package/src/capability/skill.ts +2 -0
- package/src/capability/types.ts +2 -0
- package/src/cli/auth-broker-cli.ts +1 -1
- package/src/cli/customize-doctor.ts +15 -2
- package/src/cli/doctor/repairs.ts +4 -1
- package/src/cli/doctor-supervisor.ts +3 -0
- package/src/cli/public-command-errors.ts +21 -1
- package/src/cli/public-command-registry.ts +28 -6
- package/src/cli/setup-cli.ts +4 -4
- package/src/cli/skills-cli.ts +5 -0
- package/src/commands/deep-interview.ts +47 -8
- package/src/commands/mcp-serve.ts +7 -0
- package/src/commands/sdk.ts +455 -397
- package/src/config/autorouting-tier-map.ts +117 -7
- package/src/config/file-lock.ts +316 -79
- package/src/config/mcp-schema.json +4 -0
- package/src/config/model-bindings-applier.ts +20 -0
- package/src/config/model-profile-activation.ts +240 -46
- package/src/config/model-registry.ts +47 -153
- package/src/config/skill-settings-defaults.ts +7 -0
- package/src/coordinator-mcp/policy.ts +3 -2
- package/src/coordinator-mcp/server.ts +2 -0
- package/src/cursor-delete-path.ts +10 -0
- package/src/cursor-mcp-name.ts +15 -0
- package/src/cursor.ts +13 -2
- package/src/customization/inventory.ts +4 -13
- package/src/dap/config.ts +2 -2
- package/src/debug/report-bundle-parent.ts +22 -0
- package/src/debug/report-bundle.ts +3 -0
- package/src/debug/system-info.ts +13 -1
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/register.ts +10 -6
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/stream.ts +67 -4
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/version-manager.ts +80 -0
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +105 -10
- package/src/defaults/gjc/skills/ralplan/SKILL.md +6 -4
- package/src/defaults/gjc-defaults.test.ts +18 -1
- package/src/defaults/gjc-defaults.ts +3 -0
- package/src/defaults/gjc-skills.generated.ts +58 -36
- package/src/discovery/agents.ts +6 -1
- package/src/discovery/builtin.ts +13 -1
- package/src/discovery/helpers.ts +171 -29
- package/src/discovery/mcp-json.ts +26 -12
- package/src/discovery/ssh.ts +1 -1
- package/src/discovery/substitute-plugin-root.ts +3 -1
- package/src/edit/file-read-cache.ts +1 -1
- package/src/eval/py/executor.ts +796 -154
- package/src/eval/py/kernel.ts +79 -13
- package/src/eval/py/tool-bridge.ts +4 -0
- package/src/export/html/css-color.ts +9 -0
- package/src/export/html/html-export-destination.ts +16 -0
- package/src/export/html/index.ts +7 -10
- package/src/export/html/template.generated.ts +1 -1
- package/src/extensibility/extensions/function-hooks-internal.ts +27 -0
- package/src/extensibility/extensions/runner.ts +15 -1
- package/src/extensibility/extensions/types.ts +7 -0
- package/src/extensibility/gjc-plugins/mcp-policy.ts +2 -1
- package/src/extensibility/gjc-plugins/runtime-adapters.ts +85 -8
- package/src/extensibility/plugins/manager.ts +3 -2
- package/src/extensibility/plugins/marketplace/cache.ts +15 -0
- package/src/extensibility/plugins/marketplace/manager.ts +11 -3
- package/src/extensibility/plugins/plugin-link-path.ts +12 -0
- package/src/extensibility/runtime-skill-discovery.ts +20 -2
- package/src/extensibility/skill-management.ts +9 -2
- package/src/extensibility/skills.ts +6 -1
- package/src/gjc-runtime/deep-interview-crystallize.ts +1814 -0
- package/src/gjc-runtime/deep-interview-recorder.ts +20 -2
- package/src/gjc-runtime/deep-interview-runtime.ts +1415 -13
- package/src/gjc-runtime/deep-interview-stage.ts +98 -21
- package/src/gjc-runtime/gc-runtime.ts +206 -9
- package/src/gjc-runtime/launch-worktree.ts +70 -9
- package/src/gjc-runtime/psmux-detect.ts +28 -4
- package/src/gjc-runtime/ralplan-runtime.ts +447 -52
- package/src/gjc-runtime/session-state-sidecar.ts +3 -2
- package/src/gjc-runtime/sidecar-bootstrap-env.ts +19 -0
- package/src/gjc-runtime/state-argv.ts +2 -0
- package/src/gjc-runtime/state-migrations.ts +91 -29
- package/src/gjc-runtime/state-runtime.ts +3716 -135
- package/src/gjc-runtime/state-writer.ts +105 -16
- package/src/gjc-runtime/tmux-common.ts +8 -5
- package/src/gjc-runtime/ultragoal-runtime.ts +16 -4
- package/src/gjc-runtime/workflow-manifest.generated.json +70 -42
- package/src/gjc-runtime/workflow-manifest.ts +54 -21
- package/src/harness-control-plane/operate.ts +12 -4
- package/src/harness-control-plane/owner.ts +5 -1
- package/src/hashline/parser.ts +48 -9
- package/src/hashline/recovery.ts +13 -4
- package/src/internal-urls/docs-index.generated.ts +20 -19
- package/src/internal-urls/skill-path.ts +19 -0
- package/src/internal-urls/skill-protocol.ts +2 -0
- package/src/lsp/config.ts +12 -63
- package/src/lsp/edits.ts +6 -0
- package/src/lsp/workspace-path.ts +51 -0
- package/src/main.ts +195 -31
- package/src/memories/index.ts +88 -7
- package/src/modes/acp/acp-agent.ts +88 -4
- package/src/modes/components/custom-editor.ts +14 -0
- package/src/modes/components/customization/customization-dashboard.ts +12 -0
- package/src/modes/components/extensions/extension-dashboard.ts +2 -2
- package/src/modes/components/extensions/state-manager.ts +15 -5
- package/src/modes/components/hook-editor.ts +1 -1
- package/src/modes/components/hook-selector.ts +1 -1
- package/src/modes/components/model-selector.ts +1 -4
- package/src/modes/components/provider-onboarding-selector.ts +1 -1
- package/src/modes/components/status-line/segments.ts +4 -0
- package/src/modes/controllers/event-controller.ts +11 -4
- package/src/modes/controllers/input-controller.ts +76 -31
- package/src/modes/controllers/runtime-mcp-command-controller.ts +29 -16
- package/src/modes/controllers/selector-controller.ts +24 -15
- package/src/modes/controllers/todo-command-controller.ts +1 -1
- package/src/modes/interactive-mode.ts +5 -1
- package/src/modes/runtime-init.ts +4 -0
- package/src/modes/utils/abort-message.ts +3 -1
- package/src/modes/utils/interrupt-ownership.ts +12 -0
- package/src/modes/utils/keybinding-matchers.ts +4 -0
- package/src/modes/utils/macos-option-forwarding.ts +80 -0
- package/src/progress/collect-project-progress.ts +153 -0
- package/src/progress/progress-contract.ts +172 -0
- package/src/progress/progress-snapshot.ts +140 -0
- package/src/progress/project-progress.ts +446 -0
- package/src/progress/render-progress.ts +209 -0
- package/src/prompts/system/master-mode.md +1 -0
- package/src/prompts/tools/skill-discovery.md +1 -1
- package/src/runtime-mcp/client.ts +4 -2
- package/src/runtime-mcp/config-writer.ts +10 -6
- package/src/runtime-mcp/config.ts +1 -0
- package/src/runtime-mcp/json-rpc.ts +2 -1
- package/src/runtime-mcp/manager.ts +29 -11
- package/src/runtime-mcp/mcp-redirect.ts +73 -0
- package/src/runtime-mcp/oauth-flow.ts +14 -2
- package/src/runtime-mcp/oauth-public-url.ts +14 -0
- package/src/runtime-mcp/plugin-network-boundary.ts +4 -0
- package/src/runtime-mcp/pool.ts +6 -0
- package/src/runtime-mcp/project-host-values.ts +46 -0
- package/src/runtime-mcp/smithery-registry.ts +22 -3
- package/src/runtime-mcp/transports/http.ts +4 -3
- package/src/runtime-mcp/types.ts +6 -0
- package/src/sdk/acp/adapter.ts +95 -8
- package/src/sdk/broker/broker-exit.ts +52 -23
- package/src/sdk/broker/broker.ts +81 -6
- package/src/sdk/broker/doctor-restart.ts +4 -0
- package/src/sdk/broker/ensure.ts +31 -2
- package/src/sdk/broker/lifecycle.ts +711 -66
- package/src/sdk/broker/session-index.ts +191 -81
- package/src/sdk/bus/chat-daemon-cli.ts +38 -1
- package/src/sdk/bus/chat-daemon-control.ts +2 -2
- package/src/sdk/bus/index.ts +238 -43
- package/src/sdk/bus/telegram-daemon-contract.ts +6 -1
- package/src/sdk/cli/session-cli.ts +17 -3
- package/src/sdk/client/client.ts +28 -8
- package/src/sdk/host/query/handlers.ts +9 -1
- package/src/sdk/host/session-runtime.test.ts +2705 -303
- package/src/sdk/host/session-runtime.ts +490 -143
- package/src/sdk/host/surface-policy.ts +1 -0
- package/src/sdk/index.ts +8 -0
- package/src/sdk/lifecycle-session.ts +3 -1
- package/src/sdk/prompt-deadline-manager.ts +15 -0
- package/src/sdk/protocol/operation-inventory.generated.json +146 -0
- package/src/sdk/protocol/operation-registry.ts +9 -2
- package/src/sdk/router/session-router.ts +82 -18
- package/src/sdk/session-list.ts +1 -0
- package/src/sdk/session.ts +69 -45
- package/src/session/agent-session.ts +679 -238
- package/src/session/artifacts.ts +176 -71
- package/src/session/internal/managed-gc-retirement-codec.ts +319 -0
- package/src/session/internal/managed-session-scope.ts +3779 -462
- package/src/session/internal/managed-session-storage.ts +501 -78
- package/src/session/internal/managed-task-owner-cleanup.ts +473 -0
- package/src/session/internal/task-artifact-owner-access.ts +19 -3
- package/src/session/internal/task-artifact-owner-transcript.ts +547 -1
- package/src/session/session-manager.ts +951 -133
- package/src/session/session-retirement.ts +573 -14
- package/src/session/session-storage.ts +447 -15
- package/src/session/task-artifact-owner-codec.ts +71 -8
- package/src/session/task-artifact-owner-retirement.ts +21 -19
- package/src/setup/credential-auto-import.ts +12 -3
- package/src/setup/credential-import.ts +176 -5
- package/src/setup/paseo/announce.ts +6 -1
- package/src/skill-state/active-state.ts +145 -2
- package/src/skill-state/workflow-mutation-guard.ts +102 -10
- package/src/slash-commands/builtin-registry.ts +39 -9
- package/src/slash-commands/helpers/mcp.ts +8 -4
- package/src/slash-commands/helpers/progress-report.ts +23 -0
- package/src/stt/setup.ts +3 -5
- package/src/task/commands.ts +3 -1
- package/src/task/executor.ts +4 -0
- package/src/task/index.ts +6 -0
- package/src/task/isolation-dir.ts +143 -0
- package/src/task/worktree.ts +16 -7
- package/src/tools/ask.ts +205 -6
- package/src/tools/ast-edit-write-path.ts +68 -0
- package/src/tools/ast-edit.ts +10 -1
- package/src/tools/bash-allowed-prefixes.ts +15 -0
- package/src/tools/bash-skill-urls.ts +56 -3
- package/src/tools/bash.ts +48 -79
- package/src/tools/browser/cdp-url.ts +18 -0
- package/src/tools/browser.ts +8 -1
- package/src/tools/descriptors.ts +5 -1
- package/src/tools/eval.ts +56 -36
- package/src/tools/gh.ts +10 -0
- package/src/tools/github-side-effect.ts +112 -0
- package/src/tools/image-gen.ts +1 -1
- package/src/tools/index.ts +3 -0
- package/src/tools/monitor-mutation.ts +27 -0
- package/src/tools/monitor.ts +7 -0
- package/src/tools/python.ts +188 -66
- package/src/tools/recipe/index.ts +9 -0
- package/src/tools/recipe/recipe-guard.ts +19 -0
- package/src/tools/restricted-cwd.ts +10 -0
- package/src/tools/skill-discovery.ts +5 -0
- package/src/tools/skill.ts +28 -1
- package/src/tools/todo-write.ts +10 -1
- package/src/tools/tool-catalog.generated.ts +1 -1
- package/src/tools/write.ts +1 -0
- package/src/utils/external-editor.ts +3 -2
- package/src/utils/tools-checksum.ts +34 -0
- package/src/utils/tools-manager.ts +24 -6
- package/src/web/insane/url-guard.ts +2 -1
- package/src/web/search/providers/codex.ts +3 -2
|
@@ -268,10 +268,25 @@ function validateReadOnlyCommand(words: readonly string[]): BashAllowedPrefixesC
|
|
|
268
268
|
}
|
|
269
269
|
}
|
|
270
270
|
|
|
271
|
+
const gitWrite = rejectGitHostAccess(words);
|
|
272
|
+
if (gitWrite) return gitWrite;
|
|
273
|
+
|
|
271
274
|
return { allowed: true };
|
|
272
275
|
}
|
|
273
276
|
|
|
277
|
+
function rejectGitHostAccess(words: readonly string[]): BashAllowedPrefixesCheck | undefined {
|
|
278
|
+
if (words[0] !== "git") return undefined;
|
|
279
|
+
for (const option of optionWords(words)) {
|
|
280
|
+
if (isLongOption(option, "--output") || isLongOption(option, "--no-index")) {
|
|
281
|
+
return { allowed: false, reason: "restricted bash does not allow git --output or --no-index" };
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
return undefined;
|
|
285
|
+
}
|
|
286
|
+
|
|
274
287
|
function validateMatchedGjcCommand(words: readonly string[]): BashAllowedPrefixesCheck {
|
|
288
|
+
const gitWrite = rejectGitHostAccess(words);
|
|
289
|
+
if (gitWrite) return gitWrite;
|
|
275
290
|
if (words[0] !== "gjc") return { allowed: true };
|
|
276
291
|
|
|
277
292
|
if (words[1] === "ralplan") {
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import * as fs from "node:fs/promises";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
+
import { isEnoent } from "@gajae-code/utils";
|
|
3
4
|
import type { Skill } from "../extensibility/skills";
|
|
4
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
initializeLocalRoot,
|
|
7
|
+
type LocalProtocolOptions,
|
|
8
|
+
resolveLocalRoot,
|
|
9
|
+
resolveLocalUrlToPath,
|
|
10
|
+
} from "../internal-urls/local-protocol";
|
|
5
11
|
import { validateRelativePath } from "../internal-urls/skill-protocol";
|
|
6
12
|
import type { InternalResource } from "../internal-urls/types";
|
|
7
13
|
import { normalizeLocalScheme } from "./path-utils";
|
|
@@ -125,6 +131,52 @@ function matchSkillName(
|
|
|
125
131
|
return { skill: undefined, suffix: undefined };
|
|
126
132
|
}
|
|
127
133
|
|
|
134
|
+
function localPathEscapes(realRoot: string, candidate: string): boolean {
|
|
135
|
+
return candidate !== realRoot && !candidate.startsWith(`${realRoot}${path.sep}`);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async function canonicalLocalPath(localRoot: string, lexicalPath: string): Promise<string> {
|
|
139
|
+
const realRoot = await fs.realpath(localRoot);
|
|
140
|
+
try {
|
|
141
|
+
const realTarget = await fs.realpath(lexicalPath);
|
|
142
|
+
if (localPathEscapes(realRoot, realTarget)) {
|
|
143
|
+
throw new ToolError("local:// path escapes the session local root");
|
|
144
|
+
}
|
|
145
|
+
return realTarget;
|
|
146
|
+
} catch (error) {
|
|
147
|
+
if (error instanceof ToolError || !isEnoent(error)) throw error;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const missing: string[] = [];
|
|
151
|
+
let cursor = lexicalPath;
|
|
152
|
+
for (;;) {
|
|
153
|
+
let stat: Awaited<ReturnType<typeof fs.lstat>> | undefined;
|
|
154
|
+
try {
|
|
155
|
+
stat = await fs.lstat(cursor);
|
|
156
|
+
} catch (error) {
|
|
157
|
+
if (!isEnoent(error)) throw error;
|
|
158
|
+
}
|
|
159
|
+
if (stat) {
|
|
160
|
+
let realAncestor: string;
|
|
161
|
+
try {
|
|
162
|
+
realAncestor = await fs.realpath(cursor);
|
|
163
|
+
} catch (error) {
|
|
164
|
+
if (isEnoent(error)) throw new ToolError("local:// path escapes the session local root");
|
|
165
|
+
throw error;
|
|
166
|
+
}
|
|
167
|
+
const canonical = path.join(realAncestor, ...missing);
|
|
168
|
+
if (localPathEscapes(realRoot, canonical)) {
|
|
169
|
+
throw new ToolError("local:// path escapes the session local root");
|
|
170
|
+
}
|
|
171
|
+
return canonical;
|
|
172
|
+
}
|
|
173
|
+
const parent = path.dirname(cursor);
|
|
174
|
+
if (parent === cursor) throw new ToolError("local:// path escapes the session local root");
|
|
175
|
+
missing.unshift(path.basename(cursor));
|
|
176
|
+
cursor = parent;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
128
180
|
function extractScheme(url: string): SupportedInternalScheme | undefined {
|
|
129
181
|
const match = /^([a-z][a-z0-9+.-]*):\/\//i.exec(url);
|
|
130
182
|
if (!match) return undefined;
|
|
@@ -180,10 +232,11 @@ async function resolveInternalUrlToPath(
|
|
|
180
232
|
}
|
|
181
233
|
await initializeLocalRoot(localOptions);
|
|
182
234
|
const resolvedLocalPath = resolveLocalUrlToPath(url, localOptions);
|
|
235
|
+
const realTarget = await canonicalLocalPath(resolveLocalRoot(localOptions), resolvedLocalPath);
|
|
183
236
|
if (ensureLocalParentDirs) {
|
|
184
|
-
await fs.mkdir(path.dirname(
|
|
237
|
+
await fs.mkdir(path.dirname(realTarget), { recursive: true });
|
|
185
238
|
}
|
|
186
|
-
return
|
|
239
|
+
return realTarget;
|
|
187
240
|
}
|
|
188
241
|
|
|
189
242
|
if (!internalRouter?.canHandle(url)) {
|
package/src/tools/bash.ts
CHANGED
|
@@ -7,7 +7,6 @@ import { getProjectDir, isEnoent, logger, prompt } from "@gajae-code/utils";
|
|
|
7
7
|
import * as z from "zod/v4";
|
|
8
8
|
import { AsyncJobManager, type FoldReason } from "../async";
|
|
9
9
|
import { type BashArtifactSaveResult, type BashResult, executeBash } from "../exec/bash-executor";
|
|
10
|
-
|
|
11
10
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
12
11
|
import { buildGjcRuntimeSessionEnv } from "../gjc-runtime/goal-mode-request";
|
|
13
12
|
import {
|
|
@@ -37,13 +36,13 @@ import { truncateToVisualLines } from "../modes/components/visual-truncate";
|
|
|
37
36
|
import { highlightCode, type Theme } from "../modes/theme/theme";
|
|
38
37
|
import bashDescription from "../prompts/tools/bash.md" with { type: "text" };
|
|
39
38
|
import { renderSpawnTable, runSdkSpawn, type SdkSpawnArgs } from "../sdk/cli/master-cli";
|
|
40
|
-
import type { ArtifactManager } from "../session/artifacts";
|
|
41
39
|
import type {
|
|
42
40
|
ClientBridgeTerminalExitStatus,
|
|
43
41
|
ClientBridgeTerminalHandle,
|
|
44
42
|
ClientBridgeTerminalOutput,
|
|
45
43
|
} from "../session/client-bridge";
|
|
46
44
|
import type { FoldAdapter } from "../session/fold-coordinator";
|
|
45
|
+
import type { SessionArtifactPublication } from "../session/session-manager";
|
|
47
46
|
import {
|
|
48
47
|
DEFAULT_ARTIFACT_MAX_BYTES,
|
|
49
48
|
OutputSink,
|
|
@@ -60,7 +59,6 @@ import {
|
|
|
60
59
|
registerOwnedIfLineaged,
|
|
61
60
|
unregisterOwnedRegistration,
|
|
62
61
|
} from "../session/terminal-abort";
|
|
63
|
-
|
|
64
62
|
import { renderStatusLine } from "../tui";
|
|
65
63
|
import { CachedOutputBlock, getOutputBlockContentWidth } from "../tui/output-block";
|
|
66
64
|
import { truncateToWidth } from "../tui/utils";
|
|
@@ -84,6 +82,7 @@ import {
|
|
|
84
82
|
} from "./output-meta";
|
|
85
83
|
import { resolveToCwd } from "./path-utils";
|
|
86
84
|
import { formatToolWorkingDirectory, replaceTabs } from "./render-utils";
|
|
85
|
+
import { assertCwdInsideWorkspace } from "./restricted-cwd";
|
|
87
86
|
import { steerFoldReasonLine, watchSteerForFold } from "./steer-fold";
|
|
88
87
|
import { checkTmuxSelfInjection } from "./tmux-self-injection-guard";
|
|
89
88
|
import { ToolAbortError, ToolError } from "./tool-errors";
|
|
@@ -378,6 +377,7 @@ interface PreparedClientTerminalOutput {
|
|
|
378
377
|
async function prepareClientTerminalOutput(
|
|
379
378
|
session: ToolSession,
|
|
380
379
|
current: ClientBridgeTerminalOutput,
|
|
380
|
+
artifactPublication: SessionArtifactPublication | undefined,
|
|
381
381
|
): Promise<PreparedClientTerminalOutput> {
|
|
382
382
|
const { summary, locallyTruncated } = await boundClientTerminalOutput(
|
|
383
383
|
current.output,
|
|
@@ -386,7 +386,7 @@ async function prepareClientTerminalOutput(
|
|
|
386
386
|
);
|
|
387
387
|
let artifactSaveResult: BashOriginalArtifactSaveResult | undefined;
|
|
388
388
|
if (locallyTruncated && !current.truncated) {
|
|
389
|
-
artifactSaveResult = await saveBashOriginalArtifact(
|
|
389
|
+
artifactSaveResult = await saveBashOriginalArtifact(artifactPublication, current.output);
|
|
390
390
|
if (artifactSaveResult.status === "saved") appendRawArtifactFooter(summary, artifactSaveResult);
|
|
391
391
|
}
|
|
392
392
|
const artifactSaveNotice = artifactSaveResult
|
|
@@ -468,63 +468,26 @@ function appendArtifactDetails(text: string, result: BashResult | BashInteractiv
|
|
|
468
468
|
}
|
|
469
469
|
|
|
470
470
|
async function saveBashOriginalArtifact(
|
|
471
|
-
|
|
471
|
+
artifactPublication: SessionArtifactPublication | undefined,
|
|
472
472
|
originalText: string,
|
|
473
473
|
): Promise<BashOriginalArtifactSaveResult> {
|
|
474
|
-
|
|
475
|
-
try {
|
|
476
|
-
manager = session.getArtifactManager?.();
|
|
477
|
-
} catch (error) {
|
|
478
|
-
return { status: "failed", diagnostic: boundArtifactSaveDiagnostic(error) };
|
|
479
|
-
}
|
|
480
|
-
if (manager) {
|
|
481
|
-
try {
|
|
482
|
-
const artifactId = await manager.save(originalText, "bash-original");
|
|
483
|
-
return artifactId
|
|
484
|
-
? summarizeOriginalArtifactSave(artifactId, originalText)
|
|
485
|
-
: { status: "failed", diagnostic: "storage returned no artifact id" };
|
|
486
|
-
} catch (error) {
|
|
487
|
-
return { status: "failed", diagnostic: boundArtifactSaveDiagnostic(error) };
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
if (!session.allocateOutputArtifact) return { status: "unavailable" };
|
|
492
|
-
let alloc: { id?: string; path?: string } | undefined;
|
|
493
|
-
try {
|
|
494
|
-
alloc = await session.allocateOutputArtifact("bash-original");
|
|
495
|
-
} catch (error) {
|
|
496
|
-
return { status: "failed", diagnostic: boundArtifactSaveDiagnostic(error) };
|
|
497
|
-
}
|
|
498
|
-
if (!alloc?.path || !alloc.id) return { status: "unavailable" };
|
|
474
|
+
if (!artifactPublication) return { status: "unavailable" };
|
|
499
475
|
try {
|
|
500
|
-
const
|
|
501
|
-
|
|
502
|
-
? originalText
|
|
503
|
-
: (() => {
|
|
504
|
-
const retained = truncateHeadBytes(originalText, DEFAULT_ARTIFACT_MAX_BYTES);
|
|
505
|
-
return `${retained.text}\n[artifact truncated after ${retained.bytes} bytes; omitted at least ${saveResult.omittedBytes} bytes]\n`;
|
|
506
|
-
})();
|
|
507
|
-
await Bun.write(alloc.path, payload);
|
|
508
|
-
return saveResult;
|
|
476
|
+
const artifactId = await artifactPublication(originalText, "bash-original");
|
|
477
|
+
return artifactId ? summarizeOriginalArtifactSave(artifactId, originalText) : { status: "unavailable" };
|
|
509
478
|
} catch (error) {
|
|
510
479
|
return { status: "failed", diagnostic: boundArtifactSaveDiagnostic(error) };
|
|
511
480
|
}
|
|
512
481
|
}
|
|
513
482
|
|
|
514
|
-
function createBashArtifactPublisher(
|
|
483
|
+
function createBashArtifactPublisher(
|
|
484
|
+
artifactPublication: SessionArtifactPublication | undefined,
|
|
485
|
+
): TerminalArtifactPublisher {
|
|
515
486
|
return async (content, _info): Promise<TerminalArtifactPublishResult> => {
|
|
516
|
-
|
|
517
|
-
try {
|
|
518
|
-
manager = session.getArtifactManager?.();
|
|
519
|
-
} catch (error) {
|
|
520
|
-
return { status: "failed", diagnostic: boundArtifactSaveDiagnostic(error) };
|
|
521
|
-
}
|
|
522
|
-
if (!manager) return { status: "unavailable" };
|
|
487
|
+
if (!artifactPublication) return { status: "unavailable" };
|
|
523
488
|
try {
|
|
524
|
-
const artifactId = await
|
|
525
|
-
return artifactId
|
|
526
|
-
? { status: "published", artifactId }
|
|
527
|
-
: { status: "failed", diagnostic: "storage returned no artifact id" };
|
|
489
|
+
const artifactId = await artifactPublication(content, "bash");
|
|
490
|
+
return artifactId ? { status: "published", artifactId } : { status: "unavailable" };
|
|
528
491
|
} catch (error) {
|
|
529
492
|
return { status: "failed", diagnostic: boundArtifactSaveDiagnostic(error) };
|
|
530
493
|
}
|
|
@@ -536,7 +499,8 @@ export async function saveBashOriginalArtifactForTests(
|
|
|
536
499
|
originalText: string,
|
|
537
500
|
onResult?: (result: BashOriginalArtifactSaveResult) => void,
|
|
538
501
|
): Promise<string | undefined> {
|
|
539
|
-
const
|
|
502
|
+
const artifactPublication = session.captureArtifactPublication?.();
|
|
503
|
+
const result = await saveBashOriginalArtifact(artifactPublication, originalText);
|
|
540
504
|
onResult?.(result);
|
|
541
505
|
return result.status === "saved" ? result.artifactId : undefined;
|
|
542
506
|
}
|
|
@@ -1128,6 +1092,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
1128
1092
|
onCompletion?: () => void;
|
|
1129
1093
|
/** Immutable attempt-scoped tool call id, when executed via a tool call. */
|
|
1130
1094
|
toolCallId?: string;
|
|
1095
|
+
artifactPublication: SessionArtifactPublication | undefined;
|
|
1131
1096
|
/** Accepted activity declaration, mirrored into job progress and result details. */
|
|
1132
1097
|
activity?: BashActivityDeclaration;
|
|
1133
1098
|
}): ManagedBashJobHandle {
|
|
@@ -1156,8 +1121,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
1156
1121
|
"bash",
|
|
1157
1122
|
label,
|
|
1158
1123
|
async ({ jobId, signal: runSignal, reportProgress }) => {
|
|
1159
|
-
const
|
|
1160
|
-
const artifactPublisher = createBashArtifactPublisher(this.session);
|
|
1124
|
+
const artifactPublisher = createBashArtifactPublisher(options.artifactPublication);
|
|
1161
1125
|
const spillThreshold = resolveBashOutputSinkTailBytes(this.session.settings);
|
|
1162
1126
|
const headBytes = resolveBashOutputSinkHeadBytes(this.session.settings);
|
|
1163
1127
|
const tailBuffer = new TailBuffer(spillThreshold);
|
|
@@ -1180,8 +1144,6 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
1180
1144
|
signal: runSignal,
|
|
1181
1145
|
env: options.resolvedEnv,
|
|
1182
1146
|
unsetEnv: options.unsetEnv,
|
|
1183
|
-
artifactPath,
|
|
1184
|
-
artifactId,
|
|
1185
1147
|
artifactPublisher,
|
|
1186
1148
|
spillThreshold,
|
|
1187
1149
|
headBytes,
|
|
@@ -1194,7 +1156,8 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
1194
1156
|
void reportProgress(latestText, runningDetails(jobId));
|
|
1195
1157
|
},
|
|
1196
1158
|
onRawChunk: chunk => manager.appendOutput(jobId, chunk),
|
|
1197
|
-
onMinimizedSave: async originalText =>
|
|
1159
|
+
onMinimizedSave: async originalText =>
|
|
1160
|
+
saveBashOriginalArtifact(options.artifactPublication, originalText),
|
|
1198
1161
|
});
|
|
1199
1162
|
executionResult = result;
|
|
1200
1163
|
const finalResult = this.#buildCompletedResult(result, options.timeoutSec, {
|
|
@@ -1561,6 +1524,9 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
1561
1524
|
if (!cwdStat.isDirectory()) {
|
|
1562
1525
|
throw new ToolError(`Working directory is not a directory: ${commandCwd}`);
|
|
1563
1526
|
}
|
|
1527
|
+
if (this.session.bashRestrictionProfile === "read-only" || (allowedPrefixes?.length ?? 0) > 0) {
|
|
1528
|
+
await assertCwdInsideWorkspace(this.session.cwd, commandCwd);
|
|
1529
|
+
}
|
|
1564
1530
|
|
|
1565
1531
|
const requestedTimeoutSec = input.timeout ?? 300;
|
|
1566
1532
|
const timeoutSec = clampTimeout("bash", requestedTimeoutSec);
|
|
@@ -1678,6 +1644,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
1678
1644
|
if (!manager.hasCapacity()) {
|
|
1679
1645
|
throw new ToolError("Background job limit reached. Wait for running jobs to finish or cancel one.");
|
|
1680
1646
|
}
|
|
1647
|
+
const artifactPublication = this.session.captureArtifactPublication?.();
|
|
1681
1648
|
const prepared = await this.#prepareBashExecution(input, opts.ctx);
|
|
1682
1649
|
const label =
|
|
1683
1650
|
opts.label ?? (prepared.command.length > 120 ? `${prepared.command.slice(0, 117)}...` : prepared.command);
|
|
@@ -1725,8 +1692,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
1725
1692
|
"bash",
|
|
1726
1693
|
label,
|
|
1727
1694
|
async ({ jobId: id, signal, reportProgress }) => {
|
|
1728
|
-
const
|
|
1729
|
-
const artifactPublisher = createBashArtifactPublisher(this.session);
|
|
1695
|
+
const artifactPublisher = createBashArtifactPublisher(artifactPublication);
|
|
1730
1696
|
const spillThreshold = resolveBashOutputSinkTailBytes(this.session.settings);
|
|
1731
1697
|
const headBytes = resolveBashOutputSinkHeadBytes(this.session.settings);
|
|
1732
1698
|
const tailBuffer = new TailBuffer(spillThreshold);
|
|
@@ -1740,8 +1706,6 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
1740
1706
|
signal,
|
|
1741
1707
|
env: prepared.resolvedEnv,
|
|
1742
1708
|
unsetEnv: prepared.unsetEnv,
|
|
1743
|
-
artifactPath,
|
|
1744
|
-
artifactId,
|
|
1745
1709
|
artifactPublisher,
|
|
1746
1710
|
spillThreshold,
|
|
1747
1711
|
headBytes,
|
|
@@ -1762,7 +1726,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
1762
1726
|
cursorOffset = slice.nextOffset;
|
|
1763
1727
|
dispatchLines(slice.text);
|
|
1764
1728
|
},
|
|
1765
|
-
onMinimizedSave: async originalText => saveBashOriginalArtifact(
|
|
1729
|
+
onMinimizedSave: async originalText => saveBashOriginalArtifact(artifactPublication, originalText),
|
|
1766
1730
|
});
|
|
1767
1731
|
flushTrailingLine();
|
|
1768
1732
|
const resultText = appendArtifactDetails(result.output || "(no output)", result);
|
|
@@ -1818,6 +1782,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
1818
1782
|
throw new ToolError("Background job limit reached. Wait for running jobs to finish or cancel one.");
|
|
1819
1783
|
}
|
|
1820
1784
|
|
|
1785
|
+
const artifactPublication = this.session.captureArtifactPublication?.();
|
|
1821
1786
|
const prepared = await this.#prepareBashExecution(
|
|
1822
1787
|
{ command: rawCommand, env: rawEnv, timeout: rawTimeout, cwd },
|
|
1823
1788
|
ctx,
|
|
@@ -1871,6 +1836,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
1871
1836
|
onUpdate,
|
|
1872
1837
|
startBackgrounded: true,
|
|
1873
1838
|
toolCallId,
|
|
1839
|
+
artifactPublication,
|
|
1874
1840
|
activity,
|
|
1875
1841
|
});
|
|
1876
1842
|
const jobGeneration = asyncManager.getJob(job.jobId)?.generation ?? job.jobId;
|
|
@@ -1927,6 +1893,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
1927
1893
|
managedForegroundSettled = true;
|
|
1928
1894
|
},
|
|
1929
1895
|
toolCallId,
|
|
1896
|
+
artifactPublication,
|
|
1930
1897
|
activity,
|
|
1931
1898
|
});
|
|
1932
1899
|
const jobGeneration = ownedManager.getJob(job.jobId)?.generation ?? job.jobId;
|
|
@@ -2231,7 +2198,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
2231
2198
|
});
|
|
2232
2199
|
}
|
|
2233
2200
|
appendAcpSnapshot(current.output, current.truncated);
|
|
2234
|
-
const prepared = await prepareClientTerminalOutput(this.session, current);
|
|
2201
|
+
const prepared = await prepareClientTerminalOutput(this.session, current, artifactPublication);
|
|
2235
2202
|
throw new ToolAbortError(formatClientTerminalAbortFailure(prepared, readDiagnostic, pendingNotices));
|
|
2236
2203
|
}
|
|
2237
2204
|
|
|
@@ -2263,7 +2230,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
2263
2230
|
});
|
|
2264
2231
|
}
|
|
2265
2232
|
appendAcpSnapshot(current.output, current.truncated);
|
|
2266
|
-
const prepared = await prepareClientTerminalOutput(this.session, current);
|
|
2233
|
+
const prepared = await prepareClientTerminalOutput(this.session, current, artifactPublication);
|
|
2267
2234
|
throw new ToolAbortError(
|
|
2268
2235
|
formatClientTerminalAbortFailure(prepared, readDiagnostic, pendingNotices),
|
|
2269
2236
|
);
|
|
@@ -2284,7 +2251,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
2284
2251
|
});
|
|
2285
2252
|
}
|
|
2286
2253
|
appendAcpSnapshot(current.output, current.truncated);
|
|
2287
|
-
const prepared = await prepareClientTerminalOutput(this.session, current);
|
|
2254
|
+
const prepared = await prepareClientTerminalOutput(this.session, current, artifactPublication);
|
|
2288
2255
|
throw new ToolError(
|
|
2289
2256
|
formatClientTerminalWaitFailure(
|
|
2290
2257
|
prepared,
|
|
@@ -2314,7 +2281,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
2314
2281
|
});
|
|
2315
2282
|
}
|
|
2316
2283
|
appendAcpSnapshot(current.output, current.truncated);
|
|
2317
|
-
const prepared = await prepareClientTerminalOutput(this.session, current);
|
|
2284
|
+
const prepared = await prepareClientTerminalOutput(this.session, current, artifactPublication);
|
|
2318
2285
|
const timeoutNotices = [
|
|
2319
2286
|
...pendingNotices,
|
|
2320
2287
|
...(current.truncated || prepared.locallyTruncated ? ["(output truncated)"] : []),
|
|
@@ -2351,7 +2318,11 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
2351
2318
|
const diagnostic = boundArtifactSaveDiagnostic(error);
|
|
2352
2319
|
const recoveredOutput = retainedAcpOutput();
|
|
2353
2320
|
appendAcpSnapshot(recoveredOutput.output, recoveredOutput.truncated);
|
|
2354
|
-
const prepared = await prepareClientTerminalOutput(
|
|
2321
|
+
const prepared = await prepareClientTerminalOutput(
|
|
2322
|
+
this.session,
|
|
2323
|
+
recoveredOutput,
|
|
2324
|
+
artifactPublication,
|
|
2325
|
+
);
|
|
2355
2326
|
logger.warn("ACP terminal poll output read failed", {
|
|
2356
2327
|
terminalId: handle.terminalId,
|
|
2357
2328
|
error,
|
|
@@ -2384,7 +2355,11 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
2384
2355
|
await boundedKill();
|
|
2385
2356
|
const diagnostic = boundArtifactSaveDiagnostic(error);
|
|
2386
2357
|
const recoveredOutput = retainedAcpOutput();
|
|
2387
|
-
const prepared = await prepareClientTerminalOutput(
|
|
2358
|
+
const prepared = await prepareClientTerminalOutput(
|
|
2359
|
+
this.session,
|
|
2360
|
+
recoveredOutput,
|
|
2361
|
+
artifactPublication,
|
|
2362
|
+
);
|
|
2388
2363
|
throw new ToolError(formatClientTerminalReadFailure(prepared, diagnostic, pendingNotices));
|
|
2389
2364
|
}
|
|
2390
2365
|
}
|
|
@@ -2408,7 +2383,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
2408
2383
|
});
|
|
2409
2384
|
}
|
|
2410
2385
|
appendAcpSnapshot(current.output, current.truncated);
|
|
2411
|
-
const prepared = await prepareClientTerminalOutput(this.session, current);
|
|
2386
|
+
const prepared = await prepareClientTerminalOutput(this.session, current, artifactPublication);
|
|
2412
2387
|
throw new ToolAbortError(formatClientTerminalAbortFailure(prepared, readDiagnostic, pendingNotices));
|
|
2413
2388
|
}
|
|
2414
2389
|
|
|
@@ -2434,7 +2409,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
2434
2409
|
if (runSignal?.aborted) {
|
|
2435
2410
|
await boundedKill();
|
|
2436
2411
|
appendAcpSnapshot(finalOutput.output, finalOutput.truncated);
|
|
2437
|
-
const prepared = await prepareClientTerminalOutput(this.session, finalOutput);
|
|
2412
|
+
const prepared = await prepareClientTerminalOutput(this.session, finalOutput, artifactPublication);
|
|
2438
2413
|
throw new ToolAbortError(
|
|
2439
2414
|
formatClientTerminalAbortFailure(prepared, finalReadDiagnostic, pendingNotices),
|
|
2440
2415
|
);
|
|
@@ -2446,7 +2421,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
2446
2421
|
rawExitCode != null ? rawExitCode : exitStatus.signal ? 137 : undefined;
|
|
2447
2422
|
|
|
2448
2423
|
appendAcpSnapshot(finalOutput.output, finalOutput.truncated);
|
|
2449
|
-
const prepared = await prepareClientTerminalOutput(this.session, finalOutput);
|
|
2424
|
+
const prepared = await prepareClientTerminalOutput(this.session, finalOutput, artifactPublication);
|
|
2450
2425
|
|
|
2451
2426
|
const bridgeResult: BashResult = {
|
|
2452
2427
|
...prepared.summary,
|
|
@@ -2663,9 +2638,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
2663
2638
|
// Track output for streaming updates (tail only)
|
|
2664
2639
|
const tailBuffer = new TailBuffer(spillThreshold);
|
|
2665
2640
|
|
|
2666
|
-
|
|
2667
|
-
const { path: artifactPath, id: artifactId } = (await this.session.allocateOutputArtifact?.("bash")) ?? {};
|
|
2668
|
-
const artifactPublisher = createBashArtifactPublisher(this.session);
|
|
2641
|
+
const artifactPublisher = createBashArtifactPublisher(artifactPublication);
|
|
2669
2642
|
|
|
2670
2643
|
const interactiveUi =
|
|
2671
2644
|
this.session.bashRestrictionProfile === "read-only" || directMasterSpawn
|
|
@@ -2693,8 +2666,6 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
2693
2666
|
signal,
|
|
2694
2667
|
env: resolvedEnv,
|
|
2695
2668
|
unsetEnv,
|
|
2696
|
-
artifactPath,
|
|
2697
|
-
artifactId,
|
|
2698
2669
|
artifactPublisher,
|
|
2699
2670
|
spillThreshold,
|
|
2700
2671
|
headBytes,
|
|
@@ -2862,13 +2833,11 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
2862
2833
|
signal,
|
|
2863
2834
|
env: resolvedEnv,
|
|
2864
2835
|
unsetEnv,
|
|
2865
|
-
artifactPath,
|
|
2866
|
-
artifactId,
|
|
2867
2836
|
artifactPublisher,
|
|
2868
2837
|
spillThreshold,
|
|
2869
2838
|
headBytes,
|
|
2870
2839
|
onChunk: streamTailUpdates(tailBuffer, onUpdate),
|
|
2871
|
-
onMinimizedSave: async originalText => saveBashOriginalArtifact(
|
|
2840
|
+
onMinimizedSave: async originalText => saveBashOriginalArtifact(artifactPublication, originalText),
|
|
2872
2841
|
ignoreShellPrefix: this.session.bashRestrictionProfile === "read-only" || directMasterSpawn,
|
|
2873
2842
|
disableShellSnapshot: this.session.bashRestrictionProfile === "read-only" || directMasterSpawn,
|
|
2874
2843
|
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const LOOPBACK_HOSTS = new Set(["127.0.0.1", "localhost", "::1", "[::1]"]);
|
|
2
|
+
|
|
3
|
+
/** Require an http(s) CDP URL whose host is loopback. */
|
|
4
|
+
export function assertLoopbackCdpUrl(cdpUrl: string): string {
|
|
5
|
+
let parsed: URL;
|
|
6
|
+
try {
|
|
7
|
+
parsed = new URL(cdpUrl);
|
|
8
|
+
} catch {
|
|
9
|
+
throw new Error(`Refusing non-loopback CDP endpoint: ${cdpUrl}`);
|
|
10
|
+
}
|
|
11
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
12
|
+
throw new Error(`Refusing non-loopback CDP endpoint: ${cdpUrl}`);
|
|
13
|
+
}
|
|
14
|
+
if (!LOOPBACK_HOSTS.has(parsed.hostname.toLowerCase())) {
|
|
15
|
+
throw new Error(`Refusing non-loopback CDP endpoint: ${cdpUrl}`);
|
|
16
|
+
}
|
|
17
|
+
return cdpUrl;
|
|
18
|
+
}
|
package/src/tools/browser.ts
CHANGED
|
@@ -6,6 +6,7 @@ import * as z from "zod/v4";
|
|
|
6
6
|
import browserDescription from "../prompts/tools/browser.md" with { type: "text" };
|
|
7
7
|
import type { ToolSession } from "../sdk";
|
|
8
8
|
import { type BrowserActionStep, compileActionSteps } from "./browser/actions";
|
|
9
|
+
import { assertLoopbackCdpUrl } from "./browser/cdp-url";
|
|
9
10
|
import { isChromeProfileExecutableForLaunch, isEdgeExecutable, resolveSystemChromeForProfile } from "./browser/launch";
|
|
10
11
|
import { chromeUserDataRoots, type DiscoveryEnv, defaultDiscoveryEnv } from "./browser/profile-discovery";
|
|
11
12
|
import { acquireBrowser, type BrowserHandle, type BrowserKind, type BrowserKindTag } from "./browser/registry";
|
|
@@ -245,7 +246,13 @@ async function resolveBrowserKind(
|
|
|
245
246
|
): Promise<BrowserKind> {
|
|
246
247
|
const app = params.app;
|
|
247
248
|
if (app?.cdp_url) {
|
|
248
|
-
|
|
249
|
+
const cdpUrl = app.cdp_url.replace(/\/+$/, "");
|
|
250
|
+
try {
|
|
251
|
+
assertLoopbackCdpUrl(cdpUrl);
|
|
252
|
+
} catch (error) {
|
|
253
|
+
throw new ToolError(error instanceof Error ? error.message : String(error));
|
|
254
|
+
}
|
|
255
|
+
return { kind: "connected", cdpUrl };
|
|
249
256
|
}
|
|
250
257
|
if (app?.browser === "chrome") {
|
|
251
258
|
return resolveChromeProfileKind(app, session, signal, discoveryEnv);
|
package/src/tools/descriptors.ts
CHANGED
|
@@ -351,10 +351,14 @@ const loaders: Record<string, Loader> = {
|
|
|
351
351
|
cwd: session.cwd,
|
|
352
352
|
settings: session.settings,
|
|
353
353
|
getCwd: () => session.cwd,
|
|
354
|
+
getSessionFile: () => session.getSessionFile(),
|
|
354
355
|
getSessionId: () => session.getSessionId?.() ?? null,
|
|
355
356
|
registerSessionCleanup: (cleanup: () => Promise<void> | void) => {
|
|
356
|
-
session.registerSessionCleanup?.(cleanup);
|
|
357
|
+
return session.registerSessionCleanup?.(cleanup);
|
|
357
358
|
},
|
|
359
|
+
assertEvalExecutionAllowed: () => session.assertEvalExecutionAllowed?.(),
|
|
360
|
+
trackEvalExecution: <T>(execution: Promise<T>, abortController: AbortController) =>
|
|
361
|
+
session.trackEvalExecution?.(execution, abortController) ?? execution,
|
|
358
362
|
}),
|
|
359
363
|
),
|
|
360
364
|
job: session => cached("job", () => import("./job")).then(module => module.JobTool.createIf(session)),
|