termdock 1.4.43 → 1.4.46

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 (90) hide show
  1. package/.desktop-dist/main.js +95 -27
  2. package/dist/client/assets/{abnfDiagram-VRR7QNED-B3X7vTL7.js → abnfDiagram-VRR7QNED-In9dJ8xk.js} +1 -1
  3. package/dist/client/assets/{arc-OmYbmu75.js → arc-OgDXNUfC.js} +1 -1
  4. package/dist/client/assets/{architectureDiagram-ZJ3FMSHR-CNNIlew_.js → architectureDiagram-ZJ3FMSHR-CUHWXG-6.js} +1 -1
  5. package/dist/client/assets/{blockDiagram-677ZJIJ3-eoDvsGst.js → blockDiagram-677ZJIJ3-D6iMCZrE.js} +1 -1
  6. package/dist/client/assets/{c4Diagram-LMCZKHZV-BYElS7nn.js → c4Diagram-LMCZKHZV-BQIYSHIO.js} +1 -1
  7. package/dist/client/assets/channel-DR9ZrrsH.js +1 -0
  8. package/dist/client/assets/{chunk-2Q5K7J3B-DgBhC1KN.js → chunk-2Q5K7J3B-VrJ2oEjG.js} +1 -1
  9. package/dist/client/assets/{chunk-32BRIVSS-B4LjEHPP.js → chunk-32BRIVSS-DgE4tlwU.js} +1 -1
  10. package/dist/client/assets/{chunk-5VM5RSS4-BrBK8Xy3.js → chunk-5VM5RSS4-DPL1VUbd.js} +1 -1
  11. package/dist/client/assets/{chunk-EX3LRPZG-QndtZFQ6.js → chunk-EX3LRPZG-Cnzcl0zo.js} +1 -1
  12. package/dist/client/assets/{chunk-JWPE2WC7-B8bZHm4g.js → chunk-JWPE2WC7-BwjoHnSm.js} +1 -1
  13. package/dist/client/assets/{chunk-MOJQB5TN-B5Kzsd5Z.js → chunk-MOJQB5TN-Q1VspcHf.js} +1 -1
  14. package/dist/client/assets/{chunk-RYQCIY6F-BdNa9gwg.js → chunk-RYQCIY6F-C3B0hROO.js} +1 -1
  15. package/dist/client/assets/{chunk-V7JOEXUC-DpQA4l-k.js → chunk-V7JOEXUC-CT1WyL44.js} +1 -1
  16. package/dist/client/assets/{chunk-VR4S4FIN-CtGdy3K8.js → chunk-VR4S4FIN-RHg32W0I.js} +1 -1
  17. package/dist/client/assets/{chunk-XXDRQBXY-CZBBj4P_.js → chunk-XXDRQBXY-B8nloyVH.js} +1 -1
  18. package/dist/client/assets/classDiagram-OUVF2IWQ-CSyi0dnm.js +1 -0
  19. package/dist/client/assets/classDiagram-v2-EOCWNBFH-CSyi0dnm.js +1 -0
  20. package/dist/client/assets/{cose-bilkent-JH36ORCC-gtzwCMyn.js → cose-bilkent-JH36ORCC-DM9b-HC2.js} +1 -1
  21. package/dist/client/assets/{cynefin-VYW2F7L2-B7X5gKj-.js → cynefin-VYW2F7L2-DyfTbIta.js} +1 -1
  22. package/dist/client/assets/{cynefinDiagram-TSTJHNR4-BoKfaePi.js → cynefinDiagram-TSTJHNR4-B0TfoSKo.js} +1 -1
  23. package/dist/client/assets/{dagre-VKFMJZFB-Bjh8y-RO.js → dagre-VKFMJZFB-DoYxgTE_.js} +1 -1
  24. package/dist/client/assets/{diagram-FQU43EPY-Cx8vWSw0.js → diagram-FQU43EPY-BhdYoO5s.js} +1 -1
  25. package/dist/client/assets/{diagram-G47NLZAW-DyKuyGsn.js → diagram-G47NLZAW-DU-PG20h.js} +1 -1
  26. package/dist/client/assets/{diagram-NH7WQ7WH-DwnG0pD9.js → diagram-NH7WQ7WH-WcnJXUD6.js} +1 -1
  27. package/dist/client/assets/{diagram-OA4YK3LP-wn7Eux1Q.js → diagram-OA4YK3LP-N1S0AWUf.js} +1 -1
  28. package/dist/client/assets/{diagram-WEI45ONY-DNy0FovQ.js → diagram-WEI45ONY-DBhEABdQ.js} +1 -1
  29. package/dist/client/assets/{ebnfDiagram-CCIWWBDH-TFnZlH4k.js → ebnfDiagram-CCIWWBDH-CPhAEOjW.js} +1 -1
  30. package/dist/client/assets/{erDiagram-Q63AITRT-Cx3_8T9Q.js → erDiagram-Q63AITRT-416GnX06.js} +1 -1
  31. package/dist/client/assets/{flowDiagram-23GEKE2U-CZ7KiBe4.js → flowDiagram-23GEKE2U-CQY7Be4e.js} +1 -1
  32. package/dist/client/assets/{ganttDiagram-NO4QXBWP-BRTRytgo.js → ganttDiagram-NO4QXBWP-CCdUVGY1.js} +1 -1
  33. package/dist/client/assets/{gitGraphDiagram-IHSO6WYX-DyNUwP6-.js → gitGraphDiagram-IHSO6WYX-DihTneNH.js} +1 -1
  34. package/dist/client/assets/index-DyTRm1PJ.css +1 -0
  35. package/dist/client/assets/index-SiGQTF6y.js +436 -0
  36. package/dist/client/assets/{infoDiagram-FWYZ7A6U-ClLiuIL8.js → infoDiagram-FWYZ7A6U-DxVtT8XS.js} +1 -1
  37. package/dist/client/assets/{ishikawaDiagram-FXEZZL3T-CbO_ecRd.js → ishikawaDiagram-FXEZZL3T-CI04eDRq.js} +1 -1
  38. package/dist/client/assets/{journeyDiagram-5HDEW3XC-YKjq3svJ.js → journeyDiagram-5HDEW3XC-Dku9Ke-J.js} +1 -1
  39. package/dist/client/assets/{kanban-definition-HUTT4EX6-CcnV3jvx.js → kanban-definition-HUTT4EX6-X-7cHaWp.js} +1 -1
  40. package/dist/client/assets/{linear-3N9evV-e.js → linear-BfhGmqE2.js} +1 -1
  41. package/dist/client/assets/{mermaid.core-C8HeTU54.js → mermaid.core-lwiCvpBd.js} +4 -4
  42. package/dist/client/assets/{mindmap-definition-LN4V7U3C-CgkCCxMO.js → mindmap-definition-LN4V7U3C-DI3swXAM.js} +1 -1
  43. package/dist/client/assets/{pegDiagram-2B236MQR-CQRK4LBF.js → pegDiagram-2B236MQR-ByBkCa7g.js} +1 -1
  44. package/dist/client/assets/{pieDiagram-ENE6RG2P-BHrDXKeR.js → pieDiagram-ENE6RG2P-CAbocCk6.js} +1 -1
  45. package/dist/client/assets/{quadrantDiagram-ABIIQ3AL-CuJ9UyOO.js → quadrantDiagram-ABIIQ3AL-lE4NNIct.js} +1 -1
  46. package/dist/client/assets/{railroadDiagram-RFXS5EU6-D0lUBYT1.js → railroadDiagram-RFXS5EU6-DVG7K2hA.js} +1 -1
  47. package/dist/client/assets/{requirementDiagram-TGXJPOKE-s5kYB_Ya.js → requirementDiagram-TGXJPOKE-BhjZccsb.js} +1 -1
  48. package/dist/client/assets/{sankeyDiagram-HTMAVEWB-Bhw1mAOH.js → sankeyDiagram-HTMAVEWB-BROBV7xf.js} +1 -1
  49. package/dist/client/assets/{sequenceDiagram-DBY2YBRQ-qnNrmb6g.js → sequenceDiagram-DBY2YBRQ-DCiUXSQK.js} +1 -1
  50. package/dist/client/assets/{sizeCapture-X5ZJPWSS-DufN5SxK.js → sizeCapture-X5ZJPWSS-wCRp1dLA.js} +1 -1
  51. package/dist/client/assets/{stateDiagram-2N3HPSRC-Y5rMnVoS.js → stateDiagram-2N3HPSRC-GnItAgu1.js} +1 -1
  52. package/dist/client/assets/stateDiagram-v2-6OUMAXLB-DodZ2p7d.js +1 -0
  53. package/dist/client/assets/{swimlanes-5IMT3BWC-Cmrmdfpk.js → swimlanes-5IMT3BWC-DbXlO1IP.js} +2 -2
  54. package/dist/client/assets/swimlanesDiagram-G3AALYLV-Dh3DdtaE.js +8 -0
  55. package/dist/client/assets/{timeline-definition-FHXFAJF6-CqHH1NSC.js → timeline-definition-FHXFAJF6-CQjgTVIW.js} +1 -1
  56. package/dist/client/assets/{vennDiagram-L72KCM5P-C2l_9LuC.js → vennDiagram-L72KCM5P-Bz_Lzf5a.js} +1 -1
  57. package/dist/client/assets/{wardleyDiagram-EHGQE667-CNf23qHc.js → wardleyDiagram-EHGQE667-Cgw3S7By.js} +1 -1
  58. package/dist/client/assets/{xychartDiagram-FW5EYKEG-RIp6RoVE.js → xychartDiagram-FW5EYKEG-IyZJ_VfA.js} +1 -1
  59. package/dist/client/icons/agents/kimi.svg +5 -0
  60. package/dist/client/index.html +3 -3
  61. package/dist/client/sw-notifications.js +163 -36
  62. package/dist/client/sw.js +1 -1
  63. package/dist/server/agent/installers.js +145 -1
  64. package/dist/server/agent/registry.js +3 -0
  65. package/dist/server/cli.js +25 -0
  66. package/dist/server/entry.js +53 -13
  67. package/dist/server/notifications/pushService.js +121 -35
  68. package/dist/server/notifications/pushViewers.js +44 -0
  69. package/dist/server/ptyHost.js +17 -0
  70. package/dist/server/ptyhost/manager.js +152 -5
  71. package/dist/server/quota/tokenDiscovery.js +25 -0
  72. package/dist/server/routes/filesystem.js +4 -2
  73. package/dist/server/routes/notifications.js +9 -3
  74. package/dist/server/routes/terminal.js +82 -106
  75. package/dist/server/utils/contextDraft.js +36 -0
  76. package/dist/server/utils/requestDeadline.js +104 -0
  77. package/dist/server/utils/runtimeClient.js +41 -0
  78. package/dist/server/utils/settings.js +18 -9
  79. package/package.json +5 -2
  80. package/runtime-manifest.json +12 -0
  81. package/scripts/classify-release.mjs +88 -0
  82. package/scripts/generate-runtime-manifest.mjs +77 -0
  83. package/scripts/prepare-desktop-runtime.mjs +27 -3
  84. package/dist/client/assets/channel-DBZQbHSi.js +0 -1
  85. package/dist/client/assets/classDiagram-OUVF2IWQ-BsrNzS08.js +0 -1
  86. package/dist/client/assets/classDiagram-v2-EOCWNBFH-BsrNzS08.js +0 -1
  87. package/dist/client/assets/index-CbYQuue6.css +0 -1
  88. package/dist/client/assets/index-DB-0aiWT.js +0 -433
  89. package/dist/client/assets/stateDiagram-v2-6OUMAXLB-BSqYeylv.js +0 -1
  90. package/dist/client/assets/swimlanesDiagram-G3AALYLV-CUwNpVXZ.js +0 -8
