@chainingintention/pi-web-cn 2.202610.5 → 2.202611.2

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 (997) 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-Dur6Wi62.js +3952 -0
  9. package/dist/client/assets/SettingsDialog-SOljSiee.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-DjGXa4ZP.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-CInvlJKI.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-CWcn0Deu.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-B-0wkiKe.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/relays.messages.js +38 -0
  620. package/dist/pi-packages/relays/relaysLocalization.js +19 -0
  621. package/dist/pi-packages/relays/relaysPanelElement.js +151 -96
  622. package/dist/pi-packages/scheduled-tasks/browser/pi-web-plugin.js +1135 -0
  623. package/dist/pi-packages/scheduled-tasks/domain.js +63 -0
  624. package/dist/pi-packages/scheduled-tasks/extensions/index.js +710 -0
  625. package/dist/pi-packages/scheduled-tasks/package.json +30 -0
  626. package/dist/pi-packages/scheduled-tasks/scheduler.js +89 -0
  627. package/dist/pi-packages/scheduled-tasks/server-plugin.js +9872 -0
  628. package/dist/pi-packages/scheduled-tasks/service.js +178 -0
  629. package/dist/pi-packages/scheduled-tasks/skills/scheduled-tasks/SKILL.md +30 -0
  630. package/dist/pi-packages/scheduled-tasks/sqlite.js +18 -0
  631. package/dist/pi-packages/scheduled-tasks/store.js +230 -0
  632. package/dist/pi-packages/scheduled-tasks/vite.browser.config.mjs +16 -0
  633. package/dist/pi-packages/scheduled-tasks/vite.companion.config.mjs +17 -0
  634. package/dist/pi-packages/scheduled-tasks/vite.config.mjs +17 -0
  635. package/dist/pi-packages/session-naming/config.js +78 -0
  636. package/dist/pi-packages/session-naming/extensions/index.js +74 -0
  637. package/dist/pi-packages/session-naming/generator.js +76 -0
  638. package/dist/pi-packages/session-naming/package.json +15 -0
  639. package/dist/pi-packages/workflows/browser/pi-web-plugin.js +10 -7
  640. package/dist/pi-packages/workflows/browser/workflows.messages.js +32 -0
  641. package/dist/pi-packages/workflows/browser/worktreeDialog.js +71 -50
  642. package/dist/pi-packages/workflows/server-plugin.js +137 -23
  643. package/dist/pi-web-plugins/audio/audioElement.js +61 -0
  644. package/dist/pi-web-plugins/audio/audioFormats.js +18 -0
  645. package/dist/pi-web-plugins/audio/byteRange.js +21 -0
  646. package/dist/pi-web-plugins/audio/package.json +10 -0
  647. package/dist/pi-web-plugins/audio/pi-web-plugin.js +39 -0
  648. package/dist/pi-web-plugins/audio/server.js +71 -0
  649. package/dist/pi-web-plugins/code-highlight/browser/pi-web-plugin.js +4 -4
  650. package/dist/pi-web-plugins/custom-ui-codex/codex.css +8 -0
  651. package/dist/pi-web-plugins/custom-ui-codex/fileIcons.js +30 -0
  652. package/dist/pi-web-plugins/custom-ui-codex/package.json +8 -1
  653. package/dist/pi-web-plugins/custom-ui-codex/pi-web-plugin.js +8 -8
  654. package/dist/pi-web-plugins/files/browser/pi-web-plugin.js +236 -259
  655. package/dist/pi-web-plugins/git/browser/git-panel.js +138 -59
  656. package/dist/pi-web-plugins/git/browser/git.messages.js +47 -0
  657. package/dist/pi-web-plugins/git/browser/gitFileIcon.js +71 -0
  658. package/dist/pi-web-plugins/git/browser/pi-web-plugin.js +21 -4
  659. package/dist/pi-web-plugins/git/server-plugin.js +5 -3
  660. package/dist/pi-web-plugins/info/info.messages.js +66 -0
  661. package/dist/pi-web-plugins/info/infoInternals.js +217 -217
  662. package/dist/pi-web-plugins/info/pi-web-plugin.js +19 -14
  663. package/dist/pi-web-plugins/language-spanish/catalogs.js +1896 -0
  664. package/dist/pi-web-plugins/language-spanish/package.json +14 -0
  665. package/dist/pi-web-plugins/language-spanish/pi-web-plugin.js +90 -0
  666. package/dist/pi-web-plugins/language-swedish/catalogs.js +1896 -0
  667. package/dist/pi-web-plugins/language-swedish/package.json +14 -0
  668. package/dist/pi-web-plugins/language-swedish/pi-web-plugin.js +89 -0
  669. package/dist/pi-web-plugins/mermaid/browser/pi-web-plugin.js +4 -4
  670. package/dist/pi-web-plugins/terminal/browser/pi-web-plugin.js +71 -66
  671. package/dist/pi-web-plugins/terminal/bunPtyProvider.js +109 -0
  672. package/dist/pi-web-plugins/terminal/nodePtyProvider.js +75 -0
  673. package/dist/pi-web-plugins/terminal/nodePtySpawnHelper.js +36 -0
  674. package/dist/pi-web-plugins/terminal/ptyComposition.js +12 -0
  675. package/dist/pi-web-plugins/terminal/ptyProvider.js +2 -0
  676. package/dist/pi-web-plugins/terminal/server-plugin.js +42 -14
  677. package/dist/pi-web-plugins/terminal/terminalService.js +218 -76
  678. package/dist/pi-web-plugins/themes/assets/graphite.css +56 -0
  679. package/dist/pi-web-plugins/themes/assets/paper.css +56 -0
  680. package/dist/pi-web-plugins/themes/package.json +21 -0
  681. package/dist/pi-web-plugins/updates/pi-web-plugin.js +200 -155
  682. package/dist/pi-web-plugins/updates/updates.messages.js +59 -0
  683. package/dist/pi-web-plugins/updates/updatesLogic.js +27 -29
  684. package/dist/pi-web-plugins/workspace-tasks/config.js +18 -19
  685. package/dist/pi-web-plugins/workspace-tasks/pi-web-plugin.js +13 -8
  686. package/dist/pi-web-plugins/workspace-tasks/tasks.messages.js +45 -0
  687. package/dist/pi-web-plugins/workspace-tasks/tasksLocalization.js +33 -0
  688. package/dist/pi-web-plugins/workspace-tasks/tasksPanelElement.js +56 -42
  689. package/dist/pi-web-plugins/workspace-tasks/workspaceTasksClient.js +7 -33
  690. package/dist/pi-web-plugins/zh-cn/catalogs.json +1803 -0
  691. package/dist/pi-web-plugins/zh-cn/main.json +5 -1
  692. package/dist/pi-web-plugins/zh-cn/management-errors.json +6 -0
  693. package/dist/pi-web-plugins/zh-cn/pi-web-plugin.js +13 -4
  694. package/dist/pi-web-plugins/zh-cn/server.json +1 -1
  695. package/dist/piWebVersionReport.js +2 -0
  696. package/dist/piWebVersionReport.js.map +1 -1
  697. package/dist/plugin-api.d.ts +194 -9
  698. package/dist/runtimePreflight.js +14 -0
  699. package/dist/runtimePreflight.js.map +1 -0
  700. package/dist/server/activity/workspaceActivityService.js +18 -1
  701. package/dist/server/activity/workspaceActivityService.js.map +1 -1
  702. package/dist/server/app.js +45 -10
  703. package/dist/server/app.js.map +1 -1
  704. package/dist/server/configRoutes.js +117 -139
  705. package/dist/server/configRoutes.js.map +1 -1
  706. package/dist/server/configUpdates.js +104 -0
  707. package/dist/server/configUpdates.js.map +1 -0
  708. package/dist/server/deploymentIdentity.js +12 -10
  709. package/dist/server/deploymentIdentity.js.map +1 -1
  710. package/dist/server/deploymentIdentityRoutes.js +2 -1
  711. package/dist/server/deploymentIdentityRoutes.js.map +1 -1
  712. package/dist/server/diagnostics/nodePtyNativeModule.js +0 -18
  713. package/dist/server/diagnostics/nodePtyNativeModule.js.map +1 -1
  714. package/dist/server/diagnostics/terminalPrerequisites.js +54 -0
  715. package/dist/server/diagnostics/terminalPrerequisites.js.map +1 -0
  716. package/dist/server/index.js +9 -0
  717. package/dist/server/index.js.map +1 -1
  718. package/dist/server/knownAutoInstallPiPackages.js +6 -0
  719. package/dist/server/knownAutoInstallPiPackages.js.map +1 -1
  720. package/dist/server/knownPiPackages.js +4 -4
  721. package/dist/server/knownPiPackages.js.map +1 -1
  722. package/dist/server/machines/machineClient.js +39 -17
  723. package/dist/server/machines/machineClient.js.map +1 -1
  724. package/dist/server/machines/machinePluginProxyRoutes.js +3 -1
  725. package/dist/server/machines/machinePluginProxyRoutes.js.map +1 -1
  726. package/dist/server/machines/machineProxyRoutes.js +60 -9
  727. package/dist/server/machines/machineProxyRoutes.js.map +1 -1
  728. package/dist/server/machines/machineService.js +81 -13
  729. package/dist/server/machines/machineService.js.map +1 -1
  730. package/dist/server/machines/machineStore.js.map +1 -1
  731. package/dist/server/managementEmbed.js +4 -1
  732. package/dist/server/managementEmbed.js.map +1 -1
  733. package/dist/server/managementEntryRoutes.js +51 -0
  734. package/dist/server/managementEntryRoutes.js.map +1 -0
  735. package/dist/server/managementEntryTickets.js +46 -0
  736. package/dist/server/managementEntryTickets.js.map +1 -0
  737. package/dist/server/managementTransportLimits.js +5 -0
  738. package/dist/server/managementTransportLimits.js.map +1 -0
  739. package/dist/server/navigationPreferenceRoutes.js +58 -2
  740. package/dist/server/navigationPreferenceRoutes.js.map +1 -1
  741. package/dist/server/normalAuth.js +3 -1
  742. package/dist/server/normalAuth.js.map +1 -1
  743. package/dist/server/notices/serverNoticeStore.js +4 -0
  744. package/dist/server/notices/serverNoticeStore.js.map +1 -1
  745. package/dist/server/piPackageService.js +15 -1
  746. package/dist/server/piPackageService.js.map +1 -1
  747. package/dist/server/piWebPluginCatalog.js +23 -11
  748. package/dist/server/piWebPluginCatalog.js.map +1 -1
  749. package/dist/server/piWebPluginLifecycle.js +14 -4
  750. package/dist/server/piWebPluginLifecycle.js.map +1 -1
  751. package/dist/server/piWebPluginService.js +11 -5
  752. package/dist/server/piWebPluginService.js.map +1 -1
  753. package/dist/server/piWebStatus.js +12 -10
  754. package/dist/server/piWebStatus.js.map +1 -1
  755. package/dist/server/piWebStatusCache.js +3 -1
  756. package/dist/server/piWebStatusCache.js.map +1 -1
  757. package/dist/server/plugins/pluginBackendRegistry.js +229 -4
  758. package/dist/server/plugins/pluginBackendRegistry.js.map +1 -1
  759. package/dist/server/plugins/pluginBackendResourceProxyRoutes.js +40 -0
  760. package/dist/server/plugins/pluginBackendResourceProxyRoutes.js.map +1 -0
  761. package/dist/server/plugins/pluginBackendResourceResponse.js +84 -0
  762. package/dist/server/plugins/pluginBackendResourceResponse.js.map +1 -0
  763. package/dist/server/plugins/projectPluginSettings.js +9 -2
  764. package/dist/server/plugins/projectPluginSettings.js.map +1 -1
  765. package/dist/server/plugins/serverPluginCatalogCapability.js +7 -2
  766. package/dist/server/plugins/serverPluginCatalogCapability.js.map +1 -1
  767. package/dist/server/plugins/serverPluginPiSessionsCapability.js +16 -3
  768. package/dist/server/plugins/serverPluginPiSessionsCapability.js.map +1 -1
  769. package/dist/server/plugins/serverPluginRuntime.js +25 -9
  770. package/dist/server/plugins/serverPluginRuntime.js.map +1 -1
  771. package/dist/server/plugins/serverPluginSessionLifecycleCapability.js +87 -0
  772. package/dist/server/plugins/serverPluginSessionLifecycleCapability.js.map +1 -0
  773. package/dist/server/requestLogging.js +1 -1
  774. package/dist/server/requestLogging.js.map +1 -1
  775. package/dist/server/sessiond/agentHttpDispatcher.js +14 -7
  776. package/dist/server/sessiond/agentHttpDispatcher.js.map +1 -1
  777. package/dist/server/sessiond/autoInstallPiPackageSources.js +54 -0
  778. package/dist/server/sessiond/autoInstallPiPackageSources.js.map +1 -0
  779. package/dist/server/sessiond/autoInstallPiPackages.js +77 -30
  780. package/dist/server/sessiond/autoInstallPiPackages.js.map +1 -1
  781. package/dist/server/sessiond/pluginBackendChannelRoutes.js +3 -13
  782. package/dist/server/sessiond/pluginBackendChannelRoutes.js.map +1 -1
  783. package/dist/server/sessiond/pluginBackendResourceRoutes.js +62 -0
  784. package/dist/server/sessiond/pluginBackendResourceRoutes.js.map +1 -0
  785. package/dist/server/sessiond/pluginSessionLifecycleRoutes.js +45 -0
  786. package/dist/server/sessiond/pluginSessionLifecycleRoutes.js.map +1 -0
  787. package/dist/server/sessiond/sessionProxyRoutes.js +76 -12
  788. package/dist/server/sessiond/sessionProxyRoutes.js.map +1 -1
  789. package/dist/server/sessiond/sessionServiceDependencies.js +3 -0
  790. package/dist/server/sessiond/sessionServiceDependencies.js.map +1 -1
  791. package/dist/server/sessiond.js +47 -16
  792. package/dist/server/sessiond.js.map +1 -1
  793. package/dist/server/sessions/askUserDomain.js +24 -2
  794. package/dist/server/sessions/askUserDomain.js.map +1 -1
  795. package/dist/server/sessions/askUserTool.js +1 -1
  796. package/dist/server/sessions/askUserTool.js.map +1 -1
  797. package/dist/server/sessions/dockerEnvironmentFacts.js +10 -9
  798. package/dist/server/sessions/dockerEnvironmentFacts.js.map +1 -1
  799. package/dist/server/sessions/mcpOAuthCredentialAdapter.js +4 -4
  800. package/dist/server/sessions/mcpOAuthCredentialAdapter.js.map +1 -1
  801. package/dist/server/sessions/piSessionService.js +491 -283
  802. package/dist/server/sessions/piSessionService.js.map +1 -1
  803. package/dist/server/sessions/requestHumanInterventionTool.js +27 -0
  804. package/dist/server/sessions/requestHumanInterventionTool.js.map +1 -0
  805. package/dist/server/sessions/sendSessionMessageTool.js +32 -0
  806. package/dist/server/sessions/sendSessionMessageTool.js.map +1 -0
  807. package/dist/server/sessions/sessionActivityCoordinator.js.map +1 -1
  808. package/dist/server/sessions/sessionCleanup.js +18 -1
  809. package/dist/server/sessions/sessionCleanup.js.map +1 -1
  810. package/dist/server/sessions/sessionCommandService.js +58 -52
  811. package/dist/server/sessions/sessionCommandService.js.map +1 -1
  812. package/dist/server/sessions/sessionContentSearch.js +103 -30
  813. package/dist/server/sessions/sessionContentSearch.js.map +1 -1
  814. package/dist/server/sessions/sessionIntervention.js +29 -0
  815. package/dist/server/sessions/sessionIntervention.js.map +1 -0
  816. package/dist/server/sessions/sessionNameGenerator.js +0 -60
  817. package/dist/server/sessions/sessionNameGenerator.js.map +1 -1
  818. package/dist/server/sessions/sessionNotificationStore.js +2 -1
  819. package/dist/server/sessions/sessionNotificationStore.js.map +1 -1
  820. package/dist/server/sessions/sessionRoutes.js +25 -28
  821. package/dist/server/sessions/sessionRoutes.js.map +1 -1
  822. package/dist/server/sessions/sessionSummaryScanner.js +8 -0
  823. package/dist/server/sessions/sessionSummaryScanner.js.map +1 -1
  824. package/dist/server/sessions/sessionTreeProjection.js +108 -97
  825. package/dist/server/sessions/sessionTreeProjection.js.map +1 -1
  826. package/dist/server/sessions/sessionUiEvents.js +2 -0
  827. package/dist/server/sessions/sessionUiEvents.js.map +1 -1
  828. package/dist/server/sessions/sessionUnreadStore.js +11 -1
  829. package/dist/server/sessions/sessionUnreadStore.js.map +1 -1
  830. package/dist/server/sessions/spawnSubsessionTool.js +66 -15
  831. package/dist/server/sessions/spawnSubsessionTool.js.map +1 -1
  832. package/dist/server/sessions/subsessionCompletionDelivery.js +6 -3
  833. package/dist/server/sessions/subsessionCompletionDelivery.js.map +1 -1
  834. package/dist/server/sessions/subsessionCompletionInbox.js +6 -9
  835. package/dist/server/sessions/subsessionCompletionInbox.js.map +1 -1
  836. package/dist/server/status/machineStatusService.js +15 -3
  837. package/dist/server/status/machineStatusService.js.map +1 -1
  838. package/dist/server/storage/navigationPreferenceStore.js +19 -2
  839. package/dist/server/storage/navigationPreferenceStore.js.map +1 -1
  840. package/dist/server/storage/sessionPinStore.js +101 -0
  841. package/dist/server/storage/sessionPinStore.js.map +1 -0
  842. package/dist/server/terminals/maintenanceExecutionContext.js +18 -0
  843. package/dist/server/terminals/maintenanceExecutionContext.js.map +1 -0
  844. package/dist/server/terminals/maintenanceTerminalCapability.js +25 -0
  845. package/dist/server/terminals/maintenanceTerminalCapability.js.map +1 -0
  846. package/dist/server/terminals/requiredTerminalService.js.map +1 -1
  847. package/dist/server/terminals/terminalStatusRoutes.js +22 -0
  848. package/dist/server/terminals/terminalStatusRoutes.js.map +1 -0
  849. package/dist/server/themeBootstrap.js +123 -0
  850. package/dist/server/themeBootstrap.js.map +1 -0
  851. package/dist/server/themeCatalog.js +206 -0
  852. package/dist/server/themeCatalog.js.map +1 -0
  853. package/dist/server/themeMetadata.js +74 -0
  854. package/dist/server/themeMetadata.js.map +1 -0
  855. package/dist/server/webSocketBridge.js +16 -12
  856. package/dist/server/webSocketBridge.js.map +1 -1
  857. package/dist/server/webSocketPayloadLimit.js +17 -0
  858. package/dist/server/webSocketPayloadLimit.js.map +1 -0
  859. package/dist/server/workspaces/effectivePathAccess.js +1 -1
  860. package/dist/server/workspaces/effectivePathAccess.js.map +1 -1
  861. package/dist/server/workspaces/projectPiWebConfig.js +30 -7
  862. package/dist/server/workspaces/projectPiWebConfig.js.map +1 -1
  863. package/dist/server/workspaces/sessionDaemonWorkspaceCatalog.js +2 -0
  864. package/dist/server/workspaces/sessionDaemonWorkspaceCatalog.js.map +1 -1
  865. package/dist/server/workspaces/workspaceProviderRegistry.js +6 -2
  866. package/dist/server/workspaces/workspaceProviderRegistry.js.map +1 -1
  867. package/dist/server/workspaces/workspaceRemovalService.js +6 -4
  868. package/dist/server/workspaces/workspaceRemovalService.js.map +1 -1
  869. package/dist/server-plugin-api.d.ts +39 -1
  870. package/dist/server-plugin-api.js +18 -3
  871. package/dist/server-plugin-api.js.map +1 -1
  872. package/dist/sessiond/sessionDaemonClient.js +7 -1
  873. package/dist/sessiond/sessionDaemonClient.js.map +1 -1
  874. package/dist/sessiond/sessionDaemonTerminalStatus.js +27 -0
  875. package/dist/sessiond/sessionDaemonTerminalStatus.js.map +1 -0
  876. package/dist/shared/apiTypes.js +5 -0
  877. package/dist/shared/apiTypes.js.map +1 -1
  878. package/dist/shared/capabilities.js +9 -0
  879. package/dist/shared/capabilities.js.map +1 -1
  880. package/dist/shared/commandOutputPresentation.js +17 -0
  881. package/dist/shared/commandOutputPresentation.js.map +1 -0
  882. package/dist/shared/commandResultPresentation.js +51 -0
  883. package/dist/shared/commandResultPresentation.js.map +1 -0
  884. package/dist/shared/configResolution.js +99 -0
  885. package/dist/shared/configResolution.js.map +1 -0
  886. package/dist/shared/defaultLocalization.js +60 -0
  887. package/dist/shared/defaultLocalization.js.map +1 -0
  888. package/dist/shared/federatedRoutes.js +11 -4
  889. package/dist/shared/federatedRoutes.js.map +1 -1
  890. package/dist/shared/installationName.js +21 -0
  891. package/dist/shared/installationName.js.map +1 -0
  892. package/dist/shared/localization.d.ts +55 -0
  893. package/dist/shared/localization.js +4 -0
  894. package/dist/shared/machineStatus.js +2 -0
  895. package/dist/shared/machineStatus.js.map +1 -1
  896. package/dist/shared/piWebConfigParsing.js +16 -30
  897. package/dist/shared/piWebConfigParsing.js.map +1 -1
  898. package/dist/shared/piWebRuntime.js +17 -0
  899. package/dist/shared/piWebRuntime.js.map +1 -0
  900. package/dist/shared/piWebStatusParsing.js +5 -0
  901. package/dist/shared/piWebStatusParsing.js.map +1 -1
  902. package/dist/shared/pluginApiTypes.d.ts +35 -7
  903. package/dist/shared/pluginBackendProtocol.js +24 -0
  904. package/dist/shared/pluginBackendProtocol.js.map +1 -1
  905. package/dist/shared/pluginCatalogTypes.d.ts +8 -0
  906. package/dist/shared/pluginCatalogTypes.js +15 -0
  907. package/dist/shared/pluginCatalogTypes.js.map +1 -1
  908. package/dist/shared/pluginResourceMetadata.js +58 -0
  909. package/dist/shared/pluginResourceMetadata.js.map +1 -0
  910. package/dist/shared/pluginSessionLifecycleTypes.d.ts +24 -0
  911. package/dist/shared/pluginSessionLifecycleTypes.js +56 -0
  912. package/dist/shared/pluginSessionLifecycleTypes.js.map +1 -0
  913. package/dist/shared/serverNoticePresentation.d.ts +9 -0
  914. package/dist/shared/serverNoticePresentation.js +12 -0
  915. package/dist/shared/serverNoticePresentation.js.map +1 -0
  916. package/dist/shared/sessionActivityPresentation.js +73 -0
  917. package/dist/shared/sessionActivityPresentation.js.map +1 -0
  918. package/dist/shared/sessionNotificationPresentation.js +16 -0
  919. package/dist/shared/sessionNotificationPresentation.js.map +1 -0
  920. package/dist/shared/terminalCommandRun.js +4 -0
  921. package/dist/shared/terminalCommandRun.js.map +1 -1
  922. package/dist/shared/terminalServiceStatus.js +14 -0
  923. package/dist/shared/terminalServiceStatus.js.map +1 -0
  924. package/dist/shared/terminalTitlePresentation.d.ts +10 -0
  925. package/dist/shared/terminalTitlePresentation.js +13 -0
  926. package/dist/shared/terminalTitlePresentation.js.map +1 -0
  927. package/dist/shared/themeCatalog.js +2 -0
  928. package/dist/shared/themeCatalog.js.map +1 -0
  929. package/dist/shared/themePreference.js +1 -0
  930. package/dist/shared/themePreference.js.map +1 -1
  931. package/dist/shared/thinkingLevels.d.ts +29 -0
  932. package/dist/shared/thinkingLevels.js +6 -4
  933. package/dist/shared/thinkingLevels.js.map +1 -1
  934. package/dist/shared/versionCheckPolicy.js +10 -0
  935. package/dist/shared/versionCheckPolicy.js.map +1 -0
  936. package/dist/shared/workspaceRemovalPresentation.d.ts +8 -0
  937. package/dist/shared/workspaceRemovalPresentation.js +10 -0
  938. package/dist/shared/workspaceRemovalPresentation.js.map +1 -0
  939. package/docs/README.md +7 -3
  940. package/docs/assets/pi-web-desktop-graphite.png +0 -0
  941. package/docs/assets/pi-web-desktop-paper.png +0 -0
  942. package/docs/assets/pi-web-desktop-pi-web-dark.png +0 -0
  943. package/docs/assets/pi-web-desktop-pi-web-light.png +0 -0
  944. package/docs/assets/pi-web-desktop.png +0 -0
  945. package/docs/assets/pi-web-mobile-graphite.png +0 -0
  946. package/docs/assets/pi-web-mobile-paper.png +0 -0
  947. package/docs/assets/pi-web-mobile-pi-web-dark.png +0 -0
  948. package/docs/assets/pi-web-mobile-pi-web-light.png +0 -0
  949. package/docs/assets/pi-web-mobile-themes.gif +0 -0
  950. package/docs/assets/pi-web-mobile.png +0 -0
  951. package/docs/assets/pi-web-tablet-graphite.png +0 -0
  952. package/docs/assets/pi-web-tablet-paper.png +0 -0
  953. package/docs/assets/pi-web-tablet-pi-web-dark.png +0 -0
  954. package/docs/assets/pi-web-tablet-pi-web-light.png +0 -0
  955. package/docs/assets/pi-web-tablet-themes.gif +0 -0
  956. package/docs/assets/pi-web-tablet.png +0 -0
  957. package/docs/assets/pi-web-themes.gif +0 -0
  958. package/docs/config.md +193 -55
  959. package/docs/plugins.md +350 -21
  960. package/docs/scheduled-tasks.md +127 -0
  961. package/package.json +43 -19
  962. package/dist/client/assets/CommandPicker-8oDe6AaV.js +0 -70
  963. package/dist/client/assets/PiWebApp-TCQVYghs.js +0 -3761
  964. package/dist/client/assets/SettingsDialog-DFUpwUyp.js +0 -1015
  965. package/dist/client/assets/index-DzMPXVth.js +0 -2
  966. package/dist/client/assets/managementEmbed-Bx8Mwzdw.js +0 -2
  967. package/dist/client/assets/preload-helper-XpATwJ5c.js +0 -1
  968. package/dist/pi-packages/captains-log/README.md +0 -11
  969. package/dist/pi-packages/captains-log/dist/browser/channelProtocol.js +0 -29
  970. package/dist/pi-packages/captains-log/dist/browser/index.js +0 -143
  971. package/dist/pi-packages/captains-log/dist/browser/markdown.js +0 -68
  972. package/dist/pi-packages/captains-log/dist/browser/panel.js +0 -148
  973. package/dist/pi-packages/captains-log/dist/browser/protocol.js +0 -26
  974. package/dist/pi-packages/captains-log/dist/companion.js +0 -126
  975. package/dist/pi-packages/captains-log/dist/roundtrip.js +0 -62
  976. package/dist/pi-packages/captains-log/dist/server.js +0 -210
  977. package/dist/pi-packages/captains-log/dist/store.js +0 -75
  978. package/dist/pi-packages/captains-log/docs/usage.md +0 -29
  979. package/dist/pi-packages/captains-log/i18n.js +0 -7
  980. package/dist/pi-packages/captains-log/package.json +0 -35
  981. package/dist/pi-packages/captains-log/tsconfig.json +0 -21
  982. package/dist/pi-packages/captains-log/vite.config.mjs +0 -28
  983. package/dist/server/sessions/sessionPinStore.js +0 -109
  984. package/dist/server/sessions/sessionPinStore.js.map +0 -1
  985. package/examples/session-bridge-plugin/README.md +0 -20
  986. package/examples/session-bridge-plugin/docs/usage.md +0 -54
  987. package/examples/session-bridge-plugin/package.json +0 -26
  988. package/examples/session-bridge-plugin/src/browser/index.ts +0 -87
  989. package/examples/session-bridge-plugin/src/browser/protocol.ts +0 -24
  990. package/examples/session-bridge-plugin/src/companion.ts +0 -65
  991. package/examples/session-bridge-plugin/src/reviewRun.ts +0 -39
  992. package/examples/session-bridge-plugin/src/server.ts +0 -85
  993. package/examples/session-bridge-plugin/src/store.ts +0 -80
  994. package/examples/session-bridge-plugin/tsconfig.json +0 -21
  995. /package/dist/{client/assets/classic-CyM97Akm.css → pi-web-plugins/themes/assets/classic.css} +0 -0
  996. /package/dist/{client/assets/pi-web-dark-D_KtbM95.css → pi-web-plugins/themes/assets/pi-web-dark.css} +0 -0
  997. /package/dist/{client/assets/pi-web-light-DSNLMIBI.css → pi-web-plugins/themes/assets/pi-web-light.css} +0 -0
