@adecore/agents 0.0.1 → 0.17.0-beta.1

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 (348) hide show
  1. package/LICENSE +110 -0
  2. package/README.md +33 -0
  3. package/dist/async.d.ts +2 -0
  4. package/dist/async.js +31 -0
  5. package/dist/chat/attachment-store.d.ts +10 -0
  6. package/dist/chat/attachment-store.js +93 -0
  7. package/dist/chat/backend.d.ts +214 -0
  8. package/dist/chat/backend.js +1 -0
  9. package/dist/chat/background-work.d.ts +8 -0
  10. package/dist/chat/background-work.js +33 -0
  11. package/dist/chat/bookmark-store.d.ts +25 -0
  12. package/dist/chat/bookmark-store.js +141 -0
  13. package/dist/chat/chat-core.d.ts +311 -0
  14. package/dist/chat/chat-core.js +1025 -0
  15. package/dist/chat/chat-log.d.ts +33 -0
  16. package/dist/chat/chat-log.js +163 -0
  17. package/dist/chat/chat-process.d.ts +46 -0
  18. package/dist/chat/chat-process.js +190 -0
  19. package/dist/chat/chat-session.d.ts +209 -0
  20. package/dist/chat/chat-session.js +1511 -0
  21. package/dist/chat/chat-store.d.ts +37 -0
  22. package/dist/chat/chat-store.js +202 -0
  23. package/dist/chat/chat-title.d.ts +10 -0
  24. package/dist/chat/chat-title.js +74 -0
  25. package/dist/chat/claude-backend.d.ts +35 -0
  26. package/dist/chat/claude-backend.js +214 -0
  27. package/dist/chat/claude-protocol.d.ts +41 -0
  28. package/dist/chat/claude-protocol.js +642 -0
  29. package/dist/chat/claude-title.d.ts +11 -0
  30. package/dist/chat/claude-title.js +97 -0
  31. package/dist/chat/claude-transcript.d.ts +28 -0
  32. package/dist/chat/claude-transcript.js +211 -0
  33. package/dist/chat/codex-backend.d.ts +51 -0
  34. package/dist/chat/codex-backend.js +364 -0
  35. package/dist/chat/codex-protocol.d.ts +56 -0
  36. package/dist/chat/codex-protocol.js +767 -0
  37. package/dist/chat/codex-thread.d.ts +32 -0
  38. package/dist/chat/codex-thread.js +131 -0
  39. package/dist/chat/codex-transport.d.ts +42 -0
  40. package/dist/chat/codex-transport.js +188 -0
  41. package/dist/chat/composer-preferences.d.ts +15 -0
  42. package/dist/chat/composer-preferences.js +46 -0
  43. package/dist/chat/context-breakdown.d.ts +2 -0
  44. package/dist/chat/context-breakdown.js +74 -0
  45. package/dist/chat/delta-coalescer.d.ts +12 -0
  46. package/dist/chat/delta-coalescer.js +55 -0
  47. package/dist/chat/errors.d.ts +4 -0
  48. package/dist/chat/errors.js +4 -0
  49. package/dist/chat/fake-claude.d.ts +3 -0
  50. package/dist/chat/fake-claude.js +982 -0
  51. package/dist/chat/fake-cli.d.ts +25 -0
  52. package/dist/chat/fake-cli.js +157 -0
  53. package/dist/chat/fake-codex.d.ts +10 -0
  54. package/dist/chat/fake-codex.js +502 -0
  55. package/dist/chat/fixtures/claude-2.1.285-auto-fallback.json +24 -0
  56. package/dist/chat/fixtures/claude-2.1.285-native-children.json +6600 -0
  57. package/dist/chat/fixtures/claude-2.1.285-resume-direct-compact.json +202 -0
  58. package/dist/chat/fixtures/claude-2.1.285-resume-task-notification.json +57 -0
  59. package/dist/chat/fixtures/claude-projects/-work-demo/5f1c2a9e-0b7d-4c1e-9a53-3e2f8d6b7a10/subagents/agent-a4c2e8f10b3d5a7e9.jsonl +10 -0
  60. package/dist/chat/fixtures/claude-projects/-work-demo/5f1c2a9e-0b7d-4c1e-9a53-3e2f8d6b7a10/subagents/agent-a4c2e8f10b3d5a7e9.meta.json +1 -0
  61. package/dist/chat/fixtures/claude-projects/-work-demo/5f1c2a9e-0b7d-4c1e-9a53-3e2f8d6b7a10/subagents/agent-a9b8c7d6e5f4a3b21.jsonl +2 -0
  62. package/dist/chat/fixtures/claude-projects/-work-demo/5f1c2a9e-0b7d-4c1e-9a53-3e2f8d6b7a10/subagents/agent-a9b8c7d6e5f4a3b21.meta.json +1 -0
  63. package/dist/chat/fixtures/codex-0.159.2-native-approval.json +119 -0
  64. package/dist/chat/fixtures/codex-0.159.2-native-file-approval.json +136 -0
  65. package/dist/chat/fixtures/codex-0.159.2-native-interacted.json +220 -0
  66. package/dist/chat/fixtures/codex-0.159.2-usage-windows.json +74 -0
  67. package/dist/chat/input.d.ts +19 -0
  68. package/dist/chat/input.js +71 -0
  69. package/dist/chat/limit-resume.d.ts +11 -0
  70. package/dist/chat/limit-resume.js +68 -0
  71. package/dist/chat/projector.d.ts +60 -0
  72. package/dist/chat/projector.js +860 -0
  73. package/dist/chat/request-summary.d.ts +3 -0
  74. package/dist/chat/request-summary.js +143 -0
  75. package/dist/chat/subagent-projection.d.ts +8 -0
  76. package/dist/chat/subagent-projection.js +40 -0
  77. package/dist/chat/subagent-reader.d.ts +66 -0
  78. package/dist/chat/subagent-reader.js +396 -0
  79. package/dist/chat/subagent-settlement.d.ts +6 -0
  80. package/dist/chat/subagent-settlement.js +103 -0
  81. package/dist/chat/thread.d.ts +30 -0
  82. package/dist/chat/thread.js +147 -0
  83. package/dist/chat/wake-chat.d.ts +20 -0
  84. package/dist/chat/wake-chat.js +27 -0
  85. package/dist/client-sinks.d.ts +9 -0
  86. package/dist/client-sinks.js +34 -0
  87. package/dist/coded-error.d.ts +5 -0
  88. package/dist/coded-error.js +17 -0
  89. package/dist/context/argv.d.ts +11 -0
  90. package/dist/context/argv.js +58 -0
  91. package/dist/context/refusal.d.ts +9 -0
  92. package/dist/context/refusal.js +38 -0
  93. package/dist/context/verb.d.ts +85 -0
  94. package/dist/context/verb.js +233 -0
  95. package/dist/error-text.d.ts +5 -0
  96. package/dist/error-text.js +24 -0
  97. package/dist/events.d.ts +12 -0
  98. package/dist/events.js +1 -0
  99. package/dist/fs.d.ts +9 -0
  100. package/dist/fs.js +107 -0
  101. package/dist/host/agent-host.d.ts +28 -0
  102. package/dist/host/agent-host.js +105 -0
  103. package/dist/host/environment.d.ts +7 -0
  104. package/dist/host/environment.js +22 -0
  105. package/dist/host/handlers.d.ts +30 -0
  106. package/dist/host/handlers.js +111 -0
  107. package/dist/host/memory-port.d.ts +2 -0
  108. package/dist/host/memory-port.js +25 -0
  109. package/dist/host/wiring.d.ts +40 -0
  110. package/dist/host/wiring.js +120 -0
  111. package/dist/lineage.d.ts +44 -0
  112. package/dist/lineage.js +134 -0
  113. package/dist/messages/deliver-message.d.ts +21 -0
  114. package/dist/messages/deliver-message.js +42 -0
  115. package/dist/messages/deliver-notice.d.ts +25 -0
  116. package/dist/messages/deliver-notice.js +75 -0
  117. package/dist/messages/notice-notes.d.ts +15 -0
  118. package/dist/messages/notice-notes.js +26 -0
  119. package/dist/messages/notice-store.d.ts +30 -0
  120. package/dist/messages/notice-store.js +120 -0
  121. package/dist/modes.d.ts +11 -0
  122. package/dist/modes.js +28 -0
  123. package/dist/outbox/manual-clock.d.ts +10 -0
  124. package/dist/outbox/manual-clock.js +25 -0
  125. package/dist/outbox/outbox-worker.d.ts +44 -0
  126. package/dist/outbox/outbox-worker.js +173 -0
  127. package/dist/outbox/outbox.d.ts +37 -0
  128. package/dist/outbox/outbox.js +76 -0
  129. package/dist/providers/accounts/accounts.d.ts +20 -0
  130. package/dist/providers/accounts/accounts.js +158 -0
  131. package/dist/providers/accounts/launch.d.ts +17 -0
  132. package/dist/providers/accounts/launch.js +30 -0
  133. package/dist/providers/accounts/service.d.ts +87 -0
  134. package/dist/providers/accounts/service.js +538 -0
  135. package/dist/providers/accounts/shadow-home.d.ts +8 -0
  136. package/dist/providers/accounts/shadow-home.js +70 -0
  137. package/dist/providers/accounts/status.d.ts +12 -0
  138. package/dist/providers/accounts/status.js +85 -0
  139. package/dist/providers/accounts/store.d.ts +14 -0
  140. package/dist/providers/accounts/store.js +112 -0
  141. package/dist/providers/accounts/test-accounts.d.ts +12 -0
  142. package/dist/providers/accounts/test-accounts.js +38 -0
  143. package/dist/providers/accounts/variables.d.ts +27 -0
  144. package/dist/providers/accounts/variables.js +94 -0
  145. package/dist/providers/catalog.d.ts +17 -0
  146. package/dist/providers/catalog.js +76 -0
  147. package/dist/providers/claude-models.json +114 -0
  148. package/dist/providers/claude-provider.d.ts +4 -0
  149. package/dist/providers/claude-provider.js +29 -0
  150. package/dist/providers/claude.d.ts +15 -0
  151. package/dist/providers/claude.js +105 -0
  152. package/dist/providers/codex-models.json +135 -0
  153. package/dist/providers/codex-provider.d.ts +4 -0
  154. package/dist/providers/codex-provider.js +27 -0
  155. package/dist/providers/codex-rules.d.ts +9 -0
  156. package/dist/providers/codex-rules.js +35 -0
  157. package/dist/providers/codex.d.ts +14 -0
  158. package/dist/providers/codex.js +52 -0
  159. package/dist/providers/detect.d.ts +6 -0
  160. package/dist/providers/detect.js +30 -0
  161. package/dist/providers/provider.d.ts +25 -0
  162. package/dist/providers/provider.js +1 -0
  163. package/dist/providers/registry.d.ts +28 -0
  164. package/dist/providers/registry.js +118 -0
  165. package/dist/record-directory.d.ts +27 -0
  166. package/dist/record-directory.js +114 -0
  167. package/dist/run-process.d.ts +13 -0
  168. package/dist/run-process.js +42 -0
  169. package/dist/serializer.d.ts +9 -0
  170. package/dist/serializer.js +34 -0
  171. package/dist/skills.d.ts +21 -0
  172. package/dist/skills.js +174 -0
  173. package/dist/tasks/background-limit.d.ts +16 -0
  174. package/dist/tasks/background-limit.js +55 -0
  175. package/dist/tasks/end-children.d.ts +34 -0
  176. package/dist/tasks/end-children.js +53 -0
  177. package/dist/tasks/give-task.d.ts +14 -0
  178. package/dist/tasks/give-task.js +33 -0
  179. package/dist/tasks/task-coordinator.d.ts +52 -0
  180. package/dist/tasks/task-coordinator.js +323 -0
  181. package/dist/tasks/task-store.d.ts +49 -0
  182. package/dist/tasks/task-store.js +197 -0
  183. package/dist/tasks/task-work.d.ts +47 -0
  184. package/dist/tasks/task-work.js +28 -0
  185. package/dist/tasks/waiting-child.d.ts +51 -0
  186. package/dist/tasks/waiting-child.js +143 -0
  187. package/dist/tasks/wake-parent.d.ts +19 -0
  188. package/dist/tasks/wake-parent.js +109 -0
  189. package/dist/tasks/wiring.d.ts +51 -0
  190. package/dist/tasks/wiring.js +151 -0
  191. package/dist/title-file.d.ts +2 -0
  192. package/dist/title-file.js +55 -0
  193. package/dist/usage/accounts.d.ts +15 -0
  194. package/dist/usage/accounts.js +64 -0
  195. package/dist/usage/aggregate.d.ts +12 -0
  196. package/dist/usage/aggregate.js +154 -0
  197. package/dist/usage/exchange.d.ts +16 -0
  198. package/dist/usage/exchange.js +84 -0
  199. package/dist/usage/index-file.d.ts +15 -0
  200. package/dist/usage/index-file.js +123 -0
  201. package/dist/usage/limits/monitor.d.ts +50 -0
  202. package/dist/usage/limits/monitor.js +179 -0
  203. package/dist/usage/limits/normalize.d.ts +21 -0
  204. package/dist/usage/limits/normalize.js +160 -0
  205. package/dist/usage/limits/probe.d.ts +9 -0
  206. package/dist/usage/limits/probe.js +113 -0
  207. package/dist/usage/prices-snapshot.json +1071 -0
  208. package/dist/usage/pricing.d.ts +34 -0
  209. package/dist/usage/pricing.js +186 -0
  210. package/dist/usage/projects.d.ts +17 -0
  211. package/dist/usage/projects.js +49 -0
  212. package/dist/usage/readers/claude.d.ts +3 -0
  213. package/dist/usage/readers/claude.js +59 -0
  214. package/dist/usage/readers/codex.d.ts +23 -0
  215. package/dist/usage/readers/codex.js +155 -0
  216. package/dist/usage/record.d.ts +15 -0
  217. package/dist/usage/record.js +39 -0
  218. package/dist/usage/roots.d.ts +12 -0
  219. package/dist/usage/roots.js +29 -0
  220. package/dist/usage/scanner.d.ts +30 -0
  221. package/dist/usage/scanner.js +234 -0
  222. package/dist/usage/usage-service.d.ts +35 -0
  223. package/dist/usage/usage-service.js +130 -0
  224. package/dist/watch-seam.d.ts +29 -0
  225. package/dist/watch-seam.js +78 -0
  226. package/dist/watch-test-helpers.d.ts +28 -0
  227. package/dist/watch-test-helpers.js +86 -0
  228. package/package.json +42 -3
  229. package/src/async.ts +40 -0
  230. package/src/chat/attachment-store.ts +108 -0
  231. package/src/chat/backend.ts +199 -0
  232. package/src/chat/background-work.ts +42 -0
  233. package/src/chat/bookmark-store.ts +166 -0
  234. package/src/chat/chat-core.ts +1228 -0
  235. package/src/chat/chat-log.ts +187 -0
  236. package/src/chat/chat-process.ts +237 -0
  237. package/src/chat/chat-session.ts +1723 -0
  238. package/src/chat/chat-store.ts +261 -0
  239. package/src/chat/chat-title.ts +90 -0
  240. package/src/chat/claude-backend.ts +235 -0
  241. package/src/chat/claude-protocol.ts +684 -0
  242. package/src/chat/claude-title.ts +106 -0
  243. package/src/chat/claude-transcript.ts +233 -0
  244. package/src/chat/codex-backend.ts +397 -0
  245. package/src/chat/codex-protocol.ts +872 -0
  246. package/src/chat/codex-thread.ts +162 -0
  247. package/src/chat/codex-transport.ts +224 -0
  248. package/src/chat/composer-preferences.ts +67 -0
  249. package/src/chat/context-breakdown.ts +80 -0
  250. package/src/chat/delta-coalescer.ts +62 -0
  251. package/src/chat/errors.ts +25 -0
  252. package/src/chat/fake-claude.ts +1006 -0
  253. package/src/chat/fake-cli.ts +199 -0
  254. package/src/chat/fake-codex.ts +534 -0
  255. package/src/chat/fixtures/claude-2.1.285-auto-fallback.json +24 -0
  256. package/src/chat/fixtures/claude-2.1.285-native-children.json +6600 -0
  257. package/src/chat/fixtures/claude-2.1.285-resume-direct-compact.json +202 -0
  258. package/src/chat/fixtures/claude-2.1.285-resume-task-notification.json +57 -0
  259. package/src/chat/fixtures/claude-projects/-work-demo/5f1c2a9e-0b7d-4c1e-9a53-3e2f8d6b7a10/subagents/agent-a4c2e8f10b3d5a7e9.jsonl +10 -0
  260. package/src/chat/fixtures/claude-projects/-work-demo/5f1c2a9e-0b7d-4c1e-9a53-3e2f8d6b7a10/subagents/agent-a4c2e8f10b3d5a7e9.meta.json +1 -0
  261. package/src/chat/fixtures/claude-projects/-work-demo/5f1c2a9e-0b7d-4c1e-9a53-3e2f8d6b7a10/subagents/agent-a9b8c7d6e5f4a3b21.jsonl +2 -0
  262. package/src/chat/fixtures/claude-projects/-work-demo/5f1c2a9e-0b7d-4c1e-9a53-3e2f8d6b7a10/subagents/agent-a9b8c7d6e5f4a3b21.meta.json +1 -0
  263. package/src/chat/fixtures/codex-0.159.2-native-approval.json +119 -0
  264. package/src/chat/fixtures/codex-0.159.2-native-file-approval.json +136 -0
  265. package/src/chat/fixtures/codex-0.159.2-native-interacted.json +220 -0
  266. package/src/chat/fixtures/codex-0.159.2-usage-windows.json +74 -0
  267. package/src/chat/input.ts +89 -0
  268. package/src/chat/limit-resume.ts +74 -0
  269. package/src/chat/projector.ts +969 -0
  270. package/src/chat/request-summary.ts +168 -0
  271. package/src/chat/subagent-projection.ts +45 -0
  272. package/src/chat/subagent-reader.ts +469 -0
  273. package/src/chat/subagent-settlement.ts +111 -0
  274. package/src/chat/thread.ts +167 -0
  275. package/src/chat/wake-chat.ts +45 -0
  276. package/src/client-sinks.ts +39 -0
  277. package/src/coded-error.ts +18 -0
  278. package/src/context/argv.ts +61 -0
  279. package/src/context/refusal.ts +50 -0
  280. package/src/context/verb.ts +392 -0
  281. package/src/error-text.ts +28 -0
  282. package/src/events.ts +9 -0
  283. package/src/fs.ts +118 -0
  284. package/src/host/agent-host.ts +124 -0
  285. package/src/host/environment.ts +31 -0
  286. package/src/host/handlers.ts +142 -0
  287. package/src/host/memory-port.ts +27 -0
  288. package/src/host/wiring.ts +164 -0
  289. package/src/lineage.ts +159 -0
  290. package/src/messages/deliver-message.ts +61 -0
  291. package/src/messages/deliver-notice.ts +120 -0
  292. package/src/messages/notice-notes.ts +34 -0
  293. package/src/messages/notice-store.ts +142 -0
  294. package/src/modes.ts +38 -0
  295. package/src/outbox/manual-clock.ts +31 -0
  296. package/src/outbox/outbox-worker.ts +214 -0
  297. package/src/outbox/outbox.ts +106 -0
  298. package/src/providers/accounts/accounts.ts +192 -0
  299. package/src/providers/accounts/launch.ts +55 -0
  300. package/src/providers/accounts/service.ts +632 -0
  301. package/src/providers/accounts/shadow-home.ts +85 -0
  302. package/src/providers/accounts/status.ts +106 -0
  303. package/src/providers/accounts/store.ts +158 -0
  304. package/src/providers/accounts/test-accounts.ts +48 -0
  305. package/src/providers/accounts/variables.ts +132 -0
  306. package/src/providers/catalog.ts +90 -0
  307. package/src/providers/claude-models.json +114 -0
  308. package/src/providers/claude-provider.ts +32 -0
  309. package/src/providers/claude.ts +123 -0
  310. package/src/providers/codex-models.json +135 -0
  311. package/src/providers/codex-provider.ts +30 -0
  312. package/src/providers/codex-rules.ts +54 -0
  313. package/src/providers/codex.ts +69 -0
  314. package/src/providers/detect.ts +40 -0
  315. package/src/providers/provider.ts +46 -0
  316. package/src/providers/registry.ts +150 -0
  317. package/src/record-directory.ts +136 -0
  318. package/src/run-process.ts +61 -0
  319. package/src/serializer.ts +41 -0
  320. package/src/skills.ts +199 -0
  321. package/src/tasks/background-limit.ts +72 -0
  322. package/src/tasks/end-children.ts +100 -0
  323. package/src/tasks/give-task.ts +52 -0
  324. package/src/tasks/task-coordinator.ts +384 -0
  325. package/src/tasks/task-store.ts +236 -0
  326. package/src/tasks/task-work.ts +62 -0
  327. package/src/tasks/waiting-child.ts +203 -0
  328. package/src/tasks/wake-parent.ts +142 -0
  329. package/src/tasks/wiring.ts +231 -0
  330. package/src/title-file.ts +57 -0
  331. package/src/usage/accounts.ts +86 -0
  332. package/src/usage/aggregate.ts +220 -0
  333. package/src/usage/exchange.ts +93 -0
  334. package/src/usage/index-file.ts +178 -0
  335. package/src/usage/limits/monitor.ts +239 -0
  336. package/src/usage/limits/normalize.ts +188 -0
  337. package/src/usage/limits/probe.ts +120 -0
  338. package/src/usage/prices-snapshot.json +1071 -0
  339. package/src/usage/pricing.ts +236 -0
  340. package/src/usage/projects.ts +65 -0
  341. package/src/usage/readers/claude.ts +60 -0
  342. package/src/usage/readers/codex.ts +196 -0
  343. package/src/usage/record.ts +60 -0
  344. package/src/usage/roots.ts +39 -0
  345. package/src/usage/scanner.ts +265 -0
  346. package/src/usage/usage-service.ts +161 -0
  347. package/src/watch-seam.ts +111 -0
  348. package/src/watch-test-helpers.ts +102 -0
