agentbox-app 0.1.13 → 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 (278) 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/agent-sessions.mjs +282 -268
  9. package/main/agents.mjs +179 -466
  10. package/main/analytics.mjs +12 -2
  11. package/main/answer-modes.mjs +103 -37
  12. package/main/approval-prompt-core.mjs +197 -0
  13. package/main/approval-prompt-server.mjs +4 -138
  14. package/main/approvals.mjs +101 -297
  15. package/main/artifact-path.mjs +47 -18
  16. package/main/claude-input.mjs +48 -4
  17. package/main/claude-plan.mjs +48 -0
  18. package/main/claude-session-open.mjs +28 -0
  19. package/main/claude-usage-process.mjs +40 -0
  20. package/main/claude-usage.mjs +18 -40
  21. package/main/cloud/account.mjs +179 -0
  22. package/main/cloud/aws.mjs +127 -0
  23. package/main/cloud/browser-return.mjs +58 -0
  24. package/main/cloud/clients.mjs +15 -0
  25. package/main/cloud/codex-cloud.mjs +53 -0
  26. package/main/cloud/config.mjs +107 -0
  27. package/main/cloud/docs.mjs +219 -0
  28. package/main/cloud/exec.mjs +27 -0
  29. package/main/cloud/host.mjs +165 -0
  30. package/main/cloud/kit.mjs +80 -0
  31. package/main/cloud/logins.mjs +543 -0
  32. package/main/cloud/managed.mjs +115 -0
  33. package/main/cloud/marker.mjs +104 -0
  34. package/main/cloud/org.mjs +53 -0
  35. package/main/cloud/reuse.mjs +208 -0
  36. package/main/cloud/run-cli.mjs +177 -0
  37. package/main/cloud/run.mjs +1934 -0
  38. package/main/cloud/usage.mjs +76 -0
  39. package/main/cloud-permission.mjs +51 -0
  40. package/main/codex-account.mjs +78 -0
  41. package/main/codex-app-server.mjs +276 -409
  42. package/main/codex-approvals.mjs +148 -433
  43. package/main/codex-models.mjs +20 -2
  44. package/main/codex-session.mjs +212 -507
  45. package/main/codex-threads-worker.mjs +12 -0
  46. package/main/codex-threads.mjs +71 -3
  47. package/main/codex-usage-file.mjs +5 -3
  48. package/main/codex-usage.mjs +56 -7
  49. package/main/codex-watch.mjs +17 -3
  50. package/main/codex.mjs +95 -363
  51. package/main/config.mjs +11 -1
  52. package/main/corner-tag.mjs +340 -19
  53. package/main/dev-window.mjs +1 -1
  54. package/main/engine-bin.mjs +232 -282
  55. package/main/engine-setup.mjs +21 -9
  56. package/main/feedback.mjs +3 -25
  57. package/main/folder-pictures.mjs +2 -2
  58. package/main/freeze-recorder-thread.mjs +86 -0
  59. package/main/freeze-recorder.mjs +146 -0
  60. package/main/fresh-user.mjs +20 -9
  61. package/main/git-change-offthread.mjs +17 -3
  62. package/main/git-change-thread.mjs +5 -2
  63. package/main/harnesses/claude.mjs +32 -11
  64. package/main/harnesses/codex.mjs +9 -2
  65. package/main/importable-threads.mjs +64 -6
  66. package/main/ipc.mjs +362 -111
  67. package/main/leftovers.mjs +117 -25
  68. package/main/liquid-glass.mjs +26 -0
  69. package/main/live-replies.mjs +10 -4
  70. package/main/main-went-red.mjs +330 -0
  71. package/main/main.mjs +199 -84
  72. package/main/memory-gate-history.mjs +36 -10
  73. package/main/memory-gate-server.mjs +62 -0
  74. package/main/memory-gate.mjs +14 -1
  75. package/main/menu.mjs +4 -2
  76. package/main/message-priority.mjs +2 -2
  77. package/main/mic.mjs +38 -0
  78. package/main/native/liquid-glass/build/liquid-glass.node +0 -0
  79. package/main/new-chats-watch.mjs +110 -0
  80. package/main/new-user-window.mjs +25 -0
  81. package/main/notify.mjs +24 -8
  82. package/main/phone-alerts.mjs +117 -0
  83. package/main/phone-inbox.mjs +625 -0
  84. package/main/phone-link.mjs +29 -9
  85. package/main/phone-uploads.mjs +476 -0
  86. package/main/picture-shape.mjs +114 -0
  87. package/main/quit-sequence.mjs +143 -0
  88. package/main/refresh-agent-models.mjs +15 -2
  89. package/main/relay-client.mjs +69 -1
  90. package/main/repeats.mjs +10 -4
  91. package/main/row-label.mjs +12 -41
  92. package/main/run-change.mjs +13 -0
  93. package/main/run-ledger.mjs +135 -0
  94. package/main/save-attachments.mjs +41 -0
  95. package/main/serve.mjs +45 -3
  96. package/main/settings.mjs +220 -44
  97. package/main/shell-path.mjs +185 -37
  98. package/main/ship-conflict-brief.mjs +119 -0
  99. package/main/ship-queue.mjs +115 -19
  100. package/main/source-updater.mjs +18 -10
  101. package/main/stage-attachment.mjs +68 -0
  102. package/main/stall-watch.mjs +50 -0
  103. package/main/store/home.mjs +87 -232
  104. package/main/store/paths.mjs +11 -0
  105. package/main/store/teammates-files.mjs +99 -0
  106. package/main/store/work-items.mjs +231 -13
  107. package/main/store.mjs +226 -52
  108. package/main/supervisor.mjs +3103 -341
  109. package/main/task-folders.mjs +430 -30
  110. package/main/task-terminals.mjs +110 -34
  111. package/main/team/index.mjs +114 -10
  112. package/main/team/memory-cloud.mjs +183 -1
  113. package/main/team/room-hours.mjs +48 -0
  114. package/main/team/room-setup.mjs +31 -0
  115. package/main/team/rooms-memory.mjs +454 -0
  116. package/main/team/rooms-shape.mjs +42 -0
  117. package/main/team/rooms-supabase.mjs +324 -0
  118. package/main/team/rooms.mjs +575 -0
  119. package/main/team/session.mjs +96 -26
  120. package/main/team/supabase-backend.mjs +180 -0
  121. package/main/team/sync.mjs +109 -1
  122. package/main/teammates.mjs +580 -0
  123. package/main/terminal-host.mjs +143 -0
  124. package/main/terminal-hosts.mjs +261 -0
  125. package/main/transcript-search.mjs +80 -0
  126. package/main/webview-guard.mjs +45 -0
  127. package/main/worktree-include.mjs +90 -219
  128. package/mcp/core/documents.mjs +3 -1
  129. package/mcp/core/repeats.mjs +88 -0
  130. package/mcp/core/teammates.mjs +222 -0
  131. package/mcp/core/work.mjs +76 -4
  132. package/mcp/stdio.mjs +24 -11
  133. package/mcp/tools.mjs +116 -8
  134. package/package.json +21 -5
  135. package/renderer/dist/assets/{abnfDiagram-YUKMZFIV-DPPuMWt-.js → abnfDiagram-YUKMZFIV-CoWB6YUK.js} +1 -1
  136. package/renderer/dist/assets/{arc-HmFfdseH.js → arc-Ch0NrCul.js} +1 -1
  137. package/renderer/dist/assets/{architectureDiagram-47P4ROYG-DxJ3zHrH.js → architectureDiagram-47P4ROYG-CXz9M5tQ.js} +1 -1
  138. package/renderer/dist/assets/{blockDiagram-E7TT5TSB-CbTXzOqQ.js → blockDiagram-E7TT5TSB-DchGUuHH.js} +1 -1
  139. package/renderer/dist/assets/{c4Diagram-CRA5TL53-X5ItFyLn.js → c4Diagram-CRA5TL53-Cip-zNyr.js} +1 -1
  140. package/renderer/dist/assets/channel-BQuQSL--.js +1 -0
  141. package/renderer/dist/assets/{chunk-2Q5K7J3B-DC12Ho_L.js → chunk-2Q5K7J3B-BoXid_2r.js} +1 -1
  142. package/renderer/dist/assets/{chunk-5VM5RSS4-ClVtfPd0.js → chunk-5VM5RSS4-Cpez1rRz.js} +1 -1
  143. package/renderer/dist/assets/{chunk-7TKQ45FW-DgcOm0HT.js → chunk-7TKQ45FW-DKA84YkE.js} +1 -1
  144. package/renderer/dist/assets/{chunk-AW2ZBBNX-C01s4yoF.js → chunk-AW2ZBBNX-Dg-SumPG.js} +1 -1
  145. package/renderer/dist/assets/{chunk-FVRAUYC3-Bj0zxhR4.js → chunk-FVRAUYC3-06TCvPm1.js} +2 -2
  146. package/renderer/dist/assets/{chunk-HTAEGDNF-DWDeEhLU.js → chunk-HTAEGDNF-CMEBy1Td.js} +1 -1
  147. package/renderer/dist/assets/{chunk-JWPE2WC7-Dsqwv3eW.js → chunk-JWPE2WC7-BJ2ObmV-.js} +1 -1
  148. package/renderer/dist/assets/{chunk-KQW6MTUR-CE86ANL2.js → chunk-KQW6MTUR-CGWOYXUE.js} +1 -1
  149. package/renderer/dist/assets/{chunk-XXDRQBXY-CoNTASfs.js → chunk-XXDRQBXY-CiZp07XC.js} +1 -1
  150. package/renderer/dist/assets/{classDiagram-v2-K4WV4PDN-2wprLqtw.js → classDiagram-v2-K4WV4PDN-DJNIX719.js} +1 -1
  151. package/renderer/dist/assets/cornerTag-CPgvu-q3.js +1 -0
  152. package/renderer/dist/assets/cornerTag-oMfEjzCO.css +1 -0
  153. package/renderer/dist/assets/{cose-bilkent-JH36ORCC-enqMiYbn.js → cose-bilkent-JH36ORCC-CbkyZOUH.js} +1 -1
  154. package/renderer/dist/assets/{cynefin-EF2NZ3EQ-DHngLxvQ.js → cynefin-EF2NZ3EQ-78iOroZO.js} +1 -1
  155. package/renderer/dist/assets/{cynefinDiagram-3GCD6N5R-C0rZZIl3.js → cynefinDiagram-3GCD6N5R-GcCopMs7.js} +1 -1
  156. package/renderer/dist/assets/{dagre-W4DXFKR2-DQnaEWO7.js → dagre-W4DXFKR2-DHLlXLkz.js} +1 -1
  157. package/renderer/dist/assets/{diagram-2UJZ2QOL-CS8AlGPx.js → diagram-2UJZ2QOL-DuZSUHcH.js} +1 -1
  158. package/renderer/dist/assets/{diagram-OVF4WLC6-yiDMHIkY.js → diagram-OVF4WLC6-Ckxu3cqH.js} +1 -1
  159. package/renderer/dist/assets/{diagram-PFPMY2P6-XbQKzbBA.js → diagram-PFPMY2P6-CsTw9Ycn.js} +1 -1
  160. package/renderer/dist/assets/{diagram-UMYRVEAY-dhVvlfl_.js → diagram-UMYRVEAY-CTXd8qVg.js} +1 -1
  161. package/renderer/dist/assets/{diagram-YEKJPTXX-DZHe8SCf.js → diagram-YEKJPTXX-CJs1T_9m.js} +1 -1
  162. package/renderer/dist/assets/{diagram-ZIFT7M5P-B5h6aXVR.js → diagram-ZIFT7M5P-CvjI23mf.js} +1 -1
  163. package/renderer/dist/assets/{ebnfDiagram-VR2GEFS7-PR9ScDco.js → ebnfDiagram-VR2GEFS7-d_IeAzOJ.js} +1 -1
  164. package/renderer/dist/assets/{elk-IJKZMXRS-Cg-yQXPd.js → elk-IJKZMXRS-zo9KFP3N.js} +1 -1
  165. package/renderer/dist/assets/{erDiagram-O2IAPWRE-omOrJMxu.js → erDiagram-O2IAPWRE-DqfYf5Dt.js} +1 -1
  166. package/renderer/dist/assets/{flowDiagram-OXPTDLAJ-aOX2hzvT.js → flowDiagram-OXPTDLAJ-DAWsMLmo.js} +1 -1
  167. package/renderer/dist/assets/{ganttDiagram-R7TSEDQI-B1H3pWyI.js → ganttDiagram-R7TSEDQI-4ml_bhwR.js} +1 -1
  168. package/renderer/dist/assets/{gitGraphDiagram-XJZIOB7I-Cvw304HC.js → gitGraphDiagram-XJZIOB7I-B_WcqSId.js} +1 -1
  169. package/renderer/dist/assets/{infoDiagram-5W2HQ5XZ-_ZXcNViH.js → infoDiagram-5W2HQ5XZ-CI-jYqzc.js} +1 -1
  170. package/renderer/dist/assets/{ishikawaDiagram-K3B6WC7H-C7Mx_qQk.js → ishikawaDiagram-K3B6WC7H-B56VWRlV.js} +1 -1
  171. package/renderer/dist/assets/{journeyDiagram-COXZFDF6-fr62QoAt.js → journeyDiagram-COXZFDF6-D1-p09Lr.js} +1 -1
  172. package/renderer/dist/assets/{kanban-definition-P3RFRI5V-J8zsabCe.js → kanban-definition-P3RFRI5V-Cv3w7JoN.js} +1 -1
  173. package/renderer/dist/assets/{linear-BmNdEtIi.js → linear-C35V2Spi.js} +1 -1
  174. package/renderer/dist/assets/main-BcoBiGwv.css +32 -0
  175. package/renderer/dist/assets/main-CLnIOulD.js +1191 -0
  176. package/renderer/dist/assets/{mermaid.core-CnYzvFkz.js → mermaid.core-BzGT5Vo9.js} +4 -4
  177. package/renderer/dist/assets/{mindmap-definition-LZFPQGKD-Bfcxc7PM.js → mindmap-definition-LZFPQGKD-BZUfuymC.js} +1 -1
  178. package/renderer/dist/assets/{pegDiagram-BGZESJAR-CwUJOq6X.js → pegDiagram-BGZESJAR-DFh9XNGe.js} +1 -1
  179. package/renderer/dist/assets/{pieDiagram-CAPJLFHJ-BrwMmqfC.js → pieDiagram-CAPJLFHJ-C65tPVsy.js} +1 -1
  180. package/renderer/dist/assets/{product-name-CTKLYNWY.js → product-name-CSNW6d7s.js} +1 -1
  181. package/renderer/dist/assets/{quadrantDiagram-GDMTTRAM-BN4Stoj-.js → quadrantDiagram-GDMTTRAM-Cushj_nk.js} +1 -1
  182. package/renderer/dist/assets/{railroadDiagram-SM67HX2B-CPZ5bbeR.js → railroadDiagram-SM67HX2B-DZGebGx5.js} +1 -1
  183. package/renderer/dist/assets/{requirementDiagram-X7JNWC4A-CgRnimVe.js → requirementDiagram-X7JNWC4A-DpAB0MNo.js} +1 -1
  184. package/renderer/dist/assets/{sankeyDiagram-UM26HJRW-Bt2rej__.js → sankeyDiagram-UM26HJRW-D-29rHra.js} +1 -1
  185. package/renderer/dist/assets/{sequenceDiagram-ZO4K6R2Y-Dd5nKe9G.js → sequenceDiagram-ZO4K6R2Y-FfOQAZol.js} +1 -1
  186. package/renderer/dist/assets/{sizeCapture-INFHLROL-usyNyXyh.js → sizeCapture-INFHLROL-C_n6fDBY.js} +1 -1
  187. package/renderer/dist/assets/{stateDiagram-v2-TBUQTH76-CRzUBb0u.js → stateDiagram-v2-TBUQTH76-BZjenzJG.js} +1 -1
  188. package/renderer/dist/assets/{swimlanes-N4OXWK64-C1GJvMS0.js → swimlanes-N4OXWK64-DxaMU9vX.js} +1 -1
  189. package/renderer/dist/assets/swimlanesDiagram-K3J5GTZL-Cb2kM6rr.js +8 -0
  190. package/renderer/dist/assets/{timeline-definition-YOQAKGHF-caeyPlcc.js → timeline-definition-YOQAKGHF-DTg5HJKz.js} +1 -1
  191. package/renderer/dist/assets/{usecaseDiagram-VIAY4XPW-BN_SV6PC.js → usecaseDiagram-VIAY4XPW-Bc3MZDsl.js} +1 -1
  192. package/renderer/dist/assets/{vennDiagram-BLWOH2XV-BLGuaUX-.js → vennDiagram-BLWOH2XV-GIVGk9Id.js} +1 -1
  193. package/renderer/dist/assets/{wardleyDiagram-YMQ3BMBF-Da0cJeNc.js → wardleyDiagram-YMQ3BMBF-NmJnbQOg.js} +1 -1
  194. package/renderer/dist/assets/{xychartDiagram-TAQBALBS-cGfUffMk.js → xychartDiagram-TAQBALBS-p-kfGfnW.js} +1 -1
  195. package/renderer/dist/corner-tag.html +3 -3
  196. package/renderer/dist/index.html +3 -3
  197. package/scripts/after-install.mjs +30 -8
  198. package/scripts/cloud-shim.pl +57 -0
  199. package/shared/account-names.d.mts +6 -0
  200. package/shared/account-names.mjs +15 -0
  201. package/shared/agent-hours.mjs +136 -0
  202. package/shared/agent-import.mjs +60 -34
  203. package/shared/agents.mjs +126 -522
  204. package/shared/analytics-events.mjs +12 -0
  205. package/shared/approval-card.mjs +36 -0
  206. package/shared/bridge-map.mjs +27 -1
  207. package/shared/claude-code-shape.mjs +6 -0
  208. package/shared/claude-usage.d.mts +1 -0
  209. package/shared/claude-usage.mjs +42 -1
  210. package/shared/cloud-hand-back.d.mts +7 -0
  211. package/shared/cloud-hand-back.mjs +20 -0
  212. package/shared/cloud-kit.d.mts +219 -0
  213. package/shared/cloud-kit.mjs +341 -0
  214. package/shared/cloud-login-name.mjs +4 -0
  215. package/shared/cloud-start.mjs +17 -0
  216. package/shared/cloud-versions.mjs +23 -0
  217. package/shared/codex-import.mjs +2 -2
  218. package/shared/codex-modes.d.mts +22 -9
  219. package/shared/codex-modes.mjs +67 -11
  220. package/shared/codex-usage.mjs +108 -2
  221. package/shared/corner-tag.d.mts +23 -1
  222. package/shared/corner-tag.mjs +284 -29
  223. package/shared/dead-run-trace.mjs +19 -2
  224. package/shared/engines.mjs +70 -309
  225. package/shared/feedback.d.mts +7 -0
  226. package/shared/feedback.mjs +25 -0
  227. package/shared/first-run-practice.mjs +17 -24
  228. package/shared/harness-definitions.mjs +8 -0
  229. package/shared/instruction-defaults.json +2 -2
  230. package/shared/key-caps.d.mts +14 -0
  231. package/shared/key-caps.mjs +68 -0
  232. package/shared/message-edits.d.mts +7 -0
  233. package/shared/message-edits.mjs +35 -0
  234. package/shared/move-thread.d.mts +24 -0
  235. package/shared/move-thread.mjs +112 -0
  236. package/shared/named-threads.mjs +72 -0
  237. package/shared/not-shipped.d.mts +22 -0
  238. package/shared/not-shipped.mjs +89 -0
  239. package/shared/notify-rules.d.mts +6 -0
  240. package/shared/notify-rules.mjs +36 -8
  241. package/shared/phone-files.mjs +28 -0
  242. package/shared/phone-settings.mjs +118 -0
  243. package/shared/phone-snapshot.d.mts +16 -0
  244. package/shared/phone-snapshot.mjs +348 -0
  245. package/shared/picture-formats.d.mts +1 -0
  246. package/shared/picture-formats.mjs +13 -0
  247. package/shared/rank.d.mts +2 -1
  248. package/shared/rank.mjs +32 -19
  249. package/shared/repeats.d.mts +8 -0
  250. package/shared/repeats.mjs +33 -2
  251. package/shared/room-cards.mjs +167 -0
  252. package/shared/room-links.d.mts +4 -0
  253. package/shared/room-links.mjs +21 -0
  254. package/shared/runs-on.d.mts +3 -3
  255. package/shared/runs-on.mjs +8 -5
  256. package/shared/shipped-note.d.mts +4 -0
  257. package/shared/shipped-note.mjs +6 -0
  258. package/shared/shortcuts.mjs +14 -6
  259. package/shared/spawn-trouble.d.mts +4 -0
  260. package/shared/spawn-trouble.mjs +443 -40
  261. package/shared/team-rules.mjs +9 -2
  262. package/shared/teammates.d.mts +19 -0
  263. package/shared/teammates.mjs +756 -0
  264. package/shared/terminal-focus.d.mts +1 -0
  265. package/shared/terminal-focus.mjs +13 -0
  266. package/shared/thread-cards.mjs +4 -1
  267. package/shared/usage.d.mts +9 -0
  268. package/shared/usage.mjs +49 -3
  269. package/shared/websites.d.mts +15 -0
  270. package/shared/websites.mjs +61 -0
  271. package/shared/work-items.mjs +127 -30
  272. package/shared/work-lines.mjs +92 -244
  273. package/renderer/dist/assets/channel-BlT2g9Sz.js +0 -1
  274. package/renderer/dist/assets/cornerTag-BLrxiDE5.css +0 -1
  275. package/renderer/dist/assets/cornerTag-BOT6u3Tn.js +0 -1
  276. package/renderer/dist/assets/main-ChNdnUvt.js +0 -1132
  277. package/renderer/dist/assets/main-nj0QR5kg.css +0 -32
  278. package/renderer/dist/assets/swimlanesDiagram-K3J5GTZL-Cy4Av2_p.js +0 -8
