@weavecode/weave 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (300) hide show
  1. package/node_modules/@weavecode/cli/dist/cli.js +3 -3
  2. package/node_modules/@weavecode/cli/dist/commands/daemon.d.ts +7 -0
  3. package/node_modules/@weavecode/cli/dist/commands/daemon.js +2 -2
  4. package/node_modules/@weavecode/cli/dist/commands/dashboard.d.ts +0 -2
  5. package/node_modules/@weavecode/cli/dist/commands/dashboard.js +2 -1
  6. package/node_modules/@weavecode/cli/dist/commands/doctor.js +1 -1
  7. package/node_modules/@weavecode/cli/dist/commands/init.js +1 -1
  8. package/node_modules/@weavecode/cli/dist/commands/msg.js +2 -2
  9. package/node_modules/@weavecode/cli/dist/commands/scan.js +1 -1
  10. package/node_modules/@weavecode/cli/dist/commands/status.js +2 -2
  11. package/node_modules/@weavecode/cli/dist/i18n/dict/en.js +6 -12
  12. package/node_modules/@weavecode/cli/dist/i18n/dict/zh.d.ts +44 -2
  13. package/node_modules/@weavecode/cli/dist/i18n/dict/zh.js +6 -12
  14. package/node_modules/@weavecode/cli/dist/init/claudemd-gen.d.ts +2 -3
  15. package/node_modules/@weavecode/cli/dist/init/claudemd-gen.js +4 -4
  16. package/node_modules/@weavecode/cli/dist/init/executor.js +3 -3
  17. package/node_modules/@weavecode/cli/dist/init/git-commit.js +1 -1
  18. package/node_modules/@weavecode/cli/dist/init/harnesses/claude.js +7 -7
  19. package/node_modules/@weavecode/cli/dist/init/harnesses/zcode.d.ts +29 -0
  20. package/node_modules/@weavecode/cli/dist/init/harnesses/zcode.js +1 -0
  21. package/node_modules/@weavecode/cli/dist/init/helpers-gen.d.ts +4 -0
  22. package/node_modules/@weavecode/cli/dist/init/helpers-gen.js +1 -20
  23. package/node_modules/@weavecode/cli/dist/init/mcp-gen.d.ts +3 -20
  24. package/node_modules/@weavecode/cli/dist/init/mcp-gen.js +1 -1
  25. package/node_modules/@weavecode/cli/dist/init/prompt.js +4 -4
  26. package/node_modules/@weavecode/cli/dist/init/settings-gen.d.ts +3 -30
  27. package/node_modules/@weavecode/cli/dist/init/settings-gen.js +1 -1
  28. package/node_modules/@weavecode/cli/package.json +5 -5
  29. package/node_modules/@weavecode/core/dist/harness.d.ts +45 -2
  30. package/node_modules/@weavecode/core/dist/harness.js +1 -1
  31. package/node_modules/@weavecode/core/dist/index.d.ts +2 -2
  32. package/node_modules/@weavecode/core/dist/index.js +1 -1
  33. package/node_modules/@weavecode/core/dist/terminal.d.ts +28 -4
  34. package/node_modules/@weavecode/core/dist/terminal.js +1 -1
  35. package/node_modules/@weavecode/core/dist/types.d.ts +188 -19
  36. package/node_modules/@weavecode/core/dist/types.js +1 -1
  37. package/node_modules/@weavecode/core/package.json +1 -1
  38. package/node_modules/@weavecode/harness/dist/claude/assets.d.ts +10 -0
  39. package/node_modules/@weavecode/harness/dist/claude/assets.js +4 -1
  40. package/node_modules/@weavecode/harness/dist/claude/capture.d.ts +15 -3
  41. package/node_modules/@weavecode/harness/dist/claude/capture.js +15 -9
  42. package/node_modules/@weavecode/harness/dist/claude/event-source.d.ts +1 -1
  43. package/node_modules/@weavecode/harness/dist/claude/event-source.js +1 -1
  44. package/node_modules/@weavecode/harness/dist/claude/helpers-gen.d.ts +5 -0
  45. package/node_modules/@weavecode/harness/dist/claude/helpers-gen.js +20 -0
  46. package/node_modules/@weavecode/harness/dist/claude/index.d.ts +10 -1
  47. package/node_modules/@weavecode/harness/dist/claude/index.js +1 -1
  48. package/node_modules/@weavecode/harness/dist/claude/mcp-gen.d.ts +22 -0
  49. package/node_modules/@weavecode/harness/dist/claude/mcp-gen.js +1 -0
  50. package/node_modules/@weavecode/harness/dist/claude/messaging.d.ts +11 -2
  51. package/node_modules/@weavecode/harness/dist/claude/messaging.js +4 -1
  52. package/node_modules/@weavecode/harness/dist/claude/model-aliases.d.ts +39 -0
  53. package/node_modules/@weavecode/harness/dist/claude/model-aliases.js +1 -0
  54. package/node_modules/@weavecode/harness/dist/claude/plan.d.ts +2 -0
  55. package/node_modules/@weavecode/harness/dist/claude/plan.js +1 -0
  56. package/node_modules/@weavecode/harness/dist/claude/questions.js +2 -1
  57. package/node_modules/@weavecode/harness/dist/claude/settings-gen.d.ts +32 -0
  58. package/node_modules/@weavecode/harness/dist/claude/settings-gen.js +1 -0
  59. package/node_modules/@weavecode/harness/dist/claude/side-question.d.ts +12 -0
  60. package/node_modules/@weavecode/harness/dist/claude/side-question.js +1 -0
  61. package/node_modules/@weavecode/harness/dist/claude/statusline/config.d.ts +200 -0
  62. package/node_modules/@weavecode/harness/dist/claude/statusline/config.js +1 -0
  63. package/node_modules/@weavecode/harness/dist/claude/statusline/generator.d.ts +12 -0
  64. package/node_modules/@weavecode/harness/dist/claude/statusline/generator.js +745 -0
  65. package/node_modules/@weavecode/harness/dist/claude/statusline/git-cache.d.ts +10 -0
  66. package/node_modules/@weavecode/harness/dist/claude/statusline/git-cache.js +1 -0
  67. package/node_modules/@weavecode/harness/dist/claude/statusline/surface.d.ts +20 -0
  68. package/node_modules/@weavecode/harness/dist/claude/statusline/surface.js +2 -0
  69. package/node_modules/@weavecode/harness/dist/claude/transcript.d.ts +16 -0
  70. package/node_modules/@weavecode/harness/dist/claude/transcript.js +4 -2
  71. package/node_modules/@weavecode/harness/dist/codex/assets.js +1 -1
  72. package/node_modules/@weavecode/harness/dist/codex/index.d.ts +1 -0
  73. package/node_modules/@weavecode/harness/dist/codex/index.js +1 -1
  74. package/node_modules/@weavecode/harness/dist/codex/mcp.d.ts +30 -0
  75. package/node_modules/@weavecode/harness/dist/codex/mcp.js +1 -0
  76. package/node_modules/@weavecode/harness/dist/codex/messaging.js +1 -1
  77. package/node_modules/@weavecode/harness/dist/driver.d.ts +168 -3
  78. package/node_modules/@weavecode/harness/dist/index.d.ts +1 -0
  79. package/node_modules/@weavecode/harness/dist/index.js +1 -1
  80. package/node_modules/@weavecode/harness/dist/init/generated.d.ts +37 -0
  81. package/node_modules/@weavecode/harness/dist/init/generated.js +2 -0
  82. package/node_modules/@weavecode/harness/dist/registry-wiring.d.ts +3 -1
  83. package/node_modules/@weavecode/harness/dist/zcode/assets.d.ts +8 -0
  84. package/node_modules/@weavecode/harness/dist/zcode/assets.js +1 -0
  85. package/node_modules/@weavecode/harness/dist/zcode/capture.d.ts +36 -0
  86. package/node_modules/@weavecode/harness/dist/zcode/capture.js +3 -0
  87. package/node_modules/@weavecode/harness/dist/zcode/detect.d.ts +2 -0
  88. package/node_modules/@weavecode/harness/dist/zcode/detect.js +1 -0
  89. package/node_modules/@weavecode/harness/dist/zcode/event-source.d.ts +8 -0
  90. package/node_modules/@weavecode/harness/dist/zcode/event-source.js +1 -0
  91. package/node_modules/@weavecode/harness/dist/zcode/index.d.ts +13 -0
  92. package/node_modules/@weavecode/harness/dist/zcode/index.js +1 -0
  93. package/node_modules/@weavecode/harness/dist/zcode/mcp.d.ts +6 -0
  94. package/node_modules/@weavecode/harness/dist/zcode/mcp.js +2 -0
  95. package/node_modules/@weavecode/harness/dist/zcode/messaging.d.ts +13 -0
  96. package/node_modules/@weavecode/harness/dist/zcode/messaging.js +1 -0
  97. package/node_modules/@weavecode/harness/dist/zcode/resume.d.ts +7 -0
  98. package/node_modules/@weavecode/harness/dist/zcode/resume.js +1 -0
  99. package/node_modules/@weavecode/harness/package.json +2 -2
  100. package/node_modules/@weavecode/server/dist/daemon/ai-config.js +2 -2
  101. package/node_modules/@weavecode/server/dist/daemon/ai-context.js +6 -6
  102. package/node_modules/@weavecode/server/dist/daemon/ai-routes.js +4 -4
  103. package/node_modules/@weavecode/server/dist/daemon/api-log.d.ts +48 -0
  104. package/node_modules/@weavecode/server/dist/daemon/api-log.js +3 -0
  105. package/node_modules/@weavecode/server/dist/daemon/auth-routes.js +1 -1
  106. package/node_modules/@weavecode/server/dist/daemon/auto-start.js +6 -6
  107. package/node_modules/@weavecode/server/dist/daemon/capture-routes.js +1 -1
  108. package/node_modules/@weavecode/server/dist/daemon/claude-liveness.js +1 -1
  109. package/node_modules/@weavecode/server/dist/daemon/dashboard-auth.js +2 -2
  110. package/node_modules/@weavecode/server/dist/daemon/data-bus.js +1 -1
  111. package/node_modules/@weavecode/server/dist/daemon/dev-entry.js +1 -1
  112. package/node_modules/@weavecode/server/dist/daemon/fs-browser.js +1 -1
  113. package/node_modules/@weavecode/server/dist/daemon/hook-pipeline.d.ts +13 -1
  114. package/node_modules/@weavecode/server/dist/daemon/hook-pipeline.js +1 -1
  115. package/node_modules/@weavecode/server/dist/daemon/hooks-routes.js +1 -1
  116. package/node_modules/@weavecode/server/dist/daemon/http.js +1 -1
  117. package/node_modules/@weavecode/server/dist/daemon/opener.d.ts +102 -19
  118. package/node_modules/@weavecode/server/dist/daemon/opener.js +97 -7
  119. package/node_modules/@weavecode/server/dist/daemon/port.js +1 -1
  120. package/node_modules/@weavecode/server/dist/daemon/project-harnesses.js +2 -2
  121. package/node_modules/@weavecode/server/dist/daemon/project-updates-refresher.d.ts +4 -3
  122. package/node_modules/@weavecode/server/dist/daemon/project-updates-refresher.js +1 -1
  123. package/node_modules/@weavecode/server/dist/daemon/server.d.ts +15 -0
  124. package/node_modules/@weavecode/server/dist/daemon/server.js +8 -6
  125. package/node_modules/@weavecode/server/dist/daemon/session-probe.d.ts +72 -2
  126. package/node_modules/@weavecode/server/dist/daemon/session-probe.js +1 -1
  127. package/node_modules/@weavecode/server/dist/daemon/settings.d.ts +10 -0
  128. package/node_modules/@weavecode/server/dist/daemon/settings.js +2 -2
  129. package/node_modules/@weavecode/server/dist/daemon/snapshot-refresher.d.ts +7 -1
  130. package/node_modules/@weavecode/server/dist/daemon/snapshot-refresher.js +1 -1
  131. package/node_modules/@weavecode/server/dist/daemon/sse-hub.d.ts +40 -0
  132. package/node_modules/@weavecode/server/dist/daemon/sse-hub.js +1 -0
  133. package/node_modules/@weavecode/server/dist/daemon/start.js +1 -1
  134. package/node_modules/@weavecode/server/dist/daemon/state.js +2 -2
  135. package/node_modules/@weavecode/server/dist/daemon/static.js +1 -1
  136. package/node_modules/@weavecode/server/dist/daemon/terminal-topology-refresher.d.ts +4 -1
  137. package/node_modules/@weavecode/server/dist/daemon/tls.js +1 -1
  138. package/node_modules/@weavecode/server/dist/daemon/toolkit-routes.js +1 -1
  139. package/node_modules/@weavecode/server/dist/db/db.js +38 -2
  140. package/node_modules/@weavecode/server/dist/db/paths.d.ts +4 -0
  141. package/node_modules/@weavecode/server/dist/db/paths.js +1 -1
  142. package/node_modules/@weavecode/server/dist/hooks/answer-keys.js +1 -1
  143. package/node_modules/@weavecode/server/dist/hooks/bus.d.ts +5 -0
  144. package/node_modules/@weavecode/server/dist/hooks/bus.js +1 -1
  145. package/node_modules/@weavecode/server/dist/hooks/dispatcher.js +6 -6
  146. package/node_modules/@weavecode/server/dist/hooks/handlers/webhook.js +1 -1
  147. package/node_modules/@weavecode/server/dist/hooks/headless-runner.js +2 -2
  148. package/node_modules/@weavecode/server/dist/hooks/inbox-socket.d.ts +17 -4
  149. package/node_modules/@weavecode/server/dist/hooks/inbox-socket.js +2 -1
  150. package/node_modules/@weavecode/server/dist/hooks/inbox-worker.d.ts +27 -6
  151. package/node_modules/@weavecode/server/dist/hooks/inbox-worker.js +3 -3
  152. package/node_modules/@weavecode/server/dist/hooks/match.js +1 -1
  153. package/node_modules/@weavecode/server/dist/hooks/message-deliverer.d.ts +200 -13
  154. package/node_modules/@weavecode/server/dist/hooks/message-deliverer.js +3 -2
  155. package/node_modules/@weavecode/server/dist/hooks/mirror.d.ts +9 -4
  156. package/node_modules/@weavecode/server/dist/hooks/mirror.js +4 -4
  157. package/node_modules/@weavecode/server/dist/hooks/plugin-installer.js +3 -3
  158. package/node_modules/@weavecode/server/dist/hooks/plugin-loader.js +1 -1
  159. package/node_modules/@weavecode/server/dist/hooks/plugin-project-state.js +1 -1
  160. package/node_modules/@weavecode/server/dist/hooks/prompt-flusher.js +1 -1
  161. package/node_modules/@weavecode/server/dist/hooks/promptbox.d.ts +13 -0
  162. package/node_modules/@weavecode/server/dist/hooks/promptbox.js +8 -8
  163. package/node_modules/@weavecode/server/dist/hooks/push-notify.js +2 -2
  164. package/node_modules/@weavecode/server/dist/hooks/question-tracker.d.ts +6 -4
  165. package/node_modules/@weavecode/server/dist/hooks/question-tracker.js +1 -1
  166. package/node_modules/@weavecode/server/dist/hooks/registry.js +1 -1
  167. package/node_modules/@weavecode/server/dist/hooks/resume-runner.js +1 -1
  168. package/node_modules/@weavecode/server/dist/hooks/sequence-engine.js +1 -1
  169. package/node_modules/@weavecode/server/dist/hooks/session-purge.d.ts +7 -0
  170. package/node_modules/@weavecode/server/dist/hooks/session-purge.js +1 -1
  171. package/node_modules/@weavecode/server/dist/hooks/session-sweeper.d.ts +5 -8
  172. package/node_modules/@weavecode/server/dist/hooks/session-sweeper.js +1 -1
  173. package/node_modules/@weavecode/server/dist/hooks/side-questions.d.ts +41 -0
  174. package/node_modules/@weavecode/server/dist/hooks/side-questions.js +1 -0
  175. package/node_modules/@weavecode/server/dist/hooks/toolkit-scan.js +1 -1
  176. package/node_modules/@weavecode/server/dist/hooks/toolkit.d.ts +8 -0
  177. package/node_modules/@weavecode/server/dist/hooks/toolkit.js +5 -5
  178. package/node_modules/@weavecode/server/dist/hooks/watch-engine.d.ts +7 -0
  179. package/node_modules/@weavecode/server/dist/hooks/watch-engine.js +1 -1
  180. package/node_modules/@weavecode/server/dist/index.d.ts +1 -1
  181. package/node_modules/@weavecode/server/dist/install/apply-update.d.ts +1 -1
  182. package/node_modules/@weavecode/server/dist/install/apply-update.js +1 -1
  183. package/node_modules/@weavecode/server/dist/install/capabilities.d.ts +10 -0
  184. package/node_modules/@weavecode/server/dist/install/capabilities.js +1 -1
  185. package/node_modules/@weavecode/server/dist/install/codex-toml.d.ts +8 -26
  186. package/node_modules/@weavecode/server/dist/install/codex-toml.js +1 -1
  187. package/node_modules/@weavecode/server/dist/install/file-assets.js +1 -1
  188. package/node_modules/@weavecode/server/dist/install/fingerprint.d.ts +5 -1
  189. package/node_modules/@weavecode/server/dist/install/fingerprint.js +1 -1
  190. package/node_modules/@weavecode/server/dist/install/git-classify.d.ts +30 -0
  191. package/node_modules/@weavecode/server/dist/install/git-classify.js +1 -0
  192. package/node_modules/@weavecode/server/dist/install/global-config.d.ts +2 -4
  193. package/node_modules/@weavecode/server/dist/install/global-config.js +1 -2
  194. package/node_modules/@weavecode/server/dist/install/global-file-assets.js +1 -1
  195. package/node_modules/@weavecode/server/dist/install/init-files.d.ts +46 -0
  196. package/node_modules/@weavecode/server/dist/install/init-files.js +2 -0
  197. package/node_modules/@weavecode/server/dist/install/install-ledger.js +1 -1
  198. package/node_modules/@weavecode/server/dist/install/installer.d.ts +3 -5
  199. package/node_modules/@weavecode/server/dist/install/installer.js +1 -3
  200. package/node_modules/@weavecode/server/dist/install/library-index.js +1 -1
  201. package/node_modules/@weavecode/server/dist/install/mcp-rows.d.ts +5 -5
  202. package/node_modules/@weavecode/server/dist/install/mcp-rows.js +1 -1
  203. package/node_modules/@weavecode/server/dist/install/plugin-install.js +1 -1
  204. package/node_modules/@weavecode/server/dist/install/plugin-rows.js +1 -1
  205. package/node_modules/@weavecode/server/dist/install/plugin-templates.js +1 -1
  206. package/node_modules/@weavecode/server/dist/install/project-config.d.ts +0 -2
  207. package/node_modules/@weavecode/server/dist/install/project-config.js +2 -2
  208. package/node_modules/@weavecode/server/dist/install/reader.js +1 -1
  209. package/node_modules/@weavecode/server/dist/install/scan-cache.js +1 -1
  210. package/node_modules/@weavecode/server/dist/install/scanner.js +1 -1
  211. package/node_modules/@weavecode/server/dist/install/settings-mcp.js +2 -2
  212. package/node_modules/@weavecode/server/dist/install/updates.d.ts +17 -5
  213. package/node_modules/@weavecode/server/dist/install/updates.js +1 -1
  214. package/node_modules/@weavecode/server/dist/market/builtin.js +1 -1
  215. package/node_modules/@weavecode/server/dist/market/identity.js +1 -1
  216. package/node_modules/@weavecode/server/dist/market/import.js +2 -2
  217. package/node_modules/@weavecode/server/dist/market/refresh.js +1 -1
  218. package/node_modules/@weavecode/server/dist/market/resolve.js +1 -1
  219. package/node_modules/@weavecode/server/dist/market/updates.js +1 -1
  220. package/node_modules/@weavecode/server/dist/registry.js +2 -2
  221. package/node_modules/@weavecode/server/dist/repositories/hook-dispatches.js +5 -5
  222. package/node_modules/@weavecode/server/dist/repositories/hook-events.d.ts +7 -0
  223. package/node_modules/@weavecode/server/dist/repositories/hook-events.js +2 -2
  224. package/node_modules/@weavecode/server/dist/repositories/hook-rules.js +4 -4
  225. package/node_modules/@weavecode/server/dist/repositories/libraries.js +1 -1
  226. package/node_modules/@weavecode/server/dist/repositories/plugin-states.js +1 -1
  227. package/node_modules/@weavecode/server/dist/repositories/projects.d.ts +7 -0
  228. package/node_modules/@weavecode/server/dist/repositories/projects.js +2 -2
  229. package/node_modules/@weavecode/server/dist/repositories/push-subscriptions.js +2 -2
  230. package/node_modules/@weavecode/server/dist/repositories/session-watches.js +4 -4
  231. package/node_modules/@weavecode/server/dist/repositories/sessions.d.ts +32 -8
  232. package/node_modules/@weavecode/server/dist/repositories/sessions.js +2 -2
  233. package/node_modules/@weavecode/server/dist/repositories/side-questions.d.ts +50 -0
  234. package/node_modules/@weavecode/server/dist/repositories/side-questions.js +6 -0
  235. package/node_modules/@weavecode/server/dist/repositories/uploads.d.ts +66 -0
  236. package/node_modules/@weavecode/server/dist/repositories/uploads.js +7 -0
  237. package/node_modules/@weavecode/server/dist/statusline/cache-sweeper.js +1 -1
  238. package/node_modules/@weavecode/server/dist/statusline/config.d.ts +4 -198
  239. package/node_modules/@weavecode/server/dist/statusline/config.js +1 -1
  240. package/node_modules/@weavecode/server/dist/statusline/generator.d.ts +5 -0
  241. package/node_modules/@weavecode/server/dist/statusline/generator.js +1 -676
  242. package/node_modules/@weavecode/server/dist/statusline/manager.d.ts +7 -5
  243. package/node_modules/@weavecode/server/dist/statusline/manager.js +3 -4
  244. package/node_modules/@weavecode/server/dist/surfaces.d.ts +11 -1
  245. package/node_modules/@weavecode/server/dist/surfaces.js +1 -1
  246. package/node_modules/@weavecode/server/dist/watch/cache.js +1 -1
  247. package/node_modules/@weavecode/server/dist/watch/classifier.js +1 -1
  248. package/node_modules/@weavecode/server/dist/watch/plugin-mods.js +1 -1
  249. package/node_modules/@weavecode/server/dist/watch/sync-scheduler.d.ts +8 -4
  250. package/node_modules/@weavecode/server/dist/watch/sync-scheduler.js +1 -1
  251. package/node_modules/@weavecode/server/dist/watch/watch-service.js +1 -1
  252. package/node_modules/@weavecode/server/package.json +4 -4
  253. package/node_modules/@weavecode/server/web/dist/assets/index-CHWbLAje.js +594 -0
  254. package/node_modules/@weavecode/server/web/dist/assets/index-D0s5v8QS.css +11 -0
  255. package/node_modules/@weavecode/server/web/dist/index.html +14 -2
  256. package/node_modules/@weavecode/templates/dist/resources/weave-market/plugins/core-skills/weave-plugin-creator/skills/weave-plugin-creator/SKILL.md +2 -2
  257. package/node_modules/@weavecode/templates/package.json +2 -2
  258. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/README.md +50 -32
  259. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/build/index.d.ts +86 -40
  260. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/build/index.es.js +860 -353
  261. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/build/index.js +860 -353
  262. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/package.json +20 -17
  263. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/README.md +50 -32
  264. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/build/index.d.ts +86 -40
  265. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/build/index.es.js +860 -353
  266. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/build/index.js +860 -353
  267. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/package.json +20 -17
  268. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/README.md +50 -32
  269. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/build/index.d.ts +86 -40
  270. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/build/index.es.js +860 -353
  271. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/build/index.js +860 -353
  272. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/package.json +20 -17
  273. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/README.md +50 -32
  274. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/build/index.d.ts +86 -40
  275. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/build/index.es.js +860 -353
  276. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/build/index.js +860 -353
  277. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/package.json +20 -17
  278. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/README.md +50 -32
  279. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/build/index.d.ts +86 -40
  280. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/build/index.es.js +860 -353
  281. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/build/index.js +860 -353
  282. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/package.json +20 -17
  283. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/README.md +50 -32
  284. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/build/index.d.ts +86 -40
  285. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/build/index.es.js +860 -353
  286. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/build/index.js +860 -353
  287. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/package.json +20 -17
  288. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/README.md +50 -32
  289. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/build/index.d.ts +86 -40
  290. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/build/index.es.js +860 -353
  291. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/build/index.js +860 -353
  292. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/package.json +20 -17
  293. package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/README.md +50 -32
  294. package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/build/index.d.ts +86 -40
  295. package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/build/index.es.js +860 -353
  296. package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/build/index.js +860 -353
  297. package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/package.json +20 -17
  298. package/package.json +6 -6
  299. package/node_modules/@weavecode/server/web/dist/assets/index-BOzaRlQE.js +0 -560
  300. package/node_modules/@weavecode/server/web/dist/assets/index-ChX8G8cT.css +0 -11
