@weavecode/weave 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (273) hide show
  1. package/node_modules/@weavecode/cli/dist/cli.js +4 -4
  2. package/node_modules/@weavecode/cli/dist/commands/chpass.js +1 -1
  3. package/node_modules/@weavecode/cli/dist/commands/daemon-auth.js +1 -1
  4. package/node_modules/@weavecode/cli/dist/commands/daemon.js +2 -2
  5. package/node_modules/@weavecode/cli/dist/commands/dashboard.d.ts +0 -2
  6. package/node_modules/@weavecode/cli/dist/commands/dashboard.js +2 -1
  7. package/node_modules/@weavecode/cli/dist/commands/doctor.js +1 -1
  8. package/node_modules/@weavecode/cli/dist/commands/init.js +1 -1
  9. package/node_modules/@weavecode/cli/dist/commands/msg.js +2 -2
  10. package/node_modules/@weavecode/cli/dist/commands/scan.js +1 -1
  11. package/node_modules/@weavecode/cli/dist/commands/status.js +2 -2
  12. package/node_modules/@weavecode/cli/dist/commands/uninstall.js +1 -1
  13. package/node_modules/@weavecode/cli/dist/i18n/dict/en.js +5 -3
  14. package/node_modules/@weavecode/cli/dist/i18n/dict/zh.d.ts +44 -1
  15. package/node_modules/@weavecode/cli/dist/i18n/dict/zh.js +6 -4
  16. package/node_modules/@weavecode/cli/dist/i18n/index.js +1 -1
  17. package/node_modules/@weavecode/cli/dist/i18n/t.js +1 -1
  18. package/node_modules/@weavecode/cli/dist/init/claudemd-gen.js +4 -4
  19. package/node_modules/@weavecode/cli/dist/init/executor.js +3 -3
  20. package/node_modules/@weavecode/cli/dist/init/git-commit.js +2 -2
  21. package/node_modules/@weavecode/cli/dist/init/harnesses/claude.js +7 -7
  22. package/node_modules/@weavecode/cli/dist/init/harnesses/codex.js +1 -1
  23. package/node_modules/@weavecode/cli/dist/init/helpers-gen.d.ts +4 -0
  24. package/node_modules/@weavecode/cli/dist/init/helpers-gen.js +1 -20
  25. package/node_modules/@weavecode/cli/dist/init/instruction-link.js +1 -1
  26. package/node_modules/@weavecode/cli/dist/init/mcp-gen.d.ts +3 -20
  27. package/node_modules/@weavecode/cli/dist/init/mcp-gen.js +1 -1
  28. package/node_modules/@weavecode/cli/dist/init/plugin-templates.js +1 -1
  29. package/node_modules/@weavecode/cli/dist/init/prompt.js +4 -4
  30. package/node_modules/@weavecode/cli/dist/init/settings-gen.d.ts +3 -30
  31. package/node_modules/@weavecode/cli/dist/init/settings-gen.js +1 -1
  32. package/node_modules/@weavecode/cli/dist/init/uninstall.js +6 -6
  33. package/node_modules/@weavecode/cli/dist/init/wiring.js +1 -1
  34. package/node_modules/@weavecode/cli/dist/parser.js +1 -1
  35. package/node_modules/@weavecode/cli/dist/statusline/ansi.js +1 -1
  36. package/node_modules/@weavecode/cli/dist/statusline/mock-input.js +1 -1
  37. package/node_modules/@weavecode/cli/dist/statusline/preview.js +2 -2
  38. package/node_modules/@weavecode/cli/package.json +5 -5
  39. package/node_modules/@weavecode/core/dist/harness-checks.js +1 -1
  40. package/node_modules/@weavecode/core/dist/harness.d.ts +45 -2
  41. package/node_modules/@weavecode/core/dist/harness.js +1 -1
  42. package/node_modules/@weavecode/core/dist/index.d.ts +1 -1
  43. package/node_modules/@weavecode/core/dist/index.js +1 -1
  44. package/node_modules/@weavecode/core/dist/platform.js +1 -1
  45. package/node_modules/@weavecode/core/dist/terminal.d.ts +28 -4
  46. package/node_modules/@weavecode/core/dist/terminal.js +1 -1
  47. package/node_modules/@weavecode/core/dist/types.d.ts +188 -11
  48. package/node_modules/@weavecode/core/dist/types.js +1 -1
  49. package/node_modules/@weavecode/core/dist/utils/fs.js +1 -1
  50. package/node_modules/@weavecode/core/dist/utils/logger.js +1 -1
  51. package/node_modules/@weavecode/core/package.json +1 -1
  52. package/node_modules/@weavecode/harness/dist/claude/assets.js +1 -1
  53. package/node_modules/@weavecode/harness/dist/claude/capture.d.ts +11 -1
  54. package/node_modules/@weavecode/harness/dist/claude/capture.js +5 -5
  55. package/node_modules/@weavecode/harness/dist/claude/detect.js +1 -1
  56. package/node_modules/@weavecode/harness/dist/claude/event-source.d.ts +1 -1
  57. package/node_modules/@weavecode/harness/dist/claude/event-source.js +1 -1
  58. package/node_modules/@weavecode/harness/dist/claude/helpers-gen.d.ts +5 -0
  59. package/node_modules/@weavecode/harness/dist/claude/helpers-gen.js +20 -0
  60. package/node_modules/@weavecode/harness/dist/claude/index.d.ts +5 -1
  61. package/node_modules/@weavecode/harness/dist/claude/index.js +1 -1
  62. package/node_modules/@weavecode/harness/dist/claude/mcp-gen.d.ts +22 -0
  63. package/node_modules/@weavecode/harness/dist/claude/mcp-gen.js +1 -0
  64. package/node_modules/@weavecode/harness/dist/claude/messaging.d.ts +11 -2
  65. package/node_modules/@weavecode/harness/dist/claude/messaging.js +4 -1
  66. package/node_modules/@weavecode/harness/dist/claude/model-aliases.d.ts +25 -0
  67. package/node_modules/@weavecode/harness/dist/claude/model-aliases.js +1 -0
  68. package/node_modules/@weavecode/harness/dist/claude/peers.js +1 -1
  69. package/node_modules/@weavecode/harness/dist/claude/plugins.js +4 -4
  70. package/node_modules/@weavecode/harness/dist/claude/prompt-inbox.js +1 -1
  71. package/node_modules/@weavecode/harness/dist/claude/prompt.js +3 -3
  72. package/node_modules/@weavecode/harness/dist/claude/questions.js +2 -1
  73. package/node_modules/@weavecode/harness/dist/claude/settings-gen.d.ts +32 -0
  74. package/node_modules/@weavecode/harness/dist/claude/settings-gen.js +1 -0
  75. package/node_modules/@weavecode/harness/dist/claude/transcript.d.ts +16 -0
  76. package/node_modules/@weavecode/harness/dist/claude/transcript.js +4 -2
  77. package/node_modules/@weavecode/harness/dist/codex/assets.js +1 -1
  78. package/node_modules/@weavecode/harness/dist/codex/detect.js +1 -1
  79. package/node_modules/@weavecode/harness/dist/codex/messaging.js +1 -1
  80. package/node_modules/@weavecode/harness/dist/codex/plugin-state.js +1 -1
  81. package/node_modules/@weavecode/harness/dist/codex/toml.js +9 -9
  82. package/node_modules/@weavecode/harness/dist/driver.d.ts +58 -1
  83. package/node_modules/@weavecode/harness/dist/driver.js +1 -1
  84. package/node_modules/@weavecode/harness/dist/index.d.ts +1 -0
  85. package/node_modules/@weavecode/harness/dist/index.js +1 -1
  86. package/node_modules/@weavecode/harness/dist/init/generated.d.ts +37 -0
  87. package/node_modules/@weavecode/harness/dist/init/generated.js +2 -0
  88. package/node_modules/@weavecode/harness/dist/init/pipeline.js +1 -1
  89. package/node_modules/@weavecode/harness/dist/registry-wiring.d.ts +3 -1
  90. package/node_modules/@weavecode/harness/dist/registry-wiring.js +1 -1
  91. package/node_modules/@weavecode/harness/dist/shared/install-link.js +1 -1
  92. package/node_modules/@weavecode/harness/package.json +2 -2
  93. package/node_modules/@weavecode/server/dist/daemon/ai-config.js +2 -2
  94. package/node_modules/@weavecode/server/dist/daemon/ai-context.js +6 -6
  95. package/node_modules/@weavecode/server/dist/daemon/ai-routes.js +4 -4
  96. package/node_modules/@weavecode/server/dist/daemon/api-log.d.ts +48 -0
  97. package/node_modules/@weavecode/server/dist/daemon/api-log.js +3 -0
  98. package/node_modules/@weavecode/server/dist/daemon/auth-routes.js +1 -1
  99. package/node_modules/@weavecode/server/dist/daemon/auto-start.js +6 -6
  100. package/node_modules/@weavecode/server/dist/daemon/capture-routes.js +1 -1
  101. package/node_modules/@weavecode/server/dist/daemon/claude-liveness.js +1 -1
  102. package/node_modules/@weavecode/server/dist/daemon/dashboard-auth.js +2 -2
  103. package/node_modules/@weavecode/server/dist/daemon/data-bus.js +1 -1
  104. package/node_modules/@weavecode/server/dist/daemon/dev-entry.js +1 -1
  105. package/node_modules/@weavecode/server/dist/daemon/fs-browser.js +1 -1
  106. package/node_modules/@weavecode/server/dist/daemon/hook-pipeline.d.ts +6 -1
  107. package/node_modules/@weavecode/server/dist/daemon/hook-pipeline.js +1 -1
  108. package/node_modules/@weavecode/server/dist/daemon/hooks-routes.js +1 -1
  109. package/node_modules/@weavecode/server/dist/daemon/http.js +1 -1
  110. package/node_modules/@weavecode/server/dist/daemon/opener.d.ts +102 -19
  111. package/node_modules/@weavecode/server/dist/daemon/opener.js +97 -7
  112. package/node_modules/@weavecode/server/dist/daemon/port.js +1 -1
  113. package/node_modules/@weavecode/server/dist/daemon/project-harnesses.js +2 -2
  114. package/node_modules/@weavecode/server/dist/daemon/project-updates-refresher.d.ts +4 -3
  115. package/node_modules/@weavecode/server/dist/daemon/project-updates-refresher.js +1 -1
  116. package/node_modules/@weavecode/server/dist/daemon/server.d.ts +8 -0
  117. package/node_modules/@weavecode/server/dist/daemon/server.js +6 -6
  118. package/node_modules/@weavecode/server/dist/daemon/session-probe.d.ts +59 -2
  119. package/node_modules/@weavecode/server/dist/daemon/session-probe.js +1 -1
  120. package/node_modules/@weavecode/server/dist/daemon/settings.d.ts +10 -0
  121. package/node_modules/@weavecode/server/dist/daemon/settings.js +2 -2
  122. package/node_modules/@weavecode/server/dist/daemon/start.js +1 -1
  123. package/node_modules/@weavecode/server/dist/daemon/state.js +2 -2
  124. package/node_modules/@weavecode/server/dist/daemon/static.js +1 -1
  125. package/node_modules/@weavecode/server/dist/daemon/terminal-topology-refresher.d.ts +4 -1
  126. package/node_modules/@weavecode/server/dist/daemon/tls.js +1 -1
  127. package/node_modules/@weavecode/server/dist/daemon/toolkit-routes.js +1 -1
  128. package/node_modules/@weavecode/server/dist/db/db.js +20 -2
  129. package/node_modules/@weavecode/server/dist/db/paths.d.ts +4 -0
  130. package/node_modules/@weavecode/server/dist/db/paths.js +1 -1
  131. package/node_modules/@weavecode/server/dist/hooks/answer-keys.js +1 -1
  132. package/node_modules/@weavecode/server/dist/hooks/bus.js +1 -1
  133. package/node_modules/@weavecode/server/dist/hooks/dispatcher.js +6 -6
  134. package/node_modules/@weavecode/server/dist/hooks/handlers/webhook.js +1 -1
  135. package/node_modules/@weavecode/server/dist/hooks/headless-runner.js +2 -2
  136. package/node_modules/@weavecode/server/dist/hooks/inbox-socket.d.ts +17 -4
  137. package/node_modules/@weavecode/server/dist/hooks/inbox-socket.js +2 -1
  138. package/node_modules/@weavecode/server/dist/hooks/inbox-worker.d.ts +20 -6
  139. package/node_modules/@weavecode/server/dist/hooks/inbox-worker.js +3 -3
  140. package/node_modules/@weavecode/server/dist/hooks/match.js +1 -1
  141. package/node_modules/@weavecode/server/dist/hooks/message-deliverer.d.ts +171 -13
  142. package/node_modules/@weavecode/server/dist/hooks/message-deliverer.js +3 -2
  143. package/node_modules/@weavecode/server/dist/hooks/mirror.js +4 -4
  144. package/node_modules/@weavecode/server/dist/hooks/plugin-installer.js +3 -3
  145. package/node_modules/@weavecode/server/dist/hooks/plugin-loader.js +1 -1
  146. package/node_modules/@weavecode/server/dist/hooks/plugin-project-state.js +1 -1
  147. package/node_modules/@weavecode/server/dist/hooks/prompt-flusher.js +1 -1
  148. package/node_modules/@weavecode/server/dist/hooks/promptbox.d.ts +13 -0
  149. package/node_modules/@weavecode/server/dist/hooks/promptbox.js +8 -8
  150. package/node_modules/@weavecode/server/dist/hooks/push-notify.js +2 -2
  151. package/node_modules/@weavecode/server/dist/hooks/question-tracker.d.ts +6 -4
  152. package/node_modules/@weavecode/server/dist/hooks/question-tracker.js +1 -1
  153. package/node_modules/@weavecode/server/dist/hooks/registry.js +1 -1
  154. package/node_modules/@weavecode/server/dist/hooks/resume-runner.js +1 -1
  155. package/node_modules/@weavecode/server/dist/hooks/sequence-engine.js +1 -1
  156. package/node_modules/@weavecode/server/dist/hooks/session-purge.d.ts +4 -0
  157. package/node_modules/@weavecode/server/dist/hooks/session-purge.js +1 -1
  158. package/node_modules/@weavecode/server/dist/hooks/session-sweeper.d.ts +5 -8
  159. package/node_modules/@weavecode/server/dist/hooks/session-sweeper.js +1 -1
  160. package/node_modules/@weavecode/server/dist/hooks/toolkit-scan.js +1 -1
  161. package/node_modules/@weavecode/server/dist/hooks/toolkit.d.ts +8 -0
  162. package/node_modules/@weavecode/server/dist/hooks/toolkit.js +5 -5
  163. package/node_modules/@weavecode/server/dist/hooks/watch-engine.d.ts +7 -0
  164. package/node_modules/@weavecode/server/dist/hooks/watch-engine.js +1 -1
  165. package/node_modules/@weavecode/server/dist/index.d.ts +1 -1
  166. package/node_modules/@weavecode/server/dist/install/apply-update.d.ts +1 -1
  167. package/node_modules/@weavecode/server/dist/install/apply-update.js +1 -1
  168. package/node_modules/@weavecode/server/dist/install/capabilities.js +1 -1
  169. package/node_modules/@weavecode/server/dist/install/codex-toml.js +1 -1
  170. package/node_modules/@weavecode/server/dist/install/file-assets.js +1 -1
  171. package/node_modules/@weavecode/server/dist/install/fingerprint.d.ts +5 -1
  172. package/node_modules/@weavecode/server/dist/install/fingerprint.js +1 -1
  173. package/node_modules/@weavecode/server/dist/install/git-classify.d.ts +30 -0
  174. package/node_modules/@weavecode/server/dist/install/git-classify.js +1 -0
  175. package/node_modules/@weavecode/server/dist/install/global-config.js +2 -2
  176. package/node_modules/@weavecode/server/dist/install/global-file-assets.js +1 -1
  177. package/node_modules/@weavecode/server/dist/install/init-files.d.ts +46 -0
  178. package/node_modules/@weavecode/server/dist/install/init-files.js +2 -0
  179. package/node_modules/@weavecode/server/dist/install/install-ledger.js +1 -1
  180. package/node_modules/@weavecode/server/dist/install/installer.js +3 -3
  181. package/node_modules/@weavecode/server/dist/install/library-index.js +1 -1
  182. package/node_modules/@weavecode/server/dist/install/mcp-rows.js +1 -1
  183. package/node_modules/@weavecode/server/dist/install/plugin-install.js +1 -1
  184. package/node_modules/@weavecode/server/dist/install/plugin-rows.js +1 -1
  185. package/node_modules/@weavecode/server/dist/install/plugin-templates.js +1 -1
  186. package/node_modules/@weavecode/server/dist/install/project-config.d.ts +0 -2
  187. package/node_modules/@weavecode/server/dist/install/project-config.js +2 -2
  188. package/node_modules/@weavecode/server/dist/install/reader.js +1 -1
  189. package/node_modules/@weavecode/server/dist/install/scan-cache.js +1 -1
  190. package/node_modules/@weavecode/server/dist/install/scanner.js +1 -1
  191. package/node_modules/@weavecode/server/dist/install/settings-mcp.js +2 -2
  192. package/node_modules/@weavecode/server/dist/install/updates.d.ts +17 -5
  193. package/node_modules/@weavecode/server/dist/install/updates.js +1 -1
  194. package/node_modules/@weavecode/server/dist/market/builtin.js +1 -1
  195. package/node_modules/@weavecode/server/dist/market/identity.js +1 -1
  196. package/node_modules/@weavecode/server/dist/market/import.js +2 -2
  197. package/node_modules/@weavecode/server/dist/market/refresh.js +1 -1
  198. package/node_modules/@weavecode/server/dist/market/resolve.js +1 -1
  199. package/node_modules/@weavecode/server/dist/market/updates.js +1 -1
  200. package/node_modules/@weavecode/server/dist/registry.js +2 -2
  201. package/node_modules/@weavecode/server/dist/repositories/hook-dispatches.js +5 -5
  202. package/node_modules/@weavecode/server/dist/repositories/hook-events.js +2 -2
  203. package/node_modules/@weavecode/server/dist/repositories/hook-rules.js +4 -4
  204. package/node_modules/@weavecode/server/dist/repositories/libraries.js +1 -1
  205. package/node_modules/@weavecode/server/dist/repositories/plugin-states.js +1 -1
  206. package/node_modules/@weavecode/server/dist/repositories/projects.d.ts +7 -0
  207. package/node_modules/@weavecode/server/dist/repositories/projects.js +2 -2
  208. package/node_modules/@weavecode/server/dist/repositories/push-subscriptions.js +2 -2
  209. package/node_modules/@weavecode/server/dist/repositories/session-watches.js +4 -4
  210. package/node_modules/@weavecode/server/dist/repositories/sessions.d.ts +17 -4
  211. package/node_modules/@weavecode/server/dist/repositories/sessions.js +2 -2
  212. package/node_modules/@weavecode/server/dist/repositories/uploads.d.ts +66 -0
  213. package/node_modules/@weavecode/server/dist/repositories/uploads.js +7 -0
  214. package/node_modules/@weavecode/server/dist/statusline/cache-sweeper.js +1 -1
  215. package/node_modules/@weavecode/server/dist/statusline/generator.js +81 -40
  216. package/node_modules/@weavecode/server/dist/statusline/manager.d.ts +2 -0
  217. package/node_modules/@weavecode/server/dist/statusline/manager.js +4 -4
  218. package/node_modules/@weavecode/server/dist/surfaces.js +1 -1
  219. package/node_modules/@weavecode/server/dist/watch/cache.js +1 -1
  220. package/node_modules/@weavecode/server/dist/watch/classifier.js +1 -1
  221. package/node_modules/@weavecode/server/dist/watch/plugin-mods.js +1 -1
  222. package/node_modules/@weavecode/server/dist/watch/sync-scheduler.d.ts +8 -4
  223. package/node_modules/@weavecode/server/dist/watch/sync-scheduler.js +1 -1
  224. package/node_modules/@weavecode/server/dist/watch/watch-service.js +1 -1
  225. package/node_modules/@weavecode/server/package.json +4 -4
  226. package/node_modules/@weavecode/server/web/dist/assets/index-D5WFh77i.css +11 -0
  227. package/node_modules/@weavecode/server/web/dist/assets/index-DJibaGnJ.js +585 -0
  228. package/node_modules/@weavecode/server/web/dist/index.html +14 -2
  229. package/node_modules/@weavecode/templates/dist/resources/weave-market/plugins/core-skills/weave-plugin-creator/skills/weave-plugin-creator/SKILL.md +2 -2
  230. package/node_modules/@weavecode/templates/package.json +2 -2
  231. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/README.md +50 -32
  232. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/build/index.d.ts +86 -40
  233. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/build/index.es.js +860 -353
  234. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/build/index.js +860 -353
  235. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-cms/node_modules/asn1js/package.json +20 -17
  236. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/README.md +50 -32
  237. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/build/index.d.ts +86 -40
  238. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/build/index.es.js +860 -353
  239. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/build/index.js +860 -353
  240. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-csr/node_modules/asn1js/package.json +20 -17
  241. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/README.md +50 -32
  242. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/build/index.d.ts +86 -40
  243. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/build/index.es.js +860 -353
  244. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/build/index.js +860 -353
  245. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-ecc/node_modules/asn1js/package.json +20 -17
  246. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/README.md +50 -32
  247. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/build/index.d.ts +86 -40
  248. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/build/index.es.js +860 -353
  249. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/build/index.js +860 -353
  250. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-pkcs9/node_modules/asn1js/package.json +20 -17
  251. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/README.md +50 -32
  252. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/build/index.d.ts +86 -40
  253. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/build/index.es.js +860 -353
  254. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/build/index.js +860 -353
  255. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-rsa/node_modules/asn1js/package.json +20 -17
  256. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/README.md +50 -32
  257. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/build/index.d.ts +86 -40
  258. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/build/index.es.js +860 -353
  259. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/build/index.js +860 -353
  260. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-schema/node_modules/asn1js/package.json +20 -17
  261. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/README.md +50 -32
  262. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/build/index.d.ts +86 -40
  263. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/build/index.es.js +860 -353
  264. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/build/index.js +860 -353
  265. package/node_modules/selfsigned/node_modules/@peculiar/x509/node_modules/@peculiar/asn1-x509/node_modules/asn1js/package.json +20 -17
  266. package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/README.md +50 -32
  267. package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/build/index.d.ts +86 -40
  268. package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/build/index.es.js +860 -353
  269. package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/build/index.js +860 -353
  270. package/node_modules/selfsigned/node_modules/pkijs/node_modules/asn1js/package.json +20 -17
  271. package/package.json +6 -6
  272. package/node_modules/@weavecode/server/web/dist/assets/index-BOzaRlQE.js +0 -560
  273. package/node_modules/@weavecode/server/web/dist/assets/index-ChX8G8cT.css +0 -11
