@ponythewhite/base-context 1.0.0 → 1.0.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 (285) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/NOTICE +0 -5
  3. package/README.md +44 -27
  4. package/dist/NOTICE +0 -5
  5. package/dist/base-context-runtime/pyproject.toml +1 -1
  6. package/dist/base-context-runtime/src/rlm/__init__.py +7 -5
  7. package/dist/base-context-runtime/test/test_subagent_registry.py +28 -1
  8. package/dist/base-context-runtime/uv.lock +1 -1
  9. package/dist/build-info.json +1 -1
  10. package/dist/bundle/amazon-bedrock.js +21 -0
  11. package/dist/bundle/{anthropic-YY4S534V.js → anthropic-UV5GZDGU.js} +5 -5
  12. package/dist/bundle/{azure-openai-responses-JRP6MIM3.js → azure-openai-responses-WSNPXLYC.js} +6 -6
  13. package/dist/bundle/{bundled-modules-P5HARVZA.js → bundled-modules-PWOGKUQQ.js} +71 -16
  14. package/dist/bundle/chunk-27QCJ2AZ.js +2578 -0
  15. package/dist/bundle/{chunk-BYVP7LWV.js → chunk-44PEHPOG.js} +1916 -4689
  16. package/dist/bundle/{chunk-MZHTNNVA.js → chunk-4GXPNXOJ.js} +8 -0
  17. package/dist/bundle/{chunk-SC5KG5R4.js → chunk-DGNX7HQ3.js} +1 -7
  18. package/dist/bundle/{chunk-A53O363M.js → chunk-GRJFXLBM.js} +0 -1
  19. package/dist/bundle/chunk-HKINIBP4.js +29 -0
  20. package/dist/bundle/{chunk-73DCPU3D.js → chunk-IADCPVEI.js} +1019 -3427
  21. package/dist/bundle/{chunk-UDSW6FNG.js → chunk-KTNETTHI.js} +1 -1
  22. package/dist/bundle/{chunk-U7AUVG3B.js → chunk-VSIYFWYI.js} +24 -6
  23. package/dist/bundle/{chunk-IW77OXFS.js → chunk-W46VZFI6.js} +0 -2099
  24. package/dist/bundle/{cli-main-O4X7GFGY.js → cli-main-4DS7Y3PI.js} +8 -6
  25. package/dist/bundle/cli.js +2 -2
  26. package/dist/bundle/{google-AUTVGDGZ.js → google-T32FMD4G.js} +6 -6
  27. package/dist/bundle/{google-vertex-Q75D7RKS.js → google-vertex-56KP6I3B.js} +3 -3
  28. package/dist/bundle/{main-XKOW2BV6.js → main-SV7JLVEB.js} +7 -5
  29. package/dist/bundle/{mistral-7ESB7QUD.js → mistral-WGBMYIVU.js} +5 -5
  30. package/dist/bundle/{openai-codex-responses-LV3QRPN4.js → openai-codex-responses-PIV2RQ3G.js} +6 -6
  31. package/dist/bundle/{openai-completions-OJECLPXJ.js → openai-completions-64C3JPR4.js} +11 -22
  32. package/dist/bundle/{openai-responses-FN6HZMBC.js → openai-responses-UI7RSTDV.js} +6 -6
  33. package/dist/cli/args.d.ts.map +1 -1
  34. package/dist/cli/args.js +108 -59
  35. package/dist/cli/args.js.map +1 -1
  36. package/dist/cli/daemon-ps.d.ts +4 -3
  37. package/dist/cli/daemon-ps.d.ts.map +1 -1
  38. package/dist/cli/daemon-ps.js +6 -1
  39. package/dist/cli/daemon-ps.js.map +1 -1
  40. package/dist/cli/product-doctor.d.ts +0 -1
  41. package/dist/cli/product-doctor.d.ts.map +1 -1
  42. package/dist/cli/product-doctor.js +6 -3
  43. package/dist/cli/product-doctor.js.map +1 -1
  44. package/dist/config.d.ts +0 -3
  45. package/dist/config.d.ts.map +1 -1
  46. package/dist/config.js +0 -8
  47. package/dist/config.js.map +1 -1
  48. package/dist/core/agent-session-config.d.ts +1 -2
  49. package/dist/core/agent-session-config.d.ts.map +1 -1
  50. package/dist/core/agent-session-config.js +0 -3
  51. package/dist/core/agent-session-config.js.map +1 -1
  52. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  53. package/dist/core/agent-session-runtime.js +5 -4
  54. package/dist/core/agent-session-runtime.js.map +1 -1
  55. package/dist/core/agent-session-services.d.ts +5 -3
  56. package/dist/core/agent-session-services.d.ts.map +1 -1
  57. package/dist/core/agent-session-services.js +2 -27
  58. package/dist/core/agent-session-services.js.map +1 -1
  59. package/dist/core/agent-session.d.ts +10 -6
  60. package/dist/core/agent-session.d.ts.map +1 -1
  61. package/dist/core/agent-session.js +107 -107
  62. package/dist/core/agent-session.js.map +1 -1
  63. package/dist/core/auth-storage.d.ts +8 -35
  64. package/dist/core/auth-storage.d.ts.map +1 -1
  65. package/dist/core/auth-storage.js +33 -243
  66. package/dist/core/auth-storage.js.map +1 -1
  67. package/dist/core/cron-jobs.d.ts.map +1 -1
  68. package/dist/core/cron-jobs.js +7 -1
  69. package/dist/core/cron-jobs.js.map +1 -1
  70. package/dist/core/inference-coordinator.d.ts +6 -1
  71. package/dist/core/inference-coordinator.d.ts.map +1 -1
  72. package/dist/core/inference-coordinator.js +18 -2
  73. package/dist/core/inference-coordinator.js.map +1 -1
  74. package/dist/core/kernel/bootstrap.d.ts.map +1 -1
  75. package/dist/core/kernel/bootstrap.js +2 -2
  76. package/dist/core/kernel/bootstrap.js.map +1 -1
  77. package/dist/core/kernel/repl-manager.d.ts +2 -0
  78. package/dist/core/kernel/repl-manager.d.ts.map +1 -1
  79. package/dist/core/kernel/repl-manager.js +44 -1
  80. package/dist/core/kernel/repl-manager.js.map +1 -1
  81. package/dist/core/logging.d.ts +4 -3
  82. package/dist/core/logging.d.ts.map +1 -1
  83. package/dist/core/logging.js +6 -6
  84. package/dist/core/logging.js.map +1 -1
  85. package/dist/core/mcp/mcp-manager.d.ts.map +1 -1
  86. package/dist/core/mcp/mcp-manager.js +3 -3
  87. package/dist/core/mcp/mcp-manager.js.map +1 -1
  88. package/dist/core/model-registry.d.ts +1 -16
  89. package/dist/core/model-registry.d.ts.map +1 -1
  90. package/dist/core/model-registry.js +88 -196
  91. package/dist/core/model-registry.js.map +1 -1
  92. package/dist/core/model-resolver.d.ts +2 -19
  93. package/dist/core/model-resolver.d.ts.map +1 -1
  94. package/dist/core/model-resolver.js +36 -266
  95. package/dist/core/model-resolver.js.map +1 -1
  96. package/dist/core/provider-contracts.d.ts +5 -6
  97. package/dist/core/provider-contracts.d.ts.map +1 -1
  98. package/dist/core/provider-contracts.js +25 -36
  99. package/dist/core/provider-contracts.js.map +1 -1
  100. package/dist/core/provider-display-names.d.ts.map +1 -1
  101. package/dist/core/provider-display-names.js +0 -2
  102. package/dist/core/provider-display-names.js.map +1 -1
  103. package/dist/core/rlm-max-subagents.d.ts +32 -0
  104. package/dist/core/rlm-max-subagents.d.ts.map +1 -0
  105. package/dist/core/rlm-max-subagents.js +50 -0
  106. package/dist/core/rlm-max-subagents.js.map +1 -0
  107. package/dist/core/rlm-runtime.d.ts +3 -3
  108. package/dist/core/rlm-runtime.d.ts.map +1 -1
  109. package/dist/core/rlm-runtime.js.map +1 -1
  110. package/dist/core/sdk.d.ts +4 -3
  111. package/dist/core/sdk.d.ts.map +1 -1
  112. package/dist/core/sdk.js +27 -14
  113. package/dist/core/sdk.js.map +1 -1
  114. package/dist/core/settings-manager.d.ts +3 -16
  115. package/dist/core/settings-manager.d.ts.map +1 -1
  116. package/dist/core/settings-manager.js +12 -44
  117. package/dist/core/settings-manager.js.map +1 -1
  118. package/dist/core/slash-commands.d.ts.map +1 -1
  119. package/dist/core/slash-commands.js +6 -6
  120. package/dist/core/slash-commands.js.map +1 -1
  121. package/dist/index.d.ts +1 -1
  122. package/dist/index.d.ts.map +1 -1
  123. package/dist/index.js.map +1 -1
  124. package/dist/installer.mjs +2 -3
  125. package/dist/main.d.ts.map +1 -1
  126. package/dist/main.js +39 -34
  127. package/dist/main.js.map +1 -1
  128. package/dist/modes/acp/acp-mode.d.ts.map +1 -1
  129. package/dist/modes/acp/acp-mode.js +1 -1
  130. package/dist/modes/acp/acp-mode.js.map +1 -1
  131. package/dist/modes/agent-connection/daemon-agent-connection.d.ts +6 -2
  132. package/dist/modes/agent-connection/daemon-agent-connection.d.ts.map +1 -1
  133. package/dist/modes/agent-connection/daemon-agent-connection.js +13 -2
  134. package/dist/modes/agent-connection/daemon-agent-connection.js.map +1 -1
  135. package/dist/modes/agent-connection/in-process-agent-connection.d.ts +2 -0
  136. package/dist/modes/agent-connection/in-process-agent-connection.d.ts.map +1 -1
  137. package/dist/modes/agent-connection/in-process-agent-connection.js +6 -0
  138. package/dist/modes/agent-connection/in-process-agent-connection.js.map +1 -1
  139. package/dist/modes/agent-connection/types.d.ts +3 -0
  140. package/dist/modes/agent-connection/types.d.ts.map +1 -1
  141. package/dist/modes/agent-connection/types.js.map +1 -1
  142. package/dist/modes/agents-view/agents-view-mode.d.ts.map +1 -1
  143. package/dist/modes/agents-view/agents-view-mode.js +2 -19
  144. package/dist/modes/agents-view/agents-view-mode.js.map +1 -1
  145. package/dist/modes/daemon/daemon-mode.d.ts +5 -0
  146. package/dist/modes/daemon/daemon-mode.d.ts.map +1 -1
  147. package/dist/modes/daemon/daemon-mode.js +107 -12
  148. package/dist/modes/daemon/daemon-mode.js.map +1 -1
  149. package/dist/modes/daemon/daemon-protocol.d.ts +194 -165
  150. package/dist/modes/daemon/daemon-protocol.d.ts.map +1 -1
  151. package/dist/modes/daemon/daemon-protocol.js +16 -11
  152. package/dist/modes/daemon/daemon-protocol.js.map +1 -1
  153. package/dist/modes/daemon/daemon-rlm-capacity-coordinator.d.ts +19 -0
  154. package/dist/modes/daemon/daemon-rlm-capacity-coordinator.d.ts.map +1 -0
  155. package/dist/modes/daemon/daemon-rlm-capacity-coordinator.js +74 -0
  156. package/dist/modes/daemon/daemon-rlm-capacity-coordinator.js.map +1 -0
  157. package/dist/modes/daemon/daemon-rlm-capacity.d.ts +19 -0
  158. package/dist/modes/daemon/daemon-rlm-capacity.d.ts.map +1 -0
  159. package/dist/modes/daemon/daemon-rlm-capacity.js +85 -0
  160. package/dist/modes/daemon/daemon-rlm-capacity.js.map +1 -0
  161. package/dist/modes/daemon/daemon-session-summarizer.d.ts +2 -3
  162. package/dist/modes/daemon/daemon-session-summarizer.d.ts.map +1 -1
  163. package/dist/modes/daemon/daemon-session-summarizer.js +32 -23
  164. package/dist/modes/daemon/daemon-session-summarizer.js.map +1 -1
  165. package/dist/modes/daemon/daemon-state-root.d.ts +15 -0
  166. package/dist/modes/daemon/daemon-state-root.d.ts.map +1 -0
  167. package/dist/modes/daemon/daemon-state-root.js +40 -0
  168. package/dist/modes/daemon/daemon-state-root.js.map +1 -0
  169. package/dist/modes/daemon/daemon-supervisor-ownership.d.ts +2 -0
  170. package/dist/modes/daemon/daemon-supervisor-ownership.d.ts.map +1 -1
  171. package/dist/modes/daemon/daemon-supervisor-ownership.js +27 -0
  172. package/dist/modes/daemon/daemon-supervisor-ownership.js.map +1 -1
  173. package/dist/modes/daemon/daemon-supervisor.d.ts +10 -1
  174. package/dist/modes/daemon/daemon-supervisor.d.ts.map +1 -1
  175. package/dist/modes/daemon/daemon-supervisor.js +213 -20
  176. package/dist/modes/daemon/daemon-supervisor.js.map +1 -1
  177. package/dist/modes/daemon/daemon-worker-protocol.d.ts +28 -1
  178. package/dist/modes/daemon/daemon-worker-protocol.d.ts.map +1 -1
  179. package/dist/modes/daemon/daemon-worker-protocol.js +16 -2
  180. package/dist/modes/daemon/daemon-worker-protocol.js.map +1 -1
  181. package/dist/modes/daemon/saved-session-catalog.d.ts.map +1 -1
  182. package/dist/modes/daemon/saved-session-catalog.js +2 -0
  183. package/dist/modes/daemon/saved-session-catalog.js.map +1 -1
  184. package/dist/modes/interactive/auth-flows.d.ts +0 -6
  185. package/dist/modes/interactive/auth-flows.d.ts.map +1 -1
  186. package/dist/modes/interactive/auth-flows.js +6 -126
  187. package/dist/modes/interactive/auth-flows.js.map +1 -1
  188. package/dist/modes/interactive/components/configuration-menu.d.ts +3 -0
  189. package/dist/modes/interactive/components/configuration-menu.d.ts.map +1 -1
  190. package/dist/modes/interactive/components/configuration-menu.js +13 -2
  191. package/dist/modes/interactive/components/configuration-menu.js.map +1 -1
  192. package/dist/modes/interactive/components/footer.d.ts +1 -1
  193. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  194. package/dist/modes/interactive/components/footer.js +2 -2
  195. package/dist/modes/interactive/components/footer.js.map +1 -1
  196. package/dist/modes/interactive/components/index.d.ts +0 -1
  197. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  198. package/dist/modes/interactive/components/index.js +0 -1
  199. package/dist/modes/interactive/components/index.js.map +1 -1
  200. package/dist/modes/interactive/components/login-dialog.d.ts +0 -1
  201. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  202. package/dist/modes/interactive/components/login-dialog.js +3 -40
  203. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  204. package/dist/modes/interactive/components/model-selector.d.ts +2 -0
  205. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  206. package/dist/modes/interactive/components/model-selector.js +13 -2
  207. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  208. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  209. package/dist/modes/interactive/components/oauth-selector.js +2 -11
  210. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  211. package/dist/modes/interactive/feature-hints.d.ts.map +1 -1
  212. package/dist/modes/interactive/feature-hints.js +0 -4
  213. package/dist/modes/interactive/feature-hints.js.map +1 -1
  214. package/dist/modes/interactive/interactive-mode.d.ts +3 -12
  215. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  216. package/dist/modes/interactive/interactive-mode.js +81 -507
  217. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  218. package/dist/modes/interactive/onboarding.d.ts +0 -3
  219. package/dist/modes/interactive/onboarding.d.ts.map +1 -1
  220. package/dist/modes/interactive/onboarding.js +0 -17
  221. package/dist/modes/interactive/onboarding.js.map +1 -1
  222. package/dist/modes/rpc/rpc-client.d.ts +4 -1
  223. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  224. package/dist/modes/rpc/rpc-client.js +82 -42
  225. package/dist/modes/rpc/rpc-client.js.map +1 -1
  226. package/dist/node/amazon-bedrock.d.ts +2 -0
  227. package/dist/node/amazon-bedrock.d.ts.map +1 -0
  228. package/dist/node/amazon-bedrock.js +6 -0
  229. package/dist/node/amazon-bedrock.js.map +1 -0
  230. package/dist/product-identity.d.ts +0 -1
  231. package/dist/product-identity.d.ts.map +1 -1
  232. package/dist/product-identity.js +0 -1
  233. package/dist/product-identity.js.map +1 -1
  234. package/docs/development.md +1 -1
  235. package/docs/fork-philosophy.md +4 -8
  236. package/docs/installation.md +83 -62
  237. package/docs/providers.md +23 -25
  238. package/docs/quickstart.md +19 -10
  239. package/docs/rlm-runtime.md +13 -5
  240. package/docs/rpc.md +4 -4
  241. package/docs/sdk.md +20 -11
  242. package/docs/sessions.md +0 -1
  243. package/docs/settings.md +9 -42
  244. package/docs/skills.md +0 -1
  245. package/docs/upstream-0.9.5.md +171 -0
  246. package/docs/usage.md +14 -10
  247. package/package.json +4 -4
  248. package/dist/core/agent-traces.d.ts +0 -149
  249. package/dist/core/agent-traces.d.ts.map +0 -1
  250. package/dist/core/agent-traces.js +0 -904
  251. package/dist/core/agent-traces.js.map +0 -1
  252. package/dist/core/prime-inference-auth.d.ts +0 -70
  253. package/dist/core/prime-inference-auth.d.ts.map +0 -1
  254. package/dist/core/prime-inference-auth.js +0 -352
  255. package/dist/core/prime-inference-auth.js.map +0 -1
  256. package/dist/core/prime-inference-model-selection.d.ts +0 -16
  257. package/dist/core/prime-inference-model-selection.d.ts.map +0 -1
  258. package/dist/core/prime-inference-model-selection.js +0 -16
  259. package/dist/core/prime-inference-model-selection.js.map +0 -1
  260. package/dist/core/prime-inference-models.d.ts +0 -6
  261. package/dist/core/prime-inference-models.d.ts.map +0 -1
  262. package/dist/core/prime-inference-models.js +0 -62
  263. package/dist/core/prime-inference-models.js.map +0 -1
  264. package/dist/core/telemetry.d.ts +0 -95
  265. package/dist/core/telemetry.d.ts.map +0 -1
  266. package/dist/core/telemetry.js +0 -637
  267. package/dist/core/telemetry.js.map +0 -1
  268. package/dist/modes/interactive/components/prime-onboarding-splash.d.ts +0 -39
  269. package/dist/modes/interactive/components/prime-onboarding-splash.d.ts.map +0 -1
  270. package/dist/modes/interactive/components/prime-onboarding-splash.js +0 -286
  271. package/dist/modes/interactive/components/prime-onboarding-splash.js.map +0 -1
  272. package/dist/modes/interactive/components/prime-team-selector.d.ts +0 -30
  273. package/dist/modes/interactive/components/prime-team-selector.d.ts.map +0 -1
  274. package/dist/modes/interactive/components/prime-team-selector.js +0 -166
  275. package/dist/modes/interactive/components/prime-team-selector.js.map +0 -1
  276. package/dist/skills/prime-intellect/SKILL.md +0 -87
  277. package/dist/skills/prime-intellect/references/compute.md +0 -45
  278. package/dist/skills/prime-intellect/references/environments.md +0 -73
  279. package/dist/skills/prime-intellect/references/inference.md +0 -47
  280. package/dist/skills/prime-intellect/references/sandboxes.md +0 -75
  281. package/skills/prime-intellect/SKILL.md +0 -87
  282. package/skills/prime-intellect/references/compute.md +0 -45
  283. package/skills/prime-intellect/references/environments.md +0 -73
  284. package/skills/prime-intellect/references/inference.md +0 -47
  285. package/skills/prime-intellect/references/sandboxes.md +0 -75
@@ -40,6 +40,31 @@ export type DaemonWorkerFrameHeader = {
40
40
  payloadEncoding?: "jsonl" | "assistant-delta";
41
41
  snapshotPurpose?: "attach" | "replacement" | "catchup";
42
42
  };
43
+ export interface DaemonRlmCapacityOrigin {
44
+ sessionFile?: string;
45
+ sessionId: string;
46
+ }
47
+ export type DaemonRlmCapacityOperation = (DaemonRlmCapacityOrigin & {
48
+ op: "status";
49
+ }) | (DaemonRlmCapacityOrigin & {
50
+ op: "set";
51
+ maxSubagents: number;
52
+ }) | (DaemonRlmCapacityOrigin & {
53
+ op: "reserve";
54
+ reservationId: string;
55
+ residentRoot?: true;
56
+ }) | {
57
+ op: "release";
58
+ reservationId: string;
59
+ };
60
+ export interface DaemonRlmCapacityReservation extends DaemonRlmCapacityOrigin {
61
+ reservationId: string;
62
+ residentRoot?: true;
63
+ }
64
+ export interface DaemonRlmCapacitySnapshot {
65
+ reservations: DaemonRlmCapacityReservation[];
66
+ }
67
+ export declare function isDaemonRlmCapacitySnapshot(value: unknown): value is DaemonRlmCapacitySnapshot;
43
68
  export type DaemonCreateCommand = Extract<DaemonCommand, {
44
69
  type: "create";
45
70
  }>;
