@getpaseo/server 0.1.104-beta.2 → 0.1.104-beta.3

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.
Files changed (49) hide show
  1. package/dist/server/server/agent/create-agent/create.d.ts +1 -1
  2. package/dist/server/server/agent/create-agent/create.js +4 -4
  3. package/dist/server/server/agent/providers/claude/agent.js +3 -2
  4. package/dist/server/server/agent/providers/claude/feature-definitions.js +2 -14
  5. package/dist/server/server/agent/providers/claude/model-manifest.d.ts +90 -0
  6. package/dist/server/server/agent/providers/claude/model-manifest.js +205 -0
  7. package/dist/server/server/agent/providers/claude/models.js +4 -141
  8. package/dist/server/server/agent/tools/paseo-tools.d.ts +4 -1
  9. package/dist/server/server/agent/tools/paseo-tools.js +73 -4
  10. package/dist/server/server/bootstrap.js +37 -3
  11. package/dist/server/server/browser-tools/broker.d.ts +16 -5
  12. package/dist/server/server/browser-tools/broker.js +220 -22
  13. package/dist/server/server/browser-tools/tools.js +195 -36
  14. package/dist/server/server/session.d.ts +3 -10
  15. package/dist/server/server/session.js +10 -121
  16. package/dist/server/server/websocket-server.d.ts +3 -1
  17. package/dist/server/server/websocket-server.js +18 -5
  18. package/dist/server/server/workspace-auto-name.d.ts +55 -0
  19. package/dist/server/server/workspace-auto-name.js +128 -0
  20. package/dist/server/server/worktree-session.d.ts +1 -1
  21. package/dist/server/server/worktree-session.js +1 -1
  22. package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-bridge-d9e471546cbc685a5f1a44f54114fc48.js → desktop-attachment-bridge-95a8163efd836849dd3f83730f1e84f4.js} +1 -1
  23. package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-bridge-d9e471546cbc685a5f1a44f54114fc48.js.br → desktop-attachment-bridge-95a8163efd836849dd3f83730f1e84f4.js.br} +0 -0
  24. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-95a8163efd836849dd3f83730f1e84f4.js.gz +0 -0
  25. package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-store-30526c06e214c5937e98bf1e5244cc22.js → desktop-attachment-store-9b3937a7b33a31908fa313b18c15daf6.js} +1 -1
  26. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-9b3937a7b33a31908fa313b18c15daf6.js.br +0 -0
  27. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-9b3937a7b33a31908fa313b18c15daf6.js.gz +0 -0
  28. package/dist/server/web-ui/_expo/static/js/web/{index-9f718c794c8b2995afa4a8f14218e814.js → index-690d9fe101525c0a632093e00322c944.js} +1056 -1055
  29. package/dist/server/web-ui/_expo/static/js/web/index-690d9fe101525c0a632093e00322c944.js.br +0 -0
  30. package/dist/server/web-ui/_expo/static/js/web/index-690d9fe101525c0a632093e00322c944.js.gz +0 -0
  31. package/dist/server/web-ui/_expo/static/js/web/{indexeddb-attachment-store-aa960ad0ab4cef263d0d7664e12f5b65.js → indexeddb-attachment-store-ee4a35a8c1da1c737256427f2fe19c35.js} +1 -1
  32. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-ee4a35a8c1da1c737256427f2fe19c35.js.br +0 -0
  33. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-ee4a35a8c1da1c737256427f2fe19c35.js.gz +0 -0
  34. package/dist/server/web-ui/_expo/static/js/web/{native-file-attachment-store-7837a7115a8a584b7d7231cfa2eae2cf.js → native-file-attachment-store-c4aebe23af349f0f64f418e755c84c00.js} +3 -3
  35. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-c4aebe23af349f0f64f418e755c84c00.js.br +0 -0
  36. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-c4aebe23af349f0f64f418e755c84c00.js.gz +0 -0
  37. package/dist/server/web-ui/index.html +1 -1
  38. package/dist/server/web-ui/index.html.br +0 -0
  39. package/dist/server/web-ui/index.html.gz +0 -0
  40. package/package.json +5 -5
  41. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-d9e471546cbc685a5f1a44f54114fc48.js.gz +0 -0
  42. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-30526c06e214c5937e98bf1e5244cc22.js.br +0 -0
  43. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-30526c06e214c5937e98bf1e5244cc22.js.gz +0 -0
  44. package/dist/server/web-ui/_expo/static/js/web/index-9f718c794c8b2995afa4a8f14218e814.js.br +0 -0
  45. package/dist/server/web-ui/_expo/static/js/web/index-9f718c794c8b2995afa4a8f14218e814.js.gz +0 -0
  46. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-aa960ad0ab4cef263d0d7664e12f5b65.js.br +0 -0
  47. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-aa960ad0ab4cef263d0d7664e12f5b65.js.gz +0 -0
  48. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-7837a7115a8a584b7d7231cfa2eae2cf.js.br +0 -0
  49. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-7837a7115a8a584b7d7231cfa2eae2cf.js.gz +0 -0
@@ -53,8 +53,7 @@ import { searchHomeDirectories, searchWorkspaceEntries } from "../utils/director
53
53
  import { createGitHubService } from "../services/github-service.js";
54
54
  import { summarizeFetchWorkspacesEntries, workspaceIdsOnCheckout, WorkspaceDirectory, } from "./workspace-directory.js";
55
55
  import { shouldEmitPendingBootstrapUpdate } from "./workspace-bootstrap-dedupe.js";
