@baique/pi-web-sky 0.1.55 → 0.1.57

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 (396) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +8 -4
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/prerender-manifest.json +2 -2
  5. package/.next/react-loadable-manifest.json +2 -2
  6. package/.next/required-server-files.js +3 -2
  7. package/.next/required-server-files.json +3 -2
  8. package/.next/routes-manifest.json +28 -0
  9. package/.next/server/app/_global-error/page.js +2 -2
  10. package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  11. package/.next/server/app/_global-error.html +1 -1
  12. package/.next/server/app/_global-error.rsc +1 -1
  13. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  14. package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  15. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  16. package/.next/server/app/_not-found/page.js +1 -1
  17. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  18. package/.next/server/app/_not-found.html +1 -1
  19. package/.next/server/app/_not-found.rsc +4 -3
  20. package/.next/server/app/_not-found.segments/_full.segment.rsc +4 -3
  21. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +4 -3
  22. package/.next/server/app/_not-found.segments/_tree.segment.rsc +3 -2
  23. package/.next/server/app/api/agent/[id]/bash-output/route.js +2 -2
  24. package/.next/server/app/api/agent/[id]/events/route.js +2 -2
  25. package/.next/server/app/api/agent/[id]/events/route.js.nft.json +1 -1
  26. package/.next/server/app/api/agent/[id]/route.js +1 -1
  27. package/.next/server/app/api/agent/[id]/route.js.nft.json +1 -1
  28. package/.next/server/app/api/agent/new/route.js +1 -1
  29. package/.next/server/app/api/agent/new/route.js.nft.json +1 -1
  30. package/.next/server/app/api/agent/running/route.js +1 -1
  31. package/.next/server/app/api/agent/running/route.js.nft.json +1 -1
  32. package/.next/server/app/api/app-update/route.js +1 -1
  33. package/.next/server/app/api/auth/all-providers/route.js +1 -1
  34. package/.next/server/app/api/auth/api-key/[provider]/route.js +1 -1
  35. package/.next/server/app/api/auth/login/[provider]/route.js +1 -1
  36. package/.next/server/app/api/auth/logout/[provider]/route.js +1 -1
  37. package/.next/server/app/api/auth/providers/route.js +1 -1
  38. package/.next/server/app/api/board-assets/[...path]/route.js +2 -2
  39. package/.next/server/app/api/board-assets/route.js +2 -2
  40. package/.next/server/app/api/boards/[id]/add-session/route.js +1 -0
  41. package/.next/server/app/api/boards/[id]/add-session/route.js.nft.json +1 -0
  42. package/.next/server/app/api/boards/[id]/add-session/route_client-reference-manifest.js +1 -0
  43. package/.next/server/app/api/boards/[id]/reconcile/route.js +1 -1
  44. package/.next/server/app/api/boards/[id]/route.js +1 -1
  45. package/.next/server/app/api/boards/reorder/route.js +2 -2
  46. package/.next/server/app/api/boards/route.js +1 -1
  47. package/.next/server/app/api/cwd/browse/route.js +1 -1
  48. package/.next/server/app/api/cwd/validate/route.js +2 -2
  49. package/.next/server/app/api/default-cwd/route.js +2 -2
  50. package/.next/server/app/api/file-index/route.js +2 -2
  51. package/.next/server/app/api/files/[...path]/route.js +3 -3
  52. package/.next/server/app/api/git/diff/route.js +1 -1
  53. package/.next/server/app/api/git/status/route.js +1 -1
  54. package/.next/server/app/api/home/route.js +1 -1
  55. package/.next/server/app/api/mcp/route.js +2 -2
  56. package/.next/server/app/api/models/route.js +2 -2
  57. package/.next/server/app/api/models-config/catalog/route.js +1 -1
  58. package/.next/server/app/api/models-config/discover/route.js +1 -1
  59. package/.next/server/app/api/models-config/route.js +1 -1
  60. package/.next/server/app/api/models-config/test/route.js +1 -1
  61. package/.next/server/app/api/plugins/route.js +2 -2
  62. package/.next/server/app/api/project-trust/route.js +1 -1
  63. package/.next/server/app/api/project-trust/route.js.nft.json +1 -1
  64. package/.next/server/app/api/quota/route.js +1 -1
  65. package/.next/server/app/api/search/route.js +3 -3
  66. package/.next/server/app/api/sessions/[id]/auto-name/route.js +2 -2
  67. package/.next/server/app/api/sessions/[id]/auto-name/route.js.nft.json +1 -1
  68. package/.next/server/app/api/sessions/[id]/context/route.js +1 -1
  69. package/.next/server/app/api/sessions/[id]/context/route.js.nft.json +1 -1
  70. package/.next/server/app/api/sessions/[id]/entries/[entryId]/thinking/route.js +2 -2
  71. package/.next/server/app/api/sessions/[id]/export/route.js +2 -2
  72. package/.next/server/app/api/sessions/[id]/minimap/route.js +1 -1
  73. package/.next/server/app/api/sessions/[id]/minimap/route.js.nft.json +1 -1
  74. package/.next/server/app/api/sessions/[id]/route.js +1 -1
  75. package/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
  76. package/.next/server/app/api/sessions/[id]/state/route.js +1 -1
  77. package/.next/server/app/api/sessions/[id]/state/route.js.nft.json +1 -1
  78. package/.next/server/app/api/sessions/[id]/todos/route.js +1 -1
  79. package/.next/server/app/api/sessions/[id]/todos/route.js.nft.json +1 -1
  80. package/.next/server/app/api/sessions/route.js +1 -1
  81. package/.next/server/app/api/sessions/route.js.nft.json +1 -1
  82. package/.next/server/app/api/sessions/summary/route.js +2 -2
  83. package/.next/server/app/api/skills/check/route.js +1 -1
  84. package/.next/server/app/api/skills/install/route.js +2 -2
  85. package/.next/server/app/api/skills/route.js +1 -1
  86. package/.next/server/app/api/skills/search/route.js +1 -1
  87. package/.next/server/app/api/skills/update/route.js +1 -1
  88. package/.next/server/app/api/subagents/[id]/route.js +1 -0
  89. package/.next/server/app/api/subagents/[id]/route.js.nft.json +1 -0
  90. package/.next/server/app/api/subagents/[id]/route_client-reference-manifest.js +1 -0
  91. package/.next/server/app/api/subagents/profiles/route.js +30 -0
  92. package/.next/server/app/api/subagents/profiles/route.js.nft.json +1 -0
  93. package/.next/server/app/api/subagents/profiles/route_client-reference-manifest.js +1 -0
  94. package/.next/server/app/api/subagents/settings/route.js +1 -0
  95. package/.next/server/app/api/subagents/settings/route.js.nft.json +1 -0
  96. package/.next/server/app/api/subagents/settings/route_client-reference-manifest.js +1 -0
  97. package/.next/server/app/api/task-card-questions/[id]/answer/route.js +2 -2
  98. package/.next/server/app/api/task-card-questions/route.js +2 -2
  99. package/.next/server/app/api/task-cards/[id]/route.js +1 -1
  100. package/.next/server/app/api/task-cards/route.js +1 -1
  101. package/.next/server/app/api/task-cards/unbind/route.js +3 -3
  102. package/.next/server/app/api/task-scheduler/status/route.js +1 -1
  103. package/.next/server/app/api/task-scheduler/status/route.js.nft.json +1 -1
  104. package/.next/server/app/api/tasks/[id]/assign-session/route.js +2 -12
  105. package/.next/server/app/api/tasks/[id]/board/route.js +1 -1
  106. package/.next/server/app/api/tasks/[id]/route.js +1 -1
  107. package/.next/server/app/api/tasks/[id]/route.js.nft.json +1 -1
  108. package/.next/server/app/api/tasks/reorder/route.js +2 -12
  109. package/.next/server/app/api/tasks/route.js +2 -12
  110. package/.next/server/app/api/terminal/[id]/events/route.js +2 -2
  111. package/.next/server/app/api/terminal/[id]/route.js +2 -2
  112. package/.next/server/app/api/terminal/route.js +2 -2
  113. package/.next/server/app/api/worktrees/route.js +2 -2
  114. package/.next/server/app/api/yjs-version/route.js +1 -1
  115. package/.next/server/app/favicon.ico/route.js +1 -1
  116. package/.next/server/app/index.html +1 -1
  117. package/.next/server/app/index.rsc +6 -5
  118. package/.next/server/app/index.segments/__PAGE__.segment.rsc +6 -5
  119. package/.next/server/app/index.segments/_full.segment.rsc +6 -5
  120. package/.next/server/app/index.segments/_tree.segment.rsc +3 -2
  121. package/.next/server/app/manifest.webmanifest/route.js +2 -2
  122. package/.next/server/app/page.js +175 -8
  123. package/.next/server/app/page_client-reference-manifest.js +1 -1
  124. package/.next/server/app-paths-manifest.json +8 -4
  125. package/.next/server/chunks/1937.js +14 -13
  126. package/.next/server/chunks/2524.js +2 -2
  127. package/.next/server/chunks/3379.js +1 -1
  128. package/.next/server/chunks/3500.js +1 -1
  129. package/.next/server/chunks/402.js +28 -7
  130. package/.next/server/chunks/426.js +14 -0
  131. package/.next/server/chunks/4367.js +1 -1
  132. package/.next/server/chunks/4457.js +3 -13
  133. package/.next/server/chunks/4980.js +1 -1
  134. package/.next/server/chunks/542.js +23 -4
  135. package/.next/server/chunks/5794.js +2 -2
  136. package/.next/server/chunks/5940.js +1 -1
  137. package/.next/server/chunks/6337.js +1 -1
  138. package/.next/server/chunks/6429.js +15 -2
  139. package/.next/server/chunks/6525.js +25 -4
  140. package/.next/server/chunks/6583.js +12 -11
  141. package/.next/server/chunks/7048.js +6 -0
  142. package/.next/server/instrumentation.js +1 -1
  143. package/.next/server/middleware-build-manifest.js +1 -1
  144. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  145. package/.next/server/middleware.js +3 -3
  146. package/.next/server/pages/404.html +1 -1
  147. package/.next/server/pages/500.html +1 -1
  148. package/.next/static/MPBMmQqmDG8zo8tM_bkDy/_buildManifest.js +1 -0
  149. package/.next/static/chunks/752.bafff304e6b00987.js +1 -0
  150. package/.next/static/chunks/8088.39866dc5f1d15868.js +1 -0
  151. package/.next/static/chunks/app/_global-error/page-ad6e695deb9de65c.js +1 -0
  152. package/.next/static/chunks/app/api/agent/[id]/bash-output/route-ad6e695deb9de65c.js +1 -0
  153. package/.next/static/chunks/app/api/agent/[id]/events/route-ad6e695deb9de65c.js +1 -0
  154. package/.next/static/chunks/app/api/agent/[id]/route-ad6e695deb9de65c.js +1 -0
  155. package/.next/static/chunks/app/api/agent/new/route-ad6e695deb9de65c.js +1 -0
  156. package/.next/static/chunks/app/api/agent/running/route-ad6e695deb9de65c.js +1 -0
  157. package/.next/static/chunks/app/api/app-update/route-ad6e695deb9de65c.js +1 -0
  158. package/.next/static/chunks/app/api/auth/all-providers/route-ad6e695deb9de65c.js +1 -0
  159. package/.next/static/chunks/app/api/auth/api-key/[provider]/route-ad6e695deb9de65c.js +1 -0
  160. package/.next/static/chunks/app/api/auth/login/[provider]/route-ad6e695deb9de65c.js +1 -0
  161. package/.next/static/chunks/app/api/auth/logout/[provider]/route-ad6e695deb9de65c.js +1 -0
  162. package/.next/static/chunks/app/api/auth/providers/route-ad6e695deb9de65c.js +1 -0
  163. package/.next/static/chunks/app/api/board-assets/[...path]/route-ad6e695deb9de65c.js +1 -0
  164. package/.next/static/chunks/app/api/board-assets/route-ad6e695deb9de65c.js +1 -0
  165. package/.next/static/chunks/app/api/boards/[id]/add-session/route-ad6e695deb9de65c.js +1 -0
  166. package/.next/static/chunks/app/api/boards/[id]/reconcile/route-ad6e695deb9de65c.js +1 -0
  167. package/.next/static/chunks/app/api/boards/[id]/route-ad6e695deb9de65c.js +1 -0
  168. package/.next/static/chunks/app/api/boards/reorder/route-ad6e695deb9de65c.js +1 -0
  169. package/.next/static/chunks/app/api/boards/route-ad6e695deb9de65c.js +1 -0
  170. package/.next/static/chunks/app/api/cwd/browse/route-ad6e695deb9de65c.js +1 -0
  171. package/.next/static/chunks/app/api/cwd/validate/route-ad6e695deb9de65c.js +1 -0
  172. package/.next/static/chunks/app/api/default-cwd/route-ad6e695deb9de65c.js +1 -0
  173. package/.next/static/chunks/app/api/file-index/route-ad6e695deb9de65c.js +1 -0
  174. package/.next/static/chunks/app/api/files/[...path]/route-ad6e695deb9de65c.js +1 -0
  175. package/.next/static/chunks/app/api/git/diff/route-ad6e695deb9de65c.js +1 -0
  176. package/.next/static/chunks/app/api/git/status/route-ad6e695deb9de65c.js +1 -0
  177. package/.next/static/chunks/app/api/home/route-ad6e695deb9de65c.js +1 -0
  178. package/.next/static/chunks/app/api/mcp/route-ad6e695deb9de65c.js +1 -0
  179. package/.next/static/chunks/app/api/models/route-ad6e695deb9de65c.js +1 -0
  180. package/.next/static/chunks/app/api/models-config/catalog/route-ad6e695deb9de65c.js +1 -0
  181. package/.next/static/chunks/app/api/models-config/discover/route-ad6e695deb9de65c.js +1 -0
  182. package/.next/static/chunks/app/api/models-config/route-ad6e695deb9de65c.js +1 -0
  183. package/.next/static/chunks/app/api/models-config/test/route-ad6e695deb9de65c.js +1 -0
  184. package/.next/static/chunks/app/api/plugins/route-ad6e695deb9de65c.js +1 -0
  185. package/.next/static/chunks/app/api/project-trust/route-ad6e695deb9de65c.js +1 -0
  186. package/.next/static/chunks/app/api/quota/route-ad6e695deb9de65c.js +1 -0
  187. package/.next/static/chunks/app/api/search/route-ad6e695deb9de65c.js +1 -0
  188. package/.next/static/chunks/app/api/sessions/[id]/auto-name/route-ad6e695deb9de65c.js +1 -0
  189. package/.next/static/chunks/app/api/sessions/[id]/context/route-ad6e695deb9de65c.js +1 -0
  190. package/.next/static/chunks/app/api/sessions/[id]/entries/[entryId]/thinking/route-ad6e695deb9de65c.js +1 -0
  191. package/.next/static/chunks/app/api/sessions/[id]/export/route-ad6e695deb9de65c.js +1 -0
  192. package/.next/static/chunks/app/api/sessions/[id]/minimap/route-ad6e695deb9de65c.js +1 -0
  193. package/.next/static/chunks/app/api/sessions/[id]/route-ad6e695deb9de65c.js +1 -0
  194. package/.next/static/chunks/app/api/sessions/[id]/state/route-ad6e695deb9de65c.js +1 -0
  195. package/.next/static/chunks/app/api/sessions/[id]/todos/route-ad6e695deb9de65c.js +1 -0
  196. package/.next/static/chunks/app/api/sessions/route-ad6e695deb9de65c.js +1 -0
  197. package/.next/static/chunks/app/api/sessions/summary/route-ad6e695deb9de65c.js +1 -0
  198. package/.next/static/chunks/app/api/skills/check/route-ad6e695deb9de65c.js +1 -0
  199. package/.next/static/chunks/app/api/skills/install/route-ad6e695deb9de65c.js +1 -0
  200. package/.next/static/chunks/app/api/skills/route-ad6e695deb9de65c.js +1 -0
  201. package/.next/static/chunks/app/api/skills/search/route-ad6e695deb9de65c.js +1 -0
  202. package/.next/static/chunks/app/api/skills/update/route-ad6e695deb9de65c.js +1 -0
  203. package/.next/static/chunks/app/api/subagents/[id]/route-ad6e695deb9de65c.js +1 -0
  204. package/.next/static/chunks/app/api/subagents/profiles/route-ad6e695deb9de65c.js +1 -0
  205. package/.next/static/chunks/app/api/subagents/settings/route-ad6e695deb9de65c.js +1 -0
  206. package/.next/static/chunks/app/api/task-card-questions/[id]/answer/route-ad6e695deb9de65c.js +1 -0
  207. package/.next/static/chunks/app/api/task-card-questions/route-ad6e695deb9de65c.js +1 -0
  208. package/.next/static/chunks/app/api/task-cards/[id]/route-ad6e695deb9de65c.js +1 -0
  209. package/.next/static/chunks/app/api/task-cards/route-ad6e695deb9de65c.js +1 -0
  210. package/.next/static/chunks/app/api/task-cards/unbind/route-ad6e695deb9de65c.js +1 -0
  211. package/.next/static/chunks/app/api/task-scheduler/status/route-ad6e695deb9de65c.js +1 -0
  212. package/.next/static/chunks/app/api/tasks/[id]/assign-session/route-ad6e695deb9de65c.js +1 -0
  213. package/.next/static/chunks/app/api/tasks/[id]/board/route-ad6e695deb9de65c.js +1 -0
  214. package/.next/static/chunks/app/api/tasks/[id]/route-ad6e695deb9de65c.js +1 -0
  215. package/.next/static/chunks/app/api/tasks/reorder/route-ad6e695deb9de65c.js +1 -0
  216. package/.next/static/chunks/app/api/tasks/route-ad6e695deb9de65c.js +1 -0
  217. package/.next/static/chunks/app/api/terminal/[id]/events/route-ad6e695deb9de65c.js +1 -0
  218. package/.next/static/chunks/app/api/terminal/[id]/route-ad6e695deb9de65c.js +1 -0
  219. package/.next/static/chunks/app/api/terminal/route-ad6e695deb9de65c.js +1 -0
  220. package/.next/static/chunks/app/api/worktrees/route-ad6e695deb9de65c.js +1 -0
  221. package/.next/static/chunks/app/api/yjs-version/route-ad6e695deb9de65c.js +1 -0
  222. package/.next/static/chunks/app/layout-fae2b226b3c78448.js +1 -0
  223. package/.next/static/chunks/app/manifest.webmanifest/route-ad6e695deb9de65c.js +1 -0
  224. package/.next/static/chunks/app/page-d5af3bd535589daf.js +256 -0
  225. package/.next/static/chunks/next/dist/client/components/builtin/app-error-ad6e695deb9de65c.js +1 -0
  226. package/.next/static/chunks/next/dist/client/components/builtin/forbidden-ad6e695deb9de65c.js +1 -0
  227. package/.next/static/chunks/next/dist/client/components/builtin/not-found-ad6e695deb9de65c.js +1 -0
  228. package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-ad6e695deb9de65c.js +1 -0
  229. package/.next/static/chunks/{webpack-b0effde51c1651b8.js → webpack-1ce35e1249cfd931.js} +1 -1
  230. package/.next/static/css/bb9361c7f832a89d.css +1 -0
  231. package/.next/static/css/c7d127e07b1a786c.css +1 -0
  232. package/.next/trace +8 -7
  233. package/.next/trace-build +1 -1
  234. package/.next/types/app/api/boards/[id]/add-session/route.ts +353 -0
  235. package/.next/types/app/api/subagents/[id]/route.ts +353 -0
  236. package/.next/types/app/api/subagents/profiles/route.ts +353 -0
  237. package/.next/types/app/api/subagents/settings/route.ts +353 -0
  238. package/.next/types/routes.d.ts +5 -1
  239. package/.next/types/validator.ts +36 -0
  240. package/lib/api-types.ts +10 -0
  241. package/lib/board-reconcile.test.mjs +46 -8
  242. package/lib/board-reconcile.ts +57 -1
  243. package/lib/board-store.test.mjs +2 -2
  244. package/lib/chat-lazy-load.test.mjs +0 -62
  245. package/lib/chat-lazy-load.ts +0 -13
  246. package/lib/chat-only.ts +23 -0
  247. package/lib/draft-stash.ts +4 -5
  248. package/lib/file-types.ts +16 -1
  249. package/lib/i18n/messages/en.ts +91 -0
  250. package/lib/i18n/messages/zh-CN.ts +91 -0
  251. package/lib/id.test.mjs +38 -0
  252. package/lib/id.ts +17 -0
  253. package/lib/ime-guard.test.mjs +52 -0
  254. package/lib/ime-guard.ts +54 -0
  255. package/lib/message-text.ts +24 -0
  256. package/lib/models-cache.ts +1 -1
  257. package/lib/pi-types.ts +19 -1
  258. package/lib/pin-store.ts +85 -0
  259. package/lib/powershell-settings.ts +106 -0
  260. package/lib/quoted-selection.ts +4 -0
  261. package/lib/rpc-manager.activity.test.mjs +223 -0
  262. package/lib/rpc-manager.test.mjs +22 -0
  263. package/lib/rpc-manager.title.test.mjs +152 -0
  264. package/lib/rpc-manager.ts +301 -28
  265. package/lib/session-activity.test.mjs +123 -0
  266. package/lib/session-activity.ts +77 -0
  267. package/lib/session-delete.test.mjs +45 -41
  268. package/lib/session-delete.ts +8 -34
  269. package/lib/session-family.test.mjs +49 -0
  270. package/lib/session-family.ts +80 -0
  271. package/lib/session-index-scanner.test.mjs +364 -2
  272. package/lib/session-index-scanner.ts +199 -55
  273. package/lib/session-reader.noscan.test.mjs +371 -0
  274. package/lib/session-reader.project.test.mjs +30 -52
  275. package/lib/session-reader.test.mjs +2 -65
  276. package/lib/session-reader.ts +177 -213
  277. package/lib/session-scanner.test.mjs +151 -38
  278. package/lib/session-scanner.ts +140 -61
  279. package/lib/session-search.ts +6 -5
  280. package/lib/session-time-group.test.mjs +38 -0
  281. package/lib/session-time-group.ts +55 -0
  282. package/lib/settings-navigation.ts +124 -0
  283. package/lib/sqlite-db.test.mjs +26 -0
  284. package/lib/sqlite-db.ts +10 -1
  285. package/lib/subagent-extension.test.mjs +424 -0
  286. package/lib/subagent-extension.ts +309 -0
  287. package/lib/subagent-input.test.mjs +63 -0
  288. package/lib/subagent-input.ts +71 -0
  289. package/lib/subagent-profile-precedence.ts +20 -0
  290. package/lib/subagent-prompt.test.mjs +64 -0
  291. package/lib/subagent-prompt.ts +31 -0
  292. package/lib/subagent-queue.test.mjs +35 -0
  293. package/lib/subagent-queue.ts +74 -0
  294. package/lib/subagent-runtime.test.mjs +150 -0
  295. package/lib/subagent-runtime.ts +629 -0
  296. package/lib/subagent-session-title.test.mjs +120 -0
  297. package/lib/subagent-settings.test.mjs +50 -0
  298. package/lib/subagent-settings.ts +93 -0
  299. package/lib/subagents.test.mjs +601 -0
  300. package/lib/subagents.ts +602 -0
  301. package/lib/task-scheduler.test.mjs +27 -0
  302. package/lib/task-scheduler.ts +8 -1
  303. package/lib/task-store.activity.test.mjs +141 -0
  304. package/lib/task-store.meta-row.test.mjs +25 -5
  305. package/lib/task-store.partial-row.test.mjs +198 -0
  306. package/lib/task-store.subtree.test.mjs +172 -0
  307. package/lib/task-store.test.mjs +46 -20
  308. package/lib/task-store.ts +344 -68
  309. package/lib/tool-presets.ts +4 -0
  310. package/lib/types.ts +19 -0
  311. package/lib/worktree-isolation.test.mjs +51 -0
  312. package/next.config.ts +3 -1
  313. package/package.json +1 -1
  314. package/.next/static/bsW3fla0-BlBHVMKtAM5I/_buildManifest.js +0 -1
  315. package/.next/static/chunks/752.0ad92735d5f38143.js +0 -1
  316. package/.next/static/chunks/8088.53d9cdaf15634d4b.js +0 -1
  317. package/.next/static/chunks/app/_global-error/page-2d5f6296c7e693c6.js +0 -1
  318. package/.next/static/chunks/app/api/agent/[id]/bash-output/route-2d5f6296c7e693c6.js +0 -1
  319. package/.next/static/chunks/app/api/agent/[id]/events/route-2d5f6296c7e693c6.js +0 -1
  320. package/.next/static/chunks/app/api/agent/[id]/route-2d5f6296c7e693c6.js +0 -1
  321. package/.next/static/chunks/app/api/agent/new/route-2d5f6296c7e693c6.js +0 -1
  322. package/.next/static/chunks/app/api/agent/running/route-2d5f6296c7e693c6.js +0 -1
  323. package/.next/static/chunks/app/api/app-update/route-2d5f6296c7e693c6.js +0 -1
  324. package/.next/static/chunks/app/api/auth/all-providers/route-2d5f6296c7e693c6.js +0 -1
  325. package/.next/static/chunks/app/api/auth/api-key/[provider]/route-2d5f6296c7e693c6.js +0 -1
  326. package/.next/static/chunks/app/api/auth/login/[provider]/route-2d5f6296c7e693c6.js +0 -1
  327. package/.next/static/chunks/app/api/auth/logout/[provider]/route-2d5f6296c7e693c6.js +0 -1
  328. package/.next/static/chunks/app/api/auth/providers/route-2d5f6296c7e693c6.js +0 -1
  329. package/.next/static/chunks/app/api/board-assets/[...path]/route-2d5f6296c7e693c6.js +0 -1
  330. package/.next/static/chunks/app/api/board-assets/route-2d5f6296c7e693c6.js +0 -1
  331. package/.next/static/chunks/app/api/boards/[id]/reconcile/route-2d5f6296c7e693c6.js +0 -1
  332. package/.next/static/chunks/app/api/boards/[id]/route-2d5f6296c7e693c6.js +0 -1
  333. package/.next/static/chunks/app/api/boards/reorder/route-2d5f6296c7e693c6.js +0 -1
  334. package/.next/static/chunks/app/api/boards/route-2d5f6296c7e693c6.js +0 -1
  335. package/.next/static/chunks/app/api/cwd/browse/route-2d5f6296c7e693c6.js +0 -1
  336. package/.next/static/chunks/app/api/cwd/validate/route-2d5f6296c7e693c6.js +0 -1
  337. package/.next/static/chunks/app/api/default-cwd/route-2d5f6296c7e693c6.js +0 -1
  338. package/.next/static/chunks/app/api/file-index/route-2d5f6296c7e693c6.js +0 -1
  339. package/.next/static/chunks/app/api/files/[...path]/route-2d5f6296c7e693c6.js +0 -1
  340. package/.next/static/chunks/app/api/git/diff/route-2d5f6296c7e693c6.js +0 -1
  341. package/.next/static/chunks/app/api/git/status/route-2d5f6296c7e693c6.js +0 -1
  342. package/.next/static/chunks/app/api/home/route-2d5f6296c7e693c6.js +0 -1
  343. package/.next/static/chunks/app/api/mcp/route-2d5f6296c7e693c6.js +0 -1
  344. package/.next/static/chunks/app/api/models/route-2d5f6296c7e693c6.js +0 -1
  345. package/.next/static/chunks/app/api/models-config/catalog/route-2d5f6296c7e693c6.js +0 -1
  346. package/.next/static/chunks/app/api/models-config/discover/route-2d5f6296c7e693c6.js +0 -1
  347. package/.next/static/chunks/app/api/models-config/route-2d5f6296c7e693c6.js +0 -1
  348. package/.next/static/chunks/app/api/models-config/test/route-2d5f6296c7e693c6.js +0 -1
  349. package/.next/static/chunks/app/api/plugins/route-2d5f6296c7e693c6.js +0 -1
  350. package/.next/static/chunks/app/api/project-trust/route-2d5f6296c7e693c6.js +0 -1
  351. package/.next/static/chunks/app/api/quota/route-2d5f6296c7e693c6.js +0 -1
  352. package/.next/static/chunks/app/api/search/route-2d5f6296c7e693c6.js +0 -1
  353. package/.next/static/chunks/app/api/sessions/[id]/auto-name/route-2d5f6296c7e693c6.js +0 -1
  354. package/.next/static/chunks/app/api/sessions/[id]/context/route-2d5f6296c7e693c6.js +0 -1
  355. package/.next/static/chunks/app/api/sessions/[id]/entries/[entryId]/thinking/route-2d5f6296c7e693c6.js +0 -1
  356. package/.next/static/chunks/app/api/sessions/[id]/export/route-2d5f6296c7e693c6.js +0 -1
  357. package/.next/static/chunks/app/api/sessions/[id]/minimap/route-2d5f6296c7e693c6.js +0 -1
  358. package/.next/static/chunks/app/api/sessions/[id]/route-2d5f6296c7e693c6.js +0 -1
  359. package/.next/static/chunks/app/api/sessions/[id]/state/route-2d5f6296c7e693c6.js +0 -1
  360. package/.next/static/chunks/app/api/sessions/[id]/todos/route-2d5f6296c7e693c6.js +0 -1
  361. package/.next/static/chunks/app/api/sessions/route-2d5f6296c7e693c6.js +0 -1
  362. package/.next/static/chunks/app/api/sessions/summary/route-2d5f6296c7e693c6.js +0 -1
  363. package/.next/static/chunks/app/api/skills/check/route-2d5f6296c7e693c6.js +0 -1
  364. package/.next/static/chunks/app/api/skills/install/route-2d5f6296c7e693c6.js +0 -1
  365. package/.next/static/chunks/app/api/skills/route-2d5f6296c7e693c6.js +0 -1
  366. package/.next/static/chunks/app/api/skills/search/route-2d5f6296c7e693c6.js +0 -1
  367. package/.next/static/chunks/app/api/skills/update/route-2d5f6296c7e693c6.js +0 -1
  368. package/.next/static/chunks/app/api/task-card-questions/[id]/answer/route-2d5f6296c7e693c6.js +0 -1
  369. package/.next/static/chunks/app/api/task-card-questions/route-2d5f6296c7e693c6.js +0 -1
  370. package/.next/static/chunks/app/api/task-cards/[id]/route-2d5f6296c7e693c6.js +0 -1
  371. package/.next/static/chunks/app/api/task-cards/route-2d5f6296c7e693c6.js +0 -1
  372. package/.next/static/chunks/app/api/task-cards/unbind/route-2d5f6296c7e693c6.js +0 -1
  373. package/.next/static/chunks/app/api/task-scheduler/status/route-2d5f6296c7e693c6.js +0 -1
  374. package/.next/static/chunks/app/api/tasks/[id]/assign-session/route-2d5f6296c7e693c6.js +0 -1
  375. package/.next/static/chunks/app/api/tasks/[id]/board/route-2d5f6296c7e693c6.js +0 -1
  376. package/.next/static/chunks/app/api/tasks/[id]/route-2d5f6296c7e693c6.js +0 -1
  377. package/.next/static/chunks/app/api/tasks/reorder/route-2d5f6296c7e693c6.js +0 -1
  378. package/.next/static/chunks/app/api/tasks/route-2d5f6296c7e693c6.js +0 -1
  379. package/.next/static/chunks/app/api/terminal/[id]/events/route-2d5f6296c7e693c6.js +0 -1
  380. package/.next/static/chunks/app/api/terminal/[id]/route-2d5f6296c7e693c6.js +0 -1
  381. package/.next/static/chunks/app/api/terminal/route-2d5f6296c7e693c6.js +0 -1
  382. package/.next/static/chunks/app/api/worktrees/route-2d5f6296c7e693c6.js +0 -1
  383. package/.next/static/chunks/app/api/yjs-version/route-2d5f6296c7e693c6.js +0 -1
  384. package/.next/static/chunks/app/layout-dace09825b2d3857.js +0 -1
  385. package/.next/static/chunks/app/manifest.webmanifest/route-2d5f6296c7e693c6.js +0 -1
  386. package/.next/static/chunks/app/page-64b9f4b3567a2f73.js +0 -89
  387. package/.next/static/chunks/next/dist/client/components/builtin/app-error-2d5f6296c7e693c6.js +0 -1
  388. package/.next/static/chunks/next/dist/client/components/builtin/forbidden-2d5f6296c7e693c6.js +0 -1
  389. package/.next/static/chunks/next/dist/client/components/builtin/not-found-2d5f6296c7e693c6.js +0 -1
  390. package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-2d5f6296c7e693c6.js +0 -1
  391. package/.next/static/css/fd25673802257262.css +0 -1
  392. package/lib/extension-command.test.mjs +0 -63
  393. package/lib/extension-command.ts +0 -81
  394. package/lib/subagent-widget.test.mjs +0 -87
  395. package/lib/subagent-widget.ts +0 -109
  396. /package/.next/static/{bsW3fla0-BlBHVMKtAM5I → MPBMmQqmDG8zo8tM_bkDy}/_ssgManifest.js +0 -0
