@xyit/wellspring 0.0.0-stage → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +853 -2
- package/dist/agent/pending-asks.d.ts +20 -0
- package/dist/agent/pending-asks.js +70 -0
- package/dist/agent/pending-asks.js.map +1 -0
- package/dist/agent/task-registry.d.ts +14 -0
- package/dist/agent/task-registry.js +80 -0
- package/dist/agent/task-registry.js.map +1 -0
- package/dist/agent/tool-context.d.ts +30 -0
- package/dist/agent/tool-context.js +10 -0
- package/dist/agent/tool-context.js.map +1 -0
- package/dist/agent/usage.d.ts +40 -0
- package/dist/agent/usage.js +122 -0
- package/dist/agent/usage.js.map +1 -0
- package/dist/api/host/agent.d.ts +165 -0
- package/dist/api/host/agent.js +5 -0
- package/dist/api/host/agent.js.map +1 -0
- package/dist/api/host/events.d.ts +2 -0
- package/dist/api/host/events.js +6 -0
- package/dist/api/host/events.js.map +1 -0
- package/dist/api/host/exec.d.ts +36 -0
- package/dist/api/host/exec.js +10 -0
- package/dist/api/host/exec.js.map +1 -0
- package/dist/api/host/fs.d.ts +24 -0
- package/dist/api/host/fs.js +7 -0
- package/dist/api/host/fs.js.map +1 -0
- package/dist/api/host/hooks.d.ts +210 -0
- package/dist/api/host/hooks.js +401 -0
- package/dist/api/host/hooks.js.map +1 -0
- package/dist/api/host/host.d.ts +36 -0
- package/dist/api/host/host.js +53 -0
- package/dist/api/host/host.js.map +1 -0
- package/dist/api/host/http.d.ts +58 -0
- package/dist/api/host/http.js +6 -0
- package/dist/api/host/http.js.map +1 -0
- package/dist/api/host/index.d.ts +15 -0
- package/dist/api/host/index.js +20 -0
- package/dist/api/host/index.js.map +1 -0
- package/dist/api/host/models.d.ts +65 -0
- package/dist/api/host/models.js +8 -0
- package/dist/api/host/models.js.map +1 -0
- package/dist/api/host/network.d.ts +22 -0
- package/dist/api/host/network.js +7 -0
- package/dist/api/host/network.js.map +1 -0
- package/dist/api/host/plugin.d.ts +138 -0
- package/dist/api/host/plugin.js +6 -0
- package/dist/api/host/plugin.js.map +1 -0
- package/dist/api/host/plugins.d.ts +49 -0
- package/dist/api/host/plugins.js +6 -0
- package/dist/api/host/plugins.js.map +1 -0
- package/dist/api/host/pty.d.ts +55 -0
- package/dist/api/host/pty.js +21 -0
- package/dist/api/host/pty.js.map +1 -0
- package/dist/api/host/session.d.ts +5 -0
- package/dist/api/host/session.js +52 -0
- package/dist/api/host/session.js.map +1 -0
- package/dist/api/host/version.d.ts +2 -0
- package/dist/api/host/version.js +3 -0
- package/dist/api/host/version.js.map +1 -0
- package/dist/api/host/workspace.d.ts +38 -0
- package/dist/api/host/workspace.js +9 -0
- package/dist/api/host/workspace.js.map +1 -0
- package/dist/api/plugin/http-client.d.ts +42 -0
- package/dist/api/plugin/http-client.js +364 -0
- package/dist/api/plugin/http-client.js.map +1 -0
- package/dist/api/plugin/http-protocol.d.ts +152 -0
- package/dist/api/plugin/http-protocol.js +49 -0
- package/dist/api/plugin/http-protocol.js.map +1 -0
- package/dist/api/result/result.d.ts +16 -0
- package/dist/api/result/result.js +43 -0
- package/dist/api/result/result.js.map +1 -0
- package/dist/commands/agent-turn.d.ts +63 -0
- package/dist/commands/agent-turn.js +687 -0
- package/dist/commands/agent-turn.js.map +1 -0
- package/dist/commands/ask-prompt.d.ts +6 -0
- package/dist/commands/ask-prompt.js +49 -0
- package/dist/commands/ask-prompt.js.map +1 -0
- package/dist/commands/config.d.ts +2 -0
- package/dist/commands/config.js +283 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/conversation.d.ts +51 -0
- package/dist/commands/conversation.js +630 -0
- package/dist/commands/conversation.js.map +1 -0
- package/dist/commands/doctor.d.ts +2 -0
- package/dist/commands/doctor.js +77 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/exec-approval.d.ts +3 -0
- package/dist/commands/exec-approval.js +80 -0
- package/dist/commands/exec-approval.js.map +1 -0
- package/dist/commands/help.d.ts +2 -0
- package/dist/commands/help.js +35 -0
- package/dist/commands/help.js.map +1 -0
- package/dist/commands/key.d.ts +2 -0
- package/dist/commands/key.js +226 -0
- package/dist/commands/key.js.map +1 -0
- package/dist/commands/plugin.d.ts +2 -0
- package/dist/commands/plugin.js +190 -0
- package/dist/commands/plugin.js.map +1 -0
- package/dist/commands/session.d.ts +2 -0
- package/dist/commands/session.js +167 -0
- package/dist/commands/session.js.map +1 -0
- package/dist/commands/shared.d.ts +35 -0
- package/dist/commands/shared.js +66 -0
- package/dist/commands/shared.js.map +1 -0
- package/dist/commands/start.d.ts +2 -0
- package/dist/commands/start.js +75 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/stop.d.ts +2 -0
- package/dist/commands/stop.js +24 -0
- package/dist/commands/stop.js.map +1 -0
- package/dist/commands/version.d.ts +2 -0
- package/dist/commands/version.js +33 -0
- package/dist/commands/version.js.map +1 -0
- package/dist/config/codes.d.ts +13 -0
- package/dist/config/codes.js +15 -0
- package/dist/config/codes.js.map +1 -0
- package/dist/config/credentials.d.ts +67 -0
- package/dist/config/credentials.js +214 -0
- package/dist/config/credentials.js.map +1 -0
- package/dist/config/defaults.d.ts +5 -0
- package/dist/config/defaults.js +31 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/index.d.ts +5 -0
- package/dist/config/index.js +10 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/loader.d.ts +10 -0
- package/dist/config/loader.js +68 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/providers.d.ts +30 -0
- package/dist/config/providers.js +97 -0
- package/dist/config/providers.js.map +1 -0
- package/dist/config/types.d.ts +75 -0
- package/dist/config/types.js +4 -0
- package/dist/config/types.js.map +1 -0
- package/dist/config/validate.d.ts +4 -0
- package/dist/config/validate.js +391 -0
- package/dist/config/validate.js.map +1 -0
- package/dist/display/markdown.d.ts +7 -0
- package/dist/display/markdown.js +116 -0
- package/dist/display/markdown.js.map +1 -0
- package/dist/display/tool-label.d.ts +6 -0
- package/dist/display/tool-label.js +81 -0
- package/dist/display/tool-label.js.map +1 -0
- package/dist/event/event.d.ts +27 -0
- package/dist/event/event.js +152 -0
- package/dist/event/event.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +308 -0
- package/dist/index.js.map +1 -0
- package/dist/input/codes.d.ts +15 -0
- package/dist/input/codes.js +20 -0
- package/dist/input/codes.js.map +1 -0
- package/dist/input/commands.d.ts +10 -0
- package/dist/input/commands.js +65 -0
- package/dist/input/commands.js.map +1 -0
- package/dist/input/help.d.ts +8 -0
- package/dist/input/help.js +51 -0
- package/dist/input/help.js.map +1 -0
- package/dist/input/index.d.ts +6 -0
- package/dist/input/index.js +10 -0
- package/dist/input/index.js.map +1 -0
- package/dist/input/parse-options.d.ts +11 -0
- package/dist/input/parse-options.js +51 -0
- package/dist/input/parse-options.js.map +1 -0
- package/dist/input/parse.d.ts +3 -0
- package/dist/input/parse.js +119 -0
- package/dist/input/parse.js.map +1 -0
- package/dist/input/types.d.ts +17 -0
- package/dist/input/types.js +2 -0
- package/dist/input/types.js.map +1 -0
- package/dist/logger/elog4js.d.ts +65 -0
- package/dist/logger/elog4js.js +305 -0
- package/dist/logger/elog4js.js.map +1 -0
- package/dist/logger/logger.d.ts +37 -0
- package/dist/logger/logger.js +196 -0
- package/dist/logger/logger.js.map +1 -0
- package/dist/network/index.d.ts +2 -0
- package/dist/network/index.js +6 -0
- package/dist/network/index.js.map +1 -0
- package/dist/network/openai.d.ts +117 -0
- package/dist/network/openai.js +443 -0
- package/dist/network/openai.js.map +1 -0
- package/dist/network/proxy.d.ts +9 -0
- package/dist/network/proxy.js +72 -0
- package/dist/network/proxy.js.map +1 -0
- package/dist/network/web.d.ts +34 -0
- package/dist/network/web.js +152 -0
- package/dist/network/web.js.map +1 -0
- package/dist/platform/clipboard.d.ts +15 -0
- package/dist/platform/clipboard.js +82 -0
- package/dist/platform/clipboard.js.map +1 -0
- package/dist/platform/exec.d.ts +28 -0
- package/dist/platform/exec.js +95 -0
- package/dist/platform/exec.js.map +1 -0
- package/dist/platform/file.d.ts +38 -0
- package/dist/platform/file.js +197 -0
- package/dist/platform/file.js.map +1 -0
- package/dist/platform/index.d.ts +7 -0
- package/dist/platform/index.js +12 -0
- package/dist/platform/index.js.map +1 -0
- package/dist/platform/notification.d.ts +14 -0
- package/dist/platform/notification.js +82 -0
- package/dist/platform/notification.js.map +1 -0
- package/dist/platform/open-external.d.ts +10 -0
- package/dist/platform/open-external.js +105 -0
- package/dist/platform/open-external.js.map +1 -0
- package/dist/platform/os.d.ts +20 -0
- package/dist/platform/os.js +86 -0
- package/dist/platform/os.js.map +1 -0
- package/dist/platform/path.d.ts +32 -0
- package/dist/platform/path.js +154 -0
- package/dist/platform/path.js.map +1 -0
- package/dist/plugin/access-guard.d.ts +1 -0
- package/dist/plugin/access-guard.js +40 -0
- package/dist/plugin/access-guard.js.map +1 -0
- package/dist/plugin/agent-service.d.ts +25 -0
- package/dist/plugin/agent-service.js +809 -0
- package/dist/plugin/agent-service.js.map +1 -0
- package/dist/plugin/agent-tools.d.ts +12 -0
- package/dist/plugin/agent-tools.js +31 -0
- package/dist/plugin/agent-tools.js.map +1 -0
- package/dist/plugin/capabilities.d.ts +26 -0
- package/dist/plugin/capabilities.js +192 -0
- package/dist/plugin/capabilities.js.map +1 -0
- package/dist/plugin/console-guard.d.ts +2 -0
- package/dist/plugin/console-guard.js +52 -0
- package/dist/plugin/console-guard.js.map +1 -0
- package/dist/plugin/data-access.d.ts +15 -0
- package/dist/plugin/data-access.js +57 -0
- package/dist/plugin/data-access.js.map +1 -0
- package/dist/plugin/fs.d.ts +3 -0
- package/dist/plugin/fs.js +93 -0
- package/dist/plugin/fs.js.map +1 -0
- package/dist/plugin/host-alias.d.ts +2 -0
- package/dist/plugin/host-alias.js +57 -0
- package/dist/plugin/host-alias.js.map +1 -0
- package/dist/plugin/index.d.ts +7 -0
- package/dist/plugin/index.js +11 -0
- package/dist/plugin/index.js.map +1 -0
- package/dist/plugin/install.d.ts +17 -0
- package/dist/plugin/install.js +163 -0
- package/dist/plugin/install.js.map +1 -0
- package/dist/plugin/loader.d.ts +45 -0
- package/dist/plugin/loader.js +739 -0
- package/dist/plugin/loader.js.map +1 -0
- package/dist/plugin/manage.d.ts +31 -0
- package/dist/plugin/manage.js +271 -0
- package/dist/plugin/manage.js.map +1 -0
- package/dist/plugin/models-service.d.ts +15 -0
- package/dist/plugin/models-service.js +317 -0
- package/dist/plugin/models-service.js.map +1 -0
- package/dist/plugin/network-service.d.ts +10 -0
- package/dist/plugin/network-service.js +87 -0
- package/dist/plugin/network-service.js.map +1 -0
- package/dist/plugin/package-manager.d.ts +46 -0
- package/dist/plugin/package-manager.js +148 -0
- package/dist/plugin/package-manager.js.map +1 -0
- package/dist/plugin/paths.d.ts +6 -0
- package/dist/plugin/paths.js +15 -0
- package/dist/plugin/paths.js.map +1 -0
- package/dist/plugin/registry.d.ts +17 -0
- package/dist/plugin/registry.js +82 -0
- package/dist/plugin/registry.js.map +1 -0
- package/dist/plugin/runtime.d.ts +9 -0
- package/dist/plugin/runtime.js +43 -0
- package/dist/plugin/runtime.js.map +1 -0
- package/dist/plugin/scaffold.d.ts +13 -0
- package/dist/plugin/scaffold.js +132 -0
- package/dist/plugin/scaffold.js.map +1 -0
- package/dist/plugin/state.d.ts +6 -0
- package/dist/plugin/state.js +38 -0
- package/dist/plugin/state.js.map +1 -0
- package/dist/plugin/zip.d.ts +7 -0
- package/dist/plugin/zip.js +138 -0
- package/dist/plugin/zip.js.map +1 -0
- package/dist/sandbox/audit.d.ts +12 -0
- package/dist/sandbox/audit.js +20 -0
- package/dist/sandbox/audit.js.map +1 -0
- package/dist/sandbox/backends/bwrap.d.ts +28 -0
- package/dist/sandbox/backends/bwrap.js +197 -0
- package/dist/sandbox/backends/bwrap.js.map +1 -0
- package/dist/sandbox/backends/direct.d.ts +7 -0
- package/dist/sandbox/backends/direct.js +32 -0
- package/dist/sandbox/backends/direct.js.map +1 -0
- package/dist/sandbox/bridge-state.d.ts +13 -0
- package/dist/sandbox/bridge-state.js +12 -0
- package/dist/sandbox/bridge-state.js.map +1 -0
- package/dist/sandbox/index.d.ts +5 -0
- package/dist/sandbox/index.js +6 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/sandbox/manager.d.ts +8 -0
- package/dist/sandbox/manager.js +325 -0
- package/dist/sandbox/manager.js.map +1 -0
- package/dist/sandbox/memory-limit.d.ts +44 -0
- package/dist/sandbox/memory-limit.js +193 -0
- package/dist/sandbox/memory-limit.js.map +1 -0
- package/dist/sandbox/plugin-client.d.ts +80 -0
- package/dist/sandbox/plugin-client.js +1601 -0
- package/dist/sandbox/plugin-client.js.map +1 -0
- package/dist/sandbox/plugin-host.d.ts +1 -0
- package/dist/sandbox/plugin-host.js +1001 -0
- package/dist/sandbox/plugin-host.js.map +1 -0
- package/dist/sandbox/protocol.d.ts +43 -0
- package/dist/sandbox/protocol.js +96 -0
- package/dist/sandbox/protocol.js.map +1 -0
- package/dist/sandbox/rpc-timeouts.d.ts +28 -0
- package/dist/sandbox/rpc-timeouts.js +15 -0
- package/dist/sandbox/rpc-timeouts.js.map +1 -0
- package/dist/sandbox/supervisor.d.ts +31 -0
- package/dist/sandbox/supervisor.js +114 -0
- package/dist/sandbox/supervisor.js.map +1 -0
- package/dist/sandbox/types.d.ts +124 -0
- package/dist/sandbox/types.js +17 -0
- package/dist/sandbox/types.js.map +1 -0
- package/dist/service/control.d.ts +32 -0
- package/dist/service/control.js +117 -0
- package/dist/service/control.js.map +1 -0
- package/dist/session/compress.d.ts +3 -0
- package/dist/session/compress.js +42 -0
- package/dist/session/compress.js.map +1 -0
- package/dist/session/index.d.ts +4 -0
- package/dist/session/index.js +8 -0
- package/dist/session/index.js.map +1 -0
- package/dist/session/registry.d.ts +4 -0
- package/dist/session/registry.js +12 -0
- package/dist/session/registry.js.map +1 -0
- package/dist/session/replay.d.ts +10 -0
- package/dist/session/replay.js +109 -0
- package/dist/session/replay.js.map +1 -0
- package/dist/session/session.d.ts +40 -0
- package/dist/session/session.js +108 -0
- package/dist/session/session.js.map +1 -0
- package/dist/session/store.d.ts +58 -0
- package/dist/session/store.js +382 -0
- package/dist/session/store.js.map +1 -0
- package/dist/session/types.d.ts +56 -0
- package/dist/session/types.js +3 -0
- package/dist/session/types.js.map +1 -0
- package/dist/workspace/index.d.ts +7 -0
- package/dist/workspace/index.js +17 -0
- package/dist/workspace/index.js.map +1 -0
- package/dist/workspace/registry.d.ts +25 -0
- package/dist/workspace/registry.js +293 -0
- package/dist/workspace/registry.js.map +1 -0
- package/package.json +73 -5
- package/scripts/build-node-pty.mjs +55 -0
- package/scripts/rewrite-dts.mjs +36 -0
- package/scripts/run-tests.mjs +41 -0
- package/scripts/verify-sandbox.ts +98 -0
- package/src/agent/pending-asks.ts +88 -0
- package/src/agent/task-registry.ts +108 -0
- package/src/agent/tool-context.ts +47 -0
- package/src/agent/usage.ts +170 -0
- package/src/api/host/agent.ts +162 -0
- package/src/api/host/events.ts +7 -0
- package/src/api/host/exec.ts +47 -0
- package/src/api/host/fs.ts +33 -0
- package/src/api/host/hooks.ts +635 -0
- package/src/api/host/host.ts +99 -0
- package/src/api/host/http.ts +79 -0
- package/src/api/host/index.ts +20 -0
- package/src/api/host/models.ts +81 -0
- package/src/api/host/network.ts +32 -0
- package/src/api/host/plugin.ts +158 -0
- package/src/api/host/plugins.ts +59 -0
- package/src/api/host/pty.ts +73 -0
- package/src/api/host/session.ts +61 -0
- package/src/api/host/version.ts +2 -0
- package/src/api/host/workspace.ts +51 -0
- package/src/api/plugin/http-client.ts +492 -0
- package/src/api/plugin/http-protocol.ts +231 -0
- package/src/api/result/result.ts +52 -0
- package/src/commands/agent-turn.ts +817 -0
- package/src/commands/ask-prompt.ts +52 -0
- package/src/commands/config.ts +306 -0
- package/src/commands/conversation.ts +777 -0
- package/src/commands/doctor.ts +92 -0
- package/src/commands/exec-approval.ts +91 -0
- package/src/commands/help.ts +41 -0
- package/src/commands/key.ts +281 -0
- package/src/commands/plugin.ts +222 -0
- package/src/commands/session.ts +179 -0
- package/src/commands/shared.ts +103 -0
- package/src/commands/start.ts +88 -0
- package/src/commands/stop.ts +24 -0
- package/src/commands/version.ts +40 -0
- package/src/config/codes.ts +17 -0
- package/src/config/credentials.ts +302 -0
- package/src/config/defaults.ts +32 -0
- package/src/config/index.ts +10 -0
- package/src/config/loader.ts +80 -0
- package/src/config/providers.ts +133 -0
- package/src/config/types.ts +88 -0
- package/src/config/validate.ts +458 -0
- package/src/display/markdown.ts +137 -0
- package/src/display/tool-label.ts +87 -0
- package/src/event/event.ts +171 -0
- package/src/index.ts +344 -0
- package/src/input/codes.ts +21 -0
- package/src/input/commands.ts +76 -0
- package/src/input/help.ts +60 -0
- package/src/input/index.ts +10 -0
- package/src/input/parse-options.ts +66 -0
- package/src/input/parse.ts +138 -0
- package/src/input/types.ts +19 -0
- package/src/logger/elog4js.ts +366 -0
- package/src/logger/logger.ts +251 -0
- package/src/network/index.ts +6 -0
- package/src/network/openai.ts +571 -0
- package/src/network/proxy.ts +80 -0
- package/src/network/web.ts +206 -0
- package/src/platform/clipboard.ts +107 -0
- package/src/platform/exec.ts +128 -0
- package/src/platform/file.ts +235 -0
- package/src/platform/index.ts +12 -0
- package/src/platform/notification.ts +108 -0
- package/src/platform/open-external.ts +132 -0
- package/src/platform/os.ts +101 -0
- package/src/platform/path.ts +214 -0
- package/src/plugin/access-guard.ts +46 -0
- package/src/plugin/agent-service.ts +969 -0
- package/src/plugin/agent-tools.ts +43 -0
- package/src/plugin/capabilities.ts +240 -0
- package/src/plugin/console-guard.ts +66 -0
- package/src/plugin/data-access.ts +70 -0
- package/src/plugin/fs.ts +109 -0
- package/src/plugin/host-alias.ts +61 -0
- package/src/plugin/index.ts +11 -0
- package/src/plugin/install.ts +213 -0
- package/src/plugin/loader.ts +952 -0
- package/src/plugin/manage.ts +338 -0
- package/src/plugin/models-service.ts +383 -0
- package/src/plugin/network-service.ts +102 -0
- package/src/plugin/package-manager.ts +214 -0
- package/src/plugin/paths.ts +19 -0
- package/src/plugin/registry.ts +103 -0
- package/src/plugin/runtime.ts +57 -0
- package/src/plugin/scaffold.ts +158 -0
- package/src/plugin/state.ts +52 -0
- package/src/plugin/zip.ts +156 -0
- package/src/sandbox/audit.ts +38 -0
- package/src/sandbox/backends/bwrap.ts +251 -0
- package/src/sandbox/backends/direct.ts +43 -0
- package/src/sandbox/bridge-state.ts +29 -0
- package/src/sandbox/index.ts +5 -0
- package/src/sandbox/manager.ts +406 -0
- package/src/sandbox/memory-limit.ts +245 -0
- package/src/sandbox/plugin-client.ts +1881 -0
- package/src/sandbox/plugin-host.ts +1282 -0
- package/src/sandbox/protocol.ts +142 -0
- package/src/sandbox/pty-bridge.py +154 -0
- package/src/sandbox/rpc-timeouts.ts +43 -0
- package/src/sandbox/supervisor.ts +172 -0
- package/src/sandbox/types.ts +149 -0
- package/src/service/control.ts +155 -0
- package/src/session/compress.ts +47 -0
- package/src/session/index.ts +8 -0
- package/src/session/registry.ts +17 -0
- package/src/session/replay.ts +132 -0
- package/src/session/session.ts +134 -0
- package/src/session/store.ts +468 -0
- package/src/session/types.ts +61 -0
- package/src/workspace/index.ts +21 -0
- package/src/workspace/registry.ts +356 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Sandbox RPC v1 帧协议:4 字节大端长度 + UTF-8 JSON。
|
|
3
|
+
* 供宿主 ↔ 插件 sandbox、agent-code 控制通道复用。
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export const SANDBOX_PROTOCOL_VERSION = 1
|
|
7
|
+
export const MAX_FRAME_BYTES = 4 * 1024 * 1024
|
|
8
|
+
|
|
9
|
+
export interface RpcErrorPayload {
|
|
10
|
+
readonly code: string
|
|
11
|
+
readonly message: string
|
|
12
|
+
readonly retryable?: boolean
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface RpcRequest {
|
|
16
|
+
readonly v: 1
|
|
17
|
+
readonly type: "request"
|
|
18
|
+
readonly id: string
|
|
19
|
+
readonly method: string
|
|
20
|
+
readonly params?: unknown
|
|
21
|
+
readonly timeoutMs?: number
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface RpcResponse {
|
|
25
|
+
readonly v: 1
|
|
26
|
+
readonly type: "response"
|
|
27
|
+
readonly id: string
|
|
28
|
+
readonly ok: boolean
|
|
29
|
+
readonly result?: unknown
|
|
30
|
+
readonly error?: RpcErrorPayload
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface RpcEvent {
|
|
34
|
+
readonly v: 1
|
|
35
|
+
readonly type: "event"
|
|
36
|
+
readonly method: string
|
|
37
|
+
readonly params: unknown
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type RpcMessage = RpcRequest | RpcResponse | RpcEvent
|
|
41
|
+
|
|
42
|
+
export class SandboxProtocolError extends Error {
|
|
43
|
+
readonly code: string
|
|
44
|
+
|
|
45
|
+
constructor(code: string, message: string) {
|
|
46
|
+
super(message)
|
|
47
|
+
this.name = "SandboxProtocolError"
|
|
48
|
+
this.code = code
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function isObject(value: unknown): value is Record<string, unknown> {
|
|
53
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function validateMessage(value: unknown): RpcMessage {
|
|
57
|
+
if (!isObject(value)) {
|
|
58
|
+
throw new SandboxProtocolError("sandbox.protocol", "消息不是对象")
|
|
59
|
+
}
|
|
60
|
+
if (value["v"] !== SANDBOX_PROTOCOL_VERSION) {
|
|
61
|
+
throw new SandboxProtocolError("sandbox.protocol-mismatch", "协议版本不一致")
|
|
62
|
+
}
|
|
63
|
+
const type = value["type"]
|
|
64
|
+
if (type === "request") {
|
|
65
|
+
if (typeof value["id"] !== "string" || typeof value["method"] !== "string") {
|
|
66
|
+
throw new SandboxProtocolError("sandbox.protocol", "request 缺少 id/method")
|
|
67
|
+
}
|
|
68
|
+
return value as unknown as RpcRequest
|
|
69
|
+
}
|
|
70
|
+
if (type === "response") {
|
|
71
|
+
if (typeof value["id"] !== "string" || typeof value["ok"] !== "boolean") {
|
|
72
|
+
throw new SandboxProtocolError("sandbox.protocol", "response 缺少 id/ok")
|
|
73
|
+
}
|
|
74
|
+
return value as unknown as RpcResponse
|
|
75
|
+
}
|
|
76
|
+
if (type === "event") {
|
|
77
|
+
if (typeof value["method"] !== "string") {
|
|
78
|
+
throw new SandboxProtocolError("sandbox.protocol", "event 缺少 method")
|
|
79
|
+
}
|
|
80
|
+
return value as unknown as RpcEvent
|
|
81
|
+
}
|
|
82
|
+
throw new SandboxProtocolError("sandbox.protocol", "未知消息类型")
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function encodeMessage(message: RpcMessage): Buffer {
|
|
86
|
+
const payload = Buffer.from(JSON.stringify(message), "utf8")
|
|
87
|
+
if (payload.length > MAX_FRAME_BYTES) {
|
|
88
|
+
throw new SandboxProtocolError("sandbox.protocol-limit", "帧超过上限")
|
|
89
|
+
}
|
|
90
|
+
const frame = Buffer.allocUnsafe(4 + payload.length)
|
|
91
|
+
frame.writeUInt32BE(payload.length, 0)
|
|
92
|
+
payload.copy(frame, 4)
|
|
93
|
+
return frame
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** 流式解码器;支持任意 chunk 切分 */
|
|
97
|
+
export class FrameDecoder {
|
|
98
|
+
#buffer: Buffer = Buffer.alloc(0)
|
|
99
|
+
readonly #maxFrameBytes: number
|
|
100
|
+
|
|
101
|
+
constructor(maxFrameBytes = MAX_FRAME_BYTES) {
|
|
102
|
+
this.#maxFrameBytes = maxFrameBytes
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
push(chunk: Buffer): RpcMessage[] {
|
|
106
|
+
this.#buffer = Buffer.concat([this.#buffer, chunk])
|
|
107
|
+
const messages: RpcMessage[] = []
|
|
108
|
+
while (this.#buffer.length >= 4) {
|
|
109
|
+
const length = this.#buffer.readUInt32BE(0)
|
|
110
|
+
if (length > this.#maxFrameBytes) {
|
|
111
|
+
throw new SandboxProtocolError("sandbox.protocol-limit", "帧超过上限")
|
|
112
|
+
}
|
|
113
|
+
if (this.#buffer.length < 4 + length) {
|
|
114
|
+
break
|
|
115
|
+
}
|
|
116
|
+
const payload = this.#buffer.subarray(4, 4 + length)
|
|
117
|
+
this.#buffer = this.#buffer.subarray(4 + length)
|
|
118
|
+
let parsed: unknown
|
|
119
|
+
try {
|
|
120
|
+
parsed = JSON.parse(payload.toString("utf8"))
|
|
121
|
+
} catch (error) {
|
|
122
|
+
throw new SandboxProtocolError(
|
|
123
|
+
"sandbox.protocol",
|
|
124
|
+
`JSON 解析失败:${error instanceof Error ? error.message : String(error)}`,
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
messages.push(validateMessage(parsed))
|
|
128
|
+
}
|
|
129
|
+
return messages
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
get bufferedBytes(): number {
|
|
133
|
+
return this.#buffer.length
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
let requestCounter = 0
|
|
138
|
+
|
|
139
|
+
export function nextRequestId(prefix = "req"): string {
|
|
140
|
+
requestCounter += 1
|
|
141
|
+
return `${prefix}-${Date.now().toString(36)}-${requestCounter}`
|
|
142
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""PTY 桥接器:在没有 node-pty 的机器上提供真 tty。
|
|
3
|
+
|
|
4
|
+
由宿主 spawn,标准输出直接是 pty 的原始字节流;控制命令从 fd 3 读,
|
|
5
|
+
每行一个 JSON:
|
|
6
|
+
|
|
7
|
+
{"type": "input", "data": "ls\r"}
|
|
8
|
+
{"type": "resize", "cols": 120, "rows": 30}
|
|
9
|
+
{"type": "kill"}
|
|
10
|
+
|
|
11
|
+
退出码沿用子进程的退出码,宿主据此判断会话结束。
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import errno
|
|
15
|
+
import fcntl
|
|
16
|
+
import json
|
|
17
|
+
import os
|
|
18
|
+
import select
|
|
19
|
+
import signal
|
|
20
|
+
import struct
|
|
21
|
+
import subprocess
|
|
22
|
+
import sys
|
|
23
|
+
import termios
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def set_size(fd: int, cols: int, rows: int) -> None:
|
|
27
|
+
winsize = struct.pack("HHHH", max(1, rows), max(1, cols), 0, 0)
|
|
28
|
+
fcntl.ioctl(fd, termios.TIOCSWINSZ, winsize)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def main() -> int:
|
|
32
|
+
config = json.loads(sys.argv[1]) if len(sys.argv) > 1 else {}
|
|
33
|
+
shell = config.get("shell") or os.environ.get("SHELL") or "/bin/bash"
|
|
34
|
+
args = config.get("args") or []
|
|
35
|
+
cwd = config.get("cwd") or os.getcwd()
|
|
36
|
+
cols = int(config.get("cols") or 100)
|
|
37
|
+
rows = int(config.get("rows") or 28)
|
|
38
|
+
extra_env = config.get("env") or {}
|
|
39
|
+
|
|
40
|
+
env = dict(os.environ)
|
|
41
|
+
env.update({k: str(v) for k, v in extra_env.items()})
|
|
42
|
+
env.setdefault("TERM", "xterm-256color")
|
|
43
|
+
|
|
44
|
+
master, slave = os.openpty()
|
|
45
|
+
set_size(slave, cols, rows)
|
|
46
|
+
|
|
47
|
+
child = subprocess.Popen(
|
|
48
|
+
[shell, *args],
|
|
49
|
+
stdin=slave,
|
|
50
|
+
stdout=slave,
|
|
51
|
+
stderr=slave,
|
|
52
|
+
cwd=cwd,
|
|
53
|
+
env=env,
|
|
54
|
+
preexec_fn=os.setsid,
|
|
55
|
+
close_fds=True,
|
|
56
|
+
)
|
|
57
|
+
os.close(slave)
|
|
58
|
+
|
|
59
|
+
# 控制通道默认走 stdin(宿主用 stdio 的 pipe 直连);也可指定别的 fd
|
|
60
|
+
control = int(config.get("controlFd") or 0)
|
|
61
|
+
out = sys.stdout.buffer
|
|
62
|
+
pending_control = b""
|
|
63
|
+
running = True
|
|
64
|
+
|
|
65
|
+
while running:
|
|
66
|
+
try:
|
|
67
|
+
readable, _, _ = select.select([master, control], [], [], 0.5)
|
|
68
|
+
except (OSError, ValueError):
|
|
69
|
+
break
|
|
70
|
+
|
|
71
|
+
if control in readable:
|
|
72
|
+
try:
|
|
73
|
+
chunk = os.read(control, 65536)
|
|
74
|
+
except OSError as error:
|
|
75
|
+
chunk = b"" if error.errno in (errno.EAGAIN, errno.EWOULDBLOCK) else b""
|
|
76
|
+
if chunk == b"" and child.poll() is not None:
|
|
77
|
+
running = False
|
|
78
|
+
else:
|
|
79
|
+
pending_control += chunk
|
|
80
|
+
while b"\n" in pending_control:
|
|
81
|
+
line, pending_control = pending_control.split(b"\n", 1)
|
|
82
|
+
line = line.strip()
|
|
83
|
+
if not line:
|
|
84
|
+
continue
|
|
85
|
+
try:
|
|
86
|
+
command = json.loads(line)
|
|
87
|
+
except ValueError:
|
|
88
|
+
continue
|
|
89
|
+
kind = command.get("type")
|
|
90
|
+
if kind == "input":
|
|
91
|
+
data = command.get("data") or ""
|
|
92
|
+
if data:
|
|
93
|
+
try:
|
|
94
|
+
os.write(master, data.encode("utf-8", "replace"))
|
|
95
|
+
except OSError:
|
|
96
|
+
running = False
|
|
97
|
+
elif kind == "resize":
|
|
98
|
+
try:
|
|
99
|
+
set_size(master, int(command.get("cols") or cols), int(command.get("rows") or rows))
|
|
100
|
+
except OSError:
|
|
101
|
+
pass
|
|
102
|
+
elif kind == "kill":
|
|
103
|
+
try:
|
|
104
|
+
os.killpg(os.getpgid(child.pid), signal.SIGKILL)
|
|
105
|
+
except OSError:
|
|
106
|
+
pass
|
|
107
|
+
running = False
|
|
108
|
+
|
|
109
|
+
if master in readable:
|
|
110
|
+
try:
|
|
111
|
+
data = os.read(master, 65536)
|
|
112
|
+
except OSError as error:
|
|
113
|
+
# 子进程退出后 Linux 在 master 上返回 EIO
|
|
114
|
+
if error.errno == errno.EIO:
|
|
115
|
+
break
|
|
116
|
+
if error.errno in (errno.EAGAIN, errno.EWOULDBLOCK):
|
|
117
|
+
continue
|
|
118
|
+
break
|
|
119
|
+
if not data:
|
|
120
|
+
break
|
|
121
|
+
out.write(data)
|
|
122
|
+
out.flush()
|
|
123
|
+
|
|
124
|
+
if child.poll() is not None:
|
|
125
|
+
# 把 pty 里剩余的输出取完再退出
|
|
126
|
+
while True:
|
|
127
|
+
try:
|
|
128
|
+
rest = os.read(master, 65536)
|
|
129
|
+
except OSError:
|
|
130
|
+
rest = b""
|
|
131
|
+
if not rest:
|
|
132
|
+
break
|
|
133
|
+
out.write(rest)
|
|
134
|
+
out.flush()
|
|
135
|
+
break
|
|
136
|
+
|
|
137
|
+
try:
|
|
138
|
+
os.close(master)
|
|
139
|
+
except OSError:
|
|
140
|
+
pass
|
|
141
|
+
|
|
142
|
+
code = child.poll()
|
|
143
|
+
if code is None:
|
|
144
|
+
try:
|
|
145
|
+
os.killpg(os.getpgid(child.pid), signal.SIGKILL)
|
|
146
|
+
except OSError:
|
|
147
|
+
pass
|
|
148
|
+
child.wait(timeout=2)
|
|
149
|
+
code = child.returncode
|
|
150
|
+
return code or 0
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
if __name__ == "__main__":
|
|
154
|
+
sys.exit(main())
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* 插件 sandbox(child)→ 宿主(host)方向 RPC 的超时策略。
|
|
3
|
+
* 单位毫秒;null 表示不设上限,时长由被调用能力自己的步骤/网络超时兜底。
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface RpcTimeouts {
|
|
7
|
+
/** 普通 RPC:文件、事件、HTTP 建服务、插件数据等 */
|
|
8
|
+
readonly default: number
|
|
9
|
+
/** Agent 单轮对话(非流式):耗时取决于模型与工具步骤 */
|
|
10
|
+
readonly agentChat: number
|
|
11
|
+
/** Agent 流式对话:一轮可能持续很久,不设上限 */
|
|
12
|
+
readonly agentStream: number | null
|
|
13
|
+
/** 拉取供应商模型列表:要等网络超时与重试 */
|
|
14
|
+
readonly modelsFetch: number
|
|
15
|
+
/** 安装插件:解压、写文件,以及按插件声明的包管理器自动安装依赖(最多 5 分钟) */
|
|
16
|
+
readonly pluginsInstall: number
|
|
17
|
+
/**
|
|
18
|
+
* 调用插件提供的 Agent 工具
|
|
19
|
+
*
|
|
20
|
+
* 工具自己决定执行多久(`api.exec` 的 timeoutMs 上限 600s),
|
|
21
|
+
* RPC 若用默认 30s 就会先超时:宿主放弃等待、插件仍在跑,
|
|
22
|
+
* 后续工具调用还会排在它后面,界面表现为「工具被中断后卡住」。
|
|
23
|
+
*/
|
|
24
|
+
readonly agentTool: number
|
|
25
|
+
/**
|
|
26
|
+
* 执行沙箱命令(execute_code)
|
|
27
|
+
*
|
|
28
|
+
* 沙箱自己的 timeoutMs 最长 600s,RPC 必须比它长;否则宿主已经放弃等待,
|
|
29
|
+
* 沙箱里的进程还在跑,调用方只能看到一条「host RPC 超时」。
|
|
30
|
+
*/
|
|
31
|
+
readonly sandboxExec: number
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const RPC_TIMEOUT_MS: RpcTimeouts = {
|
|
35
|
+
default: 30_000,
|
|
36
|
+
agentChat: 180_000,
|
|
37
|
+
agentStream: null,
|
|
38
|
+
modelsFetch: 120_000,
|
|
39
|
+
pluginsInstall: 660_000,
|
|
40
|
+
/* 比 exec 的最长上限(600s)再留一点余量;不设 null,避免坏插件把宿主永久挂住 */
|
|
41
|
+
agentTool: 660_000,
|
|
42
|
+
sandboxExec: 660_000,
|
|
43
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* sandbox 进程 supervisor:输出上限、超时、SIGTERM→SIGKILL、退出码。
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { spawn } from "node:child_process"
|
|
6
|
+
|
|
7
|
+
import { SandboxExecutionError, type LaunchSpec, type StopMode } from "./types.ts"
|
|
8
|
+
|
|
9
|
+
export interface ProcessLimits {
|
|
10
|
+
readonly timeoutMs: number
|
|
11
|
+
readonly outputLimitBytes: number
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface ProcessResult {
|
|
15
|
+
readonly exitCode: number | null
|
|
16
|
+
readonly signal: string | null
|
|
17
|
+
readonly stdout: string
|
|
18
|
+
readonly stderr: string
|
|
19
|
+
readonly truncated: boolean
|
|
20
|
+
readonly timedOut: boolean
|
|
21
|
+
readonly durationMs: number
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface ProcessHooks {
|
|
25
|
+
readonly onStdout?: (text: string) => void
|
|
26
|
+
readonly onStderr?: (text: string) => void
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface ProcessOptions {
|
|
30
|
+
readonly stdin?: string
|
|
31
|
+
readonly hooks?: ProcessHooks
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface SandboxProcessHandle {
|
|
35
|
+
readonly pid: number | undefined
|
|
36
|
+
readonly done: Promise<ProcessResult>
|
|
37
|
+
readonly stdout: string
|
|
38
|
+
readonly stderr: string
|
|
39
|
+
stop(mode: StopMode): void
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function startSandboxProcess(
|
|
43
|
+
spec: LaunchSpec,
|
|
44
|
+
limits: ProcessLimits,
|
|
45
|
+
options: ProcessOptions = {},
|
|
46
|
+
): SandboxProcessHandle {
|
|
47
|
+
const startedAt = Date.now()
|
|
48
|
+
const child = spawn(spec.command, [...spec.args], {
|
|
49
|
+
cwd: spec.cwd,
|
|
50
|
+
env: { ...spec.env },
|
|
51
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
52
|
+
detached: true,
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
const outChunks: Buffer[] = []
|
|
56
|
+
const errChunks: Buffer[] = []
|
|
57
|
+
let totalBytes = 0
|
|
58
|
+
let truncated = false
|
|
59
|
+
let timedOut = false
|
|
60
|
+
let settled = false
|
|
61
|
+
|
|
62
|
+
const append = (target: Buffer[], chunk: Buffer): void => {
|
|
63
|
+
const remaining = Math.max(0, limits.outputLimitBytes - totalBytes)
|
|
64
|
+
if (chunk.length > remaining) {
|
|
65
|
+
if (remaining > 0) {
|
|
66
|
+
target.push(chunk.subarray(0, remaining))
|
|
67
|
+
totalBytes += remaining
|
|
68
|
+
}
|
|
69
|
+
truncated = true
|
|
70
|
+
return
|
|
71
|
+
}
|
|
72
|
+
target.push(chunk)
|
|
73
|
+
totalBytes += chunk.length
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
child.stdout?.on("data", (chunk: Buffer) => {
|
|
77
|
+
append(outChunks, chunk)
|
|
78
|
+
options.hooks?.onStdout?.(chunk.toString("utf8"))
|
|
79
|
+
})
|
|
80
|
+
child.stderr?.on("data", (chunk: Buffer) => {
|
|
81
|
+
append(errChunks, chunk)
|
|
82
|
+
options.hooks?.onStderr?.(chunk.toString("utf8"))
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
const signal = (name: NodeJS.Signals): void => {
|
|
86
|
+
try {
|
|
87
|
+
if (child.pid !== undefined) {
|
|
88
|
+
process.kill(-child.pid, name)
|
|
89
|
+
return
|
|
90
|
+
}
|
|
91
|
+
} catch {
|
|
92
|
+
// 进程组已不存在,落到单进程 kill
|
|
93
|
+
}
|
|
94
|
+
child.kill(name)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
let forceKillTimer: NodeJS.Timeout | null = null
|
|
98
|
+
const timeoutTimer = setTimeout(
|
|
99
|
+
() => {
|
|
100
|
+
timedOut = true
|
|
101
|
+
signal("SIGTERM")
|
|
102
|
+
forceKillTimer = setTimeout(() => {
|
|
103
|
+
if (!settled) {
|
|
104
|
+
signal("SIGKILL")
|
|
105
|
+
}
|
|
106
|
+
}, 2_000)
|
|
107
|
+
forceKillTimer.unref()
|
|
108
|
+
},
|
|
109
|
+
Math.max(100, limits.timeoutMs),
|
|
110
|
+
)
|
|
111
|
+
timeoutTimer.unref()
|
|
112
|
+
|
|
113
|
+
const cleanup = (): void => {
|
|
114
|
+
settled = true
|
|
115
|
+
clearTimeout(timeoutTimer)
|
|
116
|
+
if (forceKillTimer !== null) {
|
|
117
|
+
clearTimeout(forceKillTimer)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
child.stdin?.end(options.stdin ?? "")
|
|
123
|
+
} catch {
|
|
124
|
+
// 子进程可能已关闭 stdin
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const done = new Promise<ProcessResult>((resolveExit, rejectExit) => {
|
|
128
|
+
child.once("error", (error) => {
|
|
129
|
+
cleanup()
|
|
130
|
+
rejectExit(
|
|
131
|
+
new SandboxExecutionError(
|
|
132
|
+
`sandbox 启动失败:${error instanceof Error ? error.message : String(error)}`,
|
|
133
|
+
),
|
|
134
|
+
)
|
|
135
|
+
})
|
|
136
|
+
child.once("exit", (code, exitSignal) => {
|
|
137
|
+
cleanup()
|
|
138
|
+
resolveExit({
|
|
139
|
+
exitCode: code,
|
|
140
|
+
signal: exitSignal,
|
|
141
|
+
stdout: Buffer.concat(outChunks).toString("utf8"),
|
|
142
|
+
stderr: Buffer.concat(errChunks).toString("utf8"),
|
|
143
|
+
truncated,
|
|
144
|
+
timedOut,
|
|
145
|
+
durationMs: Date.now() - startedAt,
|
|
146
|
+
})
|
|
147
|
+
})
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
const handle: SandboxProcessHandle = {
|
|
151
|
+
pid: child.pid,
|
|
152
|
+
done,
|
|
153
|
+
get stdout() {
|
|
154
|
+
return Buffer.concat(outChunks).toString("utf8")
|
|
155
|
+
},
|
|
156
|
+
get stderr() {
|
|
157
|
+
return Buffer.concat(errChunks).toString("utf8")
|
|
158
|
+
},
|
|
159
|
+
stop(mode) {
|
|
160
|
+
signal(mode === "ctrl_c" ? "SIGINT" : "SIGKILL")
|
|
161
|
+
},
|
|
162
|
+
}
|
|
163
|
+
return handle
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export async function runSandboxProcess(
|
|
167
|
+
spec: LaunchSpec,
|
|
168
|
+
limits: ProcessLimits,
|
|
169
|
+
options: ProcessOptions = {},
|
|
170
|
+
): Promise<ProcessResult> {
|
|
171
|
+
return await startSandboxProcess(spec, limits, options).done
|
|
172
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Sandbox 公共类型。
|
|
3
|
+
* plugin profile 与 agent-code profile 共用 backend / supervisor;这里先定义 agent-code。
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { SandboxAccess, SandboxSetting } from "../config/types.ts"
|
|
7
|
+
import type { ResolvedPaths } from "../platform/path.ts"
|
|
8
|
+
|
|
9
|
+
export interface SandboxLimits {
|
|
10
|
+
readonly timeoutMs: number
|
|
11
|
+
readonly memoryMB: number
|
|
12
|
+
readonly pids: number
|
|
13
|
+
readonly outputLimitBytes: number
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface SandboxArtifact {
|
|
17
|
+
readonly path: string
|
|
18
|
+
readonly size: number
|
|
19
|
+
readonly sha256: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface AgentCodeRequest {
|
|
23
|
+
readonly sessionId?: string
|
|
24
|
+
readonly command: string
|
|
25
|
+
readonly argv: readonly string[]
|
|
26
|
+
/** 默认 process.cwd() */
|
|
27
|
+
readonly workspaceDir?: string
|
|
28
|
+
/** 必须位于 workspaceDir 内;默认 workspaceDir */
|
|
29
|
+
readonly cwd?: string
|
|
30
|
+
readonly stdin?: string
|
|
31
|
+
readonly timeoutMs?: number
|
|
32
|
+
readonly memoryMB?: number
|
|
33
|
+
readonly outputLimitBytes?: number
|
|
34
|
+
readonly access?: SandboxAccess
|
|
35
|
+
readonly network?: boolean
|
|
36
|
+
/** 模型给出的提权理由 */
|
|
37
|
+
readonly justification?: string
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface AgentCodeResult {
|
|
41
|
+
readonly sandboxId: string
|
|
42
|
+
readonly backend: string
|
|
43
|
+
readonly access: SandboxAccess
|
|
44
|
+
readonly exitCode: number | null
|
|
45
|
+
readonly signal: string | null
|
|
46
|
+
readonly stdout: string
|
|
47
|
+
readonly stderr: string
|
|
48
|
+
readonly truncated: boolean
|
|
49
|
+
readonly timedOut: boolean
|
|
50
|
+
/** 物理内存限制方式:cgroup = 已挂 systemd user scope 的 MemoryMax;none = 宿主不支持/未启用 */
|
|
51
|
+
readonly memoryLimit: "cgroup" | "none"
|
|
52
|
+
/** memoryLimit 为 none 时的原因 */
|
|
53
|
+
readonly memoryLimitReason: string | null
|
|
54
|
+
/** cgroup 记录到 oom_kill(进程被内存上限杀掉) */
|
|
55
|
+
readonly oomKilled: boolean
|
|
56
|
+
readonly durationMs: number
|
|
57
|
+
readonly artifacts: readonly SandboxArtifact[]
|
|
58
|
+
/** sandbox 内可见路径;bwrap 下为 /scratch/artifacts */
|
|
59
|
+
readonly artifactDir: string | null
|
|
60
|
+
/** sandbox 内可见路径;bwrap 下为 /scratch */
|
|
61
|
+
readonly sandboxDir: string
|
|
62
|
+
/** 宿主侧路径,仅宿主使用 */
|
|
63
|
+
readonly hostArtifactDir: string | null
|
|
64
|
+
readonly hostSandboxDir: string
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export type StopMode = "ctrl_c" | "kill"
|
|
68
|
+
|
|
69
|
+
export interface AgentCodeTaskHandle {
|
|
70
|
+
readonly sandboxId: string
|
|
71
|
+
readonly backend: string
|
|
72
|
+
readonly access: SandboxAccess
|
|
73
|
+
readonly stdout: string
|
|
74
|
+
readonly stderr: string
|
|
75
|
+
stop(mode: StopMode): void
|
|
76
|
+
wait(): Promise<AgentCodeResult>
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface SandboxBackendStatus {
|
|
80
|
+
readonly available: boolean
|
|
81
|
+
readonly backend: string
|
|
82
|
+
readonly reason: string | null
|
|
83
|
+
readonly version: string | null
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface LaunchSpec {
|
|
87
|
+
readonly command: string
|
|
88
|
+
readonly args: readonly string[]
|
|
89
|
+
/** spawn 的宿主 cwd;sandbox 内部的 cwd 由 backend 参数控制 */
|
|
90
|
+
readonly cwd: string
|
|
91
|
+
readonly env: Readonly<Record<string, string>>
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface PluginLaunchInput {
|
|
95
|
+
readonly pluginDir: string
|
|
96
|
+
/** 插件内入口的相对路径,例如 index.ts */
|
|
97
|
+
readonly pluginEntryRel: string
|
|
98
|
+
readonly pluginDataDir: string
|
|
99
|
+
/** 宿主编译后的 SDK 根目录(bwrap 下挂载到 /host) */
|
|
100
|
+
readonly hostSdkDir: string
|
|
101
|
+
/** runner 在宿主上的路径 */
|
|
102
|
+
readonly runnerPath: string
|
|
103
|
+
readonly env: Readonly<Record<string, string>>
|
|
104
|
+
readonly limits: SandboxLimits
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface AgentLaunchInput {
|
|
108
|
+
readonly workspaceDir: string
|
|
109
|
+
readonly scratchDir: string
|
|
110
|
+
readonly cwd: string
|
|
111
|
+
readonly access?: SandboxAccess
|
|
112
|
+
readonly network?: boolean
|
|
113
|
+
readonly command: string
|
|
114
|
+
readonly argv: readonly string[]
|
|
115
|
+
readonly env: Readonly<Record<string, string>>
|
|
116
|
+
readonly limits: SandboxLimits
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export interface SandboxBackend {
|
|
120
|
+
readonly name: string
|
|
121
|
+
probe(): Promise<SandboxBackendStatus>
|
|
122
|
+
buildAgentLaunch(input: AgentLaunchInput): LaunchSpec
|
|
123
|
+
buildPluginLaunch(input: PluginLaunchInput): LaunchSpec
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export interface SandboxManagerOptions {
|
|
127
|
+
readonly settings: SandboxSetting
|
|
128
|
+
readonly paths: ResolvedPaths
|
|
129
|
+
/** 测试注入;生产由 probe 选择 */
|
|
130
|
+
readonly backend?: SandboxBackend
|
|
131
|
+
readonly logger?: {
|
|
132
|
+
warn(fields: Record<string, unknown>, message: string): void
|
|
133
|
+
info(fields: Record<string, unknown>, message: string): void
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export class SandboxUnavailableError extends Error {
|
|
138
|
+
constructor(reason: string) {
|
|
139
|
+
super(`sandbox 不可用:${reason}`)
|
|
140
|
+
this.name = "SandboxUnavailableError"
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export class SandboxExecutionError extends Error {
|
|
145
|
+
constructor(message: string) {
|
|
146
|
+
super(message)
|
|
147
|
+
this.name = "SandboxExecutionError"
|
|
148
|
+
}
|
|
149
|
+
}
|