@getpaseo/server 0.1.96 → 0.1.97-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) 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/create-agent-title.d.ts +2 -0
  18. package/dist/server/server/agent/create-agent-title.js +5 -0
  19. package/dist/server/server/agent/import-sessions.d.ts +1 -10
  20. package/dist/server/server/agent/import-sessions.js +1 -53
  21. package/dist/server/server/agent/lifecycle-command.js +5 -4
  22. package/dist/server/server/agent/mcp-server.d.ts +8 -5
  23. package/dist/server/server/agent/mcp-server.js +41 -14
  24. package/dist/server/server/agent/mcp-shared.d.ts +6 -3
  25. package/dist/server/server/agent/mcp-shared.js +3 -0
  26. package/dist/server/server/agent/provider-launch-config.js +1 -1
  27. package/dist/server/server/agent/providers/acp-agent.d.ts +5 -0
  28. package/dist/server/server/agent/providers/acp-agent.js +31 -26
  29. package/dist/server/server/agent/providers/claude/agent.js +45 -6
  30. package/dist/server/server/agent/providers/codex-app-server-agent.js +1 -1
  31. package/dist/server/server/agent/providers/copilot-acp-agent.js +1 -0
  32. package/dist/server/server/agent/providers/cursor-acp-agent.d.ts +0 -7
  33. package/dist/server/server/agent/providers/cursor-acp-agent.js +0 -78
  34. package/dist/server/server/agent/providers/mock-load-test-agent.d.ts +2 -0
  35. package/dist/server/server/agent/providers/mock-load-test-agent.js +73 -1
  36. package/dist/server/server/agent/providers/opencode/server-manager.js +1 -1
  37. package/dist/server/server/agent/structured-generation-providers.js +45 -1
  38. package/dist/server/server/agent-attention-policy.d.ts +12 -3
  39. package/dist/server/server/agent-attention-policy.js +15 -3
  40. package/dist/server/server/auto-archive-on-merge/archive-if-safe.d.ts +7 -6
  41. package/dist/server/server/auto-archive-on-merge/archive-if-safe.js +21 -16
  42. package/dist/server/server/bootstrap.d.ts +3 -0
  43. package/dist/server/server/bootstrap.js +125 -64
  44. package/dist/server/server/config.js +1 -0
  45. package/dist/server/server/daemon-config-store.js +1 -0
  46. package/dist/server/server/exports.d.ts +1 -1
  47. package/dist/server/server/exports.js +1 -1
  48. package/dist/server/server/loop-service.d.ts +24 -24
  49. package/dist/server/server/migrations/backfill-workspace-id.migration.d.ts +9 -0
  50. package/dist/server/server/migrations/backfill-workspace-id.migration.js +60 -0
  51. package/dist/server/server/paseo-worktree-service.d.ts +9 -0
  52. package/dist/server/server/paseo-worktree-service.js +74 -12
  53. package/dist/server/server/path-utils.d.ts +1 -0
  54. package/dist/server/server/path-utils.js +6 -1
  55. package/dist/server/server/persisted-config.d.ts +7 -0
  56. package/dist/server/server/persisted-config.js +1 -0
  57. package/dist/server/server/persistence-hooks.d.ts +1 -0
  58. package/dist/server/server/persistence-hooks.js +13 -5
  59. package/dist/server/server/resolve-workspace-id-for-path.d.ts +3 -0
  60. package/dist/server/server/resolve-workspace-id-for-path.js +41 -0
  61. package/dist/server/server/script-proxy.d.ts +1 -1
  62. package/dist/server/server/script-proxy.js +1 -1
  63. package/dist/server/server/service-proxy.js +1 -1
  64. package/dist/server/server/session.d.ts +33 -6
  65. package/dist/server/server/session.js +691 -202
  66. package/dist/server/server/websocket-server.d.ts +5 -0
  67. package/dist/server/server/websocket-server.js +137 -3
  68. package/dist/server/server/workspace-archive-service.d.ts +60 -3
  69. package/dist/server/server/workspace-archive-service.js +217 -4
  70. package/dist/server/server/workspace-directory.d.ts +20 -2
  71. package/dist/server/server/workspace-directory.js +148 -70
  72. package/dist/server/server/workspace-git-service.js +21 -21
  73. package/dist/server/server/workspace-reconciliation-service.d.ts +1 -1
  74. package/dist/server/server/workspace-reconciliation-service.js +21 -22
  75. package/dist/server/server/workspace-registry-bootstrap.js +23 -10
  76. package/dist/server/server/workspace-registry-model.d.ts +3 -3
  77. package/dist/server/server/workspace-registry-model.js +9 -10
  78. package/dist/server/server/workspace-registry.d.ts +17 -4
  79. package/dist/server/server/workspace-registry.js +27 -0
  80. package/dist/server/server/worktree/commands.d.ts +7 -5
  81. package/dist/server/server/worktree/commands.js +38 -18
  82. package/dist/server/server/worktree-bootstrap.d.ts +1 -0
  83. package/dist/server/server/worktree-bootstrap.js +4 -1
  84. package/dist/server/server/worktree-branch-name-generator.d.ts +5 -1
  85. package/dist/server/server/worktree-branch-name-generator.js +29 -7
  86. package/dist/server/server/worktree-session.d.ts +4 -5
  87. package/dist/server/server/worktree-session.js +9 -3
  88. package/dist/server/services/github-service.js +1 -1
  89. package/dist/server/terminal/activity/terminal-activity-tracker.d.ts +20 -0
  90. package/dist/server/terminal/activity/terminal-activity-tracker.js +59 -0
  91. package/dist/server/terminal/agent-hooks/agent-hook-installer.d.ts +62 -0
  92. package/dist/server/terminal/agent-hooks/agent-hook-installer.js +117 -0
  93. package/dist/server/terminal/agent-hooks/claude/claude-settings.d.ts +7 -0
  94. package/dist/server/terminal/agent-hooks/claude/claude-settings.js +88 -0
  95. package/dist/server/terminal/agent-hooks/claude/claude.d.ts +4 -0
  96. package/dist/server/terminal/agent-hooks/claude/claude.js +47 -0
  97. package/dist/server/terminal/agent-hooks/codex/codex-settings.d.ts +7 -0
  98. package/dist/server/terminal/agent-hooks/codex/codex-settings.js +99 -0
  99. package/dist/server/terminal/agent-hooks/codex/codex.d.ts +4 -0
  100. package/dist/server/terminal/agent-hooks/codex/codex.js +30 -0
  101. package/dist/server/terminal/agent-hooks/opencode/opencode-plugin.d.ts +4 -0
  102. package/dist/server/terminal/agent-hooks/opencode/opencode-plugin.js +46 -0
  103. package/dist/server/terminal/agent-hooks/opencode/opencode.d.ts +3 -0
  104. package/dist/server/terminal/agent-hooks/opencode/opencode.js +23 -0
  105. package/dist/server/terminal/agent-hooks/provider-registry.d.ts +24 -0
  106. package/dist/server/terminal/agent-hooks/provider-registry.js +36 -0
  107. package/dist/server/terminal/agent-hooks/terminal-agent-hook-setting.d.ts +10 -0
  108. package/dist/server/terminal/agent-hooks/terminal-agent-hook-setting.js +26 -0
  109. package/dist/server/terminal/terminal-manager-factory.d.ts +4 -1
  110. package/dist/server/terminal/terminal-manager-factory.js +2 -2
  111. package/dist/server/terminal/terminal-manager.d.ts +33 -2
  112. package/dist/server/terminal/terminal-manager.js +144 -18
  113. package/dist/server/terminal/terminal-output-coalescer.d.ts +4 -0
  114. package/dist/server/terminal/terminal-output-coalescer.js +18 -0
  115. package/dist/server/terminal/terminal-restore.d.ts +1 -0
  116. package/dist/server/terminal/terminal-restore.js +6 -0
  117. package/dist/server/terminal/terminal-session-controller.d.ts +4 -2
  118. package/dist/server/terminal/terminal-session-controller.js +65 -24
  119. package/dist/server/terminal/terminal-worker-process.js +146 -63
  120. package/dist/server/terminal/terminal-worker-protocol.d.ts +19 -14
  121. package/dist/server/terminal/terminal.d.ts +42 -0
  122. package/dist/server/terminal/terminal.js +235 -16
  123. package/dist/server/terminal/worker-terminal-manager.d.ts +1 -0
  124. package/dist/server/terminal/worker-terminal-manager.js +220 -36
  125. package/dist/server/utils/build-metadata-prompt.d.ts +8 -3
  126. package/dist/server/utils/build-metadata-prompt.js +10 -9
  127. package/dist/server/utils/github-remote.js +1 -1
  128. package/dist/server/utils/tree-kill.d.ts +2 -2
  129. package/dist/src/{utils/executable.js → executable-resolution/executable-resolution.js} +16 -14
  130. package/dist/src/executable-resolution/windows.js +62 -0
  131. package/dist/src/server/agent/provider-launch-config.js +1 -1
  132. package/dist/src/server/persisted-config.js +1 -0
  133. package/package.json +10 -5
  134. package/dist/server/server/agent/agent-metadata-generator.d.ts +0 -36
  135. package/dist/server/server/agent/agent-metadata-generator.js +0 -112
  136. package/dist/server/server/paseo-worktree-archive-service.d.ts +0 -41
  137. package/dist/server/server/paseo-worktree-archive-service.js +0 -144
  138. package/dist/server/utils/wrap-user-instructions.d.ts +0 -2
  139. package/dist/server/utils/wrap-user-instructions.js +0 -13
