@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,468 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* 会话存储。
|
|
3
|
+
* 路径:<dataDir>/sessions/<cwd桶>/<sessionId>/
|
|
4
|
+
* session.json 元信息
|
|
5
|
+
* .lock 写入锁
|
|
6
|
+
* turns/NNNN.jsonl.zstd 每轮一个 zstd 段
|
|
7
|
+
* last.json 存在 cwd 桶目录下,记录该 cwd 的最近会话。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { createHash } from "node:crypto"
|
|
11
|
+
import { realpathSync } from "node:fs"
|
|
12
|
+
import { readdir, writeFile } from "node:fs/promises"
|
|
13
|
+
import { basename, join, resolve } from "node:path"
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
ensureDir,
|
|
17
|
+
readBytesIfExists,
|
|
18
|
+
readJsonIfExists,
|
|
19
|
+
removePath,
|
|
20
|
+
statIfExists,
|
|
21
|
+
writeBytesAtomic,
|
|
22
|
+
writeJsonAtomic,
|
|
23
|
+
} from "../platform/file.ts"
|
|
24
|
+
import { getPaths } from "../platform/path.ts"
|
|
25
|
+
import { decodeEvents, encodeEvents } from "./compress.ts"
|
|
26
|
+
import { groupTurns } from "./replay.ts"
|
|
27
|
+
import type { SessionEvent, SessionHeader, SessionMeta, SessionTurn } from "./types.ts"
|
|
28
|
+
|
|
29
|
+
const SESSION_ID = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/
|
|
30
|
+
const SEGMENT = /^(\d+)\.jsonl\.zstd$/
|
|
31
|
+
const LOCK_STALE_MS = 10 * 60 * 1000
|
|
32
|
+
const APP_NAME = "wellspring"
|
|
33
|
+
const APP_VERSION = "1.0.0"
|
|
34
|
+
|
|
35
|
+
export class SessionNotFoundError extends Error {
|
|
36
|
+
constructor(id: string) {
|
|
37
|
+
super(`会话不存在:${id}`)
|
|
38
|
+
this.name = "SessionNotFoundError"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export class SessionAmbiguousError extends Error {
|
|
43
|
+
constructor(id: string) {
|
|
44
|
+
super(`会话 id 在多个 cwd 桶中重复:${id}`)
|
|
45
|
+
this.name = "SessionAmbiguousError"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export class SessionLockedError extends Error {
|
|
50
|
+
constructor(id: string) {
|
|
51
|
+
super(`会话正在被其他进程写入:${id}`)
|
|
52
|
+
this.name = "SessionLockedError"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface SessionData {
|
|
57
|
+
readonly meta: SessionMeta
|
|
58
|
+
readonly header: SessionHeader
|
|
59
|
+
readonly dir: string
|
|
60
|
+
events: SessionEvent[]
|
|
61
|
+
turns: SessionTurn[]
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface SessionSummary {
|
|
65
|
+
readonly id: string
|
|
66
|
+
readonly cwd: string
|
|
67
|
+
readonly dir: string
|
|
68
|
+
readonly turns: number
|
|
69
|
+
readonly updatedAt: number
|
|
70
|
+
readonly last: boolean
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface CreateSessionOptions {
|
|
74
|
+
readonly cwd: string
|
|
75
|
+
readonly workspace?: string
|
|
76
|
+
readonly model: string
|
|
77
|
+
readonly id?: string
|
|
78
|
+
readonly type?: string
|
|
79
|
+
readonly metadata?: Record<string, unknown>
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface ListSessionsOptions {
|
|
83
|
+
readonly cwd: string
|
|
84
|
+
readonly all?: boolean
|
|
85
|
+
readonly limit?: number
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function isValidSessionId(id: string): boolean {
|
|
89
|
+
return SESSION_ID.test(id)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function newSessionId(date = new Date()): string {
|
|
93
|
+
const pad = (value: number): string => String(value).padStart(2, "0")
|
|
94
|
+
const stamp =
|
|
95
|
+
`${date.getFullYear()}${pad(date.getMonth() + 1)}${pad(date.getDate())}` +
|
|
96
|
+
`-${pad(date.getHours())}${pad(date.getMinutes())}${pad(date.getSeconds())}`
|
|
97
|
+
const suffix = Math.floor(Math.random() * 0xffff)
|
|
98
|
+
.toString(16)
|
|
99
|
+
.padStart(4, "0")
|
|
100
|
+
return `${stamp}-${suffix}`
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function slugOf(name: string): string {
|
|
104
|
+
const cleaned = name
|
|
105
|
+
.replace(/[^A-Za-z0-9._-]/g, "-")
|
|
106
|
+
.replace(/-+/g, "-")
|
|
107
|
+
.replace(/^[-.]+|[-.]+$/g, "")
|
|
108
|
+
return (cleaned === "" ? "root" : cleaned).slice(0, 32)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** cwd → 桶目录名:<slug>-<sha256 前 8 位> */
|
|
112
|
+
export function sessionBucket(cwd: string): string {
|
|
113
|
+
let canonical = cwd
|
|
114
|
+
try {
|
|
115
|
+
canonical = realpathSync(cwd)
|
|
116
|
+
} catch {
|
|
117
|
+
canonical = resolve(cwd)
|
|
118
|
+
}
|
|
119
|
+
const hash = createHash("sha256").update(canonical).digest("hex").slice(0, 8)
|
|
120
|
+
return `${slugOf(basename(canonical))}-${hash}`
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function isPidAlive(pid: number): boolean {
|
|
124
|
+
try {
|
|
125
|
+
process.kill(pid, 0)
|
|
126
|
+
return true
|
|
127
|
+
} catch (error) {
|
|
128
|
+
return (error as NodeJS.ErrnoException).code === "EPERM"
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export class SessionStore {
|
|
133
|
+
readonly root: string
|
|
134
|
+
|
|
135
|
+
constructor(root = join(getPaths().dataDir, "sessions")) {
|
|
136
|
+
this.root = root
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
bucketDir(cwd: string): string {
|
|
140
|
+
return join(this.root, sessionBucket(cwd))
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async lastId(cwd: string): Promise<string | null> {
|
|
144
|
+
const last = await readJsonIfExists<{ id?: unknown }>(
|
|
145
|
+
join(this.bucketDir(cwd), "last.json"),
|
|
146
|
+
)
|
|
147
|
+
return typeof last?.id === "string" ? last.id : null
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async create(options: CreateSessionOptions): Promise<SessionData> {
|
|
151
|
+
const id = options.id ?? newSessionId()
|
|
152
|
+
if (!isValidSessionId(id)) {
|
|
153
|
+
throw new Error(`会话 id 不合法:${id}`)
|
|
154
|
+
}
|
|
155
|
+
const dir = join(this.bucketDir(options.cwd), id)
|
|
156
|
+
const existing = await this.open(id, options.cwd).catch(() => null)
|
|
157
|
+
if (existing !== null) {
|
|
158
|
+
return existing
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const workspace = resolve(options.workspace ?? options.cwd)
|
|
162
|
+
const type = options.type ?? "session"
|
|
163
|
+
const metadata = options.metadata ?? {}
|
|
164
|
+
const meta: SessionMeta = {
|
|
165
|
+
type,
|
|
166
|
+
version: 1,
|
|
167
|
+
id,
|
|
168
|
+
createdAt: Date.now(),
|
|
169
|
+
cwd: options.cwd,
|
|
170
|
+
workspace,
|
|
171
|
+
metadata,
|
|
172
|
+
app: APP_NAME,
|
|
173
|
+
appVersion: APP_VERSION,
|
|
174
|
+
model: options.model,
|
|
175
|
+
}
|
|
176
|
+
const header: SessionHeader = { type, metadata, workspace }
|
|
177
|
+
await ensureDir(join(dir, "turns"))
|
|
178
|
+
await writeBytesAtomic(
|
|
179
|
+
join(dir, "turns", "0000.jsonl.zstd"),
|
|
180
|
+
encodeEvents([
|
|
181
|
+
{
|
|
182
|
+
type: "session/header",
|
|
183
|
+
seq: 0,
|
|
184
|
+
time: meta.createdAt,
|
|
185
|
+
data: { ...header },
|
|
186
|
+
},
|
|
187
|
+
]),
|
|
188
|
+
)
|
|
189
|
+
await writeJsonAtomic(join(dir, "session.json"), meta)
|
|
190
|
+
await this.#writeLast(options.cwd, id)
|
|
191
|
+
return { meta, header, dir, events: [], turns: [] }
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/** 打开当前 cwd 桶优先,其次其他桶;不存在抛 SessionNotFoundError */
|
|
195
|
+
async open(id: string, cwd?: string): Promise<SessionData> {
|
|
196
|
+
const dir = await this.#findDir(id, cwd)
|
|
197
|
+
const stored = await readJsonIfExists<SessionMeta>(join(dir, "session.json"))
|
|
198
|
+
if (stored === null || typeof stored.type !== "string" || stored.version !== 1) {
|
|
199
|
+
throw new Error(`会话元信息损坏:${id}`)
|
|
200
|
+
}
|
|
201
|
+
const header = (await this.#readHeader(dir)) ?? {
|
|
202
|
+
type: stored.type,
|
|
203
|
+
metadata: stored.metadata ?? {},
|
|
204
|
+
workspace: stored.workspace ?? stored.cwd,
|
|
205
|
+
}
|
|
206
|
+
const meta: SessionMeta = {
|
|
207
|
+
...stored,
|
|
208
|
+
type: header.type,
|
|
209
|
+
metadata: header.metadata,
|
|
210
|
+
workspace:
|
|
211
|
+
header.workspace === "" ? (stored.workspace ?? stored.cwd) : header.workspace,
|
|
212
|
+
}
|
|
213
|
+
const events = await this.#readEvents(dir)
|
|
214
|
+
return { meta, header, dir, events, turns: groupTurns(events) }
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** 取最近一次会话;没有则创建 */
|
|
218
|
+
async openLastOrCreate(cwd: string, model: string): Promise<SessionData> {
|
|
219
|
+
const last = await this.lastId(cwd)
|
|
220
|
+
if (last !== null) {
|
|
221
|
+
try {
|
|
222
|
+
return await this.open(last, cwd)
|
|
223
|
+
} catch {
|
|
224
|
+
return await this.create({ cwd, model })
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return await this.create({ cwd, model })
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
async appendTurn(session: SessionData, events: readonly SessionEvent[]): Promise<number> {
|
|
231
|
+
if (events.length === 0) {
|
|
232
|
+
return session.turns.length
|
|
233
|
+
}
|
|
234
|
+
const release = await this.#acquireLock(session.dir, session.meta.id)
|
|
235
|
+
try {
|
|
236
|
+
const turnsDir = join(session.dir, "turns")
|
|
237
|
+
await ensureDir(turnsDir)
|
|
238
|
+
const names = await readdir(turnsDir)
|
|
239
|
+
let max = 0
|
|
240
|
+
for (const name of names) {
|
|
241
|
+
const match = SEGMENT.exec(name)
|
|
242
|
+
if (match !== null) {
|
|
243
|
+
const index = Number(match[1])
|
|
244
|
+
if (index > max) {
|
|
245
|
+
max = index
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
const next = max + 1
|
|
250
|
+
const file = join(turnsDir, `${String(next).padStart(4, "0")}.jsonl.zstd`)
|
|
251
|
+
await writeBytesAtomic(file, encodeEvents(events))
|
|
252
|
+
await this.#writeLast(session.meta.cwd, session.meta.id)
|
|
253
|
+
session.events = [...session.events, ...events]
|
|
254
|
+
session.turns = groupTurns(session.events)
|
|
255
|
+
return next
|
|
256
|
+
} finally {
|
|
257
|
+
await release()
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
async list(options: ListSessionsOptions): Promise<SessionSummary[]> {
|
|
262
|
+
const buckets =
|
|
263
|
+
options.all === true ? await this.#bucketDirs() : [this.bucketDir(options.cwd)]
|
|
264
|
+
const summaries: SessionSummary[] = []
|
|
265
|
+
|
|
266
|
+
for (const bucket of buckets) {
|
|
267
|
+
const last = await readJsonIfExists<{ id?: unknown }>(join(bucket, "last.json"))
|
|
268
|
+
const lastId = typeof last?.id === "string" ? last.id : null
|
|
269
|
+
let names: string[]
|
|
270
|
+
try {
|
|
271
|
+
names = await readdir(bucket)
|
|
272
|
+
} catch {
|
|
273
|
+
continue
|
|
274
|
+
}
|
|
275
|
+
for (const name of names) {
|
|
276
|
+
if (!isValidSessionId(name)) {
|
|
277
|
+
continue
|
|
278
|
+
}
|
|
279
|
+
const dir = join(bucket, name)
|
|
280
|
+
const meta = await readJsonIfExists<SessionMeta>(join(dir, "session.json"))
|
|
281
|
+
if (meta === null) {
|
|
282
|
+
continue
|
|
283
|
+
}
|
|
284
|
+
const segments = await this.#turnFiles(dir)
|
|
285
|
+
const lastFile =
|
|
286
|
+
segments.length === 0
|
|
287
|
+
? null
|
|
288
|
+
: await statIfExists(
|
|
289
|
+
join(dir, "turns", segments[segments.length - 1] ?? ""),
|
|
290
|
+
)
|
|
291
|
+
summaries.push({
|
|
292
|
+
id: meta.id,
|
|
293
|
+
cwd: meta.cwd,
|
|
294
|
+
dir,
|
|
295
|
+
turns: segments.length,
|
|
296
|
+
updatedAt: lastFile?.mtimeMs ?? meta.createdAt,
|
|
297
|
+
last: lastId === meta.id,
|
|
298
|
+
})
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
summaries.sort((left, right) => right.updatedAt - left.updatedAt)
|
|
303
|
+
return options.limit === undefined ? summaries : summaries.slice(0, options.limit)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
async remove(id: string): Promise<void> {
|
|
307
|
+
const dir = await this.#findDir(id)
|
|
308
|
+
const meta = await readJsonIfExists<SessionMeta>(join(dir, "session.json"))
|
|
309
|
+
await removePath(dir)
|
|
310
|
+
if (meta !== null) {
|
|
311
|
+
const last = await this.lastId(meta.cwd)
|
|
312
|
+
if (last === id) {
|
|
313
|
+
await removePath(join(this.bucketDir(meta.cwd), "last.json"))
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
async removeAll(cwd: string): Promise<number> {
|
|
319
|
+
const bucket = this.bucketDir(cwd)
|
|
320
|
+
let names: string[]
|
|
321
|
+
try {
|
|
322
|
+
names = await readdir(bucket)
|
|
323
|
+
} catch {
|
|
324
|
+
return 0
|
|
325
|
+
}
|
|
326
|
+
let removed = 0
|
|
327
|
+
for (const name of names) {
|
|
328
|
+
if (!isValidSessionId(name)) {
|
|
329
|
+
continue
|
|
330
|
+
}
|
|
331
|
+
await removePath(join(bucket, name))
|
|
332
|
+
removed += 1
|
|
333
|
+
}
|
|
334
|
+
await removePath(join(bucket, "last.json"))
|
|
335
|
+
return removed
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
async #findDir(id: string, cwd?: string): Promise<string> {
|
|
339
|
+
if (!isValidSessionId(id)) {
|
|
340
|
+
throw new Error(`会话 id 不合法:${id}`)
|
|
341
|
+
}
|
|
342
|
+
const candidates: string[] = []
|
|
343
|
+
if (cwd !== undefined) {
|
|
344
|
+
candidates.push(this.bucketDir(cwd))
|
|
345
|
+
}
|
|
346
|
+
for (const bucket of await this.#bucketDirs()) {
|
|
347
|
+
if (!candidates.includes(bucket)) {
|
|
348
|
+
candidates.push(bucket)
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const matches: string[] = []
|
|
353
|
+
for (const bucket of candidates) {
|
|
354
|
+
const dir = join(bucket, id)
|
|
355
|
+
if ((await statIfExists(dir)) !== null) {
|
|
356
|
+
matches.push(dir)
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
if (matches.length === 0) {
|
|
360
|
+
throw new SessionNotFoundError(id)
|
|
361
|
+
}
|
|
362
|
+
if (matches.length > 1) {
|
|
363
|
+
throw new SessionAmbiguousError(id)
|
|
364
|
+
}
|
|
365
|
+
return matches[0]!
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
async #bucketDirs(): Promise<string[]> {
|
|
369
|
+
let names: string[]
|
|
370
|
+
try {
|
|
371
|
+
names = await readdir(this.root, { withFileTypes: true }).then((entries) =>
|
|
372
|
+
entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name),
|
|
373
|
+
)
|
|
374
|
+
} catch {
|
|
375
|
+
return []
|
|
376
|
+
}
|
|
377
|
+
return names.sort().map((name) => join(this.root, name))
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
async #turnFiles(dir: string): Promise<string[]> {
|
|
381
|
+
try {
|
|
382
|
+
const names = await readdir(join(dir, "turns"))
|
|
383
|
+
return names
|
|
384
|
+
.filter((name) => SEGMENT.test(name) && name !== "0000.jsonl.zstd")
|
|
385
|
+
.sort(
|
|
386
|
+
(left, right) =>
|
|
387
|
+
Number(SEGMENT.exec(left)?.[1]) - Number(SEGMENT.exec(right)?.[1]),
|
|
388
|
+
)
|
|
389
|
+
} catch {
|
|
390
|
+
return []
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
async #readHeader(dir: string): Promise<SessionHeader | null> {
|
|
395
|
+
const data = await readBytesIfExists(join(dir, "turns", "0000.jsonl.zstd"))
|
|
396
|
+
if (data === null) {
|
|
397
|
+
return null
|
|
398
|
+
}
|
|
399
|
+
const event = decodeEvents(data).find((item) => item.type === "session/header")
|
|
400
|
+
if (event === undefined) {
|
|
401
|
+
return null
|
|
402
|
+
}
|
|
403
|
+
const type = event.data["type"]
|
|
404
|
+
const metadata = event.data["metadata"]
|
|
405
|
+
const workspace = event.data["workspace"]
|
|
406
|
+
return {
|
|
407
|
+
type: typeof type === "string" ? type : "session",
|
|
408
|
+
metadata:
|
|
409
|
+
typeof metadata === "object" && metadata !== null && !Array.isArray(metadata)
|
|
410
|
+
? (metadata as Record<string, unknown>)
|
|
411
|
+
: {},
|
|
412
|
+
workspace: typeof workspace === "string" ? workspace : "",
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
async #readEvents(dir: string): Promise<SessionEvent[]> {
|
|
417
|
+
const files = await this.#turnFiles(dir)
|
|
418
|
+
const events: SessionEvent[] = []
|
|
419
|
+
for (const name of files) {
|
|
420
|
+
const data = await readBytesIfExists(join(dir, "turns", name))
|
|
421
|
+
if (data === null) {
|
|
422
|
+
continue
|
|
423
|
+
}
|
|
424
|
+
events.push(...decodeEvents(data))
|
|
425
|
+
}
|
|
426
|
+
return events
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
async #writeLast(cwd: string, id: string): Promise<void> {
|
|
430
|
+
await writeJsonAtomic(join(this.bucketDir(cwd), "last.json"), {
|
|
431
|
+
id,
|
|
432
|
+
updatedAt: Date.now(),
|
|
433
|
+
})
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
async #acquireLock(dir: string, id: string): Promise<() => Promise<void>> {
|
|
437
|
+
const lock = join(dir, ".lock")
|
|
438
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
439
|
+
try {
|
|
440
|
+
await writeFile(
|
|
441
|
+
lock,
|
|
442
|
+
JSON.stringify({ pid: process.pid, acquiredAt: Date.now() }),
|
|
443
|
+
{ flag: "wx", mode: 0o600 },
|
|
444
|
+
)
|
|
445
|
+
return async () => {
|
|
446
|
+
await removePath(lock)
|
|
447
|
+
}
|
|
448
|
+
} catch (error) {
|
|
449
|
+
if ((error as NodeJS.ErrnoException).code !== "EEXIST") {
|
|
450
|
+
throw error
|
|
451
|
+
}
|
|
452
|
+
const info = await statIfExists(lock)
|
|
453
|
+
if (info === null) {
|
|
454
|
+
continue
|
|
455
|
+
}
|
|
456
|
+
const content = await readJsonIfExists<{ pid?: unknown }>(lock)
|
|
457
|
+
const pid = typeof content?.pid === "number" ? content.pid : null
|
|
458
|
+
const stale =
|
|
459
|
+
Date.now() - info.mtimeMs > LOCK_STALE_MS || pid === null || !isPidAlive(pid)
|
|
460
|
+
if (!stale) {
|
|
461
|
+
throw new SessionLockedError(id)
|
|
462
|
+
}
|
|
463
|
+
await removePath(lock)
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
throw new SessionLockedError(id)
|
|
467
|
+
}
|
|
468
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/** 会话模型:参考 DeepSeekHarness session.v4,按轮分段的 JSONL 事件流 */
|
|
2
|
+
|
|
3
|
+
export type SessionMode = "chat" | "run"
|
|
4
|
+
|
|
5
|
+
export interface SessionHeader {
|
|
6
|
+
readonly type: string
|
|
7
|
+
readonly metadata: Record<string, unknown>
|
|
8
|
+
readonly workspace: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface SessionMeta {
|
|
12
|
+
readonly type: string
|
|
13
|
+
readonly version: 1
|
|
14
|
+
readonly id: string
|
|
15
|
+
readonly createdAt: number
|
|
16
|
+
readonly cwd: string
|
|
17
|
+
readonly workspace: string
|
|
18
|
+
readonly metadata: Record<string, unknown>
|
|
19
|
+
readonly app: string
|
|
20
|
+
readonly appVersion: string
|
|
21
|
+
readonly model: string
|
|
22
|
+
readonly title?: string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type ContentPart =
|
|
26
|
+
| { readonly type: "text"; readonly text: string }
|
|
27
|
+
| { readonly type: "reasoning"; readonly text: string }
|
|
28
|
+
| {
|
|
29
|
+
readonly type: "tool-call"
|
|
30
|
+
readonly id: string
|
|
31
|
+
readonly name: string
|
|
32
|
+
readonly arguments: string
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface SessionMessageRecord {
|
|
36
|
+
readonly role: "user" | "assistant" | "system" | "tool"
|
|
37
|
+
readonly content: readonly ContentPart[]
|
|
38
|
+
readonly source?: Record<string, unknown>
|
|
39
|
+
readonly id?: string
|
|
40
|
+
readonly toolCallId?: string
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** 规范化后的流式片段 */
|
|
44
|
+
export interface StreamChunkRecord {
|
|
45
|
+
readonly type: "chunk"
|
|
46
|
+
readonly time: number
|
|
47
|
+
readonly chunk: Record<string, unknown>
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface SessionEvent {
|
|
51
|
+
readonly type: string
|
|
52
|
+
readonly seq: number
|
|
53
|
+
readonly time: number
|
|
54
|
+
readonly data: Record<string, unknown>
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface SessionTurn {
|
|
58
|
+
readonly turn: number
|
|
59
|
+
readonly mode: SessionMode | null
|
|
60
|
+
readonly events: SessionEvent[]
|
|
61
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// 工作区:会话与 Agent 工具的文件边界
|
|
2
|
+
|
|
3
|
+
import { basename, resolve } from "node:path"
|
|
4
|
+
|
|
5
|
+
export class Workspace {
|
|
6
|
+
readonly root: string
|
|
7
|
+
readonly name: string
|
|
8
|
+
|
|
9
|
+
constructor(root: string) {
|
|
10
|
+
this.root = resolve(root)
|
|
11
|
+
this.name = basename(this.root)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
static open(path = process.cwd()): Workspace {
|
|
15
|
+
return new Workspace(path)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
equals(other: Workspace): boolean {
|
|
19
|
+
return this.root === other.root
|
|
20
|
+
}
|
|
21
|
+
}
|