@@ -1 +1 @@
1
- import{existsSync as C}from"node:fs";import{readFile as $,readdir as W}from"node:fs/promises";import c from"node:path";import{pathToFileURL as D}from"node:url";import{watch as B}from"chokidar";import{builtinRulesDir as P}from"../market/builtin.js";import{HARNESS_EVENT_UNION as I,HookRuleSchema as T,PluginRuleEntrySchema as k,WEAVE_PLUGIN_MANIFEST as A,WeavePluginManifestSchema as O}from"@weavecode/core";import{getDataDir as j}from"../db/paths.js";import{marketLibraryRoots as M}from"../market/resolve.js";import{validateHandler as N}from"./registry.js";import{builtinToolkitRoot as x,discoverToolkitSources as H,discoverWeavePackDirs as U}from"./toolkit-scan.js";export function createPluginLogger(u){return{debug:e=>console.debug(`[plugin:${u}] ${e}`),info:e=>console.info(`[plugin:${u}] ${e}`),warn:e=>console.warn(`[plugin:${u}] ${e}`),error:e=>console.error(`[plugin:${u}] ${e}`)}}const R="@file:";function L(){return c.resolve(x())}export class WeavePluginLoader{deps;handlers=new Map;configs=new Map;plugins=new Map;subscribers=new Map;roots=new Map;watchStop;constructor(e){this.deps=e}list(){return[...this.plugins.values()]}getHandler(e,s){return this.handlers.get(`${e}:${s}`)}getConfig(e){return this.configs.get(e)??{}}async loadRoot(e,s,n){const i=c.resolve(e);this.roots.set(i,{scope:s,projectId:n});let o;try{o=await W(i)}catch{return[]}const t=this.priorIdsUnder(i),d=[];for(const p of o){const l=c.join(i,p);if(this.roots.has(c.resolve(l))||c.resolve(l)===L())continue;const g=await this.loadOne(l,s,n,p);this.plugins.set(g.id,g),d.push(g)}return this.finalizeScan(t,d)}async loadToolkitRoot(e,s,n){const i=c.resolve(e);this.roots.set(i,{scope:s,projectId:n,deep:!0});const o=await U(i),t=this.priorIdsUnder(i),d=[];for(const p of o){await this.ensureToolkitDefaultDisabled(p);const l=await this.loadOne(p,s,n,c.basename(p));this.plugins.set(l.id,l),d.push(l)}return this.finalizeScan(t,d)}async ensureToolkitDefaultDisabled(e){try{const s=JSON.parse(await $(c.join(e,A),"utf8"));typeof s.id=="string"&&!this.deps.states.get(s.id)&&this.deps.states.setEnabled(s.id,!1)}catch{}}priorIdsUnder(e){const s=[...this.roots.keys()].filter(n=>n!==e&&n.startsWith(e+c.sep));return new Set([...this.plugins.values()].filter(n=>n.dir.startsWith(e+c.sep)?!s.some(i=>n.dir.startsWith(i+c.sep)):!1).map(n=>n.id))}finalizeScan(e,s){const n=new Set(s.map(o=>o.id));let i=!1;for(const o of e)n.has(o)||(this.deps.rules.removeByPlugin(o),this.unloadHandlers(o),this.configs.delete(o),this.plugins.delete(o),i=!0,this.emitReload({pluginId:o,status:"rejected",ruleCount:0,removed:!0}));(i||s.length>0)&&this.deps.registry.load();for(const o of s)this.emitReload({pluginId:o.id,status:o.status,ruleCount:o.ruleCount,at:new Date().toISOString()});return s}watchRoots(e=1e3){if(this.watchStop)return this.watchStop;const s=new Map,n=[...this.roots.entries()].filter(([i])=>C(i)).map(([i,o])=>{const t=o.deep?6:o.projectId!==null?3:2,d=B(i,{ignoreInitial:!0,depth:t});return d.on("all",()=>{const p=s.get(i);p&&clearTimeout(p),s.set(i,setTimeout(()=>{s.delete(i);const l=this.roots.get(i);l&&(l.deep?this.loadToolkitRoot(i,l.scope,l.projectId):this.loadRoot(i,l.scope,l.projectId)).catch(()=>{})},e))}),d.on("error",()=>{}),d});return this.watchStop=()=>{for(const i of s.values())clearTimeout(i);s.clear();for(const i of n)i.close();this.watchStop=void 0},this.watchStop}async reloadAll(){for(const[e,s]of[...this.roots])await(s.deep?this.loadToolkitRoot(e,s.scope,s.projectId):this.loadRoot(e,s.scope,s.projectId)).catch(()=>{})}stopWatching(){this.watchStop?.()}async rescanRoots(e,s){await registerPluginRoots(this,{libraries:s},e),this.stopWatching(),await this.reloadAll(),this.watchRoots()}setPluginEnabled(e,s){const n=this.plugins.get(e);if(!n)return!1;this.deps.states.setEnabled(e,s);for(const o of this.deps.rules.listByPlugin(e))this.deps.rules.setEnabled(o.id,s);this.deps.registry.load();const i=s?n.error?"rejected":"active":"disabled";return this.plugins.set(e,{...n,status:i}),this.deps.bus?.emit({kind:"plugin.toggled",pluginId:e,enabled:s,at:new Date().toISOString()}),!0}unloadHandlers(e){for(const s of[...this.handlers.keys()])s.startsWith(`${e}:`)&&this.handlers.delete(s);this.subscribers.delete(e)}notifyEvent(e,s,n){for(const[i,o]of this.subscribers){if(!o.events.has(e))continue;const t=this.configs.get(i)??{};(async()=>{await o.sub.onEvent({eventType:e,payload:s,sessionId:n,config:t,logger:createPluginLogger(i)})})().catch(()=>{})}}emitReload(e){this.deps.bus?.emit({kind:"plugin.reloaded",at:new Date().toISOString(),...e})}async loadOne(e,s,n,i){const o=(r,a,h=i,y="0.0.0")=>{const w=this.plugins.get(r);return w&&w.dir===e&&(this.deps.rules.removeByPlugin(r),this.unloadHandlers(r),this.configs.delete(r)),{id:r,name:h,version:y,dir:e,scope:s,projectId:n,status:"rejected",error:a,ruleCount:0}};let t;try{const r=JSON.parse(await $(c.join(e,A),"utf8")),a=O.safeParse(r);if(!a.success)return o(i,`manifest \u6821\u9A8C\u5931\u8D25: ${a.error.issues[0]?.message??""}`);t=a.data}catch(r){return o(i,`manifest \u8BFB\u53D6\u5931\u8D25: ${r instanceof Error?r.message:String(r)}`)}if(s!=="builtin"&&t.id.startsWith("weave-"))return o(t.id,"id \u4EE5 weave- \u5F00\u5934\u4E3A\u5185\u7F6E\u9884\u8BBE\u547D\u540D\u7A7A\u95F4\u4FDD\u7559",t.name,t.version);const d=this.plugins.get(t.id);if(d&&d.status!=="rejected"&&d.dir!==e)return o(t.id,`\u91CD\u590D\u7684\u63D2\u4EF6 id\uFF08\u5DF2\u7531 ${d.dir} \u6CE8\u518C\uFF09`,t.name,t.version);const p=(t.requires?.events??[]).filter(r=>!I.includes(r));if(p.length>0)return o(t.id,`requires.events \u542B\u672A\u77E5\u4E8B\u4EF6: ${p.join(", ")}`,t.name,t.version);const l=[];for(const r of t.rules)try{const a=JSON.parse(await $(this.resolveWithin(e,r),"utf8"));if(!Array.isArray(a))throw new Error(`${r} \u4E0D\u662F\u6570\u7EC4`);l.push(...a)}catch(a){return o(t.id,`\u89C4\u5219\u6587\u4EF6 ${r}: ${a instanceof Error?a.message:String(a)}`,t.name,t.version)}const g=new Map;for(const r of t.handlers)try{const a=this.resolveWithin(e,r.entry),h=(await import(`${D(a).href}?t=${Date.now()}`)).default;if(!h||typeof h.execute!="function")throw new Error(`${r.entry} \u7684 default \u5BFC\u51FA\u7F3A\u5C11 execute \u51FD\u6570`);if(h.type!==r.type)throw new Error(`${r.entry} \u5BFC\u51FA type="${h.type}" \u4E0E manifest \u58F0\u660E "${r.type}" \u4E0D\u7B26`);g.set(`${t.id}:${r.type}`,h)}catch(a){return o(t.id,`handler ${r.type} \u52A0\u8F7D\u5931\u8D25: ${a instanceof Error?a.message:String(a)}`,t.name,t.version)}let F;if(t.subscribe){const r=t.subscribe.events.filter(a=>!I.includes(a));if(r.length>0)return o(t.id,`subscribe.events \u542B\u672A\u77E5\u4E8B\u4EF6: ${r.join(", ")}`,t.name,t.version);try{const a=this.resolveWithin(e,t.subscribe.entry),h=(await import(`${D(a).href}?t=${Date.now()}`)).default;if(!h||typeof h.onEvent!="function")throw new Error(`${t.subscribe.entry} \u7684 default \u5BFC\u51FA\u7F3A\u5C11 onEvent \u51FD\u6570`);F={events:new Set(t.subscribe.events),sub:h}}catch(a){return o(t.id,`subscriber \u52A0\u8F7D\u5931\u8D25: ${a instanceof Error?a.message:String(a)}`,t.name,t.version)}}const S=[];for(let r=0;r<l.length;r++){const a=l[r],h=typeof a=="object"&&a!==null&&"handler"in a?{...a,handler:_(a.handler,t.id)}:a,y=k.safeParse(h);if(!y.success)return o(t.id,`\u89C4\u5219 #${r} \u6821\u9A8C\u5931\u8D25: ${y.error.issues[0]?.message??""}`,t.name,t.version);const w=y.data;let f=w.handler;if(f.type==="plugin"&&!g.has(`${t.id}:${f.handlerType}`))return o(t.id,`\u89C4\u5219 #${r} \u5F15\u7528\u672A\u58F0\u660E\u7684 handler "${f.handlerType}"`,t.name,t.version);if((f.type==="inject"||f.type==="manual")&&f.template.startsWith(R)){const v=f.template.slice(R.length);try{const b=await $(this.resolveWithin(e,v),"utf8");f={...f,template:b}}catch(b){return o(t.id,`\u89C4\u5219 #${r} \u6A21\u677F ${v}: ${b instanceof Error?b.message:String(b)}`,t.name,t.version)}}let E;try{E=T.parse({...w,handler:f,id:`plugin:${t.id}:${r}`,projectId:n,enabled:w.enabled??!0,priority:w.priority??0,origin:s==="builtin"?"builtin":"plugin",pluginId:t.id}),N(E.source,E.handler)}catch(v){return o(t.id,`\u89C4\u5219 #${r}: ${v instanceof Error?v.message:String(v)}`,t.name,t.version)}S.push(E)}const m=this.deps.states.get(t.id);try{for(const r of S)this.deps.rules.upsertPluginRule(r)}catch(r){return this.deps.rules.removeByPlugin(t.id),o(t.id,`\u89C4\u5219\u5165\u5E93\u5931\u8D25: ${r instanceof Error?r.message:String(r)}`,t.name,t.version)}if(m&&!m.enabled)for(const r of this.deps.rules.listByPlugin(t.id))this.deps.rules.setEnabled(r.id,!1);for(const[r,a]of g)this.handlers.set(r,a);return this.configs.set(t.id,{...t.config??{},...m?.config??{}}),F&&!(m&&!m.enabled)&&this.subscribers.set(t.id,F),{id:t.id,name:t.name,version:t.version,dir:e,scope:s,projectId:n,status:m&&!m.enabled?"disabled":"active",ruleCount:S.length}}resolveWithin(e,s){const n=c.resolve(e),i=c.resolve(n,s);if(i!==n&&!i.startsWith(n+c.sep))throw new Error(`\u8DEF\u5F84\u8D8A\u51FA\u63D2\u4EF6\u76EE\u5F55: ${s}`);return i}}function _(u,e){if(typeof u!="object"||u===null)return u;const s=u;return s.type!=="plugin"||s.pluginId!==void 0?u:{...s,pluginId:e}}export async function registerPluginRoots(u,e,s){const n=[],i=H();if(e.libraries)for(const t of M(e.libraries))i.push({root:t,provenance:"market"});const o=new Set;for(const t of i){const d=c.resolve(t.root);o.has(d)||(o.add(d),n.push(...await u.loadToolkitRoot(t.root,t.provenance==="builtin"?"builtin":"user",null)))}n.push(...await u.loadRoot(P(j()),"builtin",null)),n.push(...await u.loadRoot(c.join(j(),"plugins"),"user",null));for(const t of s)n.push(...await u.loadRoot(c.join(t.path,".weave","plugins"),"project",t.id));return n}export async function loadAllPlugins(u,e){const s=new WeavePluginLoader(u),n=await registerPluginRoots(s,u,e);return{loader:s,loaded:n}}
1
+ import{existsSync as I}from"node:fs";import{readFile as S,readdir as A}from"node:fs/promises";import c from"node:path";import{pathToFileURL as P}from"node:url";import{watch as M}from"chokidar";import{builtinRulesDir as O}from"../market/builtin.js";import{HARNESS_EVENT_UNION as W,HookRuleSchema as x,PluginRuleEntrySchema as H,WEAVE_PLUGIN_MANIFEST as j,WeavePluginManifestSchema as L}from"@weavecode/core";import{getDataDir as T}from"../db/paths.js";import{marketLibraryRoots as N}from"../market/resolve.js";import{validateHandler as C}from"./registry.js";import{builtinToolkitRoot as U,discoverToolkitSources as _,discoverWeavePackDirs as B}from"./toolkit-scan.js";export function createPluginLogger(l){return{debug:e=>console.debug(`[plugin:${l}] ${e}`),info:e=>console.info(`[plugin:${l}] ${e}`),warn:e=>console.warn(`[plugin:${l}] ${e}`),error:e=>console.error(`[plugin:${l}] ${e}`)}}const D="@file:";function F(){return c.resolve(U())}export class WeavePluginLoader{deps;handlers=new Map;configs=new Map;plugins=new Map;subscribers=new Map;roots=new Map;watchStop;constructor(e){this.deps=e}list(){return[...this.plugins.values()]}getHandler(e,s){return this.handlers.get(`${e}:${s}`)}getConfig(e){return this.configs.get(e)??{}}async loadRoot(e,s,o){const n=c.resolve(e);this.roots.set(n,{scope:s,projectId:o});let i;try{i=await A(n)}catch{return[]}const t=this.priorIdsUnder(n),u=[];for(const f of i){const d=c.join(n,f);if(this.roots.has(c.resolve(d))||c.resolve(d)===F())continue;const g=await this.loadOne(d,s,o,f);this.plugins.set(g.id,g),u.push(g)}return this.finalizeScan(t,u)}async loadToolkitRoot(e,s,o){const n=c.resolve(e);this.roots.set(n,{scope:s,projectId:o,deep:!0});const i=await B(n),t=this.priorIdsUnder(n),u=[];for(const f of i){await this.ensureToolkitDefaultDisabled(f);const d=await this.loadOne(f,s,o,c.basename(f));this.plugins.set(d.id,d),u.push(d)}return this.finalizeScan(t,u)}async ensureToolkitDefaultDisabled(e){try{const s=JSON.parse(await S(c.join(e,j),"utf8"));typeof s.id=="string"&&!this.deps.states.get(s.id)&&this.deps.states.setEnabled(s.id,!1)}catch{}}priorIdsUnder(e){const s=[...this.roots.keys()].filter(o=>o!==e&&o.startsWith(e+c.sep));return new Set([...this.plugins.values()].filter(o=>o.dir.startsWith(e+c.sep)?!s.some(n=>o.dir.startsWith(n+c.sep)):!1).map(o=>o.id))}finalizeScan(e,s){const o=new Set(s.map(i=>i.id));let n=!1;for(const i of e)o.has(i)||(this.deps.rules.removeByPlugin(i),this.unloadHandlers(i),this.configs.delete(i),this.plugins.delete(i),n=!0,this.emitReload({pluginId:i,status:"rejected",ruleCount:0,removed:!0}));(n||s.length>0)&&this.deps.registry.load();for(const i of s)this.emitReload({pluginId:i.id,status:i.status,ruleCount:i.ruleCount,at:new Date().toISOString()});return s}watchRoots(e=1e3){if(this.watchStop)return this.watchStop;const s=new Map,o=[...this.roots.entries()].filter(([n])=>I(n)).map(([n,i])=>{const t=i.deep?6:i.projectId!==null?3:2,u=M(n,{ignoreInitial:!0,depth:t});return u.on("all",()=>{const f=s.get(n);f&&clearTimeout(f),s.set(n,setTimeout(()=>{s.delete(n);const d=this.roots.get(n);if(!d)return;(d.deep?this.loadToolkitRoot(n,d.scope,d.projectId):this.loadRoot(n,d.scope,d.projectId)).catch(()=>{})},e))}),u.on("error",()=>{}),u});return this.watchStop=()=>{for(const n of s.values())clearTimeout(n);s.clear();for(const n of o)n.close();this.watchStop=void 0},this.watchStop}async reloadAll(){for(const[e,s]of[...this.roots])await(s.deep?this.loadToolkitRoot(e,s.scope,s.projectId):this.loadRoot(e,s.scope,s.projectId)).catch(()=>{})}stopWatching(){this.watchStop?.()}async rescanRoots(e,s){await registerPluginRoots(this,{libraries:s},e),this.stopWatching(),await this.reloadAll(),this.watchRoots()}setPluginEnabled(e,s){const o=this.plugins.get(e);if(!o)return!1;this.deps.states.setEnabled(e,s);for(const i of this.deps.rules.listByPlugin(e))this.deps.rules.setEnabled(i.id,s);this.deps.registry.load();const n=s?o.error?"rejected":"active":"disabled";return this.plugins.set(e,{...o,status:n}),this.deps.bus?.emit({kind:"plugin.toggled",pluginId:e,enabled:s,at:new Date().toISOString()}),!0}unloadHandlers(e){for(const s of[...this.handlers.keys()])s.startsWith(`${e}:`)&&this.handlers.delete(s);this.subscribers.delete(e)}notifyEvent(e,s,o){for(const[n,i]of this.subscribers){if(!i.events.has(e))continue;const t=this.configs.get(n)??{};(async()=>{await i.sub.onEvent({eventType:e,payload:s,sessionId:o,config:t,logger:createPluginLogger(n)})})().catch(()=>{})}}emitReload(e){this.deps.bus?.emit({kind:"plugin.reloaded",at:new Date().toISOString(),...e})}async loadOne(e,s,o,n){const i=(r,a,v=n,h="0.0.0")=>{const w=this.plugins.get(r);return w&&w.dir===e&&(this.deps.rules.removeByPlugin(r),this.unloadHandlers(r),this.configs.delete(r)),{id:r,name:v,version:h,dir:e,scope:s,projectId:o,status:"rejected",error:a,ruleCount:0}};let t;try{const r=JSON.parse(await S(c.join(e,j),"utf8")),a=L.safeParse(r);if(!a.success)return i(n,`manifest \u6821\u9A8C\u5931\u8D25: ${a.error.issues[0]?.message??""}`);t=a.data}catch(r){return i(n,`manifest \u8BFB\u53D6\u5931\u8D25: ${r instanceof Error?r.message:String(r)}`)}if(s!=="builtin"&&t.id.startsWith("weave-"))return i(t.id,"id \u4EE5 weave- \u5F00\u5934\u4E3A\u5185\u7F6E\u9884\u8BBE\u547D\u540D\u7A7A\u95F4\u4FDD\u7559",t.name,t.version);const u=this.plugins.get(t.id);if(u&&u.status!=="rejected"&&u.dir!==e)return i(t.id,`\u91CD\u590D\u7684\u63D2\u4EF6 id\uFF08\u5DF2\u7531 ${u.dir} \u6CE8\u518C\uFF09`,t.name,t.version);const d=(t.requires?.events??[]).filter(r=>!W.includes(r));if(d.length>0)return i(t.id,`requires.events \u542B\u672A\u77E5\u4E8B\u4EF6: ${d.join(", ")}`,t.name,t.version);const g=[];for(const r of t.rules)try{const a=JSON.parse(await S(this.resolveWithin(e,r),"utf8"));if(!Array.isArray(a))throw new Error(`${r} \u4E0D\u662F\u6570\u7EC4`);g.push(...a)}catch(a){return i(t.id,`\u89C4\u5219\u6587\u4EF6 ${r}: ${a instanceof Error?a.message:String(a)}`,t.name,t.version)}const E=new Map;for(const r of t.handlers)try{const a=this.resolveWithin(e,r.entry),h=(await import(`${P(a).href}?t=${Date.now()}`)).default;if(!h||typeof h.execute!="function")throw new Error(`${r.entry} \u7684 default \u5BFC\u51FA\u7F3A\u5C11 execute \u51FD\u6570`);if(h.type!==r.type)throw new Error(`${r.entry} \u5BFC\u51FA type="${h.type}" \u4E0E manifest \u58F0\u660E "${r.type}" \u4E0D\u7B26`);E.set(`${t.id}:${r.type}`,h)}catch(a){return i(t.id,`handler ${r.type} \u52A0\u8F7D\u5931\u8D25: ${a instanceof Error?a.message:String(a)}`,t.name,t.version)}let R;if(t.subscribe){const r=t.subscribe.events.filter(a=>!W.includes(a));if(r.length>0)return i(t.id,`subscribe.events \u542B\u672A\u77E5\u4E8B\u4EF6: ${r.join(", ")}`,t.name,t.version);try{const a=this.resolveWithin(e,t.subscribe.entry),h=(await import(`${P(a).href}?t=${Date.now()}`)).default;if(!h||typeof h.onEvent!="function")throw new Error(`${t.subscribe.entry} \u7684 default \u5BFC\u51FA\u7F3A\u5C11 onEvent \u51FD\u6570`);R={events:new Set(t.subscribe.events),sub:h}}catch(a){return i(t.id,`subscriber \u52A0\u8F7D\u5931\u8D25: ${a instanceof Error?a.message:String(a)}`,t.name,t.version)}}const k=[];for(let r=0;r<g.length;r++){const a=g[r],v=typeof a=="object"&&a!==null&&"handler"in a?{...a,handler:q(a.handler,t.id)}:a,h=H.safeParse(v);if(!h.success)return i(t.id,`\u89C4\u5219 #${r} \u6821\u9A8C\u5931\u8D25: ${h.error.issues[0]?.message??""}`,t.name,t.version);const w=h.data;let p=w.handler;if(p.type==="plugin"&&!E.has(`${t.id}:${p.handlerType}`))return i(t.id,`\u89C4\u5219 #${r} \u5F15\u7528\u672A\u58F0\u660E\u7684 handler "${p.handlerType}"`,t.name,t.version);if((p.type==="inject"||p.type==="manual")&&p.template.startsWith(D)){const y=p.template.slice(D.length);try{const b=await S(this.resolveWithin(e,y),"utf8");p={...p,template:b}}catch(b){return i(t.id,`\u89C4\u5219 #${r} \u6A21\u677F ${y}: ${b instanceof Error?b.message:String(b)}`,t.name,t.version)}}let $;try{$=x.parse({...w,handler:p,id:`plugin:${t.id}:${r}`,projectId:o,enabled:w.enabled??!0,priority:w.priority??0,origin:s==="builtin"?"builtin":"plugin",pluginId:t.id}),C($.source,$.handler)}catch(y){return i(t.id,`\u89C4\u5219 #${r}: ${y instanceof Error?y.message:String(y)}`,t.name,t.version)}k.push($)}const m=this.deps.states.get(t.id);try{for(const r of k)this.deps.rules.upsertPluginRule(r)}catch(r){return this.deps.rules.removeByPlugin(t.id),i(t.id,`\u89C4\u5219\u5165\u5E93\u5931\u8D25: ${r instanceof Error?r.message:String(r)}`,t.name,t.version)}if(m&&!m.enabled)for(const r of this.deps.rules.listByPlugin(t.id))this.deps.rules.setEnabled(r.id,!1);for(const[r,a]of E)this.handlers.set(r,a);return this.configs.set(t.id,{...t.config??{},...m?.config??{}}),R&&!(m&&!m.enabled)&&this.subscribers.set(t.id,R),{id:t.id,name:t.name,version:t.version,dir:e,scope:s,projectId:o,status:m&&!m.enabled?"disabled":"active",ruleCount:k.length}}resolveWithin(e,s){const o=c.resolve(e),n=c.resolve(o,s);if(n!==o&&!n.startsWith(o+c.sep))throw new Error(`\u8DEF\u5F84\u8D8A\u51FA\u63D2\u4EF6\u76EE\u5F55: ${s}`);return n}}function q(l,e){if(typeof l!="object"||l===null)return l;const s=l;return s.type!=="plugin"||s.pluginId!==void 0?l:{...s,pluginId:e}}export async function registerPluginRoots(l,e,s){const o=[],n=_();if(e.libraries)for(const t of N(e.libraries))n.push({root:t,provenance:"market"});const i=new Set;for(const t of n){const u=c.resolve(t.root);i.has(u)||(i.add(u),o.push(...await l.loadToolkitRoot(t.root,t.provenance==="builtin"?"builtin":"user",null)))}o.push(...await l.loadRoot(O(T()),"builtin",null)),o.push(...await l.loadRoot(c.join(T(),"plugins"),"user",null));for(const t of s)o.push(...await l.loadRoot(c.join(t.path,".weave","plugins"),"project",t.id));return o}export async function loadAllPlugins(l,e){const s=new WeavePluginLoader(l),o=await registerPluginRoots(s,l,e);return{loader:s,loaded:o}}
@@ -1 +1 @@
1
- export function pluginsStateOf(r){const t={syncedAt:null,enabled:{}};if(r==null)return t;try{const n=JSON.parse(r);if(!n||typeof n!="object"||Array.isArray(n))return t;const e=n.plugins;if(!e||typeof e!="object"||Array.isArray(e))return t;const o=e,c=o.enabled,s={};if(c&&typeof c=="object"&&!Array.isArray(c))for(const[l,a]of Object.entries(c))typeof a=="boolean"&&(s[l]=a);return{syncedAt:typeof o.syncedAt=="string"?o.syncedAt:null,enabled:s}}catch{return t}}export function effective(r,t,n){const e=pluginsStateOf(r.meta);return Object.hasOwn(e.enabled,t)?e.enabled[t]:e.syncedAt!==null?!1:n.states.get(t)?.enabled??n.defaultEnabled??!0}export function setProjectEnabled(r,t,n,e){const o=pluginsStateOf(r.meta);e.projects.setMeta(r.id,{plugins:{syncedAt:o.syncedAt,enabled:{...o.enabled,[t]:n}}})}export function syncPlugins(r,t,n){const e={...pluginsStateOf(r.meta).enabled};for(const c of t)Object.hasOwn(e,c)||(e[c]=!1);const o=n.now??new Date().toISOString();return n.projects.setMeta(r.id,{plugins:{syncedAt:o,enabled:e}}),o}
1
+ export function pluginsStateOf(s){const e={syncedAt:null,enabled:{}};if(s==null)return e;try{const t=JSON.parse(s);if(!t||typeof t!="object"||Array.isArray(t))return e;const n=t.plugins;if(!n||typeof n!="object"||Array.isArray(n))return e;const r=n,a=r.enabled,c={};if(a&&typeof a=="object"&&!Array.isArray(a))for(const[l,o]of Object.entries(a))typeof o=="boolean"&&(c[l]=o);return{syncedAt:typeof r.syncedAt=="string"?r.syncedAt:null,enabled:c}}catch{return e}}export function effective(s,e,t){const n=pluginsStateOf(s.meta);return Object.hasOwn(n.enabled,e)?n.enabled[e]:n.syncedAt!==null?!1:t.states.get(e)?.enabled??t.defaultEnabled??!0}export function setProjectEnabled(s,e,t,n){const r=pluginsStateOf(s.meta);n.projects.setMeta(s.id,{plugins:{syncedAt:r.syncedAt,enabled:{...r.enabled,[e]:t}}})}export function syncPlugins(s,e,t){const r={...pluginsStateOf(s.meta).enabled};for(const c of e)Object.hasOwn(r,c)||(r[c]=!1);const a=t.now??new Date().toISOString();return t.projects.setMeta(s.id,{plugins:{syncedAt:a,enabled:r}}),a}
@@ -1 +1 @@
1
- export const PROMPT_FLUSH_INTERVAL_MS=15e3;export function startPromptFlusher(e){const t=setInterval(()=>{e.flushAll()},15e3);return t.unref?.(),()=>clearInterval(t)}
1
+ export const PROMPT_FLUSH_INTERVAL_MS=15e3;export function startPromptFlusher(r){const t=setInterval(()=>{r.flushAll()},15e3);return t.unref?.(),()=>clearInterval(t)}
@@ -5,6 +5,13 @@
5
5
  * shard 与 outbox 同算法(项目 token 哈希前缀);送达即删行,无 DB。