@@ -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(n=>Number.parseInt(n,10));for(let n=0;n<t.length;n++){const s=Number.isFinite(e[n])?e[n]:0;if(s>t[n])return!0;if(s<t[n])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 n=process.platform==="win32"?S("claude --version",{windowsHide:!0,shell:!0,stdio:["ignore","pipe","pipe"]}):S("claude",["--version"],{windowsHide:!0,stdio:["ignore","pipe","pipe"]}),s=setTimeout(()=>{J(n),t(null)},5e3);n.stdout?.on("data",i=>e+=i.toString()),n.on("error",()=>{clearTimeout(s),t(null)}),n.on("close",()=>{clearTimeout(s);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 n;try{n=await h(c.join(a,...t.split("/").filter(Boolean)),{withFileTypes:!0})}catch{return}for(const s of n){if(s.name==="node_modules"||s.name===".git")continue;const i=t?`${t}/${s.name}`:s.name;s.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=[],n=t.targets.includes("claude");if(t.skills.length>0)for(const s of t.targets){if(s==="claude"&&p(t))continue;const i=N(s).projectSkillsDir();for(const o of t.skills){const r=[];await C(c.join(t.dir,"skills",o),"",r);for(const l of r)e.push({src:l.abs,rel:`${i}/${o}/${l.rel}`})}}if(n&&!p(t))for(const[s,i]of[["commands","command"],["agents","agent"]]){const o=c.join(t.dir,s),r=[];if(await C(o,"",r),r.length===0)continue;const l=L(i,"claude","project",a,H());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 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 n;try{n=await h(e)}catch{return t}for(const s of n){if(!s.endsWith(".json"))continue;const i=await k(c.join(e,s)),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 n;try{n=await h(e)}catch{return t}for(const s of n){if(!s.endsWith(".json"))continue;const i=await k(c.join(e,s));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 s of t){let i=c.posix.dirname(s);for(;i&&i!=="."&&i!=="/";)e.add(i),i=c.posix.dirname(i)}const n=[...e].sort((s,i)=>i.split("/").length-s.split("/").length);for(const s of n){const i=c.join(a,...s.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 s of q(this.deps.libraries))e.push({root:s,provenance:"market"});const n=new Set;return e.filter(s=>{const i=c.resolve(s.root);return n.has(i)?!1:(n.add(i),!0)})}async allPacks(){const t=this.sources(),e=t.map(r=>c.resolve(r.root)).join("|"),n=Date.now(),s=this.packsCache;if(s&&s.key===e&&n-s.at<W)return s.packs;const i=Promise.all(t.map(r=>B(r))).then(r=>r.flat()),o={at:n,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),n=await this.allPacks(),s=await Promise.all(n.map(i=>this.packInfo(e,i)));return await this.healMeta(e,s),{packs:s,legacyCopies:await this.scanLegacyCopies(e)}}async enable(t,e,n){const s=this.requireProject(t),i=await this.resolvePack(e,n),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=s.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 E=g===null;const D=await R(r,i);for(const d of D){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),E=!0)}return D.length>0?E&&(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(s,i.id,!0,{projects:this.deps.projects}),this.rememberEnabled(s,i.id,!0),{pack:await this.packInfo(this.requireProject(t),i),warnings:o}}async disable(t,e,n){const s=this.requireProject(t),i=await this.resolvePack(e,n);return await this.applyDisabled(s,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,n){const s=this.requireProject(t),i=await this.resolvePack(e,n);return await this.applyDisabled(s,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,n){const s=x(t.path,e.id),i=await k(s);if(!i||n&&c.resolve(i.sourceRoot)!==c.resolve(n))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(s,{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 n=(await this.allPacks()).filter(o=>o.id===t);if(e){const o=n.find(r=>c.resolve(r.sourceRoot)===c.resolve(e));if(o)return o}const i=n.find(o=>o.provenance==="builtin")??n[0];if(!i)throw new ToolkitError(`Toolkit pack not found: ${t}`,"not-found");return i}async computeEnabled(t,e){const n=[],s=await this.readRecordHealed(t.path,e.id);if((await R(t.path,e)).length>0){let o=!!s;if(s){for(const r of Object.keys(s.files))if(!await M(c.join(t.path,...r.split("/")))){o=!1;break}}n.push(o)}if(p(e)&&e.targets.includes("claude")){const o=this.pluginSurface(),r=m(e.dir);n.push(await o.isInstalled(e.name,r)&&await o.readProjectEnabled(t.path,e.name,r))}return e.weavePack&&n.push(V(t,e.id,{states:this.deps.states,defaultEnabled:!1})),n.length>0?n.every(Boolean):!1}async installedScopes(t){const e=(await this.pluginSurface().readInstalled())[t];return!e||e.length===0?void 0:[...new Set(e.map(s=>s.scope??"user"))]}async packInfo(t,e){const n=await this.computeEnabled(t,e),s=m(e.dir),i=p(e)&&e.targets.includes("claude")?this.pluginSurface().pluginKey(e.name,s):void 0,o=i?await this.installedScopes(i):void 0,r={...e,...s?{namespace:s}:{},enabled:n,installed:await this.computeInstalled(t,e,n),...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,n){return e.weavePack&&!p(e)?!0:p(e)&&e.targets.includes("claude")?this.pluginSurface().isInstalled(e.name,m(e.dir)):n||!!await this.readRecordHealed(t.path,e.id)}enabledIndex(t){const n=this.deps.projects.getMeta(t.id)?.toolkit,s=n&&typeof n=="object"?n.enabled:void 0;return Array.isArray(s)?s.filter(i=>typeof i=="string"):[]}rememberEnabled(t,e,n){const s=new Set(this.enabledIndex(t));n?s.add(e):s.delete(e),this.deps.projects.setMeta(t.id,{toolkit:{enabled:[...s].sort()}})}async healMeta(t,e){const n=[...new Set(e.filter(r=>r.enabled).map(r=>r.id))].sort(),s=[...new Set(this.enabledIndex(t))].sort(),i=new Set(e.map(r=>r.id)),o=[...new Set([...s.filter(r=>!i.has(r)),...n])].sort();o.join(`
3
+ `)!==s.join(`
4
+ `)&&this.deps.projects.setMeta(t.id,{toolkit:{enabled:o}})}pluginSurface(){return this.deps.pluginSurface??$("claude")}async readRecordHealed(t,e){const n=x(t,e),s=await k(n);if(!s)return null;const i=v(c.relative(t,this.pluginSurface().projectPluginDir(t))),o=Object.keys(s.files).filter(l=>l.startsWith(`${i}/`));if(o.length===0)return s;const r=[];for(const l of o){const u=c.join(t,...l.split("/"));await y(u)===s.files[l]&&(await w(u,{force:!0}),r.push(l)),delete s.files[l]}return await _(t,r),await F(n,JSON.stringify(s,null,2)+`
5
+ `,"utf8"),s}async scanLegacyCopies(t){const e=this.pluginSurface().projectPluginDir(t.path);let n;try{n=await h(e,{withFileTypes:!0})}catch{return[]}return n.map(s=>v(c.relative(t.path,c.join(e,s.name)))).sort()}async cleanupLegacyCopies(t){const e=this.requireProject(t),n=this.pluginSurface().projectPluginDir(e.path);let s;try{s=await h(n,{withFileTypes:!0})}catch{return{removed:[]}}const i=[];for(const o of s){const r=c.join(n,o.name);await w(r,{recursive:!0,force:!0}),i.push(v(c.relative(e.path,r)))}try{(await h(n)).length===0&&await w(n,{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 g,cp as p,mkdir as d}from"node:fs/promises";import{homedir as y}from"node:os";import f from"node:path";import{installMcp as w,uninstallMcp as S}from"./installer.js";import{writeGlobalMcpServer as k}from"./global-config.js";import{writeCodexMcpServer as x}from"./codex-toml.js";import{applyStatuslineConfig as h}from"../statusline/manager.js";import{readStatuslineConfig as C}from"../statusline/manager.js";import{buildLibraryIndex as l,findSkillSource as E,findMcpSource as F,findFileAssetSource as M}from"./library-index.js";import{detectUpdates as $}from"./updates.js";import{materializePluginTemplate as b}from"./plugin-templates.js";import{applyInitFile as v}from"./init-files.js";import{FILE_ASSET_SPECS as A,fileAssetTargetDir as D,isFileAssetCategory as T}from"./file-assets.js";import{assetSurfaceFor as u}from"../surfaces.js";export async function applyUpdate(r,o,m,s){const c=m??(s?await l(s):await l([])),t=o.agent??"claude";if(o.category==="skill"){const e=E(c,o.name);if(!e)throw new Error(`No library source for skill "${o.name}"`);const n=o.scope==="user"?u(t).globalSkillsRoots(y())[0]:f.join(r,...u(t).projectSkillsDir().split("/")),i=f.join(n,o.name);await g(i,{recursive:!0,force:!0}),await p(e.dirPath,i,{recursive:!0});return}if(T(o.category)){const e=M(c,o.category,o.name);if(!e)throw new Error(`No library source for ${o.category} "${o.name}"`);const n=D(o.category,t,o.scope,r,y());await d(n,{recursive:!0});const i=f.join(n,`${o.name}${A[o.category].ext}`);await g(i,{force:!0}),await p(e.filePath,i);return}const a=F(c,o.name);if(!a)throw new Error(`No library source for MCP "${o.name}"`);if(t==="codex"){await x(o.name,a.config);return}if(o.scope==="user")await k(o.name,a.config);else{try{await S(r,o.name)}catch{}await w(r,o.name,a.config)}}export async function syncAll(r,o,m,s){const c=s??await l(o),t=await $(r,o,m,c),a=[];for(const e of t.skills)e.custom||!e.outdated||(await applyUpdate(r,{category:"skill",name:e.name,scope:e.scope,agent:e.agent},c),a.push({category:"skill",name:e.name,scope:e.scope,agent:e.agent}));for(const e of t.mcp)e.custom||!e.outdated||(await applyUpdate(r,{category:"mcp",name:e.name,scope:e.scope,agent:e.agent},c),a.push({category:"mcp",name:e.name,scope:e.scope,agent:e.agent}));for(const e of t.files)e.custom||!e.outdated||(await applyUpdate(r,{category:e.category,name:e.name,scope:e.scope},c),a.push({category:e.category,name:e.name,scope:e.scope}));for(const e of t.pluginTemplates)e.outdated&&(await b(e),a.push({category:e.category,name:e.name,scope:"project"}));for(const e of t.initFiles)await v(e)&&a.push({category:"init",name:e.relPath,scope:"project"});return{updated:a,skipped:0}}export async function refreshStatusline(r){const o=await C(r);await h(r,o)}
@@ -1 +1 @@
1
- import i from"node:path";import{homedir as l}from"node:os";import{HARNESS_KEYS as f}from"@weavecode/core";import{FILE_ASSET_SPECS as m,FILE_ASSET_CATEGORIES as S}from"./file-assets.js";import{assetSurfaces as a}from"../surfaces.js";function u(t,c){return i.join("~",i.relative(c,t)).split(i.sep).join("/")}export function installCapabilities(){const t=l(),c={};for(const s of S){const r=m[s].dirs,e=[];for(const o of f){const n=r[o];if(!n)continue;const p=[];n.project&&p.push("project"),n.user&&p.push("user"),p.length>0&&e.push({harness:o,scopes:p})}c[s]={surfaces:e}}return c.skill={surfaces:a().map(s=>{const r=[],e={};s.projectSkillsDir()&&(r.push("project"),e.project=s.projectSkillsDir());const o=s.globalSkillsRoots(t)[0];return o&&(r.push("user"),e.user=u(o,t)),{harness:s.harness,scopes:r,dest:e}})},c.mcp={surfaces:a().map(s=>{const r={},e=s.mcpDest("project",t),o=s.mcpDest("user",t);return e&&(r.project=e),o&&(r.user=u(o,t)),{harness:s.harness,scopes:s.mcpScopes(),dest:r}}).filter(s=>s.scopes.length>0)},{categories:c}}
1
+ import n from"node:path";import{homedir as a}from"node:os";import{HARNESS_KEYS as l}from"@weavecode/core";import{FILE_ASSET_SPECS as m,FILE_ASSET_CATEGORIES as h}from"./file-assets.js";import{assetSurfaces as u}from"../surfaces.js";function f(t,c){return n.join("~",n.relative(c,t)).split(n.sep).join("/")}export function installCapabilities(){const t=a(),c={};for(const s of h){const o=m[s].dirs,r=[];for(const e of l){const p=o[e];if(!p)continue;const i=[];p.project&&i.push("project"),p.user&&i.push("user"),i.length>0&&r.push({harness:e,scopes:i})}c[s]={surfaces:r}}return c.skill={surfaces:u().map(s=>{const o=[],r={};s.projectSkillsDir()&&(o.push("project"),r.project=s.projectSkillsDir());const e=s.globalSkillsRoots(t)[0];return e&&(o.push("user"),r.user=f(e,t)),{harness:s.harness,scopes:o,dest:r}})},c.mcp={surfaces:u().map(s=>{const o={},r=s.mcpDest("project",t),e=s.mcpDest("user",t);return r&&(o.project=r),e&&(o.user=f(e,t)),{harness:s.harness,scopes:s.mcpScopes(),dest:o}}).filter(s=>s.scopes.length>0)},{categories:c}}
@@ -1 +1 @@
1
- import{readFile as p,writeFile as x,access as C,mkdir as M}from"node:fs/promises";import{homedir as $}from"node:os";import b from"node:path";import{parse as m}from"smol-toml";import{assetSurfaceFor as E}from"../surfaces.js";import{CodexTomlCorruptError as l,parseSectionEntries as w,removeTomlSection as j,renderTomlHeader as A,renderTomlKey as F,renderTomlString as d,sameKey as y,splitTomlSections as v,upsertTomlSection as h}from"@weavecode/harness";export{CodexTomlCorruptError,parseDottedKey,sectionHeaderKey,renderTomlKey,renderTomlHeader,renderTomlString,splitTomlSections,upsertTomlSection,removeTomlSection,parseSectionEntries,upsertCodexPluginEnabledInText}from"@weavecode/harness";export function codexConfigFile(r=$()){return S??E("codex").userConfigFile(r)}export function readCodexMcpFromText(r){let e;try{e=m(r)}catch{return{}}const n=e.mcp_servers;if(!n||typeof n!="object"||Array.isArray(n))return{};const t={};for(const[s,o]of Object.entries(n)){const c=O(o);c&&(t[s]=c)}return t}function O(r){if(!r||typeof r!="object"||Array.isArray(r))return null;const e=r;if(typeof e.command!="string")return null;const n={command:e.command};if(Array.isArray(e.args)){const t=e.args.filter(s=>typeof s=="string");t.length>0&&(n.args=t)}if(e.env&&typeof e.env=="object"&&!Array.isArray(e.env)){const t={};for(const[s,o]of Object.entries(e.env))typeof o=="string"&&(t[s]=o);Object.keys(t).length>0&&(n.env=t)}return n}function T(r,e,n,t,s){const o=[`command = ${d(e.command)}`];if(e.args&&e.args.length>0&&o.push(`args = [${e.args.map(d).join(", ")}]`),s&&n){const i=new Set(["command","args","env"]);for(const[a,u]of w(n.lines.slice(1)))i.has(a)||o.push(u)}const c=Object.entries(e.env??{}),f=s&&t?w(t.lines.slice(1)).filter(([i])=>!(i in(e.env??{}))):[];if(c.length>0||f.length>0){o.push(""),o.push(A([...r,"env"]));for(const[i,a]of c)o.push(`${F(i)} = ${d(a)}`);for(const[,i]of f)o.push(i)}return o}export function upsertCodexMcpInText(r,e,n){const t=["mcp_servers",e],s=_(r);if(s)throw s;const o=v(r),c=o.find(a=>y(a.key,t)),f=o.find(a=>y(a.key,[...t,"env"])),i=h(r,t,T(t,n,c,f,!0));try{return m(i),i}catch{const a=h(r,t,T(t,n,c,f,!1));try{return m(a),a}catch(u){throw new l(`unable to produce valid TOML for [mcp_servers.${e}]: ${u instanceof Error?u.message:String(u)}`)}}}export function removeCodexMcpFromText(r,e){return j(r,["mcp_servers",e])}function _(r){return v(r)[0].lines.find(e=>/^\s*mcp_servers\s*=/.test(e))?new l('~/.codex/config.toml defines "mcp_servers" as an inline value \u2014 weave only manages the [mcp_servers.<name>] section form'):null}let S=null;export function setCodexConfigFileOverride(r){S=r}async function k(r){try{return await p(r,"utf-8")}catch{return""}}async function g(r){try{return await C(r),!0}catch{return!1}}export async function readCodexMcpServers(r=codexConfigFile()){return await g(r)?readCodexMcpFromText(await p(r,"utf-8")):{}}export async function codexMcpExists(r,e=codexConfigFile()){return await g(e)?K(await p(e,"utf-8"),["mcp_servers",r]):!1}function K(r,e){return v(r).some(n=>y(n.key,e))}export async function writeCodexMcpServer(r,e,n=codexConfigFile()){const t=await k(n);if(t.trim()!=="")try{m(t)}catch(s){throw new l(`${n} is not valid TOML \u2014 refusing to write: ${s instanceof Error?s.message:String(s)}`)}await M(b.dirname(n),{recursive:!0}),await x(n,upsertCodexMcpInText(t,r,e),"utf-8")}export async function removeCodexMcpServer(r,e=codexConfigFile()){if(!await g(e))return!1;const n=await p(e,"utf-8");try{m(n)}catch(o){throw new l(`${e} is not valid TOML \u2014 refusing to write: ${o instanceof Error?o.message:String(o)}`)}const{text:t,removed:s}=removeCodexMcpFromText(n,r);return s&&await x(e,t,"utf-8"),s}
1
+ import{readFile as p,writeFile as g,access as C,mkdir as E}from"node:fs/promises";import{homedir as M}from"node:os";import b from"node:path";import{parse as m}from"smol-toml";import{assetSurfaceFor as $}from"../surfaces.js";import{CodexTomlCorruptError as d,parseSectionEntries as h,removeTomlSection as k,renderTomlHeader as F,renderTomlKey as O,renderTomlString as l,sameKey as y,splitTomlSections as v,upsertTomlSection as w}from"@weavecode/harness";export{CodexTomlCorruptError,parseDottedKey,sectionHeaderKey,renderTomlKey,renderTomlHeader,renderTomlString,splitTomlSections,upsertTomlSection,removeTomlSection,parseSectionEntries,upsertCodexPluginEnabledInText}from"@weavecode/harness";export function codexConfigFile(e=M()){return S??$("codex").userConfigFile(e)}export function readCodexMcpFromText(e){let r;try{r=m(e)}catch{return{}}const n=r.mcp_servers;if(!n||typeof n!="object"||Array.isArray(n))return{};const t={};for(const[s,o]of Object.entries(n)){const a=j(o);a&&(t[s]=a)}return t}function j(e){if(!e||typeof e!="object"||Array.isArray(e))return null;const r=e;if(typeof r.command!="string")return null;const n={command:r.command};if(Array.isArray(r.args)){const t=r.args.filter(s=>typeof s=="string");t.length>0&&(n.args=t)}if(r.env&&typeof r.env=="object"&&!Array.isArray(r.env)){const t={};for(const[s,o]of Object.entries(r.env))typeof o=="string"&&(t[s]=o);Object.keys(t).length>0&&(n.env=t)}return n}function T(e,r,n,t,s){const o=[`command = ${l(r.command)}`];if(r.args&&r.args.length>0&&o.push(`args = [${r.args.map(l).join(", ")}]`),s&&n){const i=new Set(["command","args","env"]);for(const[c,u]of h(n.lines.slice(1)))i.has(c)||o.push(u)}const a=Object.entries(r.env??{}),f=s&&t?h(t.lines.slice(1)).filter(([i])=>!(i in(r.env??{}))):[];if(a.length>0||f.length>0){o.push(""),o.push(F([...e,"env"]));for(const[i,c]of a)o.push(`${O(i)} = ${l(c)}`);for(const[,i]of f)o.push(i)}return o}export function upsertCodexMcpInText(e,r,n){const t=["mcp_servers",r],s=A(e);if(s)throw s;const o=v(e),a=o.find(c=>y(c.key,t)),f=o.find(c=>y(c.key,[...t,"env"])),i=w(e,t,T(t,n,a,f,!0));try{return m(i),i}catch{const c=w(e,t,T(t,n,a,f,!1));try{return m(c),c}catch(u){throw new d(`unable to produce valid TOML for [mcp_servers.${r}]: ${u instanceof Error?u.message:String(u)}`)}}}export function removeCodexMcpFromText(e,r){return k(e,["mcp_servers",r])}function A(e){return v(e)[0].lines.find(t=>/^\s*mcp_servers\s*=/.test(t))?new d('~/.codex/config.toml defines "mcp_servers" as an inline value \u2014 weave only manages the [mcp_servers.<name>] section form'):null}let S=null;export function setCodexConfigFileOverride(e){S=e}async function _(e){try{return await p(e,"utf-8")}catch{return""}}async function x(e){try{return await C(e),!0}catch{return!1}}export async function readCodexMcpServers(e=codexConfigFile()){return await x(e)?readCodexMcpFromText(await p(e,"utf-8")):{}}export async function codexMcpExists(e,r=codexConfigFile()){return await x(r)?K(await p(r,"utf-8"),["mcp_servers",e]):!1}function K(e,r){return v(e).some(n=>y(n.key,r))}export async function writeCodexMcpServer(e,r,n=codexConfigFile()){const t=await _(n);if(t.trim()!=="")try{m(t)}catch(s){throw new d(`${n} is not valid TOML \u2014 refusing to write: ${s instanceof Error?s.message:String(s)}`)}await E(b.dirname(n),{recursive:!0}),await g(n,upsertCodexMcpInText(t,e,r),"utf-8")}export async function removeCodexMcpServer(e,r=codexConfigFile()){if(!await x(r))return!1;const n=await p(r,"utf-8");try{m(n)}catch(o){throw new d(`${r} is not valid TOML \u2014 refusing to write: ${o instanceof Error?o.message:String(o)}`)}const{text:t,removed:s}=removeCodexMcpFromText(n,e);return s&&await g(r,t,"utf-8"),s}
@@ -1 +1 @@
1
- import{assetSurfaceFor as s}from"../surfaces.js";export{FILE_ASSET_SPECS,FILE_ASSET_CATEGORIES,isFileAssetCategory}from"@weavecode/harness";export function fileAssetTargetDir(r,e,t,i,o){return s(e).targetDir(r,t,i,o)}
1
+ import{assetSurfaceFor as i}from"../surfaces.js";export{FILE_ASSET_SPECS,FILE_ASSET_CATEGORIES,isFileAssetCategory}from"@weavecode/harness";export function fileAssetTargetDir(r,e,t,o,S){return i(e).targetDir(r,t,o,S)}
@@ -10,7 +10,11 @@ export interface FingerprintCacheEntry {
10
10
  * Empty / missing directories hash to a constant.
11
11
  */
12
12
  export declare function hashSkillDir(dir: string, skipNames?: Set<string>): Promise<string>;
13
- /** Max mtime (ms) across all files in a tree — cache-invalidation signal. */
13
+ /**
14
+ * Max mtime (ms) across all files in a tree — cache-invalidation signal.
15
+ * 逐文件 stat 是这一轮的全部成本(Windows 上每次往返 ~0.1ms、一百来个技能文件
16
+ * 串起来就是 100ms+),故整层并行发起,只保序不排队。
17
+ */
14
18
  export declare function maxMtimeDir(dir: string, skipNames?: Set<string>): Promise<number>;
15
19
  /** Stable hash of an MCP server config (sorted keys → JSON → sha256). */
16
20
  export declare function hashMcpConfig(config: McpServerConfig): string;
@@ -1 +1 @@
1
- import{readdir as h,readFile as m,stat as l}from"node:fs/promises";import{createHash as c}from"node:crypto";import n from"node:path";const f=new Set([".weave",".git","node_modules"]);export async function hashSkillDir(a,e=f){const t=c("sha256"),r=[];await u(a,a,r,e),r.sort((i,s)=>i.rel.localeCompare(s.rel));for(const i of r){t.update(i.rel),t.update("\0");let s;try{s=await m(i.abs)}catch{continue}t.update(s),t.update("\0")}return t.digest("hex")}async function u(a,e,t,r){let i;try{i=await h(e,{withFileTypes:!0})}catch{return}for(const s of i)s.name.startsWith(".")&&r.has(s.name)||(!r.has(s.name)&&s.isDirectory()?await u(a,n.join(e,s.name),t,r):s.isFile()&&t.push({rel:n.relative(a,e).replace(/\\/g,"/")+"/"+s.name,abs:n.join(e,s.name)}))}export async function maxMtimeDir(a,e=f){let t=0,r;try{r=await h(a,{withFileTypes:!0})}catch{return 0}for(const i of r){if(i.name.startsWith(".")&&e.has(i.name))continue;const s=n.join(a,i.name);if(i.isDirectory())t=Math.max(t,await maxMtimeDir(s,e));else if(i.isFile())try{const p=await l(s);t=Math.max(t,p.mtimeMs)}catch{}}return t}export function hashMcpConfig(a){return c("sha256").update(JSON.stringify(o(a))).digest("hex")}export async function hashFile(a){try{const e=await m(a);return c("sha256").update(e).digest("hex")}catch{return"missing"}}function o(a){if(Array.isArray(a))return a.map(o);if(a&&typeof a=="object"){const e={};for(const t of Object.keys(a).sort())e[t]=o(a[t]);return e}return a}export class FingerprintCache{cache=new Map;fileCache=new Map;async get(e){const t=await maxMtimeDir(e),r=this.cache.get(e);if(r&&r.maxMtime===t)return r.hash;const i=await hashSkillDir(e);return this.cache.set(e,{maxMtime:t,hash:i}),i}async getFile(e){let t;try{t=(await l(e)).mtimeMs}catch{return"missing"}const r=this.fileCache.get(e);if(r&&r.maxMtime===t)return r.hash;const i=await hashFile(e);return this.fileCache.set(e,{maxMtime:t,hash:i}),i}invalidate(e){this.cache.delete(e)}clear(){this.cache.clear(),this.fileCache.clear()}}
1
+ import{readdir as m,readFile as u,stat as l}from"node:fs/promises";import{createHash as h}from"node:crypto";import c from"node:path";const f=new Set([".weave",".git","node_modules"]);export async function hashSkillDir(e,t=f){const a=h("sha256"),r=[];await p(e,e,r,t),r.sort((n,i)=>n.rel.localeCompare(i.rel));for(const n of r){a.update(n.rel),a.update("\0");let i;try{i=await u(n.abs)}catch{continue}a.update(i),a.update("\0")}return a.digest("hex")}async function p(e,t,a,r){let n;try{n=await m(t,{withFileTypes:!0})}catch{return}const i=[];for(const s of n)s.name.startsWith(".")&&r.has(s.name)||(!r.has(s.name)&&s.isDirectory()?i.push(p(e,c.join(t,s.name),a,r)):s.isFile()&&a.push({rel:c.relative(e,t).replace(/\\/g,"/")+"/"+s.name,abs:c.join(t,s.name)}));await Promise.all(i)}export async function maxMtimeDir(e,t=f){let a;try{a=await m(e,{withFileTypes:!0})}catch{return 0}return(await Promise.all(a.map(async n=>{if(n.name.startsWith(".")&&t.has(n.name))return 0;const i=c.join(e,n.name);if(n.isDirectory())return maxMtimeDir(i,t);if(!n.isFile())return 0;try{return(await l(i)).mtimeMs}catch{return 0}}))).reduce((n,i)=>Math.max(n,i),0)}export function hashMcpConfig(e){return h("sha256").update(JSON.stringify(o(e))).digest("hex")}export async function hashFile(e){try{const t=await u(e);return h("sha256").update(t).digest("hex")}catch{return"missing"}}function o(e){if(Array.isArray(e))return e.map(o);if(e&&typeof e=="object"){const t={};for(const a of Object.keys(e).sort())t[a]=o(e[a]);return t}return e}export class FingerprintCache{cache=new Map;fileCache=new Map;async get(t){const a=await maxMtimeDir(t),r=this.cache.get(t);if(r&&r.maxMtime===a)return r.hash;const n=await hashSkillDir(t);return this.cache.set(t,{maxMtime:a,hash:n}),n}async getFile(t){let a;try{a=(await l(t)).mtimeMs}catch{return"missing"}const r=this.fileCache.get(t);if(r&&r.maxMtime===a)return r.hash;const n=await hashFile(t);return this.fileCache.set(t,{maxMtime:a,hash:n}),n}invalidate(t){this.cache.delete(t)}clear(){this.cache.clear(),this.fileCache.clear()}}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * 项目内路径「进不进 git」的分类——同步域自动/手动分界的唯一判据。
3
+ *
4
+ * 用户裁决:**不进 git 的自动同步;进 git 的仍走 `weave init` 生成 + commit**,
5
+ * 同步域只检测漂移、dashboard 提醒用户去终端跑 `weave init`(不代写)。
6
+ *
7
+ * 「会进 git」= tracked ∪ untracked-but-not-ignored(后者下次 `git add` 就进)。
8
+ * 所以 `check-ignore` 单独用不够——tracked 文件也可能命中 ignore 规则,判序恒为
9
+ * 先 tracked、后 ignored。非 git 仓库全算「不进 git」。
10
+ *
11
+ * 一轮 sweep 建一次(`gitClassify`),别逐文件起进程。
12
+ */
13
+ /** 一条路径的同步归类。 */
14
+ export type SyncClass = 'auto' | 'manual';
15
+ export type GitPathKind = 'tracked' | 'ignored' | 'untracked' | 'outside';
16
+ export interface GitClassify {
17
+ /** 相对路径 → 实际 git 状态。 */
18
+ kindOf(relPath: string): GitPathKind;
19
+ /** `auto` = 不进 git(代写无害、自愈);`manual` = 会进 git(只报不写)。 */
20
+ classOf(relPath: string): SyncClass;
21
+ }
22
+ /**
23
+ * 对给定的项目相对路径(posix 分隔)做一次批量分类。
24
+ *
25
+ * 两条查询**并行**起:`ls-files` 取 tracked、`check-ignore --stdin` 取 ignored,
26
+ * 都没命中的在仓库里即 untracked。原先串行三轮(ls-files → rev-parse → check-ignore)
27
+ * 在 Windows 上是 `/projects/:id/updates` 的全部耗时(实测 ~450ms,每个 git 子进程
28
+ * 约 150ms);仓库探测改看 `ls-files` 的退出码,省掉 `rev-parse` 那一轮。
29
+ */
30
+ export declare function gitClassify(projectPath: string, relPaths: readonly string[]): Promise<GitClassify>;
@@ -0,0 +1 @@
1
+ import{spawn as l}from"node:child_process";function c(o,s,t){return new Promise(n=>{const e=l("git",["-C",o,...s],{stdio:[t===void 0?"ignore":"pipe","pipe","ignore"],windowsHide:!0});let d="";e.stdout?.setEncoding("utf-8"),e.stdout?.on("data",r=>{d+=r}),e.on("error",()=>n({stdout:"",ran:!1,code:null})),e.on("close",r=>n({stdout:d,ran:!0,code:r})),t!==void 0&&e.stdin?.end(t)})}function a(o){return o.split("\0").filter(s=>s.length>0)}export async function gitClassify(o,s){const t=[...new Set(s)],n=new Map;if(t.length===0)return u(n);const[e,d]=await Promise.all([c(o,["ls-files","-z","--",...t]),c(o,["check-ignore","-z","--stdin"],t.map(i=>`${i}\0`).join(""))]);if(!e.ran||e.code!==0){for(const i of t)n.set(i,"outside");return u(n)}const r=new Set(a(e.stdout)),f=new Set(a(d.stdout));for(const i of t)n.set(i,r.has(i)?"tracked":f.has(i)?"ignored":"untracked");return u(n)}function u(o){const s=t=>o.get(t)??"outside";return{kindOf:s,classOf:t=>{const n=s(t);return n==="ignored"||n==="outside"?"auto":"manual"}}}
@@ -1,2 +1,2 @@
1
- import{readFile as x,writeFile as N,readdir as d,access as K,stat as P,realpath as G}from"node:fs/promises";import{homedir as f}from"node:os";import l from"node:path";import{AssetNotFoundError as b}from"./installer.js";import{FileTooLargeError as B,MAX_BYTES as D}from"./reader.js";import{assetSurfaceFor as h,assetSurfaces as J,pluginStateFor as S,pluginSurfaceFor as O}from"../surfaces.js";import{installForm as R,linkOrCopy as W,removeInstalled as z}from"../market/install-link.js";export class ClaudeJsonCorruptError extends Error{constructor(e){super(e),this.name="ClaudeJsonCorruptError"}}const I=".claude.json",_=".claude/plugins/installed_plugins.json";function j(){return l.join(f(),I)}function k(){return h("claude").globalSkillsRoots(f())[0]}function L(t=f()){return l.join(t,_)}function X(){return h("claude").userConfigFile(f())}function T(){return h("codex").globalSkillsRoots(f())[0]}function Y(){return h("codex").globalSkillsRoots(f())}function A(){const t=h("codex").pluginCacheDir?.(f());if(!t)throw new Error("codex has no plugin cache surface");return t}export function globalPersonalSkillRootsOwned(){return J().flatMap(t=>t.globalSkillsRoots(f()).map(e=>({harness:t.harness,root:e})))}export function globalPersonalSkillRoots(){return globalPersonalSkillRootsOwned().map(t=>t.root)}async function F(t){try{return await K(t),!0}catch{return!1}}async function y(t){try{return(await P(t)).isDirectory()}catch{return!1}}export async function readGlobalClaudeJson(){const t=j();if(!await F(t))return{};let e;try{e=await x(t,"utf-8")}catch{return{}}let n;try{n=JSON.parse(e)}catch(a){throw new ClaudeJsonCorruptError(`~/.claude.json is not valid JSON \u2014 refusing to write: ${a instanceof Error?a.message:String(a)}`)}if(!n||typeof n!="object"||Array.isArray(n))throw new ClaudeJsonCorruptError("~/.claude.json is not a JSON object \u2014 refusing to write");return n}export async function readGlobalMcpServers(){const t=(await readGlobalClaudeJson()).mcpServers;return!t||typeof t!="object"||Array.isArray(t)?{}:t}async function M(t){await N(j(),`${JSON.stringify(t,null,2)}
2
- `,"utf-8")}export async function writeGlobalMcpServer(t,e){const n=await readGlobalClaudeJson(),a=n.mcpServers??{};a[t]=e,n.mcpServers=a,await M(n)}export async function removeGlobalMcpServer(t){const e=await readGlobalClaudeJson(),n=e.mcpServers??{};t in n&&(delete n[t],e.mcpServers=n,await M(e))}export async function readGlobalSkills(){const t=k();try{const e=await d(t,{withFileTypes:!0}),n=[];for(const a of e)!a.isDirectory()&&!a.isSymbolicLink()||await y(l.join(t,a.name))&&n.push(a.name);return n.sort((a,r)=>a.localeCompare(r))}catch{return[]}}export async function installGlobalSkill(t,e,n="claude"){const a=h(n).globalSkillsRoots(f())[0],r=l.join(a,e);if(await F(r))throw new Error(`Global ${n} skill "${e}" already exists`);return await W(t,r),r}export async function uninstallGlobalSkill(t,e="claude"){const n=h(e).globalSkillsRoots(f())[0];await z(l.join(n,t))}async function C(t=f()){const e=L(t);if(!await F(e))return{};try{const n=JSON.parse(await x(e,"utf-8"));return n&&typeof n=="object"&&!Array.isArray(n)?n:{}}catch{return{}}}async function E(t){if(!await y(t))return[];let e;try{e=await d(t,{withFileTypes:!0})}catch{return[]}const n=[];for(const a of e){if(a.name.startsWith(".")||!a.isDirectory()&&!a.isSymbolicLink())continue;const r=l.join(t,a.name);if(!await y(r))continue;const o=await R(r);o!=="absent"&&n.push({name:a.name,dir:r,form:o})}return n.sort((a,r)=>a.name.localeCompare(r.name))}export async function installedPluginNamespaces(t=f()){const e=(await C(t)).plugins;if(!e||typeof e!="object"||Array.isArray(e))return[];const n=[];for(const[a,r]of Object.entries(e)){const{market:o}=O("claude").parsePluginKey(a);for(const i of Array.isArray(r)?r:[])i&&typeof i.installPath=="string"&&n.push({dir:i.installPath,namespace:o})}return n}async function q(){const t=(await C()).plugins;if(!t||typeof t!="object"||Array.isArray(t))return[];const e=[];for(const[n,a]of Object.entries(t)){const r=Array.isArray(a)?a:[];if(r.length===0)continue;const o=[...r].filter(p=>p&&typeof p.installPath=="string").pop();if(!o?.installPath)continue;const i=await E(l.join(o.installPath,"skills")),{name:s,market:u}=O("claude").parsePluginKey(n);e.push({source:"claude-plugin",label:s,namespace:u,skills:i,pluginKey:n})}return e.sort((n,a)=>n.label.localeCompare(a.label))}async function H(){const t=new Map;for(const e of Y())for(const n of await E(e))t.has(n.name)||t.set(n.name,n);return{source:"codex-personal",label:"Codex \xB7 \u4E2A\u4EBA",skills:[...t.values()].sort((e,n)=>e.name.localeCompare(n.name))}}async function Q(){const t=A();if(!await y(t))return[];const e=[];let n;try{n=await d(t,{withFileTypes:!0})}catch{return[]}for(const a of n){if(!a.isDirectory()&&!a.isSymbolicLink())continue;const r=l.join(t,a.name);let o;try{o=await d(r,{withFileTypes:!0})}catch{continue}for(const i of o){if(!i.isDirectory()&&!i.isSymbolicLink())continue;const s=l.join(r,i.name);let u;try{u=await d(s,{withFileTypes:!0})}catch{continue}const p=u.filter(w=>w.isDirectory()||w.isSymbolicLink());if(p.length===0)continue;const m=p.map(w=>w.name).sort().pop(),c=await E(l.join(s,m,"skills")),g=`${i.name}@${a.name}`;e.push({source:"codex-plugin",label:i.name,namespace:a.name,skills:c,pluginKey:g})}}return e.sort((a,r)=>a.label.localeCompare(r.label))}async function U(){const t=k(),e=await readGlobalSkills(),n=[];for(const a of e){const r=l.join(t,a),o=await R(r);o!=="absent"&&n.push({name:a,dir:r,form:o})}return{source:"claude-personal",label:"Claude Code \xB7 \u4E2A\u4EBA",skills:n}}export async function readGlobalSkillGroups(){const[t,e,n,a,r,o]=await Promise.all([U(),q(),H(),Q(),readClaudePluginEnabled(),readCodexPluginEnabled()]),i=(s,u)=>({...s,enabled:s.pluginKey?u[s.pluginKey]??!1:void 0});return[t,...e.map(s=>i(s,r)),n,...a.map(s=>i(s,o))]}export async function resolveGlobalSkillDir(t,e,n){if(t==="claude-personal"){const c=l.join(k(),e);return await y(c)?c:null}if(t==="codex-personal"){const c=l.join(T(),e);return await y(c)?c:null}if(t==="claude-plugin"){if(!n)return null;const c=(await C()).plugins;if(!c||typeof c!="object"||Array.isArray(c))return null;const g=c[n],w=[...Array.isArray(g)?g:[]].filter($=>$&&typeof $.installPath=="string").pop();if(!w?.installPath)return null;const v=l.join(w.installPath,"skills",e);return await y(v)?v:null}if(!n)return null;const a=n.lastIndexOf("@");if(a<=0)return null;const r=n.slice(0,a),o=n.slice(a+1),i=l.join(A(),o,r);if(!await y(i))return null;let s;try{s=await d(i,{withFileTypes:!0})}catch{return null}const u=s.filter(c=>c.isDirectory()||c.isSymbolicLink());if(u.length===0)return null;const p=u.map(c=>c.name).sort().pop(),m=l.join(i,p,"skills",e);return await y(m)?m:null}function V(t){const e=l.resolve(t),n=f();return J().find(a=>{const r=[...a.globalSkillsRoots(n)],o=a.pluginCacheDir?.(n);return o&&r.push(o),r.some(i=>e===l.resolve(i)||e.startsWith(l.resolve(i)+l.sep))})?.harness??"claude"}export async function listGlobalSkillFiles(t){const e=V(t),n=[],a=async(r,o)=>{let i;try{i=await d(r,{withFileTypes:!0})}catch{return}for(const s of i){if(s.name.startsWith("."))continue;const u=l.join(r,s.name),p=o?`${o}/${s.name}`:s.name;if((s.isDirectory()||s.isSymbolicLink())&&await y(u))await a(u,p);else if(s.isFile()||s.isSymbolicLink())try{const m=await P(u);m.isFile()&&n.push({absPath:u,relPath:p,category:"skill",agent:e,mtimeMs:m.mtimeMs})}catch{}}};return await a(t,""),n.sort((r,o)=>r.relPath.localeCompare(o.relPath))}export async function readGlobalSkillFile(t,e){const n=l.normalize(e).replace(/\\/g,"/");if(l.isAbsolute(e))throw new b(`Absolute paths are not allowed: "${e}"`);if(n.split("/").some(u=>u===".."))throw new b(`Path traversal is not allowed: "${e}"`);const a=l.join(t,n);let r;try{r=await P(a)}catch{throw new b(`File not found: "${e}"`)}if(!r.isFile())throw new b(`Not a file: "${e}"`);if(r.size>D)throw new B(`File exceeds ${D} bytes: "${e}"`);let o=t,i=a;try{[o,i]=await Promise.all([G(t),G(a)])}catch{throw new b(`File not found: "${e}"`)}const s=o.endsWith(l.sep)?o:o+l.sep;if(i!==o&&!i.startsWith(s))throw new b(`Resolved path escapes the skill directory: "${e}"`);return{content:await x(a,"utf-8"),size:r.size}}export async function readClaudePluginEnabled(){return S("claude").readGlobalEnabled()}export async function writeClaudePluginEnabled(t,e){return S("claude").writeGlobalEnabled(t,e)}export async function readCodexPluginEnabled(){return S("codex").readGlobalEnabled()}export async function writeCodexPluginEnabled(t,e){return S("codex").writeGlobalEnabled(t,e)}export{k as globalSkillsPath,j as claudeJsonPath,L as claudePluginsJsonPath,X as claudeSettingsPath,T as codexSkillsPath,A as codexPluginsCachePath};
1
+ import{readFile as x,writeFile as W,readdir as m,access as _,stat as j,realpath as $}from"node:fs/promises";import{homedir as f}from"node:os";import l from"node:path";import{AssetNotFoundError as g}from"./installer.js";import{FileTooLargeError as z,MAX_BYTES as J}from"./reader.js";import{assetSurfaceFor as h,assetSurfaces as O,pluginStateFor as S,pluginSurfaceFor as R}from"../surfaces.js";import{installForm as L,linkOrCopy as I,removeInstalled as U}from"../market/install-link.js";export class ClaudeJsonCorruptError extends Error{constructor(e){super(e),this.name="ClaudeJsonCorruptError"}}const B=".claude.json",K=".claude/plugins/installed_plugins.json";function P(){return l.join(f(),B)}function k(){return h("claude").globalSkillsRoots(f())[0]}function N(t=f()){return l.join(t,K)}function X(){return h("claude").userConfigFile(f())}function M(){return h("codex").globalSkillsRoots(f())[0]}function Y(){return h("codex").globalSkillsRoots(f())}function C(){const t=h("codex").pluginCacheDir?.(f());if(!t)throw new Error("codex has no plugin cache surface");return t}export function globalPersonalSkillRootsOwned(){return O().flatMap(t=>t.globalSkillsRoots(f()).map(e=>({harness:t.harness,root:e})))}export function globalPersonalSkillRoots(){return globalPersonalSkillRootsOwned().map(t=>t.root)}async function A(t){try{return await _(t),!0}catch{return!1}}async function y(t){try{return(await j(t)).isDirectory()}catch{return!1}}export async function readGlobalClaudeJson(){const t=P();if(!await A(t))return{};let e;try{e=await x(t,"utf-8")}catch{return{}}let n;try{n=JSON.parse(e)}catch(o){throw new ClaudeJsonCorruptError(`~/.claude.json is not valid JSON \u2014 refusing to write: ${o instanceof Error?o.message:String(o)}`)}if(!n||typeof n!="object"||Array.isArray(n))throw new ClaudeJsonCorruptError("~/.claude.json is not a JSON object \u2014 refusing to write");return n}export async function readGlobalMcpServers(){const e=(await readGlobalClaudeJson()).mcpServers;return!e||typeof e!="object"||Array.isArray(e)?{}:e}async function T(t){await W(P(),`${JSON.stringify(t,null,2)}
2
+ `,"utf-8")}export async function writeGlobalMcpServer(t,e){const n=await readGlobalClaudeJson(),o=n.mcpServers??{};o[t]=e,n.mcpServers=o,await T(n)}export async function removeGlobalMcpServer(t){const e=await readGlobalClaudeJson(),n=e.mcpServers??{};t in n&&(delete n[t],e.mcpServers=n,await T(e))}export async function readGlobalSkills(){const t=k();try{const e=await m(t,{withFileTypes:!0}),n=[];for(const o of e)!o.isDirectory()&&!o.isSymbolicLink()||await y(l.join(t,o.name))&&n.push(o.name);return n.sort((o,r)=>o.localeCompare(r))}catch{return[]}}export async function installGlobalSkill(t,e,n="claude"){const o=h(n).globalSkillsRoots(f())[0],r=l.join(o,e);if(await A(r))throw new Error(`Global ${n} skill "${e}" already exists`);return await I(t,r),r}export async function uninstallGlobalSkill(t,e="claude"){const n=h(e).globalSkillsRoots(f())[0];await U(l.join(n,t))}async function F(t=f()){const e=N(t);if(!await A(e))return{};try{const n=JSON.parse(await x(e,"utf-8"));return n&&typeof n=="object"&&!Array.isArray(n)?n:{}}catch{return{}}}async function v(t){if(!await y(t))return[];let e;try{e=await m(t,{withFileTypes:!0})}catch{return[]}const n=[];for(const o of e){if(o.name.startsWith(".")||!o.isDirectory()&&!o.isSymbolicLink())continue;const r=l.join(t,o.name);if(!await y(r))continue;const i=await L(r);i!=="absent"&&n.push({name:o.name,dir:r,form:i})}return n.sort((o,r)=>o.name.localeCompare(r.name))}export async function installedPluginNamespaces(t=f()){const n=(await F(t)).plugins;if(!n||typeof n!="object"||Array.isArray(n))return[];const o=[];for(const[r,i]of Object.entries(n)){const{market:s}=R("claude").parsePluginKey(r);for(const a of Array.isArray(i)?i:[])a&&typeof a.installPath=="string"&&o.push({dir:a.installPath,namespace:s})}return o}async function q(){const e=(await F()).plugins;if(!e||typeof e!="object"||Array.isArray(e))return[];const n=[];for(const[o,r]of Object.entries(e)){const i=Array.isArray(r)?r:[];if(i.length===0)continue;const s=[...i].filter(d=>d&&typeof d.installPath=="string").pop();if(!s?.installPath)continue;const a=await v(l.join(s.installPath,"skills")),{name:c,market:p}=R("claude").parsePluginKey(o);n.push({source:"claude-plugin",label:c,namespace:p,skills:a,pluginKey:o})}return n.sort((o,r)=>o.label.localeCompare(r.label))}async function H(){const t=new Map;for(const n of Y())for(const o of await v(n))t.has(o.name)||t.set(o.name,o);return{source:"codex-personal",label:"Codex \xB7 \u4E2A\u4EBA",skills:[...t.values()].sort((n,o)=>n.name.localeCompare(o.name))}}async function Q(){const t=C();if(!await y(t))return[];const e=[];let n;try{n=await m(t,{withFileTypes:!0})}catch{return[]}for(const o of n){if(!o.isDirectory()&&!o.isSymbolicLink())continue;const r=l.join(t,o.name);let i;try{i=await m(r,{withFileTypes:!0})}catch{continue}for(const s of i){if(!s.isDirectory()&&!s.isSymbolicLink())continue;const a=l.join(r,s.name);let c;try{c=await m(a,{withFileTypes:!0})}catch{continue}const p=c.filter(w=>w.isDirectory()||w.isSymbolicLink());if(p.length===0)continue;const d=p.map(w=>w.name).sort().pop(),u=await v(l.join(a,d,"skills")),b=`${s.name}@${o.name}`;e.push({source:"codex-plugin",label:s.name,namespace:o.name,skills:u,pluginKey:b})}}return e.sort((o,r)=>o.label.localeCompare(r.label))}async function V(){const t=k(),e=await readGlobalSkills(),n=[];for(const o of e){const r=l.join(t,o),i=await L(r);i!=="absent"&&n.push({name:o,dir:r,form:i})}return{source:"claude-personal",label:"Claude Code \xB7 \u4E2A\u4EBA",skills:n}}export async function readGlobalSkillGroups(){const[t,e,n,o,r,i]=await Promise.all([V(),q(),H(),Q(),readClaudePluginEnabled(),readCodexPluginEnabled()]),s=(a,c)=>({...a,enabled:a.pluginKey?c[a.pluginKey]??!1:void 0});return[t,...e.map(a=>s(a,r)),n,...o.map(a=>s(a,i))]}export async function resolveGlobalSkillDir(t,e,n){if(t==="claude-personal"){const u=l.join(k(),e);return await y(u)?u:null}if(t==="codex-personal"){const u=l.join(M(),e);return await y(u)?u:null}if(t==="claude-plugin"){if(!n)return null;const b=(await F()).plugins;if(!b||typeof b!="object"||Array.isArray(b))return null;const w=b[n],E=[...Array.isArray(w)?w:[]].filter(G=>G&&typeof G.installPath=="string").pop();if(!E?.installPath)return null;const D=l.join(E.installPath,"skills",e);return await y(D)?D:null}if(!n)return null;const o=n.lastIndexOf("@");if(o<=0)return null;const r=n.slice(0,o),i=n.slice(o+1),s=l.join(C(),i,r);if(!await y(s))return null;let a;try{a=await m(s,{withFileTypes:!0})}catch{return null}const c=a.filter(u=>u.isDirectory()||u.isSymbolicLink());if(c.length===0)return null;const p=c.map(u=>u.name).sort().pop(),d=l.join(s,p,"skills",e);return await y(d)?d:null}function Z(t){const e=l.resolve(t),n=f();return O().find(r=>{const i=[...r.globalSkillsRoots(n)],s=r.pluginCacheDir?.(n);return s&&i.push(s),i.some(a=>e===l.resolve(a)||e.startsWith(l.resolve(a)+l.sep))})?.harness??"claude"}export async function listGlobalSkillFiles(t){const e=Z(t),n=[],o=async(r,i)=>{let s;try{s=await m(r,{withFileTypes:!0})}catch{return}for(const a of s){if(a.name.startsWith("."))continue;const c=l.join(r,a.name),p=i?`${i}/${a.name}`:a.name;if((a.isDirectory()||a.isSymbolicLink())&&await y(c))await o(c,p);else if(a.isFile()||a.isSymbolicLink())try{const d=await j(c);d.isFile()&&n.push({absPath:c,relPath:p,category:"skill",agent:e,mtimeMs:d.mtimeMs})}catch{}}};return await o(t,""),n.sort((r,i)=>r.relPath.localeCompare(i.relPath))}export async function readGlobalSkillFile(t,e){const n=l.normalize(e).replace(/\\/g,"/");if(l.isAbsolute(e))throw new g(`Absolute paths are not allowed: "${e}"`);if(n.split("/").some(p=>p===".."))throw new g(`Path traversal is not allowed: "${e}"`);const o=l.join(t,n);let r;try{r=await j(o)}catch{throw new g(`File not found: "${e}"`)}if(!r.isFile())throw new g(`Not a file: "${e}"`);if(r.size>J)throw new z(`File exceeds ${J} bytes: "${e}"`);let i=t,s=o;try{[i,s]=await Promise.all([$(t),$(o)])}catch{throw new g(`File not found: "${e}"`)}const a=i.endsWith(l.sep)?i:i+l.sep;if(s!==i&&!s.startsWith(a))throw new g(`Resolved path escapes the skill directory: "${e}"`);return{content:await x(o,"utf-8"),size:r.size}}export async function readClaudePluginEnabled(){return S("claude").readGlobalEnabled()}export async function writeClaudePluginEnabled(t,e){return S("claude").writeGlobalEnabled(t,e)}export async function readCodexPluginEnabled(){return S("codex").readGlobalEnabled()}export async function writeCodexPluginEnabled(t,e){return S("codex").writeGlobalEnabled(t,e)}export{k as globalSkillsPath,P as claudeJsonPath,N as claudePluginsJsonPath,X as claudeSettingsPath,M as codexSkillsPath,C as codexPluginsCachePath};
@@ -1 +1 @@
1
- import{lstat as y,readdir as k,stat as p}from"node:fs/promises";import{homedir as P}from"node:os";import l from"node:path";import{classifyAgent as S,classifyAsset as $}from"../watch/classifier.js";import{PluginModsSniffer as j}from"../watch/plugin-mods.js";import{installedPluginNamespaces as x}from"./global-config.js";const A=["commands","agents","workflows","rules","output-styles","hooks","themes","routines","plugins"],b=["CLAUDE.md","settings.json","settings.local.json"],v=["prompts"],D=["config.toml","AGENTS.md"],F=new Set(["skills","node_modules",".git"]),L=new Set(["marketplaces","data",".in_use"]),h=".claude/plugins",E=`${h}/`,M=6,N=10,d=5e3,T=[{prefix:".claude",dirs:A,files:b},{prefix:".codex",dirs:v,files:D}];async function g(e,i,s){try{const n=await y(e),t=n.isSymbolicLink(),o=t?await p(e):n;if(!o.isFile())return null;let a=$(i);return a==="plugin"&&(a=s.refine(a,i,e)),{absPath:e,relPath:i,category:a,agent:S(i),mtimeMs:o.mtimeMs,...t?{isSymlink:!0}:{}}}catch{return null}}async function m(e,i,s,n,t,o){if(s>t||n.length>=d)return;let a;try{a=await k(e,{withFileTypes:!0})}catch{return}for(const r of a){if(n.length>=d)return;const c=l.join(e,r.name),f=`${i}/${r.name}`;if(r.isDirectory()){if(w(f,r.name))continue;await m(c,f,s+1,n,t,o);continue}if(r.isSymbolicLink())try{if((await p(c)).isDirectory()){w(f,r.name)||await m(c,f,s+1,n,t,o);continue}}catch{continue}const u=await g(c,f,o);u&&n.push(u)}}function w(e,i){return F.has(i)?!0:e.startsWith(E)&&L.has(i)}export async function listGlobalFileAssets(e=P()){const i=new j({revalidate:!1}),s=[];for(const t of T){const o=l.join(e,...t.prefix.split("/"));for(const a of t.files){const r=await g(l.join(o,a),`${t.prefix}/${a}`,i);r&&s.push(r)}for(const a of t.dirs){const r=`${t.prefix}/${a}`,c=r===h?N:M;await m(l.join(o,a),r,1,s,c,i)}}const n=await x(e);return s.sort((t,o)=>t.relPath.localeCompare(o.relPath)),s.map(t=>{const o=_(t.absPath,n);return o?{...t,namespace:o}:t})}function _(e,i){let s;for(const n of i){const t=l.relative(l.resolve(n.dir),l.resolve(e));t===""||t.startsWith("..")||l.isAbsolute(t)||(!s||n.dir.length>s.dir.length)&&(s=n)}return s?.namespace}
1
+ import{lstat as S,readdir as _,stat as P}from"node:fs/promises";import{homedir as g}from"node:os";import c from"node:path";import{classifyAgent as w,classifyAsset as h}from"../watch/classifier.js";import{PluginModsSniffer as I}from"../watch/plugin-mods.js";import{installedPluginNamespaces as D}from"./global-config.js";const L=["commands","agents","workflows","rules","output-styles","hooks","themes","routines","plugins"],A=["CLAUDE.md","settings.json","settings.local.json"],k=["prompts"],R=["config.toml","AGENTS.md"],T=new Set(["skills","node_modules",".git"]),U=new Set(["marketplaces","data",".in_use"]),y=".claude/plugins",F=`${y}/`,N=6,O=10,$=5e3,j=[{prefix:".claude",dirs:L,files:A},{prefix:".codex",dirs:k,files:R}];async function d(s,n,o){try{const e=await S(s),a=e.isSymbolicLink(),t=a?await P(s):e;if(!t.isFile())return null;let i=h(n);return i==="plugin"&&(i=o.refine(i,n,s)),{absPath:s,relPath:n,category:i,agent:w(n),mtimeMs:t.mtimeMs,...a?{isSymlink:!0}:{}}}catch{return null}}async function f(s,n,o,e,a){if(o>e)return[];let t;try{t=await _(s,{withFileTypes:!0})}catch{return[]}return(await Promise.all(t.map(async l=>{const u=c.join(s,l.name),r=`${n}/${l.name}`;if(l.isDirectory())return E(r,l.name)?[]:f(u,r,o+1,e,a);if(l.isSymbolicLink())try{if((await P(u)).isDirectory())return E(r,l.name)?[]:f(u,r,o+1,e,a)}catch{return[]}const m=await d(u,r,a);return m?[m]:[]}))).flat()}function E(s,n){return T.has(n)?!0:s.startsWith(F)&&U.has(n)}export async function listGlobalFileAssets(s=g()){const n=new I({revalidate:!1}),e=(await Promise.all(j.map(async t=>{const i=c.join(s,...t.prefix.split("/")),[l,u]=await Promise.all([Promise.all(t.files.map(r=>d(c.join(i,r),`${t.prefix}/${r}`,n))),Promise.all(t.dirs.map(r=>{const m=`${t.prefix}/${r}`,p=m===y?O:N;return f(c.join(i,r),m,1,p,n)}))]);return[...l.filter(r=>r!==null),...u.flat()]}))).flat(),a=await D(s);return e.sort((t,i)=>t.relPath.localeCompare(i.relPath)),e.slice(0,$).map(t=>{const i=x(t.absPath,a);return i?{...t,namespace:i}:t})}function x(s,n){let o;for(const e of n){const a=c.relative(c.resolve(e.dir),c.resolve(s));a===""||a.startsWith("..")||c.isAbsolute(a)||(!o||e.dir.length>o.dir.length)&&(o=e)}return o?.namespace}
@@ -0,0 +1,46 @@
1
+ import { type Harness, type HooksConfig, type InitComponents, type MCPConfig, type Preset } from '@weavecode/core';
2
+ import { type SyncClass } from './git-classify.js';
3
+ /**
4
+ * init 生成物的漂移检测与自动落盘——`weave init` 写过的文件里,**不进 git 的**
5
+ * 由同步域自动刷新(自愈),**会进 git 的**只报不写、dashboard 提醒用户去终端
6
+ * 跑 `weave init`(保留「生成 + commit」流程)。
7
+ *
8
+ * 期望态不在此处拼:落点与内容全经 harness 的 `generateInitFiles`(与 init 落盘
9
+ * 同一套生成器),statusline 那条走 statusline 模块自己的生成器与落点。本模块只
10
+ * 做「盘上 vs 期望」的比对与按 git 归类分流。
11
+ */
12
+ export interface InitFileUpdate {
13
+ /** 项目根相对路径(posix)。 */
14
+ relPath: string;
15
+ targetPath: string;
16
+ /** 盘上缺失或内容与期望不同。 */
17
+ outdated: boolean;
18
+ /** `auto` = 可代写自愈;`manual` = 会进 git,只报不写;null = 没漂移,未归类。 */
19
+ syncClass: SyncClass | null;
20
+ /** 期望全文;null = 判不出来(盘上不可合并等)→ 不写。 */
21
+ expectedContent: string | null;
22
+ }
23
+ /** `.weave/config.yaml` 的解析结果(手写 k:v 行,对象值是 JSON 一行)。 */
24
+ interface InitRuntime {
25
+ initVersion: string | null;
26
+ preset: Preset;
27
+ harnesses: Harness[];
28
+ components: InitComponents;
29
+ hooks: HooksConfig;
30
+ mcp: MCPConfig;
31
+ }
32
+ /**
33
+ * 读 init 落档的运行时配置。旧项目没有 `hooks`/`mcp`/`components` 字段——
34
+ * 回落 DEFAULT_*(正是未加 `--hooks`/`--mcp` 时 init 的取值)。
35
+ */
36
+ export declare function readInitRuntime(projectPath: string): Promise<InitRuntime>;
37
+ /** 一个项目的 init 生成物漂移清单(含全部条目,`outdated` 标注是否需同步)。 */
38
+ export declare function detectInitFileUpdates(projectPath: string): Promise<InitFileUpdate[]>;
39
+ /**
40
+ * 落一条生成物——**只写 `auto` 归类的**(不进 git);会进 git 的写下去会改掉用户
41
+ * 正要 commit 的文件,一律拒绝。返回是否真的写了。
42
+ */
43
+ export declare function applyInitFile(update: InitFileUpdate): Promise<boolean>;
44
+ /** 会进 git、因此只能提醒用户跑 `weave init` 的漂移条目。 */
45
+ export declare function needsInit(updates: readonly InitFileUpdate[]): boolean;
46
+ export {};
@@ -0,0 +1,2 @@
1
+ import{mkdir as y,readFile as m,writeFile as g}from"node:fs/promises";import l from"node:path";import{DEFAULT_HOOKS as f,DEFAULT_MCP as w,HARNESS_KEYS as C,detectPlatform as E,isHarness as x,resolveComponents as O}from"@weavecode/core";import{WEAVE_CONTENT_MARKER as h,generateInitFiles as S}from"@weavecode/harness";import{gitClassify as k}from"./git-classify.js";import{generateStatuslineScript as F}from"../statusline/generator.js";import{readStatuslineConfig as v,statuslineScriptRelPath as A}from"../statusline/manager.js";import{WEAVE_VERSION as P}from"../version.js";function b(t){const e={};for(const o of t.split(`
2
+ `)){const n=o.indexOf(":");if(n<=0)continue;const s=o.slice(0,n).trim(),i=o.slice(n+1).trim();if(s)try{e[s]=JSON.parse(i)}catch{e[s]=i}}return e}function I(t){if(typeof t!="object"||t===null)return f;const e=t,o=Object.fromEntries(Object.keys(f).filter(n=>typeof f[n]=="boolean"&&!(n in e)).map(n=>[n,!1]));return{...f,...o,...e}}export async function readInitRuntime(t){let e;try{e=await m(l.join(t,".weave","config.yaml"),"utf-8")}catch{e=""}const o=b(e),n=o.preset,s=o.components,i=o.hooks,a=o.mcp,c=o.harnesses;return{initVersion:typeof o.initVersion=="string"?o.initVersion:null,preset:n==="minimal"||n==="full"||n==="default"?n:"default",harnesses:Array.isArray(c)?c.filter(x):[],components:O(n==="minimal"||n==="full"||n==="default"?n:"default",typeof s=="object"&&s!==null?s:void 0),hooks:I(i),mcp:{...w,...typeof a=="object"&&a!==null?a:{}}}}function R(){return E()}function V(t,e){return{projectPath:t,version:P,platform:R(),components:e.components,hooks:e.hooks,mcp:e.mcp}}async function _(t,e){if(!e.components.helpers)return[];const o=await v(t);return[{relPath:A(),weaveMarker:h,content:F(o)}]}async function N(t){try{return await m(t,"utf-8")}catch{return null}}function H(t,e){return t.merge?e===null?t.content:t.merge(e,t.content):e!==null&&!e.includes(t.weaveMarker??h)?null:t.content}async function M(t){try{return await m(l.join(t,".weave","config.yaml"),"utf-8"),!0}catch{return!1}}export async function detectInitFileUpdates(t){if(!await M(t))return[];const e=await readInitRuntime(t),o=V(t,e),n=e.harnesses.length>0?e.harnesses:[C[0]],s=[...await _(t,e)];for(const r of n)s.push(...await S(r,o));const i=[];for(const r of s){const p=l.join(t,...r.relPath.split("/")),d=await N(p),u=H(r,d);i.push({relPath:r.relPath,targetPath:p,outdated:u!==null&&u!==d,syncClass:null,expectedContent:u})}const a=i.filter(r=>r.outdated),c=await k(t,a.map(r=>r.relPath));for(const r of a)r.syncClass=c.classOf(r.relPath);return i}export async function applyInitFile(t){return t.syncClass!=="auto"||!t.outdated||t.expectedContent===null?!1:(await y(l.dirname(t.targetPath),{recursive:!0}),await g(t.targetPath,t.expectedContent,"utf-8"),!0)}export function needsInit(t){return t.some(e=>e.syncClass==="manual"&&e.outdated)}
@@ -1,2 +1,2 @@
1
- import{mkdir as l,readFile as f,writeFile as y}from"node:fs/promises";import r from"node:path";const i=r.join(".weave","installed.json"),s=e=>[e.category,e.name,e.agent,e.assetCategory??""].join("\0");function g(e){if(!e||typeof e!="object")return!1;const t=e;return(t.category==="skill"||t.category==="mcp"||t.category==="file")&&typeof t.name=="string"&&t.name!==""&&typeof t.agent=="string"}export async function readInstalledLedger(e){try{const t=JSON.parse(await f(r.join(e,i),"utf-8"));return Array.isArray(t.assets)?t.assets.filter(g):[]}catch{return[]}}export async function recordInstalled(e,t){const n=await readInstalledLedger(e);n.some(a=>s(a)===s(t))||await o(e,[...n,t])}export async function forgetInstalled(e,t){const n=await readInstalledLedger(e),a=n.filter(c=>s(c)!==s(t));a.length!==n.length&&await o(e,a)}async function o(e,t){const n=r.join(e,i);await l(r.dirname(n),{recursive:!0}),await y(n,`${JSON.stringify({version:1,assets:t},null,2)}
1
+ import{mkdir as c,readFile as l,writeFile as y}from"node:fs/promises";import r from"node:path";const i=r.join(".weave","installed.json"),s=t=>[t.category,t.name,t.agent,t.assetCategory??""].join("\0");function g(t){if(!t||typeof t!="object")return!1;const e=t;return(e.category==="skill"||e.category==="mcp"||e.category==="file")&&typeof e.name=="string"&&e.name!==""&&typeof e.agent=="string"}export async function readInstalledLedger(t){try{const e=JSON.parse(await l(r.join(t,i),"utf-8"));return Array.isArray(e.assets)?e.assets.filter(g):[]}catch{return[]}}export async function recordInstalled(t,e){const n=await readInstalledLedger(t);n.some(a=>s(a)===s(e))||await o(t,[...n,e])}export async function forgetInstalled(t,e){const n=await readInstalledLedger(t),a=n.filter(f=>s(f)!==s(e));a.length!==n.length&&await o(t,a)}async function o(t,e){const n=r.join(t,i);await c(r.dirname(n),{recursive:!0}),await y(n,`${JSON.stringify({version:1,assets:e},null,2)}
2
2
  `,"utf-8")}
@@ -1,3 +1,3 @@
1
- import{cp as w,rm as m,readFile as j,writeFile as y,access as v,mkdir as h}from"node:fs/promises";import{homedir as g}from"node:os";import s from"node:path";import{FILE_ASSET_SPECS as S,fileAssetTargetDir as x}from"./file-assets.js";import{assetSurfaceFor as E}from"../surfaces.js";import{forgetInstalled as f,recordInstalled as p}from"./install-ledger.js";export class InstallConflictError extends Error{constructor(a){super(a),this.name="InstallConflictError"}}export class AssetNotFoundError extends Error{constructor(a){super(a),this.name="AssetNotFoundError"}}const d=".mcp.json";function i(e){if(!e||e.includes("/")||e.includes("\\")||e.includes("..")||e.includes(s.sep))throw new Error(`Invalid asset name: "${e}"`)}async function l(e){try{return await v(e),!0}catch{return!1}}function $(e){return E(e).projectSkillsDir()}export async function installSkill(e,a,t,r="claude"){i(t);const n=s.join(e,$(r),t);if(await l(n))throw new InstallConflictError(`Skill "${t}" is already installed${r==="codex"?" (Codex)":""}`);return await w(a,n,{recursive:!0}),await p(e,{category:"skill",name:t,agent:r}),n}export async function uninstallSkill(e,a,t="claude"){i(a);const r=s.join(e,$(t),a);if(!await l(r))throw new AssetNotFoundError(`Skill "${a}" is not installed${t==="codex"?" (Codex)":""}`);await m(r,{recursive:!0,force:!0}),await f(e,{category:"skill",name:a,agent:t})}export async function installFileAsset(e,a,t,r,n="claude",o="project"){i(t);const c=x(a,n,o,e,g()),u=s.join(c,`${t}${S[a].ext}`);if(await l(u))throw new InstallConflictError(`${a} "${t}" is already installed`);return await h(c,{recursive:!0}),await w(r,u),o==="project"&&await p(e,{category:"file",name:t,agent:n,assetCategory:a}),u}export async function uninstallFileAsset(e,a,t,r="claude",n="project"){i(t);const o=x(a,r,n,e,g()),c=s.join(o,`${t}${S[a].ext}`);if(!await l(c))throw new AssetNotFoundError(`${a} "${t}" is not installed`);await m(c,{force:!0}),n==="project"&&await f(e,{category:"file",name:t,agent:r,assetCategory:a})}export async function installMcp(e,a,t){i(a);const r=s.join(e,d),n=await readMcpJson(r),o=n.mcpServers??{};if(a in o)throw new InstallConflictError(`MCP server "${a}" is already configured`);o[a]=t,n.mcpServers=o,await y(r,`${JSON.stringify(n,null,2)}
2
- `,"utf-8"),await p(e,{category:"mcp",name:a,agent:"claude"})}export async function uninstallMcp(e,a){i(a);const t=s.join(e,d),r=await readMcpJson(t),n=r.mcpServers??{};if(!(a in n))throw new AssetNotFoundError(`MCP server "${a}" is not configured`);delete n[a],r.mcpServers=n,await y(t,`${JSON.stringify(r,null,2)}
3
- `,"utf-8"),await f(e,{category:"mcp",name:a,agent:"claude"})}export async function readMcpJson(e){try{const a=await j(e,"utf-8"),t=JSON.parse(a);return t&&typeof t=="object"?t:{}}catch{return{}}}export async function readMcpServers(e){return(await readMcpJson(s.join(e,d))).mcpServers??{}}
1
+ import{cp as p,rm as S,readFile as E,writeFile as x,access as g,mkdir as C}from"node:fs/promises";import{homedir as y}from"node:os";import n from"node:path";import{FILE_ASSET_SPECS as $,fileAssetTargetDir as v}from"./file-assets.js";import{assetSurfaceFor as F}from"../surfaces.js";import{forgetInstalled as f,recordInstalled as d}from"./install-ledger.js";export class InstallConflictError extends Error{constructor(t){super(t),this.name="InstallConflictError"}}export class AssetNotFoundError extends Error{constructor(t){super(t),this.name="AssetNotFoundError"}}const w=".mcp.json";function c(r){if(!r||r.includes("/")||r.includes("\\")||r.includes("..")||r.includes(n.sep))throw new Error(`Invalid asset name: "${r}"`)}async function l(r){try{return await g(r),!0}catch{return!1}}function j(r){return F(r).projectSkillsDir()}export async function installSkill(r,t,i,s="claude"){c(i);const e=n.join(r,j(s),i);if(await l(e))throw new InstallConflictError(`Skill "${i}" is already installed${s==="codex"?" (Codex)":""}`);return await p(t,e,{recursive:!0}),await d(r,{category:"skill",name:i,agent:s}),e}export async function uninstallSkill(r,t,i="claude"){c(t);const s=n.join(r,j(i),t);if(!await l(s))throw new AssetNotFoundError(`Skill "${t}" is not installed${i==="codex"?" (Codex)":""}`);await S(s,{recursive:!0,force:!0}),await f(r,{category:"skill",name:t,agent:i})}export async function installFileAsset(r,t,i,s,e="claude",o="project"){c(i);const a=v(t,e,o,r,y()),u=n.join(a,`${i}${$[t].ext}`);if(await l(u))throw new InstallConflictError(`${t} "${i}" is already installed`);return await C(a,{recursive:!0}),await p(s,u),o==="project"&&await d(r,{category:"file",name:i,agent:e,assetCategory:t}),u}export async function uninstallFileAsset(r,t,i,s="claude",e="project"){c(i);const o=v(t,s,e,r,y()),a=n.join(o,`${i}${$[t].ext}`);if(!await l(a))throw new AssetNotFoundError(`${t} "${i}" is not installed`);await S(a,{force:!0}),e==="project"&&await f(r,{category:"file",name:i,agent:s,assetCategory:t})}export async function installMcp(r,t,i){c(t);const s=n.join(r,w),e=await readMcpJson(s),o=e.mcpServers??{};if(t in o)throw new InstallConflictError(`MCP server "${t}" is already configured`);o[t]=i,e.mcpServers=o,await x(s,`${JSON.stringify(e,null,2)}
2
+ `,"utf-8"),await d(r,{category:"mcp",name:t,agent:"claude"})}export async function uninstallMcp(r,t){c(t);const i=n.join(r,w),s=await readMcpJson(i),e=s.mcpServers??{};if(!(t in e))throw new AssetNotFoundError(`MCP server "${t}" is not configured`);delete e[t],s.mcpServers=e,await x(i,`${JSON.stringify(s,null,2)}
3
+ `,"utf-8"),await f(r,{category:"mcp",name:t,agent:"claude"})}export async function readMcpJson(r){try{const t=await E(r,"utf-8"),i=JSON.parse(t);return i&&typeof i=="object"?i:{}}catch{return{}}}export async function readMcpServers(r){return(await readMcpJson(n.join(r,w))).mcpServers??{}}
@@ -1 +1 @@
1
- import{getLibraryScan as u}from"./scan-cache.js";export async function buildLibraryIndex(e){const a=new Map,i=new Map,s=new Map;for(const n of e){const m=n.kind==="skill"||n.kind==="both",d=n.kind==="mcp"||n.kind==="both";let o;try{o=await u(n.path)}catch{continue}if(m){for(const t of o.skills)a.has(t.name)||a.set(t.name,{name:t.name,libraryId:n.id,libraryPath:n.path,dirPath:t.dirPath});for(const t of Object.values(o.files))for(const r of t){const c=`${r.category}/${r.name}`;s.has(c)||s.set(c,{name:r.name,category:r.category,libraryId:n.id,libraryPath:n.path,filePath:r.filePath})}}if(d){for(const t of o.mcp)if(!i.has(t.name)){const{name:r,command:c,args:f,env:l,sourcePath:h}=t,p={command:c,...f&&{args:f},...l&&{env:l}};i.set(t.name,{name:r,libraryId:n.id,libraryPath:n.path,config:p,sourcePath:h})}}}return{skills:a,mcp:i,files:s}}export function findSkillSource(e,a){return e.skills.get(a)}export function findMcpSource(e,a){return e.mcp.get(a)}export function findFileAssetSource(e,a,i){return e.files.get(`${a}/${i}`)}
1
+ import{getLibraryScan as u}from"./scan-cache.js";export async function buildLibraryIndex(e){const a=new Map,r=new Map,s=new Map;for(const t of e){const m=t.kind==="skill"||t.kind==="both",p=t.kind==="mcp"||t.kind==="both";let o;try{o=await u(t.path)}catch{continue}if(m){for(const n of o.skills)a.has(n.name)||a.set(n.name,{name:n.name,libraryId:t.id,libraryPath:t.path,dirPath:n.dirPath});for(const n of Object.values(o.files))for(const i of n){const c=`${i.category}/${i.name}`;s.has(c)||s.set(c,{name:i.name,category:i.category,libraryId:t.id,libraryPath:t.path,filePath:i.filePath})}}if(p){for(const n of o.mcp)if(!r.has(n.name)){const{name:i,command:c,args:f,env:l,sourcePath:d}=n,h={command:c,...f&&{args:f},...l&&{env:l}};r.set(n.name,{name:i,libraryId:t.id,libraryPath:t.path,config:h,sourcePath:d})}}}return{skills:a,mcp:r,files:s}}export function findSkillSource(e,a){return e.skills.get(a)}export function findMcpSource(e,a){return e.mcp.get(a)}export function findFileAssetSource(e,a,r){return e.files.get(`${a}/${r}`)}
@@ -1 +1 @@
1
- import{readMcpServers as u}from"./installer.js";import{readGlobalMcpServers as M}from"./global-config.js";import{readCodexMcpServers as v}from"./codex-toml.js";import{readMcpEnableMap as h,mcpOverrideOf as S,resolveMcpEffective as b}from"./settings-mcp.js";import{assetSurfaces as w}from"../surfaces.js";export async function readMcpRows(s){const[t,p,l,n]=await Promise.all([u(s).catch(()=>({})),M().catch(()=>({})),v().catch(()=>({})),h(s)]),f=new Map(w().map(e=>[e.harness,e.mcpScopes()])),o=[],r=(e,m,i,a)=>{for(const[c,d]of Object.entries(i))o.push({key:c,category:"mcp",harness:e,scope:m,installScopes:f.get(e)??[],enable:a?S(a,c):null,effective:a?b(a,c):!0,detail:d})};return r("claude","project",t,n),r("claude","user",p,null),r("codex","user",l,null),o}
1
+ import{readMcpServers as d}from"./installer.js";import{readGlobalMcpServers as v}from"./global-config.js";import{readCodexMcpServers as M}from"./codex-toml.js";import{readMcpEnableMap as S,mcpOverrideOf as h,resolveMcpEffective as w}from"./settings-mcp.js";import{assetSurfaces as x}from"../surfaces.js";export async function readMcpRows(s){const[p,a,n,f]=await Promise.all([d(s).catch(()=>({})),v().catch(()=>({})),M().catch(()=>({})),S(s)]),l=new Map(x().map(e=>[e.harness,e.mcpScopes()])),t=[],c=(e,m,i,r)=>{for(const[o,u]of Object.entries(i))t.push({key:o,category:"mcp",harness:e,scope:m,installScopes:l.get(e)??[],enable:r?h(r,o):null,effective:r?w(r,o):!0,detail:u})};return c("claude","project",p,f),c("claude","user",a,null),c("codex","user",n,null),t}
@@ -1 +1 @@
1
- import r from"node:path";import{marketIdOf as t}from"../market/identity.js";import{marketDir as a}from"../market/manifest.js";export async function installPluginPack(o,i){const n=t(i.dir);return o.globalInstall(i.dir,{name:i.name,version:i.version,description:i.description,...n?{marketplace:{name:n,dir:r.join(a(),n)}}:{}})}
1
+ import t from"node:path";import{marketIdOf as o}from"../market/identity.js";import{marketDir as e}from"../market/manifest.js";export async function installPluginPack(n,r){const i=o(r.dir);return n.globalInstall(r.dir,{name:r.name,version:r.version,description:r.description,...i?{marketplace:{name:i,dir:t.join(e(),i)}}:{}})}
@@ -1 +1 @@
1
- import{pluginSurfaces as b,pluginStateSurfaces as g}from"../surfaces.js";const u=["user","project","local"],y=(s,e)=>e in s?s[e]?"on":"off":"inherit";function S(s,e){for(let n=u.length-1;n>=0;n--){const o=s[u[n]][e];if(o!==void 0)return o}return!1}export async function readPluginRows(s){const e=[],n=b();for(const{harness:o,surface:a}of n){const f=a.pluginScopes(),[t,c]=await Promise.all([a.readInstalled().catch(()=>({})),a.readEnabledOverrides(s).catch(()=>({user:{},project:{},local:{}}))]),p=new Set(Object.keys(t));for(const r of u)for(const l of Object.keys(c[r]))p.add(l);for(const r of p){const l=t[r],d=S(c,r);for(const i of f)e.push({key:r,category:"plugin",harness:o,scope:i,installScopes:f,install:l?.some(h=>(h.scope??"user")===i)?"installed":"absent",enable:y(c[i],r),effective:d})}}for(const{harness:o,state:a}of g()){if(n.some(t=>t.harness===o))continue;const f=await a.readGlobalEnabled().catch(()=>({}));for(const[t,c]of Object.entries(f))e.push({key:t,category:"plugin",harness:o,scope:"user",installScopes:[],enable:c?"on":"off",effective:c})}return e}
1
+ import{pluginSurfaces as b,pluginStateSurfaces as g}from"../surfaces.js";const u=["user","project","local"],v=(s,e)=>e in s?s[e]?"on":"off":"inherit";function y(s,e){for(let n=u.length-1;n>=0;n--){const o=s[u[n]][e];if(o!==void 0)return o}return!1}export async function readPluginRows(s){const e=[],n=b();for(const{harness:o,surface:a}of n){const l=a.pluginScopes(),[t,c]=await Promise.all([a.readInstalled().catch(()=>({})),a.readEnabledOverrides(s).catch(()=>({user:{},project:{},local:{}}))]),p=new Set(Object.keys(t));for(const r of u)for(const f of Object.keys(c[r]))p.add(f);for(const r of p){const f=t[r],d=y(c,r);for(const i of l)e.push({key:r,category:"plugin",harness:o,scope:i,installScopes:l,install:f?.some(h=>(h.scope??"user")===i)?"installed":"absent",enable:v(c[i],r),effective:d})}}for(const{harness:o,state:a}of g()){if(n.some(t=>t.harness===o))continue;const l=await a.readGlobalEnabled().catch(()=>({}));for(const[t,c]of Object.entries(l))e.push({key:t,category:"plugin",harness:o,scope:"user",installScopes:[],enable:c?"on":"off",effective:c})}return e}
@@ -1 +1 @@
1
- import{cp as f,mkdir as h,readdir as d,readFile as P,rm as w}from"node:fs/promises";import{homedir as j}from"node:os";import r from"node:path";import{WEAVE_PLUGIN_MANIFEST as y,WeavePluginManifestSchema as k}from"@weavecode/core";import{assetSurfaceFor as v}from"../surfaces.js";const S={skills:"skill",commands:"command",agents:"agent"};async function F(t){const a=[];let s;try{s=await d(t)}catch{return a}for(const o of s){const i=r.join(t,o);try{const c=JSON.parse(await P(r.join(i,y),"utf8")),e=k.safeParse(c);e.success&&a.push({dir:i,manifest:e.data})}catch{}}return a}function E(t,a,s){const o=[];if(!s.templates)return o;const i=v("claude"),c=r.join(t,...i.projectSkillsDir().split("/"));for(const[e,l]of Object.entries(s.templates)){const n=S[e];if(n)for(const p of l??[]){const u=r.resolve(a,p);if(!u.startsWith(r.resolve(a)+r.sep))continue;const m=r.basename(u),g=n==="skill"?c:i.targetDir(n,"project",t,j());o.push({pluginId:s.id,category:n,name:m.replace(/\.md$/,""),sourcePath:u,targetPath:r.join(g,m)})}}return o}export async function detectPluginTemplateUpdates(t,a){const s=[],o=r.join(t,".weave","plugins");for(const{dir:i,manifest:c}of await F(o))for(const e of E(t,i,c)){const[l,n]=e.category==="skill"?await Promise.all([a.get(e.sourcePath),a.get(e.targetPath)]):await Promise.all([a.getFile(e.sourcePath),a.getFile(e.targetPath)]);s.push({...e,outdated:l!==n})}return s}export async function materializePluginTemplate(t){if(t.category==="skill"){await w(t.targetPath,{recursive:!0,force:!0}),await f(t.sourcePath,t.targetPath,{recursive:!0});return}await h(r.dirname(t.targetPath),{recursive:!0}),await f(t.sourcePath,t.targetPath)}
1
+ import{cp as f,mkdir as d,readdir as P,readFile as h,rm as w}from"node:fs/promises";import{homedir as y}from"node:os";import a from"node:path";import{WEAVE_PLUGIN_MANIFEST as k,WeavePluginManifestSchema as v}from"@weavecode/core";import{assetSurfaceFor as E}from"../surfaces.js";const T={skills:"skill",commands:"command",agents:"agent"};async function j(t){const e=[];let s;try{s=await P(t)}catch{return e}for(const o of s){const i=a.join(t,o);try{const c=JSON.parse(await h(a.join(i,k),"utf8")),r=v.safeParse(c);r.success&&e.push({dir:i,manifest:r.data})}catch{}}return e}function S(t,e,s){const o=[];if(!s.templates)return o;const i=E("claude"),c=a.join(t,...i.projectSkillsDir().split("/"));for(const[r,l]of Object.entries(s.templates)){const n=T[r];if(n)for(const p of l??[]){const u=a.resolve(e,p);if(!u.startsWith(a.resolve(e)+a.sep))continue;const m=a.basename(u),g=n==="skill"?c:i.targetDir(n,"project",t,y());o.push({pluginId:s.id,category:n,name:m.replace(/\.md$/,""),sourcePath:u,targetPath:a.join(g,m)})}}return o}export async function detectPluginTemplateUpdates(t,e){const s=[],o=a.join(t,".weave","plugins");for(const{dir:i,manifest:c}of await j(o))for(const r of S(t,i,c)){const[l,n]=r.category==="skill"?await Promise.all([e.get(r.sourcePath),e.get(r.targetPath)]):await Promise.all([e.getFile(r.sourcePath),e.getFile(r.targetPath)]);s.push({...r,outdated:l!==n})}return s}export async function materializePluginTemplate(t){if(t.category==="skill"){await w(t.targetPath,{recursive:!0,force:!0}),await f(t.sourcePath,t.targetPath,{recursive:!0});return}await d(a.dirname(t.targetPath),{recursive:!0}),await f(t.sourcePath,t.targetPath)}
@@ -1,6 +1,4 @@
1
1
  export interface ProjectConfig {
2
- /** When true, the SyncScheduler auto-applies outdated updates on its tick. */
3
- autoSync: boolean;
4
2
  /** ISO timestamp of the last successful sync (null if never). */
5
3
  lastSyncAt: string | null;
6
4
  }
@@ -1,2 +1,2 @@
1
- import{readFile as i,writeFile as e,mkdir as s}from"node:fs/promises";import c from"node:path";const o=".weave",u="config.json";export const DEFAULT_PROJECT_CONFIG={autoSync:!1,lastSyncAt:null};function r(t){return c.join(t,o,u)}function y(t){return{autoSync:t.autoSync??DEFAULT_PROJECT_CONFIG.autoSync,lastSyncAt:t.lastSyncAt??DEFAULT_PROJECT_CONFIG.lastSyncAt}}export async function readProjectConfig(t){try{const n=await i(r(t),"utf-8");return y(JSON.parse(n))}catch{return DEFAULT_PROJECT_CONFIG}}export async function writeProjectConfig(t,n){const a=c.join(t,o);await s(a,{recursive:!0}),await e(r(t),`${JSON.stringify(n,null,2)}
2
- `,"utf-8")}export async function markSynced(t,n){const a=await readProjectConfig(t);await writeProjectConfig(t,{...a,lastSyncAt:n})}
1
+ import{readFile as a,writeFile as e,mkdir as s}from"node:fs/promises";import i from"node:path";const c=".weave",f="config.json";export const DEFAULT_PROJECT_CONFIG={lastSyncAt:null};function o(t){return i.join(t,c,f)}function u(t){return{lastSyncAt:t.lastSyncAt??DEFAULT_PROJECT_CONFIG.lastSyncAt}}export async function readProjectConfig(t){try{const n=await a(o(t),"utf-8");return u(JSON.parse(n))}catch{return DEFAULT_PROJECT_CONFIG}}export async function writeProjectConfig(t,n){const r=i.join(t,c);await s(r,{recursive:!0}),await e(o(t),`${JSON.stringify(n,null,2)}
2
+ `,"utf-8")}export async function markSynced(t,n){const r=await readProjectConfig(t);await writeProjectConfig(t,{...r,lastSyncAt:n})}
@@ -1 +1 @@
1
- import{readFile as l,stat as c}from"node:fs/promises";import{homedir as h}from"node:os";import s from"node:path";import{AssetNotFoundError as a}from"./installer.js";export class PathEscapeError extends Error{constructor(e){super(e),this.name="PathEscapeError"}}export class FileTooLargeError extends Error{constructor(e){super(e),this.name="FileTooLargeError"}}export const MAX_BYTES=512*1024;export function resolveProjectFile(r,e){const t=s.normalize(e).replace(/\\/g,"/");if(s.isAbsolute(e))throw new PathEscapeError(`Absolute paths are not allowed: "${e}"`);if(t.split("/").some(n=>n===".."))throw new PathEscapeError(`Path traversal is not allowed: "${e}"`);if(!(t===".mcp.json"||t==="CLAUDE.md"||t==="AGENTS.md"||t===".claude"||t.startsWith(".claude/")||t===".codex"||t.startsWith(".codex/")||t===".weave"||t.startsWith(".weave/")))throw new PathEscapeError(`Path is outside the allowed roots: "${e}"`);const o=s.join(r,t),i=r.endsWith(s.sep)?r:r+s.sep;if(o!==r&&!o.startsWith(i))throw new PathEscapeError(`Resolved path escapes the project: "${e}"`);return o}export async function readProjectFile(r,e){const t=resolveProjectFile(r,e);let o;try{o=await c(t)}catch{throw new a(`File not found: "${e}"`)}if(!o.isFile())throw new a(`Not a file: "${e}"`);if(o.size>MAX_BYTES)throw new FileTooLargeError(`File exceeds ${MAX_BYTES} bytes: "${e}"`);return{content:await l(t,"utf-8"),size:o.size}}export async function readGlobalFile(r){return readProjectFile(h(),r)}
1
+ import{readFile as l,stat as d}from"node:fs/promises";import{homedir as w}from"node:os";import s from"node:path";import{AssetNotFoundError as n}from"./installer.js";export class PathEscapeError extends Error{constructor(e){super(e),this.name="PathEscapeError"}}export class FileTooLargeError extends Error{constructor(e){super(e),this.name="FileTooLargeError"}}export const MAX_BYTES=512*1024;export function resolveProjectFile(t,e){const o=s.normalize(e).replace(/\\/g,"/");if(s.isAbsolute(e))throw new PathEscapeError(`Absolute paths are not allowed: "${e}"`);if(o.split("/").some(c=>c===".."))throw new PathEscapeError(`Path traversal is not allowed: "${e}"`);if(!(o===".mcp.json"||o==="CLAUDE.md"||o==="AGENTS.md"||o===".claude"||o.startsWith(".claude/")||o===".codex"||o.startsWith(".codex/")||o===".weave"||o.startsWith(".weave/")))throw new PathEscapeError(`Path is outside the allowed roots: "${e}"`);const i=s.join(t,o),a=t.endsWith(s.sep)?t:t+s.sep;if(i!==t&&!i.startsWith(a))throw new PathEscapeError(`Resolved path escapes the project: "${e}"`);return i}export async function readProjectFile(t,e){const o=resolveProjectFile(t,e);let r;try{r=await d(o)}catch{throw new n(`File not found: "${e}"`)}if(!r.isFile())throw new n(`Not a file: "${e}"`);if(r.size>MAX_BYTES)throw new FileTooLargeError(`File exceeds ${MAX_BYTES} bytes: "${e}"`);return{content:await l(o,"utf-8"),size:r.size}}export async function readGlobalFile(t){return readProjectFile(w(),t)}
@@ -1 +1 @@
1
- import{mkdir as f,readFile as p,rm as w,writeFile as m}from"node:fs/promises";import s from"node:path";import{scanLibraryFileAssets as g,scanLibraryMcp as v,scanLibraryPlugins as A,scanLibrarySkills as b}from"./scanner.js";const l="scans.json",u=1;function c(a){const r=s.resolve(a);return s.join(s.dirname(r),".weave-scans",s.basename(r))}const e=new Map,o=new Map;export async function scanLibrary(a){const{plugins:r,packRoots:t}=await A(a),[i,n,y]=await Promise.all([b(a,t),v(a,t),g(a,t)]);return{plugins:r,packRoots:t,skills:i,mcp:n,files:y}}export async function getLibraryScan(a){const r=s.resolve(a),t=e.get(r);if(t)return t;const i=o.get(r);if(i)return i;const n=d(r);o.set(r,n);try{return await n}finally{o.delete(r)}}async function d(a){const r=await k(a);if(r)return e.set(a,r),r;const t=await scanLibrary(a);return await L(a,t),e.set(a,t),t}async function k(a){try{const r=JSON.parse(await p(s.join(c(a),l),"utf8"));return!r||r.version!==u||!Array.isArray(r.plugins)||!Array.isArray(r.packRoots)||!Array.isArray(r.skills)||!Array.isArray(r.mcp)||!r.files||typeof r.files!="object"?null:r}catch{return null}}async function L(a,r){try{await f(c(a),{recursive:!0}),await m(s.join(c(a),l),JSON.stringify({version:u,...r}),"utf8")}catch{}}export async function invalidateScan(a){const r=s.resolve(a);e.delete(r);const t=o.get(r);t&&await t.catch(()=>{}),await w(c(r),{recursive:!0,force:!0}),e.delete(r)}export function clearScanCache(){e.clear()}
1
+ import{mkdir as f,readFile as p,rm as w,writeFile as m}from"node:fs/promises";import t from"node:path";import{scanLibraryFileAssets as d,scanLibraryMcp as g,scanLibraryPlugins as A,scanLibrarySkills as v}from"./scanner.js";const u="scans.json",y=1;function c(n){const r=t.resolve(n);return t.join(t.dirname(r),".weave-scans",t.basename(r))}const a=new Map,o=new Map;export async function scanLibrary(n){const{plugins:r,packRoots:e}=await A(n),[s,i,l]=await Promise.all([v(n,e),g(n,e),d(n,e)]);return{plugins:r,packRoots:e,skills:s,mcp:i,files:l}}export async function getLibraryScan(n){const r=t.resolve(n),e=a.get(r);if(e)return e;const s=o.get(r);if(s)return s;const i=S(r);o.set(r,i);try{return await i}finally{o.delete(r)}}async function S(n){const r=await k(n);if(r)return a.set(n,r),r;const e=await scanLibrary(n);return await L(n,e),a.set(n,e),e}async function k(n){try{const r=JSON.parse(await p(t.join(c(n),u),"utf8"));return!r||r.version!==y||!Array.isArray(r.plugins)||!Array.isArray(r.packRoots)||!Array.isArray(r.skills)||!Array.isArray(r.mcp)||!r.files||typeof r.files!="object"?null:r}catch{return null}}async function L(n,r){try{await f(c(n),{recursive:!0}),await m(t.join(c(n),u),JSON.stringify({version:y,...r}),"utf8")}catch{}}export async function invalidateScan(n){const r=t.resolve(n);a.delete(r);const e=o.get(r);e&&await e.catch(()=>{}),await w(c(r),{recursive:!0,force:!0}),a.delete(r)}export function clearScanCache(){a.clear()}