@co0ontty/wand 4.105.1 → 4.106.0

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 (291) hide show
  1. package/dist/build-info.json +3 -3
  2. package/dist/cli.js +7 -2
  3. package/dist/distribution-manager.d.ts +2 -0
  4. package/dist/distribution-manager.js +23 -0
  5. package/dist/employee-input-scheduling.d.ts +2 -1
  6. package/dist/employee-knowledge-cli.d.ts +1 -1
  7. package/dist/employee-knowledge-cli.js +91 -20
  8. package/dist/employee-knowledge-content.js +1 -1
  9. package/dist/employee-knowledge-types.d.ts +1 -1
  10. package/dist/employee-knowledge-types.js +1 -1
  11. package/dist/employee-knowledge.d.ts +6 -3
  12. package/dist/employee-knowledge.js +54 -58
  13. package/dist/env-utils.js +1 -1
  14. package/dist/html-preview-policy.d.ts +4 -0
  15. package/dist/html-preview-policy.js +4 -0
  16. package/dist/ios-ota.d.ts +5 -0
  17. package/dist/ios-ota.js +11 -1
  18. package/dist/knowledge-skill.d.ts +2 -0
  19. package/dist/knowledge-skill.js +17 -0
  20. package/dist/knowledge-types.d.ts +36 -0
  21. package/dist/knowledge-types.js +8 -0
  22. package/dist/managed-skills-ensure.js +2 -0
  23. package/dist/middleware/api-scope.js +2 -0
  24. package/dist/path-repair.js +28 -6
  25. package/dist/pi-resource-catalog.d.ts +3 -1
  26. package/dist/pi-resource-catalog.js +25 -0
  27. package/dist/pi-session-settings.d.ts +2 -0
  28. package/dist/pi-session-settings.js +25 -0
  29. package/dist/process-manager.d.ts +2 -0
  30. package/dist/process-manager.js +35 -12
  31. package/dist/quick-terminal-session.d.ts +3 -0
  32. package/dist/quick-terminal-session.js +5 -0
  33. package/dist/retention-protection.d.ts +15 -0
  34. package/dist/retention-protection.js +134 -0
  35. package/dist/retention.d.ts +3 -2
  36. package/dist/retention.js +58 -76
  37. package/dist/server-employee-routes.js +1 -1
  38. package/dist/server-file-routes.js +84 -16
  39. package/dist/server-knowledge-routes.d.ts +4 -0
  40. package/dist/server-knowledge-routes.js +61 -0
  41. package/dist/server-local-preview-routes.js +28 -6
  42. package/dist/server-pi-defaults-routes.d.ts +1 -1
  43. package/dist/server-pi-defaults-routes.js +13 -20
  44. package/dist/server-session-lifecycle-routes.js +17 -17
  45. package/dist/server-session-list-routes.js +1 -1
  46. package/dist/server-task-routes.js +6 -0
  47. package/dist/server-update-routes.d.ts +1 -0
  48. package/dist/server-update-routes.js +62 -17
  49. package/dist/server-workspace-routes.js +5 -5
  50. package/dist/server.js +4 -2
  51. package/dist/session-questions.d.ts +7 -0
  52. package/dist/session-questions.js +25 -0
  53. package/dist/session-registry.d.ts +3 -0
  54. package/dist/session-registry.js +17 -0
  55. package/dist/session-request.d.ts +1 -1
  56. package/dist/session-request.js +6 -2
  57. package/dist/session-service.js +1 -1
  58. package/dist/storage/employees-repository.js +5 -2
  59. package/dist/storage/knowledge-repository.d.ts +35 -0
  60. package/dist/storage/knowledge-repository.js +208 -0
  61. package/dist/storage/mappers.js +1 -1
  62. package/dist/storage/migrations.js +51 -0
  63. package/dist/storage/sessions-repository.d.ts +2 -0
  64. package/dist/storage/sessions-repository.js +16 -0
  65. package/dist/storage/tasks-repository.d.ts +7 -0
  66. package/dist/storage/tasks-repository.js +21 -0
  67. package/dist/storage/workspaces-repository.d.ts +1 -0
  68. package/dist/storage/workspaces-repository.js +2 -1
  69. package/dist/storage.d.ts +3 -1
  70. package/dist/storage.js +4 -0
  71. package/dist/structured-session-manager.d.ts +3 -0
  72. package/dist/structured-session-manager.js +13 -4
  73. package/dist/task-action-types.d.ts +22 -0
  74. package/dist/task-action-types.js +1 -0
  75. package/dist/task-actions.d.ts +5 -0
  76. package/dist/task-actions.js +86 -0
  77. package/dist/task-execution-queue.d.ts +1 -1
  78. package/dist/task-execution-queue.js +4 -1
  79. package/dist/task-retention.d.ts +4 -2
  80. package/dist/task-retention.js +2 -0
  81. package/dist/types.d.ts +2 -1
  82. package/dist/web-ui/content/ai-teams.js +12 -12
  83. package/dist/web-ui/content/module-manifest.json +1 -1
  84. package/dist/web-ui/content/modules/00b168a19664439e/dropdown-surface.js +1 -0
  85. package/dist/web-ui/content/modules/059c5fb7f128d340/task-board-host.js +27 -0
  86. package/dist/web-ui/content/modules/07494f5a623e4471/chat-render.js +76 -0
  87. package/dist/web-ui/content/modules/{bc28252270bcc51a → 0a743ad3b4db6874}/chunk.js +1 -1
  88. package/dist/web-ui/content/modules/0d76e582a7a71b2f/chunk.js +1 -0
  89. package/dist/web-ui/content/modules/11af5d14b30e57b6/chunk.js +1 -0
  90. package/dist/web-ui/content/modules/16dab1297efd71a7/chunk.js +10 -0
  91. package/dist/web-ui/content/modules/182929e188c1ab3a/host.js +5 -0
  92. package/dist/web-ui/content/modules/1858670c0f84fec5/employee-profile.js +1 -0
  93. package/dist/web-ui/content/modules/{1cf252d2f64a6279 → 1eab7410d5586038}/chunk.js +1 -1
  94. package/dist/web-ui/content/modules/20c47dc0442f5a04/host.js +1 -0
  95. package/dist/web-ui/content/modules/226241b999d12008/host.js +1 -0
  96. package/dist/web-ui/content/modules/23c4b8d223ec64c5/host.js +61 -0
  97. package/dist/web-ui/content/modules/2882c97388ff4f7b/employee-card.js +1 -0
  98. package/dist/web-ui/content/modules/2a791cd2e14aa1e0/notice-view.js +1 -0
  99. package/dist/web-ui/content/modules/2c90c3be260e6cce/progress.js +1 -0
  100. package/dist/web-ui/content/modules/2d7be9935394f397/workspace-window.js +1 -0
  101. package/dist/web-ui/content/modules/2f801e53dda62770/chunk.js +1 -0
  102. package/dist/web-ui/content/modules/2f97ddba3842adaa/chunk.js +1 -0
  103. package/dist/web-ui/content/modules/31157ceb6d23b809/chunk.js +15 -0
  104. package/dist/web-ui/content/modules/389a5112332ec23a/host.js +1 -0
  105. package/dist/web-ui/content/modules/3ea13e8b3c2deaa4/panel-host.js +1 -0
  106. package/dist/web-ui/content/modules/3f8830f8ad28decc/chunk.js +3 -0
  107. package/dist/web-ui/content/modules/{70715360138f4d99 → 3fe11a75284ad8ae}/host.js +1 -1
  108. package/dist/web-ui/content/modules/{e0a1ae9163e77556 → 41445c6589dba325}/host.js +2 -2
  109. package/dist/web-ui/content/modules/{8b2f9a027ae1d7eb → 42e5c34002fcffb7}/chunk.js +1 -1
  110. package/dist/web-ui/content/modules/438807b8bf112cd0/chunk.js +1 -0
  111. package/dist/web-ui/content/modules/4861eca9a8a87ad0/chunk.js +1 -0
  112. package/dist/web-ui/content/modules/{78d06dfdc4b13d78 → 4970319a83432ec7}/chunk.js +1 -1
  113. package/dist/web-ui/content/modules/4a5d669c90f545cb/host.js +1 -0
  114. package/dist/web-ui/content/modules/4ba1e8c74bed7ef2/chunk.js +1 -0
  115. package/dist/web-ui/content/modules/5083a5dbb5b155b7/chunk.js +1 -0
  116. package/dist/web-ui/content/modules/50da446c1377c220/chunk.js +20 -0
  117. package/dist/web-ui/content/modules/52574891ef08e29b/host.js +30 -0
  118. package/dist/web-ui/content/modules/5705d25468274534/host.js +1 -0
  119. package/dist/web-ui/content/modules/579d486763d47c0d/chunk.js +1 -0
  120. package/dist/web-ui/content/modules/57c357d321db5df9/chunk.js +1 -0
  121. package/dist/web-ui/content/modules/5933ce8965aa4004/chunk.js +1 -0
  122. package/dist/web-ui/content/modules/5961ab2947c86ca1/shell-file-panel-drawer.js +1 -0
  123. package/dist/web-ui/content/modules/5b6e1369df7dea69/chunk.js +1 -0
  124. package/dist/web-ui/content/modules/5f298a8f43dd0589/chunk.js +1 -0
  125. package/dist/web-ui/content/modules/62e0023451f428cf/chunk.js +1 -0
  126. package/dist/web-ui/content/modules/6787bdcf56f743a5/host.js +1 -0
  127. package/dist/web-ui/content/modules/67c39b0398186a9f/host.js +1 -0
  128. package/dist/web-ui/content/modules/6b16f35c0627bafb/chunk.js +1 -0
  129. package/dist/web-ui/content/modules/6dd4f3e2f619f7a0/chunk.js +1 -0
  130. package/dist/web-ui/content/modules/70a2e13e0ccc8549/panel.js +1 -0
  131. package/dist/web-ui/content/modules/710db590e9707f73/runtime.js +338 -0
  132. package/dist/web-ui/content/modules/7249950f8771dbeb/workspaces-panel.js +4 -0
  133. package/dist/web-ui/content/modules/771439a41e737ee2/chunk.js +1 -0
  134. package/dist/web-ui/content/modules/{2061d4a88875b9f9 → 816eb9b3a000fb2c}/chunk.js +1 -1
  135. package/dist/web-ui/content/modules/{c0384ffb4ef740a0 → 831b6c7b43e800be}/host.js +1 -1
  136. package/dist/web-ui/content/modules/87c7f50d9455d55e/chunk.js +1 -0
  137. package/dist/web-ui/content/modules/87dcd516ffd9f688/composer-surface-adapter.js +1 -0
  138. package/dist/web-ui/content/modules/8891ca8165435ca1/chunk.js +1 -0
  139. package/dist/web-ui/content/modules/8b7cd7bffdfd69e7/brand-identity.js +1 -0
  140. package/dist/web-ui/content/modules/8bf9917f6c3429f6/host.js +1 -0
  141. package/dist/web-ui/content/modules/8de8368570ab089d/chunk.js +57 -0
  142. package/dist/web-ui/content/modules/8e612d4881fa4118/home.js +6 -0
  143. package/dist/web-ui/content/modules/8e6178262ea63dec/markdown.js +1 -0
  144. package/dist/web-ui/content/modules/913187c92a98a1ac/chunk.js +1 -0
  145. package/dist/web-ui/content/modules/96f2ae970f8c576b/host.js +1 -0
  146. package/dist/web-ui/content/modules/97d7f267959fd385/chunk.js +1 -0
  147. package/dist/web-ui/content/modules/{22497085d7cdd83b → 9b12c2301f3a18f3}/chunk.js +1 -1
  148. package/dist/web-ui/content/modules/{9f4e26a1c1867d65 → 9d941d6ff39861b8}/chunk.js +2 -2
  149. package/dist/web-ui/content/modules/9e163d54ff8fd1aa/chunk.js +1 -0
  150. package/dist/web-ui/content/modules/{0567e161e2cca41e → a2caed0139df4b21}/chunk.js +1 -1
  151. package/dist/web-ui/content/modules/a59734be368daa7e/chunk.js +1 -0
  152. package/dist/web-ui/content/modules/{e4503f8e6379ccdc → a61393bfa976d8d5}/chunk.js +1 -1
  153. package/dist/web-ui/content/modules/{df5d48b4ff04b443 → b63e075f222a1266}/library-bridge.js +2 -2
  154. package/dist/web-ui/content/modules/b713cad51ca4c512/chunk.js +1 -0
  155. package/dist/web-ui/content/modules/ba89cd97627e6682/queue-view-adapter.js +1 -0
  156. package/dist/web-ui/content/modules/bd3daf04a8bf4422/chunk.js +1 -0
  157. package/dist/web-ui/content/modules/{aa7d409d04bbd736 → bd7dc4bb46731ee7}/chunk.js +1 -1
  158. package/dist/web-ui/content/modules/bf3ee58e0da44822/chunk.js +1 -0
  159. package/dist/web-ui/content/modules/c0a446100d969f3e/chunk.js +8 -0
  160. package/dist/web-ui/content/modules/c2f09c8a472f5d83/dialog-modal.js +4 -0
  161. package/dist/web-ui/content/modules/c33935155289c22d/chunk.js +3 -0
  162. package/dist/web-ui/content/modules/c351eb11e0bdec2c/sidebar-peek.js +1 -0
  163. package/dist/web-ui/content/modules/ca7ca5902a35d26e/chunk.js +1 -0
  164. package/dist/web-ui/content/modules/cba6f13c0b2aec1c/chunk.js +1 -0
  165. package/dist/web-ui/content/modules/d434edbb2f4672e5/chunk.js +1 -0
  166. package/dist/web-ui/content/modules/{d569c96d4acfdec3 → d47d75a78ae598e3}/chunk.js +25 -25
  167. package/dist/web-ui/content/modules/d49f106c4d106057/chunk.js +1 -0
  168. package/dist/web-ui/content/modules/d5d28ec375826ef2/chunk.js +3 -0
  169. package/dist/web-ui/content/modules/{7edec8f23f8e0834 → d6b16dedb9011c33}/chunk.js +1 -1
  170. package/dist/web-ui/content/modules/d6fffe2c2a3a738d/toast-region.js +1 -0
  171. package/dist/web-ui/content/modules/d8a7011760f61719/group-editor.js +1 -0
  172. package/dist/web-ui/content/modules/{bf0b693a654e2655 → d9e2b65e9679ad39}/host.js +3 -3
  173. package/dist/web-ui/content/modules/db521a246e14e5e4/chunk.js +4 -0
  174. package/dist/web-ui/content/modules/{7994dec16e8b1039 → dedd4a19bb70e327}/page.js +2 -2
  175. package/dist/web-ui/content/modules/e060508ecd50fa7e/chunk.js +1 -0
  176. package/dist/web-ui/content/modules/e5174201f9d918fb/chunk.js +1 -0
  177. package/dist/web-ui/content/modules/e63582a3bce48f7d/chunk.js +1 -0
  178. package/dist/web-ui/content/modules/ea8fe4b9999fd2aa/chunk.js +1 -0
  179. package/dist/web-ui/content/modules/{d7cdd7dca9a0c9f8 → eac72f69716dba05}/chunk.js +1 -1
  180. package/dist/web-ui/content/modules/ebc53dedc3945514/host.js +1 -0
  181. package/dist/web-ui/content/modules/{0d7f7d954382dc42 → ec33e17c00c1eb24}/chunk.js +1 -1
  182. package/dist/web-ui/content/modules/{99e5cdf0c3bd0e3d → ed7405f064944215}/sha256.js +1 -1
  183. package/dist/web-ui/content/modules/f27a5d3c6c02a71c/chunk.js +1 -0
  184. package/dist/web-ui/content/modules/f383d892fef73483/chunk.js +1 -0
  185. package/dist/web-ui/content/modules/{084dca1ea52bf38e → f3cff7792ba39df8}/login-visual.js +1 -1
  186. package/dist/web-ui/content/modules/f43da7050badf54c/host.js +1 -0
  187. package/dist/web-ui/content/modules/face3dbf117d63e3/chunk.js +1 -0
  188. package/dist/web-ui/content/modules/fb2356eced24c4cc/host-bridge.js +1 -0
  189. package/dist/web-ui/content/styles.css +1 -1
  190. package/dist/web-ui/embedded-assets.d.ts +413 -420
  191. package/dist/web-ui/embedded-assets.js +5 -5
  192. package/dist/web-ui/group-chat-visibility.d.ts +1 -0
  193. package/dist/web-ui/group-chat-visibility.js +1 -1
  194. package/dist/web-ui/markdown.js +10 -36
  195. package/dist/web-ui/message-file-target.d.ts +8 -0
  196. package/dist/web-ui/message-file-target.js +105 -15
  197. package/dist/web-ui/page-route.js +2 -0
  198. package/dist/web-ui/react/local-preview/controller.d.ts +2 -2
  199. package/dist/web-ui/react/local-preview/controller.js +53 -10
  200. package/dist/web-ui/react/workspaces/types.d.ts +1 -0
  201. package/dist/web-ui/server-link-url.d.ts +3 -0
  202. package/dist/web-ui/server-link-url.js +18 -0
  203. package/package.json +2 -1
  204. package/skills/wand-knowledge/SKILL.md +47 -0
  205. package/skills/wand-knowledge/scripts/knowledge.mjs +18 -0
  206. package/dist/web-ui/content/modules/0341f0d00f88a16f/chunk.js +0 -1
  207. package/dist/web-ui/content/modules/069f5a4267b0a9e3/runtime.js +0 -279
  208. package/dist/web-ui/content/modules/0d62c22b7aed5f1f/host-bridge.js +0 -1
  209. package/dist/web-ui/content/modules/0da28408ec089cf7/chunk.js +0 -1
  210. package/dist/web-ui/content/modules/130e8905cc7f639c/toast-region.js +0 -1
  211. package/dist/web-ui/content/modules/186d6e3b44a3c539/host.js +0 -1
  212. package/dist/web-ui/content/modules/1870280f0e783c62/chunk.js +0 -4
  213. package/dist/web-ui/content/modules/19d3bc36fa1e9160/chunk.js +0 -1
  214. package/dist/web-ui/content/modules/1a0b5db535599f72/chunk.js +0 -1
  215. package/dist/web-ui/content/modules/1d1dc0fd8a0210aa/composer-surface-adapter.js +0 -1
  216. package/dist/web-ui/content/modules/23f15023aa2279a3/shell-file-panel-drawer.js +0 -1
  217. package/dist/web-ui/content/modules/2cab58e5d148844c/host.js +0 -1
  218. package/dist/web-ui/content/modules/32edeb64dbf339f6/chunk.js +0 -1
  219. package/dist/web-ui/content/modules/33daaeb4bf68c7ba/chunk.js +0 -9
  220. package/dist/web-ui/content/modules/37da177222b6308d/workspaces-panel.js +0 -4
  221. package/dist/web-ui/content/modules/3af7facf8a7588c7/chunk.js +0 -1
  222. package/dist/web-ui/content/modules/3b95dc1376e932ea/host.js +0 -1
  223. package/dist/web-ui/content/modules/3cbbad48df7998f8/chunk.js +0 -1
  224. package/dist/web-ui/content/modules/41cf79c899bc83c8/host.js +0 -1
  225. package/dist/web-ui/content/modules/444af9de1698eea0/host.js +0 -1
  226. package/dist/web-ui/content/modules/452327275cc5d8f8/host.js +0 -1
  227. package/dist/web-ui/content/modules/466310a17dac465f/chunk.js +0 -3
  228. package/dist/web-ui/content/modules/46f1b6c3274d399b/host.js +0 -1
  229. package/dist/web-ui/content/modules/47998d82dc65bfeb/sidebar-peek.js +0 -1
  230. package/dist/web-ui/content/modules/486a828390c5d44d/host.js +0 -30
  231. package/dist/web-ui/content/modules/4cc15b385bc6cc32/chunk.js +0 -1
  232. package/dist/web-ui/content/modules/4d5ab67f6c0ce19f/chunk.js +0 -1
  233. package/dist/web-ui/content/modules/54aaf60ac85dcb2b/chunk.js +0 -1
  234. package/dist/web-ui/content/modules/54c22eddaf009d00/chunk.js +0 -1
  235. package/dist/web-ui/content/modules/55b931232c672f4f/chunk.js +0 -1
  236. package/dist/web-ui/content/modules/583049de28ef2b02/panel.js +0 -1
  237. package/dist/web-ui/content/modules/5a2a58334d63e127/chunk.js +0 -20
  238. package/dist/web-ui/content/modules/5ba0668f5a22133b/home.js +0 -6
  239. package/dist/web-ui/content/modules/5cd5d3d65d966c5f/chunk.js +0 -1
  240. package/dist/web-ui/content/modules/6b41e59ab342482f/notice-view.js +0 -1
  241. package/dist/web-ui/content/modules/6b5445f41bef0a66/chunk.js +0 -1
  242. package/dist/web-ui/content/modules/6e8395f61c89b5aa/chunk.js +0 -1
  243. package/dist/web-ui/content/modules/6f74cede70164e19/chunk.js +0 -1
  244. package/dist/web-ui/content/modules/704690f5d6ab9157/chunk.js +0 -1
  245. package/dist/web-ui/content/modules/7dce56c1987e8d43/chunk.js +0 -29
  246. package/dist/web-ui/content/modules/80e92c14a6789896/progress.js +0 -1
  247. package/dist/web-ui/content/modules/8a828b4d087667dd/chunk.js +0 -1
  248. package/dist/web-ui/content/modules/8d6f223764846e18/brand-identity.js +0 -1
  249. package/dist/web-ui/content/modules/9136bae16758fd4c/chunk.js +0 -1
  250. package/dist/web-ui/content/modules/93fa5c35e4bcab96/chunk.js +0 -1
  251. package/dist/web-ui/content/modules/96fe39f39930d9e4/chunk.js +0 -8
  252. package/dist/web-ui/content/modules/9db41ad5ac96ffa2/chunk.js +0 -1
  253. package/dist/web-ui/content/modules/a073cb6d182ccd32/chunk.js +0 -1
  254. package/dist/web-ui/content/modules/a8cba9f1d6b49ef1/chunk.js +0 -1
  255. package/dist/web-ui/content/modules/a97b3b9b68f9ca38/chunk.js +0 -57
  256. package/dist/web-ui/content/modules/ac34ed6692b43ede/dropdown-surface.js +0 -1
  257. package/dist/web-ui/content/modules/aff19b31898aa157/chunk.js +0 -1
  258. package/dist/web-ui/content/modules/b2f6e088e6e45878/chunk.js +0 -1
  259. package/dist/web-ui/content/modules/b4446bf92e182bfb/employee-card.js +0 -1
  260. package/dist/web-ui/content/modules/b79c15aace456028/chunk.js +0 -6
  261. package/dist/web-ui/content/modules/b8c18baf7cfb61b1/chat-render.js +0 -76
  262. package/dist/web-ui/content/modules/b8c447171e3d60a0/chunk.js +0 -1
  263. package/dist/web-ui/content/modules/b945370f1fa784f9/chunk.js +0 -13
  264. package/dist/web-ui/content/modules/ba5fa76884e1f806/chunk.js +0 -1
  265. package/dist/web-ui/content/modules/bb1bb9460cc10fbe/host.js +0 -1
  266. package/dist/web-ui/content/modules/be7f1f9183a1247f/chunk.js +0 -3
  267. package/dist/web-ui/content/modules/bf7449bcf95e1454/chunk.js +0 -1
  268. package/dist/web-ui/content/modules/c091efd46e221c29/chunk.js +0 -1
  269. package/dist/web-ui/content/modules/c1ec2ebce8ea5dd8/dialog-modal.js +0 -4
  270. package/dist/web-ui/content/modules/c2f7bb50118f1603/chunk.js +0 -1
  271. package/dist/web-ui/content/modules/c369ce4eb71277e6/host.js +0 -1
  272. package/dist/web-ui/content/modules/c46b3501573953e9/chunk.js +0 -1
  273. package/dist/web-ui/content/modules/c577ad641502d509/panel-host.js +0 -1
  274. package/dist/web-ui/content/modules/c75976857c18f251/host.js +0 -1
  275. package/dist/web-ui/content/modules/c8eaffbedda0d3d0/queue-view-adapter.js +0 -3
  276. package/dist/web-ui/content/modules/cadd26ae50359434/chunk.js +0 -1
  277. package/dist/web-ui/content/modules/d37ff6684c9aeeec/chunk.js +0 -3
  278. package/dist/web-ui/content/modules/d48c1f89342bc4bc/workspace-window.js +0 -1
  279. package/dist/web-ui/content/modules/d859a83f486aab23/chunk.js +0 -15
  280. package/dist/web-ui/content/modules/d8b258a6455d77da/host.js +0 -5
  281. package/dist/web-ui/content/modules/d937e939122180b9/host.js +0 -1
  282. package/dist/web-ui/content/modules/e020beea3e7da7db/chunk.js +0 -1
  283. package/dist/web-ui/content/modules/e2feda63a603c64e/group-editor.js +0 -1
  284. package/dist/web-ui/content/modules/e70296674a841d60/chunk.js +0 -1
  285. package/dist/web-ui/content/modules/ec2f6b23d12d3a15/chunk.js +0 -1
  286. package/dist/web-ui/content/modules/ede751e1f2500d03/employee-profile.js +0 -1
  287. package/dist/web-ui/content/modules/ee4301b734e2fd43/chunk.js +0 -1
  288. package/dist/web-ui/content/modules/f4e6095edc32562c/markdown.js +0 -1
  289. package/dist/web-ui/content/modules/f7f0710962cab0e0/chunk.js +0 -10
  290. package/dist/web-ui/content/modules/fe30627fc1e59d4f/chunk.js +0 -1
  291. package/dist/web-ui/content/modules/ffbd3bcaecd8e814/task-board-host.js +0 -10
