@chainingintention/pi-web-cn 2.202610.5 → 2.202611.1

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