@@ -0,0 +1,192 @@
1
+ import { homedir } from 'node:os';
2
+ import { isAbsolute, join, resolve } from 'node:path';
3
+ import { AgentKindSchema, ProviderAccountSchema, type AgentKind, type ProviderAccount, type ProviderAccountMap } from '@adecore/agent-contracts';
4
+ import type { ChatProvider } from '../provider.ts';
5
+ import { DEFAULT_ACCOUNTS_HOST, variablesProblem, type AccountsHost, type ReservedVariables } from './variables.ts';
6
+
7
+ export type Env = Record<string, string | undefined>;
8
+
9
+ const KNOWN_KINDS: readonly string[] = AgentKindSchema.options;
10
+
11
+ export function isKnownKind(kind: string): kind is AgentKind {
12
+ return KNOWN_KINDS.includes(kind);
13
+ }
14
+
15
+ /* The default account of a CLI is the folder the CLI uses without being told, and its id is the CLI's kind. */
16
+ export function isDefaultAccount(id: string, account: Pick<ProviderAccount, 'kind'>): boolean {
17
+ return id === account.kind;
18
+ }
19
+
20
+ export function expandHome(path: string, env: Env): string {
21
+ const home = env.HOME ?? homedir();
22
+ if (path === '~') {
23
+ return home;
24
+ }
25
+ if (path.startsWith('~/')) {
26
+ return join(home, path.slice(2));
27
+ }
28
+ return resolve(path);
29
+ }
30
+
31
+ /* A folder the host can resolve the same way whatever folder it was started in. */
32
+ function isRootedPath(path: string): boolean {
33
+ return path === '~' || path.startsWith('~/') || isAbsolute(path);
34
+ }
35
+
36
+ /*
37
+ * What is wrong with an account of a CLI this version knows, or null when nothing is. An account of
38
+ * an unknown kind is never judged: it is kept the way it was written, for a version that knows it.
39
+ */
40
+ export function accountProblem(
41
+ id: string,
42
+ account: ProviderAccount,
43
+ provider: ChatProvider,
44
+ env: Env,
45
+ reserved: ReservedVariables = { host: DEFAULT_ACCOUNTS_HOST, folderVariables: [] }
46
+ ): string | null {
47
+ if (isKnownKind(id) && id !== account.kind) {
48
+ return `"${id}" is the id of the default ${id} account`;
49
+ }
50
+ const variables = variablesProblem(account.env ?? [], reserved);
51
+ if (variables !== null) {
52
+ return variables;
53
+ }
54
+ if (isDefaultAccount(id, account)) {
55
+ return account.home !== undefined || account.shadowHome !== undefined ? 'The default account uses the folder of the CLI itself' : null;
56
+ }
57
+ if (provider.home === undefined) {
58
+ return null;
59
+ }
60
+ if (account.home === undefined) {
61
+ return 'An account needs a config folder';
62
+ }
63
+ if (!isRootedPath(account.home)) {
64
+ return 'A config folder is an absolute path or starts with ~';
65
+ }
66
+ if (account.shadowHome === undefined) {
67
+ return null;
68
+ }
69
+ if (account.kind !== 'codex') {
70
+ return 'Only a Codex account has a shadow home';
71
+ }
72
+ if (!isRootedPath(account.shadowHome)) {
73
+ return 'A shadow home is an absolute path or starts with ~';
74
+ }
75
+ if (expandHome(account.shadowHome, env) === expandHome(account.home, env)) {
76
+ return 'The shadow home has to be another folder than the config folder';
77
+ }
78
+ return null;
79
+ }
80
+
81
+ /* The variables that point a CLI at its folder, which no account may set by hand. */
82
+ export function folderVariablesOf(providerOf: (kind: AgentKind) => ChatProvider): string[] {
83
+ return AgentKindSchema.options.flatMap((kind) => {
84
+ const home = providerOf(kind).home;
85
+ return home === undefined ? [] : [home.env];
86
+ });
87
+ }
88
+
89
+ /* The map with a default account for every CLI this version knows, those first and in catalog order. */
90
+ export function withDefaults(accounts: ProviderAccountMap): ProviderAccountMap {
91
+ const complete: ProviderAccountMap = {};
92
+ for (const kind of KNOWN_KINDS) {
93
+ complete[kind] = accounts[kind] ?? { kind };
94
+ }
95
+ for (const [id, account] of Object.entries(accounts)) {
96
+ complete[id] ??= account;
97
+ }
98
+ return complete;
99
+ }
100
+
101
+ /* The folder the CLI itself falls back on, as the host's own environment sets it. */
102
+ export function defaultFolder(provider: ChatProvider, env: Env): string {
103
+ if (provider.home === undefined) {
104
+ return '';
105
+ }
106
+ return env[provider.home.env] ?? join(env.HOME ?? homedir(), provider.home.fallback);
107
+ }
108
+
109
+ /* The folder a CLI of this account is started with: for a Codex account with a shadow home, that one. */
110
+ export function accountFolder(id: string, account: ProviderAccount, provider: ChatProvider, env: Env): string {
111
+ if (isDefaultAccount(id, account) || provider.home === undefined || account.home === undefined) {
112
+ return defaultFolder(provider, env);
113
+ }
114
+ return expandHome(account.shadowHome ?? account.home, env);
115
+ }
116
+
117
+ /* Where the account's conversations are written, which a shadow home shares with its `home`. */
118
+ export function transcriptFolder(id: string, account: ProviderAccount, provider: ChatProvider, env: Env): string {
119
+ if (isDefaultAccount(id, account) || provider.home === undefined || account.home === undefined) {
120
+ return defaultFolder(provider, env);
121
+ }
122
+ return expandHome(account.home, env);
123
+ }
124
+
125
+ /*
126
+ * The environment of a CLI process of this account. The default account runs in the host's own. Any
127
+ * other gets its folder in the CLI's variable, and loses the variables that would sign the CLI in over
128
+ * that folder's login: an inherited key would win, and only the bill would tell. Never HOME, which
129
+ * moves where Claude Code looks in the keychain. The account's own variables come last, so a key a
130
+ * person set there is the one that counts.
131
+ */
132
+ export function accountEnv(id: string, account: ProviderAccount, provider: ChatProvider, baseEnv: Env, variables: Record<string, string> = {}): Env {
133
+ const withVariables = (env: Env): Env => (Object.keys(variables).length === 0 ? env : { ...env, ...variables });
134
+ if (isDefaultAccount(id, account) || provider.home === undefined || account.home === undefined) {
135
+ return withVariables(baseEnv);
136
+ }
137
+ const env = { ...baseEnv };
138
+ for (const name of provider.home.loginEnv) {
139
+ delete env[name];
140
+ }
141
+ env[provider.home.env] = accountFolder(id, account, provider, baseEnv);
142
+ return withVariables(env);
143
+ }
144
+
145
+ export interface NamedAccount {
146
+ id: string;
147
+ account: ProviderAccount;
148
+ }
149
+
150
+ /*
151
+ * Whether a conversation of one account can go on under the other: the same CLI, reading the same
152
+ * transcripts. Two Codex accounts over one `home` can, shadow home or not; two Claude folders never.
153
+ */
154
+ export function canContinue(from: NamedAccount, to: NamedAccount, providerOf: (kind: AgentKind) => ChatProvider, env: Env): boolean {
155
+ if (from.id === to.id) {
156
+ return true;
157
+ }
158
+ const kind = from.account.kind;
159
+ if (kind !== to.account.kind || !isKnownKind(kind)) {
160
+ return false;
161
+ }
162
+ const provider = providerOf(kind);
163
+ return transcriptFolder(from.id, from.account, provider, env) === transcriptFolder(to.id, to.account, provider, env);
164
+ }
165
+
166
+ /*
167
+ * An account as the file holds it, or null for one to drop. An unknown kind comes back as it was
168
+ * read, extra fields included; a known kind has to parse and make sense.
169
+ */
170
+ export function readAccount(
171
+ id: string,
172
+ raw: unknown,
173
+ providerOf: (kind: AgentKind) => ChatProvider,
174
+ env: Env,
175
+ host: AccountsHost = DEFAULT_ACCOUNTS_HOST
176
+ ): unknown {
177
+ if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {
178
+ return null;
179
+ }
180
+ const kind = (raw as { kind?: unknown }).kind;
181
+ if (typeof kind !== 'string' || kind === '') {
182
+ return null;
183
+ }
184
+ if (!isKnownKind(kind)) {
185
+ return isKnownKind(id) ? null : raw;
186
+ }
187
+ const parsed = ProviderAccountSchema.safeParse(raw);
188
+ if (!parsed.success || accountProblem(id, parsed.data, providerOf(kind), env, { host, folderVariables: folderVariablesOf(providerOf) }) !== null) {
189
+ return null;
190
+ }
191
+ return parsed.data;
192
+ }
@@ -0,0 +1,55 @@
1
+ import type { AgentKind } from '@adecore/agent-contracts';
2
+ import { CodedError } from '../../coded-error.ts';
3
+ import type { Env } from './accounts.ts';
4
+
5
+ export class AccountError extends CodedError<'account-unavailable' | 'account-incompatible'> {}
6
+
7
+ /*
8
+ * The accounts as a terminal or a chat starts a CLI under one. Absent, or the CLI's own kind, is the
9
+ * default account, which runs in the host's own environment plus the variables a person gave it.
10
+ */
11
+ export interface AccountLaunches {
12
+ /* The environment of a CLI of this kind under this account. Throws an `AccountError` for one this machine cannot start. */
13
+ envFor(kind: AgentKind, account: string | undefined, baseEnv: Env): Env;
14
+ /* The config folder the CLI writes this account's conversations in; null for an account this machine does not have. */
15
+ transcriptFolder(kind: AgentKind, account: string | undefined): string | null;
16
+ /* The config folder the CLI of this account starts with, a Codex shadow home included; null for an account this machine does not have. */
17
+ homeFolder(kind: AgentKind, account: string | undefined): string | null;
18
+ /* Whether a conversation of one account can go on under the other: the same CLI, reading the same transcripts. */
19
+ canContinue(kind: AgentKind, from: string | undefined, to: string | undefined): boolean;
20
+ /* What a person calls the account. */
21
+ labelOf(account: string): string;
22
+ /* A CLI started under this account a moment ago, which is what keeps its plan read. */
23
+ launched?(kind: AgentKind, account: string | undefined): void;
24
+ }
25
+
26
+ export function isDefaultAccountOf(kind: AgentKind, account: string | undefined): boolean {
27
+ return account === undefined || account === kind;
28
+ }
29
+
30
+ /* The id a record or a node keeps: none for the default account, so nothing without accounts changes on disk. */
31
+ export function storedAccount(kind: AgentKind, account: string | undefined): string | undefined {
32
+ return isDefaultAccountOf(kind, account) ? undefined : account;
33
+ }
34
+
35
+ /* The environment of a launch; without accounts wired only the default account can start, with no variables of its own. */
36
+ export function launchEnv(accounts: AccountLaunches | null, kind: AgentKind, account: string | undefined, baseEnv: Env): Env {
37
+ if (accounts !== null) {
38
+ return accounts.envFor(kind, account, baseEnv);
39
+ }
40
+ if (isDefaultAccountOf(kind, account)) {
41
+ return baseEnv;
42
+ }
43
+ throw new AccountError('account-unavailable', `The account '${account}' is not available on this machine: it keeps no accounts.`);
44
+ }
45
+
46
+ /* An environment without its unset variables, which is what a spawned process is given. */
47
+ export function definedEnv(env: Env): Record<string, string> {
48
+ const defined: Record<string, string> = {};
49
+ for (const [key, value] of Object.entries(env)) {
50
+ if (value !== undefined) {
51
+ defined[key] = value;
52
+ }
53
+ }
54
+ return defined;
55
+ }