6
6
  */
7
7
  export declare const PROMPTBOX_MAX_LINES = 200;
8
+ /** 队列行的随附图(引用上传件;路径也落盘,重启后冲洗才能重合成投递文本)。 */
9
+ export interface PromptboxImage {
10
+ id: string;
11
+ name: string;
12
+ mediaType: string;
13
+ path: string;
14
+ }
8
15
  /** 队列行:id = 管道发号(MessageDeliverer 的 uuid),daemon 重启后仍可追溯。 */
9
16
  export interface PromptboxEntry {
10
17
  id: string;
@@ -12,6 +19,10 @@ export interface PromptboxEntry {
12
19
  text: string;
13
20
  /** 单向注入(手动面)——随行落盘,重启后冲洗仍带「无需回复」注记。 */
14
21
  oneWay?: boolean;
22
+ /** 发送人强制走层② 终端(下拉选的通道)——随行落盘,冲洗时同样不回落直投/中继。 */
23
+ forceTerminal?: boolean;
24
+ /** 随附图:`text` 恒为用户原文,投递文本由 harness `imageAttach` 现合成。 */
25
+ images?: PromptboxImage[];
15
26
  at: string;
16
27
  }
17
28
  export declare function promptboxPathOf(hooksDir: string, shardId: string): string;
@@ -21,6 +32,8 @@ export declare function appendPromptbox(hooksDir: string, token: string, entries
21
32
  sessionId: string;
22
33
  text: string;
23
34
  oneWay?: boolean;
35
+ forceTerminal?: boolean;
36
+ images?: PromptboxImage[];
24
37
  }>): void;
25
38
  /** 读一个项目的全部待递送行。 */
26
39
  export declare function readPromptbox(hooksDir: string, token: string): PromptboxEntry[];