@@ -303,6 +303,9 @@ function probeLoginShell(shell, timeoutMs) {
303
303
  `printf '\\n${ENV_BEGIN_MARKER}\\n'; command env; printf '${ENV_END_MARKER}\\n'`;
304
304
  return new Promise((resolve, reject) => {
305
305
  const child = spawn(shell, ["-lic", script], {
306
+ // Own a separate probe group: shell rc can spawn children which inherit
307
+ // our pipes, and an interactive shell may ignore SIGTERM.
308
+ detached: process.platform !== "win32",
306
309
  env: {
307
310
  ...process.env,
308
311
  // 防止 PROMPT_COMMAND / PS1 等钩子往 stdout 喷东西干扰解析
@@ -314,6 +317,25 @@ function probeLoginShell(shell, timeoutMs) {
314
317
  let stdout = "";
315
318
  let stderr = "";
316
319
  let settled = false;
320
+ let killTimer;
321
+ const terminateProbe = (signal) => {
322
+ if (process.platform !== "win32" && child.pid) {
323
+ try {
324
+ process.kill(-child.pid, signal);
325
+ return;
326
+ }
327
+ catch { /* group already gone, or spawn failed */ }
328
+ }
329
+ try {
330
+ child.kill(signal);
331
+ }
332
+ catch { /* probe already exited */ }
333
+ };
334
+ const clearTimers = () => {
335
+ clearTimeout(timer);
336
+ if (killTimer)
337
+ clearTimeout(killTimer);
338
+ };
317
339
  const finalize = (fn) => {
318
340
  if (settled)
319
341
  return;
@@ -321,20 +343,20 @@ function probeLoginShell(shell, timeoutMs) {
321
343
  fn();
322
344
  };
323
345
  const timer = setTimeout(() => {
324
- try {
325
- child.kill("SIGTERM");
326
- }
327
- catch { /* noop */ }
346
+ terminateProbe("SIGTERM");
347
+ // Kill only this detached probe group, never a provider PTY/daemon or
348
+ // another session. Descendants can keep stdout open after the shell exits.
349
+ killTimer = setTimeout(() => terminateProbe("SIGKILL"), 250);
328
350
  finalize(() => reject(new Error(`login shell probe timed out after ${timeoutMs}ms`)));
329
351
  }, timeoutMs);
330
352
  child.stdout?.on("data", (b) => { stdout += b.toString(); });
331
353
  child.stderr?.on("data", (b) => { stderr += b.toString(); });
332
354
  child.on("error", (err) => {
333
- clearTimeout(timer);
355
+ clearTimers();
334
356
  finalize(() => reject(err));
335
357
  });
336
358
  child.on("close", (code) => {
337
- clearTimeout(timer);
359
+ clearTimers();
338
360
  finalize(() => {
339
361
  if (!stdout && code !== 0) {
340
362
  reject(new Error(`login shell exited ${code}: ${stderr.trim().slice(0, 200)}`));
@@ -1,4 +1,4 @@
1
- import type { PiResourceCatalog, PiResourceSelection } from "./pi-session-settings.js";
1
+ import { type PiResourceCatalog, type PiResourceSelection, type PiSessionSettings, type PiSessionSettingsPatch } from "./pi-session-settings.js";
2
2
  import type { WandConfig } from "./types.js";
3
3
  import type { Skill, McpExtensionOptions } from "@earendil-works/pi-coding-agent";
4
4
  type McpConfig = ReturnType<NonNullable<McpExtensionOptions["loadConfig"]>>;
@@ -15,4 +15,6 @@ export declare function resolvePiResourceSelection(inventory: PiResourceInventor
15
15
  skills: Skill[];
16
16
  servers: McpConfig["servers"];
17
17
  };
18
+ /** Validate additions; an explicit unlock also releases that skill's unavailable selected reference. */
19
+ export declare function resolvePiResourceSettingsPatch(inventory: PiResourceInventory, current: PiSessionSettings, patch: PiSessionSettingsPatch): PiSessionSettingsPatch;
18
20
  export {};
@@ -3,6 +3,7 @@ import { realpath, stat } from "node:fs/promises";
3
3
  import { coreHarnessAgentDir } from "./harness-engine.js";
4
4
  import { importPiCliModule, resolvePiCliPackage } from "./pi-cli-runtime.js";
5
5
  import { cliPiResourceReader, installedPiUserResources } from "./pi-user-resources.js";
6
+ import { patchPiSessionSettings } from "./pi-session-settings.js";
6
7
  function resourceId(kind, identity) {
7
8
  return `${kind}-${createHash("sha256").update(identity).digest("hex").slice(0, 24)}`;
8
9
  }
@@ -65,3 +66,27 @@ export function resolvePiResourceSelection(inventory, selection) {
65
66
  });
66
67
  return { skills, servers };
67
68
  }
69
+ /** Validate additions; an explicit unlock also releases that skill's unavailable selected reference. */
70
+ export function resolvePiResourceSettingsPatch(inventory, current, patch) {
71
+ const next = patchPiSessionSettings(current, patch);
72
+ let resolved = patch;
73
+ if (patch.lockedSkills !== undefined && next.resources) {
74
+ const released = new Set((current.lockedSkills ?? []).filter((id) => !next.lockedSkills.includes(id) && !inventory.skills.has(id)));
75
+ if (next.resources.skills.some((id) => released.has(id))) {
76
+ resolved = { ...patch, resources: { ...next.resources,
77
+ skills: next.resources.skills.filter((id) => !released.has(id)) } };
78
+ }
79
+ }
80
+ // Keep other stale references until explicitly removed, so several unavailable items can be
81
+ // repaired one at a time. Execution still validates the complete selection and fails closed.
82
+ if (resolved.resources !== undefined)
83
+ resolvePiResourceSelection(inventory, {
84
+ skills: resolved.resources.skills.filter((id) => !current.resources?.skills.includes(id)),
85
+ mcpServers: resolved.resources.mcpServers.filter((id) => !current.resources?.mcpServers.includes(id)),
86
+ });
87
+ if (resolved.lockedSkills !== undefined)
88
+ resolvePiResourceSelection(inventory, {
89
+ skills: resolved.lockedSkills.filter((id) => !current.lockedSkills?.includes(id)), mcpServers: [],
90
+ });
91
+ return resolved;
92
+ }
@@ -33,6 +33,8 @@ export type PiSkillMode = "off" | "on" | "locked";
33
33
  export declare function piSkillMode(settings: PiSessionSettings, id: string): PiSkillMode;
34
34
  /** A single manual gesture changes selection and lock atomically, never mutating its snapshot. */
35
35
  export declare function piSkillModePatch(settings: PiSessionSettings, id: string, mode: PiSkillMode): PiSessionSettingsPatch;
36
+ /** The server may also deselect a newly unlocked Skill if it disappeared since the panel loaded. */
37
+ export declare function piResourceSettingsConfirmed(current: PiSessionSettings, patch: PiSessionSettingsPatch, confirmed: PiSessionSettings | undefined): boolean;
36
38
  export interface PiResourceSelectionNotice {
37
39
  status: "selecting" | "selected" | "fallback" | "cancelled";
38
40
  label: string;
@@ -18,6 +18,31 @@ export function piSkillModePatch(settings, id, mode) {
18
18
  lockedSkills: mode === "locked" ? [...new Set([...locks, id])] : locks.filter((value) => value !== id),
19
19
  };
20
20
  }
21
+ /** The server may also deselect a newly unlocked Skill if it disappeared since the panel loaded. */
22
+ export function piResourceSettingsConfirmed(current, patch, confirmed) {
23
+ if (!confirmed)
24
+ return false;
25
+ if (patch.lockedSkills !== undefined
26
+ && JSON.stringify(confirmed.lockedSkills) !== JSON.stringify(patch.lockedSkills))
27
+ return false;
28
+ if (patch.resources === undefined && patch.lockedSkills === undefined)
29
+ return true;
30
+ const expected = patch.resources ?? current.resources;
31
+ if (!confirmed.resources)
32
+ return !expected && !patch.lockedSkills?.length;
33
+ let resources;
34
+ try {
35
+ resources = patchPiResourceSelection(confirmed.resources);
36
+ }
37
+ catch {
38
+ return false;
39
+ }
40
+ const unlocked = new Set(patch.lockedSkills === undefined ? []
41
+ : (current.lockedSkills ?? []).filter((id) => !patch.lockedSkills.includes(id)));
42
+ const skills = (expected?.skills ?? []).filter((id) => !unlocked.has(id) || resources.skills.includes(id));
43
+ return JSON.stringify(resources.skills) === JSON.stringify(skills)
44
+ && JSON.stringify(resources.mcpServers) === JSON.stringify(expected?.mcpServers ?? []);
45
+ }
21
46
  export function patchPiResourceSelection(raw) {
22
47
  if (!raw || typeof raw !== "object" || Array.isArray(raw))
23
48
  throw new Error("请选择有效的 Skills / MCP 列表。");
@@ -302,6 +302,8 @@ export declare class ProcessManager extends EventEmitter {
302
302
  private snapshotSlim;
303
303
  private isPermissionBlocked;
304
304
  setSessionWorkspace(id: string, membership: Pick<SessionSnapshot, "workspaceId" | "workspaceTaskId">): void;
305
+ /** The source is committed by storage before the live checkpoint projection is refreshed. */
306
+ setSessionSource(id: string, sessionSource: SessionSource): void;
305
307
  setSessionTopic(id: string, title: string, description: string): SessionSnapshot;
306
308
  private setSessionTopicGenerating;
307
309
  /**
@@ -1,3 +1,4 @@
1
+ import { knowledgeInstructions } from "./employee-knowledge.js";
1
2
  import { isOpenRouterFreeSelector } from "./openrouter-free-models.js";
2
3
  import { isAutoAssignSelector, defaultModelGroupSelector, resolveModelGroupModels } from "./model-groups.js";
3
4
  import { resolveAutoAssign } from "./model-auto-assign.js";
@@ -563,6 +564,7 @@ export class ProcessManager extends EventEmitter {
563
564
  // PTY emits its asynchronous exit event. Ignore that stale incarnation.
564
565
  if (current !== record || current.ptyProcess !== child)
565
566
  return;
567
+ this.storage.revokeSessionKnowledgeAccess(record.id);
566
568
  current.timers.clearAll();
567
569
  if (current.ptyBridge) {
568
570
  current.ptyBridge.onExit(exitCode);
@@ -844,10 +846,7 @@ export class ProcessManager extends EventEmitter {
844
846
  let processedCommand = this.processCommandForMode(command, effectiveMode, provider, preferredModels[0], initialThinkingEffort);
845
847
  // 会话级系统提示:provider 有系统提示开关就走开关(PTY 与结构化行为一致),没有就并进首条输入。
846
848
  const systemPrompt = (opts?.systemPrompt ?? inheritedRole?.systemPrompt)?.trim() || undefined;
847
- const initialInputText = initialInput && systemPrompt && !systemPromptFlag(provider)
848
- ? composeSystemFallback(systemPrompt, initialInput)
849
- : initialInput;
850
- processedCommand = commandWithSystemPrompt(processedCommand, provider, systemPrompt);
849
+ let initialInputText = initialInput;
851
850
  const isCodexProvider = provider === "codex";
852
851
  const isOpenCodeProvider = provider === "opencode";
853
852
  const existingProviderSessionId = provider
@@ -873,12 +872,6 @@ export class ProcessManager extends EventEmitter {
873
872
  : null;
874
873
  const initialClaudeSessionId = existingProviderSessionId ?? assignedProviderSessionId;
875
874
  const startedAt = new Date().toISOString();
876
- const launchPlan = buildPtyShellLaunchPlan({
877
- shell: this.config.shell,
878
- command: processedCommand,
879
- bareShell: opts?.interactiveShell === true,
880
- providerCommand: provider !== undefined,
881
- });
882
875
  const record = {
883
876
  id,
884
877
  sessionSource: opts?.sessionSource ?? inheritedSessionSource ?? "interactive",
@@ -912,7 +905,7 @@ export class ProcessManager extends EventEmitter {
912
905
  processId: null,
913
906
  ptyProcess: null,
914
907
  terminalState: new PtyTerminalState(opts?.cols !== undefined ? clampDimension(opts.cols, 20, 1000) : 120, opts?.rows !== undefined ? clampDimension(opts.rows, 5, 500) : 36),
915
- providerShellMarker: launchPlan.cliExitMarker,
908
+ providerShellMarker: null,
916
909
  providerCliActive: provider !== undefined,
917
910
  providerCliExitCode: null,
918
911
  stopRequested: false,
@@ -939,7 +932,7 @@ export class ProcessManager extends EventEmitter {
939
932
  ptyCols: opts?.cols !== undefined ? clampDimension(opts.cols, 20, 1000) : 120,
940
933
  ptyRows: opts?.rows !== undefined ? clampDimension(opts.rows, 5, 500) : 36,
941
934
  ptyOutputSeq: 0,
942
- ptyLaunchMarkerToken: launchPlan.cliExitMarker?.token ?? null,
935
+ ptyLaunchMarkerToken: null,
943
936
  };
944
937
  this.sessions.set(id, record);
945
938
  this.persist(record, { forceFullSave: true });
@@ -947,13 +940,31 @@ export class ProcessManager extends EventEmitter {
947
940
  this.providerHistory.invalidate(provider);
948
941
  }
949
942
  let child;
943
+ let launchPlan;
950
944
  try {
945
+ // Derive authority only after the real session/project binding has been persisted.
946
+ const access = provider ? this.storage.knowledgeSessionScope(id) : null;
947
+ const knowledgeToken = access ? this.storage.issueKnowledgeAccess(id) : undefined;
948
+ const runtimePrompt = access ? [knowledgeInstructions(access),
949
+ "本终端会话的知识工具只在有效执行期内可用;每次使用知识先 search/read,不把旧轮次快照当作当前状态。访问失效时新开一轮结构化执行或恢复会话,不绕过权限。"].join("\n\n") : undefined;
950
+ const launchPrompt = [systemPrompt, runtimePrompt].filter(Boolean).join("\n\n") || undefined;
951
+ initialInputText = initialInput && launchPrompt && !systemPromptFlag(provider)
952
+ ? composeSystemFallback(launchPrompt, initialInput) : initialInput;
953
+ processedCommand = commandWithSystemPrompt(processedCommand, provider, launchPrompt);
954
+ launchPlan = buildPtyShellLaunchPlan({ shell: this.config.shell, command: processedCommand,
955
+ bareShell: opts?.interactiveShell === true, providerCommand: provider !== undefined });
956
+ record.providerShellMarker = launchPlan.cliExitMarker;
957
+ record.ptyLaunchMarkerToken = launchPlan.cliExitMarker?.token ?? null;
958
+ this.persist(record, { forceFullSave: true });
951
959
  const attached = await this.terminalHost.createOrAttach({
952
960
  sessionId: id,
953
961
  file: this.config.shell,
954
962
  args: launchPlan.shellArgs,
955
963
  cwd: resolvedCwd,
956
964
  env: buildChildEnv(this.config.inheritEnv !== false, {
965
+ WAND_SESSION_ID: id,
966
+ WAND_KNOWLEDGE_DB: knowledgeToken ? this.storage.databasePath() : undefined,
967
+ WAND_KNOWLEDGE_TOKEN: knowledgeToken,
957
968
  WAND_MODE: effectiveMode,
958
969
  WAND_AUTO_CONFIRM: record.autoApprovePermissions ? "1" : "0",
959
970
  WAND_AUTO_EDIT: effectiveMode === "auto-edit" ? "1" : "0",
@@ -1503,6 +1514,7 @@ export class ProcessManager extends EventEmitter {
1503
1514
  finishProviderCli(record, exitCode) {
1504
1515
  if (!record.providerCliActive)
1505
1516
  return;
1517
+ this.storage.revokeSessionKnowledgeAccess(record.id);
1506
1518
  record.providerCliActive = false;
1507
1519
  record.providerCliExitCode = exitCode;
1508
1520
  record.providerShellMarker = null;
@@ -1539,6 +1551,7 @@ export class ProcessManager extends EventEmitter {
1539
1551
  if (this.unknownTerminalOwners.has(id))
1540
1552
  throw new Error("Terminal ownership is unknown; stop was not delivered. Retry after recovery.");
1541
1553
  const record = this.mustGet(id);
1554
+ this.storage.revokeSessionKnowledgeAccess(id);
1542
1555
  const start = this.startingSessions.get(id);
1543
1556
  if (start)
1544
1557
  start.cancelled = true;
@@ -1591,6 +1604,8 @@ export class ProcessManager extends EventEmitter {
1591
1604
  return this.snapshot(record);
1592
1605
  }
1593
1606
  cleanupRecord(record, terminateTerminal = true) {
1607
+ if (terminateTerminal && record.status === "running")
1608
+ this.storage.revokeSessionKnowledgeAccess(record.id);
1594
1609
  this.clearPtyTurn(record);
1595
1610
  record.timers.clearAll();
1596
1611
  const pendingPersist = this.persistDebounceTimers.get(record.id);
@@ -1843,6 +1858,14 @@ export class ProcessManager extends EventEmitter {
1843
1858
  Object.assign(this.mustGet(id), membership);
1844
1859
  this.emitEvent({ type: "status", sessionId: id, data: membership });
1845
1860
  }
1861
+ /** The source is committed by storage before the live checkpoint projection is refreshed. */
1862
+ setSessionSource(id, sessionSource) {
1863
+ const record = this.mustGet(id);
1864
+ if (record.sessionSource === sessionSource)
1865
+ return;
1866
+ record.sessionSource = sessionSource;
1867
+ this.emitEvent({ type: "status", sessionId: id, data: { sessionSource } });
1868
+ }
1846
1869
  setSessionTopic(id, title, description) {
1847
1870
  const record = this.mustGet(id);
1848
1871
  record.title = title;
@@ -0,0 +1,3 @@
1
+ import type { SessionSnapshot } from "./types.js";
2
+ /** A quick-terminal claim never takes ownership of an Agent or automation session. */
3
+ export declare function canClaimQuickTerminal(session: SessionSnapshot): boolean;
@@ -0,0 +1,5 @@
1
+ /** A quick-terminal claim never takes ownership of an Agent or automation session. */
2
+ export function canClaimQuickTerminal(session) {
3
+ return (session.sessionKind ?? "pty") === "pty" && !session.provider && !session.automationId
4
+ && (!session.sessionSource || session.sessionSource === "interactive" || session.sessionSource === "quick-terminal");
5
+ }
@@ -0,0 +1,15 @@
1
+ import type { WandStorage } from "./storage.js";
2
+ import type { WandTask } from "./task-types.js";
3
+ import type { SessionSnapshot } from "./types.js";
4
+ /** Read all ownership/execution facts before the first destructive action. Never loads transcripts or settings. */
5
+ export declare function createRetentionProtection(storage: WandStorage, sessions: readonly SessionSnapshot[], archivedMs: number | null, now: number): {
6
+ tasks: WandTask[];
7
+ runs: import("./ai-team-types.js").AiTeamRun[];
8
+ teamSessionIds: Map<string, string[]>;
9
+ canArchiveTask: (task: WandTask) => boolean;
10
+ canPurgeTask: (id: string) => boolean;
11
+ canArchiveSession: (id: string) => boolean;
12
+ canPurgeSession: (id: string) => boolean;
13
+ canArchiveRun: (id: string) => boolean;
14
+ canPurgeRun: (id: string) => boolean;
15
+ };
@@ -0,0 +1,134 @@
1
+ import { AI_TEAM_ACTIVE_RUN_STATUSES } from "./ai-team-types.js";
2
+ import { isArchiveBlocked } from "./archive-policy.js";
3
+ import { TASK_RETENTION_ARCHIVE_VERSION } from "./task-retention.js";
4
+ import { parseTimestampMs } from "./time-utils.js";
5
+ function acceptedTask(task) {
6
+ const acceptance = task.acceptance;
7
+ return (task.status === "done" || task.status === "archived")
8
+ && typeof acceptance?.acceptedAt === "string" && parseTimestampMs(acceptance.acceptedAt) !== null
9
+ && typeof acceptance.evidence === "string" && !!acceptance.evidence.trim()
10
+ && typeof acceptance.blocker === "string" && !acceptance.blocker.trim();
11
+ }
12
+ /** Iterative, order-independent propagation; shared histories and legacy cycles cannot evade a hold. */
13
+ function spread(graph, seeds) {
14
+ const held = new Set(seeds), pending = [...held];
15
+ for (let index = 0; index < pending.length; index += 1) {
16
+ for (const next of graph.get(pending[index]) ?? []) {
17
+ if (held.has(next))
18
+ continue;
19
+ held.add(next);
20
+ pending.push(next);
21
+ }
22
+ }
23
+ return held;
24
+ }
25
+ /** Read all ownership/execution facts before the first destructive action. Never loads transcripts or settings. */
26
+ export function createRetentionProtection(storage, sessions, archivedMs, now) {
27
+ const tasks = storage.listWandTasks(), runs = storage.listAiTeamRuns();
28
+ const versions = storage.taskRetentionArchiveVersions();
29
+ const byId = new Map(tasks.map(task => [task.id, task]));
30
+ const byContainer = new Map(tasks.flatMap(task => task.workspaceTaskId ? [[task.workspaceTaskId, task]] : []));
31
+ const graph = new Map(), ancestors = new Map();
32
+ const taskNode = (id) => `task:${id}`;
33
+ const sessionNode = (id) => `session:${id}`;
34
+ const runNode = (id) => `run:${id}`;
35
+ const busy = new Set(), unfinished = new Set(), notPurgeReady = new Set();
36
+ const link = (left, right) => {
37
+ if (!graph.has(left))
38
+ graph.set(left, new Set());
39
+ if (!graph.has(right))
40
+ graph.set(right, new Set());
41
+ graph.get(left).add(right);
42
+ graph.get(right).add(left);
43
+ };
44
+ for (const task of tasks) {
45
+ const node = taskNode(task.id);
46
+ if (!acceptedTask(task))
47
+ unfinished.add(node);
48
+ const archivedAt = parseTimestampMs(task.archivedAt), acceptedAt = parseTimestampMs(task.acceptance?.acceptedAt);
49
+ if (!acceptedTask(task) || task.status !== "archived" || archivedAt === null || acceptedAt === null
50
+ || versions.get(task.id) !== TASK_RETENTION_ARCHIVE_VERSION || archivedMs === null
51
+ || now - Math.max(archivedAt, acceptedAt) < archivedMs)
52
+ notPurgeReady.add(node);
53
+ if (task.parentTaskId) {
54
+ link(node, taskNode(task.parentTaskId));
55
+ ancestors.set(node, new Set([taskNode(task.parentTaskId)]));
56
+ if (!byId.has(task.parentTaskId))
57
+ busy.add(node); // Unknown ancestry is not permission to detach history.
58
+ }
59
+ // Container-less archives can still have historical membership. Live membership comes from snapshots below.
60
+ if (!task.workspaceTaskId) {
61
+ for (const id of storage.listWandTaskSessionIds(task.id))
62
+ link(node, sessionNode(id));
63
+ }
64
+ }
65
+ const checked = new Set();
66
+ for (const task of tasks) {
67
+ const path = new Set();
68
+ let cursor = task.id;
69
+ while (cursor && !checked.has(cursor)) {
70
+ if (path.has(cursor)) {
71
+ busy.add(taskNode(cursor));
72
+ break;
73
+ }
74
+ path.add(cursor);
75
+ cursor = byId.get(cursor)?.parentTaskId ?? null;
76
+ }
77
+ for (const id of path)
78
+ checked.add(id);
79
+ }
80
+ for (const session of sessions) {
81
+ const node = sessionNode(session.id);
82
+ if (isArchiveBlocked(session))
83
+ busy.add(node);
84
+ if (session.workspaceTaskId) {
85
+ const owner = byContainer.get(session.workspaceTaskId);
86
+ if (owner)
87
+ link(node, taskNode(owner.id));
88
+ else
89
+ busy.add(node);
90
+ }
91
+ }
92
+ for (const fact of storage.taskCommentRetentionFacts()) {
93
+ const node = taskNode(fact.taskId);
94
+ if (fact.sessionId)
95
+ link(node, sessionNode(fact.sessionId));
96
+ if (fact.state !== "accepted" && fact.state !== "failed")
97
+ busy.add(node);
98
+ }
99
+ const teamSessionIds = new Map();
100
+ for (const run of runs) {
101
+ const node = runNode(run.id), ids = new Set();
102
+ if (run.chatSessionId)
103
+ ids.add(run.chatSessionId);
104
+ for (const step of storage.listAiTeamSteps(run.id))
105
+ if (step.sessionId)
106
+ ids.add(step.sessionId);
107
+ teamSessionIds.set(run.id, [...ids]);
108
+ for (const id of ids)
109
+ link(node, sessionNode(id));
110
+ if (run.taskId) {
111
+ const owner = byId.get(run.taskId) ?? byContainer.get(run.taskId);
112
+ // A dangling historical id has no surviving task context to detach; active status is handled above.
113
+ if (owner)
114
+ link(node, taskNode(owner.id));
115
+ }
116
+ if (AI_TEAM_ACTIVE_RUN_STATUSES.includes(run.status))
117
+ busy.add(node);
118
+ }
119
+ const executionHeld = spread(graph, busy);
120
+ const archiveHeld = spread(graph, [...busy, ...unfinished]);
121
+ // A task-bound history must outlive the latest acceptance/archive grace window in its whole family.
122
+ const purgeHeld = spread(graph, [...busy, ...notPurgeReady]);
123
+ const unfinishedAncestors = spread(ancestors, unfinished);
124
+ return {
125
+ tasks, runs, teamSessionIds,
126
+ canArchiveTask: (task) => task.status === "done" && acceptedTask(task)
127
+ && !executionHeld.has(taskNode(task.id)) && !unfinishedAncestors.has(taskNode(task.id)),
128
+ canPurgeTask: (id) => !purgeHeld.has(taskNode(id)),
129
+ canArchiveSession: (id) => !archiveHeld.has(sessionNode(id)),
130
+ canPurgeSession: (id) => !purgeHeld.has(sessionNode(id)),
131
+ canArchiveRun: (id) => !archiveHeld.has(runNode(id)),
132
+ canPurgeRun: (id) => !purgeHeld.has(runNode(id)),
133
+ };
134
+ }
@@ -5,8 +5,9 @@ import type { SessionSnapshot } from "./types.js";
5
5
  export declare const RETENTION_IDLE_MS: number;
6
6
  export declare const RETENTION_ARCHIVED_MS: number;
7
7
  /**
8
- * 看板任务、会话和已结束的团队运行共用 `taskRetention`。
9
- * 没配过时默认空闲 7 天归档,再过 7 天清理。
8
+ * 看板任务、会话和已结束的团队运行共用 `taskRetention` 的开关与天数。
9
+ * 只有已验收、无未完成上下文且无执行/审批/排队事实的任务才能自动归档;
10
+ * 关联会话与团队历史跟随保护。升级前的任务归档不自动删除。
10
11
  * 结构化会话看运行状态;PTY 只有正在回复或等待确认才跳过,空闲壳不算在处理。
11
12
  */
12
13
  export interface RetentionDeps {