openmausbot 0.1.97 → 0.1.99

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 (434) hide show
  1. package/dist/assets/ActivityPanel-CgUgtumZ.js +1 -0
  2. package/dist/assets/BotSettingsDialog-lJj6oiir.js +7 -0
  3. package/dist/assets/CloudBackendPicker-C5-_arUz.js +1 -0
  4. package/dist/assets/ComputerPanel-euJ2CSlH.js +1 -0
  5. package/dist/assets/DesktopViewer-XCln1Pn_.js +5 -0
  6. package/dist/assets/InspectorPanel-DKYyQZlo.js +5 -0
  7. package/dist/assets/KeyboardShortcutsModal-DkkZWZRI.js +1 -0
  8. package/dist/assets/LocalVmWorkspace-Cwt3_XSx.js +1 -0
  9. package/dist/assets/MacLocalControl-B28RbdCS.js +1 -0
  10. package/dist/assets/NewBotDialog-dMWDs5xm.js +2 -0
  11. package/dist/assets/RemoteAgentSettingsPanel-B5KWXnqH.js +1 -0
  12. package/dist/assets/RoutinesPage-DOosRYDK.js +1 -0
  13. package/dist/assets/RoutinesSection-uOfOTfkB.js +1 -0
  14. package/dist/assets/SettingsModal-BTGkFbj1.js +11 -0
  15. package/dist/assets/TeamMapPage-DqNdJn96.js +8 -0
  16. package/dist/assets/TriggersPanel-c6xkG9mi.js +1 -0
  17. package/dist/assets/VisibilitySection-DD4ffIR5.js +12 -0
  18. package/dist/assets/WebhooksPanel-Cz17K-_O.js +3 -0
  19. package/dist/assets/{abnfDiagram-O67JEVCF-k1UCNXb7.js → abnfDiagram-O67JEVCF-CX6tDpkg.js} +1 -1
  20. package/dist/assets/activity-BAVWO0Zj.js +1 -0
  21. package/dist/assets/{arc-BUWGa9UU.js → arc-h45-9NFk.js} +1 -1
  22. package/dist/assets/architectureDiagram-NJMV4G6O-CgLFXbg6.js +36 -0
  23. package/dist/assets/{blockDiagram-BEXU5L5S-Ag9nLW4H.js → blockDiagram-BEXU5L5S-DGDFFc9M.js} +1 -1
  24. package/dist/assets/brain-CeCdoTb2.js +1 -0
  25. package/dist/assets/{c4Diagram-YGBWAQC7-Bh0sjgUa.js → c4Diagram-YGBWAQC7-B9aklAUj.js} +1 -1
  26. package/dist/assets/channel-TsOXCiPg.js +1 -0
  27. package/dist/assets/{chunk-2Q5K7J3B-BFBcIIqu.js → chunk-2Q5K7J3B-BC0KmWsM.js} +1 -1
  28. package/dist/assets/{chunk-3FUC2YCW-Dvfpex-f.js → chunk-3FUC2YCW-BbDFHsJ1.js} +2 -2
  29. package/dist/assets/{chunk-5VM5RSS4-CMjP2YZW.js → chunk-5VM5RSS4-DtGbsjOM.js} +1 -1
  30. package/dist/assets/{chunk-GTNCS2PH-BryoeTc7.js → chunk-GTNCS2PH-VMghMcEl.js} +1 -1
  31. package/dist/assets/{chunk-GWA4HPMP-BhfvcchO.js → chunk-GWA4HPMP-BP_JyGWQ.js} +1 -1
  32. package/dist/assets/{chunk-JWPE2WC7-bcCVp8rp.js → chunk-JWPE2WC7-CYFyzgAU.js} +1 -1
  33. package/dist/assets/{chunk-NETBCI7D-yKIjIlkQ.js → chunk-NETBCI7D-DBNa_kqm.js} +1 -1
  34. package/dist/assets/{chunk-WEXAMYUT-D3Zqbmup.js → chunk-WEXAMYUT-BKEeM7CJ.js} +1 -1
  35. package/dist/assets/{chunk-XXDRQBXY-CjVoIMG6.js → chunk-XXDRQBXY-C__m3ZXl.js} +1 -1
  36. package/dist/assets/{classDiagram-v2-NBCMYWYE-mUCWdVyH.js → classDiagram-v2-NBCMYWYE-CBUrTSAX.js} +1 -1
  37. package/dist/assets/computer-control-NLov352p.js +1 -0
  38. package/dist/assets/core-6lvx-ypA.js +12 -0
  39. package/dist/assets/cose-bilkent-JH36ORCC-GRfL-1Vb.js +1 -0
  40. package/dist/assets/cpp-DddhVWhK.js +1 -0
  41. package/dist/assets/{cynefin-OW5HDTMX-BpRrxoO4.js → cynefin-OW5HDTMX-LopwGUjm.js} +1 -1
  42. package/dist/assets/{cynefinDiagram-VND7K2PF-D3VBWCPK.js → cynefinDiagram-VND7K2PF-DSB8ZRNS.js} +1 -1
  43. package/dist/assets/{dagre-6A5THRUB-DxEIACOO.js → dagre-6A5THRUB-DL3Kgdfk.js} +1 -1
  44. package/dist/assets/{diagram-22UHCM2B-BANgZEOS.js → diagram-22UHCM2B-DIxN34BM.js} +1 -1
  45. package/dist/assets/{diagram-3UASUU5V-Cnq7nJir.js → diagram-3UASUU5V-CJnSvXaI.js} +1 -1
  46. package/dist/assets/{diagram-ATOU4E4O-4TBDIWnz.js → diagram-ATOU4E4O-C-XF-lO8.js} +1 -1
  47. package/dist/assets/{diagram-CDSNMT55-CD_B39D4.js → diagram-CDSNMT55-Df2yZPi_.js} +1 -1
  48. package/dist/assets/{diagram-MLGK6HIB-CzvnFhEC.js → diagram-MLGK6HIB-BBs9oZFs.js} +1 -1
  49. package/dist/assets/{diagram-MPIPVDR6-C4w2SNml.js → diagram-MPIPVDR6-CEbK11mM.js} +1 -1
  50. package/dist/assets/{ebnfDiagram-ZINNZB2B-gkUEBm2s.js → ebnfDiagram-ZINNZB2B-BNq6Yv3C.js} +1 -1
  51. package/dist/assets/{elk-276RUBZZ-B_56X6mw.js → elk-276RUBZZ-CFbQ2bGm.js} +1 -1
  52. package/dist/assets/engine-javascript-D5Xfc425.js +141 -0
  53. package/dist/assets/{erDiagram-OPXOYQCR-C_oByoDS.js → erDiagram-OPXOYQCR-Bz8vmjN4.js} +1 -1
  54. package/dist/assets/{flowDiagram-KWPJA3E3-CR9xXJkC.js → flowDiagram-KWPJA3E3-cQUfEYrx.js} +1 -1
  55. package/dist/assets/ganttDiagram-FUAMR5RP-BY8n9tbI.js +292 -0
  56. package/dist/assets/{gitGraphDiagram-X574FWY7-VJ6-Tp_p.js → gitGraphDiagram-X574FWY7-KduSOMDN.js} +1 -1
  57. package/dist/assets/image-plus-DNIWU160.js +1 -0
  58. package/dist/assets/index-C8xb62XS.js +585 -0
  59. package/dist/assets/index-DbN_Hfjs.css +1 -0
  60. package/dist/assets/{infoDiagram-VRGFBTTK-2Lu9te4D.js → infoDiagram-VRGFBTTK-xBKgUkpL.js} +1 -1
  61. package/dist/assets/{ishikawaDiagram-OU5B5YK6-DR49XY-e.js → ishikawaDiagram-OU5B5YK6-_ei09tAJ.js} +1 -1
  62. package/dist/assets/{journeyDiagram-ZHPQQLJL-ZoR0M305.js → journeyDiagram-ZHPQQLJL-Fp49MkSp.js} +1 -1
  63. package/dist/assets/{kanban-definition-PNTS6WVX-DLKHxrO-.js → kanban-definition-PNTS6WVX-CY9lLm7V.js} +1 -1
  64. package/dist/assets/{linear-BASsfWly.js → linear-D2ai4eM2.js} +1 -1
  65. package/dist/assets/{mermaid.core-BVidiPkk.js → mermaid.core-DP6qPqu1.js} +5 -5
  66. package/dist/assets/{mindmap-definition-NLK3R4M7-g_Qx0U5C.js → mindmap-definition-NLK3R4M7-g1ynEw_d.js} +1 -1
  67. package/dist/assets/module-DCUsy2BQ.js +3 -0
  68. package/dist/assets/page-visible-BZn8304W.js +1 -0
  69. package/dist/assets/{pegDiagram-GJSIUBJH-DI9Cjs8w.js → pegDiagram-GJSIUBJH-Bt4ObsZj.js} +1 -1
  70. package/dist/assets/{pieDiagram-5QR66LMP-sRI0Uhr5.js → pieDiagram-5QR66LMP-CeLld8bY.js} +1 -1
  71. package/dist/assets/{quadrantDiagram-O4NWA36T-CamKTby3.js → quadrantDiagram-O4NWA36T-D4WWZw3x.js} +1 -1
  72. package/dist/assets/{railroadDiagram-XR7U4H2S-DOLlkbf3.js → railroadDiagram-XR7U4H2S-D95P5NqU.js} +1 -1
  73. package/dist/assets/remote-desktop-panel-DOIMmT4T.js +1 -0
  74. package/dist/assets/{requirementDiagram-PLB6GJNP-DrRQ5r97.js → requirementDiagram-PLB6GJNP-D12p3RhR.js} +1 -1
  75. package/dist/assets/ruby-Ct1eTYOr.js +1 -0
  76. package/dist/assets/{sankeyDiagram-IPEJSGJF-DGS_lXcX.js → sankeyDiagram-IPEJSGJF-Co26Dwcs.js} +1 -1
  77. package/dist/assets/{sequenceDiagram-PO4LG4MO-CkjWqwtf.js → sequenceDiagram-PO4LG4MO-y5YxaDKt.js} +1 -1
  78. package/dist/assets/{sizeCapture-INFHLROL-CepRgful.js → sizeCapture-INFHLROL-D49hZ8U5.js} +1 -1
  79. package/dist/assets/{stateDiagram-v2-GCMORJYK-hykr-9RS.js → stateDiagram-v2-GCMORJYK-C0sylr-r.js} +1 -1
  80. package/dist/assets/{swimlanes-2SLR337P-CKOHEZbI.js → swimlanes-2SLR337P-DmRWsDIs.js} +1 -1
  81. package/dist/assets/swimlanesDiagram-TC7HE7FX-DzhbBHtd.js +8 -0
  82. package/dist/assets/table-file.worker-KkMx-SNx.js +10 -0
  83. package/dist/assets/{timeline-definition-EJHVYXUP-CB8pJ6AC.js → timeline-definition-EJHVYXUP-DVmHYs3w.js} +1 -1
  84. package/dist/assets/{usecaseDiagram-POWQR4AR-DrclJHdl.js → usecaseDiagram-POWQR4AR-BQ1q0VV6.js} +1 -1
  85. package/dist/assets/user-B9lohN4n.js +1 -0
  86. package/dist/assets/{vennDiagram-UO4OBE2U-zS23qjv8.js → vennDiagram-UO4OBE2U-C_cnfST0.js} +1 -1
  87. package/dist/assets/{wardleyDiagram-VNRHLVJA-52jgeKxz.js → wardleyDiagram-VNRHLVJA-Bb3BSu12.js} +1 -1
  88. package/dist/assets/{xychartDiagram-PMCCYNJV-DSdl9rQ8.js → xychartDiagram-PMCCYNJV-CcwEuuEi.js} +1 -1
  89. package/dist/index.html +2 -2
  90. package/dist-server/cloud-home-start.js +19 -8
  91. package/dist-server/container-mcp.js +8 -0
  92. package/dist-server/desktop-entry.mjs +54 -0
  93. package/dist-server/drivers/agents-proxy.js +30 -12
  94. package/dist-server/index.js +2745 -1487
  95. package/dist-server/openmausbot.js +1004 -642
  96. package/dist-server/pair-cli.js +1004 -642
  97. package/dist-server/permission-proxy.js +2 -0
  98. package/dist-server/server/activity.js +2 -0
  99. package/dist-server/server/atomic.js +70 -2
  100. package/dist-server/server/checkpoints.js +55 -39
  101. package/dist-server/server/cloud-home-start.js +3 -3
  102. package/dist-server/server/config.js +22 -1
  103. package/dist-server/server/connector-card-text.js +15 -0
  104. package/dist-server/server/default-model-selection.js +7 -4
  105. package/dist-server/server/direct-apply.js +20 -0
  106. package/dist-server/server/drivers/acp/core.js +10 -0
  107. package/dist-server/server/drivers/acp/grok.js +47 -5
  108. package/dist-server/server/drivers/agents-call.js +1 -1
  109. package/dist-server/server/drivers/agents-catalog.js +34 -11
  110. package/dist-server/server/drivers/agents-proxy.js +1 -0
  111. package/dist-server/server/drivers/chat-mcp-tools.js +5 -3
  112. package/dist-server/server/drivers/claude-login-auth.js +1 -1
  113. package/dist-server/server/drivers/claude.js +35 -11
  114. package/dist-server/server/drivers/codex-device-auth.js +27 -319
  115. package/dist-server/server/drivers/codex.js +147 -24
  116. package/dist-server/server/drivers/device-auth.js +343 -0
  117. package/dist-server/server/drivers/openai-chat.js +17 -8
  118. package/dist-server/server/fleet-agent.js +18 -5
  119. package/dist-server/server/harness/http.js +5 -2
  120. package/dist-server/server/harness/registry.js +82 -45
  121. package/dist-server/server/harness-capabilities.js +7 -4
  122. package/dist-server/server/hosted-models.js +3 -1
  123. package/dist-server/server/index.js +471 -77
  124. package/dist-server/server/key-rejections.js +57 -0
  125. package/dist-server/server/mcp-oauth.js +125 -47
  126. package/dist-server/server/message-file.js +102 -7
  127. package/dist-server/server/model-requests.js +55 -4
  128. package/dist-server/server/permission-proxy.js +4 -0
  129. package/dist-server/server/profile-requests.js +80 -4
  130. package/dist-server/server/provider-key-check.js +5 -1
  131. package/dist-server/server/request-auth.js +2 -1
  132. package/dist-server/server/room-turn-timeout.js +28 -0
  133. package/dist-server/server/routes/thread-models.js +36 -0
  134. package/dist-server/server/routes/undo.js +17 -0
  135. package/dist-server/server/routine-requests.js +210 -6
  136. package/dist-server/server/routines.js +2 -2
  137. package/dist-server/server/setup-mode.js +1 -1
  138. package/dist-server/server/skill-learn.js +2 -2
  139. package/dist-server/server/skills.js +33 -2
  140. package/dist-server/server/store.js +148 -60
  141. package/dist-server/server/system-prompt.js +1 -1
  142. package/dist-server/server/team-backup.js +19 -4
  143. package/dist-server/server/thread-model.js +25 -0
  144. package/dist-server/server/turn-continuation.js +17 -16
  145. package/dist-server/server/webhook-ingress.js +8 -3
  146. package/dist-server/server/webhooks.js +40 -5
  147. package/dist-server/server/workspace-backup.js +6 -1
  148. package/dist-server/shared/device-sign-in.js +57 -0
  149. package/dist-server/shared/team-backup.js +2 -0
  150. package/dist-server/shared/thread-model.js +13 -0
  151. package/dist-server/vps-container-mcp.js +8 -0
  152. package/dist-server/workspace-backup.worker.js +42 -23
  153. package/package.json +1 -1
  154. package/skills/create-verification-skill/SKILL.md +9 -8
  155. package/skills/create-verification-skill/manifest.json +1 -1
  156. package/dist/assets/DesktopViewer-CPidMCtt.js +0 -5
  157. package/dist/assets/abap-BdImnpbu.js +0 -1
  158. package/dist/assets/actionscript-3-B3316cI-.js +0 -1
  159. package/dist/assets/ada-bCR0ucgS.js +0 -1
  160. package/dist/assets/ahk-CsyLZFj1.js +0 -1
  161. package/dist/assets/ahk2-8Zs4aa1G.js +0 -1
  162. package/dist/assets/andromeeda-C4gqWexZ.js +0 -1
  163. package/dist/assets/angular-html-DA-rfuFy.js +0 -1
  164. package/dist/assets/angular-ts-BrjP3tb8.js +0 -1
  165. package/dist/assets/apache-Pmp26Uib.js +0 -1
  166. package/dist/assets/apex-DhZFqWV2.js +0 -1
  167. package/dist/assets/apl-CORt7UWP.js +0 -1
  168. package/dist/assets/applescript-Co6uUVPk.js +0 -1
  169. package/dist/assets/ara-BRHolxvo.js +0 -1
  170. package/dist/assets/architectureDiagram-NJMV4G6O-DiPor3UT.js +0 -36
  171. package/dist/assets/asciidoc-CSVQ5wI8.js +0 -1
  172. package/dist/assets/asm-D_Q5rh1f.js +0 -1
  173. package/dist/assets/astro-HNnZUWAn.js +0 -1
  174. package/dist/assets/aurora-x-D-2ljcwZ.js +0 -1
  175. package/dist/assets/awk-DMzUqQB5.js +0 -1
  176. package/dist/assets/ayu-dark-DYE7WIF3.js +0 -1
  177. package/dist/assets/ayu-light-BA47KaF1.js +0 -1
  178. package/dist/assets/ayu-mirage-32ctXXKs.js +0 -1
  179. package/dist/assets/ballerina-BFfxhgS-.js +0 -1
  180. package/dist/assets/bat-CickPsom.js +0 -1
  181. package/dist/assets/beancount-k_qm7-4y.js +0 -1
  182. package/dist/assets/berry-uYugtg8r.js +0 -1
  183. package/dist/assets/bibtex-CHM0blh-.js +0 -1
  184. package/dist/assets/bicep-Bmn6On1c.js +0 -1
  185. package/dist/assets/bird2-Bx8U0n9b.js +0 -1
  186. package/dist/assets/blade-2xfisSek.js +0 -1
  187. package/dist/assets/bsl-DlhNcFeZ.js +0 -1
  188. package/dist/assets/c3-Dp5svz6Z.js +0 -1
  189. package/dist/assets/cadence-Bv_4Rxtq.js +0 -1
  190. package/dist/assets/cairo-KRGpt6FW.js +0 -1
  191. package/dist/assets/catppuccin-frappe-CZL1YF0i.js +0 -1
  192. package/dist/assets/catppuccin-latte-DH-8KZSZ.js +0 -1
  193. package/dist/assets/catppuccin-macchiato-B7yYVSCf.js +0 -1
  194. package/dist/assets/catppuccin-mocha-Ct7hS0mc.js +0 -1
  195. package/dist/assets/channel-DR8eD6QW.js +0 -1
  196. package/dist/assets/chapel-DTp_pixX.js +0 -1
  197. package/dist/assets/clarity-Dn5IMItf.js +0 -1
  198. package/dist/assets/clojure-P80f7IUj.js +0 -1
  199. package/dist/assets/cmake-D1j8_8rp.js +0 -1
  200. package/dist/assets/cobol-nBiQ_Alo.js +0 -1
  201. package/dist/assets/codeowners-Bp6g37R7.js +0 -1
  202. package/dist/assets/codeql-DsOJ9woJ.js +0 -1
  203. package/dist/assets/coffee-Ch7k5sss.js +0 -1
  204. package/dist/assets/common-lisp-Cg-RD9OK.js +0 -1
  205. package/dist/assets/coq-C7JzOVbR.js +0 -1
  206. package/dist/assets/cose-bilkent-JH36ORCC-BBmR1bbX.js +0 -1
  207. package/dist/assets/cpp-BMRokrvK.js +0 -1
  208. package/dist/assets/crystal-DGywbUpC.js +0 -1
  209. package/dist/assets/csv-fuZLfV_i.js +0 -1
  210. package/dist/assets/cue-D82EKSYY.js +0 -1
  211. package/dist/assets/cypher-COkxafJQ.js +0 -1
  212. package/dist/assets/d-85-TOEBH.js +0 -1
  213. package/dist/assets/dark-plus-C3mMm8J8.js +0 -1
  214. package/dist/assets/dax-CEL-wOlO.js +0 -1
  215. package/dist/assets/desktop-BmXAJ9_W.js +0 -1
  216. package/dist/assets/dotenv-Da5cRb03.js +0 -1
  217. package/dist/assets/dracula-BzJJZx-M.js +0 -1
  218. package/dist/assets/dracula-soft-BXkSAIEj.js +0 -1
  219. package/dist/assets/dream-maker-BtqSS_iP.js +0 -1
  220. package/dist/assets/edge-FbVlp4U3.js +0 -1
  221. package/dist/assets/elixir-CkH2-t6x.js +0 -1
  222. package/dist/assets/elm-DbKCFpqz.js +0 -1
  223. package/dist/assets/emacs-lisp-C_m_b--Z.js +0 -1
  224. package/dist/assets/erb-DXfck5VN.js +0 -1
  225. package/dist/assets/erlang-DsQrWhSR.js +0 -1
  226. package/dist/assets/everforest-dark-BgDCqdQA.js +0 -1
  227. package/dist/assets/everforest-light-C8M2exoo.js +0 -1
  228. package/dist/assets/fennel-BYunw83y.js +0 -1
  229. package/dist/assets/fluent-C4IJs8-o.js +0 -1
  230. package/dist/assets/fortran-fixed-form-CkoXwp7k.js +0 -1
  231. package/dist/assets/fortran-free-form-BxgE0vQu.js +0 -1
  232. package/dist/assets/fsharp-CXgrBDvD.js +0 -1
  233. package/dist/assets/ganttDiagram-FUAMR5RP-gtYBTu0B.js +0 -292
  234. package/dist/assets/gdresource-TyuKm33G.js +0 -1
  235. package/dist/assets/gdscript-DqcFQ5yU.js +0 -1
  236. package/dist/assets/gdshader-DkwncUOv.js +0 -1
  237. package/dist/assets/genie-D0YGMca9.js +0 -1
  238. package/dist/assets/gherkin-DyxjwDmM.js +0 -1
  239. package/dist/assets/git-commit-F4YmCXRG.js +0 -1
  240. package/dist/assets/git-rebase-r7XF79zn.js +0 -1
  241. package/dist/assets/github-dark-DHJKELXO.js +0 -1
  242. package/dist/assets/github-dark-dimmed-DH5Ifo-i.js +0 -1
  243. package/dist/assets/github-dark-high-contrast-E3gJ1_iC.js +0 -1
  244. package/dist/assets/github-light-DAi9KRSo.js +0 -1
  245. package/dist/assets/github-light-high-contrast-BfjtVDDH.js +0 -1
  246. package/dist/assets/gleam-BspZqrRM.js +0 -1
  247. package/dist/assets/glimmer-js-ByusRIyA.js +0 -1
  248. package/dist/assets/glimmer-ts-BfAWNZQY.js +0 -1
  249. package/dist/assets/glsl-DplSGwfg.js +0 -1
  250. package/dist/assets/gn-n2N0HUVH.js +0 -1
  251. package/dist/assets/gnuplot-DdkO51Og.js +0 -1
  252. package/dist/assets/groovy-gcz8RCvz.js +0 -1
  253. package/dist/assets/gruvbox-dark-hard-CFHQjOhq.js +0 -1
  254. package/dist/assets/gruvbox-dark-medium-GsRaNv29.js +0 -1
  255. package/dist/assets/gruvbox-dark-soft-CVdnzihN.js +0 -1
  256. package/dist/assets/gruvbox-light-hard-CH1njM8p.js +0 -1
  257. package/dist/assets/gruvbox-light-medium-DRw_LuNl.js +0 -1
  258. package/dist/assets/gruvbox-light-soft-hJgmCMqR.js +0 -1
  259. package/dist/assets/hack-BWmVpMyf.js +0 -1
  260. package/dist/assets/haml-D5jkg6IW.js +0 -1
  261. package/dist/assets/handlebars-BpdQsYii.js +0 -1
  262. package/dist/assets/haskell-Df6bDoY_.js +0 -1
  263. package/dist/assets/haxe-CfZj7gIn.js +0 -1
  264. package/dist/assets/hcl-BWvSN4gD.js +0 -1
  265. package/dist/assets/hjson-D5-asLiD.js +0 -1
  266. package/dist/assets/hlsl-D3lLCCz7.js +0 -1
  267. package/dist/assets/horizon-BUw7H-hv.js +0 -1
  268. package/dist/assets/horizon-bright-CUuTKBJd.js +0 -1
  269. package/dist/assets/houston-DnULxvSX.js +0 -1
  270. package/dist/assets/html-derivative-DlHx6ybY.js +0 -1
  271. package/dist/assets/http-jrhK8wxY.js +0 -1
  272. package/dist/assets/hurl-irOxFIW8.js +0 -1
  273. package/dist/assets/hxml-2-FPmUDs.js +0 -1
  274. package/dist/assets/hy-DFXneXwc.js +0 -1
  275. package/dist/assets/imba-DGztddWO.js +0 -1
  276. package/dist/assets/index-Cp4S4NOL.js +0 -153
  277. package/dist/assets/index-CpaIXRLp.js +0 -614
  278. package/dist/assets/index-Z81SMsgR.css +0 -1
  279. package/dist/assets/ini-BEwlwnbL.js +0 -1
  280. package/dist/assets/jinja-f2NsQr07.js +0 -1
  281. package/dist/assets/jison-wvAkD_A8.js +0 -1
  282. package/dist/assets/jsonl-DcaNXYhu.js +0 -1
  283. package/dist/assets/jsonnet-DFQXde-d.js +0 -1
  284. package/dist/assets/jssm-C2t-YnRu.js +0 -1
  285. package/dist/assets/julia-5Bft2YPA.js +0 -1
  286. package/dist/assets/just-Cwhn7H3k.js +0 -1
  287. package/dist/assets/kanagawa-dragon-BuwD2xS4.js +0 -1
  288. package/dist/assets/kanagawa-lotus-C3DzagqV.js +0 -1
  289. package/dist/assets/kanagawa-wave-DFGoQZhC.js +0 -1
  290. package/dist/assets/kdl-DV7GczEv.js +0 -1
  291. package/dist/assets/kusto-wEQ09or8.js +0 -1
  292. package/dist/assets/laserwave-DUszq2jm.js +0 -1
  293. package/dist/assets/latex-D5pSuvFb.js +0 -1
  294. package/dist/assets/lean-BZvkOJ9d.js +0 -1
  295. package/dist/assets/light-plus-B7mTdjB0.js +0 -1
  296. package/dist/assets/liquid-C0sCDyMI.js +0 -1
  297. package/dist/assets/llvm-BZoOZj88.js +0 -1
  298. package/dist/assets/log-2UxHyX5q.js +0 -1
  299. package/dist/assets/logo-BtOb2qkB.js +0 -1
  300. package/dist/assets/luau-BnpPk5vE.js +0 -1
  301. package/dist/assets/marko-DjSrsDqO.js +0 -1
  302. package/dist/assets/material-theme-D5KoaKCx.js +0 -1
  303. package/dist/assets/material-theme-darker-BfHTSMKl.js +0 -1
  304. package/dist/assets/material-theme-lighter-B0m2ddpp.js +0 -1
  305. package/dist/assets/material-theme-ocean-CyktbL80.js +0 -1
  306. package/dist/assets/material-theme-palenight-Csfq5Kiy.js +0 -1
  307. package/dist/assets/matlab-D7o27uSR.js +0 -1
  308. package/dist/assets/mdc-D1_yUvq7.js +0 -1
  309. package/dist/assets/mermaid-CQcHuHx7.js +0 -1
  310. package/dist/assets/min-dark-CafNBF8u.js +0 -1
  311. package/dist/assets/min-light-CTRr51gU.js +0 -1
  312. package/dist/assets/mipsasm-CKIfxQSi.js +0 -1
  313. package/dist/assets/mojo-DJz3ZmWd.js +0 -1
  314. package/dist/assets/monokai-BRVnQi9A.js +0 -1
  315. package/dist/assets/moonbit-CHtswR0a.js +0 -1
  316. package/dist/assets/move-el3G9tDJ.js +0 -1
  317. package/dist/assets/narrat-DRg8JJMk.js +0 -1
  318. package/dist/assets/nextflow-C-mBbutL.js +0 -1
  319. package/dist/assets/nextflow-groovy-vE_lwT2v.js +0 -1
  320. package/dist/assets/nginx-BpAMiNFr.js +0 -1
  321. package/dist/assets/night-owl-C39BiMTA.js +0 -1
  322. package/dist/assets/night-owl-light-CMTm3GFP.js +0 -1
  323. package/dist/assets/nim-BIad80T-.js +0 -1
  324. package/dist/assets/nix-CwoSXNpI.js +0 -1
  325. package/dist/assets/nord-Ddv68eIx.js +0 -1
  326. package/dist/assets/nsis-BlV79W_Q.js +0 -1
  327. package/dist/assets/nushell-D3jzshHO.js +0 -1
  328. package/dist/assets/objective-c-DXmwc3jG.js +0 -1
  329. package/dist/assets/objective-cpp-CLxacb5B.js +0 -1
  330. package/dist/assets/ocaml-C0hk2d4L.js +0 -1
  331. package/dist/assets/odin-BBf5iR-q.js +0 -1
  332. package/dist/assets/one-dark-pro-DVMEJ2y_.js +0 -1
  333. package/dist/assets/one-light-C3Wv6jpd.js +0 -1
  334. package/dist/assets/openscad-C4EeE6gA.js +0 -1
  335. package/dist/assets/org-DM6o9KBp.js +0 -1
  336. package/dist/assets/pascal-D93ZcfNL.js +0 -1
  337. package/dist/assets/perl-B9cMNwum.js +0 -1
  338. package/dist/assets/pkl-u5AG7uiY.js +0 -1
  339. package/dist/assets/plastic-3e1v2bzS.js +0 -1
  340. package/dist/assets/plsql-ChMvpjG-.js +0 -1
  341. package/dist/assets/po-BTJTHyun.js +0 -1
  342. package/dist/assets/poimandres-CS3Unz2-.js +0 -1
  343. package/dist/assets/polar-C0HS_06l.js +0 -1
  344. package/dist/assets/postcss-CXtECtnM.js +0 -1
  345. package/dist/assets/powerquery-CEu0bR-o.js +0 -1
  346. package/dist/assets/prisma-Vru482bI.js +0 -1
  347. package/dist/assets/prolog-CbFg5uaA.js +0 -1
  348. package/dist/assets/pug-DKIMFp6K.js +0 -1
  349. package/dist/assets/puppet-BMWR74SV.js +0 -1
  350. package/dist/assets/purescript-CklMAg4u.js +0 -1
  351. package/dist/assets/qml-3beO22l8.js +0 -1
  352. package/dist/assets/qmldir-C8lEn-DE.js +0 -1
  353. package/dist/assets/qss-IeuSbFQv.js +0 -1
  354. package/dist/assets/racket-BqYA7rlc.js +0 -1
  355. package/dist/assets/raku-DXvB9xmW.js +0 -1
  356. package/dist/assets/razor-BjBPvh-w.js +0 -1
  357. package/dist/assets/rbs-CpoqiR4B.js +0 -1
  358. package/dist/assets/red-hvxz__6c.js +0 -1
  359. package/dist/assets/reg-C-SQnVFl.js +0 -1
  360. package/dist/assets/regexp-CDVJQ6XC.js +0 -1
  361. package/dist/assets/rel-C3B-1QV4.js +0 -1
  362. package/dist/assets/riscv-BM1_JUlF.js +0 -1
  363. package/dist/assets/ron-D8l8udqQ.js +0 -1
  364. package/dist/assets/rose-pine-5qJOZa0Y.js +0 -1
  365. package/dist/assets/rose-pine-dawn-zx0QlTCp.js +0 -1
  366. package/dist/assets/rose-pine-moon-C9pEdX9L.js +0 -1
  367. package/dist/assets/rosmsg-BJDFO7_C.js +0 -1
  368. package/dist/assets/rst-bs7f0vWN.js +0 -1
  369. package/dist/assets/ruby-C0TQ7zu5.js +0 -1
  370. package/dist/assets/sas-DEy46yEz.js +0 -1
  371. package/dist/assets/scala-CqE71os6.js +0 -1
  372. package/dist/assets/scheme-C98Dy4si.js +0 -1
  373. package/dist/assets/sdbl-DVxCFoDh.js +0 -1
  374. package/dist/assets/shaderlab-Dg9Lc6iA.js +0 -1
  375. package/dist/assets/shellsession-BADoaaVG.js +0 -1
  376. package/dist/assets/slack-dark-BthQWCQV.js +0 -1
  377. package/dist/assets/slack-ochin-DqwNpetd.js +0 -1
  378. package/dist/assets/smalltalk-BOQMe2GC.js +0 -1
  379. package/dist/assets/smithy-cds9vsN8.js +0 -1
  380. package/dist/assets/snazzy-light-Bw305WKR.js +0 -1
  381. package/dist/assets/solarized-dark-CpvCGNkr.js +0 -1
  382. package/dist/assets/solarized-light-Dlz6yCKv.js +0 -1
  383. package/dist/assets/solidity-DijEV5ha.js +0 -1
  384. package/dist/assets/soy-8wufbnw4.js +0 -1
  385. package/dist/assets/sparql-rVzFXLq3.js +0 -1
  386. package/dist/assets/splunk-BtCnVYZw.js +0 -1
  387. package/dist/assets/ssh-config-_ykCGR6B.js +0 -1
  388. package/dist/assets/stata-DI20mbqo.js +0 -1
  389. package/dist/assets/stylus-BEDo0Tqx.js +0 -1
  390. package/dist/assets/surrealql-Cjom0U5J.js +0 -1
  391. package/dist/assets/svelte-Cy7k_4gC.js +0 -1
  392. package/dist/assets/swimlanesDiagram-TC7HE7FX-D-8vqZ4-.js +0 -8
  393. package/dist/assets/synthwave-84-CbfX1IO0.js +0 -1
  394. package/dist/assets/system-verilog-0hqHdDBg.js +0 -1
  395. package/dist/assets/systemd-4A_iFExJ.js +0 -1
  396. package/dist/assets/talonscript-CkByrt1z.js +0 -1
  397. package/dist/assets/tasl-QIJgUcNo.js +0 -1
  398. package/dist/assets/tcl-dwOrl1Do.js +0 -1
  399. package/dist/assets/templ-DhtptRzy.js +0 -1
  400. package/dist/assets/terraform-BETggiCN.js +0 -1
  401. package/dist/assets/tex-D96PA37w.js +0 -1
  402. package/dist/assets/tokyo-night-hegEt444.js +0 -1
  403. package/dist/assets/ts-tags-D351s5mN.js +0 -1
  404. package/dist/assets/tsv-B_m7g4N7.js +0 -1
  405. package/dist/assets/turtle-BsS91CYL.js +0 -1
  406. package/dist/assets/twig-27uCiNez.js +0 -1
  407. package/dist/assets/typespec-CAFt9gP4.js +0 -1
  408. package/dist/assets/typst-BUadGCkm.js +0 -1
  409. package/dist/assets/v-BGw2Nkan.js +0 -1
  410. package/dist/assets/vala-CsfeWuGM.js +0 -1
  411. package/dist/assets/vb-Cu-pLBUe.js +0 -1
  412. package/dist/assets/verilog-nZwndyjY.js +0 -1
  413. package/dist/assets/vesper-DRje8inN.js +0 -1
  414. package/dist/assets/vhdl-CeAyd5Ju.js +0 -1
  415. package/dist/assets/viml-CJc9bBzg.js +0 -1
  416. package/dist/assets/vitesse-black-Bkuqu6BP.js +0 -1
  417. package/dist/assets/vitesse-dark-D0r3Knsf.js +0 -1
  418. package/dist/assets/vitesse-light-CVO1_9PV.js +0 -1
  419. package/dist/assets/vue-BqiEGhQt.js +0 -1
  420. package/dist/assets/vue-html-AaS7Mt5G.js +0 -1
  421. package/dist/assets/vue-vine-BoDAl6tE.js +0 -1
  422. package/dist/assets/vyper-CDx5xZoG.js +0 -1
  423. package/dist/assets/wasm-CG6Dc4jp.js +0 -1
  424. package/dist/assets/wenyan-BV7otONQ.js +0 -1
  425. package/dist/assets/wgsl-Dx-B1_4e.js +0 -1
  426. package/dist/assets/wikitext-BhOHFoWU.js +0 -1
  427. package/dist/assets/wit-5i3qLPDT.js +0 -1
  428. package/dist/assets/wolfram-lXgVvXCa.js +0 -1
  429. package/dist/assets/xsl-CtQFsRM5.js +0 -1
  430. package/dist/assets/zenscript-DVFEvuxE.js +0 -1
  431. package/dist/assets/zig-VOosw3JB.js +0 -1
  432. /package/dist/assets/{shellscript-Yzrsuije.js → bash-Yzrsuije.js} +0 -0
  433. /package/dist/assets/{docker-BcOcwvcX.js → dockerfile-BcOcwvcX.js} +0 -0
  434. /package/dist/assets/{make-CHLpvVh8.js → makefile-CHLpvVh8.js} +0 -0