@@ -1,11 +1,11 @@
1
- import{mkdirSync as x,readFileSync as u,readdirSync as y,renameSync as l,writeFileSync as h}from"node:fs";import{join as f}from"node:path";import{hookShardId as m}from"./mirror.js";export const PROMPTBOX_MAX_LINES=200;export function promptboxPathOf(o,r){return f(o,"promptbox",`${r}.jsonl`)}function d(o){const r=[];for(const n of o.split(`
2
- `))if(n.trim())try{const t=JSON.parse(n);typeof t.id=="string"&&typeof t.sessionId=="string"&&typeof t.text=="string"&&r.push({id:t.id,sessionId:t.sessionId,text:t.text,oneWay:t.oneWay===!0,at:typeof t.at=="string"?t.at:""})}catch{}return r}export function appendPromptbox(o,r,n){if(n.length!==0)try{const t=promptboxPathOf(o,m(r));x(f(o,"promptbox"),{recursive:!0});let e=[];try{e=u(t,"utf8").split(`
3
- `).filter(c=>c.trim())}catch{e=[]}const p=new Date().toISOString();for(const c of n)e.push(JSON.stringify({...c,at:p}));const i=e.slice(-PROMPTBOX_MAX_LINES),s=`${t}.tmp`;h(s,i.length?i.join(`
1
+ import{mkdirSync as g,readFileSync as u,readdirSync as h,renameSync as l,writeFileSync as m}from"node:fs";import{join as a}from"node:path";import{hookShardId as y}from"./mirror.js";export const PROMPTBOX_MAX_LINES=200;export function promptboxPathOf(n,e){return a(n,"promptbox",`${e}.jsonl`)}function d(n){const e=[];for(const o of n.split(`
2
+ `))if(o.trim())try{const t=JSON.parse(o);if(typeof t.id=="string"&&typeof t.sessionId=="string"&&typeof t.text=="string"){const r=Array.isArray(t.images)?t.images.filter(i=>typeof i?.id=="string"&&typeof i?.name=="string"&&typeof i?.mediaType=="string"&&typeof i?.path=="string"):[];e.push({id:t.id,sessionId:t.sessionId,text:t.text,oneWay:t.oneWay===!0,...t.forceTerminal===!0?{forceTerminal:!0}:{},...r.length>0?{images:r}:{},at:typeof t.at=="string"?t.at:""})}}catch{}return e}export function appendPromptbox(n,e,o){if(o.length!==0)try{const t=promptboxPathOf(n,y(e));g(a(n,"promptbox"),{recursive:!0});let r=[];try{r=u(t,"utf8").split(`
3
+ `).filter(p=>p.trim())}catch{r=[]}const i=new Date().toISOString();for(const p of o)r.push(JSON.stringify({...p,at:i}));const c=r.slice(-PROMPTBOX_MAX_LINES),s=`${t}.tmp`;m(s,c.length?c.join(`
4
4
  `)+`
5
- `:""),l(s,t)}catch{}}export function readPromptbox(o,r){try{return d(u(promptboxPathOf(o,m(r)),"utf8"))}catch{return[]}}export function removePromptboxEntries(o,r,n){if(n.size!==0)try{const t=promptboxPathOf(o,m(r));let e;try{e=u(t,"utf8").split(`
6
- `).filter(s=>s.trim())}catch{return}const p=e.filter(s=>{try{return!n.has(JSON.parse(s).id??"")}catch{return!1}}),i=`${t}.tmp`;h(i,p.length?p.join(`
5
+ `:""),l(s,t)}catch{}}export function readPromptbox(n,e){try{return d(u(promptboxPathOf(n,y(e)),"utf8"))}catch{return[]}}export function removePromptboxEntries(n,e,o){if(o.size!==0)try{const t=promptboxPathOf(n,y(e));let r;try{r=u(t,"utf8").split(`
6
+ `).filter(s=>s.trim())}catch{return}const i=r.filter(s=>{try{return!o.has(JSON.parse(s).id??"")}catch{return!1}}),c=`${t}.tmp`;m(c,i.length?i.join(`
7
7
  `)+`
8
- `:""),l(i,t)}catch{}}export function readAllPromptbox(o){const r=f(o,"promptbox");let n;try{n=y(r)}catch{return[]}const t=[];for(const e of n)if(e.endsWith(".jsonl"))try{t.push(...d(u(f(r,e),"utf8")))}catch{continue}return t}export function scanQueuedSessionIds(o){return new Set(readAllPromptbox(o).map(r=>r.sessionId))}export function removePromptboxBySession(o,r){const n=f(o,"promptbox");let t;try{t=y(n)}catch{return 0}let e=0;for(const p of t){if(!p.endsWith(".jsonl"))continue;const i=f(n,p);let s;try{s=u(i,"utf8").split(`
9
- `).filter(a=>a.trim())}catch{continue}const c=s.filter(a=>{try{return JSON.parse(a).sessionId!==r}catch{return!1}});if(c.length!==s.length){e+=s.length-c.length;try{const a=`${i}.tmp`;h(a,c.length?c.join(`
8
+ `:""),l(c,t)}catch{}}export function readAllPromptbox(n){const e=a(n,"promptbox");let o;try{o=h(e)}catch{return[]}const t=[];for(const r of o)if(r.endsWith(".jsonl"))try{t.push(...d(u(a(e,r),"utf8")))}catch{continue}return t}export function scanQueuedSessionIds(n){return new Set(readAllPromptbox(n).map(e=>e.sessionId))}export function removePromptboxBySession(n,e){const o=a(n,"promptbox");let t;try{t=h(o)}catch{return 0}let r=0;for(const i of t){if(!i.endsWith(".jsonl"))continue;const c=a(o,i);let s;try{s=u(c,"utf8").split(`
9
+ `).filter(f=>f.trim())}catch{continue}const p=s.filter(f=>{try{return JSON.parse(f).sessionId!==e}catch{return!1}});if(p.length!==s.length){r+=s.length-p.length;try{const f=`${c}.tmp`;m(f,p.length?p.join(`
10
10
  `)+`
11
- `:""),l(a,i)}catch{}}}return e}
11
+ `:""),l(f,c)}catch{}}}return r}
@@ -1,2 +1,2 @@
1
- import{chmodSync as r,existsSync as c,mkdirSync as p,readFileSync as l,renameSync as d,writeFileSync as u}from"node:fs";import y from"node:path";import n from"web-push";import{getPushKeysPath as h}from"../db/paths.js";import{watchReasonPhrase as f}from"./watch-engine.js";export class PushNotifier{deps;vapid;constructor(e){this.deps=e,this.vapid=m(e.keysPath??h()),e.bus.subscribe(i=>this.onBus(i))}publicKey(){return this.vapid.publicKey}onBus(e){const i=this.payloadFor(e);if(!i)return;const s=this.deps.subscriptions.list();s.length!==0&&this.pushAll(s,JSON.stringify(i))}payloadFor(e){return e.kind==="watch.fired"?e.watcherSessionId!==null?null:{title:"weave",body:`Session ${this.labelOf(e.targetSessionId)} ${f(e.reason)}`,tag:`weave-watch-${e.targetSessionId}`,url:"/"}:e.kind==="question.pending"?{title:"weave",body:`Session ${this.labelOf(e.sessionId)} is waiting for your answer`,tag:`weave-question-${e.sessionId}`,url:"/"}:null}labelOf(e){return this.deps.sessions.getBySessionId(e)?.title??e.slice(0,8)}async pushAll(e,i){for(const s of e)try{await(this.deps.send??b)(s,i,this.vapid)}catch(o){const a=o.statusCode;(a===404||a===410)&&this.deps.subscriptions.deleteByEndpoint(s.endpoint)}}}async function b(t,e,i){n.setVapidDetails("mailto:weave@localhost",i.publicKey,i.privateKey),await n.sendNotification({endpoint:t.endpoint,keys:{p256dh:t.p256dh,auth:t.auth}},e,{TTL:3600})}function m(t){if(c(t))try{const s=JSON.parse(l(t,"utf8"));if(typeof s.publicKey=="string"&&s.publicKey&&typeof s.privateKey=="string"&&s.privateKey)return{publicKey:s.publicKey,privateKey:s.privateKey}}catch{}const e=n.generateVAPIDKeys();p(y.dirname(t),{recursive:!0});const i=`${t}.tmp`;u(i,`${JSON.stringify(e,null,2)}
2
- `,{encoding:"utf8",mode:384}),d(i,t);try{r(t,384)}catch{}return e}
1
+ import{chmodSync as a,existsSync as u,mkdirSync as p,readFileSync as c,renameSync as d,writeFileSync as l}from"node:fs";import y from"node:path";import n from"web-push";import{getPushKeysPath as h}from"../db/paths.js";import{watchReasonPhrase as f}from"./watch-engine.js";export class PushNotifier{deps;vapid;constructor(t){this.deps=t,this.vapid=w(t.keysPath??h()),t.bus.subscribe(e=>this.onBus(e))}publicKey(){return this.vapid.publicKey}onBus(t){const e=this.payloadFor(t);if(!e)return;const i=this.deps.subscriptions.list();i.length!==0&&this.pushAll(i,JSON.stringify(e))}payloadFor(t){return t.kind==="watch.fired"?t.watcherSessionId!==null?null:{title:"weave",body:`Session ${this.labelOf(t.targetSessionId)} ${f(t.reason)}`,tag:`weave-watch-${t.targetSessionId}`,url:"/"}:t.kind==="question.pending"?{title:"weave",body:`Session ${this.labelOf(t.sessionId)} is waiting for your answer`,tag:`weave-question-${t.sessionId}`,url:"/"}:null}labelOf(t){return this.deps.sessions.getBySessionId(t)?.title??t.slice(0,8)}async pushAll(t,e){for(const i of t)try{await(this.deps.send??b)(i,e,this.vapid)}catch(o){const r=o.statusCode;(r===404||r===410)&&this.deps.subscriptions.deleteByEndpoint(i.endpoint)}}}async function b(s,t,e){n.setVapidDetails("mailto:weave@localhost",e.publicKey,e.privateKey),await n.sendNotification({endpoint:s.endpoint,keys:{p256dh:s.p256dh,auth:s.auth}},t,{TTL:3600})}function w(s){if(u(s))try{const i=JSON.parse(c(s,"utf8"));if(typeof i.publicKey=="string"&&i.publicKey&&typeof i.privateKey=="string"&&i.privateKey)return{publicKey:i.publicKey,privateKey:i.privateKey}}catch{}const t=n.generateVAPIDKeys();p(y.dirname(s),{recursive:!0});const e=`${s}.tmp`;l(e,`${JSON.stringify(t,null,2)}
2
+ `,{encoding:"utf8",mode:384}),d(e,s);try{a(s,384)}catch{}return t}
@@ -9,9 +9,11 @@ import type { NormalizedHookPayload } from './types.js';
9
9
  * 作答。为什么不走 hookBus 帧:帧域不带 toolName(frameFacts 只提 agent 事实),
10
10
  * 挂点必须在 handleIngestedRecords(解析后的 payload 在手)。
11
11
  *
12
- * 置位:PreToolUse(阻塞工具) / Notification(permission_prompt);
12
+ * 置位:PreToolUse(阻塞工具) / Notification(permission_prompt) / 事件弹框
13
+ * (`spec.eventQuestion` 认出来的,如 claude 的「Switch model?」);
13
14
  * 清除:PostToolUse(同名阻塞工具) 与 UserPromptSubmit/Stop(question 态),
14
- * permission 态由任意后续非 Notification 事件清(对话框了结必有下文)。
15
+ * permission 与 switch 态由任意后续非 Notification 事件清(对话框了结必有下文;
16
+ * switch 的落定笔是 PostModelSwitch——答「No, go back」不发任何事件,留待下文清)。
15
17
  * daemon 重启由 seedFromDb 按最近事件窗口重放重建。
16
18
  *
17
19
  * 例外:卡在阻塞工具里时,该工具自己补发的 permission_prompt 不改写问题面——
@@ -30,8 +32,8 @@ import type { NormalizedHookPayload } from './types.js';
30
32
  export interface PendingQuestionEntry {
31
33
  sessionId: string;
32
34
  harness: Harness;
33
- /** question = 阻塞工具(问答/计划确认);permission = 权限确认对话框。 */
34
- kind: 'question' | 'permission';
35
+ /** question = 阻塞工具(问答/计划确认);permission = 权限确认;switch = 模型切换确认。 */
36
+ kind: 'question' | 'permission' | 'switch';
35
37
  questions: BlockingQuestion[];
36
38
  at: string;
37
39
  }