@@ -1,12 +1,17 @@
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";
7
12
  import { clientSessionFirstMessagePreview } from "./clientSessionPreview.js";
8
13
  import { readFile } from "node:fs/promises";
9
- import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
14
+ import { basename, dirname, isAbsolute, relative, resolve } from "node:path";
10
15
  import { QueueCompatibilityGuard, mirroredQueueEntries, mutableQueueAgent, mutableTextMirror, parseQueueMessageMutation, queuedMessageAttachmentCount, queuedMessageAttachmentCounts, snapshotAgentQueues } from "./queuedMessageMutation.js";
11
16
  import { createAgentSessionFromServices, createAgentSessionRuntime, createAgentSessionServices, createEventBus, createEditToolDefinition, createFindToolDefinition, createGrepToolDefinition, getAgentDir, createLsToolDefinition, createReadToolDefinition, createWriteToolDefinition, defineTool, loadSkills, ProjectTrustStore, hasTrustRequiringProjectResources, readStoredCredential, SessionManager, VERSION, } from "../../piSdk.js";
12
17
  import { projectBrowserMessage } from "../browserMessageProjection.js";
@@ -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";
@@ -35,18 +40,19 @@ import { ASK_USER_ANSWERS_CUSTOM_TYPE, SESSION_TREE_CUSTOM_INSTRUCTIONS_MAX_LENG
35
40
  import { PiSessionEventConnections } from "./piSessionEventConnections.js";
36
41
  import { resolveWebProjectTrusted } from "./projectTrust.js";
37
42
  import { createPiSessionManagerGateway } from "./piSessionManagerGateway.js";
38
- import { SessionPinStore } from "./sessionPinStore.js";
39
43
  import { SessionActivityCoordinator } from "./sessionActivityCoordinator.js";
40
- import { searchSessionContent } from "./sessionContentSearch.js";
44
+ import { compileSessionContentQuery, searchSessionContent } from "./sessionContentSearch.js";
41
45
  import { createLocalOnlyModelRuntime, modelRuntimeAuthPath } from "./authService.js";
42
46
  import { canonicalizeStoredCwd, cwdPathsEqual } from "../workingDirectory.js";
43
47
  import { clearSessionFileParent, readSessionHeaderSummary } from "./sessionFileHeader.js";
44
- import { isManagedAgentsFile, workbenchAccessHandle } from "../managementEmbed.js";
48
+ import { assertManagedCwd, isManagedAgentsFile, workbenchAccessHandle } from "../managementEmbed.js";
45
49
  import { managementPrivilegeRequested, managementPrivileges, managementUsesNormalPermissions } from "../managementPrivileges.js";
46
50
  import { DEFAULT_EXTENSION_DIALOGS_TIMEOUT_MS, piWebDataDir } from "../../config.js";
47
51
  import { createScopedSettingsManager, resolveSettingsScopeDirectory } from "./projectSettingsScope.js";
48
52
  import { parseSessionDefaults, parseSessionDefaultsUpdate } from "../../shared/sessionDefaults.js";
49
53
  import { createAskUserToolDefinition } from "./askUserTool.js";
54
+ import { createRequestHumanInterventionToolDefinition } from "./requestHumanInterventionTool.js";
55
+ import { requestsHumanIntervention, SESSION_INTERVENTION_CUSTOM_TYPE, sessionInterventionRequired } from "./sessionIntervention.js";
50
56
  import { createAskUserOutcome, renderAskUserAnswersText, resolveAskUserRequest } from "./askUserDomain.js";
51
57
  import { createSubsessionCompletionDelivery } from "./subsessionCompletionDelivery.js";
52
58
  import { completionReceiptIds, persistedSubsessionCompletions, renderSubsessionCompletions, SUBSESSION_COMPLETION_ENTRY_TYPE, SUBSESSION_NOTIFICATION_CUSTOM_TYPE, SUBSESSION_RECEIPT_ENTRY_TYPE, SubsessionCompletionInbox } from "./subsessionCompletionInbox.js";
@@ -56,6 +62,7 @@ import { ExtensionDialogWaiters, effectiveExtensionDialogTimeoutMs, extensionDia
56
62
  import { createSpawnSessionToolDefinition } from "./spawnSessionTool.js";
57
63
  import { createSubsessionToolDefinitions } from "./spawnSubsessionTool.js";
58
64
  import { buildTranscriptView } from "./subsessionTranscript.js";
65
+ import { createSendSessionMessageToolDefinition } from "./sendSessionMessageTool.js";
59
66
  import { planSessionCleanup, summarizeSessionCleanupExecution } from "./sessionCleanup.js";
60
67
  import { createManagedAgentToolOptions, createManagedBashToolDefinition, createManagedPythonToolDefinition } from "./managementAgentTools.js";
61
68
  import { PI_PERMISSION_SYSTEM_POLICY_AGENT_DIR, managementAgentToolNames, privilegedManagementToolNames, withRuntimeCreationEnvironment, writeManagementPermissionSystemPolicy } from "./managementPermissionSystem.js";
@@ -311,7 +318,8 @@ export function collectRuntimeWarnings(runtime) {
311
318
  /**
312
319
  * Verbatim TUI wording for the Anthropic subscription-auth billing notice. Kept
313
320
  * 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.
321
+ * the SDK's interactive mode as the wire fallback. Browser presentation metadata
322
+ * allows translation without matching this English string.
315
323
  */
316
324
  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
325
  /** Mirror of the SDK TUI `isAnthropicSubscriptionAuthKey` (subscription API keys start with `sk-ant-oat`). */
@@ -352,6 +360,7 @@ export function anthropicSubscriptionWarning(session, authPath) {
352
360
  return {
353
361
  severity: "warning",
354
362
  message: ANTHROPIC_SUBSCRIPTION_AUTH_WARNING,
363
+ presentation: { kind: "anthropicSubscriptionAuth" },
355
364
  source: "anthropic",
356
365
  dismiss: { id: ANTHROPIC_EXTRA_USAGE_DISMISS_ID },
357
366
  };
@@ -438,11 +447,11 @@ async function createNormalPermissionSessionServices(options) {
438
447
  });
439
448
  return { services, projectTrustDiagnostics };
440
449
  }
441
- function createDefaultRuntimeFactory(sessionEvents, normalModelRuntimeForCwd, managementModelRuntime, resolveSettingsScope, sessionManagers, spawn, subsessions, askUserEnabled = false, workbench, logger = noopLogger, managementAudit, managementProjectIdForCwd, appendSystemPromptSections = [], managementAllowPrivileged = false) {
450
+ function createDefaultRuntimeFactory(sessionEvents, normalModelRuntimeForCwd, managementModelRuntime, resolveSettingsScope, sessionManagers, spawn, subsessions, askUserEnabled = false, workbench, logger = noopLogger, managementAudit, managementProjectIdForCwd, appendSystemPromptSections = [], managementAllowPrivileged = false, messaging) {
442
451
  return async ({ cwd, agentDir, sessionManager, sessionStartEvent, managementContext, initialModel, initialThinkingLevel, delegationToolsEnabled }) => {
443
452
  const scopedModelRuntime = managementContext === undefined ? await normalModelRuntimeForCwd(cwd) : await managementModelRuntime();
444
453
  if (managementContext !== undefined) {
445
- return createManagementRuntimeFactory(scopedModelRuntime, resolveSettingsScope, sessionManagers, spawn, subsessions, askUserEnabled, managementContext, workbench, logger, managementAudit, managementProjectIdForCwd, managementAllowPrivileged, appendSystemPromptSections)({
454
+ return createManagementRuntimeFactory(scopedModelRuntime, resolveSettingsScope, sessionManagers, spawn, subsessions, askUserEnabled, managementContext, workbench, logger, managementAudit, managementProjectIdForCwd, managementAllowPrivileged, appendSystemPromptSections, messaging)({
446
455
  cwd,
447
456
  agentDir,
448
457
  sessionManager,
@@ -454,6 +463,8 @@ function createDefaultRuntimeFactory(sessionEvents, normalModelRuntimeForCwd, ma
454
463
  }
455
464
  // Resource loaders may read process.env; wait for managed overrides to be restored.
456
465
  return withRuntimeCreationEnvironment({}, async () => {
466
+ const parentSessionFile = sessionManager.getHeader()?.parentSession;
467
+ const parentHeader = parentSessionFile === undefined ? undefined : await readSessionHeaderSummary(parentSessionFile);
457
468
  const projectTrustRequiring = hasTrustRequiringProjectResources(cwd);
458
469
  const settingsManager = await createScopedSettingsManager({
459
470
  cwd,
@@ -473,7 +484,10 @@ function createDefaultRuntimeFactory(sessionEvents, normalModelRuntimeForCwd, ma
473
484
  modelRuntime: scopedModelRuntime,
474
485
  settingsManager,
475
486
  projectTrustRequiring,
476
- appendSystemPromptSections,
487
+ appendSystemPromptSections: [
488
+ ...appendSystemPromptSections,
489
+ ...(parentHeader === undefined ? [] : [`<pi_web_session_context>\nParent session ID: ${parentHeader.id}\n</pi_web_session_context>`]),
490
+ ],
477
491
  eventBus,
478
492
  mcpScope: { directory: mcpOAuthStorageDirectory(await resolveSettingsScope(cwd, "normal")) },
479
493
  extensionFactories: [sessionDispatch, ...(subsessions === undefined ? [] : [createSubsessionCompletionDelivery(subsessions)])],
@@ -488,7 +502,7 @@ function createDefaultRuntimeFactory(sessionEvents, normalModelRuntimeForCwd, ma
488
502
  const resolvedDelegationToolsEnabled = delegationToolsEnabled
489
503
  ?? await sessionAllowsDelegationTools(sessionManager, sessionManagers);
490
504
  dispatchEnabled = resolvedDelegationToolsEnabled;
491
- const customTools = createPiWebCustomToolDefinitions(cwd, resolvedDelegationToolsEnabled, spawn, subsessions, askUserEnabled);
505
+ const customTools = createPiWebCustomToolDefinitions(cwd, resolvedDelegationToolsEnabled, spawn, subsessions, askUserEnabled, messaging);
492
506
  const result = await createAgentSessionFromServices({
493
507
  services,
494
508
  sessionManager,
@@ -505,7 +519,7 @@ function createDefaultRuntimeFactory(sessionEvents, normalModelRuntimeForCwd, ma
505
519
  });
506
520
  };
507
521
  }
508
- function createManagementRuntimeFactory(modelRuntime, resolveSettingsScope, sessionManagers, spawn, subsessions, askUserEnabled, managementContext, workbench, logger, managementAudit, managementProjectIdForCwd, managementAllowPrivileged = false, appendSystemPromptSections = []) {
522
+ function createManagementRuntimeFactory(modelRuntime, resolveSettingsScope, sessionManagers, spawn, subsessions, askUserEnabled, managementContext, workbench, logger, managementAudit, managementProjectIdForCwd, managementAllowPrivileged = false, appendSystemPromptSections = [], messaging) {
509
523
  return async ({ cwd, agentDir, sessionManager, sessionStartEvent, initialModel, initialThinkingLevel, delegationToolsEnabled }) => {
510
524
  const normalPermissions = managementUsesNormalPermissions(managementContext, { allowPrivileged: managementAllowPrivileged });
511
525
  const privileges = managementPrivileges(managementContext, { allowPrivileged: managementAllowPrivileged });
@@ -541,10 +555,16 @@ function createManagementRuntimeFactory(modelRuntime, resolveSettingsScope, sess
541
555
  const scopedSpawn = spawn === undefined
542
556
  ? undefined
543
557
  : (input) => spawn({ ...input, managementContext });
558
+ const scopedMessaging = messaging === undefined ? undefined : {
559
+ send: (input) => messaging.send(input, managementContext),
560
+ };
544
561
  const scopedSubsessions = subsessions === undefined
545
562
  ? undefined
546
563
  : {
547
564
  spawn: (input) => subsessions.spawn({ ...input, managementContext }),
565
+ archive: (parentSessionId, sessionId, parentSessionFile) => subsessions.archive(parentSessionId, sessionId, parentSessionFile, managementContext),
566
+ stop: (parentSessionId, sessionId, parentSessionFile) => subsessions.stop(parentSessionId, sessionId, parentSessionFile, managementContext),
567
+ resume: (parentSessionId, sessionId, prompt, parentSessionFile) => subsessions.resume(parentSessionId, sessionId, prompt, parentSessionFile, managementContext),
548
568
  list: (parentSessionId, parentSessionFile) => subsessions.list(parentSessionId, parentSessionFile, managementContext),
549
569
  join: (parentSessionId, parentSessionFile, toolCallId) => subsessions.join(parentSessionId, parentSessionFile, toolCallId, managementContext),
550
570
  prepare: (parentSessionId, parentSessionFile) => subsessions.prepare(parentSessionId, parentSessionFile, managementContext),
@@ -560,6 +580,8 @@ function createManagementRuntimeFactory(modelRuntime, resolveSettingsScope, sess
560
580
  ...(scopedSubsessions === undefined ? [] : [createSubsessionCompletionDelivery(scopedSubsessions)]),
561
581
  ];
562
582
  const controlledManagementTools = [
583
+ defineTool(createRequestHumanInterventionToolDefinition()),
584
+ ...(scopedMessaging === undefined ? [] : [defineTool(createSendSessionMessageToolDefinition(cwd, scopedMessaging))]),
563
585
  ...(resolvedDelegationToolsEnabled && scopedSpawn !== undefined ? [defineTool(createSpawnSessionToolDefinition(cwd, { spawn: scopedSpawn }))] : []),
564
586
  ...(resolvedDelegationToolsEnabled && scopedSubsessions !== undefined ? createSubsessionToolDefinitions(cwd, scopedSubsessions).map((tool) => defineTool(tool)) : []),
565
587
  ...(askUserEnabled ? [createAskUserToolDefinition()] : []),
@@ -621,7 +643,7 @@ function createManagementRuntimeFactory(modelRuntime, resolveSettingsScope, sess
621
643
  ...(initialThinkingLevel === undefined ? {} : { initialThinkingLevel }),
622
644
  });
623
645
  services.diagnostics.push(...modelOptions.diagnostics);
624
- const customTools = normalPermissions ? createPiWebCustomToolDefinitions(cwd, resolvedDelegationToolsEnabled, scopedSpawn, scopedSubsessions, askUserEnabled) : [
646
+ const customTools = normalPermissions ? createPiWebCustomToolDefinitions(cwd, resolvedDelegationToolsEnabled, scopedSpawn, scopedSubsessions, askUserEnabled, scopedMessaging) : [
625
647
  ...managedAgentToolDefinitions(cwd, createManagedAgentToolOptions(cwd)),
626
648
  createManagedPythonToolDefinition(cwd, managementContext, { network: privileges.network }),
627
649
  createManagedBashToolDefinition(cwd, managementContext, { network: privileges.network, hostFilesystem: privileges.bash }),
@@ -651,9 +673,11 @@ function createManagementRuntimeFactory(modelRuntime, resolveSettingsScope, sess
651
673
  });
652
674
  };
653
675
  }
654
- export function createPiWebCustomToolDefinitions(cwd, delegationEnabled, spawn, subsessions, askUserEnabled = false) {
676
+ export function createPiWebCustomToolDefinitions(cwd, delegationEnabled, spawn, subsessions, askUserEnabled = false, messaging) {
655
677
  return [
656
678
  ...managedAgentToolDefinitions(cwd),
679
+ defineTool(createRequestHumanInterventionToolDefinition()),
680
+ ...(messaging === undefined ? [] : [defineTool(createSendSessionMessageToolDefinition(cwd, messaging))]),
657
681
  ...(delegationEnabled && spawn !== undefined ? [defineTool(createSpawnSessionToolDefinition(cwd, { spawn }))] : []),
658
682
  ...(delegationEnabled && subsessions !== undefined ? createSubsessionToolDefinitions(cwd, subsessions).map((tool) => defineTool(tool)) : []),
659
683
  ...(askUserEnabled ? [createAskUserToolDefinition()] : []),
@@ -686,7 +710,7 @@ function createPiWebEditToolDefinition(cwd, options) {
686
710
  async execute(toolCallId, params, signal, onUpdate, ctx) {
687
711
  const preview = await computeEditPreview(params.path, params.edits, cwd);
688
712
  if (signal?.aborted !== true) {
689
- onUpdate?.({ content: [{ type: "text", text: "Edit preview computed." }], details: { preview } });
713
+ onUpdate?.({ content: [{ type: "text", text: "Edit preview computed." }], details: { preview, presentation: { kind: "editPreviewComputed" } } });
690
714
  }
691
715
  return editTool.execute(toolCallId, params, signal, onUpdate, ctx);
692
716
  },
@@ -705,12 +729,19 @@ export class PiSessionService {
705
729
  this.activities = new SessionActivityCoordinator();
706
730
  /** Runtime-identity gate held while Pi may await abandoned-branch summarization. */
707
731
  this.treeNavigations = new WeakSet();
732
+ this.publishedSessionNames = new WeakMap();
733
+ /**
734
+ * Bare live leaf selected without an appended summary entry. Recording that
735
+ * leaf distinguishes the unpersisted move from a later runtime append that
736
+ * can anchor the selected branch on disk.
737
+ */
708
738
  this.unpersistedTreeBranchLeaves = new WeakMap();
709
739
  /** Counts async operations that may append an entry before they settle. */
710
740
  this.sessionEntryMutationCounts = new WeakMap();
711
741
  this.manualCompactionEnded = new WeakSet();
712
742
  this.extensionCommandExecution = new AsyncLocalStorage();
713
743
  this.runtimeMessageCounts = new WeakMap();
744
+ this.interventionStates = new WeakMap();
714
745
  this.snapshotMessageCounts = new WeakMap();
715
746
  this.pendingPromptEchoes = new WeakMap();
716
747
  this.publishedAssistantPartials = new WeakMap();
@@ -730,7 +761,6 @@ export class PiSessionService {
730
761
  this.subsessionStoppedParents = new WeakSet();
731
762
  this.subsessionDeliveringParents = new WeakSet();
732
763
  this.subsessionDeliveryScheduled = new WeakSet();
733
- this.deferredGeneratedSessionNames = new WeakMap();
734
764
  this.compactionPromptQueues = new Map();
735
765
  this.compactionDrainTimers = new Map();
736
766
  this.authLossWarnings = new Set();
@@ -760,6 +790,7 @@ export class PiSessionService {
760
790
  this.mcpAuthOwners = new WeakMap();
761
791
  this.notificationGenerationBySession = new WeakMap();
762
792
  this.idleSessionFileResolutions = new WeakMap();
793
+ this.unreadEligibilityRevision = 0;
763
794
  /** The parked extension Promise resolvers behind the store's open dialogs. */
764
795
  this.dialogWaiters = new ExtensionDialogWaiters();
765
796
  this.pendingUnreadMutations = [];
@@ -768,7 +799,7 @@ export class PiSessionService {
768
799
  this.t = deps.translator ?? loadNodeTranslator("server");
769
800
  this.managementAllowPrivileged = deps.managementAllowPrivileged === true;
770
801
  this.archiveStore = deps.archiveStore ?? new SessionArchiveStore();
771
- this.pinStore = deps.pinStore ?? new SessionPinStore(join(deps.dataDir ?? piWebDataDir(), "session-pins.json"));
802
+ this.sessionPins = deps.sessionPins;
772
803
  this.agentDir = deps.agentDir ?? getAgentDir();
773
804
  this.dataDir = deps.dataDir ?? piWebDataDir();
774
805
  this.projectPathForCwd = deps.projectPathForCwd;
@@ -789,6 +820,7 @@ export class PiSessionService {
789
820
  ? resolveDefaultModelRuntime
790
821
  : () => Promise.resolve(managementModelRuntime);
791
822
  this.spawnTargets = deps.spawnTargets;
823
+ this.messageTargets = deps.sessionMessagesEnabled === false ? undefined : deps.messageTargets ?? deps.spawnTargets;
792
824
  this.logger = deps.logger ?? noopLogger;
793
825
  this.normalToolAudit = deps.normalToolAudit;
794
826
  this.managementAudit = deps.managementAudit;
@@ -813,20 +845,24 @@ export class PiSessionService {
813
845
  this.sessionEvents = deps.sessionEvents ?? new PiSessionEventConnections();
814
846
  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 : {
815
847
  spawn: (input) => this.spawnSubsession(input),
848
+ archive: (parentSessionId, sessionId, parentSessionFile, context) => this.archiveSubsession(parentSessionId, sessionId, parentSessionFile, context),
849
+ stop: (parentSessionId, sessionId, parentSessionFile, context) => this.stopSubsession(parentSessionId, sessionId, parentSessionFile, context),
850
+ resume: (parentSessionId, sessionId, prompt, parentSessionFile, context) => this.resumeSubsession(parentSessionId, sessionId, prompt, parentSessionFile, context),
816
851
  list: (parentSessionId, parentSessionFile, managementContext) => this.listSubsessions(parentSessionId, parentSessionFile, managementContext),
817
852
  join: (parentSessionId, parentSessionFile, toolCallId, managementContext) => this.joinSubsessions(parentSessionId, parentSessionFile, toolCallId, managementContext),
818
853
  prepare: (parentSessionId, parentSessionFile, managementContext) => this.prepareSubsessionDelivery(parentSessionId, parentSessionFile, managementContext),
819
854
  check: (parentSessionId, sessionId, parentSessionFile, toolCallId, managementContext) => this.checkSubsession(parentSessionId, sessionId, parentSessionFile, toolCallId, managementContext),
820
855
  read: (parentSessionId, sessionId, query, parentSessionFile, toolCallId, managementContext) => this.readSubsession(parentSessionId, sessionId, query, parentSessionFile, toolCallId, managementContext),
821
- }, deps.askUserEnabled === true, deps.workbench, this.logger, this.managementAudit, this.managementProjectIdForCwd, deps.appendSystemPromptSections ?? [], deps.managementAllowPrivileged === true);
856
+ }, 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) });
822
857
  this.createAgentRuntime = deps.createAgentRuntime ?? defaultCreateAgentRuntime;
823
858
  this.workspaceActivity = deps.workspaceActivity;
824
859
  this.heartbeat = setInterval(() => { this.publishHeartbeats(); }, deps.heartbeatIntervalMs ?? 2000);
825
860
  this.commandService = new SessionCommandService((sessionId, eventScope) => this.getActiveForCommand(sessionId, eventScope), (sessionId, text, eventScope) => this.submitCommandPrompt(sessionId, text, eventScope), events, {
861
+ onSessionNameChanged: (session) => { this.publishSessionName(session); },
826
862
  onCompactionStart: (session) => {
827
863
  this.beginSessionEntryMutation(session, this.t("session.action.compact", "compact the session"));
828
864
  this.manualCompactionEnded.delete(session);
829
- this.publishActivity(session, this.t("activity.compacting", "Compacting context"), "active");
865
+ this.publishActivity(session, { kind: "compacting" }, "active");
830
866
  this.publishStatus(session);
831
867
  },
832
868
  onCompactionEnd: (session, result, detail) => {
@@ -866,43 +902,25 @@ export class PiSessionService {
866
902
  return previewResponseFromPlan(await this.cleanupPlan(request));
867
903
  }
868
904
  async cleanup(request, context) {
869
- const scope = eventScopeFromManagementContext(context);
870
905
  const plan = await this.cleanupPlan(request);
871
906
  if (plan.deleteRecords.length > 0 && this.archiveStore.deleteArchived === undefined && this.archiveStore.deleteArchivedMany === undefined)
872
907
  throw new Error(this.t("session.archiveDeleteUnsupported", "The archive store does not support deletion"));
873
- const archiveInputs = [];
874
- const readyArchiveInputs = [];
875
- const deleteRecords = [];
876
- const readyDeleteRecords = [];
877
- const skippedBusySessionIds = new Set(plan.skippedBusySessionIds);
878
- for (const input of plan.archiveInputs) {
879
- if (this.activeSessionHasWork(input.sessionId)) {
880
- skippedBusySessionIds.add(input.sessionId);
881
- continue;
882
- }
883
- await this.closeActive(input.sessionId, { kind: "clear", reason: "archive" }, scope);
884
- readyArchiveInputs.push(input);
885
- }
886
- await this.archiveStoreArchiveMany(readyArchiveInputs);
887
- archiveInputs.push(...readyArchiveInputs);
888
- await this.forgetUnreadSessions(readyArchiveInputs, scope);
889
- for (const record of plan.deleteRecords) {
890
- if (this.activeSessionHasWork(record.sessionId)) {
891
- skippedBusySessionIds.add(record.sessionId);
892
- continue;
893
- }
894
- await this.closeActive(record.sessionId, { kind: "clear", reason: "delete" }, scope);
895
- readyDeleteRecords.push(record);
896
- }
897
- const deletedSessionIds = new Set(await this.archiveStoreDeleteArchivedMany(readyDeleteRecords.map((record) => record.sessionId)));
898
- deleteRecords.push(...readyDeleteRecords.filter((record) => deletedSessionIds.has(record.sessionId)));
899
- await this.forgetUnreadSessions(deleteRecords, scope);
908
+ const archived = await this.executeArchiveBatch(plan.archiveInputs, context);
909
+ if (archived.failures.length > 0)
910
+ throw new Error(archived.failures.map((failure) => `${failure.sessionId}: ${failure.error}`).join("; "));
911
+ const deleted = await this.executeDeleteArchivedBatch(plan.deleteRecords, context);
912
+ if (deleted.failures.length > 0)
913
+ throw new Error(deleted.failures.map((failure) => `${failure.sessionId}: ${failure.error}`).join("; "));
914
+ const archiveInputs = archived.successes;
915
+ const deleteRecords = deleted.successes;
916
+ const skippedBusySessionIds = new Set([...plan.skippedBusySessionIds, ...archived.skippedBusySessionIds, ...deleted.skippedBusySessionIds]);
900
917
  return summarizeSessionCleanupExecution({
901
918
  archiveInputs,
902
919
  deleteRecords,
903
920
  thresholds: plan.thresholds,
904
921
  generatedAt: plan.generatedAt,
905
922
  skippedBusySessionIds: [...skippedBusySessionIds],
923
+ ...(plan.skippedPinnedSessionIds === undefined ? {} : { skippedPinnedSessionIds: plan.skippedPinnedSessionIds }),
906
924
  });
907
925
  }
908
926
  async dispose() {
@@ -956,6 +974,18 @@ export class PiSessionService {
956
974
  });
957
975
  await this.publishUnreadMutations([]);
958
976
  }
977
+ /** Recover cold-session intervention flags without opening agent runtimes. */
978
+ async restoreInterventionState() {
979
+ const [sessions, archives] = await Promise.all([this.sessionManager.listAll(), this.archiveStore.list()]);
980
+ const archived = new Set(archives.map((record) => record.sessionId));
981
+ for (const session of sessions) {
982
+ if (!await normalSessionReadAllowed(session.cwd, this.projectPathForCwd, this.managementProjectRoot))
983
+ continue;
984
+ if (archived.has(session.id) || this.activeForLookup({ id: session.id, cwd: session.cwd }) !== undefined)
985
+ continue;
986
+ this.workspaceActivity?.applySessionIntervention(session.cwd, session.id, session.interventionRequired === true);
987
+ }
988
+ }
959
989
  async list(cwd, managementContext) {
960
990
  return (await this.listWorkspaceSessions(cwd, managementContext)).sessions;
961
991
  }
@@ -971,37 +1001,30 @@ export class PiSessionService {
971
1001
  if (normalizedQuery === "")
972
1002
  return { results: [], matchCount: 0, truncated: false };
973
1003
  const maxMatches = 200;
974
- const { listing, sessions } = await this.searchCandidates(cwd, normalizedQuery.toLocaleLowerCase(), managementContext);
975
- const results = [];
1004
+ const listing = await this.listWorkspaceSessions(cwd, managementContext);
1005
+ const matchText = compileSessionContentQuery(normalizedQuery);
1006
+ const candidates = [];
976
1007
  let matchCount = 0;
977
- for (const session of sessions) {
978
- const remaining = maxMatches - results.reduce((count, result) => count + result.matches.length, 0);
979
- const messages = this.searchableSessionHistory(session, listing, managementContext);
980
- const view = searchSessionContent(messages, normalizedQuery, Math.max(1, remaining));
1008
+ for (const session of listing.sessions) {
1009
+ const messages = await this.searchableSessionHistory(session, listing, managementContext);
1010
+ const view = searchSessionContent(messages, matchText, maxMatches);
981
1011
  matchCount += view.matchCount;
982
- if (remaining > 0 && view.matches.length > 0)
983
- results.push({ session, matches: view.matches.slice(0, remaining) });
1012
+ candidates.push(...view.matches.map((match) => ({ session, match })));
1013
+ candidates.sort((left, right) => left.match.rank - right.match.rank);
1014
+ candidates.length = Math.min(candidates.length, maxMatches);
1015
+ }
1016
+ const grouped = new Map();
1017
+ for (const { session, match } of candidates) {
1018
+ let result = grouped.get(session.id);
1019
+ if (result === undefined) {
1020
+ result = { session, matches: [] };
1021
+ grouped.set(session.id, result);
1022
+ }
1023
+ result.matches.push({ messageIndex: match.messageIndex, role: match.role, excerpts: match.excerpts, occurrenceCount: match.occurrenceCount });
984
1024
  }
1025
+ const results = [...grouped.values()];
985
1026
  return { results, matchCount, truncated: matchCount > maxMatches };
986
1027
  }
987
- async listPinned(cwd, managementContext) {
988
- const listing = await this.listWorkspaceSessions(cwd, managementContext);
989
- const scope = sessionPinScope(cwd, managementContext);
990
- const sessionIds = await this.pinStore.prune(scope, new Set(listing.sessions.map((session) => session.id)));
991
- return { sessionIds };
992
- }
993
- async setPinned(ref, pinned, managementContext) {
994
- if (ref.cwd === "")
995
- throw new Error(this.t("session.pinWorkspaceRequired", "A workspace is required to pin a session"));
996
- const sessions = await this.list(ref.cwd, managementContext);
997
- const session = sessions.find((candidate) => candidate.id === ref.id);
998
- if (session === undefined)
999
- throw new Error(this.t("session.notFound", "Session not found"));
1000
- if (session.archived !== true && session.persisted === false)
1001
- throw new Error(this.t("session.pinPersistedOnly", "Only persisted sessions can be pinned"));
1002
- await this.pinStore.set(sessionPinScope(ref.cwd, managementContext), session.id, pinned);
1003
- return { pinned };
1004
- }
1005
1028
  async listWorkspaceSessions(cwd, managementContext) {
1006
1029
  if (managementContext === undefined)
1007
1030
  await this.normalModelRuntimeForCwd(cwd);
@@ -1025,11 +1048,17 @@ export class PiSessionService {
1025
1048
  const listed = unarchivedById.get(session.sessionId);
1026
1049
  const tracked = this.subsessionLinkForActiveChild(session) !== undefined;
1027
1050
  if (listed !== undefined) {
1028
- if (tracked && session.sessionFile !== undefined && sessionPathsEqual(listed.path, session.sessionFile))
1029
- listed.agentSubsession = true;
1051
+ // Match the file too: a clone with the same id must not inherit a
1052
+ // live runtime's classification. Disk rows otherwise use the scanner.
1053
+ if (session.sessionFile !== undefined && sessionPathsEqual(listed.path, session.sessionFile)) {
1054
+ if (tracked)
1055
+ listed.agentSubsession = true;
1056
+ listed.interventionRequired = this.statusFromSession(session).interventionRequired === true;
1057
+ }
1030
1058
  continue;
1031
1059
  }
1032
1060
  const info = clientSessionFromActiveSession(session);
1061
+ info.interventionRequired = this.statusFromSession(session).interventionRequired === true;
1033
1062
  if (tracked)
1034
1063
  info.agentSubsession = true;
1035
1064
  unarchivedById.set(session.sessionId, info);
@@ -1040,6 +1069,10 @@ export class PiSessionService {
1040
1069
  if (managementContext === undefined) {
1041
1070
  await this.publishUnreadMutations(this.unreadForScope(eventScopeFromManagementContext(managementContext)).reconcileCwd(canonicalizeStoredCwd(cwd), reconcilableSessionIds));
1042
1071
  }
1072
+ for (const session of unarchivedSessions) {
1073
+ if (this.activeForLookup({ id: session.id, cwd }, managementContext) === undefined)
1074
+ this.workspaceActivity?.applySessionIntervention(cwd, session.id, session.interventionRequired === true, eventScopeFromManagementContext(managementContext));
1075
+ }
1043
1076
  const archivedSessions = archivedForCwd
1044
1077
  .map((record) => clientSessionFromArchivedRecord(record, sessionsById.get(record.sessionId)))
1045
1078
  .filter(isDefined)
@@ -1074,18 +1107,41 @@ export class PiSessionService {
1074
1107
  continue;
1075
1108
  const row = rows.get(session.sessionId);
1076
1109
  // A disk clone with the same id must not inherit another file's runtime.
1077
- if (row !== undefined && (session.sessionFile === undefined || !sessionPathsEqual(row.path, session.sessionFile)))
1110
+ if (row !== undefined && (row.path === undefined || session.sessionFile === undefined || !sessionPathsEqual(row.path, session.sessionFile)))
1078
1111
  continue;
1079
1112
  runtimes.set(session.sessionId, session);
1080
- rows.set(session.sessionId, clientSessionFromActiveSession(session));
1113
+ const headerCreated = session.sessionManager.getHeader?.()?.timestamp;
1114
+ const metadata = readSessionUiMetadata(session.sessionManager.getEntries?.() ?? session.sessionManager.getBranch());
1115
+ const created = row?.created ?? (headerCreated !== undefined && Number.isFinite(Date.parse(headerCreated)) ? new Date(headerCreated).toISOString() : undefined);
1116
+ // Scanner dates match native cleanup eligibility. A hosted-only runtime's
1117
+ // header records creation, not its most recent activity.
1118
+ rows.set(session.sessionId, {
1119
+ id: session.sessionId,
1120
+ cwd: session.sessionManager.getCwd(),
1121
+ ...(session.sessionName === undefined ? {} : { name: session.sessionName }),
1122
+ ...(metadata === undefined ? {} : { metadata }),
1123
+ ...(created === undefined ? {} : { created }),
1124
+ ...(row?.modified === undefined ? {} : { modified: row.modified }),
1125
+ });
1081
1126
  }
1082
1127
  const entriesById = new Map(entries.map((entry) => [entry.id, entry]));
1083
1128
  for (const record of archived) {
1084
- const row = clientSessionFromArchivedRecord(record, entriesById.get(record.sessionId));
1085
- if (row !== undefined)
1086
- rows.set(row.id, row);
1129
+ const entry = entriesById.get(record.sessionId);
1130
+ const created = record.created ?? entry?.created.toISOString();
1131
+ const modified = record.modified ?? entry?.modified.toISOString();
1132
+ // Legacy records may lack transcript/path fields required by the client
1133
+ // list helper; their archive identity and known dates are still usable.
1134
+ const row = clientSessionFromArchivedRecord(record, entry) ?? {
1135
+ id: record.sessionId,
1136
+ cwd: record.cwd,
1137
+ ...(created === undefined ? {} : { created }),
1138
+ ...(modified === undefined ? {} : { modified }),
1139
+ archived: true,
1140
+ archivedAt: record.archivedAt,
1141
+ };
1142
+ rows.set(row.id, row);
1087
1143
  }
1088
- return [...rows.values()].sort((a, b) => Date.parse(b.modified) - Date.parse(a.modified)).map((row) => {
1144
+ return [...rows.values()].sort((a, b) => (b.modified === undefined ? 0 : Date.parse(b.modified)) - (a.modified === undefined ? 0 : Date.parse(a.modified))).map((row) => {
1089
1145
  const runtime = runtimes.get(row.id);
1090
1146
  return Object.freeze({
1091
1147
  id: row.id,
@@ -1093,6 +1149,9 @@ export class PiSessionService {
1093
1149
  ...(row.name === undefined ? {} : { name: row.name }),
1094
1150
  ...(row.metadata === undefined ? {} : { metadata: structuredClone(row.metadata) }),
1095
1151
  archived: row.archived === true,
1152
+ created: row.created ?? null,
1153
+ modified: row.modified ?? null,
1154
+ archivedAt: row.archived === true ? row.archivedAt ?? null : null,
1096
1155
  runtime: runtime === undefined ? "not-hosted" : this.hasActiveWork(runtime) ? "busy" : "idle",
1097
1156
  });
1098
1157
  });
@@ -1108,24 +1167,56 @@ export class PiSessionService {
1108
1167
  return Object.freeze({ id: created.id });
1109
1168
  }
1110
1169
  /** Atomically start and prompt one visible normal-mode, non-delegating session. */
1111
- async startOneShotRun(cwd, text, signal) {
1170
+ async startOneShotRun(cwd, text, signal, options = {}) {
1112
1171
  const promptText = requirePromptText(text, this.t);
1113
- return this.startManagedSession(cwd, signal, promptText);
1172
+ return this.startManagedSession(cwd, signal, promptText, options);
1114
1173
  }
1115
- async startManagedSession(cwd, signal, promptText) {
1174
+ async startManagedSession(cwd, signal, promptText, options = {}) {
1116
1175
  signal.throwIfAborted();
1117
- await this.normalModelRuntimeForCwd(cwd);
1118
- const active = await this.create(this.sessionManager.create(cwd), cwd, { startupIntent: "create", creationProvenance: "host-one-shot", startupSignal: signal });
1176
+ const modelRuntime = await this.normalModelRuntimeForCwd(cwd);
1177
+ let initialModel;
1178
+ if (options.model !== undefined) {
1179
+ await modelRuntime.refresh({ allowNetwork: false });
1180
+ signal.throwIfAborted();
1181
+ // Catalog membership alone does not mean the provider still has credentials
1182
+ // or is configured. Host overrides must be available after the refresh.
1183
+ initialModel = modelRuntime.getAvailableSnapshot().find((model) => modelScopeId(model) === options.model);
1184
+ if (initialModel === undefined) {
1185
+ throw Object.assign(new Error(`Model unavailable: ${options.model}`), { code: "PI_SESSION_MODEL_UNAVAILABLE" });
1186
+ }
1187
+ }
1188
+ const active = await this.create(this.sessionManager.create(cwd), cwd, {
1189
+ startupIntent: "create", creationProvenance: "host-one-shot", startupSignal: signal,
1190
+ ...(initialModel === undefined ? {} : { initialModel }),
1191
+ });
1119
1192
  const { session } = active.runtime;
1120
1193
  try {
1121
1194
  signal.throwIfAborted();
1122
- if (promptText !== undefined)
1123
- this.maybeGenerateSessionName(session, promptText);
1195
+ // Startup extensions may change the model. Never submit with a fallback
1196
+ // when the caller requested an exact model.
1197
+ if (options.model !== undefined && (session.model === undefined || modelScopeId(session.model) !== options.model)) {
1198
+ throw Object.assign(new Error(`Requested model is not active: ${options.model}`), { code: "PI_SESSION_MODEL_UNAVAILABLE" });
1199
+ }
1200
+ if (options.thinkingLevel !== undefined) {
1201
+ // Do not pass requested thinking into startup: the SDK can silently
1202
+ // clamp it before we have the actual model's supported levels.
1203
+ if (!session.getAvailableThinkingLevels().includes(options.thinkingLevel)) {
1204
+ throw Object.assign(new Error(`Thinking level unavailable: ${options.thinkingLevel}`), { code: "PI_SESSION_THINKING_UNAVAILABLE" });
1205
+ }
1206
+ session.setThinkingLevel(options.thinkingLevel);
1207
+ if (session.thinkingLevel !== options.thinkingLevel) {
1208
+ throw Object.assign(new Error(`Thinking level was not applied: ${options.thinkingLevel}`), { code: "PI_SESSION_THINKING_UNAVAILABLE" });
1209
+ }
1210
+ }
1211
+ const settings = {
1212
+ ...(session.model === undefined ? {} : { model: modelScopeId(session.model) }),
1213
+ thinkingLevel: session.thinkingLevel,
1214
+ };
1124
1215
  const created = this.announceCreatedSession(active, cwd);
1125
1216
  // Publication transfers lifetime ownership to normal hosting. Plugin
1126
1217
  // cancellation after this point must not abort this or later user work.
1127
1218
  const completion = promptText === undefined ? Promise.resolve() : this.submitInitialRunPrompt(session, promptText);
1128
- return Object.freeze({ id: created.id, completion });
1219
+ return Object.freeze({ id: created.id, completion, ...settings });
1129
1220
  }
1130
1221
  catch (error) {
1131
1222
  try {
@@ -1518,6 +1609,96 @@ export class PiSessionService {
1518
1609
  ...(outcome.answer === undefined ? {} : { answer: outcome.answer }),
1519
1610
  }, this.eventScopeForSession(session));
1520
1611
  }
1612
+ /** Interrupt a direct child's current run without closing its conversation. */
1613
+ async stopSubsession(parentSessionId, sessionId, parentSessionFile, managementContext) {
1614
+ const child = await this.openSubsession(parentSessionId, sessionId, parentSessionFile, managementContext);
1615
+ const cwd = child.sessionManager.getCwd();
1616
+ await this.abort({ id: sessionId, cwd }, managementContext);
1617
+ return { sessionId, cwd, status: this.subsessionStatus(child) };
1618
+ }
1619
+ /** Start another run in a direct child's conversation, without prompt expansion. */
1620
+ async resumeSubsession(parentSessionId, sessionId, prompt, parentSessionFile, managementContext) {
1621
+ const child = await this.openSubsession(parentSessionId, sessionId, parentSessionFile, managementContext);
1622
+ const cwd = child.sessionManager.getCwd();
1623
+ await this.assertWritable({ id: sessionId, cwd }, managementContext);
1624
+ this.assertTreeNavigationInactive(child, "resume a subsession");
1625
+ if (this.hasActiveWork(child))
1626
+ throw new Error("Subsession is already working");
1627
+ const text = requirePromptText(prompt ?? "Continue your previous task from the current conversation and workspace state. Check any interrupted work before repeating it.", this.t);
1628
+ void this.beginPromptSubmission(child, text, undefined, [], true, { expandPromptTemplates: false }).catch(() => undefined);
1629
+ return { sessionId, cwd, status: "working" };
1630
+ }
1631
+ /** Archive a direct child using the same idle-only operation as the browser. */
1632
+ async archiveSubsession(parentSessionId, sessionId, parentSessionFile, managementContext) {
1633
+ const child = await this.openSubsession(parentSessionId, sessionId, parentSessionFile, managementContext);
1634
+ await this.archive({ id: sessionId, cwd: child.sessionManager.getCwd() }, managementContext);
1635
+ }
1636
+ /** Send content, not control authority, to a named session in the same project. */
1637
+ async sendSessionMessage(input, managementContext) {
1638
+ if (this.messageTargets === undefined)
1639
+ throw new Error("Session messaging is unavailable");
1640
+ const message = requirePromptText(input.message, this.t);
1641
+ if (managementContext === undefined)
1642
+ await this.assertNormalSessionReadAccess(input.sendingCwd);
1643
+ else
1644
+ await this.getActive({ id: input.sendingSessionId, cwd: input.sendingCwd }, managementContext);
1645
+ const active = this.activeForLookup(input.sessionId, managementContext);
1646
+ const target = active === undefined
1647
+ ? (await this.sessionManager.listAll()).find((entry) => entry.id === input.sessionId)
1648
+ : { id: input.sessionId, cwd: active.runtime.cwd };
1649
+ if (target === undefined)
1650
+ throw new Error("Session not found");
1651
+ if (active === undefined && this.activeSessionsForId(input.sessionId).some((entry) => cwdPathsEqual(entry.runtime.cwd, target.cwd)))
1652
+ throw new Error("Session not found");
1653
+ const decision = await this.messageTargets.resolveSpawnTarget(input.sendingCwd, target.cwd, eventScopeFromManagementContext(managementContext));
1654
+ if (!decision.allowed)
1655
+ throw new Error("Session messaging is limited to sessions in the same registered project");
1656
+ if (managementContext === undefined)
1657
+ await this.assertNormalSessionReadAccess(decision.cwd);
1658
+ else {
1659
+ if (this.managementProjectRoot === undefined)
1660
+ throw new Error("Managed session messaging requires a project root");
1661
+ await assertManagedCwd(this.managementProjectRoot, managementContext, decision.cwd, { create: false });
1662
+ }
1663
+ const ref = { id: input.sessionId, cwd: decision.cwd };
1664
+ await this.assertWritable(ref, managementContext);
1665
+ const session = await this.getOrOpen(ref, managementContext);
1666
+ this.assertTreeNavigationInactive(session, "receive a session message");
1667
+ const delivery = this.hasActiveWork(session) ? "queued" : "started";
1668
+ let agentStarted = false;
1669
+ const unsubscribe = session.subscribe((event) => {
1670
+ if (getString(event, "type") === "agent_start")
1671
+ agentStarted = true;
1672
+ });
1673
+ // A custom-message turn may run for minutes. Never wait for its answer in
1674
+ // the sender: reciprocal messages must not deadlock their tool calls.
1675
+ void this.runSessionEntryMutation(session, "receive a session message", async () => {
1676
+ if (session.isCompacting || session.isBashRunning)
1677
+ await session.waitForIdle();
1678
+ if (!this.isCurrentActiveSession(session))
1679
+ throw new Error("Session was closed before message delivery");
1680
+ await session.sendCustomMessage({
1681
+ customType: "session.message",
1682
+ content: `Message from session ${input.sendingSessionId}:\n\n${message}`,
1683
+ display: true,
1684
+ details: { sendingSessionId: input.sendingSessionId },
1685
+ }, { triggerTurn: true, deliverAs: "steer" });
1686
+ }).catch((error) => {
1687
+ const detail = error instanceof Error ? error.message : String(error);
1688
+ this.logger.info({ sessionId: input.sessionId, sendingSessionId: input.sendingSessionId, error: detail }, "session message delivery failed");
1689
+ if (!this.isCurrentActiveSession(session))
1690
+ return;
1691
+ this.publishActivity(session, { kind: "error" }, "error", detail);
1692
+ const scope = this.eventScopeForSession(session);
1693
+ this.events.publish(session.sessionId, { type: "session.error", message: detail }, scope);
1694
+ if (!agentStarted && this.subsessionLinkForActiveChild(session) !== undefined)
1695
+ this.subsessionNotifyArmed.set(activeSessionKey(session.sessionId, scope), true);
1696
+ this.updateSubsessionTracking(session);
1697
+ this.publishStatus(session);
1698
+ }).finally(unsubscribe);
1699
+ this.logger.info({ sendingSessionId: input.sendingSessionId, sessionId: input.sessionId, delivery }, "session message accepted");
1700
+ return { sessionId: input.sessionId, delivery };
1701
+ }
1521
1702
  /** Summaries of the tracked subsessions spawned by `parentSessionId`. */
1522
1703
  async listSubsessions(parentSessionId, parentSessionFile, managementContext) {
1523
1704
  const parentFile = nonEmptyString(parentSessionFile);
@@ -2015,13 +2196,17 @@ export class PiSessionService {
2015
2196
  }));
2016
2197
  return { listing, sessions: matches.filter(isDefined) };
2017
2198
  }
2018
- searchableSessionHistory(session, listing, managementContext) {
2199
+ async searchableSessionHistory(session, listing, managementContext) {
2019
2200
  const eventScope = eventScopeFromManagementContext(managementContext);
2020
2201
  const active = this.activeForSessionIdAndScope(session.id, eventScope);
2021
2202
  if (active !== undefined && cwdPathsEqual(active.runtime.cwd, session.cwd))
2022
2203
  return historyMessages(active.runtime.session);
2023
2204
  const path = listing.archivedById.get(session.id)?.archivePath ?? listing.entriesById.get(session.id)?.path;
2024
- return path === undefined ? [] : historyMessagesFromManager(this.sessionManager.open(path));
2205
+ if (path === undefined)
2206
+ return [];
2207
+ if (this.sessionManager.readBranch !== undefined)
2208
+ return historyMessagesFromEntries(await this.sessionManager.readBranch(path) ?? []);
2209
+ return historyMessagesFromManager(this.sessionManager.open(path));
2025
2210
  }
2026
2211
  async streamSnapshot(ref, managementContext) {
2027
2212
  const session = await this.getOrOpen(ref, managementContext);
@@ -2159,7 +2344,7 @@ export class PiSessionService {
2159
2344
  if (model === undefined)
2160
2345
  throw new Error(this.t("model.notFound", "Model not found: {value0}/{value1}", { value0: provider, value1: modelId }));
2161
2346
  await this.runSessionEntryMutation(session, this.t("server.main.130226a572df", "change models"), () => session.setModel(model));
2162
- this.publishActivity(session, this.t("activity.model", "Model: {value0}", { value0: model.id }), "idle", model.provider);
2347
+ this.publishActivity(session, { kind: "model", value: model.id }, "idle", model.provider);
2163
2348
  this.publishStatus(session);
2164
2349
  return this.statusFromSession(session);
2165
2350
  }
@@ -2173,7 +2358,7 @@ export class PiSessionService {
2173
2358
  });
2174
2359
  if (result === undefined)
2175
2360
  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"));
2176
- this.publishActivity(session, this.t("activity.model", "Model: {value0}", { value0: result.model.id }), "idle", result.model.provider);
2361
+ this.publishActivity(session, { kind: "model", value: result.model.id }, "idle", result.model.provider);
2177
2362
  this.publishStatus(session);
2178
2363
  return this.statusFromSession(session);
2179
2364
  }
@@ -2195,7 +2380,7 @@ export class PiSessionService {
2195
2380
  session.setThinkingLevel(match);
2196
2381
  return Promise.resolve();
2197
2382
  });
2198
- this.publishActivity(session, this.t("activity.thinking", "Thinking level: {value0}", { value0: session.thinkingLevel }), "idle");
2383
+ this.publishActivity(session, { kind: "thinking", value: session.thinkingLevel }, "idle");
2199
2384
  this.publishStatus(session);
2200
2385
  return this.statusFromSession(session);
2201
2386
  }
@@ -2205,7 +2390,7 @@ export class PiSessionService {
2205
2390
  const level = await this.runSessionEntryMutation(session, this.t("session.action.changeThinking", "change the thinking level"), () => Promise.resolve(session.cycleThinkingLevel()));
2206
2391
  if (level === undefined)
2207
2392
  throw new Error(this.t("model.thinkingUnsupported", "The current model does not support thinking"));
2208
- this.publishActivity(session, this.t("ui.promptEditor.thinkingLevel", "Thinking level: {thinkingLevel}", { thinkingLevel: level }), "idle");
2393
+ this.publishActivity(session, { kind: "thinking", value: level }, "idle");
2209
2394
  this.publishStatus(session);
2210
2395
  return this.statusFromSession(session);
2211
2396
  }
@@ -2241,11 +2426,10 @@ export class PiSessionService {
2241
2426
  await this.assertWritable(ref, options?.managementContext);
2242
2427
  const session = await this.getOrOpen(ref, options?.managementContext);
2243
2428
  this.assertTreeNavigationInactive(session, this.t("server.main.94306b2fc35c", "send a prompt"));
2244
- this.maybeGenerateSessionName(session, promptText);
2245
2429
  const isQueued = session.isStreaming || session.isCompacting;
2246
2430
  const behavior = isQueued ? requestedBehavior ?? "followUp" : undefined;
2247
2431
  if (isQueued && images.length === 0 && this.hasQueuedMessageText(session, promptText)) {
2248
- this.publishActivity(session, this.t("activity.duplicateIgnored", "Duplicate queued message ignored"), "active");
2432
+ this.publishActivity(session, { kind: "duplicateQueuedMessage" }, "active");
2249
2433
  this.publishStatus(session);
2250
2434
  return;
2251
2435
  }
@@ -2267,7 +2451,7 @@ export class PiSessionService {
2267
2451
  beginPromptSubmission(session, text, behavior, images = [], echoUserMessage = true, options = {}) {
2268
2452
  if (options.auditUserPrompt !== false)
2269
2453
  this.auditUserPrompt(session, text);
2270
- 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");
2454
+ this.publishActivity(session, behavior === "steer" ? { kind: "steeringQueued" } : behavior === "followUp" ? { kind: "messageQueued" } : { kind: "promptAccepted" }, "active");
2271
2455
  const eventScope = this.eventScopeForSession(session);
2272
2456
  const echoes = this.pendingPromptEchoes.get(session) ?? [];
2273
2457
  const userCount = historyMessagesFromEntries(session.sessionManager.getBranch()).filter((message) => isRecord(message) && message["role"] === "user").length;
@@ -2308,7 +2492,7 @@ export class PiSessionService {
2308
2492
  void promptPromise.catch((error) => {
2309
2493
  this.subsessionStoppedParents.add(session);
2310
2494
  const message = error instanceof Error ? error.message : String(error);
2311
- this.publishActivity(session, this.t("activity.error", "An error occurred"), "error", message);
2495
+ this.publishActivity(session, { kind: "error" }, "error", message);
2312
2496
  this.events.publish(session.sessionId, { type: "session.error", message }, eventScope);
2313
2497
  if (this.isCurrentActiveSession(session)) {
2314
2498
  const link = this.subsessionLinkForActiveChild(session);
@@ -2372,7 +2556,7 @@ export class PiSessionService {
2372
2556
  const queue = this.compactionPromptQueues.get(sessionKey) ?? [];
2373
2557
  queue.push({ kind, text, ...(images.length > 0 ? { images } : {}), ...(echoUserMessage ? {} : { echoUserMessage: false }) });
2374
2558
  this.compactionPromptQueues.set(sessionKey, queue);
2375
- this.publishActivity(session, this.t("activity.compactionQueued", "Message queued during compaction"), "active");
2559
+ this.publishActivity(session, { kind: "queuedDuringCompaction" }, "active");
2376
2560
  this.publishStatus(session);
2377
2561
  }
2378
2562
  async saveAttachments(ref, attachments, folder, managementContext) {
@@ -2386,8 +2570,8 @@ export class PiSessionService {
2386
2570
  return saveAttachmentsToWorkspace(cwd, parsed, effectiveFolder === undefined ? {} : { folder: effectiveFolder });
2387
2571
  }
2388
2572
  async workspaceAttachmentsConfig(cwd) {
2389
- const globalConfig = this.config === undefined ? {} : (await this.config.read()).effectiveConfig;
2390
- return loadEffectiveProjectAttachmentsConfig(cwd, globalConfig);
2573
+ const response = this.config === undefined ? undefined : await this.config.read();
2574
+ return loadEffectiveProjectAttachmentsConfig(cwd, response?.effectiveConfig ?? {}, response?.enforcedSettings);
2391
2575
  }
2392
2576
  async shell(ref, text, managementContext) {
2393
2577
  await this.assertWritable(ref, managementContext);
@@ -2401,11 +2585,11 @@ export class PiSessionService {
2401
2585
  if (session.isBashRunning)
2402
2586
  throw new Error(this.t("shell.alreadyRunning", "A bash command is already running"));
2403
2587
  const eventScope = active.eventScope;
2404
- this.publishActivity(session, this.t("activity.commandRunning", "Running command"), "active", command);
2588
+ this.publishActivity(session, { kind: "runningBash" }, "active", command);
2405
2589
  this.events.publish(session.sessionId, { type: "shell.start", command, excludeFromContext: isExcluded }, eventScope);
2406
2590
  void this.runSessionEntryMutation(session, this.t("session.action.shell", "run a shell command"), () => session.executeBash(command, (chunk) => {
2407
2591
  this.events.publish(session.sessionId, { type: "shell.chunk", chunk }, eventScope);
2408
- this.publishActivity(session, this.t("activity.commandRunning", "Running command"), "active", command);
2592
+ this.publishActivity(session, { kind: "runningBash" }, "active", command);
2409
2593
  this.publishStatus(session);
2410
2594
  }, { excludeFromContext: isExcluded })).then((result) => {
2411
2595
  this.events.publish(session.sessionId, {
@@ -2416,13 +2600,13 @@ export class PiSessionService {
2416
2600
  truncated: result.truncated,
2417
2601
  ...(result.fullOutputPath === undefined ? {} : { fullOutputPath: result.fullOutputPath }),
2418
2602
  }, eventScope);
2419
- this.publishActivity(session, this.t("activity.commandCompleted", "Command completed"), result.exitCode === 0 ? "idle" : "error", command);
2603
+ this.publishActivity(session, { kind: "bashComplete" }, result.exitCode === 0 ? "idle" : "error", command);
2420
2604
  this.publishStatus(session);
2421
2605
  }).catch((error) => {
2422
2606
  const message = userFacingErrorMessage(error, this.t);
2423
2607
  this.events.publish(session.sessionId, { type: "shell.end", output: message, isError: true }, eventScope);
2424
2608
  this.events.publish(session.sessionId, { type: "session.error", message }, eventScope);
2425
- this.publishActivity(session, this.t("activity.commandFailed", "Command failed"), "error", message);
2609
+ this.publishActivity(session, { kind: "bashFailed" }, "error", message);
2426
2610
  this.publishStatus(session);
2427
2611
  });
2428
2612
  }
@@ -2469,7 +2653,7 @@ export class PiSessionService {
2469
2653
  if (retainCustomMessage && options.summarize === true)
2470
2654
  throw new Error(this.t("session.checkpointSummary", "Retaining a custom-message checkpoint requires navigation without a branch summary"));
2471
2655
  const activeEditableTargetParentId = retainCustomMessage ? undefined : activeEditableTreeTargetParentId(session.sessionManager, targetId, oldLeafId);
2472
- this.publishActivity(session, options.summarize === true ? this.t("activity.summarizing", "Summarizing branch") : this.t("activity.navigating", "Navigating session tree"), "active");
2656
+ this.publishActivity(session, options.summarize === true ? { kind: "summarizingBranch" } : { kind: "navigatingTree" }, "active");
2473
2657
  this.publishStatus(session);
2474
2658
  let result = retainCustomMessage
2475
2659
  ? await navigateTreeRetainingCustomMessage(session.sessionManager, targetId, checkpointTail["parentId"], () => navigateTree(targetId, options))
@@ -2490,7 +2674,7 @@ export class PiSessionService {
2490
2674
  }
2491
2675
  if (result.cancelled) {
2492
2676
  if (this.isCurrentActiveSession(session)) {
2493
- this.publishActivity(session, result.aborted === true ? this.t("activity.summaryAborted", "Branch summary aborted") : this.t("activity.navigationCancelled", "Session tree navigation cancelled"), "idle");
2677
+ this.publishActivity(session, result.aborted === true ? { kind: "branchSummaryAborted" } : { kind: "treeNavigationCancelled" }, "idle");
2494
2678
  }
2495
2679
  return { cancelled: true, ...(result.aborted === undefined ? {} : { aborted: result.aborted }) };
2496
2680
  }
@@ -2505,13 +2689,13 @@ export class PiSessionService {
2505
2689
  this.setSuggestedInput(session, result.editorText);
2506
2690
  this.events.publish(session.sessionId, { type: "session.tree.changed" }, this.eventScopeForSession(session));
2507
2691
  if (this.isCurrentActiveSession(session))
2508
- this.publishActivity(session, this.t("activity.navigated", "Session tree changed"), "idle");
2692
+ this.publishActivity(session, { kind: "treeNavigated" }, "idle");
2509
2693
  return { cancelled: false, ...(result.editorText === undefined ? {} : { editorText: result.editorText }) };
2510
2694
  }
2511
2695
  catch (error) {
2512
2696
  const message = userFacingErrorMessage(error, this.t);
2513
2697
  if (this.isCurrentActiveSession(session)) {
2514
- this.publishActivity(session, this.t("server.main.8cae209986b4", "tree navigation failed"), "error", message);
2698
+ this.publishActivity(session, { kind: "treeNavigationFailed" }, "error", message);
2515
2699
  this.events.publish(session.sessionId, { type: "session.error", message }, this.eventScopeForSession(session));
2516
2700
  }
2517
2701
  throw error;
@@ -2524,7 +2708,6 @@ export class PiSessionService {
2524
2708
  this.publishStatus(session);
2525
2709
  }
2526
2710
  else {
2527
- this.deferredGeneratedSessionNames.delete(session);
2528
2711
  this.subsessionInbox(session.sessionId, session.sessionFile, this.eventScopeForSession(session)).releaseClaims();
2529
2712
  }
2530
2713
  }
@@ -2551,7 +2734,7 @@ export class PiSessionService {
2551
2734
  const sourceSessionId = session.sessionId;
2552
2735
  const sourceEventScope = this.eventScopeForSession(session);
2553
2736
  const sourceCwd = session.sessionManager.getCwd();
2554
- this.publishActivity(session, this.t("server.main.4de911d3b72a", "forking session from entry"), "active");
2737
+ this.publishActivity(session, { kind: "forking" }, "active");
2555
2738
  this.publishStatus(session);
2556
2739
  try {
2557
2740
  const entryId = request.retainCheckpoint === true ? messageHistoryTargetId(session.sessionManager.getBranch(), request.entryId) : request.entryId;
@@ -2564,7 +2747,7 @@ export class PiSessionService {
2564
2747
  throw new Error(this.t("server.main.0246b6af6843", "Session fork is unavailable"));
2565
2748
  if (result.session === undefined) {
2566
2749
  if (this.isCurrentActiveSession(session)) {
2567
- this.publishActivity(session, this.t("server.main.1cceead5f414", "fork cancelled"), "idle");
2750
+ this.publishActivity(session, { kind: "forkCancelled" }, "idle");
2568
2751
  this.publishStatus(session);
2569
2752
  }
2570
2753
  return { cancelled: true };
@@ -2574,7 +2757,7 @@ export class PiSessionService {
2574
2757
  this.setSuggestedInput(forked, result.promptDraft);
2575
2758
  this.events.publish(sourceSessionId, { type: "session.tree.changed" }, sourceEventScope);
2576
2759
  if (forked !== undefined && this.isCurrentActiveSession(forked)) {
2577
- this.publishActivity(forked, this.t("command.forked", "Session forked"), "idle");
2760
+ this.publishActivity(forked, { kind: "forked" }, "idle");
2578
2761
  this.publishStatus(forked);
2579
2762
  }
2580
2763
  if (result.session.id !== sourceSessionId)
@@ -2588,7 +2771,7 @@ export class PiSessionService {
2588
2771
  catch (error) {
2589
2772
  const message = userFacingErrorMessage(error, this.t);
2590
2773
  if (this.isCurrentActiveSession(session)) {
2591
- this.publishActivity(session, this.t("server.main.08e8f3ea9eaa", "fork failed"), "error", message);
2774
+ this.publishActivity(session, { kind: "forkFailed" }, "error", message);
2592
2775
  this.events.publish(session.sessionId, { type: "session.error", message }, sourceEventScope);
2593
2776
  this.publishStatus(session);
2594
2777
  }
@@ -2599,7 +2782,7 @@ export class PiSessionService {
2599
2782
  const sessionKey = activeSessionKey(sessionId, eventScope);
2600
2783
  if (this.activities.get(sessionKey)?.phase === "active") {
2601
2784
  const at = new Date().toISOString();
2602
- const stored = { phase: "idle", label: this.t("activity.idle", "Idle"), at };
2785
+ const stored = { phase: "idle", label: "idle", at, runtimePresentation: { kind: "idle" } };
2603
2786
  this.activities.set(sessionKey, stored);
2604
2787
  const activity = { sessionId, ...stored };
2605
2788
  this.events.publish(sessionId, { type: "activity.update", activity }, eventScope);
@@ -2615,6 +2798,7 @@ export class PiSessionService {
2615
2798
  const archiveInput = await this.archiveInputForSession(session);
2616
2799
  await this.closeActiveSession(active);
2617
2800
  await this.archiveStore.archive(archiveInput);
2801
+ this.workspaceActivity?.removeSession(archiveInput.sessionId, archiveInput.cwd, active.eventScope);
2618
2802
  await this.forgetUnreadSessions([archiveInput], active.eventScope);
2619
2803
  });
2620
2804
  }
@@ -2658,43 +2842,10 @@ export class PiSessionService {
2658
2842
  failures.push({ sessionId: resolvedSessionId, error: errorMessage(error, this.t) });
2659
2843
  }
2660
2844
  }
2661
- const readyPlanItems = [];
2662
- for (const item of planItems) {
2663
- const active = item.active ?? this.activeForLookup(bulkRefToLookup({ id: item.input.sessionId, cwd: item.input.cwd }), managementContext);
2664
- if (active !== undefined && this.hasActiveWork(active.runtime.session)) {
2665
- failures.push({ sessionId: item.input.sessionId, error: this.t("session.stopBeforeArchive", "Stop current session activity before archiving") });
2666
- continue;
2667
- }
2668
- readyPlanItems.push(active === undefined ? item : { ...item, active });
2669
- }
2670
- const readyInputs = [];
2671
- const archivedSessionIds = [...alreadyArchivedSessionIds];
2672
- await this.runTreeExclusiveOperation(readyPlanItems.map(({ input, active }) => ({
2673
- sessionId: input.sessionId,
2674
- ...(active === undefined ? {} : { session: active.runtime.session, runtime: active.runtime }),
2675
- })), this.t("session.stopBeforeArchive", "Stop current session activity before archiving"), async () => {
2676
- for (const item of readyPlanItems) {
2677
- try {
2678
- if (item.active !== undefined)
2679
- await this.closeActiveSession(item.active);
2680
- else
2681
- await this.closeActiveInScope(item.input.sessionId, eventScopeFromManagementContext(managementContext));
2682
- readyInputs.push(item.input);
2683
- }
2684
- catch (error) {
2685
- failures.push({ sessionId: item.input.sessionId, error: errorMessage(error, this.t) });
2686
- }
2687
- }
2688
- try {
2689
- const archived = await this.archiveStoreArchiveMany(readyInputs);
2690
- archivedSessionIds.push(...archived.map((record) => record.sessionId));
2691
- unreadArchivedIdentities.push(...archived);
2692
- }
2693
- catch (error) {
2694
- for (const input of readyInputs)
2695
- failures.push({ sessionId: input.sessionId, error: errorMessage(error, this.t) });
2696
- }
2697
- });
2845
+ const execution = await this.executeArchiveBatch(planItems.map((item) => item.input), managementContext);
2846
+ failures.push(...execution.failures);
2847
+ failures.push(...execution.skippedBusySessionIds.map((sessionId) => ({ sessionId, error: this.t("session.stopBeforeArchive", "Stop current session activity before archiving") })));
2848
+ const archivedSessionIds = [...alreadyArchivedSessionIds, ...execution.successes.map((input) => input.sessionId)];
2698
2849
  await this.forgetUnreadSessions(unreadArchivedIdentities, eventScopeFromManagementContext(managementContext));
2699
2850
  return {
2700
2851
  archived: true,
@@ -2722,7 +2873,9 @@ export class PiSessionService {
2722
2873
  }
2723
2874
  for (const input of archiveInputs)
2724
2875
  await this.closeActiveInScope(input.sessionId, eventScopeFromManagementContext(managementContext));
2725
- await this.archiveStoreArchiveMany(archiveInputs);
2876
+ const archived = await this.archiveStoreArchiveMany(archiveInputs);
2877
+ for (const record of archived)
2878
+ this.workspaceActivity?.removeSession(record.sessionId, record.cwd, eventScopeFromManagementContext(managementContext));
2726
2879
  });
2727
2880
  await this.forgetUnreadSessions(plan.targets.map((target) => ({ sessionId: target.id, cwd: target.cwd })), eventScopeFromManagementContext(managementContext));
2728
2881
  return {
@@ -2735,10 +2888,15 @@ export class PiSessionService {
2735
2888
  async restore(ref, managementContext) {
2736
2889
  const archived = await this.getArchived(ref);
2737
2890
  if (archived === undefined)
2738
- throw new Error(this.t("session.notFound", "Session not found"));
2739
- await this.closeActiveInScope(archived.sessionId, eventScopeFromManagementContext(managementContext));
2740
- await this.archiveStore.restore(archived.sessionId);
2741
- await this.forgetUnreadSessions([archived], eventScopeFromManagementContext(managementContext));
2891
+ throw new Error("Session not found");
2892
+ const active = this.activeForLookup({ id: archived.sessionId, cwd: archived.cwd }, managementContext);
2893
+ await this.runTreeExclusiveOperation([{ sessionId: archived.sessionId, ...(active === undefined ? {} : { session: active.runtime.session, runtime: active.runtime }) }], "Stop current session activity before restoring archived session", async () => {
2894
+ await this.closeActiveInScope(archived.sessionId, eventScopeFromManagementContext(managementContext));
2895
+ await this.archiveStore.restore(archived.sessionId);
2896
+ const restored = (await this.sessionManager.list(archived.cwd)).find((entry) => entry.id === archived.sessionId);
2897
+ this.workspaceActivity?.applySessionIntervention(archived.cwd, archived.sessionId, restored?.interventionRequired === true, eventScopeFromManagementContext(managementContext));
2898
+ await this.forgetUnreadSessions([archived], eventScopeFromManagementContext(managementContext));
2899
+ });
2742
2900
  }
2743
2901
  async deleteArchived(ref, managementContext) {
2744
2902
  const record = await this.getArchived(ref);
@@ -2770,27 +2928,10 @@ export class PiSessionService {
2770
2928
  }
2771
2929
  planItems.push({ record });
2772
2930
  }
2773
- const readyRecords = [];
2774
- for (const item of planItems) {
2775
- try {
2776
- await this.closeActiveInScope(item.record.sessionId, eventScopeFromManagementContext(managementContext));
2777
- readyRecords.push(item.record);
2778
- }
2779
- catch (error) {
2780
- failures.push({ sessionId: item.record.sessionId, error: errorMessage(error, this.t) });
2781
- }
2782
- }
2783
- const deleteIds = readyRecords.map((record) => record.sessionId);
2784
- let deletedSessionIds = [];
2785
- try {
2786
- deletedSessionIds = await this.archiveStoreDeleteArchivedMany(deleteIds);
2787
- }
2788
- catch (error) {
2789
- for (const sessionId of deleteIds)
2790
- failures.push({ sessionId, error: errorMessage(error, this.t) });
2791
- }
2792
- const deletedIdSet = new Set(deletedSessionIds);
2793
- await this.forgetUnreadSessions(readyRecords.filter((record) => deletedIdSet.has(record.sessionId)), eventScopeFromManagementContext(managementContext));
2931
+ const execution = await this.executeDeleteArchivedBatch(planItems.map((item) => item.record), managementContext);
2932
+ failures.push(...execution.failures);
2933
+ failures.push(...execution.skippedBusySessionIds.map((sessionId) => ({ sessionId, error: this.t("session.stopBeforeDeleteArchive", "Stop current session activity before deleting archived session") })));
2934
+ const deletedSessionIds = execution.successes.map((record) => record.sessionId);
2794
2935
  return {
2795
2936
  deleted: true,
2796
2937
  deletedSessionIds,
@@ -2860,11 +3001,11 @@ export class PiSessionService {
2860
3001
  this.abortRunScopedExtensionDialogs(active.runtime.session);
2861
3002
  try {
2862
3003
  await this.abortSessionOperations(active.runtime.session);
2863
- this.publishActivity(active.runtime.session, this.t("activity.stopped", "Stopped"), "idle");
3004
+ this.publishActivity(active.runtime.session, { kind: "stopped" }, "idle");
2864
3005
  }
2865
3006
  catch (error) {
2866
3007
  const message = userFacingErrorMessage(error, this.t);
2867
- this.publishActivity(active.runtime.session, this.t("activity.stopFailed", "Stop failed"), "error", message);
3008
+ this.publishActivity(active.runtime.session, { kind: "stopFailed" }, "error", message);
2868
3009
  throw error;
2869
3010
  }
2870
3011
  finally {
@@ -3025,6 +3166,58 @@ export class PiSessionService {
3025
3166
  const entries = await Promise.all(uniqueCwds.map(async (cwd) => [cwd, await this.sessionManager.list(cwd)]));
3026
3167
  return new Map(entries);
3027
3168
  }
3169
+ executeArchiveBatch(inputs, context) {
3170
+ return this.executeSessionLifecycleBatch(inputs, "archive", async (ready) => (await this.archiveStoreArchiveMany(ready)).map((record) => record.sessionId), context);
3171
+ }
3172
+ executeDeleteArchivedBatch(records, context) {
3173
+ return this.executeSessionLifecycleBatch(records, "delete", (ready) => this.archiveStoreDeleteArchivedMany(ready.map((record) => record.sessionId)), context);
3174
+ }
3175
+ async executeSessionLifecycleBatch(items, reason, persist, context) {
3176
+ const scope = eventScopeFromManagementContext(context);
3177
+ const result = { successes: [], failures: [], skippedBusySessionIds: [] };
3178
+ const targets = [];
3179
+ const idleItems = [];
3180
+ // Check and reserve synchronously before any teardown can yield. Identity
3181
+ // reservations also protect unloaded sessions for the full persistence span.
3182
+ for (const item of items) {
3183
+ const active = this.activeForLookup({ id: item.sessionId, cwd: item.cwd }, context);
3184
+ if (this.isTreeExclusiveSessionIdentityActive(item.sessionId)
3185
+ || (active !== undefined && this.hasActiveWork(active.runtime.session))) {
3186
+ result.skippedBusySessionIds.push(item.sessionId);
3187
+ continue;
3188
+ }
3189
+ idleItems.push(item);
3190
+ targets.push({ sessionId: item.sessionId, ...(active === undefined ? {} : { session: active.runtime.session, runtime: active.runtime }) });
3191
+ }
3192
+ await this.runTreeExclusiveOperation(targets, "Stop current session activity before changing session lifecycle", async () => {
3193
+ const ready = [];
3194
+ for (const item of idleItems) {
3195
+ try {
3196
+ await this.closeActive(item.sessionId, { kind: "clear", reason }, scope);
3197
+ ready.push(item);
3198
+ }
3199
+ catch (error) {
3200
+ result.failures.push({ sessionId: item.sessionId, error: errorMessage(error) });
3201
+ }
3202
+ }
3203
+ try {
3204
+ const persistedIds = await persist(ready);
3205
+ const readyById = new Map(ready.map((item) => [item.sessionId, item]));
3206
+ result.successes = persistedIds.flatMap((sessionId) => {
3207
+ const item = readyById.get(sessionId);
3208
+ return item === undefined ? [] : [item];
3209
+ });
3210
+ }
3211
+ catch (error) {
3212
+ for (const item of ready)
3213
+ result.failures.push({ sessionId: item.sessionId, error: errorMessage(error) });
3214
+ }
3215
+ for (const item of result.successes)
3216
+ this.workspaceActivity?.removeSession(item.sessionId, item.cwd, scope);
3217
+ await this.forgetUnreadSessions(result.successes, scope);
3218
+ });
3219
+ return result;
3220
+ }
3028
3221
  async archiveStoreArchiveMany(inputs) {
3029
3222
  if (inputs.length === 0)
3030
3223
  return [];
@@ -3048,6 +3241,9 @@ export class PiSessionService {
3048
3241
  return [...sessionIds];
3049
3242
  }
3050
3243
  async cleanupPlan(request) {
3244
+ if (request.skipPinned === true && this.sessionPins === undefined)
3245
+ throw new Error("Authoritative session pin store is unavailable");
3246
+ const excludedPinnedSessionIds = request.skipPinned === true ? await this.sessionPins?.pinnedSessionIds() : undefined;
3051
3247
  const [sessions, archivedRecords, scopedSessions] = await Promise.all([
3052
3248
  this.sessionManager.listAll(),
3053
3249
  this.archiveStore.list(),
@@ -3060,6 +3256,7 @@ export class PiSessionService {
3060
3256
  archivedRecords,
3061
3257
  activeSessions: this.cleanupActiveSessionStatuses(),
3062
3258
  thresholds: request.thresholds,
3259
+ ...(excludedPinnedSessionIds === undefined ? {} : { excludedPinnedSessionIds }),
3063
3260
  ...(request.projectCwds === undefined ? {} : { projectCwds: request.projectCwds }),
3064
3261
  now: this.now(),
3065
3262
  });
@@ -3191,6 +3388,10 @@ export class PiSessionService {
3191
3388
  this.events.mediaIndex.forgetSession({ id: sessionId, cwd: active.runtime.session.sessionManager.getCwd(), eventScope: active.eventScope });
3192
3389
  this.activities.delete(activeSessionKey(sessionId, active.eventScope));
3193
3390
  this.workspaceActivity?.removeSession(sessionId, active.runtime.session.sessionManager.getCwd(), active.eventScope);
3391
+ const session = active.runtime.session;
3392
+ if (sessionFileExists(session.sessionFile) && this.interventionRequired(session)) {
3393
+ this.workspaceActivity?.applySessionIntervention(session.sessionManager.getCwd(), sessionId, true, active.eventScope);
3394
+ }
3194
3395
  this.clearAuthLossWarningsForSession(sessionId);
3195
3396
  this.clearCompactionPromptQueue(active.runtime.session);
3196
3397
  // Disarm subsession notification before teardown so the abort below cannot
@@ -3445,7 +3646,7 @@ export class PiSessionService {
3445
3646
  operation.error(message);
3446
3647
  return;
3447
3648
  }
3448
- this.publishActivity(session, this.t("activity.extensionError", "Extension error"), "error", message);
3649
+ this.publishActivity(session, { kind: "extensionError" }, "error", message);
3449
3650
  this.events.publish(session.sessionId, { type: "session.error", message }, owner.eventScope);
3450
3651
  },
3451
3652
  });
@@ -3501,7 +3702,7 @@ export class PiSessionService {
3501
3702
  if (current !== undefined && this.isCurrentActiveSession(current)) {
3502
3703
  const message = userFacingErrorMessage(error, this.t);
3503
3704
  current.extensionRunner.getUIContext().notify(message, "error");
3504
- this.publishActivity(current, "extension callback failed", "error", message);
3705
+ this.publishActivity(current, { kind: "extensionCallbackFailed" }, "error", message);
3505
3706
  this.events.publish(current.sessionId, { type: "session.error", message }, this.eventScopeForSession(current));
3506
3707
  }
3507
3708
  throw error;
@@ -3554,12 +3755,17 @@ export class PiSessionService {
3554
3755
  }
3555
3756
  this.reconcileRuntimeMessageCount(session);
3556
3757
  this.restoreSubsessionReceipts(session);
3758
+ this.interventionStates.set(session, sessionInterventionRequired(session.sessionManager.getEntries?.() ?? session.sessionManager.getBranch()));
3759
+ this.publishedSessionNames.set(session, { sessionId: session.sessionId, name: session.sessionName });
3557
3760
  const unsubscribe = session.subscribe((event) => {
3558
3761
  const eventType = getString(event, "type");
3762
+ if (eventType === "session_info_changed")
3763
+ this.publishSessionName(session);
3559
3764
  const message = getProperty(event, "message");
3560
3765
  const entry = getProperty(event, "entry");
3561
3766
  const inbox = this.subsessionInbox(session.sessionId, session.sessionFile, active.eventScope);
3562
3767
  if (eventType === "agent_start") {
3768
+ this.setInterventionRequired(session, false);
3563
3769
  this.restoreSubsessionReceipts(session, false);
3564
3770
  this.subsessionStoppedParents.delete(session);
3565
3771
  }
@@ -3574,6 +3780,8 @@ export class PiSessionService {
3574
3780
  if (eventType === "agent_settled")
3575
3781
  this.scheduleSubsessionDelivery(session);
3576
3782
  const role = getString(message, "role");
3783
+ if (eventType === "message_end" && requestsHumanIntervention(message))
3784
+ this.setInterventionRequired(session, true);
3577
3785
  if ((eventType === "message_end" && (role === "user" || role === "assistant" || role === "toolResult" || role === "system"))
3578
3786
  || (eventType === "entry_appended" && getString(entry, "type") === "message")) {
3579
3787
  this.runtimeMessageCounts.set(session, this.runtimeMessageCount(session) + 1);
@@ -3630,18 +3838,21 @@ export class PiSessionService {
3630
3838
  const aborted = getBoolean(event, "aborted") === true;
3631
3839
  const errorMessage = getString(event, "errorMessage");
3632
3840
  const automatic = getString(event, "reason") !== "manual";
3633
- const message = aborted
3634
- ? (automatic ? this.t("session.compaction.autoCancelled", "Automatic compaction cancelled.") : this.t("session.compaction.cancelled", "Compaction cancelled."))
3635
- : errorMessage === undefined ? undefined : this.t("session.compaction.failed", "Could not compact history. Try again.");
3841
+ const presentation = aborted
3842
+ ? { kind: automatic ? "automaticCompactionCancelled" : "compactionCancelled" }
3843
+ : errorMessage === undefined ? undefined : { kind: "compactionFailed" };
3844
+ const message = presentation === undefined ? undefined : sessionNotificationSources[presentation.kind];
3636
3845
  if (!aborted && errorMessage !== undefined) {
3637
3846
  this.events.publish(session.sessionId, { type: "session.diagnostic", message: errorMessage }, this.eventScopeForSession(session));
3638
3847
  }
3639
- 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);
3848
+ this.publishActivity(session, aborted
3849
+ ? { kind: "compactionCancelled", detailKind: automatic ? "automaticCompactionCancelled" : "compactionCancelled" }
3850
+ : errorMessage === undefined ? { kind: "compactionComplete" } : { kind: "compactionFailed", detailKind: "compactionFailed" }, !aborted && errorMessage !== undefined ? "error" : "idle", message);
3640
3851
  // Successful compaction already has a canonical summary in the transcript.
3641
3852
  // Keep cancellation/failure feedback in the refresh-safe session inbox only.
3642
3853
  const generation = this.notificationGenerationBySession.get(session);
3643
3854
  if (message !== undefined && generation !== undefined) {
3644
- this.publishNotificationMutations(this.notificationsForSession(session).addNotification(generation, message, aborted ? "info" : "error").mutations);
3855
+ this.publishNotificationMutations(this.notificationsForSession(session).addNotification(generation, message, aborted ? "info" : "error", presentation).mutations);
3645
3856
  }
3646
3857
  }
3647
3858
  scheduleCompactionQueueDrain(session, delayMs = 0) {
@@ -3719,43 +3930,6 @@ export class PiSessionService {
3719
3930
  clearTimeout(timer);
3720
3931
  this.compactionDrainTimers.clear();
3721
3932
  }
3722
- maybeGenerateSessionName(session, firstMessage) {
3723
- if (session.sessionName !== undefined || session.messages.length !== 0 || session.isStreaming || session.isCompacting)
3724
- return;
3725
- void this.generateSessionName(session, firstMessage).then((name) => {
3726
- if (name === undefined)
3727
- this.logger.info({ sessionId: session.sessionId }, "Session naming returned no title; using the first-message fallback");
3728
- this.applyGeneratedSessionName(session, name ?? fallbackSessionName(firstMessage));
3729
- }).catch((error) => {
3730
- const errorCategory = error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError") ? "timeout" : "generation";
3731
- this.logger.info({ sessionId: session.sessionId, errorCategory }, "Session naming failed; using the first-message fallback");
3732
- this.applyGeneratedSessionName(session, fallbackSessionName(firstMessage));
3733
- });
3734
- }
3735
- async generateSessionName(session, firstMessage) {
3736
- // One request keeps its settings even if the operator edits the config while it runs.
3737
- const naming = this.config === undefined ? {} : (await this.config.read()).effectiveConfig.sessionNaming ?? {};
3738
- let model = session.model;
3739
- if (naming.model !== undefined) {
3740
- const parsed = parseModelSpec(naming.model);
3741
- model = parsed === undefined ? undefined : session.modelRuntime.getModel(parsed.provider, parsed.modelId);
3742
- if (model === undefined)
3743
- throw new Error("Configured session naming model is unavailable");
3744
- }
3745
- if (model === undefined)
3746
- return undefined;
3747
- return generateShortSessionName(session.agent.streamFunction, model, firstMessage, naming);
3748
- }
3749
- applyGeneratedSessionName(session, name) {
3750
- if (name === undefined || session.sessionName !== undefined)
3751
- return;
3752
- if (this.treeNavigations.has(session)) {
3753
- this.deferredGeneratedSessionNames.set(session, name);
3754
- return;
3755
- }
3756
- session.setSessionName(name);
3757
- this.publishSessionName(session);
3758
- }
3759
3933
  applyAuthChange(change) {
3760
3934
  const changedRuntime = change.modelRuntime;
3761
3935
  for (const active of this.active.values()) {
@@ -3786,7 +3960,8 @@ export class PiSessionService {
3786
3960
  this.events.publish(session.sessionId, {
3787
3961
  type: "command.output",
3788
3962
  level: "error",
3789
- message: this.t("session.authRemoved", "Authentication for {provider}/{model} was removed. Use /model to select another model.", { provider: model.provider, model: model.id }),
3963
+ message: `Authentication for ${model.provider}/${model.id} was removed. Use /model to select another model.`,
3964
+ presentation: { kind: "modelAuthRemoved", provider: model.provider, model: model.id },
3790
3965
  }, eventScope);
3791
3966
  }
3792
3967
  clearAuthLossWarningsForSession(sessionId) {
@@ -3796,6 +3971,10 @@ export class PiSessionService {
3796
3971
  }
3797
3972
  }
3798
3973
  publishSessionName(session) {
3974
+ const previous = this.publishedSessionNames.get(session);
3975
+ if (previous?.sessionId === session.sessionId && previous.name === session.sessionName)
3976
+ return;
3977
+ this.publishedSessionNames.set(session, { sessionId: session.sessionId, name: session.sessionName });
3799
3978
  const event = session.sessionName === undefined
3800
3979
  ? { type: "session.name", sessionId: session.sessionId }
3801
3980
  : { type: "session.name", sessionId: session.sessionId, name: session.sessionName };
@@ -3819,25 +3998,25 @@ export class PiSessionService {
3819
3998
  }
3820
3999
  this.publishStatus(session);
3821
4000
  if (activity?.phase === "active")
3822
- this.publishActivity(session, activity.label, "active", activity.detail);
4001
+ this.publishActivity(session, activity.runtimePresentation, "active", activity.detail);
3823
4002
  else
3824
- this.publishActivity(session, this.activityLabelFromStatus(session), "active");
4003
+ this.publishActivity(session, this.activityPresentationFromStatus(session), "active");
3825
4004
  }
3826
4005
  }
3827
- activityLabelFromStatus(session) {
4006
+ activityPresentationFromStatus(session) {
3828
4007
  if (this.treeNavigations.has(session))
3829
- return this.t("activity.navigating", "Navigating session tree");
4008
+ return { kind: "navigatingTree" };
3830
4009
  if (this.isSessionEntryMutationActive(session))
3831
- return this.t("activity.updating", "Updating session");
4010
+ return { kind: "updatingSession" };
3832
4011
  if (session.isCompacting)
3833
- return this.t("activity.compacting", "Compacting context");
4012
+ return { kind: "compacting" };
3834
4013
  if (session.isBashRunning)
3835
- return this.t("activity.commandRunning", "Running command");
4014
+ return { kind: "runningBash" };
3836
4015
  if (session.isStreaming)
3837
- return this.t("activity.agentRunning", "Agent running");
4016
+ return { kind: "agentRunning" };
3838
4017
  if (this.pendingMessageCount(session) > 0)
3839
- return this.t("activity.queued", "Queued");
3840
- return this.t("activity.working", "Working");
4018
+ return { kind: "queued" };
4019
+ return { kind: "active" };
3841
4020
  }
3842
4021
  hasActiveWork(session) {
3843
4022
  const execution = this.extensionCommandExecution.getStore();
@@ -3942,56 +4121,56 @@ export class PiSessionService {
3942
4121
  if (eventType === undefined)
3943
4122
  return;
3944
4123
  if (eventType === "agent_start") {
3945
- this.publishActivity(session, this.t("activity.agentRunning", "Agent running"), "active");
4124
+ this.publishActivity(session, { kind: "agentRunning" }, "active");
3946
4125
  return;
3947
4126
  }
3948
4127
  if (eventType === "agent_end") {
3949
- this.publishActivity(session, this.t("activity.idle", "Idle"), "idle");
4128
+ this.publishActivity(session, { kind: "idle" }, "idle");
3950
4129
  const eventScope = this.eventScopeForSession(session);
3951
4130
  const sessionKey = activeSessionKey(session.sessionId, eventScope);
3952
4131
  this.activities.scheduleSettledRefresh(sessionKey, () => {
3953
4132
  if (this.active.get(sessionKey)?.runtime.session !== session)
3954
4133
  return;
3955
- this.publishActivity(session, this.t("activity.idle", "Idle"), "idle");
4134
+ this.publishActivity(session, { kind: "idle" }, "idle");
3956
4135
  this.publishStatus(session);
3957
4136
  }, 250);
3958
4137
  return;
3959
4138
  }
3960
4139
  if (eventType === "turn_end") {
3961
- this.publishActivity(session, this.t("activity.turnCompleted", "Turn completed"), "idle");
4140
+ this.publishActivity(session, { kind: "turnComplete" }, "idle");
3962
4141
  return;
3963
4142
  }
3964
4143
  if (eventType === "message_start") {
3965
- this.publishActivity(session, this.t("activity.messageStarted", "Message started"), "active");
4144
+ this.publishActivity(session, { kind: "messageStarted" }, "active");
3966
4145
  return;
3967
4146
  }
3968
4147
  if (eventType === "message_end") {
3969
- this.publishActivity(session, this.t("activity.messageCompleted", "Message completed"), "idle");
4148
+ this.publishActivity(session, { kind: "messageComplete" }, "idle");
3970
4149
  return;
3971
4150
  }
3972
4151
  if (eventType === "message_update") {
3973
- this.publishActivity(session, this.t("activity.receiving", "Receiving reply"), "active");
4152
+ this.publishActivity(session, { kind: "receivingResponse" }, "active");
3974
4153
  return;
3975
4154
  }
3976
4155
  if (eventType === "tool_execution_start") {
3977
- this.publishActivity(session, this.t("activity.toolRunning", "Running tool"), "active", getString(event, "toolName"));
4156
+ this.publishActivity(session, { kind: "runningTool" }, "active", getString(event, "toolName"));
3978
4157
  return;
3979
4158
  }
3980
4159
  if (eventType === "tool_execution_end") {
3981
4160
  const isError = getBoolean(event, "isError") === true;
3982
- this.publishActivity(session, isError ? this.t("activity.toolFailed", "Tool failed") : this.t("activity.toolCompleted", "Tool completed"), isError ? "error" : "idle", getString(event, "toolName"));
4161
+ this.publishActivity(session, isError ? { kind: "toolFailed" } : { kind: "toolComplete" }, isError ? "error" : "idle", getString(event, "toolName"));
3983
4162
  return;
3984
4163
  }
3985
4164
  if (eventType === "bash_execution_start") {
3986
- this.publishActivity(session, this.t("activity.commandRunning", "Running command"), "active");
4165
+ this.publishActivity(session, { kind: "runningBash" }, "active");
3987
4166
  return;
3988
4167
  }
3989
4168
  if (eventType === "bash_execution_end") {
3990
- this.publishActivity(session, this.t("activity.commandCompleted", "Command completed"), "idle");
4169
+ this.publishActivity(session, { kind: "bashComplete" }, "idle");
3991
4170
  return;
3992
4171
  }
3993
4172
  if (this.hasActiveWork(session))
3994
- this.publishActivity(session, this.t("activity.working", "Working"), "active");
4173
+ this.publishActivity(session, { kind: "event", value: eventType }, "active");
3995
4174
  }
3996
4175
  auditToolExecutionEvent(active, event) {
3997
4176
  const eventType = getString(event, "type");
@@ -4088,23 +4267,23 @@ export class PiSessionService {
4088
4267
  const sessionId = sessionManager.getSessionId();
4089
4268
  if (sessionId === "")
4090
4269
  return { report: noop, end: noop };
4091
- const label = intent === "create" ? this.t("activity.creating", "Creating session") : this.t("activity.opening", "Opening session");
4270
+ const label = intent === "create" ? "Creating session" : "Opening session";
4092
4271
  return {
4093
- report: (phase) => { this.publishStartupProgress(sessionId, startupToken, label, "active", this.startupDetail(phase), eventScope); },
4272
+ report: (stage) => {
4273
+ const catalogRefreshing = this.catalogRefreshStatus?.isRefreshInFlight() === true;
4274
+ const phase = stage === "runtime" ? STARTUP_PHASE_RUNTIME : STARTUP_PHASE_EXTENSIONS;
4275
+ const detail = catalogRefreshing ? `${phase} · ${STARTUP_CONCURRENT_CATALOG_REFRESH}` : phase;
4276
+ this.publishStartupProgress(sessionId, startupToken, label, "active", detail, eventScope, { intent, stage, catalogRefreshing });
4277
+ },
4094
4278
  end: () => {
4095
4279
  // A real activity published during the window (an extension error, say)
4096
4280
  // is the truth about this session and must survive the clear.
4097
4281
  if (this.activities.get(activeSessionKey(sessionId, eventScope)) !== undefined)
4098
4282
  return;
4099
- this.publishStartupProgress(sessionId, startupToken, this.t("activity.idle", "Idle"), "idle", undefined, eventScope);
4283
+ this.publishStartupProgress(sessionId, startupToken, "Idle", "idle", undefined, eventScope);
4100
4284
  },
4101
4285
  };
4102
4286
  }
4103
- startupDetail(phase) {
4104
- return this.catalogRefreshStatus?.isRefreshInFlight() === true
4105
- ? `${phase} · ${this.t("startup.catalogRefresh", "Provider model catalog is refreshing")}`
4106
- : phase;
4107
- }
4108
4287
  /**
4109
4288
  * Report startup progress on the global channel only, echoing the caller's
4110
4289
  * correlation token so a waiting browser row recognises its own construction.
@@ -4118,17 +4297,21 @@ export class PiSessionService {
4118
4297
  * that sets the marker, and because it writes no `activities` entry no later
4119
4298
  * heartbeat re-publication can carry it.
4120
4299
  */
4121
- publishStartupProgress(sessionId, startupToken, label, phase, detail, eventScope) {
4300
+ publishStartupProgress(sessionId, startupToken, label, phase, detail, eventScope, startupPresentation) {
4122
4301
  const at = new Date().toISOString();
4123
- const activity = detail === undefined ? { sessionId, phase, label, at, startup: true } : { sessionId, phase, label, detail, at, startup: true };
4302
+ const activity = { sessionId, phase, label, at, startup: true,
4303
+ ...(detail === undefined ? {} : { detail }),
4304
+ ...(startupPresentation === undefined ? {} : { startupPresentation }),
4305
+ };
4124
4306
  this.events.publishGlobal(startupToken === undefined ? { type: "session.startup", activity } : { type: "session.startup", startupToken, activity }, eventScope);
4125
4307
  }
4126
- publishActivity(session, label, phase, detail) {
4308
+ publishActivity(session, runtimePresentation, phase, detail) {
4127
4309
  const at = new Date().toISOString();
4128
- const stored = detail === undefined ? { phase, label, at } : { phase, label, detail, at };
4310
+ const label = runtimeActivityFallbackLabel(runtimePresentation);
4311
+ const stored = { phase, label, at, runtimePresentation, ...(detail === undefined ? {} : { detail }) };
4129
4312
  const eventScope = this.eventScopeForSession(session);
4130
4313
  this.activities.set(activeSessionKey(session.sessionId, eventScope), stored);
4131
- const activity = detail === undefined ? { sessionId: session.sessionId, phase, label, at } : { sessionId: session.sessionId, phase, label, detail, at };
4314
+ const activity = { sessionId: session.sessionId, ...stored };
4132
4315
  this.workspaceActivity?.applySessionActivity(session.sessionManager.getCwd(), activity, eventScope);
4133
4316
  this.events.publish(session.sessionId, { type: "activity.update", activity }, eventScope);
4134
4317
  this.events.publishGlobal({ type: "activity.update", activity }, eventScope);
@@ -4153,6 +4336,26 @@ export class PiSessionService {
4153
4336
  if (path !== undefined)
4154
4337
  this.managementMediaFiles.add(path);
4155
4338
  }
4339
+ interventionRequired(session) {
4340
+ return this.interventionStates.get(session)
4341
+ ?? sessionInterventionRequired(session.sessionManager.getEntries?.() ?? session.sessionManager.getBranch());
4342
+ }
4343
+ setInterventionRequired(session, required) {
4344
+ const previous = this.interventionRequired(session);
4345
+ if (previous === required)
4346
+ return;
4347
+ if (session.sessionManager.appendCustomEntry === undefined)
4348
+ throw new Error("Session manager cannot persist intervention state");
4349
+ // Update before append: the SDK emits entry_appended synchronously.
4350
+ this.interventionStates.set(session, required);
4351
+ try {
4352
+ session.sessionManager.appendCustomEntry(SESSION_INTERVENTION_CUSTOM_TYPE, { version: 1, required });
4353
+ }
4354
+ catch (error) {
4355
+ this.interventionStates.set(session, previous);
4356
+ throw error;
4357
+ }
4358
+ }
4156
4359
  publishStatus(session) {
4157
4360
  this.rememberManagementMediaFile(session, this.eventScopeForSession(session));
4158
4361
  void this.refreshActivityMarker(session);
@@ -4170,7 +4373,7 @@ export class PiSessionService {
4170
4373
  if (current?.phase !== "active" || this.hasActiveWork(session))
4171
4374
  return;
4172
4375
  const at = new Date().toISOString();
4173
- const stored = { phase: "idle", label: this.t("activity.idle", "Idle"), at };
4376
+ const stored = { phase: "idle", label: "idle", at, runtimePresentation: { kind: "idle" } };
4174
4377
  this.activities.set(activeSessionKey(session.sessionId, eventScope), stored);
4175
4378
  const activity = { sessionId: session.sessionId, ...stored };
4176
4379
  this.events.publish(session.sessionId, { type: "activity.update", activity }, eventScope);
@@ -4241,6 +4444,7 @@ export class PiSessionService {
4241
4444
  sessionId: session.sessionId,
4242
4445
  persisted: sessionFileExists(session.sessionFile),
4243
4446
  recentlyActiveElsewhere: this.eventScopeForSession(session) === NORMAL_SESSION_EVENT_SCOPE && this.activityMarker.isActiveElsewhere(session.sessionFile),
4447
+ interventionRequired: this.interventionRequired(session) || pendingDialogs.length > 0,
4244
4448
  ...(model === undefined ? {} : { model }),
4245
4449
  thinkingLevel: session.thinkingLevel,
4246
4450
  isStreaming: session.isStreaming,
@@ -4322,8 +4526,22 @@ export class PiSessionService {
4322
4526
  return this.unreadForScope(eventScope).durableCatalogSnapshot();
4323
4527
  }
4324
4528
  async reconcileUnreadWorkspaces(cwds) {
4529
+ this.unreadEligibilityRevision += 1;
4325
4530
  await this.publishUnreadMutations(this.unreadStore.reconcileWorkspaces(cwds));
4326
4531
  }
4532
+ async markUnread(sessionId, cwd, context) {
4533
+ const canonicalCwd = canonicalizeStoredCwd(cwd);
4534
+ const eligibilityRevision = this.unreadEligibilityRevision;
4535
+ const rows = await this.list(canonicalCwd, context);
4536
+ const row = rows.find((candidate) => candidate.id === sessionId && cwdPathsEqual(candidate.cwd, canonicalCwd));
4537
+ if (eligibilityRevision !== this.unreadEligibilityRevision
4538
+ || row === undefined || row.archived === true || row.persisted !== true || row.agentSubsession === true) {
4539
+ throw new Error("Session is not eligible to be marked unread");
4540
+ }
4541
+ const store = this.unreadForScope(eventScopeFromManagementContext(context));
4542
+ await this.publishUnreadMutations(store.markUnread(sessionId, canonicalCwd));
4543
+ return store.durableCatalogSnapshot();
4544
+ }
4327
4545
  async acknowledgeUnread(sessionId, request, context) {
4328
4546
  const store = this.unreadForScope(eventScopeFromManagementContext(context));
4329
4547
  const result = store.acknowledge(sessionId, {
@@ -4353,7 +4571,7 @@ export class PiSessionService {
4353
4571
  if (this.hasActiveWork(session))
4354
4572
  throw new Error(this.t("session.stopBeforeReload", "Stop current session activity before reloading"));
4355
4573
  await this.runTreeExclusiveOperation([{ sessionId: session.sessionId, session }], this.t("session.stopBeforeReload", "Stop current session activity before reloading"), async () => {
4356
- this.publishActivity(session, this.t("activity.reloading", "Reloading resources"), "active");
4574
+ this.publishActivity(session, { kind: "reloading" }, "active");
4357
4575
  const priorGeneration = this.notificationGenerationBySession.get(session);
4358
4576
  let candidateGeneration;
4359
4577
  const reloadBoundary = { beforeSessionStart: false };
@@ -4373,7 +4591,7 @@ export class PiSessionService {
4373
4591
  if (candidateGeneration !== undefined) {
4374
4592
  this.publishNotificationMutations(this.notificationsForSession(session).commitReplacement(candidateGeneration));
4375
4593
  }
4376
- this.publishActivity(session, this.t("activity.reloaded", "Resources reloaded"), "idle");
4594
+ this.publishActivity(session, { kind: "reloaded" }, "idle");
4377
4595
  this.publishStatus(session);
4378
4596
  }
4379
4597
  catch (error) {
@@ -4384,7 +4602,7 @@ export class PiSessionService {
4384
4602
  this.notificationGenerationBySession.set(session, candidateGeneration);
4385
4603
  }
4386
4604
  const message = error instanceof Error ? error.message : String(error);
4387
- this.publishActivity(session, this.t("activity.reloadFailed", "Reload failed"), "error", message);
4605
+ this.publishActivity(session, { kind: "reloadFailed" }, "error", message);
4388
4606
  this.events.publish(session.sessionId, { type: "session.error", message }, this.eventScopeForSession(session));
4389
4607
  this.publishStatus(session);
4390
4608
  throw error;
@@ -4404,7 +4622,7 @@ export class PiSessionService {
4404
4622
  return [...this.active.values()].some((active) => active.runtime.session === session);
4405
4623
  }
4406
4624
  async createSessionRuntime(sessionManager, cwd, options, startup) {
4407
- startup.report(this.t("startup.runtime", "Loading session runtime"));
4625
+ startup.report("runtime");
4408
4626
  options.startupSignal?.throwIfAborted();
4409
4627
  // Ordinary local sessions (undefined provenance) keep the current rule.
4410
4628
  // Only an explicit host one-shot forces delegation off; do not treat every
@@ -4471,7 +4689,7 @@ export class PiSessionService {
4471
4689
  await this.recoverSubsessionTrackingForOpenedSession(runtime.session);
4472
4690
  }
4473
4691
  startupSignal?.throwIfAborted();
4474
- startup.report(this.t("startup.extensions", "Starting session extensions"));
4692
+ startup.report("extensions");
4475
4693
  // Startup hooks emit through the same scoped stream as hosted turns.
4476
4694
  this.bindRuntime(active);
4477
4695
  await this.bindSessionExtensions(runtime.session, notificationGeneration, active, startupSignal);
@@ -4626,12 +4844,15 @@ export class PiSessionService {
4626
4844
  const nextCwd = canonicalizeStoredCwd(next.sessionManager.getCwd());
4627
4845
  if (previous.sessionId === next.sessionId && cwdPathsEqual(previousCwd, nextCwd))
4628
4846
  return;
4847
+ this.unreadEligibilityRevision += 1;
4629
4848
  await this.publishUnreadMutations(store.forgetSession(previous.sessionId, previousCwd));
4630
4849
  }
4631
4850
  forgetUnreadActivity(session) {
4632
4851
  this.unreadForScope(this.eventScopeForSession(session)).forgetActivity(session.sessionId, canonicalizeStoredCwd(session.sessionManager.getCwd()));
4633
4852
  }
4634
4853
  async forgetUnreadSessions(identities, scope = NORMAL_SESSION_EVENT_SCOPE) {
4854
+ if (identities.length > 0)
4855
+ this.unreadEligibilityRevision += 1;
4635
4856
  const mutations = [];
4636
4857
  for (const identity of identities) {
4637
4858
  mutations.push(...this.unreadForScope(scope).forgetSession(identity.sessionId, canonicalizeStoredCwd(identity.cwd)));
@@ -4735,16 +4956,6 @@ export class PiSessionService {
4735
4956
  this.unreadPublicationRetryDelayMs = this.unreadPublicationRetryInitialMs;
4736
4957
  }
4737
4958
  flushDeferredTreeNavigationWork(session) {
4738
- const generatedName = this.deferredGeneratedSessionNames.get(session);
4739
- this.deferredGeneratedSessionNames.delete(session);
4740
- if (generatedName !== undefined) {
4741
- try {
4742
- this.applyGeneratedSessionName(session, generatedName);
4743
- }
4744
- catch (error) {
4745
- this.logger.info({ sessionId: session.sessionId, error: error instanceof Error ? error.message : String(error) }, "failed to apply deferred session name");
4746
- }
4747
- }
4748
4959
  this.restoreSubsessionReceipts(session);
4749
4960
  this.scheduleSubsessionDelivery(session);
4750
4961
  }
@@ -4883,8 +5094,8 @@ export class PiSessionService {
4883
5094
  }, 0);
4884
5095
  }
4885
5096
  assertMcpModeAllowed(managementContext) {
4886
- if (VERSION !== "1.3.0")
4887
- throw new UserFacingError("mcpAuth.sdkUnsupported", "Dedicated MCP authentication requires Pi 1.3.0");
5097
+ if (VERSION !== "1.3.0" && VERSION !== "1.4.0")
5098
+ throw new UserFacingError("mcpAuth.sdkUnsupported", "Dedicated MCP authentication requires Pi 1.3.0 or 1.4.0");
4888
5099
  if (managementContext !== undefined && !managementUsesNormalPermissions(managementContext, { allowPrivileged: this.managementAllowPrivileged })) {
4889
5100
  throw new UserFacingError("mcpAuth.restrictedManagement", "MCP authentication is unavailable in restricted management mode");
4890
5101
  }
@@ -5034,6 +5245,7 @@ function previewResponseFromPlan(plan) {
5034
5245
  projects: plan.projects,
5035
5246
  totals: plan.totals,
5036
5247
  ...(plan.skippedBusySessionIds.length === 0 ? {} : { skippedBusySessionIds: plan.skippedBusySessionIds }),
5248
+ ...(plan.skippedPinnedSessionIds === undefined ? {} : { skippedPinnedSessionIds: plan.skippedPinnedSessionIds }),
5037
5249
  };
5038
5250
  }
5039
5251
  function uniqueBulkSessionRefs(refs) {
@@ -5121,6 +5333,7 @@ function clientSessionFromListEntry(session) {
5121
5333
  modified: session.modified.toISOString(),
5122
5334
  messageCount: session.messageCount,
5123
5335
  firstMessage: clientSessionFirstMessagePreview(session.firstMessage),
5336
+ ...(session.interventionRequired === true ? { interventionRequired: true } : {}),
5124
5337
  ...(session.parentSessionPath === undefined ? {} : { parentSessionPath: session.parentSessionPath }),
5125
5338
  };
5126
5339
  }
@@ -5252,11 +5465,6 @@ function sessionFileExists(sessionFile) {
5252
5465
  return false;
5253
5466
  }
5254
5467
  }
5255
- function sessionPinScope(cwd, managementContext) {
5256
- return managementContext === undefined
5257
- ? { mode: "normal", cwd }
5258
- : { mode: "management", rootUserId: managementContext.user.rootUserId, userId: managementContext.user.id, cwd };
5259
- }
5260
5468
  async function readArchivedSessionText(path) {
5261
5469
  try {
5262
5470
  return await readFile(path, "utf8");