@chainingintention/pi-web-cn 2.202610.4 → 2.202611.1

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 (1010) hide show
  1. package/README.md +4 -2
  2. package/dist/bin/pi-web-server.sh +91 -0
  3. package/dist/bin/pi-web-sessiond.sh +91 -0
  4. package/dist/bin/pi-web.sh +91 -0
  5. package/dist/cli.js +33 -29
  6. package/dist/cli.js.map +1 -1
  7. package/dist/client/assets/3d-Dr68X8h8.svg +1 -0
  8. package/dist/client/assets/PiWebApp-D9e-Nrxi.js +3952 -0
  9. package/dist/client/assets/SettingsDialog-BvlvoXvD.js +1129 -0
  10. package/dist/client/assets/abap-uAHVFerN.svg +1 -0
  11. package/dist/client/assets/abc-CXjdSXsv.svg +1 -0
  12. package/dist/client/assets/actionscript-BCkIwjgm.svg +1 -0
  13. package/dist/client/assets/ada-GL6JWmc_.svg +1 -0
  14. package/dist/client/assets/adobe-illustrator-DhGvkpwi.svg +1 -0
  15. package/dist/client/assets/adobe-photoshop-0hmnA7cm.svg +1 -0
  16. package/dist/client/assets/adobe-swc-myFGSGFT.svg +1 -0
  17. package/dist/client/assets/adonis-SdGYdzCA.svg +1 -0
  18. package/dist/client/assets/advpl-BWLgf_Ky.svg +1 -0
  19. package/dist/client/assets/advpl-include-DYgH3R0u.svg +1 -0
  20. package/dist/client/assets/advpl-ptm-C5Y5ffZi.svg +1 -0
  21. package/dist/client/assets/advpl-tlpp-BAlVwpPL.svg +1 -0
  22. package/dist/client/assets/agent-DAWBwR7s.svg +1 -0
  23. package/dist/client/assets/amplify-BAWPaFFb.svg +1 -0
  24. package/dist/client/assets/android-TigHCxTb.svg +1 -0
  25. package/dist/client/assets/angular-D2ijCUIg.svg +1 -0
  26. package/dist/client/assets/angular-component-eczQQRE6.svg +1 -0
  27. package/dist/client/assets/angular-directive-C_jq8cjP.svg +1 -0
  28. package/dist/client/assets/angular-guard-B4iC5rXF.svg +1 -0
  29. package/dist/client/assets/angular-interceptor-CJvi6DuQ.svg +1 -0
  30. package/dist/client/assets/angular-pipe-BQZMATB_.svg +1 -0
  31. package/dist/client/assets/angular-service-DHYn6jIk.svg +1 -0
  32. package/dist/client/assets/antlr-DkzdiGgY.svg +1 -0
  33. package/dist/client/assets/apiblueprint-BDRvCIBM.svg +1 -0
  34. package/dist/client/assets/apollo-BAVoyYDs.svg +1 -0
  35. package/dist/client/assets/applescript-Bm_R8YT0.svg +1 -0
  36. package/dist/client/assets/apps-script-6efl-CXu.svg +1 -0
  37. package/dist/client/assets/appveyor-6B1suIBr.svg +1 -0
  38. package/dist/client/assets/appwrite-D7AlK8SW.svg +1 -0
  39. package/dist/client/assets/architecture-CtuqF8rD.svg +1 -0
  40. package/dist/client/assets/arduino-DFxCIupZ.svg +1 -0
  41. package/dist/client/assets/asciidoc-DUAdVwVP.svg +1 -0
  42. package/dist/client/assets/assembly-BKikEKKy.svg +1 -0
  43. package/dist/client/assets/astro-Bivf18eC.svg +1 -0
  44. package/dist/client/assets/astro-config-Cr5suFul.svg +1 -0
  45. package/dist/client/assets/astyle-BiqOWu-0.svg +1 -0
  46. package/dist/client/assets/audio-B4FatEUD.svg +1 -0
  47. package/dist/client/assets/aurelia-CnUjHPcZ.svg +1 -0
  48. package/dist/client/assets/authors-DdaDoKVR.svg +1 -0
  49. package/dist/client/assets/auto-BOO_fhxh.svg +1 -0
  50. package/dist/client/assets/autohotkey-D87F33UG.svg +1 -0
  51. package/dist/client/assets/autoit-DQTGS66r.svg +1 -0
  52. package/dist/client/assets/azure-DMSkMABH.svg +1 -0
  53. package/dist/client/assets/azure-pipelines-CcGJw3Rl.svg +1 -0
  54. package/dist/client/assets/babel-DFMbiqHA.svg +1 -0
  55. package/dist/client/assets/ballerina-BT8MyHl8.svg +1 -0
  56. package/dist/client/assets/bashly-settings-Ch9mIpw9.svg +1 -0
  57. package/dist/client/assets/bazel-CPXexffJ.svg +1 -0
  58. package/dist/client/assets/bbx-CB-6IYxw.svg +1 -0
  59. package/dist/client/assets/beancount-DR_GSwds.svg +1 -0
  60. package/dist/client/assets/bench-js-DOHd4EZB.svg +1 -0
  61. package/dist/client/assets/bench-jsx-CLJJl81D.svg +1 -0
  62. package/dist/client/assets/bench-ts-BM8GsfrF.svg +1 -0
  63. package/dist/client/assets/bibliography-D3emS1pd.svg +1 -0
  64. package/dist/client/assets/bibtex-style-CVY4tTiP.svg +1 -0
  65. package/dist/client/assets/bicep-BMMGt18P.svg +1 -0
  66. package/dist/client/assets/biome-Bf2373dl.svg +1 -0
  67. package/dist/client/assets/bitbucket-BQr8Az5R.svg +1 -0
  68. package/dist/client/assets/bithound-BOh7-s-G.svg +1 -0
  69. package/dist/client/assets/blender-B7Vz8gxa.svg +1 -0
  70. package/dist/client/assets/blink-DVWcfhba.svg +1 -0
  71. package/dist/client/assets/blitz-B4hhOxPa.svg +1 -0
  72. package/dist/client/assets/bower-CkFcC1Ou.svg +1 -0
  73. package/dist/client/assets/brainfuck-BXozg9z7.svg +1 -0
  74. package/dist/client/assets/browserlist-CUbhNMS9.svg +1 -0
  75. package/dist/client/assets/bruno-CoSNrNfv.svg +1 -0
  76. package/dist/client/assets/buck-BRuOl0ko.svg +1 -0
  77. package/dist/client/assets/bucklescript-TfoVgTnq.svg +1 -0
  78. package/dist/client/assets/buildkite-BrDKWLhW.svg +1 -0
  79. package/dist/client/assets/bun-CZtgPBjt.svg +1 -0
  80. package/dist/client/assets/c-CCkhSkL9.svg +1 -0
  81. package/dist/client/assets/c3-J0cVtsWq.svg +1 -0
  82. package/dist/client/assets/cabal-CQb4_DnV.svg +1 -0
  83. package/dist/client/assets/caddy-ywaArsUF.svg +1 -0
  84. package/dist/client/assets/cadence-BRBsaulT.svg +1 -0
  85. package/dist/client/assets/cairo-Cls19dwE.svg +1 -0
  86. package/dist/client/assets/cake-DpuWz3gE.svg +1 -0
  87. package/dist/client/assets/capacitor-CugB3p3d.svg +1 -0
  88. package/dist/client/assets/capnp-DtxOZ2_z.svg +1 -0
  89. package/dist/client/assets/cbx-QvSmyWq4.svg +1 -0
  90. package/dist/client/assets/cds-Bi3ghsEA.svg +1 -0
  91. package/dist/client/assets/certificate-B5QPOK_C.svg +1 -0
  92. package/dist/client/assets/changelog-mhp3hE32.svg +1 -0
  93. package/dist/client/assets/chess-4hVz24Rg.svg +1 -0
  94. package/dist/client/assets/chromatic-DRZoj4Hg.svg +1 -0
  95. package/dist/client/assets/chrome-ox3b9yI4.svg +1 -0
  96. package/dist/client/assets/circleci-DubwoSEv.svg +1 -0
  97. package/dist/client/assets/citation-ldCt-JF8.svg +1 -0
  98. package/dist/client/assets/clangd-bL8W2_13.svg +1 -0
  99. package/dist/client/assets/claude-DypBvzkn.svg +1 -0
  100. package/dist/client/assets/cline-Dd7x4bMT.svg +1 -0
  101. package/dist/client/assets/clojure-wfCfR06G.svg +1 -0
  102. package/dist/client/assets/cloudfoundry-BS-9yLUv.svg +1 -0
  103. package/dist/client/assets/cmake-B7q-R28A.svg +1 -0
  104. package/dist/client/assets/coala-D4YHPVOS.svg +1 -0
  105. package/dist/client/assets/cobol-wDz3o6g-.svg +1 -0
  106. package/dist/client/assets/coconut-C7cPswso.svg +1 -0
  107. package/dist/client/assets/code-climate-BJrwzyOv.svg +1 -0
  108. package/dist/client/assets/codecov-CXg1oY95.svg +1 -0
  109. package/dist/client/assets/codeowners-D_rztV49.svg +1 -0
  110. package/dist/client/assets/coderabbit-ai-DGoTDlyw.svg +1 -0
  111. package/dist/client/assets/coffee-D5JGmA63.svg +1 -0
  112. package/dist/client/assets/coldfusion-DhOnvVS_.svg +1 -0
  113. package/dist/client/assets/coloredpetrinets-DY894G_S.svg +1 -0
  114. package/dist/client/assets/command-Df3AkI2A.svg +1 -0
  115. package/dist/client/assets/commitizen-9SU1u7to.svg +1 -0
  116. package/dist/client/assets/commitlint-3vvjpxJt.svg +1 -0
  117. package/dist/client/assets/composerShortcuts-BggqvE9J.js +31 -0
  118. package/dist/client/assets/concourse-DAGkX2vY.svg +1 -0
  119. package/dist/client/assets/conduct-2Bm8RK0N.svg +1 -0
  120. package/dist/client/assets/console-pcgGAn8Z.svg +1 -0
  121. package/dist/client/assets/contentlayer-vXTwXOHk.svg +1 -0
  122. package/dist/client/assets/context-CebLrksE.svg +1 -0
  123. package/dist/client/assets/contributing-DLcmDS34.svg +1 -0
  124. package/dist/client/assets/controller-Doc75EnV.svg +1 -0
  125. package/dist/client/assets/copilot-DBlNrZ6L.svg +1 -0
  126. package/dist/client/assets/cpp-DT2939hp.svg +1 -0
  127. package/dist/client/assets/craco-BySmcQ23.svg +1 -0
  128. package/dist/client/assets/credits-GALyqcNu.svg +1 -0
  129. package/dist/client/assets/crystal-BbNQlJLs.svg +1 -0
  130. package/dist/client/assets/csharp-D5ZKsaqY.svg +1 -0
  131. package/dist/client/assets/css-JKwEyWYb.svg +1 -0
  132. package/dist/client/assets/css-map-Ctu4D9Ve.svg +1 -0
  133. package/dist/client/assets/cucumber-B3ZYwjRe.svg +1 -0
  134. package/dist/client/assets/cuda-CRW2z42A.svg +1 -0
  135. package/dist/client/assets/cue-ni2TTLiZ.svg +1 -0
  136. package/dist/client/assets/cursor-CJahHGg2.svg +1 -0
  137. package/dist/client/assets/cypress-DR0JRbfI.svg +1 -0
  138. package/dist/client/assets/d-B87zyVMx.svg +1 -0
  139. package/dist/client/assets/dart-Dx2oVcaR.svg +1 -0
  140. package/dist/client/assets/dart_generated-Wk58pte9.svg +1 -0
  141. package/dist/client/assets/database-B_oKaDcf.svg +1 -0
  142. package/dist/client/assets/deepsource-DUTIJ9mv.svg +1 -0
  143. package/dist/client/assets/denizenscript-BJc2vgOS.svg +1 -0
  144. package/dist/client/assets/deno-CyFvrzCm.svg +1 -0
  145. package/dist/client/assets/dependabot-BgJkJLU3.svg +1 -0
  146. package/dist/client/assets/dependencies-update-CdGy9ujO.svg +1 -0
  147. package/dist/client/assets/dhall-Dmhh82EO.svg +1 -0
  148. package/dist/client/assets/diff-6SXDCokN.svg +1 -0
  149. package/dist/client/assets/dinophp-D9hQnqAR.svg +1 -0
  150. package/dist/client/assets/disc-h_dLNGEL.svg +1 -0
  151. package/dist/client/assets/django-N1UNAXk1.svg +1 -0
  152. package/dist/client/assets/dll-1DkaBp0q.svg +1 -0
  153. package/dist/client/assets/docker-CfHcr61D.svg +1 -0
  154. package/dist/client/assets/doctex-installer-Cs7SA-ct.svg +1 -0
  155. package/dist/client/assets/document-o-3iA9GQ.svg +1 -0
  156. package/dist/client/assets/dotjs-DIyH7Gzv.svg +1 -0
  157. package/dist/client/assets/drawio-2RVDLi9g.svg +1 -0
  158. package/dist/client/assets/drizzle-hhBCZx1t.svg +1 -0
  159. package/dist/client/assets/drone-KvQ2n-xY.svg +1 -0
  160. package/dist/client/assets/dtx-DdGk8fFj.svg +1 -0
  161. package/dist/client/assets/duc-CHcAZQos.svg +1 -0
  162. package/dist/client/assets/dune-DuGO6qDA.svg +1 -0
  163. package/dist/client/assets/edge-ChHKXrYp.svg +1 -0
  164. package/dist/client/assets/editorconfig-BUzUAwRX.svg +1 -0
  165. package/dist/client/assets/ejs-D_Li05n3.svg +1 -0
  166. package/dist/client/assets/elixir-75mYTx2s.svg +1 -0
  167. package/dist/client/assets/elm-DE_LIp02.svg +1 -0
  168. package/dist/client/assets/email-G8mUttGa.svg +1 -0
  169. package/dist/client/assets/ember-B1y9-Oks.svg +1 -0
  170. package/dist/client/assets/epub-DPvrBCNf.svg +1 -0
  171. package/dist/client/assets/erlang-DosS6spf.svg +1 -0
  172. package/dist/client/assets/esbuild-DV6xNZ-T.svg +1 -0
  173. package/dist/client/assets/eslint-IU_g232-.svg +1 -0
  174. package/dist/client/assets/excalidraw-BllKd-7L.svg +1 -0
  175. package/dist/client/assets/exe-SfcXmkQy.svg +1 -0
  176. package/dist/client/assets/expo-B4PonO4I.svg +1 -0
  177. package/dist/client/assets/external-Bawe0tSn.js +1 -0
  178. package/dist/client/assets/fastlane-C4SZDg50.svg +1 -0
  179. package/dist/client/assets/favicon-VsCcG-A-.svg +1 -0
  180. package/dist/client/assets/figma-C8Gjq2Xj.svg +1 -0
  181. package/dist/client/assets/file-BEIHQH8Q.svg +256 -0
  182. package/dist/client/assets/firebase-DHIO0glR.svg +1 -0
  183. package/dist/client/assets/flash-Dck7x_rj.svg +1 -0
  184. package/dist/client/assets/flow-DD4KQiTg.svg +1 -0
  185. package/dist/client/assets/font-ChbWr8nk.svg +1 -0
  186. package/dist/client/assets/forth-C3qwGqMh.svg +1 -0
  187. package/dist/client/assets/fortran-B0jORJ3v.svg +1 -0
  188. package/dist/client/assets/foxpro-D3Wp1B1h.svg +1 -0
  189. package/dist/client/assets/freemarker-BLonnh3h.svg +1 -0
  190. package/dist/client/assets/fsharp-QwwPC8x_.svg +1 -0
  191. package/dist/client/assets/fusebox-DqjzyXyI.svg +1 -0
  192. package/dist/client/assets/gamemaker-C82Pt646.svg +1 -0
  193. package/dist/client/assets/garden-BUsWpFKW.svg +1 -0
  194. package/dist/client/assets/gatsby-OA1TADMJ.svg +1 -0
  195. package/dist/client/assets/gcp-CW2RG_Wp.svg +1 -0
  196. package/dist/client/assets/gemfile-1RY6BqSx.svg +1 -0
  197. package/dist/client/assets/gemini-CIgUY8Tg.svg +1 -0
  198. package/dist/client/assets/gemini-ai-Bwe7HeFb.svg +1 -0
  199. package/dist/client/assets/git-BEMs8TOZ.svg +1 -0
  200. package/dist/client/assets/gitlab-zt07_Oa4.svg +1 -0
  201. package/dist/client/assets/gitpod-BtZJQuF0.svg +1 -0
  202. package/dist/client/assets/gleam-CKPcrRAD.svg +1 -0
  203. package/dist/client/assets/gnuplot-BvFqM0ms.svg +1 -0
  204. package/dist/client/assets/go-ByY4sxRu.svg +1 -0
  205. package/dist/client/assets/go-mod-CB6BWQDr.svg +1 -0
  206. package/dist/client/assets/godot-C1EmL4jR.svg +1 -0
  207. package/dist/client/assets/godot-assets-D-FMsuJX.svg +1 -0
  208. package/dist/client/assets/google-BnrMOJ4V.svg +1 -0
  209. package/dist/client/assets/gradle-zsQ12U1q.svg +1 -0
  210. package/dist/client/assets/grafana-alloy-D2DQ33BM.svg +1 -0
  211. package/dist/client/assets/grain-5NkvKROL.svg +1 -0
  212. package/dist/client/assets/graphcool-CInCTIdE.svg +1 -0
  213. package/dist/client/assets/graphql-DnNt2maR.svg +1 -0
  214. package/dist/client/assets/gridsome-C2H5SpaD.svg +1 -0
  215. package/dist/client/assets/groovy-B93RxI7a.svg +1 -0
  216. package/dist/client/assets/grunt-cwitasVS.svg +1 -0
  217. package/dist/client/assets/gulp-BIZ8EAl0.svg +1 -0
  218. package/dist/client/assets/h-1bd73y8t.svg +1 -0
  219. package/dist/client/assets/hack-Bsd1y9bu.svg +1 -0
  220. package/dist/client/assets/hadolint-D1aEtESc.svg +1 -0
  221. package/dist/client/assets/haml-BKq8hU-U.svg +1 -0
  222. package/dist/client/assets/handlebars-Dem98Ago.svg +1 -0
  223. package/dist/client/assets/happo-B64XokX0.svg +1 -0
  224. package/dist/client/assets/hardhat-ByFzkuf4.svg +1 -0
  225. package/dist/client/assets/harmonix-CUh3S11M.svg +1 -0
  226. package/dist/client/assets/haskell-C6GxEwdX.svg +1 -0
  227. package/dist/client/assets/haxe-DdxZWPQy.svg +1 -0
  228. package/dist/client/assets/hcl-BJiZ3gWE.svg +1 -0
  229. package/dist/client/assets/helm-CF4Mi35z.svg +1 -0
  230. package/dist/client/assets/heroku-B6vPz_TJ.svg +1 -0
  231. package/dist/client/assets/hex-BuGJuqn1.svg +1 -0
  232. package/dist/client/assets/hip-DB4xe1Ab.svg +1 -0
  233. package/dist/client/assets/histoire-BMTufysg.svg +1 -0
  234. package/dist/client/assets/hjson-Dl4ZTgK4.svg +1 -0
  235. package/dist/client/assets/horusec-z6vyrVAy.svg +1 -0
  236. package/dist/client/assets/hosts-BydfWJ9z.svg +1 -0
  237. package/dist/client/assets/hpp-HerxyIaC.svg +1 -0
  238. package/dist/client/assets/html-BNRzQ3jk.svg +1 -0
  239. package/dist/client/assets/http-Cp7RCu8F.svg +1 -0
  240. package/dist/client/assets/huff-t3uGT10D.svg +1 -0
  241. package/dist/client/assets/hurl-S3Fvmz3R.svg +1 -0
  242. package/dist/client/assets/husky-A0ALYNcp.svg +1 -0
  243. package/dist/client/assets/i18n-BezCQ09L.svg +1 -0
  244. package/dist/client/assets/idris-CfHPjxcM.svg +1 -0
  245. package/dist/client/assets/ifanr-cloud-DnqgZYHA.svg +1 -0
  246. package/dist/client/assets/image-DYZiZ4CP.svg +1 -0
  247. package/dist/client/assets/imba-C1Q6aK1I.svg +1 -0
  248. package/dist/client/assets/index-0z4D-18M.js +2 -0
  249. package/dist/client/assets/installation-p19cVXO7.svg +1 -0
  250. package/dist/client/assets/instructions-CaWEzdge.svg +1 -0
  251. package/dist/client/assets/ionic-Xp-47Icg.svg +1 -0
  252. package/dist/client/assets/istanbul-DJKvMwnq.svg +1 -0
  253. package/dist/client/assets/jar-BaN44U3v.svg +1 -0
  254. package/dist/client/assets/java-QyMrrPma.svg +1 -0
  255. package/dist/client/assets/javaclass-BU8_3KBR.svg +1 -0
  256. package/dist/client/assets/javascript-CQjpTQab.svg +1 -0
  257. package/dist/client/assets/javascript-map-BQGiWnDM.svg +1 -0
  258. package/dist/client/assets/jenkins-Bf7aNz-w.svg +1 -0
  259. package/dist/client/assets/jest-BgbiFFEd.svg +1 -0
  260. package/dist/client/assets/jinja-4WR9tA6i.svg +1 -0
  261. package/dist/client/assets/jsconfig-ZAi6fTF1.svg +1 -0
  262. package/dist/client/assets/json-NsberLUP.svg +1 -0
  263. package/dist/client/assets/json_schema-sOuobP_H.svg +1 -0
  264. package/dist/client/assets/jsr-CWVSPSyV.svg +1 -0
  265. package/dist/client/assets/julia-DCKDSo9T.svg +1 -0
  266. package/dist/client/assets/jupyter-BKV2q0IB.svg +1 -0
  267. package/dist/client/assets/just-WQgcj-TR.svg +1 -0
  268. package/dist/client/assets/karma-Dm3AtiMd.svg +1 -0
  269. package/dist/client/assets/kcl-CyzArNE1.svg +1 -0
  270. package/dist/client/assets/key-CrFjkQiv.svg +1 -0
  271. package/dist/client/assets/keystatic-BECeLiHJ.svg +1 -0
  272. package/dist/client/assets/kivy-baDYR7ar.svg +1 -0
  273. package/dist/client/assets/kl-Dy3qeUbd.svg +1 -0
  274. package/dist/client/assets/knip-BWpBMXqu.svg +1 -0
  275. package/dist/client/assets/kotlin-DcjME28v.svg +1 -0
  276. package/dist/client/assets/kubernetes-B5EEXb3e.svg +1 -0
  277. package/dist/client/assets/kusto-CIjvTfRW.svg +1 -0
  278. package/dist/client/assets/label-AKZOJqFh.svg +1 -0
  279. package/dist/client/assets/laravel-DWauj5w4.svg +1 -0
  280. package/dist/client/assets/latexmk-DQ0u8QMa.svg +1 -0
  281. package/dist/client/assets/lbx-BMCQe48q.svg +1 -0
  282. package/dist/client/assets/lean-COOrALn9.svg +1 -0
  283. package/dist/client/assets/lefthook-DClcp3br.svg +1 -0
  284. package/dist/client/assets/lerna-BsWY3uYS.svg +1 -0
  285. package/dist/client/assets/less-0c0PeB1Z.svg +1 -0
  286. package/dist/client/assets/liara-CSN9sJzE.svg +1 -0
  287. package/dist/client/assets/lib-B-NXM8aC.svg +1 -0
  288. package/dist/client/assets/license-DmydDYqK.svg +1 -0
  289. package/dist/client/assets/lighthouse-CtbIoCdK.svg +1 -0
  290. package/dist/client/assets/lilypond-CBSm3LFL.svg +1 -0
  291. package/dist/client/assets/lintstaged-Bj1Eddi5.svg +1 -0
  292. package/dist/client/assets/liquid-ClnkrScY.svg +1 -0
  293. package/dist/client/assets/lisp-CMn3epg5.svg +1 -0
  294. package/dist/client/assets/lit-CJ6w1GHF.js +2 -0
  295. package/dist/client/assets/livescript-B5PkWD8e.svg +1 -0
  296. package/dist/client/assets/lock-DRloBj1S.svg +1 -0
  297. package/dist/client/assets/log-Db6NwxHZ.svg +1 -0
  298. package/dist/client/assets/lolcode-C6q6fY1O.svg +1 -0
  299. package/dist/client/assets/lottie-ExyLYhtq.svg +1 -0
  300. package/dist/client/assets/lua-CUh_Iwk8.svg +1 -0
  301. package/dist/client/assets/luau-De_4eP_9.svg +1 -0
  302. package/dist/client/assets/lynx-B49IBNBN.svg +1 -0
  303. package/dist/client/assets/lyric-Bm3UlVp3.svg +1 -0
  304. package/dist/client/assets/macaulay2-0YotwNnE.svg +1 -0
  305. package/dist/client/assets/main-DDgPZEYp.js +2 -0
  306. package/dist/client/assets/makefile-B2WlY55Y.svg +1 -0
  307. package/dist/client/assets/markdoc-DjROVW5I.svg +1 -0
  308. package/dist/client/assets/markdoc-config-BpVRhg1B.svg +1 -0
  309. package/dist/client/assets/markdown-Bm_LLmmi.svg +1 -0
  310. package/dist/client/assets/markdownlint-D4M2LXbH.svg +1 -0
  311. package/dist/client/assets/markojs-BohUrSLp.svg +1 -0
  312. package/dist/client/assets/mathematica-BGWNQXSR.svg +1 -0
  313. package/dist/client/assets/maven-BffVB5hm.svg +1 -0
  314. package/dist/client/assets/mdsvex-Dc9CFJJa.svg +1 -0
  315. package/dist/client/assets/mdx-D6qa5U8C.svg +1 -0
  316. package/dist/client/assets/mercurial-BDoD6ubd.svg +1 -0
  317. package/dist/client/assets/merlin-D5wTXfO4.svg +1 -0
  318. package/dist/client/assets/mermaid-BTscZDRS.svg +1 -0
  319. package/dist/client/assets/meson-dcvm8lmo.svg +1 -0
  320. package/dist/client/assets/metro-XIyWX0Go.svg +1 -0
  321. package/dist/client/assets/minecraft-CE8xXE3-.svg +1 -0
  322. package/dist/client/assets/minecraft-fabric-wG6LwgIf.svg +1 -0
  323. package/dist/client/assets/mint-Cb-YXACo.svg +1 -0
  324. package/dist/client/assets/mist-DAm4UkTw.svg +1 -0
  325. package/dist/client/assets/mjml-C_r30C5E.svg +1 -0
  326. package/dist/client/assets/mocha-BF5_j65C.svg +1 -0
  327. package/dist/client/assets/modernizr-89IMS8eL.svg +1 -0
  328. package/dist/client/assets/mojo-CscjT2Jm.svg +1 -0
  329. package/dist/client/assets/moon-_L_nTq1_.svg +1 -0
  330. package/dist/client/assets/moonscript-Ayut2PrD.svg +1 -0
  331. package/dist/client/assets/mrpack-BVpGpKVf.svg +1 -0
  332. package/dist/client/assets/mxml-B21Nbdgw.svg +1 -0
  333. package/dist/client/assets/nano-staged-CAVSFkY8.svg +1 -0
  334. package/dist/client/assets/ndst-DpYLiHkx.svg +1 -0
  335. package/dist/client/assets/nest-CUu_iPqI.svg +1 -0
  336. package/dist/client/assets/netlify-Bb7vRMfV.svg +1 -0
  337. package/dist/client/assets/next-2gAImGWJ.svg +1 -0
  338. package/dist/client/assets/nextflow-dPJG5e3G.svg +1 -0
  339. package/dist/client/assets/nginx-Ss9U_SJ3.svg +1 -0
  340. package/dist/client/assets/nim-CXHB5kuH.svg +1 -0
  341. package/dist/client/assets/nix-DoxxkZ2k.svg +1 -0
  342. package/dist/client/assets/nodejs-Czg5JT6z.svg +1 -0
  343. package/dist/client/assets/nodemon-CprsexAJ.svg +1 -0
  344. package/dist/client/assets/npm-BSKPS9CC.svg +1 -0
  345. package/dist/client/assets/nuget-D_mqKH22.svg +1 -0
  346. package/dist/client/assets/nunjucks-CSL1En7R.svg +1 -0
  347. package/dist/client/assets/nuxt-BszScKzK.svg +1 -0
  348. package/dist/client/assets/nx-CTIqtdbG.svg +1 -0
  349. package/dist/client/assets/objective-c-3E5wWl6u.svg +1 -0
  350. package/dist/client/assets/objective-cpp-DjpoLOMo.svg +1 -0
  351. package/dist/client/assets/ocaml-T4fLeZFT.svg +1 -0
  352. package/dist/client/assets/odin-DlWnbZWN.svg +1 -0
  353. package/dist/client/assets/onnx-C6WInyrb.svg +1 -0
  354. package/dist/client/assets/opa-D5GoZW5M.svg +1 -0
  355. package/dist/client/assets/opam-3IZadro4.svg +1 -0
  356. package/dist/client/assets/openapi-DjlVyoOp.svg +1 -0
  357. package/dist/client/assets/opencode-BaYncWio.svg +1 -0
  358. package/dist/client/assets/opentofu-jFw9lQBP.svg +1 -0
  359. package/dist/client/assets/otne-SLiO8whA.svg +1 -0
  360. package/dist/client/assets/oxc-DN6_023j.svg +1 -0
  361. package/dist/client/assets/packship-UyLXQ_8n.svg +1 -0
  362. package/dist/client/assets/palette-C0GOsJgu.svg +1 -0
  363. package/dist/client/assets/panda-D469wGns.svg +1 -0
  364. package/dist/client/assets/parcel-BrXQSBYb.svg +1 -0
  365. package/dist/client/assets/pascal-oxGvvJ_x.svg +1 -0
  366. package/dist/client/assets/pawn-BvapPd-t.svg +1 -0
  367. package/dist/client/assets/payload-Cks6N40-.svg +1 -0
  368. package/dist/client/assets/pdf-DtjgBDdX.svg +1 -0
  369. package/dist/client/assets/pdm-CbwhGqOl.svg +1 -0
  370. package/dist/client/assets/peg-BJdFn78b.svg +1 -0
  371. package/dist/client/assets/percy-CWbuYL05.svg +1 -0
  372. package/dist/client/assets/perl-DUX0zwsQ.svg +1 -0
  373. package/dist/client/assets/php-5lebFt-d.svg +1 -0
  374. package/dist/client/assets/php-cs-fixer-D3Vv91zO.svg +1 -0
  375. package/dist/client/assets/phpstan-D9FJYotS.svg +1 -0
  376. package/dist/client/assets/phpunit-BlNyjrEw.svg +1 -0
  377. package/dist/client/assets/pinejs-CDuWmsOY.svg +1 -0
  378. package/dist/client/assets/pipeline-CCHJ-CIC.svg +1 -0
  379. package/dist/client/assets/pkl-CzHZDqdt.svg +1 -0
  380. package/dist/client/assets/plastic-CvMMB3c5.svg +1 -0
  381. package/dist/client/assets/playwright-C8c_RKic.svg +1 -0
  382. package/dist/client/assets/plop-D4uymN-_.svg +1 -0
  383. package/dist/client/assets/pm2-ecosystem-Cv28zGx9.svg +1 -0
  384. package/dist/client/assets/pnpm-ndvMXYUu.svg +1 -0
  385. package/dist/client/assets/poetry-ClZfXo_0.svg +1 -0
  386. package/dist/client/assets/postcss-g3C3DDoi.svg +1 -0
  387. package/dist/client/assets/posthtml-BkDCsIkz.svg +1 -0
  388. package/dist/client/assets/powerpoint-CCXYfzLu.svg +1 -0
  389. package/dist/client/assets/powershell-DnXi9Rjx.svg +1 -0
  390. package/dist/client/assets/pre-commit-DXbl2unR.svg +1 -0
  391. package/dist/client/assets/preload-helper-CRzLMJPS.js +1 -0
  392. package/dist/client/assets/prettier-DFxlFAp4.svg +1 -0
  393. package/dist/client/assets/prisma-BgG1MIwh.svg +1 -0
  394. package/dist/client/assets/processing-B1bs0VmW.svg +1 -0
  395. package/dist/client/assets/prolog-CxwCfnlm.svg +1 -0
  396. package/dist/client/assets/prompt-7jgVTNou.svg +1 -0
  397. package/dist/client/assets/proto-Bv4-L0XU.svg +1 -0
  398. package/dist/client/assets/protractor-CJWv1lK-.svg +1 -0
  399. package/dist/client/assets/pug-BXlORXuH.svg +1 -0
  400. package/dist/client/assets/puppet-CKCVJvZX.svg +1 -0
  401. package/dist/client/assets/puppeteer-DDZkfQNZ.svg +1 -0
  402. package/dist/client/assets/purescript-CUdIfJrp.svg +1 -0
  403. package/dist/client/assets/python-misc-BZ5TXfdG.svg +1 -0
  404. package/dist/client/assets/python-oHA753pt.svg +1 -0
  405. package/dist/client/assets/pytorch-f0udCMaw.svg +1 -0
  406. package/dist/client/assets/qsharp-BaFNvoXS.svg +1 -0
  407. package/dist/client/assets/quarto-zhC7oGOB.svg +1 -0
  408. package/dist/client/assets/quasar-BXE2pW5w.svg +1 -0
  409. package/dist/client/assets/quokka-DrMOw93T.svg +1 -0
  410. package/dist/client/assets/r-AQewf3lz.svg +1 -0
  411. package/dist/client/assets/racket-BCyLzvrP.svg +1 -0
  412. package/dist/client/assets/raml-WDbT4cRb.svg +1 -0
  413. package/dist/client/assets/razor-BAUCpTxC.svg +1 -0
  414. package/dist/client/assets/rbxmk-CZ9pB7X6.svg +1 -0
  415. package/dist/client/assets/rc-BDgxm_A8.svg +1 -0
  416. package/dist/client/assets/react-CdMrIyLK.svg +1 -0
  417. package/dist/client/assets/react_ts-9WeLJBIj.svg +1 -0
  418. package/dist/client/assets/readme-BSIQKZwq.svg +1 -0
  419. package/dist/client/assets/reason-m9vOqeqw.svg +1 -0
  420. package/dist/client/assets/red-Dzf3O8j4.svg +1 -0
  421. package/dist/client/assets/regedit-DJzxfiQN.svg +1 -0
  422. package/dist/client/assets/remark-C55cxr93.svg +1 -0
  423. package/dist/client/assets/remix-Bk2h4zH7.svg +1 -0
  424. package/dist/client/assets/renovate-zzi8oRFv.svg +1 -0
  425. package/dist/client/assets/replit-BpeMxcBh.svg +1 -0
  426. package/dist/client/assets/requiredTerminalPlugin-ZZOwUcbr.js +3 -0
  427. package/dist/client/assets/rescript-interface-a87dYX5u.svg +1 -0
  428. package/dist/client/assets/rescript-qPAwtDLa.svg +1 -0
  429. package/dist/client/assets/restql-CnZcZpny.svg +1 -0
  430. package/dist/client/assets/riot-DjRzaRVp.svg +1 -0
  431. package/dist/client/assets/roadmap-DWpVc5P5.svg +1 -0
  432. package/dist/client/assets/roblox-Bv5zbklC.svg +1 -0
  433. package/dist/client/assets/robot-Cto_i8jo.svg +1 -0
  434. package/dist/client/assets/robots-COnOCAqh.svg +1 -0
  435. package/dist/client/assets/rocket-CAmUpMm6.svg +1 -0
  436. package/dist/client/assets/rolldown-Cy_4AzVW.svg +1 -0
  437. package/dist/client/assets/rollup-2ZkmBeWV.svg +1 -0
  438. package/dist/client/assets/rome-Cq3lb2xY.svg +1 -0
  439. package/dist/client/assets/routing-BNxHhbXZ.svg +1 -0
  440. package/dist/client/assets/rspec-CoEmfx5H.svg +1 -0
  441. package/dist/client/assets/rstack-DzJ3cPXM.svg +1 -0
  442. package/dist/client/assets/rubocop-CokGq15J.svg +1 -0
  443. package/dist/client/assets/ruby-DTGQ4xCM.svg +1 -0
  444. package/dist/client/assets/ruff-BN0KpNzC.svg +1 -0
  445. package/dist/client/assets/rust-B122pUHY.svg +1 -0
  446. package/dist/client/assets/salt-B8j0OVNV.svg +1 -0
  447. package/dist/client/assets/san-C0UnyaU4.svg +1 -0
  448. package/dist/client/assets/sas-RNoBA0-Y.svg +1 -0
  449. package/dist/client/assets/sass-B7y5mYt_.svg +1 -0
  450. package/dist/client/assets/sbt-DosCci-d.svg +1 -0
  451. package/dist/client/assets/scala-CsGkKwl5.svg +1 -0
  452. package/dist/client/assets/scheme-CS2UbTis.svg +1 -0
  453. package/dist/client/assets/scons-CyqfFgvx.svg +1 -0
  454. package/dist/client/assets/screwdriver-DjTKuDz7.svg +1 -0
  455. package/dist/client/assets/search-fq7VxV09.svg +1 -0
  456. package/dist/client/assets/semantic-release-BbLzZX96.svg +1 -0
  457. package/dist/client/assets/semgrep-Cl6VUQtd.svg +1 -0
  458. package/dist/client/assets/sentry-MrouyD-P.svg +1 -0
  459. package/dist/client/assets/sequelize-BQWikTCs.svg +1 -0
  460. package/dist/client/assets/serverless-C7Jdn6_T.svg +1 -0
  461. package/dist/client/assets/settings-CtzL1evz.svg +1 -0
  462. package/dist/client/assets/shader-BZXKDeiD.svg +1 -0
  463. package/dist/client/assets/shellcheck-BgWOclub.svg +1 -0
  464. package/dist/client/assets/simulink-yQnKyx__.svg +1 -0
  465. package/dist/client/assets/siyuan-CPWD86-6.svg +1 -0
  466. package/dist/client/assets/sketch-NbltjaPf.svg +1 -0
  467. package/dist/client/assets/skill-BThvgH87.svg +1 -0
  468. package/dist/client/assets/slim-CTjdZAfz.svg +1 -0
  469. package/dist/client/assets/slint-B0xbkqgr.svg +1 -0
  470. package/dist/client/assets/slug-CWkQgR9s.svg +1 -0
  471. package/dist/client/assets/smarty-BXDiLQNt.svg +1 -0
  472. package/dist/client/assets/sml-DMkoWEN5.svg +1 -0
  473. package/dist/client/assets/snakemake-xG7xUrdI.svg +1 -0
  474. package/dist/client/assets/snapcraft-zvgAcZ4p.svg +1 -0
  475. package/dist/client/assets/snowpack-l0uHt304.svg +1 -0
  476. package/dist/client/assets/snyk-DCW3rtvv.svg +1 -0
  477. package/dist/client/assets/solidity-C4TQWJKU.svg +1 -0
  478. package/dist/client/assets/sonarcloud-ClLIXGyx.svg +1 -0
  479. package/dist/client/assets/spwn-31WG9ftR.svg +1 -0
  480. package/dist/client/assets/stackblitz-ZX6aBRKb.svg +1 -0
  481. package/dist/client/assets/stan-CPcUXbxB.svg +1 -0
  482. package/dist/client/assets/steadybit-BZtlLY-3.svg +1 -0
  483. package/dist/client/assets/stencil-D0FNO32O.svg +1 -0
  484. package/dist/client/assets/stitches-BYlEJvuz.svg +1 -0
  485. package/dist/client/assets/storybook-KxGhpZYa.svg +1 -0
  486. package/dist/client/assets/stryker-CYflxT_R.svg +1 -0
  487. package/dist/client/assets/sty-C4HqHV4z.svg +1 -0
  488. package/dist/client/assets/stylable-Bi9Gr97T.svg +1 -0
  489. package/dist/client/assets/styleSources-CdF2T_pj.js +1 -0
  490. package/dist/client/assets/stylelint-JSbd-yhE.svg +1 -0
  491. package/dist/client/assets/styles-BwN5rgmt.js +10 -0
  492. package/dist/client/assets/styles-DK4aKhCE.js +1 -0
  493. package/dist/client/assets/stylus-ZoqbP9jE.svg +1 -0
  494. package/dist/client/assets/sublime-DFvp_Ess.svg +1 -0
  495. package/dist/client/assets/subtitles-BNOc1mEf.svg +1 -0
  496. package/dist/client/assets/supabase-CX7cap86.svg +1 -0
  497. package/dist/client/assets/svelte-B8HKO6BX.svg +1 -0
  498. package/dist/client/assets/svelte_js-C_RKcwSP.svg +1 -0
  499. package/dist/client/assets/svelte_ts-APH7lcVp.svg +1 -0
  500. package/dist/client/assets/svg-DVy7iktw.svg +1 -0
  501. package/dist/client/assets/svgo-CJXaeDEN.svg +1 -0
  502. package/dist/client/assets/svgr-Dn8OFGar.svg +1 -0
  503. package/dist/client/assets/swagger-Dqyrwr4g.svg +1 -0
  504. package/dist/client/assets/sway-C1Kkif7r.svg +1 -0
  505. package/dist/client/assets/swc-BUhoW8cb.svg +1 -0
  506. package/dist/client/assets/swift-D4_pkWil.svg +1 -0
  507. package/dist/client/assets/syncpack-DtZ994Gf.svg +1 -0
  508. package/dist/client/assets/table-YhsaNNk_.svg +1 -0
  509. package/dist/client/assets/tailwindcss-DODJSdj1.svg +1 -0
  510. package/dist/client/assets/tape-DGYhnMht.svg +1 -0
  511. package/dist/client/assets/taskfile-f5DM79_-.svg +1 -0
  512. package/dist/client/assets/tauri-DBBtDoCo.svg +1 -0
  513. package/dist/client/assets/taze-BPR9LgXp.svg +1 -0
  514. package/dist/client/assets/tcl-CiAJKGaA.svg +1 -0
  515. package/dist/client/assets/teal-WyfAQok0.svg +1 -0
  516. package/dist/client/assets/templ-BHla0pe-.svg +1 -0
  517. package/dist/client/assets/template-qJWiB5gQ.svg +1 -0
  518. package/dist/client/assets/terraform-R86_iPhv.svg +1 -0
  519. package/dist/client/assets/test-js-A34KrdbK.svg +1 -0
  520. package/dist/client/assets/test-jsx-C2PQBkQP.svg +1 -0
  521. package/dist/client/assets/test-ts-fdt299ek.svg +1 -0
  522. package/dist/client/assets/tex-DpewR4UN.svg +1 -0
  523. package/dist/client/assets/textlint-pjwsbDhs.svg +1 -0
  524. package/dist/client/assets/themeCatalog-B3yda95n.js +1 -0
  525. package/dist/client/assets/themePreference-BBiJxLjs.js +1 -0
  526. package/dist/client/assets/themeStartup-0b02tNrh.js +2 -0
  527. package/dist/client/assets/tilt-Dwon5dv-.svg +1 -0
  528. package/dist/client/assets/tldraw-BnDJmluq.svg +1 -0
  529. package/dist/client/assets/tobi-CQ-666uh.svg +1 -0
  530. package/dist/client/assets/tobimake-DzDbTYW1.svg +1 -0
  531. package/dist/client/assets/toc-nUTycYjl.svg +1 -0
  532. package/dist/client/assets/todo-CpcorlsE.svg +1 -0
  533. package/dist/client/assets/toml-DvUt-GOd.svg +1 -0
  534. package/dist/client/assets/toon-CGe9RDKY.svg +1 -0
  535. package/dist/client/assets/travis-CH6zNy43.svg +1 -0
  536. package/dist/client/assets/tree-epW9JaxP.svg +1 -0
  537. package/dist/client/assets/trigger-CqdxCyG0.svg +1 -0
  538. package/dist/client/assets/tsconfig-ROp_YdWL.svg +1 -0
  539. package/dist/client/assets/tsdoc-BEXcYgLD.svg +1 -0
  540. package/dist/client/assets/tsdown-B96z16my.svg +1 -0
  541. package/dist/client/assets/tsil-D-U9yWS8.svg +1 -0
  542. package/dist/client/assets/tune-DISlqKNZ.svg +1 -0
  543. package/dist/client/assets/turborepo-CWNwoZtI.svg +1 -0
  544. package/dist/client/assets/twig-CA70AYNK.svg +1 -0
  545. package/dist/client/assets/twine-BPJsGZd2.svg +1 -0
  546. package/dist/client/assets/typedoc-FY7jFoGW.svg +1 -0
  547. package/dist/client/assets/typescript-DjjXqw-n.svg +1 -0
  548. package/dist/client/assets/typescript-def-CTN5WM5i.svg +1 -0
  549. package/dist/client/assets/typst-CnDSkp_i.svg +1 -0
  550. package/dist/client/assets/uiua-BOsurlxn.svg +1 -0
  551. package/dist/client/assets/umi-DYOjFi8w.svg +1 -0
  552. package/dist/client/assets/uml-CYijxuna.svg +1 -0
  553. package/dist/client/assets/unity-CRNCEoK6.svg +1 -0
  554. package/dist/client/assets/unlicense-DG_b3BEE.svg +1 -0
  555. package/dist/client/assets/unocss-MqLuLfeL.svg +1 -0
  556. package/dist/client/assets/url-hE4h5p6b.svg +1 -0
  557. package/dist/client/assets/uv-DRTOVSi_.svg +1 -0
  558. package/dist/client/assets/vagrant-YnxMTuKe.svg +1 -0
  559. package/dist/client/assets/vala-m_i2ZWns.svg +1 -0
  560. package/dist/client/assets/vanilla-extract-76H6-A4R.svg +1 -0
  561. package/dist/client/assets/varnish-CX3oiNcp.svg +1 -0
  562. package/dist/client/assets/vedic-D6-oQUka.svg +1 -0
  563. package/dist/client/assets/velite-nLLNxKBA.svg +1 -0
  564. package/dist/client/assets/velocity-CSvfE9yM.svg +1 -0
  565. package/dist/client/assets/vercel-CgKLo9IO.svg +1 -0
  566. package/dist/client/assets/verdaccio-gsdiCbvv.svg +1 -0
  567. package/dist/client/assets/verified-BFLtqroG.svg +1 -0
  568. package/dist/client/assets/verilog-CbZvRaae.svg +1 -0
  569. package/dist/client/assets/verse-D_RZ0Bz0.svg +1 -0
  570. package/dist/client/assets/vfl-8CAM-hjs.svg +1 -0
  571. package/dist/client/assets/video-qxpJXkH6.svg +1 -0
  572. package/dist/client/assets/vim-CB8qTVuS.svg +1 -0
  573. package/dist/client/assets/virtual-Hoc2XbZN.svg +1 -0
  574. package/dist/client/assets/visualstudio-BHj2x5q7.svg +1 -0
  575. package/dist/client/assets/vite-JKzchVew.svg +1 -0
  576. package/dist/client/assets/vitest-Cl4_wKFu.svg +1 -0
  577. package/dist/client/assets/vlang-C3-DMUIm.svg +1 -0
  578. package/dist/client/assets/vscode-BtTXhPua.svg +1 -0
  579. package/dist/client/assets/vue-BlenztPP.svg +1 -0
  580. package/dist/client/assets/vue-config-o7yPAADv.svg +1 -0
  581. package/dist/client/assets/wakatime-DNz7qcxZ.svg +1 -0
  582. package/dist/client/assets/wallaby-C0UIkEOa.svg +1 -0
  583. package/dist/client/assets/wally-Ds1quKSG.svg +1 -0
  584. package/dist/client/assets/warp-B3X5Zoeh.svg +1 -0
  585. package/dist/client/assets/watchman-7EFq9LSa.svg +1 -0
  586. package/dist/client/assets/webassembly-Bs4UtU2T.svg +1 -0
  587. package/dist/client/assets/webhint-B4I6V0Ee.svg +1 -0
  588. package/dist/client/assets/webpack-zo2uWGOg.svg +1 -0
  589. package/dist/client/assets/wepy-Cho54Qlr.svg +1 -0
  590. package/dist/client/assets/werf-BW9FiKe5.svg +1 -0
  591. package/dist/client/assets/windicss-C_8y516i.svg +1 -0
  592. package/dist/client/assets/wolframlanguage-D6C1WBYh.svg +1 -0
  593. package/dist/client/assets/word-BcPLm6YH.svg +1 -0
  594. package/dist/client/assets/wrangler-CjgAkoTg.svg +1 -0
  595. package/dist/client/assets/wxt-c6drtC9H.svg +1 -0
  596. package/dist/client/assets/xaml-DE72OHNQ.svg +1 -0
  597. package/dist/client/assets/xmake-4WNmmIJj.svg +1 -0
  598. package/dist/client/assets/xml-S4aCxoUr.svg +1 -0
  599. package/dist/client/assets/yaml-DPTMsOTP.svg +1 -0
  600. package/dist/client/assets/yang-N-7dP4WI.svg +1 -0
  601. package/dist/client/assets/yarn-Cios8OFX.svg +1 -0
  602. package/dist/client/assets/zeabur-kqbNXTTH.svg +1 -0
  603. package/dist/client/assets/zig-CdphsgLN.svg +1 -0
  604. package/dist/client/assets/zip-GDnEynqi.svg +1 -0
  605. package/dist/client/assets/zizmor-IsFFdy6W.svg +1 -0
  606. package/dist/client/index.html +12 -6
  607. package/dist/config.js +233 -87
  608. package/dist/config.js.map +1 -1
  609. package/dist/configSessionNamingMigration.js +63 -0
  610. package/dist/configSessionNamingMigration.js.map +1 -0
  611. package/dist/nativeServices/serviceDoctor.js +3 -3
  612. package/dist/nativeServices/serviceDoctor.js.map +1 -1
  613. package/dist/nativeServices/servicePlan.js +53 -23
  614. package/dist/nativeServices/servicePlan.js.map +1 -1
  615. package/dist/nativeServices/serviceProbe.js +27 -7
  616. package/dist/nativeServices/serviceProbe.js.map +1 -1
  617. package/dist/pi-packages/relays/markdownDocument.js +8 -9
  618. package/dist/pi-packages/relays/pi-web-plugin.js +11 -11
  619. package/dist/pi-packages/relays/relayDiscovery.js +5 -1
  620. package/dist/pi-packages/relays/relays.messages.js +38 -0
  621. package/dist/pi-packages/relays/relaysLocalization.js +19 -0
  622. package/dist/pi-packages/relays/relaysPanelElement.js +151 -96
  623. package/dist/pi-packages/scheduled-tasks/browser/pi-web-plugin.js +1135 -0
  624. package/dist/pi-packages/scheduled-tasks/domain.js +63 -0
  625. package/dist/pi-packages/scheduled-tasks/extensions/index.js +710 -0
  626. package/dist/pi-packages/scheduled-tasks/package.json +30 -0
  627. package/dist/pi-packages/scheduled-tasks/scheduler.js +89 -0
  628. package/dist/pi-packages/scheduled-tasks/server-plugin.js +9872 -0
  629. package/dist/pi-packages/scheduled-tasks/service.js +178 -0
  630. package/dist/pi-packages/scheduled-tasks/skills/scheduled-tasks/SKILL.md +30 -0
  631. package/dist/pi-packages/scheduled-tasks/sqlite.js +18 -0
  632. package/dist/pi-packages/scheduled-tasks/store.js +230 -0
  633. package/dist/pi-packages/scheduled-tasks/vite.browser.config.mjs +16 -0
  634. package/dist/pi-packages/scheduled-tasks/vite.companion.config.mjs +17 -0
  635. package/dist/pi-packages/scheduled-tasks/vite.config.mjs +17 -0
  636. package/dist/pi-packages/session-naming/config.js +78 -0
  637. package/dist/pi-packages/session-naming/extensions/index.js +74 -0
  638. package/dist/pi-packages/session-naming/generator.js +76 -0
  639. package/dist/pi-packages/session-naming/package.json +15 -0
  640. package/dist/pi-packages/workflows/browser/pi-web-plugin.js +10 -7
  641. package/dist/pi-packages/workflows/browser/workflows.messages.js +32 -0
  642. package/dist/pi-packages/workflows/browser/worktreeDialog.js +71 -50
  643. package/dist/pi-packages/workflows/server-plugin.js +137 -23
  644. package/dist/pi-web-plugins/audio/audioElement.js +61 -0
  645. package/dist/pi-web-plugins/audio/audioFormats.js +18 -0
  646. package/dist/pi-web-plugins/audio/byteRange.js +21 -0
  647. package/dist/pi-web-plugins/audio/package.json +10 -0
  648. package/dist/pi-web-plugins/audio/pi-web-plugin.js +39 -0
  649. package/dist/pi-web-plugins/audio/server.js +71 -0
  650. package/dist/pi-web-plugins/code-highlight/browser/pi-web-plugin.js +4 -4
  651. package/dist/pi-web-plugins/custom-ui-codex/README.md +2 -0
  652. package/dist/pi-web-plugins/custom-ui-codex/chat-settings.css +15 -2
  653. package/dist/pi-web-plugins/custom-ui-codex/codex.css +8 -0
  654. package/dist/pi-web-plugins/custom-ui-codex/fileIcons.js +30 -0
  655. package/dist/pi-web-plugins/custom-ui-codex/package.json +8 -1
  656. package/dist/pi-web-plugins/custom-ui-codex/pi-web-plugin.js +8 -8
  657. package/dist/pi-web-plugins/files/browser/pi-web-plugin.js +256 -242
  658. package/dist/pi-web-plugins/git/browser/git-panel.js +138 -59
  659. package/dist/pi-web-plugins/git/browser/git.messages.js +47 -0
  660. package/dist/pi-web-plugins/git/browser/gitFileIcon.js +71 -0
  661. package/dist/pi-web-plugins/git/browser/pi-web-plugin.js +21 -4
  662. package/dist/pi-web-plugins/git/server-plugin.js +5 -3
  663. package/dist/pi-web-plugins/info/info.messages.js +66 -0
  664. package/dist/pi-web-plugins/info/infoInternals.js +217 -217
  665. package/dist/pi-web-plugins/info/pi-web-plugin.js +19 -14
  666. package/dist/pi-web-plugins/language-spanish/catalogs.js +1896 -0
  667. package/dist/pi-web-plugins/language-spanish/package.json +14 -0
  668. package/dist/pi-web-plugins/language-spanish/pi-web-plugin.js +90 -0
  669. package/dist/pi-web-plugins/language-swedish/catalogs.js +1896 -0
  670. package/dist/pi-web-plugins/language-swedish/package.json +14 -0
  671. package/dist/pi-web-plugins/language-swedish/pi-web-plugin.js +89 -0
  672. package/dist/pi-web-plugins/mermaid/browser/pi-web-plugin.js +4 -4
  673. package/dist/pi-web-plugins/terminal/browser/pi-web-plugin.js +71 -66
  674. package/dist/pi-web-plugins/terminal/bunPtyProvider.js +109 -0
  675. package/dist/pi-web-plugins/terminal/nodePtyProvider.js +75 -0
  676. package/dist/pi-web-plugins/terminal/nodePtySpawnHelper.js +36 -0
  677. package/dist/pi-web-plugins/terminal/ptyComposition.js +12 -0
  678. package/dist/pi-web-plugins/terminal/ptyProvider.js +2 -0
  679. package/dist/pi-web-plugins/terminal/server-plugin.js +42 -14
  680. package/dist/pi-web-plugins/terminal/terminalService.js +218 -76
  681. package/dist/pi-web-plugins/themes/assets/graphite.css +56 -0
  682. package/dist/pi-web-plugins/themes/assets/paper.css +56 -0
  683. package/dist/pi-web-plugins/themes/package.json +21 -0
  684. package/dist/pi-web-plugins/updates/pi-web-plugin.js +200 -155
  685. package/dist/pi-web-plugins/updates/updates.messages.js +59 -0
  686. package/dist/pi-web-plugins/updates/updatesLogic.js +27 -29
  687. package/dist/pi-web-plugins/workspace-tasks/config.js +18 -19
  688. package/dist/pi-web-plugins/workspace-tasks/pi-web-plugin.js +13 -8
  689. package/dist/pi-web-plugins/workspace-tasks/tasks.messages.js +45 -0
  690. package/dist/pi-web-plugins/workspace-tasks/tasksLocalization.js +33 -0
  691. package/dist/pi-web-plugins/workspace-tasks/tasksPanelElement.js +75 -46
  692. package/dist/pi-web-plugins/workspace-tasks/workspaceTasksClient.js +7 -33
  693. package/dist/pi-web-plugins/zh-cn/bundled.json +31 -18
  694. package/dist/pi-web-plugins/zh-cn/catalogs.json +1803 -0
  695. package/dist/pi-web-plugins/zh-cn/components.json +2 -0
  696. package/dist/pi-web-plugins/zh-cn/files.json +7 -0
  697. package/dist/pi-web-plugins/zh-cn/main.json +5 -1
  698. package/dist/pi-web-plugins/zh-cn/management-errors.json +6 -0
  699. package/dist/pi-web-plugins/zh-cn/pi-web-plugin.js +13 -4
  700. package/dist/pi-web-plugins/zh-cn/server-main.json +4 -4
  701. package/dist/pi-web-plugins/zh-cn/server.json +1 -1
  702. package/dist/piWebVersionReport.js +2 -0
  703. package/dist/piWebVersionReport.js.map +1 -1
  704. package/dist/plugin-api.d.ts +202 -8
  705. package/dist/runtimePreflight.js +14 -0
  706. package/dist/runtimePreflight.js.map +1 -0
  707. package/dist/server/activity/workspaceActivityService.js +18 -1
  708. package/dist/server/activity/workspaceActivityService.js.map +1 -1
  709. package/dist/server/app.js +48 -10
  710. package/dist/server/app.js.map +1 -1
  711. package/dist/server/configRoutes.js +117 -139
  712. package/dist/server/configRoutes.js.map +1 -1
  713. package/dist/server/configUpdates.js +104 -0
  714. package/dist/server/configUpdates.js.map +1 -0
  715. package/dist/server/deploymentIdentity.js +12 -10
  716. package/dist/server/deploymentIdentity.js.map +1 -1
  717. package/dist/server/deploymentIdentityRoutes.js +2 -1
  718. package/dist/server/deploymentIdentityRoutes.js.map +1 -1
  719. package/dist/server/diagnostics/nodePtyNativeModule.js +0 -18
  720. package/dist/server/diagnostics/nodePtyNativeModule.js.map +1 -1
  721. package/dist/server/diagnostics/terminalPrerequisites.js +54 -0
  722. package/dist/server/diagnostics/terminalPrerequisites.js.map +1 -0
  723. package/dist/server/index.js +9 -0
  724. package/dist/server/index.js.map +1 -1
  725. package/dist/server/knownAutoInstallPiPackages.js +6 -0
  726. package/dist/server/knownAutoInstallPiPackages.js.map +1 -1
  727. package/dist/server/knownPiPackages.js +4 -4
  728. package/dist/server/knownPiPackages.js.map +1 -1
  729. package/dist/server/machines/machineClient.js +39 -17
  730. package/dist/server/machines/machineClient.js.map +1 -1
  731. package/dist/server/machines/machinePluginProxyRoutes.js +3 -1
  732. package/dist/server/machines/machinePluginProxyRoutes.js.map +1 -1
  733. package/dist/server/machines/machineProxyRoutes.js +60 -9
  734. package/dist/server/machines/machineProxyRoutes.js.map +1 -1
  735. package/dist/server/machines/machineService.js +81 -13
  736. package/dist/server/machines/machineService.js.map +1 -1
  737. package/dist/server/machines/machineStore.js.map +1 -1
  738. package/dist/server/managementAgents.js +179 -0
  739. package/dist/server/managementAgents.js.map +1 -0
  740. package/dist/server/managementAgentsRoutes.js +42 -0
  741. package/dist/server/managementAgentsRoutes.js.map +1 -0
  742. package/dist/server/managementEmbed.js +27 -44
  743. package/dist/server/managementEmbed.js.map +1 -1
  744. package/dist/server/managementEntryRoutes.js +51 -0
  745. package/dist/server/managementEntryRoutes.js.map +1 -0
  746. package/dist/server/managementEntryTickets.js +46 -0
  747. package/dist/server/managementEntryTickets.js.map +1 -0
  748. package/dist/server/managementTransportLimits.js +5 -0
  749. package/dist/server/managementTransportLimits.js.map +1 -0
  750. package/dist/server/navigationPreferenceRoutes.js +20 -1
  751. package/dist/server/navigationPreferenceRoutes.js.map +1 -1
  752. package/dist/server/normalAuth.js +3 -1
  753. package/dist/server/normalAuth.js.map +1 -1
  754. package/dist/server/notices/serverNoticeStore.js +4 -0
  755. package/dist/server/notices/serverNoticeStore.js.map +1 -1
  756. package/dist/server/piPackageService.js +15 -1
  757. package/dist/server/piPackageService.js.map +1 -1
  758. package/dist/server/piWebPluginCatalog.js +23 -11
  759. package/dist/server/piWebPluginCatalog.js.map +1 -1
  760. package/dist/server/piWebPluginLifecycle.js +14 -4
  761. package/dist/server/piWebPluginLifecycle.js.map +1 -1
  762. package/dist/server/piWebPluginService.js +11 -5
  763. package/dist/server/piWebPluginService.js.map +1 -1
  764. package/dist/server/piWebStatus.js +12 -10
  765. package/dist/server/piWebStatus.js.map +1 -1
  766. package/dist/server/piWebStatusCache.js +3 -1
  767. package/dist/server/piWebStatusCache.js.map +1 -1
  768. package/dist/server/plugins/pluginBackendRegistry.js +229 -4
  769. package/dist/server/plugins/pluginBackendRegistry.js.map +1 -1
  770. package/dist/server/plugins/pluginBackendResourceProxyRoutes.js +40 -0
  771. package/dist/server/plugins/pluginBackendResourceProxyRoutes.js.map +1 -0
  772. package/dist/server/plugins/pluginBackendResourceResponse.js +84 -0
  773. package/dist/server/plugins/pluginBackendResourceResponse.js.map +1 -0
  774. package/dist/server/plugins/projectPluginSettings.js +9 -2
  775. package/dist/server/plugins/projectPluginSettings.js.map +1 -1
  776. package/dist/server/plugins/serverPluginCatalogCapability.js +7 -2
  777. package/dist/server/plugins/serverPluginCatalogCapability.js.map +1 -1
  778. package/dist/server/plugins/serverPluginPiSessionsCapability.js +16 -3
  779. package/dist/server/plugins/serverPluginPiSessionsCapability.js.map +1 -1
  780. package/dist/server/plugins/serverPluginRuntime.js +25 -9
  781. package/dist/server/plugins/serverPluginRuntime.js.map +1 -1
  782. package/dist/server/plugins/serverPluginSessionLifecycleCapability.js +87 -0
  783. package/dist/server/plugins/serverPluginSessionLifecycleCapability.js.map +1 -0
  784. package/dist/server/requestLogging.js +1 -1
  785. package/dist/server/requestLogging.js.map +1 -1
  786. package/dist/server/sessiond/agentHttpDispatcher.js +14 -7
  787. package/dist/server/sessiond/agentHttpDispatcher.js.map +1 -1
  788. package/dist/server/sessiond/autoInstallPiPackageSources.js +54 -0
  789. package/dist/server/sessiond/autoInstallPiPackageSources.js.map +1 -0
  790. package/dist/server/sessiond/autoInstallPiPackages.js +77 -30
  791. package/dist/server/sessiond/autoInstallPiPackages.js.map +1 -1
  792. package/dist/server/sessiond/pluginBackendChannelRoutes.js +3 -13
  793. package/dist/server/sessiond/pluginBackendChannelRoutes.js.map +1 -1
  794. package/dist/server/sessiond/pluginBackendResourceRoutes.js +62 -0
  795. package/dist/server/sessiond/pluginBackendResourceRoutes.js.map +1 -0
  796. package/dist/server/sessiond/pluginSessionLifecycleRoutes.js +45 -0
  797. package/dist/server/sessiond/pluginSessionLifecycleRoutes.js.map +1 -0
  798. package/dist/server/sessiond/sessionProxyRoutes.js +55 -11
  799. package/dist/server/sessiond/sessionProxyRoutes.js.map +1 -1
  800. package/dist/server/sessiond/sessionServiceDependencies.js +3 -0
  801. package/dist/server/sessiond/sessionServiceDependencies.js.map +1 -1
  802. package/dist/server/sessiond.js +46 -15
  803. package/dist/server/sessiond.js.map +1 -1
  804. package/dist/server/sessions/askUserDomain.js +24 -2
  805. package/dist/server/sessions/askUserDomain.js.map +1 -1
  806. package/dist/server/sessions/askUserTool.js +1 -1
  807. package/dist/server/sessions/askUserTool.js.map +1 -1
  808. package/dist/server/sessions/dockerEnvironmentFacts.js +10 -9
  809. package/dist/server/sessions/dockerEnvironmentFacts.js.map +1 -1
  810. package/dist/server/sessions/mcpOAuthCredentialAdapter.js +4 -4
  811. package/dist/server/sessions/mcpOAuthCredentialAdapter.js.map +1 -1
  812. package/dist/server/sessions/piSessionService.js +500 -259
  813. package/dist/server/sessions/piSessionService.js.map +1 -1
  814. package/dist/server/sessions/requestHumanInterventionTool.js +27 -0
  815. package/dist/server/sessions/requestHumanInterventionTool.js.map +1 -0
  816. package/dist/server/sessions/sendSessionMessageTool.js +32 -0
  817. package/dist/server/sessions/sendSessionMessageTool.js.map +1 -0
  818. package/dist/server/sessions/sessionActivityCoordinator.js.map +1 -1
  819. package/dist/server/sessions/sessionCleanup.js +18 -1
  820. package/dist/server/sessions/sessionCleanup.js.map +1 -1
  821. package/dist/server/sessions/sessionCommandService.js +58 -52
  822. package/dist/server/sessions/sessionCommandService.js.map +1 -1
  823. package/dist/server/sessions/sessionContentSearch.js +103 -30
  824. package/dist/server/sessions/sessionContentSearch.js.map +1 -1
  825. package/dist/server/sessions/sessionIntervention.js +29 -0
  826. package/dist/server/sessions/sessionIntervention.js.map +1 -0
  827. package/dist/server/sessions/sessionNameGenerator.js +0 -60
  828. package/dist/server/sessions/sessionNameGenerator.js.map +1 -1
  829. package/dist/server/sessions/sessionNotificationStore.js +2 -1
  830. package/dist/server/sessions/sessionNotificationStore.js.map +1 -1
  831. package/dist/server/sessions/sessionRoutes.js +25 -1
  832. package/dist/server/sessions/sessionRoutes.js.map +1 -1
  833. package/dist/server/sessions/sessionSummaryScanner.js +8 -0
  834. package/dist/server/sessions/sessionSummaryScanner.js.map +1 -1
  835. package/dist/server/sessions/sessionTreeProjection.js +108 -97
  836. package/dist/server/sessions/sessionTreeProjection.js.map +1 -1
  837. package/dist/server/sessions/sessionUiEvents.js +2 -0
  838. package/dist/server/sessions/sessionUiEvents.js.map +1 -1
  839. package/dist/server/sessions/sessionUnreadStore.js +11 -1
  840. package/dist/server/sessions/sessionUnreadStore.js.map +1 -1
  841. package/dist/server/sessions/spawnSubsessionTool.js +66 -15
  842. package/dist/server/sessions/spawnSubsessionTool.js.map +1 -1
  843. package/dist/server/sessions/subsessionCompletionDelivery.js +6 -3
  844. package/dist/server/sessions/subsessionCompletionDelivery.js.map +1 -1
  845. package/dist/server/sessions/subsessionCompletionInbox.js +6 -9
  846. package/dist/server/sessions/subsessionCompletionInbox.js.map +1 -1
  847. package/dist/server/status/machineStatusService.js +15 -3
  848. package/dist/server/status/machineStatusService.js.map +1 -1
  849. package/dist/server/storage/navigationPreferenceStore.js +11 -0
  850. package/dist/server/storage/navigationPreferenceStore.js.map +1 -1
  851. package/dist/server/storage/sessionPinStore.js +95 -0
  852. package/dist/server/storage/sessionPinStore.js.map +1 -0
  853. package/dist/server/terminals/maintenanceExecutionContext.js +18 -0
  854. package/dist/server/terminals/maintenanceExecutionContext.js.map +1 -0
  855. package/dist/server/terminals/maintenanceTerminalCapability.js +25 -0
  856. package/dist/server/terminals/maintenanceTerminalCapability.js.map +1 -0
  857. package/dist/server/terminals/requiredTerminalService.js.map +1 -1
  858. package/dist/server/terminals/terminalStatusRoutes.js +22 -0
  859. package/dist/server/terminals/terminalStatusRoutes.js.map +1 -0
  860. package/dist/server/themeBootstrap.js +123 -0
  861. package/dist/server/themeBootstrap.js.map +1 -0
  862. package/dist/server/themeCatalog.js +206 -0
  863. package/dist/server/themeCatalog.js.map +1 -0
  864. package/dist/server/themeMetadata.js +74 -0
  865. package/dist/server/themeMetadata.js.map +1 -0
  866. package/dist/server/webSocketBridge.js +16 -12
  867. package/dist/server/webSocketBridge.js.map +1 -1
  868. package/dist/server/webSocketPayloadLimit.js +17 -0
  869. package/dist/server/webSocketPayloadLimit.js.map +1 -0
  870. package/dist/server/workspaceExplorerRoutes.js +3 -1
  871. package/dist/server/workspaceExplorerRoutes.js.map +1 -1
  872. package/dist/server/workspaces/effectivePathAccess.js +1 -1
  873. package/dist/server/workspaces/effectivePathAccess.js.map +1 -1
  874. package/dist/server/workspaces/projectPiWebConfig.js +30 -7
  875. package/dist/server/workspaces/projectPiWebConfig.js.map +1 -1
  876. package/dist/server/workspaces/sessionDaemonWorkspaceCatalog.js +2 -0
  877. package/dist/server/workspaces/sessionDaemonWorkspaceCatalog.js.map +1 -1
  878. package/dist/server/workspaces/workspaceProviderRegistry.js +6 -2
  879. package/dist/server/workspaces/workspaceProviderRegistry.js.map +1 -1
  880. package/dist/server/workspaces/workspaceRemovalService.js +6 -4
  881. package/dist/server/workspaces/workspaceRemovalService.js.map +1 -1
  882. package/dist/server-plugin-api.d.ts +39 -1
  883. package/dist/server-plugin-api.js +18 -3
  884. package/dist/server-plugin-api.js.map +1 -1
  885. package/dist/sessiond/sessionDaemonClient.js +7 -1
  886. package/dist/sessiond/sessionDaemonClient.js.map +1 -1
  887. package/dist/sessiond/sessionDaemonTerminalStatus.js +27 -0
  888. package/dist/sessiond/sessionDaemonTerminalStatus.js.map +1 -0
  889. package/dist/shared/apiTypes.js +4 -0
  890. package/dist/shared/apiTypes.js.map +1 -1
  891. package/dist/shared/capabilities.js +6 -0
  892. package/dist/shared/capabilities.js.map +1 -1
  893. package/dist/shared/commandOutputPresentation.js +17 -0
  894. package/dist/shared/commandOutputPresentation.js.map +1 -0
  895. package/dist/shared/commandResultPresentation.js +51 -0
  896. package/dist/shared/commandResultPresentation.js.map +1 -0
  897. package/dist/shared/configResolution.js +99 -0
  898. package/dist/shared/configResolution.js.map +1 -0
  899. package/dist/shared/defaultLocalization.js +60 -0
  900. package/dist/shared/defaultLocalization.js.map +1 -0
  901. package/dist/shared/federatedRoutes.js +13 -1
  902. package/dist/shared/federatedRoutes.js.map +1 -1
  903. package/dist/shared/installationName.js +21 -0
  904. package/dist/shared/installationName.js.map +1 -0
  905. package/dist/shared/localization.d.ts +55 -0
  906. package/dist/shared/localization.js +4 -0
  907. package/dist/shared/machineStatus.js +2 -0
  908. package/dist/shared/machineStatus.js.map +1 -1
  909. package/dist/shared/managedAgents.js +2 -0
  910. package/dist/shared/managedAgents.js.map +1 -0
  911. package/dist/shared/piWebConfigParsing.js +16 -30
  912. package/dist/shared/piWebConfigParsing.js.map +1 -1
  913. package/dist/shared/piWebRuntime.js +17 -0
  914. package/dist/shared/piWebRuntime.js.map +1 -0
  915. package/dist/shared/piWebStatusParsing.js +5 -0
  916. package/dist/shared/piWebStatusParsing.js.map +1 -1
  917. package/dist/shared/pluginApiTypes.d.ts +49 -7
  918. package/dist/shared/pluginBackendProtocol.js +24 -0
  919. package/dist/shared/pluginBackendProtocol.js.map +1 -1
  920. package/dist/shared/pluginCatalogTypes.d.ts +8 -0
  921. package/dist/shared/pluginCatalogTypes.js +15 -0
  922. package/dist/shared/pluginCatalogTypes.js.map +1 -1
  923. package/dist/shared/pluginResourceMetadata.js +58 -0
  924. package/dist/shared/pluginResourceMetadata.js.map +1 -0
  925. package/dist/shared/pluginSessionLifecycleTypes.d.ts +24 -0
  926. package/dist/shared/pluginSessionLifecycleTypes.js +56 -0
  927. package/dist/shared/pluginSessionLifecycleTypes.js.map +1 -0
  928. package/dist/shared/serverNoticePresentation.d.ts +9 -0
  929. package/dist/shared/serverNoticePresentation.js +12 -0
  930. package/dist/shared/serverNoticePresentation.js.map +1 -0
  931. package/dist/shared/sessionActivityPresentation.js +73 -0
  932. package/dist/shared/sessionActivityPresentation.js.map +1 -0
  933. package/dist/shared/sessionNotificationPresentation.js +16 -0
  934. package/dist/shared/sessionNotificationPresentation.js.map +1 -0
  935. package/dist/shared/terminalCommandRun.js +4 -0
  936. package/dist/shared/terminalCommandRun.js.map +1 -1
  937. package/dist/shared/terminalServiceStatus.js +14 -0
  938. package/dist/shared/terminalServiceStatus.js.map +1 -0
  939. package/dist/shared/terminalTitlePresentation.d.ts +10 -0
  940. package/dist/shared/terminalTitlePresentation.js +13 -0
  941. package/dist/shared/terminalTitlePresentation.js.map +1 -0
  942. package/dist/shared/themeCatalog.js +2 -0
  943. package/dist/shared/themeCatalog.js.map +1 -0
  944. package/dist/shared/themePreference.js +1 -0
  945. package/dist/shared/themePreference.js.map +1 -1
  946. package/dist/shared/thinkingLevels.d.ts +29 -0
  947. package/dist/shared/thinkingLevels.js +6 -4
  948. package/dist/shared/thinkingLevels.js.map +1 -1
  949. package/dist/shared/versionCheckPolicy.js +10 -0
  950. package/dist/shared/versionCheckPolicy.js.map +1 -0
  951. package/dist/shared/workspaceRemovalPresentation.d.ts +8 -0
  952. package/dist/shared/workspaceRemovalPresentation.js +10 -0
  953. package/dist/shared/workspaceRemovalPresentation.js.map +1 -0
  954. package/docs/README.md +7 -3
  955. package/docs/assets/pi-web-desktop-graphite.png +0 -0
  956. package/docs/assets/pi-web-desktop-paper.png +0 -0
  957. package/docs/assets/pi-web-desktop-pi-web-dark.png +0 -0
  958. package/docs/assets/pi-web-desktop-pi-web-light.png +0 -0
  959. package/docs/assets/pi-web-desktop.png +0 -0
  960. package/docs/assets/pi-web-mobile-graphite.png +0 -0
  961. package/docs/assets/pi-web-mobile-paper.png +0 -0
  962. package/docs/assets/pi-web-mobile-pi-web-dark.png +0 -0
  963. package/docs/assets/pi-web-mobile-pi-web-light.png +0 -0
  964. package/docs/assets/pi-web-mobile-themes.gif +0 -0
  965. package/docs/assets/pi-web-mobile.png +0 -0
  966. package/docs/assets/pi-web-tablet-graphite.png +0 -0
  967. package/docs/assets/pi-web-tablet-paper.png +0 -0
  968. package/docs/assets/pi-web-tablet-pi-web-dark.png +0 -0
  969. package/docs/assets/pi-web-tablet-pi-web-light.png +0 -0
  970. package/docs/assets/pi-web-tablet-themes.gif +0 -0
  971. package/docs/assets/pi-web-tablet.png +0 -0
  972. package/docs/assets/pi-web-themes.gif +0 -0
  973. package/docs/config.md +196 -56
  974. package/docs/plugins.md +370 -26
  975. package/docs/scheduled-tasks.md +127 -0
  976. package/package.json +43 -19
  977. package/dist/client/assets/CommandPicker-gK2biReF.js +0 -70
  978. package/dist/client/assets/PiWebApp-Do_8tp5d.js +0 -3761
  979. package/dist/client/assets/SettingsDialog-vGDo1-BJ.js +0 -1015
  980. package/dist/client/assets/index-Ura0RJyr.js +0 -2
  981. package/dist/client/assets/managementEmbed-Bx8Mwzdw.js +0 -2
  982. package/dist/client/assets/preload-helper-XpATwJ5c.js +0 -1
  983. package/dist/pi-packages/captains-log/README.md +0 -11
  984. package/dist/pi-packages/captains-log/dist/browser/channelProtocol.js +0 -29
  985. package/dist/pi-packages/captains-log/dist/browser/index.js +0 -143
  986. package/dist/pi-packages/captains-log/dist/browser/markdown.js +0 -68
  987. package/dist/pi-packages/captains-log/dist/browser/panel.js +0 -148
  988. package/dist/pi-packages/captains-log/dist/browser/protocol.js +0 -26
  989. package/dist/pi-packages/captains-log/dist/companion.js +0 -126
  990. package/dist/pi-packages/captains-log/dist/roundtrip.js +0 -62
  991. package/dist/pi-packages/captains-log/dist/server.js +0 -210
  992. package/dist/pi-packages/captains-log/dist/store.js +0 -75
  993. package/dist/pi-packages/captains-log/docs/usage.md +0 -29
  994. package/dist/pi-packages/captains-log/i18n.js +0 -7
  995. package/dist/pi-packages/captains-log/package.json +0 -35
  996. package/dist/pi-packages/captains-log/tsconfig.json +0 -21
  997. package/dist/pi-packages/captains-log/vite.config.mjs +0 -28
  998. package/examples/session-bridge-plugin/README.md +0 -20
  999. package/examples/session-bridge-plugin/docs/usage.md +0 -54
  1000. package/examples/session-bridge-plugin/package.json +0 -26
  1001. package/examples/session-bridge-plugin/src/browser/index.ts +0 -87
  1002. package/examples/session-bridge-plugin/src/browser/protocol.ts +0 -24
  1003. package/examples/session-bridge-plugin/src/companion.ts +0 -65
  1004. package/examples/session-bridge-plugin/src/reviewRun.ts +0 -39
  1005. package/examples/session-bridge-plugin/src/server.ts +0 -85
  1006. package/examples/session-bridge-plugin/src/store.ts +0 -80
  1007. package/examples/session-bridge-plugin/tsconfig.json +0 -21
  1008. /package/dist/{client/assets/classic-CyM97Akm.css → pi-web-plugins/themes/assets/classic.css} +0 -0
  1009. /package/dist/{client/assets/pi-web-dark-D_KtbM95.css → pi-web-plugins/themes/assets/pi-web-dark.css} +0 -0
  1010. /package/dist/{client/assets/pi-web-light-DSNLMIBI.css → pi-web-plugins/themes/assets/pi-web-light.css} +0 -0
