@getpaseo/server 0.1.99 → 0.1.101
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/server/executable-resolution/windows.js +3 -0
- package/dist/server/server/agent/agent-manager.d.ts +10 -0
- package/dist/server/server/agent/agent-manager.js +65 -27
- package/dist/server/server/agent/agent-sdk-types.d.ts +8 -0
- 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-registry.js +1 -0
- package/dist/server/server/agent/provider-snapshot-manager.d.ts +4 -0
- package/dist/server/server/agent/provider-snapshot-manager.js +58 -13
- package/dist/server/server/agent/providers/acp-agent.d.ts +39 -2
- package/dist/server/server/agent/providers/acp-agent.js +281 -20
- package/dist/server/server/agent/providers/claude/agent.js +96 -62
- package/dist/server/server/agent/providers/codex-app-server-agent.js +6 -57
- package/dist/server/server/agent/providers/copilot-acp-agent.d.ts +2 -1
- package/dist/server/server/agent/providers/copilot-acp-agent.js +10 -0
- 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 +4 -2
- package/dist/server/server/agent/providers/opencode/server-manager.d.ts +14 -11
- package/dist/server/server/agent/providers/opencode/server-manager.js +149 -91
- package/dist/server/server/agent/providers/opencode/test-server-manager.d.ts +6 -5
- package/dist/server/server/agent/providers/opencode/test-server-manager.js +13 -3
- package/dist/server/server/agent/providers/opencode/test-utils/{test-opencode-runtime.d.ts → test-opencode-harness.d.ts} +11 -11
- package/dist/server/server/agent/providers/opencode/test-utils/{test-opencode-runtime.js → test-opencode-harness.js} +23 -10
- package/dist/server/server/agent/providers/opencode-agent.d.ts +9 -3
- package/dist/server/server/agent/providers/opencode-agent.js +26 -38
- package/dist/server/server/agent/providers/pi/agent.d.ts +4 -2
- package/dist/server/server/agent/providers/pi/agent.js +8 -3
- package/dist/server/server/agent/providers/pi/cli-runtime.d.ts +3 -0
- package/dist/server/server/agent/providers/pi/cli-runtime.js +6 -3
- package/dist/server/server/agent/providers/pi/rpc-types.d.ts +2 -1
- package/dist/server/server/agent/providers/provider-image-output.d.ts +5 -0
- package/dist/server/server/agent/providers/provider-image-output.js +55 -0
- package/dist/server/server/agent/tools/paseo-tools.d.ts +48 -0
- package/dist/server/server/agent/tools/paseo-tools.js +2121 -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.js +71 -62
- package/dist/server/server/persisted-config.d.ts +5 -0
- package/dist/server/server/persisted-config.js +10 -2
- 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-session.d.ts +14 -0
- package/dist/server/server/session/daemon/daemon-session.js +38 -0
- package/dist/server/server/session/daemon/diagnostics.d.ts +41 -0
- package/dist/server/server/session/daemon/diagnostics.js +421 -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/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 +7 -51
- package/dist/server/server/session.js +113 -938
- 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/websocket/runtime-metrics.d.ts +20 -0
- package/dist/server/server/websocket-server.d.ts +1 -2
- package/dist/server/server/websocket-server.js +26 -21
- package/dist/server/server/worktree-bootstrap.d.ts +1 -1
- package/dist/server/server/worktree-branch-name-generator.js +3 -1
- package/dist/server/utils/checkout-git.js +51 -26
- package/dist/src/executable-resolution/windows.js +3 -0
- package/dist/src/server/persisted-config.js +10 -2
- package/package.json +5 -5
- package/dist/server/server/agent/providers/opencode/runtime.d.ts +0 -28
- package/dist/server/server/agent/providers/opencode/runtime.js +0 -5
- 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,52 @@ 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";
|
|
25
21
|
import { createAgentCommand } from "./agent/create-agent/create.js";
|
|
26
22
|
import { archiveAgentCommand, cancelAgentRunCommand, closeAgentCommand, detachAgentCommand, setAgentModeCommand, updateAgentCommand, } from "./agent/lifecycle-command.js";
|
|
27
|
-
import { buildStoredAgentPayload,
|
|
23
|
+
import { buildStoredAgentPayload, resolveStoredAgentPayloadUpdatedAt, toAgentPayload, } from "./agent/agent-projections.js";
|
|
28
24
|
import { appendTimelineItemIfAgentKnown, emitLiveTimelineItemIfAgentKnown, } from "./agent/timeline-append.js";
|
|
29
25
|
import { projectTimelineRows, selectProjectedTimelinePage, } from "./agent/timeline-projection.js";
|
|
30
|
-
import { StructuredAgentFallbackError, StructuredAgentResponseError, generateStructuredAgentResponseWithFallback, } from "./agent/agent-response-loop.js";
|
|
31
|
-
import { resolveStructuredGenerationProviders, } from "./agent/structured-generation-providers.js";
|
|
32
26
|
import { getAgentStreamEventTurnId, } from "./agent/agent-sdk-types.js";
|
|
33
27
|
import { ImportSessionsRequestError, importProviderSession, listImportableProviderSessions, normalizeImportAgentRequest, } from "./agent/import-sessions.js";
|
|
34
|
-
import { checkoutLiteFromGitSnapshot,
|
|
28
|
+
import { checkoutLiteFromGitSnapshot, deriveWorkspaceDisplayName, } from "./workspace-registry-model.js";
|
|
35
29
|
import { resolveWorkspaceIdForPath } from "./resolve-workspace-id-for-path.js";
|
|
36
|
-
import {
|
|
30
|
+
import { resolveProjectDisplayName, resolveWorkspaceDisplayName, resolveWorkspaceName, } from "./workspace-registry.js";
|
|
37
31
|
import { wrapSpokenInput } from "./voice-config.js";
|
|
38
32
|
import { isVoicePermissionAllowed } from "./voice-permission-policy.js";
|
|
39
33
|
import { VoiceSession } from "./session/voice/voice-session.js";
|
|
40
34
|
import { CheckoutSession } from "./session/checkout/checkout-session.js";
|
|
35
|
+
import { createWorkspaceGitObserverService, } from "./session/workspace-git-observer/workspace-git-observer-service.js";
|
|
36
|
+
import { createAgentStructuredTextGeneration, createGitMetadataGenerator, } from "./session/checkout/git-metadata-generator.js";
|
|
41
37
|
import { ChatScheduleLoopSession } from "./session/chat/chat-schedule-loop-session.js";
|
|
42
38
|
import { ProviderCatalogSession } from "./session/provider/provider-catalog-session.js";
|
|
43
39
|
import { WorkspaceFilesSession } from "./session/files/workspace-files-session.js";
|
|
44
40
|
import { AgentConfigSession } from "./session/agent-config/agent-config-session.js";
|
|
45
41
|
import { ProjectConfigSession } from "./session/project-config/project-config-session.js";
|
|
46
42
|
import { DaemonSession } from "./session/daemon/daemon-session.js";
|
|
47
|
-
import { buildMetadataPrompt } from "../utils/build-metadata-prompt.js";
|
|
48
43
|
import { archivePersistedWorkspaceRecord, archiveWorkspaceContents, } from "./workspace-archive-service.js";
|
|
49
44
|
import { WorkspaceReconciliationService } from "./workspace-reconciliation-service.js";
|
|
50
|
-
import {
|
|
45
|
+
import { renameCurrentBranch as renameCurrentBranchDefault } from "../utils/checkout-git.js";
|
|
46
|
+
import { createGitMutationService, } from "./session/git-mutation/git-mutation-service.js";
|
|
47
|
+
import { createWorkspaceProvisioningService, } from "./session/workspace-provisioning/workspace-provisioning-service.js";
|
|
48
|
+
import { createAgentUpdatesService, matchesAgentUpdatesFilter, } from "./session/agent-updates/agent-updates-service.js";
|
|
51
49
|
import { expandTilde } from "../utils/path.js";
|
|
52
50
|
import { searchHomeDirectories, searchWorkspaceEntries } from "../utils/directory-suggestions.js";
|
|
53
|
-
import { execCommand } from "../utils/spawn.js";
|
|
54
51
|
import { createGitHubService } from "../services/github-service.js";
|
|
55
52
|
import { summarizeFetchWorkspacesEntries, workspaceIdsOnCheckout, WorkspaceDirectory, } from "./workspace-directory.js";
|
|
56
53
|
import { shouldEmitPendingBootstrapUpdate } from "./workspace-bootstrap-dedupe.js";
|
|
57
54
|
import { attemptFirstAgentBranchAutoName, createLocalCheckoutWorkspace, createPaseoWorktree, } from "./paseo-worktree-service.js";
|
|
58
55
|
import { generateBranchNameFromFirstAgentContext, } from "./worktree-branch-name-generator.js";
|
|
59
|
-
import {
|
|
56
|
+
import { buildAgentSessionConfig as buildWorktreeAgentSessionConfig, createPaseoWorktreeWorkflow as createWorktreeWorkflow, handleCreatePaseoWorktreeRequest as handleCreateWorktreeRequest, handlePaseoWorktreeArchiveRequest as handleWorktreeArchiveRequest, handlePaseoWorktreeListRequest as handleWorktreeListRequest, handleWorkspaceSetupStatusRequest as handleWorkspaceSetupStatusRequestMessage, } from "./worktree-session.js";
|
|
60
57
|
import { archiveByScope } from "./workspace-archive-service.js";
|
|
61
58
|
import { WorktreeRequestError, toWorktreeRequestError, toWorktreeWireError, } from "./worktree-errors.js";
|
|
62
59
|
import { createWorktree } from "../utils/worktree.js";
|
|
63
60
|
import { runGitCommand } from "../utils/run-git-command.js";
|
|
64
61
|
import { CreateAgentLifecycleDispatch } from "./agent/create-agent-lifecycle-dispatch.js";
|
|
65
|
-
const WORKSPACE_GIT_WATCH_REMOVED_STATE_KEY = "__removed__";
|
|
66
62
|
// TODO: Remove once all app store clients are on >=0.1.45 and understand arbitrary provider strings.
|
|
67
63
|
// Clients before 0.1.45 validate providers with z.enum(["claude", "codex", "opencode"]) and reject
|
|
68
64
|
// the entire session message if they encounter an unknown provider.
|
|
@@ -83,13 +79,6 @@ function resolveSubscriptionId(subscribe, requestedSubscriptionId) {
|
|
|
83
79
|
}
|
|
84
80
|
return uuidv4();
|
|
85
81
|
}
|
|
86
|
-
function diffChangeTypeFor(file) {
|
|
87
|
-
if (file.isNew)
|
|
88
|
-
return "A";
|
|
89
|
-
if (file.isDeleted)
|
|
90
|
-
return "D";
|
|
91
|
-
return "M";
|
|
92
|
-
}
|
|
93
82
|
function buildWorkspaceCheckout(workspace, project,
|
|
94
83
|
// The persisted `branch` field is the source of truth, but it is null for
|
|
95
84
|
// records created before branch was lifted to its own field (no migrations,
|
|
@@ -201,19 +190,12 @@ function describeRegistryTransition(record) {
|
|
|
201
190
|
*/
|
|
202
191
|
export class Session {
|
|
203
192
|
constructor(options) {
|
|
204
|
-
// Per-session MCP client and tools
|
|
205
|
-
this.agentMcpClient = null;
|
|
206
|
-
this.agentTools = null;
|
|
207
193
|
this.unsubscribeAgentEvents = null;
|
|
208
194
|
this.unsubscribeTerminalWorkspaceContributionEvents = null;
|
|
209
|
-
this.agentUpdatesSubscription = null;
|
|
210
195
|
this.workspaceUpdatesSubscription = null;
|
|
211
196
|
this.clientActivity = null;
|
|
212
197
|
this.inflightRequests = 0;
|
|
213
198
|
this.peakInflightRequests = 0;
|
|
214
|
-
this.workspaceGitWatchTargets = new Map();
|
|
215
|
-
this.workspaceGitFetchSubscriptions = new Map();
|
|
216
|
-
this.workspaceGitSubscriptions = new Map();
|
|
217
199
|
this.agentsPager = new SortablePager({
|
|
218
200
|
validKeys: FETCH_AGENTS_SORT_KEYS,
|
|
219
201
|
defaultSort: [{ key: "updated_at", direction: "desc" }],
|
|
@@ -237,7 +219,7 @@ export class Session {
|
|
|
237
219
|
}
|
|
238
220
|
},
|
|
239
221
|
});
|
|
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,
|
|
222
|
+
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
223
|
this.clientId = clientId;
|
|
242
224
|
this.appVersion = appVersion ?? null;
|
|
243
225
|
this.clientCapabilities = parseClientCapabilities(clientCapabilities);
|
|
@@ -273,24 +255,49 @@ export class Session {
|
|
|
273
255
|
this.renameCurrentBranch = renameCurrentBranch ?? renameCurrentBranchDefault;
|
|
274
256
|
this.generateWorkspaceName = generateWorkspaceName ?? generateBranchNameFromFirstAgentContext;
|
|
275
257
|
this.workspaceGitService = workspaceGitService;
|
|
258
|
+
this.gitMutation = createGitMutationService({
|
|
259
|
+
workspaceGitService: this.workspaceGitService,
|
|
260
|
+
github: this.github,
|
|
261
|
+
logger: this.sessionLogger,
|
|
262
|
+
});
|
|
263
|
+
this.workspaceProvisioning = createWorkspaceProvisioningService({
|
|
264
|
+
workspaceRegistry: this.workspaceRegistry,
|
|
265
|
+
projectRegistry: this.projectRegistry,
|
|
266
|
+
workspaceGitService: this.workspaceGitService,
|
|
267
|
+
});
|
|
276
268
|
this.checkoutSession = new CheckoutSession({
|
|
277
269
|
host: {
|
|
278
270
|
emit: (msg) => this.emit(msg),
|
|
279
|
-
notifyGitMutation: (cwd, reason, mutationOptions) => this.notifyGitMutation(cwd, reason, mutationOptions),
|
|
280
271
|
emitWorkspaceUpdateForCwd: (cwd) => this.emitWorkspaceUpdateForCwd(cwd),
|
|
281
|
-
handleWorkspaceGitBranchSnapshot: (cwd, branchName) => this.
|
|
272
|
+
handleWorkspaceGitBranchSnapshot: (cwd, branchName) => this.workspaceGitObserver.handleBranchSnapshot(cwd, branchName),
|
|
282
273
|
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
274
|
},
|
|
275
|
+
gitMutation: this.gitMutation,
|
|
287
276
|
workspaceGitService: this.workspaceGitService,
|
|
288
277
|
github: this.github,
|
|
289
278
|
checkoutDiffManager,
|
|
279
|
+
gitMetadataGenerator: createGitMetadataGenerator({
|
|
280
|
+
workspaceGitService: this.workspaceGitService,
|
|
281
|
+
generation: createAgentStructuredTextGeneration({
|
|
282
|
+
agentManager: this.agentManager,
|
|
283
|
+
providerSnapshotManager,
|
|
284
|
+
readDaemonConfig: () => this.readStructuredGenerationDaemonConfig(),
|
|
285
|
+
getFocusedSelection: (cwd) => this.getFocusedAgentSelectionForCwd(cwd),
|
|
286
|
+
}),
|
|
287
|
+
}),
|
|
290
288
|
paseoHome: this.paseoHome,
|
|
291
289
|
worktreesRoot: this.worktreesRoot,
|
|
292
290
|
logger: this.sessionLogger,
|
|
293
291
|
});
|
|
292
|
+
this.workspaceGitObserver = createWorkspaceGitObserverService({
|
|
293
|
+
workspaceGitService: this.workspaceGitService,
|
|
294
|
+
describeWorkspaceRecordWithGitData: (workspace) => this.describeWorkspaceRecordWithGitData(workspace),
|
|
295
|
+
emitWorkspaceUpdateForCwd: (cwd) => this.emitWorkspaceUpdateForCwd(cwd),
|
|
296
|
+
emitWorkspaceUpdateForWorkspaceId: (workspaceId) => this.emitWorkspaceUpdateForWorkspaceId(workspaceId),
|
|
297
|
+
emitStatusUpdate: (cwd, snapshot) => this.checkoutSession.emitStatusUpdate(cwd, snapshot),
|
|
298
|
+
onBranchChanged,
|
|
299
|
+
logger: this.sessionLogger,
|
|
300
|
+
});
|
|
294
301
|
this.chatScheduleLoopSession = new ChatScheduleLoopSession({
|
|
295
302
|
host: {
|
|
296
303
|
emit: (msg) => this.emit(msg),
|
|
@@ -353,11 +360,14 @@ export class Session {
|
|
|
353
360
|
serverId,
|
|
354
361
|
daemonVersion,
|
|
355
362
|
daemonRuntimeConfig,
|
|
363
|
+
getWebSocketRuntimeMetrics,
|
|
356
364
|
listProviderAvailability: () => this.agentManager.listProviderAvailability(),
|
|
365
|
+
listAgents: () => this.agentManager.listAgents(),
|
|
366
|
+
listProjects: () => this.projectRegistry.list(),
|
|
367
|
+
listWorkspaces: () => this.workspaceRegistry.list(),
|
|
357
368
|
logger: this.sessionLogger,
|
|
358
369
|
});
|
|
359
370
|
this.daemonConfigStore = daemonConfigStore;
|
|
360
|
-
this.mcpBaseUrl = mcpBaseUrl ?? null;
|
|
361
371
|
this.terminalManager = terminalManager;
|
|
362
372
|
this.terminalController = new TerminalSessionController({
|
|
363
373
|
terminalManager,
|
|
@@ -370,6 +380,15 @@ export class Session {
|
|
|
370
380
|
clientSupportsWrapReflow: () => this.clientCapabilities.has(CLIENT_CAPS.terminalReflowableSnapshot),
|
|
371
381
|
getClientBufferedAmount: () => this.getTransportBufferedAmount(),
|
|
372
382
|
});
|
|
383
|
+
this.agentUpdates = createAgentUpdatesService({
|
|
384
|
+
emit: (message) => this.emit(message),
|
|
385
|
+
buildAgentPayload: (agent) => this.buildAgentPayload(agent),
|
|
386
|
+
buildStoredAgentPayload: (record) => this.buildStoredAgentPayload(record),
|
|
387
|
+
isProviderVisibleToClient: (provider) => this.isProviderVisibleToClient(provider),
|
|
388
|
+
buildProjectPlacementForWorkspaceId: (workspaceId) => this.buildProjectPlacementForWorkspaceId(workspaceId),
|
|
389
|
+
emitWorkspaceUpdateForWorkspaceId: (workspaceId) => this.emitWorkspaceUpdateForWorkspaceId(workspaceId),
|
|
390
|
+
logger: this.sessionLogger,
|
|
391
|
+
});
|
|
373
392
|
this.createAgentLifecycleDispatch = new CreateAgentLifecycleDispatch({
|
|
374
393
|
paseoHome: this.paseoHome,
|
|
375
394
|
worktreesRoot: this.worktreesRoot,
|
|
@@ -383,14 +402,7 @@ export class Session {
|
|
|
383
402
|
listActiveWorkspaces: () => this.listActiveWorkspaceRefs(),
|
|
384
403
|
archiveWorkspaceRecord: (workspaceId) => this.archiveWorkspaceRecord(workspaceId),
|
|
385
404
|
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
|
-
},
|
|
405
|
+
emitAgentRemove: (agentId) => this.agentUpdates.removeAgent(agentId),
|
|
394
406
|
emitWorkspaceUpdatesForWorkspaceIds: (workspaceIds) => this.emitWorkspaceUpdatesForWorkspaceIds(workspaceIds),
|
|
395
407
|
markWorkspaceArchiving: (workspaceIds, archivingAt) => this.markWorkspaceArchiving(workspaceIds, archivingAt),
|
|
396
408
|
clearWorkspaceArchiving: (workspaceIds) => this.clearWorkspaceArchiving(workspaceIds),
|
|
@@ -401,11 +413,24 @@ export class Session {
|
|
|
401
413
|
this.serviceProxy = serviceProxy ?? null;
|
|
402
414
|
this.scriptRuntimeStore = scriptRuntimeStore ?? null;
|
|
403
415
|
this.workspaceSetupSnapshots = workspaceSetupSnapshots ?? new Map();
|
|
404
|
-
this.onBranchChanged = onBranchChanged;
|
|
405
416
|
this.getDaemonTcpPort = getDaemonTcpPort ?? null;
|
|
406
417
|
this.getDaemonTcpHost = getDaemonTcpHost ?? null;
|
|
407
418
|
this.serviceProxyPublicBaseUrl = serviceProxyPublicBaseUrl ?? null;
|
|
408
419
|
this.resolveScriptHealth = resolveScriptHealth ?? null;
|
|
420
|
+
this.workspaceScripts = createWorkspaceScriptsService({
|
|
421
|
+
serviceProxy: this.serviceProxy,
|
|
422
|
+
scriptRuntimeStore: this.scriptRuntimeStore,
|
|
423
|
+
terminalManager: this.terminalManager,
|
|
424
|
+
workspaceRegistry: this.workspaceRegistry,
|
|
425
|
+
workspaceGitService: this.workspaceGitService,
|
|
426
|
+
getDaemonTcpPort: this.getDaemonTcpPort,
|
|
427
|
+
getDaemonTcpHost: this.getDaemonTcpHost,
|
|
428
|
+
serviceProxyPublicBaseUrl: this.serviceProxyPublicBaseUrl,
|
|
429
|
+
resolveScriptHealth: this.resolveScriptHealth,
|
|
430
|
+
logger: this.sessionLogger,
|
|
431
|
+
emit: (message) => this.emit(message),
|
|
432
|
+
spawnWorkspaceScript,
|
|
433
|
+
});
|
|
409
434
|
this.subscribeToOptionalManagers();
|
|
410
435
|
this.workspaceDirectory = new WorkspaceDirectory({
|
|
411
436
|
logger: this.sessionLogger,
|
|
@@ -440,8 +465,6 @@ export class Session {
|
|
|
440
465
|
voiceBridge,
|
|
441
466
|
dictation,
|
|
442
467
|
});
|
|
443
|
-
// Initialize agent MCP client asynchronously
|
|
444
|
-
void this.initializeAgentMcp();
|
|
445
468
|
this.subscribeToAgentEvents();
|
|
446
469
|
this.sessionLogger.trace({}, "agent.session.lifecycle.created");
|
|
447
470
|
}
|
|
@@ -457,8 +480,7 @@ export class Session {
|
|
|
457
480
|
return this.clientCapabilities.has(capability);
|
|
458
481
|
}
|
|
459
482
|
async syncWorkspaceGitObserverForWorkspace(workspace) {
|
|
460
|
-
|
|
461
|
-
this.syncWorkspaceGitObservers([descriptor]);
|
|
483
|
+
await this.workspaceGitObserver.syncObserverForWorkspace(workspace);
|
|
462
484
|
}
|
|
463
485
|
async emitWorkspaceUpdateForWorkspaceId(workspaceId) {
|
|
464
486
|
await this.emitWorkspaceUpdatesForWorkspaceIds([workspaceId], { skipReconcile: true });
|
|
@@ -476,8 +498,7 @@ export class Session {
|
|
|
476
498
|
await this.emitWorkspaceUpdatesForWorkspaceIds(workspaceIds);
|
|
477
499
|
}
|
|
478
500
|
async warmWorkspaceGitDataForWorkspace(workspace) {
|
|
479
|
-
await this.
|
|
480
|
-
await this.emitWorkspaceUpdateForWorkspaceId(workspace.workspaceId);
|
|
501
|
+
await this.workspaceGitObserver.warmGitData(workspace);
|
|
481
502
|
}
|
|
482
503
|
/**
|
|
483
504
|
* Get the client's current activity state
|
|
@@ -592,30 +613,6 @@ export class Session {
|
|
|
592
613
|
},
|
|
593
614
|
});
|
|
594
615
|
}
|
|
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
616
|
/**
|
|
620
617
|
* Subscribe to AgentManager events and forward them to the client
|
|
621
618
|
*/
|
|
@@ -644,7 +641,7 @@ export class Session {
|
|
|
644
641
|
turnId: event.agent.activeForegroundTurnId ?? undefined,
|
|
645
642
|
lifecycle: event.agent.lifecycle,
|
|
646
643
|
}, "agent.session.forward_update");
|
|
647
|
-
void this.
|
|
644
|
+
void this.agentUpdates.forwardLiveAgent(event.agent);
|
|
648
645
|
return;
|
|
649
646
|
}
|
|
650
647
|
if (this.voiceSession.isActiveForAgent(event.agentId) &&
|
|
@@ -734,148 +731,6 @@ export class Session {
|
|
|
734
731
|
}
|
|
735
732
|
return LEGACY_PROVIDER_IDS.has(provider);
|
|
736
733
|
}
|
|
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
734
|
async buildProjectPlacementForWorkspace(workspace, projectRecord) {
|
|
880
735
|
const project = projectRecord ?? (await this.projectRegistry.get(workspace.projectId));
|
|
881
736
|
if (!project) {
|
|
@@ -905,51 +760,6 @@ export class Session {
|
|
|
905
760
|
return null;
|
|
906
761
|
return this.buildProjectPlacementForWorkspace(workspace, project);
|
|
907
762
|
}
|
|
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
763
|
/**
|
|
954
764
|
* Main entry point for processing session messages
|
|
955
765
|
*/
|
|
@@ -1145,6 +955,8 @@ export class Session {
|
|
|
1145
955
|
return this.daemonSession.handleGetStatusRequest(msg);
|
|
1146
956
|
case "daemon.get_pairing_offer.request":
|
|
1147
957
|
return this.daemonSession.handleGetPairingOfferRequest(msg);
|
|
958
|
+
case "diagnostics.request":
|
|
959
|
+
return this.daemonSession.handleDiagnosticsRequest(msg);
|
|
1148
960
|
case "set_daemon_config_request":
|
|
1149
961
|
this.emit({
|
|
1150
962
|
type: "set_daemon_config_response",
|
|
@@ -1437,12 +1249,7 @@ export class Session {
|
|
|
1437
1249
|
requestId,
|
|
1438
1250
|
},
|
|
1439
1251
|
});
|
|
1440
|
-
|
|
1441
|
-
this.bufferOrEmitAgentUpdate(this.agentUpdatesSubscription, {
|
|
1442
|
-
kind: "remove",
|
|
1443
|
-
agentId,
|
|
1444
|
-
});
|
|
1445
|
-
}
|
|
1252
|
+
this.agentUpdates.removeAgent(agentId);
|
|
1446
1253
|
if (knownWorkspaceId) {
|
|
1447
1254
|
await this.emitWorkspaceUpdateForWorkspaceId(knownWorkspaceId);
|
|
1448
1255
|
}
|
|
@@ -1465,8 +1272,8 @@ export class Session {
|
|
|
1465
1272
|
agentStorage: this.agentStorage,
|
|
1466
1273
|
logger: this.sessionLogger,
|
|
1467
1274
|
}, agentId);
|
|
1468
|
-
if (this.
|
|
1469
|
-
const payload = await this.
|
|
1275
|
+
if (this.agentUpdates.hasSubscription()) {
|
|
1276
|
+
const payload = await this.agentUpdates.emitStoredRecord(archivedRecord);
|
|
1470
1277
|
if (payload.workspaceId) {
|
|
1471
1278
|
await this.emitWorkspaceUpdateForWorkspaceId(payload.workspaceId);
|
|
1472
1279
|
}
|
|
@@ -1479,7 +1286,7 @@ export class Session {
|
|
|
1479
1286
|
const result = await detachAgentCommand({ agentManager: this.agentManager }, agentId);
|
|
1480
1287
|
const affectedWorkspaceIds = new Set();
|
|
1481
1288
|
if (!result.live) {
|
|
1482
|
-
const payload = await this.
|
|
1289
|
+
const payload = await this.agentUpdates.emitStoredRecord(result.record);
|
|
1483
1290
|
if (payload.workspaceId) {
|
|
1484
1291
|
affectedWorkspaceIds.add(payload.workspaceId);
|
|
1485
1292
|
}
|
|
@@ -1878,7 +1685,7 @@ export class Session {
|
|
|
1878
1685
|
const createAgentConfig = createdWorktree
|
|
1879
1686
|
? { ...config, cwd: createdWorktree.worktree.worktreePath }
|
|
1880
1687
|
: config;
|
|
1881
|
-
const workspaceId = await this.resolveOrCreateWorkspaceIdForCreateAgent({
|
|
1688
|
+
const workspaceId = await this.workspaceProvisioning.resolveOrCreateWorkspaceIdForCreateAgent({
|
|
1882
1689
|
createdWorktree,
|
|
1883
1690
|
requestedWorkspaceId: msg.workspaceId,
|
|
1884
1691
|
cwd: createAgentConfig.cwd,
|
|
@@ -1912,7 +1719,7 @@ export class Session {
|
|
|
1912
1719
|
if (!createdWorktree && msg.workspaceId) {
|
|
1913
1720
|
await this.writeInitialWorkspaceTitleIfUntitled(workspaceId, workspacePromptTitle);
|
|
1914
1721
|
}
|
|
1915
|
-
await this.
|
|
1722
|
+
await this.agentUpdates.forwardLiveAgent(snapshot);
|
|
1916
1723
|
if (!createdWorktree && trimmedPrompt) {
|
|
1917
1724
|
await this.scheduleAutoNameLocalWorkspaceTitleForFirstAgent({
|
|
1918
1725
|
workspaceId,
|
|
@@ -2000,7 +1807,7 @@ export class Session {
|
|
|
2000
1807
|
const snapshot = await this.agentManager.resumeAgentFromPersistence(handle, overrides);
|
|
2001
1808
|
await unarchiveAgentState(this.agentStorage, this.agentManager, snapshot.id);
|
|
2002
1809
|
await this.agentManager.hydrateTimelineFromProvider(snapshot.id);
|
|
2003
|
-
await this.
|
|
1810
|
+
await this.agentUpdates.forwardLiveAgent(snapshot);
|
|
2004
1811
|
const timelineSize = this.agentManager.getTimeline(snapshot.id).length;
|
|
2005
1812
|
if (requestId) {
|
|
2006
1813
|
const agentPayload = await this.buildAgentPayload(snapshot);
|
|
@@ -2062,7 +1869,7 @@ export class Session {
|
|
|
2062
1869
|
}
|
|
2063
1870
|
// An imported agent mints its own workspace; ownership is its workspaceId,
|
|
2064
1871
|
// never an existing same-cwd workspace resolved by path.
|
|
2065
|
-
const workspace = await this.createWorkspaceForDirectory(normalized.cwd);
|
|
1872
|
+
const workspace = await this.workspaceProvisioning.createWorkspaceForDirectory(normalized.cwd);
|
|
2066
1873
|
const { snapshot, timelineSize } = await importProviderSession({
|
|
2067
1874
|
request: normalized,
|
|
2068
1875
|
workspaceId: workspace.workspaceId,
|
|
@@ -2135,7 +1942,7 @@ export class Session {
|
|
|
2135
1942
|
snapshot = await this.agentManager.resumeAgentFromPersistence(handle, buildConfigOverrides(record), agentId, extractTimestamps(record));
|
|
2136
1943
|
}
|
|
2137
1944
|
await this.agentManager.hydrateTimelineFromProvider(agentId);
|
|
2138
|
-
await this.
|
|
1945
|
+
await this.agentUpdates.forwardLiveAgent(snapshot);
|
|
2139
1946
|
const timelineSize = this.agentManager.getTimeline(agentId).length;
|
|
2140
1947
|
if (requestId) {
|
|
2141
1948
|
this.emit({
|
|
@@ -2244,8 +2051,8 @@ export class Session {
|
|
|
2244
2051
|
logger: this.sessionLogger,
|
|
2245
2052
|
},
|
|
2246
2053
|
}),
|
|
2247
|
-
checkoutExistingBranch: (cwd, branch) => this.checkoutExistingBranch(cwd, branch),
|
|
2248
|
-
createBranchFromBase: (params) => this.createBranchFromBase(params),
|
|
2054
|
+
checkoutExistingBranch: (cwd, branch) => this.gitMutation.checkoutExistingBranch(cwd, branch),
|
|
2055
|
+
createBranchFromBase: (params) => this.gitMutation.createBranchFromBase(params),
|
|
2249
2056
|
github: this.github,
|
|
2250
2057
|
}, config, gitOptions, legacyWorktreeName, firstAgentContext);
|
|
2251
2058
|
}
|
|
@@ -2290,7 +2097,7 @@ export class Session {
|
|
|
2290
2097
|
branch: result.branchName,
|
|
2291
2098
|
promptTitle: resolveFirstAgentPromptTitle(input.firstAgentContext),
|
|
2292
2099
|
});
|
|
2293
|
-
await this.notifyGitMutation(input.workspace.cwd, "rename-branch");
|
|
2100
|
+
await this.gitMutation.notifyGitMutation(input.workspace.cwd, "rename-branch");
|
|
2294
2101
|
await this.emitWorkspaceUpdateForCwd(input.workspace.cwd);
|
|
2295
2102
|
}
|
|
2296
2103
|
// Generated names may replace the prompt title set at creation, but not a user
|
|
@@ -2366,12 +2173,6 @@ export class Session {
|
|
|
2366
2173
|
firstAgentContext: input.firstAgentContext,
|
|
2367
2174
|
}), { cwd: input.cwd, message: "Failed to auto-name local workspace title" });
|
|
2368
2175
|
}
|
|
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
2176
|
isPathWithinRoot(rootPath, candidatePath) {
|
|
2376
2177
|
const resolvedRoot = resolve(rootPath);
|
|
2377
2178
|
const resolvedCandidate = resolve(candidatePath);
|
|
@@ -2380,220 +2181,6 @@ export class Session {
|
|
|
2380
2181
|
}
|
|
2381
2182
|
return resolvedCandidate.startsWith(resolvedRoot + sep);
|
|
2382
2183
|
}
|
|
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
2184
|
/**
|
|
2598
2185
|
* Handle clearing agent attention flag
|
|
2599
2186
|
*/
|
|
@@ -2797,129 +2384,6 @@ export class Session {
|
|
|
2797
2384
|
});
|
|
2798
2385
|
}
|
|
2799
2386
|
}
|
|
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
2387
|
async handlePaseoWorktreeListRequest(msg) {
|
|
2924
2388
|
return handleWorktreeListRequest({
|
|
2925
2389
|
emit: (message) => this.emit(message),
|
|
@@ -3115,7 +2579,7 @@ export class Session {
|
|
|
3115
2579
|
if (!entry) {
|
|
3116
2580
|
continue;
|
|
3117
2581
|
}
|
|
3118
|
-
if (!
|
|
2582
|
+
if (!matchesAgentUpdatesFilter({
|
|
3119
2583
|
agent: entry.agent,
|
|
3120
2584
|
project: entry.project,
|
|
3121
2585
|
filter,
|
|
@@ -3230,19 +2694,7 @@ export class Session {
|
|
|
3230
2694
|
statusEnteredAt: null,
|
|
3231
2695
|
activityAt: null,
|
|
3232
2696
|
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
|
-
: [],
|
|
2697
|
+
scripts: this.buildWorkspaceScriptPayloadSnapshot(workspace.workspaceId, workspace.cwd),
|
|
3246
2698
|
...(resolvedProjectRecord
|
|
3247
2699
|
? {
|
|
3248
2700
|
project: await this.buildProjectPlacementForWorkspace(workspace, resolvedProjectRecord),
|
|
@@ -3411,91 +2863,6 @@ export class Session {
|
|
|
3411
2863
|
});
|
|
3412
2864
|
}
|
|
3413
2865
|
}
|
|
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
2866
|
buildProjectDescriptor(project) {
|
|
3500
2867
|
return {
|
|
3501
2868
|
projectId: project.projectId,
|
|
@@ -3505,64 +2872,6 @@ export class Session {
|
|
|
3505
2872
|
projectKind: project.kind,
|
|
3506
2873
|
};
|
|
3507
2874
|
}
|
|
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
2875
|
async unarchiveOwningWorkspaceForAgent(agentId) {
|
|
3567
2876
|
const record = await this.agentStorage.get(agentId);
|
|
3568
2877
|
if (!record?.workspaceId) {
|
|
@@ -3582,7 +2891,7 @@ export class Session {
|
|
|
3582
2891
|
// missing, so the record must point at a real directory first.
|
|
3583
2892
|
await this.recreateOwningWorktreeForRestore(workspace, workspace.branch);
|
|
3584
2893
|
}
|
|
3585
|
-
await this.ensureWorkspaceRecordUnarchived(workspace);
|
|
2894
|
+
await this.workspaceProvisioning.ensureWorkspaceRecordUnarchived(workspace);
|
|
3586
2895
|
await this.emitWorkspaceUpdatesForWorkspaceIds([workspace.workspaceId]);
|
|
3587
2896
|
}
|
|
3588
2897
|
async recreateOwningWorktreeForRestore(workspace, branch) {
|
|
@@ -3635,26 +2944,6 @@ export class Session {
|
|
|
3635
2944
|
});
|
|
3636
2945
|
}
|
|
3637
2946
|
}
|
|
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
2947
|
async createPaseoWorktree(input, options) {
|
|
3659
2948
|
const result = await createPaseoWorktree(input, {
|
|
3660
2949
|
github: this.github,
|
|
@@ -3666,8 +2955,8 @@ export class Session {
|
|
|
3666
2955
|
workspaceGitService: this.workspaceGitService,
|
|
3667
2956
|
});
|
|
3668
2957
|
void Promise.all([
|
|
3669
|
-
this.notifyGitMutation(input.cwd, "create-worktree"),
|
|
3670
|
-
this.notifyGitMutation(result.worktree.worktreePath, "create-worktree"),
|
|
2958
|
+
this.gitMutation.notifyGitMutation(input.cwd, "create-worktree"),
|
|
2959
|
+
this.gitMutation.notifyGitMutation(result.worktree.worktreePath, "create-worktree"),
|
|
3671
2960
|
]).catch((error) => {
|
|
3672
2961
|
this.sessionLogger.warn({ err: error, cwd: input.cwd, worktreePath: result.worktree.worktreePath }, "Failed to warm git snapshots after creating worktree");
|
|
3673
2962
|
});
|
|
@@ -3691,10 +2980,7 @@ export class Session {
|
|
|
3691
2980
|
workspaceRegistry: this.workspaceRegistry,
|
|
3692
2981
|
});
|
|
3693
2982
|
if (!existingWorkspace) {
|
|
3694
|
-
|
|
3695
|
-
if (watchTarget) {
|
|
3696
|
-
this.removeWorkspaceGitSubscription(watchTarget.cwd);
|
|
3697
|
-
}
|
|
2983
|
+
this.workspaceGitObserver.removeForWorkspaceId(workspaceId);
|
|
3698
2984
|
return;
|
|
3699
2985
|
}
|
|
3700
2986
|
if (!existingWorkspace.archivedAt) {
|
|
@@ -3716,9 +3002,8 @@ export class Session {
|
|
|
3716
3002
|
// store is keyed by the opaque workspace id. Each cleanup uses its own key so an
|
|
3717
3003
|
// opaque id is never resolved as a filesystem path.
|
|
3718
3004
|
async teardownArchivedWorkspace(input) {
|
|
3719
|
-
|
|
3005
|
+
this.workspaceGitObserver.removeForCwd(input.cwd);
|
|
3720
3006
|
this.scriptRuntimeStore?.removeForWorkspace(input.workspaceId);
|
|
3721
|
-
this.removeWorkspaceGitSubscription(input.cwd);
|
|
3722
3007
|
}
|
|
3723
3008
|
async reconcileAndEmitWorkspaceUpdates() {
|
|
3724
3009
|
if (!this.workspaceUpdatesSubscription) {
|
|
@@ -3793,10 +3078,10 @@ export class Session {
|
|
|
3793
3078
|
? workspace
|
|
3794
3079
|
: null;
|
|
3795
3080
|
if (options?.dedupeGitState &&
|
|
3796
|
-
this.
|
|
3081
|
+
this.workspaceGitObserver.shouldSkipUpdate(workspaceId, nextWorkspace)) {
|
|
3797
3082
|
continue;
|
|
3798
3083
|
}
|
|
3799
|
-
this.
|
|
3084
|
+
this.workspaceGitObserver.recordDescriptorState(workspaceId, nextWorkspace);
|
|
3800
3085
|
if (!nextWorkspace) {
|
|
3801
3086
|
subscription.lastEmittedByWorkspaceId.delete(workspaceId);
|
|
3802
3087
|
this.bufferOrEmitWorkspaceUpdate(subscription, await this.buildWorkspaceRemoveUpdatePayload(workspaceId, options?.removedProjectId));
|
|
@@ -3818,16 +3103,6 @@ export class Session {
|
|
|
3818
3103
|
void this.reconcileAndEmitWorkspaceUpdates();
|
|
3819
3104
|
}
|
|
3820
3105
|
}
|
|
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
3106
|
async buildWorkspaceRemoveUpdatePayload(workspaceId, removedProjectId) {
|
|
3832
3107
|
if (removedProjectId) {
|
|
3833
3108
|
return { kind: "remove", id: workspaceId, removedProjectId };
|
|
@@ -3876,12 +3151,10 @@ export class Session {
|
|
|
3876
3151
|
const subscriptionId = resolveSubscriptionId(request.subscribe, requestedSubscriptionId);
|
|
3877
3152
|
try {
|
|
3878
3153
|
if (subscriptionId) {
|
|
3879
|
-
this.
|
|
3154
|
+
this.agentUpdates.beginSubscription({
|
|
3880
3155
|
subscriptionId,
|
|
3881
3156
|
filter: request.filter,
|
|
3882
|
-
|
|
3883
|
-
pendingUpdatesByAgentId: new Map(),
|
|
3884
|
-
};
|
|
3157
|
+
});
|
|
3885
3158
|
}
|
|
3886
3159
|
const payload = await this.listFetchAgentsEntries(request);
|
|
3887
3160
|
const snapshotUpdatedAtByAgentId = new Map();
|
|
@@ -3899,13 +3172,13 @@ export class Session {
|
|
|
3899
3172
|
...payload,
|
|
3900
3173
|
},
|
|
3901
3174
|
});
|
|
3902
|
-
if (subscriptionId
|
|
3903
|
-
this.
|
|
3175
|
+
if (subscriptionId) {
|
|
3176
|
+
this.agentUpdates.flushBootstrapped(subscriptionId, { snapshotUpdatedAtByAgentId });
|
|
3904
3177
|
}
|
|
3905
3178
|
}
|
|
3906
3179
|
catch (error) {
|
|
3907
|
-
if (subscriptionId
|
|
3908
|
-
this.
|
|
3180
|
+
if (subscriptionId) {
|
|
3181
|
+
this.agentUpdates.clearSubscription(subscriptionId);
|
|
3909
3182
|
}
|
|
3910
3183
|
const code = error instanceof SessionRequestError ? error.code : "fetch_agents_failed";
|
|
3911
3184
|
const message = error instanceof Error ? error.message : "Failed to fetch agents";
|
|
@@ -4004,7 +3277,7 @@ export class Session {
|
|
|
4004
3277
|
};
|
|
4005
3278
|
}
|
|
4006
3279
|
const payload = await this.listFetchWorkspacesEntries(request);
|
|
4007
|
-
this.
|
|
3280
|
+
this.workspaceGitObserver.syncObservers(payload.entries);
|
|
4008
3281
|
this.sessionLogger.debug({
|
|
4009
3282
|
requestId: request.requestId,
|
|
4010
3283
|
subscriptionId,
|
|
@@ -4246,7 +3519,7 @@ export class Session {
|
|
|
4246
3519
|
for (const workspaceRecord of await this.workspaceRegistry.list()) {
|
|
4247
3520
|
workspacesBefore.set(workspaceRecord.workspaceId, workspaceRecord);
|
|
4248
3521
|
}
|
|
4249
|
-
const workspace = await this.findOrCreateWorkspaceForDirectory(cwd);
|
|
3522
|
+
const workspace = await this.workspaceProvisioning.findOrCreateWorkspaceForDirectory(cwd);
|
|
4250
3523
|
const project = await this.projectRegistry.get(workspace.projectId);
|
|
4251
3524
|
await this.syncWorkspaceGitObserverForWorkspace(workspace);
|
|
4252
3525
|
const descriptor = await this.describeWorkspaceRecord(workspace);
|
|
@@ -4315,7 +3588,7 @@ export class Session {
|
|
|
4315
3588
|
for (const project of await this.projectRegistry.list()) {
|
|
4316
3589
|
projectsBefore.set(project.projectId, project);
|
|
4317
3590
|
}
|
|
4318
|
-
const project = await this.findOrCreateProjectForDirectory(cwd);
|
|
3591
|
+
const project = await this.workspaceProvisioning.findOrCreateProjectForDirectory(cwd);
|
|
4319
3592
|
this.sessionLogger.info({
|
|
4320
3593
|
requestedCwd,
|
|
4321
3594
|
resolvedCwd: cwd,
|
|
@@ -4345,98 +3618,13 @@ export class Session {
|
|
|
4345
3618
|
});
|
|
4346
3619
|
}
|
|
4347
3620
|
}
|
|
3621
|
+
// Named accessor: the workspace descriptor builder and the git-watch test both read a workspace's
|
|
3622
|
+
// scripts snapshot through here; the workspace-scripts module owns the payload assembly.
|
|
4348
3623
|
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
|
-
});
|
|
3624
|
+
return this.workspaceScripts.buildSnapshot(workspaceId, workspaceDirectory);
|
|
4363
3625
|
}
|
|
4364
|
-
|
|
4365
|
-
|
|
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
|
-
};
|
|
4373
|
-
}
|
|
4374
|
-
emitWorkspaceScriptStatusUpdate(workspaceId, workspaceDirectory) {
|
|
4375
|
-
this.emit({
|
|
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
|
-
}
|
|
3626
|
+
handleStartWorkspaceScriptRequest(request) {
|
|
3627
|
+
return this.workspaceScripts.start(request);
|
|
4440
3628
|
}
|
|
4441
3629
|
// COMPAT(desktopEditorBridge): added in v0.1.88, remove after 2026-12-03 once old clients no longer call daemon editor RPCs.
|
|
4442
3630
|
async handleLegacyListAvailableEditorsRequest(request) {
|
|
@@ -4489,7 +3677,7 @@ export class Session {
|
|
|
4489
3677
|
getDaemonTcpHost: this.getDaemonTcpHost,
|
|
4490
3678
|
serviceProxyPublicBaseUrl: this.serviceProxyPublicBaseUrl,
|
|
4491
3679
|
onScriptsChanged: (workspaceId, workspaceDirectory) => {
|
|
4492
|
-
this.
|
|
3680
|
+
this.workspaceScripts.emitStatusUpdate(workspaceId, workspaceDirectory);
|
|
4493
3681
|
},
|
|
4494
3682
|
}, input, options);
|
|
4495
3683
|
}
|
|
@@ -5097,29 +4285,16 @@ export class Session {
|
|
|
5097
4285
|
this.unsubscribeAgentEvents();
|
|
5098
4286
|
this.unsubscribeAgentEvents = null;
|
|
5099
4287
|
}
|
|
4288
|
+
this.agentUpdates.dispose();
|
|
5100
4289
|
if (this.unsubscribeTerminalWorkspaceContributionEvents) {
|
|
5101
4290
|
this.unsubscribeTerminalWorkspaceContributionEvents();
|
|
5102
4291
|
this.unsubscribeTerminalWorkspaceContributionEvents = null;
|
|
5103
4292
|
}
|
|
5104
4293
|
this.providerCatalogSession.dispose();
|
|
5105
4294
|
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
4295
|
this.terminalController.dispose();
|
|
5118
4296
|
this.checkoutSession.cleanup();
|
|
5119
|
-
|
|
5120
|
-
unsubscribe();
|
|
5121
|
-
}
|
|
5122
|
-
this.workspaceGitSubscriptions.clear();
|
|
4297
|
+
this.workspaceGitObserver.dispose();
|
|
5123
4298
|
}
|
|
5124
4299
|
}
|
|
5125
4300
|
//# sourceMappingURL=session.js.map
|