@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,5 @@
1
1
  import { existsSync } from "node:fs";
2
- export { quoteWindowsArgument, quoteWindowsCommand } from "./windows-command.js";
2
+ export { quoteWindowsArgument, quoteWindowsCommand } from "../utils/windows-command.js";
3
3
  export declare function probeExecutable(executablePath: string, timeoutMs?: number): Promise<boolean>;
4
4
  /**
5
5
  * Check a literal executable path. PATH search is handled by findExecutable().
@@ -7,4 +7,4 @@ export declare function probeExecutable(executablePath: string, timeoutMs?: numb
7
7
  export declare function executableExists(executablePath: string, exists?: typeof existsSync): string | null;
8
8
  export declare function findExecutable(name: string, probeTimeoutMs?: number): Promise<string | null>;
9
9
  export declare function isCommandAvailable(command: string): Promise<boolean>;
10
- //# sourceMappingURL=executable.d.ts.map
10
+ //# sourceMappingURL=executable-resolution.d.ts.map
@@ -1,9 +1,9 @@
1
1
  import { createRequire } from "node:module";
2
2
  import { existsSync } from "node:fs";
3
- import { extname } from "node:path";
4
- import { execCommand } from "./spawn.js";
5
- import { isWindowsCommandScript } from "./windows-command.js";
6
- export { quoteWindowsArgument, quoteWindowsCommand } from "./windows-command.js";
3
+ import { execCommand } from "../utils/spawn.js";
4
+ import { isWindowsCommandScript } from "../utils/windows-command.js";
5
+ import { windowsExecutableResolution } from "./windows.js";
6
+ export { quoteWindowsArgument, quoteWindowsCommand } from "../utils/windows-command.js";
7
7
  const require = createRequire(import.meta.url);
8
8
  const which = require("which");
9
9
  const PROBE_TIMEOUT_MS = 2000;
@@ -83,22 +83,24 @@ function classifyProbeError(error) {
83
83
  * Check a literal executable path. PATH search is handled by findExecutable().
84
84
  */