@@ -1,6 +1,11 @@
1
1
  import { parsePersistedChildSubsessionLink, parsePersistedParentSubsessionLink } from "./subsessionProvenance.js";
2
2
  import { AsyncLocalStorage } from "node:async_hooks";
3
3
  import { createHash, randomUUID } from "node:crypto";
4
+ import { sessionNotificationSources } from "../../shared/sessionNotificationPresentation.js";
5
+ import { runtimeActivityFallbackLabel } from "../../shared/sessionActivityPresentation.js";
6
+ const STARTUP_PHASE_RUNTIME = "Starting the Pi session";
7
+ const STARTUP_PHASE_EXTENSIONS = "Loading session extensions";
8
+ const STARTUP_CONCURRENT_CATALOG_REFRESH = "provider model lists are refreshing";
4
9
  import { readSessionUiMetadata, requireSessionUiMetadata, SESSION_UI_METADATA_CUSTOM_TYPE } from "./sessionMetadata.js";
5
10
  import { UserFacingError, createTranslator, userFacingErrorMessage } from "../../shared/i18n.js";
6
11
  import { realpathSync, statSync } from "node:fs";
@@ -26,7 +31,7 @@ import { SessionActivityMarker } from "./sessionActivityMarker.js";
26
31
  import { projectSessionTree } from "./sessionTreeProjection.js";
