@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
@@ -0,0 +1,208 @@
1
+ import crypto from "node:crypto";
2
+ import { isGlobalWorkspace } from "../workspace-binding.js";
3
+ import { normalizeEmployeeKnowledge } from "../employee-knowledge-content.js";
4
+ import { EMPLOYEE_KNOWLEDGE_MAX_ENTRIES } from "../employee-knowledge-types.js";
5
+ import { KnowledgeError } from "../knowledge-types.js";
6
+ const hash = (value) => crypto.createHash("sha256").update(value).digest("hex");
7
+ const spec = (scope) => scope === "personal"
8
+ ? { table: "employee_knowledge", owner: "employee_id" }
9
+ : { table: "project_knowledge", owner: "workspace_id" };
10
+ export class KnowledgeRepository {
11
+ db;
12
+ s;
13
+ constructor(db, s) {
14
+ this.db = db;
15
+ this.s = s;
16
+ }
17
+ #owner(scope, ownerId) {
18
+ if (scope === "personal") {
19
+ const employee = this.s.getSiliconEmployeeDefinition(ownerId);
20
+ if (!employee)
21
+ throw new KnowledgeError("员工已删除或不存在,不能改存到其他员工。", 404);
22
+ return { name: employee.name, readOnly: false };
23
+ }
24
+ const workspace = this.s.getWorkspace(ownerId);
25
+ if (workspace && !isGlobalWorkspace(workspace))
26
+ return { name: workspace.name, readOnly: false };
27
+ if (!workspace) {
28
+ const orphan = this.db.prepare("SELECT project_name FROM project_knowledge WHERE workspace_id = ? LIMIT 1").get(ownerId);
29
+ if (orphan)
30
+ return { name: `${String(orphan.project_name)}(已移除项目)`, readOnly: true };
31
+ }
32
+ throw new KnowledgeError("项目不存在,或当前空间不是项目知识库。", 404);
33
+ }
34
+ knowledgeOwners() {
35
+ const projects = this.s.listWorkspaces().filter(workspace => !isGlobalWorkspace(workspace))
36
+ .map(workspace => ({ id: workspace.id, name: workspace.name, readOnly: false }));
37
+ const orphans = this.db.prepare(`SELECT workspace_id, MAX(project_name) AS project_name FROM project_knowledge
38
+ WHERE NOT EXISTS (SELECT 1 FROM workspaces w WHERE w.id = workspace_id) GROUP BY workspace_id`).all();
39
+ for (const row of orphans)
40
+ projects.push({ id: String(row.workspace_id), name: `${String(row.project_name)}(已移除项目)`, readOnly: true });
41
+ return { employees: this.s.listSiliconEmployees({ includeArchived: true }).map(employee => ({ id: employee.id, name: employee.name })), projects };
42
+ }
43
+ #project(row, scope, ownerId) {
44
+ return { id: row.id, scope, ownerId, title: row.title || row.content.split(/\r?\n/).find(line => line.trim())?.trim().slice(0, 100) || "无标题文档",
45
+ content: row.content, folder: row.folder || "未分类", revision: row.revision, createdAt: row.created_at, updatedAt: row.updated_at || row.created_at };
46
+ }
47
+ readKnowledgeLibrary(scope, ownerId, query = "", accessToken) {
48
+ if (accessToken)
49
+ this.#requireAccess(accessToken, scope, ownerId);
50
+ const owner = this.#owner(scope, ownerId);
51
+ const { table, owner: column } = spec(scope);
52
+ const rows = this.db.prepare(`SELECT * FROM ${table} WHERE ${column} = ? ORDER BY COALESCE(updated_at, created_at) DESC, rowid DESC LIMIT ?`)
53
+ .all(ownerId, EMPLOYEE_KNOWLEDGE_MAX_ENTRIES);
54
+ const normalizedQuery = query.trim().slice(0, 200).toLocaleLowerCase();
55
+ const entries = rows.map(row => this.#project(row, scope, ownerId))
56
+ .filter(entry => `${entry.title}\n${entry.content}\n${entry.folder}`.toLocaleLowerCase().includes(normalizedQuery));
57
+ return { scope, ownerId, ownerName: owner.name, readOnly: owner.readOnly, entries, total: rows.length, limit: EMPLOYEE_KNOWLEDGE_MAX_ENTRIES };
58
+ }
59
+ getKnowledgeDocument(scope, ownerId, id, accessToken) {
60
+ if (accessToken)
61
+ this.#requireAccess(accessToken, scope, ownerId);
62
+ this.#owner(scope, ownerId);
63
+ const { table, owner } = spec(scope);
64
+ const row = this.db.prepare(`SELECT * FROM ${table} WHERE ${owner} = ? AND id = ?`).get(ownerId, id);
65
+ if (!row)
66
+ throw new KnowledgeError("文档不属于当前知识库或已删除。", 404);
67
+ return this.#project(row, scope, ownerId);
68
+ }
69
+ #normalize(input) {
70
+ let content;
71
+ try {
72
+ content = normalizeEmployeeKnowledge(input.content);
73
+ }
74
+ catch (error) {
75
+ throw new KnowledgeError(error.message);
76
+ }
77
+ const title = (input.title ?? "").trim();
78
+ const folder = (input.folder ?? "").trim();
79
+ if (title.length > 100 || folder.length > 100)
80
+ throw new KnowledgeError("标题和目录名最多 100 个字符。");
81
+ // The same credential guard covers metadata, without imposing the body non-empty rule on optional fields.
82
+ for (const value of [title, folder])
83
+ if (value) {
84
+ try {
85
+ normalizeEmployeeKnowledge(value);
86
+ }
87
+ catch (error) {
88
+ throw new KnowledgeError(error.message);
89
+ }
90
+ }
91
+ return { content, title, folder };
92
+ }
93
+ createKnowledgeDocument(scope, ownerId, input, accessToken) {
94
+ const values = this.#normalize(input);
95
+ return this.s.transaction(() => {
96
+ if (accessToken)
97
+ this.#requireAccess(accessToken, scope, ownerId);
98
+ const owner = this.#owner(scope, ownerId);
99
+ if (owner.readOnly)
100
+ throw new KnowledgeError("项目已移除,知识保留供查看和删除,不能新增或编辑。", 409);
101
+ const { table, owner: column } = spec(scope);
102
+ const contentHash = hash(values.content);
103
+ const existing = this.db.prepare(`SELECT * FROM ${table} WHERE ${column} = ? AND content_hash = ?`).get(ownerId, contentHash);
104
+ if (existing)
105
+ return { entry: this.#project(existing, scope, ownerId), created: false };
106
+ const count = Number(this.db.prepare(`SELECT COUNT(*) AS count FROM ${table} WHERE ${column} = ?`).get(ownerId)?.count ?? 0);
107
+ if (count >= EMPLOYEE_KNOWLEDGE_MAX_ENTRIES)
108
+ throw new KnowledgeError("知识库已满,请先删除不需要的文档;不会自动丢弃旧知识。");
109
+ const id = `${scope === "personal" ? "k" : "pk"}_${crypto.randomUUID().replace(/-/g, "")}`;
110
+ const now = new Date().toISOString();
111
+ if (scope === "personal")
112
+ this.db.prepare(`INSERT INTO employee_knowledge (id, employee_id, title, folder, content, content_hash, created_at, updated_at)
113
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(id, ownerId, values.title, values.folder, values.content, contentHash, now, now);
114
+ else
115
+ this.db.prepare(`INSERT INTO project_knowledge (id, workspace_id, project_name, title, folder, content, content_hash, created_at, updated_at)
116
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, ownerId, owner.name, values.title, values.folder, values.content, contentHash, now, now);
117
+ return { entry: this.getKnowledgeDocument(scope, ownerId, id), created: true };
118
+ });
119
+ }
120
+ updateKnowledgeDocument(scope, ownerId, id, revision, input, accessToken) {
121
+ const values = this.#normalize(input);
122
+ return this.s.transaction(() => {
123
+ if (accessToken)
124
+ this.#requireAccess(accessToken, scope, ownerId);
125
+ const owner = this.#owner(scope, ownerId);
126
+ if (owner.readOnly)
127
+ throw new KnowledgeError("项目已移除,知识保留供查看和删除,不能新增或编辑。", 409);
128
+ const previous = this.getKnowledgeDocument(scope, ownerId, id);
129
+ if (previous.revision !== revision)
130
+ throw new KnowledgeError("这篇文档已被修改。请重新读取,保留并核对当前草稿后再保存。", 409);
131
+ const { table, owner: column } = spec(scope);
132
+ const contentHash = hash(values.content);
133
+ const duplicate = this.db.prepare(`SELECT id FROM ${table} WHERE ${column} = ? AND content_hash = ? AND id != ?`).get(ownerId, contentHash, id);
134
+ if (duplicate)
135
+ throw new KnowledgeError("当前知识库已有相同正文,请核对后保留一篇。");
136
+ this.db.prepare(`UPDATE ${table} SET title = ?, folder = ?, content = ?, content_hash = ?, updated_at = ?, revision = revision + 1
137
+ WHERE ${column} = ? AND id = ? AND revision = ?`).run(values.title, values.folder, values.content, contentHash, new Date().toISOString(), ownerId, id, revision);
138
+ // An older execution must not recreate the previous fact after the user corrected it.
139
+ this.invalidateKnowledgeNamespace(scope, ownerId);
140
+ return this.getKnowledgeDocument(scope, ownerId, id);
141
+ });
142
+ }
143
+ deleteKnowledgeDocument(scope, ownerId, id, revision, accessToken) {
144
+ this.s.transaction(() => {
145
+ if (accessToken)
146
+ this.#requireAccess(accessToken, scope, ownerId);
147
+ const previous = this.getKnowledgeDocument(scope, ownerId, id);
148
+ if (previous.revision !== revision)
149
+ throw new KnowledgeError("文档已变化,请重新读取后再确认删除。", 409);
150
+ const { table, owner } = spec(scope);
151
+ this.db.prepare(`DELETE FROM ${table} WHERE ${owner} = ? AND id = ?`).run(ownerId, id);
152
+ this.invalidateKnowledgeNamespace(scope, ownerId);
153
+ });
154
+ }
155
+ invalidateKnowledgeNamespace(scope, ownerId) {
156
+ this.db.prepare(`INSERT INTO knowledge_namespace_versions(scope, owner_id, revision) VALUES (?, ?, 1)
157
+ ON CONFLICT(scope, owner_id) DO UPDATE SET revision = revision + 1`).run(scope, ownerId);
158
+ if (scope === "personal")
159
+ this.db.prepare("DELETE FROM employee_knowledge_access WHERE employee_id = ?").run(ownerId);
160
+ }
161
+ #namespaceRevision(scope, ownerId) {
162
+ return ownerId ? Number(this.db.prepare("SELECT revision FROM knowledge_namespace_versions WHERE scope = ? AND owner_id = ?").get(scope, ownerId)?.revision ?? 0) : 0;
163
+ }
164
+ /** Only persisted bindings count; legacy UI identity projections are not authority. */
165
+ knowledgeSessionScope(sessionId) {
166
+ const session = this.db.prepare(`SELECT automation_id,
167
+ CASE WHEN json_valid(session_options) THEN json_extract(session_options, '$.employeeId') END AS employee_id
168
+ FROM command_sessions WHERE id = ?`).get(sessionId);
169
+ if (!session || (typeof session.automation_id === "string" && session.automation_id.startsWith("dingtalk:")))
170
+ return null;
171
+ const employeeId = typeof session.employee_id === "string" && this.s.getSiliconEmployeeDefinition(session.employee_id) ? session.employee_id : null;
172
+ const binding = this.s.getSessionWorkspace(sessionId);
173
+ const task = binding?.workspaceTaskId ? this.s.getWorkspaceTask(binding.workspaceTaskId) : null;
174
+ const workspace = binding?.workspaceId ? this.s.getWorkspace(binding.workspaceId) : null;
175
+ const workspaceId = workspace && !isGlobalWorkspace(workspace) && (!binding?.workspaceTaskId || task?.workspaceId === workspace.id) ? workspace.id : null;
176
+ return employeeId || workspaceId ? { sessionId, employeeId, workspaceId } : null;
177
+ }
178
+ issueKnowledgeAccess(sessionId, now = Date.now()) {
179
+ const scope = this.knowledgeSessionScope(sessionId);
180
+ if (!scope)
181
+ throw new KnowledgeError("当前会话未绑定可用员工或项目,知识库能力不可用。", 403);
182
+ this.db.prepare("DELETE FROM knowledge_access WHERE expires_at <= ?").run(now);
183
+ const token = crypto.randomBytes(32).toString("base64url");
184
+ this.db.prepare(`INSERT INTO knowledge_access (token_hash, session_id, employee_id, workspace_id, employee_revision, project_revision, expires_at)
185
+ VALUES (?, ?, ?, ?, ?, ?, ?)`).run(hash(token), sessionId, scope.employeeId, scope.workspaceId, this.#namespaceRevision("personal", scope.employeeId), this.#namespaceRevision("project", scope.workspaceId), now + 6 * 3600_000);
186
+ return token;
187
+ }
188
+ resolveKnowledgeAccess(token, now = Date.now()) {
189
+ if (!/^[A-Za-z0-9_-]{43}$/.test(token))
190
+ return null;
191
+ const row = this.db.prepare("SELECT * FROM knowledge_access WHERE token_hash = ? AND expires_at > ?").get(hash(token), now);
192
+ if (!row)
193
+ return null;
194
+ const current = this.knowledgeSessionScope(String(row.session_id));
195
+ if (!current || current.employeeId !== row.employee_id || current.workspaceId !== row.workspace_id
196
+ || this.#namespaceRevision("personal", current.employeeId) !== row.employee_revision
197
+ || this.#namespaceRevision("project", current.workspaceId) !== row.project_revision)
198
+ return null;
199
+ return current;
200
+ }
201
+ revokeKnowledgeAccess(token) { this.db.prepare("DELETE FROM knowledge_access WHERE token_hash = ?").run(hash(token)); }
202
+ revokeSessionKnowledgeAccess(sessionId) { this.db.prepare("DELETE FROM knowledge_access WHERE session_id = ?").run(sessionId); }
203
+ #requireAccess(token, scope, ownerId) {
204
+ const access = this.resolveKnowledgeAccess(token);
205
+ if ((scope === "personal" ? access?.employeeId : access?.workspaceId) !== ownerId)
206
+ throw new KnowledgeError("知识库归属已变化或访问已失效,请等待新的会话执行。", 403);
207
+ }
208
+ }
@@ -330,7 +330,7 @@ export function normalizeWorktreeMergeStatus(raw) {
330
330
  return undefined;
331
331
  }
