agentbox-app 0.1.12 → 0.1.16

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 (370) hide show
  1. package/README.md +24 -9
  2. package/bin/agentbox.mjs +23 -1
  3. package/briefs/message-rules.md +36 -8
  4. package/briefs/worker.md +46 -23
  5. package/main/account-discovery.mjs +122 -30
  6. package/main/account-tooling.mjs +29 -1
  7. package/main/account-usage.mjs +46 -0
  8. package/main/acp.mjs +296 -0
  9. package/main/agent-homes.mjs +158 -0
  10. package/main/agent-sessions.mjs +311 -260
  11. package/main/agent-updates.mjs +9 -22
  12. package/main/agents.mjs +179 -466
  13. package/main/analytics.mjs +42 -2
  14. package/main/answer-modes.mjs +103 -37
  15. package/main/approval-prompt-core.mjs +197 -0
  16. package/main/approval-prompt-server.mjs +4 -138
  17. package/main/approvals.mjs +101 -297
  18. package/main/artifact-path.mjs +47 -18
  19. package/main/claude-bin.mjs +45 -311
  20. package/main/claude-input.mjs +57 -7
  21. package/main/claude-launch-env.mjs +54 -0
  22. package/main/claude-models.mjs +39 -7
  23. package/main/claude-plan.mjs +64 -16
  24. package/main/claude-session-open.mjs +28 -0
  25. package/main/claude-usage-process.mjs +40 -0
  26. package/main/claude-usage.mjs +94 -59
  27. package/main/cloud/account.mjs +179 -0
  28. package/main/cloud/aws.mjs +127 -0
  29. package/main/cloud/browser-return.mjs +58 -0
  30. package/main/cloud/clients.mjs +15 -0
  31. package/main/cloud/codex-cloud.mjs +53 -0
  32. package/main/cloud/config.mjs +107 -0
  33. package/main/cloud/docs.mjs +219 -0
  34. package/main/cloud/exec.mjs +27 -0
  35. package/main/cloud/host.mjs +165 -0
  36. package/main/cloud/kit.mjs +80 -0
  37. package/main/cloud/logins.mjs +543 -0
  38. package/main/cloud/managed.mjs +115 -0
  39. package/main/cloud/marker.mjs +104 -0
  40. package/main/cloud/org.mjs +53 -0
  41. package/main/cloud/reuse.mjs +208 -0
  42. package/main/cloud/run-cli.mjs +177 -0
  43. package/main/cloud/run.mjs +1934 -0
  44. package/main/cloud/usage.mjs +76 -0
  45. package/main/cloud-permission.mjs +51 -0
  46. package/main/codex-account.mjs +78 -0
  47. package/main/codex-app-server.mjs +276 -409
  48. package/main/codex-approvals.mjs +148 -433
  49. package/main/codex-bin.mjs +51 -249
  50. package/main/codex-models.mjs +20 -2
  51. package/main/codex-session.mjs +246 -506
  52. package/main/codex-threads-worker.mjs +12 -0
  53. package/main/codex-threads.mjs +112 -11
  54. package/main/codex-usage-file.mjs +5 -3
  55. package/main/codex-usage.mjs +56 -7
  56. package/main/codex-watch.mjs +83 -5
  57. package/main/codex.mjs +95 -363
  58. package/main/config.mjs +37 -5
  59. package/main/corner-tag.mjs +810 -0
  60. package/main/crash-report.mjs +26 -3
  61. package/main/dev-window.mjs +1 -1
  62. package/main/engine-bin.mjs +545 -0
  63. package/main/engine-setup.mjs +25 -24
  64. package/main/feedback.mjs +14 -31
  65. package/main/folder-pictures.mjs +2 -2
  66. package/main/freeze-recorder-thread.mjs +86 -0
  67. package/main/freeze-recorder.mjs +146 -0
  68. package/main/fresh-user.mjs +20 -9
  69. package/main/git-change-offthread.mjs +17 -3
  70. package/main/git-change-thread.mjs +5 -2
  71. package/main/harnesses/claude-stream.mjs +208 -0
  72. package/main/harnesses/claude.mjs +105 -0
  73. package/main/harnesses/codex.mjs +72 -0
  74. package/main/harnesses/common.mjs +78 -0
  75. package/main/harnesses/instructions-file.mjs +116 -0
  76. package/main/harnesses/opencode.mjs +234 -0
  77. package/main/harnesses.mjs +65 -0
  78. package/main/importable-threads.mjs +96 -0
  79. package/main/ipc.mjs +520 -135
  80. package/main/leftovers.mjs +117 -25
  81. package/main/liquid-glass.mjs +26 -0
  82. package/main/live-replies.mjs +10 -4
  83. package/main/local-app-frames.mjs +82 -0
  84. package/main/main-went-red.mjs +330 -0
  85. package/main/main.mjs +248 -37
  86. package/main/memory-gate-history.mjs +85 -20
  87. package/main/memory-gate-server.mjs +129 -11
  88. package/main/memory-gate.mjs +62 -8
  89. package/main/memory-log.mjs +124 -0
  90. package/main/menu.mjs +4 -2
  91. package/main/message-priority.mjs +2 -2
  92. package/main/mic.mjs +38 -0
  93. package/main/native/liquid-glass/build/liquid-glass.node +0 -0
  94. package/main/new-chats-watch.mjs +110 -0
  95. package/main/new-user-window.mjs +25 -0
  96. package/main/notify.mjs +64 -5
  97. package/main/opencode-server.mjs +271 -0
  98. package/main/opencode.mjs +287 -0
  99. package/main/phone-alerts.mjs +117 -0
  100. package/main/phone-inbox.mjs +625 -0
  101. package/main/phone-link.mjs +571 -0
  102. package/main/phone-uploads.mjs +476 -0
  103. package/main/picture-shape.mjs +114 -0
  104. package/main/quit-sequence.mjs +143 -0
  105. package/main/refresh-agent-models.mjs +15 -2
  106. package/main/relay-address.mjs +28 -0
  107. package/main/relay-client.mjs +314 -0
  108. package/main/repeats.mjs +10 -4
  109. package/main/row-label.mjs +18 -47
  110. package/main/run-change.mjs +13 -0
  111. package/main/run-ledger.mjs +135 -0
  112. package/main/runs-on.mjs +32 -35
  113. package/main/save-attachments.mjs +41 -0
  114. package/main/serve.mjs +155 -9
  115. package/main/settings.mjs +364 -50
  116. package/main/shell-path.mjs +234 -0
  117. package/main/ship-conflict-brief.mjs +119 -0
  118. package/main/ship-queue.mjs +134 -20
  119. package/main/sign-in-files.mjs +3 -7
  120. package/main/source-updater.mjs +45 -11
  121. package/main/stage-attachment.mjs +68 -0
  122. package/main/stall-watch.mjs +50 -0
  123. package/main/start-hold.mjs +73 -0
  124. package/main/store/home.mjs +87 -232
  125. package/main/store/paths.mjs +11 -0
  126. package/main/store/teammates-files.mjs +99 -0
  127. package/main/store/work-items.mjs +231 -13
  128. package/main/store.mjs +227 -53
  129. package/main/supervisor.mjs +3865 -699
  130. package/main/task-commands.mjs +13 -17
  131. package/main/task-folders-offthread.mjs +6 -1
  132. package/main/task-folders.mjs +897 -105
  133. package/main/task-terminals.mjs +147 -41
  134. package/main/team/index.mjs +114 -10
  135. package/main/team/memory-cloud.mjs +183 -1
  136. package/main/team/room-hours.mjs +48 -0
  137. package/main/team/room-setup.mjs +31 -0
  138. package/main/team/rooms-memory.mjs +454 -0
  139. package/main/team/rooms-shape.mjs +42 -0
  140. package/main/team/rooms-supabase.mjs +324 -0
  141. package/main/team/rooms.mjs +575 -0
  142. package/main/team/session.mjs +96 -26
  143. package/main/team/supabase-backend.mjs +180 -0
  144. package/main/team/sync.mjs +109 -1
  145. package/main/teammates.mjs +580 -0
  146. package/main/terminal-host.mjs +143 -0
  147. package/main/terminal-hosts.mjs +261 -0
  148. package/main/transcript-search.mjs +80 -0
  149. package/main/updater.mjs +71 -9
  150. package/main/webview-guard.mjs +45 -0
  151. package/main/worktree-include.mjs +365 -0
  152. package/mcp/core/documents.mjs +3 -1
  153. package/mcp/core/repeats.mjs +88 -0
  154. package/mcp/core/teammates.mjs +222 -0
  155. package/mcp/core/work.mjs +76 -4
  156. package/mcp/stdio.mjs +24 -11
  157. package/mcp/tools.mjs +116 -8
  158. package/package.json +30 -5
  159. package/renderer/dist/assets/abnfDiagram-YUKMZFIV-CoWB6YUK.js +1 -0
  160. package/renderer/dist/assets/arc-Ch0NrCul.js +1 -0
  161. package/renderer/dist/assets/architectureDiagram-47P4ROYG-CXz9M5tQ.js +36 -0
  162. package/renderer/dist/assets/blockDiagram-E7TT5TSB-DchGUuHH.js +140 -0
  163. package/renderer/dist/assets/c4Diagram-CRA5TL53-Cip-zNyr.js +38 -0
  164. package/renderer/dist/assets/channel-BQuQSL--.js +1 -0
  165. package/renderer/dist/assets/chunk-2Q5K7J3B-BoXid_2r.js +1 -0
  166. package/renderer/dist/assets/chunk-5VM5RSS4-Cpez1rRz.js +15 -0
  167. package/renderer/dist/assets/chunk-7TKQ45FW-DKA84YkE.js +1 -0
  168. package/renderer/dist/assets/chunk-AW2ZBBNX-Dg-SumPG.js +88 -0
  169. package/renderer/dist/assets/chunk-FVRAUYC3-06TCvPm1.js +2 -0
  170. package/renderer/dist/assets/chunk-HTAEGDNF-CMEBy1Td.js +1 -0
  171. package/renderer/dist/assets/chunk-JWPE2WC7-BJ2ObmV-.js +1 -0
  172. package/renderer/dist/assets/chunk-KQW6MTUR-CGWOYXUE.js +1 -0
  173. package/renderer/dist/assets/chunk-XXDRQBXY-CiZp07XC.js +1 -0
  174. package/renderer/dist/assets/classDiagram-v2-K4WV4PDN-DJNIX719.js +217 -0
  175. package/renderer/dist/assets/cornerTag-CPgvu-q3.js +1 -0
  176. package/renderer/dist/assets/cornerTag-oMfEjzCO.css +1 -0
  177. package/renderer/dist/assets/cose-bilkent-JH36ORCC-CbkyZOUH.js +1 -0
  178. package/renderer/dist/assets/cynefin-EF2NZ3EQ-78iOroZO.js +141 -0
  179. package/renderer/dist/assets/cynefinDiagram-3GCD6N5R-GcCopMs7.js +62 -0
  180. package/renderer/dist/assets/cytoscape.esm-C5JX3QLV.js +331 -0
  181. package/renderer/dist/assets/dagre-W4DXFKR2-DHLlXLkz.js +4 -0
  182. package/renderer/dist/assets/defaultLocale-DX6XiGOO.js +1 -0
  183. package/renderer/dist/assets/diagram-2UJZ2QOL-DuZSUHcH.js +200 -0
  184. package/renderer/dist/assets/diagram-OVF4WLC6-Ckxu3cqH.js +24 -0
  185. package/renderer/dist/assets/diagram-PFPMY2P6-CsTw9Ycn.js +30 -0
  186. package/renderer/dist/assets/diagram-UMYRVEAY-CTXd8qVg.js +24 -0
  187. package/renderer/dist/assets/diagram-YEKJPTXX-CJs1T_9m.js +41 -0
  188. package/renderer/dist/assets/diagram-ZIFT7M5P-CvjI23mf.js +3 -0
  189. package/renderer/dist/assets/ebnfDiagram-VR2GEFS7-d_IeAzOJ.js +1 -0
  190. package/renderer/dist/assets/elk-IJKZMXRS-zo9KFP3N.js +27 -0
  191. package/renderer/dist/assets/erDiagram-O2IAPWRE-DqfYf5Dt.js +99 -0
  192. package/renderer/dist/assets/flowDiagram-OXPTDLAJ-DAWsMLmo.js +213 -0
  193. package/renderer/dist/assets/ganttDiagram-R7TSEDQI-4ml_bhwR.js +292 -0
  194. package/renderer/dist/assets/gitGraphDiagram-XJZIOB7I-B_WcqSId.js +106 -0
  195. package/renderer/dist/assets/graph-DGbsTEsI.js +1 -0
  196. package/renderer/dist/assets/infoDiagram-5W2HQ5XZ-CI-jYqzc.js +2 -0
  197. package/renderer/dist/assets/init-Gi6I4Gst.js +1 -0
  198. package/renderer/dist/assets/ishikawaDiagram-K3B6WC7H-B56VWRlV.js +70 -0
  199. package/renderer/dist/assets/journeyDiagram-COXZFDF6-D1-p09Lr.js +139 -0
  200. package/renderer/dist/assets/kanban-definition-P3RFRI5V-Cv3w7JoN.js +89 -0
  201. package/renderer/dist/assets/katex-C5jXJg4s.js +257 -0
  202. package/renderer/dist/assets/linear-C35V2Spi.js +1 -0
  203. package/renderer/dist/assets/main-BcoBiGwv.css +32 -0
  204. package/renderer/dist/assets/main-CLnIOulD.js +1191 -0
  205. package/renderer/dist/assets/mermaid.core-BzGT5Vo9.js +314 -0
  206. package/renderer/dist/assets/mindmap-definition-LZFPQGKD-BZUfuymC.js +96 -0
  207. package/renderer/dist/assets/ordinal-Cboi1Yqb.js +1 -0
  208. package/renderer/dist/assets/pegDiagram-BGZESJAR-DFh9XNGe.js +1 -0
  209. package/renderer/dist/assets/pieDiagram-CAPJLFHJ-C65tPVsy.js +39 -0
  210. package/renderer/dist/assets/product-name-CSNW6d7s.js +40 -0
  211. package/renderer/dist/assets/quadrantDiagram-GDMTTRAM-Cushj_nk.js +7 -0
  212. package/renderer/dist/assets/railroadDiagram-SM67HX2B-DZGebGx5.js +1 -0
  213. package/renderer/dist/assets/requirementDiagram-X7JNWC4A-DpAB0MNo.js +84 -0
  214. package/renderer/dist/assets/sankeyDiagram-UM26HJRW-D-29rHra.js +40 -0
  215. package/renderer/dist/assets/sequenceDiagram-ZO4K6R2Y-FfOQAZol.js +169 -0
  216. package/renderer/dist/assets/sizeCapture-INFHLROL-C_n6fDBY.js +1 -0
  217. package/renderer/dist/assets/stateDiagram-v2-TBUQTH76-BZjenzJG.js +291 -0
  218. package/renderer/dist/assets/swimlanes-N4OXWK64-DxaMU9vX.js +1 -0
  219. package/renderer/dist/assets/swimlanesDiagram-K3J5GTZL-Cb2kM6rr.js +8 -0
  220. package/renderer/dist/assets/timeline-definition-YOQAKGHF-DTg5HJKz.js +120 -0
  221. package/renderer/dist/assets/usecaseDiagram-VIAY4XPW-Bc3MZDsl.js +370 -0
  222. package/renderer/dist/assets/vennDiagram-BLWOH2XV-GIVGk9Id.js +34 -0
  223. package/renderer/dist/assets/wardleyDiagram-YMQ3BMBF-NmJnbQOg.js +78 -0
  224. package/renderer/dist/assets/xychartDiagram-TAQBALBS-p-kfGfnW.js +7 -0
  225. package/renderer/dist/corner-tag.html +13 -0
  226. package/renderer/dist/emulator/audio-rules.mjs +74 -0
  227. package/renderer/dist/emulator/data/compression/README.md +11 -0
  228. package/renderer/dist/emulator/data/compression/extract7z.js +1 -0
  229. package/renderer/dist/emulator/data/compression/extractzip.js +1 -0
  230. package/renderer/dist/emulator/data/compression/libunrar.js +519 -0
  231. package/renderer/dist/emulator/data/compression/libunrar.wasm +0 -0
  232. package/renderer/dist/emulator/data/cores/README.md +22 -0
  233. package/renderer/dist/emulator/data/cores/mgba-legacy-wasm.data +0 -0
  234. package/renderer/dist/emulator/data/cores/mgba-thread-legacy-wasm.data +0 -0
  235. package/renderer/dist/emulator/data/cores/mgba-thread-wasm.data +0 -0
  236. package/renderer/dist/emulator/data/cores/mgba-wasm.data +0 -0
  237. package/renderer/dist/emulator/data/cores/package.json +65 -0
  238. package/renderer/dist/emulator/data/cores/reports/mgba.json +1 -0
  239. package/renderer/dist/emulator/data/emulator.css +1614 -0
  240. package/renderer/dist/emulator/data/loader.js +170 -0
  241. package/renderer/dist/emulator/data/localization/README.md +63 -0
  242. package/renderer/dist/emulator/data/localization/af-FR.json +339 -0
  243. package/renderer/dist/emulator/data/localization/ar-AR.json +301 -0
  244. package/renderer/dist/emulator/data/localization/ben-BEN.json +301 -0
  245. package/renderer/dist/emulator/data/localization/de-GER.json +301 -0
  246. package/renderer/dist/emulator/data/localization/el-GR.json +301 -0
  247. package/renderer/dist/emulator/data/localization/en-US.json +339 -0
  248. package/renderer/dist/emulator/data/localization/es-ES.json +310 -0
  249. package/renderer/dist/emulator/data/localization/fa-AF.json +310 -0
  250. package/renderer/dist/emulator/data/localization/hi-HI.json +301 -0
  251. package/renderer/dist/emulator/data/localization/it-IT.json +302 -0
  252. package/renderer/dist/emulator/data/localization/ja-JA.json +301 -0
  253. package/renderer/dist/emulator/data/localization/jv-JV.json +301 -0
  254. package/renderer/dist/emulator/data/localization/ko-KO.json +336 -0
  255. package/renderer/dist/emulator/data/localization/pt-BR.json +361 -0
  256. package/renderer/dist/emulator/data/localization/retroarch.json +617 -0
  257. package/renderer/dist/emulator/data/localization/ro-RO.json +310 -0
  258. package/renderer/dist/emulator/data/localization/ru-RU.json +301 -0
  259. package/renderer/dist/emulator/data/localization/tr-TR.json +310 -0
  260. package/renderer/dist/emulator/data/localization/vi-VN.json +302 -0
  261. package/renderer/dist/emulator/data/localization/zh-CN.json +351 -0
  262. package/renderer/dist/emulator/data/src/GameManager.js +464 -0
  263. package/renderer/dist/emulator/data/src/compression.js +142 -0
  264. package/renderer/dist/emulator/data/src/emulator.js +6158 -0
  265. package/renderer/dist/emulator/data/src/gamepad.js +167 -0
  266. package/renderer/dist/emulator/data/src/nipplejs.js +1 -0
  267. package/renderer/dist/emulator/data/src/shaders.js +236 -0
  268. package/renderer/dist/emulator/data/src/socket.io.min.js +7 -0
  269. package/renderer/dist/emulator/data/src/storage.js +125 -0
  270. package/renderer/dist/emulator/data/version.json +5 -0
  271. package/renderer/dist/emulator/host.js +297 -0
  272. package/renderer/dist/emulator/index.html +28 -0
  273. package/renderer/dist/emulator/provenance.json +6 -0
  274. package/renderer/dist/index.html +16 -3
  275. package/scripts/after-install.mjs +30 -8
  276. package/scripts/approval-server.sh +24 -5
  277. package/scripts/before-publish.mjs +12 -10
  278. package/scripts/cloud-shim.pl +57 -0
  279. package/shared/account-names.d.mts +6 -0
  280. package/shared/account-names.mjs +15 -0
  281. package/shared/agent-hours.mjs +136 -0
  282. package/shared/agent-import.mjs +62 -34
  283. package/shared/agents.d.mts +1 -0
  284. package/shared/agents.mjs +126 -522
  285. package/shared/analytics-events.mjs +12 -0
  286. package/shared/approval-card.mjs +36 -0
  287. package/shared/bridge-map.mjs +45 -1
  288. package/shared/claude-code-shape.mjs +6 -0
  289. package/shared/claude-commands.generated.mjs +6 -4
  290. package/shared/claude-models.generated.mjs +6 -4
  291. package/shared/claude-usage.d.mts +1 -0
  292. package/shared/claude-usage.mjs +42 -1
  293. package/shared/cloud-hand-back.d.mts +7 -0
  294. package/shared/cloud-hand-back.mjs +20 -0
  295. package/shared/cloud-kit.d.mts +219 -0
  296. package/shared/cloud-kit.mjs +341 -0
  297. package/shared/cloud-login-name.mjs +4 -0
  298. package/shared/cloud-start.mjs +17 -0
  299. package/shared/cloud-versions.mjs +23 -0
  300. package/shared/codex-import.mjs +2 -2
  301. package/shared/codex-modes.d.mts +22 -9
  302. package/shared/codex-modes.mjs +67 -11
  303. package/shared/codex-usage.mjs +108 -2
  304. package/shared/corner-tag.d.mts +36 -0
  305. package/shared/corner-tag.mjs +396 -0
  306. package/shared/dead-run-trace.mjs +19 -2
  307. package/shared/engines.mjs +76 -300
  308. package/shared/feedback.d.mts +7 -0
  309. package/shared/feedback.mjs +25 -0
  310. package/shared/first-run-practice.mjs +17 -24
  311. package/shared/harness-definitions.mjs +111 -0
  312. package/shared/instruction-defaults.json +2 -2
  313. package/shared/key-caps.d.mts +14 -0
  314. package/shared/key-caps.mjs +68 -0
  315. package/shared/message-edits.d.mts +7 -0
  316. package/shared/message-edits.mjs +35 -0
  317. package/shared/move-thread.d.mts +24 -0
  318. package/shared/move-thread.mjs +112 -0
  319. package/shared/named-threads.mjs +72 -0
  320. package/shared/not-shipped.d.mts +22 -0
  321. package/shared/not-shipped.mjs +89 -0
  322. package/shared/notify-rules.d.mts +31 -0
  323. package/shared/notify-rules.mjs +55 -8
  324. package/shared/phone-files.mjs +28 -0
  325. package/shared/phone-settings.mjs +118 -0
  326. package/shared/phone-snapshot.d.mts +16 -0
  327. package/shared/phone-snapshot.mjs +348 -0
  328. package/shared/picture-formats.d.mts +1 -0
  329. package/shared/picture-formats.mjs +13 -0
  330. package/shared/provider-commands.mjs +10 -2
  331. package/shared/rank.d.mts +4 -1
  332. package/shared/rank.mjs +82 -19
  333. package/shared/relay-address.mjs +6 -0
  334. package/shared/relay-crypto.mjs +165 -0
  335. package/shared/repeats.d.mts +8 -0
  336. package/shared/repeats.mjs +33 -2
  337. package/shared/room-cards.mjs +167 -0
  338. package/shared/room-links.d.mts +4 -0
  339. package/shared/room-links.mjs +21 -0
  340. package/shared/runs-on.d.mts +3 -13
  341. package/shared/runs-on.mjs +31 -52
  342. package/shared/shipped-note.d.mts +4 -0
  343. package/shared/shipped-note.mjs +6 -0
  344. package/shared/shortcuts.mjs +24 -10
  345. package/shared/spawn-trouble.d.mts +4 -0
  346. package/shared/spawn-trouble.mjs +484 -30
  347. package/shared/team-rules.mjs +9 -2
  348. package/shared/teammates.d.mts +19 -0
  349. package/shared/teammates.mjs +756 -0
  350. package/shared/terminal-focus.d.mts +1 -0
  351. package/shared/terminal-focus.mjs +13 -0
  352. package/shared/terminal-input.d.mts +1 -0
  353. package/shared/terminal-input.mjs +30 -0
  354. package/shared/terminal-keys.d.mts +1 -0
  355. package/shared/terminal-keys.mjs +16 -0
  356. package/shared/terminal-size.d.mts +4 -0
  357. package/shared/terminal-size.mjs +29 -0
  358. package/shared/thread-cards.mjs +4 -1
  359. package/shared/usage.d.mts +12 -0
  360. package/shared/usage.mjs +56 -3
  361. package/shared/websites.d.mts +15 -0
  362. package/shared/websites.mjs +61 -0
  363. package/shared/where-it-runs-from.d.mts +43 -0
  364. package/shared/where-it-runs-from.mjs +155 -0
  365. package/shared/work-items.mjs +150 -29
  366. package/shared/work-lines.mjs +93 -245
  367. package/shared/xterm-invalid-range.d.mts +2 -0
  368. package/shared/xterm-invalid-range.mjs +58 -0
  369. package/renderer/dist/assets/index-ChKsQkRw.js +0 -1169
  370. package/renderer/dist/assets/index-ClBXnq3B.css +0 -32