@@ -1 +1 @@
1
- import{isHarness as a}from"@weavecode/core";import{blockingPromptFor as c}from"../surfaces.js";const h=12;export class QuestionTracker{deps;pending=new Map;lastPreTool=new Map;permissionMode=new Map;seeding=!1;constructor(e){this.deps=e}specOf(e){return a(e)?this.deps.surfaceFor?.(e)??c(e):null}onEvent(e){const s=e.payload;if(!s)return;const n=this.specOf(e.source);if(!n)return;const t=e.sessionId,i=typeof s.toolName=="string"?s.toolName:null,p=f(s.raw);if(p&&this.permissionMode.set(t,p),s.eventType==="PreToolUse"){if(i&&this.lastPreTool.set(t,{toolName:i,toolInput:s.toolInput}),i&&n.blockingTools.includes(i)){const l=this.pending.get(t),r={sessionId:t,harness:this.harnessOf(e.source),kind:"question",questions:n.parseQuestions(i,s.toolInput),at:new Date().toISOString()};this.pending.set(t,r),!this.seeding&&l?.kind!=="question"&&this.deps.onPending?.(r)}return}if(s.eventType==="Notification"){if(n.permissionNotificationType&&g(s.raw)===n.permissionNotificationType){const l=this.permissionMode.get(t);if(l!=null&&n.silentPermissionModes.includes(l))return;const r=this.lastPreTool.get(t);if(this.pending.get(t)?.kind==="question"&&r!=null&&n.blockingTools.includes(r.toolName))return;const u=this.lastPreTool.get(t)??{toolName:null,toolInput:null};this.pending.set(t,{sessionId:t,harness:this.harnessOf(e.source),kind:"permission",questions:[n.permissionQuestion(u)],at:new Date().toISOString()})}return}const d=this.pending.get(t);if(d){if(d.kind==="permission"){this.pending.delete(t),this.lastPreTool.delete(t);return}(s.eventType==="PostToolUse"&&i!=null&&n.blockingTools.includes(i)||s.eventType==="UserPromptSubmit"||s.eventType==="Stop")&&(this.pending.delete(t),this.lastPreTool.delete(t))}}seedFromDb(){this.seeding=!0;try{for(const e of this.deps.sessions.list())for(const s of this.deps.hookEvents.listBySession(e.sessionId,h)){let n=null;try{n=JSON.parse(s.payload)}catch{n=null}this.onEvent({sessionId:e.sessionId,source:s.source,payload:n})}}finally{this.seeding=!1}}snapshot(){return[...this.pending.values()].sort((e,s)=>e.at<s.at?1:-1)}get(e){return this.pending.get(e)??null}markAnswered(e){this.pending.delete(e)}forgetSession(e){this.pending.delete(e),this.lastPreTool.delete(e),this.permissionMode.delete(e)}harnessOf(e){return e}}function f(o){if(!o||typeof o!="object")return null;const e=o.permission_mode;return typeof e=="string"&&e?e:null}function g(o){if(!o||typeof o!="object")return null;const e=o.notification_type;return typeof e=="string"&&e?e:null}
1
+ import{isHarness as c}from"@weavecode/core";import{blockingPromptFor as f}from"../surfaces.js";const h=12;export class QuestionTracker{deps;pending=new Map;lastPreTool=new Map;permissionMode=new Map;seeding=!1;constructor(e){this.deps=e}specOf(e){return c(e)?this.deps.surfaceFor?.(e)??f(e):null}onEvent(e){const s=e.payload;if(!s)return;const n=this.specOf(e.source);if(!n)return;const t=e.sessionId,r=typeof s.toolName=="string"?s.toolName:null,p=g(s.raw);if(p&&this.permissionMode.set(t,p),s.eventType==="PreToolUse"){if(r&&this.lastPreTool.set(t,{toolName:r,toolInput:s.toolInput}),r&&n.blockingTools.includes(r)){const l=this.pending.get(t),i={sessionId:t,harness:this.harnessOf(e.source),kind:"question",questions:n.parseQuestions(r,s.toolInput),at:new Date().toISOString()};this.pending.set(t,i),!this.seeding&&l?.kind!=="question"&&this.deps.onPending?.(i)}return}if(s.eventType==="Notification"){if(n.permissionNotificationType&&y(s.raw)===n.permissionNotificationType){const l=this.permissionMode.get(t);if(l!=null&&n.silentPermissionModes.includes(l))return;const i=this.lastPreTool.get(t);if(this.pending.get(t)?.kind==="question"&&i!=null&&n.blockingTools.includes(i.toolName))return;const a=this.lastPreTool.get(t)??{toolName:null,toolInput:null};this.pending.set(t,{sessionId:t,harness:this.harnessOf(e.source),kind:"permission",questions:[n.permissionQuestion({...a,message:m(s.raw),permissionMode:l??null})],at:new Date().toISOString()})}return}const d=n.eventQuestion(s.eventType,s.raw);if(d){const l=this.pending.get(t),i={sessionId:t,harness:this.harnessOf(e.source),kind:"switch",questions:[d],at:new Date().toISOString()};this.pending.set(t,i),!this.seeding&&l?.kind!=="switch"&&this.deps.onPending?.(i);return}const u=this.pending.get(t);if(!u)return;if(u.kind!=="question"){this.pending.delete(t),this.lastPreTool.delete(t);return}(s.eventType==="PostToolUse"&&r!=null&&n.blockingTools.includes(r)||s.eventType==="UserPromptSubmit"||s.eventType==="Stop")&&(this.pending.delete(t),this.lastPreTool.delete(t))}seedFromDb(){this.seeding=!0;try{for(const e of this.deps.sessions.list())for(const s of this.deps.hookEvents.listBySession(e.sessionId,h)){let n=null;try{n=JSON.parse(s.payload)}catch{n=null}this.onEvent({sessionId:e.sessionId,source:s.source,payload:n})}}finally{this.seeding=!1}}snapshot(){return[...this.pending.values()].sort((e,s)=>e.at<s.at?1:-1)}get(e){return this.pending.get(e)??null}markAnswered(e){this.pending.delete(e)}forgetSession(e){this.pending.delete(e),this.lastPreTool.delete(e),this.permissionMode.delete(e)}harnessOf(e){return e}}function g(o){if(!o||typeof o!="object")return null;const e=o.permission_mode;return typeof e=="string"&&e?e:null}function m(o){if(!o||typeof o!="object")return null;const e=o.message;return typeof e=="string"&&e.trim()?e:null}function y(o){if(!o||typeof o!="object")return null;const e=o.notification_type;return typeof e=="string"&&e?e:null}
@@ -1 +1 @@
1
- import{INJECTABLE_EVENTS as a,hookSourceHarness as c,normalizeHookRuleSource as s}from"@weavecode/core";export class HookRuleRegistry{repo;byEvent=new Map;all=[];onChange;constructor(e){this.repo=e,this.load()}load(){this.all=this.repo.list().map(e=>({...e,source:s(e.source)})),this.byEvent=new Map;for(const e of this.all){if(e.source.kind!=="hook-event")continue;const t=this.byEvent.get(e.source.event);t?t.push(e):this.byEvent.set(e.source.event,[e])}this.onChange?.()}list(e){return(e===void 0?this.all:this.repo.list(e)).map(t=>({...t,source:s(t.source)}))}get(e){return this.all.find(t=>t.id===e)}candidates(e,t){const n=this.byEvent.get(e)??[];return t?.includeDisabled?[...n]:n.filter(o=>o.enabled)}create(e){const t=s(e.source);validateHandler(t,e.handler);const n=this.repo.create({...e,source:t});return this.load(),n}update(e,t){const n=this.get(e);if(!n)return;const o=t.source?s(t.source):n.source;validateHandler(o,t.handler??n.handler);const i=this.repo.update(e,t.source?{...t,source:o}:t);return i&&this.load(),i}setEnabled(e,t){const n=this.repo.setEnabled(e,t);return n&&this.load(),n}remove(e){const t=this.repo.remove(e);return t&&this.load(),t}}export function validateHandler(r,e){const t=c(r);if(e.type==="inject"){if(t===null||t==="any")throw new Error('inject handler requires source.kind = "hook-event" with a concrete harness (legacy "claude-event" accepted; "any" rejected)');const n=a[t],o=r.kind==="claude-event"||r.kind==="hook-event"?r.event:"";if(!n.includes(o))throw new Error(`inject handler is not supported on event "${o}" (allowed: ${n.join(", ")})`);return}if(e.type==="plugin"&&t===null)throw new Error('plugin handler requires source.kind = "hook-event"')}
1
+ import{INJECTABLE_EVENTS as l,hookSourceHarness as u,normalizeHookRuleSource as s}from"@weavecode/core";export class HookRuleRegistry{repo;byEvent=new Map;all=[];onChange;constructor(e){this.repo=e,this.load()}load(){this.all=this.repo.list().map(e=>({...e,source:s(e.source)})),this.byEvent=new Map;for(const e of this.all){if(e.source.kind!=="hook-event")continue;const t=this.byEvent.get(e.source.event);t?t.push(e):this.byEvent.set(e.source.event,[e])}this.onChange?.()}list(e){return(e===void 0?this.all:this.repo.list(e)).map(n=>({...n,source:s(n.source)}))}get(e){return this.all.find(t=>t.id===e)}candidates(e,t){const n=this.byEvent.get(e)??[];return t?.includeDisabled?[...n]:n.filter(o=>o.enabled)}create(e){const t=s(e.source);validateHandler(t,e.handler);const n=this.repo.create({...e,source:t});return this.load(),n}update(e,t){const n=this.get(e);if(!n)return;const o=t.source?s(t.source):n.source;validateHandler(o,t.handler??n.handler);const i=this.repo.update(e,t.source?{...t,source:o}:t);return i&&this.load(),i}setEnabled(e,t){const n=this.repo.setEnabled(e,t);return n&&this.load(),n}remove(e){const t=this.repo.remove(e);return t&&this.load(),t}}export function validateHandler(r,e){const t=u(r);if(e.type==="inject"){if(t===null||t==="any")throw new Error('inject handler requires source.kind = "hook-event" with a concrete harness (legacy "claude-event" accepted; "any" rejected)');const n=l[t],o=r.kind==="claude-event"||r.kind==="hook-event"?r.event:"";if(!n.includes(o))throw new Error(`inject handler is not supported on event "${o}" (allowed: ${n.join(", ")})`);return}if(e.type==="plugin"&&t===null)throw new Error('plugin handler requires source.kind = "hook-event"')}
@@ -1 +1 @@
1
- import{CLAUDE_RESUME as a}from"@weavecode/harness";import{HeadlessRunner as o}from"./headless-runner.js";export class ResumeRunner{deps;headless;claudeBin;resumeSpec;timeoutMs;constructor(s){this.deps=s,this.headless=s.headless??new o({spawnImpl:s.spawnImpl,killImpl:s.killImpl}),this.resumeSpec=s.resumeSpec??a,this.claudeBin=s.claudeBin??process.env.WEAVE_CLAUDE_BIN??this.resumeSpec.bin,this.timeoutMs=s.timeoutMs}async run(s,e){const t=this.deps.dispatches.getById(s);if(!t)return{ok:!1,status:404,error:"Dispatch not found"};if(t.status!=="pending"&&t.status!=="injected")return{ok:!1,status:409,error:`Dispatch is ${t.status}`};const i=this.deps.sessions.getBySessionId(e);if(!i)return{ok:!1,status:404,error:"Session not found"};if(i.projectId==null)return{ok:!1,status:400,error:"Session has no project"};const u=this.deps.projects.getById(i.projectId);if(!u)return{ok:!1,status:400,error:"Project not found for session"};if(this.headless.isBusy(e))return{ok:!1,status:409,error:"Session already has a running dispatch"};const n={settled:!1};try{this.deps.dispatches.updateStatus(s,{status:"running"}),this.deps.bus?.emit({kind:"dispatch.started",ruleId:t.ruleId,dispatchId:s,sessionId:e,at:new Date().toISOString()}),this.headless.run({sessionId:e,cwd:u.path,prompt:t.prompt,spec:this.resumeSpec,bin:this.claudeBin,timeoutMs:this.timeoutMs,onSettle:r=>this.settle(t,e,n,r)})||this.settle(t,e,n,{status:"failed",output:null,error:"Session already has a running dispatch"})}catch(r){this.settle(t,e,n,{status:"failed",output:null,error:r instanceof Error?r.message:String(r)})}return{ok:!0,dispatchId:s}}settle(s,e,t,i){if(!t.settled){t.settled=!0;try{this.deps.dispatches.updateStatus(s.id,{status:i.status,output:i.output,error:i.error,finished:!0}),this.deps.bus?.emit({kind:"dispatch.finished",ruleId:s.ruleId,dispatchId:s.id,status:i.status,sessionId:e,at:new Date().toISOString()})}catch{}}}}
1
+ import{CLAUDE_RESUME as o}from"@weavecode/harness";import{HeadlessRunner as l}from"./headless-runner.js";export class ResumeRunner{deps;headless;claudeBin;resumeSpec;timeoutMs;constructor(t){this.deps=t,this.headless=t.headless??new l({spawnImpl:t.spawnImpl,killImpl:t.killImpl}),this.resumeSpec=t.resumeSpec??o,this.claudeBin=t.claudeBin??process.env.WEAVE_CLAUDE_BIN??this.resumeSpec.bin,this.timeoutMs=t.timeoutMs}async run(t,e){const s=this.deps.dispatches.getById(t);if(!s)return{ok:!1,status:404,error:"Dispatch not found"};if(s.status!=="pending"&&s.status!=="injected")return{ok:!1,status:409,error:`Dispatch is ${s.status}`};const r=this.deps.sessions.getBySessionId(e);if(!r)return{ok:!1,status:404,error:"Session not found"};if(r.projectId==null)return{ok:!1,status:400,error:"Session has no project"};const a=this.deps.projects.getById(r.projectId);if(!a)return{ok:!1,status:400,error:"Project not found for session"};if(this.headless.isBusy(e))return{ok:!1,status:409,error:"Session already has a running dispatch"};const u={settled:!1};try{this.deps.dispatches.updateStatus(t,{status:"running"}),this.deps.bus?.emit({kind:"dispatch.started",ruleId:s.ruleId,dispatchId:t,sessionId:e,at:new Date().toISOString()}),this.headless.run({sessionId:e,cwd:a.path,prompt:s.prompt,spec:this.resumeSpec,bin:this.claudeBin,timeoutMs:this.timeoutMs,onSettle:n=>this.settle(s,e,u,n)})||this.settle(s,e,u,{status:"failed",output:null,error:"Session already has a running dispatch"})}catch(i){this.settle(s,e,u,{status:"failed",output:null,error:i instanceof Error?i.message:String(i)})}return{ok:!0,dispatchId:t}}settle(t,e,s,r){if(!s.settled){s.settled=!0;try{this.deps.dispatches.updateStatus(t.id,{status:r.status,output:r.output,error:r.error,finished:!0}),this.deps.bus?.emit({kind:"dispatch.finished",ruleId:t.ruleId,dispatchId:t.id,status:r.status,sessionId:e,at:new Date().toISOString()})}catch{}}}}
@@ -1 +1 @@
1
- import{messagingSurfaceFor as c}from"../surfaces.js";import{claudeLivenessById as a,pidAliveOf as u}from"../daemon/claude-liveness.js";export const SEQUENCE_HOP_LIMIT=3;export class SequenceEngine{deps;constructor(e){this.deps=e,this.deps.bus.subscribe(s=>this.onBus(s))}async trigger(e){await this.fire(e.id,e.cursor)}cancel(e){return this.finish(e,"cancelled")}rearm(){try{for(const e of this.deps.sequences.listRunning()){const s=e.steps[e.cursor];if(!s){this.finish(e.id,"done");continue}if(s.messageId==null){this.finish(e.id,"failed",`step ${e.cursor+1} interrupted \u2014 daemon restarted, not re-sent`);continue}const t=this.deps.deliverer.getMessage(s.messageId);if(!(t?.status==="injected"||t?.status==="delivered")){if(t?.status==="running"){this.finish(e.id,"failed","daemon restarted during headless step");continue}t?.status==="succeeded"?this.advance(e):this.finish(e.id,"failed",`step ${e.cursor+1} ${t?.status??"message missing"}`)}}}catch{}}onEvent(e){try{if(!(this.deps.surfaceFor?.(e.source)??c(e.source)).idleSignals.includes(e.eventType))return;for(const s of this.deps.sequences.listRunning()){const t=s.steps[s.cursor];if(!t||t.to!==e.sessionId||t.messageId==null)continue;const i=this.deps.deliverer.getMessage(t.messageId);(i?.status==="injected"||i?.status==="delivered")&&this.advance(s)}}catch{}}onBus(e){if(e.kind==="message.finished")try{for(const s of this.deps.sequences.listRunning())s.steps[s.cursor]?.messageId===e.messageId&&(e.status==="succeeded"?this.advance(s):this.finish(s.id,"failed",`step ${s.cursor+1} ${e.status}`))}catch{}}advance(e){if(e.cursor+1>=e.steps.length){this.finish(e.id,"done");return}this.deps.sequences.advanceCursor(e.id,e.cursor,e.cursor+1)&&this.fire(e.id,e.cursor+1)}async fire(e,s){try{const t=this.deps.sequences.getById(e);if(!t||t.status!=="running"||t.cursor!==s)return;const i=t.steps[s];if(!i)return;this.deps.bus.emit({kind:"sequence.step",sequenceId:e,cursor:s,at:new Date().toISOString()});const n=await this.deps.deliverer.send({toSessionId:i.to,text:i.text,mode:i.mode,fromKind:"dashboard"});if(!n.ok){this.finish(e,"failed",`step ${s+1} rejected: ${n.error}`);return}if(this.deps.sequences.setStepMessage(e,s,n.messageId),n.status==="running"){const r=this.deps.deliverer.getMessage(n.messageId);if(r?.status==="succeeded"||r?.status==="failed"||r?.status==="timeout")if(r.status==="succeeded"){const d=this.deps.sequences.getById(e);d&&this.advance(d)}else this.finish(e,"failed",`step ${s+1} ${r.status}`)}}catch(t){this.finish(e,"failed",t instanceof Error?t.message:String(t))}}finish(e,s,t=null){return this.deps.sequences.finish(e,s,t)?(this.deps.bus.emit({kind:"sequence.finished",sequenceId:e,status:s,error:t,at:new Date().toISOString()}),!0):!1}sweepTerminated(){try{const e=this.deps.livenessOf?.()??a(),s=new Map(this.deps.sessions.listWithCounts().map(i=>[i.sessionId,i]));let t=0;for(const i of this.deps.sequences.listRunning()){const n=i.steps[i.cursor];if(!n)continue;const r=s.get(n.to);r&&u(r,e)!==!1||this.finish(i.id,"failed",`target session ${n.to} terminated`)&&t++}return t}catch{return 0}}}
1
+ import{messagingSurfaceFor as d}from"../surfaces.js";import{claudeLivenessById as u,pidAliveOf as a}from"../daemon/claude-liveness.js";export const SEQUENCE_HOP_LIMIT=3;export class SequenceEngine{deps;constructor(s){this.deps=s,this.deps.bus.subscribe(t=>this.onBus(t))}async trigger(s){await this.fire(s.id,s.cursor)}cancel(s){return this.finish(s,"cancelled")}rearm(){try{for(const s of this.deps.sequences.listRunning()){const t=s.steps[s.cursor];if(!t){this.finish(s.id,"done");continue}if(t.messageId==null){this.finish(s.id,"failed",`step ${s.cursor+1} interrupted \u2014 daemon restarted, not re-sent`);continue}const e=this.deps.deliverer.getMessage(t.messageId);if(!(e?.status==="injected"||e?.status==="delivered")){if(e?.status==="running"){this.finish(s.id,"failed","daemon restarted during headless step");continue}e?.status==="succeeded"?this.advance(s):this.finish(s.id,"failed",`step ${s.cursor+1} ${e?.status??"message missing"}`)}}}catch{}}onEvent(s){try{if(!(this.deps.surfaceFor?.(s.source)??d(s.source)).idleSignals.includes(s.eventType))return;for(const e of this.deps.sequences.listRunning()){const i=e.steps[e.cursor];if(!i||i.to!==s.sessionId||i.messageId==null)continue;const n=this.deps.deliverer.getMessage(i.messageId);(n?.status==="injected"||n?.status==="delivered")&&this.advance(e)}}catch{}}onBus(s){if(s.kind==="message.finished")try{for(const t of this.deps.sequences.listRunning())t.steps[t.cursor]?.messageId===s.messageId&&(s.status==="succeeded"?this.advance(t):this.finish(t.id,"failed",`step ${t.cursor+1} ${s.status}`))}catch{}}advance(s){if(s.cursor+1>=s.steps.length){this.finish(s.id,"done");return}this.deps.sequences.advanceCursor(s.id,s.cursor,s.cursor+1)&&this.fire(s.id,s.cursor+1)}async fire(s,t){try{const e=this.deps.sequences.getById(s);if(!e||e.status!=="running"||e.cursor!==t)return;const i=e.steps[t];if(!i)return;this.deps.bus.emit({kind:"sequence.step",sequenceId:s,cursor:t,at:new Date().toISOString()});const n=await this.deps.deliverer.send({toSessionId:i.to,text:i.text,mode:i.mode,fromKind:"dashboard"});if(!n.ok){this.finish(s,"failed",`step ${t+1} rejected: ${n.error}`);return}if(this.deps.sequences.setStepMessage(s,t,n.messageId),n.status==="running"){const r=this.deps.deliverer.getMessage(n.messageId);if(r?.status==="succeeded"||r?.status==="failed"||r?.status==="timeout")if(r.status==="succeeded"){const c=this.deps.sequences.getById(s);c&&this.advance(c)}else this.finish(s,"failed",`step ${t+1} ${r.status}`)}}catch(e){this.finish(s,"failed",e instanceof Error?e.message:String(e))}}finish(s,t,e=null){return this.deps.sequences.finish(s,t,e)?(this.deps.bus.emit({kind:"sequence.finished",sequenceId:s,status:t,error:e,at:new Date().toISOString()}),!0):!1}sweepTerminated(){try{const s=this.deps.livenessOf?.()??u(),t=new Map(this.deps.sessions.listWithCounts().map(i=>[i.sessionId,i]));let e=0;for(const i of this.deps.sequences.listRunning()){const n=i.steps[i.cursor];if(!n)continue;const r=t.get(n.to);r&&a(r,s)!==!1||this.finish(i.id,"failed",`target session ${n.to} terminated`)&&e++}return e}catch{return 0}}}
@@ -2,6 +2,7 @@ import type { HookDispatchRepository } from '../repositories/hook-dispatches.js'
2
2
  import type { HookEventRepository } from '../repositories/hook-events.js';
3
3
  import type { SessionSequenceRepository } from '../repositories/session-sequences.js';
4
4
  import type { SessionWatchRepository } from '../repositories/session-watches.js';
5
+ import type { SideQuestionRepository } from '../repositories/side-questions.js';
5
6
  import type { SessionRepository } from '../repositories/sessions.js';
6
7
  import type { MessageDeliverer } from './message-deliverer.js';
7
8
  import type { QuestionTracker } from './question-tracker.js';
@@ -21,6 +22,12 @@ export interface SessionPurgeDeps {
21
22
  probe?: {
22
23
  forget(sessionId: string): void;
23
24
  };
25
+ /** 旁路会话历史:该会话的侧问行一并清(不计数;这是会话的附属品)。 */
26
+ sideQuestions?: Pick<SideQuestionRepository, 'deleteBySession'>;
27
+ /** 上传件(不计数):事件清完顺带回收再没有人引用的图(文件 + 行)。 */
28
+ uploads?: {
29
+ pruneUnreferenced(): number;
30
+ };
24
31
  }
25
32
  /**
26
33
  * 删会话的数据清理:会话行 + 该会话的采集事件 + 指令池派发 + 消息管道在途一并清。
@@ -1 +1 @@
1
- export function purgeSession(e,s){const n=e.events.deleteBySession(s),o=e.dispatches?.deleteBySession(s)??0,i=e.deliverer?.forgetSession(s)??0;return e.watches?.deleteBySession(s),e.sequences?.deleteMentioning(new Set([s])),e.questions?.forgetSession(s),e.probe?.forget(s),e.sessions.remove(s),{events:n,dispatches:o,messages:i}}
1
+ export function purgeSession(e,t){const n=e.events.deleteBySession(t);e.uploads?.pruneUnreferenced();const o=e.dispatches?.deleteBySession(t)??0,r=e.deliverer?.forgetSession(t)??0;return e.watches?.deleteBySession(t),e.sequences?.deleteMentioning(new Set([t])),e.questions?.forgetSession(t),e.sideQuestions?.deleteBySession(t),e.probe?.forget(t),e.sessions.remove(t),{events:n,dispatches:o,messages:r}}
@@ -3,15 +3,12 @@ import type { WatchEngine } from './watch-engine.js';
3
3
  import type { SequenceEngine } from './sequence-engine.js';
4
4
  export declare const SWEEP_INTERVAL_MS: number;
5
5
  /**
6
- * 定时清无 prompt 幽灵会话:从未收到 UserPromptSubmit(事件全是会话引导类——
7
- * 典型形状是开了就走的 SessionStart 单例,或 SessionStart + 闲置 Notification
8
- * 组合),且静默超过保活窗。判据与期限的单一事实源 = sessions 仓储的
9
- * `listWithCounts`(`autoDeleteAt` 计算列)——本清扫器只做「过期即清」;
10
- * 收到过 prompt 的会话 autoDeleteAt 为 null,永不自动删(遵循全局事件保留期)。
6
+ * 定时清过期会话:判据与期限的单一事实源 = sessions 仓储的 `listWithCounts`
7
+ * (`autoDeleteAt` 计算列,两档——没等到用户 prompt 的新会话 1 小时快过期、
8
+ * 收到过 prompt 的走 settings `sessions.idleDays` 闲置窗),本清扫器只做「过期即清」。
11
9
  *
12
- * 注:新入库路径已不再为「仅 SessionStart」会话建行(inbox-worker 的
13
- * needsSessionRow 判据);本清扫器管住其余一切无 prompt 形状与该改动之前的
14
- * 遗留存量行。
10
+ * 注:入库路径对**每个**首现 sessionId 都建档(含仅一条 SessionStart 的新会话
11
+ * ——新建会话要马上出现在列表),期限倒计时随行展示,看得见它还剩多久。
15
12
  */