27
32
  import { SessionArchiveStore } from "./sessionArchiveStore.js";
28
33
  import { findArchiveCandidateByExactId, planSessionArchiveTree } from "./sessionArchiveTree.js";
29
- import { fallbackSessionName, generateShortSessionName, requireInitialSessionName } from "./sessionNameGenerator.js";
34
+ import { requireInitialSessionName } from "./sessionNameGenerator.js";
30
35
  import { computeEditPreview } from "./editPreview.js";
31
36
  import { attachmentsToInlineImages, saveAttachmentsToWorkspace } from "./attachmentService.js";
32
37
  import { loadEffectiveProjectAttachmentsConfig } from "../workspaces/projectPiWebConfig.js";
@@ -37,16 +42,18 @@ import { resolveWebProjectTrusted } from "./projectTrust.js";
37
42
  import { createPiSessionManagerGateway } from "./piSessionManagerGateway.js";
38
43
  import { SessionPinStore } from "./sessionPinStore.js";
39
44
  import { SessionActivityCoordinator } from "./sessionActivityCoordinator.js";
40
- import { searchSessionContent } from "./sessionContentSearch.js";
45
+ import { compileSessionContentQuery, searchSessionContent } from "./sessionContentSearch.js";
41
46
  import { createLocalOnlyModelRuntime, modelRuntimeAuthPath } from "./authService.js";
