@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
@@ -1,5 +1,6 @@
1
1
  import path from "node:path";
2
- import { classifyDirectoryForProjectMembership, normalizeWorkspaceId, } from "./workspace-registry-model.js";
2
+ import { classifyDirectoryForProjectMembership, generateWorkspaceId, } from "./workspace-registry-model.js";
3
+ import { backfillWorkspaceIdForLegacyAgents } from "./migrations/backfill-workspace-id.migration.js";
3
4
  import { createPersistedProjectRecord, createPersistedWorkspaceRecord, } from "./workspace-registry.js";
4
5
  function minIsoDate(left, right) {
5
6
  if (!left) {
@@ -32,28 +33,33 @@ export async function bootstrapWorkspaceRegistries(options) {
32
33
  ]);
33
34
  await Promise.all([options.projectRegistry.initialize(), options.workspaceRegistry.initialize()]);
34
35
  if (projectsExists && workspacesExists) {
36
+ await backfillWorkspaceIdForLegacyAgents(options);
35
37
  return;
36
38
  }
39
+ const existingWorkspaceIdsByCwd = new Map((await options.workspaceRegistry.list()).map((workspace) => [
40
+ path.resolve(workspace.cwd),
41
+ workspace.workspaceId,
42
+ ]));
37
43
  const records = await options.agentStorage.list();
38
44
  const activeRecords = records.filter((record) => !record.archivedAt);
39
- const recordsByWorkspaceId = new Map();
45
+ const recordsByDirectoryKey = new Map();
40
46
  const placements = await Promise.all(activeRecords.map(async (record) => {
41
- const normalizedCwd = normalizeWorkspaceId(record.cwd);
47
+ const normalizedCwd = path.resolve(record.cwd);
42
48
  const checkout = await options.workspaceGitService.getCheckout(normalizedCwd);
43
49
  const membership = classifyDirectoryForProjectMembership({
44
50
  cwd: normalizedCwd,
45
51
  checkout,
46
52
  });
47
- return { record, membership, workspaceId: membership.workspaceId };
53
+ return { record, membership, directoryKey: membership.workspaceDirectoryKey };
48
54
  }));
49
- for (const { record, membership, workspaceId } of placements) {
50
- const existing = recordsByWorkspaceId.get(workspaceId) ?? { membership, records: [] };
55
+ for (const { record, membership, directoryKey } of placements) {
56
+ const existing = recordsByDirectoryKey.get(directoryKey) ?? { membership, records: [] };
51
57
  existing.records.push(record);
52
- recordsByWorkspaceId.set(workspaceId, existing);
58
+ recordsByDirectoryKey.set(directoryKey, existing);
53
59
  }
54
60
  const projectRanges = new Map();
55
61
  const workspaceUpsertInputs = [];
56
- for (const [workspaceId, entry] of recordsByWorkspaceId.entries()) {
62
+ for (const entry of recordsByDirectoryKey.values()) {
57
63
  const { membership, records: workspaceRecords } = entry;
58
64
  const workspaceCwd = membership.checkout.cwd;
59
65
  let workspaceCreatedAt = null;
@@ -71,7 +77,13 @@ export async function bootstrapWorkspaceRegistries(options) {
71
77
  existingProjectRange.createdAt = minIsoDate(existingProjectRange.createdAt, createdAt);
72
78
  existingProjectRange.updatedAt = maxIsoDate(existingProjectRange.updatedAt, updatedAt);
73
79
  projectRanges.set(membership.projectKey, existingProjectRange);
74
- workspaceUpsertInputs.push({ workspaceId, membership, workspaceCwd, createdAt, updatedAt });
80
+ workspaceUpsertInputs.push({
81
+ workspaceId: existingWorkspaceIdsByCwd.get(workspaceCwd) ?? generateWorkspaceId(),
82
+ membership,
83
+ workspaceCwd,
84
+ createdAt,
85
+ updatedAt,
86
+ });
75
87
  }
76
88
  await Promise.all(workspaceUpsertInputs.flatMap(({ workspaceId, membership, workspaceCwd, createdAt, updatedAt }) => {
77
89
  const projectRange = projectRanges.get(membership.projectKey) ?? {
@@ -98,11 +110,12 @@ export async function bootstrapWorkspaceRegistries(options) {
98
110
  })),
99
111
  ];
100
112
  }));
113
+ await backfillWorkspaceIdForLegacyAgents(options);
101
114
  options.logger.info({
102
115
  projectsFile: path.join(options.paseoHome, "projects", "projects.json"),
103
116
  workspacesFile: path.join(options.paseoHome, "projects", "workspaces.json"),
104
117
  materializedProjects: projectRanges.size,
105
- materializedWorkspaces: recordsByWorkspaceId.size,
118
+ materializedWorkspaces: recordsByDirectoryKey.size,
106
119
  }, "Workspace registries bootstrapped from existing agent storage");
107
120
  }
108
121
  //# sourceMappingURL=workspace-registry-bootstrap.js.map
@@ -5,7 +5,7 @@ export type PersistedWorkspaceKind = "local_checkout" | "worktree" | "directory"
5
5
  export interface DirectoryProjectMembership {
6
6
  cwd: string;
7
7
  checkout: ProjectCheckoutLitePayload;
8
- workspaceId: string;
8
+ workspaceDirectoryKey: string;
9
9
  workspaceKind: PersistedWorkspaceKind;
10
10
  workspaceDisplayName: string;
11
11
  projectKey: string;
@@ -17,8 +17,8 @@ export interface DetectStaleWorkspacesInput {
17
17
  activeWorkspaces: PersistedWorkspaceRecord[];
18
18
  checkDirectoryExists: (cwd: string) => Promise<boolean>;
19
19
  }
20
- export declare function normalizeWorkspaceId(cwd: string): string;
21
- export declare function deriveWorkspaceId(cwd: string, checkout: ProjectCheckoutLitePayload): string;
20
+ export declare function generateWorkspaceId(): string;
21
+ export declare function deriveWorkspaceDirectoryKey(cwd: string, checkout: ProjectCheckoutLitePayload): string;
22
22
  export declare function deriveProjectGroupingKey(options: {
23
23
  cwd: string;
24
24
  remoteUrl: string | null;
@@ -1,15 +1,14 @@
1
+ import { randomBytes } from "node:crypto";
1
2
  import { resolve } from "node:path";
2
3
  import { parseGitRevParsePath } from "../utils/git-rev-parse-path.js";
3
- export function normalizeWorkspaceId(cwd) {
4
- const trimmed = cwd.trim();
5
- if (!trimmed) {
6
- return cwd;
7
- }
8
- return resolve(trimmed);
4
+ export function generateWorkspaceId() {
5
+ return `wks_${randomBytes(8).toString("hex")}`;
9
6
  }
10
- export function deriveWorkspaceId(cwd, checkout) {
7
+ // Path-derived grouping key for a workspace directory. This is NOT the opaque
8
+ // workspace identity (see generateWorkspaceId); never persist or compare it as one.
9
+ export function deriveWorkspaceDirectoryKey(cwd, checkout) {
11
10
  const worktreeRoot = checkout.worktreeRoot ? parseGitRevParsePath(checkout.worktreeRoot) : null;
12
- return worktreeRoot ?? normalizeWorkspaceId(cwd);
11
+ return worktreeRoot ?? resolve(cwd);
13
12
  }
14
13
  function deriveRemoteProjectKey(remoteUrl) {
15
14
  if (!remoteUrl) {
@@ -160,7 +159,7 @@ export function buildProjectPlacementForCwd(input) {
160
159
  };
161
160
  }
162
161
  export function classifyDirectoryForProjectMembership(input) {
163
- const normalizedCwd = normalizeWorkspaceId(input.cwd);
162
+ const normalizedCwd = resolve(input.cwd);
164
163
  const checkout = {
165
164
  ...input.checkout,
166
165
  cwd: normalizedCwd,
@@ -173,7 +172,7 @@ export function classifyDirectoryForProjectMembership(input) {
173
172
  return {
174
173
  cwd: normalizedCwd,
175
174
  checkout,
176
- workspaceId: deriveWorkspaceId(normalizedCwd, checkout),
175
+ workspaceDirectoryKey: deriveWorkspaceDirectoryKey(normalizedCwd, checkout),
177
176
  workspaceKind: deriveWorkspaceKind(checkout),
178
177
  workspaceDisplayName: deriveWorkspaceDisplayName({
179
178
  cwd: normalizedCwd,
@@ -11,19 +11,19 @@ declare const PersistedProjectRecordSchema: z.ZodObject<{
11
11
  updatedAt: z.ZodString;
12
12
  archivedAt: z.ZodNullable<z.ZodString>;
13
13
  }, "strip", z.ZodTypeAny, {
14
+ kind: "git" | "non_git";
14
15
  createdAt: string;
15
16
  updatedAt: string;
16
17
  archivedAt: string | null;
17
- kind: "git" | "non_git";
18
18
  projectId: string;
19
19
  displayName: string;
20
20
  rootPath: string;
21
21
  customName: string | null;
22
22
  }, {
23
+ kind: "git" | "non_git";
23
24
  createdAt: string;
24
25
  updatedAt: string;
25
26
  archivedAt: string | null;
26
- kind: "git" | "non_git";
27
27
  projectId: string;
28
28
  displayName: string;
29
29
  rootPath: string;
@@ -35,27 +35,33 @@ declare const PersistedWorkspaceRecordSchema: z.ZodObject<{
35
35
  cwd: z.ZodString;
36
36
  kind: z.ZodEnum<["local_checkout", "worktree", "directory"]>;
37
37
  displayName: z.ZodString;
38
+ title: z.ZodEffects<z.ZodOptional<z.ZodNullable<z.ZodString>>, string | null, string | null | undefined>;
39
+ branch: z.ZodEffects<z.ZodOptional<z.ZodNullable<z.ZodString>>, string | null, string | null | undefined>;
38
40
  createdAt: z.ZodString;
39
41
  updatedAt: z.ZodString;
40
42
  archivedAt: z.ZodNullable<z.ZodString>;
41
43
  }, "strip", z.ZodTypeAny, {
44
+ kind: "local_checkout" | "worktree" | "directory";
42
45
  workspaceId: string;
43
46
  cwd: string;
47
+ title: string | null;
44
48
  createdAt: string;
45
49
  updatedAt: string;
46
50
  archivedAt: string | null;
47
- kind: "local_checkout" | "worktree" | "directory";
48
51
  projectId: string;
49
52
  displayName: string;
53
+ branch: string | null;
50
54
  }, {
55
+ kind: "local_checkout" | "worktree" | "directory";
51
56
  workspaceId: string;
52
57
  cwd: string;
53
58
  createdAt: string;
54
59
  updatedAt: string;
55
60
  archivedAt: string | null;
56
- kind: "local_checkout" | "worktree" | "directory";
57
61
  projectId: string;
58
62
  displayName: string;
63
+ title?: string | null | undefined;
64
+ branch?: string | null | undefined;
59
65
  }>;
60
66
  export type PersistedProjectRecord = z.infer<typeof PersistedProjectRecordSchema>;
61
67
  export type PersistedWorkspaceRecord = z.infer<typeof PersistedWorkspaceRecordSchema>;
@@ -127,9 +133,16 @@ export declare function createPersistedWorkspaceRecord(input: {
127
133
  cwd: string;
128
134
  kind: PersistedWorkspaceKind;
129
135
  displayName: string;
136
+ title?: string | null;
137
+ branch?: string | null;
130
138
  createdAt: string;
131
139
  updatedAt: string;
132
140
  archivedAt?: string | null;
133
141
  }): PersistedWorkspaceRecord;
142
+ export declare function resolveWorkspaceName(input: {
143
+ title: string | null;
144
+ derivedDisplayName: string;
145
+ }): string;
146
+ export declare function resolveWorkspaceDisplayName(record: PersistedWorkspaceRecord): string;
134
147
  export {};
135
148
  //# sourceMappingURL=workspace-registry.d.ts.map
@@ -23,6 +23,22 @@ const PersistedWorkspaceRecordSchema = z.object({
23
23
  cwd: z.string(),
24
24
  kind: z.enum(["local_checkout", "worktree", "directory"]),
25
25
  displayName: z.string(),
26
+ // User-set title layered over the derived displayName. In Model B the title is
27
+ // the workspace identity; branch/directory are backing metadata. Reconciliation
28
+ // never touches this. Null means "use the derived displayName".
29
+ title: z
30
+ .string()
31
+ .nullable()
32
+ .optional()
33
+ .transform((value) => value ?? null),
34
+ // The worktree's git branch. Decoupled from displayName/title by construction:
35
+ // displayName holds the human name (title), branch holds the git branch. Only
36
+ // worktree workspaces carry a branch; directory/local_checkout leave it null.
37
+ branch: z
38
+ .string()
39
+ .nullable()
40
+ .optional()
41
+ .transform((value) => value ?? null),
26
42
  createdAt: z.string(),
27
43
  updatedAt: z.string(),
28
44
  archivedAt: z.string().nullable(),
@@ -152,7 +168,18 @@ export function resolveProjectDisplayName(record) {
152
168
  export function createPersistedWorkspaceRecord(input) {
153
169
  return PersistedWorkspaceRecordSchema.parse({
154
170
  ...input,
171
+ title: input.title ?? null,
172
+ branch: input.branch ?? null,
155
173
  archivedAt: input.archivedAt ?? null,
156
174
  });
157
175
  }
176
+ // The single workspace-name rule: the title always wins; otherwise fall back to
177
+ // the freshest available derived display name (a live branch snapshot when the
178
+ // caller has one, the persisted displayName otherwise).
179
+ export function resolveWorkspaceName(input) {
180
+ return input.title ?? input.derivedDisplayName;
181
+ }
182
+ export function resolveWorkspaceDisplayName(record) {
183
+ return resolveWorkspaceName({ title: record.title, derivedDisplayName: record.displayName });
184
+ }
158
185
  //# sourceMappingURL=workspace-registry.js.map
@@ -1,4 +1,4 @@
1
- import { type ArchivePaseoWorktreeDependencies } from "../paseo-worktree-archive-service.js";
1
+ import { type ArchiveDependencies, type ArchiveScope } from "../workspace-archive-service.js";
2
2
  import type { CreatePaseoWorktreeInput, CreatePaseoWorktreeResult } from "../paseo-worktree-service.js";
3
3
  import { type WorktreeWireError } from "../worktree-errors.js";
4
4
  import type { WorkspaceGitService, WorkspaceGitWorktreeInfo } from "../workspace-git-service.js";
@@ -29,17 +29,19 @@ export type CreatePaseoWorktreeCommandResult<Result extends CreatePaseoWorktreeR
29
29
  cause: unknown;
30
30
  };
31
31
  export declare function createPaseoWorktreeCommand<Result extends CreatePaseoWorktreeResult>(dependencies: CreatePaseoWorktreeCommandDependencies<Result>, input: CreatePaseoWorktreeCommandInput): Promise<CreatePaseoWorktreeCommandResult<Result>>;
32
- export interface ArchivePaseoWorktreeCommandDependencies extends Omit<ArchivePaseoWorktreeDependencies, "workspaceGitService"> {
32
+ export interface ArchiveCommandDependencies extends Omit<ArchiveDependencies, "workspaceGitService"> {
33
33
  workspaceGitService: Pick<WorkspaceGitService, "getSnapshot" | "listWorktrees">;
34
34
  }
35
- export interface ArchivePaseoWorktreeCommandInput {
35
+ export interface ArchiveCommandInput {
36
36
  requestId: string;
37
37
  repoRoot?: string | null;
38
38
  worktreePath?: string;
39
39
  worktreeSlug?: string;
40
40
  branchName?: string;
41
+ workspaceId?: string;
42
+ scope?: ArchiveScope["kind"];
41
43
  }
42
- export type ArchivePaseoWorktreeCommandResult = {
44
+ export type ArchiveCommandResult = {
43
45
  ok: true;
44
46
  removedAgents: string[];
45
47
  } | {
@@ -48,6 +50,6 @@ export type ArchivePaseoWorktreeCommandResult = {
48
50
  message: string;
49
51
  removedAgents: [];
50
52
  };
51
- export declare function archivePaseoWorktreeCommand(dependencies: ArchivePaseoWorktreeCommandDependencies, input: ArchivePaseoWorktreeCommandInput): Promise<ArchivePaseoWorktreeCommandResult>;
53
+ export declare function archiveCommand(dependencies: ArchiveCommandDependencies, input: ArchiveCommandInput): Promise<ArchiveCommandResult>;
52
54
  export {};
53
55
  //# sourceMappingURL=commands.d.ts.map
@@ -1,6 +1,6 @@
1
1
  import { join } from "node:path";
2
2
  import { getPaseoWorktreesRoot, isPaseoOwnedWorktreeCwd } from "../../utils/worktree.js";
3
- import { archivePaseoWorktree, } from "../paseo-worktree-archive-service.js";
3
+ import { archiveByScope, resolveWorkspaceIdAtPath, } from "../workspace-archive-service.js";
4
4
  import { toWorktreeWireError } from "../worktree-errors.js";
5
5
  export async function listPaseoWorktreesCommand(dependencies, input) {
6
6
  if (input.reason) {
@@ -29,31 +29,51 @@ export async function createPaseoWorktreeCommand(dependencies, input) {
29
29
  };
30
30
  }
31
31
  }
32
- export async function archivePaseoWorktreeCommand(dependencies, input) {
32
+ export async function archiveCommand(dependencies, input) {
33
33
  const resolvedTarget = await resolveArchiveTarget(dependencies, input);
34
- const ownership = await isPaseoOwnedWorktreeCwd(resolvedTarget.targetPath, {
35
- paseoHome: dependencies.paseoHome,
36
- worktreesRoot: dependencies.worktreesRoot,
37
- });
38
- if (!ownership.allowed) {
34
+ const scope = input.scope ?? "workspace";
35
+ if (scope === "worktree") {
36
+ const ownership = await isPaseoOwnedWorktreeCwd(resolvedTarget.targetPath, {
37
+ paseoHome: dependencies.paseoHome,
38
+ worktreesRoot: dependencies.paseoWorktreesBaseRoot,
39
+ });
40
+ if (!ownership.allowed) {
41
+ return {
42
+ ok: false,
43
+ code: "NOT_ALLOWED",
44
+ message: "Worktree is not a Paseo-owned worktree",
45
+ removedAgents: [],
46
+ };
47
+ }
48
+ const result = await archiveByScope(dependencies, {
49
+ scope: { kind: "worktree", targetPath: resolvedTarget.targetPath },
50
+ repoRoot: ownership.repoRoot ?? resolvedTarget.repoRoot ?? null,
51
+ repoWorktreesRoot: ownership.worktreeRoot,
52
+ paseoWorktreesBaseRoot: dependencies.paseoWorktreesBaseRoot,
53
+ requestId: input.requestId,
54
+ });
39
55
  return {
40
- ok: false,
41
- code: "NOT_ALLOWED",
42
- message: "Worktree is not a Paseo-owned worktree",
56
+ ok: true,
57
+ removedAgents: result.archivedAgentIds,
58
+ };
59
+ }
60
+ const workspaceId = input.workspaceId ?? (await resolveWorkspaceIdAtPath(dependencies, resolvedTarget.targetPath));
61
+ if (!workspaceId) {
62
+ dependencies.sessionLogger?.warn({ targetPath: resolvedTarget.targetPath }, "Could not resolve workspace for archive; skipping");
63
+ return {
64
+ ok: true,
43
65
  removedAgents: [],
44
66
  };
45
67
  }
46
- const repoRoot = ownership.repoRoot ?? resolvedTarget.repoRoot ?? null;
47
- const removedAgents = await archivePaseoWorktree(dependencies, {
48
- targetPath: resolvedTarget.targetPath,
49
- repoRoot,
50
- worktreesRoot: ownership.worktreeRoot,
51
- worktreesBaseRoot: dependencies.worktreesRoot,
68
+ const result = await archiveByScope(dependencies, {
69
+ scope: { kind: "workspace", workspaceId },
70
+ repoRoot: resolvedTarget.repoRoot,
71
+ paseoWorktreesBaseRoot: dependencies.paseoWorktreesBaseRoot,
52
72
  requestId: input.requestId,
53
73
  });
54
74
  return {
55
75
  ok: true,
56
- removedAgents,
76
+ removedAgents: result.archivedAgentIds,
57
77
  };
58
78
  }
59
79
  async function resolveArchiveTarget(dependencies, input) {
@@ -81,7 +101,7 @@ async function resolveArchiveTarget(dependencies, input) {
81
101
  throw new Error("worktreePath, worktreeSlug, or repoRoot+branchName is required");
82
102
  }
83
103
  async function resolveWorktreeSlugPath(dependencies, repoRoot, worktreeSlug) {
84
- const worktreesRoot = await getPaseoWorktreesRoot(repoRoot, dependencies.paseoHome, dependencies.worktreesRoot);
104
+ const worktreesRoot = await getPaseoWorktreesRoot(repoRoot, dependencies.paseoHome, dependencies.paseoWorktreesBaseRoot);
85
105
  return join(worktreesRoot, worktreeSlug);
86
106
  }
87
107
  //# sourceMappingURL=commands.js.map
@@ -13,6 +13,7 @@ export interface WorktreeBootstrapTerminalResult {
13
13
  }
14
14
  export interface RunAsyncWorktreeBootstrapOptions {
15
15
  agentId: string;
16
+ workspaceId: string;
16
17
  worktree: WorktreeConfig;
17
18
  shouldBootstrap?: boolean;
18
19
  terminalManager: TerminalManager | null;
@@ -383,6 +383,7 @@ async function runWorktreeTerminalBootstrap(options, runtimeEnv) {
383
383
  cwd: options.worktree.worktreePath,
384
384
  name: spec.name,
385
385
  env: runtimeEnv,
386
+ workspaceId: options.workspaceId,
386
387
  });
387
388
  await waitForTerminalBootstrapReadiness(terminal);
388
389
  terminal.send({
@@ -550,7 +551,7 @@ async function setupServiceScriptRoute(params) {
550
551
  return { hostname: registeredRoute.hostname, port, env };
551
552
  }
552
553
  async function acquireWorkspaceScriptTerminal(params) {
553
- const { serviceScript, existingRuntimeEntry, terminalManager, repoRoot, scriptName, env } = params;
554
+ const { serviceScript, existingRuntimeEntry, terminalManager, repoRoot, workspaceId, scriptName, env, } = params;
554
555
  let reusableTerminal = null;
555
556
  if (!serviceScript && existingRuntimeEntry?.terminalId) {
556
557
  reusableTerminal = terminalManager.getTerminal(existingRuntimeEntry.terminalId) ?? null;
@@ -558,6 +559,7 @@ async function acquireWorkspaceScriptTerminal(params) {
558
559
  const terminal = reusableTerminal ??
559
560
  (await terminalManager.createTerminal({
560
561
  cwd: repoRoot,
562
+ workspaceId,
561
563
  name: scriptName,
562
564
  title: scriptName,
563
565
  env,
@@ -612,6 +614,7 @@ export async function spawnWorkspaceScript(options) {
612
614
  existingRuntimeEntry,
613
615
  terminalManager,
614
616
  repoRoot,
617
+ workspaceId,
615
618
  scriptName,
616
619
  env,
617
620
  });
@@ -26,6 +26,10 @@ export interface GenerateBranchNameFromFirstAgentContextOptions {
26
26
  generateStructuredAgentResponseWithFallback?: typeof generateStructuredAgentResponseWithFallback;
27
27
  };
28
28
  }
29
- export declare function generateBranchNameFromFirstAgentContext(options: GenerateBranchNameFromFirstAgentContextOptions): Promise<string | null>;
29
+ export interface GeneratedWorkspaceName {
30
+ title: string | null;
31
+ branch: string | null;
32
+ }
33
+ export declare function generateBranchNameFromFirstAgentContext(options: GenerateBranchNameFromFirstAgentContextOptions): Promise<GeneratedWorkspaceName | null>;
30
34
  export {};
31
35
  //# sourceMappingURL=worktree-branch-name-generator.d.ts.map
@@ -4,19 +4,38 @@ import { resolveStructuredGenerationProviders, } from "./agent/structured-genera
4
4
  import { buildAgentBranchNameSeed } from "./agent/prompt-attachments.js";
5
5
  import { buildMetadataPrompt } from "../utils/build-metadata-prompt.js";
6
6
  const BranchNameSchema = z.object({
7
+ title: z.string().min(1).max(80),
7
8
  branch: z.string().min(1).max(100),
8
9
  });
9
10
  async function buildPrompt(seed, options) {
10
11
  return buildMetadataPrompt({
11
12
  cwd: options.cwd,
12
13
  workspaceGitService: options.workspaceGitService,
13
- configKey: "branchName",
14
- before: [
15
- "Generate a git branch name for a coding agent based on the user prompt and attachments.",
16
- "Branch: concise lowercase slug using letters, numbers, hyphens, and slashes only.",
17
- "No spaces, no uppercase, no leading or trailing hyphen, no consecutive hyphens.",
14
+ contract: [
15
+ "Generate a title and a git branch name for a coding agent from the user prompt and attachments.",
16
+ "The branch must be a valid git ref: lowercase letters, numbers, hyphens, and slashes only, with no spaces, no uppercase, no leading or trailing hyphen, and no consecutive hyphens.",
17
+ "The branch is generated directly from the prompt it is NEVER derived from or slugified from the title.",
18
18
  ].join("\n"),
19
- after: "Return JSON only with a single field 'branch'.",
19
+ styles: [
20
+ {
21
+ configKey: "title",
22
+ label: "Title style",
23
+ default: [
24
+ "A terse, task-shaped label naming what the task is about (sentence case, max 80 characters).",
25
+ "Aim for about 4 words. Go longer only when the task genuinely needs it; most titles must stay short.",
26
+ "Do not start with a generic 'do' verb (Fix, Add, Implement, Diagnose, Update, Change, Create, Set, Make) — every task is implicitly one of these, so the verb is noise. Name the thing instead.",
27
+ "Keep a verb only when it states the specific operation (Swap, Split, Extract, Rename, Merge, Inline).",
28
+ 'Good titles: "Swap sidebar history icon", "Composer keyboard shift", "Agent auto-titling", "Worktree selection memory", "Split browser pane".',
29
+ 'Bad titles: "Fix composer pushed up by keyboard in workspace", "Diagnose auto-titling still happening for agents", "Change sidebar history icon from clock to history icon".',
30
+ ].join("\n"),
31
+ },
32
+ {
33
+ configKey: "branchName",
34
+ label: "Branch style",
35
+ default: "A short, descriptive slug — a few lowercase words joined by hyphens.",
36
+ },
37
+ ],
38
+ after: "Return JSON only with fields 'title' and 'branch'.",
20
39
  trailing: `User context:\n${seed}`,
21
40
  });
22
41
  }
@@ -54,7 +73,10 @@ export async function generateBranchNameFromFirstAgentContext(options) {
54
73
  internal: true,
55
74
  },
56
75
  });
57
- return result.branch.trim() || null;
76
+ return {
77
+ title: result.title.trim() || null,
78
+ branch: result.branch.trim() || null,
79
+ };
58
80
  }
59
81
  catch (error) {
60
82
  const attempts = error instanceof StructuredAgentFallbackError ? error.attempts : undefined;
@@ -11,7 +11,7 @@ import type { GitHubService } from "../services/github-service.js";
11
11
  import type { CheckoutExistingBranchResult } from "../utils/checkout-git.js";
12
12
  import { type WorktreeConfig } from "../utils/worktree.js";
13
13
  import type { CreatePaseoWorktreeInput, CreatePaseoWorktreeResult } from "./paseo-worktree-service.js";
14
- import type { ArchivePaseoWorktreeDependencies } from "./paseo-worktree-archive-service.js";
14
+ import type { ArchiveDependencies } from "./workspace-archive-service.js";
15
15
  export interface NormalizedGitOptions {
16
16
  baseBranch?: string;
17
17
  createNewBranch: boolean;
@@ -49,9 +49,7 @@ interface BuildAgentSessionConfigDependencies {
49
49
  interface CreatePaseoWorktreeInBackgroundDependencies {
50
50
  paseoHome?: string;
51
51
  worktreesRoot?: string;
52
- emitWorkspaceUpdateForCwd: (cwd: string, options?: {
53
- dedupeGitState?: boolean;
54
- }) => Promise<void>;
52
+ emitWorkspaceUpdateForWorkspaceId: (workspaceId: string) => Promise<void>;
55
53
  cacheWorkspaceSetupSnapshot: (workspaceId: string, snapshot: WorkspaceSetupSnapshot) => void;
56
54
  emit: EmitSessionMessage;
57
55
  sessionLogger: Logger;
@@ -112,6 +110,7 @@ interface HandleCreatePaseoWorktreeRequestDependencies {
112
110
  export declare function buildAgentSessionConfig(dependencies: BuildAgentSessionConfigDependencies, config: AgentSessionConfig, gitOptions?: GitSetupOptions, legacyWorktreeName?: string, firstAgentContext?: FirstAgentContext): Promise<{
113
111
  sessionConfig: AgentSessionConfig;
114
112
  setupContinuation?: AgentWorktreeSetupContinuation;
113
+ createdWorkspaceId?: string;
115
114
  }>;
116
115
  export declare function normalizeGitOptions(gitOptions?: GitSetupOptions, legacyWorktreeName?: string): NormalizedGitOptions | null;
117
116
  export declare function assertSafeGitRef(ref: string, label: string): void;
@@ -123,7 +122,7 @@ export declare function handlePaseoWorktreeListRequest(dependencies: {
123
122
  }, msg: Extract<SessionInboundMessage, {
124
123
  type: "paseo_worktree_list_request";
125
124
  }>): Promise<void>;
126
- export declare function handlePaseoWorktreeArchiveRequest(dependencies: Omit<ArchivePaseoWorktreeDependencies, "emitWorkspaceUpdatesForWorkspaceIds" | "workspaceGitService"> & {
125
+ export declare function handlePaseoWorktreeArchiveRequest(dependencies: Omit<ArchiveDependencies, "emitWorkspaceUpdatesForWorkspaceIds" | "workspaceGitService"> & {
127
126
  emit: EmitSessionMessage;
128
127
  workspaceGitService: Pick<WorkspaceGitService, "getSnapshot" | "listWorktrees">;
129
128
  emitWorkspaceUpdatesForWorkspaceIds: (workspaceIds: Iterable<string>) => Promise<void>;
@@ -4,7 +4,7 @@ import { expandTilde } from "../utils/path.js";
4
4
  import { getWorktreeSetupCommands, resolveWorktreeRuntimeEnv, runWorktreeSetupCommands, slugify, validateBranchSlug, WorktreeSetupError, } from "../utils/worktree.js";
5
5
  import { toCheckoutError } from "./checkout-git-utils.js";
6
6
  import { toWorktreeWireError } from "./worktree-errors.js";
7
- import { archivePaseoWorktreeCommand, createPaseoWorktreeCommand, listPaseoWorktreesCommand, } from "./worktree/commands.js";
7
+ import { archiveCommand, createPaseoWorktreeCommand, listPaseoWorktreesCommand, } from "./worktree/commands.js";
8
8
  const SAFE_GIT_REF_PATTERN = /^[A-Za-z0-9._/-]+$/;
9
9
  function normalizeFirstAgentContext(request) {
10
10
  if (request.firstAgentContext) {
@@ -22,6 +22,7 @@ export async function buildAgentSessionConfig(dependencies, config, gitOptions,
22
22
  let cwd = expandTilde(config.cwd);
23
23
  const normalized = normalizeGitOptions(gitOptions, legacyWorktreeName);
24
24
  let setupContinuation;
25
+ let createdWorkspaceId;
25
26
  if (!normalized) {
26
27
  return {
27
28
  sessionConfig: {
@@ -49,6 +50,7 @@ export async function buildAgentSessionConfig(dependencies, config, gitOptions,
49
50
  });
50
51
  cwd = createdWorktree.worktree.worktreePath;
51
52
  setupContinuation = createdWorktree.setupContinuation;
53
+ createdWorkspaceId = createdWorktree.workspace.workspaceId;
52
54
  }
53
55
  else if (normalized.createNewBranch) {
54
56
  const baseBranch = normalized.baseBranch ??
@@ -70,6 +72,7 @@ export async function buildAgentSessionConfig(dependencies, config, gitOptions,
70
72
  cwd,
71
73
  },
72
74
  setupContinuation,
75
+ createdWorkspaceId,
73
76
  };
74
77
  }
75
78
  function validateNormalizedGitOptions(input) {
@@ -195,11 +198,13 @@ export async function handlePaseoWorktreeListRequest(dependencies, msg) {
195
198
  export async function handlePaseoWorktreeArchiveRequest(dependencies, msg) {
196
199
  const { requestId } = msg;
197
200
  try {
198
- const result = await archivePaseoWorktreeCommand(dependencies, {
201
+ const result = await archiveCommand(dependencies, {
199
202
  requestId,
200
203
  worktreePath: msg.worktreePath,
201
204
  repoRoot: msg.repoRoot,
202
205
  branchName: msg.branchName,
206
+ workspaceId: msg.workspaceId,
207
+ scope: msg.scope,
203
208
  });
204
209
  if (!result.ok) {
205
210
  dependencies.emit({
@@ -343,6 +348,7 @@ export async function createPaseoWorktreeWorkflow(dependencies, input, options)
343
348
  startAfterAgentCreate: ({ agentId }) => {
344
349
  void runAsyncWorktreeBootstrap({
345
350
  agentId,
351
+ workspaceId: workspace.workspaceId,
346
352
  worktree: createdWorktree.worktree,
347
353
  shouldBootstrap: createdWorktree.created,
348
354
  terminalManager: setupContinuation.terminalManager,
@@ -454,7 +460,7 @@ export async function runWorktreeSetupInBackground(dependencies, options) {
454
460
  }
455
461
  }
456
462
  finally {
457
- await dependencies.emitWorkspaceUpdateForCwd(worktree.worktreePath);
463
+ await dependencies.emitWorkspaceUpdateForWorkspaceId(options.workspaceId);
458
464
  }
459
465
  }
460
466
  //# sourceMappingURL=worktree-session.js.map
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { findExecutable } from "../utils/executable.js";
2
+ import { findExecutable } from "../executable-resolution/executable-resolution.js";
3
3
  import { resolveGitHubRemote } from "../utils/github-remote.js";
4
4
  import { runGitCommand } from "../utils/run-git-command.js";
5
5
  import { execCommand } from "../utils/spawn.js";
@@ -0,0 +1,20 @@
1
+ import type { TerminalActivityAttentionReason, TerminalActivityState } from "@getpaseo/protocol/terminal-activity";
2
+ export interface TerminalActivitySnapshot {
3
+ state: TerminalActivityState | null;
4
+ attentionReason: TerminalActivityAttentionReason | null;
5
+ changedAt: number;
6
+ }
7
+ export declare class TerminalActivityTracker {
8
+ private resolvedState;
9
+ private attentionReason;
10
+ private changedAt;
11
+ private readonly changeListeners;
12
+ set(state: TerminalActivityState): void;
13
+ clear(): void;
14
+ clearAttention(): boolean;
15
+ private setState;
16
+ onChange(listener: (snapshot: TerminalActivitySnapshot, previous: TerminalActivitySnapshot) => void): () => void;
17
+ getSnapshot(): TerminalActivitySnapshot;
18
+ dispose(): void;
19
+ }
20
+ //# sourceMappingURL=terminal-activity-tracker.d.ts.map