@@ -100,6 +125,9 @@ export type DaemonWorkerCommand = {
100
125
  } | {
101
126
  id?: string;
102
127
  type: "worker_archive_and_shutdown";
128
+ } | {
129
+ id?: string;
130
+ type: "worker_get_rlm_capacity";
103
131
  } | {
104
132
  id?: string;
105
133
  type: "worker_passivate_idle_children";
@@ -151,7 +179,6 @@ export interface DaemonWorkerDescriptor {
151
179
  rootSessionId?: string;
152
180
  sessionFile?: string;
153
181
  sessionDir?: string;
154
- telemetryDisabled?: true;
155
182
  createdAt: string;
156
183
  updatedAt: string;
157
184
  lifecycle: DaemonWorkerLifecycle;
@@ -1 +1 @@
1
- {"version":3,"file":"daemon-worker-protocol.d.ts","sourceRoot":"","sources":["../../../src/modes/daemon/daemon-worker-protocol.ts"],"names":[],"mappings":"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","sourcesContent":["import { closeSync, readFileSync } from \"node:fs\";\nimport type { AgentSessionMessageDeliveryMode, AgentSessionMessageSender } from \"../../core/agent-messages.js\";\nimport type { IdleEvictionMinutes } from \"../../core/session-action-store.js\";\n\nexport { SESSION_LEASE_OWNER_ID_ENV, SESSION_LEASES_ENABLED_ENV } from \"../../core/session-lease.js\";\n\nimport type { WorkerRosterEntry } from \"./agent-roster.js\";\nimport type { DaemonClientCapability, DaemonCommand, DaemonOutbound } from \"./daemon-protocol.js\";\n\nexport const DAEMON_WORKER_ROLE_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER\";\nexport const DAEMON_WORKER_TOKEN_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_TOKEN\";\nexport const DAEMON_WORKER_INSTANCE_ID_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_INSTANCE_ID\";\nexport const DAEMON_WORKER_ACTIVE_SESSION_ID_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_ACTIVE_SESSION_ID\";\nexport const DAEMON_WORKER_SUPERVISOR_SOCKET_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_SUPERVISOR_SOCKET\";\nexport const DAEMON_WORKER_RECOVERY_JOURNAL_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_RECOVERY_JOURNAL\";\nexport const DAEMON_WORKER_STARTUP_GATE_FD_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_STARTUP_GATE_FD\";\nexport const DAEMON_WORKER_STARTUP_GATE_COMMIT = \"start\\n\";\nexport type DaemonWorkerLifecycle = \"starting\" | \"ready\" | \"recovering\" | \"stopping\" | \"failed\";\n\n// Worker->supervisor roster frames live outside the client-facing DaemonOutbound schema.\nexport type DaemonWorkerRosterOutbound =\n\t| {\n\t\t\ttype: \"roster_delta\";\n\t\t\tentries: WorkerRosterEntry[];\n\t\t\tremovedAgentIds?: string[];\n\t\t\tsnapshot?: true;\n\t }\n\t| { type: \"roster_heartbeat\" };\n\n/** Advertised by new workers in the worker_auth response; absent on legacy workers. */\nexport const DAEMON_WORKER_ROSTER_CAPABILITY = \"agent_roster\";\n\n/** Advertised in the worker_auth response by workers that accept peer transport grants. */\nexport const DAEMON_WORKER_PEER_TRANSPORT_CAPABILITY = \"peer_transport\";\n\n/** Idle keepalive cadence for worker->supervisor roster frames; the supervisor staleness threshold derives from it. */\nexport const ROSTER_HEARTBEAT_INTERVAL_MS = 15_000;\n\nexport type DaemonWorkerFrameHeader =\n\t| {\n\t\t\tkind: \"command\";\n\t\t\trequestId: string;\n\t\t\tcommandType: string;\n\t }\n\t| {\n\t\t\tkind: \"outbound\";\n\t\t\trequestId?: string;\n\t\t\toutboundType: DaemonOutbound[\"type\"] | DaemonWorkerRosterOutbound[\"type\"];\n\t\t\tactiveSessionId?: string;\n\t\t\tsnapshotId?: string;\n\t\t\tsessionEventType?: string;\n\t\t\tpayloadEncoding?: \"jsonl\" | \"assistant-delta\";\n\t\t\tsnapshotPurpose?: \"attach\" | \"replacement\" | \"catchup\";\n\t };\n\nexport type DaemonCreateCommand = Extract<DaemonCommand, { type: \"create\" }>;\n\nexport interface DurableDaemonCreateCommand {\n\ttype: \"create\";\n\tsessionPath?: string;\n\tnoSession?: boolean;\n}\n\nexport function durableDaemonCreateCommand(command: DaemonCreateCommand): DurableDaemonCreateCommand {\n\treturn {\n\t\ttype: \"create\",\n\t\t...(command.sessionPath !== undefined ? { sessionPath: command.sessionPath } : {}),\n\t\t...(command.noSession !== undefined ? { noSession: command.noSession } : {}),\n\t};\n}\n\n/**\n * A single-use, worker-memory-only admission for one direct peer, scoped to one active-session\n * slot (stable across switch_session/new_session/fork) of one worker incarnation. The session pin\n * is a routing/accident guard, not a privilege boundary: ticket holders already hold supervisor\n * access, which can attach to, switch, or kill any session.\n */\nexport interface DaemonWorkerPeerGrant {\n\tgrantId: string;\n\ttoken: string;\n\texpiresAt: string;\n\tpurpose: \"session_client\";\n\tworkerInstanceId: string;\n\tactiveSessionId: string;\n\tissuerGeneration: string;\n}\n\n/** Commands a direct peer may send before it holds an authenticated session role. */\nexport type DaemonPeerCommand = {\n\tid?: string;\n\ttype: \"peer_auth\";\n\tgrantId: string;\n\ttoken: string;\n\tworkerInstanceId: string;\n\tpurpose: \"session_client\";\n};\n\nexport type DaemonPeerCommandBody = Omit<DaemonPeerCommand, \"id\">;\n\nexport type DaemonWorkerCommand =\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_auth\";\n\t\t\ttoken: string;\n\t\t\tworkerInstanceId?: string;\n\t\t\tsupervisorGeneration: string;\n\t\t\tsupervisorPid: number;\n\t\t\tsupervisorProcessStartId?: string;\n\t\t\tsupervisorSocketPath: string;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_subscribe\";\n\t\t\tactiveSessionId: string;\n\t\t\tcapabilities?: readonly DaemonClientCapability[];\n\t\t\tsupportsExtensionUi?: boolean;\n\t }\n\t| { id?: string; type: \"worker_unsubscribe\"; activeSessionId: string }\n\t| { id?: string; type: \"worker_register_peer_transport\"; grant: DaemonWorkerPeerGrant }\n\t| { id?: string; type: \"worker_archive_and_shutdown\" }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_passivate_idle_children\";\n\t\t\tidleEvictionMinutes: IdleEvictionMinutes;\n\t\t\tnow: number;\n\t\t\tlimit: number;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_deliver_message\";\n\t\t\ttargetActiveSessionId: string;\n\t\t\tmessage: string;\n\t\t\tsender: AgentSessionMessageSender;\n\t\t\tdeliveryMode?: AgentSessionMessageDeliveryMode;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_deliver_result\";\n\t\t\ttargetActiveSessionId: string;\n\t\t\tsummary: string;\n\t\t\tfindings: string;\n\t\t\tsender: AgentSessionMessageSender;\n\t\t\tdeliveryMode?: AgentSessionMessageDeliveryMode;\n\t }\n\t| { id?: string; type: \"worker_prepare_update\" }\n\t| { id?: string; type: \"worker_commit_update\" }\n\t| { id?: string; type: \"worker_cancel_update\" };\n\nexport type DaemonWorkerCommandBody = DaemonWorkerCommand extends infer TCommand\n\t? TCommand extends { id?: string }\n\t\t? Omit<TCommand, \"id\">\n\t\t: never\n\t: never;\n\nexport interface DaemonWorkerDescriptor {\n\tversion: 1 | 2;\n\tworkerId: string;\n\tpid: number;\n\tprocessStartId?: string;\n\tsocketPath: string;\n\trecoveryJournalPath: string;\n\torphanProcessJournalPath?: string;\n\tsupervisorSocketPath: string;\n\tauthenticationToken: string;\n\tworkerInstanceId?: string;\n\trootActiveSessionId: string;\n\t/** Stable protocol client that owns this worker. Omitted for resident sessions. */\n\townerClientId?: string;\n\trootSessionId?: string;\n\tsessionFile?: string;\n\tsessionDir?: string;\n\ttelemetryDisabled?: true;\n\tcreatedAt: string;\n\tupdatedAt: string;\n\tlifecycle: DaemonWorkerLifecycle;\n\tcreateCommand: DurableDaemonCreateCommand;\n\tconsecutiveFailures: number;\n\t/** Durable intent written before root termination so replacement supervisors never recover it. */\n\tstopRequestedAt?: string;\n\t/** Complete the root's archived lifecycle state after its process has stopped. */\n\tarchiveOnStop?: boolean;\n\tlastFailureAt?: string;\n\tlastError?: string;\n}\n\nexport function durableDaemonWorkerDescriptor(descriptor: DaemonWorkerDescriptor): DaemonWorkerDescriptor {\n\tconst versionOneCreateCommand = descriptor.createCommand as unknown as { config?: unknown };\n\tconst versionOneConfig =\n\t\tdescriptor.version === 1 &&\n\t\ttypeof versionOneCreateCommand.config === \"object\" &&\n\t\tversionOneCreateCommand.config !== null\n\t\t\t? (versionOneCreateCommand.config as Record<string, unknown>)\n\t\t\t: undefined;\n\tconst sessionDir =\n\t\tdescriptor.sessionDir ??\n\t\t(typeof versionOneConfig?.sessionDir === \"string\" ? versionOneConfig.sessionDir : undefined);\n\tconst telemetryDisabled = descriptor.telemetryDisabled === true || versionOneConfig?.telemetryDisabled === true;\n\treturn {\n\t\tversion: 2,\n\t\tworkerId: descriptor.workerId,\n\t\tpid: descriptor.pid,\n\t\t...(descriptor.processStartId !== undefined ? { processStartId: descriptor.processStartId } : {}),\n\t\tsocketPath: descriptor.socketPath,\n\t\trecoveryJournalPath: descriptor.recoveryJournalPath,\n\t\t...(descriptor.orphanProcessJournalPath !== undefined\n\t\t\t? { orphanProcessJournalPath: descriptor.orphanProcessJournalPath }\n\t\t\t: {}),\n\t\tsupervisorSocketPath: descriptor.supervisorSocketPath,\n\t\tauthenticationToken: descriptor.authenticationToken,\n\t\t...(descriptor.workerInstanceId !== undefined ? { workerInstanceId: descriptor.workerInstanceId } : {}),\n\t\trootActiveSessionId: descriptor.rootActiveSessionId,\n\t\t...(descriptor.ownerClientId !== undefined ? { ownerClientId: descriptor.ownerClientId } : {}),\n\t\t...(descriptor.rootSessionId !== undefined ? { rootSessionId: descriptor.rootSessionId } : {}),\n\t\t...(descriptor.sessionFile !== undefined ? { sessionFile: descriptor.sessionFile } : {}),\n\t\t...(sessionDir !== undefined ? { sessionDir } : {}),\n\t\t...(telemetryDisabled ? { telemetryDisabled: true as const } : {}),\n\t\tcreatedAt: descriptor.createdAt,\n\t\tupdatedAt: descriptor.updatedAt,\n\t\tlifecycle: descriptor.lifecycle,\n\t\tcreateCommand: durableDaemonCreateCommand(descriptor.createCommand),\n\t\tconsecutiveFailures: descriptor.consecutiveFailures,\n\t\t...(descriptor.stopRequestedAt !== undefined ? { stopRequestedAt: descriptor.stopRequestedAt } : {}),\n\t\t...(descriptor.archiveOnStop !== undefined ? { archiveOnStop: descriptor.archiveOnStop } : {}),\n\t\t...(descriptor.lastFailureAt !== undefined ? { lastFailureAt: descriptor.lastFailureAt } : {}),\n\t\t...(descriptor.lifecycle === \"failed\" ? { lastError: \"Waiting for a client with fresh runtime context\" } : {}),\n\t};\n}\n\nexport function isDaemonWorkerProcess(environment: NodeJS.ProcessEnv = process.env): boolean {\n\treturn environment[DAEMON_WORKER_ROLE_ENV] === \"1\";\n}\n\nexport function waitForDaemonWorkerStartupGate(environment: NodeJS.ProcessEnv = process.env): void {\n\tconst rawFd = environment[DAEMON_WORKER_STARTUP_GATE_FD_ENV];\n\tif (rawFd === undefined) {\n\t\treturn;\n\t}\n\tdelete environment[DAEMON_WORKER_STARTUP_GATE_FD_ENV];\n\tconst fd = Number(rawFd);\n\tif (!Number.isInteger(fd) || fd < 3) {\n\t\tthrow new Error(\"Daemon session worker has an invalid startup gate\");\n\t}\n\tlet marker: string;\n\ttry {\n\t\tmarker = readFileSync(fd, \"utf8\");\n\t} finally {\n\t\tcloseSync(fd);\n\t}\n\tif (marker !== DAEMON_WORKER_STARTUP_GATE_COMMIT) {\n\t\tthrow new Error(\"Daemon session worker startup was cancelled\");\n\t}\n}\n\nexport function daemonWorkerInstanceId(environment: NodeJS.ProcessEnv = process.env): string | undefined {\n\treturn environment[DAEMON_WORKER_INSTANCE_ID_ENV] || undefined;\n}\n\nexport function requireDaemonWorkerAuthenticationToken(environment: NodeJS.ProcessEnv = process.env): string {\n\tconst token = environment[DAEMON_WORKER_TOKEN_ENV];\n\tif (!token) {\n\t\tthrow new Error(\"Daemon session worker is missing its authentication token\");\n\t}\n\treturn token;\n}\n\nexport function isDaemonWorkerFrameHeader(value: unknown): value is DaemonWorkerFrameHeader {\n\tif (!value || typeof value !== \"object\") {\n\t\treturn false;\n\t}\n\tconst candidate = value as Record<string, unknown>;\n\tif (candidate.kind === \"command\") {\n\t\treturn typeof candidate.requestId === \"string\" && typeof candidate.commandType === \"string\";\n\t}\n\treturn (\n\t\tcandidate.kind === \"outbound\" &&\n\t\ttypeof candidate.outboundType === \"string\" &&\n\t\t(candidate.requestId === undefined || typeof candidate.requestId === \"string\") &&\n\t\t(candidate.activeSessionId === undefined || typeof candidate.activeSessionId === \"string\") &&\n\t\t(candidate.snapshotId === undefined || typeof candidate.snapshotId === \"string\") &&\n\t\t(candidate.sessionEventType === undefined || typeof candidate.sessionEventType === \"string\") &&\n\t\t(candidate.snapshotPurpose === undefined ||\n\t\t\tcandidate.snapshotPurpose === \"attach\" ||\n\t\t\tcandidate.snapshotPurpose === \"replacement\" ||\n\t\t\tcandidate.snapshotPurpose === \"catchup\") &&\n\t\t(candidate.payloadEncoding === undefined ||\n\t\t\tcandidate.payloadEncoding === \"jsonl\" ||\n\t\t\tcandidate.payloadEncoding === \"assistant-delta\")\n\t);\n}\n"]}
1
+ {"version":3,"file":"daemon-worker-protocol.d.ts","sourceRoot":"","sources":["../../../src/modes/daemon/daemon-worker-protocol.ts"],"names":[],"mappings":"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","sourcesContent":["import { closeSync, readFileSync } from \"node:fs\";\nimport type { AgentSessionMessageDeliveryMode, AgentSessionMessageSender } from \"../../core/agent-messages.js\";\nimport type { IdleEvictionMinutes } from \"../../core/session-action-store.js\";\n\nexport { SESSION_LEASE_OWNER_ID_ENV, SESSION_LEASES_ENABLED_ENV } from \"../../core/session-lease.js\";\n\nimport type { WorkerRosterEntry } from \"./agent-roster.js\";\nimport type { DaemonClientCapability, DaemonCommand, DaemonOutbound } from \"./daemon-protocol.js\";\n\nexport const DAEMON_WORKER_ROLE_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER\";\nexport const DAEMON_WORKER_TOKEN_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_TOKEN\";\nexport const DAEMON_WORKER_INSTANCE_ID_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_INSTANCE_ID\";\nexport const DAEMON_WORKER_ACTIVE_SESSION_ID_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_ACTIVE_SESSION_ID\";\nexport const DAEMON_WORKER_SUPERVISOR_SOCKET_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_SUPERVISOR_SOCKET\";\nexport const DAEMON_WORKER_RECOVERY_JOURNAL_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_RECOVERY_JOURNAL\";\nexport const DAEMON_WORKER_STARTUP_GATE_FD_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_STARTUP_GATE_FD\";\nexport const DAEMON_WORKER_STARTUP_GATE_COMMIT = \"start\\n\";\nexport type DaemonWorkerLifecycle = \"starting\" | \"ready\" | \"recovering\" | \"stopping\" | \"failed\";\n\n// Worker->supervisor roster frames live outside the client-facing DaemonOutbound schema.\nexport type DaemonWorkerRosterOutbound =\n\t| {\n\t\t\ttype: \"roster_delta\";\n\t\t\tentries: WorkerRosterEntry[];\n\t\t\tremovedAgentIds?: string[];\n\t\t\tsnapshot?: true;\n\t }\n\t| { type: \"roster_heartbeat\" };\n\n/** Advertised by new workers in the worker_auth response; absent on legacy workers. */\nexport const DAEMON_WORKER_ROSTER_CAPABILITY = \"agent_roster\";\n\n/** Advertised in the worker_auth response by workers that accept peer transport grants. */\nexport const DAEMON_WORKER_PEER_TRANSPORT_CAPABILITY = \"peer_transport\";\n\n/** Idle keepalive cadence for worker->supervisor roster frames; the supervisor staleness threshold derives from it. */\nexport const ROSTER_HEARTBEAT_INTERVAL_MS = 15_000;\n\nexport type DaemonWorkerFrameHeader =\n\t| {\n\t\t\tkind: \"command\";\n\t\t\trequestId: string;\n\t\t\tcommandType: string;\n\t }\n\t| {\n\t\t\tkind: \"outbound\";\n\t\t\trequestId?: string;\n\t\t\toutboundType: DaemonOutbound[\"type\"] | DaemonWorkerRosterOutbound[\"type\"];\n\t\t\tactiveSessionId?: string;\n\t\t\tsnapshotId?: string;\n\t\t\tsessionEventType?: string;\n\t\t\tpayloadEncoding?: \"jsonl\" | \"assistant-delta\";\n\t\t\tsnapshotPurpose?: \"attach\" | \"replacement\" | \"catchup\";\n\t };\n\nexport interface DaemonRlmCapacityOrigin {\n\tsessionFile?: string;\n\tsessionId: string;\n}\n\nexport type DaemonRlmCapacityOperation =\n\t| (DaemonRlmCapacityOrigin & { op: \"status\" })\n\t| (DaemonRlmCapacityOrigin & { op: \"set\"; maxSubagents: number })\n\t| (DaemonRlmCapacityOrigin & { op: \"reserve\"; reservationId: string; residentRoot?: true })\n\t| { op: \"release\"; reservationId: string };\n\nexport interface DaemonRlmCapacityReservation extends DaemonRlmCapacityOrigin {\n\treservationId: string;\n\tresidentRoot?: true;\n}\n\nexport interface DaemonRlmCapacitySnapshot {\n\treservations: DaemonRlmCapacityReservation[];\n}\n\nexport function isDaemonRlmCapacitySnapshot(value: unknown): value is DaemonRlmCapacitySnapshot {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t\"reservations\" in value &&\n\t\tArray.isArray(value.reservations) &&\n\t\tvalue.reservations.every(\n\t\t\t(entry: unknown) =>\n\t\t\t\ttypeof entry === \"object\" &&\n\t\t\t\tentry !== null &&\n\t\t\t\t\"reservationId\" in entry &&\n\t\t\t\ttypeof entry.reservationId === \"string\" &&\n\t\t\t\tentry.reservationId.length > 0 &&\n\t\t\t\t\"sessionId\" in entry &&\n\t\t\t\ttypeof entry.sessionId === \"string\" &&\n\t\t\t\tentry.sessionId.length > 0 &&\n\t\t\t\t(!(\"sessionFile\" in entry) || entry.sessionFile === undefined || typeof entry.sessionFile === \"string\") &&\n\t\t\t\t(!(\"residentRoot\" in entry) || entry.residentRoot === undefined || entry.residentRoot === true),\n\t\t)\n\t);\n}\n\nexport type DaemonCreateCommand = Extract<DaemonCommand, { type: \"create\" }>;\n\nexport interface DurableDaemonCreateCommand {\n\ttype: \"create\";\n\tsessionPath?: string;\n\tnoSession?: boolean;\n}\n\nexport function durableDaemonCreateCommand(command: DaemonCreateCommand): DurableDaemonCreateCommand {\n\treturn {\n\t\ttype: \"create\",\n\t\t...(command.sessionPath !== undefined ? { sessionPath: command.sessionPath } : {}),\n\t\t...(command.noSession !== undefined ? { noSession: command.noSession } : {}),\n\t};\n}\n\n/**\n * A single-use, worker-memory-only admission for one direct peer, scoped to one active-session\n * slot (stable across switch_session/new_session/fork) of one worker incarnation. The session pin\n * is a routing/accident guard, not a privilege boundary: ticket holders already hold supervisor\n * access, which can attach to, switch, or kill any session.\n */\nexport interface DaemonWorkerPeerGrant {\n\tgrantId: string;\n\ttoken: string;\n\texpiresAt: string;\n\tpurpose: \"session_client\";\n\tworkerInstanceId: string;\n\tactiveSessionId: string;\n\tissuerGeneration: string;\n}\n\n/** Commands a direct peer may send before it holds an authenticated session role. */\nexport type DaemonPeerCommand = {\n\tid?: string;\n\ttype: \"peer_auth\";\n\tgrantId: string;\n\ttoken: string;\n\tworkerInstanceId: string;\n\tpurpose: \"session_client\";\n};\n\nexport type DaemonPeerCommandBody = Omit<DaemonPeerCommand, \"id\">;\n\nexport type DaemonWorkerCommand =\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_auth\";\n\t\t\ttoken: string;\n\t\t\tworkerInstanceId?: string;\n\t\t\tsupervisorGeneration: string;\n\t\t\tsupervisorPid: number;\n\t\t\tsupervisorProcessStartId?: string;\n\t\t\tsupervisorSocketPath: string;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_subscribe\";\n\t\t\tactiveSessionId: string;\n\t\t\tcapabilities?: readonly DaemonClientCapability[];\n\t\t\tsupportsExtensionUi?: boolean;\n\t }\n\t| { id?: string; type: \"worker_unsubscribe\"; activeSessionId: string }\n\t| { id?: string; type: \"worker_register_peer_transport\"; grant: DaemonWorkerPeerGrant }\n\t| { id?: string; type: \"worker_archive_and_shutdown\" }\n\t| { id?: string; type: \"worker_get_rlm_capacity\" }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_passivate_idle_children\";\n\t\t\tidleEvictionMinutes: IdleEvictionMinutes;\n\t\t\tnow: number;\n\t\t\tlimit: number;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_deliver_message\";\n\t\t\ttargetActiveSessionId: string;\n\t\t\tmessage: string;\n\t\t\tsender: AgentSessionMessageSender;\n\t\t\tdeliveryMode?: AgentSessionMessageDeliveryMode;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_deliver_result\";\n\t\t\ttargetActiveSessionId: string;\n\t\t\tsummary: string;\n\t\t\tfindings: string;\n\t\t\tsender: AgentSessionMessageSender;\n\t\t\tdeliveryMode?: AgentSessionMessageDeliveryMode;\n\t }\n\t| { id?: string; type: \"worker_prepare_update\" }\n\t| { id?: string; type: \"worker_commit_update\" }\n\t| { id?: string; type: \"worker_cancel_update\" };\n\nexport type DaemonWorkerCommandBody = DaemonWorkerCommand extends infer TCommand\n\t? TCommand extends { id?: string }\n\t\t? Omit<TCommand, \"id\">\n\t\t: never\n\t: never;\n\nexport interface DaemonWorkerDescriptor {\n\tversion: 1 | 2;\n\tworkerId: string;\n\tpid: number;\n\tprocessStartId?: string;\n\tsocketPath: string;\n\trecoveryJournalPath: string;\n\torphanProcessJournalPath?: string;\n\tsupervisorSocketPath: string;\n\tauthenticationToken: string;\n\tworkerInstanceId?: string;\n\trootActiveSessionId: string;\n\t/** Stable protocol client that owns this worker. Omitted for resident sessions. */\n\townerClientId?: string;\n\trootSessionId?: string;\n\tsessionFile?: string;\n\tsessionDir?: string;\n\tcreatedAt: string;\n\tupdatedAt: string;\n\tlifecycle: DaemonWorkerLifecycle;\n\tcreateCommand: DurableDaemonCreateCommand;\n\tconsecutiveFailures: number;\n\t/** Durable intent written before root termination so replacement supervisors never recover it. */\n\tstopRequestedAt?: string;\n\t/** Complete the root's archived lifecycle state after its process has stopped. */\n\tarchiveOnStop?: boolean;\n\tlastFailureAt?: string;\n\tlastError?: string;\n}\n\nexport function durableDaemonWorkerDescriptor(descriptor: DaemonWorkerDescriptor): DaemonWorkerDescriptor {\n\tconst versionOneCreateCommand = descriptor.createCommand as unknown as { config?: unknown };\n\tconst versionOneConfig =\n\t\tdescriptor.version === 1 &&\n\t\ttypeof versionOneCreateCommand.config === \"object\" &&\n\t\tversionOneCreateCommand.config !== null\n\t\t\t? (versionOneCreateCommand.config as Record<string, unknown>)\n\t\t\t: undefined;\n\tconst sessionDir =\n\t\tdescriptor.sessionDir ??\n\t\t(typeof versionOneConfig?.sessionDir === \"string\" ? versionOneConfig.sessionDir : undefined);\n\treturn {\n\t\tversion: 2,\n\t\tworkerId: descriptor.workerId,\n\t\tpid: descriptor.pid,\n\t\t...(descriptor.processStartId !== undefined ? { processStartId: descriptor.processStartId } : {}),\n\t\tsocketPath: descriptor.socketPath,\n\t\trecoveryJournalPath: descriptor.recoveryJournalPath,\n\t\t...(descriptor.orphanProcessJournalPath !== undefined\n\t\t\t? { orphanProcessJournalPath: descriptor.orphanProcessJournalPath }\n\t\t\t: {}),\n\t\tsupervisorSocketPath: descriptor.supervisorSocketPath,\n\t\tauthenticationToken: descriptor.authenticationToken,\n\t\t...(descriptor.workerInstanceId !== undefined ? { workerInstanceId: descriptor.workerInstanceId } : {}),\n\t\trootActiveSessionId: descriptor.rootActiveSessionId,\n\t\t...(descriptor.ownerClientId !== undefined ? { ownerClientId: descriptor.ownerClientId } : {}),\n\t\t...(descriptor.rootSessionId !== undefined ? { rootSessionId: descriptor.rootSessionId } : {}),\n\t\t...(descriptor.sessionFile !== undefined ? { sessionFile: descriptor.sessionFile } : {}),\n\t\t...(sessionDir !== undefined ? { sessionDir } : {}),\n\t\tcreatedAt: descriptor.createdAt,\n\t\tupdatedAt: descriptor.updatedAt,\n\t\tlifecycle: descriptor.lifecycle,\n\t\tcreateCommand: durableDaemonCreateCommand(descriptor.createCommand),\n\t\tconsecutiveFailures: descriptor.consecutiveFailures,\n\t\t...(descriptor.stopRequestedAt !== undefined ? { stopRequestedAt: descriptor.stopRequestedAt } : {}),\n\t\t...(descriptor.archiveOnStop !== undefined ? { archiveOnStop: descriptor.archiveOnStop } : {}),\n\t\t...(descriptor.lastFailureAt !== undefined ? { lastFailureAt: descriptor.lastFailureAt } : {}),\n\t\t...(descriptor.lifecycle === \"failed\" ? { lastError: \"Waiting for a client with fresh runtime context\" } : {}),\n\t};\n}\n\nexport function isDaemonWorkerProcess(environment: NodeJS.ProcessEnv = process.env): boolean {\n\treturn environment[DAEMON_WORKER_ROLE_ENV] === \"1\";\n}\n\nexport function waitForDaemonWorkerStartupGate(environment: NodeJS.ProcessEnv = process.env): void {\n\tconst rawFd = environment[DAEMON_WORKER_STARTUP_GATE_FD_ENV];\n\tif (rawFd === undefined) {\n\t\treturn;\n\t}\n\tdelete environment[DAEMON_WORKER_STARTUP_GATE_FD_ENV];\n\tconst fd = Number(rawFd);\n\tif (!Number.isInteger(fd) || fd < 3) {\n\t\tthrow new Error(\"Daemon session worker has an invalid startup gate\");\n\t}\n\tlet marker: string;\n\ttry {\n\t\tmarker = readFileSync(fd, \"utf8\");\n\t} finally {\n\t\tcloseSync(fd);\n\t}\n\tif (marker !== DAEMON_WORKER_STARTUP_GATE_COMMIT) {\n\t\tthrow new Error(\"Daemon session worker startup was cancelled\");\n\t}\n}\n\nexport function daemonWorkerInstanceId(environment: NodeJS.ProcessEnv = process.env): string | undefined {\n\treturn environment[DAEMON_WORKER_INSTANCE_ID_ENV] || undefined;\n}\n\nexport function requireDaemonWorkerAuthenticationToken(environment: NodeJS.ProcessEnv = process.env): string {\n\tconst token = environment[DAEMON_WORKER_TOKEN_ENV];\n\tif (!token) {\n\t\tthrow new Error(\"Daemon session worker is missing its authentication token\");\n\t}\n\treturn token;\n}\n\nexport function isDaemonWorkerFrameHeader(value: unknown): value is DaemonWorkerFrameHeader {\n\tif (!value || typeof value !== \"object\") {\n\t\treturn false;\n\t}\n\tconst candidate = value as Record<string, unknown>;\n\tif (candidate.kind === \"command\") {\n\t\treturn typeof candidate.requestId === \"string\" && typeof candidate.commandType === \"string\";\n\t}\n\treturn (\n\t\tcandidate.kind === \"outbound\" &&\n\t\ttypeof candidate.outboundType === \"string\" &&\n\t\t(candidate.requestId === undefined || typeof candidate.requestId === \"string\") &&\n\t\t(candidate.activeSessionId === undefined || typeof candidate.activeSessionId === \"string\") &&\n\t\t(candidate.snapshotId === undefined || typeof candidate.snapshotId === \"string\") &&\n\t\t(candidate.sessionEventType === undefined || typeof candidate.sessionEventType === \"string\") &&\n\t\t(candidate.snapshotPurpose === undefined ||\n\t\t\tcandidate.snapshotPurpose === \"attach\" ||\n\t\t\tcandidate.snapshotPurpose === \"replacement\" ||\n\t\t\tcandidate.snapshotPurpose === \"catchup\") &&\n\t\t(candidate.payloadEncoding === undefined ||\n\t\t\tcandidate.payloadEncoding === \"jsonl\" ||\n\t\t\tcandidate.payloadEncoding === \"assistant-delta\")\n\t);\n}\n"]}
@@ -14,6 +14,22 @@ export const DAEMON_WORKER_ROSTER_CAPABILITY = "agent_roster";
14
14
  export const DAEMON_WORKER_PEER_TRANSPORT_CAPABILITY = "peer_transport";
15
15
  /** Idle keepalive cadence for worker->supervisor roster frames; the supervisor staleness threshold derives from it. */
16
16
  export const ROSTER_HEARTBEAT_INTERVAL_MS = 15_000;
17
+ export function isDaemonRlmCapacitySnapshot(value) {
18
+ return (typeof value === "object" &&
19
+ value !== null &&
20
+ "reservations" in value &&
21
+ Array.isArray(value.reservations) &&
22
+ value.reservations.every((entry) => typeof entry === "object" &&
23
+ entry !== null &&
24
+ "reservationId" in entry &&
25
+ typeof entry.reservationId === "string" &&
26
+ entry.reservationId.length > 0 &&
27
+ "sessionId" in entry &&
28
+ typeof entry.sessionId === "string" &&
29
+ entry.sessionId.length > 0 &&
30
+ (!("sessionFile" in entry) || entry.sessionFile === undefined || typeof entry.sessionFile === "string") &&
31
+ (!("residentRoot" in entry) || entry.residentRoot === undefined || entry.residentRoot === true)));
32
+ }
17
33
  export function durableDaemonCreateCommand(command) {
18
34
  return {
19
35
  type: "create",
@@ -30,7 +46,6 @@ export function durableDaemonWorkerDescriptor(descriptor) {
30
46
  : undefined;
31
47
  const sessionDir = descriptor.sessionDir ??
32
48
  (typeof versionOneConfig?.sessionDir === "string" ? versionOneConfig.sessionDir : undefined);
33
- const telemetryDisabled = descriptor.telemetryDisabled === true || versionOneConfig?.telemetryDisabled === true;
34
49
  return {
35
50
  version: 2,
36
51
  workerId: descriptor.workerId,
@@ -49,7 +64,6 @@ export function durableDaemonWorkerDescriptor(descriptor) {
49
64
  ...(descriptor.rootSessionId !== undefined ? { rootSessionId: descriptor.rootSessionId } : {}),
50
65
  ...(descriptor.sessionFile !== undefined ? { sessionFile: descriptor.sessionFile } : {}),
51
66
  ...(sessionDir !== undefined ? { sessionDir } : {}),
52
- ...(telemetryDisabled ? { telemetryDisabled: true } : {}),
53
67
  createdAt: descriptor.createdAt,
54
68
  updatedAt: descriptor.updatedAt,
55
69
  lifecycle: descriptor.lifecycle,
@@ -1 +1 @@
1
- {"version":3,"file":"daemon-worker-protocol.js","sourceRoot":"","sources":["../../../src/modes/daemon/daemon-worker-protocol.ts"],"names":[],"mappings":"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","sourcesContent":["import { closeSync, readFileSync } from \"node:fs\";\nimport type { AgentSessionMessageDeliveryMode, AgentSessionMessageSender } from \"../../core/agent-messages.js\";\nimport type { IdleEvictionMinutes } from \"../../core/session-action-store.js\";\n\nexport { SESSION_LEASE_OWNER_ID_ENV, SESSION_LEASES_ENABLED_ENV } from \"../../core/session-lease.js\";\n\nimport type { WorkerRosterEntry } from \"./agent-roster.js\";\nimport type { DaemonClientCapability, DaemonCommand, DaemonOutbound } from \"./daemon-protocol.js\";\n\nexport const DAEMON_WORKER_ROLE_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER\";\nexport const DAEMON_WORKER_TOKEN_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_TOKEN\";\nexport const DAEMON_WORKER_INSTANCE_ID_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_INSTANCE_ID\";\nexport const DAEMON_WORKER_ACTIVE_SESSION_ID_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_ACTIVE_SESSION_ID\";\nexport const DAEMON_WORKER_SUPERVISOR_SOCKET_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_SUPERVISOR_SOCKET\";\nexport const DAEMON_WORKER_RECOVERY_JOURNAL_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_RECOVERY_JOURNAL\";\nexport const DAEMON_WORKER_STARTUP_GATE_FD_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_STARTUP_GATE_FD\";\nexport const DAEMON_WORKER_STARTUP_GATE_COMMIT = \"start\\n\";\nexport type DaemonWorkerLifecycle = \"starting\" | \"ready\" | \"recovering\" | \"stopping\" | \"failed\";\n\n// Worker->supervisor roster frames live outside the client-facing DaemonOutbound schema.\nexport type DaemonWorkerRosterOutbound =\n\t| {\n\t\t\ttype: \"roster_delta\";\n\t\t\tentries: WorkerRosterEntry[];\n\t\t\tremovedAgentIds?: string[];\n\t\t\tsnapshot?: true;\n\t }\n\t| { type: \"roster_heartbeat\" };\n\n/** Advertised by new workers in the worker_auth response; absent on legacy workers. */\nexport const DAEMON_WORKER_ROSTER_CAPABILITY = \"agent_roster\";\n\n/** Advertised in the worker_auth response by workers that accept peer transport grants. */\nexport const DAEMON_WORKER_PEER_TRANSPORT_CAPABILITY = \"peer_transport\";\n\n/** Idle keepalive cadence for worker->supervisor roster frames; the supervisor staleness threshold derives from it. */\nexport const ROSTER_HEARTBEAT_INTERVAL_MS = 15_000;\n\nexport type DaemonWorkerFrameHeader =\n\t| {\n\t\t\tkind: \"command\";\n\t\t\trequestId: string;\n\t\t\tcommandType: string;\n\t }\n\t| {\n\t\t\tkind: \"outbound\";\n\t\t\trequestId?: string;\n\t\t\toutboundType: DaemonOutbound[\"type\"] | DaemonWorkerRosterOutbound[\"type\"];\n\t\t\tactiveSessionId?: string;\n\t\t\tsnapshotId?: string;\n\t\t\tsessionEventType?: string;\n\t\t\tpayloadEncoding?: \"jsonl\" | \"assistant-delta\";\n\t\t\tsnapshotPurpose?: \"attach\" | \"replacement\" | \"catchup\";\n\t };\n\nexport type DaemonCreateCommand = Extract<DaemonCommand, { type: \"create\" }>;\n\nexport interface DurableDaemonCreateCommand {\n\ttype: \"create\";\n\tsessionPath?: string;\n\tnoSession?: boolean;\n}\n\nexport function durableDaemonCreateCommand(command: DaemonCreateCommand): DurableDaemonCreateCommand {\n\treturn {\n\t\ttype: \"create\",\n\t\t...(command.sessionPath !== undefined ? { sessionPath: command.sessionPath } : {}),\n\t\t...(command.noSession !== undefined ? { noSession: command.noSession } : {}),\n\t};\n}\n\n/**\n * A single-use, worker-memory-only admission for one direct peer, scoped to one active-session\n * slot (stable across switch_session/new_session/fork) of one worker incarnation. The session pin\n * is a routing/accident guard, not a privilege boundary: ticket holders already hold supervisor\n * access, which can attach to, switch, or kill any session.\n */\nexport interface DaemonWorkerPeerGrant {\n\tgrantId: string;\n\ttoken: string;\n\texpiresAt: string;\n\tpurpose: \"session_client\";\n\tworkerInstanceId: string;\n\tactiveSessionId: string;\n\tissuerGeneration: string;\n}\n\n/** Commands a direct peer may send before it holds an authenticated session role. */\nexport type DaemonPeerCommand = {\n\tid?: string;\n\ttype: \"peer_auth\";\n\tgrantId: string;\n\ttoken: string;\n\tworkerInstanceId: string;\n\tpurpose: \"session_client\";\n};\n\nexport type DaemonPeerCommandBody = Omit<DaemonPeerCommand, \"id\">;\n\nexport type DaemonWorkerCommand =\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_auth\";\n\t\t\ttoken: string;\n\t\t\tworkerInstanceId?: string;\n\t\t\tsupervisorGeneration: string;\n\t\t\tsupervisorPid: number;\n\t\t\tsupervisorProcessStartId?: string;\n\t\t\tsupervisorSocketPath: string;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_subscribe\";\n\t\t\tactiveSessionId: string;\n\t\t\tcapabilities?: readonly DaemonClientCapability[];\n\t\t\tsupportsExtensionUi?: boolean;\n\t }\n\t| { id?: string; type: \"worker_unsubscribe\"; activeSessionId: string }\n\t| { id?: string; type: \"worker_register_peer_transport\"; grant: DaemonWorkerPeerGrant }\n\t| { id?: string; type: \"worker_archive_and_shutdown\" }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_passivate_idle_children\";\n\t\t\tidleEvictionMinutes: IdleEvictionMinutes;\n\t\t\tnow: number;\n\t\t\tlimit: number;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_deliver_message\";\n\t\t\ttargetActiveSessionId: string;\n\t\t\tmessage: string;\n\t\t\tsender: AgentSessionMessageSender;\n\t\t\tdeliveryMode?: AgentSessionMessageDeliveryMode;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_deliver_result\";\n\t\t\ttargetActiveSessionId: string;\n\t\t\tsummary: string;\n\t\t\tfindings: string;\n\t\t\tsender: AgentSessionMessageSender;\n\t\t\tdeliveryMode?: AgentSessionMessageDeliveryMode;\n\t }\n\t| { id?: string; type: \"worker_prepare_update\" }\n\t| { id?: string; type: \"worker_commit_update\" }\n\t| { id?: string; type: \"worker_cancel_update\" };\n\nexport type DaemonWorkerCommandBody = DaemonWorkerCommand extends infer TCommand\n\t? TCommand extends { id?: string }\n\t\t? Omit<TCommand, \"id\">\n\t\t: never\n\t: never;\n\nexport interface DaemonWorkerDescriptor {\n\tversion: 1 | 2;\n\tworkerId: string;\n\tpid: number;\n\tprocessStartId?: string;\n\tsocketPath: string;\n\trecoveryJournalPath: string;\n\torphanProcessJournalPath?: string;\n\tsupervisorSocketPath: string;\n\tauthenticationToken: string;\n\tworkerInstanceId?: string;\n\trootActiveSessionId: string;\n\t/** Stable protocol client that owns this worker. Omitted for resident sessions. */\n\townerClientId?: string;\n\trootSessionId?: string;\n\tsessionFile?: string;\n\tsessionDir?: string;\n\ttelemetryDisabled?: true;\n\tcreatedAt: string;\n\tupdatedAt: string;\n\tlifecycle: DaemonWorkerLifecycle;\n\tcreateCommand: DurableDaemonCreateCommand;\n\tconsecutiveFailures: number;\n\t/** Durable intent written before root termination so replacement supervisors never recover it. */\n\tstopRequestedAt?: string;\n\t/** Complete the root's archived lifecycle state after its process has stopped. */\n\tarchiveOnStop?: boolean;\n\tlastFailureAt?: string;\n\tlastError?: string;\n}\n\nexport function durableDaemonWorkerDescriptor(descriptor: DaemonWorkerDescriptor): DaemonWorkerDescriptor {\n\tconst versionOneCreateCommand = descriptor.createCommand as unknown as { config?: unknown };\n\tconst versionOneConfig =\n\t\tdescriptor.version === 1 &&\n\t\ttypeof versionOneCreateCommand.config === \"object\" &&\n\t\tversionOneCreateCommand.config !== null\n\t\t\t? (versionOneCreateCommand.config as Record<string, unknown>)\n\t\t\t: undefined;\n\tconst sessionDir =\n\t\tdescriptor.sessionDir ??\n\t\t(typeof versionOneConfig?.sessionDir === \"string\" ? versionOneConfig.sessionDir : undefined);\n\tconst telemetryDisabled = descriptor.telemetryDisabled === true || versionOneConfig?.telemetryDisabled === true;\n\treturn {\n\t\tversion: 2,\n\t\tworkerId: descriptor.workerId,\n\t\tpid: descriptor.pid,\n\t\t...(descriptor.processStartId !== undefined ? { processStartId: descriptor.processStartId } : {}),\n\t\tsocketPath: descriptor.socketPath,\n\t\trecoveryJournalPath: descriptor.recoveryJournalPath,\n\t\t...(descriptor.orphanProcessJournalPath !== undefined\n\t\t\t? { orphanProcessJournalPath: descriptor.orphanProcessJournalPath }\n\t\t\t: {}),\n\t\tsupervisorSocketPath: descriptor.supervisorSocketPath,\n\t\tauthenticationToken: descriptor.authenticationToken,\n\t\t...(descriptor.workerInstanceId !== undefined ? { workerInstanceId: descriptor.workerInstanceId } : {}),\n\t\trootActiveSessionId: descriptor.rootActiveSessionId,\n\t\t...(descriptor.ownerClientId !== undefined ? { ownerClientId: descriptor.ownerClientId } : {}),\n\t\t...(descriptor.rootSessionId !== undefined ? { rootSessionId: descriptor.rootSessionId } : {}),\n\t\t...(descriptor.sessionFile !== undefined ? { sessionFile: descriptor.sessionFile } : {}),\n\t\t...(sessionDir !== undefined ? { sessionDir } : {}),\n\t\t...(telemetryDisabled ? { telemetryDisabled: true as const } : {}),\n\t\tcreatedAt: descriptor.createdAt,\n\t\tupdatedAt: descriptor.updatedAt,\n\t\tlifecycle: descriptor.lifecycle,\n\t\tcreateCommand: durableDaemonCreateCommand(descriptor.createCommand),\n\t\tconsecutiveFailures: descriptor.consecutiveFailures,\n\t\t...(descriptor.stopRequestedAt !== undefined ? { stopRequestedAt: descriptor.stopRequestedAt } : {}),\n\t\t...(descriptor.archiveOnStop !== undefined ? { archiveOnStop: descriptor.archiveOnStop } : {}),\n\t\t...(descriptor.lastFailureAt !== undefined ? { lastFailureAt: descriptor.lastFailureAt } : {}),\n\t\t...(descriptor.lifecycle === \"failed\" ? { lastError: \"Waiting for a client with fresh runtime context\" } : {}),\n\t};\n}\n\nexport function isDaemonWorkerProcess(environment: NodeJS.ProcessEnv = process.env): boolean {\n\treturn environment[DAEMON_WORKER_ROLE_ENV] === \"1\";\n}\n\nexport function waitForDaemonWorkerStartupGate(environment: NodeJS.ProcessEnv = process.env): void {\n\tconst rawFd = environment[DAEMON_WORKER_STARTUP_GATE_FD_ENV];\n\tif (rawFd === undefined) {\n\t\treturn;\n\t}\n\tdelete environment[DAEMON_WORKER_STARTUP_GATE_FD_ENV];\n\tconst fd = Number(rawFd);\n\tif (!Number.isInteger(fd) || fd < 3) {\n\t\tthrow new Error(\"Daemon session worker has an invalid startup gate\");\n\t}\n\tlet marker: string;\n\ttry {\n\t\tmarker = readFileSync(fd, \"utf8\");\n\t} finally {\n\t\tcloseSync(fd);\n\t}\n\tif (marker !== DAEMON_WORKER_STARTUP_GATE_COMMIT) {\n\t\tthrow new Error(\"Daemon session worker startup was cancelled\");\n\t}\n}\n\nexport function daemonWorkerInstanceId(environment: NodeJS.ProcessEnv = process.env): string | undefined {\n\treturn environment[DAEMON_WORKER_INSTANCE_ID_ENV] || undefined;\n}\n\nexport function requireDaemonWorkerAuthenticationToken(environment: NodeJS.ProcessEnv = process.env): string {\n\tconst token = environment[DAEMON_WORKER_TOKEN_ENV];\n\tif (!token) {\n\t\tthrow new Error(\"Daemon session worker is missing its authentication token\");\n\t}\n\treturn token;\n}\n\nexport function isDaemonWorkerFrameHeader(value: unknown): value is DaemonWorkerFrameHeader {\n\tif (!value || typeof value !== \"object\") {\n\t\treturn false;\n\t}\n\tconst candidate = value as Record<string, unknown>;\n\tif (candidate.kind === \"command\") {\n\t\treturn typeof candidate.requestId === \"string\" && typeof candidate.commandType === \"string\";\n\t}\n\treturn (\n\t\tcandidate.kind === \"outbound\" &&\n\t\ttypeof candidate.outboundType === \"string\" &&\n\t\t(candidate.requestId === undefined || typeof candidate.requestId === \"string\") &&\n\t\t(candidate.activeSessionId === undefined || typeof candidate.activeSessionId === \"string\") &&\n\t\t(candidate.snapshotId === undefined || typeof candidate.snapshotId === \"string\") &&\n\t\t(candidate.sessionEventType === undefined || typeof candidate.sessionEventType === \"string\") &&\n\t\t(candidate.snapshotPurpose === undefined ||\n\t\t\tcandidate.snapshotPurpose === \"attach\" ||\n\t\t\tcandidate.snapshotPurpose === \"replacement\" ||\n\t\t\tcandidate.snapshotPurpose === \"catchup\") &&\n\t\t(candidate.payloadEncoding === undefined ||\n\t\t\tcandidate.payloadEncoding === \"jsonl\" ||\n\t\t\tcandidate.payloadEncoding === \"assistant-delta\")\n\t);\n}\n"]}
1
+ {"version":3,"file":"daemon-worker-protocol.js","sourceRoot":"","sources":["../../../src/modes/daemon/daemon-worker-protocol.ts"],"names":[],"mappings":"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","sourcesContent":["import { closeSync, readFileSync } from \"node:fs\";\nimport type { AgentSessionMessageDeliveryMode, AgentSessionMessageSender } from \"../../core/agent-messages.js\";\nimport type { IdleEvictionMinutes } from \"../../core/session-action-store.js\";\n\nexport { SESSION_LEASE_OWNER_ID_ENV, SESSION_LEASES_ENABLED_ENV } from \"../../core/session-lease.js\";\n\nimport type { WorkerRosterEntry } from \"./agent-roster.js\";\nimport type { DaemonClientCapability, DaemonCommand, DaemonOutbound } from \"./daemon-protocol.js\";\n\nexport const DAEMON_WORKER_ROLE_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER\";\nexport const DAEMON_WORKER_TOKEN_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_TOKEN\";\nexport const DAEMON_WORKER_INSTANCE_ID_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_INSTANCE_ID\";\nexport const DAEMON_WORKER_ACTIVE_SESSION_ID_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_ACTIVE_SESSION_ID\";\nexport const DAEMON_WORKER_SUPERVISOR_SOCKET_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_SUPERVISOR_SOCKET\";\nexport const DAEMON_WORKER_RECOVERY_JOURNAL_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_RECOVERY_JOURNAL\";\nexport const DAEMON_WORKER_STARTUP_GATE_FD_ENV = \"BASE_CONTEXT_INTERNAL_DAEMON_WORKER_STARTUP_GATE_FD\";\nexport const DAEMON_WORKER_STARTUP_GATE_COMMIT = \"start\\n\";\nexport type DaemonWorkerLifecycle = \"starting\" | \"ready\" | \"recovering\" | \"stopping\" | \"failed\";\n\n// Worker->supervisor roster frames live outside the client-facing DaemonOutbound schema.\nexport type DaemonWorkerRosterOutbound =\n\t| {\n\t\t\ttype: \"roster_delta\";\n\t\t\tentries: WorkerRosterEntry[];\n\t\t\tremovedAgentIds?: string[];\n\t\t\tsnapshot?: true;\n\t }\n\t| { type: \"roster_heartbeat\" };\n\n/** Advertised by new workers in the worker_auth response; absent on legacy workers. */\nexport const DAEMON_WORKER_ROSTER_CAPABILITY = \"agent_roster\";\n\n/** Advertised in the worker_auth response by workers that accept peer transport grants. */\nexport const DAEMON_WORKER_PEER_TRANSPORT_CAPABILITY = \"peer_transport\";\n\n/** Idle keepalive cadence for worker->supervisor roster frames; the supervisor staleness threshold derives from it. */\nexport const ROSTER_HEARTBEAT_INTERVAL_MS = 15_000;\n\nexport type DaemonWorkerFrameHeader =\n\t| {\n\t\t\tkind: \"command\";\n\t\t\trequestId: string;\n\t\t\tcommandType: string;\n\t }\n\t| {\n\t\t\tkind: \"outbound\";\n\t\t\trequestId?: string;\n\t\t\toutboundType: DaemonOutbound[\"type\"] | DaemonWorkerRosterOutbound[\"type\"];\n\t\t\tactiveSessionId?: string;\n\t\t\tsnapshotId?: string;\n\t\t\tsessionEventType?: string;\n\t\t\tpayloadEncoding?: \"jsonl\" | \"assistant-delta\";\n\t\t\tsnapshotPurpose?: \"attach\" | \"replacement\" | \"catchup\";\n\t };\n\nexport interface DaemonRlmCapacityOrigin {\n\tsessionFile?: string;\n\tsessionId: string;\n}\n\nexport type DaemonRlmCapacityOperation =\n\t| (DaemonRlmCapacityOrigin & { op: \"status\" })\n\t| (DaemonRlmCapacityOrigin & { op: \"set\"; maxSubagents: number })\n\t| (DaemonRlmCapacityOrigin & { op: \"reserve\"; reservationId: string; residentRoot?: true })\n\t| { op: \"release\"; reservationId: string };\n\nexport interface DaemonRlmCapacityReservation extends DaemonRlmCapacityOrigin {\n\treservationId: string;\n\tresidentRoot?: true;\n}\n\nexport interface DaemonRlmCapacitySnapshot {\n\treservations: DaemonRlmCapacityReservation[];\n}\n\nexport function isDaemonRlmCapacitySnapshot(value: unknown): value is DaemonRlmCapacitySnapshot {\n\treturn (\n\t\ttypeof value === \"object\" &&\n\t\tvalue !== null &&\n\t\t\"reservations\" in value &&\n\t\tArray.isArray(value.reservations) &&\n\t\tvalue.reservations.every(\n\t\t\t(entry: unknown) =>\n\t\t\t\ttypeof entry === \"object\" &&\n\t\t\t\tentry !== null &&\n\t\t\t\t\"reservationId\" in entry &&\n\t\t\t\ttypeof entry.reservationId === \"string\" &&\n\t\t\t\tentry.reservationId.length > 0 &&\n\t\t\t\t\"sessionId\" in entry &&\n\t\t\t\ttypeof entry.sessionId === \"string\" &&\n\t\t\t\tentry.sessionId.length > 0 &&\n\t\t\t\t(!(\"sessionFile\" in entry) || entry.sessionFile === undefined || typeof entry.sessionFile === \"string\") &&\n\t\t\t\t(!(\"residentRoot\" in entry) || entry.residentRoot === undefined || entry.residentRoot === true),\n\t\t)\n\t);\n}\n\nexport type DaemonCreateCommand = Extract<DaemonCommand, { type: \"create\" }>;\n\nexport interface DurableDaemonCreateCommand {\n\ttype: \"create\";\n\tsessionPath?: string;\n\tnoSession?: boolean;\n}\n\nexport function durableDaemonCreateCommand(command: DaemonCreateCommand): DurableDaemonCreateCommand {\n\treturn {\n\t\ttype: \"create\",\n\t\t...(command.sessionPath !== undefined ? { sessionPath: command.sessionPath } : {}),\n\t\t...(command.noSession !== undefined ? { noSession: command.noSession } : {}),\n\t};\n}\n\n/**\n * A single-use, worker-memory-only admission for one direct peer, scoped to one active-session\n * slot (stable across switch_session/new_session/fork) of one worker incarnation. The session pin\n * is a routing/accident guard, not a privilege boundary: ticket holders already hold supervisor\n * access, which can attach to, switch, or kill any session.\n */\nexport interface DaemonWorkerPeerGrant {\n\tgrantId: string;\n\ttoken: string;\n\texpiresAt: string;\n\tpurpose: \"session_client\";\n\tworkerInstanceId: string;\n\tactiveSessionId: string;\n\tissuerGeneration: string;\n}\n\n/** Commands a direct peer may send before it holds an authenticated session role. */\nexport type DaemonPeerCommand = {\n\tid?: string;\n\ttype: \"peer_auth\";\n\tgrantId: string;\n\ttoken: string;\n\tworkerInstanceId: string;\n\tpurpose: \"session_client\";\n};\n\nexport type DaemonPeerCommandBody = Omit<DaemonPeerCommand, \"id\">;\n\nexport type DaemonWorkerCommand =\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_auth\";\n\t\t\ttoken: string;\n\t\t\tworkerInstanceId?: string;\n\t\t\tsupervisorGeneration: string;\n\t\t\tsupervisorPid: number;\n\t\t\tsupervisorProcessStartId?: string;\n\t\t\tsupervisorSocketPath: string;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_subscribe\";\n\t\t\tactiveSessionId: string;\n\t\t\tcapabilities?: readonly DaemonClientCapability[];\n\t\t\tsupportsExtensionUi?: boolean;\n\t }\n\t| { id?: string; type: \"worker_unsubscribe\"; activeSessionId: string }\n\t| { id?: string; type: \"worker_register_peer_transport\"; grant: DaemonWorkerPeerGrant }\n\t| { id?: string; type: \"worker_archive_and_shutdown\" }\n\t| { id?: string; type: \"worker_get_rlm_capacity\" }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_passivate_idle_children\";\n\t\t\tidleEvictionMinutes: IdleEvictionMinutes;\n\t\t\tnow: number;\n\t\t\tlimit: number;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_deliver_message\";\n\t\t\ttargetActiveSessionId: string;\n\t\t\tmessage: string;\n\t\t\tsender: AgentSessionMessageSender;\n\t\t\tdeliveryMode?: AgentSessionMessageDeliveryMode;\n\t }\n\t| {\n\t\t\tid?: string;\n\t\t\ttype: \"worker_deliver_result\";\n\t\t\ttargetActiveSessionId: string;\n\t\t\tsummary: string;\n\t\t\tfindings: string;\n\t\t\tsender: AgentSessionMessageSender;\n\t\t\tdeliveryMode?: AgentSessionMessageDeliveryMode;\n\t }\n\t| { id?: string; type: \"worker_prepare_update\" }\n\t| { id?: string; type: \"worker_commit_update\" }\n\t| { id?: string; type: \"worker_cancel_update\" };\n\nexport type DaemonWorkerCommandBody = DaemonWorkerCommand extends infer TCommand\n\t? TCommand extends { id?: string }\n\t\t? Omit<TCommand, \"id\">\n\t\t: never\n\t: never;\n\nexport interface DaemonWorkerDescriptor {\n\tversion: 1 | 2;\n\tworkerId: string;\n\tpid: number;\n\tprocessStartId?: string;\n\tsocketPath: string;\n\trecoveryJournalPath: string;\n\torphanProcessJournalPath?: string;\n\tsupervisorSocketPath: string;\n\tauthenticationToken: string;\n\tworkerInstanceId?: string;\n\trootActiveSessionId: string;\n\t/** Stable protocol client that owns this worker. Omitted for resident sessions. */\n\townerClientId?: string;\n\trootSessionId?: string;\n\tsessionFile?: string;\n\tsessionDir?: string;\n\tcreatedAt: string;\n\tupdatedAt: string;\n\tlifecycle: DaemonWorkerLifecycle;\n\tcreateCommand: DurableDaemonCreateCommand;\n\tconsecutiveFailures: number;\n\t/** Durable intent written before root termination so replacement supervisors never recover it. */\n\tstopRequestedAt?: string;\n\t/** Complete the root's archived lifecycle state after its process has stopped. */\n\tarchiveOnStop?: boolean;\n\tlastFailureAt?: string;\n\tlastError?: string;\n}\n\nexport function durableDaemonWorkerDescriptor(descriptor: DaemonWorkerDescriptor): DaemonWorkerDescriptor {\n\tconst versionOneCreateCommand = descriptor.createCommand as unknown as { config?: unknown };\n\tconst versionOneConfig =\n\t\tdescriptor.version === 1 &&\n\t\ttypeof versionOneCreateCommand.config === \"object\" &&\n\t\tversionOneCreateCommand.config !== null\n\t\t\t? (versionOneCreateCommand.config as Record<string, unknown>)\n\t\t\t: undefined;\n\tconst sessionDir =\n\t\tdescriptor.sessionDir ??\n\t\t(typeof versionOneConfig?.sessionDir === \"string\" ? versionOneConfig.sessionDir : undefined);\n\treturn {\n\t\tversion: 2,\n\t\tworkerId: descriptor.workerId,\n\t\tpid: descriptor.pid,\n\t\t...(descriptor.processStartId !== undefined ? { processStartId: descriptor.processStartId } : {}),\n\t\tsocketPath: descriptor.socketPath,\n\t\trecoveryJournalPath: descriptor.recoveryJournalPath,\n\t\t...(descriptor.orphanProcessJournalPath !== undefined\n\t\t\t? { orphanProcessJournalPath: descriptor.orphanProcessJournalPath }\n\t\t\t: {}),\n\t\tsupervisorSocketPath: descriptor.supervisorSocketPath,\n\t\tauthenticationToken: descriptor.authenticationToken,\n\t\t...(descriptor.workerInstanceId !== undefined ? { workerInstanceId: descriptor.workerInstanceId } : {}),\n\t\trootActiveSessionId: descriptor.rootActiveSessionId,\n\t\t...(descriptor.ownerClientId !== undefined ? { ownerClientId: descriptor.ownerClientId } : {}),\n\t\t...(descriptor.rootSessionId !== undefined ? { rootSessionId: descriptor.rootSessionId } : {}),\n\t\t...(descriptor.sessionFile !== undefined ? { sessionFile: descriptor.sessionFile } : {}),\n\t\t...(sessionDir !== undefined ? { sessionDir } : {}),\n\t\tcreatedAt: descriptor.createdAt,\n\t\tupdatedAt: descriptor.updatedAt,\n\t\tlifecycle: descriptor.lifecycle,\n\t\tcreateCommand: durableDaemonCreateCommand(descriptor.createCommand),\n\t\tconsecutiveFailures: descriptor.consecutiveFailures,\n\t\t...(descriptor.stopRequestedAt !== undefined ? { stopRequestedAt: descriptor.stopRequestedAt } : {}),\n\t\t...(descriptor.archiveOnStop !== undefined ? { archiveOnStop: descriptor.archiveOnStop } : {}),\n\t\t...(descriptor.lastFailureAt !== undefined ? { lastFailureAt: descriptor.lastFailureAt } : {}),\n\t\t...(descriptor.lifecycle === \"failed\" ? { lastError: \"Waiting for a client with fresh runtime context\" } : {}),\n\t};\n}\n\nexport function isDaemonWorkerProcess(environment: NodeJS.ProcessEnv = process.env): boolean {\n\treturn environment[DAEMON_WORKER_ROLE_ENV] === \"1\";\n}\n\nexport function waitForDaemonWorkerStartupGate(environment: NodeJS.ProcessEnv = process.env): void {\n\tconst rawFd = environment[DAEMON_WORKER_STARTUP_GATE_FD_ENV];\n\tif (rawFd === undefined) {\n\t\treturn;\n\t}\n\tdelete environment[DAEMON_WORKER_STARTUP_GATE_FD_ENV];\n\tconst fd = Number(rawFd);\n\tif (!Number.isInteger(fd) || fd < 3) {\n\t\tthrow new Error(\"Daemon session worker has an invalid startup gate\");\n\t}\n\tlet marker: string;\n\ttry {\n\t\tmarker = readFileSync(fd, \"utf8\");\n\t} finally {\n\t\tcloseSync(fd);\n\t}\n\tif (marker !== DAEMON_WORKER_STARTUP_GATE_COMMIT) {\n\t\tthrow new Error(\"Daemon session worker startup was cancelled\");\n\t}\n}\n\nexport function daemonWorkerInstanceId(environment: NodeJS.ProcessEnv = process.env): string | undefined {\n\treturn environment[DAEMON_WORKER_INSTANCE_ID_ENV] || undefined;\n}\n\nexport function requireDaemonWorkerAuthenticationToken(environment: NodeJS.ProcessEnv = process.env): string {\n\tconst token = environment[DAEMON_WORKER_TOKEN_ENV];\n\tif (!token) {\n\t\tthrow new Error(\"Daemon session worker is missing its authentication token\");\n\t}\n\treturn token;\n}\n\nexport function isDaemonWorkerFrameHeader(value: unknown): value is DaemonWorkerFrameHeader {\n\tif (!value || typeof value !== \"object\") {\n\t\treturn false;\n\t}\n\tconst candidate = value as Record<string, unknown>;\n\tif (candidate.kind === \"command\") {\n\t\treturn typeof candidate.requestId === \"string\" && typeof candidate.commandType === \"string\";\n\t}\n\treturn (\n\t\tcandidate.kind === \"outbound\" &&\n\t\ttypeof candidate.outboundType === \"string\" &&\n\t\t(candidate.requestId === undefined || typeof candidate.requestId === \"string\") &&\n\t\t(candidate.activeSessionId === undefined || typeof candidate.activeSessionId === \"string\") &&\n\t\t(candidate.snapshotId === undefined || typeof candidate.snapshotId === \"string\") &&\n\t\t(candidate.sessionEventType === undefined || typeof candidate.sessionEventType === \"string\") &&\n\t\t(candidate.snapshotPurpose === undefined ||\n\t\t\tcandidate.snapshotPurpose === \"attach\" ||\n\t\t\tcandidate.snapshotPurpose === \"replacement\" ||\n\t\t\tcandidate.snapshotPurpose === \"catchup\") &&\n\t\t(candidate.payloadEncoding === undefined ||\n\t\t\tcandidate.payloadEncoding === \"jsonl\" ||\n\t\t\tcandidate.payloadEncoding === \"assistant-delta\")\n\t);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"saved-session-catalog.d.ts","sourceRoot":"","sources":["../../../src/modes/daemon/saved-session-catalog.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAClF,OAAO,KAAK,EACX,+BAA+B,EAC/B,gCAAgC,EAChC,mCAAmC,EACnC,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAQhE,OAAO,EAEN,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAEtE,MAAM,MAAM,gCAAgC,GAAG;IAAE,eAAe,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAElH,MAAM,MAAM,sBAAsB,GAC/B,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,EAAE,UAAU,CAAC,GAAG;IAAE,QAAQ,EAAE,+BAA+B,EAAE,CAAA;CAAE,CAAC,GACnH,OAAO,CAAC,gBAAgB,EAAE;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,CAAC,CAAC;AAEpD,wBAAgB,uBAAuB,CACtC,MAAM,EAAE,qBAAqB,EAC7B,OAAO,EAAE,gCAAgC,EACzC,KAAK,EAAE,gCAAgC,EACvC,OAAO,EAAE;IAAE,IAAI,EAAE,qBAAqB,CAAA;CAAE,GACtC,OAAO,CAAC,sBAAsB,CAAC,CAAC;AACnC,wBAAgB,uBAAuB,CACtC,MAAM,EAAE,qBAAqB,EAC7B,OAAO,EAAE,gCAAgC,EACzC,KAAK,EAAE,gCAAgC,EACvC,SAAS,CAAC,EAAE,mCAAmC,GAC7C,OAAO,CAAC,+BAA+B,EAAE,CAAC,CAAC;AAmD9C,wBAAsB,wBAAwB,CAC7C,MAAM,EAAE,qBAAqB,EAC7B,OAAO,EAAE,gCAAgC,EACzC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,GACV,OAAO,CAAC,IAAI,CAAC,CASf;AAED,wBAAsB,wBAAwB,CAC7C,MAAM,EAAE,qBAAqB,EAC7B,OAAO,EAAE,gCAAgC,EACzC,WAAW,EAAE,MAAM,GACjB,OAAO,CAAC,uBAAuB,CAAC,CAUlC","sourcesContent":["import { resolve } from \"node:path\";\nimport type { DeleteSessionFileResult } from \"../../core/session-file-actions.js\";\nimport type {\n\tAgentConnectionSavedSessionInfo,\n\tAgentConnectionSavedSessionScope,\n\tAgentConnectionSessionListCallbacks,\n} from \"../agent-connection/types.js\";\nimport type { DaemonTransportClient } from \"./daemon-client.js\";\nimport { deserializeDaemonError } from \"./daemon-errors.js\";\nimport type {\n\tDaemonCommand,\n\tDaemonDeleteSavedSessionResult,\n\tDaemonSavedSessionListCommand,\n} from \"./daemon-protocol.js\";\nimport { deserializeSavedSessionInfo } from \"./saved-session-info.js\";\nimport {\n\tcaptureSavedSessionPageQuery,\n\ttype SavedSessionPage,\n\ttype SavedSessionPageQuery,\n} from \"./saved-session-page.js\";\n\nexport { deserializeSavedSessionInfo } from \"./saved-session-info.js\";\n\nexport type DaemonSavedSessionCatalogContext = { activeSessionId: string } | { cwd: string; sessionDir?: string };\n\nexport type SavedSessionClientPage =\n\t| (Omit<Extract<SavedSessionPage, { status: \"page\" }>, \"sessions\"> & { sessions: AgentConnectionSavedSessionInfo[] })\n\t| Extract<SavedSessionPage, { status: \"refused\" }>;\n\nexport function listDaemonSavedSessions(\n\tclient: DaemonTransportClient,\n\tcontext: DaemonSavedSessionCatalogContext,\n\tscope: AgentConnectionSavedSessionScope,\n\trequest: { page: SavedSessionPageQuery },\n): Promise<SavedSessionClientPage>;\nexport function listDaemonSavedSessions(\n\tclient: DaemonTransportClient,\n\tcontext: DaemonSavedSessionCatalogContext,\n\tscope: AgentConnectionSavedSessionScope,\n\tcallbacks?: AgentConnectionSessionListCallbacks,\n): Promise<AgentConnectionSavedSessionInfo[]>;\nexport async function listDaemonSavedSessions(\n\tclient: DaemonTransportClient,\n\tcontext: DaemonSavedSessionCatalogContext,\n\tscope: AgentConnectionSavedSessionScope,\n\toptions: { page: SavedSessionPageQuery } | AgentConnectionSessionListCallbacks = {},\n): Promise<SavedSessionClientPage | AgentConnectionSavedSessionInfo[]> {\n\tif (!(\"page\" in options)) {\n\t\t// Explicit generic array callers retain all results; the interactive view never enters this branch.\n\t\tconst sessions = new Map<\n\t\t\tstring,\n\t\t\t{ session: AgentConnectionSavedSessionInfo; source: \"catalog\" | \"passive\"; ordinal: number }\n\t\t>();\n\t\tlet cursor: SavedSessionPageQuery[\"cursor\"];\n\t\twhile (true) {\n\t\t\tconst page = await listDaemonSavedSessions(client, context, scope, { page: { cursor } });\n\t\t\tif (page.status === \"refused\") throw new Error(`Saved-session catalog ${page.reason}: ${page.message}`);\n\t\t\tfor (const session of page.sessions) {\n\t\t\t\tif (!page.primary.includes(`file:${resolve(session.path)}`) || sessions.has(session.path)) continue;\n\t\t\t\tconst order = page.sourceOrder.find((item) => item.path === session.path);\n\t\t\t\tif (!order) throw new Error(\"Saved-session page is missing its generic array order\");\n\t\t\t\tsessions.set(session.path, { session, source: order.source, ordinal: order.ordinal });\n\t\t\t\toptions.onSession?.(session);\n\t\t\t}\n\t\t\tif (!page.moreAfter) break;\n\t\t\tif (!page.after) throw new Error(\"Saved-session page has no continuation\");\n\t\t\tcursor = { identity: page.after, direction: \"next\" };\n\t\t}\n\t\treturn [...sessions.values()]\n\t\t\t.sort((a, b) => {\n\t\t\t\tif (a.source !== b.source) return a.source === \"catalog\" ? -1 : 1;\n\t\t\t\treturn (\n\t\t\t\t\t(a.source === \"catalog\" ? b.session.modified.getTime() - a.session.modified.getTime() : 0) ||\n\t\t\t\t\ta.ordinal - b.ordinal\n\t\t\t\t);\n\t\t\t})\n\t\t\t.map((item) => item.session);\n\t}\n\tconst page = captureSavedSessionPageQuery(options.page);\n\tconst command: DaemonSavedSessionListCommand =\n\t\t\"activeSessionId\" in context\n\t\t\t? { type: \"list_saved_sessions\", activeSessionId: context.activeSessionId, scope, page }\n\t\t\t: { type: \"list_saved_sessions\", cwd: context.cwd, sessionDir: context.sessionDir, scope, page };\n\tconst response = await client.request(command, 30000);\n\tif (!response.success) throw deserializeDaemonError(response);\n\tconst data = response.data as SavedSessionPage;\n\tif (data.status === \"refused\") return data;\n\tif (data.status !== \"page\") throw new Error(\"Daemon did not return a bounded saved-session page\");\n\treturn { ...data, sessions: data.sessions.map(deserializeSavedSessionInfo) };\n}\n\nexport async function renameDaemonSavedSession(\n\tclient: DaemonTransportClient,\n\tcontext: DaemonSavedSessionCatalogContext,\n\tsessionPath: string,\n\tname: string,\n): Promise<void> {\n\tconst command: Extract<DaemonCommand, { type: \"rename_saved_session\" }> =\n\t\t\"activeSessionId\" in context\n\t\t\t? { type: \"rename_saved_session\", activeSessionId: context.activeSessionId, sessionPath, name }\n\t\t\t: { type: \"rename_saved_session\", sessionPath, name };\n\tconst response = await client.request(command);\n\tif (!response.success) {\n\t\tthrow deserializeDaemonError(response);\n\t}\n}\n\nexport async function deleteDaemonSavedSession(\n\tclient: DaemonTransportClient,\n\tcontext: DaemonSavedSessionCatalogContext,\n\tsessionPath: string,\n): Promise<DeleteSessionFileResult> {\n\tconst command: Extract<DaemonCommand, { type: \"delete_saved_session\" }> =\n\t\t\"activeSessionId\" in context\n\t\t\t? { type: \"delete_saved_session\", activeSessionId: context.activeSessionId, sessionPath }\n\t\t\t: { type: \"delete_saved_session\", sessionPath };\n\tconst response = await client.request(command);\n\tif (!response.success) {\n\t\tthrow deserializeDaemonError(response);\n\t}\n\treturn response.data as DaemonDeleteSavedSessionResult;\n}\n"]}
1
+ {"version":3,"file":"saved-session-catalog.d.ts","sourceRoot":"","sources":["../../../src/modes/daemon/saved-session-catalog.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAC;AAClF,OAAO,KAAK,EACX,+BAA+B,EAC/B,gCAAgC,EAChC,mCAAmC,EACnC,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAQhE,OAAO,EAEN,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAEtE,MAAM,MAAM,gCAAgC,GAAG;IAAE,eAAe,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAElH,MAAM,MAAM,sBAAsB,GAC/B,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,EAAE,UAAU,CAAC,GAAG;IAAE,QAAQ,EAAE,+BAA+B,EAAE,CAAA;CAAE,CAAC,GACnH,OAAO,CAAC,gBAAgB,EAAE;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,CAAC,CAAC;AAEpD,wBAAgB,uBAAuB,CACtC,MAAM,EAAE,qBAAqB,EAC7B,OAAO,EAAE,gCAAgC,EACzC,KAAK,EAAE,gCAAgC,EACvC,OAAO,EAAE;IAAE,IAAI,EAAE,qBAAqB,CAAA;CAAE,GACtC,OAAO,CAAC,sBAAsB,CAAC,CAAC;AACnC,wBAAgB,uBAAuB,CACtC,MAAM,EAAE,qBAAqB,EAC7B,OAAO,EAAE,gCAAgC,EACzC,KAAK,EAAE,gCAAgC,EACvC,SAAS,CAAC,EAAE,mCAAmC,GAC7C,OAAO,CAAC,+BAA+B,EAAE,CAAC,CAAC;AAqD9C,wBAAsB,wBAAwB,CAC7C,MAAM,EAAE,qBAAqB,EAC7B,OAAO,EAAE,gCAAgC,EACzC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,GACV,OAAO,CAAC,IAAI,CAAC,CASf;AAED,wBAAsB,wBAAwB,CAC7C,MAAM,EAAE,qBAAqB,EAC7B,OAAO,EAAE,gCAAgC,EACzC,WAAW,EAAE,MAAM,GACjB,OAAO,CAAC,uBAAuB,CAAC,CAUlC","sourcesContent":["import { resolve } from \"node:path\";\nimport type { DeleteSessionFileResult } from \"../../core/session-file-actions.js\";\nimport type {\n\tAgentConnectionSavedSessionInfo,\n\tAgentConnectionSavedSessionScope,\n\tAgentConnectionSessionListCallbacks,\n} from \"../agent-connection/types.js\";\nimport type { DaemonTransportClient } from \"./daemon-client.js\";\nimport { deserializeDaemonError } from \"./daemon-errors.js\";\nimport type {\n\tDaemonCommand,\n\tDaemonDeleteSavedSessionResult,\n\tDaemonSavedSessionListCommand,\n} from \"./daemon-protocol.js\";\nimport { deserializeSavedSessionInfo } from \"./saved-session-info.js\";\nimport {\n\tcaptureSavedSessionPageQuery,\n\ttype SavedSessionPage,\n\ttype SavedSessionPageQuery,\n} from \"./saved-session-page.js\";\n\nexport { deserializeSavedSessionInfo } from \"./saved-session-info.js\";\n\nexport type DaemonSavedSessionCatalogContext = { activeSessionId: string } | { cwd: string; sessionDir?: string };\n\nexport type SavedSessionClientPage =\n\t| (Omit<Extract<SavedSessionPage, { status: \"page\" }>, \"sessions\"> & { sessions: AgentConnectionSavedSessionInfo[] })\n\t| Extract<SavedSessionPage, { status: \"refused\" }>;\n\nexport function listDaemonSavedSessions(\n\tclient: DaemonTransportClient,\n\tcontext: DaemonSavedSessionCatalogContext,\n\tscope: AgentConnectionSavedSessionScope,\n\trequest: { page: SavedSessionPageQuery },\n): Promise<SavedSessionClientPage>;\nexport function listDaemonSavedSessions(\n\tclient: DaemonTransportClient,\n\tcontext: DaemonSavedSessionCatalogContext,\n\tscope: AgentConnectionSavedSessionScope,\n\tcallbacks?: AgentConnectionSessionListCallbacks,\n): Promise<AgentConnectionSavedSessionInfo[]>;\nexport async function listDaemonSavedSessions(\n\tclient: DaemonTransportClient,\n\tcontext: DaemonSavedSessionCatalogContext,\n\tscope: AgentConnectionSavedSessionScope,\n\toptions: { page: SavedSessionPageQuery } | AgentConnectionSessionListCallbacks = {},\n): Promise<SavedSessionClientPage | AgentConnectionSavedSessionInfo[]> {\n\tif (!(\"page\" in options)) {\n\t\t// Explicit generic array callers retain all results; the interactive view never enters this branch.\n\t\tconst sessions = new Map<\n\t\t\tstring,\n\t\t\t{ session: AgentConnectionSavedSessionInfo; source: \"catalog\" | \"passive\"; ordinal: number }\n\t\t>();\n\t\tlet cursor: SavedSessionPageQuery[\"cursor\"];\n\t\twhile (true) {\n\t\t\tconst page = await listDaemonSavedSessions(client, context, scope, { page: { cursor } });\n\t\t\tif (page.status === \"refused\") throw new Error(`Saved-session catalog ${page.reason}: ${page.message}`);\n\t\t\tfor (const session of page.sessions) {\n\t\t\t\tif (!page.primary.includes(`file:${resolve(session.path)}`) || sessions.has(session.path)) continue;\n\t\t\t\tconst order = page.sourceOrder.find((item) => item.path === session.path);\n\t\t\t\tif (!order) throw new Error(\"Saved-session page is missing its generic array order\");\n\t\t\t\tsessions.set(session.path, { session, source: order.source, ordinal: order.ordinal });\n\t\t\t\toptions.onSession?.(session);\n\t\t\t}\n\t\t\tif (!page.moreAfter) break;\n\t\t\tif (!page.after) throw new Error(\"Saved-session page has no continuation\");\n\t\t\tcursor = { identity: page.after, direction: \"next\" };\n\t\t}\n\t\t// Only the completed page walk has an exact total for the requested sessions.\n\t\toptions.onProgress?.(sessions.size, sessions.size);\n\t\treturn [...sessions.values()]\n\t\t\t.sort((a, b) => {\n\t\t\t\tif (a.source !== b.source) return a.source === \"catalog\" ? -1 : 1;\n\t\t\t\treturn (\n\t\t\t\t\t(a.source === \"catalog\" ? b.session.modified.getTime() - a.session.modified.getTime() : 0) ||\n\t\t\t\t\ta.ordinal - b.ordinal\n\t\t\t\t);\n\t\t\t})\n\t\t\t.map((item) => item.session);\n\t}\n\tconst page = captureSavedSessionPageQuery(options.page);\n\tconst command: DaemonSavedSessionListCommand =\n\t\t\"activeSessionId\" in context\n\t\t\t? { type: \"list_saved_sessions\", activeSessionId: context.activeSessionId, scope, page }\n\t\t\t: { type: \"list_saved_sessions\", cwd: context.cwd, sessionDir: context.sessionDir, scope, page };\n\tconst response = await client.request(command, 30000);\n\tif (!response.success) throw deserializeDaemonError(response);\n\tconst data = response.data as SavedSessionPage;\n\tif (data.status === \"refused\") return data;\n\tif (data.status !== \"page\") throw new Error(\"Daemon did not return a bounded saved-session page\");\n\treturn { ...data, sessions: data.sessions.map(deserializeSavedSessionInfo) };\n}\n\nexport async function renameDaemonSavedSession(\n\tclient: DaemonTransportClient,\n\tcontext: DaemonSavedSessionCatalogContext,\n\tsessionPath: string,\n\tname: string,\n): Promise<void> {\n\tconst command: Extract<DaemonCommand, { type: \"rename_saved_session\" }> =\n\t\t\"activeSessionId\" in context\n\t\t\t? { type: \"rename_saved_session\", activeSessionId: context.activeSessionId, sessionPath, name }\n\t\t\t: { type: \"rename_saved_session\", sessionPath, name };\n\tconst response = await client.request(command);\n\tif (!response.success) {\n\t\tthrow deserializeDaemonError(response);\n\t}\n}\n\nexport async function deleteDaemonSavedSession(\n\tclient: DaemonTransportClient,\n\tcontext: DaemonSavedSessionCatalogContext,\n\tsessionPath: string,\n): Promise<DeleteSessionFileResult> {\n\tconst command: Extract<DaemonCommand, { type: \"delete_saved_session\" }> =\n\t\t\"activeSessionId\" in context\n\t\t\t? { type: \"delete_saved_session\", activeSessionId: context.activeSessionId, sessionPath }\n\t\t\t: { type: \"delete_saved_session\", sessionPath };\n\tconst response = await client.request(command);\n\tif (!response.success) {\n\t\tthrow deserializeDaemonError(response);\n\t}\n\treturn response.data as DaemonDeleteSavedSessionResult;\n}\n"]}
@@ -27,6 +27,8 @@ export async function listDaemonSavedSessions(client, context, scope, options =
27
27
  throw new Error("Saved-session page has no continuation");
28
28
  cursor = { identity: page.after, direction: "next" };
29
29
  }
30
+ // Only the completed page walk has an exact total for the requested sessions.
31
+ options.onProgress?.(sessions.size, sessions.size);
30
32
  return [...sessions.values()]
31
33
  .sort((a, b) => {
32
34
  if (a.source !== b.source)
@@ -1 +1 @@
1
- {"version":3,"file":"saved-session-catalog.js","sourceRoot":"","sources":["../../../src/modes/daemon/saved-session-catalog.ts"],"names":[],"mappings":"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","sourcesContent":["import { resolve } from \"node:path\";\nimport type { DeleteSessionFileResult } from \"../../core/session-file-actions.js\";\nimport type {\n\tAgentConnectionSavedSessionInfo,\n\tAgentConnectionSavedSessionScope,\n\tAgentConnectionSessionListCallbacks,\n} from \"../agent-connection/types.js\";\nimport type { DaemonTransportClient } from \"./daemon-client.js\";\nimport { deserializeDaemonError } from \"./daemon-errors.js\";\nimport type {\n\tDaemonCommand,\n\tDaemonDeleteSavedSessionResult,\n\tDaemonSavedSessionListCommand,\n} from \"./daemon-protocol.js\";\nimport { deserializeSavedSessionInfo } from \"./saved-session-info.js\";\nimport {\n\tcaptureSavedSessionPageQuery,\n\ttype SavedSessionPage,\n\ttype SavedSessionPageQuery,\n} from \"./saved-session-page.js\";\n\nexport { deserializeSavedSessionInfo } from \"./saved-session-info.js\";\n\nexport type DaemonSavedSessionCatalogContext = { activeSessionId: string } | { cwd: string; sessionDir?: string };\n\nexport type SavedSessionClientPage =\n\t| (Omit<Extract<SavedSessionPage, { status: \"page\" }>, \"sessions\"> & { sessions: AgentConnectionSavedSessionInfo[] })\n\t| Extract<SavedSessionPage, { status: \"refused\" }>;\n\nexport function listDaemonSavedSessions(\n\tclient: DaemonTransportClient,\n\tcontext: DaemonSavedSessionCatalogContext,\n\tscope: AgentConnectionSavedSessionScope,\n\trequest: { page: SavedSessionPageQuery },\n): Promise<SavedSessionClientPage>;\nexport function listDaemonSavedSessions(\n\tclient: DaemonTransportClient,\n\tcontext: DaemonSavedSessionCatalogContext,\n\tscope: AgentConnectionSavedSessionScope,\n\tcallbacks?: AgentConnectionSessionListCallbacks,\n): Promise<AgentConnectionSavedSessionInfo[]>;\nexport async function listDaemonSavedSessions(\n\tclient: DaemonTransportClient,\n\tcontext: DaemonSavedSessionCatalogContext,\n\tscope: AgentConnectionSavedSessionScope,\n\toptions: { page: SavedSessionPageQuery } | AgentConnectionSessionListCallbacks = {},\n): Promise<SavedSessionClientPage | AgentConnectionSavedSessionInfo[]> {\n\tif (!(\"page\" in options)) {\n\t\t// Explicit generic array callers retain all results; the interactive view never enters this branch.\n\t\tconst sessions = new Map<\n\t\t\tstring,\n\t\t\t{ session: AgentConnectionSavedSessionInfo; source: \"catalog\" | \"passive\"; ordinal: number }\n\t\t>();\n\t\tlet cursor: SavedSessionPageQuery[\"cursor\"];\n\t\twhile (true) {\n\t\t\tconst page = await listDaemonSavedSessions(client, context, scope, { page: { cursor } });\n\t\t\tif (page.status === \"refused\") throw new Error(`Saved-session catalog ${page.reason}: ${page.message}`);\n\t\t\tfor (const session of page.sessions) {\n\t\t\t\tif (!page.primary.includes(`file:${resolve(session.path)}`) || sessions.has(session.path)) continue;\n\t\t\t\tconst order = page.sourceOrder.find((item) => item.path === session.path);\n\t\t\t\tif (!order) throw new Error(\"Saved-session page is missing its generic array order\");\n\t\t\t\tsessions.set(session.path, { session, source: order.source, ordinal: order.ordinal });\n\t\t\t\toptions.onSession?.(session);\n\t\t\t}\n\t\t\tif (!page.moreAfter) break;\n\t\t\tif (!page.after) throw new Error(\"Saved-session page has no continuation\");\n\t\t\tcursor = { identity: page.after, direction: \"next\" };\n\t\t}\n\t\treturn [...sessions.values()]\n\t\t\t.sort((a, b) => {\n\t\t\t\tif (a.source !== b.source) return a.source === \"catalog\" ? -1 : 1;\n\t\t\t\treturn (\n\t\t\t\t\t(a.source === \"catalog\" ? b.session.modified.getTime() - a.session.modified.getTime() : 0) ||\n\t\t\t\t\ta.ordinal - b.ordinal\n\t\t\t\t);\n\t\t\t})\n\t\t\t.map((item) => item.session);\n\t}\n\tconst page = captureSavedSessionPageQuery(options.page);\n\tconst command: DaemonSavedSessionListCommand =\n\t\t\"activeSessionId\" in context\n\t\t\t? { type: \"list_saved_sessions\", activeSessionId: context.activeSessionId, scope, page }\n\t\t\t: { type: \"list_saved_sessions\", cwd: context.cwd, sessionDir: context.sessionDir, scope, page };\n\tconst response = await client.request(command, 30000);\n\tif (!response.success) throw deserializeDaemonError(response);\n\tconst data = response.data as SavedSessionPage;\n\tif (data.status === \"refused\") return data;\n\tif (data.status !== \"page\") throw new Error(\"Daemon did not return a bounded saved-session page\");\n\treturn { ...data, sessions: data.sessions.map(deserializeSavedSessionInfo) };\n}\n\nexport async function renameDaemonSavedSession(\n\tclient: DaemonTransportClient,\n\tcontext: DaemonSavedSessionCatalogContext,\n\tsessionPath: string,\n\tname: string,\n): Promise<void> {\n\tconst command: Extract<DaemonCommand, { type: \"rename_saved_session\" }> =\n\t\t\"activeSessionId\" in context\n\t\t\t? { type: \"rename_saved_session\", activeSessionId: context.activeSessionId, sessionPath, name }\n\t\t\t: { type: \"rename_saved_session\", sessionPath, name };\n\tconst response = await client.request(command);\n\tif (!response.success) {\n\t\tthrow deserializeDaemonError(response);\n\t}\n}\n\nexport async function deleteDaemonSavedSession(\n\tclient: DaemonTransportClient,\n\tcontext: DaemonSavedSessionCatalogContext,\n\tsessionPath: string,\n): Promise<DeleteSessionFileResult> {\n\tconst command: Extract<DaemonCommand, { type: \"delete_saved_session\" }> =\n\t\t\"activeSessionId\" in context\n\t\t\t? { type: \"delete_saved_session\", activeSessionId: context.activeSessionId, sessionPath }\n\t\t\t: { type: \"delete_saved_session\", sessionPath };\n\tconst response = await client.request(command);\n\tif (!response.success) {\n\t\tthrow deserializeDaemonError(response);\n\t}\n\treturn response.data as DaemonDeleteSavedSessionResult;\n}\n"]}
1
+ {"version":3,"file":"saved-session-catalog.js","sourceRoot":"","sources":["../../../src/modes/daemon/saved-session-catalog.ts"],"names":[],"mappings":"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","sourcesContent":["import { resolve } from \"node:path\";\nimport type { DeleteSessionFileResult } from \"../../core/session-file-actions.js\";\nimport type {\n\tAgentConnectionSavedSessionInfo,\n\tAgentConnectionSavedSessionScope,\n\tAgentConnectionSessionListCallbacks,\n} from \"../agent-connection/types.js\";\nimport type { DaemonTransportClient } from \"./daemon-client.js\";\nimport { deserializeDaemonError } from \"./daemon-errors.js\";\nimport type {\n\tDaemonCommand,\n\tDaemonDeleteSavedSessionResult,\n\tDaemonSavedSessionListCommand,\n} from \"./daemon-protocol.js\";\nimport { deserializeSavedSessionInfo } from \"./saved-session-info.js\";\nimport {\n\tcaptureSavedSessionPageQuery,\n\ttype SavedSessionPage,\n\ttype SavedSessionPageQuery,\n} from \"./saved-session-page.js\";\n\nexport { deserializeSavedSessionInfo } from \"./saved-session-info.js\";\n\nexport type DaemonSavedSessionCatalogContext = { activeSessionId: string } | { cwd: string; sessionDir?: string };\n\nexport type SavedSessionClientPage =\n\t| (Omit<Extract<SavedSessionPage, { status: \"page\" }>, \"sessions\"> & { sessions: AgentConnectionSavedSessionInfo[] })\n\t| Extract<SavedSessionPage, { status: \"refused\" }>;\n\nexport function listDaemonSavedSessions(\n\tclient: DaemonTransportClient,\n\tcontext: DaemonSavedSessionCatalogContext,\n\tscope: AgentConnectionSavedSessionScope,\n\trequest: { page: SavedSessionPageQuery },\n): Promise<SavedSessionClientPage>;\nexport function listDaemonSavedSessions(\n\tclient: DaemonTransportClient,\n\tcontext: DaemonSavedSessionCatalogContext,\n\tscope: AgentConnectionSavedSessionScope,\n\tcallbacks?: AgentConnectionSessionListCallbacks,\n): Promise<AgentConnectionSavedSessionInfo[]>;\nexport async function listDaemonSavedSessions(\n\tclient: DaemonTransportClient,\n\tcontext: DaemonSavedSessionCatalogContext,\n\tscope: AgentConnectionSavedSessionScope,\n\toptions: { page: SavedSessionPageQuery } | AgentConnectionSessionListCallbacks = {},\n): Promise<SavedSessionClientPage | AgentConnectionSavedSessionInfo[]> {\n\tif (!(\"page\" in options)) {\n\t\t// Explicit generic array callers retain all results; the interactive view never enters this branch.\n\t\tconst sessions = new Map<\n\t\t\tstring,\n\t\t\t{ session: AgentConnectionSavedSessionInfo; source: \"catalog\" | \"passive\"; ordinal: number }\n\t\t>();\n\t\tlet cursor: SavedSessionPageQuery[\"cursor\"];\n\t\twhile (true) {\n\t\t\tconst page = await listDaemonSavedSessions(client, context, scope, { page: { cursor } });\n\t\t\tif (page.status === \"refused\") throw new Error(`Saved-session catalog ${page.reason}: ${page.message}`);\n\t\t\tfor (const session of page.sessions) {\n\t\t\t\tif (!page.primary.includes(`file:${resolve(session.path)}`) || sessions.has(session.path)) continue;\n\t\t\t\tconst order = page.sourceOrder.find((item) => item.path === session.path);\n\t\t\t\tif (!order) throw new Error(\"Saved-session page is missing its generic array order\");\n\t\t\t\tsessions.set(session.path, { session, source: order.source, ordinal: order.ordinal });\n\t\t\t\toptions.onSession?.(session);\n\t\t\t}\n\t\t\tif (!page.moreAfter) break;\n\t\t\tif (!page.after) throw new Error(\"Saved-session page has no continuation\");\n\t\t\tcursor = { identity: page.after, direction: \"next\" };\n\t\t}\n\t\t// Only the completed page walk has an exact total for the requested sessions.\n\t\toptions.onProgress?.(sessions.size, sessions.size);\n\t\treturn [...sessions.values()]\n\t\t\t.sort((a, b) => {\n\t\t\t\tif (a.source !== b.source) return a.source === \"catalog\" ? -1 : 1;\n\t\t\t\treturn (\n\t\t\t\t\t(a.source === \"catalog\" ? b.session.modified.getTime() - a.session.modified.getTime() : 0) ||\n\t\t\t\t\ta.ordinal - b.ordinal\n\t\t\t\t);\n\t\t\t})\n\t\t\t.map((item) => item.session);\n\t}\n\tconst page = captureSavedSessionPageQuery(options.page);\n\tconst command: DaemonSavedSessionListCommand =\n\t\t\"activeSessionId\" in context\n\t\t\t? { type: \"list_saved_sessions\", activeSessionId: context.activeSessionId, scope, page }\n\t\t\t: { type: \"list_saved_sessions\", cwd: context.cwd, sessionDir: context.sessionDir, scope, page };\n\tconst response = await client.request(command, 30000);\n\tif (!response.success) throw deserializeDaemonError(response);\n\tconst data = response.data as SavedSessionPage;\n\tif (data.status === \"refused\") return data;\n\tif (data.status !== \"page\") throw new Error(\"Daemon did not return a bounded saved-session page\");\n\treturn { ...data, sessions: data.sessions.map(deserializeSavedSessionInfo) };\n}\n\nexport async function renameDaemonSavedSession(\n\tclient: DaemonTransportClient,\n\tcontext: DaemonSavedSessionCatalogContext,\n\tsessionPath: string,\n\tname: string,\n): Promise<void> {\n\tconst command: Extract<DaemonCommand, { type: \"rename_saved_session\" }> =\n\t\t\"activeSessionId\" in context\n\t\t\t? { type: \"rename_saved_session\", activeSessionId: context.activeSessionId, sessionPath, name }\n\t\t\t: { type: \"rename_saved_session\", sessionPath, name };\n\tconst response = await client.request(command);\n\tif (!response.success) {\n\t\tthrow deserializeDaemonError(response);\n\t}\n}\n\nexport async function deleteDaemonSavedSession(\n\tclient: DaemonTransportClient,\n\tcontext: DaemonSavedSessionCatalogContext,\n\tsessionPath: string,\n): Promise<DeleteSessionFileResult> {\n\tconst command: Extract<DaemonCommand, { type: \"delete_saved_session\" }> =\n\t\t\"activeSessionId\" in context\n\t\t\t? { type: \"delete_saved_session\", activeSessionId: context.activeSessionId, sessionPath }\n\t\t\t: { type: \"delete_saved_session\", sessionPath };\n\tconst response = await client.request(command);\n\tif (!response.success) {\n\t\tthrow deserializeDaemonError(response);\n\t}\n\treturn response.data as DaemonDeleteSavedSessionResult;\n}\n"]}
@@ -58,12 +58,6 @@ export declare class ProviderAuthFlows {
58
58
  private completeExternalProviderSetup;
59
59
  private hasAvailableProviderModels;
60
60
  private showBedrockSetupDialog;
61
- private showPrimeTeamSelector;
62
- private getPrimeInferenceDefaultTeamStatus;
63
- private selectPrimeInferenceTeam;
64
- private completePrimeInferenceLogin;
65
- runPrimeInferenceLogin(): Promise<AuthenticationResult>;
66
- runPrimeAgentTracesLogin(): Promise<AuthenticationResult>;
67
61
  private showApiKeyLoginDialog;
68
62
  private showOAuthLoginSelect;
69
63
  private showLoginDialog;
@@ -1 +1 @@
1
- {"version":3,"file":"auth-flows.d.ts","sourceRoot":"","sources":["../../../src/modes/interactive/auth-flows.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from \"node:path\";\nimport {\n\tgetPrimeTeamId,\n\tgetProviders,\n\ttype OAuthProviderId,\n\ttype OAuthSelectPrompt,\n} from \"@ponythewhite/base-context-ai\";\nimport type { OverlayHandle, TUI } from \"@ponythewhite/base-context-tui\";\nimport { getAuthPath, getDocsPath } from \"../../config.js\";\nimport type { ModelRegistry } from \"../../core/model-registry.js\";\nimport {\n\tBASE_CONTEXT_TRACES_PROVIDER_NAME,\n\tcheckPrimeInferenceAccess,\n\tfetchPrimeTeams,\n\tloadPrimeCliConfig,\n\tPRIME_INFERENCE_PROVIDER_ID,\n\tPRIME_INFERENCE_PROVIDER_NAME,\n\ttype PrimeTeam,\n} from \"../../core/prime-inference-auth.js\";\nimport { getProviderAuthContract } from \"../../core/provider-contracts.js\";\nimport { BUILT_IN_PROVIDER_DISPLAY_NAMES } from \"../../core/provider-display-names.js\";\nimport { SERPER_CREDENTIAL_ID, SERPER_CREDENTIAL_NAME } from \"../../core/websearch-credential.js\";\nimport { showFullPaneOverlay } from \"./components/centered-overlay.js\";\nimport { ExtensionSelectorComponent } from \"./components/extension-selector.js\";\nimport { LoginDialogComponent } from \"./components/login-dialog.js\";\nimport {\n\ttype AuthSelectorCategory,\n\ttype AuthSelectorProvider,\n\tcompareAuthSelectorProviders,\n\tOAuthSelectorComponent,\n} from \"./components/oauth-selector.js\";\nimport { PrimeTeamSelectorComponent } from \"./components/prime-team-selector.js\";\nimport { theme } from \"./theme/theme.js\";\n\nexport type AuthenticationResult =\n\t| {\n\t\t\tstatus: \"success\";\n\t\t\tproviderId: string;\n\t\t\tproviderName: string;\n\t\t\tauthType: \"oauth\" | \"api_key\";\n\t\t\t/** \"service\" credentials (e.g. web search) don't affect model selection. */\n\t\t\tkind?: \"provider\" | \"service\";\n\t }\n\t| { status: \"cancelled\" }\n\t| { status: \"failed\" };\n\nexport const BEDROCK_PROVIDER_ID = \"amazon-bedrock\";\n\nexport const ANTHROPIC_SUBSCRIPTION_AUTH_WARNING =\n\t\"Anthropic subscription auth is active. Third-party harness usage draws from extra usage and is billed per token, not your Claude plan limits. Manage extra usage at https://claude.ai/settings/usage.\";\n\nfunction isAnthropicSubscriptionAuthKey(apiKey: string | undefined): boolean {\n\treturn typeof apiKey === \"string\" && apiKey.startsWith(\"sk-ant-oat\");\n}\n\nexport async function getAnthropicSubscriptionAuthWarning(\n\tmodelRegistry: ModelRegistry,\n\tmodel: { provider: string } | undefined,\n): Promise<string | undefined> {\n\tif (!model || model.provider !== \"anthropic\" || getProviderAuthContract(model.provider).oauth !== \"validated\") {\n\t\treturn undefined;\n\t}\n\n\tconst storedCredential = modelRegistry.authStorage.get(\"anthropic\");\n\tif (storedCredential?.type === \"oauth\") {\n\t\treturn ANTHROPIC_SUBSCRIPTION_AUTH_WARNING;\n\t}\n\n\ttry {\n\t\tconst apiKey = await modelRegistry.getApiKeyForProvider(model.provider);\n\t\tif (isAnthropicSubscriptionAuthKey(apiKey)) {\n\t\t\treturn ANTHROPIC_SUBSCRIPTION_AUTH_WARNING;\n\t\t}\n\t} catch {\n\t\t// Ignore auth lookup failures for warning-only checks.\n\t}\n\treturn undefined;\n}\n\nconst BUILT_IN_MODEL_PROVIDERS = new Set<string>(getProviders());\n\nexport function isApiKeyLoginProvider(\n\tproviderId: string,\n\toauthProviderIds: ReadonlySet<string>,\n\tbuiltInProviderIds: ReadonlySet<string> = BUILT_IN_MODEL_PROVIDERS,\n): boolean {\n\tif (BUILT_IN_PROVIDER_DISPLAY_NAMES[providerId]) {\n\t\treturn true;\n\t}\n\tif (builtInProviderIds.has(providerId)) {\n\t\treturn false;\n\t}\n\treturn !oauthProviderIds.has(providerId);\n}\n\nexport interface ProviderAuthFlowsHost {\n\treadonly ui: TUI;\n\treadonly modelRegistry: ModelRegistry;\n\tshowStatus(message: string): void;\n\tshowError(message: string): void;\n\t/** Models currently visible to the host; used to detect providers configured via external credentials. */\n\tgetAvailableModels(): Promise<ReadonlyArray<{ provider: string }>>;\n\t/** Invoked after stored credentials change so the host can refresh dependent UI. */\n\tonAuthChanged?(): void | Promise<void>;\n\t/** Invoked after a successful login (e.g. to surface billing warnings). */\n\tonLoginCompleted?(): void;\n}\n\nexport interface ProviderLoginOptions {\n\tauthType?: \"oauth\" | \"api_key\";\n\tinitialCategory?: AuthSelectorCategory;\n}\n\n/** Shared auth dialogs: host-specific refresh and billing effects remain outside the flow. */\nexport class ProviderAuthFlows {\n\tconstructor(private readonly host: ProviderAuthFlowsHost) {}\n\n\t/**\n\t * Run the OAuth login flow for an MCP integration server.\n\t *\n\t * The provider must already be registered (the McpManager does this as\n\t * `mcp:<server>`). On success the credentials land in auth.json and the\n\t * caller should reload resources so the integration's skill enables.\n\t */\n\trunMcpLogin(server: string, label?: string): Promise<AuthenticationResult> {\n\t\tconst providerId = `mcp:${server}`;\n\t\tconst contract = getProviderAuthContract(providerId);\n\t\tif (contract.oauth !== \"validated\") {\n\t\t\tthis.host.showError(contract.guidance);\n\t\t\treturn Promise.resolve({ status: \"failed\" });\n\t\t}\n\t\tconst provider = this.host.modelRegistry.authStorage.getOAuthProviders().find((p) => p.id === providerId);\n\t\tif (!provider) {\n\t\t\tthis.host.showError(`Unknown MCP integration: ${server}`);\n\t\t\treturn Promise.resolve({ status: \"failed\" });\n\t\t}\n\t\treturn this.showLoginDialog(providerId, label ?? provider.name, \"service\");\n\t}\n\n\trunLogin(options: ProviderLoginOptions = {}): Promise<AuthenticationResult> {\n\t\tconst { authType, initialCategory } = options;\n\t\tconst providerOptions = this.getLoginProviderOptions(authType);\n\t\tif (providerOptions.length === 0) {\n\t\t\tthis.host.showStatus(\n\t\t\t\tauthType === \"oauth\"\n\t\t\t\t\t? \"Subscription OAuth is unavailable in Base Context until provider client contracts are validated. Use /login API Keys instead.\"\n\t\t\t\t\t: authType === \"api_key\"\n\t\t\t\t\t\t? \"No API key providers available.\"\n\t\t\t\t\t\t: \"No providers available.\",\n\t\t\t);\n\t\t\treturn Promise.resolve({ status: \"failed\" });\n\t\t}\n\n\t\treturn new Promise((resolve) => {\n\t\t\tlet handle: OverlayHandle | undefined;\n\t\t\tconst close = () => {\n\t\t\t\thandle?.hide();\n\t\t\t\tthis.host.ui.requestRender();\n\t\t\t};\n\t\t\tconst selector = new OAuthSelectorComponent(\n\t\t\t\t\"login\",\n\t\t\t\tthis.host.modelRegistry.authStorage,\n\t\t\t\tproviderOptions,\n\t\t\t\tasync (providerOption: AuthSelectorProvider) => {\n\t\t\t\t\tclose();\n\t\t\t\t\tresolve(await this.loginProvider(providerOption));\n\t\t\t\t},\n\t\t\t\t() => {\n\t\t\t\t\tclose();\n\t\t\t\t\tresolve({ status: \"cancelled\" });\n\t\t\t\t},\n\t\t\t\t(providerId) => this.host.modelRegistry.getProviderAuthStatus(providerId),\n\t\t\t\t{ getRows: () => this.host.ui.terminal.rows, initialCategory },\n\t\t\t);\n\t\t\thandle = showFullPaneOverlay(this.host.ui, selector, 78);\n\t\t});\n\t}\n\n\tloginProvider(providerOption: AuthSelectorProvider): Promise<AuthenticationResult> {\n\t\tconst kind = providerOption.category === \"service\" ? \"service\" : \"provider\";\n\t\tif (providerOption.authType === \"oauth\") {\n\t\t\treturn this.showLoginDialog(providerOption.id, providerOption.name, kind);\n\t\t}\n\t\tif (providerOption.id === PRIME_INFERENCE_PROVIDER_ID) {\n\t\t\treturn this.runPrimeInferenceLogin();\n\t\t}\n\t\tif (providerOption.id === BEDROCK_PROVIDER_ID) {\n\t\t\treturn this.showBedrockSetupDialog(providerOption.id, providerOption.name);\n\t\t}\n\t\treturn this.showApiKeyLoginDialog(providerOption.id, providerOption.name, kind);\n\t}\n\n\trunLogout(): Promise<string | null> {\n\t\tconst providerOptions = this.getLogoutProviderOptions();\n\t\tif (providerOptions.length === 0) {\n\t\t\tthis.host.showStatus(\n\t\t\t\t\"No stored credentials to remove. /logout only removes credentials saved by /login; environment variables and models.json config are unchanged.\",\n\t\t\t);\n\t\t\treturn Promise.resolve(null);\n\t\t}\n\n\t\treturn new Promise((resolve) => {\n\t\t\tlet handle: OverlayHandle | undefined;\n\t\t\tconst close = () => {\n\t\t\t\thandle?.hide();\n\t\t\t\tthis.host.ui.requestRender();\n\t\t\t};\n\t\t\tconst selector = new OAuthSelectorComponent(\n\t\t\t\t\"logout\",\n\t\t\t\tthis.host.modelRegistry.authStorage,\n\t\t\t\tproviderOptions,\n\t\t\t\tasync (providerOption: AuthSelectorProvider) => {\n\t\t\t\t\tclose();\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.host.modelRegistry.authStorage.logout(providerOption.id);\n\t\t\t\t\t\tthis.host.modelRegistry.refresh();\n\t\t\t\t\t\tawait this.host.onAuthChanged?.();\n\t\t\t\t\t\tconst message =\n\t\t\t\t\t\t\tproviderOption.authType === \"oauth\"\n\t\t\t\t\t\t\t\t? `Logged out of ${providerOption.name}`\n\t\t\t\t\t\t\t\t: `Removed stored API key for ${providerOption.name}. Environment variables and models.json config are unchanged.`;\n\t\t\t\t\t\tthis.host.showStatus(message);\n\t\t\t\t\t\tresolve(providerOption.id);\n\t\t\t\t\t} catch (error: unknown) {\n\t\t\t\t\t\tthis.host.showError(`Logout failed: ${error instanceof Error ? error.message : String(error)}`);\n\t\t\t\t\t\tresolve(null);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t() => {\n\t\t\t\t\tclose();\n\t\t\t\t\tresolve(null);\n\t\t\t\t},\n\t\t\t\tundefined,\n\t\t\t\t{ getRows: () => this.host.ui.terminal.rows },\n\t\t\t);\n\t\t\thandle = showFullPaneOverlay(this.host.ui, selector, 78);\n\t\t});\n\t}\n\n\tgetLoginProviderOptions(authType?: \"oauth\" | \"api_key\"): AuthSelectorProvider[] {\n\t\tconst authStorage = this.host.modelRegistry.authStorage;\n\t\tconst oauthProviders = authStorage.getOAuthProviders();\n\t\tconst oauthProviderIds = new Set(oauthProviders.map((provider) => provider.id));\n\t\tconst options: AuthSelectorProvider[] = oauthProviders.map((provider) => ({\n\t\t\tid: provider.id,\n\t\t\tname: provider.name,\n\t\t\tauthType: \"oauth\",\n\t\t\t// MCP integrations (mcp:<server>) are services, not model providers.\n\t\t\t...(provider.id.startsWith(\"mcp:\") ? { category: \"service\" as const } : {}),\n\t\t}));\n\n\t\tconst modelProviders = new Set(this.host.modelRegistry.getAll().map((model) => model.provider));\n\t\tfor (const providerId of modelProviders) {\n\t\t\tif (!isApiKeyLoginProvider(providerId, oauthProviderIds)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\toptions.push({\n\t\t\t\tid: providerId,\n\t\t\t\tname: this.host.modelRegistry.getProviderDisplayName(providerId),\n\t\t\t\tauthType: \"api_key\",\n\t\t\t});\n\t\t}\n\n\t\t// Serper is a skill credential, not a model provider, so add it manually.\n\t\toptions.push({\n\t\t\tid: SERPER_CREDENTIAL_ID,\n\t\t\tname: SERPER_CREDENTIAL_NAME,\n\t\t\tauthType: \"api_key\",\n\t\t\tcategory: \"service\",\n\t\t});\n\n\t\tconst filteredOptions = authType ? options.filter((option) => option.authType === authType) : options;\n\t\treturn filteredOptions.sort(compareAuthSelectorProviders);\n\t}\n\n\tprivate getLogoutProviderOptions(): AuthSelectorProvider[] {\n\t\tconst authStorage = this.host.modelRegistry.authStorage;\n\t\tconst options: AuthSelectorProvider[] = [];\n\n\t\tconst oauthProvidersById = new Map(authStorage.getOAuthProviders().map((p) => [p.id, p]));\n\t\tfor (const providerId of authStorage.list()) {\n\t\t\tconst credential = authStorage.get(providerId);\n\t\t\tif (!credential) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst isSerper = providerId === SERPER_CREDENTIAL_ID;\n\t\t\tconst isMcp = providerId.startsWith(\"mcp:\");\n\t\t\tconst name = isSerper\n\t\t\t\t? SERPER_CREDENTIAL_NAME\n\t\t\t\t: isMcp\n\t\t\t\t\t? (oauthProvidersById.get(providerId)?.name ?? providerId.slice(\"mcp:\".length))\n\t\t\t\t\t: this.host.modelRegistry.getProviderDisplayName(providerId);\n\t\t\toptions.push({\n\t\t\t\tid: providerId,\n\t\t\t\tname,\n\t\t\t\tauthType: credential.type,\n\t\t\t\tcategory: isSerper || isMcp ? \"service\" : \"provider\",\n\t\t\t});\n\t\t}\n\n\t\tif (!options.some((option) => option.id === PRIME_INFERENCE_PROVIDER_ID)) {\n\t\t\tconst primeInferenceStatus = authStorage.getAuthStatus(PRIME_INFERENCE_PROVIDER_ID);\n\t\t\tif (primeInferenceStatus.source === \"prime_cli\") {\n\t\t\t\toptions.push({\n\t\t\t\t\tid: PRIME_INFERENCE_PROVIDER_ID,\n\t\t\t\t\tname: PRIME_INFERENCE_PROVIDER_NAME,\n\t\t\t\t\tauthType: \"api_key\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn options.sort((a, b) => a.name.localeCompare(b.name));\n\t}\n\n\tprivate async completeProviderAuthentication(\n\t\tproviderId: string,\n\t\tproviderName: string,\n\t\tauthType: \"oauth\" | \"api_key\",\n\t\tstatusSuffix?: string,\n\t\tkind: \"provider\" | \"service\" = \"provider\",\n\t\tcredentialPath: string = getAuthPath(),\n\t): Promise<AuthenticationResult> {\n\t\tthis.host.modelRegistry.refresh();\n\n\t\tconst actionLabel = authType === \"oauth\" ? `Logged in to ${providerName}` : `Saved API key for ${providerName}`;\n\t\tawait this.host.onAuthChanged?.();\n\t\tthis.host.showStatus(\n\t\t\t`${actionLabel}. Credentials saved to ${credentialPath}${statusSuffix ? `. ${statusSuffix}` : \"\"}`,\n\t\t);\n\t\tthis.host.onLoginCompleted?.();\n\t\treturn {\n\t\t\tstatus: \"success\",\n\t\t\tproviderId,\n\t\t\tproviderName,\n\t\t\tauthType,\n\t\t\tkind,\n\t\t};\n\t}\n\n\tprivate async completeExternalProviderSetup(\n\t\tproviderId: string,\n\t\tproviderName: string,\n\t): Promise<AuthenticationResult> {\n\t\tthis.host.modelRegistry.refresh();\n\t\tawait this.host.onAuthChanged?.();\n\t\tthis.host.showStatus(`${providerName} uses external credentials. Select a model after configuring them.`);\n\t\treturn {\n\t\t\tstatus: \"success\",\n\t\t\tproviderId,\n\t\t\tproviderName,\n\t\t\tauthType: \"api_key\",\n\t\t};\n\t}\n\n\tprivate async hasAvailableProviderModels(providerId: string): Promise<boolean> {\n\t\tconst models = await this.host.getAvailableModels();\n\t\treturn models.some((model) => model.provider === providerId);\n\t}\n\n\tprivate async showBedrockSetupDialog(providerId: string, providerName: string): Promise<AuthenticationResult> {\n\t\tconst dialog = new LoginDialogComponent(this.host.ui, providerId, () => {}, providerName, \"Amazon Bedrock setup\");\n\t\tconst handle = showFullPaneOverlay(this.host.ui, dialog, 88);\n\t\tconst closeDialog = () => {\n\t\t\thandle.hide();\n\t\t\tthis.host.ui.requestRender();\n\t\t};\n\n\t\ttry {\n\t\t\tawait dialog.showContinueInfo([\n\t\t\t\ttheme.fg(\"text\", \"Amazon Bedrock uses AWS credentials instead of a single API key.\"),\n\t\t\t\ttheme.fg(\"text\", \"Configure an AWS profile, IAM keys, bearer token, or role-based credentials.\"),\n\t\t\t\ttheme.fg(\"muted\", \"See:\"),\n\t\t\t\ttheme.fg(\"accent\", ` ${path.join(getDocsPath(), \"providers.md\")}`),\n\t\t\t]);\n\t\t\tcloseDialog();\n\t\t\tif (!(await this.hasAvailableProviderModels(providerId))) {\n\t\t\t\tthis.host.showStatus(`${providerName} credentials were not detected. Configure them, then reopen /model.`);\n\t\t\t\treturn { status: \"cancelled\" };\n\t\t\t}\n\t\t\treturn await this.completeExternalProviderSetup(providerId, providerName);\n\t\t} catch (error: unknown) {\n\t\t\tcloseDialog();\n\t\t\tconst errorMsg = error instanceof Error ? error.message : String(error);\n\t\t\tif (errorMsg !== \"Login cancelled\") {\n\t\t\t\tthis.host.showError(`Failed to set up ${providerName}: ${errorMsg}`);\n\t\t\t\treturn { status: \"failed\" };\n\t\t\t}\n\t\t\treturn { status: \"cancelled\" };\n\t\t}\n\t}\n\n\tprivate showPrimeTeamSelector(\n\t\tteams: PrimeTeam[],\n\t\tcurrentTeamId: string | undefined,\n\t): Promise<PrimeTeam | null | undefined> {\n\t\treturn new Promise((resolve) => {\n\t\t\tlet handle: OverlayHandle | undefined;\n\t\t\tconst close = () => {\n\t\t\t\thandle?.hide();\n\t\t\t\tthis.host.ui.requestRender();\n\t\t\t};\n\t\t\tconst selector = new PrimeTeamSelectorComponent(\n\t\t\t\tteams,\n\t\t\t\tcurrentTeamId,\n\t\t\t\t(team) => {\n\t\t\t\t\tclose();\n\t\t\t\t\tresolve(team);\n\t\t\t\t},\n\t\t\t\t() => {\n\t\t\t\t\tclose();\n\t\t\t\t\tresolve(undefined);\n\t\t\t\t},\n\t\t\t\t{ getRows: () => this.host.ui.terminal.rows },\n\t\t\t);\n\t\t\thandle = showFullPaneOverlay(this.host.ui, selector, 78);\n\t\t});\n\t}\n\n\tprivate getPrimeInferenceDefaultTeamStatus(): string {\n\t\tif (getPrimeTeamId()) {\n\t\t\treturn \"Using team from PRIME_TEAM_ID.\";\n\t\t}\n\t\tconst storedTeam = this.host.modelRegistry.authStorage.getPrimeInferenceTeamSelection();\n\t\treturn storedTeam ? `Using team \"${storedTeam.name}\".` : \"Using personal account.\";\n\t}\n\n\tprivate async selectPrimeInferenceTeam(apiKey: string, dialog: LoginDialogComponent): Promise<string | undefined> {\n\t\ttry {\n\t\t\tif (getPrimeTeamId()) {\n\t\t\t\tthis.host.modelRegistry.authStorage.reload();\n\t\t\t\treturn \"Using team from PRIME_TEAM_ID.\";\n\t\t\t}\n\n\t\t\tconst config = loadPrimeCliConfig(this.host.modelRegistry.authStorage.getPrimeCliConfigPath());\n\t\t\tdialog.showProgress(\"Loading Prime teams...\");\n\t\t\tconst teams = await fetchPrimeTeams(apiKey, config.baseUrl, { signal: dialog.signal });\n\t\t\tif (dialog.signal.aborted) {\n\t\t\t\treturn this.getPrimeInferenceDefaultTeamStatus();\n\t\t\t}\n\t\t\tif (teams.length === 0) {\n\t\t\t\tthis.host.modelRegistry.authStorage.setPrimeInferenceTeamSelection(null);\n\t\t\t\treturn \"Using personal account.\";\n\t\t\t}\n\n\t\t\tconst storedTeam = this.host.modelRegistry.authStorage.getPrimeInferenceTeamSelection();\n\t\t\tconst currentTeamId = storedTeam === null ? undefined : (storedTeam?.teamId ?? config.teamId);\n\t\t\tconst selectedTeam = await this.showPrimeTeamSelector(teams, currentTeamId);\n\t\t\tif (selectedTeam !== undefined) {\n\t\t\t\tthis.host.modelRegistry.authStorage.setPrimeInferenceTeamSelection(selectedTeam);\n\t\t\t}\n\t\t\treturn selectedTeam\n\t\t\t\t? `Using team \"${selectedTeam.name}\".`\n\t\t\t\t: selectedTeam === null\n\t\t\t\t\t? \"Using personal account.\"\n\t\t\t\t\t: this.getPrimeInferenceDefaultTeamStatus();\n\t\t} catch {\n\t\t\tthis.host.modelRegistry.authStorage.reload();\n\t\t\treturn this.getPrimeInferenceDefaultTeamStatus();\n\t\t}\n\t}\n\n\tprivate async completePrimeInferenceLogin(\n\t\tapiKey: string,\n\t\tdialog: LoginDialogComponent,\n\t\tcloseDialog: () => void,\n\t): Promise<AuthenticationResult> {\n\t\tthis.host.modelRegistry.authStorage.setPrimeInferenceApiKey(apiKey);\n\t\tconst teamStatus = await this.selectPrimeInferenceTeam(apiKey, dialog);\n\n\t\tcloseDialog();\n\t\treturn await this.completeProviderAuthentication(\n\t\t\tPRIME_INFERENCE_PROVIDER_ID,\n\t\t\tPRIME_INFERENCE_PROVIDER_NAME,\n\t\t\t\"api_key\",\n\t\t\tteamStatus,\n\t\t\t\"provider\",\n\t\t\tthis.host.modelRegistry.authStorage.getPrimeCliConfigPath() ?? getAuthPath(),\n\t\t);\n\t}\n\n\tasync runPrimeInferenceLogin(): Promise<AuthenticationResult> {\n\t\tconst dialog = new LoginDialogComponent(\n\t\t\tthis.host.ui,\n\t\t\tPRIME_INFERENCE_PROVIDER_ID,\n\t\t\t(_success, _message) => {},\n\t\t\tPRIME_INFERENCE_PROVIDER_NAME,\n\t\t);\n\t\tconst handle = showFullPaneOverlay(this.host.ui, dialog, {\n\t\t\tmaxContentWidth: 88,\n\t\t\tsuspendFullscreenMouse: true,\n\t\t});\n\t\tconst closeDialog = () => {\n\t\t\thandle.hide();\n\t\t\tthis.host.ui.requestRender();\n\t\t};\n\n\t\ttry {\n\t\t\tconst apiKey = (await dialog.showPrompt(\"Enter Prime Inference API key:\")).trim();\n\t\t\tif (!apiKey) {\n\t\t\t\tthrow new Error(\"API key cannot be empty.\");\n\t\t\t}\n\t\t\tdialog.showProgress(\"Checking Prime Inference access...\");\n\t\t\tconst config = loadPrimeCliConfig(this.host.modelRegistry.authStorage.getPrimeCliConfigPath());\n\t\t\tconst access = await checkPrimeInferenceAccess(apiKey, config.baseUrl, { signal: dialog.signal });\n\t\t\tif (dialog.signal.aborted) {\n\t\t\t\tcloseDialog();\n\t\t\t\treturn { status: \"cancelled\" };\n\t\t\t}\n\t\t\tif (!access.ok) {\n\t\t\t\tconst status = access.status === undefined ? \"\" : `HTTP ${access.status}: `;\n\t\t\t\tthrow new Error(`Prime API key does not have Prime Inference access (${status}${access.message})`);\n\t\t\t}\n\t\t\treturn await this.completePrimeInferenceLogin(apiKey, dialog, closeDialog);\n\t\t} catch (error: unknown) {\n\t\t\tcloseDialog();\n\t\t\tconst errorMsg = error instanceof Error ? error.message : String(error);\n\t\t\tif (!dialog.signal.aborted && errorMsg !== \"Login cancelled\") {\n\t\t\t\tthis.host.showError(`Failed to login to ${PRIME_INFERENCE_PROVIDER_NAME}: ${errorMsg}`);\n\t\t\t\treturn { status: \"failed\" };\n\t\t\t}\n\t\t\treturn { status: \"cancelled\" };\n\t\t}\n\t}\n\n\tasync runPrimeAgentTracesLogin(): Promise<AuthenticationResult> {\n\t\tthis.host.showError(\n\t\t\t`${BASE_CONTEXT_TRACES_PROVIDER_NAME} login is not configured. Set BASE_CONTEXT_TRACES_BASE_URL and a dedicated BASE_CONTEXT_TRACES_API_KEY; Prime Inference credentials are not used for traces.`,\n\t\t);\n\t\treturn { status: \"failed\" };\n\t}\n\n\tprivate async showApiKeyLoginDialog(\n\t\tproviderId: string,\n\t\tproviderName: string,\n\t\tkind: \"provider\" | \"service\" = \"provider\",\n\t): Promise<AuthenticationResult> {\n\t\tconst dialog = new LoginDialogComponent(this.host.ui, providerId, (_success, _message) => {}, providerName);\n\n\t\tconst handle = showFullPaneOverlay(this.host.ui, dialog, 88);\n\n\t\tconst closeDialog = () => {\n\t\t\thandle.hide();\n\t\t\tthis.host.ui.requestRender();\n\t\t};\n\n\t\ttry {\n\t\t\tconst apiKey = (await dialog.showPrompt(\"Enter API key:\")).trim();\n\t\t\tif (!apiKey) {\n\t\t\t\tthrow new Error(\"API key cannot be empty.\");\n\t\t\t}\n\n\t\t\tthis.host.modelRegistry.authStorage.set(providerId, { type: \"api_key\", key: apiKey });\n\n\t\t\tcloseDialog();\n\t\t\treturn await this.completeProviderAuthentication(providerId, providerName, \"api_key\", undefined, kind);\n\t\t} catch (error: unknown) {\n\t\t\tcloseDialog();\n\t\t\tconst errorMsg = error instanceof Error ? error.message : String(error);\n\t\t\tif (errorMsg !== \"Login cancelled\") {\n\t\t\t\tthis.host.showError(`Failed to save API key for ${providerName}: ${errorMsg}`);\n\t\t\t\treturn { status: \"failed\" };\n\t\t\t}\n\t\t\treturn { status: \"cancelled\" };\n\t\t}\n\t}\n\n\tprivate showOAuthLoginSelect(dialogHandle: OverlayHandle, prompt: OAuthSelectPrompt): Promise<string | undefined> {\n\t\treturn new Promise((resolve) => {\n\t\t\tdialogHandle.setHidden(true);\n\t\t\tlet selectorHandle: OverlayHandle | undefined;\n\t\t\tconst restoreDialog = () => {\n\t\t\t\tselectorHandle?.hide();\n\t\t\t\tdialogHandle.setHidden(false);\n\t\t\t\tdialogHandle.focus();\n\t\t\t\tthis.host.ui.requestRender();\n\t\t\t};\n\t\t\tconst labels = prompt.options.map((option) => option.label);\n\t\t\tconst selector = new ExtensionSelectorComponent(\n\t\t\t\tprompt.message,\n\t\t\t\tlabels,\n\t\t\t\t(optionLabel) => {\n\t\t\t\t\trestoreDialog();\n\t\t\t\t\tresolve(prompt.options.find((option) => option.label === optionLabel)?.id);\n\t\t\t\t},\n\t\t\t\t() => {\n\t\t\t\t\trestoreDialog();\n\t\t\t\t\tresolve(undefined);\n\t\t\t\t},\n\t\t\t\t{ getRows: () => this.host.ui.terminal.rows },\n\t\t\t);\n\t\t\tselectorHandle = showFullPaneOverlay(this.host.ui, selector, 76);\n\t\t});\n\t}\n\n\tprivate async showLoginDialog(\n\t\tproviderId: string,\n\t\tproviderName: string,\n\t\tkind: \"provider\" | \"service\" = \"provider\",\n\t): Promise<AuthenticationResult> {\n\t\tconst contract = getProviderAuthContract(providerId);\n\t\tif (contract.oauth !== \"validated\") {\n\t\t\tthis.host.showError(contract.guidance);\n\t\t\treturn { status: \"failed\" };\n\t\t}\n\t\tconst providerInfo = this.host.modelRegistry.authStorage\n\t\t\t.getOAuthProviders()\n\t\t\t.find((provider) => provider.id === providerId);\n\n\t\tconst usesCallbackServer = providerInfo?.usesCallbackServer ?? false;\n\n\t\tconst dialog = new LoginDialogComponent(this.host.ui, providerId, (_success, _message) => {}, providerName);\n\n\t\tconst dialogHandle = showFullPaneOverlay(this.host.ui, dialog, {\n\t\t\tmaxContentWidth: 88,\n\t\t\tsuspendFullscreenMouse: true,\n\t\t});\n\n\t\tlet manualCodeResolve: ((code: string) => void) | undefined;\n\t\tlet manualCodeReject: ((err: Error) => void) | undefined;\n\t\tconst manualCodePromise = new Promise<string>((resolve, reject) => {\n\t\t\tmanualCodeResolve = resolve;\n\t\t\tmanualCodeReject = reject;\n\t\t});\n\n\t\tconst closeDialog = () => {\n\t\t\tdialogHandle.hide();\n\t\t\tthis.host.ui.requestRender();\n\t\t};\n\n\t\ttry {\n\t\t\tawait this.host.modelRegistry.authStorage.login(providerId as OAuthProviderId, {\n\t\t\t\tonAuth: (info: { url: string; instructions?: string }) => {\n\t\t\t\t\tdialog.showAuth(info.url, info.instructions);\n\n\t\t\t\t\tif (usesCallbackServer) {\n\t\t\t\t\t\tdialog\n\t\t\t\t\t\t\t.showManualInput(\"Paste redirect URL below, or complete login in browser:\")\n\t\t\t\t\t\t\t.then((value) => {\n\t\t\t\t\t\t\t\tif (value && manualCodeResolve) {\n\t\t\t\t\t\t\t\t\tmanualCodeResolve(value);\n\t\t\t\t\t\t\t\t\tmanualCodeResolve = undefined;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t.catch(() => {\n\t\t\t\t\t\t\t\tif (manualCodeReject) {\n\t\t\t\t\t\t\t\t\tmanualCodeReject(new Error(\"Login cancelled\"));\n\t\t\t\t\t\t\t\t\tmanualCodeReject = undefined;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t} else if (providerId === \"github-copilot\") {\n\t\t\t\t\t\tdialog.showWaiting(\"Waiting for browser authentication...\");\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\tonPrompt: async (prompt: { message: string; placeholder?: string }) => {\n\t\t\t\t\treturn dialog.showPrompt(prompt.message, prompt.placeholder);\n\t\t\t\t},\n\n\t\t\t\tonProgress: (message: string) => {\n\t\t\t\t\tdialog.showProgress(message);\n\t\t\t\t},\n\n\t\t\t\tonSelect: (prompt: OAuthSelectPrompt) => this.showOAuthLoginSelect(dialogHandle, prompt),\n\n\t\t\t\tonManualCodeInput: () => manualCodePromise,\n\n\t\t\t\tsignal: dialog.signal,\n\t\t\t});\n\n\t\t\tcloseDialog();\n\t\t\treturn await this.completeProviderAuthentication(providerId, providerName, \"oauth\", undefined, kind);\n\t\t} catch (error: unknown) {\n\t\t\tcloseDialog();\n\t\t\tconst errorMsg = error instanceof Error ? error.message : String(error);\n\t\t\tif (errorMsg !== \"Login cancelled\") {\n\t\t\t\tthis.host.showError(`Failed to login to ${providerName}: ${errorMsg}`);\n\t\t\t\treturn { status: \"failed\" };\n\t\t\t}\n\t\t\treturn { status: \"cancelled\" };\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"auth-flows.d.ts","sourceRoot":"","sources":["../../../src/modes/interactive/auth-flows.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAiB,GAAG,EAAE,MAAM,gCAAgC,CAAC;AAEzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAOlE,OAAO,EACN,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EAGzB,MAAM,gCAAgC,CAAC;AAGxC,MAAM,MAAM,oBAAoB,GAC7B;IACA,MAAM,EAAE,SAAS,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,4EAA4E;IAC5E,IAAI,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;CAC7B,GACD;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,GACvB;IAAE,MAAM,EAAE,QAAQ,CAAA;CAAE,CAAC;AAExB,eAAO,MAAM,mBAAmB,mBAAmB,CAAC;AAEpD,eAAO,MAAM,mCAAmC,0MACwJ,CAAC;AAMzM,wBAAsB,mCAAmC,CACxD,aAAa,EAAE,aAAa,EAC5B,KAAK,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,GACrC,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAmB7B;AAID,wBAAgB,qBAAqB,CACpC,UAAU,EAAE,MAAM,EAClB,gBAAgB,EAAE,WAAW,CAAC,MAAM,CAAC,EACrC,kBAAkB,GAAE,WAAW,CAAC,MAAM,CAA4B,GAChE,OAAO,CAQT;AAED,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC;IACjB,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,0GAA0G;IAC1G,kBAAkB,IAAI,OAAO,CAAC,aAAa,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACnE,oFAAoF;IACpF,aAAa,CAAC,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,2EAA2E;IAC3E,gBAAgB,CAAC,IAAI,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC/B,eAAe,CAAC,EAAE,oBAAoB,CAAC;CACvC;AAED,8FAA8F;AAC9F,qBAAa,iBAAiB;IACjB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAjC,YAA6B,IAAI,EAAE,qBAAqB,EAAI;IAE5D;;;;;;OAMG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAazE;IAED,QAAQ,CAAC,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAqC1E;IAED,aAAa,CAAC,cAAc,EAAE,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CASjF;IAED,SAAS,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA8ClC;IAED,uBAAuB,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,oBAAoB,EAAE,CAkC9E;IAED,OAAO,CAAC,wBAAwB;YA4BlB,8BAA8B;YAyB9B,6BAA6B;YAe7B,0BAA0B;YAK1B,sBAAsB;YAgCtB,qBAAqB;IAmCnC,OAAO,CAAC,oBAAoB;YA4Bd,eAAe;CA6F7B","sourcesContent":["import * as path from \"node:path\";\nimport { getProviders, type OAuthProviderId, type OAuthSelectPrompt } from \"@ponythewhite/base-context-ai\";\nimport type { OverlayHandle, TUI } from \"@ponythewhite/base-context-tui\";\nimport { getAuthPath, getDocsPath } from \"../../config.js\";\nimport type { ModelRegistry } from \"../../core/model-registry.js\";\nimport { getProviderAuthContract } from \"../../core/provider-contracts.js\";\nimport { BUILT_IN_PROVIDER_DISPLAY_NAMES } from \"../../core/provider-display-names.js\";\nimport { SERPER_CREDENTIAL_ID, SERPER_CREDENTIAL_NAME } from \"../../core/websearch-credential.js\";\nimport { showFullPaneOverlay } from \"./components/centered-overlay.js\";\nimport { ExtensionSelectorComponent } from \"./components/extension-selector.js\";\nimport { LoginDialogComponent } from \"./components/login-dialog.js\";\nimport {\n\ttype AuthSelectorCategory,\n\ttype AuthSelectorProvider,\n\tcompareAuthSelectorProviders,\n\tOAuthSelectorComponent,\n} from \"./components/oauth-selector.js\";\nimport { theme } from \"./theme/theme.js\";\n\nexport type AuthenticationResult =\n\t| {\n\t\t\tstatus: \"success\";\n\t\t\tproviderId: string;\n\t\t\tproviderName: string;\n\t\t\tauthType: \"oauth\" | \"api_key\";\n\t\t\t/** \"service\" credentials (e.g. web search) don't affect model selection. */\n\t\t\tkind?: \"provider\" | \"service\";\n\t }\n\t| { status: \"cancelled\" }\n\t| { status: \"failed\" };\n\nexport const BEDROCK_PROVIDER_ID = \"amazon-bedrock\";\n\nexport const ANTHROPIC_SUBSCRIPTION_AUTH_WARNING =\n\t\"Anthropic subscription auth is active. Third-party harness usage draws from extra usage and is billed per token, not your Claude plan limits. Manage extra usage at https://claude.ai/settings/usage.\";\n\nfunction isAnthropicSubscriptionAuthKey(apiKey: string | undefined): boolean {\n\treturn typeof apiKey === \"string\" && apiKey.startsWith(\"sk-ant-oat\");\n}\n\nexport async function getAnthropicSubscriptionAuthWarning(\n\tmodelRegistry: ModelRegistry,\n\tmodel: { provider: string } | undefined,\n): Promise<string | undefined> {\n\tif (!model || model.provider !== \"anthropic\" || getProviderAuthContract(model.provider).oauth !== \"supported\") {\n\t\treturn undefined;\n\t}\n\n\tconst storedCredential = modelRegistry.authStorage.get(\"anthropic\");\n\tif (storedCredential?.type === \"oauth\") {\n\t\treturn ANTHROPIC_SUBSCRIPTION_AUTH_WARNING;\n\t}\n\n\ttry {\n\t\tconst apiKey = await modelRegistry.getApiKeyForProvider(model.provider);\n\t\tif (isAnthropicSubscriptionAuthKey(apiKey)) {\n\t\t\treturn ANTHROPIC_SUBSCRIPTION_AUTH_WARNING;\n\t\t}\n\t} catch {\n\t\t// Ignore auth lookup failures for warning-only checks.\n\t}\n\treturn undefined;\n}\n\nconst BUILT_IN_MODEL_PROVIDERS = new Set<string>(getProviders());\n\nexport function isApiKeyLoginProvider(\n\tproviderId: string,\n\toauthProviderIds: ReadonlySet<string>,\n\tbuiltInProviderIds: ReadonlySet<string> = BUILT_IN_MODEL_PROVIDERS,\n): boolean {\n\tif (BUILT_IN_PROVIDER_DISPLAY_NAMES[providerId]) {\n\t\treturn true;\n\t}\n\tif (builtInProviderIds.has(providerId)) {\n\t\treturn false;\n\t}\n\treturn !oauthProviderIds.has(providerId);\n}\n\nexport interface ProviderAuthFlowsHost {\n\treadonly ui: TUI;\n\treadonly modelRegistry: ModelRegistry;\n\tshowStatus(message: string): void;\n\tshowError(message: string): void;\n\t/** Models currently visible to the host; used to detect providers configured via external credentials. */\n\tgetAvailableModels(): Promise<ReadonlyArray<{ provider: string }>>;\n\t/** Invoked after stored credentials change so the host can refresh dependent UI. */\n\tonAuthChanged?(): void | Promise<void>;\n\t/** Invoked after a successful login (e.g. to surface billing warnings). */\n\tonLoginCompleted?(): void;\n}\n\nexport interface ProviderLoginOptions {\n\tauthType?: \"oauth\" | \"api_key\";\n\tinitialCategory?: AuthSelectorCategory;\n}\n\n/** Shared auth dialogs: host-specific refresh and billing effects remain outside the flow. */\nexport class ProviderAuthFlows {\n\tconstructor(private readonly host: ProviderAuthFlowsHost) {}\n\n\t/**\n\t * Run the OAuth login flow for an MCP integration server.\n\t *\n\t * The provider must already be registered (the McpManager does this as\n\t * `mcp:<server>`). On success the credentials land in auth.json and the\n\t * caller should reload resources so the integration's skill enables.\n\t */\n\trunMcpLogin(server: string, label?: string): Promise<AuthenticationResult> {\n\t\tconst providerId = `mcp:${server}`;\n\t\tconst contract = getProviderAuthContract(providerId);\n\t\tif (contract.oauth !== \"supported\") {\n\t\t\tthis.host.showError(contract.guidance);\n\t\t\treturn Promise.resolve({ status: \"failed\" });\n\t\t}\n\t\tconst provider = this.host.modelRegistry.authStorage.getOAuthProviders().find((p) => p.id === providerId);\n\t\tif (!provider) {\n\t\t\tthis.host.showError(`Unknown MCP integration: ${server}`);\n\t\t\treturn Promise.resolve({ status: \"failed\" });\n\t\t}\n\t\treturn this.showLoginDialog(providerId, label ?? provider.name, \"service\");\n\t}\n\n\trunLogin(options: ProviderLoginOptions = {}): Promise<AuthenticationResult> {\n\t\tconst { authType, initialCategory } = options;\n\t\tconst providerOptions = this.getLoginProviderOptions(authType);\n\t\tif (providerOptions.length === 0) {\n\t\t\tthis.host.showStatus(\n\t\t\t\tauthType === \"oauth\"\n\t\t\t\t\t? \"No supported OAuth providers are registered. Use /login to configure an API-key provider.\"\n\t\t\t\t\t: authType === \"api_key\"\n\t\t\t\t\t\t? \"No API key providers available.\"\n\t\t\t\t\t\t: \"No providers available.\",\n\t\t\t);\n\t\t\treturn Promise.resolve({ status: \"failed\" });\n\t\t}\n\n\t\treturn new Promise((resolve) => {\n\t\t\tlet handle: OverlayHandle | undefined;\n\t\t\tconst close = () => {\n\t\t\t\thandle?.hide();\n\t\t\t\tthis.host.ui.requestRender();\n\t\t\t};\n\t\t\tconst selector = new OAuthSelectorComponent(\n\t\t\t\t\"login\",\n\t\t\t\tthis.host.modelRegistry.authStorage,\n\t\t\t\tproviderOptions,\n\t\t\t\tasync (providerOption: AuthSelectorProvider) => {\n\t\t\t\t\tclose();\n\t\t\t\t\tresolve(await this.loginProvider(providerOption));\n\t\t\t\t},\n\t\t\t\t() => {\n\t\t\t\t\tclose();\n\t\t\t\t\tresolve({ status: \"cancelled\" });\n\t\t\t\t},\n\t\t\t\t(providerId) => this.host.modelRegistry.getProviderAuthStatus(providerId),\n\t\t\t\t{ getRows: () => this.host.ui.terminal.rows, initialCategory },\n\t\t\t);\n\t\t\thandle = showFullPaneOverlay(this.host.ui, selector, 78);\n\t\t});\n\t}\n\n\tloginProvider(providerOption: AuthSelectorProvider): Promise<AuthenticationResult> {\n\t\tconst kind = providerOption.category === \"service\" ? \"service\" : \"provider\";\n\t\tif (providerOption.authType === \"oauth\") {\n\t\t\treturn this.showLoginDialog(providerOption.id, providerOption.name, kind);\n\t\t}\n\t\tif (providerOption.id === BEDROCK_PROVIDER_ID) {\n\t\t\treturn this.showBedrockSetupDialog(providerOption.id, providerOption.name);\n\t\t}\n\t\treturn this.showApiKeyLoginDialog(providerOption.id, providerOption.name, kind);\n\t}\n\n\trunLogout(): Promise<string | null> {\n\t\tconst providerOptions = this.getLogoutProviderOptions();\n\t\tif (providerOptions.length === 0) {\n\t\t\tthis.host.showStatus(\n\t\t\t\t\"No stored credentials to remove. /logout only removes credentials saved by /login; environment variables and models.json config are unchanged.\",\n\t\t\t);\n\t\t\treturn Promise.resolve(null);\n\t\t}\n\n\t\treturn new Promise((resolve) => {\n\t\t\tlet handle: OverlayHandle | undefined;\n\t\t\tconst close = () => {\n\t\t\t\thandle?.hide();\n\t\t\t\tthis.host.ui.requestRender();\n\t\t\t};\n\t\t\tconst selector = new OAuthSelectorComponent(\n\t\t\t\t\"logout\",\n\t\t\t\tthis.host.modelRegistry.authStorage,\n\t\t\t\tproviderOptions,\n\t\t\t\tasync (providerOption: AuthSelectorProvider) => {\n\t\t\t\t\tclose();\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.host.modelRegistry.authStorage.logout(providerOption.id);\n\t\t\t\t\t\tthis.host.modelRegistry.refresh();\n\t\t\t\t\t\tawait this.host.onAuthChanged?.();\n\t\t\t\t\t\tconst message =\n\t\t\t\t\t\t\tproviderOption.authType === \"oauth\"\n\t\t\t\t\t\t\t\t? `Logged out of ${providerOption.name}`\n\t\t\t\t\t\t\t\t: `Removed stored API key for ${providerOption.name}. Environment variables and models.json config are unchanged.`;\n\t\t\t\t\t\tthis.host.showStatus(message);\n\t\t\t\t\t\tresolve(providerOption.id);\n\t\t\t\t\t} catch (error: unknown) {\n\t\t\t\t\t\tthis.host.showError(`Logout failed: ${error instanceof Error ? error.message : String(error)}`);\n\t\t\t\t\t\tresolve(null);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t() => {\n\t\t\t\t\tclose();\n\t\t\t\t\tresolve(null);\n\t\t\t\t},\n\t\t\t\tundefined,\n\t\t\t\t{ getRows: () => this.host.ui.terminal.rows },\n\t\t\t);\n\t\t\thandle = showFullPaneOverlay(this.host.ui, selector, 78);\n\t\t});\n\t}\n\n\tgetLoginProviderOptions(authType?: \"oauth\" | \"api_key\"): AuthSelectorProvider[] {\n\t\tconst authStorage = this.host.modelRegistry.authStorage;\n\t\tconst oauthProviders = authStorage.getOAuthProviders();\n\t\tconst oauthProviderIds = new Set(oauthProviders.map((provider) => provider.id));\n\t\tconst options: AuthSelectorProvider[] = oauthProviders.map((provider) => ({\n\t\t\tid: provider.id,\n\t\t\tname: provider.name,\n\t\t\tauthType: \"oauth\",\n\t\t\t// MCP integrations (mcp:<server>) are services, not model providers.\n\t\t\t...(provider.id.startsWith(\"mcp:\") ? { category: \"service\" as const } : {}),\n\t\t}));\n\n\t\tconst modelProviders = new Set(this.host.modelRegistry.getAll().map((model) => model.provider));\n\t\tfor (const providerId of modelProviders) {\n\t\t\tif (!isApiKeyLoginProvider(providerId, oauthProviderIds)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\toptions.push({\n\t\t\t\tid: providerId,\n\t\t\t\tname: this.host.modelRegistry.getProviderDisplayName(providerId),\n\t\t\t\tauthType: \"api_key\",\n\t\t\t});\n\t\t}\n\n\t\t// Serper is a skill credential, not a model provider, so add it manually.\n\t\toptions.push({\n\t\t\tid: SERPER_CREDENTIAL_ID,\n\t\t\tname: SERPER_CREDENTIAL_NAME,\n\t\t\tauthType: \"api_key\",\n\t\t\tcategory: \"service\",\n\t\t});\n\n\t\tconst filteredOptions = authType ? options.filter((option) => option.authType === authType) : options;\n\t\treturn filteredOptions.sort(compareAuthSelectorProviders);\n\t}\n\n\tprivate getLogoutProviderOptions(): AuthSelectorProvider[] {\n\t\tconst authStorage = this.host.modelRegistry.authStorage;\n\t\tconst options: AuthSelectorProvider[] = [];\n\n\t\tconst oauthProvidersById = new Map(authStorage.getOAuthProviders().map((p) => [p.id, p]));\n\t\tfor (const providerId of authStorage.list()) {\n\t\t\tconst credential = authStorage.get(providerId);\n\t\t\tif (!credential) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst isSerper = providerId === SERPER_CREDENTIAL_ID;\n\t\t\tconst isMcp = providerId.startsWith(\"mcp:\");\n\t\t\tconst name = isSerper\n\t\t\t\t? SERPER_CREDENTIAL_NAME\n\t\t\t\t: isMcp\n\t\t\t\t\t? (oauthProvidersById.get(providerId)?.name ?? providerId.slice(\"mcp:\".length))\n\t\t\t\t\t: this.host.modelRegistry.getProviderDisplayName(providerId);\n\t\t\toptions.push({\n\t\t\t\tid: providerId,\n\t\t\t\tname,\n\t\t\t\tauthType: credential.type,\n\t\t\t\tcategory: isSerper || isMcp ? \"service\" : \"provider\",\n\t\t\t});\n\t\t}\n\n\t\treturn options.sort((a, b) => a.name.localeCompare(b.name));\n\t}\n\n\tprivate async completeProviderAuthentication(\n\t\tproviderId: string,\n\t\tproviderName: string,\n\t\tauthType: \"oauth\" | \"api_key\",\n\t\tstatusSuffix?: string,\n\t\tkind: \"provider\" | \"service\" = \"provider\",\n\t\tcredentialPath: string = getAuthPath(),\n\t): Promise<AuthenticationResult> {\n\t\tthis.host.modelRegistry.refresh();\n\n\t\tconst actionLabel = authType === \"oauth\" ? `Logged in to ${providerName}` : `Saved API key for ${providerName}`;\n\t\tawait this.host.onAuthChanged?.();\n\t\tthis.host.showStatus(\n\t\t\t`${actionLabel}. Credentials saved to ${credentialPath}${statusSuffix ? `. ${statusSuffix}` : \"\"}`,\n\t\t);\n\t\tthis.host.onLoginCompleted?.();\n\t\treturn {\n\t\t\tstatus: \"success\",\n\t\t\tproviderId,\n\t\t\tproviderName,\n\t\t\tauthType,\n\t\t\tkind,\n\t\t};\n\t}\n\n\tprivate async completeExternalProviderSetup(\n\t\tproviderId: string,\n\t\tproviderName: string,\n\t): Promise<AuthenticationResult> {\n\t\tthis.host.modelRegistry.refresh();\n\t\tawait this.host.onAuthChanged?.();\n\t\tthis.host.showStatus(`${providerName} uses external credentials. Select a model after configuring them.`);\n\t\treturn {\n\t\t\tstatus: \"success\",\n\t\t\tproviderId,\n\t\t\tproviderName,\n\t\t\tauthType: \"api_key\",\n\t\t};\n\t}\n\n\tprivate async hasAvailableProviderModels(providerId: string): Promise<boolean> {\n\t\tconst models = await this.host.getAvailableModels();\n\t\treturn models.some((model) => model.provider === providerId);\n\t}\n\n\tprivate async showBedrockSetupDialog(providerId: string, providerName: string): Promise<AuthenticationResult> {\n\t\tconst dialog = new LoginDialogComponent(this.host.ui, providerId, () => {}, providerName, \"Amazon Bedrock setup\");\n\t\tconst handle = showFullPaneOverlay(this.host.ui, dialog, 88);\n\t\tconst closeDialog = () => {\n\t\t\thandle.hide();\n\t\t\tthis.host.ui.requestRender();\n\t\t};\n\n\t\ttry {\n\t\t\tawait dialog.showContinueInfo([\n\t\t\t\ttheme.fg(\"text\", \"Amazon Bedrock uses AWS credentials instead of a single API key.\"),\n\t\t\t\ttheme.fg(\"text\", \"Configure an AWS profile, IAM keys, bearer token, or role-based credentials.\"),\n\t\t\t\ttheme.fg(\"muted\", \"See:\"),\n\t\t\t\ttheme.fg(\"accent\", ` ${path.join(getDocsPath(), \"providers.md\")}`),\n\t\t\t]);\n\t\t\tcloseDialog();\n\t\t\tif (!(await this.hasAvailableProviderModels(providerId))) {\n\t\t\t\tthis.host.showStatus(`${providerName} credentials were not detected. Configure them, then reopen /model.`);\n\t\t\t\treturn { status: \"cancelled\" };\n\t\t\t}\n\t\t\treturn await this.completeExternalProviderSetup(providerId, providerName);\n\t\t} catch (error: unknown) {\n\t\t\tcloseDialog();\n\t\t\tconst errorMsg = error instanceof Error ? error.message : String(error);\n\t\t\tif (errorMsg !== \"Login cancelled\") {\n\t\t\t\tthis.host.showError(`Failed to set up ${providerName}: ${errorMsg}`);\n\t\t\t\treturn { status: \"failed\" };\n\t\t\t}\n\t\t\treturn { status: \"cancelled\" };\n\t\t}\n\t}\n\n\tprivate async showApiKeyLoginDialog(\n\t\tproviderId: string,\n\t\tproviderName: string,\n\t\tkind: \"provider\" | \"service\" = \"provider\",\n\t): Promise<AuthenticationResult> {\n\t\tconst dialog = new LoginDialogComponent(this.host.ui, providerId, (_success, _message) => {}, providerName);\n\n\t\tconst handle = showFullPaneOverlay(this.host.ui, dialog, 88);\n\n\t\tconst closeDialog = () => {\n\t\t\thandle.hide();\n\t\t\tthis.host.ui.requestRender();\n\t\t};\n\n\t\ttry {\n\t\t\tconst apiKey = (await dialog.showPrompt(\"Enter API key:\")).trim();\n\t\t\tif (!apiKey) {\n\t\t\t\tthrow new Error(\"API key cannot be empty.\");\n\t\t\t}\n\n\t\t\tthis.host.modelRegistry.authStorage.set(providerId, { type: \"api_key\", key: apiKey });\n\n\t\t\tcloseDialog();\n\t\t\treturn await this.completeProviderAuthentication(providerId, providerName, \"api_key\", undefined, kind);\n\t\t} catch (error: unknown) {\n\t\t\tcloseDialog();\n\t\t\tconst errorMsg = error instanceof Error ? error.message : String(error);\n\t\t\tif (errorMsg !== \"Login cancelled\") {\n\t\t\t\tthis.host.showError(`Failed to save API key for ${providerName}: ${errorMsg}`);\n\t\t\t\treturn { status: \"failed\" };\n\t\t\t}\n\t\t\treturn { status: \"cancelled\" };\n\t\t}\n\t}\n\n\tprivate showOAuthLoginSelect(dialogHandle: OverlayHandle, prompt: OAuthSelectPrompt): Promise<string | undefined> {\n\t\treturn new Promise((resolve) => {\n\t\t\tdialogHandle.setHidden(true);\n\t\t\tlet selectorHandle: OverlayHandle | undefined;\n\t\t\tconst restoreDialog = () => {\n\t\t\t\tselectorHandle?.hide();\n\t\t\t\tdialogHandle.setHidden(false);\n\t\t\t\tdialogHandle.focus();\n\t\t\t\tthis.host.ui.requestRender();\n\t\t\t};\n\t\t\tconst labels = prompt.options.map((option) => option.label);\n\t\t\tconst selector = new ExtensionSelectorComponent(\n\t\t\t\tprompt.message,\n\t\t\t\tlabels,\n\t\t\t\t(optionLabel) => {\n\t\t\t\t\trestoreDialog();\n\t\t\t\t\tresolve(prompt.options.find((option) => option.label === optionLabel)?.id);\n\t\t\t\t},\n\t\t\t\t() => {\n\t\t\t\t\trestoreDialog();\n\t\t\t\t\tresolve(undefined);\n\t\t\t\t},\n\t\t\t\t{ getRows: () => this.host.ui.terminal.rows },\n\t\t\t);\n\t\t\tselectorHandle = showFullPaneOverlay(this.host.ui, selector, 76);\n\t\t});\n\t}\n\n\tprivate async showLoginDialog(\n\t\tproviderId: string,\n\t\tproviderName: string,\n\t\tkind: \"provider\" | \"service\" = \"provider\",\n\t): Promise<AuthenticationResult> {\n\t\tconst contract = getProviderAuthContract(providerId);\n\t\tif (contract.oauth !== \"supported\") {\n\t\t\tthis.host.showError(contract.guidance);\n\t\t\treturn { status: \"failed\" };\n\t\t}\n\t\tconst providerInfo = this.host.modelRegistry.authStorage\n\t\t\t.getOAuthProviders()\n\t\t\t.find((provider) => provider.id === providerId);\n\n\t\tconst usesCallbackServer = providerInfo?.usesCallbackServer ?? false;\n\n\t\tconst dialog = new LoginDialogComponent(this.host.ui, providerId, (_success, _message) => {}, providerName);\n\n\t\tconst dialogHandle = showFullPaneOverlay(this.host.ui, dialog, {\n\t\t\tmaxContentWidth: 88,\n\t\t\tsuspendFullscreenMouse: true,\n\t\t});\n\n\t\tlet manualCodeResolve: ((code: string) => void) | undefined;\n\t\tlet manualCodeReject: ((err: Error) => void) | undefined;\n\t\tconst manualCodePromise = new Promise<string>((resolve, reject) => {\n\t\t\tmanualCodeResolve = resolve;\n\t\t\tmanualCodeReject = reject;\n\t\t});\n\n\t\tconst closeDialog = () => {\n\t\t\tdialogHandle.hide();\n\t\t\tthis.host.ui.requestRender();\n\t\t};\n\n\t\ttry {\n\t\t\tawait this.host.modelRegistry.authStorage.login(providerId as OAuthProviderId, {\n\t\t\t\tonAuth: (info: { url: string; instructions?: string }) => {\n\t\t\t\t\tdialog.showAuth(info.url, info.instructions);\n\n\t\t\t\t\tif (usesCallbackServer) {\n\t\t\t\t\t\tdialog\n\t\t\t\t\t\t\t.showManualInput(\"Paste redirect URL below, or complete login in browser:\")\n\t\t\t\t\t\t\t.then((value) => {\n\t\t\t\t\t\t\t\tif (value && manualCodeResolve) {\n\t\t\t\t\t\t\t\t\tmanualCodeResolve(value);\n\t\t\t\t\t\t\t\t\tmanualCodeResolve = undefined;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t.catch(() => {\n\t\t\t\t\t\t\t\tif (manualCodeReject) {\n\t\t\t\t\t\t\t\t\tmanualCodeReject(new Error(\"Login cancelled\"));\n\t\t\t\t\t\t\t\t\tmanualCodeReject = undefined;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t} else if (providerId === \"github-copilot\") {\n\t\t\t\t\t\tdialog.showWaiting(\"Waiting for browser authentication...\");\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\tonPrompt: async (prompt: { message: string; placeholder?: string }) => {\n\t\t\t\t\treturn dialog.showPrompt(prompt.message, prompt.placeholder);\n\t\t\t\t},\n\n\t\t\t\tonProgress: (message: string) => {\n\t\t\t\t\tdialog.showProgress(message);\n\t\t\t\t},\n\n\t\t\t\tonSelect: (prompt: OAuthSelectPrompt) => this.showOAuthLoginSelect(dialogHandle, prompt),\n\n\t\t\t\tonManualCodeInput: () => manualCodePromise,\n\n\t\t\t\tsignal: dialog.signal,\n\t\t\t});\n\n\t\t\tcloseDialog();\n\t\t\treturn await this.completeProviderAuthentication(\n\t\t\t\tproviderId,\n\t\t\t\tproviderName,\n\t\t\t\t\"oauth\",\n\t\t\t\tkind === \"provider\" ? \"Use /model to select a model\" : undefined,\n\t\t\t\tkind,\n\t\t\t);\n\t\t} catch (error: unknown) {\n\t\t\tcloseDialog();\n\t\t\tconst errorMsg = error instanceof Error ? error.message : String(error);\n\t\t\tif (errorMsg !== \"Login cancelled\") {\n\t\t\t\tthis.host.showError(`Failed to login to ${providerName}: ${errorMsg}`);\n\t\t\t\treturn { status: \"failed\" };\n\t\t\t}\n\t\t\treturn { status: \"cancelled\" };\n\t\t}\n\t}\n}\n"]}