42
47
  import { canonicalizeStoredCwd, cwdPathsEqual } from "../workingDirectory.js";
43
48
  import { clearSessionFileParent, readSessionHeaderSummary } from "./sessionFileHeader.js";
44
- import { isManagedAgentsFile, workbenchAccessHandle } from "../managementEmbed.js";
49
+ import { assertManagedCwd, isManagedAgentsFile, workbenchAccessHandle } from "../managementEmbed.js";
45
50
  import { managementPrivilegeRequested, managementPrivileges, managementUsesNormalPermissions } from "../managementPrivileges.js";
46
51
  import { DEFAULT_EXTENSION_DIALOGS_TIMEOUT_MS, piWebDataDir } from "../../config.js";
47
52
  import { createScopedSettingsManager, resolveSettingsScopeDirectory } from "./projectSettingsScope.js";
48
53
  import { parseSessionDefaults, parseSessionDefaultsUpdate } from "../../shared/sessionDefaults.js";
49
54
  import { createAskUserToolDefinition } from "./askUserTool.js";
55
+ import { createRequestHumanInterventionToolDefinition } from "./requestHumanInterventionTool.js";
56
+ import { requestsHumanIntervention, SESSION_INTERVENTION_CUSTOM_TYPE, sessionInterventionRequired } from "./sessionIntervention.js";
50
57
  import { createAskUserOutcome, renderAskUserAnswersText, resolveAskUserRequest } from "./askUserDomain.js";
51
58
  import { createSubsessionCompletionDelivery } from "./subsessionCompletionDelivery.js";
52
59
  import { completionReceiptIds, persistedSubsessionCompletions, renderSubsessionCompletions, SUBSESSION_COMPLETION_ENTRY_TYPE, SUBSESSION_NOTIFICATION_CUSTOM_TYPE, SUBSESSION_RECEIPT_ENTRY_TYPE, SubsessionCompletionInbox } from "./subsessionCompletionInbox.js";
