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
@@ -18,7 +18,7 @@ import crypto from 'node:crypto';
18
18
  import { machineryPath } from './home.mjs';
19
19
  import { withProjectLock } from './project-lock.mjs';
20
20
  import {
21
- foldWorkItems, normalizeLine, buildLine, buildClaimLine, buildHeartbeatLine, buildReleaseLine,
21
+ foldWorkItems, foldRawInto, finishItem, normalizeLine, buildLine, buildClaimLine, buildHeartbeatLine, buildReleaseLine,
22
22
  isClaimable, sortForPull, matchesFilter, isWorkItemId, MAX_LINE_BYTES, LEASE_MS,
23
23
  } from '../../shared/work-items.mjs';
24
24
 
@@ -140,32 +140,190 @@ function readLines(file) {
140
140
  // themselves would let one caller's edit become every later caller's truth.
141
141
  const folded = new Map();
142
142
  const MAX_FOLDS_HELD = 64;
143
+ const REWINDOW_BYTES = 2 * 1024 * 1024;
143
144
 
144
- function ledgerStamp(file) {
145
- try {
146
- const st = fs.statSync(file);
147
- return `${st.ino}:${st.size}:${st.mtimeMs}`;
148
- } catch (err) {
149
- if (err.code === 'ENOENT') return 'absent';
150
- throw err;
145
+ // A STAMP OF SIZE AND TIME CANNOT TELL A REPLACED LEDGER FROM AN UNTOUCHED ONE,
146
+ // so the file that was folded is held open.
147
+ //
148
+ // What broke (2026-10-19, on GitHub's Linux runner): a ledger deleted and
149
+ // written again at the same length answered with the fold of the old one.
150
+ // Deleting it freed its inode number for the new file to take, and the clock
151
+ // that filesystem stamps a write with is coarse enough that both writes landed
152
+ // on one mtime, so all three parts of the stamp matched. On APFS the two writes
153
+ // get different nanoseconds, which is why no Mac ever saw it.
154
+ //
155
+ // An open descriptor settles it: while one is held, that inode number cannot be
156
+ // given to another file, so a number we do not recognise means a different
157
+ // file. The generation below carries that into the stamp, so a replaced ledger
158
+ // is read from the start by every cache keyed on it, not just the fold.
159
+ const pinned = new Map();
160
+ const MAX_PINS = 64;
161
+ let generations = 0;
162
+
163
+ function dropPin(file) {
164
+ const pin = pinned.get(file);
165
+ if (!pin) return;
166
+ pinned.delete(file);
167
+ try { fs.closeSync(pin.fd); } catch { /* already gone */ }
168
+ }
169
+
170
+ function ledgerPin(file) {
171
+ const absent = { stamp: 'absent', st: null, fd: null, gen: 0 };
172
+ let st = null;
173
+ try { st = fs.statSync(file); } catch (err) { if (err.code !== 'ENOENT') throw err; }
174
+ if (!st) { dropPin(file); return absent; }
175
+ let pin = pinned.get(file);
176
+ if (!pin || pin.ino !== st.ino) {
177
+ dropPin(file);
178
+ let fd;
179
+ try { fd = fs.openSync(file, 'r'); } catch (err) {
180
+ if (err.code !== 'ENOENT') throw err;
181
+ return absent;
182
+ }
183
+ // The file that ended up held, which is a different one from the stat above
184
+ // if it was replaced between the two calls.
185
+ st = fs.fstatSync(fd);
186
+ generations += 1;
187
+ if (pinned.size >= MAX_PINS) dropPin(pinned.keys().next().value);
188
+ pin = { fd, ino: st.ino, gen: generations };
189
+ pinned.set(file, pin);
151
190
  }
191
+ return { stamp: `${pin.gen}:${st.size}:${st.mtimeMs}`, st, fd: pin.fd, gen: pin.gen };
192
+ }
193
+
194
+ function ledgerStamp(file) {
195
+ return ledgerPin(file).stamp;
152
196
  }
153
197
 
198
+ const usable = (l) => l && Buffer.byteLength(l, 'utf8') <= MAX_LINE_BYTES;
199
+
200
+ // A ledger that has only grown is folded on from where it was: every running
201
+ // agent's heartbeat changes the file, and folding all 8 MB again each time
202
+ // held up every request the window made. A file that shrank, was replaced, or
203
+ // changed without growing is read from the start.
154
204
  function foldedLedger(file) {
155
- const stamp = ledgerStamp(file);
205
+ const pin = ledgerPin(file);
206
+ const st = pin.st;
156
207
  const held = folded.get(file);
157
- if (held && held.stamp === stamp) return held.items;
208
+ if (held && held.stamp === pin.stamp) return held.items;
209
+ // While it still holds no more than the 8 MB a fresh read would, give or
210
+ // take REWINDOW_BYTES added since: a fold kept much longer would show
211
+ // threads a fresh read cuts off.
212
+ const inWindow = held && st && (held.from === 0 ? st.size <= MAX_LEDGER_BYTES : st.size - held.from <= MAX_LEDGER_BYTES + REWINDOW_BYTES);
213
+ if (held && st && held.gen === pin.gen && st.size > held.offset && held.raw && inWindow) {
214
+ const buf = Buffer.allocUnsafe(st.size - held.offset);
215
+ const n = fs.readSync(pin.fd, buf, 0, buf.length, held.offset);
216
+ // Whole lines only, by the byte: a line still being written waits for
217
+ // the next read rather than being cut through a character.
218
+ const end = n ? buf.lastIndexOf(0x0a, n - 1) + 1 : 0;
219
+ const chunk = buf.toString('utf8', 0, end);
220
+ held.offset += end;
221
+ const touched = new Set();
222
+ foldRawInto(held.raw, chunk.split('\n').filter(usable), touched);
223
+ // Only threads new to this fold or reopened in it: the rest were looked at
224
+ // already, and one with no title anywhere would be read for on every line.
225
+ if (held.from > 0) {
226
+ const was = (id) => held.items.get(id);
227
+ const arrived = [...touched].filter((id) => !was(id) || was(id).status === 'done');
228
+ restoreCutHeads(held.raw, arrived, pin.fd, held.from, held.offset);
229
+ }
230
+ for (const id of touched) held.items.set(id, finishItem(held.raw.get(id), 0));
231
+ held.stamp = pin.stamp;
232
+ return held.items;
233
+ }
158
234
  // Time zero, so the lease pass inside the fold expires nothing: a lease is
159
235
  // only ever lapsed against the clock of the call asking, and that is `aged`.
160
- const items = stamp === 'absent' ? new Map() : foldWorkItems(readLines(file), 0);
236
+ const raw = new Map();
237
+ let offset = 0;
238
+ let from = 0;
239
+ if (st) {
240
+ const read = readWindow(file, st.size, pin.fd);
241
+ foldRawInto(raw, read.text.split('\n').filter(usable));
242
+ if (read.from > 0) restoreCutHeads(raw, raw.keys(), pin.fd, read.from, read.end);
243
+ offset = read.end;
244
+ from = read.from;
245
+ }
246
+ const items = new Map();
247
+ for (const [id, item] of raw) items.set(id, finishItem(item, 0));
161
248
  // One entry per ledger, so a real store has a few dozen. The cap is for the
162
249
  // long-lived MCP server, which walks temporary project dirs that never come
163
250
  // back; a Map iterates in insertion order, so the oldest key goes first.
164
251
  if (folded.size >= MAX_FOLDS_HELD) folded.delete(folded.keys().next().value);
165
- folded.set(file, { stamp, items });
252
+ folded.set(file, { stamp: pin.stamp, items, raw, gen: pin.gen, offset, from });
166
253
  return items;
167
254
  }
168
255
 
256
+ // The ledger's trailing window, as text, to its last whole line, and the byte
257
+ // that ends at, read through the descriptor the fold holds open.
258
+ function readWindow(file, size, fd) {
259
+ if (size > MAX_LEDGER_BYTES && !warnedOversize.has(file)) {
260
+ warnedOversize.add(file);
261
+ console.warn(`work-items: ${file} is ${size} bytes; reading only the last ${MAX_LEDGER_BYTES}`);
262
+ }
263
+ const from = Math.max(0, size - MAX_LEDGER_BYTES);
264
+ const buf = Buffer.allocUnsafe(size - from);
265
+ const n = fs.readSync(fd, buf, 0, buf.length, from);
266
+ const end = n ? buf.lastIndexOf(0x0a, n - 1) + 1 : 0;
267
+ return { text: buf.toString('utf8', 0, end), end: from + end, from };
268
+ }
269
+
270
+ // AN UNFINISHED THREAD WHOSE FIRST LINE IS BEFORE THE WINDOW is folded from its
271
+ // later lines alone: no title, so a blank row in the inbox. A title is written
272
+ // once, by the line that makes a thread, so no title means the cut went through
273
+ // it, and its own lines are read from the start of the file and folded again.
274
+ // A finished one is left to `readOlderWorkItems`, so a ledger without such a
275
+ // thread is read exactly as it always was.
276
+ //
277
+ // THE CLAIM STAYS THE WINDOW'S. `claimWorkItem` numbers a claim from the window,
278
+ // so one made after the cut can be lower than one before it, and the older one
279
+ // would fence off everything its agent wrote since.
280
+ function restoreCutHeads(raw, ids, fd, from, end) {
281
+ const cut = new Set();
282
+ for (const id of ids) {
283
+ const item = raw.get(id);
284
+ if (!item.wrote.title && item.status !== 'done') cut.add(id);
285
+ }
286
+ if (!cut.size) return;
287
+ const lines = linesUpTo(fd, end, cut);
288
+ const restored = new Map();
289
+ foldRawInto(restored, lines.filter((l) => l.at < from).map((l) => l.text));
290
+ const found = [...restored.keys()].filter((id) => cut.has(id));
291
+ for (const id of found) Object.assign(restored.get(id), { epoch: 0, claim: null });
292
+ foldRawInto(restored, lines.filter((l) => l.at >= from).map((l) => l.text));
293
+ for (const id of found) raw.set(id, restored.get(id));
294
+ }
295
+
296
+ // The whole lines before byte `end` that carry one of `ids`, with the byte each
297
+ // starts at, read a megabyte at a time. Searched as bytes, so a line that is
298
+ // not one of them is never decoded; the fold checks whose each line really is.
299
+ const PIECE_BYTES = 1024 * 1024;
300
+ const ID_KEY = Buffer.from('"id":"');
301
+ function linesUpTo(fd, end, ids) {
302
+ const out = [];
303
+ let rest = Buffer.alloc(0);
304
+ let restAt = 0;
305
+ for (let pos = 0; pos < end;) {
306
+ const buf = Buffer.allocUnsafe(Math.min(PIECE_BYTES, end - pos));
307
+ const n = fs.readSync(fd, buf, 0, buf.length, pos);
308
+ if (!n) break;
309
+ pos += n;
310
+ const bytes = rest.length ? Buffer.concat([rest, buf.subarray(0, n)]) : buf.subarray(0, n);
311
+ const whole = bytes.lastIndexOf(0x0a) + 1;
312
+ const starts = new Set();
313
+ for (let at = bytes.indexOf(ID_KEY); at !== -1 && at < whole; at = bytes.indexOf(ID_KEY, at + ID_KEY.length)) {
314
+ const from = at + ID_KEY.length;
315
+ if (ids.has(bytes.toString('latin1', from, bytes.indexOf(0x22, from)))) starts.add(bytes.lastIndexOf(0x0a, at) + 1);
316
+ }
317
+ for (const start of starts) {
318
+ const text = bytes.toString('utf8', start, bytes.indexOf(0x0a, start));
319
+ if (usable(text)) out.push({ text, at: restAt + start });
320
+ }
321
+ rest = bytes.subarray(whole);
322
+ restAt += whole;
323
+ }
324
+ return out;
325
+ }
326
+
169
327
  // One item as of `now`: a copy, with the lease rule that `foldWorkItems` applies
170
328
  // at the end of its own pass applied here instead. The two mutable fields a
171
329
  // caller can reach through a spread are copied with it.
@@ -238,6 +396,56 @@ export function readWorkItem(projectDir, id, now = Date.now()) {
238
396
  return item ? aged(item, now) : null;
239
397
  }
240
398
 
399
+ /**
400
+ * ONE THREAD'S LINES, OLDEST FIRST, without the lease lines (heartbeats and
401
+ * releases), the last `max` of them.
402
+ *
403
+ * The phone pass (main/phone-inbox.mjs) asks this for every thread of a
404
+ * project, up to 300, and each ask used to read and parse the whole ledger:
405
+ * 20,929 ms of blocked main thread on the real 17,797-line agentbox-team
406
+ * ledger, against 101 ms for one read (2026-10-14, the endless beachball). So
407
+ * the ledger is read once per change of the file, grouped by thread, and kept,
408
+ * keyed on the file's identity exactly as the fold is. The lines handed out are
409
+ * the kept ones, frozen, so no caller can edit what the next one reads.
410
+ */
411
+ const histories = new Map();
412
+ const HISTORIES_HELD = 8;
413
+ function deepFreeze(v) {
414
+ if (v && typeof v === 'object' && !Object.isFrozen(v)) {
415
+ Object.freeze(v);
416
+ for (const k of Object.keys(v)) deepFreeze(v[k]);
417
+ }
418
+ return v;
419
+ }
420
+ function historiesOf(file) {
421
+ const stamp = ledgerStamp(file);
422
+ const held = histories.get(file);
423
+ if (held && held.stamp === stamp) return held.byId;
424
+ const byId = new Map();
425
+ if (stamp !== 'absent') {
426
+ for (const raw of readLines(file)) {
427
+ let line;
428
+ try { line = JSON.parse(raw); } catch { continue; }
429
+ if (!line || typeof line.id !== 'string' || line.heartbeat || line.release) continue;
430
+ let list = byId.get(line.id);
431
+ if (!list) byId.set(line.id, (list = []));
432
+ list.push(deepFreeze(line));
433
+ }
434
+ }
435
+ histories.delete(file);
436
+ if (histories.size >= HISTORIES_HELD) histories.delete(histories.keys().next().value);
437
+ histories.set(file, { stamp, byId });
438
+ return byId;
439
+ }
440
+ // `before` keeps the lines written at or before that moment, and the cap then
441
+ // counts back from there rather than from the newest line.
442
+ export function readItemHistory(projectDir, id, { max = 400, before } = {}) {
443
+ const lines = historiesOf(ledgerPath(projectDir)).get(id);
444
+ if (!lines) return [];
445
+ const upTo = Number.isFinite(before) ? lines.filter((l) => l.ts <= before) : lines;
446
+ return upTo.slice(-max);
447
+ }
448
+
241
449
  /* -------------------------------- mutating ------------------------------- */
242
450
  export function newWorkItemId() {
243
451
  return `w-${crypto.randomBytes(5).toString('hex')}`;
@@ -440,4 +648,14 @@ export function readLinesFrom(projectDir, offset = 0) {
440
648
  }
441
649
 
442
650
  export { LEASE_MS };
443
- export const _internals = { appendLine, readLines, ledgerPath, forgetFolds: () => folded.clear() };
651
+ export const _internals = {
652
+ appendLine,
653
+ readLines,
654
+ ledgerPath,
655
+ forgetFolds: () => {
656
+ folded.clear();
657
+ histories.clear();
658
+ wholeFolds.clear();
659
+ for (const file of [...pinned.keys()]) dropPin(file);
660
+ },
661
+ };