56
- import { attemptFirstAgentBranchAutoName, createLocalCheckoutWorkspace, createPaseoWorktree, } from "./paseo-worktree-service.js";
57
- import { generateBranchNameFromFirstAgentContext, } from "./worktree-branch-name-generator.js";
56
+ import { createLocalCheckoutWorkspace, createPaseoWorktree, } from "./paseo-worktree-service.js";
58
57
  import { buildAgentSessionConfig as buildWorktreeAgentSessionConfig, createPaseoWorktreeWorkflow as createWorktreeWorkflow, handleCreatePaseoWorktreeRequest as handleCreateWorktreeRequest, handlePaseoWorktreeArchiveRequest as handleWorktreeArchiveRequest, handlePaseoWorktreeListRequest as handleWorktreeListRequest, handleWorkspaceSetupStatusRequest as handleWorkspaceSetupStatusRequestMessage, } from "./worktree-session.js";
59
58
  import { archiveByScope } from "./workspace-archive-service.js";
60
59
  import { WorktreeRequestError, toWorktreeRequestError, toWorktreeWireError, } from "./worktree-errors.js";
@@ -221,7 +220,7 @@ export class Session {
221
220
  }
222
221
  },
223
222
  });
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;
223
+ const { clientId, appVersion, clientCapabilities, onMessage, onBinaryMessage, getTransportBufferedAmount, onLifecycleIntent, logger, downloadTokenStore, pushTokenStore, paseoHome, worktreesRoot, agentManager, agentStorage, projectRegistry, workspaceRegistry, filesystem, chatService, scheduleService, loopService, checkoutDiffManager, github, renameCurrentBranch, workspaceGitService, workspaceAutoName, daemonConfigStore, stt, sttLanguage, tts, terminalManager, providerSnapshotManager, providerUsageService, serviceProxy, scriptRuntimeStore, workspaceSetupSnapshots, onBranchChanged, getDaemonTcpPort, getDaemonTcpHost, serviceProxyPublicBaseUrl, resolveScriptHealth, voice, voiceBridge, dictation, serverId, daemonVersion, daemonRuntimeConfig, getWebSocketRuntimeMetrics, } = options;
225
224
  this.clientId = clientId;
226
225
  this.appVersion = appVersion ?? null;
227
226
  this.clientCapabilities = parseClientCapabilities(clientCapabilities);
