agentbox-app 0.1.6

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 (302) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +176 -0
  3. package/bin/agentbox.mjs +103 -0
  4. package/briefs/adhd-mode.md +5 -0
  5. package/briefs/message-rules.md +95 -0
  6. package/briefs/worker.md +230 -0
  7. package/briefs/writing-rules.md +336 -0
  8. package/main/account-discovery.mjs +145 -0
  9. package/main/account-tooling.mjs +261 -0
  10. package/main/agent-activity.mjs +56 -0
  11. package/main/agent-files.mjs +422 -0
  12. package/main/agent-schedule.mjs +254 -0
  13. package/main/agent-sessions.mjs +435 -0
  14. package/main/agents.mjs +1095 -0
  15. package/main/analytics.mjs +206 -0
  16. package/main/answer-modes.mjs +206 -0
  17. package/main/approval-prompt-server.mjs +160 -0
  18. package/main/approvals.mjs +487 -0
  19. package/main/artifact-path.mjs +144 -0
  20. package/main/claude-bin.mjs +311 -0
  21. package/main/claude-input.mjs +117 -0
  22. package/main/claude-models.mjs +244 -0
  23. package/main/claude-plan.mjs +148 -0
  24. package/main/claude-usage.mjs +149 -0
  25. package/main/code-change.mjs +383 -0
  26. package/main/code-file.mjs +116 -0
  27. package/main/codex-account.mjs +146 -0
  28. package/main/codex-app-server.mjs +796 -0
  29. package/main/codex-approvals.mjs +712 -0
  30. package/main/codex-bin.mjs +261 -0
  31. package/main/codex-compaction.mjs +49 -0
  32. package/main/codex-models.mjs +194 -0
  33. package/main/codex-session.mjs +797 -0
  34. package/main/codex-threads.mjs +268 -0
  35. package/main/codex-usage-file.mjs +192 -0
  36. package/main/codex-usage.mjs +149 -0
  37. package/main/codex-watch.mjs +35 -0
  38. package/main/codex.mjs +757 -0
  39. package/main/config.mjs +345 -0
  40. package/main/copy-selection.mjs +55 -0
  41. package/main/crash-report.mjs +158 -0
  42. package/main/demo.mjs +254 -0
  43. package/main/dev-window.mjs +103 -0
  44. package/main/doc-file.mjs +99 -0
  45. package/main/doc-scheme.mjs +126 -0
  46. package/main/first-run.mjs +190 -0
  47. package/main/folders.mjs +91 -0
  48. package/main/fresh-user.mjs +120 -0
  49. package/main/git-change.mjs +323 -0
  50. package/main/img-scheme.mjs +90 -0
  51. package/main/instruction-settings.mjs +205 -0
  52. package/main/ipc.mjs +1558 -0
  53. package/main/live-replies.mjs +77 -0
  54. package/main/machine.mjs +113 -0
  55. package/main/main.mjs +972 -0
  56. package/main/menu.mjs +177 -0
  57. package/main/notify.mjs +155 -0
  58. package/main/open-source-file.mjs +8 -0
  59. package/main/project-identity.mjs +149 -0
  60. package/main/provider-commands.mjs +32 -0
  61. package/main/rail-note.mjs +74 -0
  62. package/main/repeats.mjs +261 -0
  63. package/main/row-label.mjs +185 -0
  64. package/main/screen-detail.mjs +44 -0
  65. package/main/serve.mjs +262 -0
  66. package/main/settings.mjs +912 -0
  67. package/main/staleness.mjs +76 -0
  68. package/main/store/chats.mjs +188 -0
  69. package/main/store/home.mjs +383 -0
  70. package/main/store/migrate.mjs +40 -0
  71. package/main/store/paths.mjs +82 -0
  72. package/main/store/pending-writes.mjs +122 -0
  73. package/main/store/project-lock.mjs +200 -0
  74. package/main/store/project.mjs +523 -0
  75. package/main/store/queues.mjs +31 -0
  76. package/main/store/work-items.mjs +299 -0
  77. package/main/store/write-queue.mjs +14 -0
  78. package/main/store-modules.mjs +23 -0
  79. package/main/store.mjs +1269 -0
  80. package/main/supervisor.mjs +6875 -0
  81. package/main/task-commands.mjs +161 -0
  82. package/main/task-folders-offthread.mjs +84 -0
  83. package/main/task-folders-thread.mjs +13 -0
  84. package/main/task-folders.mjs +409 -0
  85. package/main/task-remote-control.mjs +65 -0
  86. package/main/task-terminals.mjs +169 -0
  87. package/main/terminal-access.mjs +6 -0
  88. package/main/updater.mjs +240 -0
  89. package/main/zoom-keys.mjs +54 -0
  90. package/main/zoom-readout.mjs +20 -0
  91. package/mcp/agentbox-mcp.sh +34 -0
  92. package/mcp/core/account.mjs +77 -0
  93. package/mcp/core/chat.mjs +61 -0
  94. package/mcp/core/documents.mjs +238 -0
  95. package/mcp/core/page.mjs +152 -0
  96. package/mcp/core/products.mjs +110 -0
  97. package/mcp/core/skills.mjs +126 -0
  98. package/mcp/core/work.mjs +377 -0
  99. package/mcp/stdio.mjs +70 -0
  100. package/mcp/tools.mjs +257 -0
  101. package/package.json +186 -0
  102. package/renderer/dist/assets/Geist-Variable-Bj2R_7yk.woff2 +0 -0
  103. package/renderer/dist/assets/GeistMono-Variable-Dispecij.woff2 +0 -0
  104. package/renderer/dist/assets/addon-fit-YJmn1quW.js +12 -0
  105. package/renderer/dist/assets/addon-serialize-CsFQTvP_.js +13 -0
  106. package/renderer/dist/assets/cel-dusk-CS5I7kJS.webp +0 -0
  107. package/renderer/dist/assets/cel-dusk-DUslqS6B.webp +0 -0
  108. package/renderer/dist/assets/cel-dusk-Jt_xVGxp.webp +0 -0
  109. package/renderer/dist/assets/cel-dusk-sm-BBkV-tWT.webp +0 -0
  110. package/renderer/dist/assets/frost-haze-CxPSOBEg.webp +0 -0
  111. package/renderer/dist/assets/frost-haze-sm-C_w21qgd.webp +0 -0
  112. package/renderer/dist/assets/gouache-valley-ChSu14-t.webp +0 -0
  113. package/renderer/dist/assets/gouache-valley-d9qasI6k.webp +0 -0
  114. package/renderer/dist/assets/gouache-valley-sm-CdLjT5Ec.webp +0 -0
  115. package/renderer/dist/assets/ice-BC8luINc.webp +0 -0
  116. package/renderer/dist/assets/ice-CP9PrKHo.webp +0 -0
  117. package/renderer/dist/assets/ice-river-D6ziOhLY.webp +0 -0
  118. package/renderer/dist/assets/ice-river-UVM2-JY_.webp +0 -0
  119. package/renderer/dist/assets/ice-river-bErJwYWW.webp +0 -0
  120. package/renderer/dist/assets/ice-river-sm-Bg1U-SIj.webp +0 -0
  121. package/renderer/dist/assets/ice-sm-CbVcg3_D.webp +0 -0
  122. package/renderer/dist/assets/index-CwiDv5bL.css +32 -0
  123. package/renderer/dist/assets/index-D9hCAVPl.js +684 -0
  124. package/renderer/dist/assets/lake-C0WaW-6E.webp +0 -0
  125. package/renderer/dist/assets/lake-CSKjLC5K.webp +0 -0
  126. package/renderer/dist/assets/lake-ETGcOb25.webp +0 -0
  127. package/renderer/dist/assets/lake-harbour-BCQRbrHb.webp +0 -0
  128. package/renderer/dist/assets/lake-harbour-B_wfXTmE.webp +0 -0
  129. package/renderer/dist/assets/lake-harbour-Te1pEvBh.webp +0 -0
  130. package/renderer/dist/assets/lake-harbour-sm-Cme_ShEg.webp +0 -0
  131. package/renderer/dist/assets/lake-sm-CbG72Hbv.webp +0 -0
  132. package/renderer/dist/assets/lino-coast-CUZHcucI.webp +0 -0
  133. package/renderer/dist/assets/lino-coast-DP4J7cgd.webp +0 -0
  134. package/renderer/dist/assets/lino-coast-kOIAffr_.webp +0 -0
  135. package/renderer/dist/assets/lino-coast-sm-C1Mdbgit.webp +0 -0
  136. package/renderer/dist/assets/moon-pines-BskgnnXR.webp +0 -0
  137. package/renderer/dist/assets/moon-pines-CFSIIwt0.webp +0 -0
  138. package/renderer/dist/assets/moon-pines-PNhdOYww.webp +0 -0
  139. package/renderer/dist/assets/moon-pines-sm-C6K1NomK.webp +0 -0
  140. package/renderer/dist/assets/orbit-rings-2XV36Ch3.webp +0 -0
  141. package/renderer/dist/assets/orbit-rings-C4NrcYGQ.webp +0 -0
  142. package/renderer/dist/assets/orbit-rings-DGLk07dT.webp +0 -0
  143. package/renderer/dist/assets/orbit-rings-sm-Dky3YdvL.webp +0 -0
  144. package/renderer/dist/assets/peach-haze-2-C6f7xnWw.webp +0 -0
  145. package/renderer/dist/assets/peach-haze-2-sm-Dj_Ez_Sb.webp +0 -0
  146. package/renderer/dist/assets/pixel-harbour-DQjqMROg.webp +0 -0
  147. package/renderer/dist/assets/pixel-harbour-Dw71H_bc.webp +0 -0
  148. package/renderer/dist/assets/pixel-harbour-kOZfm-GM.webp +0 -0
  149. package/renderer/dist/assets/pixel-harbour-sm-Dturjuky.webp +0 -0
  150. package/renderer/dist/assets/pixel-orbit-C296JVMO.webp +0 -0
  151. package/renderer/dist/assets/pixel-orbit-C4oMRDSx.webp +0 -0
  152. package/renderer/dist/assets/pixel-orbit-CqVmQ4eh.webp +0 -0
  153. package/renderer/dist/assets/pixel-orbit-sm-CHagC_nO.webp +0 -0
  154. package/renderer/dist/assets/pixel-ridge-C6LYu6uE.webp +0 -0
  155. package/renderer/dist/assets/pixel-ridge-CIUCEESs.webp +0 -0
  156. package/renderer/dist/assets/pixel-ridge-sm-BnE0F_w-.webp +0 -0
  157. package/renderer/dist/assets/riso-hills-7heKVtry.webp +0 -0
  158. package/renderer/dist/assets/riso-hills-CIjAL3J6.webp +0 -0
  159. package/renderer/dist/assets/riso-hills-sm-DHsnbCfP.webp +0 -0
  160. package/renderer/dist/assets/slate-haze-BPWdkNsw.webp +0 -0
  161. package/renderer/dist/assets/slate-haze-sm-B0Cb5a2W.webp +0 -0
  162. package/renderer/dist/assets/source-sans-3-cyrillic-ext-wght-normal-DzyfIafT.woff2 +0 -0
  163. package/renderer/dist/assets/source-sans-3-cyrillic-wght-normal-BMDVbyM7.woff2 +0 -0
  164. package/renderer/dist/assets/source-sans-3-greek-ext-wght-normal-BWSLJLk6.woff2 +0 -0
  165. package/renderer/dist/assets/source-sans-3-greek-wght-normal-C9H9m1vD.woff2 +0 -0
  166. package/renderer/dist/assets/source-sans-3-latin-ext-wght-normal-C8iNium2.woff2 +0 -0
  167. package/renderer/dist/assets/source-sans-3-latin-wght-normal-BqRLTx4X.woff2 +0 -0
  168. package/renderer/dist/assets/source-sans-3-vietnamese-wght-normal-C1uRvKPU.woff2 +0 -0
  169. package/renderer/dist/assets/valley-haze-BDHPqoJy.webp +0 -0
  170. package/renderer/dist/assets/valley-haze-sm-CTyjmPAG.webp +0 -0
  171. package/renderer/dist/assets/vector-dunes-DzzWLdKo.webp +0 -0
  172. package/renderer/dist/assets/vector-dunes-Yr9NBQUy.webp +0 -0
  173. package/renderer/dist/assets/vector-dunes-sm-D8MYY6ms.webp +0 -0
  174. package/renderer/dist/assets/watercolour-mist-BCGKN4u4.webp +0 -0
  175. package/renderer/dist/assets/watercolour-mist-BF-jk5MC.webp +0 -0
  176. package/renderer/dist/assets/watercolour-mist-sm-Ds1xzTw9.webp +0 -0
  177. package/renderer/dist/assets/woodblock-sea-B1um67Z9.webp +0 -0
  178. package/renderer/dist/assets/woodblock-sea-DKQdYs32.webp +0 -0
  179. package/renderer/dist/assets/woodblock-sea-sm-BJzNq8xh.webp +0 -0
  180. package/renderer/dist/assets/xterm-BT7tBf8A.js +27 -0
  181. package/renderer/dist/emulator/audio-rules.mjs +74 -0
  182. package/renderer/dist/emulator/data/compression/README.md +11 -0
  183. package/renderer/dist/emulator/data/compression/extract7z.js +1 -0
  184. package/renderer/dist/emulator/data/compression/extractzip.js +1 -0
  185. package/renderer/dist/emulator/data/compression/libunrar.js +519 -0
  186. package/renderer/dist/emulator/data/compression/libunrar.wasm +0 -0
  187. package/renderer/dist/emulator/data/cores/README.md +22 -0
  188. package/renderer/dist/emulator/data/cores/mgba-legacy-wasm.data +0 -0
  189. package/renderer/dist/emulator/data/cores/mgba-thread-legacy-wasm.data +0 -0
  190. package/renderer/dist/emulator/data/cores/mgba-thread-wasm.data +0 -0
  191. package/renderer/dist/emulator/data/cores/mgba-wasm.data +0 -0
  192. package/renderer/dist/emulator/data/cores/package.json +65 -0
  193. package/renderer/dist/emulator/data/cores/reports/mgba.json +1 -0
  194. package/renderer/dist/emulator/data/emulator.css +1614 -0
  195. package/renderer/dist/emulator/data/loader.js +170 -0
  196. package/renderer/dist/emulator/data/localization/README.md +63 -0
  197. package/renderer/dist/emulator/data/localization/af-FR.json +339 -0
  198. package/renderer/dist/emulator/data/localization/ar-AR.json +301 -0
  199. package/renderer/dist/emulator/data/localization/ben-BEN.json +301 -0
  200. package/renderer/dist/emulator/data/localization/de-GER.json +301 -0
  201. package/renderer/dist/emulator/data/localization/el-GR.json +301 -0
  202. package/renderer/dist/emulator/data/localization/en-US.json +339 -0
  203. package/renderer/dist/emulator/data/localization/es-ES.json +310 -0
  204. package/renderer/dist/emulator/data/localization/fa-AF.json +310 -0
  205. package/renderer/dist/emulator/data/localization/hi-HI.json +301 -0
  206. package/renderer/dist/emulator/data/localization/it-IT.json +302 -0
  207. package/renderer/dist/emulator/data/localization/ja-JA.json +301 -0
  208. package/renderer/dist/emulator/data/localization/jv-JV.json +301 -0
  209. package/renderer/dist/emulator/data/localization/ko-KO.json +336 -0
  210. package/renderer/dist/emulator/data/localization/pt-BR.json +361 -0
  211. package/renderer/dist/emulator/data/localization/retroarch.json +617 -0
  212. package/renderer/dist/emulator/data/localization/ro-RO.json +310 -0
  213. package/renderer/dist/emulator/data/localization/ru-RU.json +301 -0
  214. package/renderer/dist/emulator/data/localization/tr-TR.json +310 -0
  215. package/renderer/dist/emulator/data/localization/vi-VN.json +302 -0
  216. package/renderer/dist/emulator/data/localization/zh-CN.json +351 -0
  217. package/renderer/dist/emulator/data/src/GameManager.js +464 -0
  218. package/renderer/dist/emulator/data/src/compression.js +142 -0
  219. package/renderer/dist/emulator/data/src/emulator.js +6158 -0
  220. package/renderer/dist/emulator/data/src/gamepad.js +167 -0
  221. package/renderer/dist/emulator/data/src/nipplejs.js +1 -0
  222. package/renderer/dist/emulator/data/src/shaders.js +236 -0
  223. package/renderer/dist/emulator/data/src/socket.io.min.js +7 -0
  224. package/renderer/dist/emulator/data/src/storage.js +125 -0
  225. package/renderer/dist/emulator/data/version.json +5 -0
  226. package/renderer/dist/emulator/host.js +299 -0
  227. package/renderer/dist/emulator/index.html +28 -0
  228. package/renderer/dist/emulator/provenance.json +6 -0
  229. package/renderer/dist/fixtures/onboard/designs/w-n13/the-first-row.html +1 -0
  230. package/renderer/dist/index.html +13 -0
  231. package/scripts/after-install.mjs +59 -0
  232. package/scripts/approval-server.sh +43 -0
  233. package/scripts/before-publish.mjs +133 -0
  234. package/shared/agent-import.d.mts +13 -0
  235. package/shared/agent-import.mjs +252 -0
  236. package/shared/agents.d.mts +190 -0
  237. package/shared/agents.mjs +937 -0
  238. package/shared/analytics-events.mjs +63 -0
  239. package/shared/answers.d.mts +12 -0
  240. package/shared/answers.mjs +80 -0
  241. package/shared/artifact-keys.d.mts +28 -0
  242. package/shared/artifact-keys.mjs +140 -0
  243. package/shared/bridge-map.mjs +128 -0
  244. package/shared/claude-commands.d.mts +20 -0
  245. package/shared/claude-commands.generated.mjs +149 -0
  246. package/shared/claude-commands.mjs +131 -0
  247. package/shared/claude-models.generated.d.mts +15 -0
  248. package/shared/claude-models.generated.mjs +26 -0
  249. package/shared/claude-usage.d.mts +16 -0
  250. package/shared/claude-usage.mjs +172 -0
  251. package/shared/codex-commands.d.mts +4 -0
  252. package/shared/codex-commands.mjs +17 -0
  253. package/shared/codex-import.d.mts +38 -0
  254. package/shared/codex-import.mjs +232 -0
  255. package/shared/codex-modes.mjs +159 -0
  256. package/shared/codex-usage.mjs +180 -0
  257. package/shared/contracts.mjs +412 -0
  258. package/shared/crash-scrub.mjs +182 -0
  259. package/shared/dashboard.mjs +481 -0
  260. package/shared/dead-run-trace.mjs +127 -0
  261. package/shared/demo-world.mjs +415 -0
  262. package/shared/effort-levels.d.mts +15 -0
  263. package/shared/effort-levels.mjs +76 -0
  264. package/shared/engines.d.mts +62 -0
  265. package/shared/engines.mjs +389 -0
  266. package/shared/first-run-examples.mjs +60 -0
  267. package/shared/first-run-line.mjs +149 -0
  268. package/shared/first-run-practice.d.mts +32 -0
  269. package/shared/first-run-practice.mjs +254 -0
  270. package/shared/first-run-shape.mjs +100 -0
  271. package/shared/fresh-user-home.mjs +189 -0
  272. package/shared/hook-failure.mjs +22 -0
  273. package/shared/install-id.mjs +39 -0
  274. package/shared/instruction-defaults.json +5 -0
  275. package/shared/library-folder.mjs +28 -0
  276. package/shared/notify-rules.mjs +120 -0
  277. package/shared/product-name.d.mts +6 -0
  278. package/shared/product-name.mjs +144 -0
  279. package/shared/project-folder-check.d.mts +22 -0
  280. package/shared/project-folder-check.mjs +152 -0
  281. package/shared/provider-commands.d.mts +8 -0
  282. package/shared/provider-commands.mjs +58 -0
  283. package/shared/rank.d.mts +19 -0
  284. package/shared/rank.mjs +146 -0
  285. package/shared/recovery.mjs +26 -0
  286. package/shared/referenced-files.d.mts +11 -0
  287. package/shared/referenced-files.mjs +122 -0
  288. package/shared/repeats.d.mts +45 -0
  289. package/shared/repeats.mjs +193 -0
  290. package/shared/schemes.mjs +33 -0
  291. package/shared/settings-terminal.d.mts +1 -0
  292. package/shared/settings-terminal.mjs +14 -0
  293. package/shared/side-build.mjs +57 -0
  294. package/shared/spawn-trouble.d.mts +8 -0
  295. package/shared/spawn-trouble.mjs +599 -0
  296. package/shared/terminal-state.d.mts +1 -0
  297. package/shared/terminal-state.mjs +58 -0
  298. package/shared/usage.d.mts +53 -0
  299. package/shared/usage.mjs +319 -0
  300. package/shared/work-items.mjs +561 -0
  301. package/shared/work-lines.mjs +360 -0
  302. package/worker-permissions.json +6 -0