@@ -0,0 +1,629 @@
1
+ import type { ThinkingLevel } from "@earendil-works/pi-agent-core";
2
+ import {
3
+ createAgentSessionFromServices,
4
+ createAgentSessionServices,
5
+ getAgentDir,
6
+ initTheme,
7
+ SessionManager,
8
+ SettingsManager,
9
+ type ModelRuntime,
10
+ } from "@earendil-works/pi-coding-agent";
11
+ import type { AgentSessionLike } from "./pi-types";
12
+ import {
13
+ subagentFinalText,
14
+ subagentToolDetails,
15
+ type ResumeSubagentRequest,
16
+ type StartSubagentRequest,
17
+ type SubagentExecution,
18
+ type SubagentExtensionRuntime,
19
+ } from "./subagent-extension";
20
+ import {
21
+ readSubagentRun,
22
+ resolveSubagentProfile,
23
+ SUBAGENT_CONTROL_TOOL_NAMES,
24
+ SUBAGENT_META_TYPE,
25
+ SUBAGENT_STATUS_TYPE,
26
+ SUBAGENT_RESULT_TYPE,
27
+ selectSubagentExtensionTools,
28
+ withSubagentExtensionTools,
29
+ type SubagentMetadata,
30
+ type SubagentResultMetadata,
31
+ type SubagentRunInfo,
32
+ } from "./subagents";
33
+ import type { SessionEntry } from "./types";
34
+ import { buildSubagentPromptPlan } from "./subagent-prompt";
35
+ import { appendSubagentInputFiles, loadSubagentInputFiles } from "./subagent-input";
36
+ import { projectTrustReloadOptions } from "./project-trust";
37
+ import { resolveShellTools } from "./powershell-settings";
38
+ import { isBuiltInSubagentsEnabled, readSubagentSettings } from "./subagent-settings";
39
+ import { SubagentQueue } from "./subagent-queue";
40
+ import { addWorktree, removeWorktree } from "./worktree";
41
+ import { projectIdentityKey } from "./project-identity";
42
+ import { ensureSessionMetaRow, taskForSession } from "./task-store";
43
+ import { randomUUID } from "node:crypto";
44
+
45
+ interface HostSession {
46
+ readonly inner: AgentSessionLike;
47
+ readonly sessionFile: string;
48
+ readonly cwd: string;
49
+ isAlive(): boolean;
50
+ isRunning(): boolean;
51
+ waitUntilReady(): Promise<void>;
52
+ }
53
+
54
+ export interface SubagentRuntimeDependencies {
55
+ getSession(sessionId: string): HostSession | undefined;
56
+ registerSession(
57
+ inner: AgentSessionLike,
58
+ options?: { exactSystemPrompt?: string; chatOnly?: boolean },
59
+ ): void;
60
+ reopenSession(sessionId: string, sessionFile: string): Promise<HostSession>;
61
+ resolveSessionPath(sessionId: string): Promise<string | null>;
62
+ invalidateSessionList(): void;
63
+ isBuiltInSubagentsEnabled?(): boolean;
64
+ }
65
+
66
+ export interface SubagentController {
67
+ readonly extensionRuntime: SubagentExtensionRuntime;
68
+ get(sessionId: string): Promise<SubagentRunInfo | null>;
69
+ steer(sessionId: string, message: string): Promise<void>;
70
+ abort(sessionId: string): Promise<void>;
71
+ }
72
+
73
+ type StoredSubagentExecution = {
74
+ run: SubagentRunInfo;
75
+ completion: Promise<SubagentRunInfo>;
76
+ abortRequested: boolean;
77
+ cancelQueued?: () => boolean;
78
+ };
79
+
80
+ declare global {
81
+ var __piSubagentRuns: Map<string, StoredSubagentExecution> | undefined;
82
+ var __piSubagentQueue: SubagentQueue<SubagentRunInfo> | undefined;
83
+ }
84
+ const SUBAGENT_CONTEXT_LIMIT = 50_000;
85
+ const THINKING_LEVELS = new Set<ThinkingLevel>(["off", "minimal", "low", "medium", "high", "xhigh", "max"]);
86
+
87
+ function getSubagentRuns(): Map<string, StoredSubagentExecution> {
88
+ if (!globalThis.__piSubagentRuns) globalThis.__piSubagentRuns = new Map();
89
+ return globalThis.__piSubagentRuns;
90
+ }
91
+
92
+ function getSubagentQueue(): SubagentQueue<SubagentRunInfo> {
93
+ if (!globalThis.__piSubagentQueue) globalThis.__piSubagentQueue = new SubagentQueue();
94
+ return globalThis.__piSubagentQueue;
95
+ }
96
+
97
+ function parseSubagentModel(runtime: ModelRuntime, value: string | undefined) {
98
+ if (!value?.trim()) return undefined;
99
+ const requested = value.trim();
100
+ const slash = requested.indexOf("/");
101
+ if (slash > 0) {
102
+ const provider = requested.slice(0, slash);
103
+ const modelId = requested.slice(slash + 1);
104
+ const model = runtime.getModel(provider, modelId);
105
+ if (!model) throw new Error(`Subagent model not found: ${requested}`);
106
+ return model;
107
+ }
108
+ const matches = runtime.getModels().filter((model) => model.id === requested);
109
+ if (matches.length === 1) return matches[0];
110
+ if (matches.length === 0) throw new Error(`Subagent model not found: ${requested}`);
111
+ throw new Error(`Subagent model is ambiguous; use provider/modelId: ${requested}`);
112
+ }
113
+
114
+ function parentContextText(parent: HostSession): string {
115
+ const messages = parent.inner.sessionManager.buildSessionContext().messages;
116
+ const serialized = JSON.stringify(messages);
117
+ if (serialized.length <= SUBAGENT_CONTEXT_LIMIT) return serialized;
118
+ return `${serialized.slice(0, SUBAGENT_CONTEXT_LIMIT)}\n[Parent context truncated]`;
119
+ }
120
+
121
+ async function cleanupWorktree(
122
+ parentCwd: string,
123
+ worktree: { path: string; branch: string } | undefined,
124
+ ): Promise<string | undefined> {
125
+ if (!worktree) return undefined;
126
+ try {
127
+ await removeWorktree(parentCwd, worktree.path);
128
+ return undefined;
129
+ } catch (error) {
130
+ return `Worktree retained at ${worktree.path}: ${error instanceof Error ? error.message : String(error)}`;
131
+ }
132
+ }
133
+
134
+ /** 内置 subagent 出生即建行(父会话归属 + 任务归属,否则只会在聊天区当孤儿根出现)。
135
+ * `title` **只**取 `description`(用户 2026-09-18 规则:描述有值即会话标题,展示优先于首条消息);
136
+ * 空/全空白不写 title——既不写空串、也不拿 run 元数据里的 profile 显示名兜底(展示链是
137
+ * `title || first_message`,拿 "Explore" 当标题会把被委派任务的原文挤掉,正是要修的病)。
138
+ * `first_message` 是内容派生列,这里**不写**:留给扫描器/事件链路按真实首条用户消息回填,
139
+ * 否则「首条消息」会变成 describe 文案而不是被委派的任务。 */
140
+ export function ensureSubagentSessionRow(sessionId: string, row: {
141
+ path: string;
142
+ cwd: string;
143
+ projectKey: string;
144
+ parentId: string;
145
+ taskId?: string | null;
146
+ /** Agent 工具传来的短描述(request.description)——有值即标题。 */
147
+ description: string;
148
+ }): void {
149
+ const title = row.description.trim();
150
+ ensureSessionMetaRow(sessionId, {
151
+ path: row.path,
152
+ cwd: row.cwd,
153
+ projectKey: row.projectKey,
154
+ parentId: row.parentId,
155
+ taskId: row.taskId,
156
+ ...(title ? { title } : {}),
157
+ });
158
+ }
159
+
160
+ export function createSubagentController(
161
+ dependencies: SubagentRuntimeDependencies,
162
+ ): SubagentController {
163
+ async function start(request: StartSubagentRequest): Promise<SubagentExecution> {
164
+ const enabled = dependencies.isBuiltInSubagentsEnabled ?? isBuiltInSubagentsEnabled;
165
+ if (!enabled()) throw new Error("Pi Web built-in sub-agents are disabled");
166
+ const parentSessionId = request.parentContext.sessionManager.getSessionId();
167
+ const parent = dependencies.getSession(parentSessionId);
168
+ if (!parent?.isAlive()) throw new Error("Parent session is no longer available");
169
+ if (!parent.sessionFile) throw new Error("Parent session must be persisted before starting a subagent");
170
+
171
+ let isolatedWorktree: { path: string; branch: string } | undefined;
172
+ try {
173
+ const profile = resolveSubagentProfile(parent.cwd, request.profile);
174
+ if (!profile) throw new Error(`Unknown or disabled subagent profile: ${request.profile}`);
175
+
176
+ const runInBackground = request.runInBackground ?? profile.runInBackground;
177
+ const isolation = profile.isolation === "off" ? undefined : request.isolation ?? profile.isolation;
178
+ if (isolation === "worktree") {
179
+ isolatedWorktree = await addWorktree(parent.cwd, `pi-web-agent-${randomUUID()}`);
180
+ }
181
+ const childCwd = isolatedWorktree?.path ?? parent.cwd;
182
+ const inheritContext = request.inheritContext ?? profile.inheritContext;
183
+ const maxTurns = request.maxTurns ?? profile.maxTurns;
184
+ if (maxTurns !== undefined && (!Number.isFinite(maxTurns) || maxTurns < 0)) {
185
+ throw new Error("max_turns must be a non-negative number");
186
+ }
187
+ const turnLimit = maxTurns && maxTurns > 0 ? Math.floor(maxTurns) : undefined;
188
+ const thinking = request.thinking ?? profile.thinking ?? parent.inner.agent.state?.thinkingLevel;
189
+ if (thinking && !THINKING_LEVELS.has(thinking as ThinkingLevel)) {
190
+ throw new Error(`Invalid subagent thinking level: ${thinking}`);
191
+ }
192
+
193
+ const agentDir = getAgentDir();
194
+ const parentModelRuntime = (parent.inner as unknown as { modelRuntime: ModelRuntime }).modelRuntime;
195
+ const settingsManager = SettingsManager.create(childCwd, agentDir);
196
+ const inheritedParentContext = inheritContext
197
+ ? `The following is the active conversation context from the parent session. Use it only as background for the delegated task:\n${parentContextText(parent)}`
198
+ : undefined;
199
+ const inputFiles = loadSubagentInputFiles(parent.cwd, request.inputFiles ?? []);
200
+ const promptPlan = buildSubagentPromptPlan({
201
+ profileSystemPrompt: profile.systemPrompt,
202
+ tools: profile.tools,
203
+ loadSkills: profile.loadSkills,
204
+ loadExtensions: profile.loadExtensions,
205
+ promptMode: profile.promptMode,
206
+ task: appendSubagentInputFiles(request.task, inputFiles),
207
+ inheritedParentContext,
208
+ });
209
+ const { chatOnly, appendSystemPrompt, delegatedTask } = promptPlan;
210
+ if (!chatOnly) initTheme();
211
+ const services = await createAgentSessionServices({
212
+ cwd: childCwd,
213
+ agentDir,
214
+ modelRuntime: parentModelRuntime,
215
+ settingsManager,
216
+ resourceLoaderOptions: {
217
+ noExtensions: !profile.loadExtensions,
218
+ noSkills: !profile.loadSkills,
219
+ noPromptTemplates: true,
220
+ noThemes: true,
221
+ noContextFiles: true,
222
+ ...(chatOnly || promptPlan.exactSystemPrompt !== undefined
223
+ ? {
224
+ systemPrompt: " ",
225
+ systemPromptOverride: () => undefined,
226
+ }
227
+ : {}),
228
+ appendSystemPrompt,
229
+ },
230
+ ...((profile.loadExtensions || profile.loadSkills)
231
+ ? { resourceLoaderReloadOptions: projectTrustReloadOptions(childCwd, agentDir) }
232
+ : {}),
233
+ });
234
+
235
+ const extensionToolNames = profile.loadExtensions
236
+ ? profile.extensionTools?.length
237
+ ? selectSubagentExtensionTools(services.resourceLoader.getExtensions().extensions, profile.extensionTools)
238
+ : services.resourceLoader.getExtensions().extensions.flatMap((extension) => [...extension.tools.keys()])
239
+ : [];
240
+ const activeTools = resolveShellTools(
241
+ withSubagentExtensionTools(profile.tools, extensionToolNames),
242
+ settingsManager.getDefaultTools(),
243
+ );
244
+
245
+ const sessionManager = isolatedWorktree
246
+ ? SessionManager.create(childCwd, undefined, { parentSession: parent.sessionFile })
247
+ : SessionManager.create(parent.cwd, undefined, { parentSession: parent.sessionFile });
248
+ const createdAt = new Date().toISOString();
249
+ const metadata: SubagentMetadata = {
250
+ version: 1,
251
+ parentSessionId,
252
+ parentSessionPath: parent.sessionFile,
253
+ parentToolCallId: request.parentToolCallId,
254
+ profile: profile.name,
255
+ description: request.description.trim() || profile.displayName,
256
+ task: request.task,
257
+ runInBackground,
258
+ createdAt,
259
+ resourceSnapshot: {
260
+ version: 1,
261
+ appendSystemPrompt: [...appendSystemPrompt],
262
+ tools: [...activeTools],
263
+ loadSkills: profile.loadSkills,
264
+ loadExtensions: profile.loadExtensions,
265
+ ...(promptPlan.exactSystemPrompt !== undefined ? { exactSystemPrompt: promptPlan.exactSystemPrompt } : {}),
266
+ },
267
+ ...(isolatedWorktree ? { worktreePath: isolatedWorktree.path, worktreeBranch: isolatedWorktree.branch } : {}),
268
+ };
269
+ sessionManager.appendCustomEntry(SUBAGENT_META_TYPE, metadata);
270
+ sessionManager.appendSessionInfo(metadata.description);
271
+
272
+ const requestedModel = parseSubagentModel(parentModelRuntime, request.model ?? profile.model);
273
+ const parentModel = parent.inner.model as ReturnType<ModelRuntime["getModel"]>;
274
+ const { session: inner } = await createAgentSessionFromServices({
275
+ services,
276
+ sessionManager,
277
+ model: requestedModel ?? parentModel,
278
+ ...(thinking ? { thinkingLevel: thinking as ThinkingLevel } : {}),
279
+ tools: activeTools,
280
+ excludeTools: [...SUBAGENT_CONTROL_TOOL_NAMES],
281
+ });
282
+ dependencies.registerSession(inner, {
283
+ ...(promptPlan.exactSystemPrompt !== undefined
284
+ ? { exactSystemPrompt: promptPlan.exactSystemPrompt }
285
+ : {}),
286
+ chatOnly,
287
+ });
288
+
289
+ // 子代理会话与 fork 同规则:落库即带父会话归属(否则只会在聊天区当孤儿根出现)。
290
+ try {
291
+ ensureSubagentSessionRow(inner.sessionId, {
292
+ path: inner.sessionFile ?? "",
293
+ cwd: (isolatedWorktree ? childCwd : parent.cwd) ?? "",
294
+ projectKey: projectIdentityKey((isolatedWorktree ? childCwd : parent.cwd) ?? ""),
295
+ parentId: parentSessionId,
296
+ taskId: taskForSession(parentSessionId),
297
+ description: request.description,
298
+ });
299
+ } catch (e) {
300
+ console.error("[pi-web] subagent 会话建行失败:", e instanceof Error ? e.message : String(e));
301
+ }
302
+
303
+ const initialRun: SubagentRunInfo = {
304
+ sessionId: inner.sessionId,
305
+ sessionPath: inner.sessionFile ?? sessionManager.getSessionFile() ?? "",
306
+ parentSessionId,
307
+ parentToolCallId: request.parentToolCallId,
308
+ profile: profile.name,
309
+ description: metadata.description,
310
+ task: request.task,
311
+ runInBackground,
312
+ status: "queued",
313
+ createdAt,
314
+ ...(isolatedWorktree ? { worktreePath: isolatedWorktree.path, worktreeBranch: isolatedWorktree.branch } : {}),
315
+ };
316
+
317
+ let turnCount = 0;
318
+ let maxTurnsReached = false;
319
+ let softLimitReached = false;
320
+ const unsubscribeTurns = turnLimit
321
+ ? inner.subscribe((event) => {
322
+ if (event.type !== "turn_end") return;
323
+ turnCount += 1;
324
+ if (!softLimitReached && turnCount >= turnLimit) {
325
+ softLimitReached = true;
326
+ void inner.steer("You have reached your turn limit. Wrap up immediately and provide your final answer now.");
327
+ } else if (softLimitReached && turnCount >= turnLimit + 1) {
328
+ maxTurnsReached = true;
329
+ void inner.abort();
330
+ }
331
+ })
332
+ : () => {};
333
+ let resolveCompletion!: (run: SubagentRunInfo) => void;
334
+ const completion = new Promise<SubagentRunInfo>((resolve) => { resolveCompletion = resolve; });
335
+ const stored: StoredSubagentExecution = {
336
+ run: initialRun,
337
+ completion,
338
+ abortRequested: false,
339
+ };
340
+ getSubagentRuns().set(initialRun.sessionId, stored);
341
+ request.onUpdate?.(initialRun);
342
+ dependencies.invalidateSessionList();
343
+
344
+ const handleParentAbort = () => {
345
+ stored.abortRequested = true;
346
+ if (stored.run.status === "queued") stored.cancelQueued?.();
347
+ else void inner.abort();
348
+ };
349
+ if (!runInBackground) request.signal?.addEventListener("abort", handleParentAbort, { once: true });
350
+
351
+ const execute = async (): Promise<SubagentRunInfo> => {
352
+ if (stored.abortRequested) {
353
+ const result: SubagentRunInfo = { ...initialRun, status: "aborted", completedAt: new Date().toISOString() };
354
+ sessionManager.appendCustomEntry(SUBAGENT_RESULT_TYPE, { version: 1, status: "aborted", completedAt: result.completedAt });
355
+ await cleanupWorktree(parent.cwd, isolatedWorktree);
356
+ stored.run = result;
357
+ request.onUpdate?.(result);
358
+ getSubagentRuns().delete(initialRun.sessionId);
359
+ dependencies.invalidateSessionList();
360
+ return result;
361
+ }
362
+ stored.run = { ...stored.run, status: "running" };
363
+ sessionManager.appendCustomEntry(SUBAGENT_STATUS_TYPE, { version: 1, status: "running" });
364
+ request.onUpdate?.(stored.run);
365
+ dependencies.invalidateSessionList();
366
+ let result: SubagentRunInfo;
367
+ try {
368
+ await inner.prompt(delegatedTask, {
369
+ source: "rpc",
370
+ ...(chatOnly
371
+ ? {
372
+ preflightResult: (success: boolean) => {
373
+ if (success && inner.agent.state) {
374
+ inner.agent.state.systemPrompt = profile.systemPrompt;
375
+ }
376
+ },
377
+ }
378
+ : {}),
379
+ });
380
+ const text = inner.getLastAssistantText()?.trim();
381
+ const aborted = stored.abortRequested && !maxTurnsReached;
382
+ result = {
383
+ ...initialRun,
384
+ status: aborted ? "aborted" : "completed",
385
+ completedAt: new Date().toISOString(),
386
+ ...(text ? { result: text } : {}),
387
+ };
388
+ } catch (error) {
389
+ const text = inner.getLastAssistantText()?.trim();
390
+ const aborted = stored.abortRequested || request.signal?.aborted;
391
+ result = {
392
+ ...initialRun,
393
+ status: aborted ? "aborted" : maxTurnsReached ? "completed" : "failed",
394
+ completedAt: new Date().toISOString(),
395
+ ...(text ? { result: text } : {}),
396
+ ...(!aborted && !maxTurnsReached
397
+ ? { error: error instanceof Error ? error.message : String(error) }
398
+ : {}),
399
+ };
400
+ } finally {
401
+ unsubscribeTurns();
402
+ request.signal?.removeEventListener("abort", handleParentAbort);
403
+ }
404
+
405
+ const cleanupError = await cleanupWorktree(parent.cwd, isolatedWorktree);
406
+ if (cleanupError) result = { ...result, worktreeCleanupError: cleanupError };
407
+ const persisted: SubagentResultMetadata = {
408
+ version: 1,
409
+ status: result.status as SubagentResultMetadata["status"],
410
+ completedAt: result.completedAt!,
411
+ ...(result.result ? { result: result.result } : {}),
412
+ ...(result.error ? { error: result.error } : {}),
413
+ ...(result.worktreeCleanupError ? { worktreeCleanupError: result.worktreeCleanupError } : {}),
414
+ };
415
+ sessionManager.appendCustomEntry(SUBAGENT_RESULT_TYPE, persisted);
416
+ stored.run = result;
417
+ request.onUpdate?.(result);
418
+ getSubagentRuns().delete(initialRun.sessionId);
419
+ dependencies.invalidateSessionList();
420
+ return result;
421
+ };
422
+
423
+ const finishQueuedAbort = async () => {
424
+ if (stored.run.status !== "queued") return;
425
+ const result: SubagentRunInfo = { ...initialRun, status: "aborted", completedAt: new Date().toISOString() };
426
+ const cleanupError = await cleanupWorktree(parent.cwd, isolatedWorktree);
427
+ const finalResult = cleanupError ? { ...result, worktreeCleanupError: cleanupError } : result;
428
+ sessionManager.appendCustomEntry(SUBAGENT_RESULT_TYPE, { version: 1, status: "aborted", completedAt: finalResult.completedAt, ...(cleanupError ? { worktreeCleanupError: cleanupError } : {}) });
429
+ stored.run = finalResult;
430
+ request.onUpdate?.(finalResult);
431
+ getSubagentRuns().delete(initialRun.sessionId);
432
+ dependencies.invalidateSessionList();
433
+ resolveCompletion(finalResult);
434
+ };
435
+ const queued = getSubagentQueue().enqueue(
436
+ parentSessionId,
437
+ readSubagentSettings().maxConcurrent,
438
+ execute,
439
+ (state) => {
440
+ if (state === "queued") {
441
+ sessionManager.appendCustomEntry(SUBAGENT_STATUS_TYPE, { version: 1, status: "queued" });
442
+ }
443
+ request.onUpdate?.({ ...stored.run, status: state });
444
+ stored.run = { ...stored.run, status: state };
445
+ dependencies.invalidateSessionList();
446
+ },
447
+ finishQueuedAbort,
448
+ );
449
+ stored.cancelQueued = queued.cancel;
450
+ void queued.promise.then(resolveCompletion, (error) => {
451
+ resolveCompletion({ ...initialRun, status: "failed", completedAt: new Date().toISOString(), error: error instanceof Error ? error.message : String(error) });
452
+ });
453
+
454
+ return { run: stored.run, completion: stored.completion };
455
+ } catch (error) {
456
+ if (isolatedWorktree) {
457
+ try { await removeWorktree(parent.cwd, isolatedWorktree.path); } catch { /* preserve setup failure and avoid force deletion */ }
458
+ }
459
+ throw error;
460
+ }
461
+ }
462
+
463
+ async function resume(request: ResumeSubagentRequest): Promise<SubagentExecution> {
464
+ const enabled = dependencies.isBuiltInSubagentsEnabled ?? isBuiltInSubagentsEnabled;
465
+ if (!enabled()) throw new Error("Pi Web built-in sub-agents are disabled");
466
+ const parentSessionId = request.parentContext.sessionManager.getSessionId();
467
+ const existing = await get(request.sessionId);
468
+ if (!existing) throw new Error(`Subagent not found: ${request.sessionId}`);
469
+ if (existing.parentSessionId !== parentSessionId) throw new Error("Subagent does not belong to this parent session");
470
+ if (existing.status === "running" || existing.status === "queued") throw new Error("Subagent is already running");
471
+ const parent = dependencies.getSession(parentSessionId);
472
+ if (!parent?.isAlive()) throw new Error("Parent session is no longer available");
473
+ const sessionPath = existing.sessionPath || await dependencies.resolveSessionPath(request.sessionId);
474
+ if (!sessionPath) throw new Error(`Subagent session file not found: ${request.sessionId}`);
475
+ let wrapper = dependencies.getSession(request.sessionId);
476
+ if (!wrapper?.isAlive()) wrapper = await dependencies.reopenSession(request.sessionId, sessionPath);
477
+ if (!wrapper.isAlive()) throw new Error("Subagent session is no longer available");
478
+ if (wrapper.isRunning()) throw new Error("Subagent is already running");
479
+
480
+ const runInBackground = request.runInBackground ?? existing.runInBackground;
481
+ const initialRun: SubagentRunInfo = {
482
+ ...existing,
483
+ parentToolCallId: request.parentToolCallId,
484
+ task: request.task,
485
+ description: request.description.trim() || existing.description,
486
+ runInBackground,
487
+ status: "queued",
488
+ completedAt: undefined,
489
+ result: undefined,
490
+ error: undefined,
491
+ };
492
+ const manager = wrapper.inner.sessionManager;
493
+ let resolveCompletion!: (run: SubagentRunInfo) => void;
494
+ const completion = new Promise<SubagentRunInfo>((resolve) => { resolveCompletion = resolve; });
495
+ const stored: StoredSubagentExecution = { run: initialRun, completion, abortRequested: false };
496
+ getSubagentRuns().set(request.sessionId, stored);
497
+ request.onUpdate?.(initialRun);
498
+ dependencies.invalidateSessionList();
499
+ const handleParentAbort = () => {
500
+ stored.abortRequested = true;
501
+ if (stored.run.status === "queued") stored.cancelQueued?.();
502
+ else void wrapper!.inner.abort();
503
+ };
504
+ if (!runInBackground) request.signal?.addEventListener("abort", handleParentAbort, { once: true });
505
+
506
+ const execute = async (): Promise<SubagentRunInfo> => {
507
+ if (stored.abortRequested) {
508
+ const result: SubagentRunInfo = { ...initialRun, status: "aborted", completedAt: new Date().toISOString() };
509
+ manager.appendCustomEntry(SUBAGENT_RESULT_TYPE, { version: 1, status: "aborted", completedAt: result.completedAt });
510
+ stored.run = result;
511
+ getSubagentRuns().delete(request.sessionId);
512
+ resolveCompletion(result);
513
+ return result;
514
+ }
515
+ stored.run = { ...stored.run, status: "running" };
516
+ manager.appendCustomEntry(SUBAGENT_STATUS_TYPE, { version: 1, status: "running" });
517
+ request.onUpdate?.(stored.run);
518
+ let result: SubagentRunInfo;
519
+ try {
520
+ await wrapper!.inner.prompt(request.task, { source: "rpc" });
521
+ const text = wrapper!.inner.getLastAssistantText()?.trim();
522
+ result = { ...initialRun, status: stored.abortRequested ? "aborted" : "completed", completedAt: new Date().toISOString(), ...(text ? { result: text } : {}) };
523
+ } catch (error) {
524
+ result = {
525
+ ...initialRun,
526
+ status: stored.abortRequested || request.signal?.aborted ? "aborted" : "failed",
527
+ completedAt: new Date().toISOString(),
528
+ ...(!stored.abortRequested && !request.signal?.aborted ? { error: error instanceof Error ? error.message : String(error) } : {}),
529
+ };
530
+ } finally {
531
+ request.signal?.removeEventListener("abort", handleParentAbort);
532
+ }
533
+ manager.appendCustomEntry(SUBAGENT_RESULT_TYPE, {
534
+ version: 1,
535
+ status: result.status as "completed" | "failed" | "aborted",
536
+ completedAt: result.completedAt!,
537
+ ...(result.result ? { result: result.result } : {}),
538
+ ...(result.error ? { error: result.error } : {}),
539
+ });
540
+ stored.run = result;
541
+ request.onUpdate?.(result);
542
+ getSubagentRuns().delete(request.sessionId);
543
+ dependencies.invalidateSessionList();
544
+ return result;
545
+ };
546
+ const finishQueuedAbort = () => {
547
+ if (stored.run.status !== "queued") return;
548
+ const result: SubagentRunInfo = { ...initialRun, status: "aborted", completedAt: new Date().toISOString() };
549
+ manager.appendCustomEntry(SUBAGENT_RESULT_TYPE, { version: 1, status: "aborted", completedAt: result.completedAt });
550
+ stored.run = result;
551
+ request.onUpdate?.(result);
552
+ getSubagentRuns().delete(request.sessionId);
553
+ dependencies.invalidateSessionList();
554
+ resolveCompletion(result);
555
+ };
556
+ const queued = getSubagentQueue().enqueue(parentSessionId, readSubagentSettings().maxConcurrent, execute, (state) => {
557
+ if (state === "queued") manager.appendCustomEntry(SUBAGENT_STATUS_TYPE, { version: 1, status: "queued" });
558
+ stored.run = { ...stored.run, status: state };
559
+ request.onUpdate?.(stored.run);
560
+ dependencies.invalidateSessionList();
561
+ }, finishQueuedAbort);
562
+ stored.cancelQueued = queued.cancel;
563
+ void queued.promise.then(resolveCompletion, (error) => resolveCompletion({ ...initialRun, status: "failed", completedAt: new Date().toISOString(), error: error instanceof Error ? error.message : String(error) }));
564
+ return { run: stored.run, completion };
565
+ }
566
+
567
+ async function get(sessionId: string): Promise<SubagentRunInfo | null> {
568
+ const stored = getSubagentRuns().get(sessionId);
569
+ if (stored) return stored.run;
570
+ const wrapper = dependencies.getSession(sessionId);
571
+ if (wrapper?.isAlive()) {
572
+ const run = readSubagentRun(
573
+ wrapper.inner.sessionManager.getEntries() as unknown as SessionEntry[],
574
+ sessionId,
575
+ wrapper.sessionFile,
576
+ );
577
+ if (run && wrapper.isRunning()) return { ...run, status: "running" };
578
+ if (run) return run;
579
+ }
580
+ const sessionPath = await dependencies.resolveSessionPath(sessionId);
581
+ if (!sessionPath) return null;
582
+ const manager = SessionManager.open(sessionPath);
583
+ return readSubagentRun(manager.getEntries() as unknown as SessionEntry[], sessionId, sessionPath);
584
+ }
585
+
586
+ async function steer(sessionId: string, message: string): Promise<void> {
587
+ const wrapper = dependencies.getSession(sessionId);
588
+ if (!wrapper?.isAlive() || !wrapper.isRunning()) throw new Error("Subagent is not running");
589
+ if (!message.trim()) throw new Error("Steering message is required");
590
+ await wrapper.inner.steer(message.trim());
591
+ }
592
+
593
+ async function notifyParent(run: SubagentRunInfo): Promise<void> {
594
+ let parent = dependencies.getSession(run.parentSessionId);
595
+ if (!parent?.isAlive()) {
596
+ const sessionFile = await dependencies.resolveSessionPath(run.parentSessionId);
597
+ if (!sessionFile) throw new Error(`Parent session not found: ${run.parentSessionId}`);
598
+ parent = await dependencies.reopenSession(run.parentSessionId, sessionFile);
599
+ }
600
+ await parent.waitUntilReady();
601
+ if (!parent.isAlive()) throw new Error(`Parent session is no longer available: ${run.parentSessionId}`);
602
+ await parent.inner.sendCustomMessage({
603
+ customType: "pi-web:subagent-notification",
604
+ content: subagentFinalText(run),
605
+ display: true,
606
+ details: subagentToolDetails(run),
607
+ }, { deliverAs: "followUp", triggerTurn: true });
608
+ }
609
+
610
+ async function abort(sessionId: string): Promise<void> {
611
+ const wrapper = dependencies.getSession(sessionId);
612
+ const stored = getSubagentRuns().get(sessionId);
613
+ if (stored?.run.status === "queued") {
614
+ stored.abortRequested = true;
615
+ if (!stored.cancelQueued?.()) throw new Error("Subagent is no longer queued");
616
+ return;
617
+ }
618
+ if (!wrapper?.isAlive() || !wrapper.isRunning()) throw new Error("Subagent is not running");
619
+ if (stored) stored.abortRequested = true;
620
+ await wrapper.inner.abort();
621
+ }
622
+
623
+ return {
624
+ extensionRuntime: { start, resume, get, steer, notifyParent },
625
+ get,
626
+ steer,
627
+ abort,
628
+ };
629
+ }