16
13
  export declare class SessionSweeper {
17
14
  private readonly deps;
@@ -1 +1 @@
1
- import{purgeSession as r}from"./session-purge.js";export const SWEEP_INTERVAL_MS=5*6e4;export class SessionSweeper{deps;now;constructor(e,s=Date.now){this.deps=e,this.now=s}sweep(){const e=this.now();let s=0;for(const t of this.deps.sessions.listWithCounts()){const o=t.autoDeleteAt==null?null:Date.parse(t.autoDeleteAt);o==null||e<o||(r(this.deps,t.sessionId),s++)}return this.deps.watchEngine?.sweepTerminated(),this.deps.sequenceEngine?.sweepTerminated(),s}start(){this.sweep();const e=setInterval(()=>this.sweep(),SWEEP_INTERVAL_MS);return e.unref(),e}}export function startSessionSweeper(n){return new SessionSweeper(n).start()}
1
+ import{purgeSession as r}from"./session-purge.js";export const SWEEP_INTERVAL_MS=5*6e4;export class SessionSweeper{deps;now;constructor(e,s=Date.now){this.deps=e,this.now=s}sweep(){const e=this.now();let s=0;for(const t of this.deps.sessions.listWithCounts()){const o=t.autoDeleteAt==null?null:Date.parse(t.autoDeleteAt);o==null||e<o||(r(this.deps,t.sessionId),s++)}return this.deps.uploads?.pruneUnreferenced(),this.deps.watchEngine?.sweepTerminated(),this.deps.sequenceEngine?.sweepTerminated(),s}start(){this.sweep();const e=setInterval(()=>this.sweep(),SWEEP_INTERVAL_MS);return e.unref(),e}}export function startSessionSweeper(n){return new SessionSweeper(n).start()}
@@ -0,0 +1,41 @@
1
+ import { type Harness } from '@weavecode/core';
2
+ import type { MessagingSurface } from '@weavecode/harness';
3
+ import type { SideQuestionRepository, SideQuestionRow } from '../repositories/side-questions.js';
4
+ import type { HookEventBus } from './bus.js';
5
+ /**
6
+ * 旁路会话域(claude = `/btw`)的 server 侧协调:send 归 `MessageDeliverer`
7
+ * (终端文本通道),认领归这里。
8
+ *
9
+ * 为什么必须自己记:宿主的侧问查询开着 `skipTranscript`——问题与回答都**不落
10
+ * 任何文件**(面板历史只在宿主内存里),故问句只有 weave 自己发出去时才知道。
11
+ * 回答倒是会以采集事件回来,但事件会按保留策略清掉,而这条问答是用户的历史。
12
+ */
13
+ /** 回答窗口:超过这个时间还没认领到回答就落 timeout(宿主面板可能被 Esc 关掉、
14
+ * 主回合可能已经收尾)——同一窗口也用作认领下界,迟到的回答不认领旧行。 */
15
+ export declare const SIDE_ANSWER_WINDOW_MS: number;
16
+ export interface SideQuestionDeps {
17
+ repo: SideQuestionRepository;
18
+ bus?: HookEventBus;
19
+ /** 能力面访问器(测试注入);缺省 surfaces.ts 模块级 registry。 */
20
+ surfaceFor?: (harness: Harness) => MessagingSurface;
21
+ now?: () => number;
22
+ }
23
+ /** 一条入库事件(认领的输入面;payload = 解析后的归一化载荷)。 */
24
+ export interface SideQuestionEvent {
25
+ sessionId: string;
26
+ source: string;
27
+ eventType: string;
28
+ payload: unknown;
29
+ eventId: number;
30
+ }
31
+ /**
32
+ * 采集事件 → 认领一条旁路回答。**判据归 harness 能力面**
33
+ * (`SideQuestionSpec.answerOf`):宿主的事件名、以及「哪类子 agent 没转录」
34
+ * 都是 harness 知识,server 不认,也不猜。
35
+ */
36
+ export declare function claimSideAnswer(deps: SideQuestionDeps, input: SideQuestionEvent): SideQuestionRow | null;
37
+ /** 历史列表(游标向前翻页):先把超窗的 pending 落定,再读——不另起定时器。 */
38
+ export declare function readSideQuestions(deps: SideQuestionDeps, sessionId: string, opts: {
39
+ beforeId?: number;
40
+ limit: number;
41
+ }): SideQuestionRow[];
@@ -0,0 +1 @@
1
+ import{isHarness as i}from"@weavecode/core";import{messagingSurfaceFor as a}from"../surfaces.js";export const SIDE_ANSWER_WINDOW_MS=10*6e4;export function claimSideAnswer(n,e){if(!i(e.source))return null;const s=(n.surfaceFor?.(e.source)??a(e.source)).sideQuestion?.answerOf(e.eventType,e.payload);if(!s)return null;const t=new Date((n.now?.()??Date.now())-SIDE_ANSWER_WINDOW_MS).toISOString(),r=n.repo.claim(e.sessionId,s,e.eventId,t);return r?(n.bus?.emit({kind:"sideQuestion.answered",sessionId:r.sessionId,sideQuestionId:r.id,at:r.answeredAt??new Date().toISOString()}),r):null}export function readSideQuestions(n,e,o){return n.repo.expirePending(new Date((n.now?.()??Date.now())-SIDE_ANSWER_WINDOW_MS).toISOString()),n.repo.list(e,o)}
@@ -1 +1 @@
1
- import{readFile as R,readdir as h,stat as w}from"node:fs/promises";import a from"node:path";import{WEAVE_PLUGIN_MANIFEST as k,WeavePluginManifestSchema as I,HARNESS_KEYS as G}from"@weavecode/core";import{builtinPacksDir as J}from"../market/builtin.js";import{getDataDir as K}from"../db/paths.js";import{hasNonEmptyModules as T}from"../watch/plugin-mods.js";const D=".claude-plugin",A="plugin.json",L="weave.json",F=2,O=10,S=["claude"];export function builtinToolkitRoot(){return a.resolve(J(K()))}async function j(n){try{return(await w(n)).isDirectory()}catch{return!1}}async function f(n){try{const t=JSON.parse(await R(n,"utf8"));return t&&typeof t=="object"&&!Array.isArray(t)?t:null}catch{return null}}export async function isToolkitPackDir(n){return await b(n)?!0:await j(a.join(n,"skills"))||await j(a.join(n,"commands"))||await j(a.join(n,"agents"))}async function b(n){if(await f(a.join(n,D,A)))return!0;try{return await w(a.join(n,k)),!0}catch{}return T(await f(a.join(n,"hooks","hooks.json")))}async function V(n){try{return(await h(n,{withFileTypes:!0})).filter(t=>t.isDirectory()).map(t=>t.name).sort()}catch{return[]}}async function x(n){try{return(await h(n,{withFileTypes:!0})).filter(t=>t.isFile()&&t.name.endsWith(".md")).map(t=>t.name.replace(/\.md$/,"")).sort()}catch{return[]}}function C(n){if(!Array.isArray(n)||n.length===0)return S;const t=n.filter(r=>G.includes(r));return t.length>0?t:S}export async function parseToolkitPack(n,t,r){const s=a.basename(n),o=await f(a.join(n,D,A)),i=await f(a.join(n,k)),e=await f(a.join(n,L)),p=await V(a.join(n,"skills")),d=await x(a.join(n,"commands")),c=await x(a.join(n,"agents")),m=await f(a.join(n,"hooks","hooks.json")),v=T(m),g=!!m&&typeof m.hooks=="object"&&m.hooks!==null,u=[];if(p.length>0&&u.push("skill"),d.length>0&&u.push("command"),c.length>0&&u.push("agent"),v?u.push("mod"):g&&u.push("hook"),i&&u.push("rule"),u.length===0)return null;const y=typeof e?.kind=="string"?e.kind:null,N=y&&["skill","hook","mod","rule","surface"].includes(y)?y:v?"mod":g?"hook":i&&!o?"rule":p.length>0?"skill":"surface",l=i?I.safeParse(i):null,W=l?.success?l.data.id:s,_=(typeof o?.name=="string"?o.name:void 0)??(l?.success?l.data.name:void 0)??s,M=(l?.success?l.data.version:void 0)??(typeof o?.version=="string"?o.version:void 0)??"0.0.0",P=(typeof o?.description=="string"?o.description:void 0)??(l?.success?l.data.description:void 0);return{id:W,name:_,version:M,...P?{description:P}:{},scope:r,dir:n,provenance:t.provenance,sourceRoot:t.root,targets:C(e?.targets),kind:N,components:u,ccPack:!!o,weavePack:!!i,skills:p}}function E(n){return n==="node_modules"||n.startsWith(".")}export async function discoverToolkitPacks(n){const t=[],r=n.provenance==="market",s=r?O:F,o=async(i,e,p)=>{if(await isToolkitPackDir(i)&&!(e===0&&r&&!await b(i))){const c=await parseToolkitPack(i,n,p);c&&t.push(c);return}if(e>=s)return;let d;try{d=await h(i,{withFileTypes:!0})}catch{return}for(const c of d)!c.isDirectory()||E(c.name)||await o(a.join(i,c.name),e+1,e===0?c.name:p)};return await o(n.root,0,""),t}export function discoverToolkitSources(){return[{root:builtinToolkitRoot(),provenance:"builtin"}]}export async function discoverWeavePackDirs(n){const t=[],r=async(s,o)=>{try{await w(a.join(s,k)),t.push(s);return}catch{}if(o>=F)return;let i;try{i=await h(s,{withFileTypes:!0})}catch{return}for(const e of i)!e.isDirectory()||E(e.name)||await r(a.join(s,e.name),o+1)};return await r(n,0),t}
1
+ import{readFile as L,readdir as h,stat as w}from"node:fs/promises";import e from"node:path";import{WEAVE_PLUGIN_MANIFEST as y,WeavePluginManifestSchema as R,HARNESS_KEYS as I}from"@weavecode/core";import{builtinPacksDir as W}from"../market/builtin.js";import{getDataDir as J}from"../db/paths.js";import{hasNonEmptyModules as E}from"../watch/plugin-mods.js";const S=".claude-plugin",v="plugin.json",K="weave.json",D=2,O=10,_=["claude"];export function builtinToolkitRoot(){return e.resolve(W(J()))}async function d(t){try{return(await w(t)).isDirectory()}catch{return!1}}async function p(t){try{const n=JSON.parse(await L(t,"utf8"));return n&&typeof n=="object"&&!Array.isArray(n)?n:null}catch{return null}}export async function isToolkitPackDir(t){return await N(t)?!0:await d(e.join(t,"skills"))||await d(e.join(t,"commands"))||await d(e.join(t,"agents"))}async function N(t){if(await p(e.join(t,S,v)))return!0;try{return await w(e.join(t,y)),!0}catch{}return E(await p(e.join(t,"hooks","hooks.json")))}async function V(t){try{return(await h(t,{withFileTypes:!0})).filter(o=>o.isDirectory()).map(o=>o.name).sort()}catch{return[]}}async function P(t){try{return(await h(t,{withFileTypes:!0})).filter(o=>o.isFile()&&o.name.endsWith(".md")).map(o=>o.name.replace(/\.md$/,"")).sort()}catch{return[]}}function G(t){if(!Array.isArray(t)||t.length===0)return _;const n=t.filter(o=>I.includes(o));return n.length>0?n:_}export async function parseToolkitPack(t,n,o){const i=e.basename(t),a=await p(e.join(t,S,v)),s=await p(e.join(t,y)),r=await p(e.join(t,K)),m=await V(e.join(t,"skills")),g=await P(e.join(t,"commands")),c=await P(e.join(t,"agents")),f=await p(e.join(t,"hooks","hooks.json")),j=E(f),T=!!f&&typeof f.hooks=="object"&&f.hooks!==null,u=[];if(m.length>0&&u.push("skill"),g.length>0&&u.push("command"),c.length>0&&u.push("agent"),j?u.push("mod"):T&&u.push("hook"),s&&u.push("rule"),u.length===0)return null;const k=typeof r?.kind=="string"?r.kind:null,F=k&&["skill","hook","mod","rule","surface"].includes(k)?k:j?"mod":T?"hook":s&&!a?"rule":m.length>0?"skill":"surface",l=s?R.safeParse(s):null,C=l?.success?l.data.id:i,b=(typeof a?.name=="string"?a.name:void 0)??(l?.success?l.data.name:void 0)??i,x=(l?.success?l.data.version:void 0)??(typeof a?.version=="string"?a.version:void 0)??"0.0.0",A=(typeof a?.description=="string"?a.description:void 0)??(l?.success?l.data.description:void 0);return{id:C,name:b,version:x,...A?{description:A}:{},scope:o,dir:t,provenance:n.provenance,sourceRoot:n.root,targets:G(r?.targets),kind:F,components:u,ccPack:!!a,weavePack:!!s,skills:m}}function M(t){return t==="node_modules"||t.startsWith(".")}export async function discoverToolkitPacks(t){const n=t.provenance==="market",o=n?O:D,i=async(a,s,r)=>{if(await isToolkitPackDir(a)&&!(s===0&&n&&!await N(a))){const f=await parseToolkitPack(a,t,r);return f?[f]:[]}if(s>=o)return[];let m;try{m=await h(a,{withFileTypes:!0})}catch{return[]}return(await Promise.all(m.filter(c=>c.isDirectory()&&!M(c.name)).map(c=>i(e.join(a,c.name),s+1,s===0?c.name:r)))).flat()};return i(t.root,0,"")}export function discoverToolkitSources(){return[{root:builtinToolkitRoot(),provenance:"builtin"}]}export async function discoverWeavePackDirs(t){const n=[],o=async(i,a)=>{try{await w(e.join(i,y)),n.push(i);return}catch{}if(a>=D)return;let s;try{s=await h(i,{withFileTypes:!0})}catch{return}for(const r of s)!r.isDirectory()||M(r.name)||await o(e.join(i,r.name),a+1)};return await o(t,0),n}
@@ -105,9 +105,17 @@ export interface ToolkitServiceDeps {
105
105
  }
106
106
  export declare class ToolkitService {
107
107
  private readonly deps;
108
+ private packsCache;
108
109
  constructor(deps: ToolkitServiceDeps);
109
110
  /** 扫描源:内置根(测试可覆盖)+ managed 市场资源根。 */
110
111
  private sources;
112
+ /**
113
+ * 各扫描源并行发现(市场源要下钻 10 层,一个一个来就是把最慢的那个乘上根数)。
114
+ *
115
+ * 盘上清单只在装/卸/导入市场时才变,而 `list` 是面板每次打开都要打的一发
116
+ * (实测 ~200ms)——10s 内复用上一次的扫描结果,在飞请求共用同一个 Promise
117
+ * (单飞)。缓存键带扫描根集合:导入/移除市场换了根即重扫,不等 TTL。
118
+ */
111
119
  private allPacks;
112
120
  /**
113
121
  * 包清单 + 启用态(读侧以落盘/级联校验),顺带把 meta 索引自愈到事实、
@@ -1,5 +1,5 @@
1
- import{cp as I,mkdir as b,readFile as C,readdir as h,rm as w,writeFile as x}from"node:fs/promises";import{spawn as P}from"node:child_process";import{homedir as M}from"node:os";import c from"node:path";import{hashFile as k}from"../install/fingerprint.js";import{fileAssetTargetDir as H}from"../install/file-assets.js";import{assetSurfaceFor as $,pluginSurfaceFor as q}from"../surfaces.js";import{marketLibraryRoots as A}from"../market/resolve.js";import{marketIdOf as m}from"../market/identity.js";import{installPluginPack as N}from"../install/plugin-install.js";import{effective as _,setProjectEnabled as O}from"./plugin-project-state.js";import{builtinToolkitRoot as L,discoverToolkitPacks as V}from"./toolkit-scan.js";export class ToolkitError extends Error{code;constructor(e,t){super(e),this.code=t,this.name="ToolkitError"}}export const MIN_MOD_HOST_VERSION=[2,1,287];export function isVersionAtLeast(r,e){const t=r.split(".").map(s=>Number.parseInt(s,10));for(let s=0;s<e.length;s++){const a=Number.isFinite(t[s])?t[s]:0;if(a>e[s])return!0;if(a<e[s])return!1}return!0}let y;function K(r){if(!(r.exitCode!==null||r.signalCode!==null)){if(process.platform==="win32"&&r.pid!==void 0){P("taskkill",["/pid",String(r.pid),"/t","/f"],{windowsHide:!0,stdio:"ignore"}).unref();return}r.kill("SIGKILL")}}export async function detectClaudeVersion(){if(y&&Date.now()-y.at<6e5)return y.value;const r=await new Promise(e=>{let t="";const s=process.platform==="win32"?P("claude --version",{windowsHide:!0,shell:!0,stdio:["ignore","pipe","pipe"]}):P("claude",["--version"],{windowsHide:!0,stdio:["ignore","pipe","pipe"]}),a=setTimeout(()=>{K(s),e(null)},5e3);s.stdout?.on("data",i=>t+=i.toString()),s.on("error",()=>{clearTimeout(a),e(null)}),s.on("close",()=>{clearTimeout(a);const i=/(\d+\.\d+\.\d+)/.exec(t);e(i?i[1]:null)})});return r!==null&&(y={value:r,at:Date.now()}),r}async function S(r,e,t){let s;try{s=await h(c.join(r,...e.split("/").filter(Boolean)),{withFileTypes:!0})}catch{return}for(const a of s){if(a.name==="node_modules"||a.name===".git")continue;const i=e?`${e}/${a.name}`:a.name;a.isDirectory()?await S(r,i,t):t.push({rel:i,abs:c.join(r,...i.split("/"))})}}const f=r=>r.ccPack||r.kind==="mod";async function R(r,e){const t=[],s=e.targets.includes("claude");if(e.skills.length>0)for(const a of e.targets){if(a==="claude"&&f(e))continue;const i=$(a).projectSkillsDir();for(const o of e.skills){const n=[];await S(c.join(e.dir,"skills",o),"",n);for(const l of n)t.push({src:l.abs,rel:`${i}/${o}/${l.rel}`})}}if(s&&!f(e))for(const[a,i]of[["commands","command"],["agents","agent"]]){const o=c.join(e.dir,a),n=[];if(await S(o,"",n),n.length===0)continue;const l=H(i,"claude","project",r,M());for(const u of n){const g=u.rel.split("/").pop();t.push({src:u.abs,rel:j(c.relative(r,c.join(l,g)))})}}return t}function j(r){return r.split(c.sep).join("/")}function E(r,e){return c.join(r,".weave","toolkit",`${e}.json`)}async function v(r){try{const e=JSON.parse(await C(r,"utf8"));return e&&typeof e=="object"&&typeof e.packId=="string"?e:null}catch{return null}}export async function projectFileNamespaces(r){const e=new Map,t=c.join(r,".weave","toolkit");let s;try{s=await h(t)}catch{return e}for(const a of s){if(!a.endsWith(".json"))continue;const i=await v(c.join(t,a)),o=i?m(i.sourceDir):void 0;if(!(!i||!o))for(const n of Object.keys(i.files))e.set(n,o)}return e}export async function projectPackFiles(r){const e=new Map,t=c.join(r,".weave","toolkit");let s;try{s=await h(t)}catch{return e}for(const a of s){if(!a.endsWith(".json"))continue;const i=await v(c.join(t,a));if(i)for(const[o,n]of Object.entries(i.files))typeof n=="string"&&e.set(o,n)}return e}async function T(r){try{return await C(r),!0}catch{return!1}}async function B(r,e){const t=new Set;for(const a of e){let i=c.posix.dirname(a);for(;i&&i!=="."&&i!=="/";)t.add(i),i=c.posix.dirname(i)}const s=[...t].sort((a,i)=>i.split("/").length-a.split("/").length);for(const a of s){const i=c.join(r,...a.split("/"));try{(await h(i)).length===0&&await w(i,{recursive:!0,force:!0})}catch{}}}export function evaluateModHostGate(r){return process.env.WEAVE_SKIP_MOD_VERSION_CHECK==="1"?{ok:!0}:r?isVersionAtLeast(r,MIN_MOD_HOST_VERSION)?{ok:!0}:{ok:!1,message:`\u5BBF\u4E3B Claude Code ${r} \u4F4E\u4E8E 2.1.287\uFF0Cmod \u5DE5\u5177\u5305\u4E0D\u843D\u76D8\uFF08\u8BF7\u5148\u5347\u7EA7 Claude Code\uFF09`}:{ok:!0,warning:"\u65E0\u6CD5\u68C0\u6D4B\u5BBF\u4E3B Claude Code \u7248\u672C\uFF0Cmod \u5DE5\u5177\u5305\u9700\u8981 \u2265 2.1.287 \u624D\u80FD\u88AB\u52A0\u8F7D"}}export class ToolkitService{deps;constructor(e){this.deps=e}sources(){const e=[{root:this.deps.builtinRoot??L(),provenance:"builtin"}];if(this.deps.libraries)for(const s of A(this.deps.libraries))e.push({root:s,provenance:"market"});const t=new Set;return e.filter(s=>{const a=c.resolve(s.root);return t.has(a)?!1:(t.add(a),!0)})}async allPacks(){const e=[];for(const t of this.sources())e.push(...await V(t));return e}async list(e){const t=this.requireProject(e),s=await this.allPacks(),a=[];for(const i of s)a.push(await this.packInfo(t,i));return await this.healMeta(t,a),{packs:a,legacyCopies:await this.scanLegacyCopies(t)}}async enable(e,t,s){const a=this.requireProject(e),i=await this.resolvePack(t,s),o=[];if(i.kind==="mod"&&i.targets.includes("claude")){const d=this.deps.claudeVersion??detectClaudeVersion,p=evaluateModHostGate(await d());if(!p.ok)throw new ToolkitError(p.message??"mod host gate","host-version");p.warning&&o.push(p.warning)}const n=a.path;if(f(i)&&i.targets.includes("claude")){const d=this.pluginSurface();await N(d,i),await d.setProjectEnabled(n,i.name,!0,m(i.dir))}const l=E(n,i.id),u=await this.readRecordHealed(n,i.id),g=u??{packId:i.id,provenance:i.provenance,sourceRoot:i.sourceRoot,sourceDir:i.dir,enabledAt:new Date().toISOString(),files:{}};let F=u===null;const D=await R(n,i);for(const d of D){const p=c.join(n,...d.rel.split("/"));if(g.files[d.rel]!==void 0){await T(p)||(await b(c.dirname(p),{recursive:!0}),await I(d.src,p));continue}await k(p)==="missing"&&(await b(c.dirname(p),{recursive:!0}),await I(d.src,p),g.files[d.rel]=await k(d.src),F=!0)}return D.length>0?F&&(await b(c.dirname(l),{recursive:!0}),await x(l,JSON.stringify(g,null,2)+`
2
- `,"utf8")):u&&await w(l,{force:!0}),i.weavePack&&O(a,i.id,!0,{projects:this.deps.projects}),this.rememberEnabled(a,i.id,!0),{pack:await this.packInfo(this.requireProject(e),i),warnings:o}}async disable(e,t,s){const a=this.requireProject(e),i=await this.resolvePack(t,s);return await this.applyDisabled(a,i),{pack:await this.packInfo(this.requireProject(e),i),warnings:[]}}async applyDisabled(e,t){await this.removePackFiles(e,t,t.sourceRoot),f(t)&&t.targets.includes("claude")&&await this.pluginSurface().setProjectEnabled(e.path,t.name,!1,m(t.dir)),t.weavePack&&O(e,t.id,!1,{projects:this.deps.projects}),this.rememberEnabled(e,t.id,!1)}async uninstall(e,t,s){const a=this.requireProject(e),i=await this.resolvePack(t,s);return await this.applyDisabled(a,i),f(i)&&i.targets.includes("claude")&&await this.pluginSurface().uninstall(i.name,m(i.dir)),{pack:await this.packInfo(this.requireProject(e),i),warnings:[]}}async removePackFiles(e,t,s){const a=E(e.path,t.id),i=await v(a);if(!i||s&&c.resolve(i.sourceRoot)!==c.resolve(s))return;const o=[];for(const[n,l]of Object.entries(i.files)){const u=c.join(e.path,...n.split("/"));await k(u)===l&&(await w(u,{force:!0}),o.push(n))}await w(a,{force:!0}),await B(e.path,o)}requireProject(e){const t=this.deps.projects.getById(e);if(!t)throw new ToolkitError(`Project not found: ${e}`,"not-found");return t}async resolvePack(e,t){const s=(await this.allPacks()).filter(i=>i.id===e);if(t){const i=s.find(o=>c.resolve(o.sourceRoot)===c.resolve(t));if(i)return i}const a=s.find(i=>i.provenance==="builtin")??s[0];if(!a)throw new ToolkitError(`Toolkit pack not found: ${e}`,"not-found");return a}async computeEnabled(e,t){const s=[],a=await this.readRecordHealed(e.path,t.id);if((await R(e.path,t)).length>0){let i=!!a;if(a){for(const o of Object.keys(a.files))if(!await T(c.join(e.path,...o.split("/")))){i=!1;break}}s.push(i)}if(f(t)&&t.targets.includes("claude")){const i=this.pluginSurface(),o=m(t.dir);s.push(await i.isInstalled(t.name,o)&&await i.readProjectEnabled(e.path,t.name,o))}return t.weavePack&&s.push(_(e,t.id,{states:this.deps.states,defaultEnabled:!1})),s.length>0?s.every(Boolean):!1}async installedScopes(e){const t=(await this.pluginSurface().readInstalled())[e];return!t||t.length===0?void 0:[...new Set(t.map(s=>s.scope??"user"))]}async packInfo(e,t){const s=await this.computeEnabled(e,t),a=m(t.dir),i=f(t)&&t.targets.includes("claude")?this.pluginSurface().pluginKey(t.name,a):void 0,o=i?await this.installedScopes(i):void 0,n={...t,...a?{namespace:a}:{},enabled:s,installed:await this.computeInstalled(e,t,s),...i?{key:i}:{},...o&&o.length>0?{scopes:o}:{}};if(t.weavePack){const l=this.deps.plugins.list().find(u=>u.id===t.id);l&&(n.weave={status:l.status,ruleCount:l.ruleCount,...l.error?{error:l.error}:{}})}return n}async computeInstalled(e,t,s){return t.weavePack&&!f(t)?!0:f(t)&&t.targets.includes("claude")?this.pluginSurface().isInstalled(t.name,m(t.dir)):s||!!await this.readRecordHealed(e.path,t.id)}enabledIndex(e){const t=this.deps.projects.getMeta(e.id)?.toolkit,s=t&&typeof t=="object"?t.enabled:void 0;return Array.isArray(s)?s.filter(a=>typeof a=="string"):[]}rememberEnabled(e,t,s){const a=new Set(this.enabledIndex(e));s?a.add(t):a.delete(t),this.deps.projects.setMeta(e.id,{toolkit:{enabled:[...a].sort()}})}async healMeta(e,t){const s=[...new Set(t.filter(n=>n.enabled).map(n=>n.id))].sort(),a=[...new Set(this.enabledIndex(e))].sort(),i=new Set(t.map(n=>n.id)),o=[...new Set([...a.filter(n=>!i.has(n)),...s])].sort();o.join(`
3
- `)!==a.join(`
4
- `)&&this.deps.projects.setMeta(e.id,{toolkit:{enabled:o}})}pluginSurface(){return this.deps.pluginSurface??q("claude")}async readRecordHealed(e,t){const s=E(e,t),a=await v(s);if(!a)return null;const i=j(c.relative(e,this.pluginSurface().projectPluginDir(e))),o=Object.keys(a.files).filter(l=>l.startsWith(`${i}/`));if(o.length===0)return a;const n=[];for(const l of o){const u=c.join(e,...l.split("/"));await k(u)===a.files[l]&&(await w(u,{force:!0}),n.push(l)),delete a.files[l]}return await B(e,n),await x(s,JSON.stringify(a,null,2)+`
5
- `,"utf8"),a}async scanLegacyCopies(e){const t=this.pluginSurface().projectPluginDir(e.path);let s;try{s=await h(t,{withFileTypes:!0})}catch{return[]}return s.map(a=>j(c.relative(e.path,c.join(t,a.name)))).sort()}async cleanupLegacyCopies(e){const t=this.requireProject(e),s=this.pluginSurface().projectPluginDir(t.path);let a;try{a=await h(s,{withFileTypes:!0})}catch{return{removed:[]}}const i=[];for(const o of a){const n=c.join(s,o.name);await w(n,{recursive:!0,force:!0}),i.push(j(c.relative(t.path,n)))}try{(await h(s)).length===0&&await w(s,{recursive:!0,force:!0})}catch{}return{removed:i.sort()}}}
1
+ import{cp as I,mkdir as P,readFile as T,readdir as h,rm as w,writeFile as F}from"node:fs/promises";import{spawn as S}from"node:child_process";import{homedir as H}from"node:os";import c from"node:path";import{hashFile as y}from"../install/fingerprint.js";import{fileAssetTargetDir as L}from"../install/file-assets.js";import{assetSurfaceFor as N,pluginSurfaceFor as $}from"../surfaces.js";import{marketLibraryRoots as q}from"../market/resolve.js";import{marketIdOf as m}from"../market/identity.js";import{installPluginPack as A}from"../install/plugin-install.js";import{effective as V,setProjectEnabled as O}from"./plugin-project-state.js";import{builtinToolkitRoot as K,discoverToolkitPacks as B}from"./toolkit-scan.js";export class ToolkitError extends Error{code;constructor(t,e){super(t),this.code=e,this.name="ToolkitError"}}export const MIN_MOD_HOST_VERSION=[2,1,287];const W=1e4;export function isVersionAtLeast(a,t){const e=a.split(".").map(s=>Number.parseInt(s,10));for(let s=0;s<t.length;s++){const n=Number.isFinite(e[s])?e[s]:0;if(n>t[s])return!0;if(n<t[s])return!1}return!0}let b;function J(a){if(!(a.exitCode!==null||a.signalCode!==null)){if(process.platform==="win32"&&a.pid!==void 0){S("taskkill",["/pid",String(a.pid),"/t","/f"],{windowsHide:!0,stdio:"ignore"}).unref();return}a.kill("SIGKILL")}}export async function detectClaudeVersion(){if(b&&Date.now()-b.at<6e5)return b.value;const a=await new Promise(t=>{let e="";const s=process.platform==="win32"?S("claude --version",{windowsHide:!0,shell:!0,stdio:["ignore","pipe","pipe"]}):S("claude",["--version"],{windowsHide:!0,stdio:["ignore","pipe","pipe"]}),n=setTimeout(()=>{J(s),t(null)},5e3);s.stdout?.on("data",i=>e+=i.toString()),s.on("error",()=>{clearTimeout(n),t(null)}),s.on("close",()=>{clearTimeout(n);const i=/(\d+\.\d+\.\d+)/.exec(e);t(i?i[1]:null)})});return a!==null&&(b={value:a,at:Date.now()}),a}async function C(a,t,e){let s;try{s=await h(c.join(a,...t.split("/").filter(Boolean)),{withFileTypes:!0})}catch{return}for(const n of s){if(n.name==="node_modules"||n.name===".git")continue;const i=t?`${t}/${n.name}`:n.name;n.isDirectory()?await C(a,i,e):e.push({rel:i,abs:c.join(a,...i.split("/"))})}}const p=a=>a.ccPack||a.kind==="mod";async function R(a,t){const e=[];if(t.skills.length>0)for(const s of t.targets){if(s==="claude"&&p(t))continue;const n=N(s).projectSkillsDir();for(const i of t.skills){const o=[];await C(c.join(t.dir,"skills",i),"",o);for(const r of o)e.push({src:r.abs,rel:`${n}/${i}/${r.rel}`})}}if(!p(t))for(const s of t.targets)for(const[n,i]of[["commands","command"],["agents","agent"]]){const o=c.join(t.dir,n),r=[];if(await C(o,"",r),r.length===0)continue;const l=G(i,s,a);if(l)for(const u of r){const g=u.rel.split("/").pop();e.push({src:u.abs,rel:v(c.relative(a,c.join(l,g)))})}}return e}function G(a,t,e){try{return L(a,t,"project",e,H())}catch{return null}}function v(a){return a.split(c.sep).join("/")}function x(a,t){return c.join(a,".weave","toolkit",`${t}.json`)}async function k(a){try{const t=JSON.parse(await T(a,"utf8"));return t&&typeof t=="object"&&typeof t.packId=="string"?t:null}catch{return null}}export async function projectFileNamespaces(a){const t=new Map,e=c.join(a,".weave","toolkit");let s;try{s=await h(e)}catch{return t}for(const n of s){if(!n.endsWith(".json"))continue;const i=await k(c.join(e,n)),o=i?m(i.sourceDir):void 0;if(!(!i||!o))for(const r of Object.keys(i.files))t.set(r,o)}return t}export async function projectPackFiles(a){const t=new Map,e=c.join(a,".weave","toolkit");let s;try{s=await h(e)}catch{return t}for(const n of s){if(!n.endsWith(".json"))continue;const i=await k(c.join(e,n));if(i)for(const[o,r]of Object.entries(i.files))typeof r=="string"&&t.set(o,r)}return t}async function M(a){try{return await T(a),!0}catch{return!1}}async function _(a,t){const e=new Set;for(const n of t){let i=c.posix.dirname(n);for(;i&&i!=="."&&i!=="/";)e.add(i),i=c.posix.dirname(i)}const s=[...e].sort((n,i)=>i.split("/").length-n.split("/").length);for(const n of s){const i=c.join(a,...n.split("/"));try{(await h(i)).length===0&&await w(i,{recursive:!0,force:!0})}catch{}}}export function evaluateModHostGate(a){return process.env.WEAVE_SKIP_MOD_VERSION_CHECK==="1"?{ok:!0}:a?isVersionAtLeast(a,MIN_MOD_HOST_VERSION)?{ok:!0}:{ok:!1,message:`\u5BBF\u4E3B Claude Code ${a} \u4F4E\u4E8E 2.1.287\uFF0Cmod \u5DE5\u5177\u5305\u4E0D\u843D\u76D8\uFF08\u8BF7\u5148\u5347\u7EA7 Claude Code\uFF09`}:{ok:!0,warning:"\u65E0\u6CD5\u68C0\u6D4B\u5BBF\u4E3B Claude Code \u7248\u672C\uFF0Cmod \u5DE5\u5177\u5305\u9700\u8981 \u2265 2.1.287 \u624D\u80FD\u88AB\u52A0\u8F7D"}}export class ToolkitService{deps;packsCache;constructor(t){this.deps=t}sources(){const e=[{root:this.deps.builtinRoot??K(),provenance:"builtin"}];if(this.deps.libraries)for(const n of q(this.deps.libraries))e.push({root:n,provenance:"market"});const s=new Set;return e.filter(n=>{const i=c.resolve(n.root);return s.has(i)?!1:(s.add(i),!0)})}async allPacks(){const t=this.sources(),e=t.map(r=>c.resolve(r.root)).join("|"),s=Date.now(),n=this.packsCache;if(n&&n.key===e&&s-n.at<W)return n.packs;const i=Promise.all(t.map(r=>B(r))).then(r=>r.flat()),o={at:s,key:e,packs:i};return this.packsCache=o,i.catch(()=>{this.packsCache===o&&(this.packsCache=void 0)}),i}async list(t){const e=this.requireProject(t),s=await this.allPacks(),n=await Promise.all(s.map(i=>this.packInfo(e,i)));return await this.healMeta(e,n),{packs:n,legacyCopies:await this.scanLegacyCopies(e)}}async enable(t,e,s){const n=this.requireProject(t),i=await this.resolvePack(e,s),o=[];if(i.kind==="mod"&&i.targets.includes("claude")){const d=this.deps.claudeVersion??detectClaudeVersion,f=evaluateModHostGate(await d());if(!f.ok)throw new ToolkitError(f.message??"mod host gate","host-version");f.warning&&o.push(f.warning)}const r=n.path;if(p(i)&&i.targets.includes("claude")){const d=this.pluginSurface();await A(d,i),await d.setProjectEnabled(r,i.name,!0,m(i.dir))}const u=x(r,i.id),g=await this.readRecordHealed(r,i.id),j=g??{packId:i.id,provenance:i.provenance,sourceRoot:i.sourceRoot,sourceDir:i.dir,enabledAt:new Date().toISOString(),files:{}};let D=g===null;const E=await R(r,i);for(const d of E){const f=c.join(r,...d.rel.split("/"));if(j.files[d.rel]!==void 0){await M(f)||(await P(c.dirname(f),{recursive:!0}),await I(d.src,f));continue}await y(f)==="missing"&&(await P(c.dirname(f),{recursive:!0}),await I(d.src,f),j.files[d.rel]=await y(d.src),D=!0)}return E.length>0?D&&(await P(c.dirname(u),{recursive:!0}),await F(u,JSON.stringify(j,null,2)+`
2
+ `,"utf8")):g&&await w(u,{force:!0}),i.weavePack&&O(n,i.id,!0,{projects:this.deps.projects}),this.rememberEnabled(n,i.id,!0),{pack:await this.packInfo(this.requireProject(t),i),warnings:o}}async disable(t,e,s){const n=this.requireProject(t),i=await this.resolvePack(e,s);return await this.applyDisabled(n,i),{pack:await this.packInfo(this.requireProject(t),i),warnings:[]}}async applyDisabled(t,e){await this.removePackFiles(t,e,e.sourceRoot),p(e)&&e.targets.includes("claude")&&await this.pluginSurface().setProjectEnabled(t.path,e.name,!1,m(e.dir)),e.weavePack&&O(t,e.id,!1,{projects:this.deps.projects}),this.rememberEnabled(t,e.id,!1)}async uninstall(t,e,s){const n=this.requireProject(t),i=await this.resolvePack(e,s);return await this.applyDisabled(n,i),p(i)&&i.targets.includes("claude")&&await this.pluginSurface().uninstall(i.name,m(i.dir)),{pack:await this.packInfo(this.requireProject(t),i),warnings:[]}}async removePackFiles(t,e,s){const n=x(t.path,e.id),i=await k(n);if(!i||s&&c.resolve(i.sourceRoot)!==c.resolve(s))return;const o=[];for(const[r,l]of Object.entries(i.files)){const u=c.join(t.path,...r.split("/"));await y(u)===l&&(await w(u,{force:!0}),o.push(r))}await w(n,{force:!0}),await _(t.path,o)}requireProject(t){const e=this.deps.projects.getById(t);if(!e)throw new ToolkitError(`Project not found: ${t}`,"not-found");return e}async resolvePack(t,e){this.packsCache=void 0;const s=(await this.allPacks()).filter(o=>o.id===t);if(e){const o=s.find(r=>c.resolve(r.sourceRoot)===c.resolve(e));if(o)return o}const i=s.find(o=>o.provenance==="builtin")??s[0];if(!i)throw new ToolkitError(`Toolkit pack not found: ${t}`,"not-found");return i}async computeEnabled(t,e){const s=[],n=await this.readRecordHealed(t.path,e.id);if((await R(t.path,e)).length>0){let o=!!n;if(n){for(const r of Object.keys(n.files))if(!await M(c.join(t.path,...r.split("/")))){o=!1;break}}s.push(o)}if(p(e)&&e.targets.includes("claude")){const o=this.pluginSurface(),r=m(e.dir);s.push(await o.isInstalled(e.name,r)&&await o.readProjectEnabled(t.path,e.name,r))}return e.weavePack&&s.push(V(t,e.id,{states:this.deps.states,defaultEnabled:!1})),s.length>0?s.every(Boolean):!1}async installedScopes(t){const e=(await this.pluginSurface().readInstalled())[t];return!e||e.length===0?void 0:[...new Set(e.map(n=>n.scope??"user"))]}async packInfo(t,e){const s=await this.computeEnabled(t,e),n=m(e.dir),i=p(e)&&e.targets.includes("claude")?this.pluginSurface().pluginKey(e.name,n):void 0,o=i?await this.installedScopes(i):void 0,r={...e,...n?{namespace:n}:{},enabled:s,installed:await this.computeInstalled(t,e,s),...i?{key:i}:{},...o&&o.length>0?{scopes:o}:{}};if(e.weavePack){const l=this.deps.plugins.list().find(u=>u.id===e.id);l&&(r.weave={status:l.status,ruleCount:l.ruleCount,...l.error?{error:l.error}:{}})}return r}async computeInstalled(t,e,s){return e.weavePack&&!p(e)?!0:p(e)&&e.targets.includes("claude")?this.pluginSurface().isInstalled(e.name,m(e.dir)):s||!!await this.readRecordHealed(t.path,e.id)}enabledIndex(t){const s=this.deps.projects.getMeta(t.id)?.toolkit,n=s&&typeof s=="object"?s.enabled:void 0;return Array.isArray(n)?n.filter(i=>typeof i=="string"):[]}rememberEnabled(t,e,s){const n=new Set(this.enabledIndex(t));s?n.add(e):n.delete(e),this.deps.projects.setMeta(t.id,{toolkit:{enabled:[...n].sort()}})}async healMeta(t,e){const s=[...new Set(e.filter(r=>r.enabled).map(r=>r.id))].sort(),n=[...new Set(this.enabledIndex(t))].sort(),i=new Set(e.map(r=>r.id)),o=[...new Set([...n.filter(r=>!i.has(r)),...s])].sort();o.join(`
3
+ `)!==n.join(`
4
+ `)&&this.deps.projects.setMeta(t.id,{toolkit:{enabled:o}})}pluginSurface(){return this.deps.pluginSurface??$("claude")}async readRecordHealed(t,e){const s=x(t,e),n=await k(s);if(!n)return null;const i=v(c.relative(t,this.pluginSurface().projectPluginDir(t))),o=Object.keys(n.files).filter(l=>l.startsWith(`${i}/`));if(o.length===0)return n;const r=[];for(const l of o){const u=c.join(t,...l.split("/"));await y(u)===n.files[l]&&(await w(u,{force:!0}),r.push(l)),delete n.files[l]}return await _(t,r),await F(s,JSON.stringify(n,null,2)+`
5
+ `,"utf8"),n}async scanLegacyCopies(t){const e=this.pluginSurface().projectPluginDir(t.path);let s;try{s=await h(e,{withFileTypes:!0})}catch{return[]}return s.map(n=>v(c.relative(t.path,c.join(e,n.name)))).sort()}async cleanupLegacyCopies(t){const e=this.requireProject(t),s=this.pluginSurface().projectPluginDir(e.path);let n;try{n=await h(s,{withFileTypes:!0})}catch{return{removed:[]}}const i=[];for(const o of n){const r=c.join(s,o.name);await w(r,{recursive:!0,force:!0}),i.push(v(c.relative(e.path,r)))}try{(await h(s)).length===0&&await w(s,{recursive:!0,force:!0})}catch{}return{removed:i.sort()}}}
@@ -61,6 +61,13 @@ export declare class WatchEngine {
61
61
  * terminated 补射:全部 pending 订阅里,目标已判死(claude 注册表 pidAlive
62
62
  * false;目标行已消失 = 等待永不可解)的补 fire。判不动(null)不猜——
63
63
  * 会话可能只是安静。返回补射数(可反复调用,已 fire 的自然不在 pending)。
64
+ *
65
+ * 只补计数订阅:补射是为了找回「离线期间错过的那一次」转场,计数订阅 fire
66
+ * 即落定(consumeHit 减到 0),tick 反复扫也幂等。持久化订阅(remaining
67
+ * null)没有「那一次」,且 consumeHit 永不落定——放在这里就是每 5 分钟给
68
+ * 已终止的会话补一记「已空闲」,toast/浏览器通知/Web Push 三腿齐发刷屏
69
+ * (实机见三条 pending 齐刷)。已终止的会话不会再有转场;目标被 resume 后
70
+ * 的真实事件会自己来。
64
71
  */
65
72
  sweepTerminated(): number;
66
73
  /**
@@ -1 +1 @@
1
- import{HARNESS_LIFECYCLE as r}from"@weavecode/core";import{messagingSurfaceFor as a}from"../surfaces.js";import{claudeLivenessById as c,pidAliveOf as l}from"../daemon/claude-liveness.js";const u=1e3;export class WatchEngine{deps;lastHitAt=new Map;constructor(s){this.deps=s,s.bus.subscribe(e=>this.onBus(e))}onEvent(s){try{const e=(this.deps.surfaceFor?.(s.source)??a(s.source)).idleSignals.includes(s.eventType),i=r[s.source].close.includes(s.eventType);if(!e&&!i)return;for(const t of this.deps.watches.listPendingByTarget(s.sessionId))i&&t.onEvents.includes("turnEnd")?this.fire(t,"turnEnd"):e&&t.onEvents.includes("idle")&&this.fire(t,"idle")}catch{}}onBus(s){if(s.kind==="message.finished"&&!(s.status!=="failed"&&s.status!=="timeout"))try{for(const e of this.deps.watches.listPendingByTarget(s.sessionId))e.onEvents.includes("messageFailed")&&this.fire(e,"messageFailed")}catch{}}created(s){try{if(!s.onEvents.includes("idle")&&!s.onEvents.includes("turnEnd"))return;this.deps.sessions.turnOpenOf(s.targetSessionId)===!1&&this.fire(s,s.onEvents.includes("idle")?"idle":"turnEnd")}catch{}}sweepTerminated(){try{const s=this.deps.livenessOf?.()??c(),e=new Map(this.deps.sessions.listWithCounts().map(t=>[t.sessionId,t]));let i=0;for(const t of this.deps.watches.listPending()){if(!t.onEvents.includes("idle")&&!t.onEvents.includes("turnEnd"))continue;const n=e.get(t.targetSessionId);n&&l(n,s)!==!1||this.fire(t,"idle")&&i++}return i}catch{return 0}}fire(s,e){const i=Date.now(),t=this.lastHitAt.get(s.id);if(t!==void 0&&i-t<u)return!1;const n=this.deps.watches.consumeHit(s.id);if(!n)return!1;this.lastHitAt.set(s.id,i),n.firedAt!==null&&this.lastHitAt.delete(s.id);const o=new Date(i).toISOString();return this.deps.bus.emit({kind:"watch.fired",watchId:s.id,targetSessionId:s.targetSessionId,watcherSessionId:s.watcherSessionId,reason:e,at:o}),s.watcherSessionId==null||this.deps.deliverer.send({toSessionId:s.watcherSessionId,text:s.notify??this.defaultNotify(s.targetSessionId,e),fromKind:"session",fromSessionId:s.targetSessionId,mode:"inject"}).catch(()=>{}),!0}defaultNotify(s,e){return`Session ${this.deps.sessions.getBySessionId(s)?.title??s.slice(0,8)} ${watchReasonPhrase(e)} (trigger=watch:${s})`}}export function watchReasonPhrase(d){return d==="messageFailed"?"had a failed message delivery":d==="turnEnd"?"finished its turn":"is now idle"}
1
+ import{HARNESS_LIFECYCLE as o}from"@weavecode/core";import{messagingSurfaceFor as c}from"../surfaces.js";import{claudeLivenessById as a,pidAliveOf as l}from"../daemon/claude-liveness.js";const f=1e3;export class WatchEngine{deps;lastHitAt=new Map;constructor(e){this.deps=e,e.bus.subscribe(t=>this.onBus(t))}onEvent(e){try{const i=(this.deps.surfaceFor?.(e.source)??c(e.source)).idleSignals.includes(e.eventType),n=o[e.source].close.includes(e.eventType);if(!i&&!n)return;for(const d of this.deps.watches.listPendingByTarget(e.sessionId))n&&d.onEvents.includes("turnEnd")?this.fire(d,"turnEnd"):i&&d.onEvents.includes("idle")&&this.fire(d,"idle")}catch{}}onBus(e){if(e.kind==="message.finished"&&!(e.status!=="failed"&&e.status!=="timeout"))try{for(const t of this.deps.watches.listPendingByTarget(e.sessionId))t.onEvents.includes("messageFailed")&&this.fire(t,"messageFailed")}catch{}}created(e){try{if(!e.onEvents.includes("idle")&&!e.onEvents.includes("turnEnd"))return;this.deps.sessions.turnOpenOf(e.targetSessionId)===!1&&this.fire(e,e.onEvents.includes("idle")?"idle":"turnEnd")}catch{}}sweepTerminated(){try{const e=this.deps.livenessOf?.()??a(),t=new Map(this.deps.sessions.listWithCounts().map(s=>[s.sessionId,s]));let i=0;for(const s of this.deps.watches.listPending()){if(s.remaining===null||!s.onEvents.includes("idle")&&!s.onEvents.includes("turnEnd"))continue;const n=t.get(s.targetSessionId);n&&l(n,e)!==!1||this.fire(s,"idle")&&i++}return i}catch{return 0}}fire(e,t){const i=Date.now(),s=this.lastHitAt.get(e.id);if(s!==void 0&&i-s<f)return!1;const n=this.deps.watches.consumeHit(e.id);if(!n)return!1;this.lastHitAt.set(e.id,i),n.firedAt!==null&&this.lastHitAt.delete(e.id);const d=new Date(i).toISOString();return this.deps.bus.emit({kind:"watch.fired",watchId:e.id,targetSessionId:e.targetSessionId,watcherSessionId:e.watcherSessionId,reason:t,at:d}),e.watcherSessionId==null||this.deps.deliverer.send({toSessionId:e.watcherSessionId,text:e.notify??this.defaultNotify(e.targetSessionId,t),fromKind:"session",fromSessionId:e.targetSessionId,mode:"inject"}).catch(()=>{}),!0}defaultNotify(e,t){return`Session ${this.deps.sessions.getBySessionId(e)?.title??e.slice(0,8)} ${watchReasonPhrase(t)} (trigger=watch:${e})`}}export function watchReasonPhrase(r){return r==="messageFailed"?"had a failed message delivery":r==="turnEnd"?"finished its turn":"is now idle"}
@@ -60,7 +60,7 @@ export { hashSkillDir, maxMtimeDir, hashMcpConfig, hashFile, FingerprintCache }
60
60
  export type { FingerprintCacheEntry } from './install/fingerprint.js';
61
61
  export { projectFileNamespaces, projectPackFiles } from './hooks/toolkit.js';
62
62
  export { detectUpdates, detectSkillUpdates, detectFileAssetUpdates, detectProjectUpdateCounts, } from './install/updates.js';
63
- export type { SkillUpdate, McpUpdate, FileAssetUpdate, UpdateReport } from './install/updates.js';
63
+ export type { SkillUpdate, McpUpdate, FileAssetUpdate, UpdateReport, ProjectUpdateSummary, } from './install/updates.js';
64
64
  export { detectPluginTemplateUpdates } from './install/plugin-templates.js';
65
65
  export type { PluginTemplateUpdate, PluginTemplateCategory } from './install/plugin-templates.js';
66
66
  export { readProjectFile, resolveProjectFile, PathEscapeError, FileTooLargeError, } from './install/reader.js';
@@ -17,7 +17,7 @@ import type { LibraryRow } from '../repositories/libraries.js';
17
17
  * file assets → the kind's project dir (see file-assets.ts)
18
18
  */
19
19
  export interface ApplyUpdateInput {
20
- category: 'skill' | 'mcp' | 'command' | 'agent' | 'workflow' | 'rule' | 'output-style';
20
+ category: 'skill' | 'mcp' | 'command' | 'agent' | 'workflow' | 'rule' | 'output-style' | 'init';
21
21
  name: string;
22
22
  scope: 'project' | 'user';
23
23
  /** Which agent's surface to refresh (skills + codex MCP matter). */
@@ -1 +1 @@
1
- import{rm as l,cp as u,mkdir as w}from"node:fs/promises";import{homedir as g}from"node:os";import p from"node:path";import{installMcp as d,uninstallMcp as S}from"./installer.js";import{writeGlobalMcpServer as h}from"./global-config.js";import{writeCodexMcpServer as k}from"./codex-toml.js";import{applyStatuslineConfig as b}from"../statusline/manager.js";import{readStatuslineConfig as x}from"../statusline/manager.js";import{buildLibraryIndex as f,findSkillSource as C,findMcpSource as E,findFileAssetSource as M}from"./library-index.js";import{detectUpdates as $}from"./updates.js";import{materializePluginTemplate as v}from"./plugin-templates.js";import{FILE_ASSET_SPECS as A,fileAssetTargetDir as j,isFileAssetCategory as F}from"./file-assets.js";import{assetSurfaceFor as y}from"../surfaces.js";export async function applyUpdate(t,a,m,c){const s=m??(c?await f(c):await f([])),o=a.agent??"claude";if(a.category==="skill"){const e=C(s,a.name);if(!e)throw new Error(`No library source for skill "${a.name}"`);const n=a.scope==="user"?y(o).globalSkillsRoots(g())[0]:p.join(t,...y(o).projectSkillsDir().split("/")),i=p.join(n,a.name);await l(i,{recursive:!0,force:!0}),await u(e.dirPath,i,{recursive:!0});return}if(F(a.category)){const e=M(s,a.category,a.name);if(!e)throw new Error(`No library source for ${a.category} "${a.name}"`);const n=j(a.category,o,a.scope,t,g());await w(n,{recursive:!0});const i=p.join(n,`${a.name}${A[a.category].ext}`);await l(i,{force:!0}),await u(e.filePath,i);return}const r=E(s,a.name);if(!r)throw new Error(`No library source for MCP "${a.name}"`);if(o==="codex"){await k(a.name,r.config);return}if(a.scope==="user")await h(a.name,r.config);else{try{await S(t,a.name)}catch{}await d(t,a.name,r.config)}}export async function syncAll(t,a,m,c){const s=c??await f(a),o=await $(t,a,m,s),r=[];for(const e of o.skills)e.custom||!e.outdated||(await applyUpdate(t,{category:"skill",name:e.name,scope:e.scope,agent:e.agent},s),r.push({category:"skill",name:e.name,scope:e.scope,agent:e.agent}));for(const e of o.mcp)e.custom||!e.outdated||(await applyUpdate(t,{category:"mcp",name:e.name,scope:e.scope,agent:e.agent},s),r.push({category:"mcp",name:e.name,scope:e.scope,agent:e.agent}));for(const e of o.files)e.custom||!e.outdated||(await applyUpdate(t,{category:e.category,name:e.name,scope:e.scope},s),r.push({category:e.category,name:e.name,scope:e.scope}));for(const e of o.pluginTemplates)e.outdated&&(await v(e),r.push({category:e.category,name:e.name,scope:"project"}));return{updated:r,skipped:0}}export async function refreshStatusline(t){const a=await x(t);await b(t,a)}
1
+ import{rm as u,cp as y,mkdir as d}from"node:fs/promises";import{homedir as f}from"node:os";import l from"node:path";import{applyStatuslineConfig as w}from"../statusline/manager.js";import{readStatuslineConfig as S}from"../statusline/manager.js";import{buildLibraryIndex as g,findSkillSource as k,findMcpSource as h,findFileAssetSource as x}from"./library-index.js";import{detectUpdates as E}from"./updates.js";import{materializePluginTemplate as F}from"./plugin-templates.js";import{applyInitFile as $}from"./init-files.js";import{FILE_ASSET_SPECS as A,fileAssetTargetDir as C,isFileAssetCategory as b}from"./file-assets.js";import{assetSurfaceFor as p}from"../surfaces.js";export async function applyUpdate(t,o,m,i){const c=m??(i?await g(i):await g([])),a=o.agent??"claude";if(o.category==="skill"){const e=k(c,o.name);if(!e)throw new Error(`No library source for skill "${o.name}"`);const n=o.scope==="user"?p(a).globalSkillsRoots(f())[0]:l.join(t,...p(a).projectSkillsDir().split("/")),s=l.join(n,o.name);await u(s,{recursive:!0,force:!0}),await y(e.dirPath,s,{recursive:!0});return}if(b(o.category)){const e=x(c,o.category,o.name);if(!e)throw new Error(`No library source for ${o.category} "${o.name}"`);const n=C(o.category,a,o.scope,t,f());await d(n,{recursive:!0});const s=l.join(n,`${o.name}${A[o.category].ext}`);await u(s,{force:!0}),await y(e.filePath,s);return}const r=h(c,o.name);if(!r)throw new Error(`No library source for MCP "${o.name}"`);await p(a).mcpWrite(o.scope,t,f(),o.name,r.config)}export async function syncAll(t,o,m,i){const c=i??await g(o),a=await E(t,o,m,c),r=[];for(const e of a.skills)e.custom||!e.outdated||(await applyUpdate(t,{category:"skill",name:e.name,scope:e.scope,agent:e.agent},c),r.push({category:"skill",name:e.name,scope:e.scope,agent:e.agent}));for(const e of a.mcp)e.custom||!e.outdated||(await applyUpdate(t,{category:"mcp",name:e.name,scope:e.scope,agent:e.agent},c),r.push({category:"mcp",name:e.name,scope:e.scope,agent:e.agent}));for(const e of a.files)e.custom||!e.outdated||(await applyUpdate(t,{category:e.category,name:e.name,scope:e.scope},c),r.push({category:e.category,name:e.name,scope:e.scope}));for(const e of a.pluginTemplates)e.outdated&&(await F(e),r.push({category:e.category,name:e.name,scope:"project"}));for(const e of a.initFiles)await $(e)&&r.push({category:"init",name:e.relPath,scope:"project"});return{updated:r,skipped:0}}export async function refreshStatusline(t){const o=await S(t);await w(t,o)}