@@ -34,17 +34,17 @@ declare const LoopVerifyCheckResultSchema: z.ZodObject<{
34
34
  startedAt: z.ZodString;
35
35
  completedAt: z.ZodString;
36
36
  }, "strip", z.ZodTypeAny, {
37
+ stdout: string;
37
38
  exitCode: number;
38
39
  command: string;
39
- stdout: string;
40
40
  stderr: string;
41
41
  startedAt: string;
42
42
  completedAt: string;
43
43
  passed: boolean;
44
44
  }, {
45
+ stdout: string;
45
46
  exitCode: number;
46
47
  command: string;
47
- stdout: string;
48
48
  stderr: string;
49
49
  startedAt: string;
50
50
  completedAt: string;
@@ -57,15 +57,15 @@ declare const LoopVerifyPromptResultSchema: z.ZodObject<{
57
57
  startedAt: z.ZodString;
58
58
  completedAt: z.ZodString;
59
59
  }, "strip", z.ZodTypeAny, {
60
- reason: string;
61
60
  startedAt: string;
62
61
  completedAt: string;
62
+ reason: string;
63
63
  passed: boolean;
64
64
  verifierAgentId: string | null;
65
65
  }, {
66
- reason: string;
67
66
  startedAt: string;
68
67
  completedAt: string;
68
+ reason: string;
69
69
  passed: boolean;
70
70
  verifierAgentId: string | null;
71
71
  }>;
@@ -87,17 +87,17 @@ declare const LoopIterationRecordSchema: z.ZodObject<{
87
87
  startedAt: z.ZodString;
88
88
  completedAt: z.ZodString;
89
89
  }, "strip", z.ZodTypeAny, {
90
+ stdout: string;
90
91
  exitCode: number;
91
92
  command: string;
92
- stdout: string;
93
93
  stderr: string;
94
94
  startedAt: string;
95
95
  completedAt: string;
96
96
  passed: boolean;
97
97
  }, {
98
+ stdout: string;
98
99
  exitCode: number;
99
100
  command: string;
100
- stdout: string;
101
101
  stderr: string;
102
102
  startedAt: string;
103
103
  completedAt: string;
@@ -110,15 +110,15 @@ declare const LoopIterationRecordSchema: z.ZodObject<{
110
110
  startedAt: z.ZodString;
111
111
  completedAt: z.ZodString;
112
112
  }, "strip", z.ZodTypeAny, {
113
- reason: string;
114
113
  startedAt: string;
115
114
  completedAt: string;
115
+ reason: string;
116
116
  passed: boolean;
117
117
  verifierAgentId: string | null;
118
118
  }, {
119
- reason: string;
120
119
  startedAt: string;
121
120
  completedAt: string;
121
+ reason: string;
122
122
  passed: boolean;
123
123
  verifierAgentId: string | null;
124
124
  }>>;
@@ -132,18 +132,18 @@ declare const LoopIterationRecordSchema: z.ZodObject<{
132
132
  workerOutcome: "completed" | "failed" | "canceled" | null;
133
133
  failureReason: string | null;
134
134
  verifyChecks: {
135
+ stdout: string;
135
136
  exitCode: number;
136
137
  command: string;
137
- stdout: string;
138
138
  stderr: string;
139
139
  startedAt: string;
140
140
  completedAt: string;
141
141
  passed: boolean;
142
142
  }[];
143
143
  verifyPrompt: {
144
- reason: string;
145
144
  startedAt: string;
146
145
  completedAt: string;
146
+ reason: string;
147
147
  passed: boolean;
148
148
  verifierAgentId: string | null;
149
149
  } | null;
@@ -157,18 +157,18 @@ declare const LoopIterationRecordSchema: z.ZodObject<{
157
157
  workerOutcome: "completed" | "failed" | "canceled" | null;
158
158
  failureReason: string | null;
159
159
  verifyChecks: {
160
+ stdout: string;
160
161
  exitCode: number;
161
162
  command: string;
162
- stdout: string;
163
163
  stderr: string;
164
164
  startedAt: string;
165
165
  completedAt: string;
166
166
  passed: boolean;
167
167
  }[];
168
168
  verifyPrompt: {
169
- reason: string;
170
169
  startedAt: string;
171
170
  completedAt: string;
171
+ reason: string;
172
172
  passed: boolean;
173
173
  verifierAgentId: string | null;
174
174
  } | null;
@@ -216,17 +216,17 @@ declare const LoopRecordSchema: z.ZodObject<{
216
216
  startedAt: z.ZodString;
217
217
  completedAt: z.ZodString;
218
218
  }, "strip", z.ZodTypeAny, {
219
+ stdout: string;
219
220
  exitCode: number;
220
221
  command: string;
221
- stdout: string;
222
222
  stderr: string;
223
223
  startedAt: string;
224
224
  completedAt: string;
225
225
  passed: boolean;
226
226
  }, {
227
+ stdout: string;
227
228
  exitCode: number;
228
229
  command: string;
229
- stdout: string;
230
230
  stderr: string;
231
231
  startedAt: string;
232
232
  completedAt: string;
@@ -239,15 +239,15 @@ declare const LoopRecordSchema: z.ZodObject<{
239
239
  startedAt: z.ZodString;
240
240
  completedAt: z.ZodString;
241
241
  }, "strip", z.ZodTypeAny, {
242
- reason: string;
243
242
  startedAt: string;
244
243
  completedAt: string;
244
+ reason: string;
245
245
  passed: boolean;
246
246
  verifierAgentId: string | null;
247
247
  }, {
248
- reason: string;
249
248
  startedAt: string;
250
249
  completedAt: string;
250
+ reason: string;
251
251
  passed: boolean;
252
252
  verifierAgentId: string | null;
253
253
  }>>;
@@ -261,18 +261,18 @@ declare const LoopRecordSchema: z.ZodObject<{
261
261
  workerOutcome: "completed" | "failed" | "canceled" | null;
262
262
  failureReason: string | null;
263
263
  verifyChecks: {
264
+ stdout: string;
264
265
  exitCode: number;
265
266
  command: string;
266
- stdout: string;
267
267
  stderr: string;
268
268
  startedAt: string;
269
269
  completedAt: string;
270
270
  passed: boolean;
271
271
  }[];
272
272
  verifyPrompt: {
273
- reason: string;
274
273
  startedAt: string;
275
274
  completedAt: string;
275
+ reason: string;
276
276
  passed: boolean;
277
277
  verifierAgentId: string | null;
278
278
  } | null;
@@ -286,18 +286,18 @@ declare const LoopRecordSchema: z.ZodObject<{
286
286
  workerOutcome: "completed" | "failed" | "canceled" | null;
287
287
  failureReason: string | null;
288
288
  verifyChecks: {
289
+ stdout: string;
289
290
  exitCode: number;
290
291
  command: string;
291
- stdout: string;
292
292
  stderr: string;
293
293
  startedAt: string;
294
294
  completedAt: string;
295
295
  passed: boolean;
296
296
  }[];
297
297
  verifyPrompt: {
298
- reason: string;
299
298
  startedAt: string;
300
299
  completedAt: string;
300
+ reason: string;
301
301
  passed: boolean;
302
302
  verifierAgentId: string | null;
303
303
  } | null;
@@ -351,18 +351,18 @@ declare const LoopRecordSchema: z.ZodObject<{
351
351
  workerOutcome: "completed" | "failed" | "canceled" | null;
352
352
  failureReason: string | null;
353
353
  verifyChecks: {
354
+ stdout: string;
354
355
  exitCode: number;
355
356
  command: string;
356
- stdout: string;
357
357
  stderr: string;
358
358
  startedAt: string;
359
359
  completedAt: string;
360
360
  passed: boolean;
361
361
  }[];
362
362
  verifyPrompt: {
363
- reason: string;
364
363
  startedAt: string;
365
364
  completedAt: string;
365
+ reason: string;
366
366
  passed: boolean;
367
367
  verifierAgentId: string | null;
368
368
  } | null;
@@ -413,18 +413,18 @@ declare const LoopRecordSchema: z.ZodObject<{
413
413
  workerOutcome: "completed" | "failed" | "canceled" | null;
414
414
  failureReason: string | null;
415
415
  verifyChecks: {
416
+ stdout: string;
416
417
  exitCode: number;
417
418
  command: string;
418
- stdout: string;
419
419
  stderr: string;
420
420
  startedAt: string;
421
421
  completedAt: string;
422
422
  passed: boolean;
423
423
  }[];
424
424
  verifyPrompt: {
425
- reason: string;
426
425
  startedAt: string;
427
426
  completedAt: string;
427
+ reason: string;
428
428
  passed: boolean;
429
429
  verifierAgentId: string | null;
430
430
  } | null;
@@ -0,0 +1,9 @@
1
+ import type { Logger } from "pino";
2
+ import type { AgentStorage } from "../agent/agent-storage.js";
3
+ import type { WorkspaceRegistry } from "../workspace-registry.js";
4
+ export declare function backfillWorkspaceIdForLegacyAgents(options: {
5
+ agentStorage: AgentStorage;
6
+ workspaceRegistry: WorkspaceRegistry;
7
+ logger: Logger;
8
+ }): Promise<number>;
9
+ //# sourceMappingURL=backfill-workspace-id.migration.d.ts.map
@@ -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,9 +1,11 @@
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";
6
7
  import { markPaseoWorktreeFirstAgentBranchAutoNameAttempted, readPaseoWorktreeMetadata, writePaseoWorktreeFirstAgentBranchAutoNameMetadata, } from "../utils/worktree-metadata.js";
8
+ import { resolveFirstAgentPromptTitle } from "./agent/create-agent-title.js";
7
9
  import { buildAgentBranchNameSeed } from "./agent/prompt-attachments.js";
8
10
  export async function createPaseoWorktree(input, deps) {
9
11
  const createdWorktree = await createWorktreeCore(input, deps);
@@ -13,6 +15,7 @@ export async function createPaseoWorktree(input, deps) {
13
15
  projectId: input.projectId,
14
16
  repoRoot: createdWorktree.repoRoot,
15
17
  worktree: createdWorktree.worktree,
18
+ title: resolveFirstAgentPromptTitle(input.firstAgentContext),
16
19
  deps,
17
20
  });
18
21
  deps.github.invalidate({ cwd: createdWorktree.worktree.worktreePath });
@@ -107,18 +110,20 @@ function maybeMarkFirstAgentBranchAutoNameEligible(options) {
107
110
  });
108
111
  }
109
112
  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);
113
+ const normalizedCwd = resolve(options.worktree.worktreePath);
114
+ const normalizedInputCwd = resolve(options.inputCwd);
115
+ const normalizedRepoRoot = resolve(options.repoRoot);
116
+ // Creation never deduplicates by directory: a worktree directory may back
117
+ // more than one workspace. We still resolve the source project from the
118
+ // originating checkout, but always mint a fresh workspace record.
114
119
  const sourceProject = await resolveSourceProjectForWorktree({
115
120
  inputCwd: normalizedInputCwd,
116
121
  projectId: options.projectId,
117
122
  repoRoot: normalizedRepoRoot,
118
- existingWorkspace,
123
+ existingWorkspace: null,
119
124
  deps: options.deps,
120
125
  });
121
- const workspaceId = normalizedCwd;
126
+ const workspaceId = generateWorkspaceId();
122
127
  const now = new Date().toISOString();
123
128
  await options.deps.projectRegistry.upsert(createPersistedProjectRecord({
124
129
  projectId: sourceProject.projectId,
@@ -136,13 +141,74 @@ async function upsertWorkspaceForWorktree(options) {
136
141
  cwd: normalizedCwd,
137
142
  kind: "worktree",
138
143
  displayName: options.worktree.branchName || normalizedCwd,
139
- createdAt: existingWorkspace?.createdAt ?? now,
144
+ branch: options.worktree.branchName || null,
145
+ title: options.title ?? null,
146
+ createdAt: now,
140
147
  updatedAt: now,
141
148
  archivedAt: null,
142
149
  });
143
150
  await options.deps.workspaceRegistry.upsert(workspace);
144
151
  return (await options.deps.workspaceRegistry.get(workspace.workspaceId)) ?? workspace;
145
152
  }
153
+ // Always create a NEW workspace record backed by the existing directory `cwd`.
154
+ // Never reuses a same-cwd record: a directory may back any number of
155
+ // workspaces. Used by explicit user creation.
156
+ export async function createLocalCheckoutWorkspace(options, deps) {
157
+ const normalizedCwd = resolve(options.cwd);
158
+ const checkout = await deps.workspaceGitService.getCheckout(normalizedCwd);
159
+ const membership = classifyDirectoryForProjectMembership({ cwd: normalizedCwd, checkout });
160
+ const now = new Date().toISOString();
161
+ const projectRecord = await resolveProjectRecordForMembership({
162
+ membership,
163
+ timestamp: now,
164
+ projectRegistry: deps.projectRegistry,
165
+ });
166
+ await deps.projectRegistry.upsert(projectRecord);
167
+ const trimmedTitle = options.title?.trim();
168
+ // Persist the live git branch into the dedicated `branch` field so
169
+ // buildWorkspaceCheckout reports the real branch for directory/local_checkout
170
+ // workspaces too (it reads workspace.branch). Same source deriveWorkspaceDisplayName
171
+ // reads. HEAD/detached resolves to null — there is no branch to report.
172
+ const currentBranch = checkout.currentBranch?.trim() ?? null;
173
+ const branch = currentBranch && currentBranch.toUpperCase() !== "HEAD" ? currentBranch : null;
174
+ const workspace = createPersistedWorkspaceRecord({
175
+ workspaceId: generateWorkspaceId(),
176
+ projectId: projectRecord.projectId,
177
+ cwd: normalizedCwd,
178
+ kind: membership.workspaceKind,
179
+ displayName: membership.workspaceDisplayName,
180
+ branch,
181
+ title: trimmedTitle ? trimmedTitle : null,
182
+ createdAt: now,
183
+ updatedAt: now,
184
+ });
185
+ await deps.workspaceRegistry.upsert(workspace);
186
+ return workspace;
187
+ }
188
+ async function resolveProjectRecordForMembership(options) {
189
+ const rootPath = options.membership.projectRootPath;
190
+ const projects = await options.projectRegistry.list();
191
+ const existingProject = projects.find((project) => !project.archivedAt && project.rootPath === rootPath) ??
192
+ projects.find((project) => project.rootPath === rootPath) ??
193
+ null;
194
+ if (!existingProject) {
195
+ return createPersistedProjectRecord({
196
+ projectId: options.membership.projectKey,
197
+ rootPath,
198
+ kind: options.membership.projectKind,
199
+ displayName: options.membership.projectName,
200
+ createdAt: options.timestamp,
201
+ updatedAt: options.timestamp,
202
+ });
203
+ }
204
+ return {
205
+ ...existingProject,
206
+ rootPath,
207
+ kind: options.membership.projectKind,
208
+ archivedAt: null,
209
+ updatedAt: options.timestamp,
210
+ };
211
+ }
146
212
  function sourceProjectFromRecord(record) {
147
213
  return {
148
214
  projectId: record.projectId,
@@ -211,8 +277,4 @@ async function findWorkspaceForSource(options) {
211
277
  workspaces.find((workspace) => workspace.cwd === options.repoRoot && !workspace.archivedAt) ??
212
278
  null);
213
279
  }
214
- async function findWorkspaceByDirectory(cwd, workspaceRegistry) {
215
- const workspaces = await workspaceRegistry.list();
216
- return workspaces.find((workspace) => workspace.cwd === cwd) ?? null;
217
- }
218
280
  //# 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;