@getpaseo/server 0.1.100 → 0.1.102-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 (172) hide show
  1. package/dist/scripts/supervisor.js +26 -8
  2. package/dist/server/executable-resolution/windows.js +3 -0
  3. package/dist/server/server/agent/activity-curator.d.ts +17 -0
  4. package/dist/server/server/agent/activity-curator.js +101 -24
  5. package/dist/server/server/agent/agent-manager.d.ts +10 -0
  6. package/dist/server/server/agent/agent-manager.js +69 -27
  7. package/dist/server/server/agent/agent-sdk-types.d.ts +15 -2
  8. package/dist/server/server/agent/mcp-server.d.ts +2 -45
  9. package/dist/server/server/agent/mcp-server.js +45 -1985
  10. package/dist/server/server/agent/prompt-attachments.js +6 -2
  11. package/dist/server/server/agent/provider-snapshot-manager.d.ts +12 -1
  12. package/dist/server/server/agent/provider-snapshot-manager.js +132 -42
  13. package/dist/server/server/agent/providers/acp-agent.d.ts +27 -1
  14. package/dist/server/server/agent/providers/acp-agent.js +178 -27
  15. package/dist/server/server/agent/providers/claude/agent.js +111 -24
  16. package/dist/server/server/agent/providers/claude/query.d.ts +3 -0
  17. package/dist/server/server/agent/providers/claude/query.js +4 -2
  18. package/dist/server/server/agent/providers/codex-app-server-agent.js +6 -57
  19. package/dist/server/server/agent/providers/diagnostic-utils.d.ts +1 -0
  20. package/dist/server/server/agent/providers/diagnostic-utils.js +1 -1
  21. package/dist/server/server/agent/providers/generic-acp-agent.d.ts +3 -0
  22. package/dist/server/server/agent/providers/generic-acp-agent.js +41 -23
  23. package/dist/server/server/agent/providers/mock-load-test-agent.js +12 -2
  24. package/dist/server/server/agent/providers/opencode/paths.d.ts +2 -0
  25. package/dist/server/server/agent/providers/opencode/paths.js +7 -0
  26. package/dist/server/server/agent/providers/opencode/server-manager.d.ts +2 -0
  27. package/dist/server/server/agent/providers/opencode/server-manager.js +34 -5
  28. package/dist/server/server/agent/providers/opencode-agent.d.ts +4 -0
  29. package/dist/server/server/agent/providers/opencode-agent.js +14 -2
  30. package/dist/server/server/agent/providers/pi/agent.d.ts +5 -1
  31. package/dist/server/server/agent/providers/pi/agent.js +12 -3
  32. package/dist/server/server/agent/providers/provider-image-output.d.ts +5 -0
  33. package/dist/server/server/agent/providers/provider-image-output.js +61 -1
  34. package/dist/server/server/agent/tools/paseo-tools.d.ts +48 -0
  35. package/dist/server/server/agent/tools/paseo-tools.js +2119 -0
  36. package/dist/server/server/agent/tools/types.d.ts +36 -0
  37. package/dist/server/server/agent/tools/types.js +2 -0
  38. package/dist/server/server/bootstrap.d.ts +7 -1
  39. package/dist/server/server/bootstrap.js +89 -62
  40. package/dist/server/server/config.d.ts +2 -0
  41. package/dist/server/server/config.js +57 -1
  42. package/dist/server/server/daemon-worker.js +19 -7
  43. package/dist/server/server/lifecycle-reasons.d.ts +4 -0
  44. package/dist/server/server/lifecycle-reasons.js +6 -0
  45. package/dist/server/server/persisted-config.d.ts +12 -0
  46. package/dist/server/server/persisted-config.js +18 -2
  47. package/dist/server/server/process-diagnostics.d.ts +17 -0
  48. package/dist/server/server/process-diagnostics.js +22 -0
  49. package/dist/server/server/relay-transport.js +1 -0
  50. package/dist/server/server/resolve-worktree-creation-intent.js +3 -1
  51. package/dist/server/server/session/agent-updates/agent-updates-service.d.ts +59 -0
  52. package/dist/server/server/session/agent-updates/agent-updates-service.js +220 -0
  53. package/dist/server/server/session/checkout/checkout-session.d.ts +13 -15
  54. package/dist/server/server/session/checkout/checkout-session.js +18 -16
  55. package/dist/server/server/session/checkout/git-metadata-generator.d.ts +53 -0
  56. package/dist/server/server/session/checkout/git-metadata-generator.js +159 -0
  57. package/dist/server/server/session/daemon/daemon-self-update-session-controller.d.ts +32 -0
  58. package/dist/server/server/session/daemon/daemon-self-update-session-controller.js +88 -0
  59. package/dist/server/server/session/daemon/daemon-self-updater.d.ts +32 -0
  60. package/dist/server/server/session/daemon/daemon-self-updater.js +56 -0
  61. package/dist/server/server/session/daemon/daemon-session.d.ts +26 -0
  62. package/dist/server/server/session/daemon/daemon-session.js +50 -0
  63. package/dist/server/server/session/daemon/diagnostics.d.ts +41 -0
  64. package/dist/server/server/session/daemon/diagnostics.js +431 -0
  65. package/dist/server/server/session/daemon/install-origin.d.ts +7 -0
  66. package/dist/server/server/session/daemon/install-origin.js +64 -0
  67. package/dist/server/server/session/daemon/npm-global-cli.d.ts +29 -0
  68. package/dist/server/server/session/daemon/npm-global-cli.js +98 -0
  69. package/dist/server/server/session/git-mutation/git-mutation-service.d.ts +34 -0
  70. package/dist/server/server/session/git-mutation/git-mutation-service.js +71 -0
  71. package/dist/server/server/session/provider/provider-catalog-session.js +8 -4
  72. package/dist/server/server/session/workspace-git-observer/workspace-git-observer-service.d.ts +36 -0
  73. package/dist/server/server/session/workspace-git-observer/workspace-git-observer-service.js +134 -0
  74. package/dist/server/server/session/workspace-provisioning/workspace-provisioning-service.d.ts +34 -0
  75. package/dist/server/server/session/workspace-provisioning/workspace-provisioning-service.js +190 -0
  76. package/dist/server/server/session/workspace-scripts/workspace-scripts-service.d.ts +41 -0
  77. package/dist/server/server/session/workspace-scripts/workspace-scripts-service.js +100 -0
  78. package/dist/server/server/session.d.ts +12 -54
  79. package/dist/server/server/session.js +187 -970
  80. package/dist/server/server/speech/providers/openai/config.d.ts +1 -2
  81. package/dist/server/server/speech/providers/openai/config.js +13 -9
  82. package/dist/server/server/speech/providers/openai/runtime.js +2 -16
  83. package/dist/server/server/speech/providers/openai/stt.d.ts +1 -0
  84. package/dist/server/server/speech/providers/openai/stt.js +4 -2
  85. package/dist/server/server/speech/providers/openai/tts.d.ts +1 -0
  86. package/dist/server/server/speech/providers/openai/tts.js +1 -0
  87. package/dist/server/server/web-ui.d.ts +10 -0
  88. package/dist/server/server/web-ui.js +205 -0
  89. package/dist/server/server/websocket/runtime-metrics.d.ts +23 -0
  90. package/dist/server/server/websocket-server.d.ts +4 -2
  91. package/dist/server/server/websocket-server.js +215 -52
  92. package/dist/server/server/worktree-bootstrap.d.ts +1 -1
  93. package/dist/server/server/worktree-branch-name-generator.js +3 -1
  94. package/dist/server/services/quota-fetcher/manifest.js +5 -0
  95. package/dist/server/services/quota-fetcher/providers/minimax.d.ts +29 -0
  96. package/dist/server/services/quota-fetcher/providers/minimax.js +227 -0
  97. package/dist/server/terminal/agent-hooks/agent-hook-installer.js +2 -2
  98. package/dist/server/utils/checkout-git.js +203 -25
  99. package/dist/server/utils/directory-suggestions.js +1 -4
  100. package/dist/server/utils/path.d.ts +2 -0
  101. package/dist/server/utils/path.js +13 -0
  102. package/dist/server/utils/worktree.d.ts +1 -0
  103. package/dist/server/utils/worktree.js +92 -11
  104. package/dist/server/web-ui/_expo/static/css/xterm-3bb1704bf6cb0876640973dc0244b4cb.css +1 -0
  105. package/dist/server/web-ui/_expo/static/css/xterm-3bb1704bf6cb0876640973dc0244b4cb.css.br +0 -0
  106. package/dist/server/web-ui/_expo/static/css/xterm-3bb1704bf6cb0876640973dc0244b4cb.css.gz +0 -0
  107. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-b01555c9b42665a03988c0a0032ef528.js +1 -0
  108. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-b01555c9b42665a03988c0a0032ef528.js.br +0 -0
  109. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-b01555c9b42665a03988c0a0032ef528.js.gz +0 -0
  110. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-648388eca5c510b496e1eddf523f70ff.js +1 -0
  111. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-648388eca5c510b496e1eddf523f70ff.js.br +0 -0
  112. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-648388eca5c510b496e1eddf523f70ff.js.gz +0 -0
  113. package/dist/server/web-ui/_expo/static/js/web/index-0ebbea2cd337f0c0680fdb3f8d4d5af3.js +16157 -0
  114. package/dist/server/web-ui/_expo/static/js/web/index-0ebbea2cd337f0c0680fdb3f8d4d5af3.js.br +0 -0
  115. package/dist/server/web-ui/_expo/static/js/web/index-0ebbea2cd337f0c0680fdb3f8d4d5af3.js.gz +0 -0
  116. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-c64fa2416284927857a39087fd8d1332.js +1 -0
  117. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-c64fa2416284927857a39087fd8d1332.js.br +0 -0
  118. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-c64fa2416284927857a39087fd8d1332.js.gz +0 -0
  119. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-a9784226715772edf87ef36c596599c2.js +3 -0
  120. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-a9784226715772edf87ef36c596599c2.js.br +0 -0
  121. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-a9784226715772edf87ef36c596599c2.js.gz +0 -0
  122. package/dist/server/web-ui/apple-touch-icon.png +0 -0
  123. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/back-icon-mask.0a328cd9c1afd0afe8e3b1ec5165b1b4.png +0 -0
  124. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/back-icon.35ba0eaec5a4f5ed12ca16fabeae451d.png +0 -0
  125. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55.png +0 -0
  126. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@2x.png +0 -0
  127. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@3x.png +0 -0
  128. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@4x.png +0 -0
  129. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7.png +0 -0
  130. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@2x.png +0 -0
  131. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@3x.png +0 -0
  132. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@4x.png +0 -0
  133. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/search-icon.286d67d3f74808a60a78d3ebf1a5fb57.png +0 -0
  134. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/arrow_down.017bc6ba3fc25503e5eb5e53826d48a8.png +0 -0
  135. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/error.d1ea1496f9057eb392d5bbf3732a61b7.png +0 -0
  136. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/file.19eeb73b9593a38f8e9f418337fc7d10.png +0 -0
  137. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/forward.d8b800c443b8972542883e0b9de2bdc6.png +0 -0
  138. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/pkg.ab19f4cbc543357183a20571f68380a3.png +0 -0
  139. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/sitemap.412dd9275b6b48ad28f5e3d81bb1f626.png +0 -0
  140. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/unmatched.20e71bdf79e3a97bf55fd9e164041578.png +0 -0
  141. package/dist/server/web-ui/assets/assets/images/editor-apps/antigravity.6e91a685c33435e0b466a56db86cf141.png +0 -0
  142. package/dist/server/web-ui/assets/assets/images/editor-apps/cursor.c31d6bce4fe9aadc3fe59962f4c4fcf3.png +0 -0
  143. package/dist/server/web-ui/assets/assets/images/editor-apps/file-explorer.3e15e8f72c825c85ce336bcb0cdef776.png +0 -0
  144. package/dist/server/web-ui/assets/assets/images/editor-apps/finder.7f68fc2c475621a672e1be09309d5567.png +0 -0
  145. package/dist/server/web-ui/assets/assets/images/editor-apps/vscode.832bdb4c685d930f1c864c793703600b.png +0 -0
  146. package/dist/server/web-ui/assets/assets/images/editor-apps/webstorm.aa5dc2cd8c20cc0a155c4c5c5ab3c5f5.png +0 -0
  147. package/dist/server/web-ui/assets/assets/images/editor-apps/zed.f3a670b7f9aa226da4fe53fb86f1abbd.png +0 -0
  148. package/dist/server/web-ui/assets/assets/images/favicon-dark-attention.882b3a27dcb2073e9e31b334f9ed9728.png +0 -0
  149. package/dist/server/web-ui/assets/assets/images/favicon-dark-running.8112342ff0d39e047a7f8d4fad9402f3.png +0 -0
  150. package/dist/server/web-ui/assets/assets/images/favicon-dark.8005ed36ac07a5a7c60de25780897bd4.png +0 -0
  151. package/dist/server/web-ui/assets/assets/images/favicon-light-attention.882b3a27dcb2073e9e31b334f9ed9728.png +0 -0
  152. package/dist/server/web-ui/assets/assets/images/favicon-light-running.8112342ff0d39e047a7f8d4fad9402f3.png +0 -0
  153. package/dist/server/web-ui/assets/assets/images/favicon-light.8005ed36ac07a5a7c60de25780897bd4.png +0 -0
  154. package/dist/server/web-ui/assets/assets/images/notification-icon.3bf81d33ddbf380606bdd248ba83e158.png +0 -0
  155. package/dist/server/web-ui/favicon.ico +0 -0
  156. package/dist/server/web-ui/index.html +90 -0
  157. package/dist/server/web-ui/index.html.br +0 -0
  158. package/dist/server/web-ui/index.html.gz +0 -0
  159. package/dist/server/web-ui/manifest.json +27 -0
  160. package/dist/server/web-ui/manifest.json.br +0 -0
  161. package/dist/server/web-ui/manifest.json.gz +0 -0
  162. package/dist/server/web-ui/metadata.json +1 -0
  163. package/dist/server/web-ui/metadata.json.br +1 -0
  164. package/dist/server/web-ui/metadata.json.gz +0 -0
  165. package/dist/server/web-ui/pwa-icon-192.png +0 -0
  166. package/dist/server/web-ui/pwa-icon-512.png +0 -0
  167. package/dist/server/web-ui/robots.txt +2 -0
  168. package/dist/src/executable-resolution/windows.js +3 -0
  169. package/dist/src/server/persisted-config.js +18 -2
  170. package/package.json +7 -7
  171. package/dist/server/server/speech/providers/openai/realtime-transcription-session.d.ts +0 -42
  172. package/dist/server/server/speech/providers/openai/realtime-transcription-session.js +0 -168