@@ -255,13 +254,13 @@ export class Session {
255
254
  this.filesystem = filesystem ?? nodeSessionFileSystem;
256
255
  this.github = github ?? createGitHubService();
257
256
  this.renameCurrentBranch = renameCurrentBranch ?? renameCurrentBranchDefault;
258
- this.generateWorkspaceName = generateWorkspaceName ?? generateBranchNameFromFirstAgentContext;
259
257
  this.workspaceGitService = workspaceGitService;
260
258
  this.gitMutation = createGitMutationService({
261
259
  workspaceGitService: this.workspaceGitService,
262
260
  github: this.github,
263
261
  logger: this.sessionLogger,
264
262
  });
263
+ this.workspaceAutoName = workspaceAutoName;
265
264
  this.workspaceProvisioning = createWorkspaceProvisioningService({
266
265
  workspaceRegistry: this.workspaceRegistry,
267
266
  projectRegistry: this.projectRegistry,
@@ -1734,11 +1733,11 @@ export class Session {
1734
1733
  createdAgentId = snapshot.id;
1735
1734
  await this.agentUpdates.forwardLiveAgent(snapshot);
1736
1735
  if (createdDirectoryWorkspaceForAgent && trimmedPrompt) {
1737
- await this.scheduleAutoNameLocalWorkspaceTitleForFirstAgent({
1736
+ this.workspaceAutoName.scheduleForDirectory({
1738
1737
  workspaceId,
1739
1738
  cwd: createAgentConfig.cwd,
1740
1739
  firstAgentContext,
1741
- });
1740
+ }, { currentSelection: this.getFocusedAgentSelectionForCwd(createAgentConfig.cwd) });
1742
1741
  }
1743
1742
  this.createAgentLifecycleDispatch.registerAutoArchiveIfRequested({
1744
1743
  autoArchive,
@@ -2069,109 +2068,6 @@ export class Session {
2069
2068
  github: this.github,
2070
2069
  }, config, gitOptions, legacyWorktreeName, firstAgentContext);
2071
2070
  }
2072
- scheduleAutoNameWorkspaceBranchForFirstAgent(input) {
2073
- this.scheduleWorkspaceNaming(() => this.maybeAutoNameWorkspaceBranchForFirstAgent(input), {
2074
- cwd: input.workspace.cwd,
2075
- message: "Failed to auto-name worktree branch",
2076
- });
2077
- }
2078
- async maybeAutoNameWorkspaceBranchForFirstAgent(input) {
2079
- // Capture the generated title from the generator callback so we can write
2080
- // title := generated title after the branch rename completes.
2081
- let generatedTitle = null;
2082
- const result = await attemptFirstAgentBranchAutoName({
2083
- cwd: input.workspace.cwd,
2084
- firstAgentContext: input.firstAgentContext,
2085
- generateBranchNameFromContext: ({ cwd, firstAgentContext }) => {
2086
- return this.generateWorkspaceName({
2087
- agentManager: this.agentManager,
2088
- cwd,
2089
- workspaceGitService: this.workspaceGitService,
2090
- providerSnapshotManager: this.providerSnapshotManager,
2091
- daemonConfig: this.readStructuredGenerationDaemonConfig(),
2092
- currentSelection: this.getFocusedAgentSelectionForCwd(cwd),
2093
- firstAgentContext,
2094
- logger: this.sessionLogger,
2095
- }).then((r) => {
2096
- generatedTitle = r?.title ?? null;
2097
- return r?.branch ?? null;
2098
- });
2099
- },
2100
- });
2101
- if (!result.renamed || !generatedTitle) {
2102
- return;
2103
- }
2104
- // K4: re-read from the registry before writing so any concurrent upsert
2105
- // that happened between workspace creation and this async path is not clobbered.
2106
- // The first-agent rename renamed the git branch too, so persist the new branch
2107
- // alongside the title — both are this path's own fields.
2108
- await this.applyGeneratedWorkspaceTitle(input.workspace.workspaceId, {
2109
- title: generatedTitle,
2110
- branch: result.branchName,
2111
- promptTitle: resolveFirstAgentPromptTitle(input.firstAgentContext),
2112
- });
2113
- await this.gitMutation.notifyGitMutation(input.workspace.cwd, "rename-branch");
2114
- await this.emitWorkspaceUpdateForCwd(input.workspace.cwd);
2115
- }
2116
- // Generated names may replace the prompt title set at creation, but not a user
2117
- // rename that landed while the async generator was running.
2118
- async applyGeneratedWorkspaceTitle(workspaceId, input) {
2119
- const current = await this.workspaceRegistry.get(workspaceId);
2120
- if (!current) {
2121
- return;
2122
- }
2123
- let title = current.title;
2124
- if (!title || (input.promptTitle && title === input.promptTitle)) {
2125
- title = input.title;
2126
- }
2127
- await this.workspaceRegistry.upsert({
2128
- ...current,
2129
- title,
2130
- ...(input.branch ? { branch: input.branch } : {}),
2131
- updatedAt: new Date().toISOString(),
2132
- });
2133
- }
2134
- // Wraps the injected workspace-name generator for a directory workspace.
2135
- async generateWorkspaceTitleFromContext(input) {
2136
- return this.generateWorkspaceName({
2137
- agentManager: this.agentManager,
2138
- cwd: input.cwd,
2139
- workspaceGitService: this.workspaceGitService,
2140
- providerSnapshotManager: this.providerSnapshotManager,
2141
- daemonConfig: this.readStructuredGenerationDaemonConfig(),
2142
- currentSelection: this.getFocusedAgentSelectionForCwd(input.cwd),
2143
- firstAgentContext: input.firstAgentContext,
2144
- logger: this.sessionLogger,
2145
- });
2146
- }
2147
- // Generates a human title for a directory workspace from the firstAgentContext
2148
- // prompt. No branch rename — directory workspaces have no worktree git state.
2149
- // TODO(K7): same-dir directory-workspace display disambiguation not yet implemented.
2150
- async maybeAutoNameDirectoryWorkspaceTitle(input) {
2151
- const generated = await this.generateWorkspaceTitleFromContext({
2152
- cwd: input.cwd,
2153
- firstAgentContext: input.firstAgentContext,
2154
- });
2155
- const title = generated?.title ?? null;
2156
- if (!title) {
2157
- return;
2158
- }
2159
- // K4: applyGeneratedWorkspaceTitle re-reads from the registry before writing.
2160
- // Directory workspaces have no branch — write only the title.
2161
- await this.applyGeneratedWorkspaceTitle(input.workspaceId, {
2162
- title,
2163
- promptTitle: resolveFirstAgentPromptTitle(input.firstAgentContext),
2164
- });
2165
- await this.emitWorkspaceUpdateForWorkspaceId(input.workspaceId);
2166
- }
2167
- async scheduleAutoNameLocalWorkspaceTitleForFirstAgent(input) {
2168
- const workspaceId = input.workspaceId;
2169
- this.scheduleWorkspaceNaming(() => this.maybeAutoNameDirectoryWorkspaceTitle({
2170
- workspaceId,
2171
- cwd: input.cwd,
2172
- firstAgentContext: input.firstAgentContext,
2173
- }), { cwd: input.cwd, message: "Failed to auto-name local workspace title" });
2174
- }
2175
2071
  isPathWithinRoot(rootPath, candidatePath) {
2176
2072
  const resolvedRoot = resolve(rootPath);
2177
2073
  const resolvedCandidate = resolve(candidatePath);
@@ -3408,22 +3304,13 @@ export class Session {
3408
3304
  });
3409
3305
  if (request.firstAgentContext) {
3410
3306
  const firstAgentContext = request.firstAgentContext;
3411
- this.scheduleWorkspaceNaming(() => this.maybeAutoNameDirectoryWorkspaceTitle({
3307
+ this.workspaceAutoName.scheduleForDirectory({
3412
3308
  workspaceId: workspace.workspaceId,
3413
3309
  cwd: workspace.cwd,
3414
3310
  firstAgentContext,
3415
- }), { cwd: workspace.cwd, message: "Failed to auto-name directory workspace title" });
3311
+ }, { currentSelection: this.getFocusedAgentSelectionForCwd(workspace.cwd) });
3416
3312
  }
3417
3313
  }
3418
- // Schedules a background workspace-naming write off the request path. The
3419
- // setTimeout(0) keeps the LLM call off the hot path.
3420
- scheduleWorkspaceNaming(run, context) {
3421
- setTimeout(() => {
3422
- void run().catch((error) => {
3423
- this.sessionLogger.warn({ err: error, cwd: context.cwd }, context.message);
3424
- });
3425
- }, 0);
3426
- }
3427
3314
  async handleWorkspaceCreateWorktree(request) {
3428
3315
  if (request.source.kind !== "worktree") {
3429
3316
  return;
@@ -3659,7 +3546,9 @@ export class Session {
3659
3546
  worktreesRoot: this.worktreesRoot,
3660
3547
  createPaseoWorktree: (workflowInput, serviceOptions) => this.createPaseoWorktree(workflowInput, serviceOptions),
3661
3548
  warmWorkspaceGitData: (workspace) => this.warmWorkspaceGitDataForWorkspace(workspace),
3662
- autoNameWorkspaceBranchForFirstAgent: (autoNameInput) => this.scheduleAutoNameWorkspaceBranchForFirstAgent(autoNameInput),
3549
+ autoNameWorkspaceBranchForFirstAgent: (autoNameInput) => this.workspaceAutoName.scheduleForWorktree(autoNameInput, {
3550
+ currentSelection: this.getFocusedAgentSelectionForCwd(autoNameInput.workspace.cwd),
3551
+ }),
3663
3552
  emitWorkspaceUpdateForWorkspaceId: (workspaceId) => this.emitWorkspaceUpdateForWorkspaceId(workspaceId),
3664
3553
  cacheWorkspaceSetupSnapshot: (workspaceId, snapshot) => {
3665
3554
  this.workspaceSetupSnapshots.set(workspaceId, snapshot);
@@ -15,6 +15,7 @@ import type { HostnamesConfig } from "./hostnames.js";
15
15
  import { Session, type SessionLifecycleIntent } from "./session.js";
16
16
  import { ProviderSnapshotManager } from "./agent/provider-snapshot-manager.js";
17
17
  import type { WorkspaceGitService } from "./workspace-git-service.js";
18
+ import type { WorkspaceAutoName } from "./workspace-auto-name.js";
18
19
  import { type PushNotificationSender } from "./push/notifications.js";
19
20
  import type { ScriptHealthState } from "./script-health-monitor.js";
20
21
  import type { ServiceProxySubsystem } from "./service-proxy.js";
@@ -67,6 +68,7 @@ export declare class VoiceAssistantWebSocketServer {
67
68
  private readonly checkoutDiffManager;
68
69
  private readonly github;
69
70
  private readonly workspaceGitService;
71
+ private readonly workspaceAutoName;
70
72
  private readonly downloadTokenStore;
71
73
  private readonly paseoHome;
72
74
  private readonly worktreesRoot;
@@ -100,7 +102,7 @@ export declare class VoiceAssistantWebSocketServer {
100
102
  private unsubscribeTerminalActivity;
101
103
  private readonly browserToolsBroker;
102
104
  private readonly browserToolsRegistrations;
103
- constructor(server: HTTPServer, logger: pino.Logger, serverId: string, agentManager: AgentManager, agentStorage: AgentStorage, downloadTokenStore: DownloadTokenStore, paseoHome: string, daemonConfigStore: DaemonConfigStore, mcpBaseUrl: string | null, wsConfig: WebSocketServerConfig, auth?: DaemonAuthConfig, speech?: SpeechService | null, terminalManager?: TerminalManager | null, dictation?: {
105
+ constructor(server: HTTPServer, logger: pino.Logger, serverId: string, agentManager: AgentManager, agentStorage: AgentStorage, downloadTokenStore: DownloadTokenStore, paseoHome: string, daemonConfigStore: DaemonConfigStore, mcpBaseUrl: string | null, wsConfig: WebSocketServerConfig, workspaceAutoName: WorkspaceAutoName, auth?: DaemonAuthConfig, speech?: SpeechService | null, terminalManager?: TerminalManager | null, dictation?: {
104
106
  finalTimeoutMs?: number;
105
107
  }, daemonVersion?: string, onLifecycleIntent?: (intent: SessionLifecycleIntent) => void, projectRegistry?: ProjectRegistry, workspaceRegistry?: WorkspaceRegistry, chatService?: FileBackedChatService, loopService?: LoopService, scheduleService?: ScheduleService, checkoutDiffManager?: CheckoutDiffManager, serviceProxy?: ServiceProxySubsystem | null, scriptRuntimeStore?: WorkspaceScriptRuntimeStore | null, onBranchChanged?: (workspaceId: string, oldBranch: string | null, newBranch: string | null) => void, getDaemonTcpPort?: () => number | null, getDaemonTcpHost?: () => string | null, resolveScriptHealth?: (hostname: string) => ScriptHealthState | null, workspaceGitService?: WorkspaceGitService, github?: GitHubService, pushNotificationSender?: PushNotificationSender, providerSnapshotManager?: ProviderSnapshotManager, daemonRuntimeConfig?: {
106
108
  listen: string | null;
@@ -19,6 +19,7 @@ import { ProviderUsageService } from "../services/quota-fetcher/service.js";
19
19
  import { getProcessMemoryDiagnostics, getProcessUptimeSeconds } from "./process-diagnostics.js";
20
20
  import { CLIENT_SHUTDOWN_RPC_REASON, normalizeClientRestartRpcReason, } from "./lifecycle-reasons.js";
21
21
  import { CLIENT_CAPS } from "@getpaseo/protocol/client-capabilities";
22
+ import { BrowserAutomationHostCapabilitySchema, } from "@getpaseo/protocol/browser-automation/capabilities";
22
23
  const WS_CLOSE_DAEMON_AUTH_FAILED = 4401;
23
24
  function resolveTerminalAttentionReason(input) {
24
25
  if (input.attentionReason === "finished")
@@ -189,8 +190,9 @@ function bufferFromWsData(data) {
189
190
  return data;
190
191
  return Buffer.from(data);
191
192
  }
192
- function hasDesktopBrowserAutomationCapability(capabilities) {
193
- return capabilities?.[CLIENT_CAPS.desktopBrowserAutomation] === true;
193
+ function getBrowserHostCapability(capabilities) {
194
+ const parsed = BrowserAutomationHostCapabilitySchema.safeParse(capabilities?.[CLIENT_CAPS.browserHost]);
195
+ return parsed.success ? parsed.data : null;
194
196
  }
195
197
  const SLOW_REQUEST_THRESHOLD_MS = 500;
196
198
  const EXTERNAL_SESSION_DISCONNECT_GRACE_MS = 90000;
@@ -226,7 +228,7 @@ function requireWebSocketServices(params) {
226
228
  * WebSocket server that only accepts sockets + parses/forwards messages to the session layer.
227
229
  */
228
230
  export class VoiceAssistantWebSocketServer {
229
- constructor(server, logger, serverId, agentManager, agentStorage, downloadTokenStore, paseoHome, daemonConfigStore, mcpBaseUrl, wsConfig, auth, speech, terminalManager, dictation, daemonVersion, onLifecycleIntent, projectRegistry, workspaceRegistry, chatService, loopService, scheduleService, checkoutDiffManager, serviceProxy, scriptRuntimeStore, onBranchChanged, getDaemonTcpPort, getDaemonTcpHost, resolveScriptHealth, workspaceGitService, github, pushNotificationSender, providerSnapshotManager, daemonRuntimeConfig, serviceProxyPublicBaseUrl, browserToolsBroker) {
231
+ constructor(server, logger, serverId, agentManager, agentStorage, downloadTokenStore, paseoHome, daemonConfigStore, mcpBaseUrl, wsConfig, workspaceAutoName, auth, speech, terminalManager, dictation, daemonVersion, onLifecycleIntent, projectRegistry, workspaceRegistry, chatService, loopService, scheduleService, checkoutDiffManager, serviceProxy, scriptRuntimeStore, onBranchChanged, getDaemonTcpPort, getDaemonTcpHost, resolveScriptHealth, workspaceGitService, github, pushNotificationSender, providerSnapshotManager, daemonRuntimeConfig, serviceProxyPublicBaseUrl, browserToolsBroker) {
230
232
  this.pendingConnections = new Map();
231
233
  this.sessions = new Map();
232
234
  this.socketIdentities = new Map();
@@ -266,6 +268,7 @@ export class VoiceAssistantWebSocketServer {
266
268
  this.checkoutDiffManager = requiredServices.checkoutDiffManager;
267
269
  this.github = github ?? createGitHubService();
268
270
  this.workspaceGitService = workspaceGitService ?? createFallbackWorkspaceGitService();
271
+ this.workspaceAutoName = workspaceAutoName;
269
272
  this.downloadTokenStore = downloadTokenStore;
270
273
  this.paseoHome = paseoHome;
271
274
  this.worktreesRoot = daemonRuntimeConfig?.worktreesRoot;
@@ -647,6 +650,7 @@ export class VoiceAssistantWebSocketServer {
647
650
  checkoutDiffManager: this.checkoutDiffManager,
648
651
  github: this.github,
649
652
  workspaceGitService: this.workspaceGitService,
653
+ workspaceAutoName: this.workspaceAutoName,
650
654
  daemonConfigStore: this.daemonConfigStore,
651
655
  mcpBaseUrl: this.mcpBaseUrl,
652
656
  stt: () => this.speech?.resolveStt() ?? null,
@@ -981,21 +985,30 @@ export class VoiceAssistantWebSocketServer {
981
985
  if (!this.browserToolsBroker) {
982
986
  return;
983
987
  }
984
- if (!hasDesktopBrowserAutomationCapability(connection.clientCapabilities)) {
988
+ const browserHostCapability = getBrowserHostCapability(connection.clientCapabilities);
989
+ if (!browserHostCapability) {
985
990
  this.unregisterBrowserToolsClient(connection.clientId);
986
991
  return;
987
992
  }
993
+ const capabilitySignature = JSON.stringify(browserHostCapability);
988
994
  const existing = this.browserToolsRegistrations.get(connection.clientId);
989
- if (existing) {
995
+ if (existing?.capabilitySignature === capabilitySignature) {
990
996
  return;
991
997
  }
998
+ if (existing) {
999
+ this.browserToolsRegistrations.delete(connection.clientId);
1000
+ existing.unregister();
1001
+ }
992
1002
  const unregister = this.browserToolsBroker.registerClient({
993
1003
  id: connection.clientId,
1004
+ hostKind: browserHostCapability.hostKind,
1005
+ supportedCommands: browserHostCapability.supportedCommands,
994
1006
  sendBrowserAutomationRequest: (request) => {
995
1007
  this.sendToConnection(connection, wrapSessionMessage(request));
996
1008
  },
997
1009
  });
998
1010
  this.browserToolsRegistrations.set(connection.clientId, {
1011
+ capabilitySignature,
999
1012
  unregister,
1000
1013
  });
1001
1014
  }
@@ -0,0 +1,55 @@
1
+ import type pino from "pino";
2
+ import type { FirstAgentContext } from "@getpaseo/protocol/messages";
3
+ import type { AgentManager } from "./agent/agent-manager.js";
4
+ import type { ProviderSnapshotManager } from "./agent/provider-snapshot-manager.js";
5
+ import type { StructuredGenerationDaemonConfig } from "./agent/structured-generation-providers.js";
6
+ import type { GitMutationService } from "./session/git-mutation/git-mutation-service.js";
7
+ import type { WorkspaceGitService } from "./workspace-git-service.js";
8
+ import type { PersistedWorkspaceRecord, WorkspaceRegistry } from "./workspace-registry.js";
9
+ import { generateBranchNameFromFirstAgentContext, type GenerateBranchNameFromFirstAgentContextOptions } from "./worktree-branch-name-generator.js";
10
+ type WorkspaceNameGenerator = typeof generateBranchNameFromFirstAgentContext;
11
+ type CurrentSelection = GenerateBranchNameFromFirstAgentContextOptions["currentSelection"] | null;
12
+ interface WorkspaceAutoNameOptions {
13
+ agentManager: AgentManager;
14
+ workspaceRegistry: Pick<WorkspaceRegistry, "get" | "upsert">;
15
+ workspaceGitService: WorkspaceGitService;
16
+ providerSnapshotManager: ProviderSnapshotManager;
17
+ readDaemonConfig: () => StructuredGenerationDaemonConfig;
18
+ gitMutation: Pick<GitMutationService, "notifyGitMutation">;
19
+ emitWorkspaceUpdateForCwd: (cwd: string) => Promise<void>;
20
+ emitWorkspaceUpdateForWorkspaceId: (workspaceId: string) => Promise<void>;
21
+ logger: pino.Logger;
22
+ generateWorkspaceName?: WorkspaceNameGenerator;
23
+ }
24
+ interface ScheduleContext {
25
+ currentSelection?: CurrentSelection;
26
+ }
27
+ export declare class WorkspaceAutoName {
28
+ private readonly agentManager;
29
+ private readonly workspaceRegistry;
30
+ private readonly workspaceGitService;
31
+ private readonly providerSnapshotManager;
32
+ private readonly readDaemonConfig;
33
+ private readonly gitMutation;
34
+ private readonly emitWorkspaceUpdateForCwd;
35
+ private readonly emitWorkspaceUpdateForWorkspaceId;
36
+ private readonly logger;
37
+ private readonly generateWorkspaceName;
38
+ constructor(options: WorkspaceAutoNameOptions);
39
+ scheduleForWorktree(input: {
40
+ workspace: PersistedWorkspaceRecord;
41
+ firstAgentContext: FirstAgentContext;
42
+ }, context?: ScheduleContext): void;
43
+ scheduleForDirectory(input: {
44
+ workspaceId: string;
45
+ cwd: string;
46
+ firstAgentContext: FirstAgentContext;
47
+ }, context?: ScheduleContext): void;
48
+ private maybeAutoNameWorkspaceBranchForFirstAgent;
49
+ private maybeAutoNameDirectoryWorkspaceTitle;
50
+ private applyGeneratedWorkspaceTitle;
51
+ private generateFromContext;
52
+ private schedule;
53
+ }
54
+ export {};
55
+ //# sourceMappingURL=workspace-auto-name.d.ts.map
@@ -0,0 +1,128 @@
1
+ import { resolveFirstAgentPromptTitle } from "./agent/create-agent-title.js";
2
+ import { attemptFirstAgentBranchAutoName, } from "./paseo-worktree-service.js";
3
+ import { generateBranchNameFromFirstAgentContext, } from "./worktree-branch-name-generator.js";
4
+ export class WorkspaceAutoName {
5
+ constructor(options) {
6
+ this.agentManager = options.agentManager;
7
+ this.workspaceRegistry = options.workspaceRegistry;
8
+ this.workspaceGitService = options.workspaceGitService;
9
+ this.providerSnapshotManager = options.providerSnapshotManager;
10
+ this.readDaemonConfig = options.readDaemonConfig;
11
+ this.gitMutation = options.gitMutation;
12
+ this.emitWorkspaceUpdateForCwd = options.emitWorkspaceUpdateForCwd;
13
+ this.emitWorkspaceUpdateForWorkspaceId = options.emitWorkspaceUpdateForWorkspaceId;
14
+ this.logger = options.logger;
15
+ this.generateWorkspaceName =
16
+ options.generateWorkspaceName ?? generateBranchNameFromFirstAgentContext;
17
+ }
18
+ scheduleForWorktree(input, context = {}) {
19
+ this.schedule(() => this.maybeAutoNameWorkspaceBranchForFirstAgent({
20
+ ...input,
21
+ currentSelection: context.currentSelection ?? null,
22
+ }), {
23
+ cwd: input.workspace.cwd,
24
+ message: "Failed to auto-name worktree branch",
25
+ });
26
+ }
27
+ scheduleForDirectory(input, context = {}) {
28
+ this.schedule(() => this.maybeAutoNameDirectoryWorkspaceTitle({
29
+ ...input,
30
+ currentSelection: context.currentSelection ?? null,
31
+ }), { cwd: input.cwd, message: "Failed to auto-name directory workspace title" });
32
+ }
33
+ async maybeAutoNameWorkspaceBranchForFirstAgent(input) {
34
+ let generated = null;
35
+ const result = await attemptFirstAgentBranchAutoName({
36
+ cwd: input.workspace.cwd,
37
+ firstAgentContext: input.firstAgentContext,
38
+ generateBranchNameFromContext: ({ cwd, firstAgentContext }) => {
39
+ return this.generateFromContext({
40
+ cwd,
41
+ firstAgentContext,
42
+ currentSelection: input.currentSelection,
43
+ }).then((nextGenerated) => {
44
+ generated = nextGenerated;
45
+ return nextGenerated?.branch ?? null;
46
+ });
47
+ },
48
+ });
49
+ if (!generated) {
50
+ generated = await this.generateFromContext({
51
+ cwd: input.workspace.cwd,
52
+ firstAgentContext: input.firstAgentContext,
53
+ currentSelection: input.currentSelection,
54
+ });
55
+ }
56
+ const generatedTitle = generated?.title ?? null;
57
+ if (!generatedTitle) {
58
+ return;
59
+ }
60
+ // K4: re-read from the registry before writing so any concurrent upsert
61
+ // that happened between workspace creation and this async path is not clobbered.
62
+ // When the first-agent rename changed the git branch too, persist that branch
63
+ // alongside the title — both are this path's own fields.
64
+ await this.applyGeneratedWorkspaceTitle(input.workspace.workspaceId, {
65
+ title: generatedTitle,
66
+ ...(result.renamed ? { branch: result.branchName } : {}),
67
+ promptTitle: resolveFirstAgentPromptTitle(input.firstAgentContext),
68
+ });
69
+ if (result.renamed) {
70
+ await this.gitMutation.notifyGitMutation(input.workspace.cwd, "rename-branch");
71
+ }
72
+ await this.emitWorkspaceUpdateForCwd(input.workspace.cwd);
73
+ }
74
+ async maybeAutoNameDirectoryWorkspaceTitle(input) {
75
+ const generated = await this.generateFromContext({
76
+ cwd: input.cwd,
77
+ firstAgentContext: input.firstAgentContext,
78
+ currentSelection: input.currentSelection,
79
+ });
80
+ const title = generated?.title ?? null;
81
+ if (!title) {
82
+ return;
83
+ }
84
+ // K4: applyGeneratedWorkspaceTitle re-reads from the registry before writing.
85
+ // Directory workspaces have no branch — write only the title.
86
+ await this.applyGeneratedWorkspaceTitle(input.workspaceId, {
87
+ title,
88
+ promptTitle: resolveFirstAgentPromptTitle(input.firstAgentContext),
89
+ });
90
+ await this.emitWorkspaceUpdateForWorkspaceId(input.workspaceId);
91
+ }
92
+ async applyGeneratedWorkspaceTitle(workspaceId, input) {
93
+ const current = await this.workspaceRegistry.get(workspaceId);
94
+ if (!current) {
95
+ return;
96
+ }
97
+ let title = current.title;
98
+ if (!title || (input.promptTitle && title === input.promptTitle)) {
99
+ title = input.title;
100
+ }
101
+ await this.workspaceRegistry.upsert({
102
+ ...current,
103
+ title,
104
+ ...(input.branch ? { branch: input.branch } : {}),
105
+ updatedAt: new Date().toISOString(),
106
+ });
107
+ }
108
+ generateFromContext(input) {
109
+ return this.generateWorkspaceName({
110
+ agentManager: this.agentManager,
111
+ cwd: input.cwd,
112
+ workspaceGitService: this.workspaceGitService,
113
+ providerSnapshotManager: this.providerSnapshotManager,
114
+ daemonConfig: this.readDaemonConfig(),
115
+ currentSelection: input.currentSelection ?? undefined,
116
+ firstAgentContext: input.firstAgentContext,
117
+ logger: this.logger,
118
+ });
119
+ }
120
+ schedule(run, context) {
121
+ setTimeout(() => {
122
+ void run().catch((error) => {
123
+ this.logger.warn({ err: error, cwd: context.cwd }, context.message);
124
+ });
125
+ }, 0);
126
+ }
127
+ }
128
+ //# sourceMappingURL=workspace-auto-name.js.map
@@ -67,7 +67,7 @@ interface CreatePaseoWorktreeWorkflowDependencies extends CreatePaseoWorktreeInB
67
67
  resolveDefaultBranch?: (repoRoot: string) => Promise<string>;
68
68
  }) => Promise<CreatePaseoWorktreeResult>;
69
69
  warmWorkspaceGitData: (workspace: PersistedWorkspaceRecord) => Promise<void>;
70
- autoNameWorkspaceBranchForFirstAgent?: (input: {
70
+ autoNameWorkspaceBranchForFirstAgent: (input: {
71
71
  workspace: PersistedWorkspaceRecord;
72
72
  firstAgentContext: FirstAgentContext;
73
73
  }) => void;
@@ -320,7 +320,7 @@ export async function createPaseoWorktreeWorkflow(dependencies, input, options)
320
320
  const setupContinuation = options?.setupContinuation ?? { kind: "workspace" };
321
321
  setTimeout(() => {
322
322
  if (input.firstAgentContext) {
323
- dependencies.autoNameWorkspaceBranchForFirstAgent?.({
323
+ dependencies.autoNameWorkspaceBranchForFirstAgent({
324
324
  workspace,
325
325
  firstAgentContext: input.firstAgentContext,
326
326
  });
@@ -1 +1 @@
1
- __d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createDesktopAttachmentBridge=function(){const l=(0,s.createDesktopPreviewUrlResolver)({reader:(0,s.createDesktopFileReader)(),objectUrls:(0,s.createBrowserObjectUrlMinter)()});return{copyFile:t.copyDesktopAttachmentFile,writeBase64:t.writeDesktopAttachmentBase64,writeBytes:t.writeDesktopAttachmentBytes,deleteFile:t.deleteDesktopAttachmentFile,garbageCollect:t.garbageCollectDesktopAttachmentFiles,readFileBase64:s.readDesktopFileBase64,resolvePreviewUrl:t=>l.resolve(t),releasePreviewUrl:t=>l.release(t)}};var t=r(d[0]),s=r(d[1])},4418,[3927,3928]);
1
+ __d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createDesktopAttachmentBridge=function(){const l=(0,s.createDesktopPreviewUrlResolver)({reader:(0,s.createDesktopFileReader)(),objectUrls:(0,s.createBrowserObjectUrlMinter)()});return{copyFile:t.copyDesktopAttachmentFile,writeBase64:t.writeDesktopAttachmentBase64,writeBytes:t.writeDesktopAttachmentBytes,deleteFile:t.deleteDesktopAttachmentFile,garbageCollect:t.garbageCollectDesktopAttachmentFiles,readFileBase64:s.readDesktopFileBase64,resolvePreviewUrl:t=>l.resolve(t),releasePreviewUrl:t=>l.release(t)}};var t=r(d[0]),s=r(d[1])},4419,[3928,3929]);
@@ -1 +1 @@
1
- __d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createDesktopAttachmentStore=function(n){return{storageType:"desktop-file",async save(s){const o=s.id??(0,t.generateAttachmentId)(),l=s.fileName??null;if("file_uri"===s.source.kind)return await c(n,{id:o,uri:s.source.uri,mimeType:s.mimeType,fileName:l});if("data_url"===s.source.kind){const c=(0,t.parseDataUrl)(s.source.dataUrl),p=(0,t.normalizeMimeType)(s.mimeType??c.mimeType);return await y(n,{id:o,base64:c.base64,mimeType:p,fileName:l})}if("bytes"===s.source.kind){const c=(0,t.normalizeMimeType)(s.mimeType);return await p(n,{id:o,bytes:s.source.bytes,mimeType:c,fileName:l})}const f=(0,t.normalizeMimeType)(s.mimeType??s.source.blob.type),u=await(0,t.blobToBase64)(s.source.blob);return await y(n,{id:o,base64:u,mimeType:f,fileName:l})},encodeBase64:async({attachment:t})=>(f(t),await n.readFileBase64(t.storageKey)),resolvePreviewUrl:async({attachment:t})=>(f(t),await n.resolvePreviewUrl(t)),async releasePreviewUrl({attachment:t,url:s}){f(t),await n.releasePreviewUrl({url:s})},async delete({attachment:t}){f(t),await n.deleteFile({path:t.storageKey})},async garbageCollect({referencedIds:t}){await n.garbageCollect({referencedIds:Array.from(t)})}}};var t=r(d[0]);const n={"image/png":".png","image/jpeg":".jpg","image/jpg":".jpg","image/gif":".gif","image/webp":".webp","image/avif":".avif","image/heic":".heic","image/heif":".heif","image/tiff":".tiff","image/bmp":".bmp","image/svg+xml":".svg"};function s(t){const n=t.replace(/\\/g,"/").split("/"),s=n[n.length-1];return s&&s.length>0?s:null}function o(s){const o=(0,t.getFileExtensionFromName)(s.fileName);if(o)return o;const l=(0,t.getFileExtensionFromName)(s.sourcePath);return l||(n[s.mimeType]??".img")}function l(t){return{id:t.id,mimeType:t.mimeType,storageType:"desktop-file",storageKey:t.storagePath,fileName:t.fileName??null,byteSize:t.byteSize,createdAt:Date.now()}}async function c(n,c){const y=(0,t.fileUriToPath)(c.uri),p=c.fileName??s(y),f=(0,t.normalizeMimeType)(c.mimeType),u=o({fileName:p,sourcePath:y,mimeType:f}),T=await n.copyFile({attachmentId:c.id,sourcePath:y,extension:u});return l({id:c.id,mimeType:f,storagePath:T.path,byteSize:T.byteSize,fileName:p})}async function y(t,n){const s=o({fileName:n.fileName,mimeType:n.mimeType}),c=await t.writeBase64({attachmentId:n.id,base64:n.base64,extension:s});return l({id:n.id,mimeType:n.mimeType,storagePath:c.path,byteSize:c.byteSize,fileName:n.fileName})}async function p(t,n){const s=o({fileName:n.fileName,mimeType:n.mimeType}),c=await t.writeBytes({attachmentId:n.id,bytes:n.bytes,extension:s});return l({id:n.id,mimeType:n.mimeType,storagePath:c.path,byteSize:c.byteSize,fileName:n.fileName})}function f(t){if("desktop-file"!==t.storageType)throw new Error(`Unsupported desktop attachment storage type '${t.storageType}'.`)}},4417,[3929]);
1
+ __d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,'__esModule',{value:!0}),e.createDesktopAttachmentStore=function(n){return{storageType:"desktop-file",async save(s){const o=s.id??(0,t.generateAttachmentId)(),l=s.fileName??null;if("file_uri"===s.source.kind)return await c(n,{id:o,uri:s.source.uri,mimeType:s.mimeType,fileName:l});if("data_url"===s.source.kind){const c=(0,t.parseDataUrl)(s.source.dataUrl),p=(0,t.normalizeMimeType)(s.mimeType??c.mimeType);return await y(n,{id:o,base64:c.base64,mimeType:p,fileName:l})}if("bytes"===s.source.kind){const c=(0,t.normalizeMimeType)(s.mimeType);return await p(n,{id:o,bytes:s.source.bytes,mimeType:c,fileName:l})}const f=(0,t.normalizeMimeType)(s.mimeType??s.source.blob.type),u=await(0,t.blobToBase64)(s.source.blob);return await y(n,{id:o,base64:u,mimeType:f,fileName:l})},encodeBase64:async({attachment:t})=>(f(t),await n.readFileBase64(t.storageKey)),resolvePreviewUrl:async({attachment:t})=>(f(t),await n.resolvePreviewUrl(t)),async releasePreviewUrl({attachment:t,url:s}){f(t),await n.releasePreviewUrl({url:s})},async delete({attachment:t}){f(t),await n.deleteFile({path:t.storageKey})},async garbageCollect({referencedIds:t}){await n.garbageCollect({referencedIds:Array.from(t)})}}};var t=r(d[0]);const n={"image/png":".png","image/jpeg":".jpg","image/jpg":".jpg","image/gif":".gif","image/webp":".webp","image/avif":".avif","image/heic":".heic","image/heif":".heif","image/tiff":".tiff","image/bmp":".bmp","image/svg+xml":".svg"};function s(t){const n=t.replace(/\\/g,"/").split("/"),s=n[n.length-1];return s&&s.length>0?s:null}function o(s){const o=(0,t.getFileExtensionFromName)(s.fileName);if(o)return o;const l=(0,t.getFileExtensionFromName)(s.sourcePath);return l||(n[s.mimeType]??".img")}function l(t){return{id:t.id,mimeType:t.mimeType,storageType:"desktop-file",storageKey:t.storagePath,fileName:t.fileName??null,byteSize:t.byteSize,createdAt:Date.now()}}async function c(n,c){const y=(0,t.fileUriToPath)(c.uri),p=c.fileName??s(y),f=(0,t.normalizeMimeType)(c.mimeType),u=o({fileName:p,sourcePath:y,mimeType:f}),T=await n.copyFile({attachmentId:c.id,sourcePath:y,extension:u});return l({id:c.id,mimeType:f,storagePath:T.path,byteSize:T.byteSize,fileName:p})}async function y(t,n){const s=o({fileName:n.fileName,mimeType:n.mimeType}),c=await t.writeBase64({attachmentId:n.id,base64:n.base64,extension:s});return l({id:n.id,mimeType:n.mimeType,storagePath:c.path,byteSize:c.byteSize,fileName:n.fileName})}async function p(t,n){const s=o({fileName:n.fileName,mimeType:n.mimeType}),c=await t.writeBytes({attachmentId:n.id,bytes:n.bytes,extension:s});return l({id:n.id,mimeType:n.mimeType,storagePath:c.path,byteSize:c.byteSize,fileName:n.fileName})}function f(t){if("desktop-file"!==t.storageType)throw new Error(`Unsupported desktop attachment storage type '${t.storageType}'.`)}},4418,[3930]);