@getpaseo/server 0.1.95 → 0.1.97-beta.1

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 (134) hide show
  1. package/dist/server/{utils/executable.d.ts → executable-resolution/executable-resolution.d.ts} +2 -2
  2. package/dist/server/{utils/executable.js → executable-resolution/executable-resolution.js} +16 -14
  3. package/dist/server/executable-resolution/windows.d.ts +18 -0
  4. package/dist/server/executable-resolution/windows.js +62 -0
  5. package/dist/server/server/agent/agent-loading.js +4 -1
  6. package/dist/server/server/agent/agent-manager.d.ts +10 -2
  7. package/dist/server/server/agent/agent-manager.js +34 -46
  8. package/dist/server/server/agent/agent-projections.js +3 -0
  9. package/dist/server/server/agent/agent-prompt.js +19 -1
  10. package/dist/server/server/agent/agent-response-loop.js +2 -4
  11. package/dist/server/server/agent/agent-storage.d.ts +18 -19
  12. package/dist/server/server/agent/agent-storage.js +6 -23
  13. package/dist/server/server/agent/create-agent/create.d.ts +2 -12
  14. package/dist/server/server/agent/create-agent/create.js +28 -30
  15. package/dist/server/server/agent/create-agent-lifecycle-dispatch.d.ts +4 -2
  16. package/dist/server/server/agent/create-agent-lifecycle-dispatch.js +31 -22
  17. package/dist/server/server/agent/import-sessions.d.ts +1 -10
  18. package/dist/server/server/agent/import-sessions.js +1 -53
  19. package/dist/server/server/agent/lifecycle-command.js +5 -4
  20. package/dist/server/server/agent/mcp-server.d.ts +8 -5
  21. package/dist/server/server/agent/mcp-server.js +41 -14
  22. package/dist/server/server/agent/mcp-shared.d.ts +6 -3
  23. package/dist/server/server/agent/mcp-shared.js +3 -0
  24. package/dist/server/server/agent/provider-launch-config.js +1 -1
  25. package/dist/server/server/agent/providers/acp-agent.d.ts +5 -0
  26. package/dist/server/server/agent/providers/acp-agent.js +31 -26
  27. package/dist/server/server/agent/providers/claude/agent.js +45 -6
  28. package/dist/server/server/agent/providers/codex-app-server-agent.js +1 -1
  29. package/dist/server/server/agent/providers/copilot-acp-agent.js +1 -0
  30. package/dist/server/server/agent/providers/cursor-acp-agent.d.ts +0 -7
  31. package/dist/server/server/agent/providers/cursor-acp-agent.js +0 -78
  32. package/dist/server/server/agent/providers/mock-load-test-agent.d.ts +2 -0
  33. package/dist/server/server/agent/providers/mock-load-test-agent.js +73 -1
  34. package/dist/server/server/agent/providers/opencode/server-manager.js +1 -1
  35. package/dist/server/server/agent/structured-generation-providers.js +45 -1
  36. package/dist/server/server/agent-attention-policy.d.ts +12 -3
  37. package/dist/server/server/agent-attention-policy.js +15 -3
  38. package/dist/server/server/auto-archive-on-merge/archive-if-safe.d.ts +7 -6
  39. package/dist/server/server/auto-archive-on-merge/archive-if-safe.js +21 -16
  40. package/dist/server/server/bootstrap.d.ts +3 -0
  41. package/dist/server/server/bootstrap.js +91 -12
  42. package/dist/server/server/config.js +1 -0
  43. package/dist/server/server/daemon-config-store.js +1 -0
  44. package/dist/server/server/exports.d.ts +1 -1
  45. package/dist/server/server/exports.js +1 -1
  46. package/dist/server/server/loop-service.d.ts +24 -24
  47. package/dist/server/server/migrations/backfill-workspace-id.migration.d.ts +9 -0
  48. package/dist/server/server/migrations/backfill-workspace-id.migration.js +60 -0
  49. package/dist/server/server/paseo-worktree-service.d.ts +9 -0
  50. package/dist/server/server/paseo-worktree-service.js +71 -12
  51. package/dist/server/server/path-utils.d.ts +1 -0
  52. package/dist/server/server/path-utils.js +6 -1
  53. package/dist/server/server/persisted-config.d.ts +7 -0
  54. package/dist/server/server/persisted-config.js +1 -0
  55. package/dist/server/server/persistence-hooks.d.ts +1 -0
  56. package/dist/server/server/persistence-hooks.js +13 -5
  57. package/dist/server/server/resolve-workspace-id-for-path.d.ts +3 -0
  58. package/dist/server/server/resolve-workspace-id-for-path.js +41 -0
  59. package/dist/server/server/script-proxy.d.ts +1 -1
  60. package/dist/server/server/script-proxy.js +1 -1
  61. package/dist/server/server/service-proxy.js +1 -1
  62. package/dist/server/server/session.d.ts +31 -6
  63. package/dist/server/server/session.js +640 -196
  64. package/dist/server/server/websocket-server.d.ts +5 -0
  65. package/dist/server/server/websocket-server.js +137 -3
  66. package/dist/server/server/workspace-archive-service.d.ts +60 -3
  67. package/dist/server/server/workspace-archive-service.js +217 -4
  68. package/dist/server/server/workspace-directory.d.ts +20 -2
  69. package/dist/server/server/workspace-directory.js +148 -70
  70. package/dist/server/server/workspace-git-service.js +21 -21
  71. package/dist/server/server/workspace-reconciliation-service.d.ts +1 -1
  72. package/dist/server/server/workspace-reconciliation-service.js +21 -22
  73. package/dist/server/server/workspace-registry-bootstrap.js +23 -10
  74. package/dist/server/server/workspace-registry-model.d.ts +3 -3
  75. package/dist/server/server/workspace-registry-model.js +9 -10
  76. package/dist/server/server/workspace-registry.d.ts +17 -4
  77. package/dist/server/server/workspace-registry.js +27 -0
  78. package/dist/server/server/worktree/commands.d.ts +7 -5
  79. package/dist/server/server/worktree/commands.js +38 -18
  80. package/dist/server/server/worktree-bootstrap.d.ts +1 -0
  81. package/dist/server/server/worktree-bootstrap.js +4 -1
  82. package/dist/server/server/worktree-branch-name-generator.d.ts +5 -1
  83. package/dist/server/server/worktree-branch-name-generator.js +8 -2
  84. package/dist/server/server/worktree-session.d.ts +4 -5
  85. package/dist/server/server/worktree-session.js +9 -3
  86. package/dist/server/services/github-service.js +1 -1
  87. package/dist/server/terminal/activity/terminal-activity-tracker.d.ts +20 -0
  88. package/dist/server/terminal/activity/terminal-activity-tracker.js +59 -0
  89. package/dist/server/terminal/agent-hooks/agent-hook-installer.d.ts +62 -0
  90. package/dist/server/terminal/agent-hooks/agent-hook-installer.js +117 -0
  91. package/dist/server/terminal/agent-hooks/claude/claude-settings.d.ts +7 -0
  92. package/dist/server/terminal/agent-hooks/claude/claude-settings.js +88 -0
  93. package/dist/server/terminal/agent-hooks/claude/claude.d.ts +4 -0
  94. package/dist/server/terminal/agent-hooks/claude/claude.js +47 -0
  95. package/dist/server/terminal/agent-hooks/codex/codex-settings.d.ts +7 -0
  96. package/dist/server/terminal/agent-hooks/codex/codex-settings.js +99 -0
  97. package/dist/server/terminal/agent-hooks/codex/codex.d.ts +4 -0
  98. package/dist/server/terminal/agent-hooks/codex/codex.js +30 -0
  99. package/dist/server/terminal/agent-hooks/opencode/opencode-plugin.d.ts +4 -0
  100. package/dist/server/terminal/agent-hooks/opencode/opencode-plugin.js +46 -0
  101. package/dist/server/terminal/agent-hooks/opencode/opencode.d.ts +3 -0
  102. package/dist/server/terminal/agent-hooks/opencode/opencode.js +23 -0
  103. package/dist/server/terminal/agent-hooks/provider-registry.d.ts +24 -0
  104. package/dist/server/terminal/agent-hooks/provider-registry.js +36 -0
  105. package/dist/server/terminal/agent-hooks/terminal-agent-hook-setting.d.ts +10 -0
  106. package/dist/server/terminal/agent-hooks/terminal-agent-hook-setting.js +26 -0
  107. package/dist/server/terminal/terminal-manager-factory.d.ts +4 -1
  108. package/dist/server/terminal/terminal-manager-factory.js +2 -2
  109. package/dist/server/terminal/terminal-manager.d.ts +33 -2
  110. package/dist/server/terminal/terminal-manager.js +144 -18
  111. package/dist/server/terminal/terminal-output-coalescer.d.ts +4 -0
  112. package/dist/server/terminal/terminal-output-coalescer.js +18 -0
  113. package/dist/server/terminal/terminal-restore.d.ts +1 -0
  114. package/dist/server/terminal/terminal-restore.js +6 -0
  115. package/dist/server/terminal/terminal-session-controller.d.ts +4 -2
  116. package/dist/server/terminal/terminal-session-controller.js +65 -24
  117. package/dist/server/terminal/terminal-worker-process.js +146 -63
  118. package/dist/server/terminal/terminal-worker-protocol.d.ts +19 -14
  119. package/dist/server/terminal/terminal.d.ts +42 -0
  120. package/dist/server/terminal/terminal.js +235 -16
  121. package/dist/server/terminal/worker-terminal-manager.d.ts +1 -0
  122. package/dist/server/terminal/worker-terminal-manager.js +220 -36
  123. package/dist/server/utils/build-metadata-prompt.d.ts +1 -1
  124. package/dist/server/utils/github-remote.js +1 -1
  125. package/dist/server/utils/tree-kill.d.ts +2 -2
  126. package/dist/src/{utils/executable.js → executable-resolution/executable-resolution.js} +16 -14
  127. package/dist/src/executable-resolution/windows.js +62 -0
  128. package/dist/src/server/agent/provider-launch-config.js +1 -1
  129. package/dist/src/server/persisted-config.js +1 -0
  130. package/package.json +10 -5
  131. package/dist/server/server/agent/agent-metadata-generator.d.ts +0 -36
  132. package/dist/server/server/agent/agent-metadata-generator.js +0 -112
  133. package/dist/server/server/paseo-worktree-archive-service.d.ts +0 -41
  134. package/dist/server/server/paseo-worktree-archive-service.js +0 -144