@@ -11,6 +11,7 @@ import { PROFILE_REQUEST_FIELDS } from "../shared/profile-request.js";
11
11
  import { parseBotProfilePatch } from "./bot-profile.js";
12
12
  import { validateBotCwd } from "./bot-cwd.js";
13
13
  import { newId } from "./contracts.js";
14
+ import { UNDO_STALE } from "./direct-apply.js";
14
15
  import { profileRevision, profileSnapshot } from "./profile-revision.js";
15
16
  import { recordProfileChange } from "./profile-versions.js";
16
17
  import { redactSecretsInText } from "./redact.js";
@@ -205,6 +206,9 @@ export class ProfileRequestService {
205
206
  const snapshot = profileSnapshot(target);
206
207
  const before = {};
207
208
  const finalChanges = {};
209
+ // Undo restores `before`, so it is offered only when the card holds the
210
+ // old values exactly (credential-shaped text is scrubbed from cards).
211
+ let exactBefore = true;
208
212
  for (const field of PROFILE_REQUEST_FIELDS) {
209
213
  if (field === "notifications" || field === "speakReplies") {
210
214
  const value = changes[field];
@@ -218,6 +222,8 @@ export class ProfileRequestService {
218
222
  if (value === undefined || value === snapshot[field])
219
223
  continue;
220
224
  before[field] = redactSecretsInText(snapshot[field]);
225
+ if (before[field] !== snapshot[field])
226
+ exactBefore = false;
221
227
  finalChanges[field] = value;
222
228
  }
223
229
  }
@@ -240,11 +246,14 @@ export class ProfileRequestService {
240
246
  expectedRevision: profileRevision(target),
241
247
  };
242
248
  const copy = profileCardCopy({ name: targetName, crossBot }, snapshot, before, finalChanges, reason);
243
- const persistence = this.canPersist?.(args.botId, args.threadId);
249
+ const grant = submitted ? this.autoApply?.(args.botId, args.threadId, targetBotId) ?? null : null;
250
+ // A new working folder widens what the bot's tools read and write
251
+ // without asking, so below Full access it keeps today's card.
252
+ const automatic = grant === "full-access" || (grant === "self" && finalChanges.cwd === undefined);
253
+ const persistence = this.canPersist?.(args.botId, args.threadId, !automatic);
244
254
  if (persistence && !persistence.ok) {
245
255
  throw new ProfileRequestError(persistence.error, persistence.status);
246
256
  }
247
- const automatic = submitted && this.autoApply?.(args.botId, args.threadId) === true;
248
257
  const messageInput = {
249
258
  role: "bot",
250
259
  kind: "options",
@@ -267,10 +276,77 @@ export class ProfileRequestService {
267
276
  // The hidden receipt is persisted before the profile changes. The same
268
277
  // validation and durable commit marker serve both automatic and human decisions.
269
278
  const result = this.resolve({ botId: args.botId, threadId: args.threadId, requestId, behavior: "allow" });
270
- if (result.state === "applied")
271
- return { ...proposal, result };
279
+ if (result.state === "applied") {
280
+ if (!result.settlementPending)
281
+ this.recordAutoApplied(args.threadId, message.id, targetBotId, exactBefore);
282
+ return { ...proposal, result, appliedBy: grant };
283
+ }
272
284
  throw new ProfileRequestError(result.state === "invalid" ? result.error : "The profile change could not be applied", result.state === "invalid" ? result.status : 409);
273
285
  }
286
+ /** Marks a card whose change applied without a person, with the revision
287
+ * its Undo checks. A failure here only loses the Undo. */
288
+ recordAutoApplied(threadId, messageId, targetBotId, exactBefore) {
289
+ try {
290
+ const card = this.store.messagesFor(threadId).find((candidate) => candidate.id === messageId)?.card;
291
+ const target = this.store.bot(targetBotId);
292
+ if (!card?.profileRequest || !target)
293
+ return;
294
+ this.store.patchMessage(threadId, messageId, {
295
+ card: {
296
+ ...card,
297
+ autoApplied: true,
298
+ profileRequest: { ...card.profileRequest, ...(exactBefore ? { undo: { appliedRevision: profileRevision(target) } } : {}) },
299
+ },
300
+ });
301
+ }
302
+ catch {
303
+ // The profile change itself is durable; only its Undo is lost.
304
+ }
305
+ }
306
+ /** Puts back the fields a change that applied without a person changed.
307
+ * Authorized by the caller exactly like answering the card; refuses,
308
+ * applying nothing, once the profile changed since. */
309
+ undo(args) {
310
+ const message = this.store
311
+ .messagesFor(args.threadId)
312
+ .find((candidate) => candidate.card?.requestId === args.requestId && candidate.card.profileRequest);
313
+ const card = message?.card;
314
+ const payload = card?.profileRequest;
315
+ if (!message || !card || !payload)
316
+ return { claimed: false };
317
+ if (card.undone)
318
+ return { claimed: true, state: "already_undone" };
319
+ const cannot = (error, status = 409) => ({ claimed: true, state: "invalid", error, status });
320
+ if (!card.autoApplied || card.answered !== "allow")
321
+ return cannot("Only a change that applied on its own can be undone here.");
322
+ if (payload.botId !== args.botId || payload.threadId !== args.threadId) {
323
+ return cannot("This profile change belongs to another conversation", 403);
324
+ }
325
+ if (!payload.undo)
326
+ return cannot("This change can't be undone here.");
327
+ const target = this.store.bot(payload.targetBotId);
328
+ if (!target || profileRevision(target) !== payload.undo.appliedRevision) {
329
+ return { claimed: true, state: "invalid", error: UNDO_STALE, status: 409, stale: true };
330
+ }
331
+ const { cwd, ...rest } = payload.before;
332
+ const patch = {};
333
+ for (const field of PROFILE_REQUEST_FIELDS) {
334
+ if (field === "cwd" || payload.changes[field] === undefined)
335
+ continue;
336
+ patch[field] = rest[field];
337
+ }
338
+ if (payload.changes.cwd !== undefined) {
339
+ const checked = validateBotCwd(cwd || null);
340
+ if (!checked.ok)
341
+ return cannot(checked.error);
342
+ patch.cwd = checked.cwd ?? undefined;
343
+ }
344
+ if (!this.store.patchBotProfile(target.id, patch))
345
+ return cannot(NO_SUCH_BOT, 404);
346
+ recordProfileChange(target.id, "user", `undo:${message.id}`, payload.changes, payload.before);
347
+ this.store.patchMessage(args.threadId, message.id, { card: { ...card, undone: true } });
348
+ return { claimed: true, state: "undone", targetBotId: target.id };
349
+ }
274
350
  /** Claims a profile card even after it was settled, so a duplicate click
275
351
  * never re-applies an already-applied change. */
276
352
  resolve(args) {
@@ -14,9 +14,13 @@ export function isLoopback(hostname) {
14
14
  const host = hostname.replace(/^\[|\]$/g, "");
15
15
  return host === "localhost" || host === "127.0.0.1" || host === "::1" || host.startsWith("127.");
16
16
  }
17
+ /** A provider's base URL: the configured one, or its default. */
18
+ export function providerBaseUrl(provider, base) {
19
+ return (base?.trim() || DEFAULT_URLS[provider]).replace(/\/+$/, "");
20
+ }
17
21
  /** The models endpoint for a provider, from its base URL or the default. */
18
22
  export function providerModelsUrl(provider, base) {
19
- const root = (base?.trim() || DEFAULT_URLS[provider]).replace(/\/+$/, "");
23
+ const root = providerBaseUrl(provider, base);
20
24
  if (provider === "anthropic")
21
25
  return root.endsWith("/v1") ? `${root}/models` : `${root}/v1/models`;
22
26
  return `${root}/models`;
@@ -283,6 +283,7 @@ export const CLIENT_ALLOW = [
283
283
  // approvals and cards
284
284
  { methods: ["POST"], path: /^\/api\/bots\/[\w-]+\/respond$/ },
285
285
  { methods: ["POST"], path: /^\/api\/threads\/[\w-]+\/respond$/ },
286
+ { methods: ["POST"], path: /^\/api\/threads\/[\w-]+\/undo$/ }, // whoever may answer the card: see the handler
286
287
  { methods: ["PATCH"], path: /^\/api\/bots\/[\w-]+\/cards\/[\w-]+$/ },
287
288
  { methods: ["POST"], path: /^\/api\/bots\/[\w-]+\/secret-cards\/[\w-]+\/(?:resume|dismiss)$/ },
288
289
  { methods: ["GET"], path: /^\/api\/bots\/[\w-]+\/connector-cards\/[\w-]+\/status$/ },
@@ -340,7 +341,7 @@ export function clientBotPatchViolation(body) {
340
341
  return null;
341
342
  }
342
343
  /** Same for a room: name and reading state, never its folder or who answers. */
343
- const CLIENT_GROUP_PATCH_FIELDS = new Set(["name", "bulletin", "unread", "pinnedMessageId", "section"]);
344
+ const CLIENT_GROUP_PATCH_FIELDS = new Set(["name", "bulletin", "unread", "pinnedMessageId", "section", "turnTimeoutMinutes"]);
344
345
  export function clientGroupPatchViolation(body) {
345
346
  if (!body || typeof body !== "object" || Array.isArray(body))
346
347
  return "body";
@@ -1,6 +1,34 @@
1
+ import { MAX_ROOM_TURN_TIMEOUT_MINUTES, MIN_ROOM_TURN_TIMEOUT_MINUTES, } from "./config.js";
1
2
  export function roomTurnTimeoutMs(minutes) {
2
3
  return minutes * 60_000;
3
4
  }
5
+ /** A conversation may replace the global group ceiling. Null clears that
6
+ * choice. Anything else is refused rather than silently clamped. */
7
+ export function parseConversationTurnTimeout(value) {
8
+ if (value === null)
9
+ return { ok: true, minutes: null };
10
+ if (typeof value !== "number" ||
11
+ !Number.isInteger(value) ||
12
+ value < MIN_ROOM_TURN_TIMEOUT_MINUTES ||
13
+ value > MAX_ROOM_TURN_TIMEOUT_MINUTES) {
14
+ return {
15
+ ok: false,
16
+ error: "Turn limit must be a whole number from 1 to 1,440, or null to use the group default.",
17
+ };
18
+ }
19
+ return { ok: true, minutes: value };
20
+ }
21
+ /** The ceiling captured for one turn. An override wins; a missing or
22
+ * unusable one keeps the global group limit. */
23
+ export function effectiveRoomTurnTimeoutMinutes(globalMinutes, override) {
24
+ if (typeof override === "number" &&
25
+ Number.isInteger(override) &&
26
+ override >= MIN_ROOM_TURN_TIMEOUT_MINUTES &&
27
+ override <= MAX_ROOM_TURN_TIMEOUT_MINUTES) {
28
+ return override;
29
+ }
30
+ return globalMinutes;
31
+ }
4
32
  /**
5
33
  * One room turn's slice of the configured room ceiling.
6
34
  *
@@ -0,0 +1,36 @@
1
+ import { sameModelSelection } from "../../shared/thread-model.js";
2
+ import { PASS } from "./table.js";
3
+ const MAX_THREAD_IDS = 10_000;
4
+ export function createThreadModelRoutes(deps) {
5
+ return async ({ req, res, path, method, auth, json, readBody }) => {
6
+ const m = path.match(/^\/api\/bots\/([\w-]+)\/threads\/follow-model$/);
7
+ if (!m || method !== "POST")
8
+ return PASS;
9
+ const bot = deps.bot(m[1]);
10
+ if (!bot)
11
+ return json(res, 404, { error: "no such bot" });
12
+ if (!deps.mayChangeModel(auth))
13
+ return json(res, 403, { error: "On this Cloud only its owner can change a bot's model." });
14
+ const body = await readBody(req);
15
+ if (!body || typeof body !== "object" || Array.isArray(body) || Object.keys(body).some((key) => key !== "threadIds")) {
16
+ return json(res, 400, { error: "send {} or { threadIds }" });
17
+ }
18
+ const raw = body.threadIds;
19
+ if (raw !== undefined && (!Array.isArray(raw) || raw.length > MAX_THREAD_IDS || raw.some((id) => typeof id !== "string"))) {
20
+ return json(res, 400, { error: "threadIds must be a list of this bot's thread ids" });
21
+ }
22
+ const tasks = bot.tasks ?? [];
23
+ const ids = new Set(tasks.map((task) => task.threadId));
24
+ const foreign = raw?.find((id) => !ids.has(id));
25
+ if (foreign !== undefined)
26
+ return json(res, 400, { error: `"${foreign}" is not one of this bot's threads` });
27
+ if (bot.approvalGrant)
28
+ return json(res, 409, { error: "wait for the approval-level change to finish before changing models" });
29
+ const listed = raw === undefined ? null : new Set(raw);
30
+ const own = tasks.filter((task) => (!listed || listed.has(task.threadId)) &&
31
+ task.modelSelection !== undefined && !sameModelSelection(task.modelSelection, bot.modelSelection));
32
+ const busy = own.filter((task) => deps.busy(bot.id, task.threadId));
33
+ const switched = deps.follow(bot.id, own.filter((task) => !busy.includes(task)).map((task) => task.threadId));
34
+ return json(res, 200, { switched: switched.length, busy: busy.length, bot: deps.reply(bot.id) });
35
+ };
36
+ }
@@ -0,0 +1,17 @@
1
+ import { PASS } from "./table.js";
2
+ export function createUndoRoutes(deps) {
3
+ return async ({ req, res, path, method, auth, json, readBody }) => {
4
+ const m = path.match(/^\/api\/threads\/([\w-]+)\/undo$/);
5
+ if (!m || method !== "POST")
6
+ return PASS;
7
+ const threadId = m[1];
8
+ const body = await readBody(req);
9
+ const requestId = typeof body?.requestId === "string" ? body.requestId : "";
10
+ if (!requestId)
11
+ return json(res, 400, { error: "requestId is required" });
12
+ const refusal = deps.refusal(auth, threadId, requestId);
13
+ if (refusal)
14
+ return json(res, 403, { error: refusal });
15
+ deps.undo(auth, res, threadId, requestId);
16
+ };
17
+ }
@@ -4,6 +4,7 @@ import { z } from "zod";
4
4
  import { cronScheduleLabel } from "../shared/cron-label.js";
5
5
  import { normalizeCronSchedule, nextCronRuns } from "../shared/routine-schedule.js";
6
6
  import { newId } from "./contracts.js";
7
+ import { SELF_ROUTINE_CAP, UNDO_STALE } from "./direct-apply.js";
7
8
  import { redactSecretsInText } from "./redact.js";
8
9
  import { parseJson, schemaIssue } from "./schema.js";
9
10
  import { intervalHasRestrictions, nextOccurrence, } from "./routines.js";
@@ -200,6 +201,19 @@ const storedOperationSchema = z.discriminatedUnion("action", [
200
201
  z.object({ action: z.literal("run_now"), ...storedManageBase }).strict(),
201
202
  z.object({ action: z.literal("delete"), ...storedManageBase }).strict(),
202
203
  ]);
204
+ const storedSnapshotSchema = storedDefinitionSchema.extend({
205
+ enabled: z.boolean(),
206
+ target: z.literal("room-goal").optional(),
207
+ groupId: z.string().min(1).max(128).optional(),
208
+ resultsThreadId: z.string().min(1).max(128).optional(),
209
+ }).strict();
210
+ const storedUndoSchema = z.object({
211
+ name: z.string().max(200),
212
+ schedule: storedScheduleSchema.optional(),
213
+ appliedUpdatedAt: z.number().int().nonnegative().optional(),
214
+ before: storedSnapshotSchema.optional(),
215
+ ownersBefore: z.boolean().optional(),
216
+ }).strict();
203
217
  const routineRequestCardDataSchema = z.object({
204
218
  version: z.literal(1),
205
219
  requestId: z.string().min(1).max(128),
@@ -209,6 +223,7 @@ const routineRequestCardDataSchema = z.object({
209
223
  operation: storedOperationSchema,
210
224
  appliedAt: z.number().int().nonnegative().optional(),
211
225
  resultId: z.string().min(1).max(128).optional(),
226
+ undo: storedUndoSchema.optional(),
212
227
  }).strict();
213
228
  export class RoutineRequestError extends Error {
214
229
  status;
@@ -896,6 +911,47 @@ function revalidateOperation(operation, manager, botId, now) {
896
911
  }
897
912
  }
898
913
  }
914
+ /** The routine as it stands, kept for Undo. None when it carries what a
915
+ * card cannot hold exactly: attachments, or credential-shaped text the
916
+ * transcript scrubs. */
917
+ function routineSnapshot(routine) {
918
+ if (routine.attachments?.length)
919
+ return undefined;
920
+ if (redactSecretsInText(routine.name) !== routine.name || redactSecretsInText(routine.prompt) !== routine.prompt)
921
+ return undefined;
922
+ const snapshot = {
923
+ name: routine.name,
924
+ instructions: routine.prompt,
925
+ schedule: structuredClone(routine.schedule),
926
+ runOn: routine.runOn,
927
+ durationMinutes: routine.durationMinutes,
928
+ ...(routine.timeoutMinutes === undefined ? {} : { timeoutMinutes: routine.timeoutMinutes }),
929
+ ...(routine.continuity ? { continuity: true } : {}),
930
+ ...(routine.overlap === "queue" ? { overlap: "queue" } : {}),
931
+ enabled: routine.enabled,
932
+ ...(routine.target === "room-goal" ? { target: "room-goal" } : {}),
933
+ ...(routine.groupId ? { groupId: routine.groupId } : {}),
934
+ ...(routine.resultsThreadId ? { resultsThreadId: routine.resultsThreadId } : {}),
935
+ };
936
+ return storedSnapshotSchema.safeParse(snapshot).success ? snapshot : undefined;
937
+ }
938
+ /** Puts an updated routine's definition back exactly: an interval's
939
+ * restrictions are cleared explicitly, since an omitted one is kept. */
940
+ function restorePatch(before, now) {
941
+ const schedule = asSchedule(before.schedule, now);
942
+ return {
943
+ name: before.name,
944
+ prompt: before.instructions,
945
+ runOn: before.runOn,
946
+ schedule: schedule.type === "interval"
947
+ ? { ...schedule, weekdays: schedule.weekdays ?? null, window: schedule.window ?? null, endsAt: schedule.endsAt ?? null }
948
+ : schedule,
949
+ durationMinutes: before.durationMinutes,
950
+ timeoutMinutes: before.timeoutMinutes ?? null,
951
+ continuity: before.continuity === true,
952
+ overlap: before.overlap ?? "skip",
953
+ };
954
+ }
899
955
  export class RoutineRequestService {
900
956
  store;
901
957
  routines;
@@ -968,18 +1024,27 @@ export class RoutineRequestService {
968
1024
  };
969
1025
  if (args.from)
970
1026
  messageInput.from = args.from;
1027
+ // Resolve the current source-thread grant after the asynchronous probe.
1028
+ const owner = operation.forBot?.botId ?? botId;
1029
+ const grant = submitted ? this.autoApply?.(botId, threadId, owner) ?? null : null;
1030
+ // A bot applying its own routines keeps at most SELF_ROUTINE_CAP of them
1031
+ // on; a create or resume past that shows the card, as before. Full
1032
+ // access has no cap.
1033
+ const automatic = grant === "full-access" || (grant === "self" && !this.overSelfCap(operation, owner));
971
1034
  // This check and append are deliberately adjacent and synchronous. JS
972
1035
  // cannot interleave another completed proposal between the capacity /
973
1036
  // ownership decision and the durable transcript write.
974
- const persistence = this.canPersist?.(botId, threadId);
1037
+ const persistence = this.canPersist?.(botId, threadId, !automatic);
975
1038
  if (persistence && !persistence.ok) {
976
1039
  throw new RoutineRequestError(persistence.error, persistence.status);
977
1040
  }
978
1041
  if (args.canCommit && !args.canCommit()) {
979
1042
  throw new RoutineRequestError("The requesting turn ended before this proposal could be saved", 401);
980
1043
  }
981
- // Resolve the current source-thread grant after the asynchronous probe.
982
- const automatic = submitted && this.autoApply?.(botId, threadId) === true;
1044
+ // What Undo puts back, taken before the change.
1045
+ const before = automatic && (operation.action === "update" || operation.action === "delete")
1046
+ ? this.snapshotOf(operation.routineId, owner)
1047
+ : undefined;
983
1048
  if (automatic) {
984
1049
  messageInput.card.options = [];
985
1050
  messageInput.card.dismissed = true;
@@ -1005,8 +1070,10 @@ export class RoutineRequestService {
1005
1070
  catch (error) {
1006
1071
  result = { claimed: true, state: "invalid", error: error instanceof Error ? error.message : String(error), status: error instanceof RoutineRequestError ? error.status : 400 };
1007
1072
  }
1008
- if (result.state === "applied")
1009
- return { ...proposal, result };
1073
+ if (result.state === "applied") {
1074
+ this.recordAutoApplied(threadId, message.id, definition, before);
1075
+ return { ...proposal, result, ...(grant ? { appliedBy: grant } : {}) };
1076
+ }
1010
1077
  // The scheduler commit can succeed even if settling its transcript
1011
1078
  // fails. Report that exact result; a retry only finishes the receipt.
1012
1079
  const receipt = this.routines.routineRequestReceipt(requestId);
@@ -1015,10 +1082,147 @@ export class RoutineRequestService {
1015
1082
  return { ...proposal, result: {
1016
1083
  claimed: true, state: "applied", action: receipt.action, resultId: receipt.resultId,
1017
1084
  settlementPending: true, message: "Routine change applied. Recording the operation receipt could not finish; the change will not be applied again.",
1018
- } };
1085
+ }, ...(grant ? { appliedBy: grant } : {}) };
1019
1086
  }
1020
1087
  throw new RoutineRequestError(result.state === "invalid" ? result.error : "The routine change could not be applied", result.state === "invalid" ? result.status : 409);
1021
1088
  }
1089
+ /** Whether one more enabled routine would take the bot past the cap. */
1090
+ overSelfCap(operation, owner) {
1091
+ if (operation.action !== "create" && operation.action !== "resume")
1092
+ return false;
1093
+ const enabled = this.routines.listRoutines().filter((routine) => routine.botId === owner && routine.enabled).length;
1094
+ return enabled + 1 > SELF_ROUTINE_CAP;
1095
+ }
1096
+ snapshotOf(routineId, owner) {
1097
+ const routine = ownedRoutine(this.routines, routineId, owner);
1098
+ return routine ? routineSnapshot(routine) : undefined;
1099
+ }
1100
+ /** Marks a card whose change applied without a person, with what its
1101
+ * one-line receipt and Undo need. A failure here leaves the change
1102
+ * applied and the card as it was, only without Undo. */
1103
+ recordAutoApplied(threadId, messageId, definition, before) {
1104
+ try {
1105
+ const message = this.store.messagesFor(threadId).find((candidate) => candidate.id === messageId);
1106
+ const card = message?.card;
1107
+ const payload = card?.routineRequest;
1108
+ if (!message || !card || !payload)
1109
+ return;
1110
+ const action = payload.operation.action;
1111
+ const routineId = payload.operation.action === "create" ? payload.resultId : payload.operation.routineId;
1112
+ const after = routineId ? this.routines.listRoutines().find((routine) => routine.id === routineId) : undefined;
1113
+ const undo = {
1114
+ name: redactSecretsInText(after?.name ?? definition?.name ?? before?.name ?? "routine"),
1115
+ ...(action === "create" || action === "update" || action === "resume"
1116
+ ? { schedule: structuredClone(after?.schedule ?? definition?.schedule) }
1117
+ : {}),
1118
+ ...(after && (action === "update" || action === "pause" || action === "resume") ? { appliedUpdatedAt: after.updatedAt } : {}),
1119
+ ...(before ? { before } : {}),
1120
+ };
1121
+ if (!storedUndoSchema.safeParse(undo).success)
1122
+ delete undo.schedule;
1123
+ this.store.patchMessage(threadId, messageId, {
1124
+ card: { ...card, autoApplied: true, routineRequest: { ...payload, undo } },
1125
+ });
1126
+ }
1127
+ catch {
1128
+ // The routine change itself is durable; only its Undo is lost.
1129
+ }
1130
+ }
1131
+ /** Puts back a change that applied without a person. Authorized by the
1132
+ * caller exactly like answering the card; refuses, applying nothing, once
1133
+ * the routine changed since. A second Undo reports already undone. */
1134
+ undo(args) {
1135
+ const message = this.store
1136
+ .messagesFor(args.threadId)
1137
+ .find((candidate) => candidate.card?.requestId === args.requestId && candidate.card.routineRequest);
1138
+ const card = message?.card;
1139
+ if (!message || !card)
1140
+ return { claimed: false };
1141
+ if (card.undone)
1142
+ return { claimed: true, state: "already_undone" };
1143
+ const cannot = (error, status = 409) => ({ claimed: true, state: "invalid", error, status });
1144
+ if (!card.autoApplied || card.answered !== "allow")
1145
+ return cannot("Only a change that applied on its own can be undone here.");
1146
+ const parsed = routineRequestCardDataSchema.safeParse(card.routineRequest);
1147
+ if (!parsed.success)
1148
+ return cannot("This change can't be undone here.");
1149
+ const payload = parsed.data;
1150
+ if (payload.botId !== args.botId || payload.threadId !== args.threadId) {
1151
+ return cannot("This routine change belongs to another conversation", 403);
1152
+ }
1153
+ const operation = payload.operation;
1154
+ const owner = operation.forBot?.botId ?? payload.botId;
1155
+ const undo = payload.undo;
1156
+ const stale = { claimed: true, state: "invalid", error: UNDO_STALE, status: 409, stale: true };
1157
+ const now = this.now();
1158
+ let routineId;
1159
+ let restoredId;
1160
+ try {
1161
+ switch (operation.action) {
1162
+ case "run_now":
1163
+ return cannot("A routine run can't be undone.");
1164
+ case "create": {
1165
+ routineId = payload.resultId ?? "";
1166
+ if (!routineId || !ownedRoutine(this.routines, routineId, owner))
1167
+ return stale;
1168
+ this.routines.remove(routineId);
1169
+ break;
1170
+ }
1171
+ case "update":
1172
+ case "pause":
1173
+ case "resume": {
1174
+ routineId = operation.routineId;
1175
+ if (undo?.appliedUpdatedAt === undefined || (operation.action === "update" && !undo.before)) {
1176
+ return cannot("This change can't be undone here.");
1177
+ }
1178
+ const current = ownedRoutine(this.routines, routineId, owner);
1179
+ if (!current || current.updatedAt !== undo.appliedUpdatedAt)
1180
+ return stale;
1181
+ const patch = operation.action === "update"
1182
+ ? restorePatch(undo.before, now)
1183
+ : { enabled: operation.action === "pause" };
1184
+ if (!this.routines.update(routineId, patch))
1185
+ return stale;
1186
+ break;
1187
+ }
1188
+ case "delete": {
1189
+ routineId = operation.routineId;
1190
+ const before = undo?.before;
1191
+ if (!before)
1192
+ return cannot("This change can't be undone here.");
1193
+ restoredId = this.routines.create({
1194
+ name: before.name,
1195
+ prompt: before.instructions,
1196
+ botId: owner,
1197
+ ...(before.target ? { target: before.target, groupId: before.groupId } : {}),
1198
+ runOn: before.runOn,
1199
+ enabled: before.enabled,
1200
+ schedule: asSchedule(before.schedule, now),
1201
+ durationMinutes: before.durationMinutes,
1202
+ ...(before.timeoutMinutes === undefined ? {} : { timeoutMinutes: before.timeoutMinutes }),
1203
+ ...(before.continuity ? { continuity: true } : {}),
1204
+ ...(before.overlap === "queue" ? { overlap: "queue" } : {}),
1205
+ ...(before.resultsThreadId ? { resultsThreadId: before.resultsThreadId } : {}),
1206
+ }).id;
1207
+ break;
1208
+ }
1209
+ default:
1210
+ return cannot("This change can't be undone here.");
1211
+ }
1212
+ }
1213
+ catch (error) {
1214
+ return cannot(redactSecretsInText(error instanceof Error ? error.message : String(error)).slice(0, 500));
1215
+ }
1216
+ this.store.patchMessage(args.threadId, message.id, { card: { ...card, undone: true } });
1217
+ return {
1218
+ claimed: true,
1219
+ state: "undone",
1220
+ action: operation.action,
1221
+ routineId,
1222
+ ...(restoredId ? { restoredId } : {}),
1223
+ ...(undo?.ownersBefore !== undefined ? { ownersBefore: undo.ownersBefore } : {}),
1224
+ };
1225
+ }
1022
1226
  async requireCloudReadiness(operation, proposerBotId) {
1023
1227
  if (!this.cloudReady || operation.action === "pause" || operation.action === "delete")
1024
1228
  return;
@@ -943,7 +943,7 @@ export class RoutineManager {
943
943
  this.commitMutation(() => {
944
944
  run = this.newRun(routine, this.now(), true, allocations, request?.threadId ?? routine.sourceThreadId);
945
945
  // Preserve the invoking chat as provenance/fallback for this run.
946
- // An explicitly configured results destination continues to win.
946
+ // The routine's results destination continues to win.
947
947
  if (request)
948
948
  run.sourceThreadId = request.threadId;
949
949
  if (request)
@@ -1546,7 +1546,7 @@ export class RoutineManager {
1546
1546
  if (value === null) {
1547
1547
  const destination = this.options.resolveResultsThread?.(routine, true);
1548
1548
  if (!destination)
1549
- throw new Error("Could not create a results thread for this routine");
1549
+ throw new Error("Could not find a results thread for this routine");
1550
1550
  routine.resultsThreadId = destination;
1551
1551
  return () => this.options.discardResultsThread?.(routine.botId, destination);
1552
1552
  }
@@ -45,7 +45,7 @@ function folderClause(cwd) {
45
45
  function buildSetupPrompt(profileAside, cwd) {
46
46
  return ("\n\nThe user explicitly asked you to set yourself up. For this setup request, help configure the bot from what the user tells you." +
47
47
  ` First ask at most four questions that change what you would build: what the job is, when it should happen (on demand, on a schedule, or when something arrives), which apps or accounts it touches, and ${folderClause(cwd)}.` +
48
- " Then, before any tool call, tell the user in plain language what you intend: who you will be, what you will do and when, where you will work, what you will need from them, and what you will not do. Ask for missing choices, not an extra yes for already-requested actions under granted Full Access." +
48
+ " Then, before any tool call, tell the user in plain language what you intend: who you will be, what you will do and when, where you will work, what you will need from them, and what you will not do. Ask for missing choices, not an extra yes for already-requested actions: changes to your own profile and routines apply immediately, and the person sees each with an Undo." +
49
49
  " First send one message describing the changes you are about to request, then make the tool calls. Follow each result: if applied, continue without another confirmation; if pending, end the turn and wait for its in-app decision. Do not repeat the list or claim success from the permission mode alone." +
50
50
  ` Use propose_profile for your identity, standing rules ${profileAside}, and the working folder (cwd), propose_routine only for a schedule the user requested, and request_credential for any missing token.` +
51
51
  " Full Access does not supply answers, credentials, or broader permissions for another bot. A credential request still needs the user's secure entry. Report failed or cancelled changes honestly." +
@@ -1,6 +1,6 @@
1
1
  // `/learn` — turn a described workflow, URL, folder, or "what we just did"
2
2
  // into a reusable SKILL.md. The live agent authors the skill with skill_manage;
3
- // the harness applies it under granted Full Access or stages a pending review.
3
+ // the harness applies it (a bot's own skill applies at any level) or stages a pending review.
4
4
  //
5
5
  // There is no separate distillation engine. This module only builds the
6
6
  // prompt and recognises the slash command, so it works on every engine
@@ -61,7 +61,7 @@ export function buildLearnPrompt(userRequest) {
61
61
  "1. Inventory every source the user named, using the tools you already have — file tools for local paths, web fetch for URLs, and this conversation if they referred to something you just did. If the request is ambiguous about scope, make a reasonable choice and note it; do not stall.\n" +
62
62
  "2. Check existing skills with skills_list. If one already covers this topic, leave it alone unless the user explicitly asked to revise that named learned/editable skill. For an explicit revision, read only the exact SKILL.md path listed for that skill in your system prompt (the native .agents/skills/<exact-name>/SKILL.md link is a fallback), preserve every still-valid step, re-verify what changed, then call skill_manage with action=\"update\" and skill_name set to that exact name. If you cannot read or verify the current skill, stop instead of replacing it from memory. For a genuinely new skill, use action=\"create\".\n" +
63
63
  "3. Pass source as the exact URL or folder you used, or \"conversation\" when the conversation is the source.\n" +
64
- "4. Follow the skill_manage result: with granted Full Access it may apply immediately. After an applied result, continue the requested work without another confirmation. If review is pending, a create stays inactive and an update leaves the current version untouched; end the turn and wait for the in-app decision. Never claim success from the permission mode alone, and report failed or cancelled changes honestly.\n\n" +
64
+ "4. Follow the skill_manage result: your own skill changes apply immediately and the person sees them with an Undo. After an applied result, continue the requested work without another confirmation. If review is pending, a create stays inactive and an update leaves the current version untouched; end the turn and wait for the in-app decision. Never claim success from the permission mode alone, and report failed or cancelled changes honestly.\n\n" +
65
65
  AUTHORING_STANDARDS +
66
66
  "\n\nWhen done, tell the user the skill name and a one-line summary of what it captured.");
67
67
  }
@@ -29,7 +29,7 @@ import { createHash, randomUUID } from "node:crypto";
29
29
  import { closeSync, constants, existsSync, fstatSync, lstatSync, mkdirSync, openSync, readdirSync, readFileSync, readlinkSync, realpathSync, renameSync, rmSync, symlinkSync, unlinkSync, writeFileSync, } from "node:fs";
30
30
  import { dirname, join, relative, resolve } from "node:path";
31
31
  import { z } from "zod";
32
- import { writeFileAtomic } from "./atomic.js";
32
+ import { writeFileAtomic, writeFileAtomicIfChanged } from "./atomic.js";
33
33
  import { DATA_DIR } from "./config.js";
34
34
  import { redactSecretsInText } from "./redact.js";
35
35
  import { LEARN_SOURCE_PREFIX } from "./skill-learn.js";
@@ -191,9 +191,10 @@ function readManagedLinks(botId) {
191
191
  return [];
192
192
  }
193
193
  }
194
+ // Rebuilt on every turn and almost always the same list.
194
195
  function writeManagedLinks(botId, names) {
195
196
  mkdirSync(skillStateDir(botId), { recursive: true, mode: 0o700 });
196
- writeFileAtomic(managedLinksPath(botId), `${JSON.stringify([...new Set(names)].sort(), null, 2)}\n`, { mode: 0o600 });
197
+ writeFileAtomicIfChanged(managedLinksPath(botId), `${JSON.stringify([...new Set(names)].sort(), null, 2)}\n`, { mode: 0o600 });
197
198
  }
198
199
  function manifestFromFile(path) {
199
200
  try {
@@ -1188,6 +1189,36 @@ export function applySkillWriteWithReceipt(botId, staged, recordApplied) {
1188
1189
  message: "Skill change applied. Recording its receipt or cleaning up staging could not finish; do not apply it again." };
1189
1190
  }
1190
1191
  }
1192
+ /** Undo for a learned-skill write that applied without a person: a create
1193
+ * is removed; an update gets the SKILL.md it replaced back, as a fresh
1194
+ * revision through the same stage and apply path. Only while the skill is
1195
+ * exactly as that write left it; otherwise `stale`, and nothing changes. */
1196
+ export function undoSkillWrite(botId, write) {
1197
+ const entry = readManifest(botId)[write.name];
1198
+ if (!entry || entry.appliedStageId !== write.stagedId || !installedLearnedSkillMatches(botId, write.name, entry)) {
1199
+ return { stale: true };
1200
+ }
1201
+ if (write.action === "create") {
1202
+ const removed = removeSkill(botId, write.name);
1203
+ return "error" in removed ? removed : { undone: true };
1204
+ }
1205
+ if (!write.previous)
1206
+ return { error: "This change can't be undone here." };
1207
+ const staged = stageSkillWrite(botId, {
1208
+ action: "update",
1209
+ targetName: write.name,
1210
+ files: [{ path: "SKILL.md", content: write.previous.skillMd }],
1211
+ source: write.previous.source,
1212
+ });
1213
+ if ("error" in staged)
1214
+ return staged;
1215
+ const applied = applyStagedSkillWrite(botId, staged.id, { expectedSha256: staged.sha256 });
1216
+ if ("error" in applied) {
1217
+ rejectStagedSkillWrite(botId, staged.id);
1218
+ return applied;
1219
+ }
1220
+ return { undone: true };
1221
+ }
1191
1222
  /** The skills block appended to a bot's system prompt: enabled skills only,
1192
1223
  * index lines only — the same progressive-disclosure shape the spec asks
1193
1224
  * agents for. Bodies never ride the prompt; the bot reads the file when a