@@ -0,0 +1,12 @@
1
+ // Reads Codex transcripts for the watch, off the app's main process
2
+ // (codex-threads.mjs readCodexThreadsOffThread).
3
+ import { parentPort } from 'node:worker_threads';
4
+ import { readCodexThreads } from './codex-threads.mjs';
5
+
6
+ parentPort.on('message', ({ id, opts }) => {
7
+ try {
8
+ parentPort.postMessage({ id, ok: true, value: readCodexThreads(opts) });
9
+ } catch (err) {
10
+ parentPort.postMessage({ id, ok: false, error: String(err?.message ?? err) });
11
+ }
12
+ });
@@ -24,10 +24,13 @@
24
24
  // table. It is not read: Electron ships no sqlite, the file is written live
25
25
  // under WAL, and the two plain files carry what the row needs.
26
26
  import fs from 'node:fs';
27
+ import { Worker } from 'node:worker_threads';
27
28
  import os from 'node:os';
28
29
  import path from 'node:path';
29
30
  import { RECENT_DAYS, isScratchFolder, shortFolder, threadTitle } from './agent-sessions.mjs';
31
+ import { codexDataDirs } from './agent-homes.mjs';
30
32
  import { WAS_SLUGS, nameSlug } from '../shared/product-name.mjs';