@@ -0,0 +1,60 @@
1
+ // COMPAT(workspaceIdBackfill): one-time legacy backfill, delete after 2026-12-16
2
+ // once floor >= the release that always stamps workspaceId at create time.
3
+ //
4
+ // This is the ONLY place in the codebase that maps a cwd to a workspaceId.
5
+ // Every other code path treats a record's `workspaceId` field as authoritative
6
+ // ownership. Legacy agent records persisted before workspaceId stamping have no
7
+ // owner, so this migration stamps each one with the workspace that owned its
8
+ // directory at the time it was written. It runs once at startup and writes the
9
+ // id back to storage, after which all runtime code can assume the field exists.
10
+ import { homedir } from "node:os";
11
+ import { resolve, sep } from "node:path";
12
+ // Picks the workspace that owned `cwd` for a legacy, unstamped agent record.
13
+ // Prefers an exact-cwd workspace (oldest wins) and otherwise attributes to the
14
+ // deepest enclosing workspace directory, never letting the home directory own
15
+ // descendants. Used only by the one-time backfill below.
16
+ function resolveLegacyWorkspaceOwner(cwd, workspaces) {
17
+ const normalizedCwd = resolve(cwd);
18
+ const userHome = resolve(homedir());
19
+ const activeWorkspaces = Array.from(workspaces).filter((workspace) => !workspace.archivedAt);
20
+ const exactMatches = activeWorkspaces.filter((workspace) => resolve(workspace.cwd) === normalizedCwd);
21
+ if (exactMatches.length > 0) {
22
+ return oldestWorkspace(exactMatches).workspaceId;
23
+ }
24
+ const prefixMatches = activeWorkspaces.filter((workspace) => {
25
+ const workspaceCwd = resolve(workspace.cwd);
26
+ if (workspaceCwd === userHome) {
27
+ return false;
28
+ }
29
+ return normalizedCwd === workspaceCwd || normalizedCwd.startsWith(`${workspaceCwd}${sep}`);
30
+ });
31
+ if (prefixMatches.length === 0) {
32
+ return null;
33
+ }
34
+ const deepestPrefixLength = Math.max(...prefixMatches.map((workspace) => resolve(workspace.cwd).length));
35
+ return oldestWorkspace(prefixMatches.filter((workspace) => resolve(workspace.cwd).length === deepestPrefixLength)).workspaceId;
36
+ }
37
+ function oldestWorkspace(workspaces) {
38
+ return workspaces.reduce((oldest, candidate) => candidate.createdAt < oldest.createdAt ? candidate : oldest);
39
+ }
40
+ export async function backfillWorkspaceIdForLegacyAgents(options) {
41
+ const workspaceRecords = await options.workspaceRegistry.list();
42
+ const records = await options.agentStorage.list();
43
+ let migrated = 0;
44
+ for (const record of records) {
45
+ if (record.workspaceId) {
46
+ continue;
47
+ }
48
+ const workspaceId = resolveLegacyWorkspaceOwner(record.cwd, workspaceRecords);
49
+ if (!workspaceId) {
50
+ continue;
51
+ }
52
+ await options.agentStorage.upsert({ ...record, workspaceId });
53
+ migrated += 1;
54
+ }
55
+ if (migrated > 0) {
56
+ options.logger.info({ migrated }, "Backfilled workspaceId for legacy agent records");
57
+ }
58
+ return migrated;
59
+ }
60
+ //# sourceMappingURL=backfill-workspace-id.migration.js.map
@@ -40,4 +40,13 @@ export declare function attemptFirstAgentBranchAutoName(options: {
40
40
  renameCurrentBranch?: typeof renameCurrentBranch;
41
41
  localBranchExists?: typeof localBranchExists;
42
42
  }): Promise<AttemptFirstAgentBranchAutoNameResult>;