332
332
  export function normalizeSessionSource(raw) {
333
- return raw === "automation" || raw === "startup" || raw === "interactive" ? raw : "interactive";
333
+ return raw === "automation" || raw === "startup" || raw === "interactive" || raw === "quick-terminal" ? raw : "interactive";
334
334
  }
335
335
  export function mapWorktreeMergeFields(row) {
336
336
  return {
@@ -9,6 +9,49 @@ import { isThinkingEffort } from "../structured-provider-common.js";
9
9
  import { DEFAULT_WAND_TASK_PRIORITY, normalizeWandTaskAgentMode } from "../task-types.js";
10
10
  import { GLOBAL_WORKSPACE_ID } from "../types.js";
11
11
  import { mapSessionCore, parseWandTaskAgent, sessionSelectFields } from "./mappers.js";
12
+ /** Additive, idempotent initialization; legacy content and IDs are never rewritten. */
13
+ function migrateKnowledgeDocumentsV22(db) {
14
+ const columns = new Set(db.prepare("PRAGMA table_info(employee_knowledge)").all().map(row => row.name));
15
+ for (const [name, definition] of [["title", "TEXT NOT NULL DEFAULT ''"], ["folder", "TEXT NOT NULL DEFAULT ''"], ["revision", "INTEGER NOT NULL DEFAULT 1"], ["updated_at", "TEXT"]]) {
16
+ if (!columns.has(name))
17
+ db.exec(`ALTER TABLE employee_knowledge ADD COLUMN ${name} ${definition}`);
18
+ }
19
+ db.exec(`
20
+ CREATE TABLE IF NOT EXISTS project_knowledge (
21
+ id TEXT PRIMARY KEY, workspace_id TEXT NOT NULL, project_name TEXT NOT NULL,
22
+ title TEXT NOT NULL DEFAULT '', folder TEXT NOT NULL DEFAULT '', content TEXT NOT NULL,
23
+ content_hash TEXT NOT NULL, revision INTEGER NOT NULL DEFAULT 1,
24
+ created_at TEXT NOT NULL, updated_at TEXT, UNIQUE(workspace_id, content_hash)
25
+ );
26
+ CREATE INDEX IF NOT EXISTS idx_project_knowledge_owner ON project_knowledge(workspace_id);
27
+ CREATE TABLE IF NOT EXISTS knowledge_namespace_versions (
28
+ scope TEXT NOT NULL, owner_id TEXT NOT NULL, revision INTEGER NOT NULL DEFAULT 0,
29
+ PRIMARY KEY(scope, owner_id)
30
+ );
31
+ CREATE TABLE IF NOT EXISTS knowledge_access (
32
+ token_hash TEXT PRIMARY KEY, session_id TEXT NOT NULL REFERENCES command_sessions(id) ON DELETE CASCADE,
33
+ employee_id TEXT, workspace_id TEXT, employee_revision INTEGER NOT NULL,
34
+ project_revision INTEGER NOT NULL, expires_at INTEGER NOT NULL
35
+ );
36
+ CREATE INDEX IF NOT EXISTS idx_knowledge_access_session ON knowledge_access(session_id);
37
+ CREATE TRIGGER IF NOT EXISTS revoke_knowledge_access_on_session_binding
38
+ AFTER UPDATE OF workspace_id, workspace_task_id, session_options, automation_id ON command_sessions
39
+ WHEN OLD.workspace_id IS NOT NEW.workspace_id
40
+ OR OLD.workspace_task_id IS NOT NEW.workspace_task_id
41
+ OR OLD.automation_id IS NOT NEW.automation_id
42
+ OR (CASE WHEN json_valid(OLD.session_options) THEN json_extract(OLD.session_options, '$.employeeId') END)
43
+ IS NOT (CASE WHEN json_valid(NEW.session_options) THEN json_extract(NEW.session_options, '$.employeeId') END)
44
+ BEGIN
45
+ DELETE FROM knowledge_access WHERE session_id = NEW.id;
46
+ DELETE FROM employee_knowledge_access WHERE session_id = NEW.id;
47
+ END;
48
+ CREATE TRIGGER IF NOT EXISTS revoke_knowledge_access_on_employee_delete
49
+ AFTER DELETE ON silicon_employees
50
+ BEGIN
51
+ DELETE FROM knowledge_access WHERE employee_id = OLD.id;
52
+ END;
53
+ `);
54
+ }
12
55
  const LEGACY_TASK_RECORDS_KEY = "pref:taskRecordsVersion";
13
56
  function nowIsoFrozen() {
14
57
  return new Date().toISOString();
@@ -352,4 +395,12 @@ export const STORAGE_MIGRATIONS = [
352
395
  `) },
353
396
  { version: 20, name: "apns-device-subscriptions-and-outbox", up: db => db.exec(APNS_SCHEMA) },
354
397
  { version: 21, name: "apns-live-activity-updates", up: db => db.exec(LIVE_ACTIVITY_SCHEMA) },
398
+ { version: 22, name: "scoped-knowledge-documents", up: migrateKnowledgeDocumentsV22 },
399
+ { version: 23, name: "task-retention-archive-provenance", up: db => {
400
+ const columns = db.prepare("PRAGMA table_info(wand_tasks)").all();
401
+ if (!columns.some(column => column.name === "retention_archive_version")) {
402
+ // NULL deliberately protects every pre-policy archive, even if it was once accepted.
403
+ db.exec("ALTER TABLE wand_tasks ADD COLUMN retention_archive_version INTEGER");
404
+ }
405
+ } },
355
406
  ];
@@ -8,6 +8,8 @@ export declare class SessionRepository {
8
8
  private readonly db;
9
9
  private readonly s;
10
10
  constructor(db: DatabaseSync, s: WandStorage);
11
+ /** Change only the client surface binding; preserve the process, transcript and task membership. */
12
+ claimQuickTerminal(id: string): SessionSnapshot;
11
13
  listGithubIssueBindings(owner: string, repo: string, issueNumber: number): Array<{
12
14
  sessionId: string;
13
15
  boundAt: string;
@@ -4,6 +4,8 @@ import { nowIso } from "../password-manager.js";
4
4
  import { sessionSelectFields, sessionPersistFields, sessionPersistAssignments, sessionRuntimeMetadataAssignments, mapSessionCore, sessionRowQuery } from "./mappers.js";
5
5
  import { SYSTEM_AI_AUXILIARY_PURPOSES, SYSTEM_AI_CALL_PREFIX } from "../system-ai-call.js";
6
6
  import { validPiCliCheckpoint } from "../pi-cli-checkpoint.js";
7
+ import { canClaimQuickTerminal } from "../quick-terminal-session.js";
8
+ import { badRequest, notFound } from "../http-error.js";
7
9
  const AUXILIARY_HISTORY_PATTERNS = SYSTEM_AI_AUXILIARY_PURPOSES.map(purpose => `${SYSTEM_AI_CALL_PREFIX}${purpose}:?*`);
8
10
  /** Session storage: one domain of the WandStorage facade. Shares the connection and the facade's transaction. */
9
11
  export class SessionRepository {
@@ -13,6 +15,20 @@ export class SessionRepository {
13
15
  this.db = db;
14
16
  this.s = s;
15
17
  }
18
+ /** Change only the client surface binding; preserve the process, transcript and task membership. */
19
+ claimQuickTerminal(id) {
20
+ return this.s.transaction(() => {
21
+ const session = this.getSession(id);
22
+ if (!session)
23
+ throw notFound("未找到该终端,可能已被删除。");
24
+ if (!canClaimQuickTerminal(session))
25
+ throw badRequest("只有普通空白终端可以作为快捷终端。");
26
+ if (session.sessionSource !== "quick-terminal") {
27
+ this.db.prepare("UPDATE command_sessions SET session_source = 'quick-terminal' WHERE id = ?").run(id);
28
+ }
29
+ return { ...session, sessionSource: "quick-terminal" };
30
+ });
31
+ }
16
32
  listGithubIssueBindings(owner, repo, issueNumber) {
17
33
  const rows = this.db.prepare(`SELECT session_id, bound_at FROM github_issue_bindings
18
34
  WHERE owner = ? AND repo = ? AND issue_number = ? ORDER BY bound_at ASC`).all(owner, repo, issueNumber);
@@ -106,6 +106,13 @@ export declare class TaskRepository {
106
106
  recordTaskCommentSessionEvent(event: import("../types.js").ProcessEvent): void;
107
107
  getWandTask(id: string): WandTask | null;
108
108
  getWandTaskByWorkspaceTaskId(workspaceTaskId: string): WandTask | null;
109
+ /** Internal retention facts only: no settings, transcripts, or public DTO fields. */
110
+ taskRetentionArchiveVersions(): Map<string, number>;
111
+ taskCommentRetentionFacts(): Array<{
112
+ taskId: string;
113
+ sessionId: string | null;
114
+ state: string;
115
+ }>;
109
116
  insertWandTask(input: CreateWandTaskInput, createdAt?: string): WandTask;
110
117
  private insertWandTaskBody;
111
118
  createWandTask(input: CreateWandTaskInput): WandTask;
@@ -1,5 +1,6 @@
1
1
  import crypto from "node:crypto";
2
2
  import { assertTaskHierarchy } from "../task-hierarchy.js";
3
+ import { TASK_RETENTION_ARCHIVE_VERSION } from "../task-retention.js";
3
4
  import { firstLayoutTabId } from "../layout-tree.js";
4
5
  import { nowIso } from "../password-manager.js";
5
6
  import { isSessionProvider } from "../session-provider.js";
@@ -426,6 +427,17 @@ export class TaskRepository {
426
427
  .get(workspaceTaskId);
427
428
  return row ? this.mapWandTaskRow(row) : null;
428
429
  }
430
+ /** Internal retention facts only: no settings, transcripts, or public DTO fields. */
431
+ taskRetentionArchiveVersions() {
432
+ const rows = this.db.prepare("SELECT id, retention_archive_version FROM wand_tasks WHERE status = 'archived' AND retention_archive_version IS NOT NULL")
433
+ .all();
434
+ return new Map(rows.map(row => [row.id, row.retention_archive_version]));
435
+ }
436
+ taskCommentRetentionFacts() {
437
+ return this.db.prepare("SELECT task_id, session_id, state FROM wand_task_comment_dispatches")
438
+ .all()
439
+ .map(row => ({ taskId: row.task_id, sessionId: row.session_id, state: row.state }));
440
+ }
429
441
  insertWandTask(input, createdAt = nowIso()) {
430
442
  return this.s.transaction(() => this.insertWandTaskBody(input, createdAt));
431
443
  }
@@ -453,6 +465,10 @@ export class TaskRepository {
453
465
  }
454
466
  throw error;
455
467
  }
468
+ if (status === "archived") {
469
+ this.db.prepare("UPDATE wand_tasks SET retention_archive_version = ? WHERE id = ?")
470
+ .run(TASK_RETENTION_ARCHIVE_VERSION, id);
471
+ }
456
472
  if (input.parentTaskId) {
457
473
  const parent = this.getWandTask(input.parentTaskId);
458
474
  if (parent?.acceptance?.acceptedAt)
@@ -537,6 +553,11 @@ export class TaskRepository {
537
553
  archived_at = ?, updated_at = ?, acceptance_json = ?
538
554
  WHERE id = ?`)
539
555
  .run(next.workspaceId, next.workspaceTaskId, next.parentTaskId, next.title, next.titleSource, next.autoTitleSignature ?? null, next.description, next.status, next.priority, JSON.stringify(next.labels), next.dueDate, next.milestoneId ?? null, next.sortOrder, next.agent ? JSON.stringify(next.agent) : null, next.executionSubject ? JSON.stringify(next.executionSubject) : null, next.archivedAt, next.updatedAt, next.acceptance ? JSON.stringify(next.acceptance) : null, next.id);
556
+ // Only a real transition may opt into the new policy. Editing/backfilling an old archive must not do so.
557
+ if (next.status !== current.status) {
558
+ this.db.prepare("UPDATE wand_tasks SET retention_archive_version = ? WHERE id = ?")
559
+ .run(next.status === "archived" ? TASK_RETENTION_ARCHIVE_VERSION : null, next.id);
560
+ }
540
561
  if (patch.workspaceId !== undefined && next.workspaceTaskId) {
541
562
  const workspaceId = next.workspaceId ?? this.s.ensureGlobalWorkspace().id;
542
563
  // The container FK/index and standalone session workspace bucket follow the canonical project.
@@ -38,6 +38,7 @@ export declare class WorkspaceRepository {
38
38
  countSessionsByWorkspace(options?: {
39
39
  includeArchived?: boolean;
40
40
  excludeSystemAiCalls?: boolean;
41
+ excludeQuickTerminals?: boolean;
41
42
  }): Map<string, number>;
42
43
  /** Count user-initiated CLI launches (one per session), including archived sessions. */
43
44
  countInteractiveSessionsByProvider(): Record<SessionProvider, number>;
@@ -175,8 +175,9 @@ export class WorkspaceRepository {
175
175
  ORDER BY updated_at DESC, rowid DESC LIMIT 1
176
176
  ), '') <> 'archived'))
177
177
  AND (? = 0 OR COALESCE(session.automation_id, '') NOT GLOB ?)
178
+ AND (? = 0 OR session.session_source <> 'quick-terminal')
178
179
  GROUP BY session.workspace_id`)
179
- .all(options.includeArchived === true ? 1 : 0, options.excludeSystemAiCalls === true ? 1 : 0, `${SYSTEM_AI_CALL_PREFIX}*`);
180
+ .all(options.includeArchived === true ? 1 : 0, options.excludeSystemAiCalls === true ? 1 : 0, `${SYSTEM_AI_CALL_PREFIX}*`, options.excludeQuickTerminals === true ? 1 : 0);
180
181
  return new Map(rows.map((row) => [row.id, Number(row.n) || 0]));
181
182
  }
182
183
  /** Count user-initiated CLI launches (one per session), including archived sessions. */
package/dist/storage.d.ts CHANGED
@@ -11,6 +11,7 @@ import { PreferencesRepository } from "./storage/preferences-repository.js";
11
11
  import { WorkspaceRepository } from "./storage/workspaces-repository.js";
12
12
  import { TaskRepository } from "./storage/tasks-repository.js";
13
13
  import { SecretsRepository } from "./storage/secrets-repository.js";
14
+ import { KnowledgeRepository } from "./storage/knowledge-repository.js";
14
15
  import { EmployeeRepository } from "./storage/employees-repository.js";
15
16
  import { UserMemoryRepository } from "./storage/user-memory-repository.js";
16
17
  import { AiTeamRepository } from "./storage/ai-teams-repository.js";
@@ -25,7 +26,7 @@ export { ensureDatabaseFile } from "./storage-schema.js";
25
26
  type RepositoryMethods<T> = Pick<T, {
26
27
  [K in keyof T]: T[K] extends (...args: never[]) => unknown ? K : never;
27
28
  }[keyof T]>;
28
- export interface WandStorage extends RepositoryMethods<DingTalkRepository>, RepositoryMethods<ConversationRepository>, RepositoryMethods<ConversationOrganizationRepository>, RepositoryMethods<PreferencesRepository>, RepositoryMethods<WorkspaceRepository>, RepositoryMethods<TaskRepository>, RepositoryMethods<SecretsRepository>, RepositoryMethods<EmployeeRepository>, RepositoryMethods<UserMemoryRepository>, RepositoryMethods<AiTeamRepository>, RepositoryMethods<MissionRepository>, RepositoryMethods<SessionRepository>, RepositoryMethods<UploadRepository>, RepositoryMethods<FeedbackRepository> {
29
+ export interface WandStorage extends RepositoryMethods<DingTalkRepository>, RepositoryMethods<ConversationRepository>, RepositoryMethods<ConversationOrganizationRepository>, RepositoryMethods<PreferencesRepository>, RepositoryMethods<WorkspaceRepository>, RepositoryMethods<TaskRepository>, RepositoryMethods<SecretsRepository>, RepositoryMethods<EmployeeRepository>, RepositoryMethods<KnowledgeRepository>, RepositoryMethods<UserMemoryRepository>, RepositoryMethods<AiTeamRepository>, RepositoryMethods<MissionRepository>, RepositoryMethods<SessionRepository>, RepositoryMethods<UploadRepository>, RepositoryMethods<FeedbackRepository> {
29
30
  }
30
31
  export declare class WandStorage {
31
32
  readonly dingtalk: DingTalkRepository;
@@ -38,6 +39,7 @@ export declare class WandStorage {
38
39
  readonly tasks: TaskRepository;
39
40
  readonly secrets: SecretsRepository;
40
41
  readonly employees: EmployeeRepository;
42
+ readonly knowledge: KnowledgeRepository;
41
43
  readonly userMemory: UserMemoryRepository;
42
44
  readonly aiTeams: AiTeamRepository;
43
45
  readonly missions: MissionRepository;
package/dist/storage.js CHANGED
@@ -14,6 +14,7 @@ import { PreferencesRepository } from "./storage/preferences-repository.js";
14
14
  import { WorkspaceRepository } from "./storage/workspaces-repository.js";
15
15
  import { TaskRepository } from "./storage/tasks-repository.js";
16
16
  import { SecretsRepository } from "./storage/secrets-repository.js";
17
+ import { KnowledgeRepository } from "./storage/knowledge-repository.js";
17
18
  import { EmployeeRepository } from "./storage/employees-repository.js";
18
19
  import { UserMemoryRepository } from "./storage/user-memory-repository.js";
19
20
  import { AiTeamRepository } from "./storage/ai-teams-repository.js";
@@ -34,6 +35,7 @@ export class WandStorage {
34
35
  tasks;
35
36
  secrets;
36
37
  employees;
38
+ knowledge;
37
39
  userMemory;
38
40
  aiTeams;
39
41
  missions;
@@ -100,6 +102,7 @@ export class WandStorage {
100
102
  this.tasks = new TaskRepository(this.db, this);
101
103
  this.secrets = new SecretsRepository(this.db, this);
102
104
  this.employees = new EmployeeRepository(this.db, this);
105
+ this.knowledge = new KnowledgeRepository(this.db, this);
103
106
  this.userMemory = new UserMemoryRepository(this.db, this);
104
107
  this.aiTeams = new AiTeamRepository(this.db, this);
105
108
  this.missions = new MissionRepository(this.db, this);
@@ -255,6 +258,7 @@ const REPOSITORY_FORWARDS = [
255
258
  ["tasks", TaskRepository],
256
259
  ["secrets", SecretsRepository],
257
260
  ["employees", EmployeeRepository],
261
+ ["knowledge", KnowledgeRepository],
258
262
  ["userMemory", UserMemoryRepository],
259
263
  ["aiTeams", AiTeamRepository],
260
264
  ["missions", MissionRepository],
@@ -96,6 +96,8 @@ export declare class StructuredSessionManager {
96
96
  private readonly autoAssignPending;
97
97
  private readonly preserveQueueOnInterrupt;
98
98
  private readonly interruptedScheduling;
99
+ /** 排队条「立即发送」中断后要补发的那条,也不得再回到员工并发排队。 */
100
+ private readonly interruptedImmediateStart;
99
101
  private employeeInputAdmission;
100
102
  private inputSequence;
101
103
  /** Last wall-clock time (ms) a streaming checkpoint reached SQLite. */
@@ -249,6 +251,7 @@ export declare class StructuredSessionManager {
249
251
  idempotencyKey?: string;
250
252
  preserveQueue?: boolean;
251
253
  queueAlreadyRemoved?: boolean;
254
+ immediateStart?: boolean;
252
255
  teamRequestStarted?: (sessionId: string, requestId: string) => void;
253
256
  source?: EmployeeInputScheduling["source"];
254
257
  scheduling?: EmployeeInputScheduling;
@@ -118,6 +118,8 @@ export class StructuredSessionManager {
118
118
  autoAssignPending = new Map();
119
119
  preserveQueueOnInterrupt = new Set();
120
120
  interruptedScheduling = new Map();
121
+ /** 排队条「立即发送」中断后要补发的那条,也不得再回到员工并发排队。 */
122
+ interruptedImmediateStart = new Set();
121
123
  employeeInputAdmission = null;
122
124
  inputSequence = 0;
123
125
  /** Last wall-clock time (ms) a streaming checkpoint reached SQLite. */
@@ -421,6 +423,7 @@ export class StructuredSessionManager {
421
423
  this.pendingRunnerExecutions.clear();
422
424
  this.interruptedWith.clear();
423
425
  this.interruptedScheduling.clear();
426
+ this.interruptedImmediateStart.clear();
424
427
  this.preserveQueueOnInterrupt.clear();
425
428
  for (const token of this.autoAssignPending.values())
426
429
  token.cancelled = true;
@@ -982,8 +985,9 @@ export class StructuredSessionManager {
982
985
  this.preserveQueueOnInterrupt.delete(sessionId);
983
986
  const scheduling = this.interruptedScheduling.get(sessionId);
984
987
  this.interruptedScheduling.delete(sessionId);
988
+ const immediateStart = this.interruptedImmediateStart.delete(sessionId);
985
989
  setImmediate(() => {
986
- this.sendMessage(sessionId, interruptPrompt, { scheduling }).catch((error) => {
990
+ this.sendMessage(sessionId, interruptPrompt, { scheduling, immediateStart }).catch((error) => {
987
991
  console.error("[WAND] recovered interrupt-and-send failed:", error);
988
992
  });
989
993
  });
@@ -1082,6 +1086,7 @@ export class StructuredSessionManager {
1082
1086
  }
1083
1087
  this.interruptedWith.delete(sessionId);
1084
1088
  this.interruptedScheduling.delete(sessionId);
1089
+ this.interruptedImmediateStart.delete(sessionId);
1085
1090
  this.preserveQueueOnInterrupt.delete(sessionId);
1086
1091
  this.clearStreamingCheckpoint(sessionId);
1087
1092
  this.disarmCandidateStartupWatchdog(sessionId);
@@ -1524,7 +1529,7 @@ export class StructuredSessionManager {
1524
1529
  if ("result" in inFlight)
1525
1530
  return inFlight.result;
1526
1531
  session = inFlight.session;
1527
- if (session.employeeId && this.employeeInputAdmission && !this.employeeInputAdmission.canStart(session, scheduling)) {
1532
+ if (session.employeeId && this.employeeInputAdmission && !this.employeeInputAdmission.canStart(session, scheduling, opts?.immediateStart)) {
1528
1533
  return this.enqueueInput(session, prompt, false, scheduling);
1529
1534
  }
1530
1535
  if (isAutoAssignSelector(session.selectedModel)) {
@@ -1545,7 +1550,7 @@ export class StructuredSessionManager {
1545
1550
  // await, so the drain cannot observe idle and then admit a new Core turn.
1546
1551
  if (this.coreRestartDrains > 0 && this.usesCoreEngine(session))
1547
1552
  return this.enqueueInput(session, prompt, false, scheduling);
1548
- if (session.employeeId && this.employeeInputAdmission && !this.employeeInputAdmission.canStart(session, scheduling)) {
1553
+ if (session.employeeId && this.employeeInputAdmission && !this.employeeInputAdmission.canStart(session, scheduling, opts?.immediateStart)) {
1549
1554
  return this.enqueueInput(session, prompt, true, scheduling);
1550
1555
  }
1551
1556
  // 检测上一轮 assistant 是否有未配对的 AskUserQuestion tool_use(说明前一次
@@ -1667,6 +1672,8 @@ export class StructuredSessionManager {
1667
1672
  this.interruptedWith.set(id, prompt);
1668
1673
  if (opts.scheduling)
1669
1674
  this.interruptedScheduling.set(id, opts.scheduling);
1675
+ if (opts.immediateStart)
1676
+ this.interruptedImmediateStart.add(id);
1670
1677
  let current = session;
1671
1678
  if (opts.preserveQueue) {
1672
1679
  this.preserveQueueOnInterrupt.add(id);
@@ -1996,6 +2003,7 @@ export class StructuredSessionManager {
1996
2003
  interrupt: inFlight,
1997
2004
  preserveQueue: inFlight,
1998
2005
  queueAlreadyRemoved: true,
2006
+ immediateStart: true,
1999
2007
  idempotencyKey,
2000
2008
  source: "user",
2001
2009
  });
@@ -2945,8 +2953,9 @@ export class StructuredSessionManager {
2945
2953
  this.preserveQueueOnInterrupt.delete(sessionId);
2946
2954
  const scheduling = this.interruptedScheduling.get(sessionId);
2947
2955
  this.interruptedScheduling.delete(sessionId);
2956
+ const immediateStart = this.interruptedImmediateStart.delete(sessionId);
2948
2957
  setImmediate(() => {
2949
- this.sendMessage(sessionId, interruptPrompt, { scheduling }).catch((error) => {
2958
+ this.sendMessage(sessionId, interruptPrompt, { scheduling, immediateStart }).catch((error) => {
2950
2959
  console.error("[WAND] interrupt-and-send failed:", error);
2951
2960
  });
2952
2961
  });
@@ -0,0 +1,22 @@
1
+ /** Read-only navigation projection; not a task status, queue, or mutation protocol. */
2
+ export type TaskActionKind = "permission" | "question" | "plan" | "reply" | "review" | "blocker";
3
+ export interface TaskActionItem {
4
+ key: string;
5
+ taskId: string;
6
+ identifier: string;
7
+ title: string;
8
+ workspaceId: string | null;
9
+ kind: TaskActionKind;
10
+ reason: string;
11
+ source: {
12
+ sessionId?: string;
13
+ requestId?: string;
14
+ toolId?: string;
15
+ runId?: string;
16
+ };
17
+ }
18
+ export interface TaskActionsSnapshot {
19
+ items: TaskActionItem[];
20
+ /** Non-zero means counts are lower bounds, never a verified empty inbox. */
21
+ incompleteSources: number;
22
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ import type { SessionRegistry } from "./session-registry.js";
2
+ import type { WandStorage } from "./storage.js";
3
+ import type { TaskActionsSnapshot } from "./task-action-types.js";
4
+ /** Read-only, runtime-backed navigation. No stored transcript hydration, repair, or mutation. */
5
+ export declare function readTaskActions(storage: WandStorage, registry?: SessionRegistry, workspaceId?: string): TaskActionsSnapshot;