@getpaseo/server 0.1.100 → 0.1.102-beta.2
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.js +26 -8
- package/dist/server/executable-resolution/windows.js +3 -0
- package/dist/server/server/agent/activity-curator.d.ts +17 -0
- package/dist/server/server/agent/activity-curator.js +101 -24
- package/dist/server/server/agent/agent-manager.d.ts +10 -0
- package/dist/server/server/agent/agent-manager.js +69 -27
- package/dist/server/server/agent/agent-sdk-types.d.ts +15 -2
- package/dist/server/server/agent/mcp-server.d.ts +2 -45
- package/dist/server/server/agent/mcp-server.js +45 -1985
- package/dist/server/server/agent/prompt-attachments.js +6 -2
- package/dist/server/server/agent/provider-snapshot-manager.d.ts +12 -1
- package/dist/server/server/agent/provider-snapshot-manager.js +132 -42
- package/dist/server/server/agent/providers/acp-agent.d.ts +27 -1
- package/dist/server/server/agent/providers/acp-agent.js +178 -27
- package/dist/server/server/agent/providers/claude/agent.js +111 -24
- package/dist/server/server/agent/providers/claude/query.d.ts +3 -0
- package/dist/server/server/agent/providers/claude/query.js +4 -2
- package/dist/server/server/agent/providers/codex-app-server-agent.js +6 -57
- package/dist/server/server/agent/providers/diagnostic-utils.d.ts +1 -0
- package/dist/server/server/agent/providers/diagnostic-utils.js +1 -1
- package/dist/server/server/agent/providers/generic-acp-agent.d.ts +3 -0
- package/dist/server/server/agent/providers/generic-acp-agent.js +41 -23
- package/dist/server/server/agent/providers/mock-load-test-agent.js +12 -2
- package/dist/server/server/agent/providers/opencode/paths.d.ts +2 -0
- package/dist/server/server/agent/providers/opencode/paths.js +7 -0
- package/dist/server/server/agent/providers/opencode/server-manager.d.ts +2 -0
- package/dist/server/server/agent/providers/opencode/server-manager.js +34 -5
- package/dist/server/server/agent/providers/opencode-agent.d.ts +4 -0
- package/dist/server/server/agent/providers/opencode-agent.js +14 -2
- package/dist/server/server/agent/providers/pi/agent.d.ts +5 -1
- package/dist/server/server/agent/providers/pi/agent.js +12 -3
- package/dist/server/server/agent/providers/provider-image-output.d.ts +5 -0
- package/dist/server/server/agent/providers/provider-image-output.js +61 -1
- package/dist/server/server/agent/tools/paseo-tools.d.ts +48 -0
- package/dist/server/server/agent/tools/paseo-tools.js +2119 -0
- package/dist/server/server/agent/tools/types.d.ts +36 -0
- package/dist/server/server/agent/tools/types.js +2 -0
- package/dist/server/server/bootstrap.d.ts +7 -1
- package/dist/server/server/bootstrap.js +89 -62
- package/dist/server/server/config.d.ts +2 -0
- package/dist/server/server/config.js +57 -1
- package/dist/server/server/daemon-worker.js +19 -7
- package/dist/server/server/lifecycle-reasons.d.ts +4 -0
- package/dist/server/server/lifecycle-reasons.js +6 -0
- package/dist/server/server/persisted-config.d.ts +12 -0
- package/dist/server/server/persisted-config.js +18 -2
- package/dist/server/server/process-diagnostics.d.ts +17 -0
- package/dist/server/server/process-diagnostics.js +22 -0
- package/dist/server/server/relay-transport.js +1 -0
- package/dist/server/server/resolve-worktree-creation-intent.js +3 -1
- package/dist/server/server/session/agent-updates/agent-updates-service.d.ts +59 -0
- package/dist/server/server/session/agent-updates/agent-updates-service.js +220 -0
- package/dist/server/server/session/checkout/checkout-session.d.ts +13 -15
- package/dist/server/server/session/checkout/checkout-session.js +18 -16
- package/dist/server/server/session/checkout/git-metadata-generator.d.ts +53 -0
- package/dist/server/server/session/checkout/git-metadata-generator.js +159 -0
- package/dist/server/server/session/daemon/daemon-self-update-session-controller.d.ts +32 -0
- package/dist/server/server/session/daemon/daemon-self-update-session-controller.js +88 -0
- package/dist/server/server/session/daemon/daemon-self-updater.d.ts +32 -0
- package/dist/server/server/session/daemon/daemon-self-updater.js +56 -0
- package/dist/server/server/session/daemon/daemon-session.d.ts +26 -0
- package/dist/server/server/session/daemon/daemon-session.js +50 -0
- package/dist/server/server/session/daemon/diagnostics.d.ts +41 -0
- package/dist/server/server/session/daemon/diagnostics.js +431 -0
- package/dist/server/server/session/daemon/install-origin.d.ts +7 -0
- package/dist/server/server/session/daemon/install-origin.js +64 -0
- package/dist/server/server/session/daemon/npm-global-cli.d.ts +29 -0
- package/dist/server/server/session/daemon/npm-global-cli.js +98 -0
- package/dist/server/server/session/git-mutation/git-mutation-service.d.ts +34 -0
- package/dist/server/server/session/git-mutation/git-mutation-service.js +71 -0
- package/dist/server/server/session/provider/provider-catalog-session.js +8 -4
- package/dist/server/server/session/workspace-git-observer/workspace-git-observer-service.d.ts +36 -0
- package/dist/server/server/session/workspace-git-observer/workspace-git-observer-service.js +134 -0
- package/dist/server/server/session/workspace-provisioning/workspace-provisioning-service.d.ts +34 -0
- package/dist/server/server/session/workspace-provisioning/workspace-provisioning-service.js +190 -0
- package/dist/server/server/session/workspace-scripts/workspace-scripts-service.d.ts +41 -0
- package/dist/server/server/session/workspace-scripts/workspace-scripts-service.js +100 -0
- package/dist/server/server/session.d.ts +12 -54
- package/dist/server/server/session.js +187 -970
- package/dist/server/server/speech/providers/openai/config.d.ts +1 -2
- package/dist/server/server/speech/providers/openai/config.js +13 -9
- package/dist/server/server/speech/providers/openai/runtime.js +2 -16
- package/dist/server/server/speech/providers/openai/stt.d.ts +1 -0
- package/dist/server/server/speech/providers/openai/stt.js +4 -2
- package/dist/server/server/speech/providers/openai/tts.d.ts +1 -0
- package/dist/server/server/speech/providers/openai/tts.js +1 -0
- package/dist/server/server/web-ui.d.ts +10 -0
- package/dist/server/server/web-ui.js +205 -0
- package/dist/server/server/websocket/runtime-metrics.d.ts +23 -0
- package/dist/server/server/websocket-server.d.ts +4 -2
- package/dist/server/server/websocket-server.js +215 -52
- package/dist/server/server/worktree-bootstrap.d.ts +1 -1
- package/dist/server/server/worktree-branch-name-generator.js +3 -1
- package/dist/server/services/quota-fetcher/manifest.js +5 -0
- package/dist/server/services/quota-fetcher/providers/minimax.d.ts +29 -0
- package/dist/server/services/quota-fetcher/providers/minimax.js +227 -0
- package/dist/server/terminal/agent-hooks/agent-hook-installer.js +2 -2
- package/dist/server/utils/checkout-git.js +203 -25
- package/dist/server/utils/directory-suggestions.js +1 -4
- package/dist/server/utils/path.d.ts +2 -0
- package/dist/server/utils/path.js +13 -0
- package/dist/server/utils/worktree.d.ts +1 -0
- package/dist/server/utils/worktree.js +92 -11
- package/dist/server/web-ui/_expo/static/css/xterm-3bb1704bf6cb0876640973dc0244b4cb.css +1 -0
- package/dist/server/web-ui/_expo/static/css/xterm-3bb1704bf6cb0876640973dc0244b4cb.css.br +0 -0
- package/dist/server/web-ui/_expo/static/css/xterm-3bb1704bf6cb0876640973dc0244b4cb.css.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-b01555c9b42665a03988c0a0032ef528.js +1 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-b01555c9b42665a03988c0a0032ef528.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-b01555c9b42665a03988c0a0032ef528.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-648388eca5c510b496e1eddf523f70ff.js +1 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-648388eca5c510b496e1eddf523f70ff.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-648388eca5c510b496e1eddf523f70ff.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-0ebbea2cd337f0c0680fdb3f8d4d5af3.js +16157 -0
- package/dist/server/web-ui/_expo/static/js/web/index-0ebbea2cd337f0c0680fdb3f8d4d5af3.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-0ebbea2cd337f0c0680fdb3f8d4d5af3.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-c64fa2416284927857a39087fd8d1332.js +1 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-c64fa2416284927857a39087fd8d1332.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-c64fa2416284927857a39087fd8d1332.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-a9784226715772edf87ef36c596599c2.js +3 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-a9784226715772edf87ef36c596599c2.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-a9784226715772edf87ef36c596599c2.js.gz +0 -0
- package/dist/server/web-ui/apple-touch-icon.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/back-icon-mask.0a328cd9c1afd0afe8e3b1ec5165b1b4.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/back-icon.35ba0eaec5a4f5ed12ca16fabeae451d.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@2x.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@3x.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@4x.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@2x.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@3x.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@4x.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/search-icon.286d67d3f74808a60a78d3ebf1a5fb57.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/expo-router/assets/arrow_down.017bc6ba3fc25503e5eb5e53826d48a8.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/expo-router/assets/error.d1ea1496f9057eb392d5bbf3732a61b7.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/expo-router/assets/file.19eeb73b9593a38f8e9f418337fc7d10.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/expo-router/assets/forward.d8b800c443b8972542883e0b9de2bdc6.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/expo-router/assets/pkg.ab19f4cbc543357183a20571f68380a3.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/expo-router/assets/sitemap.412dd9275b6b48ad28f5e3d81bb1f626.png +0 -0
- package/dist/server/web-ui/assets/__node_modules/expo-router/assets/unmatched.20e71bdf79e3a97bf55fd9e164041578.png +0 -0
- package/dist/server/web-ui/assets/assets/images/editor-apps/antigravity.6e91a685c33435e0b466a56db86cf141.png +0 -0
- package/dist/server/web-ui/assets/assets/images/editor-apps/cursor.c31d6bce4fe9aadc3fe59962f4c4fcf3.png +0 -0
- package/dist/server/web-ui/assets/assets/images/editor-apps/file-explorer.3e15e8f72c825c85ce336bcb0cdef776.png +0 -0
- package/dist/server/web-ui/assets/assets/images/editor-apps/finder.7f68fc2c475621a672e1be09309d5567.png +0 -0
- package/dist/server/web-ui/assets/assets/images/editor-apps/vscode.832bdb4c685d930f1c864c793703600b.png +0 -0
- package/dist/server/web-ui/assets/assets/images/editor-apps/webstorm.aa5dc2cd8c20cc0a155c4c5c5ab3c5f5.png +0 -0
- package/dist/server/web-ui/assets/assets/images/editor-apps/zed.f3a670b7f9aa226da4fe53fb86f1abbd.png +0 -0
- package/dist/server/web-ui/assets/assets/images/favicon-dark-attention.882b3a27dcb2073e9e31b334f9ed9728.png +0 -0
- package/dist/server/web-ui/assets/assets/images/favicon-dark-running.8112342ff0d39e047a7f8d4fad9402f3.png +0 -0
- package/dist/server/web-ui/assets/assets/images/favicon-dark.8005ed36ac07a5a7c60de25780897bd4.png +0 -0
- package/dist/server/web-ui/assets/assets/images/favicon-light-attention.882b3a27dcb2073e9e31b334f9ed9728.png +0 -0
- package/dist/server/web-ui/assets/assets/images/favicon-light-running.8112342ff0d39e047a7f8d4fad9402f3.png +0 -0
- package/dist/server/web-ui/assets/assets/images/favicon-light.8005ed36ac07a5a7c60de25780897bd4.png +0 -0
- package/dist/server/web-ui/assets/assets/images/notification-icon.3bf81d33ddbf380606bdd248ba83e158.png +0 -0
- package/dist/server/web-ui/favicon.ico +0 -0
- package/dist/server/web-ui/index.html +90 -0
- package/dist/server/web-ui/index.html.br +0 -0
- package/dist/server/web-ui/index.html.gz +0 -0
- package/dist/server/web-ui/manifest.json +27 -0
- package/dist/server/web-ui/manifest.json.br +0 -0
- package/dist/server/web-ui/manifest.json.gz +0 -0
- package/dist/server/web-ui/metadata.json +1 -0
- package/dist/server/web-ui/metadata.json.br +1 -0
- package/dist/server/web-ui/metadata.json.gz +0 -0
- package/dist/server/web-ui/pwa-icon-192.png +0 -0
- package/dist/server/web-ui/pwa-icon-512.png +0 -0
- package/dist/server/web-ui/robots.txt +2 -0
- package/dist/src/executable-resolution/windows.js +3 -0
- package/dist/src/server/persisted-config.js +18 -2
- package/package.json +7 -7
- package/dist/server/server/speech/providers/openai/realtime-transcription-session.d.ts +0 -42
- package/dist/server/server/speech/providers/openai/realtime-transcription-session.js +0 -168
|
@@ -3,7 +3,6 @@ import { v4 as uuidv4 } from "uuid";
|
|
|
3
3
|
import { stat } from "node:fs/promises";
|
|
4
4
|
import { basename, normalize, resolve, sep } from "path";
|
|
5
5
|
import { homedir } from "node:os";
|
|
6
|
-
import { z } from "zod";
|
|
7
6
|
import { CLIENT_CAPS } from "@getpaseo/protocol/client-capabilities";
|
|
8
7
|
import { serializeAgentStreamEvent, } from "./messages.js";
|
|
9
8
|
import { TerminalSessionController } from "../terminal/terminal-session-controller.js";
|
|
@@ -14,55 +13,54 @@ import { ensureAgentLoaded } from "./agent/agent-loading.js";
|
|
|
14
13
|
import { formatSystemNotificationPrompt, sendPromptToAgent, waitForAgentRunStartWithTimeout, unarchiveAgentState, } from "./agent/agent-prompt.js";
|
|
15
14
|
import { resolveCreateAgentTitles, resolveFirstAgentPromptTitle, } from "./agent/create-agent-title.js";
|
|
16
15
|
import { respondToAgentPermission } from "./agent/permission-response.js";
|
|
17
|
-
import { experimental_createMCPClient } from "ai";
|
|
18
|
-
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
19
|
-
import { buildWorkspaceScriptPayloads, readPaseoConfigForProjection, } from "./script-status-projection.js";
|
|
20
|
-
import { deriveProjectSlug } from "./workspace-git-metadata.js";
|
|
21
16
|
import { spawnWorkspaceScript } from "./worktree-bootstrap.js";
|
|
17
|
+
import { createWorkspaceScriptsService, } from "./session/workspace-scripts/workspace-scripts-service.js";
|
|
22
18
|
import { getErrorMessage, getErrorMessageOr } from "@getpaseo/protocol/error-utils";
|
|
23
19
|
import { getAgentStatusPriority } from "@getpaseo/protocol/agent-state-bucket";
|
|
24
20
|
import { getParentAgentIdFromLabels } from "@getpaseo/protocol/agent-labels";
|
|
21
|
+
import { CLIENT_SHUTDOWN_RPC_REASON, normalizeClientRestartRpcReason, } from "./lifecycle-reasons.js";
|
|
25
22
|
import { createAgentCommand } from "./agent/create-agent/create.js";
|
|
26
23
|
import { archiveAgentCommand, cancelAgentRunCommand, closeAgentCommand, detachAgentCommand, setAgentModeCommand, updateAgentCommand, } from "./agent/lifecycle-command.js";
|
|
27
|
-
import { buildStoredAgentPayload,
|
|
24
|
+
import { buildStoredAgentPayload, resolveStoredAgentPayloadUpdatedAt, toAgentPayload, } from "./agent/agent-projections.js";
|
|
28
25
|
import { appendTimelineItemIfAgentKnown, emitLiveTimelineItemIfAgentKnown, } from "./agent/timeline-append.js";
|
|
29
26
|
import { projectTimelineRows, selectProjectedTimelinePage, } from "./agent/timeline-projection.js";
|
|
30
|
-
import {
|
|
31
|
-
import { resolveStructuredGenerationProviders, } from "./agent/structured-generation-providers.js";
|
|
27
|
+
import { buildAgentForkContextAttachment } from "./agent/activity-curator.js";
|
|
32
28
|
import { getAgentStreamEventTurnId, } from "./agent/agent-sdk-types.js";
|
|
33
29
|
import { ImportSessionsRequestError, importProviderSession, listImportableProviderSessions, normalizeImportAgentRequest, } from "./agent/import-sessions.js";
|
|
34
|
-
import { checkoutLiteFromGitSnapshot,
|
|
30
|
+
import { checkoutLiteFromGitSnapshot, deriveWorkspaceDisplayName, } from "./workspace-registry-model.js";
|
|
35
31
|
import { resolveWorkspaceIdForPath } from "./resolve-workspace-id-for-path.js";
|
|
36
|
-
import {
|
|
32
|
+
import { resolveProjectDisplayName, resolveWorkspaceDisplayName, resolveWorkspaceName, } from "./workspace-registry.js";
|
|
37
33
|
import { wrapSpokenInput } from "./voice-config.js";
|
|
38
34
|
import { isVoicePermissionAllowed } from "./voice-permission-policy.js";
|
|
39
35
|
import { VoiceSession } from "./session/voice/voice-session.js";
|
|
40
36
|
import { CheckoutSession } from "./session/checkout/checkout-session.js";
|
|
37
|
+
import { createWorkspaceGitObserverService, } from "./session/workspace-git-observer/workspace-git-observer-service.js";
|
|
38
|
+
import { createAgentStructuredTextGeneration, createGitMetadataGenerator, } from "./session/checkout/git-metadata-generator.js";
|
|
41
39
|
import { ChatScheduleLoopSession } from "./session/chat/chat-schedule-loop-session.js";
|
|
42
40
|
import { ProviderCatalogSession } from "./session/provider/provider-catalog-session.js";
|
|
43
41
|
import { WorkspaceFilesSession } from "./session/files/workspace-files-session.js";
|
|
44
42
|
import { AgentConfigSession } from "./session/agent-config/agent-config-session.js";
|
|
45
43
|
import { ProjectConfigSession } from "./session/project-config/project-config-session.js";
|
|
46
44
|
import { DaemonSession } from "./session/daemon/daemon-session.js";
|
|
47
|
-
import { buildMetadataPrompt } from "../utils/build-metadata-prompt.js";
|
|
48
45
|
import { archivePersistedWorkspaceRecord, archiveWorkspaceContents, } from "./workspace-archive-service.js";
|
|
49
46
|
import { WorkspaceReconciliationService } from "./workspace-reconciliation-service.js";
|
|
50
|
-
import {
|
|
47
|
+
import { renameCurrentBranch as renameCurrentBranchDefault } from "../utils/checkout-git.js";
|
|
48
|
+
import { createGitMutationService, } from "./session/git-mutation/git-mutation-service.js";
|
|
49
|
+
import { createWorkspaceProvisioningService, } from "./session/workspace-provisioning/workspace-provisioning-service.js";
|
|
50
|
+
import { createAgentUpdatesService, matchesAgentUpdatesFilter, } from "./session/agent-updates/agent-updates-service.js";
|
|
51
51
|
import { expandTilde } from "../utils/path.js";
|
|
52
52
|
import { searchHomeDirectories, searchWorkspaceEntries } from "../utils/directory-suggestions.js";
|
|
53
|
-
import { execCommand } from "../utils/spawn.js";
|
|
54
53
|
import { createGitHubService } from "../services/github-service.js";
|
|
55
54
|
import { summarizeFetchWorkspacesEntries, workspaceIdsOnCheckout, WorkspaceDirectory, } from "./workspace-directory.js";
|
|
56
55
|
import { shouldEmitPendingBootstrapUpdate } from "./workspace-bootstrap-dedupe.js";
|
|
57
56
|
import { attemptFirstAgentBranchAutoName, createLocalCheckoutWorkspace, createPaseoWorktree, } from "./paseo-worktree-service.js";
|
|
58
57
|
import { generateBranchNameFromFirstAgentContext, } from "./worktree-branch-name-generator.js";
|
|
59
|
-
import {
|
|
58
|
+
import { buildAgentSessionConfig as buildWorktreeAgentSessionConfig, createPaseoWorktreeWorkflow as createWorktreeWorkflow, handleCreatePaseoWorktreeRequest as handleCreateWorktreeRequest, handlePaseoWorktreeArchiveRequest as handleWorktreeArchiveRequest, handlePaseoWorktreeListRequest as handleWorktreeListRequest, handleWorkspaceSetupStatusRequest as handleWorkspaceSetupStatusRequestMessage, } from "./worktree-session.js";
|
|
60
59
|
import { archiveByScope } from "./workspace-archive-service.js";
|
|
61
60
|
import { WorktreeRequestError, toWorktreeRequestError, toWorktreeWireError, } from "./worktree-errors.js";
|
|
62
61
|
import { createWorktree } from "../utils/worktree.js";
|
|
63
62
|
import { runGitCommand } from "../utils/run-git-command.js";
|
|
64
63
|
import { CreateAgentLifecycleDispatch } from "./agent/create-agent-lifecycle-dispatch.js";
|
|
65
|
-
const WORKSPACE_GIT_WATCH_REMOVED_STATE_KEY = "__removed__";
|
|
66
64
|
// TODO: Remove once all app store clients are on >=0.1.45 and understand arbitrary provider strings.
|
|
67
65
|
// Clients before 0.1.45 validate providers with z.enum(["claude", "codex", "opencode"]) and reject
|
|
68
66
|
// the entire session message if they encounter an unknown provider.
|
|
@@ -83,13 +81,6 @@ function resolveSubscriptionId(subscribe, requestedSubscriptionId) {
|
|
|
83
81
|
}
|
|
84
82
|
return uuidv4();
|
|
85
83
|
}
|
|
86
|
-
function diffChangeTypeFor(file) {
|
|
87
|
-
if (file.isNew)
|
|
88
|
-
return "A";
|
|
89
|
-
if (file.isDeleted)
|
|
90
|
-
return "D";
|
|
91
|
-
return "M";
|
|
92
|
-
}
|
|
93
84
|
function buildWorkspaceCheckout(workspace, project,
|
|
94
85
|
// The persisted `branch` field is the source of truth, but it is null for
|
|
95
86
|
// records created before branch was lifted to its own field (no migrations,
|
|
@@ -201,19 +192,12 @@ function describeRegistryTransition(record) {
|
|
|
201
192
|
*/
|
|
202
193
|
export class Session {
|
|
203
194
|
constructor(options) {
|
|
204
|
-
// Per-session MCP client and tools
|
|
205
|
-
this.agentMcpClient = null;
|
|
206
|
-
this.agentTools = null;
|
|
207
195
|
this.unsubscribeAgentEvents = null;
|
|
208
196
|
this.unsubscribeTerminalWorkspaceContributionEvents = null;
|
|
209
|
-
this.agentUpdatesSubscription = null;
|
|
210
197
|
this.workspaceUpdatesSubscription = null;
|
|
211
198
|
this.clientActivity = null;
|
|
212
199
|
this.inflightRequests = 0;
|
|
213
200
|
this.peakInflightRequests = 0;
|
|
214
|
-
this.workspaceGitWatchTargets = new Map();
|
|
215
|
-
this.workspaceGitFetchSubscriptions = new Map();
|
|
216
|
-
this.workspaceGitSubscriptions = new Map();
|
|
217
201
|
this.agentsPager = new SortablePager({
|
|
218
202
|
validKeys: FETCH_AGENTS_SORT_KEYS,
|
|
219
203
|
defaultSort: [{ key: "updated_at", direction: "desc" }],
|
|
@@ -237,7 +221,7 @@ export class Session {
|
|
|
237
221
|
}
|
|
238
222
|
},
|
|
239
223
|
});
|
|
240
|
-
const { clientId, appVersion, clientCapabilities, onMessage, onBinaryMessage, getTransportBufferedAmount, onLifecycleIntent, logger, downloadTokenStore, pushTokenStore, paseoHome, worktreesRoot, agentManager, agentStorage, projectRegistry, workspaceRegistry, filesystem, chatService, scheduleService, loopService, checkoutDiffManager, github, renameCurrentBranch, generateWorkspaceName, workspaceGitService, daemonConfigStore,
|
|
224
|
+
const { clientId, appVersion, clientCapabilities, onMessage, onBinaryMessage, getTransportBufferedAmount, onLifecycleIntent, logger, downloadTokenStore, pushTokenStore, paseoHome, worktreesRoot, agentManager, agentStorage, projectRegistry, workspaceRegistry, filesystem, chatService, scheduleService, loopService, checkoutDiffManager, github, renameCurrentBranch, generateWorkspaceName, workspaceGitService, daemonConfigStore, stt, sttLanguage, tts, terminalManager, providerSnapshotManager, providerUsageService, serviceProxy, scriptRuntimeStore, workspaceSetupSnapshots, onBranchChanged, getDaemonTcpPort, getDaemonTcpHost, serviceProxyPublicBaseUrl, resolveScriptHealth, voice, voiceBridge, dictation, serverId, daemonVersion, daemonRuntimeConfig, getWebSocketRuntimeMetrics, } = options;
|
|
241
225
|
this.clientId = clientId;
|
|
242
226
|
this.appVersion = appVersion ?? null;
|
|
243
227
|
this.clientCapabilities = parseClientCapabilities(clientCapabilities);
|
|
@@ -273,24 +257,49 @@ export class Session {
|
|
|
273
257
|
this.renameCurrentBranch = renameCurrentBranch ?? renameCurrentBranchDefault;
|
|
274
258
|
this.generateWorkspaceName = generateWorkspaceName ?? generateBranchNameFromFirstAgentContext;
|
|
275
259
|
this.workspaceGitService = workspaceGitService;
|
|
260
|
+
this.gitMutation = createGitMutationService({
|
|
261
|
+
workspaceGitService: this.workspaceGitService,
|
|
262
|
+
github: this.github,
|
|
263
|
+
logger: this.sessionLogger,
|
|
264
|
+
});
|
|
265
|
+
this.workspaceProvisioning = createWorkspaceProvisioningService({
|
|
266
|
+
workspaceRegistry: this.workspaceRegistry,
|
|
267
|
+
projectRegistry: this.projectRegistry,
|
|
268
|
+
workspaceGitService: this.workspaceGitService,
|
|
269
|
+
});
|
|
276
270
|
this.checkoutSession = new CheckoutSession({
|
|
277
271
|
host: {
|
|
278
272
|
emit: (msg) => this.emit(msg),
|
|
279
|
-
notifyGitMutation: (cwd, reason, mutationOptions) => this.notifyGitMutation(cwd, reason, mutationOptions),
|
|
280
273
|
emitWorkspaceUpdateForCwd: (cwd) => this.emitWorkspaceUpdateForCwd(cwd),
|
|
281
|
-
handleWorkspaceGitBranchSnapshot: (cwd, branchName) => this.
|
|
274
|
+
handleWorkspaceGitBranchSnapshot: (cwd, branchName) => this.workspaceGitObserver.handleBranchSnapshot(cwd, branchName),
|
|
282
275
|
renameCurrentBranch: (cwd, branch) => this.renameCurrentBranch(cwd, branch),
|
|
283
|
-
checkoutExistingBranch: (cwd, branch) => this.checkoutExistingBranch(cwd, branch),
|
|
284
|
-
generateCommitMessage: (cwd) => this.generateCommitMessage(cwd),
|
|
285
|
-
generatePullRequestText: (cwd, baseRef) => this.generatePullRequestText(cwd, baseRef),
|
|
286
276
|
},
|
|
277
|
+
gitMutation: this.gitMutation,
|
|
287
278
|
workspaceGitService: this.workspaceGitService,
|
|
288
279
|
github: this.github,
|
|
289
280
|
checkoutDiffManager,
|
|
281
|
+
gitMetadataGenerator: createGitMetadataGenerator({
|
|
282
|
+
workspaceGitService: this.workspaceGitService,
|
|
283
|
+
generation: createAgentStructuredTextGeneration({
|
|
284
|
+
agentManager: this.agentManager,
|
|
285
|
+
providerSnapshotManager,
|
|
286
|
+
readDaemonConfig: () => this.readStructuredGenerationDaemonConfig(),
|
|
287
|
+
getFocusedSelection: (cwd) => this.getFocusedAgentSelectionForCwd(cwd),
|
|
288
|
+
}),
|
|
289
|
+
}),
|
|
290
290
|
paseoHome: this.paseoHome,
|
|
291
291
|
worktreesRoot: this.worktreesRoot,
|
|
292
292
|
logger: this.sessionLogger,
|
|
293
293
|
});
|
|
294
|
+
this.workspaceGitObserver = createWorkspaceGitObserverService({
|
|
295
|
+
workspaceGitService: this.workspaceGitService,
|
|
296
|
+
describeWorkspaceRecordWithGitData: (workspace) => this.describeWorkspaceRecordWithGitData(workspace),
|
|
297
|
+
emitWorkspaceUpdateForCwd: (cwd) => this.emitWorkspaceUpdateForCwd(cwd),
|
|
298
|
+
emitWorkspaceUpdateForWorkspaceId: (workspaceId) => this.emitWorkspaceUpdateForWorkspaceId(workspaceId),
|
|
299
|
+
emitStatusUpdate: (cwd, snapshot) => this.checkoutSession.emitStatusUpdate(cwd, snapshot),
|
|
300
|
+
onBranchChanged,
|
|
301
|
+
logger: this.sessionLogger,
|
|
302
|
+
});
|
|
294
303
|
this.chatScheduleLoopSession = new ChatScheduleLoopSession({
|
|
295
304
|
host: {
|
|
296
305
|
emit: (msg) => this.emit(msg),
|
|
@@ -348,16 +357,21 @@ export class Session {
|
|
|
348
357
|
this.daemonSession = new DaemonSession({
|
|
349
358
|
host: {
|
|
350
359
|
emit: (msg) => this.emit(msg),
|
|
360
|
+
emitLifecycleIntent: (intent) => this.emitLifecycleIntent(intent),
|
|
351
361
|
},
|
|
362
|
+
clientId: this.clientId,
|
|
352
363
|
paseoHome: this.paseoHome,
|
|
353
364
|
serverId,
|
|
354
365
|
daemonVersion,
|
|
355
366
|
daemonRuntimeConfig,
|
|
367
|
+
getWebSocketRuntimeMetrics,
|
|
356
368
|
listProviderAvailability: () => this.agentManager.listProviderAvailability(),
|
|
369
|
+
listAgents: () => this.agentManager.listAgents(),
|
|
370
|
+
listProjects: () => this.projectRegistry.list(),
|
|
371
|
+
listWorkspaces: () => this.workspaceRegistry.list(),
|
|
357
372
|
logger: this.sessionLogger,
|
|
358
373
|
});
|
|
359
374
|
this.daemonConfigStore = daemonConfigStore;
|
|
360
|
-
this.mcpBaseUrl = mcpBaseUrl ?? null;
|
|
361
375
|
this.terminalManager = terminalManager;
|
|
362
376
|
this.terminalController = new TerminalSessionController({
|
|
363
377
|
terminalManager,
|
|
@@ -370,6 +384,15 @@ export class Session {
|
|
|
370
384
|
clientSupportsWrapReflow: () => this.clientCapabilities.has(CLIENT_CAPS.terminalReflowableSnapshot),
|
|
371
385
|
getClientBufferedAmount: () => this.getTransportBufferedAmount(),
|
|
372
386
|
});
|
|
387
|
+
this.agentUpdates = createAgentUpdatesService({
|
|
388
|
+
emit: (message) => this.emit(message),
|
|
389
|
+
buildAgentPayload: (agent) => this.buildAgentPayload(agent),
|
|
390
|
+
buildStoredAgentPayload: (record) => this.buildStoredAgentPayload(record),
|
|
391
|
+
isProviderVisibleToClient: (provider) => this.isProviderVisibleToClient(provider),
|
|
392
|
+
buildProjectPlacementForWorkspaceId: (workspaceId) => this.buildProjectPlacementForWorkspaceId(workspaceId),
|
|
393
|
+
emitWorkspaceUpdateForWorkspaceId: (workspaceId) => this.emitWorkspaceUpdateForWorkspaceId(workspaceId),
|
|
394
|
+
logger: this.sessionLogger,
|
|
395
|
+
});
|
|
373
396
|
this.createAgentLifecycleDispatch = new CreateAgentLifecycleDispatch({
|
|
374
397
|
paseoHome: this.paseoHome,
|
|
375
398
|
worktreesRoot: this.worktreesRoot,
|
|
@@ -383,14 +406,7 @@ export class Session {
|
|
|
383
406
|
listActiveWorkspaces: () => this.listActiveWorkspaceRefs(),
|
|
384
407
|
archiveWorkspaceRecord: (workspaceId) => this.archiveWorkspaceRecord(workspaceId),
|
|
385
408
|
emit: (message) => this.emit(message),
|
|
386
|
-
emitAgentRemove: (agentId) =>
|
|
387
|
-
if (this.agentUpdatesSubscription) {
|
|
388
|
-
this.bufferOrEmitAgentUpdate(this.agentUpdatesSubscription, {
|
|
389
|
-
kind: "remove",
|
|
390
|
-
agentId,
|
|
391
|
-
});
|
|
392
|
-
}
|
|
393
|
-
},
|
|
409
|
+
emitAgentRemove: (agentId) => this.agentUpdates.removeAgent(agentId),
|
|
394
410
|
emitWorkspaceUpdatesForWorkspaceIds: (workspaceIds) => this.emitWorkspaceUpdatesForWorkspaceIds(workspaceIds),
|
|
395
411
|
markWorkspaceArchiving: (workspaceIds, archivingAt) => this.markWorkspaceArchiving(workspaceIds, archivingAt),
|
|
396
412
|
clearWorkspaceArchiving: (workspaceIds) => this.clearWorkspaceArchiving(workspaceIds),
|
|
@@ -401,11 +417,24 @@ export class Session {
|
|
|
401
417
|
this.serviceProxy = serviceProxy ?? null;
|
|
402
418
|
this.scriptRuntimeStore = scriptRuntimeStore ?? null;
|
|
403
419
|
this.workspaceSetupSnapshots = workspaceSetupSnapshots ?? new Map();
|
|
404
|
-
this.onBranchChanged = onBranchChanged;
|
|
405
420
|
this.getDaemonTcpPort = getDaemonTcpPort ?? null;
|
|
406
421
|
this.getDaemonTcpHost = getDaemonTcpHost ?? null;
|
|
407
422
|
this.serviceProxyPublicBaseUrl = serviceProxyPublicBaseUrl ?? null;
|
|
408
423
|
this.resolveScriptHealth = resolveScriptHealth ?? null;
|
|
424
|
+
this.workspaceScripts = createWorkspaceScriptsService({
|
|
425
|
+
serviceProxy: this.serviceProxy,
|
|
426
|
+
scriptRuntimeStore: this.scriptRuntimeStore,
|
|
427
|
+
terminalManager: this.terminalManager,
|
|
428
|
+
workspaceRegistry: this.workspaceRegistry,
|
|
429
|
+
workspaceGitService: this.workspaceGitService,
|
|
430
|
+
getDaemonTcpPort: this.getDaemonTcpPort,
|
|
431
|
+
getDaemonTcpHost: this.getDaemonTcpHost,
|
|
432
|
+
serviceProxyPublicBaseUrl: this.serviceProxyPublicBaseUrl,
|
|
433
|
+
resolveScriptHealth: this.resolveScriptHealth,
|
|
434
|
+
logger: this.sessionLogger,
|
|
435
|
+
emit: (message) => this.emit(message),
|
|
436
|
+
spawnWorkspaceScript,
|
|
437
|
+
});
|
|
409
438
|
this.subscribeToOptionalManagers();
|
|
410
439
|
this.workspaceDirectory = new WorkspaceDirectory({
|
|
411
440
|
logger: this.sessionLogger,
|
|
@@ -440,8 +469,6 @@ export class Session {
|
|
|
440
469
|
voiceBridge,
|
|
441
470
|
dictation,
|
|
442
471
|
});
|
|
443
|
-
// Initialize agent MCP client asynchronously
|
|
444
|
-
void this.initializeAgentMcp();
|
|
445
472
|
this.subscribeToAgentEvents();
|
|
446
473
|
this.sessionLogger.trace({}, "agent.session.lifecycle.created");
|
|
447
474
|
}
|
|
@@ -457,8 +484,7 @@ export class Session {
|
|
|
457
484
|
return this.clientCapabilities.has(capability);
|
|
458
485
|
}
|
|
459
486
|
async syncWorkspaceGitObserverForWorkspace(workspace) {
|
|
460
|
-
|
|
461
|
-
this.syncWorkspaceGitObservers([descriptor]);
|
|
487
|
+
await this.workspaceGitObserver.syncObserverForWorkspace(workspace);
|
|
462
488
|
}
|
|
463
489
|
async emitWorkspaceUpdateForWorkspaceId(workspaceId) {
|
|
464
490
|
await this.emitWorkspaceUpdatesForWorkspaceIds([workspaceId], { skipReconcile: true });
|
|
@@ -476,8 +502,7 @@ export class Session {
|
|
|
476
502
|
await this.emitWorkspaceUpdatesForWorkspaceIds(workspaceIds);
|
|
477
503
|
}
|
|
478
504
|
async warmWorkspaceGitDataForWorkspace(workspace) {
|
|
479
|
-
await this.
|
|
480
|
-
await this.emitWorkspaceUpdateForWorkspaceId(workspace.workspaceId);
|
|
505
|
+
await this.workspaceGitObserver.warmGitData(workspace);
|
|
481
506
|
}
|
|
482
507
|
/**
|
|
483
508
|
* Get the client's current activity state
|
|
@@ -592,30 +617,6 @@ export class Session {
|
|
|
592
617
|
},
|
|
593
618
|
});
|
|
594
619
|
}
|
|
595
|
-
/**
|
|
596
|
-
* Initialize Agent MCP client for this session using the daemon's HTTP MCP endpoint.
|
|
597
|
-
*/
|
|
598
|
-
async initializeAgentMcp() {
|
|
599
|
-
try {
|
|
600
|
-
if (!this.mcpBaseUrl) {
|
|
601
|
-
this.sessionLogger.info("Skipping Agent MCP initialization because no MCP base URL is configured");
|
|
602
|
-
return;
|
|
603
|
-
}
|
|
604
|
-
const authToken = this.agentManager.getMcpAuthToken();
|
|
605
|
-
const transport = new StreamableHTTPClientTransport(new URL(this.mcpBaseUrl), authToken
|
|
606
|
-
? { requestInit: { headers: { Authorization: `Bearer ${authToken}` } } }
|
|
607
|
-
: undefined);
|
|
608
|
-
this.agentMcpClient = await experimental_createMCPClient({
|
|
609
|
-
transport,
|
|
610
|
-
});
|
|
611
|
-
this.agentTools = (await this.agentMcpClient.tools());
|
|
612
|
-
const agentToolCount = Object.keys(this.agentTools ?? {}).length;
|
|
613
|
-
this.sessionLogger.trace({ agentToolCount }, "agent.session.mcp_init");
|
|
614
|
-
}
|
|
615
|
-
catch (error) {
|
|
616
|
-
this.sessionLogger.error({ err: error }, "Failed to initialize Agent MCP");
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
620
|
/**
|
|
620
621
|
* Subscribe to AgentManager events and forward them to the client
|
|
621
622
|
*/
|
|
@@ -644,7 +645,7 @@ export class Session {
|
|
|
644
645
|
turnId: event.agent.activeForegroundTurnId ?? undefined,
|
|
645
646
|
lifecycle: event.agent.lifecycle,
|
|
646
647
|
}, "agent.session.forward_update");
|
|
647
|
-
void this.
|
|
648
|
+
void this.agentUpdates.forwardLiveAgent(event.agent);
|
|
648
649
|
return;
|
|
649
650
|
}
|
|
650
651
|
if (this.voiceSession.isActiveForAgent(event.agentId) &&
|
|
@@ -734,148 +735,6 @@ export class Session {
|
|
|
734
735
|
}
|
|
735
736
|
return LEGACY_PROVIDER_IDS.has(provider);
|
|
736
737
|
}
|
|
737
|
-
agentThinkingOptionMatchesFilter(agent, filter) {
|
|
738
|
-
if (filter.thinkingOptionId === undefined) {
|
|
739
|
-
return true;
|
|
740
|
-
}
|
|
741
|
-
const expectedThinkingOptionId = resolveEffectiveThinkingOptionId({
|
|
742
|
-
configuredThinkingOptionId: filter.thinkingOptionId ?? null,
|
|
743
|
-
});
|
|
744
|
-
const resolvedThinkingOptionId = agent.effectiveThinkingOptionId ??
|
|
745
|
-
resolveEffectiveThinkingOptionId({
|
|
746
|
-
runtimeInfo: agent.runtimeInfo,
|
|
747
|
-
configuredThinkingOptionId: agent.thinkingOptionId ?? null,
|
|
748
|
-
});
|
|
749
|
-
return resolvedThinkingOptionId === expectedThinkingOptionId;
|
|
750
|
-
}
|
|
751
|
-
matchesAgentStructuralFilter(agent, project, filter) {
|
|
752
|
-
if (filter.statuses && filter.statuses.length > 0) {
|
|
753
|
-
const statuses = new Set(filter.statuses);
|
|
754
|
-
if (!statuses.has(agent.status)) {
|
|
755
|
-
return false;
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
if (typeof filter.requiresAttention === "boolean") {
|
|
759
|
-
const requiresAttention = agent.requiresAttention ?? false;
|
|
760
|
-
if (requiresAttention !== filter.requiresAttention) {
|
|
761
|
-
return false;
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
if (filter.projectKeys && filter.projectKeys.length > 0) {
|
|
765
|
-
const projectKeys = new Set(filter.projectKeys.filter((item) => item.trim().length > 0));
|
|
766
|
-
if (projectKeys.size > 0 && !projectKeys.has(project.projectKey)) {
|
|
767
|
-
return false;
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
return true;
|
|
771
|
-
}
|
|
772
|
-
matchesAgentFilter(options) {
|
|
773
|
-
const { agent, project, filter } = options;
|
|
774
|
-
if (filter?.labels) {
|
|
775
|
-
const matchesLabels = Object.entries(filter.labels).every(([key, value]) => agent.labels[key] === value);
|
|
776
|
-
if (!matchesLabels) {
|
|
777
|
-
return false;
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
const includeArchived = filter?.includeArchived ?? false;
|
|
781
|
-
if (!includeArchived && agent.archivedAt) {
|
|
782
|
-
return false;
|
|
783
|
-
}
|
|
784
|
-
if (filter && !this.agentThinkingOptionMatchesFilter(agent, filter)) {
|
|
785
|
-
return false;
|
|
786
|
-
}
|
|
787
|
-
if (filter && !this.matchesAgentStructuralFilter(agent, project, filter)) {
|
|
788
|
-
return false;
|
|
789
|
-
}
|
|
790
|
-
return true;
|
|
791
|
-
}
|
|
792
|
-
getAgentUpdateTargetId(update) {
|
|
793
|
-
return update.kind === "remove" ? update.agentId : update.agent.id;
|
|
794
|
-
}
|
|
795
|
-
bufferOrEmitAgentUpdate(subscription, payload) {
|
|
796
|
-
if (payload.kind === "upsert" && !this.isProviderVisibleToClient(payload.agent.provider)) {
|
|
797
|
-
return;
|
|
798
|
-
}
|
|
799
|
-
if (subscription.isBootstrapping) {
|
|
800
|
-
subscription.pendingUpdatesByAgentId.set(this.getAgentUpdateTargetId(payload), payload);
|
|
801
|
-
return;
|
|
802
|
-
}
|
|
803
|
-
this.emit({
|
|
804
|
-
type: "agent_update",
|
|
805
|
-
payload,
|
|
806
|
-
});
|
|
807
|
-
}
|
|
808
|
-
async emitStoredAgentUpdate(record) {
|
|
809
|
-
const payload = this.buildStoredAgentPayload(record);
|
|
810
|
-
const subscription = this.agentUpdatesSubscription;
|
|
811
|
-
if (!subscription) {
|
|
812
|
-
return payload;
|
|
813
|
-
}
|
|
814
|
-
const project = payload.workspaceId
|
|
815
|
-
? await this.buildProjectPlacementForWorkspaceId(payload.workspaceId)
|
|
816
|
-
: null;
|
|
817
|
-
if (!project) {
|
|
818
|
-
this.bufferOrEmitAgentUpdate(subscription, {
|
|
819
|
-
kind: "remove",
|
|
820
|
-
agentId: payload.id,
|
|
821
|
-
});
|
|
822
|
-
return payload;
|
|
823
|
-
}
|
|
824
|
-
const matches = this.matchesAgentFilter({
|
|
825
|
-
agent: payload,
|
|
826
|
-
project,
|
|
827
|
-
filter: subscription.filter,
|
|
828
|
-
});
|
|
829
|
-
this.bufferOrEmitAgentUpdate(subscription, matches
|
|
830
|
-
? {
|
|
831
|
-
kind: "upsert",
|
|
832
|
-
agent: payload,
|
|
833
|
-
project,
|
|
834
|
-
}
|
|
835
|
-
: {
|
|
836
|
-
kind: "remove",
|
|
837
|
-
agentId: payload.id,
|
|
838
|
-
});
|
|
839
|
-
return payload;
|
|
840
|
-
}
|
|
841
|
-
flushBootstrappedAgentUpdates(options) {
|
|
842
|
-
const subscription = this.agentUpdatesSubscription;
|
|
843
|
-
if (!subscription || !subscription.isBootstrapping) {
|
|
844
|
-
return;
|
|
845
|
-
}
|
|
846
|
-
subscription.isBootstrapping = false;
|
|
847
|
-
const pending = Array.from(subscription.pendingUpdatesByAgentId.values());
|
|
848
|
-
subscription.pendingUpdatesByAgentId.clear();
|
|
849
|
-
for (const payload of pending) {
|
|
850
|
-
if (payload.kind === "upsert") {
|
|
851
|
-
const snapshotUpdatedAt = options?.snapshotUpdatedAtByAgentId?.get(payload.agent.id);
|
|
852
|
-
if (typeof snapshotUpdatedAt === "number") {
|
|
853
|
-
const updateUpdatedAt = Date.parse(payload.agent.updatedAt);
|
|
854
|
-
if (!Number.isNaN(updateUpdatedAt) && updateUpdatedAt <= snapshotUpdatedAt) {
|
|
855
|
-
continue;
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
this.emit({
|
|
860
|
-
type: "agent_update",
|
|
861
|
-
payload,
|
|
862
|
-
});
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
async findExactWorkspaceByDirectory(cwd, options) {
|
|
866
|
-
const normalizedCwd = await this.resolveWorkspaceDirectory(cwd, options);
|
|
867
|
-
const workspaces = await this.workspaceRegistry.list();
|
|
868
|
-
return workspaces.find((workspace) => workspace.cwd === normalizedCwd) ?? null;
|
|
869
|
-
}
|
|
870
|
-
async resolveWorkspaceDirectory(cwd, options) {
|
|
871
|
-
const normalizedCwd = resolve(cwd);
|
|
872
|
-
if (options?.refreshGit === false) {
|
|
873
|
-
const snapshot = this.workspaceGitService.peekSnapshot(normalizedCwd);
|
|
874
|
-
return resolve(snapshot?.git.repoRoot ?? normalizedCwd);
|
|
875
|
-
}
|
|
876
|
-
const checkout = await this.workspaceGitService.getCheckout(normalizedCwd);
|
|
877
|
-
return resolve(checkout.worktreeRoot ?? normalizedCwd);
|
|
878
|
-
}
|
|
879
738
|
async buildProjectPlacementForWorkspace(workspace, projectRecord) {
|
|
880
739
|
const project = projectRecord ?? (await this.projectRegistry.get(workspace.projectId));
|
|
881
740
|
if (!project) {
|
|
@@ -891,12 +750,6 @@ export class Session {
|
|
|
891
750
|
};
|
|
892
751
|
}
|
|
893
752
|
async buildProjectPlacementForWorkspaceId(workspaceId) {
|
|
894
|
-
const workspace = await this.workspaceRegistry.get(workspaceId);
|
|
895
|
-
if (!workspace)
|
|
896
|
-
return null;
|
|
897
|
-
return this.buildProjectPlacementForWorkspace(workspace);
|
|
898
|
-
}
|
|
899
|
-
async buildProjectPlacementForExistingWorkspaceProject(workspaceId) {
|
|
900
753
|
const workspace = await this.workspaceRegistry.get(workspaceId);
|
|
901
754
|
if (!workspace)
|
|
902
755
|
return null;
|
|
@@ -905,51 +758,6 @@ export class Session {
|
|
|
905
758
|
return null;
|
|
906
759
|
return this.buildProjectPlacementForWorkspace(workspace, project);
|
|
907
760
|
}
|
|
908
|
-
async forwardAgentUpdate(agent) {
|
|
909
|
-
try {
|
|
910
|
-
const subscription = this.agentUpdatesSubscription;
|
|
911
|
-
const payload = await this.buildAgentPayload(agent);
|
|
912
|
-
if (subscription) {
|
|
913
|
-
const project = payload.workspaceId
|
|
914
|
-
? await this.buildProjectPlacementForWorkspaceId(payload.workspaceId)
|
|
915
|
-
: null;
|
|
916
|
-
if (!project) {
|
|
917
|
-
this.bufferOrEmitAgentUpdate(subscription, {
|
|
918
|
-
kind: "remove",
|
|
919
|
-
agentId: payload.id,
|
|
920
|
-
});
|
|
921
|
-
}
|
|
922
|
-
else {
|
|
923
|
-
const matches = this.matchesAgentFilter({
|
|
924
|
-
agent: payload,
|
|
925
|
-
project,
|
|
926
|
-
filter: subscription.filter,
|
|
927
|
-
});
|
|
928
|
-
if (matches) {
|
|
929
|
-
this.bufferOrEmitAgentUpdate(subscription, {
|
|
930
|
-
kind: "upsert",
|
|
931
|
-
agent: payload,
|
|
932
|
-
project,
|
|
933
|
-
});
|
|
934
|
-
}
|
|
935
|
-
else {
|
|
936
|
-
this.bufferOrEmitAgentUpdate(subscription, {
|
|
937
|
-
kind: "remove",
|
|
938
|
-
agentId: payload.id,
|
|
939
|
-
});
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
}
|
|
943
|
-
// A lifecycle change updates exactly the agent's owning workspace, never
|
|
944
|
-
// every workspace sharing its cwd. Ownership is the agent's workspaceId.
|
|
945
|
-
if (payload.workspaceId) {
|
|
946
|
-
await this.emitWorkspaceUpdateForWorkspaceId(payload.workspaceId);
|
|
947
|
-
}
|
|
948
|
-
}
|
|
949
|
-
catch (error) {
|
|
950
|
-
this.sessionLogger.error({ err: error }, "Failed to emit agent update");
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
761
|
/**
|
|
954
762
|
* Main entry point for processing session messages
|
|
955
763
|
*/
|
|
@@ -1005,6 +813,7 @@ export class Session {
|
|
|
1005
813
|
const promise = this.dispatchVoiceAndControlMessage(msg) ??
|
|
1006
814
|
this.dispatchAgentRewindMessage(msg) ??
|
|
1007
815
|
this.dispatchAgentRelationshipMessage(msg) ??
|
|
816
|
+
this.dispatchAgentTimelineMessage(msg) ??
|
|
1008
817
|
this.dispatchAgentLifecycleMessage(msg) ??
|
|
1009
818
|
this.dispatchAgentConfigMessage(msg) ??
|
|
1010
819
|
this.dispatchCheckoutMessage(msg) ??
|
|
@@ -1081,6 +890,16 @@ export class Session {
|
|
|
1081
890
|
return undefined;
|
|
1082
891
|
}
|
|
1083
892
|
}
|
|
893
|
+
dispatchAgentTimelineMessage(msg) {
|
|
894
|
+
switch (msg.type) {
|
|
895
|
+
case "fetch_agent_timeline_request":
|
|
896
|
+
return this.handleFetchAgentTimelineRequest(msg);
|
|
897
|
+
case "agent.fork_context.request":
|
|
898
|
+
return this.handleAgentForkContextRequest(msg);
|
|
899
|
+
default:
|
|
900
|
+
return undefined;
|
|
901
|
+
}
|
|
902
|
+
}
|
|
1084
903
|
dispatchAgentLifecycleMessage(msg) {
|
|
1085
904
|
switch (msg.type) {
|
|
1086
905
|
case "fetch_agents_request":
|
|
@@ -1115,8 +934,6 @@ export class Session {
|
|
|
1115
934
|
return this.handleRefreshAgentRequest(msg);
|
|
1116
935
|
case "cancel_agent_request":
|
|
1117
936
|
return this.handleCancelAgentRequest(msg.agentId, msg.requestId);
|
|
1118
|
-
case "fetch_agent_timeline_request":
|
|
1119
|
-
return this.handleFetchAgentTimelineRequest(msg);
|
|
1120
937
|
case "agent_permission_response":
|
|
1121
938
|
return this.handleAgentPermissionResponse(msg.agentId, msg.requestId, msg.response);
|
|
1122
939
|
case "clear_agent_attention":
|
|
@@ -1145,6 +962,10 @@ export class Session {
|
|
|
1145
962
|
return this.daemonSession.handleGetStatusRequest(msg);
|
|
1146
963
|
case "daemon.get_pairing_offer.request":
|
|
1147
964
|
return this.daemonSession.handleGetPairingOfferRequest(msg);
|
|
965
|
+
case "diagnostics.request":
|
|
966
|
+
return this.daemonSession.handleDiagnosticsRequest(msg);
|
|
967
|
+
case "daemon.update.request":
|
|
968
|
+
return this.daemonSession.handleUpdateRequest(msg);
|
|
1148
969
|
case "set_daemon_config_request":
|
|
1149
970
|
this.emit({
|
|
1150
971
|
type: "set_daemon_config_response",
|
|
@@ -1352,6 +1173,9 @@ export class Session {
|
|
|
1352
1173
|
resetPeakInflight() {
|
|
1353
1174
|
this.peakInflightRequests = this.inflightRequests;
|
|
1354
1175
|
}
|
|
1176
|
+
getSessionId() {
|
|
1177
|
+
return this.sessionId;
|
|
1178
|
+
}
|
|
1355
1179
|
async handleBinaryFrame(binaryFrame) {
|
|
1356
1180
|
if (binaryFrame.kind === "file_transfer") {
|
|
1357
1181
|
await this.workspaceFilesSession.handleFileTransferFrame(binaryFrame.frame);
|
|
@@ -1360,6 +1184,7 @@ export class Session {
|
|
|
1360
1184
|
this.terminalController.handleBinaryFrame(binaryFrame.frame);
|
|
1361
1185
|
}
|
|
1362
1186
|
async handleRestartServerRequest(requestId, reason) {
|
|
1187
|
+
const lifecycleReason = normalizeClientRestartRpcReason(reason);
|
|
1363
1188
|
const payload = {
|
|
1364
1189
|
status: "restart_requested",
|
|
1365
1190
|
clientId: this.clientId,
|
|
@@ -1368,7 +1193,7 @@ export class Session {
|
|
|
1368
1193
|
payload.reason = reason;
|
|
1369
1194
|
}
|
|
1370
1195
|
payload.requestId = requestId;
|
|
1371
|
-
this.sessionLogger.warn({ reason }, "Restart requested via websocket");
|
|
1196
|
+
this.sessionLogger.warn({ reason: lifecycleReason }, "Restart requested via websocket");
|
|
1372
1197
|
this.emit({
|
|
1373
1198
|
type: "status",
|
|
1374
1199
|
payload,
|
|
@@ -1377,11 +1202,12 @@ export class Session {
|
|
|
1377
1202
|
type: "restart",
|
|
1378
1203
|
clientId: this.clientId,
|
|
1379
1204
|
requestId,
|
|
1380
|
-
|
|
1205
|
+
reason: lifecycleReason,
|
|
1381
1206
|
});
|
|
1382
1207
|
}
|
|
1383
1208
|
async handleShutdownServerRequest(requestId) {
|
|
1384
|
-
|
|
1209
|
+
const reason = CLIENT_SHUTDOWN_RPC_REASON;
|
|
1210
|
+
this.sessionLogger.warn({ reason }, "Shutdown requested via websocket");
|
|
1385
1211
|
this.emit({
|
|
1386
1212
|
type: "status",
|
|
1387
1213
|
payload: {
|
|
@@ -1394,6 +1220,7 @@ export class Session {
|
|
|
1394
1220
|
type: "shutdown",
|
|
1395
1221
|
clientId: this.clientId,
|
|
1396
1222
|
requestId,
|
|
1223
|
+
reason,
|
|
1397
1224
|
});
|
|
1398
1225
|
}
|
|
1399
1226
|
emitLifecycleIntent(intent) {
|
|
@@ -1437,12 +1264,7 @@ export class Session {
|
|
|
1437
1264
|
requestId,
|
|
1438
1265
|
},
|
|
1439
1266
|
});
|
|
1440
|
-
|
|
1441
|
-
this.bufferOrEmitAgentUpdate(this.agentUpdatesSubscription, {
|
|
1442
|
-
kind: "remove",
|
|
1443
|
-
agentId,
|
|
1444
|
-
});
|
|
1445
|
-
}
|
|
1267
|
+
this.agentUpdates.removeAgent(agentId);
|
|
1446
1268
|
if (knownWorkspaceId) {
|
|
1447
1269
|
await this.emitWorkspaceUpdateForWorkspaceId(knownWorkspaceId);
|
|
1448
1270
|
}
|
|
@@ -1465,8 +1287,8 @@ export class Session {
|
|
|
1465
1287
|
agentStorage: this.agentStorage,
|
|
1466
1288
|
logger: this.sessionLogger,
|
|
1467
1289
|
}, agentId);
|
|
1468
|
-
if (this.
|
|
1469
|
-
const payload = await this.
|
|
1290
|
+
if (this.agentUpdates.hasSubscription()) {
|
|
1291
|
+
const payload = await this.agentUpdates.emitStoredRecord(archivedRecord);
|
|
1470
1292
|
if (payload.workspaceId) {
|
|
1471
1293
|
await this.emitWorkspaceUpdateForWorkspaceId(payload.workspaceId);
|
|
1472
1294
|
}
|
|
@@ -1479,7 +1301,7 @@ export class Session {
|
|
|
1479
1301
|
const result = await detachAgentCommand({ agentManager: this.agentManager }, agentId);
|
|
1480
1302
|
const affectedWorkspaceIds = new Set();
|
|
1481
1303
|
if (!result.live) {
|
|
1482
|
-
const payload = await this.
|
|
1304
|
+
const payload = await this.agentUpdates.emitStoredRecord(result.record);
|
|
1483
1305
|
if (payload.workspaceId) {
|
|
1484
1306
|
affectedWorkspaceIds.add(payload.workspaceId);
|
|
1485
1307
|
}
|
|
@@ -1878,12 +1700,13 @@ export class Session {
|
|
|
1878
1700
|
const createAgentConfig = createdWorktree
|
|
1879
1701
|
? { ...config, cwd: createdWorktree.worktree.worktreePath }
|
|
1880
1702
|
: config;
|
|
1881
|
-
const workspaceId = await this.resolveOrCreateWorkspaceIdForCreateAgent({
|
|
1703
|
+
const workspaceId = await this.workspaceProvisioning.resolveOrCreateWorkspaceIdForCreateAgent({
|
|
1882
1704
|
createdWorktree,
|
|
1883
1705
|
requestedWorkspaceId: msg.workspaceId,
|
|
1884
1706
|
cwd: createAgentConfig.cwd,
|
|
1885
1707
|
initialTitle: workspacePromptTitle,
|
|
1886
1708
|
});
|
|
1709
|
+
const createdDirectoryWorkspaceForAgent = !createdWorktree && !msg.workspaceId;
|
|
1887
1710
|
const { snapshot, liveSnapshot } = await createAgentCommand({
|
|
1888
1711
|
agentManager: this.agentManager,
|
|
1889
1712
|
agentStorage: this.agentStorage,
|
|
@@ -1909,11 +1732,8 @@ export class Session {
|
|
|
1909
1732
|
buildSessionConfig: (sessionConfig, gitOptions, legacyWorktreeName, ctx) => this.buildAgentSessionConfig(sessionConfig, gitOptions, legacyWorktreeName, ctx),
|
|
1910
1733
|
});
|
|
1911
1734
|
createdAgentId = snapshot.id;
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
}
|
|
1915
|
-
await this.forwardAgentUpdate(snapshot);
|
|
1916
|
-
if (!createdWorktree && trimmedPrompt) {
|
|
1735
|
+
await this.agentUpdates.forwardLiveAgent(snapshot);
|
|
1736
|
+
if (createdDirectoryWorkspaceForAgent && trimmedPrompt) {
|
|
1917
1737
|
await this.scheduleAutoNameLocalWorkspaceTitleForFirstAgent({
|
|
1918
1738
|
workspaceId,
|
|
1919
1739
|
cwd: createAgentConfig.cwd,
|
|
@@ -2000,7 +1820,7 @@ export class Session {
|
|
|
2000
1820
|
const snapshot = await this.agentManager.resumeAgentFromPersistence(handle, overrides);
|
|
2001
1821
|
await unarchiveAgentState(this.agentStorage, this.agentManager, snapshot.id);
|
|
2002
1822
|
await this.agentManager.hydrateTimelineFromProvider(snapshot.id);
|
|
2003
|
-
await this.
|
|
1823
|
+
await this.agentUpdates.forwardLiveAgent(snapshot);
|
|
2004
1824
|
const timelineSize = this.agentManager.getTimeline(snapshot.id).length;
|
|
2005
1825
|
if (requestId) {
|
|
2006
1826
|
const agentPayload = await this.buildAgentPayload(snapshot);
|
|
@@ -2062,7 +1882,7 @@ export class Session {
|
|
|
2062
1882
|
}
|
|
2063
1883
|
// An imported agent mints its own workspace; ownership is its workspaceId,
|
|
2064
1884
|
// never an existing same-cwd workspace resolved by path.
|
|
2065
|
-
const workspace = await this.createWorkspaceForDirectory(normalized.cwd);
|
|
1885
|
+
const workspace = await this.workspaceProvisioning.createWorkspaceForDirectory(normalized.cwd);
|
|
2066
1886
|
const { snapshot, timelineSize } = await importProviderSession({
|
|
2067
1887
|
request: normalized,
|
|
2068
1888
|
workspaceId: workspace.workspaceId,
|
|
@@ -2135,7 +1955,7 @@ export class Session {
|
|
|
2135
1955
|
snapshot = await this.agentManager.resumeAgentFromPersistence(handle, buildConfigOverrides(record), agentId, extractTimestamps(record));
|
|
2136
1956
|
}
|
|
2137
1957
|
await this.agentManager.hydrateTimelineFromProvider(agentId);
|
|
2138
|
-
await this.
|
|
1958
|
+
await this.agentUpdates.forwardLiveAgent(snapshot);
|
|
2139
1959
|
const timelineSize = this.agentManager.getTimeline(agentId).length;
|
|
2140
1960
|
if (requestId) {
|
|
2141
1961
|
this.emit({
|
|
@@ -2244,8 +2064,8 @@ export class Session {
|
|
|
2244
2064
|
logger: this.sessionLogger,
|
|
2245
2065
|
},
|
|
2246
2066
|
}),
|
|
2247
|
-
checkoutExistingBranch: (cwd, branch) => this.checkoutExistingBranch(cwd, branch),
|
|
2248
|
-
createBranchFromBase: (params) => this.createBranchFromBase(params),
|
|
2067
|
+
checkoutExistingBranch: (cwd, branch) => this.gitMutation.checkoutExistingBranch(cwd, branch),
|
|
2068
|
+
createBranchFromBase: (params) => this.gitMutation.createBranchFromBase(params),
|
|
2249
2069
|
github: this.github,
|
|
2250
2070
|
}, config, gitOptions, legacyWorktreeName, firstAgentContext);
|
|
2251
2071
|
}
|
|
@@ -2290,7 +2110,7 @@ export class Session {
|
|
|
2290
2110
|
branch: result.branchName,
|
|
2291
2111
|
promptTitle: resolveFirstAgentPromptTitle(input.firstAgentContext),
|
|
2292
2112
|
});
|
|
2293
|
-
await this.notifyGitMutation(input.workspace.cwd, "rename-branch");
|
|
2113
|
+
await this.gitMutation.notifyGitMutation(input.workspace.cwd, "rename-branch");
|
|
2294
2114
|
await this.emitWorkspaceUpdateForCwd(input.workspace.cwd);
|
|
2295
2115
|
}
|
|
2296
2116
|
// Generated names may replace the prompt title set at creation, but not a user
|
|
@@ -2311,20 +2131,6 @@ export class Session {
|
|
|
2311
2131
|
updatedAt: new Date().toISOString(),
|
|
2312
2132
|
});
|
|
2313
2133
|
}
|
|
2314
|
-
async writeInitialWorkspaceTitleIfUntitled(workspaceId, title) {
|
|
2315
|
-
if (!title) {
|
|
2316
|
-
return;
|
|
2317
|
-
}
|
|
2318
|
-
const current = await this.workspaceRegistry.get(workspaceId);
|
|
2319
|
-
if (!current || current.title) {
|
|
2320
|
-
return;
|
|
2321
|
-
}
|
|
2322
|
-
await this.workspaceRegistry.upsert({
|
|
2323
|
-
...current,
|
|
2324
|
-
title,
|
|
2325
|
-
updatedAt: new Date().toISOString(),
|
|
2326
|
-
});
|
|
2327
|
-
}
|
|
2328
2134
|
// Wraps the injected workspace-name generator for a directory workspace.
|
|
2329
2135
|
async generateWorkspaceTitleFromContext(input) {
|
|
2330
2136
|
return this.generateWorkspaceName({
|
|
@@ -2366,12 +2172,6 @@ export class Session {
|
|
|
2366
2172
|
firstAgentContext: input.firstAgentContext,
|
|
2367
2173
|
}), { cwd: input.cwd, message: "Failed to auto-name local workspace title" });
|
|
2368
2174
|
}
|
|
2369
|
-
assertSafeGitRef(ref, label) {
|
|
2370
|
-
if (!/^[A-Za-z0-9._/-]+$/.test(ref)) {
|
|
2371
|
-
throw new Error(`Invalid ${label}: ${ref}`);
|
|
2372
|
-
}
|
|
2373
|
-
assertWorktreeSafeGitRef(ref, label);
|
|
2374
|
-
}
|
|
2375
2175
|
isPathWithinRoot(rootPath, candidatePath) {
|
|
2376
2176
|
const resolvedRoot = resolve(rootPath);
|
|
2377
2177
|
const resolvedCandidate = resolve(candidatePath);
|
|
@@ -2380,220 +2180,6 @@ export class Session {
|
|
|
2380
2180
|
}
|
|
2381
2181
|
return resolvedCandidate.startsWith(resolvedRoot + sep);
|
|
2382
2182
|
}
|
|
2383
|
-
async generateCommitMessage(cwd) {
|
|
2384
|
-
const diff = await this.workspaceGitService.getCheckoutDiff(cwd, {
|
|
2385
|
-
mode: "uncommitted",
|
|
2386
|
-
includeStructured: true,
|
|
2387
|
-
});
|
|
2388
|
-
const schema = z.object({
|
|
2389
|
-
message: z
|
|
2390
|
-
.string()
|
|
2391
|
-
.min(1)
|
|
2392
|
-
.max(72)
|
|
2393
|
-
.describe("Concise git commit message, imperative mood, no trailing period."),
|
|
2394
|
-
});
|
|
2395
|
-
const fileList = diff.structured && diff.structured.length > 0
|
|
2396
|
-
? [
|
|
2397
|
-
"Files changed:",
|
|
2398
|
-
...diff.structured.map((file) => {
|
|
2399
|
-
const changeType = diffChangeTypeFor(file);
|
|
2400
|
-
const status = file.status && file.status !== "ok" ? ` [${file.status}]` : "";
|
|
2401
|
-
return `${changeType}\t${file.path}\t(+${file.additions} -${file.deletions})${status}`;
|
|
2402
|
-
}),
|
|
2403
|
-
].join("\n")
|
|
2404
|
-
: "Files changed: (unknown)";
|
|
2405
|
-
const maxPatchChars = 120000;
|
|
2406
|
-
const patch = diff.diff.length > maxPatchChars
|
|
2407
|
-
? `${diff.diff.slice(0, maxPatchChars)}\n\n... (diff truncated to ${maxPatchChars} chars)\n`
|
|
2408
|
-
: diff.diff;
|
|
2409
|
-
const prompt = await buildMetadataPrompt({
|
|
2410
|
-
cwd,
|
|
2411
|
-
workspaceGitService: this.workspaceGitService,
|
|
2412
|
-
contract: "Write a concise git commit message for the changes below.",
|
|
2413
|
-
styles: [
|
|
2414
|
-
{
|
|
2415
|
-
configKey: "commitMessage",
|
|
2416
|
-
default: "Concise, imperative mood, no trailing period.",
|
|
2417
|
-
},
|
|
2418
|
-
],
|
|
2419
|
-
after: [
|
|
2420
|
-
"Return JSON only with a single field 'message'.",
|
|
2421
|
-
"",
|
|
2422
|
-
fileList,
|
|
2423
|
-
"",
|
|
2424
|
-
patch.length > 0 ? patch : "(No diff available)",
|
|
2425
|
-
].join("\n"),
|
|
2426
|
-
});
|
|
2427
|
-
const providers = await resolveStructuredGenerationProviders({
|
|
2428
|
-
cwd,
|
|
2429
|
-
providerSnapshotManager: this.providerSnapshotManager,
|
|
2430
|
-
daemonConfig: this.readStructuredGenerationDaemonConfig(),
|
|
2431
|
-
currentSelection: this.getFocusedAgentSelectionForCwd(cwd),
|
|
2432
|
-
});
|
|
2433
|
-
try {
|
|
2434
|
-
const result = await generateStructuredAgentResponseWithFallback({
|
|
2435
|
-
manager: this.agentManager,
|
|
2436
|
-
cwd,
|
|
2437
|
-
prompt,
|
|
2438
|
-
schema,
|
|
2439
|
-
schemaName: "CommitMessage",
|
|
2440
|
-
maxRetries: 2,
|
|
2441
|
-
providers,
|
|
2442
|
-
persistSession: false,
|
|
2443
|
-
agentConfigOverrides: {
|
|
2444
|
-
title: "Commit generator",
|
|
2445
|
-
internal: true,
|
|
2446
|
-
},
|
|
2447
|
-
});
|
|
2448
|
-
return result.message;
|
|
2449
|
-
}
|
|
2450
|
-
catch (error) {
|
|
2451
|
-
if (error instanceof StructuredAgentResponseError ||
|
|
2452
|
-
error instanceof StructuredAgentFallbackError) {
|
|
2453
|
-
return "Update files";
|
|
2454
|
-
}
|
|
2455
|
-
throw error;
|
|
2456
|
-
}
|
|
2457
|
-
}
|
|
2458
|
-
async generatePullRequestText(cwd, baseRef) {
|
|
2459
|
-
const diff = await this.workspaceGitService.getCheckoutDiff(cwd, {
|
|
2460
|
-
mode: "base",
|
|
2461
|
-
baseRef,
|
|
2462
|
-
includeStructured: true,
|
|
2463
|
-
});
|
|
2464
|
-
const schema = z.object({
|
|
2465
|
-
title: z.string().min(1).max(72),
|
|
2466
|
-
body: z.string().min(1),
|
|
2467
|
-
});
|
|
2468
|
-
const fileList = diff.structured && diff.structured.length > 0
|
|
2469
|
-
? [
|
|
2470
|
-
"Files changed:",
|
|
2471
|
-
...diff.structured.map((file) => {
|
|
2472
|
-
const changeType = diffChangeTypeFor(file);
|
|
2473
|
-
const status = file.status && file.status !== "ok" ? ` [${file.status}]` : "";
|
|
2474
|
-
return `${changeType}\t${file.path}\t(+${file.additions} -${file.deletions})${status}`;
|
|
2475
|
-
}),
|
|
2476
|
-
].join("\n")
|
|
2477
|
-
: "Files changed: (unknown)";
|
|
2478
|
-
const maxPatchChars = 200000;
|
|
2479
|
-
const patch = diff.diff.length > maxPatchChars
|
|
2480
|
-
? `${diff.diff.slice(0, maxPatchChars)}\n\n... (diff truncated to ${maxPatchChars} chars)\n`
|
|
2481
|
-
: diff.diff;
|
|
2482
|
-
const prompt = await buildMetadataPrompt({
|
|
2483
|
-
cwd,
|
|
2484
|
-
workspaceGitService: this.workspaceGitService,
|
|
2485
|
-
contract: "Write a pull request title and body for the changes below.",
|
|
2486
|
-
styles: [
|
|
2487
|
-
{
|
|
2488
|
-
configKey: "pullRequest",
|
|
2489
|
-
default: "Clear, descriptive title; body explaining what changed and why.",
|
|
2490
|
-
},
|
|
2491
|
-
],
|
|
2492
|
-
after: [
|
|
2493
|
-
"Return JSON only with fields 'title' and 'body'.",
|
|
2494
|
-
"",
|
|
2495
|
-
fileList,
|
|
2496
|
-
"",
|
|
2497
|
-
patch.length > 0 ? patch : "(No diff available)",
|
|
2498
|
-
].join("\n"),
|
|
2499
|
-
});
|
|
2500
|
-
const providers = await resolveStructuredGenerationProviders({
|
|
2501
|
-
cwd,
|
|
2502
|
-
providerSnapshotManager: this.providerSnapshotManager,
|
|
2503
|
-
daemonConfig: this.readStructuredGenerationDaemonConfig(),
|
|
2504
|
-
currentSelection: this.getFocusedAgentSelectionForCwd(cwd),
|
|
2505
|
-
});
|
|
2506
|
-
try {
|
|
2507
|
-
return await generateStructuredAgentResponseWithFallback({
|
|
2508
|
-
manager: this.agentManager,
|
|
2509
|
-
cwd,
|
|
2510
|
-
prompt,
|
|
2511
|
-
schema,
|
|
2512
|
-
schemaName: "PullRequest",
|
|
2513
|
-
maxRetries: 2,
|
|
2514
|
-
providers,
|
|
2515
|
-
persistSession: false,
|
|
2516
|
-
agentConfigOverrides: {
|
|
2517
|
-
title: "PR generator",
|
|
2518
|
-
internal: true,
|
|
2519
|
-
},
|
|
2520
|
-
});
|
|
2521
|
-
}
|
|
2522
|
-
catch (error) {
|
|
2523
|
-
if (error instanceof StructuredAgentResponseError ||
|
|
2524
|
-
error instanceof StructuredAgentFallbackError) {
|
|
2525
|
-
return {
|
|
2526
|
-
title: "Update changes",
|
|
2527
|
-
body: "Automated PR generated by Paseo.",
|
|
2528
|
-
};
|
|
2529
|
-
}
|
|
2530
|
-
throw error;
|
|
2531
|
-
}
|
|
2532
|
-
}
|
|
2533
|
-
async ensureCleanWorkingTree(cwd) {
|
|
2534
|
-
const dirty = await this.isWorkingTreeDirty(cwd);
|
|
2535
|
-
if (dirty) {
|
|
2536
|
-
throw new Error("Working directory has uncommitted changes. Commit or stash before switching branches.");
|
|
2537
|
-
}
|
|
2538
|
-
}
|
|
2539
|
-
async isWorkingTreeDirty(cwd) {
|
|
2540
|
-
try {
|
|
2541
|
-
const snapshot = await this.workspaceGitService.getSnapshot(cwd);
|
|
2542
|
-
return snapshot.git.isDirty === true;
|
|
2543
|
-
}
|
|
2544
|
-
catch (error) {
|
|
2545
|
-
throw new Error(`Unable to inspect git status for ${cwd}: ${getErrorMessage(error)}`, {
|
|
2546
|
-
cause: error,
|
|
2547
|
-
});
|
|
2548
|
-
}
|
|
2549
|
-
}
|
|
2550
|
-
async checkoutExistingBranch(cwd, branch) {
|
|
2551
|
-
this.assertSafeGitRef(branch, "branch");
|
|
2552
|
-
const resolution = await this.workspaceGitService.validateBranchRef(cwd, branch);
|
|
2553
|
-
if (resolution.kind === "not-found") {
|
|
2554
|
-
throw new Error(`Branch not found: ${branch}`);
|
|
2555
|
-
}
|
|
2556
|
-
await this.ensureCleanWorkingTree(cwd);
|
|
2557
|
-
const result = await checkoutResolvedBranch({
|
|
2558
|
-
cwd,
|
|
2559
|
-
resolution,
|
|
2560
|
-
});
|
|
2561
|
-
await this.notifyGitMutation(cwd, "switch-branch", { invalidateGithub: true });
|
|
2562
|
-
return result;
|
|
2563
|
-
}
|
|
2564
|
-
async createBranchFromBase(params) {
|
|
2565
|
-
const { cwd, baseBranch, newBranchName } = params;
|
|
2566
|
-
this.assertSafeGitRef(baseBranch, "base branch");
|
|
2567
|
-
this.assertSafeGitRef(newBranchName, "new branch");
|
|
2568
|
-
const baseResolution = await this.workspaceGitService.validateBranchRef(cwd, baseBranch);
|
|
2569
|
-
if (baseResolution.kind === "not-found") {
|
|
2570
|
-
throw new Error(`Base branch not found: ${baseBranch}`);
|
|
2571
|
-
}
|
|
2572
|
-
const exists = await this.doesLocalBranchExist(cwd, newBranchName);
|
|
2573
|
-
if (exists) {
|
|
2574
|
-
throw new Error(`Branch already exists: ${newBranchName}`);
|
|
2575
|
-
}
|
|
2576
|
-
await this.ensureCleanWorkingTree(cwd);
|
|
2577
|
-
await execCommand("git", ["checkout", "-b", newBranchName, baseBranch], {
|
|
2578
|
-
cwd,
|
|
2579
|
-
});
|
|
2580
|
-
await this.notifyGitMutation(cwd, "create-branch");
|
|
2581
|
-
}
|
|
2582
|
-
async doesLocalBranchExist(cwd, branch) {
|
|
2583
|
-
this.assertSafeGitRef(branch, "branch");
|
|
2584
|
-
return this.workspaceGitService.hasLocalBranch(cwd, branch);
|
|
2585
|
-
}
|
|
2586
|
-
async notifyGitMutation(cwd, reason, options) {
|
|
2587
|
-
if (options?.invalidateGithub) {
|
|
2588
|
-
this.github.invalidate({ cwd });
|
|
2589
|
-
}
|
|
2590
|
-
try {
|
|
2591
|
-
await this.workspaceGitService.getSnapshot(cwd, { force: true, reason });
|
|
2592
|
-
}
|
|
2593
|
-
catch (error) {
|
|
2594
|
-
this.sessionLogger.warn({ err: error, cwd, reason }, "Failed to force-refresh workspace git snapshot after mutation");
|
|
2595
|
-
}
|
|
2596
|
-
}
|
|
2597
2183
|
/**
|
|
2598
2184
|
* Handle clearing agent attention flag
|
|
2599
2185
|
*/
|
|
@@ -2797,129 +2383,6 @@ export class Session {
|
|
|
2797
2383
|
});
|
|
2798
2384
|
}
|
|
2799
2385
|
}
|
|
2800
|
-
closeWorkspaceGitWatchTarget(target) {
|
|
2801
|
-
if (target.debounceTimer) {
|
|
2802
|
-
clearTimeout(target.debounceTimer);
|
|
2803
|
-
target.debounceTimer = null;
|
|
2804
|
-
}
|
|
2805
|
-
for (const watcher of target.watchers) {
|
|
2806
|
-
try {
|
|
2807
|
-
watcher.close();
|
|
2808
|
-
}
|
|
2809
|
-
catch {
|
|
2810
|
-
// Ignore watcher close errors
|
|
2811
|
-
}
|
|
2812
|
-
}
|
|
2813
|
-
target.watchers.length = 0;
|
|
2814
|
-
}
|
|
2815
|
-
async removeWorkspaceGitWatchTarget(cwd) {
|
|
2816
|
-
const normalizedCwd = resolve(cwd);
|
|
2817
|
-
const target = this.workspaceGitWatchTargets.get(normalizedCwd);
|
|
2818
|
-
if (target) {
|
|
2819
|
-
this.closeWorkspaceGitWatchTarget(target);
|
|
2820
|
-
this.workspaceGitWatchTargets.delete(normalizedCwd);
|
|
2821
|
-
}
|
|
2822
|
-
}
|
|
2823
|
-
removeWorkspaceGitSubscription(cwd) {
|
|
2824
|
-
const normalizedCwd = resolve(cwd);
|
|
2825
|
-
const target = this.workspaceGitWatchTargets.get(normalizedCwd);
|
|
2826
|
-
if (target) {
|
|
2827
|
-
const unsubscribeFetch = this.workspaceGitFetchSubscriptions.get(normalizedCwd);
|
|
2828
|
-
unsubscribeFetch?.();
|
|
2829
|
-
this.workspaceGitFetchSubscriptions.delete(normalizedCwd);
|
|
2830
|
-
this.closeWorkspaceGitWatchTarget(target);
|
|
2831
|
-
this.workspaceGitWatchTargets.delete(normalizedCwd);
|
|
2832
|
-
}
|
|
2833
|
-
this.workspaceGitSubscriptions.get(normalizedCwd)?.();
|
|
2834
|
-
this.workspaceGitSubscriptions.delete(normalizedCwd);
|
|
2835
|
-
}
|
|
2836
|
-
workspaceGitDescriptorStateKey(workspace) {
|
|
2837
|
-
if (!workspace) {
|
|
2838
|
-
return WORKSPACE_GIT_WATCH_REMOVED_STATE_KEY;
|
|
2839
|
-
}
|
|
2840
|
-
return JSON.stringify([
|
|
2841
|
-
workspace.name,
|
|
2842
|
-
workspace.diffStat ? [workspace.diffStat.additions, workspace.diffStat.deletions] : null,
|
|
2843
|
-
]);
|
|
2844
|
-
}
|
|
2845
|
-
resolveWorkspaceGitWatchTarget(workspaceId) {
|
|
2846
|
-
for (const target of this.workspaceGitWatchTargets.values()) {
|
|
2847
|
-
if (target.workspaceId === workspaceId) {
|
|
2848
|
-
return target;
|
|
2849
|
-
}
|
|
2850
|
-
}
|
|
2851
|
-
return null;
|
|
2852
|
-
}
|
|
2853
|
-
shouldSkipWorkspaceGitWatchUpdate(workspaceId, workspace) {
|
|
2854
|
-
const target = this.resolveWorkspaceGitWatchTarget(workspaceId);
|
|
2855
|
-
if (!target) {
|
|
2856
|
-
return false;
|
|
2857
|
-
}
|
|
2858
|
-
const nextStateKey = this.workspaceGitDescriptorStateKey(workspace);
|
|
2859
|
-
if (target.latestDescriptorStateKey === nextStateKey) {
|
|
2860
|
-
return true;
|
|
2861
|
-
}
|
|
2862
|
-
target.latestDescriptorStateKey = nextStateKey;
|
|
2863
|
-
return false;
|
|
2864
|
-
}
|
|
2865
|
-
rememberWorkspaceGitDescriptorState(workspaceId, workspace) {
|
|
2866
|
-
const target = this.resolveWorkspaceGitWatchTarget(workspaceId);
|
|
2867
|
-
if (!target) {
|
|
2868
|
-
return;
|
|
2869
|
-
}
|
|
2870
|
-
target.latestDescriptorStateKey = this.workspaceGitDescriptorStateKey(workspace);
|
|
2871
|
-
target.lastBranchName = workspace?.name ?? null;
|
|
2872
|
-
}
|
|
2873
|
-
handleWorkspaceGitBranchSnapshot(cwd, branchName) {
|
|
2874
|
-
const target = this.workspaceGitWatchTargets.get(resolve(cwd));
|
|
2875
|
-
if (!target) {
|
|
2876
|
-
return;
|
|
2877
|
-
}
|
|
2878
|
-
const previousBranchName = target.lastBranchName;
|
|
2879
|
-
if (branchName === previousBranchName) {
|
|
2880
|
-
return;
|
|
2881
|
-
}
|
|
2882
|
-
target.lastBranchName = branchName;
|
|
2883
|
-
this.onBranchChanged?.(target.workspaceId, previousBranchName, branchName);
|
|
2884
|
-
}
|
|
2885
|
-
syncWorkspaceGitObservers(workspaces) {
|
|
2886
|
-
for (const workspace of workspaces) {
|
|
2887
|
-
this.syncWorkspaceGitObserver(workspace.workspaceDirectory, {
|
|
2888
|
-
isGit: workspace.projectKind === "git",
|
|
2889
|
-
workspaceId: workspace.id,
|
|
2890
|
-
});
|
|
2891
|
-
this.rememberWorkspaceGitDescriptorState(workspace.workspaceDirectory, workspace);
|
|
2892
|
-
}
|
|
2893
|
-
}
|
|
2894
|
-
syncWorkspaceGitObserver(cwd, options) {
|
|
2895
|
-
const normalizedCwd = resolve(cwd);
|
|
2896
|
-
if (!options.isGit) {
|
|
2897
|
-
this.removeWorkspaceGitSubscription(normalizedCwd);
|
|
2898
|
-
return;
|
|
2899
|
-
}
|
|
2900
|
-
if (this.workspaceGitSubscriptions.has(normalizedCwd)) {
|
|
2901
|
-
return;
|
|
2902
|
-
}
|
|
2903
|
-
const target = {
|
|
2904
|
-
cwd: normalizedCwd,
|
|
2905
|
-
workspaceId: options.workspaceId,
|
|
2906
|
-
watchers: [],
|
|
2907
|
-
debounceTimer: null,
|
|
2908
|
-
refreshPromise: null,
|
|
2909
|
-
refreshQueued: false,
|
|
2910
|
-
latestDescriptorStateKey: null,
|
|
2911
|
-
lastBranchName: null,
|
|
2912
|
-
};
|
|
2913
|
-
this.workspaceGitWatchTargets.set(normalizedCwd, target);
|
|
2914
|
-
const subscription = this.workspaceGitService.registerWorkspace({ cwd: normalizedCwd }, (snapshot) => {
|
|
2915
|
-
this.handleWorkspaceGitBranchSnapshot(normalizedCwd, snapshot.git.currentBranch ?? null);
|
|
2916
|
-
void this.emitWorkspaceUpdateForCwd(normalizedCwd).catch((error) => {
|
|
2917
|
-
this.sessionLogger.warn({ err: error, cwd: normalizedCwd }, "Failed to emit workspace update after git branch snapshot");
|
|
2918
|
-
});
|
|
2919
|
-
this.checkoutSession.emitStatusUpdate(normalizedCwd, snapshot);
|
|
2920
|
-
});
|
|
2921
|
-
this.workspaceGitSubscriptions.set(normalizedCwd, subscription.unsubscribe);
|
|
2922
|
-
}
|
|
2923
2386
|
async handlePaseoWorktreeListRequest(msg) {
|
|
2924
2387
|
return handleWorktreeListRequest({
|
|
2925
2388
|
emit: (message) => this.emit(message),
|
|
@@ -3115,7 +2578,7 @@ export class Session {
|
|
|
3115
2578
|
if (!entry) {
|
|
3116
2579
|
continue;
|
|
3117
2580
|
}
|
|
3118
|
-
if (!
|
|
2581
|
+
if (!matchesAgentUpdatesFilter({
|
|
3119
2582
|
agent: entry.agent,
|
|
3120
2583
|
project: entry.project,
|
|
3121
2584
|
filter,
|
|
@@ -3160,9 +2623,7 @@ export class Session {
|
|
|
3160
2623
|
if (existing) {
|
|
3161
2624
|
return existing;
|
|
3162
2625
|
}
|
|
3163
|
-
const placementPromise =
|
|
3164
|
-
? this.buildProjectPlacementForExistingWorkspaceProject(workspaceId)
|
|
3165
|
-
: this.buildProjectPlacementForWorkspaceId(workspaceId);
|
|
2626
|
+
const placementPromise = this.buildProjectPlacementForWorkspaceId(workspaceId);
|
|
3166
2627
|
placementByWorkspaceId.set(workspaceId, placementPromise);
|
|
3167
2628
|
return placementPromise;
|
|
3168
2629
|
};
|
|
@@ -3230,19 +2691,7 @@ export class Session {
|
|
|
3230
2691
|
statusEnteredAt: null,
|
|
3231
2692
|
activityAt: null,
|
|
3232
2693
|
diffStat,
|
|
3233
|
-
scripts: this.
|
|
3234
|
-
? buildWorkspaceScriptPayloads({
|
|
3235
|
-
workspaceId: workspace.workspaceId,
|
|
3236
|
-
workspaceDirectory: workspace.cwd,
|
|
3237
|
-
paseoConfig: readPaseoConfigForProjection(workspace.cwd, this.sessionLogger),
|
|
3238
|
-
serviceProxy: this.serviceProxy,
|
|
3239
|
-
runtimeStore: this.scriptRuntimeStore,
|
|
3240
|
-
daemonPort: this.getDaemonTcpPort?.() ?? null,
|
|
3241
|
-
serviceProxyPublicBaseUrl: this.serviceProxyPublicBaseUrl,
|
|
3242
|
-
gitMetadata: this.resolveWorkspaceScriptGitMetadata(workspace.cwd),
|
|
3243
|
-
resolveHealth: this.resolveScriptHealth ?? undefined,
|
|
3244
|
-
})
|
|
3245
|
-
: [],
|
|
2694
|
+
scripts: this.buildWorkspaceScriptPayloadSnapshot(workspace.workspaceId, workspace.cwd),
|
|
3246
2695
|
...(resolvedProjectRecord
|
|
3247
2696
|
? {
|
|
3248
2697
|
project: await this.buildProjectPlacementForWorkspace(workspace, resolvedProjectRecord),
|
|
@@ -3411,91 +2860,6 @@ export class Session {
|
|
|
3411
2860
|
});
|
|
3412
2861
|
}
|
|
3413
2862
|
}
|
|
3414
|
-
async findOrCreateWorkspaceForDirectory(cwd) {
|
|
3415
|
-
const inputCwd = resolve(cwd);
|
|
3416
|
-
const normalizedCwd = await this.resolveWorkspaceDirectory(cwd);
|
|
3417
|
-
const existingWorkspace = await this.findExactWorkspaceByDirectory(normalizedCwd, {
|
|
3418
|
-
refreshGit: false,
|
|
3419
|
-
});
|
|
3420
|
-
if (existingWorkspace) {
|
|
3421
|
-
if (existingWorkspace.archivedAt && inputCwd !== normalizedCwd) {
|
|
3422
|
-
const timestamp = new Date().toISOString();
|
|
3423
|
-
const checkout = checkoutLiteFromGitSnapshot(inputCwd, {
|
|
3424
|
-
isGit: false,
|
|
3425
|
-
currentBranch: null,
|
|
3426
|
-
remoteUrl: null,
|
|
3427
|
-
repoRoot: null,
|
|
3428
|
-
isPaseoOwnedWorktree: false,
|
|
3429
|
-
mainRepoRoot: null,
|
|
3430
|
-
});
|
|
3431
|
-
const membership = classifyDirectoryForProjectMembership({ cwd: inputCwd, checkout });
|
|
3432
|
-
const projectRecord = await this.resolveProjectRecordForPlacement({
|
|
3433
|
-
membership,
|
|
3434
|
-
timestamp,
|
|
3435
|
-
});
|
|
3436
|
-
await this.projectRegistry.upsert(projectRecord);
|
|
3437
|
-
const workspaceRecord = createPersistedWorkspaceRecord({
|
|
3438
|
-
workspaceId: generateWorkspaceId(),
|
|
3439
|
-
projectId: projectRecord.projectId,
|
|
3440
|
-
cwd: inputCwd,
|
|
3441
|
-
kind: membership.workspaceKind,
|
|
3442
|
-
displayName: membership.workspaceDisplayName,
|
|
3443
|
-
createdAt: timestamp,
|
|
3444
|
-
updatedAt: timestamp,
|
|
3445
|
-
});
|
|
3446
|
-
await this.workspaceRegistry.upsert(workspaceRecord);
|
|
3447
|
-
return workspaceRecord;
|
|
3448
|
-
}
|
|
3449
|
-
return this.reclassifyOrUnarchiveWorkspaceForDirectory({
|
|
3450
|
-
workspace: existingWorkspace,
|
|
3451
|
-
project: await this.projectRegistry.get(existingWorkspace.projectId),
|
|
3452
|
-
cwd: normalizedCwd,
|
|
3453
|
-
});
|
|
3454
|
-
}
|
|
3455
|
-
return this.createWorkspaceForDirectory(normalizedCwd);
|
|
3456
|
-
}
|
|
3457
|
-
async resolveOrCreateWorkspaceIdForCreateAgent(input) {
|
|
3458
|
-
if (input.createdWorktree) {
|
|
3459
|
-
return input.createdWorktree.workspace.workspaceId;
|
|
3460
|
-
}
|
|
3461
|
-
if (input.requestedWorkspaceId) {
|
|
3462
|
-
return input.requestedWorkspaceId;
|
|
3463
|
-
}
|
|
3464
|
-
return (await this.createWorkspaceForDirectory(input.cwd, input.initialTitle)).workspaceId;
|
|
3465
|
-
}
|
|
3466
|
-
async createWorkspaceForDirectory(cwd, title) {
|
|
3467
|
-
const checkout = await this.workspaceGitService.getCheckout(cwd);
|
|
3468
|
-
const membership = classifyDirectoryForProjectMembership({ cwd, checkout });
|
|
3469
|
-
const timestamp = new Date().toISOString();
|
|
3470
|
-
const projectRecord = await this.resolveProjectRecordForPlacement({
|
|
3471
|
-
membership,
|
|
3472
|
-
timestamp,
|
|
3473
|
-
});
|
|
3474
|
-
await this.projectRegistry.upsert(projectRecord);
|
|
3475
|
-
const workspaceRecord = createPersistedWorkspaceRecord({
|
|
3476
|
-
workspaceId: generateWorkspaceId(),
|
|
3477
|
-
projectId: projectRecord.projectId,
|
|
3478
|
-
cwd,
|
|
3479
|
-
kind: membership.workspaceKind,
|
|
3480
|
-
displayName: membership.workspaceDisplayName,
|
|
3481
|
-
title: title ?? null,
|
|
3482
|
-
createdAt: timestamp,
|
|
3483
|
-
updatedAt: timestamp,
|
|
3484
|
-
});
|
|
3485
|
-
await this.workspaceRegistry.upsert(workspaceRecord);
|
|
3486
|
-
return workspaceRecord;
|
|
3487
|
-
}
|
|
3488
|
-
async findOrCreateProjectForDirectory(cwd) {
|
|
3489
|
-
const normalizedCwd = resolve(cwd);
|
|
3490
|
-
const checkout = await this.workspaceGitService.getCheckout(normalizedCwd);
|
|
3491
|
-
const membership = classifyDirectoryForProjectMembership({ cwd: normalizedCwd, checkout });
|
|
3492
|
-
const projectRecord = await this.resolveProjectRecordForPlacement({
|
|
3493
|
-
membership,
|
|
3494
|
-
timestamp: new Date().toISOString(),
|
|
3495
|
-
});
|
|
3496
|
-
await this.projectRegistry.upsert(projectRecord);
|
|
3497
|
-
return projectRecord;
|
|
3498
|
-
}
|
|
3499
2863
|
buildProjectDescriptor(project) {
|
|
3500
2864
|
return {
|
|
3501
2865
|
projectId: project.projectId,
|
|
@@ -3505,64 +2869,6 @@ export class Session {
|
|
|
3505
2869
|
projectKind: project.kind,
|
|
3506
2870
|
};
|
|
3507
2871
|
}
|
|
3508
|
-
async reclassifyOrUnarchiveWorkspaceForDirectory(input) {
|
|
3509
|
-
const checkout = await this.workspaceGitService.getCheckout(input.cwd);
|
|
3510
|
-
const membership = classifyDirectoryForProjectMembership({ cwd: input.cwd, checkout });
|
|
3511
|
-
const timestamp = new Date().toISOString();
|
|
3512
|
-
const projectRecord = await this.resolveProjectRecordForPlacement({
|
|
3513
|
-
membership,
|
|
3514
|
-
timestamp,
|
|
3515
|
-
});
|
|
3516
|
-
const projectId = projectRecord.projectId;
|
|
3517
|
-
const kind = membership.workspaceKind;
|
|
3518
|
-
const displayName = membership.workspaceDisplayName;
|
|
3519
|
-
if (input.workspace.projectId === projectId &&
|
|
3520
|
-
input.workspace.kind === kind &&
|
|
3521
|
-
input.workspace.displayName === displayName) {
|
|
3522
|
-
if (!input.project) {
|
|
3523
|
-
await this.projectRegistry.upsert(projectRecord);
|
|
3524
|
-
}
|
|
3525
|
-
return this.ensureWorkspaceRecordUnarchived(input.workspace);
|
|
3526
|
-
}
|
|
3527
|
-
await this.projectRegistry.upsert(projectRecord);
|
|
3528
|
-
const nextWorkspace = {
|
|
3529
|
-
...input.workspace,
|
|
3530
|
-
workspaceId: input.workspace.workspaceId,
|
|
3531
|
-
projectId,
|
|
3532
|
-
cwd: input.cwd,
|
|
3533
|
-
kind,
|
|
3534
|
-
displayName,
|
|
3535
|
-
archivedAt: null,
|
|
3536
|
-
updatedAt: timestamp,
|
|
3537
|
-
};
|
|
3538
|
-
await this.workspaceRegistry.upsert(nextWorkspace);
|
|
3539
|
-
return nextWorkspace;
|
|
3540
|
-
}
|
|
3541
|
-
async resolveProjectRecordForPlacement(input) {
|
|
3542
|
-
const rootPath = input.membership.projectRootPath;
|
|
3543
|
-
const kind = input.membership.projectKind;
|
|
3544
|
-
const projects = await this.projectRegistry.list();
|
|
3545
|
-
const existingProject = projects.find((project) => !project.archivedAt && project.rootPath === rootPath) ??
|
|
3546
|
-
projects.find((project) => project.rootPath === rootPath) ??
|
|
3547
|
-
null;
|
|
3548
|
-
if (!existingProject) {
|
|
3549
|
-
return createPersistedProjectRecord({
|
|
3550
|
-
projectId: input.membership.projectKey,
|
|
3551
|
-
rootPath,
|
|
3552
|
-
kind,
|
|
3553
|
-
displayName: input.membership.projectName,
|
|
3554
|
-
createdAt: input.timestamp,
|
|
3555
|
-
updatedAt: input.timestamp,
|
|
3556
|
-
});
|
|
3557
|
-
}
|
|
3558
|
-
return {
|
|
3559
|
-
...existingProject,
|
|
3560
|
-
rootPath,
|
|
3561
|
-
kind,
|
|
3562
|
-
archivedAt: null,
|
|
3563
|
-
updatedAt: input.timestamp,
|
|
3564
|
-
};
|
|
3565
|
-
}
|
|
3566
2872
|
async unarchiveOwningWorkspaceForAgent(agentId) {
|
|
3567
2873
|
const record = await this.agentStorage.get(agentId);
|
|
3568
2874
|
if (!record?.workspaceId) {
|
|
@@ -3582,7 +2888,7 @@ export class Session {
|
|
|
3582
2888
|
// missing, so the record must point at a real directory first.
|
|
3583
2889
|
await this.recreateOwningWorktreeForRestore(workspace, workspace.branch);
|
|
3584
2890
|
}
|
|
3585
|
-
await this.ensureWorkspaceRecordUnarchived(workspace);
|
|
2891
|
+
await this.workspaceProvisioning.ensureWorkspaceRecordUnarchived(workspace);
|
|
3586
2892
|
await this.emitWorkspaceUpdatesForWorkspaceIds([workspace.workspaceId]);
|
|
3587
2893
|
}
|
|
3588
2894
|
async recreateOwningWorktreeForRestore(workspace, branch) {
|
|
@@ -3635,26 +2941,6 @@ export class Session {
|
|
|
3635
2941
|
});
|
|
3636
2942
|
}
|
|
3637
2943
|
}
|
|
3638
|
-
async ensureWorkspaceRecordUnarchived(workspace) {
|
|
3639
|
-
const project = await this.projectRegistry.get(workspace.projectId);
|
|
3640
|
-
if (!workspace.archivedAt && (!project || !project.archivedAt)) {
|
|
3641
|
-
return workspace;
|
|
3642
|
-
}
|
|
3643
|
-
const timestamp = new Date().toISOString();
|
|
3644
|
-
let unarchivedWorkspace = workspace;
|
|
3645
|
-
if (workspace.archivedAt) {
|
|
3646
|
-
unarchivedWorkspace = { ...workspace, archivedAt: null, updatedAt: timestamp };
|
|
3647
|
-
await this.workspaceRegistry.upsert(unarchivedWorkspace);
|
|
3648
|
-
}
|
|
3649
|
-
if (project?.archivedAt) {
|
|
3650
|
-
await this.projectRegistry.upsert({
|
|
3651
|
-
...project,
|
|
3652
|
-
archivedAt: null,
|
|
3653
|
-
updatedAt: timestamp,
|
|
3654
|
-
});
|
|
3655
|
-
}
|
|
3656
|
-
return unarchivedWorkspace;
|
|
3657
|
-
}
|
|
3658
2944
|
async createPaseoWorktree(input, options) {
|
|
3659
2945
|
const result = await createPaseoWorktree(input, {
|
|
3660
2946
|
github: this.github,
|
|
@@ -3666,8 +2952,8 @@ export class Session {
|
|
|
3666
2952
|
workspaceGitService: this.workspaceGitService,
|
|
3667
2953
|
});
|
|
3668
2954
|
void Promise.all([
|
|
3669
|
-
this.notifyGitMutation(input.cwd, "create-worktree"),
|
|
3670
|
-
this.notifyGitMutation(result.worktree.worktreePath, "create-worktree"),
|
|
2955
|
+
this.gitMutation.notifyGitMutation(input.cwd, "create-worktree"),
|
|
2956
|
+
this.gitMutation.notifyGitMutation(result.worktree.worktreePath, "create-worktree"),
|
|
3671
2957
|
]).catch((error) => {
|
|
3672
2958
|
this.sessionLogger.warn({ err: error, cwd: input.cwd, worktreePath: result.worktree.worktreePath }, "Failed to warm git snapshots after creating worktree");
|
|
3673
2959
|
});
|
|
@@ -3691,10 +2977,7 @@ export class Session {
|
|
|
3691
2977
|
workspaceRegistry: this.workspaceRegistry,
|
|
3692
2978
|
});
|
|
3693
2979
|
if (!existingWorkspace) {
|
|
3694
|
-
|
|
3695
|
-
if (watchTarget) {
|
|
3696
|
-
this.removeWorkspaceGitSubscription(watchTarget.cwd);
|
|
3697
|
-
}
|
|
2980
|
+
this.workspaceGitObserver.removeForWorkspaceId(workspaceId);
|
|
3698
2981
|
return;
|
|
3699
2982
|
}
|
|
3700
2983
|
if (!existingWorkspace.archivedAt) {
|
|
@@ -3716,9 +2999,8 @@ export class Session {
|
|
|
3716
2999
|
// store is keyed by the opaque workspace id. Each cleanup uses its own key so an
|
|
3717
3000
|
// opaque id is never resolved as a filesystem path.
|
|
3718
3001
|
async teardownArchivedWorkspace(input) {
|
|
3719
|
-
|
|
3002
|
+
this.workspaceGitObserver.removeForCwd(input.cwd);
|
|
3720
3003
|
this.scriptRuntimeStore?.removeForWorkspace(input.workspaceId);
|
|
3721
|
-
this.removeWorkspaceGitSubscription(input.cwd);
|
|
3722
3004
|
}
|
|
3723
3005
|
async reconcileAndEmitWorkspaceUpdates() {
|
|
3724
3006
|
if (!this.workspaceUpdatesSubscription) {
|
|
@@ -3793,10 +3075,10 @@ export class Session {
|
|
|
3793
3075
|
? workspace
|
|
3794
3076
|
: null;
|
|
3795
3077
|
if (options?.dedupeGitState &&
|
|
3796
|
-
this.
|
|
3078
|
+
this.workspaceGitObserver.shouldSkipUpdate(workspaceId, nextWorkspace)) {
|
|
3797
3079
|
continue;
|
|
3798
3080
|
}
|
|
3799
|
-
this.
|
|
3081
|
+
this.workspaceGitObserver.recordDescriptorState(workspaceId, nextWorkspace);
|
|
3800
3082
|
if (!nextWorkspace) {
|
|
3801
3083
|
subscription.lastEmittedByWorkspaceId.delete(workspaceId);
|
|
3802
3084
|
this.bufferOrEmitWorkspaceUpdate(subscription, await this.buildWorkspaceRemoveUpdatePayload(workspaceId, options?.removedProjectId));
|
|
@@ -3818,16 +3100,6 @@ export class Session {
|
|
|
3818
3100
|
void this.reconcileAndEmitWorkspaceUpdates();
|
|
3819
3101
|
}
|
|
3820
3102
|
}
|
|
3821
|
-
recordWorkspaceGitDescriptorState(workspaceId, nextWorkspace) {
|
|
3822
|
-
const watchTarget = this.resolveWorkspaceGitWatchTarget(workspaceId);
|
|
3823
|
-
if (watchTarget && this.onBranchChanged) {
|
|
3824
|
-
const newBranchName = nextWorkspace?.name ?? null;
|
|
3825
|
-
if (newBranchName !== watchTarget.lastBranchName) {
|
|
3826
|
-
this.onBranchChanged(workspaceId, watchTarget.lastBranchName, newBranchName);
|
|
3827
|
-
}
|
|
3828
|
-
}
|
|
3829
|
-
this.rememberWorkspaceGitDescriptorState(workspaceId, nextWorkspace);
|
|
3830
|
-
}
|
|
3831
3103
|
async buildWorkspaceRemoveUpdatePayload(workspaceId, removedProjectId) {
|
|
3832
3104
|
if (removedProjectId) {
|
|
3833
3105
|
return { kind: "remove", id: workspaceId, removedProjectId };
|
|
@@ -3876,12 +3148,10 @@ export class Session {
|
|
|
3876
3148
|
const subscriptionId = resolveSubscriptionId(request.subscribe, requestedSubscriptionId);
|
|
3877
3149
|
try {
|
|
3878
3150
|
if (subscriptionId) {
|
|
3879
|
-
this.
|
|
3151
|
+
this.agentUpdates.beginSubscription({
|
|
3880
3152
|
subscriptionId,
|
|
3881
3153
|
filter: request.filter,
|
|
3882
|
-
|
|
3883
|
-
pendingUpdatesByAgentId: new Map(),
|
|
3884
|
-
};
|
|
3154
|
+
});
|
|
3885
3155
|
}
|
|
3886
3156
|
const payload = await this.listFetchAgentsEntries(request);
|
|
3887
3157
|
const snapshotUpdatedAtByAgentId = new Map();
|
|
@@ -3899,13 +3169,13 @@ export class Session {
|
|
|
3899
3169
|
...payload,
|
|
3900
3170
|
},
|
|
3901
3171
|
});
|
|
3902
|
-
if (subscriptionId
|
|
3903
|
-
this.
|
|
3172
|
+
if (subscriptionId) {
|
|
3173
|
+
this.agentUpdates.flushBootstrapped(subscriptionId, { snapshotUpdatedAtByAgentId });
|
|
3904
3174
|
}
|
|
3905
3175
|
}
|
|
3906
3176
|
catch (error) {
|
|
3907
|
-
if (subscriptionId
|
|
3908
|
-
this.
|
|
3177
|
+
if (subscriptionId) {
|
|
3178
|
+
this.agentUpdates.clearSubscription(subscriptionId);
|
|
3909
3179
|
}
|
|
3910
3180
|
const code = error instanceof SessionRequestError ? error.code : "fetch_agents_failed";
|
|
3911
3181
|
const message = error instanceof Error ? error.message : "Failed to fetch agents";
|
|
@@ -4004,7 +3274,7 @@ export class Session {
|
|
|
4004
3274
|
};
|
|
4005
3275
|
}
|
|
4006
3276
|
const payload = await this.listFetchWorkspacesEntries(request);
|
|
4007
|
-
this.
|
|
3277
|
+
this.workspaceGitObserver.syncObservers(payload.entries);
|
|
4008
3278
|
this.sessionLogger.debug({
|
|
4009
3279
|
requestId: request.requestId,
|
|
4010
3280
|
subscriptionId,
|
|
@@ -4246,7 +3516,7 @@ export class Session {
|
|
|
4246
3516
|
for (const workspaceRecord of await this.workspaceRegistry.list()) {
|
|
4247
3517
|
workspacesBefore.set(workspaceRecord.workspaceId, workspaceRecord);
|
|
4248
3518
|
}
|
|
4249
|
-
const workspace = await this.findOrCreateWorkspaceForDirectory(cwd);
|
|
3519
|
+
const workspace = await this.workspaceProvisioning.findOrCreateWorkspaceForDirectory(cwd);
|
|
4250
3520
|
const project = await this.projectRegistry.get(workspace.projectId);
|
|
4251
3521
|
await this.syncWorkspaceGitObserverForWorkspace(workspace);
|
|
4252
3522
|
const descriptor = await this.describeWorkspaceRecord(workspace);
|
|
@@ -4315,7 +3585,7 @@ export class Session {
|
|
|
4315
3585
|
for (const project of await this.projectRegistry.list()) {
|
|
4316
3586
|
projectsBefore.set(project.projectId, project);
|
|
4317
3587
|
}
|
|
4318
|
-
const project = await this.findOrCreateProjectForDirectory(cwd);
|
|
3588
|
+
const project = await this.workspaceProvisioning.findOrCreateProjectForDirectory(cwd);
|
|
4319
3589
|
this.sessionLogger.info({
|
|
4320
3590
|
requestedCwd,
|
|
4321
3591
|
resolvedCwd: cwd,
|
|
@@ -4345,98 +3615,13 @@ export class Session {
|
|
|
4345
3615
|
});
|
|
4346
3616
|
}
|
|
4347
3617
|
}
|
|
3618
|
+
// Named accessor: the workspace descriptor builder and the git-watch test both read a workspace's
|
|
3619
|
+
// scripts snapshot through here; the workspace-scripts module owns the payload assembly.
|
|
4348
3620
|
buildWorkspaceScriptPayloadSnapshot(workspaceId, workspaceDirectory) {
|
|
4349
|
-
|
|
4350
|
-
return [];
|
|
4351
|
-
}
|
|
4352
|
-
return buildWorkspaceScriptPayloads({
|
|
4353
|
-
workspaceId,
|
|
4354
|
-
workspaceDirectory,
|
|
4355
|
-
paseoConfig: readPaseoConfigForProjection(workspaceDirectory, this.sessionLogger),
|
|
4356
|
-
serviceProxy: this.serviceProxy,
|
|
4357
|
-
runtimeStore: this.scriptRuntimeStore,
|
|
4358
|
-
daemonPort: this.getDaemonTcpPort?.() ?? null,
|
|
4359
|
-
serviceProxyPublicBaseUrl: this.serviceProxyPublicBaseUrl,
|
|
4360
|
-
gitMetadata: this.resolveWorkspaceScriptGitMetadata(workspaceDirectory),
|
|
4361
|
-
resolveHealth: this.resolveScriptHealth ?? undefined,
|
|
4362
|
-
});
|
|
4363
|
-
}
|
|
4364
|
-
resolveWorkspaceScriptGitMetadata(workspaceDirectory) {
|
|
4365
|
-
const snapshot = this.workspaceGitService.peekSnapshot(workspaceDirectory);
|
|
4366
|
-
if (!snapshot) {
|
|
4367
|
-
return undefined;
|
|
4368
|
-
}
|
|
4369
|
-
return {
|
|
4370
|
-
projectSlug: deriveProjectSlug(workspaceDirectory, snapshot.git.isGit ? snapshot.git.remoteUrl : null),
|
|
4371
|
-
currentBranch: snapshot.git.currentBranch,
|
|
4372
|
-
};
|
|
3621
|
+
return this.workspaceScripts.buildSnapshot(workspaceId, workspaceDirectory);
|
|
4373
3622
|
}
|
|
4374
|
-
|
|
4375
|
-
this.
|
|
4376
|
-
type: "script_status_update",
|
|
4377
|
-
payload: {
|
|
4378
|
-
workspaceId,
|
|
4379
|
-
scripts: this.buildWorkspaceScriptPayloadSnapshot(workspaceId, workspaceDirectory),
|
|
4380
|
-
},
|
|
4381
|
-
});
|
|
4382
|
-
}
|
|
4383
|
-
async handleStartWorkspaceScriptRequest(request) {
|
|
4384
|
-
try {
|
|
4385
|
-
if (!this.terminalManager || !this.serviceProxy || !this.scriptRuntimeStore) {
|
|
4386
|
-
throw new Error("Workspace scripts are not available on this daemon");
|
|
4387
|
-
}
|
|
4388
|
-
const workspace = await this.workspaceRegistry.get(request.workspaceId);
|
|
4389
|
-
if (!workspace) {
|
|
4390
|
-
throw new Error(`Workspace not found: ${request.workspaceId}`);
|
|
4391
|
-
}
|
|
4392
|
-
const gitMetadata = await this.workspaceGitService.getWorkspaceGitMetadata(workspace.cwd);
|
|
4393
|
-
const serviceResult = await spawnWorkspaceScript({
|
|
4394
|
-
repoRoot: workspace.cwd,
|
|
4395
|
-
workspaceId: workspace.workspaceId,
|
|
4396
|
-
projectSlug: gitMetadata.projectSlug,
|
|
4397
|
-
branchName: gitMetadata.currentBranch,
|
|
4398
|
-
scriptName: request.scriptName,
|
|
4399
|
-
daemonPort: this.getDaemonTcpPort?.() ?? null,
|
|
4400
|
-
daemonListenHost: this.getDaemonTcpHost?.() ?? null,
|
|
4401
|
-
serviceProxyPublicBaseUrl: this.serviceProxyPublicBaseUrl,
|
|
4402
|
-
serviceProxy: this.serviceProxy,
|
|
4403
|
-
runtimeStore: this.scriptRuntimeStore,
|
|
4404
|
-
terminalManager: this.terminalManager,
|
|
4405
|
-
logger: this.sessionLogger,
|
|
4406
|
-
onLifecycleChanged: () => {
|
|
4407
|
-
this.emitWorkspaceScriptStatusUpdate(workspace.workspaceId, workspace.cwd);
|
|
4408
|
-
},
|
|
4409
|
-
});
|
|
4410
|
-
this.emitWorkspaceScriptStatusUpdate(workspace.workspaceId, workspace.cwd);
|
|
4411
|
-
this.emit({
|
|
4412
|
-
type: "start_workspace_script_response",
|
|
4413
|
-
payload: {
|
|
4414
|
-
requestId: request.requestId,
|
|
4415
|
-
workspaceId: request.workspaceId,
|
|
4416
|
-
scriptName: request.scriptName,
|
|
4417
|
-
terminalId: serviceResult.terminalId,
|
|
4418
|
-
error: null,
|
|
4419
|
-
},
|
|
4420
|
-
});
|
|
4421
|
-
}
|
|
4422
|
-
catch (error) {
|
|
4423
|
-
const message = error instanceof Error ? error.message : "Failed to start workspace script";
|
|
4424
|
-
this.sessionLogger.error({
|
|
4425
|
-
err: error,
|
|
4426
|
-
workspaceId: request.workspaceId,
|
|
4427
|
-
scriptName: request.scriptName,
|
|
4428
|
-
}, "Failed to start workspace script");
|
|
4429
|
-
this.emit({
|
|
4430
|
-
type: "start_workspace_script_response",
|
|
4431
|
-
payload: {
|
|
4432
|
-
requestId: request.requestId,
|
|
4433
|
-
workspaceId: request.workspaceId,
|
|
4434
|
-
scriptName: request.scriptName,
|
|
4435
|
-
terminalId: null,
|
|
4436
|
-
error: message,
|
|
4437
|
-
},
|
|
4438
|
-
});
|
|
4439
|
-
}
|
|
3623
|
+
handleStartWorkspaceScriptRequest(request) {
|
|
3624
|
+
return this.workspaceScripts.start(request);
|
|
4440
3625
|
}
|
|
4441
3626
|
// COMPAT(desktopEditorBridge): added in v0.1.88, remove after 2026-12-03 once old clients no longer call daemon editor RPCs.
|
|
4442
3627
|
async handleLegacyListAvailableEditorsRequest(request) {
|
|
@@ -4489,7 +3674,7 @@ export class Session {
|
|
|
4489
3674
|
getDaemonTcpHost: this.getDaemonTcpHost,
|
|
4490
3675
|
serviceProxyPublicBaseUrl: this.serviceProxyPublicBaseUrl,
|
|
4491
3676
|
onScriptsChanged: (workspaceId, workspaceDirectory) => {
|
|
4492
|
-
this.
|
|
3677
|
+
this.workspaceScripts.emitStatusUpdate(workspaceId, workspaceDirectory);
|
|
4493
3678
|
},
|
|
4494
3679
|
}, input, options);
|
|
4495
3680
|
}
|
|
@@ -4850,6 +4035,51 @@ export class Session {
|
|
|
4850
4035
|
});
|
|
4851
4036
|
}
|
|
4852
4037
|
}
|
|
4038
|
+
async handleAgentForkContextRequest(msg) {
|
|
4039
|
+
try {
|
|
4040
|
+
const snapshot = await ensureAgentLoaded(msg.agentId, {
|
|
4041
|
+
agentManager: this.agentManager,
|
|
4042
|
+
agentStorage: this.agentStorage,
|
|
4043
|
+
logger: this.sessionLogger,
|
|
4044
|
+
});
|
|
4045
|
+
const agentPayload = await this.buildAgentPayload(snapshot);
|
|
4046
|
+
const rows = this.agentManager.fetchTimeline(msg.agentId, {
|
|
4047
|
+
direction: "tail",
|
|
4048
|
+
limit: 0,
|
|
4049
|
+
}).rows;
|
|
4050
|
+
const forkContext = buildAgentForkContextAttachment({
|
|
4051
|
+
rows,
|
|
4052
|
+
boundaryMessageId: msg.boundaryMessageId,
|
|
4053
|
+
agentTitle: agentPayload.title,
|
|
4054
|
+
cwd: snapshot.cwd,
|
|
4055
|
+
});
|
|
4056
|
+
this.emit({
|
|
4057
|
+
type: "agent.fork_context.response",
|
|
4058
|
+
payload: {
|
|
4059
|
+
requestId: msg.requestId,
|
|
4060
|
+
agentId: msg.agentId,
|
|
4061
|
+
attachment: forkContext.attachment,
|
|
4062
|
+
itemCount: forkContext.itemCount,
|
|
4063
|
+
boundaryMessageId: forkContext.boundaryMessageId,
|
|
4064
|
+
error: null,
|
|
4065
|
+
},
|
|
4066
|
+
});
|
|
4067
|
+
}
|
|
4068
|
+
catch (error) {
|
|
4069
|
+
this.sessionLogger.error({ err: error, agentId: msg.agentId }, "Failed to handle agent.fork_context.request");
|
|
4070
|
+
this.emit({
|
|
4071
|
+
type: "agent.fork_context.response",
|
|
4072
|
+
payload: {
|
|
4073
|
+
requestId: msg.requestId,
|
|
4074
|
+
agentId: msg.agentId,
|
|
4075
|
+
attachment: null,
|
|
4076
|
+
itemCount: 0,
|
|
4077
|
+
boundaryMessageId: msg.boundaryMessageId ?? null,
|
|
4078
|
+
error: error instanceof Error ? error.message : String(error),
|
|
4079
|
+
},
|
|
4080
|
+
});
|
|
4081
|
+
}
|
|
4082
|
+
}
|
|
4853
4083
|
async handleSendAgentMessageRequest(msg) {
|
|
4854
4084
|
const resolved = await this.resolveAgentIdentifier(msg.agentId);
|
|
4855
4085
|
if (!resolved.ok) {
|
|
@@ -5097,29 +4327,16 @@ export class Session {
|
|
|
5097
4327
|
this.unsubscribeAgentEvents();
|
|
5098
4328
|
this.unsubscribeAgentEvents = null;
|
|
5099
4329
|
}
|
|
4330
|
+
this.agentUpdates.dispose();
|
|
5100
4331
|
if (this.unsubscribeTerminalWorkspaceContributionEvents) {
|
|
5101
4332
|
this.unsubscribeTerminalWorkspaceContributionEvents();
|
|
5102
4333
|
this.unsubscribeTerminalWorkspaceContributionEvents = null;
|
|
5103
4334
|
}
|
|
5104
4335
|
this.providerCatalogSession.dispose();
|
|
5105
4336
|
await this.voiceSession.cleanup();
|
|
5106
|
-
// Close MCP clients
|
|
5107
|
-
if (this.agentMcpClient) {
|
|
5108
|
-
try {
|
|
5109
|
-
await this.agentMcpClient.close();
|
|
5110
|
-
}
|
|
5111
|
-
catch (error) {
|
|
5112
|
-
this.sessionLogger.error({ err: error }, "Failed to close Agent MCP client");
|
|
5113
|
-
}
|
|
5114
|
-
this.agentMcpClient = null;
|
|
5115
|
-
this.agentTools = null;
|
|
5116
|
-
}
|
|
5117
4337
|
this.terminalController.dispose();
|
|
5118
4338
|
this.checkoutSession.cleanup();
|
|
5119
|
-
|
|
5120
|
-
unsubscribe();
|
|
5121
|
-
}
|
|
5122
|
-
this.workspaceGitSubscriptions.clear();
|
|
4339
|
+
this.workspaceGitObserver.dispose();
|
|
5123
4340
|
}
|
|
5124
4341
|
}
|
|
5125
4342
|
//# sourceMappingURL=session.js.map
|