43
+ export interface CreateLocalCheckoutWorkspaceDeps {
44
+ projectRegistry: Pick<ProjectRegistry, "get" | "list" | "upsert">;
45
+ workspaceRegistry: Pick<WorkspaceRegistry, "list" | "upsert">;
46
+ workspaceGitService: Pick<WorkspaceGitService, "getCheckout">;
47
+ }
48
+ export declare function createLocalCheckoutWorkspace(options: {
49
+ cwd: string;
50
+ title?: string | null;
51
+ }, deps: CreateLocalCheckoutWorkspaceDeps): Promise<PersistedWorkspaceRecord>;
43
52
  //# sourceMappingURL=paseo-worktree-service.d.ts.map
@@ -1,5 +1,6 @@
1
+ import { resolve } from "node:path";
1
2
  import { createPersistedProjectRecord, createPersistedWorkspaceRecord, } from "./workspace-registry.js";
2
- import { deriveProjectGroupingName, normalizeWorkspaceId } from "./workspace-registry-model.js";
3
+ import { classifyDirectoryForProjectMembership, deriveProjectGroupingName, generateWorkspaceId, } from "./workspace-registry-model.js";
3
4
  import { createWorktreeCore, } from "./worktree-core.js";
4
5
  import { validateBranchSlug } from "../utils/worktree.js";
5
6
  import { getCurrentBranch, localBranchExists, renameCurrentBranch } from "../utils/checkout-git.js";
@@ -107,18 +108,20 @@ function maybeMarkFirstAgentBranchAutoNameEligible(options) {
107
108
  });
108
109
  }