@@ -56,6 +63,7 @@ import { ExtensionDialogWaiters, effectiveExtensionDialogTimeoutMs, extensionDia
56
63
  import { createSpawnSessionToolDefinition } from "./spawnSessionTool.js";
57
64
  import { createSubsessionToolDefinitions } from "./spawnSubsessionTool.js";
58
65
  import { buildTranscriptView } from "./subsessionTranscript.js";
66
+ import { createSendSessionMessageToolDefinition } from "./sendSessionMessageTool.js";
59
67
  import { planSessionCleanup, summarizeSessionCleanupExecution } from "./sessionCleanup.js";
60
68
  import { createManagedAgentToolOptions, createManagedBashToolDefinition, createManagedPythonToolDefinition } from "./managementAgentTools.js";
61
69
  import { PI_PERMISSION_SYSTEM_POLICY_AGENT_DIR, managementAgentToolNames, privilegedManagementToolNames, withRuntimeCreationEnvironment, writeManagementPermissionSystemPolicy } from "./managementPermissionSystem.js";
@@ -311,7 +319,8 @@ export function collectRuntimeWarnings(runtime) {
311
319
  /**
312
320
  * Verbatim TUI wording for the Anthropic subscription-auth billing notice. Kept
313
321
  * character-for-character in sync with `ANTHROPIC_SUBSCRIPTION_AUTH_WARNING` in
314
- * the SDK's interactive mode so the browser shows the same message the TUI does.
322
+ * the SDK's interactive mode as the wire fallback. Browser presentation metadata
323
+ * allows translation without matching this English string.
315
324
  */
316
325
  const ANTHROPIC_SUBSCRIPTION_AUTH_WARNING = "Anthropic subscription auth is active. Third-party harness usage draws from extra usage and is billed per token, not your Claude plan limits. Manage extra usage at https://claude.ai/settings/usage.";
317
326
  /** Mirror of the SDK TUI `isAnthropicSubscriptionAuthKey` (subscription API keys start with `sk-ant-oat`). */
@@ -352,6 +361,7 @@ export function anthropicSubscriptionWarning(session, authPath) {
352
361
  return {
353
362
  severity: "warning",
354
363
  message: ANTHROPIC_SUBSCRIPTION_AUTH_WARNING,
364
+ presentation: { kind: "anthropicSubscriptionAuth" },
355
365
  source: "anthropic",
356
366
  dismiss: { id: ANTHROPIC_EXTRA_USAGE_DISMISS_ID },
357
367
  };
@@ -438,11 +448,11 @@ async function createNormalPermissionSessionServices(options) {
438
448
  });
439
449
  return { services, projectTrustDiagnostics };
440
450
  }
441
- function createDefaultRuntimeFactory(sessionEvents, normalModelRuntimeForCwd, managementModelRuntime, resolveSettingsScope, sessionManagers, spawn, subsessions, askUserEnabled = false, workbench, logger = noopLogger, managementAudit, managementProjectIdForCwd, appendSystemPromptSections = [], managementAllowPrivileged = false) {
451
+ function createDefaultRuntimeFactory(sessionEvents, normalModelRuntimeForCwd, managementModelRuntime, resolveSettingsScope, sessionManagers, spawn, subsessions, askUserEnabled = false, workbench, logger = noopLogger, managementAudit, managementProjectIdForCwd, appendSystemPromptSections = [], managementAllowPrivileged = false, messaging) {
442
452
  return async ({ cwd, agentDir, sessionManager, sessionStartEvent, managementContext, initialModel, initialThinkingLevel, delegationToolsEnabled }) => {
443
453
  const scopedModelRuntime = managementContext === undefined ? await normalModelRuntimeForCwd(cwd) : await managementModelRuntime();
444
454
  if (managementContext !== undefined) {
445
- return createManagementRuntimeFactory(scopedModelRuntime, resolveSettingsScope, sessionManagers, spawn, subsessions, askUserEnabled, managementContext, workbench, logger, managementAudit, managementProjectIdForCwd, managementAllowPrivileged, appendSystemPromptSections)({
455
+ return createManagementRuntimeFactory(scopedModelRuntime, resolveSettingsScope, sessionManagers, spawn, subsessions, askUserEnabled, managementContext, workbench, logger, managementAudit, managementProjectIdForCwd, managementAllowPrivileged, appendSystemPromptSections, messaging)({
446
456
  cwd,
447
457
  agentDir,
448
458
  sessionManager,
@@ -454,6 +464,8 @@ function createDefaultRuntimeFactory(sessionEvents, normalModelRuntimeForCwd, ma
454
464
  }
455
465
  // Resource loaders may read process.env; wait for managed overrides to be restored.
456
466
  return withRuntimeCreationEnvironment({}, async () => {
467
+ const parentSessionFile = sessionManager.getHeader()?.parentSession;
468
+ const parentHeader = parentSessionFile === undefined ? undefined : await readSessionHeaderSummary(parentSessionFile);
457
469
  const projectTrustRequiring = hasTrustRequiringProjectResources(cwd);
458
470
  const settingsManager = await createScopedSettingsManager({
459
471
  cwd,
@@ -473,7 +485,10 @@ function createDefaultRuntimeFactory(sessionEvents, normalModelRuntimeForCwd, ma
473
485
  modelRuntime: scopedModelRuntime,
474
486
  settingsManager,
475
487
  projectTrustRequiring,
476
- appendSystemPromptSections,
488
+ appendSystemPromptSections: [
489
+ ...appendSystemPromptSections,
490
+ ...(parentHeader === undefined ? [] : [`<pi_web_session_context>\nParent session ID: ${parentHeader.id}\n</pi_web_session_context>`]),
491
+ ],
477
492
  eventBus,
478
493
  mcpScope: { directory: mcpOAuthStorageDirectory(await resolveSettingsScope(cwd, "normal")) },
479
494
  extensionFactories: [sessionDispatch, ...(subsessions === undefined ? [] : [createSubsessionCompletionDelivery(subsessions)])],
@@ -488,7 +503,7 @@ function createDefaultRuntimeFactory(sessionEvents, normalModelRuntimeForCwd, ma
488
503
  const resolvedDelegationToolsEnabled = delegationToolsEnabled
489
504
  ?? await sessionAllowsDelegationTools(sessionManager, sessionManagers);
490
505
  dispatchEnabled = resolvedDelegationToolsEnabled;
491
- const customTools = createPiWebCustomToolDefinitions(cwd, resolvedDelegationToolsEnabled, spawn, subsessions, askUserEnabled);
506
+ const customTools = createPiWebCustomToolDefinitions(cwd, resolvedDelegationToolsEnabled, spawn, subsessions, askUserEnabled, messaging);
492
507
  const result = await createAgentSessionFromServices({
493
508
  services,
494
509
  sessionManager,
@@ -505,7 +520,7 @@ function createDefaultRuntimeFactory(sessionEvents, normalModelRuntimeForCwd, ma
505
520
  });
506
521
  };
507
522
  }
508
- function createManagementRuntimeFactory(modelRuntime, resolveSettingsScope, sessionManagers, spawn, subsessions, askUserEnabled, managementContext, workbench, logger, managementAudit, managementProjectIdForCwd, managementAllowPrivileged = false, appendSystemPromptSections = []) {
523
+ function createManagementRuntimeFactory(modelRuntime, resolveSettingsScope, sessionManagers, spawn, subsessions, askUserEnabled, managementContext, workbench, logger, managementAudit, managementProjectIdForCwd, managementAllowPrivileged = false, appendSystemPromptSections = [], messaging) {
509
524
  return async ({ cwd, agentDir, sessionManager, sessionStartEvent, initialModel, initialThinkingLevel, delegationToolsEnabled }) => {
510
525
  const normalPermissions = managementUsesNormalPermissions(managementContext, { allowPrivileged: managementAllowPrivileged });
511
526
  const privileges = managementPrivileges(managementContext, { allowPrivileged: managementAllowPrivileged });
@@ -541,10 +556,16 @@ function createManagementRuntimeFactory(modelRuntime, resolveSettingsScope, sess
541
556
  const scopedSpawn = spawn === undefined
542
557
  ? undefined
543
558
  : (input) => spawn({ ...input, managementContext });
559
+ const scopedMessaging = messaging === undefined ? undefined : {
560
+ send: (input) => messaging.send(input, managementContext),
561
+ };
544
562
  const scopedSubsessions = subsessions === undefined
545
563
  ? undefined
546
564
  : {
547
565
  spawn: (input) => subsessions.spawn({ ...input, managementContext }),
566
+ archive: (parentSessionId, sessionId, parentSessionFile) => subsessions.archive(parentSessionId, sessionId, parentSessionFile, managementContext),
567
+ stop: (parentSessionId, sessionId, parentSessionFile) => subsessions.stop(parentSessionId, sessionId, parentSessionFile, managementContext),
568
+ resume: (parentSessionId, sessionId, prompt, parentSessionFile) => subsessions.resume(parentSessionId, sessionId, prompt, parentSessionFile, managementContext),
548
569
  list: (parentSessionId, parentSessionFile) => subsessions.list(parentSessionId, parentSessionFile, managementContext),
549
570
  join: (parentSessionId, parentSessionFile, toolCallId) => subsessions.join(parentSessionId, parentSessionFile, toolCallId, managementContext),
550
571
  prepare: (parentSessionId, parentSessionFile) => subsessions.prepare(parentSessionId, parentSessionFile, managementContext),
@@ -552,10 +573,16 @@ function createManagementRuntimeFactory(modelRuntime, resolveSettingsScope, sess
552
573
  read: (parentSessionId, sessionId, query, parentSessionFile, toolCallId) => subsessions.read(parentSessionId, sessionId, query, parentSessionFile, toolCallId, managementContext),
553
574
  };
554
575
  const managementFactories = [
555
- ...(normalPermissions ? [createExtensionSessionDispatch(cwd, { ...(scopedSpawn === undefined ? {} : { spawn: scopedSpawn }), isEnabled: () => resolvedDelegationToolsEnabled })] : []),
576
+ createExtensionSessionDispatch(cwd, {
577
+ ...(scopedSpawn === undefined ? {} : { spawn: scopedSpawn }),
578
+ isEnabled: () => resolvedDelegationToolsEnabled
579
+ && (normalPermissions || managementContext.tools?.deny?.includes("dispatch_relay") !== true),
580
+ }),
556
581
  ...(scopedSubsessions === undefined ? [] : [createSubsessionCompletionDelivery(scopedSubsessions)]),
557
582
  ];
558
583
  const controlledManagementTools = [
584
+ defineTool(createRequestHumanInterventionToolDefinition()),
585
+ ...(scopedMessaging === undefined ? [] : [defineTool(createSendSessionMessageToolDefinition(cwd, scopedMessaging))]),
559
586
  ...(resolvedDelegationToolsEnabled && scopedSpawn !== undefined ? [defineTool(createSpawnSessionToolDefinition(cwd, { spawn: scopedSpawn }))] : []),
560
587
  ...(resolvedDelegationToolsEnabled && scopedSubsessions !== undefined ? createSubsessionToolDefinitions(cwd, scopedSubsessions).map((tool) => defineTool(tool)) : []),
561
588
  ...(askUserEnabled ? [createAskUserToolDefinition()] : []),
@@ -569,7 +596,11 @@ function createManagementRuntimeFactory(modelRuntime, resolveSettingsScope, sess
569
596
  requestedNetwork: managementContext.privileged?.network === true,
570
597
  }, "management privileged grant ignored because managementEmbed.allowPrivileged is disabled");
571
598
  }
572
- const extraToolNames = [...controlledManagementToolNames, ...privilegedManagementToolNames(privileges)];
599
+ const extraToolNames = [
600
+ ...controlledManagementToolNames,
601
+ ...(resolvedDelegationToolsEnabled && scopedSpawn !== undefined ? ["dispatch_relay"] : []),
602
+ ...privilegedManagementToolNames(privileges),
603
+ ];
573
604
  const policyAgentDir = normalPermissions ? undefined : await writeManagementPermissionSystemPolicy(agentDir, cwd, managementContext, extraToolNames, privileges);
574
605
  const resourceEnvironment = normalPermissions ? {} : { [PI_PERMISSION_SYSTEM_POLICY_AGENT_DIR]: policyAgentDir };
575
606
  return withRuntimeCreationEnvironment(resourceEnvironment, async () => {
@@ -613,7 +644,7 @@ function createManagementRuntimeFactory(modelRuntime, resolveSettingsScope, sess
613
644
  ...(initialThinkingLevel === undefined ? {} : { initialThinkingLevel }),
614
645
  });
615
646
  services.diagnostics.push(...modelOptions.diagnostics);
616
- const customTools = normalPermissions ? createPiWebCustomToolDefinitions(cwd, resolvedDelegationToolsEnabled, scopedSpawn, scopedSubsessions, askUserEnabled) : [
647
+ const customTools = normalPermissions ? createPiWebCustomToolDefinitions(cwd, resolvedDelegationToolsEnabled, scopedSpawn, scopedSubsessions, askUserEnabled, scopedMessaging) : [
617
648
  ...managedAgentToolDefinitions(cwd, createManagedAgentToolOptions(cwd)),
618
649
  createManagedPythonToolDefinition(cwd, managementContext, { network: privileges.network }),
619
650
  createManagedBashToolDefinition(cwd, managementContext, { network: privileges.network, hostFilesystem: privileges.bash }),
@@ -643,9 +674,11 @@ function createManagementRuntimeFactory(modelRuntime, resolveSettingsScope, sess
643
674
  });
644
675
  };
645
676
  }
646
- export function createPiWebCustomToolDefinitions(cwd, delegationEnabled, spawn, subsessions, askUserEnabled = false) {
677
+ export function createPiWebCustomToolDefinitions(cwd, delegationEnabled, spawn, subsessions, askUserEnabled = false, messaging) {
647
678
  return [
648
679
  ...managedAgentToolDefinitions(cwd),
680
+ defineTool(createRequestHumanInterventionToolDefinition()),
681
+ ...(messaging === undefined ? [] : [defineTool(createSendSessionMessageToolDefinition(cwd, messaging))]),
649
682
  ...(delegationEnabled && spawn !== undefined ? [defineTool(createSpawnSessionToolDefinition(cwd, { spawn }))] : []),
650
683
  ...(delegationEnabled && subsessions !== undefined ? createSubsessionToolDefinitions(cwd, subsessions).map((tool) => defineTool(tool)) : []),
651
684
  ...(askUserEnabled ? [createAskUserToolDefinition()] : []),
@@ -678,7 +711,7 @@ function createPiWebEditToolDefinition(cwd, options) {
678
711
  async execute(toolCallId, params, signal, onUpdate, ctx) {
679
712
  const preview = await computeEditPreview(params.path, params.edits, cwd);
680
713
  if (signal?.aborted !== true) {
681
- onUpdate?.({ content: [{ type: "text", text: "Edit preview computed." }], details: { preview } });
714
+ onUpdate?.({ content: [{ type: "text", text: "Edit preview computed." }], details: { preview, presentation: { kind: "editPreviewComputed" } } });
682
715
  }
683
716
  return editTool.execute(toolCallId, params, signal, onUpdate, ctx);
684
717
  },
@@ -697,12 +730,19 @@ export class PiSessionService {
697
730
  this.activities = new SessionActivityCoordinator();
698
731
  /** Runtime-identity gate held while Pi may await abandoned-branch summarization. */
699
732
  this.treeNavigations = new WeakSet();
733
+ this.publishedSessionNames = new WeakMap();
734
+ /**
735
+ * Bare live leaf selected without an appended summary entry. Recording that
736
+ * leaf distinguishes the unpersisted move from a later runtime append that
737
+ * can anchor the selected branch on disk.
738
+ */
700
739
  this.unpersistedTreeBranchLeaves = new WeakMap();
701
740
  /** Counts async operations that may append an entry before they settle. */
702
741
  this.sessionEntryMutationCounts = new WeakMap();
703
742
  this.manualCompactionEnded = new WeakSet();
704
743
  this.extensionCommandExecution = new AsyncLocalStorage();
705
744
  this.runtimeMessageCounts = new WeakMap();
745
+ this.interventionStates = new WeakMap();
706
746
  this.snapshotMessageCounts = new WeakMap();
707
747
  this.pendingPromptEchoes = new WeakMap();
708
748
  this.publishedAssistantPartials = new WeakMap();
@@ -722,7 +762,6 @@ export class PiSessionService {
722
762
  this.subsessionStoppedParents = new WeakSet();
723
763
  this.subsessionDeliveringParents = new WeakSet();
724
764
  this.subsessionDeliveryScheduled = new WeakSet();
725
- this.deferredGeneratedSessionNames = new WeakMap();
726
765
  this.compactionPromptQueues = new Map();
727
766
  this.compactionDrainTimers = new Map();
728
767
  this.authLossWarnings = new Set();
@@ -752,6 +791,7 @@ export class PiSessionService {
752
791
  this.mcpAuthOwners = new WeakMap();
753
792
  this.notificationGenerationBySession = new WeakMap();
754
793
  this.idleSessionFileResolutions = new WeakMap();
794
+ this.unreadEligibilityRevision = 0;
755
795
  /** The parked extension Promise resolvers behind the store's open dialogs. */
756
796
  this.dialogWaiters = new ExtensionDialogWaiters();
757
797
  this.pendingUnreadMutations = [];
@@ -760,6 +800,7 @@ export class PiSessionService {
760
800
  this.t = deps.translator ?? loadNodeTranslator("server");
761
801
  this.managementAllowPrivileged = deps.managementAllowPrivileged === true;
762
802
  this.archiveStore = deps.archiveStore ?? new SessionArchiveStore();
803
+ this.sessionPins = deps.sessionPins;
763
804
  this.pinStore = deps.pinStore ?? new SessionPinStore(join(deps.dataDir ?? piWebDataDir(), "session-pins.json"));
764
805
  this.agentDir = deps.agentDir ?? getAgentDir();
765
806
  this.dataDir = deps.dataDir ?? piWebDataDir();
@@ -781,6 +822,7 @@ export class PiSessionService {
781
822
  ? resolveDefaultModelRuntime
782
823
  : () => Promise.resolve(managementModelRuntime);
783
824
  this.spawnTargets = deps.spawnTargets;
825
+ this.messageTargets = deps.sessionMessagesEnabled === false ? undefined : deps.messageTargets ?? deps.spawnTargets;
784
826
  this.logger = deps.logger ?? noopLogger;
785
827
  this.normalToolAudit = deps.normalToolAudit;
786
828
  this.managementAudit = deps.managementAudit;
@@ -805,20 +847,24 @@ export class PiSessionService {
805
847
  this.sessionEvents = deps.sessionEvents ?? new PiSessionEventConnections();
806
848
  this.createRuntime = deps.createRuntime ?? createDefaultRuntimeFactory(this.sessionEvents, this.normalModelRuntimeForCwd, this.managementModelRuntime, (cwd, mode) => this.resolveSettingsScopeDirectory(cwd, mode), this.sessionManager, this.spawnTargets === undefined ? undefined : (input) => this.spawnSession(input), !subsessionsActive ? undefined : {
807
849
  spawn: (input) => this.spawnSubsession(input),
850
+ archive: (parentSessionId, sessionId, parentSessionFile, context) => this.archiveSubsession(parentSessionId, sessionId, parentSessionFile, context),
851
+ stop: (parentSessionId, sessionId, parentSessionFile, context) => this.stopSubsession(parentSessionId, sessionId, parentSessionFile, context),
852
+ resume: (parentSessionId, sessionId, prompt, parentSessionFile, context) => this.resumeSubsession(parentSessionId, sessionId, prompt, parentSessionFile, context),
808
853
  list: (parentSessionId, parentSessionFile, managementContext) => this.listSubsessions(parentSessionId, parentSessionFile, managementContext),
809
854
  join: (parentSessionId, parentSessionFile, toolCallId, managementContext) => this.joinSubsessions(parentSessionId, parentSessionFile, toolCallId, managementContext),
810
855
  prepare: (parentSessionId, parentSessionFile, managementContext) => this.prepareSubsessionDelivery(parentSessionId, parentSessionFile, managementContext),
811
856
  check: (parentSessionId, sessionId, parentSessionFile, toolCallId, managementContext) => this.checkSubsession(parentSessionId, sessionId, parentSessionFile, toolCallId, managementContext),
812
857
  read: (parentSessionId, sessionId, query, parentSessionFile, toolCallId, managementContext) => this.readSubsession(parentSessionId, sessionId, query, parentSessionFile, toolCallId, managementContext),
813
- }, deps.askUserEnabled === true, deps.workbench, this.logger, this.managementAudit, this.managementProjectIdForCwd, deps.appendSystemPromptSections ?? [], deps.managementAllowPrivileged === true);
858
+ }, deps.askUserEnabled === true, deps.workbench, this.logger, this.managementAudit, this.managementProjectIdForCwd, deps.appendSystemPromptSections ?? [], deps.managementAllowPrivileged === true, this.messageTargets === undefined ? undefined : { send: (input, context) => this.sendSessionMessage(input, context) });
814
859
  this.createAgentRuntime = deps.createAgentRuntime ?? defaultCreateAgentRuntime;
815
860
  this.workspaceActivity = deps.workspaceActivity;
816
861
  this.heartbeat = setInterval(() => { this.publishHeartbeats(); }, deps.heartbeatIntervalMs ?? 2000);
817
862
  this.commandService = new SessionCommandService((sessionId, eventScope) => this.getActiveForCommand(sessionId, eventScope), (sessionId, text, eventScope) => this.submitCommandPrompt(sessionId, text, eventScope), events, {
863
+ onSessionNameChanged: (session) => { this.publishSessionName(session); },
818
864
  onCompactionStart: (session) => {
819
865
  this.beginSessionEntryMutation(session, this.t("session.action.compact", "compact the session"));
820
866
  this.manualCompactionEnded.delete(session);
821
- this.publishActivity(session, this.t("activity.compacting", "Compacting context"), "active");
867
+ this.publishActivity(session, { kind: "compacting" }, "active");
822
868
  this.publishStatus(session);
823
869
  },
824
870
  onCompactionEnd: (session, result, detail) => {
@@ -858,43 +904,25 @@ export class PiSessionService {
858
904
  return previewResponseFromPlan(await this.cleanupPlan(request));
859
905
  }
860
906
  async cleanup(request, context) {
861
- const scope = eventScopeFromManagementContext(context);
862
907
  const plan = await this.cleanupPlan(request);
863
908
  if (plan.deleteRecords.length > 0 && this.archiveStore.deleteArchived === undefined && this.archiveStore.deleteArchivedMany === undefined)
864
909
  throw new Error(this.t("session.archiveDeleteUnsupported", "The archive store does not support deletion"));
865
- const archiveInputs = [];
866
- const readyArchiveInputs = [];
867
- const deleteRecords = [];
868
- const readyDeleteRecords = [];
869
- const skippedBusySessionIds = new Set(plan.skippedBusySessionIds);
870
- for (const input of plan.archiveInputs) {
871
- if (this.activeSessionHasWork(input.sessionId)) {
872
- skippedBusySessionIds.add(input.sessionId);
873
- continue;
874
- }
875
- await this.closeActive(input.sessionId, { kind: "clear", reason: "archive" }, scope);
876
- readyArchiveInputs.push(input);
877
- }
878
- await this.archiveStoreArchiveMany(readyArchiveInputs);
879
- archiveInputs.push(...readyArchiveInputs);
880
- await this.forgetUnreadSessions(readyArchiveInputs, scope);
881
- for (const record of plan.deleteRecords) {
882
- if (this.activeSessionHasWork(record.sessionId)) {
883
- skippedBusySessionIds.add(record.sessionId);
884
- continue;
885
- }
886
- await this.closeActive(record.sessionId, { kind: "clear", reason: "delete" }, scope);
887
- readyDeleteRecords.push(record);
888
- }
889
- const deletedSessionIds = new Set(await this.archiveStoreDeleteArchivedMany(readyDeleteRecords.map((record) => record.sessionId)));
890
- deleteRecords.push(...readyDeleteRecords.filter((record) => deletedSessionIds.has(record.sessionId)));
891
- await this.forgetUnreadSessions(deleteRecords, scope);
910
+ const archived = await this.executeArchiveBatch(plan.archiveInputs, context);
911
+ if (archived.failures.length > 0)
912
+ throw new Error(archived.failures.map((failure) => `${failure.sessionId}: ${failure.error}`).join("; "));
913
+ const deleted = await this.executeDeleteArchivedBatch(plan.deleteRecords, context);
914
+ if (deleted.failures.length > 0)
915
+ throw new Error(deleted.failures.map((failure) => `${failure.sessionId}: ${failure.error}`).join("; "));
916
+ const archiveInputs = archived.successes;
917
+ const deleteRecords = deleted.successes;
918
+ const skippedBusySessionIds = new Set([...plan.skippedBusySessionIds, ...archived.skippedBusySessionIds, ...deleted.skippedBusySessionIds]);
892
919
  return summarizeSessionCleanupExecution({
893
920
  archiveInputs,
894
921
  deleteRecords,
895
922
  thresholds: plan.thresholds,
896
923
  generatedAt: plan.generatedAt,
897
924
  skippedBusySessionIds: [...skippedBusySessionIds],
925
+ ...(plan.skippedPinnedSessionIds === undefined ? {} : { skippedPinnedSessionIds: plan.skippedPinnedSessionIds }),
898
926
  });
899
927
  }
900
928
  async dispose() {
@@ -948,6 +976,18 @@ export class PiSessionService {
948
976
  });
949
977
  await this.publishUnreadMutations([]);
950
978
  }
979
+ /** Recover cold-session intervention flags without opening agent runtimes. */
980
+ async restoreInterventionState() {
981
+ const [sessions, archives] = await Promise.all([this.sessionManager.listAll(), this.archiveStore.list()]);
982
+ const archived = new Set(archives.map((record) => record.sessionId));
983
+ for (const session of sessions) {
984
+ if (!await normalSessionReadAllowed(session.cwd, this.projectPathForCwd, this.managementProjectRoot))
985
+ continue;
986
+ if (archived.has(session.id) || this.activeForLookup({ id: session.id, cwd: session.cwd }) !== undefined)
987
+ continue;
988
+ this.workspaceActivity?.applySessionIntervention(session.cwd, session.id, session.interventionRequired === true);
989
+ }
990
+ }
951
991
  async list(cwd, managementContext) {
952
992
  return (await this.listWorkspaceSessions(cwd, managementContext)).sessions;
953
993
  }
@@ -963,17 +1003,28 @@ export class PiSessionService {
963
1003
  if (normalizedQuery === "")
964
1004
  return { results: [], matchCount: 0, truncated: false };
965
1005
  const maxMatches = 200;
966
- const { listing, sessions } = await this.searchCandidates(cwd, normalizedQuery.toLocaleLowerCase(), managementContext);
967
- const results = [];
1006
+ const listing = await this.listWorkspaceSessions(cwd, managementContext);
1007
+ const matchText = compileSessionContentQuery(normalizedQuery);
1008
+ const candidates = [];
968
1009
  let matchCount = 0;
969
- for (const session of sessions) {
970
- const remaining = maxMatches - results.reduce((count, result) => count + result.matches.length, 0);
971
- const messages = this.searchableSessionHistory(session, listing, managementContext);
972
- const view = searchSessionContent(messages, normalizedQuery, Math.max(1, remaining));
1010
+ for (const session of listing.sessions) {
1011
+ const messages = await this.searchableSessionHistory(session, listing, managementContext);
1012
+ const view = searchSessionContent(messages, matchText, maxMatches);
973
1013
  matchCount += view.matchCount;
974
- if (remaining > 0 && view.matches.length > 0)
975
- results.push({ session, matches: view.matches.slice(0, remaining) });
1014
+ candidates.push(...view.matches.map((match) => ({ session, match })));
1015
+ candidates.sort((left, right) => left.match.rank - right.match.rank);
1016
+ candidates.length = Math.min(candidates.length, maxMatches);
1017
+ }
1018
+ const grouped = new Map();
1019
+ for (const { session, match } of candidates) {
1020
+ let result = grouped.get(session.id);
1021
+ if (result === undefined) {
1022
+ result = { session, matches: [] };
1023
+ grouped.set(session.id, result);
1024
+ }
1025
+ result.matches.push({ messageIndex: match.messageIndex, role: match.role, excerpts: match.excerpts, occurrenceCount: match.occurrenceCount });
976
1026
  }
1027
+ const results = [...grouped.values()];
977
1028
  return { results, matchCount, truncated: matchCount > maxMatches };
978
1029
  }
979
1030
  async listPinned(cwd, managementContext) {
@@ -1017,11 +1068,17 @@ export class PiSessionService {
1017
1068
  const listed = unarchivedById.get(session.sessionId);
1018
1069
  const tracked = this.subsessionLinkForActiveChild(session) !== undefined;
1019
1070
  if (listed !== undefined) {
1020
- if (tracked && session.sessionFile !== undefined && sessionPathsEqual(listed.path, session.sessionFile))
1021
- listed.agentSubsession = true;
1071
+ // Match the file too: a clone with the same id must not inherit a
1072
+ // live runtime's classification. Disk rows otherwise use the scanner.
1073
+ if (session.sessionFile !== undefined && sessionPathsEqual(listed.path, session.sessionFile)) {
1074
+ if (tracked)
1075
+ listed.agentSubsession = true;
1076
+ listed.interventionRequired = this.statusFromSession(session).interventionRequired === true;
1077
+ }
1022
1078
  continue;
1023
1079
  }
1024
1080
  const info = clientSessionFromActiveSession(session);
1081
+ info.interventionRequired = this.statusFromSession(session).interventionRequired === true;
1025
1082
  if (tracked)
1026
1083
  info.agentSubsession = true;
1027
1084
  unarchivedById.set(session.sessionId, info);
@@ -1032,6 +1089,10 @@ export class PiSessionService {
1032
1089
  if (managementContext === undefined) {
1033
1090
  await this.publishUnreadMutations(this.unreadForScope(eventScopeFromManagementContext(managementContext)).reconcileCwd(canonicalizeStoredCwd(cwd), reconcilableSessionIds));
1034
1091
  }
1092
+ for (const session of unarchivedSessions) {
1093
+ if (this.activeForLookup({ id: session.id, cwd }, managementContext) === undefined)
1094
+ this.workspaceActivity?.applySessionIntervention(cwd, session.id, session.interventionRequired === true, eventScopeFromManagementContext(managementContext));
1095
+ }
1035
1096
  const archivedSessions = archivedForCwd
1036
1097
  .map((record) => clientSessionFromArchivedRecord(record, sessionsById.get(record.sessionId)))
1037
1098
  .filter(isDefined)
@@ -1066,18 +1127,41 @@ export class PiSessionService {
1066
1127
  continue;
1067
1128
  const row = rows.get(session.sessionId);
1068
1129
  // A disk clone with the same id must not inherit another file's runtime.
1069
- if (row !== undefined && (session.sessionFile === undefined || !sessionPathsEqual(row.path, session.sessionFile)))
1130
+ if (row !== undefined && (row.path === undefined || session.sessionFile === undefined || !sessionPathsEqual(row.path, session.sessionFile)))
1070
1131
  continue;
1071
1132
  runtimes.set(session.sessionId, session);
1072
- rows.set(session.sessionId, clientSessionFromActiveSession(session));
1133
+ const headerCreated = session.sessionManager.getHeader?.()?.timestamp;
1134
+ const metadata = readSessionUiMetadata(session.sessionManager.getEntries?.() ?? session.sessionManager.getBranch());
1135
+ const created = row?.created ?? (headerCreated !== undefined && Number.isFinite(Date.parse(headerCreated)) ? new Date(headerCreated).toISOString() : undefined);
1136
+ // Scanner dates match native cleanup eligibility. A hosted-only runtime's
1137
+ // header records creation, not its most recent activity.
1138
+ rows.set(session.sessionId, {
1139
+ id: session.sessionId,
1140
+ cwd: session.sessionManager.getCwd(),
1141
+ ...(session.sessionName === undefined ? {} : { name: session.sessionName }),
1142
+ ...(metadata === undefined ? {} : { metadata }),
1143
+ ...(created === undefined ? {} : { created }),
1144
+ ...(row?.modified === undefined ? {} : { modified: row.modified }),
1145
+ });
1073
1146
  }
1074
1147
  const entriesById = new Map(entries.map((entry) => [entry.id, entry]));
1075
1148
  for (const record of archived) {
1076
- const row = clientSessionFromArchivedRecord(record, entriesById.get(record.sessionId));
1077
- if (row !== undefined)
1078
- rows.set(row.id, row);
1149
+ const entry = entriesById.get(record.sessionId);
1150
+ const created = record.created ?? entry?.created.toISOString();
1151
+ const modified = record.modified ?? entry?.modified.toISOString();
1152
+ // Legacy records may lack transcript/path fields required by the client
1153
+ // list helper; their archive identity and known dates are still usable.
1154
+ const row = clientSessionFromArchivedRecord(record, entry) ?? {
1155
+ id: record.sessionId,
1156
+ cwd: record.cwd,
1157
+ ...(created === undefined ? {} : { created }),
1158
+ ...(modified === undefined ? {} : { modified }),
1159
+ archived: true,
1160
+ archivedAt: record.archivedAt,
1161
+ };
1162
+ rows.set(row.id, row);
1079
1163
  }
1080
- return [...rows.values()].sort((a, b) => Date.parse(b.modified) - Date.parse(a.modified)).map((row) => {
1164
+ return [...rows.values()].sort((a, b) => (b.modified === undefined ? 0 : Date.parse(b.modified)) - (a.modified === undefined ? 0 : Date.parse(a.modified))).map((row) => {
1081
1165
  const runtime = runtimes.get(row.id);
1082
1166
  return Object.freeze({
1083
1167
  id: row.id,
@@ -1085,6 +1169,9 @@ export class PiSessionService {
1085
1169
  ...(row.name === undefined ? {} : { name: row.name }),
1086
1170
  ...(row.metadata === undefined ? {} : { metadata: structuredClone(row.metadata) }),
1087
1171
  archived: row.archived === true,
1172
+ created: row.created ?? null,
1173
+ modified: row.modified ?? null,
1174
+ archivedAt: row.archived === true ? row.archivedAt ?? null : null,
1088
1175
  runtime: runtime === undefined ? "not-hosted" : this.hasActiveWork(runtime) ? "busy" : "idle",
1089
1176
  });
1090
1177
  });
@@ -1100,24 +1187,56 @@ export class PiSessionService {
1100
1187
  return Object.freeze({ id: created.id });
1101
1188
  }
1102
1189
  /** Atomically start and prompt one visible normal-mode, non-delegating session. */
1103
- async startOneShotRun(cwd, text, signal) {
1190
+ async startOneShotRun(cwd, text, signal, options = {}) {
1104
1191
  const promptText = requirePromptText(text, this.t);
1105
- return this.startManagedSession(cwd, signal, promptText);
1192
+ return this.startManagedSession(cwd, signal, promptText, options);
1106
1193
  }
1107
- async startManagedSession(cwd, signal, promptText) {
1194
+ async startManagedSession(cwd, signal, promptText, options = {}) {
1108
1195
  signal.throwIfAborted();
1109
- await this.normalModelRuntimeForCwd(cwd);
1110
- const active = await this.create(this.sessionManager.create(cwd), cwd, { startupIntent: "create", creationProvenance: "host-one-shot", startupSignal: signal });
1196
+ const modelRuntime = await this.normalModelRuntimeForCwd(cwd);
1197
+ let initialModel;
1198
+ if (options.model !== undefined) {
1199
+ await modelRuntime.refresh({ allowNetwork: false });
1200
+ signal.throwIfAborted();
1201
+ // Catalog membership alone does not mean the provider still has credentials
1202
+ // or is configured. Host overrides must be available after the refresh.
1203
+ initialModel = modelRuntime.getAvailableSnapshot().find((model) => modelScopeId(model) === options.model);
1204
+ if (initialModel === undefined) {
1205
+ throw Object.assign(new Error(`Model unavailable: ${options.model}`), { code: "PI_SESSION_MODEL_UNAVAILABLE" });
1206
+ }
1207
+ }
1208
+ const active = await this.create(this.sessionManager.create(cwd), cwd, {
1209
+ startupIntent: "create", creationProvenance: "host-one-shot", startupSignal: signal,
1210
+ ...(initialModel === undefined ? {} : { initialModel }),
1211
+ });
1111
1212
  const { session } = active.runtime;
1112
1213
  try {
1113
1214
  signal.throwIfAborted();
1114
- if (promptText !== undefined)
1115
- this.maybeGenerateSessionName(session, promptText);
1215
+ // Startup extensions may change the model. Never submit with a fallback
1216
+ // when the caller requested an exact model.
1217
+ if (options.model !== undefined && (session.model === undefined || modelScopeId(session.model) !== options.model)) {
1218
+ throw Object.assign(new Error(`Requested model is not active: ${options.model}`), { code: "PI_SESSION_MODEL_UNAVAILABLE" });
1219
+ }
1220
+ if (options.thinkingLevel !== undefined) {
1221
+ // Do not pass requested thinking into startup: the SDK can silently
1222
+ // clamp it before we have the actual model's supported levels.
1223
+ if (!session.getAvailableThinkingLevels().includes(options.thinkingLevel)) {
1224
+ throw Object.assign(new Error(`Thinking level unavailable: ${options.thinkingLevel}`), { code: "PI_SESSION_THINKING_UNAVAILABLE" });
1225
+ }
1226
+ session.setThinkingLevel(options.thinkingLevel);
1227
+ if (session.thinkingLevel !== options.thinkingLevel) {
1228
+ throw Object.assign(new Error(`Thinking level was not applied: ${options.thinkingLevel}`), { code: "PI_SESSION_THINKING_UNAVAILABLE" });
1229
+ }
1230
+ }
1231
+ const settings = {
1232
+ ...(session.model === undefined ? {} : { model: modelScopeId(session.model) }),
1233
+ thinkingLevel: session.thinkingLevel,
1234
+ };
1116
1235
  const created = this.announceCreatedSession(active, cwd);
1117
1236
  // Publication transfers lifetime ownership to normal hosting. Plugin
1118
1237
  // cancellation after this point must not abort this or later user work.
1119
1238
  const completion = promptText === undefined ? Promise.resolve() : this.submitInitialRunPrompt(session, promptText);
1120
- return Object.freeze({ id: created.id, completion });
1239
+ return Object.freeze({ id: created.id, completion, ...settings });
1121
1240
  }
1122
1241
  catch (error) {
1123
1242
  try {
@@ -1510,6 +1629,96 @@ export class PiSessionService {
1510
1629
  ...(outcome.answer === undefined ? {} : { answer: outcome.answer }),
1511
1630
  }, this.eventScopeForSession(session));
1512
1631
  }
1632
+ /** Interrupt a direct child's current run without closing its conversation. */
1633
+ async stopSubsession(parentSessionId, sessionId, parentSessionFile, managementContext) {
1634
+ const child = await this.openSubsession(parentSessionId, sessionId, parentSessionFile, managementContext);
1635
+ const cwd = child.sessionManager.getCwd();
1636
+ await this.abort({ id: sessionId, cwd }, managementContext);
1637
+ return { sessionId, cwd, status: this.subsessionStatus(child) };
1638
+ }
1639
+ /** Start another run in a direct child's conversation, without prompt expansion. */
1640
+ async resumeSubsession(parentSessionId, sessionId, prompt, parentSessionFile, managementContext) {
1641
+ const child = await this.openSubsession(parentSessionId, sessionId, parentSessionFile, managementContext);
1642
+ const cwd = child.sessionManager.getCwd();
1643
+ await this.assertWritable({ id: sessionId, cwd }, managementContext);
1644
+ this.assertTreeNavigationInactive(child, "resume a subsession");
1645
+ if (this.hasActiveWork(child))
1646
+ throw new Error("Subsession is already working");
1647
+ const text = requirePromptText(prompt ?? "Continue your previous task from the current conversation and workspace state. Check any interrupted work before repeating it.", this.t);
1648
+ void this.beginPromptSubmission(child, text, undefined, [], true, { expandPromptTemplates: false }).catch(() => undefined);
1649
+ return { sessionId, cwd, status: "working" };
1650
+ }
1651
+ /** Archive a direct child using the same idle-only operation as the browser. */
1652
+ async archiveSubsession(parentSessionId, sessionId, parentSessionFile, managementContext) {
1653
+ const child = await this.openSubsession(parentSessionId, sessionId, parentSessionFile, managementContext);
1654
+ await this.archive({ id: sessionId, cwd: child.sessionManager.getCwd() }, managementContext);
1655
+ }
1656
+ /** Send content, not control authority, to a named session in the same project. */
1657
+ async sendSessionMessage(input, managementContext) {
1658
+ if (this.messageTargets === undefined)
1659
+ throw new Error("Session messaging is unavailable");
1660
+ const message = requirePromptText(input.message, this.t);
1661
+ if (managementContext === undefined)
1662
+ await this.assertNormalSessionReadAccess(input.sendingCwd);
1663
+ else
1664
+ await this.getActive({ id: input.sendingSessionId, cwd: input.sendingCwd }, managementContext);
1665
+ const active = this.activeForLookup(input.sessionId, managementContext);
1666
+ const target = active === undefined
1667
+ ? (await this.sessionManager.listAll()).find((entry) => entry.id === input.sessionId)
1668
+ : { id: input.sessionId, cwd: active.runtime.cwd };
1669
+ if (target === undefined)
1670
+ throw new Error("Session not found");
1671
+ if (active === undefined && this.activeSessionsForId(input.sessionId).some((entry) => cwdPathsEqual(entry.runtime.cwd, target.cwd)))
1672
+ throw new Error("Session not found");
1673
+ const decision = await this.messageTargets.resolveSpawnTarget(input.sendingCwd, target.cwd, eventScopeFromManagementContext(managementContext));
1674
+ if (!decision.allowed)
1675
+ throw new Error("Session messaging is limited to sessions in the same registered project");
1676
+ if (managementContext === undefined)
1677
+ await this.assertNormalSessionReadAccess(decision.cwd);
1678
+ else {
1679
+ if (this.managementProjectRoot === undefined)
1680
+ throw new Error("Managed session messaging requires a project root");
1681
+ await assertManagedCwd(this.managementProjectRoot, managementContext, decision.cwd, { create: false });
1682
+ }
1683
+ const ref = { id: input.sessionId, cwd: decision.cwd };
1684
+ await this.assertWritable(ref, managementContext);
1685
+ const session = await this.getOrOpen(ref, managementContext);
1686
+ this.assertTreeNavigationInactive(session, "receive a session message");
1687
+ const delivery = this.hasActiveWork(session) ? "queued" : "started";
1688
+ let agentStarted = false;
1689
+ const unsubscribe = session.subscribe((event) => {
1690
+ if (getString(event, "type") === "agent_start")
1691
+ agentStarted = true;
1692
+ });
1693
+ // A custom-message turn may run for minutes. Never wait for its answer in
1694
+ // the sender: reciprocal messages must not deadlock their tool calls.
1695
+ void this.runSessionEntryMutation(session, "receive a session message", async () => {
1696
+ if (session.isCompacting || session.isBashRunning)
1697
+ await session.waitForIdle();
1698
+ if (!this.isCurrentActiveSession(session))
1699
+ throw new Error("Session was closed before message delivery");
1700
+ await session.sendCustomMessage({
1701
+ customType: "session.message",
1702
+ content: `Message from session ${input.sendingSessionId}:\n\n${message}`,
1703
+ display: true,
1704
+ details: { sendingSessionId: input.sendingSessionId },
1705
+ }, { triggerTurn: true, deliverAs: "steer" });
1706
+ }).catch((error) => {
1707
+ const detail = error instanceof Error ? error.message : String(error);
1708
+ this.logger.info({ sessionId: input.sessionId, sendingSessionId: input.sendingSessionId, error: detail }, "session message delivery failed");
1709
+ if (!this.isCurrentActiveSession(session))
1710
+ return;
1711
+ this.publishActivity(session, { kind: "error" }, "error", detail);
1712
+ const scope = this.eventScopeForSession(session);
1713
+ this.events.publish(session.sessionId, { type: "session.error", message: detail }, scope);
1714
+ if (!agentStarted && this.subsessionLinkForActiveChild(session) !== undefined)
1715
+ this.subsessionNotifyArmed.set(activeSessionKey(session.sessionId, scope), true);
1716
+ this.updateSubsessionTracking(session);
1717
+ this.publishStatus(session);
1718
+ }).finally(unsubscribe);
1719
+ this.logger.info({ sendingSessionId: input.sendingSessionId, sessionId: input.sessionId, delivery }, "session message accepted");
1720
+ return { sessionId: input.sessionId, delivery };
1721
+ }
1513
1722
  /** Summaries of the tracked subsessions spawned by `parentSessionId`. */
1514
1723
  async listSubsessions(parentSessionId, parentSessionFile, managementContext) {
1515
1724
  const parentFile = nonEmptyString(parentSessionFile);
@@ -2007,13 +2216,17 @@ export class PiSessionService {
2007
2216
  }));
2008
2217
  return { listing, sessions: matches.filter(isDefined) };
2009
2218
  }
2010
- searchableSessionHistory(session, listing, managementContext) {
2219
+ async searchableSessionHistory(session, listing, managementContext) {
2011
2220
  const eventScope = eventScopeFromManagementContext(managementContext);
2012
2221
  const active = this.activeForSessionIdAndScope(session.id, eventScope);
2013
2222
  if (active !== undefined && cwdPathsEqual(active.runtime.cwd, session.cwd))
2014
2223
  return historyMessages(active.runtime.session);
2015
2224
  const path = listing.archivedById.get(session.id)?.archivePath ?? listing.entriesById.get(session.id)?.path;
2016
- return path === undefined ? [] : historyMessagesFromManager(this.sessionManager.open(path));
2225
+ if (path === undefined)
2226
+ return [];
2227
+ if (this.sessionManager.readBranch !== undefined)
2228
+ return historyMessagesFromEntries(await this.sessionManager.readBranch(path) ?? []);
2229
+ return historyMessagesFromManager(this.sessionManager.open(path));
2017
2230
  }
2018
2231
  async streamSnapshot(ref, managementContext) {
2019
2232
  const session = await this.getOrOpen(ref, managementContext);
@@ -2151,7 +2364,7 @@ export class PiSessionService {
2151
2364
  if (model === undefined)
2152
2365
  throw new Error(this.t("model.notFound", "Model not found: {value0}/{value1}", { value0: provider, value1: modelId }));
2153
2366
  await this.runSessionEntryMutation(session, this.t("server.main.130226a572df", "change models"), () => session.setModel(model));
2154
- this.publishActivity(session, this.t("activity.model", "Model: {value0}", { value0: model.id }), "idle", model.provider);
2367
+ this.publishActivity(session, { kind: "model", value: model.id }, "idle", model.provider);
2155
2368
  this.publishStatus(session);
2156
2369
  return this.statusFromSession(session);
2157
2370
  }
@@ -2165,7 +2378,7 @@ export class PiSessionService {
2165
2378
  });
2166
2379
  if (result === undefined)
2167
2380
  throw new Error(session.scopedModels.length > 0 ? this.t("model.oneScoped", "Only one scoped model is available") : this.t("model.oneAvailable", "Only one model is available"));
2168
- this.publishActivity(session, this.t("activity.model", "Model: {value0}", { value0: result.model.id }), "idle", result.model.provider);
2381
+ this.publishActivity(session, { kind: "model", value: result.model.id }, "idle", result.model.provider);
2169
2382
  this.publishStatus(session);
2170
2383
  return this.statusFromSession(session);
2171
2384
  }
@@ -2187,7 +2400,7 @@ export class PiSessionService {
2187
2400
  session.setThinkingLevel(match);
2188
2401
  return Promise.resolve();
2189
2402
  });
2190
- this.publishActivity(session, this.t("activity.thinking", "Thinking level: {value0}", { value0: session.thinkingLevel }), "idle");
2403
+ this.publishActivity(session, { kind: "thinking", value: session.thinkingLevel }, "idle");
2191
2404
  this.publishStatus(session);
2192
2405
  return this.statusFromSession(session);
2193
2406
  }
@@ -2197,7 +2410,7 @@ export class PiSessionService {
2197
2410
  const level = await this.runSessionEntryMutation(session, this.t("session.action.changeThinking", "change the thinking level"), () => Promise.resolve(session.cycleThinkingLevel()));
2198
2411
  if (level === undefined)
2199
2412
  throw new Error(this.t("model.thinkingUnsupported", "The current model does not support thinking"));
2200
- this.publishActivity(session, this.t("ui.promptEditor.thinkingLevel", "Thinking level: {thinkingLevel}", { thinkingLevel: level }), "idle");
2413
+ this.publishActivity(session, { kind: "thinking", value: level }, "idle");
2201
2414
  this.publishStatus(session);
2202
2415
  return this.statusFromSession(session);
2203
2416
  }
@@ -2233,11 +2446,10 @@ export class PiSessionService {
2233
2446
  await this.assertWritable(ref, options?.managementContext);
2234
2447
  const session = await this.getOrOpen(ref, options?.managementContext);
2235
2448
  this.assertTreeNavigationInactive(session, this.t("server.main.94306b2fc35c", "send a prompt"));
2236
- this.maybeGenerateSessionName(session, promptText);
2237
2449
  const isQueued = session.isStreaming || session.isCompacting;
2238
2450
  const behavior = isQueued ? requestedBehavior ?? "followUp" : undefined;
2239
2451
  if (isQueued && images.length === 0 && this.hasQueuedMessageText(session, promptText)) {
2240
- this.publishActivity(session, this.t("activity.duplicateIgnored", "Duplicate queued message ignored"), "active");
2452
+ this.publishActivity(session, { kind: "duplicateQueuedMessage" }, "active");
2241
2453
  this.publishStatus(session);
2242
2454
  return;
2243
2455
  }
@@ -2259,7 +2471,7 @@ export class PiSessionService {
2259
2471
  beginPromptSubmission(session, text, behavior, images = [], echoUserMessage = true, options = {}) {
2260
2472
  if (options.auditUserPrompt !== false)
2261
2473
  this.auditUserPrompt(session, text);
2262
- this.publishActivity(session, behavior === "steer" ? this.t("activity.steerQueued", "Steering message queued") : behavior === "followUp" ? this.t("activity.messageQueued", "Message queued") : this.t("activity.messageReceived", "Message received"), "active");
2474
+ this.publishActivity(session, behavior === "steer" ? { kind: "steeringQueued" } : behavior === "followUp" ? { kind: "messageQueued" } : { kind: "promptAccepted" }, "active");
2263
2475
  const eventScope = this.eventScopeForSession(session);
2264
2476
  const echoes = this.pendingPromptEchoes.get(session) ?? [];
2265
2477
  const userCount = historyMessagesFromEntries(session.sessionManager.getBranch()).filter((message) => isRecord(message) && message["role"] === "user").length;
@@ -2300,7 +2512,7 @@ export class PiSessionService {
2300
2512
  void promptPromise.catch((error) => {
2301
2513
  this.subsessionStoppedParents.add(session);
2302
2514
  const message = error instanceof Error ? error.message : String(error);
2303
- this.publishActivity(session, this.t("activity.error", "An error occurred"), "error", message);
2515
+ this.publishActivity(session, { kind: "error" }, "error", message);
2304
2516
  this.events.publish(session.sessionId, { type: "session.error", message }, eventScope);
2305
2517
  if (this.isCurrentActiveSession(session)) {
2306
2518
  const link = this.subsessionLinkForActiveChild(session);
@@ -2364,7 +2576,7 @@ export class PiSessionService {
2364
2576
  const queue = this.compactionPromptQueues.get(sessionKey) ?? [];
2365
2577
  queue.push({ kind, text, ...(images.length > 0 ? { images } : {}), ...(echoUserMessage ? {} : { echoUserMessage: false }) });
2366
2578
  this.compactionPromptQueues.set(sessionKey, queue);
2367
- this.publishActivity(session, this.t("activity.compactionQueued", "Message queued during compaction"), "active");
2579
+ this.publishActivity(session, { kind: "queuedDuringCompaction" }, "active");
2368
2580
  this.publishStatus(session);
2369
2581
  }
2370
2582
  async saveAttachments(ref, attachments, folder, managementContext) {
@@ -2378,8 +2590,8 @@ export class PiSessionService {
2378
2590
  return saveAttachmentsToWorkspace(cwd, parsed, effectiveFolder === undefined ? {} : { folder: effectiveFolder });
2379
2591
  }
2380
2592
  async workspaceAttachmentsConfig(cwd) {
2381
- const globalConfig = this.config === undefined ? {} : (await this.config.read()).effectiveConfig;
2382
- return loadEffectiveProjectAttachmentsConfig(cwd, globalConfig);
2593
+ const response = this.config === undefined ? undefined : await this.config.read();
2594
+ return loadEffectiveProjectAttachmentsConfig(cwd, response?.effectiveConfig ?? {}, response?.enforcedSettings);
2383
2595
  }
2384
2596
  async shell(ref, text, managementContext) {
2385
2597
  await this.assertWritable(ref, managementContext);
@@ -2393,11 +2605,11 @@ export class PiSessionService {
2393
2605
  if (session.isBashRunning)
2394
2606
  throw new Error(this.t("shell.alreadyRunning", "A bash command is already running"));
2395
2607
  const eventScope = active.eventScope;
2396
- this.publishActivity(session, this.t("activity.commandRunning", "Running command"), "active", command);
2608
+ this.publishActivity(session, { kind: "runningBash" }, "active", command);
2397
2609
  this.events.publish(session.sessionId, { type: "shell.start", command, excludeFromContext: isExcluded }, eventScope);
2398
2610
  void this.runSessionEntryMutation(session, this.t("session.action.shell", "run a shell command"), () => session.executeBash(command, (chunk) => {
2399
2611
  this.events.publish(session.sessionId, { type: "shell.chunk", chunk }, eventScope);
2400
- this.publishActivity(session, this.t("activity.commandRunning", "Running command"), "active", command);
2612
+ this.publishActivity(session, { kind: "runningBash" }, "active", command);
2401
2613
  this.publishStatus(session);
2402
2614
  }, { excludeFromContext: isExcluded })).then((result) => {
2403
2615
  this.events.publish(session.sessionId, {
@@ -2408,13 +2620,13 @@ export class PiSessionService {
2408
2620
  truncated: result.truncated,
2409
2621
  ...(result.fullOutputPath === undefined ? {} : { fullOutputPath: result.fullOutputPath }),
2410
2622
  }, eventScope);
2411
- this.publishActivity(session, this.t("activity.commandCompleted", "Command completed"), result.exitCode === 0 ? "idle" : "error", command);
2623
+ this.publishActivity(session, { kind: "bashComplete" }, result.exitCode === 0 ? "idle" : "error", command);
2412
2624
  this.publishStatus(session);
2413
2625
  }).catch((error) => {
2414
2626
  const message = userFacingErrorMessage(error, this.t);
2415
2627
  this.events.publish(session.sessionId, { type: "shell.end", output: message, isError: true }, eventScope);
2416
2628
  this.events.publish(session.sessionId, { type: "session.error", message }, eventScope);
2417
- this.publishActivity(session, this.t("activity.commandFailed", "Command failed"), "error", message);
2629
+ this.publishActivity(session, { kind: "bashFailed" }, "error", message);
2418
2630
  this.publishStatus(session);
2419
2631
  });
2420
2632
  }
@@ -2461,7 +2673,7 @@ export class PiSessionService {
2461
2673
  if (retainCustomMessage && options.summarize === true)
2462
2674
  throw new Error(this.t("session.checkpointSummary", "Retaining a custom-message checkpoint requires navigation without a branch summary"));
2463
2675
  const activeEditableTargetParentId = retainCustomMessage ? undefined : activeEditableTreeTargetParentId(session.sessionManager, targetId, oldLeafId);
2464
- this.publishActivity(session, options.summarize === true ? this.t("activity.summarizing", "Summarizing branch") : this.t("activity.navigating", "Navigating session tree"), "active");
2676
+ this.publishActivity(session, options.summarize === true ? { kind: "summarizingBranch" } : { kind: "navigatingTree" }, "active");
2465
2677
  this.publishStatus(session);
2466
2678
  let result = retainCustomMessage
2467
2679
  ? await navigateTreeRetainingCustomMessage(session.sessionManager, targetId, checkpointTail["parentId"], () => navigateTree(targetId, options))
@@ -2482,7 +2694,7 @@ export class PiSessionService {
2482
2694
  }
2483
2695
  if (result.cancelled) {
2484
2696
  if (this.isCurrentActiveSession(session)) {
2485
- this.publishActivity(session, result.aborted === true ? this.t("activity.summaryAborted", "Branch summary aborted") : this.t("activity.navigationCancelled", "Session tree navigation cancelled"), "idle");
2697
+ this.publishActivity(session, result.aborted === true ? { kind: "branchSummaryAborted" } : { kind: "treeNavigationCancelled" }, "idle");
2486
2698
  }
2487
2699
  return { cancelled: true, ...(result.aborted === undefined ? {} : { aborted: result.aborted }) };
2488
2700
  }
@@ -2497,13 +2709,13 @@ export class PiSessionService {
2497
2709
  this.setSuggestedInput(session, result.editorText);
2498
2710
  this.events.publish(session.sessionId, { type: "session.tree.changed" }, this.eventScopeForSession(session));
2499
2711
  if (this.isCurrentActiveSession(session))
2500
- this.publishActivity(session, this.t("activity.navigated", "Session tree changed"), "idle");
2712
+ this.publishActivity(session, { kind: "treeNavigated" }, "idle");
2501
2713
  return { cancelled: false, ...(result.editorText === undefined ? {} : { editorText: result.editorText }) };
2502
2714
  }
2503
2715
  catch (error) {
2504
2716
  const message = userFacingErrorMessage(error, this.t);
2505
2717
  if (this.isCurrentActiveSession(session)) {
2506
- this.publishActivity(session, this.t("server.main.8cae209986b4", "tree navigation failed"), "error", message);
2718
+ this.publishActivity(session, { kind: "treeNavigationFailed" }, "error", message);
2507
2719
  this.events.publish(session.sessionId, { type: "session.error", message }, this.eventScopeForSession(session));
2508
2720
  }
2509
2721
  throw error;
@@ -2516,7 +2728,6 @@ export class PiSessionService {
2516
2728
  this.publishStatus(session);
2517
2729
  }
2518
2730
  else {
2519
- this.deferredGeneratedSessionNames.delete(session);
2520
2731
  this.subsessionInbox(session.sessionId, session.sessionFile, this.eventScopeForSession(session)).releaseClaims();
2521
2732
  }
2522
2733
  }
@@ -2543,7 +2754,7 @@ export class PiSessionService {
2543
2754
  const sourceSessionId = session.sessionId;
2544
2755
  const sourceEventScope = this.eventScopeForSession(session);
2545
2756
  const sourceCwd = session.sessionManager.getCwd();
2546
- this.publishActivity(session, this.t("server.main.4de911d3b72a", "forking session from entry"), "active");
2757
+ this.publishActivity(session, { kind: "forking" }, "active");
2547
2758
  this.publishStatus(session);
2548
2759
  try {
2549
2760
  const entryId = request.retainCheckpoint === true ? messageHistoryTargetId(session.sessionManager.getBranch(), request.entryId) : request.entryId;
@@ -2556,7 +2767,7 @@ export class PiSessionService {
2556
2767
  throw new Error(this.t("server.main.0246b6af6843", "Session fork is unavailable"));
2557
2768
  if (result.session === undefined) {
2558
2769
  if (this.isCurrentActiveSession(session)) {
2559
- this.publishActivity(session, this.t("server.main.1cceead5f414", "fork cancelled"), "idle");
2770
+ this.publishActivity(session, { kind: "forkCancelled" }, "idle");
2560
2771
  this.publishStatus(session);
2561
2772
  }
2562
2773
  return { cancelled: true };
@@ -2566,7 +2777,7 @@ export class PiSessionService {
2566
2777
  this.setSuggestedInput(forked, result.promptDraft);
2567
2778
  this.events.publish(sourceSessionId, { type: "session.tree.changed" }, sourceEventScope);
2568
2779
  if (forked !== undefined && this.isCurrentActiveSession(forked)) {
2569
- this.publishActivity(forked, this.t("command.forked", "Session forked"), "idle");
2780
+ this.publishActivity(forked, { kind: "forked" }, "idle");
2570
2781
  this.publishStatus(forked);
2571
2782
  }
2572
2783
  if (result.session.id !== sourceSessionId)
@@ -2580,7 +2791,7 @@ export class PiSessionService {
2580
2791
  catch (error) {
2581
2792
  const message = userFacingErrorMessage(error, this.t);
2582
2793
  if (this.isCurrentActiveSession(session)) {
2583
- this.publishActivity(session, this.t("server.main.08e8f3ea9eaa", "fork failed"), "error", message);
2794
+ this.publishActivity(session, { kind: "forkFailed" }, "error", message);
2584
2795
  this.events.publish(session.sessionId, { type: "session.error", message }, sourceEventScope);
2585
2796
  this.publishStatus(session);
2586
2797
  }
@@ -2591,7 +2802,7 @@ export class PiSessionService {
2591
2802
  const sessionKey = activeSessionKey(sessionId, eventScope);
2592
2803
  if (this.activities.get(sessionKey)?.phase === "active") {
2593
2804
  const at = new Date().toISOString();
2594
- const stored = { phase: "idle", label: this.t("activity.idle", "Idle"), at };
2805
+ const stored = { phase: "idle", label: "idle", at, runtimePresentation: { kind: "idle" } };
2595
2806
  this.activities.set(sessionKey, stored);
2596
2807
  const activity = { sessionId, ...stored };
2597
2808
  this.events.publish(sessionId, { type: "activity.update", activity }, eventScope);
@@ -2607,6 +2818,7 @@ export class PiSessionService {
2607
2818
  const archiveInput = await this.archiveInputForSession(session);
2608
2819
  await this.closeActiveSession(active);
2609
2820
  await this.archiveStore.archive(archiveInput);
2821
+ this.workspaceActivity?.removeSession(archiveInput.sessionId, archiveInput.cwd, active.eventScope);
2610
2822
  await this.forgetUnreadSessions([archiveInput], active.eventScope);
2611
2823
  });
2612
2824
  }
@@ -2650,43 +2862,10 @@ export class PiSessionService {
2650
2862
  failures.push({ sessionId: resolvedSessionId, error: errorMessage(error, this.t) });
2651
2863
  }
2652
2864
  }
2653
- const readyPlanItems = [];
2654
- for (const item of planItems) {
2655
- const active = item.active ?? this.activeForLookup(bulkRefToLookup({ id: item.input.sessionId, cwd: item.input.cwd }), managementContext);
2656
- if (active !== undefined && this.hasActiveWork(active.runtime.session)) {
2657
- failures.push({ sessionId: item.input.sessionId, error: this.t("session.stopBeforeArchive", "Stop current session activity before archiving") });
2658
- continue;
2659
- }
2660
- readyPlanItems.push(active === undefined ? item : { ...item, active });
2661
- }
2662
- const readyInputs = [];
2663
- const archivedSessionIds = [...alreadyArchivedSessionIds];
2664
- await this.runTreeExclusiveOperation(readyPlanItems.map(({ input, active }) => ({
2665
- sessionId: input.sessionId,
2666
- ...(active === undefined ? {} : { session: active.runtime.session, runtime: active.runtime }),
2667
- })), this.t("session.stopBeforeArchive", "Stop current session activity before archiving"), async () => {
2668
- for (const item of readyPlanItems) {
2669
- try {
2670
- if (item.active !== undefined)
2671
- await this.closeActiveSession(item.active);
2672
- else
2673
- await this.closeActiveInScope(item.input.sessionId, eventScopeFromManagementContext(managementContext));
2674
- readyInputs.push(item.input);
2675
- }
2676
- catch (error) {
2677
- failures.push({ sessionId: item.input.sessionId, error: errorMessage(error, this.t) });
2678
- }
2679
- }
2680
- try {
2681
- const archived = await this.archiveStoreArchiveMany(readyInputs);
2682
- archivedSessionIds.push(...archived.map((record) => record.sessionId));
2683
- unreadArchivedIdentities.push(...archived);
2684
- }
2685
- catch (error) {
2686
- for (const input of readyInputs)
2687
- failures.push({ sessionId: input.sessionId, error: errorMessage(error, this.t) });
2688
- }
2689
- });
2865
+ const execution = await this.executeArchiveBatch(planItems.map((item) => item.input), managementContext);
2866
+ failures.push(...execution.failures);
2867
+ failures.push(...execution.skippedBusySessionIds.map((sessionId) => ({ sessionId, error: this.t("session.stopBeforeArchive", "Stop current session activity before archiving") })));
2868
+ const archivedSessionIds = [...alreadyArchivedSessionIds, ...execution.successes.map((input) => input.sessionId)];
2690
2869
  await this.forgetUnreadSessions(unreadArchivedIdentities, eventScopeFromManagementContext(managementContext));
2691
2870
  return {
2692
2871
  archived: true,
@@ -2714,7 +2893,9 @@ export class PiSessionService {
2714
2893
  }
2715
2894
  for (const input of archiveInputs)
2716
2895
  await this.closeActiveInScope(input.sessionId, eventScopeFromManagementContext(managementContext));
2717
- await this.archiveStoreArchiveMany(archiveInputs);
2896
+ const archived = await this.archiveStoreArchiveMany(archiveInputs);
2897
+ for (const record of archived)
2898
+ this.workspaceActivity?.removeSession(record.sessionId, record.cwd, eventScopeFromManagementContext(managementContext));
2718
2899
  });
2719
2900
  await this.forgetUnreadSessions(plan.targets.map((target) => ({ sessionId: target.id, cwd: target.cwd })), eventScopeFromManagementContext(managementContext));
2720
2901
  return {
@@ -2727,10 +2908,15 @@ export class PiSessionService {
2727
2908
  async restore(ref, managementContext) {
2728
2909
  const archived = await this.getArchived(ref);
2729
2910
  if (archived === undefined)
2730
- throw new Error(this.t("session.notFound", "Session not found"));
2731
- await this.closeActiveInScope(archived.sessionId, eventScopeFromManagementContext(managementContext));
2732
- await this.archiveStore.restore(archived.sessionId);
2733
- await this.forgetUnreadSessions([archived], eventScopeFromManagementContext(managementContext));
2911
+ throw new Error("Session not found");
2912
+ const active = this.activeForLookup({ id: archived.sessionId, cwd: archived.cwd }, managementContext);
2913
+ await this.runTreeExclusiveOperation([{ sessionId: archived.sessionId, ...(active === undefined ? {} : { session: active.runtime.session, runtime: active.runtime }) }], "Stop current session activity before restoring archived session", async () => {
2914
+ await this.closeActiveInScope(archived.sessionId, eventScopeFromManagementContext(managementContext));
2915
+ await this.archiveStore.restore(archived.sessionId);
2916
+ const restored = (await this.sessionManager.list(archived.cwd)).find((entry) => entry.id === archived.sessionId);
2917
+ this.workspaceActivity?.applySessionIntervention(archived.cwd, archived.sessionId, restored?.interventionRequired === true, eventScopeFromManagementContext(managementContext));
2918
+ await this.forgetUnreadSessions([archived], eventScopeFromManagementContext(managementContext));
2919
+ });
2734
2920
  }
2735
2921
  async deleteArchived(ref, managementContext) {
2736
2922
  const record = await this.getArchived(ref);
@@ -2762,27 +2948,10 @@ export class PiSessionService {
2762
2948
  }
2763
2949
  planItems.push({ record });
2764
2950
  }
2765
- const readyRecords = [];
2766
- for (const item of planItems) {
2767
- try {
2768
- await this.closeActiveInScope(item.record.sessionId, eventScopeFromManagementContext(managementContext));
2769
- readyRecords.push(item.record);
2770
- }
2771
- catch (error) {
2772
- failures.push({ sessionId: item.record.sessionId, error: errorMessage(error, this.t) });
2773
- }
2774
- }
2775
- const deleteIds = readyRecords.map((record) => record.sessionId);
2776
- let deletedSessionIds = [];
2777
- try {
2778
- deletedSessionIds = await this.archiveStoreDeleteArchivedMany(deleteIds);
2779
- }
2780
- catch (error) {
2781
- for (const sessionId of deleteIds)
2782
- failures.push({ sessionId, error: errorMessage(error, this.t) });
2783
- }
2784
- const deletedIdSet = new Set(deletedSessionIds);
2785
- await this.forgetUnreadSessions(readyRecords.filter((record) => deletedIdSet.has(record.sessionId)), eventScopeFromManagementContext(managementContext));
2951
+ const execution = await this.executeDeleteArchivedBatch(planItems.map((item) => item.record), managementContext);
2952
+ failures.push(...execution.failures);
2953
+ failures.push(...execution.skippedBusySessionIds.map((sessionId) => ({ sessionId, error: this.t("session.stopBeforeDeleteArchive", "Stop current session activity before deleting archived session") })));
2954
+ const deletedSessionIds = execution.successes.map((record) => record.sessionId);
2786
2955
  return {
2787
2956
  deleted: true,
2788
2957
  deletedSessionIds,
@@ -2852,11 +3021,11 @@ export class PiSessionService {
2852
3021
  this.abortRunScopedExtensionDialogs(active.runtime.session);
2853
3022
  try {
2854
3023
  await this.abortSessionOperations(active.runtime.session);
2855
- this.publishActivity(active.runtime.session, this.t("activity.stopped", "Stopped"), "idle");
3024
+ this.publishActivity(active.runtime.session, { kind: "stopped" }, "idle");
2856
3025
  }
2857
3026
  catch (error) {
2858
3027
  const message = userFacingErrorMessage(error, this.t);
2859
- this.publishActivity(active.runtime.session, this.t("activity.stopFailed", "Stop failed"), "error", message);
3028
+ this.publishActivity(active.runtime.session, { kind: "stopFailed" }, "error", message);
2860
3029
  throw error;
2861
3030
  }
2862
3031
  finally {
@@ -3017,6 +3186,58 @@ export class PiSessionService {
3017
3186
  const entries = await Promise.all(uniqueCwds.map(async (cwd) => [cwd, await this.sessionManager.list(cwd)]));
3018
3187
  return new Map(entries);
3019
3188
  }
3189
+ executeArchiveBatch(inputs, context) {
3190
+ return this.executeSessionLifecycleBatch(inputs, "archive", async (ready) => (await this.archiveStoreArchiveMany(ready)).map((record) => record.sessionId), context);
3191
+ }
3192
+ executeDeleteArchivedBatch(records, context) {
3193
+ return this.executeSessionLifecycleBatch(records, "delete", (ready) => this.archiveStoreDeleteArchivedMany(ready.map((record) => record.sessionId)), context);
3194
+ }
3195
+ async executeSessionLifecycleBatch(items, reason, persist, context) {
3196
+ const scope = eventScopeFromManagementContext(context);
3197
+ const result = { successes: [], failures: [], skippedBusySessionIds: [] };
3198
+ const targets = [];
3199
+ const idleItems = [];
3200
+ // Check and reserve synchronously before any teardown can yield. Identity
3201
+ // reservations also protect unloaded sessions for the full persistence span.
3202
+ for (const item of items) {
3203
+ const active = this.activeForLookup({ id: item.sessionId, cwd: item.cwd }, context);
3204
+ if (this.isTreeExclusiveSessionIdentityActive(item.sessionId)
3205
+ || (active !== undefined && this.hasActiveWork(active.runtime.session))) {
3206
+ result.skippedBusySessionIds.push(item.sessionId);
3207
+ continue;
3208
+ }
3209
+ idleItems.push(item);
3210
+ targets.push({ sessionId: item.sessionId, ...(active === undefined ? {} : { session: active.runtime.session, runtime: active.runtime }) });
3211
+ }
3212
+ await this.runTreeExclusiveOperation(targets, "Stop current session activity before changing session lifecycle", async () => {
3213
+ const ready = [];
3214
+ for (const item of idleItems) {
3215
+ try {
3216
+ await this.closeActive(item.sessionId, { kind: "clear", reason }, scope);
3217
+ ready.push(item);
3218
+ }
3219
+ catch (error) {
3220
+ result.failures.push({ sessionId: item.sessionId, error: errorMessage(error) });
3221
+ }
3222
+ }
3223
+ try {
3224
+ const persistedIds = await persist(ready);
3225
+ const readyById = new Map(ready.map((item) => [item.sessionId, item]));
3226
+ result.successes = persistedIds.flatMap((sessionId) => {
3227
+ const item = readyById.get(sessionId);
3228
+ return item === undefined ? [] : [item];
3229
+ });
3230
+ }
3231
+ catch (error) {
3232
+ for (const item of ready)
3233
+ result.failures.push({ sessionId: item.sessionId, error: errorMessage(error) });
3234
+ }
3235
+ for (const item of result.successes)
3236
+ this.workspaceActivity?.removeSession(item.sessionId, item.cwd, scope);
3237
+ await this.forgetUnreadSessions(result.successes, scope);
3238
+ });
3239
+ return result;
3240
+ }
3020
3241
  async archiveStoreArchiveMany(inputs) {
3021
3242
  if (inputs.length === 0)
3022
3243
  return [];
@@ -3040,6 +3261,9 @@ export class PiSessionService {
3040
3261
  return [...sessionIds];
3041
3262
  }
3042
3263
  async cleanupPlan(request) {
3264
+ if (request.skipPinned === true && this.sessionPins === undefined)
3265
+ throw new Error("Authoritative session pin store is unavailable");
3266
+ const excludedPinnedSessionIds = request.skipPinned === true ? await this.sessionPins?.pinnedSessionIds() : undefined;
3043
3267
  const [sessions, archivedRecords, scopedSessions] = await Promise.all([
3044
3268
  this.sessionManager.listAll(),
3045
3269
  this.archiveStore.list(),
@@ -3052,6 +3276,7 @@ export class PiSessionService {
3052
3276
  archivedRecords,
3053
3277
  activeSessions: this.cleanupActiveSessionStatuses(),
3054
3278
  thresholds: request.thresholds,
3279
+ ...(excludedPinnedSessionIds === undefined ? {} : { excludedPinnedSessionIds }),
3055
3280
  ...(request.projectCwds === undefined ? {} : { projectCwds: request.projectCwds }),
3056
3281
  now: this.now(),
3057
3282
  });
@@ -3183,6 +3408,10 @@ export class PiSessionService {
3183
3408
  this.events.mediaIndex.forgetSession({ id: sessionId, cwd: active.runtime.session.sessionManager.getCwd(), eventScope: active.eventScope });
3184
3409
  this.activities.delete(activeSessionKey(sessionId, active.eventScope));
3185
3410
  this.workspaceActivity?.removeSession(sessionId, active.runtime.session.sessionManager.getCwd(), active.eventScope);
3411
+ const session = active.runtime.session;
3412
+ if (sessionFileExists(session.sessionFile) && this.interventionRequired(session)) {
3413
+ this.workspaceActivity?.applySessionIntervention(session.sessionManager.getCwd(), sessionId, true, active.eventScope);
3414
+ }
3186
3415
  this.clearAuthLossWarningsForSession(sessionId);
3187
3416
  this.clearCompactionPromptQueue(active.runtime.session);
3188
3417
  // Disarm subsession notification before teardown so the abort below cannot
@@ -3437,7 +3666,7 @@ export class PiSessionService {
3437
3666
  operation.error(message);
3438
3667
  return;
3439
3668
  }
3440
- this.publishActivity(session, this.t("activity.extensionError", "Extension error"), "error", message);
3669
+ this.publishActivity(session, { kind: "extensionError" }, "error", message);
3441
3670
  this.events.publish(session.sessionId, { type: "session.error", message }, owner.eventScope);
3442
3671
  },
3443
3672
  });
@@ -3493,7 +3722,7 @@ export class PiSessionService {
3493
3722
  if (current !== undefined && this.isCurrentActiveSession(current)) {
3494
3723
  const message = userFacingErrorMessage(error, this.t);
3495
3724
  current.extensionRunner.getUIContext().notify(message, "error");
3496
- this.publishActivity(current, "extension callback failed", "error", message);
3725
+ this.publishActivity(current, { kind: "extensionCallbackFailed" }, "error", message);
3497
3726
  this.events.publish(current.sessionId, { type: "session.error", message }, this.eventScopeForSession(current));
3498
3727
  }
3499
3728
  throw error;
@@ -3546,12 +3775,17 @@ export class PiSessionService {
3546
3775
  }
3547
3776
  this.reconcileRuntimeMessageCount(session);
3548
3777
  this.restoreSubsessionReceipts(session);
3778
+ this.interventionStates.set(session, sessionInterventionRequired(session.sessionManager.getEntries?.() ?? session.sessionManager.getBranch()));
3779
+ this.publishedSessionNames.set(session, { sessionId: session.sessionId, name: session.sessionName });
3549
3780
  const unsubscribe = session.subscribe((event) => {
3550
3781
  const eventType = getString(event, "type");
3782
+ if (eventType === "session_info_changed")
3783
+ this.publishSessionName(session);
3551
3784
  const message = getProperty(event, "message");
3552
3785
  const entry = getProperty(event, "entry");
3553
3786
  const inbox = this.subsessionInbox(session.sessionId, session.sessionFile, active.eventScope);
3554
3787
  if (eventType === "agent_start") {
3788
+ this.setInterventionRequired(session, false);
3555
3789
  this.restoreSubsessionReceipts(session, false);
3556
3790
  this.subsessionStoppedParents.delete(session);
3557
3791
  }
@@ -3566,6 +3800,8 @@ export class PiSessionService {
3566
3800
  if (eventType === "agent_settled")
3567
3801
  this.scheduleSubsessionDelivery(session);
3568
3802
  const role = getString(message, "role");
3803
+ if (eventType === "message_end" && requestsHumanIntervention(message))
3804
+ this.setInterventionRequired(session, true);
3569
3805
  if ((eventType === "message_end" && (role === "user" || role === "assistant" || role === "toolResult" || role === "system"))
3570
3806
  || (eventType === "entry_appended" && getString(entry, "type") === "message")) {
3571
3807
  this.runtimeMessageCounts.set(session, this.runtimeMessageCount(session) + 1);
@@ -3622,18 +3858,21 @@ export class PiSessionService {
3622
3858
  const aborted = getBoolean(event, "aborted") === true;
3623
3859
  const errorMessage = getString(event, "errorMessage");
3624
3860
  const automatic = getString(event, "reason") !== "manual";
3625
- const message = aborted
3626
- ? (automatic ? this.t("session.compaction.autoCancelled", "Automatic compaction cancelled.") : this.t("session.compaction.cancelled", "Compaction cancelled."))
3627
- : errorMessage === undefined ? undefined : this.t("session.compaction.failed", "Could not compact history. Try again.");
3861
+ const presentation = aborted
3862
+ ? { kind: automatic ? "automaticCompactionCancelled" : "compactionCancelled" }
3863
+ : errorMessage === undefined ? undefined : { kind: "compactionFailed" };
3864
+ const message = presentation === undefined ? undefined : sessionNotificationSources[presentation.kind];
3628
3865
  if (!aborted && errorMessage !== undefined) {
3629
3866
  this.events.publish(session.sessionId, { type: "session.diagnostic", message: errorMessage }, this.eventScopeForSession(session));
3630
3867
  }
3631
- this.publishActivity(session, aborted ? this.t("activity.compactionCancelled", "Compaction cancelled") : errorMessage === undefined ? this.t("activity.compacted", "Context compacted") : this.t("activity.compactionFailed", "Context compaction failed"), !aborted && errorMessage !== undefined ? "error" : "idle", message);
3868
+ this.publishActivity(session, aborted
3869
+ ? { kind: "compactionCancelled", detailKind: automatic ? "automaticCompactionCancelled" : "compactionCancelled" }
3870
+ : errorMessage === undefined ? { kind: "compactionComplete" } : { kind: "compactionFailed", detailKind: "compactionFailed" }, !aborted && errorMessage !== undefined ? "error" : "idle", message);
3632
3871
  // Successful compaction already has a canonical summary in the transcript.
3633
3872
  // Keep cancellation/failure feedback in the refresh-safe session inbox only.
3634
3873
  const generation = this.notificationGenerationBySession.get(session);
3635
3874
  if (message !== undefined && generation !== undefined) {
3636
- this.publishNotificationMutations(this.notificationsForSession(session).addNotification(generation, message, aborted ? "info" : "error").mutations);
3875
+ this.publishNotificationMutations(this.notificationsForSession(session).addNotification(generation, message, aborted ? "info" : "error", presentation).mutations);
3637
3876
  }
3638
3877
  }
3639
3878
  scheduleCompactionQueueDrain(session, delayMs = 0) {
@@ -3711,43 +3950,6 @@ export class PiSessionService {
3711
3950
  clearTimeout(timer);
3712
3951
  this.compactionDrainTimers.clear();
3713
3952
  }
3714
- maybeGenerateSessionName(session, firstMessage) {
3715
- if (session.sessionName !== undefined || session.messages.length !== 0 || session.isStreaming || session.isCompacting)
3716
- return;
3717
- void this.generateSessionName(session, firstMessage).then((name) => {
3718
- if (name === undefined)
3719
- this.logger.info({ sessionId: session.sessionId }, "Session naming returned no title; using the first-message fallback");
3720
- this.applyGeneratedSessionName(session, name ?? fallbackSessionName(firstMessage));
3721
- }).catch((error) => {
3722
- const errorCategory = error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError") ? "timeout" : "generation";
3723
- this.logger.info({ sessionId: session.sessionId, errorCategory }, "Session naming failed; using the first-message fallback");
3724
- this.applyGeneratedSessionName(session, fallbackSessionName(firstMessage));
3725
- });
3726
- }
3727
- async generateSessionName(session, firstMessage) {
3728
- // One request keeps its settings even if the operator edits the config while it runs.
3729
- const naming = this.config === undefined ? {} : (await this.config.read()).effectiveConfig.sessionNaming ?? {};
3730
- let model = session.model;
3731
- if (naming.model !== undefined) {
3732
- const parsed = parseModelSpec(naming.model);
3733
- model = parsed === undefined ? undefined : session.modelRuntime.getModel(parsed.provider, parsed.modelId);
3734
- if (model === undefined)
3735
- throw new Error("Configured session naming model is unavailable");
3736
- }
3737
- if (model === undefined)
3738
- return undefined;
3739
- return generateShortSessionName(session.agent.streamFunction, model, firstMessage, naming);
3740
- }
3741
- applyGeneratedSessionName(session, name) {
3742
- if (name === undefined || session.sessionName !== undefined)
3743
- return;
3744
- if (this.treeNavigations.has(session)) {
3745
- this.deferredGeneratedSessionNames.set(session, name);
3746
- return;
3747
- }
3748
- session.setSessionName(name);
3749
- this.publishSessionName(session);
3750
- }
3751
3953
  applyAuthChange(change) {
3752
3954
  const changedRuntime = change.modelRuntime;
3753
3955
  for (const active of this.active.values()) {
@@ -3778,7 +3980,8 @@ export class PiSessionService {
3778
3980
  this.events.publish(session.sessionId, {
3779
3981
  type: "command.output",
3780
3982
  level: "error",
3781
- message: this.t("session.authRemoved", "Authentication for {provider}/{model} was removed. Use /model to select another model.", { provider: model.provider, model: model.id }),
3983
+ message: `Authentication for ${model.provider}/${model.id} was removed. Use /model to select another model.`,
3984
+ presentation: { kind: "modelAuthRemoved", provider: model.provider, model: model.id },
3782
3985
  }, eventScope);
3783
3986
  }
3784
3987
  clearAuthLossWarningsForSession(sessionId) {
@@ -3788,6 +3991,10 @@ export class PiSessionService {
3788
3991
  }
3789
3992
  }
3790
3993
  publishSessionName(session) {
3994
+ const previous = this.publishedSessionNames.get(session);
3995
+ if (previous?.sessionId === session.sessionId && previous.name === session.sessionName)
3996
+ return;
3997
+ this.publishedSessionNames.set(session, { sessionId: session.sessionId, name: session.sessionName });
3791
3998
  const event = session.sessionName === undefined
3792
3999
  ? { type: "session.name", sessionId: session.sessionId }
3793
4000
  : { type: "session.name", sessionId: session.sessionId, name: session.sessionName };
@@ -3811,25 +4018,25 @@ export class PiSessionService {
3811
4018
  }
3812
4019
  this.publishStatus(session);
3813
4020
  if (activity?.phase === "active")
3814
- this.publishActivity(session, activity.label, "active", activity.detail);
4021
+ this.publishActivity(session, activity.runtimePresentation, "active", activity.detail);
3815
4022
  else
3816
- this.publishActivity(session, this.activityLabelFromStatus(session), "active");
4023
+ this.publishActivity(session, this.activityPresentationFromStatus(session), "active");
3817
4024
  }
3818
4025
  }
3819
- activityLabelFromStatus(session) {
4026
+ activityPresentationFromStatus(session) {
3820
4027
  if (this.treeNavigations.has(session))
3821
- return this.t("activity.navigating", "Navigating session tree");
4028
+ return { kind: "navigatingTree" };
3822
4029
  if (this.isSessionEntryMutationActive(session))
3823
- return this.t("activity.updating", "Updating session");
4030
+ return { kind: "updatingSession" };
3824
4031
  if (session.isCompacting)
3825
- return this.t("activity.compacting", "Compacting context");
4032
+ return { kind: "compacting" };
3826
4033
  if (session.isBashRunning)
3827
- return this.t("activity.commandRunning", "Running command");
4034
+ return { kind: "runningBash" };
3828
4035
  if (session.isStreaming)
3829
- return this.t("activity.agentRunning", "Agent running");
4036
+ return { kind: "agentRunning" };
3830
4037
  if (this.pendingMessageCount(session) > 0)
3831
- return this.t("activity.queued", "Queued");
3832
- return this.t("activity.working", "Working");
4038
+ return { kind: "queued" };
4039
+ return { kind: "active" };
3833
4040
  }
3834
4041
  hasActiveWork(session) {
3835
4042
  const execution = this.extensionCommandExecution.getStore();
@@ -3934,56 +4141,56 @@ export class PiSessionService {
3934
4141
  if (eventType === undefined)
3935
4142
  return;
3936
4143
  if (eventType === "agent_start") {
3937
- this.publishActivity(session, this.t("activity.agentRunning", "Agent running"), "active");
4144
+ this.publishActivity(session, { kind: "agentRunning" }, "active");
3938
4145
  return;
3939
4146
  }
3940
4147
  if (eventType === "agent_end") {
3941
- this.publishActivity(session, this.t("activity.idle", "Idle"), "idle");
4148
+ this.publishActivity(session, { kind: "idle" }, "idle");
3942
4149
  const eventScope = this.eventScopeForSession(session);
3943
4150
  const sessionKey = activeSessionKey(session.sessionId, eventScope);
3944
4151
  this.activities.scheduleSettledRefresh(sessionKey, () => {
3945
4152
  if (this.active.get(sessionKey)?.runtime.session !== session)
3946
4153
  return;
3947
- this.publishActivity(session, this.t("activity.idle", "Idle"), "idle");
4154
+ this.publishActivity(session, { kind: "idle" }, "idle");
3948
4155
  this.publishStatus(session);
3949
4156
  }, 250);
3950
4157
  return;
3951
4158
  }
3952
4159
  if (eventType === "turn_end") {
3953
- this.publishActivity(session, this.t("activity.turnCompleted", "Turn completed"), "idle");
4160
+ this.publishActivity(session, { kind: "turnComplete" }, "idle");
3954
4161
  return;
3955
4162
  }
3956
4163
  if (eventType === "message_start") {
3957
- this.publishActivity(session, this.t("activity.messageStarted", "Message started"), "active");
4164
+ this.publishActivity(session, { kind: "messageStarted" }, "active");
3958
4165
  return;
3959
4166
  }
3960
4167
  if (eventType === "message_end") {
3961
- this.publishActivity(session, this.t("activity.messageCompleted", "Message completed"), "idle");
4168
+ this.publishActivity(session, { kind: "messageComplete" }, "idle");
3962
4169
  return;
3963
4170
  }
3964
4171
  if (eventType === "message_update") {
3965
- this.publishActivity(session, this.t("activity.receiving", "Receiving reply"), "active");
4172
+ this.publishActivity(session, { kind: "receivingResponse" }, "active");
3966
4173
  return;
3967
4174
  }
3968
4175
  if (eventType === "tool_execution_start") {
3969
- this.publishActivity(session, this.t("activity.toolRunning", "Running tool"), "active", getString(event, "toolName"));
4176
+ this.publishActivity(session, { kind: "runningTool" }, "active", getString(event, "toolName"));
3970
4177
  return;
3971
4178
  }
3972
4179
  if (eventType === "tool_execution_end") {
3973
4180
  const isError = getBoolean(event, "isError") === true;
3974
- this.publishActivity(session, isError ? this.t("activity.toolFailed", "Tool failed") : this.t("activity.toolCompleted", "Tool completed"), isError ? "error" : "idle", getString(event, "toolName"));
4181
+ this.publishActivity(session, isError ? { kind: "toolFailed" } : { kind: "toolComplete" }, isError ? "error" : "idle", getString(event, "toolName"));
3975
4182
  return;
3976
4183
  }
3977
4184
  if (eventType === "bash_execution_start") {
3978
- this.publishActivity(session, this.t("activity.commandRunning", "Running command"), "active");
4185
+ this.publishActivity(session, { kind: "runningBash" }, "active");
3979
4186
  return;
3980
4187
  }
3981
4188
  if (eventType === "bash_execution_end") {
3982
- this.publishActivity(session, this.t("activity.commandCompleted", "Command completed"), "idle");
4189
+ this.publishActivity(session, { kind: "bashComplete" }, "idle");
3983
4190
  return;
3984
4191
  }
3985
4192
  if (this.hasActiveWork(session))
3986
- this.publishActivity(session, this.t("activity.working", "Working"), "active");
4193
+ this.publishActivity(session, { kind: "event", value: eventType }, "active");
3987
4194
  }
3988
4195
  auditToolExecutionEvent(active, event) {
3989
4196
  const eventType = getString(event, "type");
@@ -4080,23 +4287,23 @@ export class PiSessionService {
4080
4287
  const sessionId = sessionManager.getSessionId();
4081
4288
  if (sessionId === "")
4082
4289
  return { report: noop, end: noop };
4083
- const label = intent === "create" ? this.t("activity.creating", "Creating session") : this.t("activity.opening", "Opening session");
4290
+ const label = intent === "create" ? "Creating session" : "Opening session";
4084
4291
  return {
4085
- report: (phase) => { this.publishStartupProgress(sessionId, startupToken, label, "active", this.startupDetail(phase), eventScope); },
4292
+ report: (stage) => {
4293
+ const catalogRefreshing = this.catalogRefreshStatus?.isRefreshInFlight() === true;
4294
+ const phase = stage === "runtime" ? STARTUP_PHASE_RUNTIME : STARTUP_PHASE_EXTENSIONS;
4295
+ const detail = catalogRefreshing ? `${phase} · ${STARTUP_CONCURRENT_CATALOG_REFRESH}` : phase;
4296
+ this.publishStartupProgress(sessionId, startupToken, label, "active", detail, eventScope, { intent, stage, catalogRefreshing });
4297
+ },
4086
4298
  end: () => {
4087
4299
  // A real activity published during the window (an extension error, say)
4088
4300
  // is the truth about this session and must survive the clear.
4089
4301
  if (this.activities.get(activeSessionKey(sessionId, eventScope)) !== undefined)
4090
4302
  return;
4091
- this.publishStartupProgress(sessionId, startupToken, this.t("activity.idle", "Idle"), "idle", undefined, eventScope);
4303
+ this.publishStartupProgress(sessionId, startupToken, "Idle", "idle", undefined, eventScope);
4092
4304
  },
4093
4305
  };
4094
4306
  }
4095
- startupDetail(phase) {
4096
- return this.catalogRefreshStatus?.isRefreshInFlight() === true
4097
- ? `${phase} · ${this.t("startup.catalogRefresh", "Provider model catalog is refreshing")}`
4098
- : phase;
4099
- }
4100
4307
  /**
4101
4308
  * Report startup progress on the global channel only, echoing the caller's
4102
4309
  * correlation token so a waiting browser row recognises its own construction.
@@ -4110,17 +4317,21 @@ export class PiSessionService {
4110
4317
  * that sets the marker, and because it writes no `activities` entry no later
4111
4318
  * heartbeat re-publication can carry it.
4112
4319
  */
4113
- publishStartupProgress(sessionId, startupToken, label, phase, detail, eventScope) {
4320
+ publishStartupProgress(sessionId, startupToken, label, phase, detail, eventScope, startupPresentation) {
4114
4321
  const at = new Date().toISOString();
4115
- const activity = detail === undefined ? { sessionId, phase, label, at, startup: true } : { sessionId, phase, label, detail, at, startup: true };
4322
+ const activity = { sessionId, phase, label, at, startup: true,
4323
+ ...(detail === undefined ? {} : { detail }),
4324
+ ...(startupPresentation === undefined ? {} : { startupPresentation }),
4325
+ };
4116
4326
  this.events.publishGlobal(startupToken === undefined ? { type: "session.startup", activity } : { type: "session.startup", startupToken, activity }, eventScope);
4117
4327
  }
4118
- publishActivity(session, label, phase, detail) {
4328
+ publishActivity(session, runtimePresentation, phase, detail) {
4119
4329
  const at = new Date().toISOString();
4120
- const stored = detail === undefined ? { phase, label, at } : { phase, label, detail, at };
4330
+ const label = runtimeActivityFallbackLabel(runtimePresentation);
4331
+ const stored = { phase, label, at, runtimePresentation, ...(detail === undefined ? {} : { detail }) };
4121
4332
  const eventScope = this.eventScopeForSession(session);
4122
4333
  this.activities.set(activeSessionKey(session.sessionId, eventScope), stored);
4123
- const activity = detail === undefined ? { sessionId: session.sessionId, phase, label, at } : { sessionId: session.sessionId, phase, label, detail, at };
4334
+ const activity = { sessionId: session.sessionId, ...stored };
4124
4335
  this.workspaceActivity?.applySessionActivity(session.sessionManager.getCwd(), activity, eventScope);
4125
4336
  this.events.publish(session.sessionId, { type: "activity.update", activity }, eventScope);
4126
4337
  this.events.publishGlobal({ type: "activity.update", activity }, eventScope);
@@ -4145,6 +4356,26 @@ export class PiSessionService {
4145
4356
  if (path !== undefined)
4146
4357
  this.managementMediaFiles.add(path);
4147
4358
  }
4359
+ interventionRequired(session) {
4360
+ return this.interventionStates.get(session)
4361
+ ?? sessionInterventionRequired(session.sessionManager.getEntries?.() ?? session.sessionManager.getBranch());
4362
+ }
4363
+ setInterventionRequired(session, required) {
4364
+ const previous = this.interventionRequired(session);
4365
+ if (previous === required)
4366
+ return;
4367
+ if (session.sessionManager.appendCustomEntry === undefined)
4368
+ throw new Error("Session manager cannot persist intervention state");
4369
+ // Update before append: the SDK emits entry_appended synchronously.
4370
+ this.interventionStates.set(session, required);
4371
+ try {
4372
+ session.sessionManager.appendCustomEntry(SESSION_INTERVENTION_CUSTOM_TYPE, { version: 1, required });
4373
+ }
4374
+ catch (error) {
4375
+ this.interventionStates.set(session, previous);
4376
+ throw error;
4377
+ }
4378
+ }
4148
4379
  publishStatus(session) {
4149
4380
  this.rememberManagementMediaFile(session, this.eventScopeForSession(session));
4150
4381
  void this.refreshActivityMarker(session);
@@ -4162,7 +4393,7 @@ export class PiSessionService {
4162
4393
  if (current?.phase !== "active" || this.hasActiveWork(session))
4163
4394
  return;
4164
4395
  const at = new Date().toISOString();
4165
- const stored = { phase: "idle", label: this.t("activity.idle", "Idle"), at };
4396
+ const stored = { phase: "idle", label: "idle", at, runtimePresentation: { kind: "idle" } };
4166
4397
  this.activities.set(activeSessionKey(session.sessionId, eventScope), stored);
4167
4398
  const activity = { sessionId: session.sessionId, ...stored };
4168
4399
  this.events.publish(session.sessionId, { type: "activity.update", activity }, eventScope);
@@ -4233,6 +4464,7 @@ export class PiSessionService {
4233
4464
  sessionId: session.sessionId,
4234
4465
  persisted: sessionFileExists(session.sessionFile),
4235
4466
  recentlyActiveElsewhere: this.eventScopeForSession(session) === NORMAL_SESSION_EVENT_SCOPE && this.activityMarker.isActiveElsewhere(session.sessionFile),
4467
+ interventionRequired: this.interventionRequired(session) || pendingDialogs.length > 0,
4236
4468
  ...(model === undefined ? {} : { model }),
4237
4469
  thinkingLevel: session.thinkingLevel,
4238
4470
  isStreaming: session.isStreaming,
@@ -4314,8 +4546,22 @@ export class PiSessionService {
4314
4546
  return this.unreadForScope(eventScope).durableCatalogSnapshot();
4315
4547
  }
4316
4548
  async reconcileUnreadWorkspaces(cwds) {
4549
+ this.unreadEligibilityRevision += 1;
4317
4550
  await this.publishUnreadMutations(this.unreadStore.reconcileWorkspaces(cwds));
4318
4551
  }
4552
+ async markUnread(sessionId, cwd, context) {
4553
+ const canonicalCwd = canonicalizeStoredCwd(cwd);
4554
+ const eligibilityRevision = this.unreadEligibilityRevision;
4555
+ const rows = await this.list(canonicalCwd, context);
4556
+ const row = rows.find((candidate) => candidate.id === sessionId && cwdPathsEqual(candidate.cwd, canonicalCwd));
4557
+ if (eligibilityRevision !== this.unreadEligibilityRevision
4558
+ || row === undefined || row.archived === true || row.persisted !== true || row.agentSubsession === true) {
4559
+ throw new Error("Session is not eligible to be marked unread");
4560
+ }
4561
+ const store = this.unreadForScope(eventScopeFromManagementContext(context));
4562
+ await this.publishUnreadMutations(store.markUnread(sessionId, canonicalCwd));
4563
+ return store.durableCatalogSnapshot();
4564
+ }
4319
4565
  async acknowledgeUnread(sessionId, request, context) {
4320
4566
  const store = this.unreadForScope(eventScopeFromManagementContext(context));
4321
4567
  const result = store.acknowledge(sessionId, {
@@ -4345,7 +4591,7 @@ export class PiSessionService {
4345
4591
  if (this.hasActiveWork(session))
4346
4592
  throw new Error(this.t("session.stopBeforeReload", "Stop current session activity before reloading"));
4347
4593
  await this.runTreeExclusiveOperation([{ sessionId: session.sessionId, session }], this.t("session.stopBeforeReload", "Stop current session activity before reloading"), async () => {
4348
- this.publishActivity(session, this.t("activity.reloading", "Reloading resources"), "active");
4594
+ this.publishActivity(session, { kind: "reloading" }, "active");
4349
4595
  const priorGeneration = this.notificationGenerationBySession.get(session);
4350
4596
  let candidateGeneration;
4351
4597
  const reloadBoundary = { beforeSessionStart: false };
@@ -4365,7 +4611,7 @@ export class PiSessionService {
4365
4611
  if (candidateGeneration !== undefined) {
4366
4612
  this.publishNotificationMutations(this.notificationsForSession(session).commitReplacement(candidateGeneration));
4367
4613
  }
4368
- this.publishActivity(session, this.t("activity.reloaded", "Resources reloaded"), "idle");
4614
+ this.publishActivity(session, { kind: "reloaded" }, "idle");
4369
4615
  this.publishStatus(session);
4370
4616
  }
4371
4617
  catch (error) {
@@ -4376,7 +4622,7 @@ export class PiSessionService {
4376
4622
  this.notificationGenerationBySession.set(session, candidateGeneration);
4377
4623
  }
4378
4624
  const message = error instanceof Error ? error.message : String(error);
4379
- this.publishActivity(session, this.t("activity.reloadFailed", "Reload failed"), "error", message);
4625
+ this.publishActivity(session, { kind: "reloadFailed" }, "error", message);
4380
4626
  this.events.publish(session.sessionId, { type: "session.error", message }, this.eventScopeForSession(session));
4381
4627
  this.publishStatus(session);
4382
4628
  throw error;
@@ -4396,7 +4642,7 @@ export class PiSessionService {
4396
4642
  return [...this.active.values()].some((active) => active.runtime.session === session);
4397
4643
  }
4398
4644
  async createSessionRuntime(sessionManager, cwd, options, startup) {
4399
- startup.report(this.t("startup.runtime", "Loading session runtime"));
4645
+ startup.report("runtime");
4400
4646
  options.startupSignal?.throwIfAborted();
4401
4647
  // Ordinary local sessions (undefined provenance) keep the current rule.
4402
4648
  // Only an explicit host one-shot forces delegation off; do not treat every
@@ -4463,7 +4709,7 @@ export class PiSessionService {
4463
4709
  await this.recoverSubsessionTrackingForOpenedSession(runtime.session);
4464
4710
  }
4465
4711
  startupSignal?.throwIfAborted();
4466
- startup.report(this.t("startup.extensions", "Starting session extensions"));
4712
+ startup.report("extensions");
4467
4713
  // Startup hooks emit through the same scoped stream as hosted turns.
4468
4714
  this.bindRuntime(active);
4469
4715
  await this.bindSessionExtensions(runtime.session, notificationGeneration, active, startupSignal);
@@ -4618,12 +4864,15 @@ export class PiSessionService {
4618
4864
  const nextCwd = canonicalizeStoredCwd(next.sessionManager.getCwd());
4619
4865
  if (previous.sessionId === next.sessionId && cwdPathsEqual(previousCwd, nextCwd))
4620
4866
  return;
4867
+ this.unreadEligibilityRevision += 1;
4621
4868
  await this.publishUnreadMutations(store.forgetSession(previous.sessionId, previousCwd));
4622
4869
  }
4623
4870
  forgetUnreadActivity(session) {
4624
4871
  this.unreadForScope(this.eventScopeForSession(session)).forgetActivity(session.sessionId, canonicalizeStoredCwd(session.sessionManager.getCwd()));
4625
4872
  }
4626
4873
  async forgetUnreadSessions(identities, scope = NORMAL_SESSION_EVENT_SCOPE) {
4874
+ if (identities.length > 0)
4875
+ this.unreadEligibilityRevision += 1;
4627
4876
  const mutations = [];
4628
4877
  for (const identity of identities) {
4629
4878
  mutations.push(...this.unreadForScope(scope).forgetSession(identity.sessionId, canonicalizeStoredCwd(identity.cwd)));
@@ -4727,16 +4976,6 @@ export class PiSessionService {
4727
4976
  this.unreadPublicationRetryDelayMs = this.unreadPublicationRetryInitialMs;
4728
4977
  }
4729
4978
  flushDeferredTreeNavigationWork(session) {
4730
- const generatedName = this.deferredGeneratedSessionNames.get(session);
4731
- this.deferredGeneratedSessionNames.delete(session);
4732
- if (generatedName !== undefined) {
4733
- try {
4734
- this.applyGeneratedSessionName(session, generatedName);
4735
- }
4736
- catch (error) {
4737
- this.logger.info({ sessionId: session.sessionId, error: error instanceof Error ? error.message : String(error) }, "failed to apply deferred session name");
4738
- }
4739
- }
4740
4979
  this.restoreSubsessionReceipts(session);
4741
4980
  this.scheduleSubsessionDelivery(session);
4742
4981
  }
@@ -4875,8 +5114,8 @@ export class PiSessionService {
4875
5114
  }, 0);
4876
5115
  }
4877
5116
  assertMcpModeAllowed(managementContext) {
4878
- if (VERSION !== "1.3.0")
4879
- throw new UserFacingError("mcpAuth.sdkUnsupported", "Dedicated MCP authentication requires Pi 1.3.0");
5117
+ if (VERSION !== "1.3.0" && VERSION !== "1.4.0")
5118
+ throw new UserFacingError("mcpAuth.sdkUnsupported", "Dedicated MCP authentication requires Pi 1.3.0 or 1.4.0");
4880
5119
  if (managementContext !== undefined && !managementUsesNormalPermissions(managementContext, { allowPrivileged: this.managementAllowPrivileged })) {
4881
5120
  throw new UserFacingError("mcpAuth.restrictedManagement", "MCP authentication is unavailable in restricted management mode");
4882
5121
  }
@@ -5026,6 +5265,7 @@ function previewResponseFromPlan(plan) {
5026
5265
  projects: plan.projects,
5027
5266
  totals: plan.totals,
5028
5267
  ...(plan.skippedBusySessionIds.length === 0 ? {} : { skippedBusySessionIds: plan.skippedBusySessionIds }),
5268
+ ...(plan.skippedPinnedSessionIds === undefined ? {} : { skippedPinnedSessionIds: plan.skippedPinnedSessionIds }),
5029
5269
  };
5030
5270
  }
5031
5271
  function uniqueBulkSessionRefs(refs) {
@@ -5113,6 +5353,7 @@ function clientSessionFromListEntry(session) {
5113
5353
  modified: session.modified.toISOString(),
5114
5354
  messageCount: session.messageCount,
5115
5355
  firstMessage: clientSessionFirstMessagePreview(session.firstMessage),
5356
+ ...(session.interventionRequired === true ? { interventionRequired: true } : {}),
5116
5357
  ...(session.parentSessionPath === undefined ? {} : { parentSessionPath: session.parentSessionPath }),
5117
5358
  };
5118
5359
  }