@thaut/claude-ide 0.0.0-stage → 1.0.0

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 (559) hide show
  1. package/bin/claude-ide.js +23 -0
  2. package/package.json +75 -4
  3. package/server/add-dirs.ts +126 -0
  4. package/server/auth.test.ts +148 -0
  5. package/server/auth.ts +235 -0
  6. package/server/bang.ts +54 -0
  7. package/server/btw-instructions.ts +19 -0
  8. package/server/btw-policy.ts +17 -0
  9. package/server/btw.ts +143 -0
  10. package/server/child-env.ts +29 -0
  11. package/server/cli-control.ts +255 -0
  12. package/server/cli-files.ts +55 -0
  13. package/server/cli-info.ts +73 -0
  14. package/server/config/account.ts +65 -0
  15. package/server/config/agents.ts +186 -0
  16. package/server/config/mcp.ts +86 -0
  17. package/server/config/memory.ts +193 -0
  18. package/server/config/paths.ts +156 -0
  19. package/server/config/plugins.ts +204 -0
  20. package/server/config/routes.ts +95 -0
  21. package/server/config/settings.ts +246 -0
  22. package/server/config.ts +46 -0
  23. package/server/db.ts +121 -0
  24. package/server/directories.test.ts +180 -0
  25. package/server/directories.ts +87 -0
  26. package/server/dist-version.ts +69 -0
  27. package/server/durable-tasks.ts +61 -0
  28. package/server/file-transfers.ts +79 -0
  29. package/server/files.test.ts +127 -0
  30. package/server/files.ts +386 -0
  31. package/server/fs-queue.ts +14 -0
  32. package/server/fsutil.ts +144 -0
  33. package/server/git.ts +86 -0
  34. package/server/goal-state.test.ts +64 -0
  35. package/server/goal-state.ts +78 -0
  36. package/server/history-pages.test.ts +619 -0
  37. package/server/history-pages.ts +513 -0
  38. package/server/http-channel-manager.ts +468 -0
  39. package/server/http-channel-pull.test.ts +314 -0
  40. package/server/http-channel-push.test.ts +364 -0
  41. package/server/http-channel-registration.test.ts +291 -0
  42. package/server/http-channel-routes.ts +73 -0
  43. package/server/http-channel-store.ts +142 -0
  44. package/server/http-channel-test-fixture.ts +103 -0
  45. package/server/ide-messages-mcp.test.ts +82 -0
  46. package/server/ide-messages-mcp.ts +47 -0
  47. package/server/idecron-mcp.ts +65 -0
  48. package/server/idecron.test.ts +79 -0
  49. package/server/idecron.ts +271 -0
  50. package/server/index.ts +336 -0
  51. package/server/live-session.test.ts +1126 -0
  52. package/server/live-session.ts +1165 -0
  53. package/server/project-routes.ts +46 -0
  54. package/server/projects.test.ts +28 -0
  55. package/server/push.ts +315 -0
  56. package/server/report-cache.ts +28 -0
  57. package/server/session-aliases.test.ts +57 -0
  58. package/server/session-aliases.ts +50 -0
  59. package/server/session-branch.ts +71 -0
  60. package/server/session-dirs.ts +189 -0
  61. package/server/session-file.test.ts +134 -0
  62. package/server/session-file.ts +113 -0
  63. package/server/session-messaging.test.ts +297 -0
  64. package/server/session-messaging.ts +165 -0
  65. package/server/sessions.ts +638 -0
  66. package/server/subagents.test.ts +43 -0
  67. package/server/subagents.ts +58 -0
  68. package/server/tool-images.test.ts +76 -0
  69. package/server/tool-images.ts +45 -0
  70. package/server/turn-changes.ts +308 -0
  71. package/server/worktree-git.ts +87 -0
  72. package/server/worktrees.ts +138 -0
  73. package/server/ws.test.ts +195 -0
  74. package/server/ws.ts +197 -0
  75. package/shared/agent-model.ts +15 -0
  76. package/shared/agent-tasks.ts +12 -0
  77. package/shared/config.ts +175 -0
  78. package/shared/directories.ts +12 -0
  79. package/shared/files.ts +51 -0
  80. package/shared/http-channels.ts +63 -0
  81. package/shared/message-window.ts +189 -0
  82. package/shared/project.ts +77 -0
  83. package/shared/protocol.ts +203 -0
  84. package/shared/task-types.ts +4 -0
  85. package/shared/todos.ts +40 -0
  86. package/shared/write-policy.ts +9 -0
  87. package/web/dist/assets/AgentView-wrTKgcJ3.js +1 -0
  88. package/web/dist/assets/AnnotationSelection-BZmNmwVW.js +7 -0
  89. package/web/dist/assets/ChangesView-G1WTzh4q.js +2 -0
  90. package/web/dist/assets/FilesView-DPgAbYt_.js +6 -0
  91. package/web/dist/assets/Form-BKTwiYyw.js +1 -0
  92. package/web/dist/assets/HomePage-Dq2apjBe.js +1 -0
  93. package/web/dist/assets/Markdown-IwP-xF29.js +67 -0
  94. package/web/dist/assets/MessageList-DD9GypSy.js +15 -0
  95. package/web/dist/assets/Modal-g2rv8I_n.js +1 -0
  96. package/web/dist/assets/NotificationSettings-DpuLO_Bv.js +1 -0
  97. package/web/dist/assets/OverviewPage-Dx6miabE.js +1 -0
  98. package/web/dist/assets/ProjectHome-CousyTLL.js +1 -0
  99. package/web/dist/assets/SessionView-CPVL7_HO.js +2 -0
  100. package/web/dist/assets/SettingsPage-D_oYSnW2.js +7 -0
  101. package/web/dist/assets/WorktreesView-C7e0HV__.js +1 -0
  102. package/web/dist/assets/abap-CLvhMVsD.js +1 -0
  103. package/web/dist/assets/actionscript-3-Cs6JJXT5.js +1 -0
  104. package/web/dist/assets/ada-X3Y2mlq2.js +1 -0
  105. package/web/dist/assets/ahk-DwADkxyd.js +1 -0
  106. package/web/dist/assets/ahk2-_6rzW9BS.js +1 -0
  107. package/web/dist/assets/andromeeda-vGVdxbeo.js +1 -0
  108. package/web/dist/assets/angular-html-Cw29lun8.js +1 -0
  109. package/web/dist/assets/angular-ts-BXz-O3SJ.js +1 -0
  110. package/web/dist/assets/apache-U0d_L8uA.js +1 -0
  111. package/web/dist/assets/apex-KFGFyKwG.js +1 -0
  112. package/web/dist/assets/apl-xBchdRhy.js +1 -0
  113. package/web/dist/assets/applescript-CCn79oCD.js +1 -0
  114. package/web/dist/assets/ara-4CJ0cIlV.js +1 -0
  115. package/web/dist/assets/asciidoc-SCjQUq34.js +1 -0
  116. package/web/dist/assets/asm-Cmm7eHzH.js +1 -0
  117. package/web/dist/assets/astro-1q6DGuN3.js +1 -0
  118. package/web/dist/assets/aurora-x-CDeNXAV0.js +1 -0
  119. package/web/dist/assets/awk-BWXHIvNe.js +1 -0
  120. package/web/dist/assets/ayu-dark-DluEY0Gj.js +1 -0
  121. package/web/dist/assets/ayu-light-C3h-C4tm.js +1 -0
  122. package/web/dist/assets/ayu-mirage-Bqwy1Gya.js +1 -0
  123. package/web/dist/assets/ballerina-B7ZEbQpA.js +1 -0
  124. package/web/dist/assets/bat-qdxAdBWQ.js +1 -0
  125. package/web/dist/assets/beancount-C2IN4Vk8.js +1 -0
  126. package/web/dist/assets/berry-DKpUyyne.js +1 -0
  127. package/web/dist/assets/bibtex-Ci_nEsc7.js +1 -0
  128. package/web/dist/assets/bicep-CUHmPFLl.js +1 -0
  129. package/web/dist/assets/bird2-CYIUgYqB.js +1 -0
  130. package/web/dist/assets/blade-Cqdv4oZN.js +1 -0
  131. package/web/dist/assets/bsl-CVED6lJ1.js +1 -0
  132. package/web/dist/assets/c-D9gIxSfx.js +1 -0
  133. package/web/dist/assets/c3-D0apG41V.js +1 -0
  134. package/web/dist/assets/cadence-CQ2zXKGN.js +1 -0
  135. package/web/dist/assets/cairo-DRAZz75c.js +1 -0
  136. package/web/dist/assets/catppuccin-frappe-C9Q5zVZY.js +1 -0
  137. package/web/dist/assets/catppuccin-latte-CtsyrtPq.js +1 -0
  138. package/web/dist/assets/catppuccin-macchiato-R8nAf1vR.js +1 -0
  139. package/web/dist/assets/catppuccin-mocha-DjuaAJKi.js +1 -0
  140. package/web/dist/assets/chapel-CuseGurG.js +1 -0
  141. package/web/dist/assets/clarity-CtfBBspg.js +1 -0
  142. package/web/dist/assets/clojure-DqKBuwfJ.js +1 -0
  143. package/web/dist/assets/cmake-Bj61d0ZC.js +1 -0
  144. package/web/dist/assets/cobol-Bdpj3Qoh.js +1 -0
  145. package/web/dist/assets/codeowners-C8r90Shi.js +1 -0
  146. package/web/dist/assets/codeql-oeQT6MSM.js +1 -0
  147. package/web/dist/assets/coffee-Sk8pHFjs.js +1 -0
  148. package/web/dist/assets/common-lisp-Cv5bFMCO.js +1 -0
  149. package/web/dist/assets/coq-CGaSfhwR.js +1 -0
  150. package/web/dist/assets/core-BxI4V4-T.js +12 -0
  151. package/web/dist/assets/cpp-BQfBYKx3.js +1 -0
  152. package/web/dist/assets/crystal-B3j7DoOZ.js +1 -0
  153. package/web/dist/assets/csharp-dmMxLVLW.js +1 -0
  154. package/web/dist/assets/css-DpFbYmRh.js +1 -0
  155. package/web/dist/assets/csv-Dx-8-gkx.js +1 -0
  156. package/web/dist/assets/cue-CE9AQfxI.js +1 -0
  157. package/web/dist/assets/cypher-ClKdZ_lG.js +1 -0
  158. package/web/dist/assets/d-qD-0Kul2.js +1 -0
  159. package/web/dist/assets/dark-plus-Cs2F2srj.js +1 -0
  160. package/web/dist/assets/dart-CHZY9Xhz.js +1 -0
  161. package/web/dist/assets/dax-BkyTk9wS.js +1 -0
  162. package/web/dist/assets/desktop-Dlh5hvp9.js +1 -0
  163. package/web/dist/assets/diff-woXpYk--.js +1 -0
  164. package/web/dist/assets/docker-IyjqRm3v.js +1 -0
  165. package/web/dist/assets/dotenv-CuH5my32.js +1 -0
  166. package/web/dist/assets/dracula-BHWKrbxM.js +1 -0
  167. package/web/dist/assets/dracula-soft-5eyTD99u.js +1 -0
  168. package/web/dist/assets/dream-maker-DW3nJb8Q.js +1 -0
  169. package/web/dist/assets/edge-DXQWmXTB.js +1 -0
  170. package/web/dist/assets/elixir-CrDIY2Vo.js +1 -0
  171. package/web/dist/assets/elm-BslFEg8K.js +1 -0
  172. package/web/dist/assets/emacs-lisp-DR2vtWaj.js +1 -0
  173. package/web/dist/assets/engine-javascript-DJg3-Vu2.js +141 -0
  174. package/web/dist/assets/erb-CUYhg0Ws.js +1 -0
  175. package/web/dist/assets/erlang-BXdgHVfi.js +1 -0
  176. package/web/dist/assets/everforest-dark-sB-x3p7T.js +1 -0
  177. package/web/dist/assets/everforest-light-Df2xbC6M.js +1 -0
  178. package/web/dist/assets/fennel-DQxkIbk2.js +1 -0
  179. package/web/dist/assets/fish-BJitypiv.js +1 -0
  180. package/web/dist/assets/fluent-C03EYrpw.js +1 -0
  181. package/web/dist/assets/format-DrBC7w0A.js +1 -0
  182. package/web/dist/assets/fortran-fixed-form-D6mN0kjy.js +1 -0
  183. package/web/dist/assets/fortran-free-form-CYNrtFtB.js +1 -0
  184. package/web/dist/assets/fsharp-CwoEF39o.js +1 -0
  185. package/web/dist/assets/gdresource-CZkFGo3B.js +1 -0
  186. package/web/dist/assets/gdscript-DYvRD3hg.js +1 -0
  187. package/web/dist/assets/gdshader-CBce3t8t.js +1 -0
  188. package/web/dist/assets/genie-CV2tkWYe.js +1 -0
  189. package/web/dist/assets/gherkin-DExj1W_8.js +1 -0
  190. package/web/dist/assets/git-commit-dUGrvm6Q.js +1 -0
  191. package/web/dist/assets/git-rebase-4zCRqF28.js +1 -0
  192. package/web/dist/assets/github-dark-C-LZuMrd.js +1 -0
  193. package/web/dist/assets/github-dark-default-DXG-b-1a.js +1 -0
  194. package/web/dist/assets/github-dark-dimmed-Bx1FflLF.js +1 -0
  195. package/web/dist/assets/github-dark-high-contrast-B_tTalzw.js +1 -0
  196. package/web/dist/assets/github-light-EUqPIrTm.js +1 -0
  197. package/web/dist/assets/github-light-default-BXViO-2h.js +1 -0
  198. package/web/dist/assets/github-light-high-contrast-B68TUdTA.js +1 -0
  199. package/web/dist/assets/gleam-CSRkHgEL.js +1 -0
  200. package/web/dist/assets/glimmer-js-7adTRvH4.js +1 -0
  201. package/web/dist/assets/glimmer-ts-IdSskDYw.js +1 -0
  202. package/web/dist/assets/glsl-Qzy53KDt.js +1 -0
  203. package/web/dist/assets/gn-CAXYAgV-.js +1 -0
  204. package/web/dist/assets/gnuplot-7GGW24-e.js +1 -0
  205. package/web/dist/assets/go-rLFTqkRN.js +1 -0
  206. package/web/dist/assets/graphql-CV_puxbB.js +1 -0
  207. package/web/dist/assets/groovy-CacY0gHj.js +1 -0
  208. package/web/dist/assets/gruvbox-dark-hard-C820rvS2.js +1 -0
  209. package/web/dist/assets/gruvbox-dark-medium-BPjhmG05.js +1 -0
  210. package/web/dist/assets/gruvbox-dark-soft-MrdJrrXF.js +1 -0
  211. package/web/dist/assets/gruvbox-light-hard-BC_s9l72.js +1 -0
  212. package/web/dist/assets/gruvbox-light-medium-BAWPOn9u.js +1 -0
  213. package/web/dist/assets/gruvbox-light-soft-BSMLrYjP.js +1 -0
  214. package/web/dist/assets/hack-C5GPjiLV.js +1 -0
  215. package/web/dist/assets/haml-BQ5YR1DQ.js +1 -0
  216. package/web/dist/assets/handlebars-DnhRK9A1.js +1 -0
  217. package/web/dist/assets/haskell-D8IpX4py.js +1 -0
  218. package/web/dist/assets/haxe-C8oCnwJJ.js +1 -0
  219. package/web/dist/assets/hcl-Dh228itO.js +1 -0
  220. package/web/dist/assets/highlight.worker-CY-ZeDAl.js +1 -0
  221. package/web/dist/assets/hjson-CxZEssPk.js +1 -0
  222. package/web/dist/assets/hlsl-Cvrh5tZx.js +1 -0
  223. package/web/dist/assets/horizon-CE9ld1lL.js +1 -0
  224. package/web/dist/assets/horizon-bright-DSNQnXHK.js +1 -0
  225. package/web/dist/assets/houston-CsvMBhTu.js +1 -0
  226. package/web/dist/assets/html-CmHiEKV9.js +1 -0
  227. package/web/dist/assets/html-derivative-BXE-rYIK.js +1 -0
  228. package/web/dist/assets/http-DPjjqtcL.js +1 -0
  229. package/web/dist/assets/hurl-AMBpSloO.js +1 -0
  230. package/web/dist/assets/hxml-D7Y24wKF.js +1 -0
  231. package/web/dist/assets/hy-CZbG8q4J.js +1 -0
  232. package/web/dist/assets/imba-DsUTQ-LC.js +1 -0
  233. package/web/dist/assets/index-DNPnl4sh.css +2 -0
  234. package/web/dist/assets/index-DQh72lEx.js +14 -0
  235. package/web/dist/assets/ini-B5eOa1yu.js +1 -0
  236. package/web/dist/assets/java-CEM7Tdw_.js +1 -0
  237. package/web/dist/assets/javascript-CU3PLowd.js +1 -0
  238. package/web/dist/assets/jinja-fR0x_9Xy.js +1 -0
  239. package/web/dist/assets/jison-BoKsxs5M.js +1 -0
  240. package/web/dist/assets/json-BM2FWsRB.js +1 -0
  241. package/web/dist/assets/json5-BR5RXkoi.js +1 -0
  242. package/web/dist/assets/jsonc-CYpm1nAK.js +1 -0
  243. package/web/dist/assets/jsonl-CmCQp5Yx.js +1 -0
  244. package/web/dist/assets/jsonnet-CJTPZ8u_.js +1 -0
  245. package/web/dist/assets/jssm-DXw9l8Rf.js +1 -0
  246. package/web/dist/assets/jsx-B5fTecQP.js +1 -0
  247. package/web/dist/assets/julia-DGyDG39_.js +1 -0
  248. package/web/dist/assets/just-B-RyLcSR.js +1 -0
  249. package/web/dist/assets/kanagawa-dragon-Bozd7klA.js +1 -0
  250. package/web/dist/assets/kanagawa-lotus-BmuOG9ZW.js +1 -0
  251. package/web/dist/assets/kanagawa-wave-BML5mF2J.js +1 -0
  252. package/web/dist/assets/kdl-CsD5j6eV.js +1 -0
  253. package/web/dist/assets/kotlin-DhhofPvG.js +1 -0
  254. package/web/dist/assets/kusto-C7mF5XQf.js +1 -0
  255. package/web/dist/assets/langs-CciPKqaF.js +1 -0
  256. package/web/dist/assets/laserwave-C_8bwKvT.js +1 -0
  257. package/web/dist/assets/latex-CV1pQelm.js +1 -0
  258. package/web/dist/assets/lean-CewbzKMR.js +1 -0
  259. package/web/dist/assets/less-DVTAwKKz.js +1 -0
  260. package/web/dist/assets/lib-DlcVMUqT.js +1 -0
  261. package/web/dist/assets/light-plus-DVQuIRkW.js +1 -0
  262. package/web/dist/assets/liquid-9p05RSzQ.js +1 -0
  263. package/web/dist/assets/llvm-DqHOMS-s.js +1 -0
  264. package/web/dist/assets/log-BNLmms1o.js +1 -0
  265. package/web/dist/assets/logo-Cluzi2Zq.js +1 -0
  266. package/web/dist/assets/lua-CIPVh0S-.js +1 -0
  267. package/web/dist/assets/luau-VGWVLoqX.js +1 -0
  268. package/web/dist/assets/make-Dixweg8N.js +1 -0
  269. package/web/dist/assets/markdown-BYOwaDjH.js +1 -0
  270. package/web/dist/assets/marko-h2h6YUMS.js +1 -0
  271. package/web/dist/assets/material-theme-Bm3Qr25_.js +1 -0
  272. package/web/dist/assets/material-theme-darker-2IIEA8gg.js +1 -0
  273. package/web/dist/assets/material-theme-lighter-uhdI0v04.js +1 -0
  274. package/web/dist/assets/material-theme-ocean-CHQ94UKr.js +1 -0
  275. package/web/dist/assets/material-theme-palenight-B5W6OYN7.js +1 -0
  276. package/web/dist/assets/matlab-D7qyCx1q.js +1 -0
  277. package/web/dist/assets/mdc-yAyZMdoC.js +1 -0
  278. package/web/dist/assets/mdx-DQZ5AkYe.js +1 -0
  279. package/web/dist/assets/mermaid-BxpfTIzt.js +1 -0
  280. package/web/dist/assets/message-font-size-DoaZfwkT.js +1 -0
  281. package/web/dist/assets/min-dark-BSWPekZh.js +1 -0
  282. package/web/dist/assets/min-light-DDpmG2fV.js +1 -0
  283. package/web/dist/assets/mipsasm-BMqwQI7S.js +1 -0
  284. package/web/dist/assets/mojo-fg40_ntQ.js +1 -0
  285. package/web/dist/assets/monokai-BscAjiQZ.js +1 -0
  286. package/web/dist/assets/moonbit-D9W784E_.js +1 -0
  287. package/web/dist/assets/move-BYnGhZoM.js +1 -0
  288. package/web/dist/assets/narrat-_X_XdTYD.js +1 -0
  289. package/web/dist/assets/nextflow-BoTnSBQ_.js +1 -0
  290. package/web/dist/assets/nextflow-groovy-D7IRt6Pp.js +1 -0
  291. package/web/dist/assets/nginx-jWINucNT.js +1 -0
  292. package/web/dist/assets/night-owl-DhmEMT88.js +1 -0
  293. package/web/dist/assets/night-owl-light-eJ-hLW7d.js +1 -0
  294. package/web/dist/assets/nim-Dtt9DZ0t.js +1 -0
  295. package/web/dist/assets/nix-Cl_7024t.js +1 -0
  296. package/web/dist/assets/nord-Cb4Vim4T.js +1 -0
  297. package/web/dist/assets/nsis-CjNLYCLg.js +1 -0
  298. package/web/dist/assets/nushell--0fT3PI1.js +1 -0
  299. package/web/dist/assets/objective-c-D1A_Heim.js +1 -0
  300. package/web/dist/assets/objective-cpp-BsSzOQcm.js +1 -0
  301. package/web/dist/assets/ocaml-O90oeIOV.js +1 -0
  302. package/web/dist/assets/odin-B1RWQWA5.js +1 -0
  303. package/web/dist/assets/one-dark-pro-C6YyR8OD.js +1 -0
  304. package/web/dist/assets/one-light-D7Lr4KcI.js +1 -0
  305. package/web/dist/assets/openscad-BUDT5pXO.js +1 -0
  306. package/web/dist/assets/org-ClD5huOa.js +1 -0
  307. package/web/dist/assets/pascal-4ZHwLPI5.js +1 -0
  308. package/web/dist/assets/perl-BFegxyeJ.js +1 -0
  309. package/web/dist/assets/php-B-qOA3Y4.js +1 -0
  310. package/web/dist/assets/pkl-ot-7Btpt.js +1 -0
  311. package/web/dist/assets/plastic-DQwYfKfQ.js +1 -0
  312. package/web/dist/assets/plsql-DGHpHOYJ.js +1 -0
  313. package/web/dist/assets/po-BiJDBrnU.js +1 -0
  314. package/web/dist/assets/poimandres-DRFjx7u4.js +1 -0
  315. package/web/dist/assets/polar-C7UOKdEL.js +1 -0
  316. package/web/dist/assets/postcss-BXeXVLqQ.js +1 -0
  317. package/web/dist/assets/powerquery-DNMTfnFr.js +1 -0
  318. package/web/dist/assets/powershell-QtSnmXcu.js +1 -0
  319. package/web/dist/assets/prisma-DMgNhnYS.js +1 -0
  320. package/web/dist/assets/prolog-iXnhIJG7.js +1 -0
  321. package/web/dist/assets/proto-DB4EqR-F.js +1 -0
  322. package/web/dist/assets/pug-Cq0NBPu-.js +1 -0
  323. package/web/dist/assets/puppet-CDv2pdJW.js +1 -0
  324. package/web/dist/assets/purescript-9MfHhQsQ.js +1 -0
  325. package/web/dist/assets/python-gzcpVVnB.js +1 -0
  326. package/web/dist/assets/qml-CYUsa87k.js +1 -0
  327. package/web/dist/assets/qmldir-DCQb3MpD.js +1 -0
  328. package/web/dist/assets/qss-Fe1Jh2GI.js +1 -0
  329. package/web/dist/assets/r-4xJhgbOf.js +1 -0
  330. package/web/dist/assets/racket-DcIDlBhZ.js +1 -0
  331. package/web/dist/assets/raku-B3gFvitq.js +1 -0
  332. package/web/dist/assets/razor-BlHaOHx8.js +1 -0
  333. package/web/dist/assets/rbs-C0MpOrj4.js +1 -0
  334. package/web/dist/assets/react-B4UGpcWC.js +1 -0
  335. package/web/dist/assets/red-CYlAq2b0.js +1 -0
  336. package/web/dist/assets/reg-CRGYupPL.js +1 -0
  337. package/web/dist/assets/regexp-BUSxjv2o.js +1 -0
  338. package/web/dist/assets/rel-BtDbiS_P.js +1 -0
  339. package/web/dist/assets/riscv-Ckw8ddFX.js +1 -0
  340. package/web/dist/assets/ron-VUp2lXgN.js +1 -0
  341. package/web/dist/assets/rose-pine-aMsaMD1D.js +1 -0
  342. package/web/dist/assets/rose-pine-dawn-8PwUyIlP.js +1 -0
  343. package/web/dist/assets/rose-pine-moon-DO-qXg-I.js +1 -0
  344. package/web/dist/assets/rosmsg-CAekHB0j.js +1 -0
  345. package/web/dist/assets/rst-zjfguEh7.js +1 -0
  346. package/web/dist/assets/ruby-4oR9waBK.js +1 -0
  347. package/web/dist/assets/rust-DpiIf5JO.js +1 -0
  348. package/web/dist/assets/sas-Do4V_2i9.js +1 -0
  349. package/web/dist/assets/sass-DXrisJhu.js +1 -0
  350. package/web/dist/assets/scala-BiFt_7mu.js +1 -0
  351. package/web/dist/assets/scheme-DQCgrYNe.js +1 -0
  352. package/web/dist/assets/scss-CW6JPtag.js +1 -0
  353. package/web/dist/assets/sdbl-bTVj8UrX.js +1 -0
  354. package/web/dist/assets/shaderlab-C4rnI7x0.js +1 -0
  355. package/web/dist/assets/shellscript-zBmOMFJh.js +1 -0
  356. package/web/dist/assets/shellsession-DxGUTWaf.js +1 -0
  357. package/web/dist/assets/slack-dark-DnToyrRv.js +1 -0
  358. package/web/dist/assets/slack-ochin-B2OO5cIa.js +1 -0
  359. package/web/dist/assets/smalltalk-BHpQb5nM.js +1 -0
  360. package/web/dist/assets/smithy-Dgaz7aur.js +1 -0
  361. package/web/dist/assets/snazzy-light-4G7pJPwS.js +1 -0
  362. package/web/dist/assets/solarized-dark-b97czJOk.js +1 -0
  363. package/web/dist/assets/solarized-light-DFPxpIYQ.js +1 -0
  364. package/web/dist/assets/solidity-Bj7E1mRn.js +1 -0
  365. package/web/dist/assets/soy-DVtw20Yn.js +1 -0
  366. package/web/dist/assets/sparql-C0ia5K60.js +1 -0
  367. package/web/dist/assets/splunk-BC2Px7Mm.js +1 -0
  368. package/web/dist/assets/sql-DGCM-jag.js +1 -0
  369. package/web/dist/assets/ssh-config-BgfXC-Er.js +1 -0
  370. package/web/dist/assets/stata-DfuMOXna.js +1 -0
  371. package/web/dist/assets/stylus-B6D30XZt.js +1 -0
  372. package/web/dist/assets/surrealql-CBoRWxfR.js +1 -0
  373. package/web/dist/assets/svelte-g_uCUem5.js +1 -0
  374. package/web/dist/assets/swift-CyEgAFGc.js +1 -0
  375. package/web/dist/assets/synthwave-84-nFMaYfgc.js +1 -0
  376. package/web/dist/assets/system-verilog-Dh5ihWbf.js +1 -0
  377. package/web/dist/assets/systemd-BxMlprV5.js +1 -0
  378. package/web/dist/assets/talonscript-CohzipZa.js +1 -0
  379. package/web/dist/assets/tasl-DMoTqEGO.js +1 -0
  380. package/web/dist/assets/tcl-CZd0xW_V.js +1 -0
  381. package/web/dist/assets/templ-N5C1hJ4Y.js +1 -0
  382. package/web/dist/assets/terraform-DswuEJGm.js +1 -0
  383. package/web/dist/assets/tex-mx6xDwuK.js +1 -0
  384. package/web/dist/assets/themes-CNElGaXw.js +1 -0
  385. package/web/dist/assets/tokyo-night-oM2G3aXe.js +1 -0
  386. package/web/dist/assets/toml-CcmNWLt0.js +1 -0
  387. package/web/dist/assets/ts-tags-C-j71FRb.js +1 -0
  388. package/web/dist/assets/tsv-sltzmVWM.js +1 -0
  389. package/web/dist/assets/tsx-z04y7qR9.js +1 -0
  390. package/web/dist/assets/turtle-ByJddavk.js +1 -0
  391. package/web/dist/assets/twig-Bz57G_nl.js +1 -0
  392. package/web/dist/assets/typescript-RMqVTmzR.js +1 -0
  393. package/web/dist/assets/typespec-BGhR2SqG.js +1 -0
  394. package/web/dist/assets/typst-BgkqA2Pg.js +1 -0
  395. package/web/dist/assets/v-DBj4K9d_.js +1 -0
  396. package/web/dist/assets/vala-zf12oZj6.js +1 -0
  397. package/web/dist/assets/vb-DOwzaHZ0.js +1 -0
  398. package/web/dist/assets/verilog-B2gwz-sJ.js +1 -0
  399. package/web/dist/assets/vesper-DdrHHSXu.js +1 -0
  400. package/web/dist/assets/vhdl-BroJfC0k.js +1 -0
  401. package/web/dist/assets/viml-DvXPmvsu.js +1 -0
  402. package/web/dist/assets/vitesse-black-fwtXNY1n.js +1 -0
  403. package/web/dist/assets/vitesse-dark-BZCL-v6S.js +1 -0
  404. package/web/dist/assets/vitesse-light-VbXTXTou.js +1 -0
  405. package/web/dist/assets/vue-CQgvQytb.js +1 -0
  406. package/web/dist/assets/vue-html-Dhl6fh9l.js +1 -0
  407. package/web/dist/assets/vue-vine-Dw_uU59K.js +1 -0
  408. package/web/dist/assets/vyper-CgoNMtux.js +1 -0
  409. package/web/dist/assets/wasm-ByWQv1Qj.js +1 -0
  410. package/web/dist/assets/wenyan-C8pVoKbM.js +1 -0
  411. package/web/dist/assets/wgsl-BsKzXJz4.js +1 -0
  412. package/web/dist/assets/wikitext-ClFFjSW2.js +1 -0
  413. package/web/dist/assets/wit-DdvCle-K.js +1 -0
  414. package/web/dist/assets/wolfram-DLL8P-h_.js +1 -0
  415. package/web/dist/assets/xml-B49klYQ3.js +1 -0
  416. package/web/dist/assets/xsl-D7tnD3qq.js +1 -0
  417. package/web/dist/assets/yaml-DNQ5_xkL.js +1 -0
  418. package/web/dist/assets/zenscript-BnlCZFoB.js +1 -0
  419. package/web/dist/assets/zig-CMLA9XwU.js +1 -0
  420. package/web/dist/icons/apple-touch-icon.png +0 -0
  421. package/web/dist/icons/badge-96.png +0 -0
  422. package/web/dist/icons/icon-192.png +0 -0
  423. package/web/dist/icons/icon-512.png +0 -0
  424. package/web/dist/icons/icon.svg +4 -0
  425. package/web/dist/icons/maskable-192.png +0 -0
  426. package/web/dist/icons/maskable-512.png +0 -0
  427. package/web/dist/index.html +30 -0
  428. package/web/dist/manifest.webmanifest +20 -0
  429. package/web/dist/sw.js +176 -0
  430. package/web/dist/version.json +1 -0
  431. package/web/src/App.tsx +97 -0
  432. package/web/src/agent-history-flow.test.ts +191 -0
  433. package/web/src/agent-history-flow.ts +58 -0
  434. package/web/src/agent-owners.ts +30 -0
  435. package/web/src/annotation-selection.test.ts +36 -0
  436. package/web/src/annotation-selection.ts +123 -0
  437. package/web/src/annotations.test.ts +279 -0
  438. package/web/src/annotations.ts +191 -0
  439. package/web/src/api.ts +27 -0
  440. package/web/src/auth-events.ts +11 -0
  441. package/web/src/auth-lifecycle.test.ts +105 -0
  442. package/web/src/clipboard.ts +32 -0
  443. package/web/src/components/ActivityNotifier.tsx +22 -0
  444. package/web/src/components/AnnotationEditor.tsx +135 -0
  445. package/web/src/components/AnnotationSelection.tsx +122 -0
  446. package/web/src/components/Automation.tsx +390 -0
  447. package/web/src/components/CodeView.tsx +121 -0
  448. package/web/src/components/Composer.tsx +552 -0
  449. package/web/src/components/ComposerAnnotations.tsx +45 -0
  450. package/web/src/components/Confirmation.tsx +91 -0
  451. package/web/src/components/CopyButton.tsx +23 -0
  452. package/web/src/components/DiffView.tsx +94 -0
  453. package/web/src/components/DirectoryPicker.tsx +230 -0
  454. package/web/src/components/FileCopyMenu.tsx +58 -0
  455. package/web/src/components/FileEntryActions.tsx +95 -0
  456. package/web/src/components/ImagePreview.tsx +68 -0
  457. package/web/src/components/Items.tsx +608 -0
  458. package/web/src/components/Markdown.tsx +73 -0
  459. package/web/src/components/MessageList.tsx +458 -0
  460. package/web/src/components/Modal.tsx +72 -0
  461. package/web/src/components/NotificationEntry.tsx +31 -0
  462. package/web/src/components/NotificationSettings.tsx +226 -0
  463. package/web/src/components/NotificationToasts.tsx +59 -0
  464. package/web/src/components/OpenTabs.tsx +112 -0
  465. package/web/src/components/Pending.tsx +175 -0
  466. package/web/src/components/ProjectExtras.tsx +299 -0
  467. package/web/src/components/ProjectNav.tsx +47 -0
  468. package/web/src/components/SessionActions.tsx +271 -0
  469. package/web/src/components/SessionChannels.tsx +288 -0
  470. package/web/src/components/SessionExtras.tsx +263 -0
  471. package/web/src/components/SettingsLink.tsx +21 -0
  472. package/web/src/components/Shell.tsx +320 -0
  473. package/web/src/components/SvgPreview.tsx +18 -0
  474. package/web/src/components/TodoPanel.tsx +37 -0
  475. package/web/src/components/VersionNotice.tsx +40 -0
  476. package/web/src/components/icons.tsx +43 -0
  477. package/web/src/diff.ts +62 -0
  478. package/web/src/drafts.test.ts +80 -0
  479. package/web/src/drafts.ts +64 -0
  480. package/web/src/format.ts +5 -0
  481. package/web/src/highlight.worker.ts +49 -0
  482. package/web/src/hooks.ts +59 -0
  483. package/web/src/item-view-state.test.ts +51 -0
  484. package/web/src/item-view-state.ts +43 -0
  485. package/web/src/live-history-flow.test.ts +77 -0
  486. package/web/src/live-merge.test.ts +64 -0
  487. package/web/src/live-merge.ts +50 -0
  488. package/web/src/live-message-hydration.test.ts +253 -0
  489. package/web/src/live.ts +404 -0
  490. package/web/src/main.tsx +27 -0
  491. package/web/src/markdown-assets.test.ts +70 -0
  492. package/web/src/markdown-assets.ts +78 -0
  493. package/web/src/markdown-html.test.ts +84 -0
  494. package/web/src/markdown-html.ts +60 -0
  495. package/web/src/markdown-svg.test.ts +37 -0
  496. package/web/src/markdown-svg.ts +42 -0
  497. package/web/src/markdown-tables.test.ts +34 -0
  498. package/web/src/markdown-tables.ts +17 -0
  499. package/web/src/message-bodies.ts +117 -0
  500. package/web/src/message-cache.test.ts +208 -0
  501. package/web/src/message-cache.ts +158 -0
  502. package/web/src/message-font-size.test.ts +41 -0
  503. package/web/src/message-font-size.ts +57 -0
  504. package/web/src/message-time.test.ts +32 -0
  505. package/web/src/message-time.ts +26 -0
  506. package/web/src/notify.ts +132 -0
  507. package/web/src/open-tabs.test.ts +69 -0
  508. package/web/src/open-tabs.ts +110 -0
  509. package/web/src/pages/AgentView.tsx +138 -0
  510. package/web/src/pages/ChangesView.tsx +193 -0
  511. package/web/src/pages/FilesView.tsx +406 -0
  512. package/web/src/pages/HomePage.tsx +96 -0
  513. package/web/src/pages/LoginPage.tsx +56 -0
  514. package/web/src/pages/OverviewPage.tsx +124 -0
  515. package/web/src/pages/ProjectHome.tsx +136 -0
  516. package/web/src/pages/SessionView.tsx +238 -0
  517. package/web/src/pages/WorktreesView.tsx +197 -0
  518. package/web/src/pages/settings/AccountPage.tsx +149 -0
  519. package/web/src/pages/settings/AgentsPage.tsx +182 -0
  520. package/web/src/pages/settings/ConfigPage.tsx +181 -0
  521. package/web/src/pages/settings/GeneralPage.tsx +27 -0
  522. package/web/src/pages/settings/HooksPage.tsx +244 -0
  523. package/web/src/pages/settings/McpPage.tsx +310 -0
  524. package/web/src/pages/settings/MemoryPage.tsx +309 -0
  525. package/web/src/pages/settings/PermissionsPage.tsx +160 -0
  526. package/web/src/pages/settings/PluginsPage.tsx +251 -0
  527. package/web/src/pages/settings/SettingsPage.tsx +141 -0
  528. package/web/src/pages/settings/SkillsPage.tsx +142 -0
  529. package/web/src/pages/settings/ui.tsx +165 -0
  530. package/web/src/preference-document.ts +133 -0
  531. package/web/src/project-actions.ts +18 -0
  532. package/web/src/project-files-state.test.ts +49 -0
  533. package/web/src/project-files-state.ts +64 -0
  534. package/web/src/project-images.ts +13 -0
  535. package/web/src/pwa.ts +33 -0
  536. package/web/src/queryClient.ts +5 -0
  537. package/web/src/reasoning-preference.test.ts +39 -0
  538. package/web/src/reasoning-preference.ts +42 -0
  539. package/web/src/session-confirmations.ts +36 -0
  540. package/web/src/stream-replay.test.ts +163 -0
  541. package/web/src/styles.css +231 -0
  542. package/web/src/tool-result-body.test.ts +115 -0
  543. package/web/src/transcript.test.ts +186 -0
  544. package/web/src/transcript.ts +583 -0
  545. package/web/src/turns.test.ts +338 -0
  546. package/web/src/turns.ts +178 -0
  547. package/web/src/ui/Button.tsx +60 -0
  548. package/web/src/ui/Controls.tsx +227 -0
  549. package/web/src/ui/Form.tsx +203 -0
  550. package/web/src/ui/MenuPopover.tsx +144 -0
  551. package/web/src/ui/Popover.tsx +147 -0
  552. package/web/src/ui/ResizablePane.tsx +110 -0
  553. package/web/src/ui/Select.tsx +150 -0
  554. package/web/src/ui/icons.tsx +270 -0
  555. package/web/src/unsaved.tsx +99 -0
  556. package/web/src/user-text.test.ts +60 -0
  557. package/web/src/user-text.ts +35 -0
  558. package/web/src/uuid.ts +12 -0
  559. package/README.md +0 -3
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Settings pages (M6): memory, permissions, MCP, plugins, skills, hooks, agents,
3
+ * settings and account. Everything is read from / written to the CLI's own files
4
+ * or `claude` subcommands; these are only the wire shapes.
5
+ */
6
+
7
+ /** Settings layers the web edits (managed/policy settings are read-only and not listed). */
8
+ export type SettingsScope = "user" | "project" | "local";
9
+ export const SCOPE_LABEL: Record<SettingsScope, string> = { user: "用户", project: "项目(共享)", local: "项目(本地)" };
10
+
11
+ export type ScopeFile = { scope: SettingsScope; path: string; exists: boolean };
12
+
13
+ // ---------- memory ----------
14
+
15
+ export type MemoryKind = "user" | "user-rule" | "project" | "project-rule" | "local" | "auto" | "other";
16
+
17
+ export type MemoryFile = {
18
+ kind: MemoryKind;
19
+ path: string;
20
+ /** Short label, e.g. "~/.claude/CLAUDE.md" or "MEMORY.md" */
21
+ label: string;
22
+ exists: boolean;
23
+ size?: number;
24
+ mtime?: number;
25
+ };
26
+
27
+ export type MemoryListing = {
28
+ files: MemoryFile[];
29
+ /** Directories where new files may be created (rules dirs, auto-memory dir) */
30
+ dirs: { kind: MemoryKind; path: string; label: string }[];
31
+ autoMemory: { enabled: boolean; dir: string | null; scope: SettingsScope | null };
32
+ };
33
+
34
+ export type TextFile = { path: string; content: string; mtime: number };
35
+
36
+ // ---------- permissions ----------
37
+
38
+ export type PermissionKind = "allow" | "deny" | "ask" | "additionalDirectories";
39
+ export const PERMISSION_KINDS: PermissionKind[] = ["allow", "deny", "ask", "additionalDirectories"];
40
+
41
+ export type PermissionLayer = ScopeFile & { lists: Record<PermissionKind, string[]> };
42
+
43
+ export type PermissionOp =
44
+ | { scope: SettingsScope; kind: PermissionKind; op: "add"; value: string }
45
+ | { scope: SettingsScope; kind: PermissionKind; op: "remove"; value: string }
46
+ | { scope: SettingsScope; kind: PermissionKind; op: "replace"; old: string; value: string };
47
+
48
+ // ---------- hooks ----------
49
+
50
+ export type HookCommand = { type: string; command?: string; timeout?: number; [k: string]: unknown };
51
+ export type HookGroup = { matcher?: string; hooks: HookCommand[] };
52
+ export type HookLayer = ScopeFile & { hooks: Record<string, HookGroup[]> };
53
+ export type HookEventInfo = { name: string; summary: string; supportsMatcher: boolean };
54
+ export type HooksListing = {
55
+ layers: HookLayer[];
56
+ events: HookEventInfo[];
57
+ /** Hooks from sources the web does not edit (plugins, managed policy) */
58
+ readonly: { event: string; matcher?: string; source: string; label: string; text: string }[];
59
+ };
60
+
61
+ export type HookOp =
62
+ | { scope: SettingsScope; op: "add"; event: string; matcher?: string; hook: HookCommand }
63
+ | { scope: SettingsScope; op: "remove"; event: string; group: number; index: number }
64
+ | { scope: SettingsScope; op: "replace"; event: string; group: number; index: number; matcher?: string; hook: HookCommand };
65
+
66
+ // ---------- settings (/config) ----------
67
+
68
+ export type SettingsLayer = ScopeFile & { settings: Record<string, unknown> };
69
+ export type SettingsInfo = {
70
+ layers: SettingsLayer[];
71
+ effective: Record<string, unknown>;
72
+ outputStyles: string[];
73
+ models: { value: string; displayName: string; description?: string }[];
74
+ };
75
+
76
+ // ---------- agents ----------
77
+
78
+ export type AgentFile = {
79
+ scope: "user" | "project";
80
+ /** File name without .md */
81
+ file: string;
82
+ path: string;
83
+ name: string;
84
+ description: string;
85
+ tools: string;
86
+ model: string;
87
+ /** Other frontmatter keys, kept verbatim */
88
+ extra: string;
89
+ prompt: string;
90
+ mtime: number;
91
+ };
92
+
93
+ export type AgentInput = {
94
+ scope: "user" | "project";
95
+ /** Existing file name when editing; omitted when creating */
96
+ file?: string;
97
+ name: string;
98
+ description: string;
99
+ tools: string;
100
+ model: string;
101
+ prompt: string;
102
+ };
103
+
104
+ // ---------- MCP ----------
105
+
106
+ export type McpServer = {
107
+ name: string;
108
+ /** local / project / user from config; plugin / claudeai / dynamic etc. are read-only */
109
+ scope: string;
110
+ status: string;
111
+ error?: string;
112
+ config: Record<string, unknown>;
113
+ editable: boolean;
114
+ };
115
+
116
+ export type McpAddInput = {
117
+ name: string;
118
+ scope: SettingsScope;
119
+ transport: "stdio" | "http" | "sse";
120
+ command?: string;
121
+ args?: string[];
122
+ env?: Record<string, string>;
123
+ url?: string;
124
+ headers?: Record<string, string>;
125
+ };
126
+
127
+ export type McpAuthStart = { flowId: string; authUrl: string | null; requiresUserAction: boolean; callbackPort?: number };
128
+
129
+ // ---------- plugins & skills ----------
130
+
131
+ export type InstalledPlugin = {
132
+ id: string;
133
+ version?: string;
134
+ scope: string;
135
+ enabled: boolean;
136
+ installPath?: string;
137
+ description?: string;
138
+ };
139
+
140
+ export type Marketplace = { name: string; source?: string; repo?: string; url?: string; path?: string; installLocation?: string };
141
+
142
+ export type AvailablePlugin = { pluginId: string; name: string; description?: string; marketplaceName: string; installCount?: number };
143
+
144
+ export type PluginListing = { installed: InstalledPlugin[]; marketplaces: Marketplace[] };
145
+
146
+ /** Result of a plugin command; `confirm` is set when the marketplace declares a command to run. */
147
+ export type PluginActionResult = {
148
+ ok: boolean;
149
+ message: string;
150
+ confirm?: { sha256: string; command: unknown; kind?: string };
151
+ };
152
+
153
+ export type SkillInfo = {
154
+ name: string;
155
+ source: string;
156
+ description: string;
157
+ path: string | null;
158
+ state?: string;
159
+ plugin?: string;
160
+ };
161
+
162
+ // ---------- account ----------
163
+
164
+ export type RateWindow = { utilization: number | null; resetsAt: string | null };
165
+
166
+ export type AccountStatus = {
167
+ auth: { loggedIn: boolean; authMethod?: string; email?: string; orgName?: string; subscriptionType?: string; raw: Record<string, unknown> } | null;
168
+ account: Record<string, unknown> | null;
169
+ version: string | null;
170
+ model: string | null;
171
+ usage: { fiveHour: RateWindow | null; sevenDay: RateWindow | null; extra: { label: string; utilization: number | null; resetsAt: string | null }[] } | null;
172
+ status: { title: string; rows: { label: string; value: string }[] }[];
173
+ configDir: string;
174
+ errors: string[];
175
+ };
@@ -0,0 +1,12 @@
1
+ /** Directories on the server, including paths not yet registered as projects. */
2
+ export type DirectoryListing = {
3
+ path: string;
4
+ parent: string | null;
5
+ home: string;
6
+ entries: { name: string; path: string; type?: "dir" | "file" }[];
7
+ truncated: boolean;
8
+ /** Completion keeps the typed target separate from the directory being listed. */
9
+ requestedPath?: string;
10
+ requestedType?: "dir" | "file" | "missing";
11
+ prefix?: string;
12
+ };
@@ -0,0 +1,51 @@
1
+ /** REST shapes for the project file browser and git change views. */
2
+
3
+ export type DirEntry = {
4
+ name: string;
5
+ /** Path relative to the project root, forward slashes */
6
+ path: string;
7
+ type: "dir" | "file" | "other";
8
+ size?: number;
9
+ /** Matched by .gitignore (still viewable, shown dimmed) */
10
+ ignored?: boolean;
11
+ /** Entry is a symlink */
12
+ link?: boolean;
13
+ /** Symlink whose target is outside the project (not openable) */
14
+ outside?: boolean;
15
+ };
16
+
17
+ export type DirListing = { path: string; entries: DirEntry[]; truncated: boolean; git: boolean };
18
+
19
+ export type FileContent = {
20
+ path: string;
21
+ size: number;
22
+ /** Only a preview was returned (normally the first 1 MiB). */
23
+ truncated: boolean;
24
+ binary: boolean;
25
+ content?: string;
26
+ };
27
+
28
+ export type FileMatch = { path: string; score: number };
29
+
30
+ /** `start`/`end` are string indices of the first hit within `text`. */
31
+ export type ContentMatch = { path: string; line: number; text: string; start?: number; end?: number };
32
+
33
+ /** Display status: M modified, A added, D deleted, U conflict, ?? untracked. */
34
+ export type ChangeStatus = "M" | "A" | "D" | "U" | "??";
35
+
36
+ export type GitChange = { path: string; status: ChangeStatus; staged: boolean; unstaged: boolean };
37
+
38
+ export type GitStatus = { isRepo: false } | { isRepo: true; branch: string | null; changes: GitChange[] };
39
+
40
+ export type GitDiff = { path: string; status: ChangeStatus | null; diff: string; truncated: boolean };
41
+
42
+ export const IMAGE_EXTENSIONS = [".png", ".jpg", ".jpeg", ".gif", ".webp", ".avif", ".bmp", ".ico", ".svg"];
43
+ export const AUDIO_TYPES: Record<string, string> = {
44
+ ".mp3": "audio/mpeg", ".wav": "audio/wav", ".wave": "audio/wav", ".ogg": "audio/ogg", ".oga": "audio/ogg",
45
+ ".opus": "audio/ogg", ".m4a": "audio/mp4", ".aac": "audio/aac", ".flac": "audio/flac", ".weba": "audio/webm",
46
+ ".aif": "audio/aiff", ".aiff": "audio/aiff",
47
+ };
48
+
49
+ export const MAX_UPLOAD_BYTES = 50 * 1024 * 1024;
50
+ export const MAX_UPLOAD_FILES = 100;
51
+ export type UploadResult = { files: string[]; conflicts: string[] };
@@ -0,0 +1,63 @@
1
+ export const HTTP_CHANNEL_LIMIT = 32;
2
+ export const HTTP_INBOX_LIMIT = 1024;
3
+
4
+ export type HttpChannelDirection = "subscribe" | "push";
5
+ export type HttpSourceKind = "http" | "brain-api";
6
+ export type HttpSubscribeMethod = "GET" | "POST";
7
+ export type HttpTextMessage = { kind: "text"; id: string; text: string };
8
+ export type HttpPollResponse = { kind: "empty" } | { kind: "text"; id?: string; text: string };
9
+ export type HttpPushMessage = HttpTextMessage & { sessionId: string };
10
+ export type HttpJsonValue = string | number | boolean | null | HttpJsonValue[] | { [key: string]: HttpJsonValue };
11
+ export type HttpExtraBody = Record<string, HttpJsonValue>;
12
+
13
+ export type HttpSource = {
14
+ id: string;
15
+ kind: HttpSourceKind;
16
+ brainId: string | null;
17
+ brainVoice: string | null;
18
+ name: string;
19
+ url: string;
20
+ timeoutMs: number;
21
+ subscribeMethod: HttpSubscribeMethod;
22
+ hasHeaders: boolean;
23
+ hasExtraBody: boolean;
24
+ };
25
+ export type HttpSourceInput = { name?: string; url: string; kind?: HttpSourceKind; brainId?: string | null; brainVoice?: string | null; timeoutMs?: number; subscribeMethod?: HttpSubscribeMethod; headers?: Record<string, string>; extraBody?: HttpExtraBody };
26
+ /** Loaded explicitly when editing; the general source listing omits header values. */
27
+ export type HttpSourceDetails = HttpSource & { headers: Record<string, string>; extraBody: HttpExtraBody };
28
+ /** null inherits the source; an empty voice explicitly suppresses its header. */
29
+ export type HttpBindingOverrides = { brainId?: string | null; brainVoice?: string | null };
30
+ export type HttpChannelStats = {
31
+ requests: number;
32
+ delivered: number;
33
+ received: number;
34
+ pushed: number;
35
+ duplicates: number;
36
+ dropped: number;
37
+ pending: number;
38
+ lastSuccessAt?: number;
39
+ lastError?: string;
40
+ lastPullError?: string;
41
+ lastPushError?: string;
42
+ };
43
+ export type HttpChannelBinding = {
44
+ id: string;
45
+ sessionId: string;
46
+ projectId: string;
47
+ sourceId: string;
48
+ direction: HttpChannelDirection;
49
+ brainId: string | null;
50
+ brainVoice: string | null;
51
+ active: boolean;
52
+ activatedAt: number | null;
53
+ inactiveReason: string | null;
54
+ stats: HttpChannelStats | null;
55
+ };
56
+ export type HttpChannelsInfo = {
57
+ sources: HttpSource[];
58
+ bindings: HttpChannelBinding[];
59
+ activeCount: number;
60
+ activeLimit: number;
61
+ inboxSize: number;
62
+ inboxLimit: number;
63
+ };
@@ -0,0 +1,189 @@
1
+ import type { LiveEvent, SdkMessageLike, SeqEvent } from "./protocol.ts";
2
+
3
+ export const MESSAGE_LIMIT = 1500;
4
+ export const SESSION_BYTES = 40 * 1024 * 1024;
5
+ export const TOTAL_BYTES = 120 * 1024 * 1024;
6
+ export const SESSION_LIMIT = 5;
7
+ export const PAGE_LIMIT = 100;
8
+ export const PAGE_BYTES = 512 * 1024;
9
+
10
+ /** Approximate retained string payload, not a promise about the JS heap. */
11
+ export function contentBytes(value: unknown): number {
12
+ if (typeof value === "string") return value.length * 2;
13
+ if (!value || typeof value !== "object") return 16;
14
+ if (Array.isArray(value)) return value.reduce((n, v) => n + contentBytes(v), 24);
15
+ return Object.entries(value).reduce((n, [k, v]) => n + k.length * 2 + contentBytes(v), 32);
16
+ }
17
+
18
+ const displaySizes = new WeakMap<object, number>();
19
+
20
+ /** Large records stay in JSONL; a display placeholder can be hydrated explicitly. */
21
+ export function displayMessage(m: SdkMessageLike, bytes?: number): SdkMessageLike {
22
+ if (m._deferred || m._hydrated) return m;
23
+ if (bytes === undefined) {
24
+ bytes = displaySizes.get(m);
25
+ if (bytes === undefined) { bytes = contentBytes(m); displaySizes.set(m, bytes); }
26
+ }
27
+ if (bytes <= PAGE_BYTES / 2) return m;
28
+ let nodes = 0;
29
+ let chars = 0;
30
+ const preview = (v: unknown): unknown => {
31
+ if (++nodes > 256) return "…";
32
+ if (typeof v === "string") { const text = v.slice(0, Math.min(2000, Math.max(0, 16000 - chars))); chars += text.length; return text; }
33
+ if (Array.isArray(v)) return v.slice(0, 20).map(preview);
34
+ if (!v || typeof v !== "object") return v;
35
+ return Object.fromEntries(Object.entries(v).filter(([k]) => k !== "data").slice(0, 30).map(([k, v]) => [k, preview(v)]));
36
+ };
37
+ // Completed shell XML may be clipped in the middle of its command. Retain a
38
+ // bounded structured preview so completion and output do not depend on parsing it.
39
+ const payload = (m.message as { content?: unknown } | undefined)?.content;
40
+ const text = typeof payload === "string" ? payload : Array.isArray(payload)
41
+ ? (payload.find((b) => b?.type === "text") as { text?: string } | undefined)?.text : undefined;
42
+ const shell = m.type === "user" && typeof text === "string"
43
+ ? /^\s*<bash-input>([\s\S]*?)<\/bash-input>\s*<bash-stdout>([\s\S]*?)<\/bash-stdout><bash-stderr>([\s\S]*?)<\/bash-stderr>/.exec(text) : null;
44
+ // Presentation payloads may be abbreviated; lifecycle and attribution must survive.
45
+ const controlKeys = ["session_id", "parent_agent_id", "timestamp", "isCompactSummary", "isQueuedCommand", "isCompletedLocalCommand", "is_meta", "error", "aborted",
46
+ "is_error", "total_cost_usd", "turn_cost_usd", "duration_ms", "duration_api_ms", "num_turns", "user_message_uuids",
47
+ "task_id", "tool_use_id", "parent_task_id", "spawn_depth", "run_id", "status", "subagent_type", "is_backgrounded", "task_type", "patch", "usage", "_streamBlocks", "_streamThinking"];
48
+ const controls = Object.fromEntries(controlKeys.filter((key) => m[key] !== undefined).map((key) => [key, m[key]]));
49
+ if (m.errors !== undefined) controls.errors = preview(m.errors);
50
+ if (m.description !== undefined) controls.description = preview(m.description);
51
+ if (m.summary !== undefined) controls.summary = preview(m.summary);
52
+ return { type: m.type, subtype: m.subtype, uuid: m.uuid, parent_tool_use_id: m.parent_tool_use_id,
53
+ ...controls, ...(shell ? { _bash: { command: shell[1]!.slice(0, 2000), stdout: shell[2]!.slice(0, 2000), stderr: shell[3]!.slice(0, 2000) } } : {}), message: preview(m.message), content: preview(m.content), _deferred: { bytes } };
54
+ }
55
+
56
+ export function displayEvent(ev: LiveEvent): LiveEvent {
57
+ if (ev.k === "sdk") return { ...ev, m: displayMessage(ev.m) };
58
+ if (ev.k === "user" && contentBytes(ev) > PAGE_BYTES / 2) {
59
+ return { k: "sdk", m: displayMessage({ type: "user", uuid: ev.uuid, message: { role: "user", content: [
60
+ ...(ev.imageData ?? []).map((i) => ({ type: "image", source: { media_type: i.mediaType, data: i.data } })),
61
+ { type: "text", text: ev.text },
62
+ ] } }) };
63
+ }
64
+ // Deltas are accumulated before trimming; truncating individual fragments loses their middle.
65
+ return ev;
66
+ }
67
+
68
+ export function eventUuid(ev: LiveEvent): string | undefined {
69
+ return ev.k === "sdk" ? ev.m.uuid : ev.k === "user" || ev.k === "bash" ? ev.uuid : undefined;
70
+ }
71
+
72
+ type Delta = Extract<LiveEvent, { k: "delta" }>;
73
+ const streamKey = (d: Delta) => `${d.parent ?? ""}:${d.msgId}:${d.index}`;
74
+ const STREAM_BYTES = SESSION_BYTES / 4;
75
+ const STREAM_BLOCK_CHARS = SESSION_BYTES / 16;
76
+ type StreamSettlement = { indexes: number[]; thinking: Record<number, number> };
77
+
78
+ /** Cumulative previews of unfinished blocks, independent of the replay ring buffer. */
79
+ export class StreamingReplay {
80
+ private pending = new Map<string, SeqEvent & { ev: Delta }>();
81
+ private completed = new Set<string>();
82
+ private settled = new Set<string>();
83
+ private bytes = 0;
84
+
85
+ clear() { this.pending.clear(); this.completed.clear(); this.settled.clear(); this.bytes = 0; }
86
+ get checkpoints(): SeqEvent[] { return [...this.pending.values()]; }
87
+
88
+ push(event: SeqEvent): StreamSettlement {
89
+ const settled: StreamSettlement = { indexes: [], thinking: {} };
90
+ const ev = event.ev;
91
+ if (ev.k === "reset") { this.clear(); return settled; }
92
+ if (ev.k === "delta") {
93
+ const key = streamKey(ev);
94
+ if (this.settled.has(key)) return settled;
95
+ const previous = this.pending.get(key);
96
+ const prefix = ev.checkpoint ? "" : previous?.ev.text ?? "";
97
+ const oldBytes = previous?.ev.text.length ? previous.ev.text.length * 2 : 0;
98
+ const available = Math.max(0, (STREAM_BYTES - this.bytes + oldBytes) / 2);
99
+ const limit = Math.min(STREAM_BLOCK_CHARS, available);
100
+ const text = prefix.length >= limit ? prefix.slice(0, limit) : prefix + ev.text.slice(0, limit - prefix.length);
101
+ const truncated = !!ev.truncated || !!previous?.ev.truncated && !ev.checkpoint || prefix.length + ev.text.length > limit;
102
+ this.bytes += text.length * 2 - oldBytes;
103
+ this.pending.set(key, { seq: event.seq, ev: { ...ev, text, checkpoint: true, ...(truncated ? { truncated: true } : {}) } });
104
+ // One CLI can only stream a small number of blocks concurrently. Bound identities as well as text.
105
+ while (this.pending.size > 128) this.remove(this.pending.keys().next().value!);
106
+ } else if (ev.k === "sdk" && ev.m.type === "assistant") {
107
+ if (ev.m.uuid) {
108
+ if (this.completed.has(ev.m.uuid)) return settled;
109
+ this.completed.add(ev.m.uuid);
110
+ if (this.completed.size > 5000) this.completed.delete(this.completed.values().next().value!);
111
+ }
112
+ const message = ev.m.message as { id?: string; content?: { type?: string }[] } | undefined;
113
+ if (!message?.id || !Array.isArray(message.content)) return settled;
114
+ const indexes = Array.isArray(ev.m._streamBlocks) ? ev.m._streamBlocks.filter((index): index is number => typeof index === "number") : [];
115
+ settled.indexes = indexes;
116
+ if (indexes.length) {
117
+ for (const index of indexes) this.settle(`${ev.m.parent_tool_use_id ?? ""}:${message.id}:${index}`);
118
+ // This metadata was already established before an earlier compaction.
119
+ if (ev.m._streamThinking) settled.thinking = ev.m._streamThinking as Record<number, number>;
120
+ return settled;
121
+ }
122
+ for (const [blockIndex, block] of message.content.entries()) {
123
+ if (block.type !== "text" && block.type !== "thinking") continue;
124
+ const match = [...this.pending].filter(([, d]) => d.ev.msgId === message.id && d.ev.parent === (ev.m.parent_tool_use_id ?? null) && d.ev.kind === block.type)
125
+ .sort((a, b) => a[1].ev.index - b[1].ev.index)[0];
126
+ if (match) {
127
+ indexes.push(match[1].ev.index);
128
+ if (block.type === "thinking") settled.thinking[blockIndex] = match[1].ev.index;
129
+ this.settle(match[0]);
130
+ }
131
+ }
132
+ return settled;
133
+ } else if (ev.k === "sdk" && ev.m.type === "result") {
134
+ for (const [key, d] of this.pending) if (d.ev.parent === (ev.m.parent_tool_use_id ?? null)) this.remove(key);
135
+ }
136
+ return settled;
137
+ }
138
+
139
+ private settle(key: string) {
140
+ this.remove(key);
141
+ this.settled.add(key);
142
+ if (this.settled.size > 5000) this.settled.delete(this.settled.values().next().value!);
143
+ }
144
+
145
+ private remove(key: string) {
146
+ const entry = this.pending.get(key);
147
+ if (entry) this.bytes -= entry.ev.text.length * 2;
148
+ this.pending.delete(key);
149
+ }
150
+ }
151
+
152
+ /** Fold streaming fragments before any count/byte slice; active prefixes are reserved at the end. */
153
+ export function compactReplayEvents(events: SeqEvent[], checkpoints: SeqEvent[] = []): SeqEvent[] {
154
+ const streaming = new StreamingReplay();
155
+ const out: SeqEvent[] = [];
156
+ if (checkpoints.length) {
157
+ const replaced = new Set(checkpoints.flatMap(({ ev }) => ev.k === "delta" ? [streamKey(ev)] : []));
158
+ // A checkpoint already includes every raw fragment up to its seq. Keep its real
159
+ // position relative to completion frames, including frames still in the ring.
160
+ events = [...events.filter(({ ev }) => ev.k !== "delta" || !replaced.has(streamKey(ev))), ...checkpoints].sort((a, b) => a.seq - b.seq);
161
+ }
162
+ for (const event of events) {
163
+ const settled = streaming.push(event);
164
+ if (event.ev.k !== "delta") out.push(event.ev.k === "sdk" && settled.indexes.length && !event.ev.m._streamBlocks
165
+ ? { ...event, ev: { ...event.ev, m: { ...event.ev.m, _streamBlocks: settled.indexes,
166
+ ...(Object.keys(settled.thinking).length ? { _streamThinking: settled.thinking } : {}) } } } : event);
167
+ }
168
+ return [...out, ...streaming.checkpoints];
169
+ }
170
+
171
+ export function compactStreamEvents(events: LiveEvent[]): LiveEvent[] {
172
+ return compactReplayEvents(events.map((ev, seq) => ({ seq, ev }))).map((entry) => entry.ev);
173
+ }
174
+
175
+ /** Never bootstrap the browser with the entire 5,000-event server replay buffer. */
176
+ export function boundedReplay(events: SeqEvent[], checkpoints: SeqEvent[] = []): SeqEvent[] {
177
+ events = compactReplayEvents(events, checkpoints);
178
+ const out: SeqEvent[] = [];
179
+ let bytes = 0;
180
+ for (let i = events.length - 1; i >= 0 && out.length < MESSAGE_LIMIT; i--) {
181
+ const e = events[i]!;
182
+ const ev = displayEvent(e.ev);
183
+ const size = contentBytes(ev);
184
+ if (bytes + size > SESSION_BYTES / 2) break;
185
+ out.push({ seq: e.seq, ev });
186
+ bytes += size;
187
+ }
188
+ return out.reverse();
189
+ }
@@ -0,0 +1,77 @@
1
+ /** REST shapes for M4's project features: per-turn file changes, extra directories, worktrees. */
2
+
3
+ // ---------- files changed by a turn ----------
4
+
5
+ export type TurnFileStatus = "A" | "M" | "D";
6
+
7
+ export type TurnFile = {
8
+ /** Relative to the session cwd when inside it, absolute otherwise */
9
+ path: string;
10
+ status: TurnFileStatus;
11
+ additions: number;
12
+ deletions: number;
13
+ /** Tools of this turn that touched the file (Edit, Write…) */
14
+ tools: string[];
15
+ /** Before/after content comes from the CLI's checkpoints; false = only the tool calls' own patches */
16
+ checkpoint: boolean;
17
+ /** Touched, but the content at the end of the turn equals the start */
18
+ unchanged?: boolean;
19
+ };
20
+
21
+ export type TurnChanges = {
22
+ /** The user message the CLI checkpointed (file-history-snapshot.messageId) */
23
+ id: string;
24
+ /** The visible prompt that started the turn (where the UI anchors it) */
25
+ prompt: string;
26
+ files: TurnFile[];
27
+ };
28
+
29
+ export type TurnChangesInfo = { turns: TurnChanges[] };
30
+
31
+ export type Hunk = { oldStart: number; newStart: number; lines: string[] };
32
+
33
+ export type TurnFileDiff = {
34
+ path: string;
35
+ status: TurnFileStatus;
36
+ binary?: boolean;
37
+ truncated?: boolean;
38
+ /** Whole-file content before / after the turn (checkpoints); null = file did not exist */
39
+ before?: string | null;
40
+ after?: string | null;
41
+ /** Without checkpoints: the edits' own patches, in order */
42
+ patches?: Hunk[];
43
+ };
44
+
45
+ // ---------- extra directories ----------
46
+
47
+ export type ExtraDirSource = "session" | "local" | "project" | "user";
48
+
49
+ export type ExtraDir = {
50
+ path: string;
51
+ /** session: this session only (sqlite); local/project/user: permissions.additionalDirectories in that settings file */
52
+ sources: ExtraDirSource[];
53
+ exists: boolean;
54
+ };
55
+
56
+ export type ExtraDirsInfo = { cwd: string; dirs: ExtraDir[]; localSettingsFile: string };
57
+
58
+ // ---------- worktrees ----------
59
+
60
+ export type WorktreeSession = { id: string; title: string; lastModified: number; draft: boolean };
61
+
62
+ export type WorktreeInfo = {
63
+ name: string;
64
+ path: string;
65
+ /** Session cwd inside this worktree (path + the project's subdirectory, if any) */
66
+ cwd: string;
67
+ branch: string | null;
68
+ head: string;
69
+ dirty: boolean;
70
+ /** Number of changed/untracked files */
71
+ changes: number;
72
+ locked: boolean;
73
+ exists: boolean;
74
+ sessions: WorktreeSession[];
75
+ };
76
+
77
+ export type WorktreeList = { isRepo: false } | { isRepo: true; root: string; branch: string | null; worktrees: WorktreeInfo[] };