@@ -0,0 +1,63 @@
1
+ // THE WHOLE LIST OF WHAT AGENTBOX MAY SEND. Nothing else can leave.
2
+ //
3
+ // Her eight, approved 2026-08-19 under her 08-18 rule: NO CODE, PROMPTS, KEYS
4
+ // OR PATHS. Seven of them are counts and the eighth is the version pair, which
5
+ // is not an event but a property on every one of them, exactly as
6
+ // `legal/privacy.html` section 5.1 describes it.
7
+ //
8
+ // This file is SHARED so the code and the published promise cannot drift apart.
9
+ // The privacy page lists these sentences; a test reads them from here and fails
10
+ // the build when one of them is missing from the page, and
11
+ // `scripts/shot-legal-pages.mjs` in the store fails from the other side.
12
+ //
13
+ // The naming rule that matters: an event name says THAT something happened. It
14
+ // never carries what it happened to. There is no room in this file for a title,
15
+ // a path, a repo name or a slug, and the property allowlist below is what stops
16
+ // a future caller adding one by accident.
17
+
18
+ // name -> the sentence the privacy page promises, word for word.
19
+ import { Name } from '../shared/product-name.mjs';
20
+ export const EVENTS = {
21
+ app_opened: `${Name} was opened`,
22
+ first_run_finished: 'First run finished',
23
+ repo_connected: 'A repo was connected',
24
+ agent_seen: 'An agent was seen',
25
+ task_opened: 'A task was opened',
26
+ reply_sent: 'A reply was sent',
27
+ task_finished: 'A task finished',
28
+ };
29
+
30
+ export const EVENT_NAMES = Object.keys(EVENTS);
31
+
32
+ // THE ONLY PROPERTIES A CALLER MAY ATTACH, and every one of them is a number or
33
+ // a boolean. A string is refused outright rather than scrubbed, because a
34
+ // scrubbed string is a promise about a regular expression and this is a promise
35
+ // about a type. The version pair is set by the sender itself (`main/analytics
36
+ // .mjs`), never by a caller, which is why it is not in here.
37
+ export const ALLOWED_PROPS = new Set([
38
+ 'seconds', // how long something took, rounded
39
+ 'count', // how many of a thing, never which ones
40
+ 'kind', // -> KINDS below, an enum and nothing else
41
+ 'fromAgent', // whether an agent or the founder did it
42
+ ]);
43
+
44
+ // `kind` is the one property that is not a number, so it is a closed list. A
45
+ // value outside it is dropped, not passed through.
46
+ export const KINDS = new Set(['task', 'question', 'review', 'directive', 'agent', 'digest']);
47
+
48
+ // Refuse an event nobody approved; drop a property nobody approved. Returns the
49
+ // payload that may be sent, or null when the event itself is not one of hers.
50
+ export function sanitize(name, props = {}) {
51
+ if (!EVENT_NAMES.includes(name)) return null;
52
+ const out = {};
53
+ for (const [key, value] of Object.entries(props ?? {})) {
54
+ if (!ALLOWED_PROPS.has(key)) continue;
55
+ if (key === 'kind') {
56
+ if (typeof value === 'string' && KINDS.has(value)) out.kind = value;
57
+ continue;
58
+ }
59
+ if (typeof value === 'number' && Number.isFinite(value)) out[key] = value;
60
+ else if (typeof value === 'boolean') out[key] = value;
61
+ }
62
+ return out;
63
+ }
@@ -0,0 +1,12 @@
1
+ // Types for shared/answers.mjs, which is plain ESM so that main (Node) and the
2
+ // renderer (Vite) can share one copy of the rule.
3
+
4
+ export interface AnsweredItem {
5
+ answer?: string;
6
+ answeredThrough?: number;
7
+ wrote?: Record<string, { ts: number; source: string } | undefined>;
8
+ }
9
+
10
+ export function agentSpokeSince(item: AnsweredItem | null | undefined, since: number): boolean;
11
+ export function answerSettled(item: AnsweredItem | null | undefined): boolean;
12
+ export function answerTs(item: AnsweredItem | null | undefined): number;
@@ -0,0 +1,80 @@
1
+ // HAS THE AGENT FINISHED ACTING ON WHAT SHE SAID? One rule, read by the
2
+ // supervisor (Node) and the inbox (Vite), because the two used to answer it
3
+ // differently and both used to answer it wrong.
4
+ //
5
+ // An answer is a fact with two states and the ledger only ever recorded one of
6
+ // them. She writes `answer`, a worker is spawned to carry it, and then the
7
+ // worker finishes and leaves the row exactly as it found it: `open`, her answer
8
+ // still on it, because the thread is alive and closing it is the wrong move
9
+ // (one row was filed on a one-word status question with a whole workstream
10
+ // inside it). Nothing on disk said the answer had been DEALT WITH. The only
11
+ // record was `_handledAnswers`, in supervisor memory, invisible to the
12
+ // renderer and wiped by every "Resume interrupted agents".
13
+ //
14
+ // So a finished thread was indistinguishable from a stranded one, and read as
15
+ // the worse of the two everywhere: out of her inbox, red in In progress, and
16
+ // respawnable forever. Twelve of her ro).
17
+ //
18
+ // `answeredThrough` is that missing fact, written on the item by the supervisor
19
+ // when a session finishes: the ts of the answer it acted on. It is compared
20
+ // against `wrote.answer.ts` rather than stored as a flag, so her NEXT answer
21
+ // carries a later ts and the row goes live again on its own, with nothing to
22
+ // clear and nothing to remember to clear.
23
+ //
24
+ // AND THE SESSION MUST HAVE LEFT A WORD ON THE ROW, which is the half that was
25
+ // missing until 2026-08-14 and is the whole of what she saw.
26
+ //
27
+ // The mark above is written from the SESSION's outcome: its process exited with
28
+ // a result and no error. That is a fact about a child process, not about her
29
+ // row. A session that spawned, read the brief and exited having written nothing
30
+ // satisfies it, and the row is then declared finished-and-delivered while
31
+ // carrying the exact words it carried before she spoke.).
32
+ //
33
+ // It happened five times in her store in two days. On it took 22 seconds: she
34
+ // replied at 12:32:19, a session exited at 12:32:42 having touched nothing, and
35
+ // the row was back in front of her.
36
+ //
37
+ // The delivery this rule was written for always had the word in it. Eleven of
38
+ // the twelve rows that named the original bug had a RESULT written after her
39
+ // answer, and the titles were the reports. So the word is not a new condition,
40
+ // it is the one that was assumed: news is news because somebody wrote it.
41
+ //
42
+ // A WORD IS ONE SHE CAN READ. This branch delivers finished work to her inbox,
43
+ // so the only writes that make it news are the ones the row shows her: the
44
+ // result, and the title and body a session rewrites when the answer changed
45
+ // what they say (instructions.md). Everything else is invisible from where she
46
+ // sits, and a row that comes back with nothing readably new is the whole
47
+ // complaint however busy the session was.
48
+ //
49
+ // A `note` is the checkpoint the NEXT session reads, not something she sees,
50
+ // and it is excluded for that reason. It cost one real row: on (2026-08-13) she
51
+ // answered at 12:32:54, a session wrote a note at 12:57:13 and no result, and
52
+ // the row was handed back to her carrying a result written ten minutes BEFORE
53
+ // she spoke.
54
+ //
55
+ // Status is not a word either. Claiming a row and releasing it writes `status`
56
+ // twice and says nothing, which is exactly the session this catches. The two
57
+ // statuses that would count, `done` and `blocked`, route on their own branches
58
+ // in list-rules.ts and never reach this rule.
59
+ const SPOKEN = ['result', 'title', 'body'];
60
+
61
+ export function agentSpokeSince(item, since) {
62
+ return SPOKEN.some((field) => {
63
+ const w = item?.wrote?.[field];
64
+ return !!w && w.source === 'agent' && (w.ts ?? 0) > since;
65
+ });
66
+ }
67
+
68
+ export function answerSettled(item) {
69
+ const answer = item?.answer;
70
+ if (!answer || answer === '(withdrawn)') return false;
71
+ const ts = item?.wrote?.answer?.ts ?? 0;
72
+ if (!(ts > 0 && (item?.answeredThrough ?? 0) >= ts)) return false;
73
+ return agentSpokeSince(item, ts);
74
+ }
75
+
76
+ // The moment of the answer a session was spawned to carry, which is what gets
77
+ // written down when it finishes. The app for a row nobody has answered.
78
+ export function answerTs(item) {
79
+ return item?.wrote?.answer?.ts ?? 0;
80
+ }
@@ -0,0 +1,28 @@
1
+ // Types for shared/artifact-keys.mjs, which is plain ESM so that main (Node)
2
+ // and the pane (Vite) can share one copy of the rule. The whole reason this
3
+ // rule exists is that it was applied in three places and disagreed in all
4
+ // three; see the module itself for the measurements.
5
+
6
+ export interface KeyPress {
7
+ key: string;
8
+ metaKey?: boolean;
9
+ ctrlKey?: boolean;
10
+ altKey?: boolean;
11
+ }
12
+
13
+ export function theAppKeepsThisKey(e: KeyPress | null | undefined): boolean;
14
+ export function theAppKeepsThisInput(
15
+ input: { key?: string; meta?: boolean; control?: boolean; alt?: boolean } | null | undefined,
16
+ ): boolean;
17
+ export function whatTheFileSentUp(
18
+ k: { key?: string; meta?: boolean; ctrl?: boolean; alt?: boolean } | null | undefined,
19
+ ): 'close' | 'palette' | 'app' | null;
20
+
21
+ // Her own single-letter shortcuts, which a PAGE has no claim on because there
22
+ // is nothing in a page to type.
23
+ export const HER_LETTERS_IN_A_PAGE: Set<string>;
24
+ export function theAppKeepsThisLetterInAPage(
25
+ input: { key?: string; meta?: boolean; control?: boolean; alt?: boolean } | null | undefined,
26
+ ): boolean;
27
+ // Asked OF the page, by main, because only a frame can see its own focus.
28
+ export const IS_SHE_TYPING_IN_THE_PAGE: string;
@@ -0,0 +1,140 @@
1
+ // PURE. Which keys still belong to the APP while the keyboard is inside an
2
+ // open artifact.
3
+ //
4
+ // MEASURED BEFORE ANYTHING WAS TOUCHED, on the real renderer with her real
5
+ // cards and her real files (scripts/measure-keys-with-an-artifact.mjs, run
6
+ // 2026-08-24). "Inside the file" is one click in the artifact, which is what a
7
+ // person does with an artifact:
8
+ //
9
+ // markdown, caret in the file ⌘K dead j dead Escape dead
10
+ // page, clicked inside it ⌘K dead j dead Escape closes it
11
+ // change, caret in a line ⌘K works j dead Escape dead
12
+ //
13
+ // THREE MECHANISMS, AND THAT IS WHY THIS FILE EXISTS RATHER THAN THREE PATCHES.
14
+ //
15
+ // 1. The markdown editor swallowed every key it saw. `DocText` stopped
16
+ // propagation on every keydown so that a letter typed into a file is not
17
+ // also a shortcut — right intent, and the app already refuses letters by
18
+ // itself (`inInput` in App.tsx) — but the app's own window listener sits
19
+ // ABOVE the React root, so the same line also swallowed ⌘K and Escape.
20
+ // 2. A page is its own document in its own origin, so no key crosses into
21
+ // the app at all. Main forwards from below the page, and it forwarded
22
+ // exactly one key, Escape.
23
+ // 3. A line of a change is a contentEditable, so `inInput` is true and the
24
+ // app's guard returns on everything single-letter — including Escape,
25
+ // which is the one key that has to work from in there.
26
+ //
27
+ // So the rule is written once, here, and applied at all three: A CHORD IS NEVER
28
+ // TEXT, AND ESCAPE IS ALWAYS THE WAY BACK. Everything else typed inside a file
29
+ // is typing, and the app keeps its hands off it, which is the part that was
30
+ // already right.
31
+
32
+ /**
33
+ * Does this press belong to the app even though the keyboard is in the file?
34
+ *
35
+ * Escape, and any Command or Control chord. NOT Option on its own: on a Mac
36
+ * option-e is a letter she is typing, and treating it as a chord would take
37
+ * accented characters away from a file she is editing.
38
+ *
39
+ * ⌘S IS DELIBERATELY IN HERE even though it is the file's own save. The save
40
+ * listener is a window listener too (`DocText`), so it was dead for exactly the
41
+ * same reason and by exactly the same line: her "Saved." never appeared when
42
+ * the caret was in the document, which is the only place ⌘S is ever pressed.
43
+ * Letting the chord through is what makes that one work again as well.
44
+ */
45
+ export function theAppKeepsThisKey(e) {
46
+ if (!e || typeof e.key !== 'string') return false;
47
+ if (e.key === 'Escape') return true;
48
+ return !!(e.metaKey || e.ctrlKey);
49
+ }
50
+
51
+ /**
52
+ * The same question asked from the main process, where a key arrives as an
53
+ * Electron `input` rather than a DOM event. One rule, two vocabularies.
54
+ */
55
+ export function theAppKeepsThisInput(input) {
56
+ if (!input || typeof input.key !== 'string') return false;
57
+ return theAppKeepsThisKey({ key: input.key, metaKey: !!input.meta, ctrlKey: !!input.control, altKey: !!input.alt });
58
+ }
59
+
60
+ /**
61
+ * What the app does with a key that came up from inside a page in the pane.
62
+ *
63
+ * 'close' is Escape, which has meant "out of the file" since. 'palette' is ⌘K,
64
+ * which is the app's own and which a page drawn in a frame has no claim on.
65
+ * 'app' is one of her letters coming up out of a PAGE, where nothing is text.
66
+ * The pane hands it straight back to the app's own handler rather than
67
+ * restating what any letter means, so E archives, J and K walk, R replies, and
68
+ * each of them keeps every guard the app already puts in front of it. null is
69
+ * every other chord: ⌘R, ⌘=, ⌘Y and the rest are answered in the main process
70
+ * already, and the window must not answer them a second time.
71
+ */
72
+ export function whatTheFileSentUp(k) {
73
+ if (!k || typeof k.key !== 'string') return null;
74
+ if (k.key === 'Escape') return 'close';
75
+ if ((k.meta || k.ctrl) && k.key.toLowerCase() === 'k') return 'palette';
76
+ if (theAppKeepsThisLetterInAPage({ key: k.key, meta: k.meta, control: k.ctrl, alt: k.alt })) return 'app';
77
+ return null;
78
+ }
79
+
80
+ // ─────────────────────────────────────────────────────────────────────────────
81
+ // A PAGE HAS NOTHING TO TYPE IN, SO IT KEEPS NONE OF HER LETTERS.
82
+ //
83
+ // MEASURED BEFORE ANYTHING WAS TOUCHED
84
+ // (scripts/measure-keys-with-an-artifact.mjs, the run recorded in
85
+ // shots//e-before.json). E is not dead the way ⌘K was dead. With the keyboard
86
+ // ON THE MESSAGE it archives the card whether a file is open beside it or not;
87
+ // the app's handler runs, `inInput` is false, and the write goes through. It
88
+ // dies only once she clicks INTO the artifact, and there the three kinds are
89
+ // not the same thing at all:
90
+ //
91
+ // markdown, caret in the file E is a letter she is typing. Correct.
92
+ // change, caret in a line E is a letter she is typing. Correct.
93
+ // page, clicked inside it E is nothing at all. The bug.
94
+ //
95
+ // Escape hands the keyboard back and then E works, which is the idiom the whole
96
+ // of this file is built on.
97
+ //
98
+ // A page is the odd one. There is nothing in it to type, so no key in it is
99
+ // text, and the only reason E was dead is that the list of keys the app asks
100
+ // for from below the page was Escape and chords — the list above. Her letters
101
+ // were never on it. So they go on it, here, once.
102
+ //
103
+ // WHAT IS DELIBERATELY NOT ON IT:
104
+ // Arrows, Enter, space, Tab the page's own. Arrows SCROLL a page; taking
105
+ // them would break reading the very thing she
106
+ // opened. Tab walks the page's own links.
107
+ // 1 through 9 those APPROVE an option, and approval in this
108
+ // app only ever happens deliberately (App.tsx
109
+ // says so where E used to approve and burned
110
+ // her). A forwarded digit is not deliberate.
111
+ export const HER_LETTERS_IN_A_PAGE = new Set(['e', 'j', 'k', 'r', 'c', 'n', 's', 'z', 'b', 'g', '/', '\\']);
112
+
113
+ /**
114
+ * Is this one of her letters, arriving from inside a page where there is
115
+ * nothing to type?
116
+ *
117
+ * Bare or shifted only. A chord is already answered by theAppKeepsThisInput
118
+ * above, and Option-e is a letter on a Mac, so neither belongs here.
119
+ */
120
+ export function theAppKeepsThisLetterInAPage(input) {
121
+ if (!input || typeof input.key !== 'string') return false;
122
+ if (input.meta || input.control || input.alt) return false;
123
+ return HER_LETTERS_IN_A_PAGE.has(input.key.toLowerCase());
124
+ }
125
+
126
+ /**
127
+ * The one question main cannot answer by itself: is she typing INSIDE the page?
128
+ *
129
+ * A page is her own html and 15 of the 406 under her product's designs, reports
130
+ * and landing folders carry a real text field (counted 2026-08-24). If she is
131
+ * in one of those, every letter she types is text and none of it is a shortcut
132
+ * — the same rule the app applies to its own fields, applied one document down.
133
+ * Main asks the frame this, because only the frame can see its own focus.
134
+ */
135
+ export const IS_SHE_TYPING_IN_THE_PAGE = `(() => {
136
+ const a = document.activeElement;
137
+ if (!a) return false;
138
+ const t = String(a.tagName || '').toUpperCase();
139
+ return t === 'INPUT' || t === 'TEXTAREA' || t === 'SELECT' || !!a.isContentEditable;
140
+ })()`;
@@ -0,0 +1,128 @@
1
+ // THE ONE LIST OF WHAT THE SCREEN MAY ASK FOR.
2
+ //
3
+ // preload.cjs is the desktop half of this: it turns each name below into an
4
+ // Electron invoke. renderer/src/browser-bridge.ts is the other half and turns
5
+ // the same name into a POST to the local server. Both doors read this list, so
6
+ // a channel added to one cannot go missing from the other, and
7
+ // tests/both-front-doors-offer-the-same-bridge.test.mjs fails the suite if
8
+ // preload.cjs and this file ever disagree.
9
+ //
10
+ // The keys are the screen's own vocabulary, the values are the channels
11
+ // main/ipc.mjs registered. Nothing here decides anything; it is a phone book.
12
+
13
+ /** Asked, and the screen waits for the answer. */
14
+ export const REQUEST_CHANNELS = {
15
+ terminal: 'zero:terminal',
16
+ snapshot: 'zero:snapshot',
17
+ dashboard: 'zero:dashboard',
18
+ commandCatalog: 'zero:command-catalog',
19
+ remoteControl: 'zero:remote-control',
20
+ command: 'zero:command',
21
+ compact: 'zero:compact',
22
+ compactionStatus: 'zero:compaction-status',
23
+ answer: 'zero:answer',
24
+ compose: 'zero:compose',
25
+ schedule: 'zero:schedule',
26
+ repeats: 'zero:repeats',
27
+ composeRepeat: 'zero:compose-repeat',
28
+ setRepeat: 'zero:set-repeat',
29
+ endRepeat: 'zero:end-repeat',
30
+ pauseSupervisor: 'zero:supervisor-pause',
31
+ createProduct: 'zero:create-product',
32
+ firstRunAnswer: 'zero:first-run-answer',
33
+ firstRunExamples: 'zero:first-run-examples',
34
+ firstRunPractice: 'zero:first-run-practice',
35
+ firstRunPracticeEnd: 'zero:first-run-practice-end',
36
+ firstRunWalking: 'zero:first-run-walking',
37
+ openFreshUser: 'zero:open-fresh-user',
38
+ openDemo: 'zero:open-demo',
39
+ chooseFolder: 'zero:choose-folder',
40
+ listFolders: 'zero:list-folders',
41
+ folderExists: 'zero:folder-exists',
42
+ agentFiles: 'zero:agent-files',
43
+ agentFolders: 'zero:agent-folders',
44
+ importAgents: 'zero:import-agents',
45
+ agentThreads: 'zero:agent-threads',
46
+ importThreads: 'zero:import-threads',
47
+ badge: 'zero:badge',
48
+ bootInfo: 'zero:boot-info',
49
+ updateCheck: 'zero:update-check',
50
+ updateInstall: 'zero:update-install',
51
+ notify: 'zero:notify',
52
+ stopSession: 'zero:stop-session',
53
+ reopen: 'zero:reopen',
54
+ instructionRead: 'zero:instruction-read',
55
+ instructionWrite: 'zero:instruction-write',
56
+ instructionHistory: 'zero:instruction-history',
57
+ instructionVersion: 'zero:instruction-version',
58
+ standingRead: 'zero:standing-read',
59
+ standingWrite: 'zero:standing-write',
60
+ messageRulesRead: 'zero:message-rules-read',
61
+ messageRulesWrite: 'zero:message-rules-write',
62
+ settingsRead: 'zero:settings-read',
63
+ claudeRecheck: 'zero:claude-recheck',
64
+ codexRecheck: 'zero:codex-recheck',
65
+ codexAddAccount: 'zero:codex-add-account',
66
+ claudeAddAccount: 'zero:claude-add-account',
67
+ setProjectSetting: 'zero:settings-set-project',
68
+ setWorkspaceSetting: 'zero:settings-set-workspace',
69
+ projectRename: 'zero:project-rename',
70
+ projectIcon: 'zero:project-icon',
71
+ projectIconClear: 'zero:project-icon-clear',
72
+ projectInstructionsRead: 'zero:project-instructions-read',
73
+ projectInstructionsWrite: 'zero:project-instructions-write',
74
+ saveAttachments: 'zero:save-attachments',
75
+ stageAttachment: 'zero:stage-attachment',
76
+ crash: 'zero:crash',
77
+ track: 'zero:track',
78
+ sessionTrace: 'zero:session-trace',
79
+ itemHistory: 'zero:item-history',
80
+ openArtifact: 'zero:open-artifact',
81
+ readDoc: 'zero:read-doc',
82
+ codeChange: 'zero:code-change',
83
+ codeFile: 'zero:code-file',
84
+ saveCodeFile: 'zero:save-code-file',
85
+ writeDoc: 'zero:write-doc',
86
+ railNote: 'zero:rail-note',
87
+ saveRailNote: 'zero:save-rail-note',
88
+ agentReply: 'zero:agent-reply',
89
+ agentReveal: 'zero:agent-reveal',
90
+ agentConversation: 'zero:agent-conversation',
91
+ scheduleAgent: 'zero:schedule-agent',
92
+ closeAgent: 'zero:close-agent',
93
+ unreplyAgent: 'zero:unreply-agent',
94
+ resumeAgents: 'zero:resume-agents',
95
+ resumeItems: 'zero:resume-items',
96
+ redeliver: 'zero:redeliver',
97
+ setProductOrder: 'zero:set-product-order',
98
+ setProductHidden: 'zero:set-product-hidden',
99
+ approve: 'zero:approve',
100
+ };
101
+
102
+ /** Told rather than asked: the app talks and the screen listens. */
103
+ export const PUSH_CHANNELS = {
104
+ onApprovalAnswered: 'zero:approval-answered',
105
+ onChanged: 'zero:changed',
106
+ onFind: 'zero:find',
107
+ onZoomPercent: 'zero:zoom-percent',
108
+ onRecovered: 'zero:recovered',
109
+ onOpenItem: 'zero:open-item',
110
+ onScreenDetail: 'zero:screen-detail',
111
+ onEscapeBrowser: 'zero:escape-browser',
112
+ onKeyInTheFile: 'zero:key-in-the-file',
113
+ };
114
+
115
+ // THE FEW THAT ARE NOT A STRAIGHT HANDOVER. Each is called with bare values
116
+ // and the handler on the far side reads an object, so the key each value goes
117
+ // under is part of the contract and belongs here beside the channel.
118
+ export const WRAPPED_ARGS = {
119
+ notify: ['arrivals'],
120
+ track: ['name'],
121
+ instructionWrite: ['id', 'text'],
122
+ instructionVersion: ['id', 'at'],
123
+ };
124
+
125
+ // Electron can tell you the real path of a file somebody dropped onto the
126
+ // window. A browser cannot, by design, and no server can answer it either, so
127
+ // this one is absent there rather than wrong. The screen already reads null.
128
+ export const DESKTOP_ONLY = ['pathForFile'];
@@ -0,0 +1,20 @@
1
+ export interface ClaudeCommand {
2
+ name: string;
3
+ description: string;
4
+ /** Claude Code's own shorter sentence, where they wrote one for a menu. */
5
+ menuDescription: string | null;
6
+ /** False when a getter composes the description at run time and we cut it at
7
+ * the interpolation, so nothing may present it as a quotation. */
8
+ whole: boolean;
9
+ argumentHint: string | null;
10
+ aliases: string[];
11
+ }
12
+
13
+ export declare const CLAUDE_COMMANDS: ClaudeCommand[];
14
+ export declare const READ_FROM: string | null;
15
+ export declare const READ_AT: string | null;
16
+ export declare function commandWords(cmd: ClaudeCommand): string[];
17
+ export declare function commandHint(cmd: ClaudeCommand): string;
18
+ export declare function commandMatches(query: string | null): ClaudeCommand[];
19
+ export declare function commandDraft(cmd: ClaudeCommand): string;
20
+ export declare function commandPrompt(reply: unknown, nativeNames?: string[]): string | null;
@@ -0,0 +1,149 @@
1
+ // GENERATED BY scripts/read-claude-commands.mjs. DO NOT EDIT BY HAND.
2
+ //
3
+ // Claude Code's own words for the commands Agentbox's reply box offers,
4
+ // read out of the copy of Claude Code installed on the machine that built
5
+ // this. `npm run build` rewrites it. Committed so a machine with no Claude
6
+ // Code on it can still build, and so a version that renames one of the eight
7
+ // shows up as a diff rather than as a wrong menu.
8
+ //
9
+ // WHY IT IS READ AND NOT TYPED: reading them out of the installed binary at
10
+ // build time, rather than typing them into a file, is the only way the list
11
+ // cannot rot quietly.
12
+
13
+ export const READ_FROM = "2.1.283";
14
+ export const READ_AT = "2026-09-29";
15
+ export const CLAUDE_COMMANDS = [
16
+ {
17
+ "name": "model",
18
+ "description": "Set the AI model for Claude Code",
19
+ "menuDescription": null,
20
+ "whole": true,
21
+ "argumentHint": "<model>",
22
+ "aliases": []
23
+ },
24
+ {
25
+ "name": "effort",
26
+ "description": "Set effort level for model usage",
27
+ "menuDescription": null,
28
+ "whole": true,
29
+ "argumentHint": null,
30
+ "aliases": []
31
+ },
32
+ {
33
+ "name": "fast",
34
+ "description": "Toggle fast mode",
35
+ "menuDescription": null,
36
+ "whole": false,
37
+ "argumentHint": "[on|off]",
38
+ "aliases": []
39
+ },
40
+ {
41
+ "name": "goal",
42
+ "description": "Set a goal — keep working until the condition is met",
43
+ "menuDescription": null,
44
+ "whole": true,
45
+ "argumentHint": null,
46
+ "aliases": []
47
+ },
48
+ {
49
+ "name": "context",
50
+ "description": "Show current context usage",
51
+ "menuDescription": null,
52
+ "whole": true,
53
+ "argumentHint": null,
54
+ "aliases": []
55
+ },
56
+ {
57
+ "name": "usage",
58
+ "description": "Show session cost, plan usage, and what's contributing to your limits",
59
+ "menuDescription": "Show session cost and plan usage",
60
+ "whole": true,
61
+ "argumentHint": null,
62
+ "aliases": [
63
+ "cost",
64
+ "stats"
65
+ ]
66
+ },
67
+ {
68
+ "name": "mcp",
69
+ "description": "Manage MCP servers",
70
+ "menuDescription": null,
71
+ "whole": true,
72
+ "argumentHint": "[reconnect|enable|disable [<server>|all]]",
73
+ "aliases": []
74
+ },
75
+ {
76
+ "name": "compact",
77
+ "description": "Free up context by summarizing the conversation so far",
78
+ "menuDescription": null,
79
+ "whole": true,
80
+ "argumentHint": "<optional custom summarization instructions>",
81
+ "aliases": []
82
+ },
83
+ {
84
+ "name": "advisor",
85
+ "description": "Let Claude consult a stronger model at key moments",
86
+ "menuDescription": null,
87
+ "whole": true,
88
+ "argumentHint": null,
89
+ "aliases": []
90
+ },
91
+ {
92
+ "name": "autocompact",
93
+ "description": "Configure the auto-compact window size",
94
+ "menuDescription": null,
95
+ "whole": true,
96
+ "argumentHint": "[auto|<tokens>]",
97
+ "aliases": []
98
+ },
99
+ {
100
+ "name": "output-style",
101
+ "description": "List output styles or switch to one",
102
+ "menuDescription": null,
103
+ "whole": true,
104
+ "argumentHint": "[style]",
105
+ "aliases": []
106
+ },
107
+ {
108
+ "name": "recap",
109
+ "description": "Generate a one-line session recap now",
110
+ "menuDescription": null,
111
+ "whole": true,
112
+ "argumentHint": null,
113
+ "aliases": []
114
+ },
115
+ {
116
+ "name": "reload-skills",
117
+ "description": "Pick up skills added or changed on disk during this session",
118
+ "menuDescription": null,
119
+ "whole": true,
120
+ "argumentHint": null,
121
+ "aliases": []
122
+ },
123
+ {
124
+ "name": "list-agents",
125
+ "description": "List subagents, teammates, and other Claude sessions you can message",
126
+ "menuDescription": null,
127
+ "whole": true,
128
+ "argumentHint": null,
129
+ "aliases": [
130
+ "peers"
131
+ ]
132
+ },
133
+ {
134
+ "name": "focus",
135
+ "description": "Toggle focus view: just your prompt, summary, and response",
136
+ "menuDescription": null,
137
+ "whole": true,
138
+ "argumentHint": "[on|off]",
139
+ "aliases": []
140
+ },
141
+ {
142
+ "name": "reload-plugins",
143
+ "description": "Activate pending plugin changes in the current session",
144
+ "menuDescription": null,
145
+ "whole": true,
146
+ "argumentHint": "[--force]",
147
+ "aliases": []
148
+ }
149
+ ];