33
+ import { howTheChatEnded } from '../shared/agent-import.mjs';
31
34
 
32
35
  export const CODEX_RECENT_DAYS = RECENT_DAYS;
33
36
  /** The originator Codex records for a run this app started (CLIENT_INFO.name), now and before. */
@@ -163,7 +166,25 @@ const partsOf = (payload) => (Array.isArray(payload?.content) ? payload.content
163
166
  * `message` with a `role` and a `content` array of `input_text`, `input_image`
164
167
  * and `output_text` parts. Current Codex threads are paginated, and a build
165
168
  * that read only legacy showed "Codex has not answered yet." on every row. */
169
+ // Each transcript as last read, kept while its size and time are unchanged:
170
+ // her Codex folder can hold thousands of them, and reading every one again
171
+ // each minute held the app for seconds.
172
+ const ROLLOUTS_KEPT = 5000;
173
+ const rollouts = new Map();
174
+
166
175
  export function readRollout(file) {
176
+ let st = null;
177
+ try { st = fs.statSync(file); } catch { return null; }
178
+ const kept = rollouts.get(file);
179
+ if (kept && kept.size === st.size && kept.mtimeMs === st.mtimeMs) return kept.value;
180
+ const value = readRolloutAfresh(file);
181
+ rollouts.delete(file);
182
+ rollouts.set(file, { size: st.size, mtimeMs: st.mtimeMs, value });
183
+ if (rollouts.size > ROLLOUTS_KEPT) rollouts.delete(rollouts.keys().next().value);
184
+ return value;
185
+ }
186
+
187
+ function readRolloutAfresh(file) {
167
188
  let text = '';
168
189
  try {
169
190
  const fd = fs.openSync(file, 'r');
@@ -178,6 +199,8 @@ export function readRollout(file) {
178
199
  let meta = null;
179
200
  let prompt = '';
180
201
  let last = '';
202
+ // Whether the person wrote after Codex's last answer, so it is not waiting.
203
+ let herTurnLast = false;
181
204
  let turns = 0;
182
205
  let images = 0;
183
206
  let lastActive = 0;
@@ -212,11 +235,12 @@ export function readRollout(file) {
212
235
  if (p.type === 'user_message') {
213
236
  const said = cleanPrompt(p.message);
214
237
  if (!prompt && said && !isInjected(said)) prompt = said;
238
+ if (said && !isInjected(said)) herTurnLast = true;
215
239
  turns += 1;
216
240
  sawEventTurns = true;
217
241
  } else if (p.type === 'agent_message') {
218
242
  const said = cleanAnswer(p.message);
219
- if (said) last = said;
243
+ if (said) { last = said; herTurnLast = false; }
220
244
  }
221
245
  continue;
222
246
  }
@@ -230,16 +254,17 @@ export function readRollout(file) {
230
254
  .filter(Boolean);
231
255
  if (!hers.length) continue; // a turn made of nothing but Codex's own preamble
232
256
  if (!prompt) prompt = hers.join('\n\n').trim();
257
+ herTurnLast = true;
233
258
  if (!sawEventTurns) turns += 1;
234
259
  } else if (p.role === 'assistant') {
235
260
  const said = cleanAnswer(partsOf(p).filter((c) => c.type === 'output_text').map((c) => c.text ?? '').join('\n'));
236
- if (said) last = said;
261
+ if (said) { last = said; herTurnLast = false; }
237
262
  }
238
263
  }
239
264
  if (!meta || !meta.id) return null;
240
265
  let mtime = 0;
241
266
  try { mtime = fs.statSync(file).mtimeMs; } catch { mtime = 0; }
242
- return { ...meta, prompt, last, turns, images, lastActive, path: file, mtime };
267
+ return { ...meta, prompt, last, herTurnLast, turns, images, lastActive, path: file, mtime };
243
268
  }
244
269
 
245
270
  /**
@@ -252,12 +277,40 @@ export const isLive = (mtime, now = Date.now()) => Number(mtime) > 0 && now - Nu
252
277
  /**
253
278
  * THE USER'S CONVERSATIONS, newest first, in the shape the import card and the
254
279
  * import row both read. One entry per thread a person typed into, in a real folder,
255
- * touched in the last `days` days. */
256
- export function readCodexThreads({ home = os.homedir(), codexDir = codexHome(home), days = CODEX_RECENT_DAYS, now = Date.now() } = {}) {
257
- const index = readCodexIndex(codexDir);
280
+ * touched in the last `days` days.
281
+ *
282
+ * EVERY CODEX FOLDER ON THE MACHINE, not only `~/.codex` (w-e46f2e9cea): a
283
+ * second login under `~/.codex-<name>` or a `CODEX_HOME` holds conversations
284
+ * the import never offered. `codexDirs` is the list main/agent-homes.mjs makes;
285
+ * `codexDir` still names exactly one folder for a caller that means one. The
286
+ * same conversation in two folders is one row.
287
+ *
288
+ * WHICH COPY, AND WHICH NAME, decided apart (Codex's review of this change,
289
+ * 2026-10-11). The copy kept is the transcript file written last, judged by
290
+ * the file alone: judging by `when`, which folds in the index's own date, let
291
+ * a stale copy whose folder's index was touched later beat the copy still
292
+ * being written. And the name Codex gave a conversation is read from every
293
+ * folder's index, newest entry winning, so the copy kept still carries a name
294
+ * that only another folder's index knew. */
295
+ export function readCodexThreads({ home = os.homedir(), codexDir = null, codexDirs = null, days = CODEX_RECENT_DAYS, now = Date.now() } = {}) {
296
+ const dirs = codexDirs ?? (codexDir ? [codexDir] : codexDataDirs({ home }));
258
297
  const cutoff = now - Math.max(0, Number(days) || 0) * 86400 * 1000;
259
- const out = [];
260
- const skipped = { notHers: 0, scratch: 0, old: 0, empty: 0, unreadable: 0 };
298
+ const index = new Map();
299
+ for (const dir of dirs) {
300
+ for (const [id, entry] of readCodexIndex(dir)) {
301
+ const had = index.get(id);
302
+ if (!had || (entry.name && (!had.name || entry.updatedAt > had.updatedAt))) index.set(id, entry);
303
+ }
304
+ }
305
+ const byId = new Map();
306
+ const skipped = { notHers: 0, scratch: 0, old: 0, empty: 0, unreadable: 0, copy: 0 };
307
+ for (const dir of dirs) readOneCodexHome(dir, { home, days, now, cutoff, index, byId, skipped });
308
+ const out = [...byId.values()].map(({ fileTime, ...t }) => t);
309
+ out.sort((a, b) => b.when - a.when);
310
+ return { threads: out, skipped };
311
+ }
312
+
313
+ function readOneCodexHome(codexDir, { home, days, now, cutoff, index, byId, skipped }) {
261
314
  for (const file of listRolloutFiles(codexDir, { days, since: cutoff })) {
262
315
  const r = readRollout(file);
263
316
  if (!r) { skipped.unreadable += 1; continue; }
@@ -268,7 +321,13 @@ export function readCodexThreads({ home = os.homedir(), codexDir = codexHome(hom
268
321
  if (when < cutoff) { skipped.old += 1; continue; }
269
322
  const title = named?.name || threadTitle([r.prompt]);
270
323
  if (!title) { skipped.empty += 1; continue; }
271
- out.push({
324
+ const had = byId.get(r.id);
325
+ if (had) {
326
+ skipped.copy += 1;
327
+ if (had.fileTime >= r.mtime) continue;
328
+ }
329
+ byId.set(r.id, {
330
+ fileTime: r.mtime,
272
331
  id: r.id,
273
332
  source: 'codex',
274
333
  folder: r.cwd,
@@ -284,8 +343,50 @@ export function readCodexThreads({ home = os.homedir(), codexDir = codexHome(hom
284
343
  prompt: r.prompt,
285
344
  last: r.last,
286
345
  live: isLive(r.mtime, now),
346
+ ...(r.herTurnLast ? { waiting: false, ask: '' } : howTheChatEnded(r.last)),
347
+ lastSaid: r.last,
348
+ firstSaid: r.prompt,
287
349
  });
288
350
  }
289
- out.sort((a, b) => b.when - a.when);
290
- return { threads: out, skipped };
351
+ }
352
+
353
+ // THE SAME READ IN A THREAD OF ITS OWN, for the watch that runs every minute:
354
+ // a first read of a large Codex folder takes seconds, and on the main process
355
+ // that is seconds of the app not answering. One worker, kept for the life of
356
+ // the app, so its transcripts stay remembered between reads. Where a worker
357
+ // cannot start, the read runs here as before.
358
+ const OFF_THREAD_DEADLINE_MS = 5 * 60_000;
359
+ let worker = null;
360
+ let asked = 0;
361
+ const waiting = new Map();
362
+ export function readCodexThreadsOffThread(opts = {}) {
363
+ try {
364
+ if (!worker) {
365
+ worker = new Worker(new URL('./codex-threads-worker.mjs', import.meta.url));
366
+ worker.unref();
367
+ worker.on('message', ({ id, ok, value, error }) => {
368
+ const w = waiting.get(id);
369
+ if (!w) return;
370
+ waiting.delete(id);
371
+ clearTimeout(w.timer);
372
+ if (ok) w.resolve(value); else w.reject(new Error(error));
373
+ });
374
+ const fail = (err) => {
375
+ for (const w of waiting.values()) { clearTimeout(w.timer); w.reject(err); }
376
+ waiting.clear();
377
+ worker = null;
378
+ };
379
+ worker.on('error', fail);
380
+ worker.on('exit', () => fail(new Error('the Codex reader stopped')));
381
+ }
382
+ } catch {
383
+ return Promise.resolve().then(() => readCodexThreads(opts));
384
+ }
385
+ const id = (asked += 1);
386
+ return new Promise((resolve, reject) => {
387
+ const timer = setTimeout(() => { waiting.delete(id); reject(new Error('the Codex reader did not answer in time')); }, OFF_THREAD_DEADLINE_MS);
388
+ timer.unref?.();
389
+ waiting.set(id, { resolve, reject, timer });
390
+ worker.postMessage({ id, opts });
391
+ });
291
392
  }
@@ -16,9 +16,11 @@
16
16
  // such records across its most recent sessions, the newest written within
17
17
  // the minute.
18
18
  //
19
- // THE PUSH STILL WINS. A live notification is this second's truth and a log is
20
- // the last thing anybody wrote down, so main/codex-usage.mjs reads this only when
21
- // it has nothing of its own. Nothing about the existing path changes.
19
+ // A LIVE PUSH STILL WINS, AND A QUIET ONE NO LONGER DOES (w-7b7182ef61). A
20
+ // notification that arrived a moment ago is this second's truth and nothing on
21
+ // disk can be newer, so main/codex-usage.mjs does not open a file while one is
22
+ // fresh. Past that the two are compared and the newer is read, because an hours
23
+ // old push was being drawn over a newer line in this log.
22
24
  //
23
25
  // IT IS THE SAME ACCOUNT OR IT IS NOT READ. One CODEX_HOME is one login, and the
24
26
  // log lives inside the home, so a reading taken from `~/.codex/sessions` is a
@@ -62,8 +62,38 @@
62
62
  // level down.
63
63
 
64
64
  import { codexLimits, mergeRateLimits } from '../shared/codex-usage.mjs';
65
+ import { limitsStillRunning } from '../shared/usage.mjs';
65
66
  import { loggedCodexLimits } from './codex-usage-file.mjs';
66
67
 
68
+ const LOG_EVERY_MS = 30_000;
69
+
70
+ /**
71
+ * HOW LONG A PUSH IS THIS SECOND'S TRUTH (w-7b7182ef61).
72
+ *
73
+ * "The push still wins" holds while pushes are arriving, which is every few
74
+ * seconds during a turn; nothing on disk can be newer than one of those, so the
75
+ * busy case never opens a file. A push from four hours ago is just the oldest
76
+ * thing anybody knows, so past this it is compared against the log instead.
77
+ */
78
+ const PUSH_FRESH_MS = 60_000;
79
+
80
+ /**
81
+ * Every Codex login's own reading, for the Settings page: each out of the
82
+ * session logs under its own home, and the one in use from `current`, which
83
+ * the push keeps newer while it works. A login that has never run here gets
84
+ * no limits rather than zeroes, and a window that has reset since is dropped,
85
+ * because a login not in use can go days without a new reading.
86
+ */
87
+ export function codexAccountReadings({ profiles, homeOf, current = null, currentHome = null, now = Date.now(), readLog = loggedCodexLimits }) {
88
+ return profiles.map((profile) => {
89
+ const home = homeOf(profile);
90
+ const live = !!current?.limits?.length && home === currentHome;
91
+ const reading = live ? current : readLog(home, { now });
92
+ const limits = limitsStillRunning(live ? current.limits : codexLimits(reading?.snapshot), now);
93
+ return limits.length ? { profile, limits, at: reading.at } : { profile };
94
+ });
95
+ }
96
+
67
97
  export class CodexUsage {
68
98
  /**
69
99
  * @param {object} how @param { => string|null} how.home Which CODEX_HOME the
@@ -94,23 +124,42 @@ export class CodexUsage {
94
124
  read() {
95
125
  if (this._takenUnder !== null && this._takenUnder !== this._home()) this._forget();
96
126
  const limits = codexLimits(this._snapshot);
97
- if (limits.length) return { limits, at: this._at };
98
- // NOTHING HAS PUSHED, SO ASK WHAT CODEX ALREADY WROTE DOWN. This is the
99
- // whole of: the push only ever arrives for work the app itself ran, and a
100
- // person who runs Codex in its own app would see the panel stay empty
127
+ const pushed = limits.length ? { limits, at: this._at } : null;
128
+ if (pushed && this._now() - pushed.at < PUSH_FRESH_MS) return pushed;
129
+ // NOTHING HAS PUSHED LATELY, SO ASK WHAT CODEX ALREADY WROTE DOWN. This is
130
+ // the whole of: the push only ever arrives for work the app itself ran, and
131
+ // a person who runs Codex in its own app would see the panel stay empty
101
132
  // while their weekly limit was full. main/codex-usage-file.mjs is a read of a file
102
133
  // under this same CODEX_HOME. It starts no process and sends nothing
103
134
  // anywhere, so neither rule above is bent.
104
- return this._logged();
135
+ const logged = this._logged();
136
+ if (!pushed) return logged;
137
+ return logged && logged.at > pushed.at ? logged : pushed;
138
+ }
139
+
140
+ /**
141
+ * `read()` with the log cache dropped, for a person who pressed Refresh:
142
+ * inside `LOG_EVERY_MS` a press would otherwise change nothing. It asks
143
+ * nobody anything, so both rules at the top of this file still hold. */
144
+ refreshNow() {
145
+ this._loggedRead = null;
146
+ return this.read();
105
147
  }
106
148
 
107
149
  /**
108
150
  * The last figure in Codex's own session log under this home, shaped exactly
109
151
  * like a pushed one. Null on a Mac where Codex has never run. */
110
152
  _logged() {
111
- const reading = this._readLog(this._home(), { now: this._now() });
153
+ // Asked on every request the window makes; the log is walked at most
154
+ // every half minute.
155
+ const home = this._home();
156
+ const now = this._now();
157
+ if (this._loggedRead && this._loggedRead.home === home && now - this._loggedRead.at < LOG_EVERY_MS) return this._loggedRead.value;
158
+ const reading = this._readLog(home, { now });
112
159
  const limits = codexLimits(reading?.snapshot);
113
- return limits.length ? { limits, at: reading.at } : null;
160
+ const value = limits.length ? { limits, at: reading.at } : null;
161
+ this._loggedRead = { home, at: now, value };
162
+ return value;
114
163
  }
115
164
 
116
165
  /**
@@ -10,21 +10,99 @@
10
10
  // The founder, before launch: "after onboarding for both anthropic and openai
11
11
  // harnesses, it should only import on command, not continuously". Importing is
12
12
  // now the walk's last card and ⌘K import, for Claude Code and Codex alike.
13
+ //
14
+ // IT IS ALSO WHERE A CODEX AGENT IS NOTICED (w-1116fbb68a, 2026-10-08). It is
15
+ // the one thing in the app that already knows a person's Codex conversations,
16
+ // and it reads them on a timer rather than on the snapshot, which is what makes
17
+ // it the right place: see `noticeCodexAgents` below.
13
18
  import { readCodexThreads } from './codex-threads.mjs';
14
19
 
15
20
  export const CODEX_POLL_MS = 60_000;
16
21
 
17
- export function scanCodex({ store, readThreads = readCodexThreads, now = Date.now() } = {}) {
18
- let threads = [];
19
- try { ({ threads } = readThreads({ now })); } catch { return { refreshed: 0, retold: 0, threads: 0 }; }
22
+ /**
23
+ * HOW LONG AFTER ITS LAST WRITE A CODEX THREAD IS STILL AN AGENT THAT WAS SEEN.
24
+ *
25
+ * A Claude Code session is a process, so `agent_seen` catches one that has sat
26
+ * open since earlier in the sitting (main/ipc.mjs, liveAgents). A Codex thread
27
+ * leaves no process behind: `isLive` is two minutes of file mtime, so counting
28
+ * only live threads would notice a Codex user ONLY when this watch's minute
29
+ * happened to land while they were typing. An hour is one sitting, which is
30
+ * the span the Claude read already covers without being asked to.
31
+ *
32
+ * AND IT IS NOT A DAY. The reader hands over ten days of conversations, and
33
+ * counting those would say every install with Codex on it had an agent up on
34
+ * every day the app was opened, which is the opposite of the under-count this
35
+ * was added to fix.
36
+ */
37
+ export const CODEX_SEEN_MS = 60 * 60_000;
38
+
39
+ /**
40
+ * "AN AGENT WAS SEEN", FOR CODEX TOO (w-1116fbb68a, 2026-10-08).
41
+ *
42
+ * `agent_seen` listed Claude Code processes and nothing else, and about a
43
+ * third of the people on this app are on Codex, so whether they had an agent
44
+ * at all was read off proxies: a run this app started, or a reply. The threads
45
+ * are already in hand once a minute for the mirror refresh, so this costs
46
+ * nothing beyond the comparison.
47
+ *
48
+ * NOTHING ABOUT A THREAD IS SENT. Not its folder, not its title, not its id,
49
+ * which is only ever compared inside this process. `engine` is the whole of
50
+ * the payload and it is one of two fixed words.
51
+ *
52
+ * ONCE PER THREAD PER RUN OF THE APP, for the reason the Claude side keeps a
53
+ * set: this reads the same conversations every minute, so without it one
54
+ * conversation would send an event a minute all day.
55
+ */
56
+ export function noticeCodexAgents(threads, { count = null, seen = null, now = Date.now() } = {}) {
57
+ if (typeof count !== 'function') return 0;
58
+ let sent = 0;
59
+ for (const t of threads ?? []) {
60
+ const id = String(t?.id ?? '');
61
+ if (!id) continue;
62
+ const at = Number(t.lastActive ?? 0);
63
+ if (!t.live && !(at > 0 && now - at < CODEX_SEEN_MS)) continue;
64
+ if (seen) {
65
+ if (seen.has(id)) continue;
66
+ seen.add(id);
67
+ }
68
+ // A count is never worth the watch: the mirror refresh below is what
69
+ // somebody actually sees, and it runs whatever the switch does.
70
+ try { count('agent_seen', { engine: 'codex' }); } catch { /* nothing */ }
71
+ sent += 1;
72
+ }
73
+ return sent;
74
+ }
75
+
76
+ // Answers at once for a reader that answers at once, and as a promise for one
77
+ // that reads off the main process (readCodexThreadsOffThread).
78
+ export function scanCodex({ store, readThreads = readCodexThreads, now = Date.now(), count = null, seen = null } = {}) {
79
+ const none = { refreshed: 0, retold: 0, threads: 0 };
80
+ let read;
81
+ try { read = readThreads({ now }); } catch { return none; }
82
+ if (typeof read?.then === 'function') return read.then(({ threads }) => applyCodexThreads(threads, { store, now, count, seen }), () => none);
83
+ return applyCodexThreads(read?.threads ?? [], { store, now, count, seen });
84
+ }
85
+
86
+ function applyCodexThreads(threads, { store, now, count, seen }) {
87
+ noticeCodexAgents(threads, { count, seen, now });
20
88
  const refreshed = store.refreshCodexMirrors(threads, { now });
21
89
  const retold = store.refreshCodexAsks(threads, { now });
22
90
  return { refreshed, retold, threads: threads.length };
23
91
  }
24
92
 
25
- export function startCodexWatch({ store, readThreads = readCodexThreads, pollMs = CODEX_POLL_MS, firstDelayMs = 8_000 } = {}) {
93
+ export function startCodexWatch({ store, readThreads = readCodexThreads, pollMs = CODEX_POLL_MS, firstDelayMs = 8_000, count = null } = {}) {
94
+ // Conversations this run has already counted. In memory on purpose, exactly
95
+ // as the Claude side's set is: a fresh launch seeing the same conversation
96
+ // again is a fresh fact about the app being used.
97
+ const seen = new Set();
98
+ // One scan at a time: a read slower than the minute must not stack up.
99
+ let scanning = null;
26
100
  const run = () => {
27
- try { scanCodex({ store, readThreads }); } catch (e) { console.warn('codex watch:', e?.message ?? e); }
101
+ if (scanning) return scanning;
102
+ scanning = Promise.resolve().then(() => scanCodex({ store, readThreads, count, seen }))
103
+ .catch((e) => console.warn('codex watch:', e?.message ?? e))
104
+ .finally(() => { scanning = null; });
105
+ return scanning;
28
106
  };
29
107
  const first = setTimeout(run, firstDelayMs);
30
108
  const timer = setInterval(run, pollMs);