109
110
  async function upsertWorkspaceForWorktree(options) {
110
- const normalizedCwd = normalizeWorkspaceId(options.worktree.worktreePath);
111
- const normalizedInputCwd = normalizeWorkspaceId(options.inputCwd);
112
- const normalizedRepoRoot = normalizeWorkspaceId(options.repoRoot);
113
- const existingWorkspace = await findWorkspaceByDirectory(normalizedCwd, options.deps.workspaceRegistry);
111
+ const normalizedCwd = resolve(options.worktree.worktreePath);
112
+ const normalizedInputCwd = resolve(options.inputCwd);
113
+ const normalizedRepoRoot = resolve(options.repoRoot);
114
+ // Creation never deduplicates by directory: a worktree directory may back
115
+ // more than one workspace. We still resolve the source project from the
116
+ // originating checkout, but always mint a fresh workspace record.
114
117
  const sourceProject = await resolveSourceProjectForWorktree({
115
118
  inputCwd: normalizedInputCwd,
116
119
  projectId: options.projectId,
117
120
  repoRoot: normalizedRepoRoot,
118
- existingWorkspace,
121
+ existingWorkspace: null,
119
122
  deps: options.deps,
120
123
  });
121
- const workspaceId = normalizedCwd;
124
+ const workspaceId = generateWorkspaceId();
122
125
  const now = new Date().toISOString();
123
126
  await options.deps.projectRegistry.upsert(createPersistedProjectRecord({
124
127
  projectId: sourceProject.projectId,
@@ -136,13 +139,73 @@ async function upsertWorkspaceForWorktree(options) {
136
139
  cwd: normalizedCwd,
137
140
  kind: "worktree",
138
141
  displayName: options.worktree.branchName || normalizedCwd,
139
- createdAt: existingWorkspace?.createdAt ?? now,
142
+ branch: options.worktree.branchName || null,
143
+ createdAt: now,
140
144
  updatedAt: now,
141
145
  archivedAt: null,
142
146
  });
143
147
  await options.deps.workspaceRegistry.upsert(workspace);
144
148
  return (await options.deps.workspaceRegistry.get(workspace.workspaceId)) ?? workspace;
145
149
  }
150
+ // Always create a NEW workspace record backed by the existing directory `cwd`.
151
+ // Never reuses a same-cwd record: a directory may back any number of
152
+ // workspaces. Used by explicit user creation.
153
+ export async function createLocalCheckoutWorkspace(options, deps) {
154
+ const normalizedCwd = resolve(options.cwd);
155
+ const checkout = await deps.workspaceGitService.getCheckout(normalizedCwd);
156
+ const membership = classifyDirectoryForProjectMembership({ cwd: normalizedCwd, checkout });
157
+ const now = new Date().toISOString();
158
+ const projectRecord = await resolveProjectRecordForMembership({
159
+ membership,
160
+ timestamp: now,
161
+ projectRegistry: deps.projectRegistry,
162
+ });
163
+ await deps.projectRegistry.upsert(projectRecord);
164
+ const trimmedTitle = options.title?.trim();
165
+ // Persist the live git branch into the dedicated `branch` field so
166
+ // buildWorkspaceCheckout reports the real branch for directory/local_checkout
167
+ // workspaces too (it reads workspace.branch). Same source deriveWorkspaceDisplayName
168
+ // reads. HEAD/detached resolves to null — there is no branch to report.
169
+ const currentBranch = checkout.currentBranch?.trim() ?? null;
170
+ const branch = currentBranch && currentBranch.toUpperCase() !== "HEAD" ? currentBranch : null;
171
+ const workspace = createPersistedWorkspaceRecord({
172
+ workspaceId: generateWorkspaceId(),
173
+ projectId: projectRecord.projectId,
174
+ cwd: normalizedCwd,
175
+ kind: membership.workspaceKind,
176
+ displayName: membership.workspaceDisplayName,
177
+ branch,
178
+ title: trimmedTitle ? trimmedTitle : null,
179
+ createdAt: now,
180
+ updatedAt: now,
181
+ });
182
+ await deps.workspaceRegistry.upsert(workspace);
183
+ return workspace;
184
+ }
185
+ async function resolveProjectRecordForMembership(options) {
186
+ const rootPath = options.membership.projectRootPath;
187
+ const projects = await options.projectRegistry.list();
188
+ const existingProject = projects.find((project) => !project.archivedAt && project.rootPath === rootPath) ??
189
+ projects.find((project) => project.rootPath === rootPath) ??
190
+ null;
191
+ if (!existingProject) {
192
+ return createPersistedProjectRecord({
193
+ projectId: options.membership.projectKey,
194
+ rootPath,
195
+ kind: options.membership.projectKind,
196
+ displayName: options.membership.projectName,
197
+ createdAt: options.timestamp,
198
+ updatedAt: options.timestamp,
199
+ });
200
+ }
201
+ return {
202
+ ...existingProject,
203
+ rootPath,
204
+ kind: options.membership.projectKind,
205
+ archivedAt: null,
206
+ updatedAt: options.timestamp,
207
+ };
208
+ }
146
209
  function sourceProjectFromRecord(record) {
147
210
  return {
148
211
  projectId: record.projectId,
@@ -211,8 +274,4 @@ async function findWorkspaceForSource(options) {
211
274
  workspaces.find((workspace) => workspace.cwd === options.repoRoot && !workspace.archivedAt) ??
212
275
  null);
213
276
  }
214
- async function findWorkspaceByDirectory(cwd, workspaceRegistry) {
215
- const workspaces = await workspaceRegistry.list();
216
- return workspaces.find((workspace) => workspace.cwd === cwd) ?? null;
217
- }
218
277
  //# sourceMappingURL=paseo-worktree-service.js.map
@@ -1,3 +1,4 @@
1
+ export declare function assertAbsolutePath(cwd: string): void;
1
2
  export declare function expandUserPath(value: string): string;
2
3
  export declare function resolvePathFromBase(baseCwd: string, requestedPath: string): string;
3
4
  export declare function isSameOrDescendantPath(basePath: string, candidatePath: string): boolean;
@@ -1,5 +1,10 @@
1
1
  import { homedir } from "node:os";
2
- import { isAbsolute, resolve } from "node:path";
2
+ import { isAbsolute, posix, resolve, win32 } from "node:path";
3
+ export function assertAbsolutePath(cwd) {
4
+ if (!posix.isAbsolute(cwd) && !win32.isAbsolute(cwd)) {
5
+ throw new Error("cwd must be absolute path");
6
+ }
7
+ }
3
8
  function hasHomePrefix(value) {
4
9
  return value === "~" || value.startsWith("~/");
5
10
  }
@@ -20,6 +20,7 @@ export declare const PersistedConfigSchema: z.ZodObject<{
20
20
  injectIntoAgents: z.ZodOptional<z.ZodBoolean>;
21
21
  }, z.ZodTypeAny, "passthrough">>>;
22
22
  autoArchiveAfterMerge: z.ZodOptional<z.ZodBoolean>;
23
+ enableTerminalAgentHooks: z.ZodOptional<z.ZodBoolean>;
23
24
  appendSystemPrompt: z.ZodOptional<z.ZodString>;
24
25
  terminalProfiles: z.ZodOptional<z.ZodArray<z.ZodObject<{
25
26
  id: z.ZodString;
@@ -98,6 +99,7 @@ export declare const PersistedConfigSchema: z.ZodObject<{
98
99
  hostnames?: true | string[] | undefined;
99
100
  allowedHosts?: true | string[] | undefined;
100
101
  autoArchiveAfterMerge?: boolean | undefined;
102
+ enableTerminalAgentHooks?: boolean | undefined;
101
103
  appendSystemPrompt?: string | undefined;
102
104
  terminalProfiles?: z.objectOutputType<{
103
105
  id: z.ZodString;
@@ -133,6 +135,7 @@ export declare const PersistedConfigSchema: z.ZodObject<{
133
135
  hostnames?: true | string[] | undefined;
134
136
  allowedHosts?: true | string[] | undefined;
135
137
  autoArchiveAfterMerge?: boolean | undefined;
138
+ enableTerminalAgentHooks?: boolean | undefined;
136
139
  appendSystemPrompt?: string | undefined;
137
140
  terminalProfiles?: z.objectInputType<{
138
141
  id: z.ZodString;
@@ -167,6 +170,7 @@ export declare const PersistedConfigSchema: z.ZodObject<{
167
170
  listen?: string | undefined;
168
171
  hostnames?: true | string[] | undefined;
169
172
  autoArchiveAfterMerge?: boolean | undefined;
173
+ enableTerminalAgentHooks?: boolean | undefined;
170
174
  appendSystemPrompt?: string | undefined;
171
175
  terminalProfiles?: z.objectOutputType<{
172
176
  id: z.ZodString;
@@ -202,6 +206,7 @@ export declare const PersistedConfigSchema: z.ZodObject<{
202
206
  hostnames?: true | string[] | undefined;
203
207
  allowedHosts?: true | string[] | undefined;
204
208
  autoArchiveAfterMerge?: boolean | undefined;
209
+ enableTerminalAgentHooks?: boolean | undefined;
205
210
  appendSystemPrompt?: string | undefined;
206
211
  terminalProfiles?: z.objectInputType<{
207
212
  id: z.ZodString;
@@ -899,6 +904,7 @@ export declare const PersistedConfigSchema: z.ZodObject<{
899
904
  listen?: string | undefined;
900
905
  hostnames?: true | string[] | undefined;
901
906
  autoArchiveAfterMerge?: boolean | undefined;
907
+ enableTerminalAgentHooks?: boolean | undefined;
902
908
  appendSystemPrompt?: string | undefined;
903
909
  terminalProfiles?: z.objectOutputType<{
904
910
  id: z.ZodString;
@@ -1045,6 +1051,7 @@ export declare const PersistedConfigSchema: z.ZodObject<{
1045
1051
  hostnames?: true | string[] | undefined;
1046
1052
  allowedHosts?: true | string[] | undefined;
1047
1053
  autoArchiveAfterMerge?: boolean | undefined;
1054
+ enableTerminalAgentHooks?: boolean | undefined;
1048
1055
  appendSystemPrompt?: string | undefined;
1049
1056
  terminalProfiles?: z.objectInputType<{
1050
1057
  id: z.ZodString;
@@ -187,6 +187,7 @@ export const PersistedConfigSchema = z
187
187
  .passthrough()
188
188
  .optional(),
189
189
  autoArchiveAfterMerge: z.boolean().optional(),
190
+ enableTerminalAgentHooks: z.boolean().optional(),
190
191
  appendSystemPrompt: z.string().optional(),
191
192
  terminalProfiles: z.array(TerminalProfileSchema).optional(),
192
193
  cors: z
@@ -24,6 +24,7 @@ export declare function extractTimestamps(record: StoredAgentRecord): {
24
24
  updatedAt: Date;
25
25
  lastUserMessageAt: Date | null;
26
26
  labels?: Record<string, string>;
27
+ workspaceId?: string;
27
28
  };
28
29
  export declare function toAgentPersistenceHandle(registeredProviders: Iterable<AgentProvider>, handle: StoredAgentRecord["persistence"]): AgentPersistenceHandle | null;
29
30
  export {};
@@ -2,6 +2,15 @@ import { stripInternalPaseoMcpServer } from "./agent/runtime-mcp-config.js";
2
2
  function getLogger(logger) {
3
3
  return logger.child({ module: "persistence" });
4
4
  }
5
+ function isProviderRegistered(validProviders, provider) {
6
+ if (!validProviders) {
7
+ return true;
8
+ }
9
+ if (validProviders instanceof Set) {
10
+ return validProviders.has(provider);
11
+ }
12
+ return new Set(validProviders).has(provider);
13
+ }
5
14
  /**
6
15
  * Attach AgentStorage persistence to an AgentManager instance so every
7
16
  * agent_state snapshot is flushed to disk.
@@ -35,9 +44,7 @@ export function buildConfigOverrides(record) {
35
44
  });
36
45
  }
37
46
  export function buildSessionConfig(record, options) {
38
- const validProviders = options?.validProviders;
39
- const isValidProvider = validProviders ? new Set(validProviders).has(record.provider) : true;
40
- if (!isValidProvider) {
47
+ if (!isProviderRegistered(options?.validProviders, record.provider)) {
41
48
  return null;
42
49
  }
43
50
  const overrides = buildConfigOverrides(record);
@@ -54,7 +61,7 @@ export function buildSessionConfig(record, options) {
54
61
  });
55
62
  }
56
63
  export function isStoredAgentProviderAvailable(record, validProviders) {
57
- return buildSessionConfig(record, { validProviders }) !== null;
64
+ return isProviderRegistered(validProviders, record.provider);
58
65
  }
59
66
  export function extractTimestamps(record) {
60
67
  return {
@@ -62,6 +69,7 @@ export function extractTimestamps(record) {
62
69
  updatedAt: new Date(record.lastActivityAt ?? record.updatedAt),
63
70
  lastUserMessageAt: record.lastUserMessageAt ? new Date(record.lastUserMessageAt) : null,
64
71
  labels: record.labels,
72
+ workspaceId: record.workspaceId,
65
73
  };
66
74
  }
67
75
  export function toAgentPersistenceHandle(registeredProviders, handle) {
@@ -69,7 +77,7 @@ export function toAgentPersistenceHandle(registeredProviders, handle) {
69
77
  return null;
70
78
  }
71
79
  const provider = handle.provider;
72
- if (!new Set(registeredProviders).has(provider)) {
80
+ if (!isProviderRegistered(registeredProviders, provider)) {
73
81
  return null;
74
82
  }
75
83
  if (!handle.sessionId) {
@@ -0,0 +1,3 @@
1
+ import type { PersistedWorkspaceRecord } from "./workspace-registry.js";
2
+ export declare function resolveWorkspaceIdForPath(cwd: string, workspaces: Iterable<PersistedWorkspaceRecord>): string | null;
3
+ //# sourceMappingURL=resolve-workspace-id-for-path.d.ts.map
@@ -0,0 +1,41 @@
1
+ import { homedir } from "node:os";
2
+ import { resolve, sep } from "node:path";
3
+ // external path→workspace adapter, not ownership.
4
+ //
5
+ // Resolves a raw filesystem path to a single workspace id ONLY at the boundary
6
+ // where a client hands the daemon a bare worktree path with no id:
7
+ // archive-by-path (old client / CLI), auto-archive-after-merge, and the MCP
8
+ // `archive_worktree` tool. It is NEVER used to attribute agent status or place
9
+ // agents under a workspace — those are keyed by `workspaceId`, and git facts
10
+ // derive from a workspace's OWN cwd (id → cwd).
11
+ //
12
+ // Resolution: an exact directory match wins; otherwise the deepest enclosing
13
+ // workspace directory, never the home directory; null when nothing encloses it.
14
+ export function resolveWorkspaceIdForPath(cwd, workspaces) {
15
+ const workspaceRecords = Array.from(workspaces);
16
+ const resolvedCwd = resolve(cwd);
17
+ const exactMatch = workspaceRecords.find((workspace) => resolve(workspace.cwd) === resolvedCwd);
18
+ if (exactMatch) {
19
+ return exactMatch.workspaceId;
20
+ }
21
+ const userHome = resolve(homedir());
22
+ let bestMatchLength = 0;
23
+ let bestMatch = null;
24
+ for (const workspace of workspaceRecords) {
25
+ if (workspace.archivedAt)
26
+ continue;
27
+ const workspaceCwd = resolve(workspace.cwd);
28
+ if (workspaceCwd === userHome)
29
+ continue;
30
+ const prefix = workspaceCwd.endsWith(sep) ? workspaceCwd : `${workspaceCwd}${sep}`;
31
+ if (!resolvedCwd.startsWith(prefix)) {
32
+ continue;
33
+ }
34
+ if (workspaceCwd.length > bestMatchLength) {
35
+ bestMatchLength = workspaceCwd.length;
36
+ bestMatch = workspace;
37
+ }
38
+ }
39
+ return bestMatch?.workspaceId ?? null;
40
+ }
41
+ //# sourceMappingURL=resolve-workspace-id-for-path.js.map
@@ -1,3 +1,3 @@
1
- export { createScriptProxyMiddleware, createScriptProxyUpgradeHandler, findFreePort, ScriptRouteStore, } from "./service-proxy.js";
1
+ export { createScriptProxyMiddleware, createScriptProxyUpgradeHandler, findFreePort, ScriptRouteStore, ServiceProxyRouteCollisionError, } from "./service-proxy.js";
2
2
  export type { ScriptRoute, ScriptRouteEntry } from "./service-proxy.js";
3
3
  //# sourceMappingURL=script-proxy.d.ts.map
@@ -1,2 +1,2 @@
1
- export { createScriptProxyMiddleware, createScriptProxyUpgradeHandler, findFreePort, ScriptRouteStore, } from "./service-proxy.js";
1
+ export { createScriptProxyMiddleware, createScriptProxyUpgradeHandler, findFreePort, ScriptRouteStore, ServiceProxyRouteCollisionError, } from "./service-proxy.js";
2
2
  //# sourceMappingURL=script-proxy.js.map
@@ -187,7 +187,7 @@ function sameRouteOwner(left, right) {
187
187
  }
188
188
  export class ServiceProxyRouteCollisionError extends Error {
189
189
  constructor(hostname, existing, incoming) {
190
- super(`Service proxy hostname collision for ${hostname}: ${existing.workspaceId}/${existing.scriptName} already owns it`);
190
+ super(`Another workspace is already serving "${incoming.scriptName}" at ${hostname}. Stop that service or run this one on a different branch to free the address.`);
191
191
  this.hostname = hostname;
192
192
  this.existing = existing;
193
193
  this.incoming = incoming;
@@ -16,6 +16,7 @@ import { type PersistedWorkspaceRecord, type ProjectRegistry, type WorkspaceRegi
16
16
  import { DownloadTokenStore } from "./file-download/token-store.js";
17
17
  import { PushTokenStore } from "./push/token-store.js";
18
18
  import type { ServiceProxySubsystem } from "./service-proxy.js";
19
+ import { renameCurrentBranch as renameCurrentBranchDefault } from "../utils/checkout-git.js";
19
20
  import { CheckoutDiffManager } from "./checkout-diff-manager.js";
20
21
  import { type Resolvable } from "./speech/provider-resolver.js";
21
22
  import type { SpeechReadinessSnapshot } from "./speech/speech-runtime.js";
@@ -24,6 +25,7 @@ import { FileBackedChatService } from "./chat/chat-service.js";
24
25
  import { LoopService } from "./loop-service.js";
25
26
  import { ScheduleService } from "./schedule/service.js";
26
27
  import { type GitHubService } from "../services/github-service.js";
28
+ import { generateBranchNameFromFirstAgentContext } from "./worktree-branch-name-generator.js";
27
29
  export declare function resolveWaitForFinishError(options: {
28
30
  status: "permission" | "error" | "idle";
29
31
  final: AgentSnapshotPayload | null;
@@ -44,6 +46,7 @@ export interface SessionOptions {
44
46
  clientCapabilities?: Record<string, unknown> | null;
45
47
  onMessage: (msg: SessionOutboundMessage) => void;
46
48
  onBinaryMessage?: (frame: Uint8Array) => void;
49
+ getTransportBufferedAmount?: () => number | null;
47
50
  onLifecycleIntent?: (intent: SessionLifecycleIntent) => void;
48
51
  logger: pino.Logger;
49
52
  downloadTokenStore: DownloadTokenStore;
@@ -61,6 +64,8 @@ export interface SessionOptions {
61
64
  checkoutDiffManager: CheckoutDiffManager;
62
65
  github?: GitHubService;
63
66
  createAgentMcpTransport?: AgentMcpTransportFactory;
67
+ renameCurrentBranch?: typeof renameCurrentBranchDefault;
68
+ generateWorkspaceName?: typeof generateBranchNameFromFirstAgentContext;
64
69
  workspaceGitService: WorkspaceGitService;
65
70
  daemonConfigStore: DaemonConfigStore;
66
71
  mcpBaseUrl?: string | null;
@@ -96,6 +101,7 @@ export interface SessionOptions {
96
101
  daemonVersion?: string;
97
102
  daemonRuntimeConfig?: {
98
103
  listen: string | null;
104
+ appBaseUrl?: string;
99
105
  relay: {
100
106
  enabled: boolean;
101
107
  endpoint: string;
@@ -127,6 +133,7 @@ export declare class Session {
127
133
  private readonly sessionId;
128
134
  private readonly onMessage;
129
135
  private readonly onBinaryMessage;
136
+ private readonly getTransportBufferedAmount;
130
137
  private readonly onLifecycleIntent;
131
138
  private readonly sessionLogger;
132
139
  private readonly paseoHome;
@@ -159,12 +166,15 @@ export declare class Session {
159
166
  private readonly loopService;
160
167
  private readonly checkoutDiffManager;
161
168
  private readonly github;
169
+ private readonly renameCurrentBranch;
170
+ private readonly generateWorkspaceName;
162
171
  private readonly workspaceGitService;
163
172
  private readonly daemonConfigStore;
164
173
  private readonly mcpBaseUrl;
165
174
  private readonly downloadTokenStore;
166
175
  private readonly pushTokenStore;
167
176
  private unsubscribeAgentEvents;
177
+ private unsubscribeTerminalWorkspaceContributionEvents;
168
178
  private agentUpdatesSubscription;
169
179
  private workspaceUpdatesSubscription;
170
180
  private clientActivity;
@@ -212,7 +222,6 @@ export declare class Session {
212
222
  markWorkspaceArchivingForExternalMutation(workspaceIds: Iterable<string>, archivingAt: string): void;
213
223
  clearWorkspaceArchivingForExternalMutation(workspaceIds: Iterable<string>): void;
214
224
  emitWorkspaceUpdatesForExternalWorkspaceIds(workspaceIds: Iterable<string>): Promise<void>;
215
- emitWorkspaceUpdatesForExternalCwds(cwds: Iterable<string>): Promise<void>;
216
225
  warmWorkspaceGitDataForWorkspace(workspace: PersistedWorkspaceRecord): Promise<void>;
217
226
  /**
218
227
  * Get the client's current activity state
@@ -220,6 +229,7 @@ export declare class Session {
220
229
  getClientActivity(): {
221
230
  deviceType: "web" | "mobile";
222
231
  focusedAgentId: string | null;
232
+ focusedTerminalId: string | null;
223
233
  lastActivityAt: Date;
224
234
  appVisible: boolean;
225
235
  appVisibilityChangedAt: Date;
@@ -264,11 +274,10 @@ export declare class Session {
264
274
  private getAgentUpdateTargetId;
265
275
  private bufferOrEmitAgentUpdate;
266
276
  private flushBootstrappedAgentUpdates;
267
- private findWorkspaceByDirectory;
268
277
  private findExactWorkspaceByDirectory;
269
278
  private resolveWorkspaceDirectory;
270
279
  private buildProjectPlacementForWorkspace;
271
- private buildProjectPlacementForCwd;
280
+ private buildProjectPlacementForWorkspaceId;
272
281
  private forwardAgentUpdate;
273
282
  /**
274
283
  * Main entry point for processing session messages
@@ -303,6 +312,7 @@ export declare class Session {
303
312
  private unarchiveAgentByHandle;
304
313
  private handleUpdateAgentRequest;
305
314
  private handleProjectRenameRequest;
315
+ private handleWorkspaceTitleSetRequest;
306
316
  private toVoiceFeatureUnavailableContext;
307
317
  private resolveModeReadinessState;
308
318
  private getVoiceFeatureUnavailableResponseMetadata;
@@ -326,7 +336,6 @@ export declare class Session {
326
336
  * Handle create agent request
327
337
  */
328
338
  private handleCreateAgentRequest;
329
- private resolveCreateAgentWorkspace;
330
339
  private handleResumeAgentRequest;
331
340
  private handleImportAgentRequest;
332
341
  private handleRefreshAgentRequest;
@@ -335,6 +344,10 @@ export declare class Session {
335
344
  private buildAgentSessionConfig;
336
345
  private scheduleAutoNameWorkspaceBranchForFirstAgent;
337
346
  private maybeAutoNameWorkspaceBranchForFirstAgent;
347
+ private applyGeneratedWorkspaceTitle;
348
+ private generateWorkspaceTitleFromContext;
349
+ private maybeAutoNameDirectoryWorkspaceTitle;
350
+ private scheduleAutoNameLocalWorkspaceTitleForFirstAgent;
338
351
  private emitProviderDisabledResponse;
339
352
  private handleListProviderModelsRequest;
340
353
  private handleListProviderModesRequest;
@@ -372,6 +385,7 @@ export declare class Session {
372
385
  * Handle client heartbeat for activity tracking
373
386
  */
374
387
  private handleClientHeartbeat;
388
+ private clearFocusedTerminalAttention;
375
389
  /**
376
390
  * Handle push token registration
377
391
  */
@@ -393,6 +407,7 @@ export declare class Session {
393
407
  private removeWorkspaceGitWatchTarget;
394
408
  private removeWorkspaceGitSubscription;
395
409
  private workspaceGitDescriptorStateKey;
410
+ private resolveWorkspaceGitWatchTarget;
396
411
  private shouldSkipWorkspaceGitWatchUpdate;
397
412
  private rememberWorkspaceGitDescriptorState;
398
413
  private handleWorkspaceGitBranchSnapshot;
@@ -437,13 +452,14 @@ export declare class Session {
437
452
  * Handle file download token request scoped to a workspace cwd
438
453
  */
439
454
  private handleFileDownloadTokenRequest;
455
+ private listTerminalActivityContributions;
440
456
  /**
441
457
  * Build the current agent list payload (live + persisted), optionally filtered by labels.
442
458
  */
443
459
  private listAgentPayloads;
444
460
  private resolveAgentIdentifier;
445
461
  private getAgentPayloadById;
446
- private buildActiveProjectPlacementsByWorkspaceCwd;
462
+ private buildActiveProjectPlacementsByWorkspaceId;
447
463
  private collectFetchAgentsEntries;
448
464
  private listFetchAgentsEntries;
449
465
  private readonly agentsPager;
@@ -457,7 +473,7 @@ export declare class Session {
457
473
  markWorkspaceArchiving(workspaceIds: Iterable<string>, archivingAt: string): void;
458
474
  clearWorkspaceArchiving(workspaceIds: Iterable<string>): void;
459
475
  private buildWorkspaceDescriptorMap;
460
- private resolveRegisteredWorkspaceIdForCwd;
476
+ private findWorkspaceIdForCwd;
461
477
  private matchesWorkspaceFilter;
462
478
  private listFetchWorkspacesEntries;
463
479
  private bufferOrEmitWorkspaceUpdate;
@@ -468,10 +484,14 @@ export declare class Session {
468
484
  private resolveProjectRecordForPlacement;
469
485
  private ensureWorkspaceRecordUnarchived;
470
486
  private createPaseoWorktree;
487
+ private listActiveWorkspaceRefs;
471
488
  private archiveWorkspaceRecord;
489
+ private teardownArchivedWorkspace;
472
490
  private reconcileAndEmitWorkspaceUpdates;
473
491
  private reconcileActiveWorkspaceRecords;
474
492
  private emitWorkspaceUpdatesForWorkspaceIds;
493
+ private resolveEmptyProjectForArchivedWorkspace;
494
+ private emitWorkspaceUpdateForTerminalContribution;
475
495
  private emitWorkspaceUpdateForCwd;
476
496
  private handleFetchAgents;
477
497
  private handleFetchAgentHistory;
@@ -479,6 +499,11 @@ export declare class Session {
479
499
  private handleFetchWorkspacesRequest;
480
500
  private buildBootstrapSnapshot;
481
501
  private registerWorkspaceForImportedAgent;
502
+ private handleWorkspaceCreateRequest;
503
+ private handleWorkspaceCreateLocal;
504
+ private scheduleWorkspaceNaming;
505
+ private handleWorkspaceCreateWorktree;
506
+ private resolveWorktreeSourceCwd;
482
507
  private handleOpenProjectRequest;
483
508
  private buildWorkspaceScriptPayloadSnapshot;
484
509
  private resolveWorkspaceScriptGitMetadata;