@seawork/server 1.0.22-rc.3 → 2.0.2-rc.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/scripts/supervisor-entrypoint.js +48 -8
- package/dist/scripts/supervisor-entrypoint.js.map +1 -1
- package/dist/scripts/supervisor-native-classifier.js +77 -5
- package/dist/scripts/supervisor-native-classifier.js.map +1 -1
- package/dist/scripts/supervisor-stdio-tail.js +27 -0
- package/dist/scripts/supervisor-stdio-tail.js.map +1 -0
- package/dist/scripts/supervisor.js +12 -0
- package/dist/scripts/supervisor.js.map +1 -1
- package/dist/server/client/daemon-client.d.ts +142 -2
- package/dist/server/client/daemon-client.d.ts.map +1 -1
- package/dist/server/client/daemon-client.js +384 -3
- package/dist/server/client/daemon-client.js.map +1 -1
- package/dist/server/server/agent/agent-manager.d.ts +55 -3
- package/dist/server/server/agent/agent-manager.d.ts.map +1 -1
- package/dist/server/server/agent/agent-manager.js +324 -45
- package/dist/server/server/agent/agent-manager.js.map +1 -1
- package/dist/server/server/agent/agent-metadata-generator.d.ts +1 -0
- package/dist/server/server/agent/agent-metadata-generator.d.ts.map +1 -1
- package/dist/server/server/agent/agent-metadata-generator.js +8 -0
- package/dist/server/server/agent/agent-metadata-generator.js.map +1 -1
- package/dist/server/server/agent/agent-projections.js +7 -2
- package/dist/server/server/agent/agent-projections.js.map +1 -1
- package/dist/server/server/agent/agent-response-loop.d.ts +3 -1
- package/dist/server/server/agent/agent-response-loop.d.ts.map +1 -1
- package/dist/server/server/agent/agent-response-loop.js +33 -6
- package/dist/server/server/agent/agent-response-loop.js.map +1 -1
- package/dist/server/server/agent/agent-sdk-types.d.ts +43 -1
- package/dist/server/server/agent/agent-sdk-types.d.ts.map +1 -1
- package/dist/server/server/agent/claude-memory.d.ts +4 -0
- package/dist/server/server/agent/claude-memory.d.ts.map +1 -0
- package/dist/server/server/agent/claude-memory.js +97 -0
- package/dist/server/server/agent/claude-memory.js.map +1 -0
- package/dist/server/server/agent/mcp-server.d.ts.map +1 -1
- package/dist/server/server/agent/mcp-server.js +247 -0
- package/dist/server/server/agent/mcp-server.js.map +1 -1
- package/dist/server/server/agent/mcp-shared.d.ts +2 -0
- package/dist/server/server/agent/mcp-shared.d.ts.map +1 -1
- package/dist/server/server/agent/provider-launch-config.d.ts +6 -139
- package/dist/server/server/agent/provider-launch-config.d.ts.map +1 -1
- package/dist/server/server/agent/provider-launch-config.js +65 -33
- package/dist/server/server/agent/provider-launch-config.js.map +1 -1
- package/dist/server/server/agent/provider-manifest.d.ts +1 -0
- package/dist/server/server/agent/provider-manifest.d.ts.map +1 -1
- package/dist/server/server/agent/provider-manifest.js +36 -0
- package/dist/server/server/agent/provider-manifest.js.map +1 -1
- package/dist/server/server/agent/provider-registry.d.ts.map +1 -1
- package/dist/server/server/agent/provider-registry.js +4 -0
- package/dist/server/server/agent/provider-registry.js.map +1 -1
- package/dist/server/server/agent/provider-snapshot-manager.d.ts +3 -1
- package/dist/server/server/agent/provider-snapshot-manager.d.ts.map +1 -1
- package/dist/server/server/agent/provider-snapshot-manager.js +13 -0
- package/dist/server/server/agent/provider-snapshot-manager.js.map +1 -1
- package/dist/server/server/agent/providers/claude-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/claude-agent.js +141 -27
- package/dist/server/server/agent/providers/claude-agent.js.map +1 -1
- package/dist/server/server/agent/providers/codex/tool-call-mapper.d.ts.map +1 -1
- package/dist/server/server/agent/providers/codex/tool-call-mapper.js +14 -1
- package/dist/server/server/agent/providers/codex/tool-call-mapper.js.map +1 -1
- package/dist/server/server/agent/providers/codex-app-server-agent.d.ts +132 -4
- package/dist/server/server/agent/providers/codex-app-server-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/codex-app-server-agent.js +2233 -163
- package/dist/server/server/agent/providers/codex-app-server-agent.js.map +1 -1
- package/dist/server/server/agent/providers/codex-binary-resolver.d.ts +9 -0
- package/dist/server/server/agent/providers/codex-binary-resolver.d.ts.map +1 -1
- package/dist/server/server/agent/providers/codex-binary-resolver.js +35 -14
- package/dist/server/server/agent/providers/codex-binary-resolver.js.map +1 -1
- package/dist/server/server/agent/providers/codex-health-probe.js +1 -1
- package/dist/server/server/agent/providers/codex-health-probe.js.map +1 -1
- package/dist/server/server/agent/providers/deepseek/constants.d.ts +4 -0
- package/dist/server/server/agent/providers/deepseek/constants.d.ts.map +1 -0
- package/dist/server/server/agent/providers/deepseek/constants.js +11 -0
- package/dist/server/server/agent/providers/deepseek/constants.js.map +1 -0
- package/dist/server/server/agent/providers/deepseek/event-mapper.d.ts +21 -0
- package/dist/server/server/agent/providers/deepseek/event-mapper.d.ts.map +1 -0
- package/dist/server/server/agent/providers/deepseek/event-mapper.js +286 -0
- package/dist/server/server/agent/providers/deepseek/event-mapper.js.map +1 -0
- package/dist/server/server/agent/providers/deepseek/serve-client.d.ts +94 -0
- package/dist/server/server/agent/providers/deepseek/serve-client.d.ts.map +1 -0
- package/dist/server/server/agent/providers/deepseek/serve-client.js +142 -0
- package/dist/server/server/agent/providers/deepseek/serve-client.js.map +1 -0
- package/dist/server/server/agent/providers/deepseek/serve-process.d.ts +18 -0
- package/dist/server/server/agent/providers/deepseek/serve-process.d.ts.map +1 -0
- package/dist/server/server/agent/providers/deepseek/serve-process.js +93 -0
- package/dist/server/server/agent/providers/deepseek/serve-process.js.map +1 -0
- package/dist/server/server/agent/providers/deepseek-agent.d.ts +94 -0
- package/dist/server/server/agent/providers/deepseek-agent.d.ts.map +1 -0
- package/dist/server/server/agent/providers/deepseek-agent.js +811 -0
- package/dist/server/server/agent/providers/deepseek-agent.js.map +1 -0
- package/dist/server/server/agent/providers/gateway-telemetry.d.ts +9 -0
- package/dist/server/server/agent/providers/gateway-telemetry.d.ts.map +1 -0
- package/dist/server/server/agent/providers/gateway-telemetry.js +36 -0
- package/dist/server/server/agent/providers/gateway-telemetry.js.map +1 -0
- package/dist/server/server/agent/providers/seaagent/constants.d.ts +3 -0
- package/dist/server/server/agent/providers/seaagent/constants.d.ts.map +1 -0
- package/dist/server/server/agent/providers/seaagent/constants.js +3 -0
- package/dist/server/server/agent/providers/seaagent/constants.js.map +1 -0
- package/dist/server/server/agent/providers/seaagent/event-mapper.d.ts +3 -0
- package/dist/server/server/agent/providers/seaagent/event-mapper.d.ts.map +1 -0
- package/dist/server/server/agent/providers/seaagent/event-mapper.js +69 -0
- package/dist/server/server/agent/providers/seaagent/event-mapper.js.map +1 -0
- package/dist/server/server/agent/providers/seaagent/rpc-client.d.ts +23 -0
- package/dist/server/server/agent/providers/seaagent/rpc-client.d.ts.map +1 -0
- package/dist/server/server/agent/providers/seaagent/rpc-client.js +139 -0
- package/dist/server/server/agent/providers/seaagent/rpc-client.js.map +1 -0
- package/dist/server/server/agent/providers/seaagent/tool-call-mapper.d.ts +3 -0
- package/dist/server/server/agent/providers/seaagent/tool-call-mapper.d.ts.map +1 -0
- package/dist/server/server/agent/providers/seaagent/tool-call-mapper.js +38 -0
- package/dist/server/server/agent/providers/seaagent/tool-call-mapper.js.map +1 -0
- package/dist/server/server/agent/providers/seaagent-agent.d.ts +81 -0
- package/dist/server/server/agent/providers/seaagent-agent.d.ts.map +1 -0
- package/dist/server/server/agent/providers/seaagent-agent.js +502 -0
- package/dist/server/server/agent/providers/seaagent-agent.js.map +1 -0
- package/dist/server/server/agent/providers/seaagent-binary-resolver.d.ts +18 -0
- package/dist/server/server/agent/providers/seaagent-binary-resolver.d.ts.map +1 -0
- package/dist/server/server/agent/providers/seaagent-binary-resolver.js +46 -0
- package/dist/server/server/agent/providers/seaagent-binary-resolver.js.map +1 -0
- package/dist/server/server/agent/providers/seaagent-health-probe.d.ts +11 -0
- package/dist/server/server/agent/providers/seaagent-health-probe.d.ts.map +1 -0
- package/dist/server/server/agent/providers/seaagent-health-probe.js +49 -0
- package/dist/server/server/agent/providers/seaagent-health-probe.js.map +1 -0
- package/dist/server/server/agent/providers/seawork-models.d.ts +8 -0
- package/dist/server/server/agent/providers/seawork-models.d.ts.map +1 -1
- package/dist/server/server/agent/providers/seawork-models.js +118 -74
- package/dist/server/server/agent/providers/seawork-models.js.map +1 -1
- package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts +2 -2
- package/dist/server/server/agent/timeline-projection.d.ts +5 -1
- package/dist/server/server/agent/timeline-projection.d.ts.map +1 -1
- package/dist/server/server/agent/timeline-projection.js +20 -4
- package/dist/server/server/agent/timeline-projection.js.map +1 -1
- package/dist/server/server/agent-attention-policy.d.ts +1 -0
- package/dist/server/server/agent-attention-policy.d.ts.map +1 -1
- package/dist/server/server/agent-attention-policy.js +6 -0
- package/dist/server/server/agent-attention-policy.js.map +1 -1
- package/dist/server/server/allowed-hosts.d.ts +13 -0
- package/dist/server/server/allowed-hosts.d.ts.map +1 -1
- package/dist/server/server/allowed-hosts.js +33 -0
- package/dist/server/server/allowed-hosts.js.map +1 -1
- package/dist/server/server/bootstrap.d.ts +2 -0
- package/dist/server/server/bootstrap.d.ts.map +1 -1
- package/dist/server/server/bootstrap.js +200 -14
- package/dist/server/server/bootstrap.js.map +1 -1
- package/dist/server/server/browser-extension-token.d.ts +23 -0
- package/dist/server/server/browser-extension-token.d.ts.map +1 -0
- package/dist/server/server/browser-extension-token.js +114 -0
- package/dist/server/server/browser-extension-token.js.map +1 -0
- package/dist/server/server/bug-report-handler.d.ts +7 -1
- package/dist/server/server/bug-report-handler.d.ts.map +1 -1
- package/dist/server/server/bug-report-handler.js +73 -5
- package/dist/server/server/bug-report-handler.js.map +1 -1
- package/dist/server/server/bug-report-redact.d.ts +25 -1
- package/dist/server/server/bug-report-redact.d.ts.map +1 -1
- package/dist/server/server/bug-report-redact.js +42 -5
- package/dist/server/server/bug-report-redact.js.map +1 -1
- package/dist/server/server/config.d.ts +1 -0
- package/dist/server/server/config.d.ts.map +1 -1
- package/dist/server/server/config.js +51 -1
- package/dist/server/server/config.js.map +1 -1
- package/dist/server/server/crash-report.d.ts.map +1 -1
- package/dist/server/server/crash-report.js +18 -0
- package/dist/server/server/crash-report.js.map +1 -1
- package/dist/server/server/daemon-config-store.d.ts.map +1 -1
- package/dist/server/server/daemon-config-store.js +94 -3
- package/dist/server/server/daemon-config-store.js.map +1 -1
- package/dist/server/server/disk-full.d.ts +4 -0
- package/dist/server/server/disk-full.d.ts.map +1 -0
- package/dist/server/server/disk-full.js +46 -0
- package/dist/server/server/disk-full.js.map +1 -0
- package/dist/server/server/exports.d.ts +3 -2
- package/dist/server/server/exports.d.ts.map +1 -1
- package/dist/server/server/exports.js +2 -1
- package/dist/server/server/exports.js.map +1 -1
- package/dist/server/server/git-forge/github-client.d.ts +18 -0
- package/dist/server/server/git-forge/github-client.d.ts.map +1 -1
- package/dist/server/server/git-forge/github-client.js +88 -0
- package/dist/server/server/git-forge/github-client.js.map +1 -1
- package/dist/server/server/git-forge/parse-remote.d.ts +2 -0
- package/dist/server/server/git-forge/parse-remote.d.ts.map +1 -1
- package/dist/server/server/git-forge/parse-remote.js +71 -6
- package/dist/server/server/git-forge/parse-remote.js.map +1 -1
- package/dist/server/server/git-forge/service.d.ts +87 -0
- package/dist/server/server/git-forge/service.d.ts.map +1 -1
- package/dist/server/server/git-forge/service.js +198 -4
- package/dist/server/server/git-forge/service.js.map +1 -1
- package/dist/server/server/index.js +72 -0
- package/dist/server/server/index.js.map +1 -1
- package/dist/server/server/integrations/wecom-openclaw/bridge.d.ts +88 -0
- package/dist/server/server/integrations/wecom-openclaw/bridge.d.ts.map +1 -0
- package/dist/server/server/integrations/wecom-openclaw/bridge.js +1229 -0
- package/dist/server/server/integrations/wecom-openclaw/bridge.js.map +1 -0
- package/dist/server/server/integrations/wecom-openclaw/qr.d.ts +38 -0
- package/dist/server/server/integrations/wecom-openclaw/qr.d.ts.map +1 -0
- package/dist/server/server/integrations/wecom-openclaw/qr.js +101 -0
- package/dist/server/server/integrations/wecom-openclaw/qr.js.map +1 -0
- package/dist/server/server/integrations/wecom-openclaw/workspace.d.ts +5 -0
- package/dist/server/server/integrations/wecom-openclaw/workspace.d.ts.map +1 -0
- package/dist/server/server/integrations/wecom-openclaw/workspace.js +40 -0
- package/dist/server/server/integrations/wecom-openclaw/workspace.js.map +1 -0
- package/dist/server/server/latency-proxy.d.ts.map +1 -1
- package/dist/server/server/latency-proxy.js +45 -5
- package/dist/server/server/latency-proxy.js.map +1 -1
- package/dist/server/server/library/codex-skill-discovery.d.ts +9 -0
- package/dist/server/server/library/codex-skill-discovery.d.ts.map +1 -0
- package/dist/server/server/library/codex-skill-discovery.js +49 -0
- package/dist/server/server/library/codex-skill-discovery.js.map +1 -0
- package/dist/server/server/library/hub-install.d.ts +79 -0
- package/dist/server/server/library/hub-install.d.ts.map +1 -0
- package/dist/server/server/library/hub-install.js +263 -0
- package/dist/server/server/library/hub-install.js.map +1 -0
- package/dist/server/server/library/hub-test-run.d.ts +81 -0
- package/dist/server/server/library/hub-test-run.d.ts.map +1 -0
- package/dist/server/server/library/hub-test-run.js +237 -0
- package/dist/server/server/library/hub-test-run.js.map +1 -0
- package/dist/server/server/library/library-import.d.ts +27 -0
- package/dist/server/server/library/library-import.d.ts.map +1 -0
- package/dist/server/server/library/library-import.js +227 -0
- package/dist/server/server/library/library-import.js.map +1 -0
- package/dist/server/server/library/library-injection.d.ts +16 -0
- package/dist/server/server/library/library-injection.d.ts.map +1 -0
- package/dist/server/server/library/library-injection.js +49 -0
- package/dist/server/server/library/library-injection.js.map +1 -0
- package/dist/server/server/library/library-rpc.d.ts +73 -0
- package/dist/server/server/library/library-rpc.d.ts.map +1 -0
- package/dist/server/server/library/library-rpc.js +239 -0
- package/dist/server/server/library/library-rpc.js.map +1 -0
- package/dist/server/server/library/library-store.d.ts +35 -0
- package/dist/server/server/library/library-store.d.ts.map +1 -0
- package/dist/server/server/library/library-store.js +169 -0
- package/dist/server/server/library/library-store.js.map +1 -0
- package/dist/server/server/library/library-sync.d.ts +46 -0
- package/dist/server/server/library/library-sync.d.ts.map +1 -0
- package/dist/server/server/library/library-sync.js +235 -0
- package/dist/server/server/library/library-sync.js.map +1 -0
- package/dist/server/server/library/library-types.d.ts +756 -0
- package/dist/server/server/library/library-types.d.ts.map +1 -0
- package/dist/server/server/library/library-types.js +99 -0
- package/dist/server/server/library/library-types.js.map +1 -0
- package/dist/server/server/library/worktree-dev.d.ts +14 -0
- package/dist/server/server/library/worktree-dev.d.ts.map +1 -0
- package/dist/server/server/library/worktree-dev.js +24 -0
- package/dist/server/server/library/worktree-dev.js.map +1 -0
- package/dist/server/server/log-stream-error.d.ts +2 -0
- package/dist/server/server/log-stream-error.d.ts.map +1 -0
- package/dist/server/server/log-stream-error.js +33 -0
- package/dist/server/server/log-stream-error.js.map +1 -0
- package/dist/server/server/logger.d.ts +1 -0
- package/dist/server/server/logger.d.ts.map +1 -1
- package/dist/server/server/logger.js +32 -0
- package/dist/server/server/logger.js.map +1 -1
- package/dist/server/server/loop/rpc-schemas.d.ts +96 -96
- package/dist/server/server/loop-service.d.ts +18 -18
- package/dist/server/server/messages.d.ts +4 -1
- package/dist/server/server/messages.d.ts.map +1 -1
- package/dist/server/server/messages.js +40 -2
- package/dist/server/server/messages.js.map +1 -1
- package/dist/server/server/node-pty-error.d.ts +2 -0
- package/dist/server/server/node-pty-error.d.ts.map +1 -0
- package/dist/server/server/node-pty-error.js +19 -0
- package/dist/server/server/node-pty-error.js.map +1 -0
- package/dist/server/server/persisted-config.d.ts +219 -135
- package/dist/server/server/persisted-config.d.ts.map +1 -1
- package/dist/server/server/persisted-config.js +35 -1
- package/dist/server/server/persisted-config.js.map +1 -1
- package/dist/server/server/port-in-use.d.ts +4 -0
- package/dist/server/server/port-in-use.d.ts.map +1 -0
- package/dist/server/server/port-in-use.js +35 -0
- package/dist/server/server/port-in-use.js.map +1 -0
- package/dist/server/server/provider-runtime-settings-mask.d.ts +7 -0
- package/dist/server/server/provider-runtime-settings-mask.d.ts.map +1 -0
- package/dist/server/server/provider-runtime-settings-mask.js +65 -0
- package/dist/server/server/provider-runtime-settings-mask.js.map +1 -0
- package/dist/server/server/sac/auth.d.ts +12 -0
- package/dist/server/server/sac/auth.d.ts.map +1 -1
- package/dist/server/server/sac/auth.js +19 -1
- package/dist/server/server/sac/auth.js.map +1 -1
- package/dist/server/server/sac/index.d.ts +2 -2
- package/dist/server/server/sac/index.d.ts.map +1 -1
- package/dist/server/server/sac/index.js +2 -2
- package/dist/server/server/sac/index.js.map +1 -1
- package/dist/server/server/sac/poll.d.ts +2 -0
- package/dist/server/server/sac/poll.d.ts.map +1 -1
- package/dist/server/server/sac/poll.js +7 -2
- package/dist/server/server/sac/poll.js.map +1 -1
- package/dist/server/server/schedule/cron.d.ts.map +1 -1
- package/dist/server/server/schedule/cron.js +6 -6
- package/dist/server/server/schedule/cron.js.map +1 -1
- package/dist/server/server/schedule/rpc-schemas.d.ts +895 -0
- package/dist/server/server/schedule/rpc-schemas.d.ts.map +1 -1
- package/dist/server/server/schedule/rpc-schemas.js +34 -0
- package/dist/server/server/schedule/rpc-schemas.js.map +1 -1
- package/dist/server/server/schedule/service.d.ts +5 -1
- package/dist/server/server/schedule/service.d.ts.map +1 -1
- package/dist/server/server/schedule/service.js +97 -14
- package/dist/server/server/schedule/service.js.map +1 -1
- package/dist/server/server/schedule/types.d.ts +19 -0
- package/dist/server/server/schedule/types.d.ts.map +1 -1
- package/dist/server/server/schedule/types.js +1 -0
- package/dist/server/server/schedule/types.js.map +1 -1
- package/dist/server/server/session.d.ts +83 -2
- package/dist/server/server/session.d.ts.map +1 -1
- package/dist/server/server/session.js +895 -82
- package/dist/server/server/session.js.map +1 -1
- package/dist/server/server/speech/native-runtime-guard.d.ts +1 -0
- package/dist/server/server/speech/native-runtime-guard.d.ts.map +1 -1
- package/dist/server/server/speech/native-runtime-guard.js +10 -4
- package/dist/server/server/speech/native-runtime-guard.js.map +1 -1
- package/dist/server/server/websocket-server.d.ts +6 -1
- package/dist/server/server/websocket-server.d.ts.map +1 -1
- package/dist/server/server/websocket-server.js +79 -7
- package/dist/server/server/websocket-server.js.map +1 -1
- package/dist/server/server/workspace-git-service.d.ts +2 -1
- package/dist/server/server/workspace-git-service.d.ts.map +1 -1
- package/dist/server/server/workspace-git-service.js +7 -3
- package/dist/server/server/workspace-git-service.js.map +1 -1
- package/dist/server/server/workspace-registry-model.d.ts +1 -0
- package/dist/server/server/workspace-registry-model.d.ts.map +1 -1
- package/dist/server/server/workspace-registry-model.js +18 -0
- package/dist/server/server/workspace-registry-model.js.map +1 -1
- package/dist/server/server/worktree-session.d.ts +3 -3
- package/dist/server/server/worktree-session.d.ts.map +1 -1
- package/dist/server/server/worktree-session.js +1 -3
- package/dist/server/server/worktree-session.js.map +1 -1
- package/dist/server/shared/messages.d.ts +59658 -21927
- package/dist/server/shared/messages.d.ts.map +1 -1
- package/dist/server/shared/messages.js +531 -3
- package/dist/server/shared/messages.js.map +1 -1
- package/dist/server/shared/provider-runtime-settings.d.ts +87 -0
- package/dist/server/shared/provider-runtime-settings.d.ts.map +1 -0
- package/dist/server/shared/provider-runtime-settings.js +33 -0
- package/dist/server/shared/provider-runtime-settings.js.map +1 -0
- package/dist/server/terminal/terminal.d.ts +9 -0
- package/dist/server/terminal/terminal.d.ts.map +1 -1
- package/dist/server/terminal/terminal.js +100 -3
- package/dist/server/terminal/terminal.js.map +1 -1
- package/dist/server/utils/checkout-git.d.ts +23 -1
- package/dist/server/utils/checkout-git.d.ts.map +1 -1
- package/dist/server/utils/checkout-git.js +182 -21
- package/dist/server/utils/checkout-git.js.map +1 -1
- package/dist/server/utils/directory-suggestions.d.ts.map +1 -1
- package/dist/server/utils/directory-suggestions.js +57 -9
- package/dist/server/utils/directory-suggestions.js.map +1 -1
- package/dist/src/server/bug-report-redact.js +42 -5
- package/dist/src/server/bug-report-redact.js.map +1 -1
- package/dist/src/server/crash-report.js +18 -0
- package/dist/src/server/crash-report.js.map +1 -1
- package/dist/src/server/speech/native-runtime-guard.js +177 -0
- package/dist/src/server/speech/native-runtime-guard.js.map +1 -0
- package/dist/src/server/speech/speech-types.js +8 -0
- package/dist/src/server/speech/speech-types.js.map +1 -0
- package/package.json +16 -4
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { exec, execFile } from "node:child_process";
|
|
2
2
|
import { homedir, tmpdir } from "node:os";
|
|
3
|
+
import { TTLCache } from "@isaacs/ttlcache";
|
|
3
4
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
4
5
|
import { experimental_createMCPClient } from "ai";
|
|
5
6
|
import equal from "fast-deep-equal";
|
|
@@ -10,11 +11,10 @@ import { v4 as uuidv4 } from "uuid";
|
|
|
10
11
|
import { z } from "zod";
|
|
11
12
|
import { decodeTerminalResizePayload, encodeTerminalSnapshotPayload, encodeTerminalStreamFrame, TerminalStreamOpcode, } from "../shared/terminal-stream-protocol.js";
|
|
12
13
|
import { captureTerminalLines } from "../terminal/terminal.js";
|
|
13
|
-
import { commitChanges, createPullRequest, getCheckoutDiff, getCheckoutStatus, listBranchSuggestions, mergeFromBase, mergeToBase, pullCurrentBranch, pushCurrentBranch, } from "../utils/checkout-git.js";
|
|
14
|
+
import { commitChanges, createPullRequest, getCachedCheckoutShortstat, getCheckoutDiff, getCheckoutStatus, hasWorkingTreeChanges, invalidateCheckoutShortstatCache, listBranchSuggestions, mergeFromBase, mergeToBase, pullCurrentBranch, pushCurrentBranch, warmCheckoutShortstatInBackground, } from "../utils/checkout-git.js";
|
|
14
15
|
import { searchHomeDirectories, searchWorkspaceEntries } from "../utils/directory-suggestions.js";
|
|
15
16
|
import { expandTilde } from "../utils/path.js";
|
|
16
17
|
import { getProjectIcon } from "../utils/project-icon.js";
|
|
17
|
-
import { latencyTracker } from "./latency-tracker.js";
|
|
18
18
|
import { scheduleAgentMetadataGeneration } from "./agent/agent-metadata-generator.js";
|
|
19
19
|
import { resolveEffectiveThinkingOptionId, toAgentPayload } from "./agent/agent-projections.js";
|
|
20
20
|
import { DEFAULT_STRUCTURED_GENERATION_PROVIDERS, generateStructuredAgentResponseWithFallback, StructuredAgentFallbackError, StructuredAgentResponseError, } from "./agent/agent-response-loop.js";
|
|
@@ -33,22 +33,29 @@ import { notifyChatMentions } from "./chat/chat-mentions.js";
|
|
|
33
33
|
import { ChatServiceError } from "./chat/chat-service.js";
|
|
34
34
|
import { READ_ONLY_GIT_ENV, toCheckoutError } from "./checkout-git-utils.js";
|
|
35
35
|
import { resolveClientMessageId } from "./client-message-id.js";
|
|
36
|
-
import { fetchGitForgeIssues } from "./git-forge/service.js";
|
|
37
|
-
import { redactGitForgeTokens, rehydratePatchTokens } from "./git-forge/token-mask.js";
|
|
38
36
|
import { DictationStreamManager, } from "./dictation/dictation-stream-manager.js";
|
|
39
37
|
import { listAvailableEditorTargets, openInEditorTarget } from "./editor-targets.js";
|
|
40
38
|
import { createDirectoryEntry, createFileEntry, getDownloadableFileInfo, listDirectoryEntries, readExplorerFile, } from "./file-explorer/service.js";
|
|
41
|
-
import { WorkspaceIgnoreStore } from "./workspace-ignore/store.js";
|
|
42
39
|
import { handleGetPublicIssue, handleListIssueComments, handleListPublicIssues, handlePostIssueComment, handleToggleIssueReaction, } from "./forum-handler.js";
|
|
40
|
+
import { discoverGitForgeIssueWork, fetchGitForgeIssues, transitionGitForgeIssueWork, } from "./git-forge/service.js";
|
|
41
|
+
import { redactGitForgeTokens, rehydratePatchTokens } from "./git-forge/token-mask.js";
|
|
42
|
+
import { fetchWeComOpenClawQrCode, queryWeComOpenClawQrResult, } from "./integrations/wecom-openclaw/qr.js";
|
|
43
|
+
import { resolveWeComOpenClawAgentCwd } from "./integrations/wecom-openclaw/workspace.js";
|
|
44
|
+
import { latencyTracker } from "./latency-tracker.js";
|
|
45
|
+
import { handleHubTestRunCancel, handleHubTestRunStart } from "./library/hub-test-run.js";
|
|
46
|
+
import { filterLibrarySkillCommands } from "./library/library-injection.js";
|
|
47
|
+
import { handleLibraryRequest } from "./library/library-rpc.js";
|
|
43
48
|
import { handleListMyIssues } from "./list-my-issues-handler.js";
|
|
44
|
-
import { isLegacyEditorTargetId, serializeAgentStreamEvent, } from "./messages.js";
|
|
49
|
+
import { isLegacyEditorTargetId, PROVIDER_ENV_VALUE_REDACTED, serializeAgentStreamEvent, } from "./messages.js";
|
|
45
50
|
import { buildConfigOverrides, buildSessionConfig, extractTimestamps, } from "./persistence-hooks.js";
|
|
51
|
+
import { redactProviderEnv, rehydratePatchProviderEnv } from "./provider-runtime-settings-mask.js";
|
|
46
52
|
import { toResolver } from "./speech/provider-resolver.js";
|
|
47
53
|
import { createVoiceTurnController, } from "./voice/voice-turn-controller.js";
|
|
48
54
|
import { buildVoiceModeSystemPrompt, stripVoiceModeSystemPrompt, wrapSpokenInput, } from "./voice-config.js";
|
|
49
55
|
import { isVoicePermissionAllowed } from "./voice-permission-policy.js";
|
|
56
|
+
import { WorkspaceIgnoreStore } from "./workspace-ignore/store.js";
|
|
50
57
|
import { createPersistedProjectRecord, createPersistedWorkspaceRecord, } from "./workspace-registry.js";
|
|
51
|
-
import { buildProjectPlacementForCwd, deriveProjectKind, deriveProjectRootPath, deriveWorkspaceDisplayName, deriveWorkspaceId, deriveWorkspaceKind, detectStaleWorkspaces, normalizeWorkspaceId as normalizePersistedWorkspaceId, } from "./workspace-registry-model.js";
|
|
58
|
+
import { buildProjectPlacementForCwd, deriveProjectKind, deriveProjectRootPath, deriveWorkspaceDisplayName, deriveWorkspaceId, deriveWorkspaceKind, detectStaleWorkspaces, normalizeWorkspaceId as normalizePersistedWorkspaceId, normalizeWorkspaceLookupKey, } from "./workspace-registry-model.js";
|
|
52
59
|
import { runAsyncWorktreeBootstrap } from "./worktree-bootstrap.js";
|
|
53
60
|
import { assertSafeGitRef as assertWorktreeSafeGitRef, buildAgentSessionConfig as buildWorktreeAgentSessionConfig, createSeaworkWorktreeInBackground as createWorktreeInBackgroundSession, handleCreateSeaworkWorktreeRequest as handleCreateWorktreeRequest, handleSeaworkWorktreeArchiveRequest as handleWorktreeArchiveRequest, handleSeaworkWorktreeListRequest as handleWorktreeListRequest, killTerminalsUnderPath as killWorktreeTerminalsUnderPath, registerPendingWorktreeWorkspace as registerPendingWorktreeWorkspaceSession, } from "./worktree-session.js";
|
|
54
61
|
const execAsync = promisify(exec);
|
|
@@ -84,11 +91,30 @@ function clientSupportsAllProviders(appVersion) {
|
|
|
84
91
|
function clientSupportsFlexibleEditorIds(appVersion) {
|
|
85
92
|
return isAppVersionAtLeast(appVersion, MIN_VERSION_FLEXIBLE_EDITOR_IDS);
|
|
86
93
|
}
|
|
94
|
+
function clientSupportsTimelineErrorItems(appVersion) {
|
|
95
|
+
return isAppVersionAtLeast(appVersion, "1.0.34");
|
|
96
|
+
}
|
|
97
|
+
function clientSupportsTimelineReconnectingItems(appVersion) {
|
|
98
|
+
return isAppVersionAtLeast(appVersion, "1.0.39");
|
|
99
|
+
}
|
|
100
|
+
function legacyTimelineProjectionOptions(appVersion) {
|
|
101
|
+
return {
|
|
102
|
+
legacySystemErrorsAsAssistantMessage: !clientSupportsTimelineErrorItems(appVersion),
|
|
103
|
+
legacyReconnectingAsReasoning: !clientSupportsTimelineReconnectingItems(appVersion),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
87
106
|
const MAX_TERMINAL_STREAM_SLOTS = 256;
|
|
88
107
|
// Reuse the cached PR snapshot for this long before re-shelling out to `gh`.
|
|
89
108
|
// Background watchers + periodic fetches keep it warm; the client polls every
|
|
90
109
|
// 15s, so this dedupes overlapping panels without delaying real changes.
|
|
91
110
|
const CHECKOUT_PR_STATUS_CACHE_TTL_MS = 10000;
|
|
111
|
+
const AVAILABLE_EDITOR_TARGETS_CACHE_TTL_MS = 60000;
|
|
112
|
+
const AVAILABLE_EDITOR_TARGETS_CACHE_KEY = "available";
|
|
113
|
+
// Coalesces repeated buildProjectPlacement calls (each spawns 3+ git children)
|
|
114
|
+
// across concurrent fetch_agents / fetch_workspaces requests. Slow disks or
|
|
115
|
+
// missing-external-drive cwds previously caused tens of seconds of stacked git
|
|
116
|
+
// invocations per cwd; see issue #635 / #770.
|
|
117
|
+
const PROJECT_PLACEMENT_CACHE_TTL_MS = 5000;
|
|
92
118
|
function computeCheckoutPrAgeMs(snap) {
|
|
93
119
|
const t = snap?.github.refreshedAt;
|
|
94
120
|
if (!t)
|
|
@@ -232,6 +258,164 @@ function toAgentPersistenceHandle(logger, handle) {
|
|
|
232
258
|
metadata: handle.metadata,
|
|
233
259
|
};
|
|
234
260
|
}
|
|
261
|
+
const OFFLINE_TIMELINE_EPOCH = "offline-persisted";
|
|
262
|
+
const DEFAULT_OFFLINE_TIMELINE_FETCH_LIMIT = 200;
|
|
263
|
+
function buildOfflineTimelineRows(items, timestamp) {
|
|
264
|
+
return items.map((item, index) => ({
|
|
265
|
+
seq: index + 1,
|
|
266
|
+
timestamp,
|
|
267
|
+
item,
|
|
268
|
+
}));
|
|
269
|
+
}
|
|
270
|
+
function selectOfflineTimelineWindow(params) {
|
|
271
|
+
const rows = buildOfflineTimelineRows(params.items, params.timestamp);
|
|
272
|
+
const direction = params.direction;
|
|
273
|
+
const limit = params.limit === undefined
|
|
274
|
+
? DEFAULT_OFFLINE_TIMELINE_FETCH_LIMIT
|
|
275
|
+
: Math.max(0, Math.floor(params.limit));
|
|
276
|
+
const minSeq = rows.length ? rows[0].seq : 0;
|
|
277
|
+
const maxSeq = rows.length ? rows[rows.length - 1].seq : 0;
|
|
278
|
+
const nextSeq = maxSeq + 1;
|
|
279
|
+
const window = { minSeq, maxSeq, nextSeq };
|
|
280
|
+
const cloneRows = (selected) => selected.map((row) => ({ ...row }));
|
|
281
|
+
const selectAll = limit === 0;
|
|
282
|
+
if (params.cursor && params.cursor.epoch !== OFFLINE_TIMELINE_EPOCH) {
|
|
283
|
+
return {
|
|
284
|
+
agentProvider: params.agentProvider,
|
|
285
|
+
epoch: OFFLINE_TIMELINE_EPOCH,
|
|
286
|
+
reset: true,
|
|
287
|
+
staleCursor: true,
|
|
288
|
+
gap: false,
|
|
289
|
+
window,
|
|
290
|
+
hasOlder: false,
|
|
291
|
+
hasNewer: false,
|
|
292
|
+
rows: cloneRows(rows),
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
if (direction === "after" && params.cursor && rows.length > 0 && params.cursor.seq < minSeq - 1) {
|
|
296
|
+
return {
|
|
297
|
+
agentProvider: params.agentProvider,
|
|
298
|
+
epoch: OFFLINE_TIMELINE_EPOCH,
|
|
299
|
+
reset: true,
|
|
300
|
+
staleCursor: false,
|
|
301
|
+
gap: true,
|
|
302
|
+
window,
|
|
303
|
+
hasOlder: false,
|
|
304
|
+
hasNewer: false,
|
|
305
|
+
rows: cloneRows(rows),
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
if (rows.length === 0) {
|
|
309
|
+
return {
|
|
310
|
+
agentProvider: params.agentProvider,
|
|
311
|
+
epoch: OFFLINE_TIMELINE_EPOCH,
|
|
312
|
+
reset: false,
|
|
313
|
+
staleCursor: false,
|
|
314
|
+
gap: false,
|
|
315
|
+
window,
|
|
316
|
+
hasOlder: false,
|
|
317
|
+
hasNewer: false,
|
|
318
|
+
rows: [],
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
if (direction === "tail") {
|
|
322
|
+
const selected = selectAll || limit >= rows.length ? rows : rows.slice(rows.length - limit);
|
|
323
|
+
return {
|
|
324
|
+
agentProvider: params.agentProvider,
|
|
325
|
+
epoch: OFFLINE_TIMELINE_EPOCH,
|
|
326
|
+
reset: false,
|
|
327
|
+
staleCursor: false,
|
|
328
|
+
gap: false,
|
|
329
|
+
window,
|
|
330
|
+
hasOlder: selected.length > 0 && selected[0].seq > minSeq,
|
|
331
|
+
hasNewer: false,
|
|
332
|
+
rows: cloneRows(selected),
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
if (direction === "after") {
|
|
336
|
+
const baseSeq = params.cursor?.seq ?? 0;
|
|
337
|
+
const startIdx = rows.findIndex((row) => row.seq > baseSeq);
|
|
338
|
+
if (startIdx < 0) {
|
|
339
|
+
return {
|
|
340
|
+
agentProvider: params.agentProvider,
|
|
341
|
+
epoch: OFFLINE_TIMELINE_EPOCH,
|
|
342
|
+
reset: false,
|
|
343
|
+
staleCursor: false,
|
|
344
|
+
gap: false,
|
|
345
|
+
window,
|
|
346
|
+
hasOlder: baseSeq >= minSeq,
|
|
347
|
+
hasNewer: false,
|
|
348
|
+
rows: [],
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
const selected = selectAll ? rows.slice(startIdx) : rows.slice(startIdx, startIdx + limit);
|
|
352
|
+
const lastSelected = selected[selected.length - 1];
|
|
353
|
+
return {
|
|
354
|
+
agentProvider: params.agentProvider,
|
|
355
|
+
epoch: OFFLINE_TIMELINE_EPOCH,
|
|
356
|
+
reset: false,
|
|
357
|
+
staleCursor: false,
|
|
358
|
+
gap: false,
|
|
359
|
+
window,
|
|
360
|
+
hasOlder: selected[0].seq > minSeq,
|
|
361
|
+
hasNewer: Boolean(lastSelected && lastSelected.seq < maxSeq),
|
|
362
|
+
rows: cloneRows(selected),
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
const beforeSeq = params.cursor?.seq ?? nextSeq;
|
|
366
|
+
const endExclusive = rows.findIndex((row) => row.seq >= beforeSeq);
|
|
367
|
+
const boundedRows = endExclusive < 0 ? rows : rows.slice(0, endExclusive);
|
|
368
|
+
const selected = selectAll || limit >= boundedRows.length
|
|
369
|
+
? boundedRows
|
|
370
|
+
: boundedRows.slice(boundedRows.length - limit);
|
|
371
|
+
return {
|
|
372
|
+
agentProvider: params.agentProvider,
|
|
373
|
+
epoch: OFFLINE_TIMELINE_EPOCH,
|
|
374
|
+
reset: false,
|
|
375
|
+
staleCursor: false,
|
|
376
|
+
gap: false,
|
|
377
|
+
window,
|
|
378
|
+
hasOlder: selected.length > 0 && selected[0].seq > minSeq,
|
|
379
|
+
hasNewer: endExclusive >= 0,
|
|
380
|
+
rows: cloneRows(selected),
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
function projectOfflineTimelineFetchResponse(params) {
|
|
384
|
+
let hasOlder = params.model.hasOlder;
|
|
385
|
+
let hasNewer = params.model.hasNewer;
|
|
386
|
+
let startCursor = null;
|
|
387
|
+
let endCursor = null;
|
|
388
|
+
let entries;
|
|
389
|
+
if (params.shouldLimitByProjectedWindow) {
|
|
390
|
+
const projectedLimit = Math.max(1, Math.floor(params.requestedLimit ?? 1));
|
|
391
|
+
const projectedWindow = selectTimelineWindowByProjectedLimit({
|
|
392
|
+
rows: params.model.rows,
|
|
393
|
+
provider: params.model.agentProvider,
|
|
394
|
+
direction: params.direction,
|
|
395
|
+
limit: projectedLimit,
|
|
396
|
+
collapseToolLifecycle: false,
|
|
397
|
+
});
|
|
398
|
+
entries = projectTimelineRows(projectedWindow.selectedRows, params.model.agentProvider, params.projection, params.projectionOptions);
|
|
399
|
+
if (projectedWindow.minSeq !== null && projectedWindow.maxSeq !== null) {
|
|
400
|
+
startCursor = { epoch: params.model.epoch, seq: projectedWindow.minSeq };
|
|
401
|
+
endCursor = { epoch: params.model.epoch, seq: projectedWindow.maxSeq };
|
|
402
|
+
hasOlder = projectedWindow.minSeq > params.model.window.minSeq;
|
|
403
|
+
hasNewer = false;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
else {
|
|
407
|
+
const firstRow = params.model.rows[0];
|
|
408
|
+
const lastRow = params.model.rows[params.model.rows.length - 1];
|
|
409
|
+
startCursor = firstRow ? { epoch: params.model.epoch, seq: firstRow.seq } : null;
|
|
410
|
+
endCursor = lastRow ? { epoch: params.model.epoch, seq: lastRow.seq } : null;
|
|
411
|
+
entries = projectTimelineRows(params.model.rows, params.model.agentProvider, params.projection, params.projectionOptions);
|
|
412
|
+
}
|
|
413
|
+
return { entries, startCursor, endCursor, hasOlder, hasNewer };
|
|
414
|
+
}
|
|
415
|
+
export const __sessionTimelineInternals = {
|
|
416
|
+
projectOfflineTimelineFetchResponse,
|
|
417
|
+
selectOfflineTimelineWindow,
|
|
418
|
+
};
|
|
235
419
|
/**
|
|
236
420
|
* Session represents a single connected client session.
|
|
237
421
|
* It owns all state management, orchestration logic, and message processing.
|
|
@@ -259,11 +443,14 @@ export class Session {
|
|
|
259
443
|
// Per-session MCP client and tools
|
|
260
444
|
this.agentMcpClient = null;
|
|
261
445
|
this.agentTools = null;
|
|
446
|
+
/** In-flight Hub "test run" sandboxes, keyed by requestId, for cancellation. */
|
|
447
|
+
this.hubTestRuns = new Map();
|
|
262
448
|
this.unsubscribeAgentEvents = null;
|
|
263
449
|
this.agentUpdatesSubscription = null;
|
|
264
450
|
this.workspaceUpdatesSubscription = null;
|
|
265
451
|
this.clientActivity = null;
|
|
266
452
|
this.MOBILE_BACKGROUND_STREAM_GRACE_MS = 60000;
|
|
453
|
+
this.wecomOpenClawQr = null;
|
|
267
454
|
this.unsubscribeProviderSnapshotEvents = null;
|
|
268
455
|
this.subscribedTerminalDirectories = new Set();
|
|
269
456
|
this.unsubscribeTerminalsChanged = null;
|
|
@@ -273,6 +460,18 @@ export class Session {
|
|
|
273
460
|
this.nextTerminalSlot = 0;
|
|
274
461
|
this.inflightRequests = 0;
|
|
275
462
|
this.peakInflightRequests = 0;
|
|
463
|
+
this.availableEditorTargetsCache = new TTLCache({
|
|
464
|
+
ttl: AVAILABLE_EDITOR_TARGETS_CACHE_TTL_MS,
|
|
465
|
+
max: 1,
|
|
466
|
+
checkAgeOnGet: true,
|
|
467
|
+
});
|
|
468
|
+
this.availableEditorTargetsInflight = null;
|
|
469
|
+
this.projectPlacementCache = new TTLCache({
|
|
470
|
+
ttl: PROJECT_PLACEMENT_CACHE_TTL_MS,
|
|
471
|
+
max: 500,
|
|
472
|
+
checkAgeOnGet: true,
|
|
473
|
+
});
|
|
474
|
+
this.projectPlacementInflight = new Map();
|
|
276
475
|
this.bugReportWsMessageRing = [];
|
|
277
476
|
this.checkoutDiffSubscriptions = new Map();
|
|
278
477
|
this.workspaceGitSubscriptions = new Map();
|
|
@@ -285,7 +484,7 @@ export class Session {
|
|
|
285
484
|
attention: 3,
|
|
286
485
|
done: 4,
|
|
287
486
|
};
|
|
288
|
-
const { clientId, appVersion, onMessage, onBinaryMessage, onLifecycleIntent, logger, downloadTokenStore, pushTokenStore, seaworkHome, agentManager, agentStorage, projectRegistry, workspaceRegistry, chatService, scheduleService, loopService, checkoutDiffManager, workspaceGitService, daemonConfigStore, mcpBaseUrl, stt, tts, terminalManager, providerSnapshotManager, voice, voiceBridge, dictation, agentProviderRuntimeSettings, } = options;
|
|
487
|
+
const { clientId, appVersion, onMessage, onBinaryMessage, onLifecycleIntent, logger, downloadTokenStore, pushTokenStore, seaworkHome, agentManager, agentStorage, projectRegistry, workspaceRegistry, chatService, scheduleService, loopService, checkoutDiffManager, workspaceGitService, daemonConfigStore, mcpBaseUrl, stt, tts, terminalManager, providerSnapshotManager, voice, voiceBridge, dictation, agentProviderRuntimeSettings, library, broadcastLibraryUpdate, } = options;
|
|
289
488
|
this.clientId = clientId;
|
|
290
489
|
this.appVersion = appVersion;
|
|
291
490
|
this.sessionId = uuidv4();
|
|
@@ -306,6 +505,8 @@ export class Session {
|
|
|
306
505
|
this.workspaceGitService = workspaceGitService;
|
|
307
506
|
this.daemonConfigStore = daemonConfigStore;
|
|
308
507
|
this.mcpBaseUrl = mcpBaseUrl ?? null;
|
|
508
|
+
this.library = library ?? null;
|
|
509
|
+
this.broadcastLibraryUpdate = broadcastLibraryUpdate ?? null;
|
|
309
510
|
this.terminalManager = terminalManager;
|
|
310
511
|
this.providerSnapshotManager = providerSnapshotManager ?? null;
|
|
311
512
|
if (this.terminalManager) {
|
|
@@ -574,15 +775,20 @@ export class Session {
|
|
|
574
775
|
}
|
|
575
776
|
}
|
|
576
777
|
}
|
|
577
|
-
const serializedEvent = serializeAgentStreamEvent(event.event
|
|
778
|
+
const serializedEvent = serializeAgentStreamEvent(event.event, {
|
|
779
|
+
...legacyTimelineProjectionOptions(this.appVersion),
|
|
780
|
+
});
|
|
578
781
|
if (!serializedEvent) {
|
|
579
782
|
return;
|
|
580
783
|
}
|
|
581
|
-
// Log timing for key stream events
|
|
784
|
+
// Log timing for key stream events. "timeline" is intentionally
|
|
785
|
+
// excluded: it fires once per delta, so a long turn floods daemon.log
|
|
786
|
+
// and evicts the real turn_failed error from the bug-report tail
|
|
787
|
+
// window (#1215). Keep only the once-per-turn markers.
|
|
582
788
|
const evtType = event.event.type;
|
|
583
|
-
if (evtType === "
|
|
584
|
-
evtType === "turn_completed" ||
|
|
789
|
+
if (evtType === "turn_completed" ||
|
|
585
790
|
evtType === "turn_failed" ||
|
|
791
|
+
evtType === "turn_canceled" ||
|
|
586
792
|
evtType === "usage_updated") {
|
|
587
793
|
this.sessionLogger.info({
|
|
588
794
|
agentId: event.agentId,
|
|
@@ -717,6 +923,7 @@ export class Session {
|
|
|
717
923
|
async ensureAgentLoaded(agentId) {
|
|
718
924
|
const existing = this.agentManager.getAgent(agentId);
|
|
719
925
|
if (existing) {
|
|
926
|
+
await this.agentManager.hydrateTimelineFromProvider(agentId);
|
|
720
927
|
return existing;
|
|
721
928
|
}
|
|
722
929
|
const inflight = pendingAgentInitializations.get(agentId);
|
|
@@ -753,6 +960,36 @@ export class Session {
|
|
|
753
960
|
}
|
|
754
961
|
}
|
|
755
962
|
}
|
|
963
|
+
async loadOfflineTimelineForStoredAgent(params) {
|
|
964
|
+
const record = await this.agentStorage.get(params.agentId);
|
|
965
|
+
if (!record) {
|
|
966
|
+
return null;
|
|
967
|
+
}
|
|
968
|
+
const handle = toAgentPersistenceHandle(this.sessionLogger, record.persistence);
|
|
969
|
+
if (!handle) {
|
|
970
|
+
return null;
|
|
971
|
+
}
|
|
972
|
+
const provider = coerceAgentProvider(this.sessionLogger, record.provider, record.id);
|
|
973
|
+
const client = this.providerRegistry[provider]?.createClient(this.sessionLogger);
|
|
974
|
+
if (!client?.loadPersistedTimeline) {
|
|
975
|
+
return null;
|
|
976
|
+
}
|
|
977
|
+
const items = await client.loadPersistedTimeline(handle);
|
|
978
|
+
if (items.length === 0) {
|
|
979
|
+
return null;
|
|
980
|
+
}
|
|
981
|
+
return {
|
|
982
|
+
record,
|
|
983
|
+
model: selectOfflineTimelineWindow({
|
|
984
|
+
agentProvider: provider,
|
|
985
|
+
items,
|
|
986
|
+
direction: params.direction,
|
|
987
|
+
cursor: params.cursor,
|
|
988
|
+
limit: params.limit,
|
|
989
|
+
timestamp: this.resolveStoredAgentPayloadUpdatedAt(record),
|
|
990
|
+
}),
|
|
991
|
+
};
|
|
992
|
+
}
|
|
756
993
|
// TODO: Remove once all app store clients are on >=0.1.45.
|
|
757
994
|
isProviderVisibleToClient(provider) {
|
|
758
995
|
if (clientSupportsAllProviders(this.appVersion))
|
|
@@ -852,10 +1089,27 @@ export class Session {
|
|
|
852
1089
|
}
|
|
853
1090
|
}
|
|
854
1091
|
async buildProjectPlacement(cwd) {
|
|
855
|
-
|
|
1092
|
+
const cached = this.projectPlacementCache.get(cwd);
|
|
1093
|
+
if (cached) {
|
|
1094
|
+
return cached;
|
|
1095
|
+
}
|
|
1096
|
+
const inflight = this.projectPlacementInflight.get(cwd);
|
|
1097
|
+
if (inflight) {
|
|
1098
|
+
return inflight;
|
|
1099
|
+
}
|
|
1100
|
+
const promise = buildProjectPlacementForCwd({
|
|
856
1101
|
cwd,
|
|
857
1102
|
seaworkHome: this.seaworkHome,
|
|
1103
|
+
})
|
|
1104
|
+
.then((placement) => {
|
|
1105
|
+
this.projectPlacementCache.set(cwd, placement);
|
|
1106
|
+
return placement;
|
|
1107
|
+
})
|
|
1108
|
+
.finally(() => {
|
|
1109
|
+
this.projectPlacementInflight.delete(cwd);
|
|
858
1110
|
});
|
|
1111
|
+
this.projectPlacementInflight.set(cwd, promise);
|
|
1112
|
+
return promise;
|
|
859
1113
|
}
|
|
860
1114
|
buildPersistedProjectRecord(input) {
|
|
861
1115
|
return createPersistedProjectRecord({
|
|
@@ -1106,6 +1360,36 @@ export class Session {
|
|
|
1106
1360
|
case "toggle_issue_reaction_request":
|
|
1107
1361
|
await this.handleToggleIssueReactionRequest(msg);
|
|
1108
1362
|
break;
|
|
1363
|
+
case "library_list_request":
|
|
1364
|
+
case "library_upsert_mcp_request":
|
|
1365
|
+
case "library_upsert_skill_request":
|
|
1366
|
+
case "library_delete_request":
|
|
1367
|
+
case "library_set_autoattach_request":
|
|
1368
|
+
case "library_import_existing_request":
|
|
1369
|
+
case "library_install_from_hub_request":
|
|
1370
|
+
case "library_uninstall_from_hub_request": {
|
|
1371
|
+
const response = await handleLibraryRequest(msg, {
|
|
1372
|
+
library: this.library,
|
|
1373
|
+
seaworkHome: this.seaworkHome,
|
|
1374
|
+
logger: this.sessionLogger,
|
|
1375
|
+
broadcastUpdate: (snapshot) => this.broadcastLibraryUpdate?.(snapshot),
|
|
1376
|
+
});
|
|
1377
|
+
this.emit(response);
|
|
1378
|
+
break;
|
|
1379
|
+
}
|
|
1380
|
+
case "hub_test_run_start_request": {
|
|
1381
|
+
const done = await handleHubTestRunStart(msg, {
|
|
1382
|
+
codexClient: this.providerRegistry.codex.createClient(this.sessionLogger),
|
|
1383
|
+
logger: this.sessionLogger,
|
|
1384
|
+
emitChunk: (chunk) => this.emit(chunk),
|
|
1385
|
+
inFlight: this.hubTestRuns,
|
|
1386
|
+
});
|
|
1387
|
+
this.emit(done);
|
|
1388
|
+
break;
|
|
1389
|
+
}
|
|
1390
|
+
case "hub_test_run_cancel_request":
|
|
1391
|
+
handleHubTestRunCancel(msg.requestId, this.hubTestRuns);
|
|
1392
|
+
break;
|
|
1109
1393
|
case "archive_agent_request":
|
|
1110
1394
|
await this.handleArchiveAgentRequest(msg.agentId, msg.requestId);
|
|
1111
1395
|
break;
|
|
@@ -1129,25 +1413,41 @@ export class Session {
|
|
|
1129
1413
|
type: "get_daemon_config_response",
|
|
1130
1414
|
payload: {
|
|
1131
1415
|
requestId: msg.requestId,
|
|
1132
|
-
config:
|
|
1416
|
+
config: this.redactDaemonConfig(this.daemonConfigStore.get()),
|
|
1133
1417
|
},
|
|
1134
1418
|
});
|
|
1135
1419
|
break;
|
|
1136
1420
|
case "set_daemon_config_request": {
|
|
1137
|
-
const
|
|
1421
|
+
const tokenRehydrated = rehydratePatchTokens({
|
|
1138
1422
|
patch: msg.config,
|
|
1139
1423
|
current: this.daemonConfigStore.get(),
|
|
1140
1424
|
});
|
|
1141
|
-
const
|
|
1425
|
+
const providerEnvRehydrated = rehydratePatchProviderEnv({
|
|
1426
|
+
patch: tokenRehydrated,
|
|
1427
|
+
current: this.daemonConfigStore.get(),
|
|
1428
|
+
});
|
|
1429
|
+
const rehydrated = rehydratePatchWeComOpenClawSecret({
|
|
1430
|
+
patch: providerEnvRehydrated,
|
|
1431
|
+
current: this.daemonConfigStore.get(),
|
|
1432
|
+
});
|
|
1433
|
+
const cwdResolved = resolvePatchWeComOpenClawAgentCwd({
|
|
1434
|
+
patch: rehydrated,
|
|
1435
|
+
seaworkHome: this.seaworkHome,
|
|
1436
|
+
});
|
|
1437
|
+
const promptInjectionResolved = resolvePatchPromptInjectionCwds(cwdResolved);
|
|
1438
|
+
const next = this.daemonConfigStore.patch(promptInjectionResolved);
|
|
1142
1439
|
this.emit({
|
|
1143
1440
|
type: "set_daemon_config_response",
|
|
1144
1441
|
payload: {
|
|
1145
1442
|
requestId: msg.requestId,
|
|
1146
|
-
config:
|
|
1443
|
+
config: this.redactDaemonConfig(next),
|
|
1147
1444
|
},
|
|
1148
1445
|
});
|
|
1149
1446
|
break;
|
|
1150
1447
|
}
|
|
1448
|
+
case "wecom_openclaw_qr_request":
|
|
1449
|
+
await this.handleWeComOpenClawQrRequest(msg.requestId, msg.poll === true);
|
|
1450
|
+
break;
|
|
1151
1451
|
case "fetch_git_forge_issues_request": {
|
|
1152
1452
|
const result = await fetchGitForgeIssues({ workspaceId: msg.workspaceId, cwd: msg.cwd }, {
|
|
1153
1453
|
configStore: this.daemonConfigStore,
|
|
@@ -1162,6 +1462,41 @@ export class Session {
|
|
|
1162
1462
|
});
|
|
1163
1463
|
break;
|
|
1164
1464
|
}
|
|
1465
|
+
case "discover_git_forge_issue_work_request": {
|
|
1466
|
+
const result = await discoverGitForgeIssueWork({ workspaceId: msg.workspaceId, cwd: msg.cwd, number: msg.number }, {
|
|
1467
|
+
configStore: this.daemonConfigStore,
|
|
1468
|
+
workspaceRegistry: this.workspaceRegistry,
|
|
1469
|
+
agentManager: this.agentManager,
|
|
1470
|
+
seaworkHome: this.seaworkHome,
|
|
1471
|
+
});
|
|
1472
|
+
this.emit({
|
|
1473
|
+
type: "discover_git_forge_issue_work_response",
|
|
1474
|
+
payload: {
|
|
1475
|
+
requestId: msg.requestId,
|
|
1476
|
+
result,
|
|
1477
|
+
},
|
|
1478
|
+
});
|
|
1479
|
+
break;
|
|
1480
|
+
}
|
|
1481
|
+
case "transition_git_forge_issue_work_request": {
|
|
1482
|
+
const result = await transitionGitForgeIssueWork({
|
|
1483
|
+
workspaceId: msg.workspaceId,
|
|
1484
|
+
cwd: msg.cwd,
|
|
1485
|
+
number: msg.number,
|
|
1486
|
+
source: msg.source,
|
|
1487
|
+
}, {
|
|
1488
|
+
configStore: this.daemonConfigStore,
|
|
1489
|
+
workspaceRegistry: this.workspaceRegistry,
|
|
1490
|
+
});
|
|
1491
|
+
this.emit({
|
|
1492
|
+
type: "transition_git_forge_issue_work_response",
|
|
1493
|
+
payload: {
|
|
1494
|
+
requestId: msg.requestId,
|
|
1495
|
+
result,
|
|
1496
|
+
},
|
|
1497
|
+
});
|
|
1498
|
+
break;
|
|
1499
|
+
}
|
|
1165
1500
|
case "dictation_stream_start":
|
|
1166
1501
|
{
|
|
1167
1502
|
const unavailable = this.resolveVoiceFeatureUnavailableContext("dictation");
|
|
@@ -1448,6 +1783,12 @@ export class Session {
|
|
|
1448
1783
|
case "schedule/resume":
|
|
1449
1784
|
await this.handleScheduleResumeRequest(msg);
|
|
1450
1785
|
break;
|
|
1786
|
+
case "schedule/update":
|
|
1787
|
+
await this.handleScheduleUpdateRequest(msg);
|
|
1788
|
+
break;
|
|
1789
|
+
case "schedule/run-now":
|
|
1790
|
+
await this.handleScheduleRunNowRequest(msg);
|
|
1791
|
+
break;
|
|
1451
1792
|
case "schedule/delete":
|
|
1452
1793
|
await this.handleScheduleDeleteRequest(msg);
|
|
1453
1794
|
break;
|
|
@@ -1646,6 +1987,7 @@ export class Session {
|
|
|
1646
1987
|
focusedAgentId: this.clientActivity?.focusedAgentId,
|
|
1647
1988
|
}),
|
|
1648
1989
|
getWsMessageRing: () => this.getBugReportWsMessageRing(),
|
|
1990
|
+
getRecentTurnTraces: () => this.agentManager.getBugReportTurnTraces(),
|
|
1649
1991
|
});
|
|
1650
1992
|
this.emit(response);
|
|
1651
1993
|
}
|
|
@@ -2186,7 +2528,7 @@ export class Session {
|
|
|
2186
2528
|
/**
|
|
2187
2529
|
* Handle text message to agent (with optional image + document attachments)
|
|
2188
2530
|
*/
|
|
2189
|
-
async handleSendAgentMessage(agentId, text, messageId, images, runOptions, options, documents) {
|
|
2531
|
+
async handleSendAgentMessage(agentId, text, messageId, images, runOptions, options, documents, imageAttachments) {
|
|
2190
2532
|
this.sessionLogger.info({
|
|
2191
2533
|
agentId,
|
|
2192
2534
|
textPreview: text.substring(0, 50),
|
|
@@ -2195,7 +2537,14 @@ export class Session {
|
|
|
2195
2537
|
}, `Sending text to agent ${agentId}${images && images.length > 0 ? ` with ${images.length} image attachment(s)` : ""}${documents && documents.length > 0 ? ` with ${documents.length} document attachment(s)` : ""}`);
|
|
2196
2538
|
await this.unarchiveAgentState(agentId);
|
|
2197
2539
|
try {
|
|
2198
|
-
|
|
2540
|
+
if (options?.skipAgentLoad) {
|
|
2541
|
+
if (!this.agentManager.getAgent(agentId)) {
|
|
2542
|
+
throw new Error(`Agent not found: ${agentId}`);
|
|
2543
|
+
}
|
|
2544
|
+
}
|
|
2545
|
+
else {
|
|
2546
|
+
await this.ensureAgentLoaded(agentId);
|
|
2547
|
+
}
|
|
2199
2548
|
}
|
|
2200
2549
|
catch (error) {
|
|
2201
2550
|
this.handleAgentRunError(agentId, error, "Failed to initialize agent before sending prompt");
|
|
@@ -2207,12 +2556,26 @@ export class Session {
|
|
|
2207
2556
|
try {
|
|
2208
2557
|
this.agentManager.recordUserMessage(agentId, text, {
|
|
2209
2558
|
messageId,
|
|
2559
|
+
images: imageAttachments,
|
|
2210
2560
|
emitState: false,
|
|
2211
2561
|
});
|
|
2212
2562
|
}
|
|
2213
2563
|
catch (error) {
|
|
2214
2564
|
this.sessionLogger.error({ err: error, agentId }, `Failed to record user message for agent ${agentId}`);
|
|
2215
2565
|
}
|
|
2566
|
+
// Out-of-band slash commands (e.g. /goal) are handled as a side effect
|
|
2567
|
+
// without allocating a turn. Spoken input is never treated as a command.
|
|
2568
|
+
if (!options?.spokenInput) {
|
|
2569
|
+
const oob = await this.agentManager.tryRunOutOfBand(agentId, text);
|
|
2570
|
+
if (oob) {
|
|
2571
|
+
await this.agentManager.appendTimelineItem(agentId, {
|
|
2572
|
+
type: "assistant_message",
|
|
2573
|
+
text: oob.response,
|
|
2574
|
+
});
|
|
2575
|
+
this.agentManager.emitAgentState(agentId);
|
|
2576
|
+
return { ok: true };
|
|
2577
|
+
}
|
|
2578
|
+
}
|
|
2216
2579
|
const promptText = options?.spokenInput ? wrapSpokenInput(text) : text;
|
|
2217
2580
|
const prompt = this.buildAgentPrompt(promptText, images, documents);
|
|
2218
2581
|
return this.startAgentStream(agentId, prompt, runOptions);
|
|
@@ -2221,7 +2584,7 @@ export class Session {
|
|
|
2221
2584
|
* Handle create agent request
|
|
2222
2585
|
*/
|
|
2223
2586
|
async handleCreateAgentRequest(msg) {
|
|
2224
|
-
const { config, worktreeName, requestId, initialPrompt, clientMessageId, outputSchema, git, images, documents, labels, } = msg;
|
|
2587
|
+
const { config, worktreeName, requestId, initialPrompt, clientMessageId, outputSchema, git, images, imageAttachments, documents, labels, } = msg;
|
|
2225
2588
|
this.sessionLogger.info({ cwd: config.cwd, provider: config.provider, worktreeName }, `Creating agent in ${config.cwd} (${config.provider})${worktreeName ? ` with worktree ${worktreeName}` : ""}`);
|
|
2226
2589
|
try {
|
|
2227
2590
|
const trimmedPrompt = initialPrompt?.trim();
|
|
@@ -2250,7 +2613,7 @@ export class Session {
|
|
|
2250
2613
|
seaworkHome: this.seaworkHome,
|
|
2251
2614
|
logger: this.sessionLogger,
|
|
2252
2615
|
});
|
|
2253
|
-
const started = await this.handleSendAgentMessage(snapshot.id, trimmedPrompt, resolveClientMessageId(clientMessageId), images, outputSchema ? { outputSchema } : undefined,
|
|
2616
|
+
const started = await this.handleSendAgentMessage(snapshot.id, trimmedPrompt, resolveClientMessageId(clientMessageId), images, outputSchema ? { outputSchema } : undefined, { skipAgentLoad: true }, documents, imageAttachments);
|
|
2254
2617
|
if (!started.ok) {
|
|
2255
2618
|
throw new Error(started.error);
|
|
2256
2619
|
}
|
|
@@ -2428,6 +2791,7 @@ export class Session {
|
|
|
2428
2791
|
const sessions = await this.agentManager.listPersistedAgents({
|
|
2429
2792
|
...(provider ? { provider } : {}),
|
|
2430
2793
|
...(fetchLimit !== undefined ? { limit: fetchLimit } : {}),
|
|
2794
|
+
...(includeTimeline ? { includeTimeline: true } : {}),
|
|
2431
2795
|
});
|
|
2432
2796
|
// Only claim sessions that are currently live — archived Seawork records
|
|
2433
2797
|
// should reappear in the Resume list so the user can pick them back up
|
|
@@ -2552,34 +2916,99 @@ export class Session {
|
|
|
2552
2916
|
}, config, gitOptions, legacyWorktreeName, _labels);
|
|
2553
2917
|
}
|
|
2554
2918
|
async handleListProviderModelsRequest(msg) {
|
|
2919
|
+
const cwd = msg.cwd ? expandTilde(msg.cwd) : undefined;
|
|
2555
2920
|
const fetchedAt = new Date().toISOString();
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
});
|
|
2921
|
+
const providerDefinition = this.providerRegistry[msg.provider];
|
|
2922
|
+
const manager = this.providerSnapshotManager;
|
|
2923
|
+
if (!providerDefinition) {
|
|
2560
2924
|
this.emit({
|
|
2561
2925
|
type: "list_provider_models_response",
|
|
2562
2926
|
payload: {
|
|
2563
2927
|
provider: msg.provider,
|
|
2564
|
-
models,
|
|
2565
|
-
error:
|
|
2928
|
+
models: [],
|
|
2929
|
+
error: `Unknown provider: ${msg.provider}`,
|
|
2566
2930
|
fetchedAt,
|
|
2567
2931
|
requestId: msg.requestId,
|
|
2568
2932
|
},
|
|
2569
2933
|
});
|
|
2934
|
+
return;
|
|
2570
2935
|
}
|
|
2571
|
-
|
|
2572
|
-
|
|
2936
|
+
if (!manager) {
|
|
2937
|
+
try {
|
|
2938
|
+
const models = await providerDefinition.fetchModels({ cwd });
|
|
2939
|
+
this.emit({
|
|
2940
|
+
type: "list_provider_models_response",
|
|
2941
|
+
payload: {
|
|
2942
|
+
provider: msg.provider,
|
|
2943
|
+
models,
|
|
2944
|
+
error: null,
|
|
2945
|
+
fetchedAt,
|
|
2946
|
+
requestId: msg.requestId,
|
|
2947
|
+
},
|
|
2948
|
+
});
|
|
2949
|
+
}
|
|
2950
|
+
catch (error) {
|
|
2951
|
+
this.sessionLogger.error({ err: error, provider: msg.provider }, `Failed to list models for ${msg.provider}`);
|
|
2952
|
+
this.emit({
|
|
2953
|
+
type: "list_provider_models_response",
|
|
2954
|
+
payload: {
|
|
2955
|
+
provider: msg.provider,
|
|
2956
|
+
models: [],
|
|
2957
|
+
error: error?.message ?? String(error),
|
|
2958
|
+
fetchedAt,
|
|
2959
|
+
requestId: msg.requestId,
|
|
2960
|
+
},
|
|
2961
|
+
});
|
|
2962
|
+
}
|
|
2963
|
+
return;
|
|
2964
|
+
}
|
|
2965
|
+
// Route through the snapshot manager so simultaneous calls dedupe through
|
|
2966
|
+
// the in-flight warmup and cached entries are served without re-spawning.
|
|
2967
|
+
const findEntry = () => manager.getSnapshot(cwd).find((candidate) => candidate.provider === msg.provider);
|
|
2968
|
+
let entry = findEntry();
|
|
2969
|
+
if (!entry || entry.status === "loading") {
|
|
2970
|
+
await manager.ensureSnapshot(cwd);
|
|
2971
|
+
entry = findEntry();
|
|
2972
|
+
}
|
|
2973
|
+
if (!entry) {
|
|
2573
2974
|
this.emit({
|
|
2574
2975
|
type: "list_provider_models_response",
|
|
2575
2976
|
payload: {
|
|
2576
2977
|
provider: msg.provider,
|
|
2577
|
-
|
|
2978
|
+
models: [],
|
|
2979
|
+
error: `Unknown provider: ${msg.provider}`,
|
|
2578
2980
|
fetchedAt,
|
|
2579
2981
|
requestId: msg.requestId,
|
|
2580
2982
|
},
|
|
2581
2983
|
});
|
|
2984
|
+
return;
|
|
2985
|
+
}
|
|
2986
|
+
if (entry.status === "ready") {
|
|
2987
|
+
this.emit({
|
|
2988
|
+
type: "list_provider_models_response",
|
|
2989
|
+
payload: {
|
|
2990
|
+
provider: msg.provider,
|
|
2991
|
+
models: entry.models ?? [],
|
|
2992
|
+
error: null,
|
|
2993
|
+
fetchedAt: entry.fetchedAt ?? fetchedAt,
|
|
2994
|
+
requestId: msg.requestId,
|
|
2995
|
+
},
|
|
2996
|
+
});
|
|
2997
|
+
return;
|
|
2582
2998
|
}
|
|
2999
|
+
const errorMessage = entry.status === "error"
|
|
3000
|
+
? (entry.error ?? `Failed to list models for ${msg.provider}`)
|
|
3001
|
+
: `Provider ${msg.provider} is not available`;
|
|
3002
|
+
this.emit({
|
|
3003
|
+
type: "list_provider_models_response",
|
|
3004
|
+
payload: {
|
|
3005
|
+
provider: msg.provider,
|
|
3006
|
+
models: [],
|
|
3007
|
+
error: errorMessage,
|
|
3008
|
+
fetchedAt,
|
|
3009
|
+
requestId: msg.requestId,
|
|
3010
|
+
},
|
|
3011
|
+
});
|
|
2583
3012
|
}
|
|
2584
3013
|
async handleListProviderModesRequest(msg) {
|
|
2585
3014
|
const fetchedAt = new Date().toISOString();
|
|
@@ -2621,6 +3050,12 @@ export class Session {
|
|
|
2621
3050
|
...(draftConfig.featureValues ? { featureValues: draftConfig.featureValues } : {}),
|
|
2622
3051
|
};
|
|
2623
3052
|
}
|
|
3053
|
+
async filterLibraryCommands(commands, config) {
|
|
3054
|
+
if (!this.library || (config.provider !== "claude" && config.provider !== "codex")) {
|
|
3055
|
+
return commands;
|
|
3056
|
+
}
|
|
3057
|
+
return filterLibrarySkillCommands(commands, await this.library.load(), config.provider, config.perAgentDisabled);
|
|
3058
|
+
}
|
|
2624
3059
|
async handleListProviderFeaturesRequest(msg) {
|
|
2625
3060
|
const fetchedAt = new Date().toISOString();
|
|
2626
3061
|
try {
|
|
@@ -2710,6 +3145,94 @@ export class Session {
|
|
|
2710
3145
|
},
|
|
2711
3146
|
});
|
|
2712
3147
|
}
|
|
3148
|
+
redactDaemonConfig(config) {
|
|
3149
|
+
const redacted = redactProviderEnv(redactGitForgeTokens(config));
|
|
3150
|
+
const wecomOpenClaw = redacted.integrations?.wecomOpenClaw;
|
|
3151
|
+
if (!wecomOpenClaw?.secret) {
|
|
3152
|
+
return redacted;
|
|
3153
|
+
}
|
|
3154
|
+
return {
|
|
3155
|
+
...redacted,
|
|
3156
|
+
integrations: {
|
|
3157
|
+
...redacted.integrations,
|
|
3158
|
+
wecomOpenClaw: {
|
|
3159
|
+
...wecomOpenClaw,
|
|
3160
|
+
secret: "<configured>",
|
|
3161
|
+
},
|
|
3162
|
+
},
|
|
3163
|
+
};
|
|
3164
|
+
}
|
|
3165
|
+
async handleWeComOpenClawQrRequest(requestId, poll) {
|
|
3166
|
+
try {
|
|
3167
|
+
if (!this.wecomOpenClawQr || !poll) {
|
|
3168
|
+
this.wecomOpenClawQr = await fetchWeComOpenClawQrCode();
|
|
3169
|
+
}
|
|
3170
|
+
const qr = this.wecomOpenClawQr;
|
|
3171
|
+
const credentials = await queryWeComOpenClawQrResult(qr.scode);
|
|
3172
|
+
if (!credentials) {
|
|
3173
|
+
this.emit({
|
|
3174
|
+
type: "wecom_openclaw_qr_response",
|
|
3175
|
+
payload: {
|
|
3176
|
+
requestId,
|
|
3177
|
+
status: "pending",
|
|
3178
|
+
scode: qr.scode,
|
|
3179
|
+
authUrl: qr.authUrl,
|
|
3180
|
+
qrPageUrl: qr.qrPageUrl,
|
|
3181
|
+
config: null,
|
|
3182
|
+
error: null,
|
|
3183
|
+
},
|
|
3184
|
+
});
|
|
3185
|
+
return;
|
|
3186
|
+
}
|
|
3187
|
+
const currentWeCom = this.daemonConfigStore.get().integrations?.wecomOpenClaw ?? {};
|
|
3188
|
+
const allowUsers = mergeUniqueNonEmptyStrings(currentWeCom.allowUsers, credentials.authorizedUserId ? [credentials.authorizedUserId] : []);
|
|
3189
|
+
const hasAllowlist = allowUsers.length > 0 || normalizeNonEmptyStrings(currentWeCom.allowChats).length > 0;
|
|
3190
|
+
const pendingAllowFirstUser = !hasAllowlist;
|
|
3191
|
+
const cwd = resolveWeComOpenClawAgentCwd(currentWeCom.cwd, this.seaworkHome);
|
|
3192
|
+
const next = this.daemonConfigStore.patch({
|
|
3193
|
+
integrations: {
|
|
3194
|
+
wecomOpenClaw: {
|
|
3195
|
+
...currentWeCom,
|
|
3196
|
+
enabled: hasAllowlist || pendingAllowFirstUser,
|
|
3197
|
+
botId: credentials.botId,
|
|
3198
|
+
secret: credentials.secret,
|
|
3199
|
+
cwd,
|
|
3200
|
+
provider: currentWeCom.provider ?? DEFAULT_AGENT_PROVIDER,
|
|
3201
|
+
agentMode: currentWeCom.agentMode ?? "new",
|
|
3202
|
+
allowUsers,
|
|
3203
|
+
pendingAllowFirstUser,
|
|
3204
|
+
},
|
|
3205
|
+
},
|
|
3206
|
+
});
|
|
3207
|
+
this.wecomOpenClawQr = null;
|
|
3208
|
+
this.emit({
|
|
3209
|
+
type: "wecom_openclaw_qr_response",
|
|
3210
|
+
payload: {
|
|
3211
|
+
requestId,
|
|
3212
|
+
status: "success",
|
|
3213
|
+
scode: qr.scode,
|
|
3214
|
+
authUrl: qr.authUrl,
|
|
3215
|
+
qrPageUrl: qr.qrPageUrl,
|
|
3216
|
+
config: this.redactDaemonConfig(next),
|
|
3217
|
+
error: null,
|
|
3218
|
+
},
|
|
3219
|
+
});
|
|
3220
|
+
}
|
|
3221
|
+
catch (error) {
|
|
3222
|
+
this.emit({
|
|
3223
|
+
type: "wecom_openclaw_qr_response",
|
|
3224
|
+
payload: {
|
|
3225
|
+
requestId,
|
|
3226
|
+
status: "error",
|
|
3227
|
+
scode: this.wecomOpenClawQr?.scode ?? null,
|
|
3228
|
+
authUrl: this.wecomOpenClawQr?.authUrl ?? null,
|
|
3229
|
+
qrPageUrl: this.wecomOpenClawQr?.qrPageUrl ?? null,
|
|
3230
|
+
config: null,
|
|
3231
|
+
error: formatUnknownError(error),
|
|
3232
|
+
},
|
|
3233
|
+
});
|
|
3234
|
+
}
|
|
3235
|
+
}
|
|
2713
3236
|
async handleRefreshProvidersSnapshotRequest(msg) {
|
|
2714
3237
|
this.providerSnapshotManager?.refresh(msg.cwd ? expandTilde(msg.cwd) : undefined);
|
|
2715
3238
|
this.emit({
|
|
@@ -2877,22 +3400,16 @@ export class Session {
|
|
|
2877
3400
|
}
|
|
2878
3401
|
}
|
|
2879
3402
|
async ensureCleanWorkingTree(cwd) {
|
|
2880
|
-
|
|
2881
|
-
if (dirty) {
|
|
2882
|
-
throw new Error("Working directory has uncommitted changes. Commit or stash before switching branches.");
|
|
2883
|
-
}
|
|
2884
|
-
}
|
|
2885
|
-
async isWorkingTreeDirty(cwd) {
|
|
3403
|
+
let dirty;
|
|
2886
3404
|
try {
|
|
2887
|
-
|
|
2888
|
-
cwd,
|
|
2889
|
-
env: READ_ONLY_GIT_ENV,
|
|
2890
|
-
});
|
|
2891
|
-
return stdout.trim().length > 0;
|
|
3405
|
+
dirty = await hasWorkingTreeChanges(cwd);
|
|
2892
3406
|
}
|
|
2893
3407
|
catch (error) {
|
|
2894
3408
|
throw new Error(`Unable to inspect git status for ${cwd}: ${error.message}`);
|
|
2895
3409
|
}
|
|
3410
|
+
if (dirty) {
|
|
3411
|
+
throw new Error("Working directory has uncommitted changes. Commit or stash before switching branches.");
|
|
3412
|
+
}
|
|
2896
3413
|
}
|
|
2897
3414
|
async checkoutExistingBranch(cwd, branch) {
|
|
2898
3415
|
this.assertSafeGitRef(branch, "branch");
|
|
@@ -3100,6 +3617,7 @@ export class Session {
|
|
|
3100
3617
|
lastActivityAt: new Date(msg.lastActivityAt),
|
|
3101
3618
|
appVisible: msg.appVisible,
|
|
3102
3619
|
appVisibilityChangedAt,
|
|
3620
|
+
desktopRuntime: msg.desktopRuntime ?? null,
|
|
3103
3621
|
};
|
|
3104
3622
|
}
|
|
3105
3623
|
/**
|
|
@@ -3119,7 +3637,8 @@ export class Session {
|
|
|
3119
3637
|
const agents = this.agentManager.listAgents();
|
|
3120
3638
|
const agent = agents.find((a) => a.id === agentId);
|
|
3121
3639
|
if (agent?.session?.listCommands) {
|
|
3122
|
-
|
|
3640
|
+
await this.agentManager.refreshLibrarySkillPolicy(agent.id);
|
|
3641
|
+
const commands = await this.filterLibraryCommands(await agent.session.listCommands(), agent.config);
|
|
3123
3642
|
this.emit({
|
|
3124
3643
|
type: "list_commands_response",
|
|
3125
3644
|
payload: {
|
|
@@ -3133,7 +3652,7 @@ export class Session {
|
|
|
3133
3652
|
}
|
|
3134
3653
|
if (!agent && draftConfig) {
|
|
3135
3654
|
const sessionConfig = this.buildDraftAgentSessionConfig(draftConfig);
|
|
3136
|
-
const commands = await this.agentManager.listDraftCommands(sessionConfig);
|
|
3655
|
+
const commands = await this.filterLibraryCommands(await this.agentManager.listDraftCommands(sessionConfig), sessionConfig);
|
|
3137
3656
|
this.emit({
|
|
3138
3657
|
type: "list_commands_response",
|
|
3139
3658
|
payload: {
|
|
@@ -3479,6 +3998,8 @@ export class Session {
|
|
|
3479
3998
|
try {
|
|
3480
3999
|
await this.checkoutExistingBranch(cwd, branch);
|
|
3481
4000
|
this.checkoutDiffManager.scheduleRefreshForCwd(cwd);
|
|
4001
|
+
invalidateCheckoutShortstatCache(cwd);
|
|
4002
|
+
void this.workspaceGitService.refresh(cwd, { priority: "high" });
|
|
3482
4003
|
// Push a workspace_update immediately so the sidebar/header reflect
|
|
3483
4004
|
// the new branch name without waiting for the background git watcher.
|
|
3484
4005
|
await this.emitWorkspaceUpdateForCwd(cwd);
|
|
@@ -3514,7 +4035,9 @@ export class Session {
|
|
|
3514
4035
|
? `${Session.SEAWORK_STASH_PREFIX} ${branchLabel}`
|
|
3515
4036
|
: `${Session.SEAWORK_STASH_PREFIX} unnamed`;
|
|
3516
4037
|
await execFileAsync("git", ["stash", "push", "--include-untracked", "-m", message], { cwd });
|
|
4038
|
+
invalidateCheckoutShortstatCache(cwd);
|
|
3517
4039
|
this.checkoutDiffManager.scheduleRefreshForCwd(cwd);
|
|
4040
|
+
void this.workspaceGitService.refresh(cwd, { priority: "high" });
|
|
3518
4041
|
this.emit({
|
|
3519
4042
|
type: "stash_save_response",
|
|
3520
4043
|
payload: { cwd, success: true, error: null, requestId },
|
|
@@ -3531,7 +4054,9 @@ export class Session {
|
|
|
3531
4054
|
const { cwd, stashIndex, requestId } = msg;
|
|
3532
4055
|
try {
|
|
3533
4056
|
await execFileAsync("git", ["stash", "pop", `stash@{${stashIndex}}`], { cwd });
|
|
4057
|
+
invalidateCheckoutShortstatCache(cwd);
|
|
3534
4058
|
this.checkoutDiffManager.scheduleRefreshForCwd(cwd);
|
|
4059
|
+
void this.workspaceGitService.refresh(cwd, { priority: "high" });
|
|
3535
4060
|
this.emit({
|
|
3536
4061
|
type: "stash_pop_response",
|
|
3537
4062
|
payload: { cwd, success: true, error: null, requestId },
|
|
@@ -3599,7 +4124,9 @@ export class Session {
|
|
|
3599
4124
|
message,
|
|
3600
4125
|
addAll: msg.addAll ?? true,
|
|
3601
4126
|
});
|
|
4127
|
+
invalidateCheckoutShortstatCache(cwd);
|
|
3602
4128
|
this.checkoutDiffManager.scheduleRefreshForCwd(cwd);
|
|
4129
|
+
void this.workspaceGitService.refresh(cwd, { priority: "high" });
|
|
3603
4130
|
this.emit({
|
|
3604
4131
|
type: "checkout_commit_response",
|
|
3605
4132
|
payload: {
|
|
@@ -3643,11 +4170,7 @@ export class Session {
|
|
|
3643
4170
|
}
|
|
3644
4171
|
}
|
|
3645
4172
|
if (msg.requireCleanTarget) {
|
|
3646
|
-
|
|
3647
|
-
cwd,
|
|
3648
|
-
env: READ_ONLY_GIT_ENV,
|
|
3649
|
-
});
|
|
3650
|
-
if (stdout.trim().length > 0) {
|
|
4173
|
+
if (await hasWorkingTreeChanges(cwd)) {
|
|
3651
4174
|
throw new Error("Working directory has uncommitted changes.");
|
|
3652
4175
|
}
|
|
3653
4176
|
}
|
|
@@ -3658,11 +4181,13 @@ export class Session {
|
|
|
3658
4181
|
if (baseRef.startsWith("origin/")) {
|
|
3659
4182
|
baseRef = baseRef.slice("origin/".length);
|
|
3660
4183
|
}
|
|
3661
|
-
await mergeToBase(cwd, {
|
|
4184
|
+
const mutatedCwd = await mergeToBase(cwd, {
|
|
3662
4185
|
baseRef,
|
|
3663
4186
|
mode: msg.strategy === "squash" ? "squash" : "merge",
|
|
3664
4187
|
}, { seaworkHome: this.seaworkHome });
|
|
3665
4188
|
this.checkoutDiffManager.scheduleRefreshForCwd(cwd);
|
|
4189
|
+
invalidateCheckoutShortstatCache(mutatedCwd);
|
|
4190
|
+
void this.workspaceGitService.refresh(mutatedCwd, { priority: "high" });
|
|
3666
4191
|
this.emit({
|
|
3667
4192
|
type: "checkout_merge_response",
|
|
3668
4193
|
payload: {
|
|
@@ -3689,11 +4214,7 @@ export class Session {
|
|
|
3689
4214
|
const { cwd, requestId } = msg;
|
|
3690
4215
|
try {
|
|
3691
4216
|
if (msg.requireCleanTarget ?? true) {
|
|
3692
|
-
|
|
3693
|
-
cwd,
|
|
3694
|
-
env: READ_ONLY_GIT_ENV,
|
|
3695
|
-
});
|
|
3696
|
-
if (stdout.trim().length > 0) {
|
|
4217
|
+
if (await hasWorkingTreeChanges(cwd)) {
|
|
3697
4218
|
throw new Error("Working directory has uncommitted changes.");
|
|
3698
4219
|
}
|
|
3699
4220
|
}
|
|
@@ -3702,6 +4223,8 @@ export class Session {
|
|
|
3702
4223
|
requireCleanTarget: msg.requireCleanTarget ?? true,
|
|
3703
4224
|
});
|
|
3704
4225
|
this.checkoutDiffManager.scheduleRefreshForCwd(cwd);
|
|
4226
|
+
invalidateCheckoutShortstatCache(cwd);
|
|
4227
|
+
void this.workspaceGitService.refresh(cwd, { priority: "high" });
|
|
3705
4228
|
this.emit({
|
|
3706
4229
|
type: "checkout_merge_from_base_response",
|
|
3707
4230
|
payload: {
|
|
@@ -3729,6 +4252,8 @@ export class Session {
|
|
|
3729
4252
|
try {
|
|
3730
4253
|
await pullCurrentBranch(cwd);
|
|
3731
4254
|
this.checkoutDiffManager.scheduleRefreshForCwd(cwd);
|
|
4255
|
+
invalidateCheckoutShortstatCache(cwd);
|
|
4256
|
+
void this.workspaceGitService.refresh(cwd, { priority: "high" });
|
|
3732
4257
|
this.emit({
|
|
3733
4258
|
type: "checkout_pull_response",
|
|
3734
4259
|
payload: {
|
|
@@ -3755,6 +4280,8 @@ export class Session {
|
|
|
3755
4280
|
const { cwd, requestId } = msg;
|
|
3756
4281
|
try {
|
|
3757
4282
|
await pushCurrentBranch(cwd);
|
|
4283
|
+
invalidateCheckoutShortstatCache(cwd);
|
|
4284
|
+
void this.workspaceGitService.refresh(cwd, { priority: "high" });
|
|
3758
4285
|
this.emit({
|
|
3759
4286
|
type: "checkout_push_response",
|
|
3760
4287
|
payload: {
|
|
@@ -3794,6 +4321,8 @@ export class Session {
|
|
|
3794
4321
|
body,
|
|
3795
4322
|
base: msg.baseRef,
|
|
3796
4323
|
});
|
|
4324
|
+
invalidateCheckoutShortstatCache(cwd);
|
|
4325
|
+
void this.workspaceGitService.refresh(cwd, { priority: "high" });
|
|
3797
4326
|
this.emit({
|
|
3798
4327
|
type: "checkout_pr_create_response",
|
|
3799
4328
|
payload: {
|
|
@@ -3938,7 +4467,17 @@ export class Session {
|
|
|
3938
4467
|
}
|
|
3939
4468
|
}
|
|
3940
4469
|
catch (error) {
|
|
3941
|
-
|
|
4470
|
+
// Workspace on a removable drive that's been ejected — log at WARN so
|
|
4471
|
+
// a power user with a flaky external disk doesn't fill daemon.log with
|
|
4472
|
+
// ERROR-level entries for an expected condition. See issue #662 / #632.
|
|
4473
|
+
const code = error?.code;
|
|
4474
|
+
const isMissingPath = code === "ENOENT";
|
|
4475
|
+
if (isMissingPath) {
|
|
4476
|
+
this.sessionLogger.warn({ err: error, cwd, path: requestedPath }, `Workspace offline for file explorer request: ${cwd}`);
|
|
4477
|
+
}
|
|
4478
|
+
else {
|
|
4479
|
+
this.sessionLogger.error({ err: error, cwd, path: requestedPath }, `Failed to fulfill file explorer request for workspace ${cwd}`);
|
|
4480
|
+
}
|
|
3942
4481
|
this.emit({
|
|
3943
4482
|
type: "file_explorer_response",
|
|
3944
4483
|
payload: {
|
|
@@ -4490,7 +5029,8 @@ export class Session {
|
|
|
4490
5029
|
placementByCwd.set(cwd, placementPromise);
|
|
4491
5030
|
return placementPromise;
|
|
4492
5031
|
};
|
|
4493
|
-
|
|
5032
|
+
const includeArchived = filter?.includeArchived ?? false;
|
|
5033
|
+
let candidates = includeArchived ? [...agents] : agents.filter((a) => !a.archivedAt);
|
|
4494
5034
|
candidates.sort((left, right) => this.compareFetchAgentsAgents(left, right, sort));
|
|
4495
5035
|
const cursorToken = request.page?.cursor;
|
|
4496
5036
|
if (cursorToken) {
|
|
@@ -4552,6 +5092,19 @@ export class Session {
|
|
|
4552
5092
|
}
|
|
4553
5093
|
async describeWorkspaceRecord(workspace, projectRecord) {
|
|
4554
5094
|
const resolvedProjectRecord = projectRecord ?? (await this.projectRegistry.get(workspace.projectId));
|
|
5095
|
+
let diffStat = null;
|
|
5096
|
+
const cachedShortstat = getCachedCheckoutShortstat(workspace.cwd);
|
|
5097
|
+
if (cachedShortstat !== undefined) {
|
|
5098
|
+
diffStat = cachedShortstat;
|
|
5099
|
+
}
|
|
5100
|
+
else {
|
|
5101
|
+
const cwd = workspace.cwd;
|
|
5102
|
+
warmCheckoutShortstatInBackground(cwd, undefined, () => {
|
|
5103
|
+
this.emitWorkspaceUpdateForCwd(cwd).catch((error) => {
|
|
5104
|
+
this.sessionLogger.warn({ error, cwd }, "Failed to emit workspace update after shortstat warm");
|
|
5105
|
+
});
|
|
5106
|
+
});
|
|
5107
|
+
}
|
|
4555
5108
|
return {
|
|
4556
5109
|
id: workspace.workspaceId,
|
|
4557
5110
|
projectId: workspace.projectId,
|
|
@@ -4562,7 +5115,7 @@ export class Session {
|
|
|
4562
5115
|
name: workspace.displayName,
|
|
4563
5116
|
status: "done",
|
|
4564
5117
|
activityAt: null,
|
|
4565
|
-
diffStat
|
|
5118
|
+
diffStat,
|
|
4566
5119
|
};
|
|
4567
5120
|
}
|
|
4568
5121
|
buildWorkspaceGitRuntimePayload(snapshot) {
|
|
@@ -4605,7 +5158,10 @@ export class Session {
|
|
|
4605
5158
|
return {
|
|
4606
5159
|
...base,
|
|
4607
5160
|
name: displayName,
|
|
4608
|
-
|
|
5161
|
+
// Prefer the live git-runtime snapshot, but fall back to the shortstat
|
|
5162
|
+
// cache that describeWorkspaceRecord warmed so the background update is
|
|
5163
|
+
// not discarded when the snapshot has no diffStat yet.
|
|
5164
|
+
diffStat: snapshot?.git.diffStat ?? base.diffStat,
|
|
4609
5165
|
gitRuntime: snapshot ? this.buildWorkspaceGitRuntimePayload(snapshot) : undefined,
|
|
4610
5166
|
githubRuntime: snapshot ? this.buildWorkspaceGitHubRuntimePayload(snapshot) : undefined,
|
|
4611
5167
|
};
|
|
@@ -4630,17 +5186,17 @@ export class Session {
|
|
|
4630
5186
|
const workspaceIds = options.workspaceIds
|
|
4631
5187
|
? new Set(Array.from(options.workspaceIds, (workspaceId) => normalizePersistedWorkspaceId(workspaceId)))
|
|
4632
5188
|
: null;
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
5189
|
+
const filteredRecords = workspaceIds
|
|
5190
|
+
? activeRecords.filter((workspace) => workspaceIds.has(workspace.workspaceId))
|
|
5191
|
+
: activeRecords;
|
|
5192
|
+
await Promise.all(filteredRecords.map(async (workspace) => {
|
|
4637
5193
|
const projectRecord = activeProjects.get(workspace.projectId) ?? null;
|
|
4638
5194
|
descriptorsByWorkspaceId.set(workspace.workspaceId, await this.buildWorkspaceDescriptor({
|
|
4639
5195
|
workspace,
|
|
4640
5196
|
projectRecord,
|
|
4641
5197
|
includeGitData: options.includeGitData,
|
|
4642
5198
|
}));
|
|
4643
|
-
}
|
|
5199
|
+
}));
|
|
4644
5200
|
for (const agent of agents) {
|
|
4645
5201
|
if (agent.archivedAt) {
|
|
4646
5202
|
continue;
|
|
@@ -4891,7 +5447,6 @@ export class Session {
|
|
|
4891
5447
|
buildPersistedWorkspaceRecord: (input) => this.buildPersistedWorkspaceRecord(input),
|
|
4892
5448
|
buildProjectPlacement: (cwd) => this.buildProjectPlacement(cwd),
|
|
4893
5449
|
projectRegistry: this.projectRegistry,
|
|
4894
|
-
syncWorkspaceGitWatchTarget: (cwd, syncOptions) => this.syncWorkspaceGitWatchTarget(cwd, syncOptions),
|
|
4895
5450
|
workspaceRegistry: this.workspaceRegistry,
|
|
4896
5451
|
archiveProjectRecordIfEmpty: (projectId, archivedAt) => this.archiveProjectRecordIfEmpty(projectId, archivedAt),
|
|
4897
5452
|
}, options);
|
|
@@ -4910,6 +5465,46 @@ export class Session {
|
|
|
4910
5465
|
await this.projectRegistry.archive(existing.projectId, nextArchivedAt);
|
|
4911
5466
|
}
|
|
4912
5467
|
}
|
|
5468
|
+
async findWorkspaceRecordForRequest(workspaceId) {
|
|
5469
|
+
const normalizedWorkspaceId = normalizePersistedWorkspaceId(workspaceId);
|
|
5470
|
+
const normalized = await this.workspaceRegistry.get(normalizedWorkspaceId);
|
|
5471
|
+
if (normalized) {
|
|
5472
|
+
return normalized;
|
|
5473
|
+
}
|
|
5474
|
+
if (normalizedWorkspaceId !== workspaceId) {
|
|
5475
|
+
const raw = await this.workspaceRegistry.get(workspaceId);
|
|
5476
|
+
if (raw) {
|
|
5477
|
+
return raw;
|
|
5478
|
+
}
|
|
5479
|
+
}
|
|
5480
|
+
const lookupKey = normalizeWorkspaceLookupKey(workspaceId);
|
|
5481
|
+
const records = await this.workspaceRegistry.list();
|
|
5482
|
+
return (records.find((record) => normalizeWorkspaceLookupKey(record.workspaceId) === lookupKey) ??
|
|
5483
|
+
null);
|
|
5484
|
+
}
|
|
5485
|
+
emitWorkspaceRemoveForId(workspaceId) {
|
|
5486
|
+
const subscription = this.workspaceUpdatesSubscription;
|
|
5487
|
+
const id = workspaceId.trim();
|
|
5488
|
+
if (!subscription || !id) {
|
|
5489
|
+
return;
|
|
5490
|
+
}
|
|
5491
|
+
this.bufferOrEmitWorkspaceUpdate(subscription, {
|
|
5492
|
+
kind: "remove",
|
|
5493
|
+
id,
|
|
5494
|
+
});
|
|
5495
|
+
}
|
|
5496
|
+
emitWorkspaceRemoveAliasesForRequest(requestedWorkspaceId, persistedWorkspaceId) {
|
|
5497
|
+
this.emitWorkspaceRemoveForId(persistedWorkspaceId);
|
|
5498
|
+
const requested = requestedWorkspaceId.trim();
|
|
5499
|
+
if (!requested || requested === persistedWorkspaceId) {
|
|
5500
|
+
return;
|
|
5501
|
+
}
|
|
5502
|
+
if (normalizeWorkspaceLookupKey(requestedWorkspaceId) !==
|
|
5503
|
+
normalizeWorkspaceLookupKey(persistedWorkspaceId)) {
|
|
5504
|
+
return;
|
|
5505
|
+
}
|
|
5506
|
+
this.emitWorkspaceRemoveForId(requested);
|
|
5507
|
+
}
|
|
4913
5508
|
async reconcileAndEmitWorkspaceUpdates() {
|
|
4914
5509
|
if (!this.workspaceUpdatesSubscription) {
|
|
4915
5510
|
return;
|
|
@@ -5125,8 +5720,30 @@ export class Session {
|
|
|
5125
5720
|
});
|
|
5126
5721
|
}
|
|
5127
5722
|
}
|
|
5723
|
+
async resolveAvailableEditorTargets() {
|
|
5724
|
+
return listAvailableEditorTargets();
|
|
5725
|
+
}
|
|
5726
|
+
async getMemoizedAvailableEditorTargets() {
|
|
5727
|
+
const cached = this.availableEditorTargetsCache.get(AVAILABLE_EDITOR_TARGETS_CACHE_KEY);
|
|
5728
|
+
if (cached) {
|
|
5729
|
+
return cached;
|
|
5730
|
+
}
|
|
5731
|
+
if (this.availableEditorTargetsInflight) {
|
|
5732
|
+
return this.availableEditorTargetsInflight;
|
|
5733
|
+
}
|
|
5734
|
+
const inflight = this.resolveAvailableEditorTargets()
|
|
5735
|
+
.then((editors) => {
|
|
5736
|
+
this.availableEditorTargetsCache.set(AVAILABLE_EDITOR_TARGETS_CACHE_KEY, editors);
|
|
5737
|
+
return editors;
|
|
5738
|
+
})
|
|
5739
|
+
.finally(() => {
|
|
5740
|
+
this.availableEditorTargetsInflight = null;
|
|
5741
|
+
});
|
|
5742
|
+
this.availableEditorTargetsInflight = inflight;
|
|
5743
|
+
return inflight;
|
|
5744
|
+
}
|
|
5128
5745
|
async getAvailableEditorTargets() {
|
|
5129
|
-
return this.filterEditorsForClient(await
|
|
5746
|
+
return this.filterEditorsForClient(await this.getMemoizedAvailableEditorTargets());
|
|
5130
5747
|
}
|
|
5131
5748
|
async openEditorTarget(options) {
|
|
5132
5749
|
await openInEditorTarget(options);
|
|
@@ -5194,6 +5811,7 @@ export class Session {
|
|
|
5194
5811
|
describeWorkspaceRecord: (workspace) => this.describeWorkspaceRecordWithGitData(workspace),
|
|
5195
5812
|
emit: (message) => this.emit(message),
|
|
5196
5813
|
registerPendingWorktreeWorkspace: (options) => this.registerPendingWorktreeWorkspace(options),
|
|
5814
|
+
syncWorkspaceGitWatchTarget: (cwd, syncOptions) => this.syncWorkspaceGitWatchTarget(cwd, syncOptions),
|
|
5197
5815
|
sessionLogger: this.sessionLogger,
|
|
5198
5816
|
createSeaworkWorktreeInBackground: (options) => this.createSeaworkWorktreeInBackground(options),
|
|
5199
5817
|
}, request);
|
|
@@ -5320,14 +5938,27 @@ export class Session {
|
|
|
5320
5938
|
}
|
|
5321
5939
|
async handleArchiveWorkspaceRequest(request) {
|
|
5322
5940
|
try {
|
|
5323
|
-
const existing = await this.
|
|
5324
|
-
if (!existing
|
|
5941
|
+
const existing = await this.findWorkspaceRecordForRequest(request.workspaceId);
|
|
5942
|
+
if (!existing) {
|
|
5325
5943
|
this.emit({
|
|
5326
5944
|
type: "archive_workspace_response",
|
|
5327
5945
|
payload: {
|
|
5328
5946
|
requestId: request.requestId,
|
|
5329
5947
|
workspaceId: request.workspaceId,
|
|
5330
|
-
archivedAt:
|
|
5948
|
+
archivedAt: null,
|
|
5949
|
+
error: null,
|
|
5950
|
+
},
|
|
5951
|
+
});
|
|
5952
|
+
return;
|
|
5953
|
+
}
|
|
5954
|
+
if (existing.archivedAt) {
|
|
5955
|
+
this.emitWorkspaceRemoveAliasesForRequest(request.workspaceId, existing.workspaceId);
|
|
5956
|
+
this.emit({
|
|
5957
|
+
type: "archive_workspace_response",
|
|
5958
|
+
payload: {
|
|
5959
|
+
requestId: request.requestId,
|
|
5960
|
+
workspaceId: request.workspaceId,
|
|
5961
|
+
archivedAt: existing.archivedAt,
|
|
5331
5962
|
error: null,
|
|
5332
5963
|
},
|
|
5333
5964
|
});
|
|
@@ -5337,8 +5968,8 @@ export class Session {
|
|
|
5337
5968
|
throw new Error("Use worktree archive for Seawork worktrees");
|
|
5338
5969
|
}
|
|
5339
5970
|
const archivedAt = new Date().toISOString();
|
|
5340
|
-
await this.archiveWorkspaceRecord(
|
|
5341
|
-
|
|
5971
|
+
await this.archiveWorkspaceRecord(existing.workspaceId, archivedAt);
|
|
5972
|
+
this.emitWorkspaceRemoveAliasesForRequest(request.workspaceId, existing.workspaceId);
|
|
5342
5973
|
this.emit({
|
|
5343
5974
|
type: "archive_workspace_response",
|
|
5344
5975
|
payload: {
|
|
@@ -5397,7 +6028,7 @@ export class Session {
|
|
|
5397
6028
|
const requestedLimit = msg.limit;
|
|
5398
6029
|
const limit = requestedLimit ?? (direction === "after" ? 0 : undefined);
|
|
5399
6030
|
const shouldLimitByProjectedWindow = projection === "canonical" &&
|
|
5400
|
-
direction === "tail" &&
|
|
6031
|
+
(direction === "tail" || direction === "before") &&
|
|
5401
6032
|
typeof requestedLimit === "number" &&
|
|
5402
6033
|
requestedLimit > 0;
|
|
5403
6034
|
const cursor = msg.cursor
|
|
@@ -5433,13 +6064,17 @@ export class Session {
|
|
|
5433
6064
|
});
|
|
5434
6065
|
while (timeline.hasOlder) {
|
|
5435
6066
|
const needsMoreProjectedEntries = projectedWindow.projectedEntries.length < projectedLimit;
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
const
|
|
5442
|
-
|
|
6067
|
+
// Both tail and before select the newest projected entries within the
|
|
6068
|
+
// loaded window, so a canonical-limit cut can only land at the OLDEST
|
|
6069
|
+
// end (rows[0]); the newest end abuts the cursor and is chunk-safe.
|
|
6070
|
+
const oldestLoadedRow = timeline.rows[0];
|
|
6071
|
+
const oldestSelectedRow = projectedWindow.selectedRows[0];
|
|
6072
|
+
const selectedStartsAtOldestLoadedBoundary = oldestLoadedRow != null &&
|
|
6073
|
+
oldestSelectedRow != null &&
|
|
6074
|
+
oldestSelectedRow.seq === oldestLoadedRow.seq;
|
|
6075
|
+
const oldestBoundaryIsAssistantChunk = selectedStartsAtOldestLoadedBoundary &&
|
|
6076
|
+
oldestLoadedRow.item.type === "assistant_message";
|
|
6077
|
+
if (!needsMoreProjectedEntries && !oldestBoundaryIsAssistantChunk) {
|
|
5443
6078
|
break;
|
|
5444
6079
|
}
|
|
5445
6080
|
const maxRows = Math.max(0, timeline.window.maxSeq - timeline.window.minSeq + 1);
|
|
@@ -5462,12 +6097,16 @@ export class Session {
|
|
|
5462
6097
|
});
|
|
5463
6098
|
}
|
|
5464
6099
|
const selectedRows = projectedWindow.selectedRows;
|
|
5465
|
-
entries = projectTimelineRows(selectedRows, snapshot.provider, projection
|
|
6100
|
+
entries = projectTimelineRows(selectedRows, snapshot.provider, projection, {
|
|
6101
|
+
...legacyTimelineProjectionOptions(this.appVersion),
|
|
6102
|
+
});
|
|
5466
6103
|
if (projectedWindow.minSeq !== null && projectedWindow.maxSeq !== null) {
|
|
5467
6104
|
startCursor = { epoch: timeline.epoch, seq: projectedWindow.minSeq };
|
|
5468
6105
|
endCursor = { epoch: timeline.epoch, seq: projectedWindow.maxSeq };
|
|
5469
6106
|
hasOlder = projectedWindow.minSeq > timeline.window.minSeq;
|
|
5470
|
-
|
|
6107
|
+
// For tail this is always false (the window IS the newest rows); for
|
|
6108
|
+
// before it is true whenever newer rows remain above the page.
|
|
6109
|
+
hasNewer = projectedWindow.maxSeq < timeline.window.maxSeq;
|
|
5471
6110
|
}
|
|
5472
6111
|
}
|
|
5473
6112
|
else {
|
|
@@ -5475,7 +6114,9 @@ export class Session {
|
|
|
5475
6114
|
const lastRow = timeline.rows[timeline.rows.length - 1];
|
|
5476
6115
|
startCursor = firstRow ? { epoch: timeline.epoch, seq: firstRow.seq } : null;
|
|
5477
6116
|
endCursor = lastRow ? { epoch: timeline.epoch, seq: lastRow.seq } : null;
|
|
5478
|
-
entries = projectTimelineRows(timeline.rows, snapshot.provider, projection
|
|
6117
|
+
entries = projectTimelineRows(timeline.rows, snapshot.provider, projection, {
|
|
6118
|
+
...legacyTimelineProjectionOptions(this.appVersion),
|
|
6119
|
+
});
|
|
5479
6120
|
}
|
|
5480
6121
|
this.emit({
|
|
5481
6122
|
type: "fetch_agent_timeline_response",
|
|
@@ -5500,7 +6141,62 @@ export class Session {
|
|
|
5500
6141
|
});
|
|
5501
6142
|
}
|
|
5502
6143
|
catch (error) {
|
|
5503
|
-
|
|
6144
|
+
// Workspaces on external/removable drives can vanish between sessions;
|
|
6145
|
+
// this is a known/expected condition for resume requests and shouldn't
|
|
6146
|
+
// pollute the daemon log at ERROR. See issue #662 / #632.
|
|
6147
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6148
|
+
const isMissingCwd = /Working directory does not exist/.test(message);
|
|
6149
|
+
let offlineTimeline = null;
|
|
6150
|
+
try {
|
|
6151
|
+
offlineTimeline = await this.loadOfflineTimelineForStoredAgent({
|
|
6152
|
+
agentId: msg.agentId,
|
|
6153
|
+
direction,
|
|
6154
|
+
cursor,
|
|
6155
|
+
limit: shouldLimitByProjectedWindow && typeof requestedLimit === "number" ? 0 : limit,
|
|
6156
|
+
});
|
|
6157
|
+
}
|
|
6158
|
+
catch (offlineError) {
|
|
6159
|
+
this.sessionLogger.warn({ err: offlineError, agentId: msg.agentId }, "Failed to load offline persisted agent timeline");
|
|
6160
|
+
}
|
|
6161
|
+
if (offlineTimeline) {
|
|
6162
|
+
const projected = projectOfflineTimelineFetchResponse({
|
|
6163
|
+
model: offlineTimeline.model,
|
|
6164
|
+
direction,
|
|
6165
|
+
projection,
|
|
6166
|
+
shouldLimitByProjectedWindow,
|
|
6167
|
+
requestedLimit,
|
|
6168
|
+
projectionOptions: legacyTimelineProjectionOptions(this.appVersion),
|
|
6169
|
+
});
|
|
6170
|
+
this.sessionLogger.warn({ err: error, agentId: msg.agentId, provider: offlineTimeline.model.agentProvider }, "Loaded persisted agent timeline without resuming provider session");
|
|
6171
|
+
this.emit({
|
|
6172
|
+
type: "fetch_agent_timeline_response",
|
|
6173
|
+
payload: {
|
|
6174
|
+
requestId: msg.requestId,
|
|
6175
|
+
agentId: msg.agentId,
|
|
6176
|
+
agent: this.buildStoredAgentPayload(offlineTimeline.record),
|
|
6177
|
+
direction,
|
|
6178
|
+
projection,
|
|
6179
|
+
epoch: offlineTimeline.model.epoch,
|
|
6180
|
+
reset: offlineTimeline.model.reset,
|
|
6181
|
+
staleCursor: offlineTimeline.model.staleCursor,
|
|
6182
|
+
gap: offlineTimeline.model.gap,
|
|
6183
|
+
window: offlineTimeline.model.window,
|
|
6184
|
+
startCursor: projected.startCursor,
|
|
6185
|
+
endCursor: projected.endCursor,
|
|
6186
|
+
hasOlder: projected.hasOlder,
|
|
6187
|
+
hasNewer: projected.hasNewer,
|
|
6188
|
+
entries: projected.entries,
|
|
6189
|
+
error: null,
|
|
6190
|
+
},
|
|
6191
|
+
});
|
|
6192
|
+
return;
|
|
6193
|
+
}
|
|
6194
|
+
if (isMissingCwd) {
|
|
6195
|
+
this.sessionLogger.warn({ err: error, agentId: msg.agentId }, "Workspace offline while loading agent timeline");
|
|
6196
|
+
}
|
|
6197
|
+
else {
|
|
6198
|
+
this.sessionLogger.error({ err: error, agentId: msg.agentId }, "Failed to handle fetch_agent_timeline_request");
|
|
6199
|
+
}
|
|
5504
6200
|
this.emit({
|
|
5505
6201
|
type: "fetch_agent_timeline_response",
|
|
5506
6202
|
payload: {
|
|
@@ -5555,6 +6251,7 @@ export class Session {
|
|
|
5555
6251
|
try {
|
|
5556
6252
|
this.agentManager.recordUserMessage(agentId, msg.text, {
|
|
5557
6253
|
messageId: msg.messageId,
|
|
6254
|
+
images: msg.imageAttachments,
|
|
5558
6255
|
emitState: false,
|
|
5559
6256
|
});
|
|
5560
6257
|
}
|
|
@@ -5562,6 +6259,22 @@ export class Session {
|
|
|
5562
6259
|
this.sessionLogger.error({ err: error, agentId }, "Failed to record user message for send_agent_message_request");
|
|
5563
6260
|
}
|
|
5564
6261
|
const prompt = this.buildAgentPrompt(msg.text, msg.images, msg.documents);
|
|
6262
|
+
if (typeof prompt === "string") {
|
|
6263
|
+
const oob = await this.agentManager.tryRunOutOfBand(agentId, prompt);
|
|
6264
|
+
if (oob) {
|
|
6265
|
+
await this.agentManager.appendTimelineItem(agentId, {
|
|
6266
|
+
type: "assistant_message",
|
|
6267
|
+
text: oob.response,
|
|
6268
|
+
});
|
|
6269
|
+
this.agentManager.emitAgentState(agentId);
|
|
6270
|
+
latencyTracker.dropPending(agentId);
|
|
6271
|
+
this.emit({
|
|
6272
|
+
type: "send_agent_message_response",
|
|
6273
|
+
payload: { requestId: msg.requestId, agentId, accepted: true, error: null },
|
|
6274
|
+
});
|
|
6275
|
+
return;
|
|
6276
|
+
}
|
|
6277
|
+
}
|
|
5565
6278
|
this.sessionLogger.info({
|
|
5566
6279
|
agentId,
|
|
5567
6280
|
messageId: msg.messageId,
|
|
@@ -6609,6 +7322,38 @@ export class Session {
|
|
|
6609
7322
|
this.emitScheduleRpcError(request, error);
|
|
6610
7323
|
}
|
|
6611
7324
|
}
|
|
7325
|
+
async handleScheduleUpdateRequest(request) {
|
|
7326
|
+
try {
|
|
7327
|
+
const schedule = await this.scheduleService.update(request.scheduleId, request.patch);
|
|
7328
|
+
this.emit({
|
|
7329
|
+
type: "schedule/update/response",
|
|
7330
|
+
payload: {
|
|
7331
|
+
requestId: request.requestId,
|
|
7332
|
+
schedule: this.toScheduleSummary(schedule),
|
|
7333
|
+
error: null,
|
|
7334
|
+
},
|
|
7335
|
+
});
|
|
7336
|
+
}
|
|
7337
|
+
catch (error) {
|
|
7338
|
+
this.emitScheduleRpcError(request, error);
|
|
7339
|
+
}
|
|
7340
|
+
}
|
|
7341
|
+
async handleScheduleRunNowRequest(request) {
|
|
7342
|
+
try {
|
|
7343
|
+
const run = await this.scheduleService.triggerNow(request.scheduleId);
|
|
7344
|
+
this.emit({
|
|
7345
|
+
type: "schedule/run-now/response",
|
|
7346
|
+
payload: {
|
|
7347
|
+
requestId: request.requestId,
|
|
7348
|
+
run,
|
|
7349
|
+
error: null,
|
|
7350
|
+
},
|
|
7351
|
+
});
|
|
7352
|
+
}
|
|
7353
|
+
catch (error) {
|
|
7354
|
+
this.emitScheduleRpcError(request, error);
|
|
7355
|
+
}
|
|
7356
|
+
}
|
|
6612
7357
|
emitLoopRpcError(request, error) {
|
|
6613
7358
|
const message = error instanceof Error ? error.message : String(error);
|
|
6614
7359
|
this.sessionLogger.error({ err: error, requestType: request.type }, "Loop request failed");
|
|
@@ -7137,4 +7882,72 @@ export class Session {
|
|
|
7137
7882
|
// Stash handlers
|
|
7138
7883
|
// ---------------------------------------------------------------------------
|
|
7139
7884
|
Session.SEAWORK_STASH_PREFIX = "seawork-auto-stash:";
|
|
7885
|
+
function formatUnknownError(error) {
|
|
7886
|
+
if (error instanceof Error) {
|
|
7887
|
+
return error.message;
|
|
7888
|
+
}
|
|
7889
|
+
if (typeof error === "string") {
|
|
7890
|
+
return error;
|
|
7891
|
+
}
|
|
7892
|
+
return "Unknown error";
|
|
7893
|
+
}
|
|
7894
|
+
function normalizeNonEmptyStrings(values) {
|
|
7895
|
+
return (values ?? []).map((value) => value.trim()).filter(Boolean);
|
|
7896
|
+
}
|
|
7897
|
+
function mergeUniqueNonEmptyStrings(current, incoming) {
|
|
7898
|
+
return [
|
|
7899
|
+
...new Set([...normalizeNonEmptyStrings(current), ...normalizeNonEmptyStrings(incoming)]),
|
|
7900
|
+
];
|
|
7901
|
+
}
|
|
7902
|
+
function rehydratePatchWeComOpenClawSecret(input) {
|
|
7903
|
+
const incoming = input.patch.integrations?.wecomOpenClaw;
|
|
7904
|
+
if (!incoming || incoming.secret !== PROVIDER_ENV_VALUE_REDACTED) {
|
|
7905
|
+
return input.patch;
|
|
7906
|
+
}
|
|
7907
|
+
const currentSecret = input.current.integrations?.wecomOpenClaw?.secret;
|
|
7908
|
+
if (!currentSecret) {
|
|
7909
|
+
return input.patch;
|
|
7910
|
+
}
|
|
7911
|
+
return {
|
|
7912
|
+
...input.patch,
|
|
7913
|
+
integrations: {
|
|
7914
|
+
...input.patch.integrations,
|
|
7915
|
+
wecomOpenClaw: {
|
|
7916
|
+
...incoming,
|
|
7917
|
+
secret: currentSecret,
|
|
7918
|
+
},
|
|
7919
|
+
},
|
|
7920
|
+
};
|
|
7921
|
+
}
|
|
7922
|
+
function resolvePatchWeComOpenClawAgentCwd(input) {
|
|
7923
|
+
const incoming = input.patch.integrations?.wecomOpenClaw;
|
|
7924
|
+
if (!incoming || incoming.cwd === undefined) {
|
|
7925
|
+
return input.patch;
|
|
7926
|
+
}
|
|
7927
|
+
return {
|
|
7928
|
+
...input.patch,
|
|
7929
|
+
integrations: {
|
|
7930
|
+
...input.patch.integrations,
|
|
7931
|
+
wecomOpenClaw: {
|
|
7932
|
+
...incoming,
|
|
7933
|
+
cwd: resolveWeComOpenClawAgentCwd(incoming.cwd, input.seaworkHome),
|
|
7934
|
+
},
|
|
7935
|
+
},
|
|
7936
|
+
};
|
|
7937
|
+
}
|
|
7938
|
+
// Normalize per-project cwds (tilde-expand + path.resolve) at storage time so
|
|
7939
|
+
// they match the agent's already-expanded cwd in resolvePromptInjection.
|
|
7940
|
+
function resolvePatchPromptInjectionCwds(patch) {
|
|
7941
|
+
const projects = patch.promptInjection?.projects;
|
|
7942
|
+
if (!projects) {
|
|
7943
|
+
return patch;
|
|
7944
|
+
}
|
|
7945
|
+
return {
|
|
7946
|
+
...patch,
|
|
7947
|
+
promptInjection: {
|
|
7948
|
+
...patch.promptInjection,
|
|
7949
|
+
projects: projects.map((p) => ({ ...p, cwd: resolve(expandTilde(p.cwd)) })),
|
|
7950
|
+
},
|
|
7951
|
+
};
|
|
7952
|
+
}
|
|
7140
7953
|
//# sourceMappingURL=session.js.map
|