package/dist/client/sw.js CHANGED
@@ -1 +1 @@
1
- if(!self.define){let s,e={};const i=(i,l)=>(i=new URL(i+".js",l).href,e[i]||new Promise(e=>{if("document"in self){const s=document.createElement("script");s.src=i,s.onload=e,document.head.appendChild(s)}else s=i,importScripts(i),e()}).then(()=>{let s=e[i];if(!s)throw new Error(`Module ${i} didn’t register its module`);return s}));self.define=(l,n)=>{const r=s||("document"in self?document.currentScript.src:"")||location.href;if(e[r])return;let a={};const o=s=>i(s,r),u={module:{uri:r},exports:a,require:o};e[r]=Promise.all(l.map(s=>u[s]||o(s))).then(s=>(n(...s),a))}}define(["./workbox-9c191d2f"],function(s){"use strict";importScripts("sw-notifications.js"),self.skipWaiting(),s.clientsClaim(),s.precacheAndRoute([{url:"sw-notifications.js",revision:"2ed386d64dc020bf9a7da8efd9dbea42"},{url:"registerSW.js",revision:"1872c500de691dce40960bb85481de07"},{url:"pwa-64x64.png",revision:"c1ca9f6daa67743b38564b230314277a"},{url:"pwa-512x512.svg",revision:"149a151133f52feb34ab6ecedf349936"},{url:"pwa-512x512.png",revision:"0885dd7ec8932e7f878b013d51a380a4"},{url:"pwa-192x192.svg",revision:"541ace289ca5d6f3d269d1286cde5283"},{url:"pwa-192x192.png",revision:"4d6f899888cfb8ccd7a1fd3c9e583ad2"},{url:"maskable-icon-512x512.png",revision:"4d489331fd81f0713c400b26426442b9"},{url:"index.html",revision:"75a3a2ea7df85d2ed6ccce0deb75df09"},{url:"favicon.ico",revision:"2994debfa6f59a0898e24eb0c54d64b5"},{url:"apple-touch-icon-180x180.png",revision:"628c2e2f28a9b545aa57be1352025643"},{url:"icons/agents/opencode.svg",revision:"851c2931d95821ba2b39b68587b48976"},{url:"icons/agents/grok.svg",revision:"cd745b0b964545bc7a6b4f36021c3298"},{url:"icons/agents/goose.svg",revision:"c79b927278983c19098d77b4b0c11ab3"},{url:"icons/agents/gemini.svg",revision:"7a64f6d6f80a908255e9c0256903882e"},{url:"icons/agents/droid.svg",revision:"f28723b8c5c115e0908ba3c72613e256"},{url:"icons/agents/cursor.svg",revision:"a1528f3d3cda497f75a5db28defb19de"},{url:"icons/agents/copilot.svg",revision:"dd52e96c1eac0b6ec4bedcd0ddd3b52d"},{url:"icons/agents/codex.svg",revision:"608e55babb0b217e1f2da287342b46d3"},{url:"icons/agents/claude.svg",revision:"08af0225b7acdd8e8f573f3247e5e1c3"},{url:"icons/agents/amp.svg",revision:"af12f8b33faa81e4d46ea7b93c7e43f3"},{url:"fonts/TermdockStarSymbol-Subset.woff2",revision:"853a8d84112dd97a91d6cff1e7ab6bdf"},{url:"fonts/SymbolsNerdFontMono-Regular.woff2",revision:"54113ea8487e607f9d9a482c5877aed4"},{url:"fonts/NotoSansSymbols2-Subset.woff2",revision:"8257a6beabcc8858199b208908a96ee9"},{url:"fonts/NotoSansMonoCJKsc-Subset.woff2",revision:"e52357967aa973c04cce881c50cce0c8"},{url:"fonts/NotoSansMonoCJKsc-Bold-Subset.woff2",revision:"7e37d6b9fb1339898c00ac3b49c8b12e"},{url:"fonts/JetBrainsMonoNLNerdFontMono-Regular.ttf",revision:"ed6fa47e3c1fc9aa68e9015a5300419f"},{url:"fonts/JetBrainsMonoNLNerdFontMono-Italic.ttf",revision:"5624a73ef0a476e93ef5949dd6e452e1"},{url:"fonts/JetBrainsMonoNLNerdFontMono-BoldItalic.ttf",revision:"9b7603423a37fd2f544f75e9669689a0"},{url:"fonts/JetBrainsMonoNLNerdFontMono-Bold.ttf",revision:"7deed80e7a4195a51f2c0b82aa364e97"},{url:"fonts/JetBrainsMonoNL-Regular.woff2",revision:"3bb268888f64810d496dd10295d4337c"},{url:"fonts/JetBrainsMonoNL-Italic.woff2",revision:"e035d3c7673175237d40687fc14d5b40"},{url:"fonts/JetBrainsMonoNL-BoldItalic.woff2",revision:"bc3577cc820eaef00d9a985058bca2b7"},{url:"fonts/JetBrainsMonoNL-Bold.woff2",revision:"7c0305a4db8f2977b061631755556ec0"},{url:"assets/xychartDiagram-FW5EYKEG-RIp6RoVE.js",revision:null},{url:"assets/wardleyDiagram-EHGQE667-CNf23qHc.js",revision:null},{url:"assets/vennDiagram-L72KCM5P-C2l_9LuC.js",revision:null},{url:"assets/timeline-definition-FHXFAJF6-CqHH1NSC.js",revision:null},{url:"assets/terminal-C7X98Amf.js",revision:null},{url:"assets/swimlanesDiagram-G3AALYLV-CUwNpVXZ.js",revision:null},{url:"assets/swimlanes-5IMT3BWC-Cmrmdfpk.js",revision:null},{url:"assets/stateDiagram-v2-6OUMAXLB-BSqYeylv.js",revision:null},{url:"assets/stateDiagram-2N3HPSRC-Y5rMnVoS.js",revision:null},{url:"assets/sizeCapture-X5ZJPWSS-DufN5SxK.js",revision:null},{url:"assets/sequenceDiagram-DBY2YBRQ-qnNrmb6g.js",revision:null},{url:"assets/sankeyDiagram-HTMAVEWB-Bhw1mAOH.js",revision:null},{url:"assets/requirementDiagram-TGXJPOKE-s5kYB_Ya.js",revision:null},{url:"assets/react-XDCjal2T.js",revision:null},{url:"assets/railroadDiagram-RFXS5EU6-D0lUBYT1.js",revision:null},{url:"assets/quadrantDiagram-ABIIQ3AL-CuJ9UyOO.js",revision:null},{url:"assets/purify.es-CC4Brkr_.js",revision:null},{url:"assets/pieDiagram-ENE6RG2P-BHrDXKeR.js",revision:null},{url:"assets/pegDiagram-2B236MQR-CQRK4LBF.js",revision:null},{url:"assets/ordinal-Cboi1Yqb.js",revision:null},{url:"assets/mindmap-definition-LN4V7U3C-CgkCCxMO.js",revision:null},{url:"assets/mermaid.core-C8HeTU54.js",revision:null},{url:"assets/map-BdqsVdb3.js",revision:null},{url:"assets/linear-3N9evV-e.js",revision:null},{url:"assets/layout-1eBIAoSl.js",revision:null},{url:"assets/katex-HP8lGamR.js",revision:null},{url:"assets/katex-DnlPpQZa.js",revision:null},{url:"assets/katex-55ZPZeOF.css",revision:null},{url:"assets/kanban-definition-HUTT4EX6-CcnV3jvx.js",revision:null},{url:"assets/journeyDiagram-5HDEW3XC-YKjq3svJ.js",revision:null},{url:"assets/ishikawaDiagram-FXEZZL3T-CbO_ecRd.js",revision:null},{url:"assets/init-Gi6I4Gst.js",revision:null},{url:"assets/infoDiagram-FWYZ7A6U-ClLiuIL8.js",revision:null},{url:"assets/index-DB-0aiWT.js",revision:null},{url:"assets/index-CbYQuue6.css",revision:null},{url:"assets/index-Ca-rq7yX.js",revision:null},{url:"assets/graph-D2o_JWn5.js",revision:null},{url:"assets/gitGraphDiagram-IHSO6WYX-DyNUwP6-.js",revision:null},{url:"assets/ganttDiagram-NO4QXBWP-BRTRytgo.js",revision:null},{url:"assets/flowDiagram-23GEKE2U-CZ7KiBe4.js",revision:null},{url:"assets/erDiagram-Q63AITRT-Cx3_8T9Q.js",revision:null},{url:"assets/ebnfDiagram-CCIWWBDH-TFnZlH4k.js",revision:null},{url:"assets/dnd-BCFAPC0L.js",revision:null},{url:"assets/diffWorker-BFIcKxCt.js",revision:null},{url:"assets/diagram-WEI45ONY-DNy0FovQ.js",revision:null},{url:"assets/diagram-OA4YK3LP-wn7Eux1Q.js",revision:null},{url:"assets/diagram-NH7WQ7WH-DwnG0pD9.js",revision:null},{url:"assets/diagram-G47NLZAW-DyKuyGsn.js",revision:null},{url:"assets/diagram-FQU43EPY-Cx8vWSw0.js",revision:null},{url:"assets/defaultLocale-CrowFXzY.js",revision:null},{url:"assets/dagre-VKFMJZFB-Bjh8y-RO.js",revision:null},{url:"assets/cytoscape.esm-D3_iZ_3b.js",revision:null},{url:"assets/cynefinDiagram-TSTJHNR4-BoKfaePi.js",revision:null},{url:"assets/cynefin-VYW2F7L2-B7X5gKj-.js",revision:null},{url:"assets/cose-bilkent-JH36ORCC-gtzwCMyn.js",revision:null},{url:"assets/classDiagram-v2-EOCWNBFH-BsrNzS08.js",revision:null},{url:"assets/classDiagram-OUVF2IWQ-BsrNzS08.js",revision:null},{url:"assets/chunk-XXDRQBXY-CZBBj4P_.js",revision:null},{url:"assets/chunk-VR4S4FIN-CtGdy3K8.js",revision:null},{url:"assets/chunk-V7JOEXUC-DpQA4l-k.js",revision:null},{url:"assets/chunk-RYQCIY6F-BdNa9gwg.js",revision:null},{url:"assets/chunk-MOJQB5TN-B5Kzsd5Z.js",revision:null},{url:"assets/chunk-JWPE2WC7-B8bZHm4g.js",revision:null},{url:"assets/chunk-EX3LRPZG-QndtZFQ6.js",revision:null},{url:"assets/chunk-5VM5RSS4-BrBK8Xy3.js",revision:null},{url:"assets/chunk-32BRIVSS-B4LjEHPP.js",revision:null},{url:"assets/chunk-2Q5K7J3B-DgBhC1KN.js",revision:null},{url:"assets/channel-DBZQbHSi.js",revision:null},{url:"assets/c4Diagram-LMCZKHZV-BYElS7nn.js",revision:null},{url:"assets/blockDiagram-677ZJIJ3-eoDvsGst.js",revision:null},{url:"assets/architectureDiagram-ZJ3FMSHR-CNNIlew_.js",revision:null},{url:"assets/arc-OmYbmu75.js",revision:null},{url:"assets/abnfDiagram-VRR7QNED-B3X7vTL7.js",revision:null},{url:"assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf",revision:null},{url:"assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2",revision:null},{url:"assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2",revision:null},{url:"assets/KaTeX_Size4-Regular-DWFBv043.ttf",revision:null},{url:"assets/KaTeX_Size3-Regular-DgpXs0kz.ttf",revision:null},{url:"assets/KaTeX_Size2-Regular-Dy4dx90m.woff2",revision:null},{url:"assets/KaTeX_Size2-Regular-B7gKUWhC.ttf",revision:null},{url:"assets/KaTeX_Size1-Regular-mCD8mA8B.woff2",revision:null},{url:"assets/KaTeX_Size1-Regular-Dbsnue_I.ttf",revision:null},{url:"assets/KaTeX_Script-Regular-D3wIWfF6.woff2",revision:null},{url:"assets/KaTeX_Script-Regular-C5JkGWo-.ttf",revision:null},{url:"assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2",revision:null},{url:"assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf",revision:null},{url:"assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf",revision:null},{url:"assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2",revision:null},{url:"assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2",revision:null},{url:"assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf",revision:null},{url:"assets/KaTeX_Math-Italic-t53AETM-.woff2",revision:null},{url:"assets/KaTeX_Math-Italic-flOr_0UB.ttf",revision:null},{url:"assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2",revision:null},{url:"assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf",revision:null},{url:"assets/KaTeX_Main-Regular-ypZvNtVU.ttf",revision:null},{url:"assets/KaTeX_Main-Regular-B22Nviop.woff2",revision:null},{url:"assets/KaTeX_Main-Italic-NWA7e6Wa.woff2",revision:null},{url:"assets/KaTeX_Main-Italic-3WenGoN9.ttf",revision:null},{url:"assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf",revision:null},{url:"assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2",revision:null},{url:"assets/KaTeX_Main-Bold-waoOVXN0.ttf",revision:null},{url:"assets/KaTeX_Main-Bold-Cx986IdX.woff2",revision:null},{url:"assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2",revision:null},{url:"assets/KaTeX_Fraktur-Regular-CB_wures.ttf",revision:null},{url:"assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2",revision:null},{url:"assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf",revision:null},{url:"assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf",revision:null},{url:"assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2",revision:null},{url:"assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2",revision:null},{url:"assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf",revision:null},{url:"assets/KaTeX_AMS-Regular-DRggAlZN.ttf",revision:null},{url:"assets/KaTeX_AMS-Regular-BQhdFMY1.woff2",revision:null},{url:"apple-touch-icon-180x180.png",revision:"628c2e2f28a9b545aa57be1352025643"},{url:"favicon.ico",revision:"2994debfa6f59a0898e24eb0c54d64b5"},{url:"maskable-icon-512x512.png",revision:"4d489331fd81f0713c400b26426442b9"},{url:"pwa-192x192.png",revision:"4d6f899888cfb8ccd7a1fd3c9e583ad2"},{url:"pwa-512x512.png",revision:"0885dd7ec8932e7f878b013d51a380a4"},{url:"robots.txt",revision:"d9339907142917dee4aac78494ac9cfe"},{url:"sw-notifications.js",revision:"2ed386d64dc020bf9a7da8efd9dbea42"},{url:"fonts/JetBrainsMonoNL-Bold.woff2",revision:"7c0305a4db8f2977b061631755556ec0"},{url:"fonts/JetBrainsMonoNL-BoldItalic.woff2",revision:"bc3577cc820eaef00d9a985058bca2b7"},{url:"fonts/JetBrainsMonoNL-Italic.woff2",revision:"e035d3c7673175237d40687fc14d5b40"},{url:"fonts/JetBrainsMonoNL-Regular.woff2",revision:"3bb268888f64810d496dd10295d4337c"},{url:"fonts/JetBrainsMonoNLNerdFontMono-Bold.ttf",revision:"7deed80e7a4195a51f2c0b82aa364e97"},{url:"fonts/JetBrainsMonoNLNerdFontMono-BoldItalic.ttf",revision:"9b7603423a37fd2f544f75e9669689a0"},{url:"fonts/JetBrainsMonoNLNerdFontMono-Italic.ttf",revision:"5624a73ef0a476e93ef5949dd6e452e1"},{url:"fonts/JetBrainsMonoNLNerdFontMono-Regular.ttf",revision:"ed6fa47e3c1fc9aa68e9015a5300419f"},{url:"fonts/NotoSansMonoCJKsc-Bold-Subset.woff2",revision:"7e37d6b9fb1339898c00ac3b49c8b12e"},{url:"fonts/NotoSansMonoCJKsc-Subset.woff2",revision:"e52357967aa973c04cce881c50cce0c8"},{url:"fonts/NotoSansSymbols2-Subset.woff2",revision:"8257a6beabcc8858199b208908a96ee9"},{url:"fonts/SymbolsNerdFontMono-Regular.woff2",revision:"54113ea8487e607f9d9a482c5877aed4"},{url:"fonts/TermdockStarSymbol-Subset.woff2",revision:"853a8d84112dd97a91d6cff1e7ab6bdf"},{url:"manifest.webmanifest",revision:"83f9a43b74c236012adafb077fb6d774"}],{}),s.cleanupOutdatedCaches(),s.registerRoute(new s.NavigationRoute(s.createHandlerBoundToURL("index.html"),{denylist:[/^\/api\//,/^\/health$/]}))});
1
+ if(!self.define){let s,e={};const i=(i,l)=>(i=new URL(i+".js",l).href,e[i]||new Promise(e=>{if("document"in self){const s=document.createElement("script");s.src=i,s.onload=e,document.head.appendChild(s)}else s=i,importScripts(i),e()}).then(()=>{let s=e[i];if(!s)throw new Error(`Module ${i} didn’t register its module`);return s}));self.define=(l,n)=>{const r=s||("document"in self?document.currentScript.src:"")||location.href;if(e[r])return;let a={};const o=s=>i(s,r),t={module:{uri:r},exports:a,require:o};e[r]=Promise.all(l.map(s=>t[s]||o(s))).then(s=>(n(...s),a))}}define(["./workbox-9c191d2f"],function(s){"use strict";importScripts("sw-notifications.js"),self.skipWaiting(),s.clientsClaim(),s.precacheAndRoute([{url:"sw-notifications.js",revision:"91964c9b57d28d34a4e9e4911f8d72d8"},{url:"registerSW.js",revision:"1872c500de691dce40960bb85481de07"},{url:"pwa-64x64.png",revision:"c1ca9f6daa67743b38564b230314277a"},{url:"pwa-512x512.svg",revision:"149a151133f52feb34ab6ecedf349936"},{url:"pwa-512x512.png",revision:"0885dd7ec8932e7f878b013d51a380a4"},{url:"pwa-192x192.svg",revision:"541ace289ca5d6f3d269d1286cde5283"},{url:"pwa-192x192.png",revision:"4d6f899888cfb8ccd7a1fd3c9e583ad2"},{url:"maskable-icon-512x512.png",revision:"4d489331fd81f0713c400b26426442b9"},{url:"index.html",revision:"f7ad5f4b46b1b9f639610dac37df8a1b"},{url:"favicon.ico",revision:"2994debfa6f59a0898e24eb0c54d64b5"},{url:"apple-touch-icon-180x180.png",revision:"628c2e2f28a9b545aa57be1352025643"},{url:"icons/agents/opencode.svg",revision:"851c2931d95821ba2b39b68587b48976"},{url:"icons/agents/kimi.svg",revision:"5366c710f4f763022fe159a69cf17409"},{url:"icons/agents/grok.svg",revision:"cd745b0b964545bc7a6b4f36021c3298"},{url:"icons/agents/goose.svg",revision:"c79b927278983c19098d77b4b0c11ab3"},{url:"icons/agents/gemini.svg",revision:"7a64f6d6f80a908255e9c0256903882e"},{url:"icons/agents/droid.svg",revision:"f28723b8c5c115e0908ba3c72613e256"},{url:"icons/agents/cursor.svg",revision:"a1528f3d3cda497f75a5db28defb19de"},{url:"icons/agents/copilot.svg",revision:"dd52e96c1eac0b6ec4bedcd0ddd3b52d"},{url:"icons/agents/codex.svg",revision:"608e55babb0b217e1f2da287342b46d3"},{url:"icons/agents/claude.svg",revision:"08af0225b7acdd8e8f573f3247e5e1c3"},{url:"icons/agents/amp.svg",revision:"af12f8b33faa81e4d46ea7b93c7e43f3"},{url:"fonts/TermdockStarSymbol-Subset.woff2",revision:"853a8d84112dd97a91d6cff1e7ab6bdf"},{url:"fonts/SymbolsNerdFontMono-Regular.woff2",revision:"54113ea8487e607f9d9a482c5877aed4"},{url:"fonts/NotoSansSymbols2-Subset.woff2",revision:"8257a6beabcc8858199b208908a96ee9"},{url:"fonts/NotoSansMonoCJKsc-Subset.woff2",revision:"e52357967aa973c04cce881c50cce0c8"},{url:"fonts/NotoSansMonoCJKsc-Bold-Subset.woff2",revision:"7e37d6b9fb1339898c00ac3b49c8b12e"},{url:"fonts/JetBrainsMonoNLNerdFontMono-Regular.ttf",revision:"ed6fa47e3c1fc9aa68e9015a5300419f"},{url:"fonts/JetBrainsMonoNLNerdFontMono-Italic.ttf",revision:"5624a73ef0a476e93ef5949dd6e452e1"},{url:"fonts/JetBrainsMonoNLNerdFontMono-BoldItalic.ttf",revision:"9b7603423a37fd2f544f75e9669689a0"},{url:"fonts/JetBrainsMonoNLNerdFontMono-Bold.ttf",revision:"7deed80e7a4195a51f2c0b82aa364e97"},{url:"fonts/JetBrainsMonoNL-Regular.woff2",revision:"3bb268888f64810d496dd10295d4337c"},{url:"fonts/JetBrainsMonoNL-Italic.woff2",revision:"e035d3c7673175237d40687fc14d5b40"},{url:"fonts/JetBrainsMonoNL-BoldItalic.woff2",revision:"bc3577cc820eaef00d9a985058bca2b7"},{url:"fonts/JetBrainsMonoNL-Bold.woff2",revision:"7c0305a4db8f2977b061631755556ec0"},{url:"assets/xychartDiagram-FW5EYKEG-IyZJ_VfA.js",revision:null},{url:"assets/wardleyDiagram-EHGQE667-Cgw3S7By.js",revision:null},{url:"assets/vennDiagram-L72KCM5P-Bz_Lzf5a.js",revision:null},{url:"assets/timeline-definition-FHXFAJF6-CQjgTVIW.js",revision:null},{url:"assets/terminal-C7X98Amf.js",revision:null},{url:"assets/swimlanesDiagram-G3AALYLV-Dh3DdtaE.js",revision:null},{url:"assets/swimlanes-5IMT3BWC-DbXlO1IP.js",revision:null},{url:"assets/stateDiagram-v2-6OUMAXLB-DodZ2p7d.js",revision:null},{url:"assets/stateDiagram-2N3HPSRC-GnItAgu1.js",revision:null},{url:"assets/sizeCapture-X5ZJPWSS-wCRp1dLA.js",revision:null},{url:"assets/sequenceDiagram-DBY2YBRQ-DCiUXSQK.js",revision:null},{url:"assets/sankeyDiagram-HTMAVEWB-BROBV7xf.js",revision:null},{url:"assets/requirementDiagram-TGXJPOKE-BhjZccsb.js",revision:null},{url:"assets/react-XDCjal2T.js",revision:null},{url:"assets/railroadDiagram-RFXS5EU6-DVG7K2hA.js",revision:null},{url:"assets/quadrantDiagram-ABIIQ3AL-lE4NNIct.js",revision:null},{url:"assets/purify.es-CC4Brkr_.js",revision:null},{url:"assets/pieDiagram-ENE6RG2P-CAbocCk6.js",revision:null},{url:"assets/pegDiagram-2B236MQR-ByBkCa7g.js",revision:null},{url:"assets/ordinal-Cboi1Yqb.js",revision:null},{url:"assets/mindmap-definition-LN4V7U3C-DI3swXAM.js",revision:null},{url:"assets/mermaid.core-lwiCvpBd.js",revision:null},{url:"assets/map-BdqsVdb3.js",revision:null},{url:"assets/linear-BfhGmqE2.js",revision:null},{url:"assets/layout-1eBIAoSl.js",revision:null},{url:"assets/katex-HP8lGamR.js",revision:null},{url:"assets/katex-DnlPpQZa.js",revision:null},{url:"assets/katex-55ZPZeOF.css",revision:null},{url:"assets/kanban-definition-HUTT4EX6-X-7cHaWp.js",revision:null},{url:"assets/journeyDiagram-5HDEW3XC-Dku9Ke-J.js",revision:null},{url:"assets/ishikawaDiagram-FXEZZL3T-CI04eDRq.js",revision:null},{url:"assets/init-Gi6I4Gst.js",revision:null},{url:"assets/infoDiagram-FWYZ7A6U-DxVtT8XS.js",revision:null},{url:"assets/index-SiGQTF6y.js",revision:null},{url:"assets/index-DyTRm1PJ.css",revision:null},{url:"assets/index-Ca-rq7yX.js",revision:null},{url:"assets/graph-D2o_JWn5.js",revision:null},{url:"assets/gitGraphDiagram-IHSO6WYX-DihTneNH.js",revision:null},{url:"assets/ganttDiagram-NO4QXBWP-CCdUVGY1.js",revision:null},{url:"assets/flowDiagram-23GEKE2U-CQY7Be4e.js",revision:null},{url:"assets/erDiagram-Q63AITRT-416GnX06.js",revision:null},{url:"assets/ebnfDiagram-CCIWWBDH-CPhAEOjW.js",revision:null},{url:"assets/dnd-BCFAPC0L.js",revision:null},{url:"assets/diffWorker-BFIcKxCt.js",revision:null},{url:"assets/diagram-WEI45ONY-DBhEABdQ.js",revision:null},{url:"assets/diagram-OA4YK3LP-N1S0AWUf.js",revision:null},{url:"assets/diagram-NH7WQ7WH-WcnJXUD6.js",revision:null},{url:"assets/diagram-G47NLZAW-DU-PG20h.js",revision:null},{url:"assets/diagram-FQU43EPY-BhdYoO5s.js",revision:null},{url:"assets/defaultLocale-CrowFXzY.js",revision:null},{url:"assets/dagre-VKFMJZFB-DoYxgTE_.js",revision:null},{url:"assets/cytoscape.esm-D3_iZ_3b.js",revision:null},{url:"assets/cynefinDiagram-TSTJHNR4-B0TfoSKo.js",revision:null},{url:"assets/cynefin-VYW2F7L2-DyfTbIta.js",revision:null},{url:"assets/cose-bilkent-JH36ORCC-DM9b-HC2.js",revision:null},{url:"assets/classDiagram-v2-EOCWNBFH-CSyi0dnm.js",revision:null},{url:"assets/classDiagram-OUVF2IWQ-CSyi0dnm.js",revision:null},{url:"assets/chunk-XXDRQBXY-B8nloyVH.js",revision:null},{url:"assets/chunk-VR4S4FIN-RHg32W0I.js",revision:null},{url:"assets/chunk-V7JOEXUC-CT1WyL44.js",revision:null},{url:"assets/chunk-RYQCIY6F-C3B0hROO.js",revision:null},{url:"assets/chunk-MOJQB5TN-Q1VspcHf.js",revision:null},{url:"assets/chunk-JWPE2WC7-BwjoHnSm.js",revision:null},{url:"assets/chunk-EX3LRPZG-Cnzcl0zo.js",revision:null},{url:"assets/chunk-5VM5RSS4-DPL1VUbd.js",revision:null},{url:"assets/chunk-32BRIVSS-DgE4tlwU.js",revision:null},{url:"assets/chunk-2Q5K7J3B-VrJ2oEjG.js",revision:null},{url:"assets/channel-DR9ZrrsH.js",revision:null},{url:"assets/c4Diagram-LMCZKHZV-BQIYSHIO.js",revision:null},{url:"assets/blockDiagram-677ZJIJ3-D6iMCZrE.js",revision:null},{url:"assets/architectureDiagram-ZJ3FMSHR-CUHWXG-6.js",revision:null},{url:"assets/arc-OgDXNUfC.js",revision:null},{url:"assets/abnfDiagram-VRR7QNED-In9dJ8xk.js",revision:null},{url:"assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf",revision:null},{url:"assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2",revision:null},{url:"assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2",revision:null},{url:"assets/KaTeX_Size4-Regular-DWFBv043.ttf",revision:null},{url:"assets/KaTeX_Size3-Regular-DgpXs0kz.ttf",revision:null},{url:"assets/KaTeX_Size2-Regular-Dy4dx90m.woff2",revision:null},{url:"assets/KaTeX_Size2-Regular-B7gKUWhC.ttf",revision:null},{url:"assets/KaTeX_Size1-Regular-mCD8mA8B.woff2",revision:null},{url:"assets/KaTeX_Size1-Regular-Dbsnue_I.ttf",revision:null},{url:"assets/KaTeX_Script-Regular-D3wIWfF6.woff2",revision:null},{url:"assets/KaTeX_Script-Regular-C5JkGWo-.ttf",revision:null},{url:"assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2",revision:null},{url:"assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf",revision:null},{url:"assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf",revision:null},{url:"assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2",revision:null},{url:"assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2",revision:null},{url:"assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf",revision:null},{url:"assets/KaTeX_Math-Italic-t53AETM-.woff2",revision:null},{url:"assets/KaTeX_Math-Italic-flOr_0UB.ttf",revision:null},{url:"assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2",revision:null},{url:"assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf",revision:null},{url:"assets/KaTeX_Main-Regular-ypZvNtVU.ttf",revision:null},{url:"assets/KaTeX_Main-Regular-B22Nviop.woff2",revision:null},{url:"assets/KaTeX_Main-Italic-NWA7e6Wa.woff2",revision:null},{url:"assets/KaTeX_Main-Italic-3WenGoN9.ttf",revision:null},{url:"assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf",revision:null},{url:"assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2",revision:null},{url:"assets/KaTeX_Main-Bold-waoOVXN0.ttf",revision:null},{url:"assets/KaTeX_Main-Bold-Cx986IdX.woff2",revision:null},{url:"assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2",revision:null},{url:"assets/KaTeX_Fraktur-Regular-CB_wures.ttf",revision:null},{url:"assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2",revision:null},{url:"assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf",revision:null},{url:"assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf",revision:null},{url:"assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2",revision:null},{url:"assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2",revision:null},{url:"assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf",revision:null},{url:"assets/KaTeX_AMS-Regular-DRggAlZN.ttf",revision:null},{url:"assets/KaTeX_AMS-Regular-BQhdFMY1.woff2",revision:null},{url:"apple-touch-icon-180x180.png",revision:"628c2e2f28a9b545aa57be1352025643"},{url:"favicon.ico",revision:"2994debfa6f59a0898e24eb0c54d64b5"},{url:"maskable-icon-512x512.png",revision:"4d489331fd81f0713c400b26426442b9"},{url:"pwa-192x192.png",revision:"4d6f899888cfb8ccd7a1fd3c9e583ad2"},{url:"pwa-512x512.png",revision:"0885dd7ec8932e7f878b013d51a380a4"},{url:"robots.txt",revision:"d9339907142917dee4aac78494ac9cfe"},{url:"sw-notifications.js",revision:"91964c9b57d28d34a4e9e4911f8d72d8"},{url:"fonts/JetBrainsMonoNL-Bold.woff2",revision:"7c0305a4db8f2977b061631755556ec0"},{url:"fonts/JetBrainsMonoNL-BoldItalic.woff2",revision:"bc3577cc820eaef00d9a985058bca2b7"},{url:"fonts/JetBrainsMonoNL-Italic.woff2",revision:"e035d3c7673175237d40687fc14d5b40"},{url:"fonts/JetBrainsMonoNL-Regular.woff2",revision:"3bb268888f64810d496dd10295d4337c"},{url:"fonts/JetBrainsMonoNLNerdFontMono-Bold.ttf",revision:"7deed80e7a4195a51f2c0b82aa364e97"},{url:"fonts/JetBrainsMonoNLNerdFontMono-BoldItalic.ttf",revision:"9b7603423a37fd2f544f75e9669689a0"},{url:"fonts/JetBrainsMonoNLNerdFontMono-Italic.ttf",revision:"5624a73ef0a476e93ef5949dd6e452e1"},{url:"fonts/JetBrainsMonoNLNerdFontMono-Regular.ttf",revision:"ed6fa47e3c1fc9aa68e9015a5300419f"},{url:"fonts/NotoSansMonoCJKsc-Bold-Subset.woff2",revision:"7e37d6b9fb1339898c00ac3b49c8b12e"},{url:"fonts/NotoSansMonoCJKsc-Subset.woff2",revision:"e52357967aa973c04cce881c50cce0c8"},{url:"fonts/NotoSansSymbols2-Subset.woff2",revision:"8257a6beabcc8858199b208908a96ee9"},{url:"fonts/SymbolsNerdFontMono-Regular.woff2",revision:"54113ea8487e607f9d9a482c5877aed4"},{url:"fonts/TermdockStarSymbol-Subset.woff2",revision:"853a8d84112dd97a91d6cff1e7ab6bdf"},{url:"manifest.webmanifest",revision:"83f9a43b74c236012adafb077fb6d774"}],{}),s.cleanupOutdatedCaches(),s.registerRoute(new s.NavigationRoute(s.createHandlerBoundToURL("index.html"),{denylist:[/^\/api\//,/^\/health$/]}))});
@@ -19,7 +19,7 @@ import path from 'node:path';
19
19
  import { execFile } from 'node:child_process';
20
20
  import { agentBySlug, isPluginAgent } from './registry.js';
21
21
  import { loadPlugins, resolveHookTarget } from './plugins.js';
22
- export const HOOK_AGENTS = ['claude', 'codex', 'copilot', 'opencode', 'pi', 'grok'];
22
+ export const HOOK_AGENTS = ['claude', 'codex', 'copilot', 'opencode', 'pi', 'grok', 'kimi'];
23
23
  const DISPLAY_NAMES = {
24
24
  claude: 'Claude Code',
25
25
  codex: 'Codex',
@@ -27,6 +27,7 @@ const DISPLAY_NAMES = {
27
27
  opencode: 'OpenCode',
28
28
  pi: 'Pi',
29
29
  grok: 'Grok Build',
30
+ kimi: 'Kimi Code',
30
31
  };
31
32
  // ---------------------------------------------------------------------------
32
33
  // Paths and the hook command line
@@ -58,6 +59,7 @@ function targetPath(agent) {
58
59
  case 'opencode': return path.join(xdgConfigDir(), 'opencode', 'plugins', OWNED_FILE_STEM_JS);
59
60
  case 'pi': return path.join(homeDir(), '.pi', 'agent', 'extensions', 'termdock', 'index.ts');
60
61
  case 'grok': return path.join(homeDir(), '.grok', 'hooks', OWNED_FILE_STEM_JSON);
62
+ case 'kimi': return path.join(homeDir(), '.kimi-code', 'config.toml');
61
63
  }
62
64
  }
63
65
  function abbreviateHome(p) {
@@ -127,6 +129,29 @@ const CODEX_HOOK_EVENTS = [
127
129
  ['UserPromptSubmit', 'prompt-submit'],
128
130
  ['Stop', 'stop'],
129
131
  ];
132
+ /**
133
+ * Kimi Code's hook events (~/.kimi-code/config.toml `[[hooks]]` entries, TOML).
134
+ * `PermissionRequest` is the genuine block (fires right before the approval
135
+ * wait); `PostToolUse` is the way *back* — Kimi has a `PermissionResult`
136
+ * event, but the approved tool completing is the same recovery edge Claude
137
+ * uses, and it keeps the state machine on the shared vocabulary. `Stop` does
138
+ * NOT fire when the user interrupts (Esc) or the turn errors — Kimi sends
139
+ * `Interrupt` / `StopFailure` instead, so both fold onto `stop` to keep the
140
+ * pane from sticking in working.
141
+ */
142
+ export const KIMI_HOOK_EVENTS = [
143
+ ['SessionStart', 'session-start'],
144
+ ['UserPromptSubmit', 'prompt-submit'],
145
+ ['PermissionRequest', 'permission-request'],
146
+ ['PostToolUse', 'tool-complete'],
147
+ ['Stop', 'stop'],
148
+ ['StopFailure', 'stop'],
149
+ ['Interrupt', 'stop'],
150
+ ['SessionEnd', 'session-end'],
151
+ ];
152
+ /** Seconds Kimi gives one termdock hook before killing it (its default is
153
+ * 30s; ours writes a few bytes). */
154
+ const KIMI_HOOK_TIMEOUT_SECS = 5;
130
155
  /**
131
156
  * Grok Build's hook events — Claude Code's vocabulary (grok mirrors it
132
157
  * deliberately, it even reads ~/.claude/settings.json) — plus the matcher
@@ -473,6 +498,113 @@ function ownedFileUninstall(file, mark) {
473
498
  return 'Removed';
474
499
  }
475
500
  // ---------------------------------------------------------------------------
501
+ // TOML hooks installer (Kimi Code): kimi keeps hooks in `[[hooks]]` array-of-
502
+ // tables inside ~/.kimi-code/config.toml — free-form TOML we must NOT rewrite
503
+ // wholesale (comments, ordering, other tables are the user's). So instead of
504
+ // parsing, the file is treated as a sequence of *sections* (a `[table]` /
505
+ // `[[array]]` header line plus the lines up to the next header); termdock
506
+ // owns exactly the sections whose command carries the marker, appends fresh
507
+ // `[[hooks]]` blocks at the end of the file, and never touches the rest.
508
+ // ---------------------------------------------------------------------------
509
+ /** Split TOML text into sections: everything before the first header is one
510
+ * (preamble) section; each later section starts at its header line.
511
+ * `sections.join('\n')` reproduces the input byte-for-byte. */
512
+ function splitTomlSections(text) {
513
+ const lines = text.split('\n');
514
+ const sections = [];
515
+ let current = [];
516
+ for (const line of lines) {
517
+ if (/^\s*\[/.test(line) && current.length > 0) {
518
+ sections.push(current.join('\n'));
519
+ current = [];
520
+ }
521
+ current.push(line);
522
+ }
523
+ sections.push(current.join('\n'));
524
+ return sections;
525
+ }
526
+ /** The `event = "…"` value of a `[[hooks]]` section, if it declares one. */
527
+ function tomlSectionEvent(section) {
528
+ const m = section.match(/^\s*event\s*=\s*"([^"]+)"\s*(?:#.*)?$/m);
529
+ return m ? m[1] : null;
530
+ }
531
+ /** The `command = '…'` value of a `[[hooks]]` section (literal-string form —
532
+ * the only form termdock writes; the command embeds double quotes). */
533
+ function tomlSectionCommand(section) {
534
+ const m = section.match(/^\s*command\s*=\s*'(.*)'\s*(?:#.*)?$/m);
535
+ return m ? m[1] : null;
536
+ }
537
+ /** One `[[hooks]]` block as termdock writes it. Kimi allows exactly the
538
+ * fields event/matcher/command/timeout. */
539
+ function tomlHookBlock(hookEvent, command) {
540
+ return `[[hooks]]\nevent = "${hookEvent}"\ncommand = '${command}'\ntimeout = ${KIMI_HOOK_TIMEOUT_SECS}`;
541
+ }
542
+ function readTextFile(file) {
543
+ try {
544
+ return fs.readFileSync(file, 'utf8');
545
+ }
546
+ catch {
547
+ return null;
548
+ }
549
+ }
550
+ // Exported for tests — the public entry points are hooksState/installHooks/
551
+ // uninstallHooks; these take an explicit file path so tests can use tmp files.
552
+ export function tomlHooksState(file, agent, events) {
553
+ const text = readTextFile(file);
554
+ if (text === null)
555
+ return 'not-installed';
556
+ const mark = marker(agent);
557
+ const ours = splitTomlSections(text).filter((s) => s.includes(mark));
558
+ if (ours.length === 0)
559
+ return 'not-installed';
560
+ for (const [hookEvent, sentinel] of events) {
561
+ const expected = hookCommand(agent, sentinel);
562
+ const ok = ours.some((s) => tomlSectionEvent(s) === hookEvent && tomlSectionCommand(s) === expected);
563
+ if (!ok)
564
+ return 'outdated';
565
+ }
566
+ return 'installed';
567
+ }
568
+ /** Merge termdock's `[[hooks]]` blocks into config.toml, preserving
569
+ * everything else (including the user's own hooks) byte-for-byte. */
570
+ export function tomlHooksInstall(file, agent, events) {
571
+ const text = readTextFile(file) ?? '';
572
+ const mark = marker(agent);
573
+ // Drop any previous termdock blocks (stale exe path / older event set)…
574
+ const kept = splitTomlSections(text).filter((s) => !s.includes(mark));
575
+ let out = kept.join('\n');
576
+ // …then append the fresh set at the end of the file, where new
577
+ // `[[hooks]]` tables can never swallow the user's trailing keys.
578
+ if (out.length > 0 && !out.endsWith('\n'))
579
+ out += '\n';
580
+ if (out.trim().length > 0)
581
+ out += '\n';
582
+ out += events
583
+ .map(([hookEvent, sentinel]) => tomlHookBlock(hookEvent, hookCommand(agent, sentinel)))
584
+ .join('\n\n');
585
+ out += '\n';
586
+ writeAtomic(file, out);
587
+ }
588
+ /** Remove every termdock `[[hooks]]` block, leaving the rest of the file
589
+ * (user hooks included) untouched. */
590
+ export function tomlHooksUninstall(file, agent) {
591
+ const text = readTextFile(file);
592
+ if (text === null)
593
+ return 'Nothing installed; nothing to remove';
594
+ const mark = marker(agent);
595
+ const sections = splitTomlSections(text);
596
+ const removed = sections.filter((s) => s.includes(mark)).length;
597
+ if (removed === 0)
598
+ return 'No termdock hooks found; nothing to remove';
599
+ const out = sections
600
+ .filter((s) => !s.includes(mark))
601
+ .join('\n')
602
+ .replace(/\n{3,}/g, '\n\n')
603
+ .replace(/\n+$/, '\n');
604
+ writeAtomic(file, out);
605
+ return 'Removed';
606
+ }
607
+ // ---------------------------------------------------------------------------
476
608
  // Public API — built-in agents
477
609
  // ---------------------------------------------------------------------------
478
610
  export function hooksState(agent) {
@@ -481,6 +613,8 @@ export function hooksState(agent) {
481
613
  return hookMapState(file, agent, CLAUDE_HOOK_EVENTS);
482
614
  if (agent === 'codex')
483
615
  return hookMapState(file, agent, CODEX_HOOK_EVENTS);
616
+ if (agent === 'kimi')
617
+ return tomlHooksState(file, agent, KIMI_HOOK_EVENTS);
484
618
  const expected = ownedFileContent(agent);
485
619
  if (expected === null)
486
620
  return 'not-installed';
@@ -518,6 +652,13 @@ export async function installHooks(agent) {
518
652
  };
519
653
  }
520
654
  }
655
+ if (agent === 'kimi') {
656
+ tomlHooksInstall(file, agent, KIMI_HOOK_EVENTS);
657
+ return {
658
+ summary: 'Installed — run /reload in any open Kimi session (or restart it) for hooks to take effect',
659
+ devMode,
660
+ };
661
+ }
521
662
  const content = ownedFileContent(agent);
522
663
  if (content === null)
523
664
  throw new Error(`no owned-file integration for ${agent}`);
@@ -529,6 +670,9 @@ export async function uninstallHooks(agent) {
529
670
  if (agent === 'claude' || agent === 'codex') {
530
671
  return hookMapUninstall(file, agent);
531
672
  }
673
+ if (agent === 'kimi') {
674
+ return tomlHooksUninstall(file, agent);
675
+ }
532
676
  return ownedFileUninstall(file, marker(agent));
533
677
  }
534
678
  /** Collect all plugin agents that define hooks. */
@@ -18,6 +18,7 @@ const AGENTS = [
18
18
  { slug: 'antigravity', displayName: 'Antigravity', aliases: ['agy', 'antigravity'], accentColor: '#2563EB', icon: null },
19
19
  { slug: 'grok', displayName: 'Grok', aliases: ['grok'], accentColor: '#000000', icon: 'grok' },
20
20
  { slug: 'qwen', displayName: 'Qwen Code', aliases: ['qwen', 'qwen-code'], accentColor: '#7C3AED', icon: null },
21
+ { slug: 'kimi', displayName: 'Kimi Code', aliases: ['kimi', 'kimi-code'], accentColor: '#000000', icon: 'kimi' },
21
22
  ];
22
23
  const BY_ALIAS = new Map();
23
24
  const BY_SLUG = new Map();
@@ -137,6 +138,7 @@ function resumeCommandFor(agent, sessionId, flags) {
137
138
  case 'cursor': return `cursor-agent${f} --resume ${sessionId}`;
138
139
  case 'copilot': return `copilot${f} --resume ${sessionId}`;
139
140
  case 'grok': return `grok${f} --resume ${sessionId}`;
141
+ case 'kimi': return `kimi${f} --session ${sessionId}`;
140
142
  default: return null;
141
143
  }
142
144
  }
@@ -150,6 +152,7 @@ const STALE_SESSION_FLAGS = {
150
152
  codex: ['--last'],
151
153
  grok: ['--resume', '-r', '--load', '--continue', '-c', '--session-id', '-s',
152
154
  '--fork-session', '--worktree', '-w', '--worktree-ref', '--ref'],
155
+ kimi: ['--session', '-S', '--continue', '-c'],
153
156
  };
154
157
  /**
155
158
  * The launch-flag tail of argv worth replaying on a resume command, or null
@@ -1,4 +1,8 @@
1
1
  #!/usr/bin/env node
2
+ // libuv 线程池默认只有 4 个线程,慢/挂起的异步 IO(fs.promises、crypto 等)
3
+ // 会把池耗尽,表现为整个服务的 IO 全部卡死。必须在任何异步 fs 调用之前
4
+ // 设置(同步 fs 不占线程池,所以放在文件体顶部仍然足够早)。
5
+ process.env.UV_THREADPOOL_SIZE ||= '16';
2
6
  import { config as loadDotenv } from 'dotenv';
3
7
  import os from 'os';
4
8
  import { resolve } from 'path';
@@ -1915,6 +1919,26 @@ async function ensureTmuxFocusEvents() {
1915
1919
  maxBuffer: 64 * 1024,
1916
1920
  });
1917
1921
  }
1922
+ // Let tmux forward modified Enter keys (Ctrl/Shift/Alt+Enter) to pane apps.
1923
+ // The option only exists in tmux >= 3.2; on older versions the probe fails
1924
+ // and we silently skip.
1925
+ async function ensureTmuxExtendedKeys() {
1926
+ try {
1927
+ const { stdout } = await execFileAsync('tmux', ['show-options', '-gqv', 'extended-keys'], {
1928
+ timeout: 5000,
1929
+ maxBuffer: 64 * 1024,
1930
+ });
1931
+ if (stdout.trim() === 'on')
1932
+ return;
1933
+ await execFileAsync('tmux', ['set-option', '-g', 'extended-keys', 'on'], {
1934
+ timeout: 5000,
1935
+ maxBuffer: 64 * 1024,
1936
+ });
1937
+ }
1938
+ catch {
1939
+ // extended-keys unsupported on this tmux; nothing to do
1940
+ }
1941
+ }
1918
1942
  async function ensureTmuxScrollbackProfile(sessionName) {
1919
1943
  await execFileAsync('tmux', ['set-option', '-g', 'history-limit', String(TERMDOCK_TMUX_HISTORY_LIMIT)], {
1920
1944
  timeout: 5000,
@@ -2060,6 +2084,7 @@ async function ensureStampedTmuxSession(sessionName, cwd) {
2060
2084
  });
2061
2085
  }
2062
2086
  await ensureTmuxFocusEvents();
2087
+ await ensureTmuxExtendedKeys();
2063
2088
  await ensureTmuxColorEnvironment(sessionName);
2064
2089
  await ensureTmuxCliSessionOptions(sessionName);
2065
2090
  await setTmuxOption(sessionName, '@termdock-version', TERMDOCK_VERSION);
@@ -22,20 +22,38 @@ import { isUpgradeRequestAuthenticated, requireAuth } from './utils/authProtecti
22
22
  import { localAccessManager } from './utils/localAccess.js';
23
23
  import { isAllowedHost, isUpgradeOriginAllowed, validateHostMiddleware, } from './utils/requestSecurity.js';
24
24
  import { getCookieSecurityOptions, setSecureCookieMode } from './utils/cookieSecurity.js';
25
+ import { requestDeadlineMiddleware } from './utils/requestDeadline.js';
25
26
  import { startOnboardingServer, stopOnboardingServer, getOnboardingServerUrl } from './onboardingServer.js';
26
27
  import { CertificateWatcher } from './certificateWatcher.js';
27
28
  import { writeDiffTraceLog, writeErrorLog, writeJsonLog, writeTextLog } from './utils/serverLogger.js';
29
+ import { resolveRuntimeClientDist } from './utils/runtimeClient.js';
28
30
  import { getTermdockVersion, TERMDOCK_CAPABILITIES, TERMDOCK_PROTOCOL_VERSION, } from './utils/version.js';
29
31
  import { PORT, DEFAULT_HOST } from './config.js';
30
32
  const CLIENT_STATE_COOKIE = 'termdock-client';
31
33
  export const DEFAULT_PORT = PORT.backend;
34
+ /** Read one cookie from a raw Cookie header (upgrade requests bypass the
35
+ * cookie-parser middleware). Values are percent-encoded. */
36
+ function getCookieValue(cookieHeader, name) {
37
+ if (!cookieHeader)
38
+ return undefined;
39
+ const pattern = new RegExp(`(?:^|;\\s*)${name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}=([^;]*)`);
40
+ const match = cookieHeader.match(pattern);
41
+ if (!match)
42
+ return undefined;
43
+ try {
44
+ return decodeURIComponent(match[1]);
45
+ }
46
+ catch {
47
+ return match[1];
48
+ }
49
+ }
32
50
  const CLIENT_LOG_DEDUP_WINDOW_MS = 5_000;
33
51
  const CLIENT_LOG_RATE_WINDOW_MS = 10_000;
34
52
  const CLIENT_LOG_RATE_LIMIT = 120;
35
53
  const currentFilePath = fileURLToPath(import.meta.url);
36
54
  const currentDirPath = path.dirname(currentFilePath);
37
- const clientDistPath = path.resolve(currentDirPath, '../client');
38
- const clientIndexPath = path.join(clientDistPath, 'index.html');
55
+ const bundledClientDistPath = path.resolve(currentDirPath, '../client');
56
+ const bundledClientIndexPath = path.join(bundledClientDistPath, 'index.html');
39
57
  const clientLogRecent = new Map();
40
58
  let clientLogWindowStartedAt = 0;
41
59
  let clientLogWindowCount = 0;
@@ -302,6 +320,9 @@ export function createApp(options = {}) {
302
320
  });
303
321
  next();
304
322
  });
323
+ // 全局请求兜底超时:任何 handler 挂起最多活 30s(长连接流按表豁免),
324
+ // 到期销毁 socket 释放浏览器连接槽。必须在所有路由与静态资源之前挂载。
325
+ app.use(requestDeadlineMiddleware());
305
326
  app.use('/api', (req, res, next) => {
306
327
  // JSON/API responses must never hit browser conditional caching. A 304 with
307
328
  // an empty body breaks fetch().json() callers and looks like random IO
@@ -397,18 +418,36 @@ export function createApp(options = {}) {
397
418
  app.use('/api/terminal', terminalRoutes);
398
419
  // 文件系统路由(继承 /api/terminal 上的 auth + CSRF 保护)
399
420
  app.use('/api/terminal/fs', filesystemRoutes);
400
- if (fs.existsSync(clientIndexPath)) {
401
- app.use(createStaticCompressionMiddleware(clientDistPath));
402
- app.use(express.static(clientDistPath, {
403
- setHeaders: (res, filePath, stat) => {
404
- void stat;
405
- const relativePath = `/${path.relative(clientDistPath, filePath).split(path.sep).join('/')}`;
406
- setStaticCacheHeaders({ url: relativePath, path: relativePath }, res);
407
- },
408
- }));
421
+ if (fs.existsSync(bundledClientIndexPath)) {
422
+ let cachedClientPath = '';
423
+ let cachedCompression = null;
424
+ let cachedStatic = null;
425
+ const activeClientHandlers = () => {
426
+ const clientPath = resolveRuntimeClientDist(bundledClientDistPath);
427
+ if (clientPath !== cachedClientPath || !cachedCompression || !cachedStatic) {
428
+ cachedClientPath = clientPath;
429
+ cachedCompression = createStaticCompressionMiddleware(clientPath);
430
+ cachedStatic = express.static(clientPath, {
431
+ setHeaders: (res, filePath, stat) => {
432
+ void stat;
433
+ const relativePath = `/${path.relative(clientPath, filePath).split(path.sep).join('/')}`;
434
+ setStaticCacheHeaders({ url: relativePath, path: relativePath }, res);
435
+ },
436
+ });
437
+ }
438
+ return { clientPath, compression: cachedCompression, staticFiles: cachedStatic };
439
+ };
440
+ app.use((req, res, next) => {
441
+ const handlers = activeClientHandlers();
442
+ handlers.compression(req, res, (compressionError) => {
443
+ if (compressionError)
444
+ return next(compressionError);
445
+ handlers.staticFiles(req, res, next);
446
+ });
447
+ });
409
448
  app.get(/^(?!\/api(?:\/|$)|\/health$|\/onboarding(?:\/|$)|\/ca(?:\/|$)).*/, (req, res) => {
410
449
  setStaticCacheHeaders(req, res);
411
- res.sendFile(clientIndexPath);
450
+ res.sendFile(path.join(activeClientHandlers().clientPath, 'index.html'));
412
451
  });
413
452
  }
414
453
  return app;
@@ -523,11 +562,12 @@ export function startServer(options = {}) {
523
562
  }
524
563
  const sessionId = match[1];
525
564
  const clientId = crypto.randomUUID();
565
+ const pushClientId = getCookieValue(cookieHeader, CLIENT_STATE_COOKIE);
526
566
  // 短线重连时客户端会带上 ?since=<lastSeq>,让服务端只补发增量。
527
567
  const sinceParam = url.searchParams.get('since');
528
568
  const sinceSeq = sinceParam ? Math.max(0, Number.parseInt(sinceParam, 10) || 0) : 0;
529
569
  wss.handleUpgrade(request, socket, head, (ws) => {
530
- handleTerminalWebSocket(ws, sessionId, clientId, { sinceSeq });
570
+ handleTerminalWebSocket(ws, sessionId, clientId, { sinceSeq, pushClientId });
531
571
  });
532
572
  });
533
573
  server.listen(port, host, () => {