@@ -64,9 +64,10 @@ async function resolveGitHubPrCheckoutIntent(params) {
64
64
  const baseRefName = checkoutTarget?.baseRefName?.trim() ||
65
65
  (await resolveDefaultBranch(params.repoRoot, params.deps));
66
66
  const localBranchName = buildGitHubPrLocalBranchName({ headRef, checkoutTarget });
67
- const pushRemoteUrl = checkoutTarget
67
+ const pushRemoteUrl = checkoutTarget?.isCrossRepository
68
68
  ? checkoutTarget.headRepositorySshUrl || checkoutTarget.headRepositoryUrl || undefined
69
69
  : undefined;
70
+ const trackOriginHead = checkoutTarget ? !checkoutTarget.isCrossRepository : false;
70
71
  return {
71
72
  kind: "checkout-github-pr",
72
73
  githubPrNumber: params.githubPrNumber,
@@ -74,6 +75,7 @@ async function resolveGitHubPrCheckoutIntent(params) {
74
75
  baseRefName,
75
76
  ...(localBranchName !== headRef ? { localBranchName } : {}),
76
77
  ...(pushRemoteUrl ? { pushRemoteUrl } : {}),
78
+ ...(trackOriginHead ? { trackOriginHead } : {}),
77
79
  };
78
80
  }
79
81
  async function resolveGitHubPrCheckoutTarget(params) {
@@ -0,0 +1,59 @@
1
+ import type pino from "pino";
2
+ import type { AgentSnapshotPayload, ProjectPlacementPayload, SessionInboundMessage, SessionOutboundMessage } from "../../messages.js";
3
+ import type { ManagedAgent } from "../../agent/agent-manager.js";
4
+ import type { StoredAgentRecord } from "../../agent/agent-storage.js";
5
+ type AgentUpdatesFilter = NonNullable<Extract<SessionInboundMessage, {
6
+ type: "fetch_agents_request";
7
+ }>["filter"]>;
8
+ /**
9
+ * Owns the single per-client `agent_update` subscription: when a client subscribes
10
+ * via `fetch_agents_request`, every later agent lifecycle change (live forward,
11
+ * stored-record archive/detach, delete) is filtered against the subscription's
12
+ * filter and either emitted or — while the initial snapshot is still being built —
13
+ * buffered and replayed on flush. Keeping the mutable subscription state, the
14
+ * bootstrap buffer, the provider-visibility gate, and the filter predicate behind
15
+ * one interface stops the rest of session.ts from poking the subscription shape or
16
+ * hand-rolling `agent_update` payloads, and the (previously untested) filter/buffer/
17
+ * flush branches become exercisable through injected fakes.
18
+ *
19
+ * The snapshot listing path applies the SAME filter via the pure
20
+ * `matchesAgentUpdatesFilter` so a subscription's initial page and its live updates
21
+ * stay consistent.
22
+ */
23
+ export interface AgentUpdatesService {
24
+ beginSubscription(input: {
25
+ subscriptionId: string;
26
+ filter?: AgentUpdatesFilter;
27
+ }): void;
28
+ flushBootstrapped(subscriptionId: string, options?: {
29
+ snapshotUpdatedAtByAgentId?: Map<string, number>;
30
+ }): void;
31
+ clearSubscription(subscriptionId: string): void;
32
+ hasSubscription(): boolean;
33
+ forwardLiveAgent(agent: ManagedAgent): Promise<void>;
34
+ emitStoredRecord(record: StoredAgentRecord): Promise<AgentSnapshotPayload>;
35
+ removeAgent(agentId: string): void;
36
+ dispose(): void;
37
+ }
38
+ export interface AgentUpdatesServiceDeps {
39
+ emit(message: SessionOutboundMessage): void;
40
+ buildAgentPayload(agent: ManagedAgent): Promise<AgentSnapshotPayload>;
41
+ buildStoredAgentPayload(record: StoredAgentRecord): AgentSnapshotPayload;
42
+ isProviderVisibleToClient(provider: string): boolean;
43
+ buildProjectPlacementForWorkspaceId(workspaceId: string): Promise<ProjectPlacementPayload | null>;
44
+ emitWorkspaceUpdateForWorkspaceId(workspaceId: string): Promise<void>;
45
+ logger: pino.Logger;
46
+ }
47
+ /**
48
+ * Pure predicate shared by the live subscription stream and the snapshot listing
49
+ * pager: does an agent (with its resolved project placement) satisfy a
50
+ * `fetch_agents` filter?
51
+ */
52
+ export declare function matchesAgentUpdatesFilter(input: {
53
+ agent: AgentSnapshotPayload;
54
+ project: ProjectPlacementPayload;
55
+ filter?: AgentUpdatesFilter;
56
+ }): boolean;
57
+ export declare function createAgentUpdatesService(deps: AgentUpdatesServiceDeps): AgentUpdatesService;
58
+ export {};
59
+ //# sourceMappingURL=agent-updates-service.d.ts.map
@@ -0,0 +1,220 @@
1
+ import { resolveEffectiveThinkingOptionId } from "../../agent/agent-projections.js";
2
+ function agentThinkingOptionMatchesFilter(agent, filter) {
3
+ if (filter.thinkingOptionId === undefined) {
4
+ return true;
5
+ }
6
+ const expectedThinkingOptionId = resolveEffectiveThinkingOptionId({
7
+ configuredThinkingOptionId: filter.thinkingOptionId ?? null,
8
+ });
9
+ const resolvedThinkingOptionId = agent.effectiveThinkingOptionId ??
10
+ resolveEffectiveThinkingOptionId({
11
+ runtimeInfo: agent.runtimeInfo,
12
+ configuredThinkingOptionId: agent.thinkingOptionId ?? null,
13
+ });
14
+ return resolvedThinkingOptionId === expectedThinkingOptionId;
15
+ }
16
+ function matchesAgentStructuralFilter(agent, project, filter) {
17
+ if (filter.statuses && filter.statuses.length > 0) {
18
+ const statuses = new Set(filter.statuses);
19
+ if (!statuses.has(agent.status)) {
20
+ return false;
21
+ }
22
+ }
23
+ if (typeof filter.requiresAttention === "boolean") {
24
+ const requiresAttention = agent.requiresAttention ?? false;
25
+ if (requiresAttention !== filter.requiresAttention) {
26
+ return false;
27
+ }
28
+ }
29
+ if (filter.projectKeys && filter.projectKeys.length > 0) {
30
+ const projectKeys = new Set(filter.projectKeys.filter((item) => item.trim().length > 0));
31
+ if (projectKeys.size > 0 && !projectKeys.has(project.projectKey)) {
32
+ return false;
33
+ }
34
+ }
35
+ return true;
36
+ }
37
+ /**
38
+ * Pure predicate shared by the live subscription stream and the snapshot listing
39
+ * pager: does an agent (with its resolved project placement) satisfy a
40
+ * `fetch_agents` filter?
41
+ */
42
+ export function matchesAgentUpdatesFilter(input) {
43
+ const { agent, project, filter } = input;
44
+ if (filter?.labels) {
45
+ const matchesLabels = Object.entries(filter.labels).every(([key, value]) => agent.labels[key] === value);
46
+ if (!matchesLabels) {
47
+ return false;
48
+ }
49
+ }
50
+ const includeArchived = filter?.includeArchived ?? false;
51
+ if (!includeArchived && agent.archivedAt) {
52
+ return false;
53
+ }
54
+ if (filter && !agentThinkingOptionMatchesFilter(agent, filter)) {
55
+ return false;
56
+ }
57
+ if (filter && !matchesAgentStructuralFilter(agent, project, filter)) {
58
+ return false;
59
+ }
60
+ return true;
61
+ }
62
+ function agentUpdateTargetId(update) {
63
+ return update.kind === "remove" ? update.agentId : update.agent.id;
64
+ }
65
+ export function createAgentUpdatesService(deps) {
66
+ let subscription = null;
67
+ function bufferOrEmit(sub, payload) {
68
+ if (payload.kind === "upsert" && !deps.isProviderVisibleToClient(payload.agent.provider)) {
69
+ return;
70
+ }
71
+ if (sub.isBootstrapping) {
72
+ sub.pendingUpdatesByAgentId.set(agentUpdateTargetId(payload), payload);
73
+ return;
74
+ }
75
+ deps.emit({
76
+ type: "agent_update",
77
+ payload,
78
+ });
79
+ }
80
+ function beginSubscription(input) {
81
+ subscription = {
82
+ subscriptionId: input.subscriptionId,
83
+ filter: input.filter,
84
+ isBootstrapping: true,
85
+ pendingUpdatesByAgentId: new Map(),
86
+ };
87
+ }
88
+ function flushBootstrapped(subscriptionId, options) {
89
+ if (!subscription || subscription.subscriptionId !== subscriptionId) {
90
+ return;
91
+ }
92
+ if (!subscription.isBootstrapping) {
93
+ return;
94
+ }
95
+ subscription.isBootstrapping = false;
96
+ const pending = Array.from(subscription.pendingUpdatesByAgentId.values());
97
+ subscription.pendingUpdatesByAgentId.clear();
98
+ for (const payload of pending) {
99
+ if (payload.kind === "upsert") {
100
+ const snapshotUpdatedAt = options?.snapshotUpdatedAtByAgentId?.get(payload.agent.id);
101
+ if (typeof snapshotUpdatedAt === "number") {
102
+ const updateUpdatedAt = Date.parse(payload.agent.updatedAt);
103
+ if (!Number.isNaN(updateUpdatedAt) && updateUpdatedAt <= snapshotUpdatedAt) {
104
+ continue;
105
+ }
106
+ }
107
+ }
108
+ deps.emit({
109
+ type: "agent_update",
110
+ payload,
111
+ });
112
+ }
113
+ }
114
+ function clearSubscription(subscriptionId) {
115
+ if (subscription && subscription.subscriptionId === subscriptionId) {
116
+ subscription = null;
117
+ }
118
+ }
119
+ function hasSubscription() {
120
+ return subscription !== null;
121
+ }
122
+ function removeAgent(agentId) {
123
+ if (!subscription) {
124
+ return;
125
+ }
126
+ bufferOrEmit(subscription, { kind: "remove", agentId });
127
+ }
128
+ async function emitStoredRecord(record) {
129
+ const payload = deps.buildStoredAgentPayload(record);
130
+ const sub = subscription;
131
+ if (!sub) {
132
+ return payload;
133
+ }
134
+ const project = payload.workspaceId
135
+ ? await deps.buildProjectPlacementForWorkspaceId(payload.workspaceId)
136
+ : null;
137
+ if (!project) {
138
+ bufferOrEmit(sub, {
139
+ kind: "remove",
140
+ agentId: payload.id,
141
+ });
142
+ return payload;
143
+ }
144
+ const matches = matchesAgentUpdatesFilter({
145
+ agent: payload,
146
+ project,
147
+ filter: sub.filter,
148
+ });
149
+ bufferOrEmit(sub, matches
150
+ ? {
151
+ kind: "upsert",
152
+ agent: payload,
153
+ project,
154
+ }
155
+ : {
156
+ kind: "remove",
157
+ agentId: payload.id,
158
+ });
159
+ return payload;
160
+ }
161
+ async function forwardLiveAgent(agent) {
162
+ try {
163
+ const sub = subscription;
164
+ const payload = await deps.buildAgentPayload(agent);
165
+ if (sub) {
166
+ const project = payload.workspaceId
167
+ ? await deps.buildProjectPlacementForWorkspaceId(payload.workspaceId)
168
+ : null;
169
+ if (!project) {
170
+ bufferOrEmit(sub, {
171
+ kind: "remove",
172
+ agentId: payload.id,
173
+ });
174
+ }
175
+ else {
176
+ const matches = matchesAgentUpdatesFilter({
177
+ agent: payload,
178
+ project,
179
+ filter: sub.filter,
180
+ });
181
+ if (matches) {
182
+ bufferOrEmit(sub, {
183
+ kind: "upsert",
184
+ agent: payload,
185
+ project,
186
+ });
187
+ }
188
+ else {
189
+ bufferOrEmit(sub, {
190
+ kind: "remove",
191
+ agentId: payload.id,
192
+ });
193
+ }
194
+ }
195
+ }
196
+ // A lifecycle change updates exactly the agent's owning workspace, never
197
+ // every workspace sharing its cwd. Ownership is the agent's workspaceId.
198
+ if (payload.workspaceId) {
199
+ await deps.emitWorkspaceUpdateForWorkspaceId(payload.workspaceId);
200
+ }
201
+ }
202
+ catch (error) {
203
+ deps.logger.error({ err: error }, "Failed to emit agent update");
204
+ }
205
+ }
206
+ function dispose() {
207
+ subscription = null;
208
+ }
209
+ return {
210
+ beginSubscription,
211
+ flushBootstrapped,
212
+ clearSubscription,
213
+ hasSubscription,
214
+ forwardLiveAgent,
215
+ emitStoredRecord,
216
+ removeAgent,
217
+ dispose,
218
+ };
219
+ }
220
+ //# sourceMappingURL=agent-updates-service.js.map
@@ -2,32 +2,26 @@ import type pino from "pino";
2
2
  import type { BranchSuggestionsRequest, CheckoutRefreshRequest, CheckoutRenameBranchRequest, CheckoutStatusRequest, SessionInboundMessage, SessionOutboundMessage, SubscribeCheckoutDiffRequest, UnsubscribeCheckoutDiffRequest, ValidateBranchRequest } from "../../messages.js";
3
3
  import type { CheckoutDiffCompareInput, CheckoutDiffSnapshotPayload } from "../../checkout-diff-manager.js";
4
4
  import type { WorkspaceGitRuntimeSnapshot, WorkspaceGitService } from "../../workspace-git-service.js";
5
+ import type { GitMutationService } from "../git-mutation/git-mutation-service.js";
5
6
  import { type GitHubService } from "../../../services/github-service.js";
6
- import { type CheckoutExistingBranchResult, type GitMutationRefreshReason } from "../../../utils/checkout-git.js";
7
+ import type { GitMetadataGenerator } from "./git-metadata-generator.js";
7
8
  /**
8
9
  * The collaborators a checkout command reaches that are NOT part of the checkout
9
- * domain: the git-mutation refresh primitive and workspace-update emitters owned
10
- * by the Session shell (also used by worktree/workspace creation), the injected
11
- * branch operations, and the LLM-backed commit/PR text generators. CheckoutSession
12
- * orchestrates them but does not own them.
10
+ * domain and stay owned by the Session shell: client emit, workspace-update
11
+ * emission, the git branch-snapshot notifier, and the current-branch rename
12
+ * primitive. CheckoutSession orchestrates them but does not own them. The
13
+ * git-mutation primitives it performs (switch branch, force snapshot refresh) are
14
+ * injected separately as `gitMutation`, since they are shared with worktree and
15
+ * workspace creation.
13
16
  */
14
17
  export interface CheckoutSessionHost {
15
18
  emit(msg: SessionOutboundMessage): void;
16
- notifyGitMutation(cwd: string, reason: GitMutationRefreshReason, options?: {
17
- invalidateGithub?: boolean;
18
- }): Promise<void>;
19
19
  emitWorkspaceUpdateForCwd(cwd: string): Promise<void>;
20
20
  handleWorkspaceGitBranchSnapshot(cwd: string, branchName: string | null): void;
21
21
  renameCurrentBranch(cwd: string, branch: string): Promise<{
22
22
  previousBranch: string | null;
23
23
  currentBranch: string | null;
24
24
  }>;
25
- checkoutExistingBranch(cwd: string, branch: string): Promise<CheckoutExistingBranchResult>;
26
- generateCommitMessage(cwd: string): Promise<string>;
27
- generatePullRequestText(cwd: string, baseRef?: string): Promise<{
28
- title: string;
29
- body: string;
30
- }>;
31
25
  }
32
26
  /**
33
27
  * The slice of CheckoutDiffManager that CheckoutSession needs: open a live diff
@@ -46,9 +40,11 @@ export interface CheckoutDiffSubscriber {
46
40
  }
47
41
  export interface CheckoutSessionOptions {
48
42
  host: CheckoutSessionHost;
43
+ gitMutation: Pick<GitMutationService, "checkoutExistingBranch" | "notifyGitMutation">;
49
44
  workspaceGitService: WorkspaceGitService;
50
45
  github: GitHubService;
51
46
  checkoutDiffManager: CheckoutDiffSubscriber;
47
+ gitMetadataGenerator: GitMetadataGenerator;
52
48
  paseoHome: string;
53
49
  worktreesRoot: string | undefined;
54
50
  logger: pino.Logger;
@@ -60,15 +56,17 @@ export interface CheckoutSessionOptions {
60
56
  * merge/pull/push/stash and the GitHub-PR operations).
61
57
  *
62
58
  * Command operations keep the live diff in sync by calling scheduleDiffRefresh()
63
- * and refresh the workspace git snapshot through host.notifyGitMutation(); the
59
+ * and refresh the workspace git snapshot through gitMutation.notifyGitMutation(); the
64
60
  * workspace git observer streams branch changes through emitStatusUpdate().
65
61
  */
66
62
  export declare class CheckoutSession {
67
63
  private static readonly PASEO_STASH_PREFIX;
68
64
  private readonly host;
65
+ private readonly gitMutation;
69
66
  private readonly workspaceGitService;
70
67
  private readonly github;
71
68
  private readonly checkoutDiffManager;
69
+ private readonly gitMetadataGenerator;
72
70
  private readonly paseoHome;
73
71
  private readonly worktreesRoot;
74
72
  private readonly logger;
@@ -14,16 +14,18 @@ import { expandTilde } from "../../../utils/path.js";
14
14
  * merge/pull/push/stash and the GitHub-PR operations).
15
15
  *
16
16
  * Command operations keep the live diff in sync by calling scheduleDiffRefresh()
17
- * and refresh the workspace git snapshot through host.notifyGitMutation(); the
17
+ * and refresh the workspace git snapshot through gitMutation.notifyGitMutation(); the
18
18
  * workspace git observer streams branch changes through emitStatusUpdate().
19
19
  */
20
20
  export class CheckoutSession {
21
21
  constructor(options) {
22
22
  this.diffSubscriptions = new Map();
23
23
  this.host = options.host;
24
+ this.gitMutation = options.gitMutation;
24
25
  this.workspaceGitService = options.workspaceGitService;
25
26
  this.github = options.github;
26
27
  this.checkoutDiffManager = options.checkoutDiffManager;
28
+ this.gitMetadataGenerator = options.gitMetadataGenerator;
27
29
  this.paseoHome = options.paseoHome;
28
30
  this.worktreesRoot = options.worktreesRoot;
29
31
  this.logger = options.logger;
@@ -252,7 +254,7 @@ export class CheckoutSession {
252
254
  async handleCheckoutSwitchBranchRequest(msg) {
253
255
  const { cwd, branch, requestId } = msg;
254
256
  try {
255
- const checkoutResult = await this.host.checkoutExistingBranch(cwd, branch);
257
+ const checkoutResult = await this.gitMutation.checkoutExistingBranch(cwd, branch);
256
258
  this.scheduleDiffRefresh(cwd);
257
259
  // Push a workspace_update immediately so the sidebar/header reflect
258
260
  // the new branch name without waiting for the background git watcher.
@@ -300,7 +302,7 @@ export class CheckoutSession {
300
302
  }
301
303
  try {
302
304
  const result = await this.host.renameCurrentBranch(cwd, branch);
303
- await this.host.notifyGitMutation(cwd, "rename-branch", { invalidateGithub: true });
305
+ await this.gitMutation.notifyGitMutation(cwd, "rename-branch", { invalidateGithub: true });
304
306
  this.scheduleDiffRefresh(cwd);
305
307
  this.host.handleWorkspaceGitBranchSnapshot(cwd, result.currentBranch);
306
308
  // Branch is a git fact derived per-descriptor from each workspace's own
@@ -344,7 +346,7 @@ export class CheckoutSession {
344
346
  await execCommand("git", ["stash", "push", "--include-untracked", "-m", message], {
345
347
  cwd,
346
348
  });
347
- await this.host.notifyGitMutation(cwd, "stash-push");
349
+ await this.gitMutation.notifyGitMutation(cwd, "stash-push");
348
350
  this.scheduleDiffRefresh(cwd);
349
351
  this.host.emit({
350
352
  type: "stash_save_response",
@@ -364,7 +366,7 @@ export class CheckoutSession {
364
366
  await execCommand("git", ["stash", "pop", `stash@{${stashIndex}}`], {
365
367
  cwd,
366
368
  });
367
- await this.host.notifyGitMutation(cwd, "stash-pop");
369
+ await this.gitMutation.notifyGitMutation(cwd, "stash-pop");
368
370
  this.scheduleDiffRefresh(cwd);
369
371
  this.host.emit({
370
372
  type: "stash_pop_response",
@@ -400,7 +402,7 @@ export class CheckoutSession {
400
402
  try {
401
403
  let message = msg.message?.trim() ?? "";
402
404
  if (!message) {
403
- message = await this.host.generateCommitMessage(cwd);
405
+ message = await this.gitMetadataGenerator.generateCommitMessage(cwd);
404
406
  }
405
407
  if (!message) {
406
408
  throw new Error("Commit message is required");
@@ -409,7 +411,7 @@ export class CheckoutSession {
409
411
  message,
410
412
  addAll: msg.addAll ?? true,
411
413
  });
412
- await this.host.notifyGitMutation(cwd, "commit-changes");
414
+ await this.gitMutation.notifyGitMutation(cwd, "commit-changes");
413
415
  this.scheduleDiffRefresh(cwd);
414
416
  this.host.emit({
415
417
  type: "checkout_commit_response",
@@ -457,8 +459,8 @@ export class CheckoutSession {
457
459
  mode: msg.strategy === "squash" ? "squash" : "merge",
458
460
  }, { paseoHome: this.paseoHome, worktreesRoot: this.worktreesRoot });
459
461
  await Promise.all([
460
- this.host.notifyGitMutation(mutatedCwd, "merge-to-base", { invalidateGithub: true }),
461
- ...(mutatedCwd !== cwd ? [this.host.notifyGitMutation(cwd, "merge-to-base")] : []),
462
+ this.gitMutation.notifyGitMutation(mutatedCwd, "merge-to-base", { invalidateGithub: true }),
463
+ ...(mutatedCwd !== cwd ? [this.gitMutation.notifyGitMutation(cwd, "merge-to-base")] : []),
462
464
  ]);
463
465
  this.scheduleDiffRefresh(cwd);
464
466
  this.host.emit({
@@ -496,7 +498,7 @@ export class CheckoutSession {
496
498
  baseRef: msg.baseRef,
497
499
  requireCleanTarget: msg.requireCleanTarget ?? true,
498
500
  });
499
- await this.host.notifyGitMutation(cwd, "merge-from-base", { invalidateGithub: true });
501
+ await this.gitMutation.notifyGitMutation(cwd, "merge-from-base", { invalidateGithub: true });
500
502
  this.scheduleDiffRefresh(cwd);
501
503
  this.host.emit({
502
504
  type: "checkout_merge_from_base_response",
@@ -524,7 +526,7 @@ export class CheckoutSession {
524
526
  const { cwd, requestId } = msg;
525
527
  try {
526
528
  await pullCurrentBranch(cwd);
527
- await this.host.notifyGitMutation(cwd, "pull", { invalidateGithub: true });
529
+ await this.gitMutation.notifyGitMutation(cwd, "pull", { invalidateGithub: true });
528
530
  this.scheduleDiffRefresh(cwd);
529
531
  this.host.emit({
530
532
  type: "checkout_pull_response",
@@ -552,7 +554,7 @@ export class CheckoutSession {
552
554
  const { cwd, requestId } = msg;
553
555
  try {
554
556
  await pushCurrentBranch(cwd);
555
- await this.host.notifyGitMutation(cwd, "push", { invalidateGithub: true });
557
+ await this.gitMutation.notifyGitMutation(cwd, "push", { invalidateGithub: true });
556
558
  this.host.emit({
557
559
  type: "checkout_push_response",
558
560
  payload: {
@@ -581,7 +583,7 @@ export class CheckoutSession {
581
583
  let title = msg.title?.trim() ?? "";
582
584
  let body = msg.body?.trim() ?? "";
583
585
  if (!title || !body) {
584
- const generated = await this.host.generatePullRequestText(cwd, msg.baseRef);
586
+ const generated = await this.gitMetadataGenerator.generatePullRequestText(cwd, msg.baseRef);
585
587
  if (!title)
586
588
  title = generated.title;
587
589
  if (!body)
@@ -592,7 +594,7 @@ export class CheckoutSession {
592
594
  body,
593
595
  base: msg.baseRef,
594
596
  }, this.github);
595
- await this.host.notifyGitMutation(cwd, "create-pr", { invalidateGithub: true });
597
+ await this.gitMutation.notifyGitMutation(cwd, "create-pr", { invalidateGithub: true });
596
598
  this.host.emit({
597
599
  type: "checkout_pr_create_response",
598
600
  payload: {
@@ -632,7 +634,7 @@ export class CheckoutSession {
632
634
  mergeMethod: msg.mergeMethod,
633
635
  status: pullRequest,
634
636
  });
635
- await this.host.notifyGitMutation(cwd, "merge-pr", { invalidateGithub: true });
637
+ await this.gitMutation.notifyGitMutation(cwd, "merge-pr", { invalidateGithub: true });
636
638
  this.host.emit({
637
639
  type: "checkout_pr_merge_response",
638
640
  payload: {
@@ -695,7 +697,7 @@ export class CheckoutSession {
695
697
  status: pullRequest,
696
698
  });
697
699
  }
698
- await this.host.notifyGitMutation(cwd, msg.enabled ? "enable-pr-auto-merge" : "disable-pr-auto-merge", {
700
+ await this.gitMutation.notifyGitMutation(cwd, msg.enabled ? "enable-pr-auto-merge" : "disable-pr-auto-merge", {
699
701
  invalidateGithub: true,
700
702
  });
701
703
  this.host.emit({
@@ -0,0 +1,53 @@
1
+ import { z } from "zod";
2
+ import type { AgentManager } from "../../agent/agent-manager.js";
3
+ import type { ProviderSnapshotManager } from "../../agent/provider-snapshot-manager.js";
4
+ import { type ResolveStructuredGenerationProvidersOptions, type StructuredGenerationDaemonConfig } from "../../agent/structured-generation-providers.js";
5
+ import type { WorkspaceGitService } from "../../workspace-git-service.js";
6
+ export interface PullRequestText {
7
+ title: string;
8
+ body: string;
9
+ }
10
+ /**
11
+ * Generates a workspace's commit message and pull-request text from its git diff
12
+ * via the agent LLM. The checkout subsystem is the only consumer; it owns the
13
+ * commit/PR commands and asks this for the wording when the user left it blank.
14
+ */
15
+ export interface GitMetadataGenerator {
16
+ generateCommitMessage(cwd: string): Promise<string>;
17
+ generatePullRequestText(cwd: string, baseRef?: string): Promise<PullRequestText>;
18
+ }
19
+ /**
20
+ * The LLM boundary, injected so the generator's prompt-building and fallback
21
+ * behaviour is unit-testable with a fake. Production wires
22
+ * createAgentStructuredTextGeneration (resolve providers → run structured
23
+ * generation); a failed generation throws StructuredAgent*Error, which the
24
+ * generator catches and turns into the product fallback text.
25
+ */
26
+ export interface StructuredTextGeneration {
27
+ generate<T>(request: StructuredTextGenerationRequest<T>): Promise<T>;
28
+ }
29
+ export interface StructuredTextGenerationRequest<T> {
30
+ cwd: string;
31
+ prompt: string;
32
+ schema: z.ZodType<T>;
33
+ schemaName: string;
34
+ agentTitle: string;
35
+ }
36
+ type GitMetadataDiffSource = Pick<WorkspaceGitService, "getCheckoutDiff" | "resolveRepoRoot">;
37
+ export declare function createGitMetadataGenerator(deps: {
38
+ workspaceGitService: GitMetadataDiffSource;
39
+ generation: StructuredTextGeneration;
40
+ }): GitMetadataGenerator;
41
+ /**
42
+ * Production StructuredTextGeneration: resolve the structured-generation providers
43
+ * for the cwd, then run the agent with a 2-retry fallback as an internal,
44
+ * non-persisted session.
45
+ */
46
+ export declare function createAgentStructuredTextGeneration(deps: {
47
+ agentManager: AgentManager;
48
+ providerSnapshotManager: Pick<ProviderSnapshotManager, "listProviders">;
49
+ readDaemonConfig: () => StructuredGenerationDaemonConfig;
50
+ getFocusedSelection: (cwd: string) => ResolveStructuredGenerationProvidersOptions["currentSelection"];
51
+ }): StructuredTextGeneration;
52
+ export {};
53
+ //# sourceMappingURL=git-metadata-generator.d.ts.map