@@ -34,6 +34,18 @@ export const EVENTS = {
34
34
  task_written: 'A task was written',
35
35
  run_started: 'An agent started work',
36
36
  run_finished: 'An agent stopped work',
37
+ // WHAT HAPPENS IN THE MINUTES AFTER SETUP (2026-10-16). Most installs on
38
+ // 0.1.13 went quiet within minutes of finishing setup, and nothing said
39
+ // whether they quit, put the corner tag away, or what the import brought in
40
+ // (tests/what-people-do-after-setup-is-counted.test.mjs).
41
+ app_quit: `${Name} was quit`,
42
+ tag_hidden: 'The corner tag was hidden',
43
+ tag_turned_off: 'The corner tag was turned off',
44
+ import_offered: 'Setup offered agents to import',
45
+ import_taken: 'Setup imported agents',
46
+ // Sent as the switch goes off and never again, so an install that opted out
47
+ // is not read as one that stopped using the app.
48
+ counts_turned_off: 'Counts were turned off',
37
49
  };
38
50
 
39
51
  export const EVENT_NAMES = Object.keys(EVENTS);
@@ -0,0 +1,36 @@
1
+ // A PERMISSION CARD'S FINGERPRINT, the one string the computer and the cloud
2
+ // server (cloud/gateway/phone.mjs) each take of a card on their own, and the
3
+ // phone sends back with her answer. main/approvals.mjs has why it is a digest
4
+ // of what was shown rather than of the request file.
5
+ //
6
+ // If the two sides canonicalise differently, every approval is denied with no
7
+ // reason shown. So the digest is taken after one JSON round trip, which does
8
+ // what the write to disk did, and then keys are sorted.
9
+ import crypto from 'node:crypto';
10
+
11
+ function canonical(value) {
12
+ if (Array.isArray(value)) return `[${value.map((v) => canonical(v) ?? 'null').join(',')}]`;
13
+ if (value && typeof value === 'object') {
14
+ const fields = [];
15
+ for (const key of Object.keys(value).sort()) {
16
+ const v = canonical(value[key]);
17
+ if (v !== undefined) fields.push(`${JSON.stringify(key)}:${v}`);
18
+ }
19
+ return `{${fields.join(',')}}`;
20
+ }
21
+ return JSON.stringify(value);
22
+ }
23
+
24
+ /**
25
+ * The card as one string either side can compute on its own. Null for a
26
+ * non-object or anything JSON cannot express; null never equals a digest, so
27
+ * callers deny. No Unicode normalisation: two byte strings that look the same
28
+ * are still two different commands to her shell.
29
+ */
30
+ export function cardDigest(request) {
31
+ if (!request || typeof request !== 'object' || Array.isArray(request)) return null;
32
+ let text;
33
+ try { text = canonical(JSON.parse(JSON.stringify(request))); } catch { return null; }
34
+ if (typeof text !== 'string') return null;
35
+ return crypto.createHash('sha256').update(text, 'utf8').digest('base64');
36
+ }
@@ -16,6 +16,7 @@ export const REQUEST_CHANNELS = {
16
16
  agentUpdate: 'zero:agent-update',
17
17
  snapshot: 'zero:snapshot',
18
18
  refreshUsage: 'zero:refresh-usage',
19
+ accountUsage: 'zero:account-usage',
19
20
  // Whether a screen reader is running, which is the terminal pane's question
20
21
  // before it builds xterm's accessibility tree.
21
22
  assistiveTech: 'zero:assistiveTech',
@@ -53,8 +54,18 @@ export const REQUEST_CHANNELS = {
53
54
  teamSync: 'zero:team-sync',
54
55
  teamRoute: 'zero:team-route',
55
56
  teamReact: 'zero:team-react',
57
+ // New words for a message you sent to a teammate, or the message taken back.
58
+ teamEdit: 'zero:team-edit',
59
+ // The microphone, asked for when a voice note starts recording.
60
+ micAccess: 'zero:mic-access',
56
61
  teamMessage: 'zero:team-message',
62
+ rooms: 'zero:rooms',
63
+ // Teammates: make, describe, start, edit, write to, and what they remember.
64
+ teammates: 'zero:teammates',
65
+ takeJoin: 'zero:take-join',
57
66
  threadEdit: 'zero:thread-edit',
67
+ // Move a thread to another project (shared/move-thread.mjs).
68
+ moveItem: 'zero:move-item',
58
69
  repeats: 'zero:repeats',
59
70
  composeRepeat: 'zero:compose-repeat',
60
71
  setRepeat: 'zero:set-repeat',
@@ -75,6 +86,7 @@ export const REQUEST_CHANNELS = {
75
86
  agentFolders: 'zero:agent-folders',
76
87
  importAgents: 'zero:import-agents',
77
88
  agentThreads: 'zero:agent-threads',
89
+ searchAgentThreads: 'zero:search-agent-threads',
78
90
  importThreads: 'zero:import-threads',
79
91
  badge: 'zero:badge',
80
92
  cornerTag: 'zero:corner-tag',
@@ -106,6 +118,18 @@ export const REQUEST_CHANNELS = {
106
118
  claudeAddAccount: 'zero:claude-add-account',
107
119
  setProjectSetting: 'zero:settings-set-project',
108
120
  setWorkspaceSetting: 'zero:settings-set-workspace',
121
+ // The cloud setup's sign-in for one account, made in the cloud (main/cloud/logins.mjs).
122
+ cloudSignIn: 'zero:cloud-signin',
123
+ // Claude's sign-in code, read from the clipboard while one is waiting for it.
124
+ cloudClipboardCode: 'zero:cloud-clipboard-code',
125
+ // Signing in to Agentbox Cloud itself, on the app's sign-in page (main/cloud/account.mjs).
126
+ cloudAccountSignIn: 'zero:cloud-account-sign-in',
127
+ cloudAccountCancel: 'zero:cloud-account-cancel',
128
+ cloudAccountReopen: 'zero:cloud-account-reopen',
129
+ cloudAccountSignOut: 'zero:cloud-account-sign-out',
130
+ cloudAccountPlan: 'zero:cloud-account-plan',
131
+ cloudAccountPay: 'zero:cloud-account-pay',
132
+ cloudAccountBilling: 'zero:cloud-account-billing',
109
133
  projectRename: 'zero:project-rename',
110
134
  projectArchive: 'zero:project-archive',
111
135
  projectSeenBy: 'zero:project-seen-by',
@@ -140,6 +164,7 @@ export const REQUEST_CHANNELS = {
140
164
  setProductOrder: 'zero:set-product-order',
141
165
  setThreadPlaces: 'zero:set-thread-places',
142
166
  setThreadPins: 'zero:set-thread-pins',
167
+ setThreadOnMac: 'zero:set-thread-on-mac',
143
168
  setProductHidden: 'zero:set-product-hidden',
144
169
  approve: 'zero:approve',
145
170
  // The phone door's Settings page (main/phone-link.mjs): its state, on, off,
@@ -154,6 +179,7 @@ export const PUSH_CHANNELS = {
154
179
  onFind: 'zero:find',
155
180
  onZoomPercent: 'zero:zoom-percent',
156
181
  onRecovered: 'zero:recovered',
182
+ onJoinRoom: 'zero:join-room',
157
183
  onOpenItem: 'zero:open-item',
158
184
  onOpenSettings: 'zero:open-settings',
159
185
  onScreenDetail: 'zero:screen-detail',
@@ -167,7 +193,7 @@ export const PUSH_CHANNELS = {
167
193
  // and the handler on the far side reads an object, so the key each value goes
168
194
  // under is part of the contract and belongs here beside the channel.
169
195
  export const WRAPPED_ARGS = {
170
- notify: ['arrivals'],
196
+ notify: ['arrivals', 'needsYou'],
171
197
  track: ['name'],
172
198
  instructionWrite: ['id', 'text'],
173
199
  instructionVersion: ['id', 'at'],
@@ -0,0 +1,6 @@
1
+ // WHAT CLAUDE'S SIGN-IN CODE LOOKS LIKE: the authorization code, a `#`, and
2
+ // the state, as Claude's sign-in page shows it to copy. Used to fill the code
3
+ // in from the clipboard (main/ipc.mjs) without taking anything else she copied.
4
+ export function looksLikeClaudeCode(text) {
5
+ return /^[A-Za-z0-9._~+/=-]{10,}#[A-Za-z0-9._~+/=-]{6,}$/.test(String(text || '').trim());
6
+ }
@@ -10,6 +10,7 @@ import type { UsageLimit } from './usage.d.mts';
10
10
 
11
11
  export declare function resetAt(text: string, now?: number, zoneNow?: string | null): number | null;
12
12
  export declare function readUsage(text: string | null | undefined, now?: number, zoneNow?: string | null): UsageLimit[];
13
+ export declare function readUsageReport(value: unknown, now?: number): UsageLimit[];
13
14
  export declare function pillText(
14
15
  limits: UsageLimit[] | null | undefined,
15
16
  now?: number,
@@ -22,7 +22,7 @@
22
22
  // timezone stamp it prints, and the refusal to count down from a stamp computed
23
23
  // somewhere else. What belongs to a LIMIT, any limit, is next door.
24
24
 
25
- import { instantIn, localZone, sessionLimit, untilReset, wallIn } from './usage.mjs';
25
+ import { instantIn, localZone, resetDay, sessionLimit, toMinute, untilReset, wallIn } from './usage.mjs';
26
26
 
27
27
  /** One limit, as the CLI reported it. */
28
28
  // { span, qualifier, name, percent, resetsAt|null, resetsText, resetsOn, zone }
@@ -153,6 +153,47 @@ export function readUsage(text, now = Date.now(), zoneNow = localZone()) {
153
153
  return out;
154
154
  }
155
155
 
156
+ /** Provider limits from Claude Code's get_usage response, without local activity estimates. */
157
+ export function readUsageReport(value, now = Date.now()) {
158
+ let report = value;
159
+ if (typeof report === 'string') {
160
+ try { report = JSON.parse(report); } catch { return []; }
161
+ }
162
+ if (report?.rate_limits_available !== true || !report.rate_limits) return [];
163
+ const data = report.rate_limits;
164
+ const windows = [
165
+ ['session', null, data.five_hour],
166
+ ['week', 'all models', data.seven_day],
167
+ ['week', 'OAuth apps', data.seven_day_oauth_apps],
168
+ ['week', 'Opus', data.seven_day_opus],
169
+ ['week', 'Sonnet', data.seven_day_sonnet],
170
+ ...(Array.isArray(data.model_scoped) ? data.model_scoped : [])
171
+ .filter(row => typeof row?.display_name === 'string' && row.display_name.trim())
172
+ .map(row => ['week', row.display_name, row]),
173
+ ];
174
+ return windows.flatMap(([span, qualifier, row]) => {
175
+ const percent = row?.utilization;
176
+ // Over 100 is a limit past its allowance, which is full, not unreadable.
177
+ if (typeof percent !== 'number' || !Number.isFinite(percent) || percent < 0) return [];
178
+ const at = typeof row.resets_at === 'string' ? Date.parse(row.resets_at) : NaN;
179
+ // Whole percents, as the text report printed them; only a full limit reads 100, only an unused one 0.
180
+ const whole = percent === 0 || percent >= 100 ? Math.min(100, percent) : Math.min(99, Math.max(1, Math.round(percent)));
181
+ const known = Number.isFinite(at);
182
+ return [{ span, qualifier, name: limitName(span, qualifier), percent: whole, resetsAt: known ? at : null,
183
+ ...(known ? clockWords(at, now) : { resetsText: null, resetsOn: null }), zone: known ? localZone() : null }];
184
+ });
185
+ }
186
+
187
+ // The words the text report used to carry, in this machine's zone, so the
188
+ // panel keeps saying "Resets 6:19pm" and not a countdown (limitRows, shared/usage.mjs).
189
+ function clockWords(at, now) {
190
+ const d = new Date(toMinute(at));
191
+ const h = d.getHours();
192
+ const m = d.getMinutes();
193
+ const resetsText = `${h % 12 || 12}${m ? `:${String(m).padStart(2, '0')}` : ''}${h < 12 ? 'am' : 'pm'}`;
194
+ return { resetsText, resetsOn: resetDay(at, now) };
195
+ }
196
+
156
197
  /**
157
198
  * WHAT THE PILL SAYS. Null when there is nothing honest to print, and then
158
199
  * nothing is drawn at all rather than a pill saying it does not know.
@@ -0,0 +1,7 @@
1
+ // Types for shared/cloud-hand-back.mjs, read by the supervisor and the thread.
2
+
3
+ /** The line a cloud run ends on when its request needs this computer. */
4
+ export const HAND_BACK: string;
5
+
6
+ /** Whether a reply hands its thread back: the marked line, at a line's start. */
7
+ export function handsBack(result: string | null | undefined): boolean;
@@ -0,0 +1,20 @@
1
+ // THE LINE A CLOUD RUN ENDS ON WHEN ITS REQUEST NEEDS THIS COMPUTER. The cloud
2
+ // run is told to write it (main/cloud/run.mjs CLOUD_NOTE); the supervisor reads
3
+ // it and moves the thread here (Supervisor#_noteCloudHandBack). No leading
4
+ // bracket: a trace line that starts with one is read as a tool call.
5
+ export const HAND_BACK = 'AGENTBOX-NEEDS-THE-COMPUTER:';
6
+
7
+ /** Whether a reply hands its thread back: the marked line, at a line's start. */
8
+ export function handsBack(result) {
9
+ return String(result ?? '').split('\n').some((line) => line.trimStart().startsWith(HAND_BACK));
10
+ }
11
+
12
+ /** What the run said it was missing, cut to fit a card; null when it said nothing. */
13
+ export function handBackWhat(result, max = 90) {
14
+ const line = String(result ?? '').split('\n').map((l) => l.trimStart()).find((l) => l.startsWith(HAND_BACK));
15
+ const what = line?.slice(HAND_BACK.length).trim().replace(/[.\s]+$/, '') ?? '';
16
+ if (!what) return null;
17
+ if (what.length <= max) return what;
18
+ const cut = what.lastIndexOf(' ', max);
19
+ return `${what.slice(0, cut > 0 ? cut : max)}…`;
20
+ }
@@ -0,0 +1,219 @@
1
+ // Types for shared/cloud-kit.mjs, the kit a cloud run is started from.
2
+ //
3
+ // The screen asks it one thing, `runOfClaim` (renderer/src/phone-rows.ts), and
4
+ // a declaration that stopped there would come through as `any` the day the
5
+ // screen asks it a second. So every export is here, and the kit's own fields
6
+ // are the ones `checkKit` reads: that function is the agreement between the
7
+ // computer, the server and the phone, and this says the same thing in types.
8
+
9
+ /** Where a reply goes in a turn's prompt. */
10
+ export interface ReplyFrame {
11
+ before: string;
12
+ after: string;
13
+ }
14
+
15
+ /** What an agent said, as this file reads it off a run's event log. */
16
+ export interface Answer {
17
+ text: string;
18
+ isError: boolean;
19
+ }
20
+
21
+ /** The lines that open a Codex kit's thread, and the settings its turns carry. */
22
+ export interface CodexKit {
23
+ open: string[];
24
+ /** A new thread starts one (`thread/start`); a kept thread resumes one. */
25
+ startId?: number;
26
+ resumeId?: number;
27
+ firstTurnId: number;
28
+ turn: { threadId?: string } & Record<string, unknown>;
29
+ }
30
+
31
+ /** A thread's next turn, left in storage for the cloud to start. */
32
+ export interface Kit {
33
+ v: number;
34
+ engine: 'claude' | 'codex';
35
+ madeAt: number;
36
+ cwd: string;
37
+ argv: string[];
38
+ frame: ReplyFrame;
39
+ login: { engine: 'claude' | 'codex'; key: string; id?: string | null };
40
+ /** Which thread, on which computer, in which project. */
41
+ item?: string;
42
+ device?: string;
43
+ project?: string;
44
+ /** What a computer joining this run needs to write its own marker. */
45
+ marker?: { configDir?: string } & Record<string, unknown>;
46
+ /** The cloud's note at the top of the agent's first line. */
47
+ note?: string | null;
48
+ /** Carried into the run's `offline.kept`. */
49
+ kept?: unknown;
50
+ env?: Record<string, string>;
51
+ /** A folder with no repository behind it, so no bundle and no branch. */
52
+ plain?: boolean;
53
+ branch?: string | null;
54
+ bundleKey?: string | null;
55
+ base?: { key: string; sha: string } | null;
56
+ refs?: Record<string, string> | null;
57
+ changesRef?: string;
58
+ remote?: string | null;
59
+ docs?: unknown;
60
+ files?: { path: string; key: string; untar?: string }[];
61
+ homeFiles?: { rel: string; key: string }[];
62
+ bringDirs?: { name: string; dir: string }[];
63
+ /** Servers whose calls wait for an answer rather than being refused. */
64
+ hold?: string[];
65
+ handshakes?: Record<string, unknown>;
66
+ codex?: CodexKit;
67
+ /** On a project's new-thread kit: the first prompt, the main to branch at,
68
+ * and what that kit runs, which a phone's choices have to match. */
69
+ newThread?: {
70
+ brief: string;
71
+ mainSha: string;
72
+ model?: string | null;
73
+ effort?: string | null;
74
+ defaultEngine?: 'claude' | 'codex';
75
+ };
76
+ }
77
+
78
+ /** What a sandbox is handed to start a run from a kit. */
79
+ export interface StartPayload {
80
+ action: 'start';
81
+ runId: string;
82
+ cwd: string;
83
+ branch: string | null;
84
+ bundleUrl?: string;
85
+ plain?: true;
86
+ base?: { url: string; sha: string };
87
+ refs?: Record<string, string> | null;
88
+ argv: string[];
89
+ env: Record<string, string>;
90
+ files: { path: string; url: string; untar?: string }[];
91
+ changesRef?: string;
92
+ remote?: string | null;
93
+ docs?: unknown;
94
+ homeFiles?: { rel: string; url: string }[];
95
+ login: { engine: string; id: string | null; url: string };
96
+ results: {
97
+ bundleUrl: string;
98
+ changesUrl: string;
99
+ docsUrl: string;
100
+ eventsUrl: string;
101
+ doneUrl: string;
102
+ bring: { dir: string; url: string }[];
103
+ };
104
+ tails: true;
105
+ offline: {
106
+ afterMs: number;
107
+ endTurn: string;
108
+ kept: unknown;
109
+ hold?: string[];
110
+ handshakes?: Record<string, unknown>;
111
+ away?: true;
112
+ };
113
+ }
114
+
115
+ /** A turn carried across reads of a Codex run's lines. */
116
+ export interface CodexReadState {
117
+ resumeId?: number;
118
+ turnIds?: number[];
119
+ /** True once the resume was answered, or why it was refused. */
120
+ resumed?: true | string;
121
+ threadId?: string;
122
+ result?: string | null;
123
+ final?: boolean;
124
+ }
125
+
126
+ export const KIT_VERSION: number;
127
+ export const REPLY_MARK: string;
128
+ export const CLOUD_TAKES_AFTER_MS: number;
129
+ export const CLOUD_TAKES_UNTIL_MS: number;
130
+ export const KIT_FRESH_MS: number;
131
+
132
+ /** The command a cloud run claims a reply with. */
133
+ export function cloudClaim(runId: string): string;
134
+ /** The run id inside such a claim, or null when it is not one. */
135
+ export function runOfClaim(claimedBy: unknown): string | null;
136
+ /** The session name a run gets, whoever starts it. */
137
+ export function cloudSessionId(item: string | null | undefined, runId: string): string;
138
+
139
+ /** Where a thread's kit lives in the person's own storage. */
140
+ export function kitKey(device: string | null | undefined, project: string | null | undefined, item: string | null | undefined): string;
141
+ /** What the server keeps about a run it started, for the moment it ends. */
142
+ export function serverRunKey(runId: string | null | undefined): string;
143
+ /** Written by a computer that has joined a run the server started. */
144
+ export function serverJoinedKey(runId: string | null | undefined): string;
145
+ /** The objects a run writes as it ends. */
146
+ export function runKey(runId: string, name: string): string;
147
+
148
+ /** The text either side of the reply, or null when the prompt has no one place for it. */
149
+ export function replyFrame(prompt: string | null | undefined): ReplyFrame | null;
150
+ export function replyPrompt(frame: ReplyFrame, reply: string | null | undefined): string;
151
+ /** The first line on the agent's input, as the computer writes one. */
152
+ export function cloudUserLine(text: string, opts?: { note?: string | null; uuid?: string }): string;
153
+
154
+ /** Why a kit cannot be started from, or null. */
155
+ export function checkKit(kit: unknown, opts?: { now?: number }): string | null;
156
+
157
+ /** The sandbox's `start` for a run from this kit. */
158
+ export function startPayload(kit: Kit, opts: {
159
+ runId: string;
160
+ getUrl: (key: string) => string | Promise<string>;
161
+ putUrl: (key: string) => string | Promise<string>;
162
+ loginName: (key: string) => string;
163
+ offlineAfterMs?: number;
164
+ kept?: unknown;
165
+ endTurn?: string;
166
+ refs?: Record<string, string> | null;
167
+ away?: boolean;
168
+ }): Promise<StartPayload>;
169
+
170
+ export const APPROVALS_SERVER: string;
171
+ /** A held request's card id, marked as the cloud's. */
172
+ export function askId(runId: string | number, conn: string | number, id: string | number): string;
173
+ /** Whether a card's id is one the cloud put on the phone. */
174
+ export function cloudCard(approval: unknown): boolean;
175
+ export const DECLINED: string;
176
+ /** The answer to a held approval_prompt call, as the app's own server would write it. */
177
+ export function approvalAnswerLine(id: string | number, opts?: { allow: boolean; note?: string | null; input?: Record<string, unknown> }): string;
178
+
179
+ /** Each of Claude Code's `result` lines, in order, off a run's event log. */
180
+ export function answersIn(eventsText: string | null | undefined): Answer[];
181
+ /** The `result`s among stream-json lines. */
182
+ export function resultsInLines(lines: string[]): Answer[];
183
+ /** What the agent last said, or null when the run never got that far. */
184
+ export function lastAnswerIn(eventsText: string | null | undefined): Answer | null;
185
+
186
+ // These two take the parts of a kit they read rather than a whole one, because
187
+ // the server writes a turn from what it kept of a run and not from the kit
188
+ // (cloud/gateway/phone.mjs).
189
+ /** What opens a Codex kit's thread in the cloud, as one input. */
190
+ export function codexOpenLines(kit: { codex: Pick<CodexKit, 'open'> }): string;
191
+ /** A reply as one turn of the kit's thread, with request id `id`. */
192
+ export function codexTurnLines(
193
+ kit: { frame: ReplyFrame; codex: Pick<CodexKit, 'turn'> },
194
+ reply: string | null | undefined,
195
+ opts: { id: number; raw?: string | null; threadId?: string | null },
196
+ ): string;
197
+ /** Each answer among a Codex run's lines, with `state` carrying a turn across reads. */
198
+ export function codexReadLines(lines: string[], state?: CodexReadState): Answer[];
199
+ /** Each Codex turn's answer, in order, off a run's event log. */
200
+ export function codexAnswersIn(eventsText: string | null | undefined, state?: CodexReadState): Answer[];
201
+ /** A Codex run's last answer off its event log, or null. */
202
+ export function codexAnswerIn(eventsText: string | null | undefined): Answer | null;
203
+
204
+ export const NEW_THREAD: string;
205
+ export const NEW_ITEM_MARK: string;
206
+ export const NEW_TITLE_MARK: string;
207
+ export const NEW_BODY_MARK: string;
208
+ export const NEW_THREAD_CODEX: string;
209
+ export function newThreadKitKey(device: string | null | undefined, project: string | null | undefined, engine?: 'claude' | 'codex'): string;
210
+
211
+ /**
212
+ * A project's new-thread kit made the kit of thread `itemId`, or null for a kit
213
+ * that is not one. */
214
+ export function fillNewThreadKit(kit: Kit | null | undefined, who: { itemId: string; title?: string; body?: string }): {
215
+ kit: Kit;
216
+ prompt: string;
217
+ refs: Record<string, string>;
218
+ mainSha: string;
219
+ } | null;