@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,502 @@
1
+ /*
2
+ * Network-free `codex app-server` fake. Prompt commands exercise approvals, edits, questions,
3
+ * interrupts, failures, names, subagents, pagination and forks through the real JSON-RPC shapes.
4
+ */
5
+ import { runOverStdio } from './fake-cli.js';
6
+ // How many steps a spawned agent takes: more than a thread row keeps, so only its own thread has them all.
7
+ export const FAKE_CHILD_STEPS = 250;
8
+ // The threads of spawned agents, outside any one process: the real ones are on disk, so a process that never ran them reads them too.
9
+ const childThreads = new Map();
10
+ // The turn ids per thread, outside any one process for the same reason.
11
+ const threadTurns = new Map();
12
+ // The developer instructions per thread, kept from its start the way Codex keeps them in the rollout.
13
+ const threadInstructions = new Map();
14
+ // Every `thread/fork` a fake was asked, oldest first, so a test can see what the daemon forked at.
15
+ export const fakeCodexForks = [];
16
+ export function fakeCodexWith(options) {
17
+ return (io) => {
18
+ const out = io.out;
19
+ let serverRequestId = 0;
20
+ let itemCounter = 0;
21
+ let threadId = '';
22
+ let threadModel = 'fake-model';
23
+ let threadName = null;
24
+ let threadSandbox = '';
25
+ let threadApproval = '';
26
+ let turnId = '';
27
+ let turnEffort = null;
28
+ let pasted = null;
29
+ const notify = (method, params) => {
30
+ out({ method, params, emittedAtMs: Date.now() });
31
+ };
32
+ // Codex item ids are unique across processes (UUIDs and response ids); a nonce keeps the fake honest.
33
+ const nonce = Math.random().toString(36).slice(2, 6);
34
+ const item = (type, fields) => ({ type, id: `${type}-${nonce}-${++itemCounter}`, ...fields });
35
+ const started = (entry) => {
36
+ notify('item/started', { item: entry, threadId, turnId, startedAtMs: Date.now() });
37
+ };
38
+ const completed = (entry) => {
39
+ notify('item/completed', { item: entry, threadId, turnId, completedAtMs: Date.now() });
40
+ };
41
+ const usage = () => {
42
+ notify('thread/tokenUsage/updated', {
43
+ threadId,
44
+ turnId,
45
+ tokenUsage: {
46
+ total: {
47
+ totalTokens: 25090,
48
+ inputTokens: 25085,
49
+ cachedInputTokens: 12928,
50
+ cacheWriteInputTokens: 0,
51
+ outputTokens: 5,
52
+ reasoningOutputTokens: 0
53
+ },
54
+ last: {
55
+ totalTokens: 25090,
56
+ inputTokens: 25085,
57
+ cachedInputTokens: 12928,
58
+ cacheWriteInputTokens: 0,
59
+ outputTokens: 5,
60
+ reasoningOutputTokens: 0
61
+ },
62
+ // Codex reports the window of the model the thread runs on, which spark makes smaller.
63
+ modelContextWindow: threadModel.includes('spark') ? 121600 : 258400
64
+ }
65
+ });
66
+ };
67
+ const agentMessage = (text) => {
68
+ const entry = item('agentMessage', { text: '', phase: 'final_answer', memoryCitation: null, delivery: null, questions: null });
69
+ started(entry);
70
+ const half = Math.ceil(text.length / 2);
71
+ notify('item/agentMessage/delta', { threadId, turnId, itemId: entry.id, delta: text.slice(0, half) });
72
+ notify('item/agentMessage/delta', { threadId, turnId, itemId: entry.id, delta: text.slice(half) });
73
+ completed({ ...entry, text });
74
+ };
75
+ const turnStarted = () => {
76
+ turnId = `turn-${nonce}-${++itemCounter}`;
77
+ threadTurns.set(threadId, [...(threadTurns.get(threadId) ?? []), turnId]);
78
+ notify('thread/status/changed', { threadId, status: { type: 'active', activeFlags: [] } });
79
+ notify('turn/started', { threadId, turn: { id: turnId, items: [], itemsView: 'notLoaded', status: 'inProgress', error: null } });
80
+ };
81
+ const turnCompleted = (status, error = null, codexErrorInfo = null) => {
82
+ usage();
83
+ notify('thread/status/changed', { threadId, status: { type: 'idle' } });
84
+ notify('turn/completed', {
85
+ threadId,
86
+ turn: {
87
+ id: turnId,
88
+ items: [],
89
+ itemsView: 'summary',
90
+ status,
91
+ error: error ? { message: error, codexErrorInfo, additionalDetails: null } : null
92
+ }
93
+ });
94
+ turnId = '';
95
+ };
96
+ let pendingApproval = null;
97
+ let pendingQuestion = null;
98
+ let pendingSteer = false;
99
+ let slow = false;
100
+ const askApproval = (kind, entry, params) => {
101
+ pendingApproval = { rpcId: serverRequestId, entry, kind };
102
+ notify('thread/status/changed', { threadId, status: { type: 'active', activeFlags: ['waitingOnApproval'] } });
103
+ out({
104
+ method: kind === 'command' ? 'item/commandExecution/requestApproval' : 'item/fileChange/requestApproval',
105
+ id: serverRequestId++,
106
+ params: { threadId, turnId, itemId: entry.id, startedAtMs: Date.now(), ...params }
107
+ });
108
+ };
109
+ const handleTurnStart = (params) => {
110
+ turnEffort = typeof params.effort === 'string' ? params.effort : null;
111
+ const input = Array.isArray(params.input) ? params.input[0] : undefined;
112
+ const raw = input?.text ?? '';
113
+ const gap = raw.indexOf('\n\n');
114
+ const noted = options.resumeLead !== undefined && raw.startsWith(options.resumeLead) && gap !== -1;
115
+ if (noted) {
116
+ pasted = raw.slice(0, gap);
117
+ }
118
+ const text = noted ? raw.slice(gap + 2) : raw;
119
+ if (text === 'name?') {
120
+ turnStarted();
121
+ agentMessage(threadName ?? 'unnamed');
122
+ turnCompleted('completed');
123
+ return;
124
+ }
125
+ if (text === 'note?' || text === 'pasted?') {
126
+ turnStarted();
127
+ agentMessage((text === 'note?' ? threadInstructions.get(threadId) : pasted) ?? 'nothing');
128
+ turnCompleted('completed');
129
+ return;
130
+ }
131
+ turnStarted();
132
+ const user = item('userMessage', { clientId: null, content: [{ type: 'text', text, text_elements: [] }] });
133
+ started(user);
134
+ completed(user);
135
+ if (text === 'crash') {
136
+ io.exit(1);
137
+ return;
138
+ }
139
+ if (text === 'crash loudly') {
140
+ io.err('Error: the fake lost its thread\n');
141
+ io.exit(1);
142
+ return;
143
+ }
144
+ if (text === 'fail') {
145
+ turnCompleted('failed', 'The model is overloaded');
146
+ return;
147
+ }
148
+ // Lines of their own, so a task brief around them still fails the way Codex 0.156.1 does.
149
+ const lines = text.split('\n');
150
+ // A dev server Codex leaves running past the turn; its process ends once the test says later is.
151
+ if (lines.includes('serve')) {
152
+ const command = item('commandExecution', { command: "/bin/zsh -lc 'bun dev'", cwd: io.cwd, processId: `pty-${nonce}`, status: 'inProgress' });
153
+ started(command);
154
+ io.later(() => completed({ ...command, status: 'completed', aggregatedOutput: '', exitCode: 0 }));
155
+ }
156
+ if (lines.includes('overloaded')) {
157
+ turnCompleted('failed', 'Selected model is at capacity. Please try a different model.', 'serverOverloaded');
158
+ return;
159
+ }
160
+ const limit = lines.find((line) => line.startsWith('limit:'));
161
+ if (limit !== undefined) {
162
+ notify('account/rateLimits/updated', {
163
+ rateLimits: {
164
+ limitId: 'codex',
165
+ primary: { usedPercent: 100, windowDurationMins: 300, resetsAt: Number(limit.slice(6)) },
166
+ secondary: { usedPercent: 40, windowDurationMins: 10080, resetsAt: Number(limit.slice(6)) + 86_400 }
167
+ }
168
+ });
169
+ turnCompleted('failed', "You've hit your usage limit.", 'usageLimitExceeded');
170
+ return;
171
+ }
172
+ if (text === 'slow') {
173
+ slow = true;
174
+ started(item('agentMessage', { text: '', phase: 'final_answer', memoryCitation: null, delivery: null, questions: null }));
175
+ return;
176
+ }
177
+ if (text.startsWith('tool:')) {
178
+ const command = text.slice(5).trim();
179
+ const entry = item('commandExecution', {
180
+ command: `/bin/zsh -lc ${command}`,
181
+ cwd: io.cwd,
182
+ status: 'inProgress',
183
+ aggregatedOutput: null,
184
+ exitCode: null
185
+ });
186
+ started(entry);
187
+ askApproval('command', entry, {
188
+ kind: 'command',
189
+ command: `/bin/zsh -lc ${command}`,
190
+ cwd: io.cwd,
191
+ reason: 'Run a command',
192
+ proposedExecpolicyAmendment: [command.split(' ')[0]],
193
+ availableDecisions: ['accept', { acceptWithExecpolicyAmendment: { execpolicy_amendment: [command.split(' ')[0]] } }, 'cancel']
194
+ });
195
+ return;
196
+ }
197
+ if (text.startsWith('edit:')) {
198
+ const path = text.slice(5).trim();
199
+ const entry = item('fileChange', { changes: [{ path, kind: { type: 'add' }, diff: `+++ ${path}\n+hello\n` }], status: 'inProgress' });
200
+ started(entry);
201
+ askApproval('fileChange', entry, { reason: 'Write outside the sandbox' });
202
+ return;
203
+ }
204
+ const finish = text.startsWith('spawn and finish:');
205
+ if (finish || text.startsWith('spawn:')) {
206
+ const prompt = text.slice(text.indexOf(':') + 1).trim();
207
+ const childId = `child-${nonce}-${++itemCounter}`;
208
+ const steps = [{ type: 'userMessage', id: `${childId}-prompt`, content: [{ type: 'text', text: prompt, text_elements: [] }] }];
209
+ for (let step = 1; step <= FAKE_CHILD_STEPS; step++) {
210
+ steps.push({
211
+ type: 'commandExecution',
212
+ id: `${childId}-step-${step}`,
213
+ command: `/bin/zsh -lc 'echo ${step}'`,
214
+ cwd: io.cwd,
215
+ status: 'completed',
216
+ aggregatedOutput: `${step}\n`,
217
+ exitCode: 0
218
+ });
219
+ }
220
+ childThreads.set(childId, steps);
221
+ const spawn = item('collabAgentToolCall', {
222
+ tool: 'spawnAgent',
223
+ prompt,
224
+ model: 'fake-model',
225
+ senderThreadId: threadId,
226
+ receiverThreadIds: [],
227
+ agentsStates: {},
228
+ status: 'inProgress'
229
+ });
230
+ started(spawn);
231
+ const running = { ...spawn, receiverThreadIds: [childId], agentsStates: { [childId]: { status: 'running', message: null } } };
232
+ if (!finish) {
233
+ completed(running);
234
+ agentMessage('spawned');
235
+ turnCompleted('completed');
236
+ return;
237
+ }
238
+ completed({ ...running, status: 'completed', agentsStates: { [childId]: { status: 'completed', message: 'the docs are read' } } });
239
+ agentMessage('spawned');
240
+ const spawnedIn = turnId;
241
+ turnCompleted('completed');
242
+ // A snapshot of the call from while its agent still ran, delivered after the agent finished.
243
+ io.later(() => notify('item/completed', { item: running, threadId, turnId: spawnedIn, completedAtMs: Date.now() }));
244
+ return;
245
+ }
246
+ /*
247
+ * A spawn the way Codex 0.156.1 reports it: no spawnAgent call, a `subAgentActivity` that started under
248
+ * the call id, the agent's own thread streaming over the same connection, and a `completed` activity
249
+ * with an id of its own once the agent is done, here after the parent's turn ended.
250
+ */
251
+ if (text.startsWith('spawn agent:')) {
252
+ const prompt = text.slice(text.indexOf(':') + 1).trim();
253
+ const childId = `child-${nonce}-${++itemCounter}`;
254
+ const childTurn = `turn-${nonce}-${++itemCounter}`;
255
+ childThreads.set(childId, [{ type: 'userMessage', id: `${childId}-prompt`, content: [{ type: 'text', text: prompt, text_elements: [] }] }]);
256
+ const activity = (id, kind) => {
257
+ const entry = { type: 'subAgentActivity', id, kind, agentThreadId: childId, agentPath: '/root/survey' };
258
+ started(entry);
259
+ completed(entry);
260
+ };
261
+ const inChild = (method, params) => {
262
+ notify(method, { threadId: childId, ...params });
263
+ };
264
+ activity(`call-spawn-${nonce}-${++itemCounter}`, 'started');
265
+ inChild('thread/status/changed', { status: { type: 'active', activeFlags: [] } });
266
+ inChild('turn/started', { turn: { id: childTurn, items: [], itemsView: 'notLoaded', status: 'inProgress', error: null } });
267
+ const step = { type: 'commandExecution', id: `${childId}-step`, command: "/bin/zsh -lc 'echo PONG'", cwd: io.cwd, status: 'completed' };
268
+ inChild('item/started', { turnId: childTurn, item: { ...step, status: 'inProgress' } });
269
+ inChild('item/completed', { turnId: childTurn, item: { ...step, aggregatedOutput: 'PONG\n', exitCode: 0 } });
270
+ inChild('item/completed', { turnId: childTurn, item: { type: 'agentMessage', id: `${childId}-answer`, text: 'PONG', phase: 'final_answer' } });
271
+ inChild('turn/completed', { turn: { id: childTurn, items: [], itemsView: 'summary', status: 'completed', error: null } });
272
+ agentMessage('spawned');
273
+ turnCompleted('completed');
274
+ io.later(() => activity(`subagent-completed-${childTurn}`, 'completed'));
275
+ return;
276
+ }
277
+ if (text.startsWith('ask:')) {
278
+ const question = text.slice(4).trim();
279
+ pendingQuestion = { rpcId: serverRequestId, questionId: 'color' };
280
+ out({
281
+ method: 'item/tool/requestUserInput',
282
+ id: serverRequestId++,
283
+ params: {
284
+ threadId,
285
+ turnId,
286
+ itemId: 'tool-q',
287
+ isBlocking: true,
288
+ questions: [
289
+ {
290
+ id: 'color',
291
+ header: 'Choice',
292
+ question,
293
+ isOther: false,
294
+ isSecret: false,
295
+ options: [
296
+ { label: 'Red', description: 'Warm' },
297
+ { label: 'Blue', description: 'Cool' }
298
+ ]
299
+ }
300
+ ]
301
+ }
302
+ });
303
+ return;
304
+ }
305
+ if (text.startsWith('async:')) {
306
+ const question = text.slice(6).trim();
307
+ pendingSteer = true;
308
+ const entry = item('agentMessage', {
309
+ text: `${question}\n- Red\n- Blue`,
310
+ phase: 'final_answer',
311
+ memoryCitation: null,
312
+ delivery: 'async',
313
+ questions: [{ title: question, options: ['Red', 'Blue'] }]
314
+ });
315
+ started(entry);
316
+ completed(entry);
317
+ return;
318
+ }
319
+ agentMessage(`echo: ${text}${turnEffort ? ` (${turnEffort})` : ''}`);
320
+ turnCompleted('completed');
321
+ };
322
+ const handleApprovalResponse = (approval, result) => {
323
+ pendingApproval = null;
324
+ notify('serverRequest/resolved', { threadId, requestId: approval.rpcId });
325
+ const decision = result.decision;
326
+ const accepted = decision === 'accept' || decision === 'acceptForSession' || (typeof decision === 'object' && decision !== null);
327
+ const always = decision === 'acceptForSession' || (typeof decision === 'object' && decision !== null);
328
+ if (approval.kind === 'command') {
329
+ const command = String(approval.entry.command).replace('/bin/zsh -lc ', '');
330
+ completed({
331
+ ...approval.entry,
332
+ status: accepted ? 'completed' : 'declined',
333
+ aggregatedOutput: accepted ? `ran: ${command}\n` : null,
334
+ exitCode: accepted ? 0 : null
335
+ });
336
+ }
337
+ else {
338
+ completed({ ...approval.entry, status: accepted ? 'completed' : 'declined' });
339
+ }
340
+ agentMessage(accepted ? (always ? 'done, remembered' : 'done') : 'denied');
341
+ turnCompleted('completed');
342
+ };
343
+ const handleQuestionResponse = (question, result) => {
344
+ pendingQuestion = null;
345
+ const answers = result.answers;
346
+ agentMessage(`you chose ${answers?.[question.questionId]?.answers?.[0] ?? 'no answer'}`);
347
+ turnCompleted('completed');
348
+ };
349
+ const handleRequest = (id, method, params) => {
350
+ switch (method) {
351
+ case 'initialize':
352
+ out({ id, result: { userAgent: 'fake-codex/0.0.0', codexHome: io.cwd, platformFamily: 'unix', platformOs: 'test' } });
353
+ return;
354
+ case 'model/list':
355
+ out({
356
+ id,
357
+ result: {
358
+ data: [{ model: threadModel, inputModalities: threadModel.includes('spark') ? ['text'] : ['text', 'image'] }],
359
+ nextCursor: null
360
+ }
361
+ });
362
+ return;
363
+ case 'thread/start':
364
+ case 'thread/resume': {
365
+ const resumed = method === 'thread/resume' ? String(params.threadId) : null;
366
+ if (resumed === 'gone') {
367
+ out({ id, error: { code: -32600, message: 'no thread gone' } });
368
+ return;
369
+ }
370
+ threadId = resumed ?? `fake-${Math.random().toString(36).slice(2, 8)}`;
371
+ // Codex 0.154 ignores developer instructions on a resume; only a start sets them.
372
+ if (resumed === null) {
373
+ threadInstructions.set(threadId, typeof params.developerInstructions === 'string' ? params.developerInstructions : null);
374
+ }
375
+ threadModel = typeof params.model === 'string' ? params.model : 'fake-model';
376
+ threadSandbox = typeof params.sandbox === 'string' ? params.sandbox : '';
377
+ threadApproval = typeof params.approvalPolicy === 'string' ? params.approvalPolicy : '';
378
+ threadName = threadId.startsWith('named-') ? 'Named before' : null;
379
+ const thread = { id: threadId, model: threadModel, cwd: params.cwd, turns: [], name: threadName };
380
+ out({
381
+ id,
382
+ result: {
383
+ thread,
384
+ model: `${threadModel} ${threadApproval} ${threadSandbox}`,
385
+ modelProvider: 'fake',
386
+ cwd: params.cwd,
387
+ approvalPolicy: threadApproval,
388
+ sandbox: { type: threadSandbox }
389
+ }
390
+ });
391
+ notify('thread/started', { thread });
392
+ return;
393
+ }
394
+ case 'thread/fork': {
395
+ const source = String(params.threadId);
396
+ const turns = threadTurns.get(source) ?? [];
397
+ const last = typeof params.lastTurnId === 'string' ? turns.indexOf(params.lastTurnId) : turns.length - 1;
398
+ if (!threadTurns.has(source) || (typeof params.lastTurnId === 'string' && last < 0)) {
399
+ out({ id, error: { code: -32600, message: `no rollout found for thread id ${source}` } });
400
+ return;
401
+ }
402
+ fakeCodexForks.push(params);
403
+ const forked = `fork-${Math.random().toString(36).slice(2, 8)}`;
404
+ threadTurns.set(forked, turns.slice(0, last + 1));
405
+ threadInstructions.set(forked, threadInstructions.get(source) ?? null);
406
+ out({ id, result: { thread: { id: forked, forkedFromId: source, cwd: params.cwd, turns: [] }, model: params.model ?? 'fake-model' } });
407
+ return;
408
+ }
409
+ case 'thread/turns/list': {
410
+ const turns = threadTurns.get(String(params.threadId)) ?? [];
411
+ out({ id, result: { data: turns.map((turn) => ({ id: turn, items: [], status: 'completed', error: null })), nextCursor: null } });
412
+ return;
413
+ }
414
+ case 'thread/items/list': {
415
+ const steps = childThreads.get(String(params.threadId));
416
+ if (!steps) {
417
+ out({ id, error: { code: -32600, message: `no rollout found for thread id ${String(params.threadId)}` } });
418
+ return;
419
+ }
420
+ // The cursor is where the next page starts, counted from the end the list is sorted from.
421
+ const ordered = params.sortDirection === 'asc' ? steps : [...steps].reverse();
422
+ const start = typeof params.cursor === 'string' ? Number(params.cursor) : 0;
423
+ const limit = typeof params.limit === 'number' ? params.limit : 50;
424
+ const page = ordered.slice(start, start + limit);
425
+ const next = start + limit < ordered.length ? String(start + limit) : null;
426
+ out({ id, result: { data: page.map((entry) => ({ item: entry, turnId: 'child-turn' })), nextCursor: next, backwardsCursor: null } });
427
+ return;
428
+ }
429
+ case 'thread/name/set':
430
+ threadName = String(params.name);
431
+ out({ id, result: {} });
432
+ notify('thread/name/updated', { threadId, threadName });
433
+ return;
434
+ case 'turn/start':
435
+ out({ id, result: { turn: { id: `turn-${nonce}-${itemCounter + 1}`, items: [], status: 'inProgress', error: null } } });
436
+ handleTurnStart(params);
437
+ return;
438
+ case 'turn/steer': {
439
+ // The real app-server refuses a steer that does not name the turn it is meant for.
440
+ if (params.expectedTurnId !== turnId) {
441
+ out({ id, error: { code: -32602, message: 'Invalid request: missing field `expectedTurnId`' } });
442
+ // The real turn would go on polling; ending it here makes a test fail on its
443
+ // assertion rather than on a timeout.
444
+ pendingSteer = false;
445
+ turnCompleted('failed');
446
+ return;
447
+ }
448
+ out({ id, result: { turnId } });
449
+ if (pendingSteer) {
450
+ pendingSteer = false;
451
+ const input = Array.isArray(params.input) ? params.input[0] : undefined;
452
+ agentMessage(`you chose ${input?.text ?? 'no answer'}`);
453
+ turnCompleted('completed');
454
+ }
455
+ return;
456
+ }
457
+ case 'turn/interrupt':
458
+ out({ id, result: {} });
459
+ if (slow) {
460
+ slow = false;
461
+ turnCompleted('interrupted');
462
+ }
463
+ return;
464
+ case 'thread/compact/start':
465
+ out({ id, result: {} });
466
+ turnStarted();
467
+ started(item('contextCompaction', {}));
468
+ completed(item('contextCompaction', {}));
469
+ turnCompleted('completed');
470
+ return;
471
+ default:
472
+ out({ id, error: { code: -32601, message: `unknown method ${method}` } });
473
+ }
474
+ };
475
+ return {
476
+ onLine: (line) => {
477
+ const frame = JSON.parse(line);
478
+ const params = (frame.params ?? {});
479
+ if (typeof frame.method === 'string' && frame.id !== undefined) {
480
+ handleRequest(frame.id, frame.method, params);
481
+ return;
482
+ }
483
+ if (frame.id === undefined || frame.result === undefined) {
484
+ return;
485
+ }
486
+ const result = frame.result;
487
+ const approval = pendingApproval;
488
+ const question = pendingQuestion;
489
+ if (approval && approval.rpcId === frame.id) {
490
+ handleApprovalResponse(approval, result);
491
+ }
492
+ else if (question && question.rpcId === frame.id) {
493
+ handleQuestionResponse(question, result);
494
+ }
495
+ }
496
+ };
497
+ };
498
+ }
499
+ export const fakeCodex = fakeCodexWith({});
500
+ if (import.meta.main) {
501
+ await runOverStdio(fakeCodex);
502
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "version": "Claude Code 2.1.285",
3
+ "capturedAt": "2026-09-30",
4
+ "requestedMode": "auto",
5
+ "model": "claude-haiku-4-5",
6
+ "source": "Live Claude stream-json in an isolated temporary folder. Init reports auto; after one native Write attempt the status frame reports default. Only permission metadata is retained.",
7
+ "frames": [
8
+ {
9
+ "type": "system",
10
+ "subtype": "init",
11
+ "session_id": "6e4ac93f-9fd7-466b-bef4-bae6303cf342",
12
+ "model": "claude-haiku-4-5",
13
+ "permissionMode": "auto",
14
+ "fast_mode_state": "off"
15
+ },
16
+ {
17
+ "type": "system",
18
+ "subtype": "status",
19
+ "status": null,
20
+ "permissionMode": "default",
21
+ "session_id": "6e4ac93f-9fd7-466b-bef4-bae6303cf342"
22
+ }
23
+ ]
24
+ }