85
85
  export function executableExists(executablePath, exists = existsSync) {
86
- if (exists(executablePath))
87
- return executablePath;
88
- if (process.platform === "win32" && !extname(executablePath)) {
89
- for (const ext of [".exe", ".cmd"]) {
90
- const candidate = executablePath + ext;
91
- if (exists(candidate))
92
- return candidate;
93
- }
86
+ if (process.platform === "win32") {
87
+ return windowsExecutableResolution.exists(executablePath, { exists });
94
88
  }
95
- return null;
89
+ return exists(executablePath) ? executablePath : null;
96
90
  }
97
91
  export async function findExecutable(name, probeTimeoutMs = PROBE_TIMEOUT_MS) {
98
92
  const trimmed = name.trim();
99
93
  if (!trimmed) {
100
94
  return null;
101
95
  }
96
+ if (process.platform === "win32") {
97
+ return windowsExecutableResolution.find(trimmed, {
98
+ enumeratePathCandidates: enumerateCandidates,
99
+ probeExecutable,
100
+ exists: existsSync,
101
+ probeTimeoutMs,
102
+ });
103
+ }
102
104
  if (hasPathSeparator(trimmed)) {
103
105
  return (await probeExecutable(trimmed, probeTimeoutMs)) ? trimmed : null;
104
106
  }
@@ -113,4 +115,4 @@ export async function findExecutable(name, probeTimeoutMs = PROBE_TIMEOUT_MS) {
113
115
  export async function isCommandAvailable(command) {
114
116
  return (await findExecutable(command)) !== null;
115
117
  }
116
- //# sourceMappingURL=executable.js.map
118
+ //# sourceMappingURL=executable-resolution.js.map
@@ -0,0 +1,18 @@
1
+ interface WindowsFindExecutableOptions {
2
+ enumeratePathCandidates: (name: string) => Promise<string[]>;
3
+ probeExecutable: (executablePath: string, timeoutMs: number) => Promise<boolean>;
4
+ exists: (path: string) => boolean;
5
+ localAppData?: string;
6
+ probeTimeoutMs: number;
7
+ }
8
+ interface WindowsExecutableExistsOptions {
9
+ exists: (path: string) => boolean;
10
+ }
11
+ declare function find(input: string, options: WindowsFindExecutableOptions): Promise<string | null>;
12
+ declare function exists(executablePath: string, options: WindowsExecutableExistsOptions): string | null;
13
+ export declare const windowsExecutableResolution: {
14
+ exists: typeof exists;
15
+ find: typeof find;
16
+ };
17
+ export {};
18
+ //# sourceMappingURL=windows.d.ts.map
@@ -0,0 +1,62 @@
1
+ import { readdirSync } from "node:fs";
2
+ import { extname, join } from "node:path";
3
+ function hasPathSeparator(value) {
4
+ return value.includes("/") || value.includes("\\");
5
+ }
6
+ function enumerateLiteralPathCandidates(executablePath) {
7
+ if (extname(executablePath)) {
8
+ return [executablePath];
9
+ }
10
+ return [executablePath, `${executablePath}.exe`, `${executablePath}.cmd`];
11
+ }
12
+ function enumerateWingetPackageCandidates(name, localAppData) {
13
+ if (!localAppData) {
14
+ return [];
15
+ }
16
+ const wingetPackages = join(localAppData, "Microsoft", "WinGet", "Packages");
17
+ let packageDirs;
18
+ try {
19
+ packageDirs = readdirSync(wingetPackages, { withFileTypes: true })
20
+ .filter((entry) => entry.isDirectory())
21
+ .map((entry) => entry.name);
22
+ }
23
+ catch {
24
+ return [];
25
+ }
26
+ const exeName = `${name}.exe`;
27
+ return packageDirs.map((packageDir) => join(wingetPackages, packageDir, exeName));
28
+ }
29
+ async function find(input, options) {
30
+ if (hasPathSeparator(input)) {
31
+ return findFirstProbeable(enumerateLiteralPathCandidates(input), options);
32
+ }
33
+ const pathCandidates = await options.enumeratePathCandidates(input);
34
+ const wingetCandidates = enumerateWingetPackageCandidates(input, options.localAppData ?? process.env.LOCALAPPDATA).filter(options.exists);
35
+ return findFirstProbeable([...pathCandidates, ...wingetCandidates], options);
36
+ }
37
+ async function findFirstProbeable(candidates, options) {
38
+ const seen = new Set();
39
+ for (const candidate of candidates) {
40
+ if (seen.has(candidate)) {
41
+ continue;
42
+ }
43
+ seen.add(candidate);
44
+ if (await options.probeExecutable(candidate, options.probeTimeoutMs)) {
45
+ return candidate;
46
+ }
47
+ }
48
+ return null;
49
+ }
50
+ function exists(executablePath, options) {
51
+ for (const candidate of enumerateLiteralPathCandidates(executablePath)) {
52
+ if (options.exists(candidate)) {
53
+ return candidate;
54
+ }
55
+ }
56
+ return null;
57
+ }
58
+ export const windowsExecutableResolution = {
59
+ exists,
60
+ find,
61
+ };
62
+ //# sourceMappingURL=windows.js.map
@@ -31,7 +31,10 @@ export async function ensureAgentLoaded(agentId, deps) {
31
31
  if (!config) {
32
32
  throw new Error(`Agent ${agentId} references unavailable provider '${record.provider}'`);
33
33
  }
34
- snapshot = await deps.agentManager.createAgent(config, agentId, { labels: record.labels });
34
+ snapshot = await deps.agentManager.createAgent(config, agentId, {
35
+ labels: record.labels,
36
+ workspaceId: record.workspaceId,
37
+ });
35
38
  deps.logger.info({ agentId, provider: record.provider }, "Agent created from stored config");
36
39
  }
37
40
  await deps.agentManager.hydrateTimelineFromProvider(agentId);
@@ -100,6 +100,12 @@ interface ManagedAgentBase {
100
100
  id: string;
101
101
  provider: AgentProvider;
102
102
  cwd: string;
103
+ /**
104
+ * Workspace this agent belongs to, stamped at creation. Independent of cwd:
105
+ * cwd answers "where does it run", workspaceId answers "which workspace owns it".
106
+ * Null/undefined for legacy agents created before ownership stamping.
107
+ */
108
+ workspaceId?: string;
103
109
  capabilities: AgentCapabilityFlags;
104
110
  config: AgentSessionConfig;
105
111
  runtimeInfo?: AgentRuntimeInfo;
@@ -217,6 +223,7 @@ export declare class AgentManager {
217
223
  listImportableSessions(options?: ImportablePersistedAgentQueryOptions): Promise<ManagedImportableProviderSession[]>;
218
224
  private isProviderImportable;
219
225
  listProviderAvailability(): Promise<ProviderAvailability[]>;
226
+ getProviderAvailability(provider: AgentProvider): Promise<ProviderAvailability>;
220
227
  listDraftCommands(config: AgentSessionConfig): Promise<AgentSlashCommand[]>;
221
228
  listDraftFeatures(config: AgentSessionConfig): Promise<AgentFeature[]>;
222
229
  getAgent(id: string): ManagedAgent | null;
@@ -225,11 +232,11 @@ export declare class AgentManager {
225
232
  fetchTimeline(id: string, options?: AgentTimelineFetchOptions): AgentTimelineFetchResult;
226
233
  createAgent(config: AgentSessionConfig, agentId?: string, options?: {
227
234
  labels?: Record<string, string>;
228
- workspaceId?: string;
229
235
  initialPrompt?: string;
230
236
  env?: Record<string, string>;
231
237
  persistSession?: boolean;
232
238
  initialTitle?: string | null;
239
+ workspaceId?: string;
233
240
  }): Promise<ManagedAgent>;
234
241
  private buildCreateSessionOptions;
235
242
  resumeAgentFromPersistence(handle: AgentPersistenceHandle, overrides?: Partial<AgentSessionConfig>, agentId?: string, options?: {
@@ -237,11 +244,13 @@ export declare class AgentManager {
237
244
  updatedAt?: Date;
238
245
  lastUserMessageAt?: Date | null;
239
246
  labels?: Record<string, string>;
247
+ workspaceId?: string;
240
248
  }): Promise<ManagedAgent>;
241
249
  importProviderSession(input: {
242
250
  provider: AgentProvider;
243
251
  providerHandleId: string;
244
252
  cwd: string;
253
+ workspaceId: string;
245
254
  labels?: Record<string, string>;
246
255
  }): Promise<ManagedAgent>;
247
256
  reloadAgentSession(agentId: string, overrides?: Partial<AgentSessionConfig>, options?: {
@@ -262,7 +271,6 @@ export declare class AgentManager {
262
271
  setAgentThinkingOption(agentId: string, thinkingOptionId: string | null): Promise<void>;
263
272
  setAgentFeature(agentId: string, featureId: string, value: unknown): Promise<void>;
264
273
  setTitle(agentId: string, title: string): Promise<void>;
265
- setGeneratedTitle(agentId: string, title: string): Promise<void>;
266
274
  setLabels(agentId: string, labels: Record<string, string>): Promise<void>;
267
275
  notifyAgentState(agentId: string): void;
268
276
  clearAgentAttention(agentId: string): Promise<void>;
@@ -361,34 +361,34 @@ export class AgentManager {
361
361
  return true;
362
362
  }
363
363
  async listProviderAvailability() {
364
- const checks = Array.from(this.clients.keys()).map(async (provider) => {
365
- const client = this.clients.get(provider);
366
- if (!client) {
367
- return {
368
- provider,
369
- available: false,
370
- error: `No client registered for provider '${provider}'`,
371
- };
372
- }
373
- try {
374
- const available = await client.isAvailable();
375
- return {
376
- provider,
377
- available,
378
- error: null,
379
- };
380
- }
381
- catch (error) {
382
- const message = error instanceof Error ? error.message : String(error);
383
- this.logger.warn({ err: error, provider }, "Failed to check provider availability");
384
- return {
385
- provider,
386
- available: false,
387
- error: message,
388
- };
389
- }
390
- });
391
- return Promise.all(checks);
364
+ return Promise.all(Array.from(this.clients.keys()).map((provider) => this.getProviderAvailability(provider)));
365
+ }
366
+ async getProviderAvailability(provider) {
367
+ const client = this.clients.get(provider);
368
+ if (!client) {
369
+ return {
370
+ provider,
371
+ available: false,
372
+ error: `No client registered for provider '${provider}'`,
373
+ };
374
+ }
375
+ try {
376
+ const available = await client.isAvailable();
377
+ return {
378
+ provider,
379
+ available,
380
+ error: null,
381
+ };
382
+ }
383
+ catch (error) {
384
+ const message = error instanceof Error ? error.message : String(error);
385
+ this.logger.warn({ err: error, provider }, "Failed to check provider availability");
386
+ return {
387
+ provider,
388
+ available: false,
389
+ error: message,
390
+ };
391
+ }
392
392
  }
393
393
  async listDraftCommands(config) {
394
394
  const normalizedConfig = await this.normalizeConfig(config);
@@ -470,8 +470,8 @@ export class AgentManager {
470
470
  const session = await client.createSession(launchConfig, launchContext, createOptions);
471
471
  return this.registerSession(session, storedConfig, resolvedAgentId, {
472
472
  labels: options?.labels,
473
- workspaceId: options?.workspaceId,
474
473
  initialTitle: options?.initialTitle,
474
+ workspaceId: options?.workspaceId,
475
475
  });
476
476
  }
477
477
  buildCreateSessionOptions(options) {
@@ -520,6 +520,7 @@ export class AgentManager {
520
520
  const initialTitle = resolveImportedAgentTitle(importedConfig, timelineRows);
521
521
  return this.registerSession(imported.session, importedConfig, resolvedAgentId, {
522
522
  labels: input.labels,
523
+ workspaceId: input.workspaceId,
523
524
  timelineRows,
524
525
  timelineNextSeq: timelineRows.length + 1,
525
526
  persistence: imported.persistence,
@@ -577,6 +578,7 @@ export class AgentManager {
577
578
  // Preserve existing labels and timeline during reload.
578
579
  return this.registerSession(session, storedConfig, agentId, {
579
580
  labels: existing.labels,
581
+ workspaceId: existing.workspaceId,
580
582
  createdAt: existing.createdAt,
581
583
  updatedAt: existing.updatedAt,
582
584
  lastUserMessageAt: existing.lastUserMessageAt,
@@ -734,6 +736,7 @@ export class AgentManager {
734
736
  id: record.id,
735
737
  provider: record.provider,
736
738
  cwd: record.cwd,
739
+ workspaceId: record.workspaceId,
737
740
  session: null,
738
741
  capabilities: STORED_AGENT_CAPABILITIES,
739
742
  config: buildStoredAgentConfig(record),
@@ -832,17 +835,6 @@ export class AgentManager {
832
835
  await this.persistSnapshot(agent, { title: normalizedTitle });
833
836
  this.emitState(agent, { persist: false });
834
837
  }
835
- async setGeneratedTitle(agentId, title) {
836
- const agent = this.requireAgent(agentId);
837
- const normalizedTitle = title.trim();
838
- if (!normalizedTitle) {
839
- return;
840
- }
841
- const registry = this.requireRegistry();
842
- const persisted = await registry.setGeneratedTitle(agent.id, normalizedTitle);
843
- agent.updatedAt = new Date(persisted.updatedAt);
844
- this.emitState(agent, { persist: false });
845
- }
846
838
  async setLabels(agentId, labels) {
847
839
  const agent = this.requireAgent(agentId);
848
840
  agent.labels = { ...agent.labels, ...labels };
@@ -1677,7 +1669,6 @@ export class AgentManager {
1677
1669
  this.previousStatuses.set(resolvedAgentId, managed.lifecycle);
1678
1670
  await this.refreshRuntimeInfo(managed, { emit: !options?.publishWhenReady });
1679
1671
  await this.persistSnapshot(managed, {
1680
- workspaceId: options?.workspaceId,
1681
1672
  title: initialPersistedTitle,
1682
1673
  });
1683
1674
  if (!options?.publishWhenReady) {
@@ -1685,7 +1676,7 @@ export class AgentManager {
1685
1676
  }
1686
1677
  await this.refreshSessionState(managed, { emit: !options?.publishWhenReady });
1687
1678
  managed.lifecycle = "idle";
1688
- await this.persistSnapshot(managed, { workspaceId: options?.workspaceId });
1679
+ await this.persistSnapshot(managed);
1689
1680
  this.emitState(managed, { persist: false });
1690
1681
  this.subscribeToSession(managed);
1691
1682
  return { ...managed };
@@ -1715,6 +1706,7 @@ export class AgentManager {
1715
1706
  id: resolvedAgentId,
1716
1707
  provider: config.provider,
1717
1708
  cwd: config.cwd,
1709
+ workspaceId: options?.workspaceId,
1718
1710
  session,
1719
1711
  capabilities: session.capabilities,
1720
1712
  config,
@@ -1872,10 +1864,6 @@ export class AgentManager {
1872
1864
  if (agent.internal) {
1873
1865
  return;
1874
1866
  }
1875
- if (options?.workspaceId !== undefined) {
1876
- await this.registry.applySnapshot(agent, options.workspaceId, options);
1877
- return;
1878
- }
1879
1867
  await this.registry.applySnapshot(agent, options);
1880
1868
  }
1881
1869
  requireRegistry() {
@@ -27,6 +27,7 @@ export function toStoredAgentRecord(agent, options) {
27
27
  id: agent.id,
28
28
  provider: agent.provider,
29
29
  cwd: agent.cwd,
30
+ workspaceId: agent.workspaceId,
30
31
  createdAt,
31
32
  updatedAt: agent.updatedAt.toISOString(),
32
33
  lastActivityAt: agent.updatedAt.toISOString(),
@@ -59,6 +60,7 @@ export function toAgentPayload(agent, options) {
59
60
  id: agent.id,
60
61
  provider: agent.provider,
61
62
  cwd: agent.cwd,
63
+ ...(agent.workspaceId ? { workspaceId: agent.workspaceId } : {}),
62
64
  model: agent.config.model ?? null,
63
65
  thinkingOptionId,
64
66
  effectiveThinkingOptionId,
@@ -145,6 +147,7 @@ export function buildStoredAgentPayload(record, validProviders) {
145
147
  id: record.id,
146
148
  provider: record.provider,
147
149
  cwd: record.cwd,
150
+ ...(record.workspaceId ? { workspaceId: record.workspaceId } : {}),
148
151
  model: record.config?.model ?? null,
149
152
  thinkingOptionId: record.config?.thinkingOptionId ?? null,
150
153
  effectiveThinkingOptionId: resolveEffectiveThinkingOptionId({
@@ -148,6 +148,14 @@ export async function startCreatedAgentInitialPrompt(params) {
148
148
  }
149
149
  return refreshedSnapshot;
150
150
  }
151
+ function formatFinishNotificationBody(params) {
152
+ const statusLine = `Agent ${params.childAgentId} (${params.title}) ${params.reason}.`;
153
+ const lastAssistantMessage = params.lastAssistantMessage?.trim();
154
+ if (!lastAssistantMessage) {
155
+ return statusLine;
156
+ }
157
+ return `${statusLine}\n\n<agent-response>\n${lastAssistantMessage}\n</agent-response>`;
158
+ }
151
159
  export function setupFinishNotification(params) {
152
160
  const { agentManager, agentStorage, childAgentId, callerAgentId, logger } = params;
153
161
  let hasSeenRunning = false;
@@ -159,9 +167,19 @@ export function setupFinishNotification(params) {
159
167
  }
160
168
  fired = true;
161
169
  unsubscribe?.();
170
+ const callerRecord = await agentStorage.get(callerAgentId);
171
+ if (callerRecord?.archivedAt) {
172
+ return;
173
+ }
162
174
  const record = await agentStorage.get(childAgentId);
163
175
  const title = record?.title ?? childAgentId;
164
- const body = `Agent ${childAgentId} (${title}) ${reason}.`;
176
+ const lastAssistantMessage = await agentManager.getLastAssistantMessage(childAgentId);
177
+ const body = formatFinishNotificationBody({
178
+ childAgentId,
179
+ title,
180
+ reason,
181
+ lastAssistantMessage,
182
+ });
165
183
  await sendPromptToAgent({
166
184
  agentManager,
167
185
  agentStorage,
@@ -265,12 +265,10 @@ export async function generateStructuredAgentResponseWithFallback(options) {
265
265
  }
266
266
  const runStructured = runner ??
267
267
  ((input) => generateStructuredAgentResponse(input));
268
- const availability = await manager.listProviderAvailability();
269
- const availabilityByProvider = new Map(availability.map((entry) => [entry.provider, entry]));
270
268
  const attempts = [];
271
269
  for (const candidate of providers) {
272
- const availabilityEntry = availabilityByProvider.get(candidate.provider);
273
- if (availabilityEntry && !availabilityEntry.available) {
270
+ const availabilityEntry = await manager.getProviderAvailability(candidate.provider);
271
+ if (!availabilityEntry.available) {
274
272
  const reason = availabilityEntry.error ?? "unavailable";
275
273
  attempts.push({
276
274
  provider: candidate.provider,
@@ -6,6 +6,7 @@ declare const STORED_AGENT_SCHEMA: z.ZodObject<{
6
6
  id: z.ZodString;
7
7
  provider: z.ZodString;
8
8
  cwd: z.ZodString;
9
+ workspaceId: z.ZodOptional<z.ZodString>;
9
10
  createdAt: z.ZodString;
10
11
  updatedAt: z.ZodString;
11
12
  lastActivityAt: z.ZodOptional<z.ZodString>;
@@ -70,16 +71,16 @@ declare const STORED_AGENT_SCHEMA: z.ZodObject<{
70
71
  icon: z.ZodOptional<z.ZodString>;
71
72
  value: z.ZodBoolean;
72
73
  }, "strip", z.ZodTypeAny, {
73
- type: "toggle";
74
74
  value: boolean;
75
+ type: "toggle";
75
76
  id: string;
76
77
  label: string;
77
78
  description?: string | undefined;
78
79
  icon?: string | undefined;
79
80
  tooltip?: string | undefined;
80
81
  }, {
81
- type: "toggle";
82
82
  value: boolean;
83
+ type: "toggle";
83
84
  id: string;
84
85
  label: string;
85
86
  description?: string | undefined;
@@ -113,7 +114,6 @@ declare const STORED_AGENT_SCHEMA: z.ZodObject<{
113
114
  isDefault?: boolean | undefined;
114
115
  }>, "many">;
115
116
  }, "strip", z.ZodTypeAny, {
116
- type: "select";
117
117
  value: string | null;
118
118
  options: {
119
119
  id: string;
@@ -122,13 +122,13 @@ declare const STORED_AGENT_SCHEMA: z.ZodObject<{
122
122
  metadata?: Record<string, unknown> | undefined;
123
123
  isDefault?: boolean | undefined;
124
124
  }[];
125
+ type: "select";
125
126
  id: string;
126
127
  label: string;
127
128
  description?: string | undefined;
128
129
  icon?: string | undefined;
129
130
  tooltip?: string | undefined;
130
131
  }, {
131
- type: "select";
132
132
  value: string | null;
133
133
  options: {
134
134
  id: string;
@@ -137,6 +137,7 @@ declare const STORED_AGENT_SCHEMA: z.ZodObject<{
137
137
  metadata?: Record<string, unknown> | undefined;
138
138
  isDefault?: boolean | undefined;
139
139
  }[];
140
+ type: "select";
140
141
  id: string;
141
142
  label: string;
142
143
  description?: string | undefined;
@@ -172,7 +173,10 @@ declare const STORED_AGENT_SCHEMA: z.ZodObject<{
172
173
  createdAt: string;
173
174
  updatedAt: string;
174
175
  labels: Record<string, string>;
175
- lastStatus: "error" | "running" | "initializing" | "idle" | "closed";
176
+ lastStatus: "error" | "idle" | "running" | "initializing" | "closed";
177
+ workspaceId?: string | undefined;
178
+ internal?: boolean | undefined;
179
+ attentionReason?: "finished" | "error" | "permission" | null | undefined;
176
180
  title?: string | null | undefined;
177
181
  persistence?: {
178
182
  provider: string;
@@ -201,15 +205,14 @@ declare const STORED_AGENT_SCHEMA: z.ZodObject<{
201
205
  extra?: Record<string, unknown> | undefined;
202
206
  } | undefined;
203
207
  features?: ({
204
- type: "toggle";
205
208
  value: boolean;
209
+ type: "toggle";
206
210
  id: string;
207
211
  label: string;
208
212
  description?: string | undefined;
209
213
  icon?: string | undefined;
210
214
  tooltip?: string | undefined;
211
215
  } | {
212
- type: "select";
213
216
  value: string | null;
214
217
  options: {
215
218
  id: string;
@@ -218,6 +221,7 @@ declare const STORED_AGENT_SCHEMA: z.ZodObject<{
218
221
  metadata?: Record<string, unknown> | undefined;
219
222
  isDefault?: boolean | undefined;
220
223
  }[];
224
+ type: "select";
221
225
  id: string;
222
226
  label: string;
223
227
  description?: string | undefined;
@@ -226,9 +230,7 @@ declare const STORED_AGENT_SCHEMA: z.ZodObject<{
226
230
  })[] | undefined;
227
231
  lastError?: string | null | undefined;
228
232
  requiresAttention?: boolean | undefined;
229
- attentionReason?: "finished" | "error" | "permission" | null | undefined;
230
233
  attentionTimestamp?: string | null | undefined;
231
- internal?: boolean | undefined;
232
234
  archivedAt?: string | null | undefined;
233
235
  }, {
234
236
  cwd: string;
@@ -236,6 +238,9 @@ declare const STORED_AGENT_SCHEMA: z.ZodObject<{
236
238
  provider: string;
237
239
  createdAt: string;
238
240
  updatedAt: string;
241
+ workspaceId?: string | undefined;
242
+ internal?: boolean | undefined;
243
+ attentionReason?: "finished" | "error" | "permission" | null | undefined;
239
244
  title?: string | null | undefined;
240
245
  persistence?: {
241
246
  provider: string;
@@ -246,7 +251,7 @@ declare const STORED_AGENT_SCHEMA: z.ZodObject<{
246
251
  lastActivityAt?: string | undefined;
247
252
  lastUserMessageAt?: string | null | undefined;
248
253
  labels?: Record<string, string> | undefined;
249
- lastStatus?: "error" | "running" | "initializing" | "idle" | "closed" | undefined;
254
+ lastStatus?: "error" | "idle" | "running" | "initializing" | "closed" | undefined;
250
255
  lastModeId?: string | null | undefined;
251
256
  config?: {
252
257
  modeId?: string | null | undefined;
@@ -266,15 +271,14 @@ declare const STORED_AGENT_SCHEMA: z.ZodObject<{
266
271
  extra?: Record<string, unknown> | undefined;
267
272
  } | undefined;
268
273
  features?: ({
269
- type: "toggle";
270
274
  value: boolean;
275
+ type: "toggle";
271
276
  id: string;
272
277
  label: string;
273
278
  description?: string | undefined;
274
279
  icon?: string | undefined;
275
280
  tooltip?: string | undefined;
276
281
  } | {
277
- type: "select";
278
282
  value: string | null;
279
283
  options: {
280
284
  id: string;
@@ -283,6 +287,7 @@ declare const STORED_AGENT_SCHEMA: z.ZodObject<{
283
287
  metadata?: Record<string, unknown> | undefined;
284
288
  isDefault?: boolean | undefined;
285
289
  }[];
290
+ type: "select";
286
291
  id: string;
287
292
  label: string;
288
293
  description?: string | undefined;
@@ -291,9 +296,7 @@ declare const STORED_AGENT_SCHEMA: z.ZodObject<{
291
296
  })[] | undefined;
292
297
  lastError?: string | null | undefined;
293
298
  requiresAttention?: boolean | undefined;
294
- attentionReason?: "finished" | "error" | "permission" | null | undefined;
295
299
  attentionTimestamp?: string | null | undefined;
296
- internal?: boolean | undefined;
297
300
  archivedAt?: string | null | undefined;
298
301
  }>;
299
302
  export type SerializableAgentConfig = Pick<AgentSessionConfig, "modeId" | "model" | "thinkingOptionId" | "featureValues" | "extra" | "systemPrompt" | "mcpServers">;
@@ -318,15 +321,11 @@ export declare class AgentStorage {
318
321
  private writeRecord;
319
322
  beginDelete(agentId: string): void;
320
323
  remove(agentId: string): Promise<void>;
321
- applySnapshot(agent: ManagedAgent, workspaceIdOrOptions?: string | {
322
- title?: string | null;
323
- internal?: boolean;
324
- }, options?: {
324
+ applySnapshot(agent: ManagedAgent, options?: {
325
325
  title?: string | null;
326
326
  internal?: boolean;
327
327
  }): Promise<void>;
328
328
  setTitle(agentId: string, title: string): Promise<void>;
329
- setGeneratedTitle(agentId: string, title: string): Promise<StoredAgentRecord>;
330
329
  flush(): Promise<void>;
331
330
  private load;
332
331
  private doLoad;
@@ -29,6 +29,7 @@ const STORED_AGENT_SCHEMA = z.object({
29
29
  id: z.string(),
30
30
  provider: z.string(),
31
31
  cwd: z.string(),
32
+ workspaceId: z.string().optional(),
32
33
  createdAt: z.string(),
33
34
  updatedAt: z.string(),
34
35
  lastActivityAt: z.string().optional(),
@@ -146,19 +147,16 @@ export class AgentStorage {
146
147
  this.pathById.delete(agentId);
147
148
  this.pathsById.delete(agentId);
148
149
  }
149
- async applySnapshot(agent, workspaceIdOrOptions, options) {
150
- const nextOptions = typeof workspaceIdOrOptions === "string" ? options : workspaceIdOrOptions;
150
+ async applySnapshot(agent, options) {
151
151
  await this.load();
152
152
  await this.waitForPendingWrite(agent.id);
153
153
  const existing = (await this.get(agent.id)) ?? null;
154
- const hasTitleOverride = nextOptions !== undefined && Object.prototype.hasOwnProperty.call(nextOptions, "title");
155
- const hasInternalOverride = nextOptions !== undefined && Object.prototype.hasOwnProperty.call(nextOptions, "internal");
154
+ const hasTitleOverride = options !== undefined && Object.prototype.hasOwnProperty.call(options, "title");
155
+ const hasInternalOverride = options !== undefined && Object.prototype.hasOwnProperty.call(options, "internal");
156
156
  const record = toStoredAgentRecord(agent, {
157
- title: hasTitleOverride ? (nextOptions?.title ?? null) : (existing?.title ?? null),
157
+ title: hasTitleOverride ? (options?.title ?? null) : (existing?.title ?? null),
158
158
  createdAt: existing?.createdAt,
159
- internal: hasInternalOverride
160
- ? nextOptions?.internal
161
- : (agent.internal ?? existing?.internal),
159
+ internal: hasInternalOverride ? options?.internal : (agent.internal ?? existing?.internal),
162
160
  });
163
161
  // Preserve soft-delete/archive status across snapshot flushes.
164
162
  // `archivedAt` is not part of the ManagedAgent snapshot, so a naive projection
@@ -177,21 +175,6 @@ export class AgentStorage {
177
175
  }
178
176
  await this.upsert({ ...record, title });
179
177
  }
180
- async setGeneratedTitle(agentId, title) {
181
- await this.load();
182
- await this.waitForPendingWrite(agentId);
183
- const record = this.cache.get(agentId) ?? null;
184
- if (!record) {
185
- throw new Error(`Agent ${agentId} not found`);
186
- }
187
- const nextRecord = {
188
- ...record,
189
- title,
190
- updatedAt: new Date().toISOString(),
191
- };
192
- await this.queueRecordWrite(nextRecord);
193
- return nextRecord;
194
- }
195
178
  async flush() {
196
179
  await this.load().catch(() => undefined);
197
180
  const writes = Array.from(this.pendingWrites.values());