@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,97 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { readdir, stat } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { usageRoots } from '../usage/roots.js';
5
+ import { cleanTitle, readLines } from '../title-file.js';
6
+ // The two records carry these words; a line without them is never parsed.
7
+ const MARKERS = ['"ai-title"', '"custom-title"'];
8
+ /*
9
+ * The name Claude Code gave a session, out of its own transcript. It writes an `ai-title` record a
10
+ * few seconds after the first prompt, anywhere in the file and more than once, and a `custom-title`
11
+ * when a person ran /rename in the CLI, which wins because a person chose it. A transcript only ever
12
+ * grows, so each path is read from where the previous read stopped: a file of many megabytes costs
13
+ * its full read once, and every read after that only the lines added since.
14
+ */
15
+ export class ClaudeTitleReader {
16
+ progress = new Map();
17
+ found = new Map();
18
+ projectsDir;
19
+ chunkBytes;
20
+ constructor(projectsDir = usageRoots().find((root) => root.provider === 'claude')?.path ?? '', chunkBytes = 4 * 1024 * 1024) {
21
+ this.projectsDir = projectsDir;
22
+ this.chunkBytes = chunkBytes;
23
+ }
24
+ /* The title of a session found by its id, for a chat, which knows no transcript path; in the projects of its account. */
25
+ async forSession(agentSessionId, projectsDir = this.projectsDir) {
26
+ const path = await this.locate(agentSessionId, projectsDir);
27
+ return path === null ? null : await this.forTranscript(path);
28
+ }
29
+ async forTranscript(path) {
30
+ let size;
31
+ try {
32
+ size = (await stat(path)).size;
33
+ }
34
+ catch {
35
+ return null;
36
+ }
37
+ let progress = this.progress.get(path);
38
+ // Smaller than where we were is a file that was replaced, not one that grew.
39
+ if (!progress || size < progress.offset) {
40
+ progress = { offset: 0, aiTitle: null, customTitle: null };
41
+ this.progress.set(path, progress);
42
+ }
43
+ if (size > progress.offset) {
44
+ const current = progress;
45
+ current.offset = await readLines(path, current.offset, size, this.chunkBytes, (line) => this.take(line, current));
46
+ }
47
+ return progress.customTitle ?? progress.aiTitle;
48
+ }
49
+ take(line, progress) {
50
+ if (!MARKERS.some((marker) => line.includes(marker))) {
51
+ return;
52
+ }
53
+ let record;
54
+ try {
55
+ record = JSON.parse(line);
56
+ }
57
+ catch {
58
+ return;
59
+ }
60
+ if (typeof record !== 'object' || record === null) {
61
+ return;
62
+ }
63
+ const entry = record;
64
+ if (entry.type === 'ai-title') {
65
+ progress.aiTitle = cleanTitle(entry.aiTitle) ?? progress.aiTitle;
66
+ }
67
+ else if (entry.type === 'custom-title') {
68
+ progress.customTitle = cleanTitle(entry.customTitle) ?? progress.customTitle;
69
+ }
70
+ }
71
+ /* The folder a transcript sits in is named after the working directory, so the file name is the only key a session id gives. */
72
+ async locate(agentSessionId, projectsDir) {
73
+ const known = this.found.get(agentSessionId);
74
+ if (known !== undefined && existsSync(known)) {
75
+ return known;
76
+ }
77
+ if (projectsDir === '' || agentSessionId.includes('/')) {
78
+ return null;
79
+ }
80
+ let dirs;
81
+ try {
82
+ dirs = await readdir(projectsDir);
83
+ }
84
+ catch {
85
+ return null;
86
+ }
87
+ const file = `${agentSessionId}.jsonl`;
88
+ for (const dir of dirs) {
89
+ const path = join(projectsDir, dir, file);
90
+ if (existsSync(path)) {
91
+ this.found.set(agentSessionId, path);
92
+ return path;
93
+ }
94
+ }
95
+ return null;
96
+ }
97
+ }
@@ -0,0 +1,28 @@
1
+ import type { ChatHistoryResult, ChatItem } from '@adecore/agent-contracts';
2
+ export interface SubagentMeta {
3
+ agentId: string;
4
+ toolUseId: string | null;
5
+ parentAgentId: string | null;
6
+ description: string | null;
7
+ transcript: string;
8
+ }
9
+ export declare function claudeProjectSlug(cwd: string): string;
10
+ export declare function findSubagentsDir(projectsDir: string, cwd: string, sessionId: string): Promise<string | null>;
11
+ export declare function readSubagentMetas(dir: string): Promise<SubagentMeta[]>;
12
+ export declare function findWorkflowAgent(subagentsDir: string, agentId: string): Promise<SubagentMeta | null>;
13
+ export declare class TranscriptProjection {
14
+ readonly path: string;
15
+ private thread;
16
+ private projector;
17
+ private protocol;
18
+ private offset;
19
+ private size;
20
+ private mtimeMs;
21
+ private lineTime;
22
+ constructor(path: string);
23
+ refresh(): Promise<boolean>;
24
+ items(): ChatItem[];
25
+ page(limit: number, cursor?: string): ChatHistoryResult;
26
+ private reset;
27
+ private take;
28
+ }
@@ -0,0 +1,211 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { readdir, readFile, stat } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { readLines } from '../title-file.js';
5
+ import { ClaudeProtocol } from './claude-protocol.js';
6
+ import { readingThread, settledReading } from './subagent-projection.js';
7
+ const CHUNK_BYTES = 4 * 1024 * 1024;
8
+ function isRecord(value) {
9
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
10
+ }
11
+ function str(value) {
12
+ return typeof value === 'string' && value !== '' ? value : null;
13
+ }
14
+ /* The words of a user line that somebody said, or null for a line that carries tool results. */
15
+ function spokenText(content) {
16
+ if (typeof content === 'string') {
17
+ return content;
18
+ }
19
+ if (!Array.isArray(content) || content.some((block) => isRecord(block) && block.type === 'tool_result')) {
20
+ return null;
21
+ }
22
+ const texts = content.filter((block) => isRecord(block) && block.type === 'text').map((block) => String(block.text ?? ''));
23
+ return texts.length === 0 ? null : texts.join('\n');
24
+ }
25
+ /* The folder name Claude Code gives a working directory: every character that is not a letter or a digit becomes a dash. */
26
+ export function claudeProjectSlug(cwd) {
27
+ return cwd.replace(/[^a-zA-Z0-9]/g, '-');
28
+ }
29
+ /*
30
+ * Where the subagents of a session keep their transcripts. The folder of the chat's own directory
31
+ * first; a slug the CLI wrote differently (or a session resumed from somewhere else) is found by the
32
+ * session id alone, which is unique across every project.
33
+ */
34
+ export async function findSubagentsDir(projectsDir, cwd, sessionId) {
35
+ if (projectsDir === '' || sessionId.includes('/') || sessionId.includes('..')) {
36
+ return null;
37
+ }
38
+ const own = join(projectsDir, claudeProjectSlug(cwd), sessionId, 'subagents');
39
+ if (existsSync(own)) {
40
+ return own;
41
+ }
42
+ let dirs;
43
+ try {
44
+ dirs = await readdir(projectsDir);
45
+ }
46
+ catch {
47
+ return null;
48
+ }
49
+ for (const dir of dirs) {
50
+ const candidate = join(projectsDir, dir, sessionId, 'subagents');
51
+ if (existsSync(candidate)) {
52
+ return candidate;
53
+ }
54
+ }
55
+ return null;
56
+ }
57
+ /* Every meta file in a subagents folder that says which agent it is about; one that does not parse is left out. */
58
+ export async function readSubagentMetas(dir) {
59
+ let names;
60
+ try {
61
+ names = await readdir(dir);
62
+ }
63
+ catch {
64
+ return [];
65
+ }
66
+ const metas = [];
67
+ for (const name of names) {
68
+ const match = /^agent-(.+)\.meta\.json$/.exec(name);
69
+ if (!match) {
70
+ continue;
71
+ }
72
+ let parsed;
73
+ try {
74
+ parsed = JSON.parse(await readFile(join(dir, name), 'utf8'));
75
+ }
76
+ catch {
77
+ continue;
78
+ }
79
+ if (!isRecord(parsed)) {
80
+ continue;
81
+ }
82
+ const agentId = match[1];
83
+ metas.push({
84
+ agentId,
85
+ toolUseId: str(parsed.toolUseId),
86
+ parentAgentId: str(parsed.parentAgentId),
87
+ description: str(parsed.description),
88
+ transcript: join(dir, `agent-${agentId}.jsonl`)
89
+ });
90
+ }
91
+ return metas;
92
+ }
93
+ /*
94
+ * The transcript of one agent a workflow started. Claude Code 2.1.282 keeps a folder per run under
95
+ * `workflows` in the subagents folder, and nothing but the agent id ties an agent to its run.
96
+ */
97
+ export async function findWorkflowAgent(subagentsDir, agentId) {
98
+ if (!/^[\w-]+$/.test(agentId)) {
99
+ return null;
100
+ }
101
+ const workflowsDir = join(subagentsDir, 'workflows');
102
+ let runs;
103
+ try {
104
+ runs = await readdir(workflowsDir);
105
+ }
106
+ catch {
107
+ return null;
108
+ }
109
+ for (const run of runs) {
110
+ const dir = join(workflowsDir, run);
111
+ const transcript = join(dir, `agent-${agentId}.jsonl`);
112
+ if (existsSync(transcript)) {
113
+ return { agentId, toolUseId: null, parentAgentId: null, description: null, transcript };
114
+ }
115
+ }
116
+ return null;
117
+ }
118
+ /*
119
+ * One subagent transcript as thread items, read on from where the last read stopped: a transcript only
120
+ * grows, and a panel that follows a working agent asks again every time a line lands. The lines have
121
+ * the envelope of the main transcript, so an assistant or a tool result goes through the same mapping
122
+ * the live stream does. A file that shrank or was rewritten is read again from the start under a new
123
+ * thread, whose cursors then no longer match, so a client holding one is told the history expired.
124
+ */
125
+ export class TranscriptProjection {
126
+ path;
127
+ thread;
128
+ projector;
129
+ protocol;
130
+ offset = 0;
131
+ size = 0;
132
+ mtimeMs = 0;
133
+ lineTime = 0;
134
+ constructor(path) {
135
+ this.path = path;
136
+ this.reset();
137
+ }
138
+ /* Reads what was added since the last call; false when the file is not there. */
139
+ async refresh() {
140
+ let info;
141
+ try {
142
+ info = await stat(this.path);
143
+ }
144
+ catch {
145
+ return false;
146
+ }
147
+ if (info.size < this.size || info.mtimeMs < this.mtimeMs) {
148
+ this.reset();
149
+ }
150
+ this.size = info.size;
151
+ this.mtimeMs = info.mtimeMs;
152
+ if (info.size > this.offset) {
153
+ this.offset = await readLines(this.path, this.offset, info.size, CHUNK_BYTES, (line) => this.take(line));
154
+ }
155
+ return true;
156
+ }
157
+ items() {
158
+ return this.thread.list().map(settledReading);
159
+ }
160
+ /* The page before `cursor`, or the newest page without one; the cursors are the thread's own. */
161
+ page(limit, cursor) {
162
+ const page = this.thread.history(limit, cursor);
163
+ return { items: page.items.map(settledReading), history: page.history };
164
+ }
165
+ reset() {
166
+ const reading = readingThread('Claude', () => this.lineTime);
167
+ this.thread = reading.thread;
168
+ this.projector = reading.projector;
169
+ this.protocol = new ClaudeProtocol();
170
+ this.offset = 0;
171
+ this.size = 0;
172
+ this.mtimeMs = 0;
173
+ }
174
+ take(line) {
175
+ if (line.trim() === '') {
176
+ return;
177
+ }
178
+ let entry;
179
+ try {
180
+ entry = JSON.parse(line);
181
+ }
182
+ catch {
183
+ return;
184
+ }
185
+ if (!isRecord(entry) || (entry.type !== 'user' && entry.type !== 'assistant')) {
186
+ return;
187
+ }
188
+ const time = typeof entry.timestamp === 'string' ? Date.parse(entry.timestamp) : Number.NaN;
189
+ if (Number.isFinite(time)) {
190
+ this.lineTime = time;
191
+ }
192
+ const message = isRecord(entry.message) ? entry.message : {};
193
+ const said = entry.type === 'user' ? spokenText(message.content) : null;
194
+ if (said !== null) {
195
+ // The prompt it was given, or a message sent to it later; a reminder the CLI slipped in is not somebody talking.
196
+ if (entry.isMeta !== true && said.trim() !== '') {
197
+ this.thread.upsert({
198
+ id: `user-${str(entry.uuid) ?? this.thread.list().length}`,
199
+ kind: 'user',
200
+ createdAt: this.lineTime,
201
+ turnId: null,
202
+ text: said
203
+ });
204
+ }
205
+ return;
206
+ }
207
+ for (const event of this.protocol.handle({ type: entry.type, message })) {
208
+ this.projector.project(0, event);
209
+ }
210
+ }
211
+ }
@@ -0,0 +1,51 @@
1
+ import { type ChatSkill } from '@adecore/agent-contracts';
2
+ import type { ApprovalDecision, BackendHost, BackendLaunch, ChatBackend, TurnInput } from './backend.ts';
3
+ import { type CodexClientInfo } from './codex-transport.ts';
4
+ export declare function parseSkillsList(result: unknown): ChatSkill[];
5
+ export interface CodexBackendOptions {
6
+ client?: CodexClientInfo;
7
+ }
8
+ export declare class CodexBackend implements ChatBackend {
9
+ readonly acknowledgesTurns = true;
10
+ private promptId;
11
+ private readonly launch;
12
+ private readonly host;
13
+ private readonly protocol;
14
+ private readonly client;
15
+ private transport;
16
+ private threadId;
17
+ private contextPending;
18
+ private imageInputSupported;
19
+ private turnUnnamed;
20
+ private interruptOwed;
21
+ constructor(launch: BackendLaunch, host: BackendHost, options?: CodexBackendOptions);
22
+ get running(): boolean;
23
+ get pid(): number | null;
24
+ start(): Promise<void>;
25
+ sendTurn(input: TurnInput): void;
26
+ private acceptPrompt;
27
+ private fail;
28
+ private respond;
29
+ private readImageSupport;
30
+ compact(): void;
31
+ setTitle(title: string): void;
32
+ listSkills(): Promise<ChatSkill[]>;
33
+ listThreadItems(params: {
34
+ threadId: string;
35
+ cursor?: string;
36
+ limit: number;
37
+ sortDirection: 'asc' | 'desc';
38
+ }): Promise<unknown>;
39
+ interrupt(): void;
40
+ stopTask(taskId: string): void;
41
+ respondApproval(requestId: string, decision: ApprovalDecision): boolean;
42
+ respondQuestion(requestId: string, answers: Record<string, string>): boolean;
43
+ dismissRequest(requestId: string): boolean;
44
+ declineRequest(requestId: string, _message: string): boolean;
45
+ stop(): void;
46
+ dispose(): Promise<void>;
47
+ private request;
48
+ private handleFrame;
49
+ private handleExit;
50
+ private emit;
51
+ }