@xopcai/xopc 0.0.82 → 0.0.84

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 (740) hide show
  1. package/README.md +3 -1
  2. package/README.zh-CN.md +3 -1
  3. package/dist/browser-ext/manifest.json +1 -1
  4. package/dist/extensions/feishu/src/outbound/media-load.js +2 -3
  5. package/dist/extensions/feishu/src/outbound/media-load.js.map +1 -1
  6. package/dist/extensions/feishu/src/schema/config-schema.d.ts +6 -6
  7. package/dist/extensions/telegram/src/config-schema.d.ts +6 -6
  8. package/dist/extensions/telegram/src/plugin.d.ts +1 -1
  9. package/dist/extensions/telegram/src/plugin.js +1 -1
  10. package/dist/extensions/telegram/src/routing-integration.js +2 -2
  11. package/dist/extensions/telegram/xopc.extension.json +1 -1
  12. package/dist/extensions/weixin/src/api/api.js +3 -3
  13. package/dist/extensions/weixin/src/auth/accounts.js +1 -1
  14. package/dist/extensions/weixin/src/cdn/upload.js +1 -1
  15. package/dist/extensions/weixin/src/config-schema.d.ts +3 -3
  16. package/dist/extensions/weixin/src/media/data-url.js +1 -1
  17. package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
  18. package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
  19. package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
  20. package/dist/extensions/weixin/src/plugin.js +1 -1
  21. package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
  22. package/dist/gateway/static/root/assets/agents-tR-nNP04.js +222 -0
  23. package/dist/gateway/static/root/assets/{apps-page-pJ27dsqn.js → apps-page-BDw6SP-d.js} +1 -1
  24. package/dist/gateway/static/root/assets/channels-settings-DEFd-jj1.js +1 -0
  25. package/dist/gateway/static/root/assets/{channels-status-swr-D1KYmOmi.js → channels-status-swr-DI5FHdGe.js} +1 -1
  26. package/dist/gateway/static/root/assets/{cron-api-Y2wfSJVI.js → cron-api-BSqY8LwW.js} +1 -1
  27. package/dist/gateway/static/root/assets/{cron-page-B97KU_RG.js → cron-page-D7lVDjcR.js} +1 -1
  28. package/dist/gateway/static/root/assets/{dist-CboA_Css.js → dist-CqNMNhJM.js} +1 -1
  29. package/dist/gateway/static/root/assets/{extension-debug-page-DN_zNmpo.js → extension-debug-page-gf2L0kY_.js} +1 -1
  30. package/dist/gateway/static/root/assets/{extension-page-BUXtOzv5.js → extension-page-CQo2Xsmg.js} +1 -1
  31. package/dist/gateway/static/root/assets/{extension-settings-page-C2dX4KCW.js → extension-settings-page-CZf0WoZg.js} +1 -1
  32. package/dist/gateway/static/root/assets/fetch-2iRFmd3n.js +3 -0
  33. package/dist/gateway/static/root/assets/{field-primitives-B9rOLqdm.js → field-primitives-DTtlp-l8.js} +1 -1
  34. package/dist/gateway/static/root/assets/{heartbeat-config-api-DvfiRVrc.js → heartbeat-config-api-B0drdQEJ.js} +1 -1
  35. package/dist/gateway/static/root/assets/{index-DQuaMye9.js → index-0Gt3TG4j.js} +94 -85
  36. package/dist/gateway/static/root/assets/index-BuFldCsB.css +1 -0
  37. package/dist/gateway/static/root/assets/{logs-page-BQuBpHcc.js → logs-page-DMuORLfC.js} +1 -1
  38. package/dist/gateway/static/root/assets/sessions-page-_UO8g6NN.js +1 -0
  39. package/dist/gateway/static/root/assets/{settings-form-section-2Yu-FASs.js → settings-form-section-DkmHkknc.js} +1 -1
  40. package/dist/gateway/static/root/assets/settings-page-Cz8FoW_A.js +3 -0
  41. package/dist/gateway/static/root/assets/skills-page-HrUOxF7H.js +2 -0
  42. package/dist/gateway/static/root/assets/{theme-store-DnwYutiX.js → theme-store-D01dJt95.js} +1 -1
  43. package/dist/gateway/static/root/assets/{utils-D2Gn2qod.js → utils-BFwcR6pL.js} +1 -1
  44. package/dist/gateway/static/root/assets/voice-api-key-field-JF8-aqc5.js +1 -0
  45. package/dist/gateway/static/root/index.html +4 -4
  46. package/dist/package.js +1 -1
  47. package/dist/src/agent/agent-instance-gateway.d.ts +50 -0
  48. package/dist/src/agent/agent-instance-gateway.js +1 -0
  49. package/dist/src/agent/agent-manager.d.ts +20 -14
  50. package/dist/src/agent/agent-manager.js +74 -186
  51. package/dist/src/agent/agent-manager.js.map +1 -1
  52. package/dist/src/agent/background-review/coordinator.d.ts +61 -0
  53. package/dist/src/agent/background-review/coordinator.js +120 -0
  54. package/dist/src/agent/background-review/coordinator.js.map +1 -0
  55. package/dist/src/agent/bootstrap/load-bootstrap-files.js +1 -1
  56. package/dist/src/agent/child-agent-factory.d.ts +14 -0
  57. package/dist/src/agent/child-agent-factory.js +2 -8
  58. package/dist/src/agent/child-agent-factory.js.map +1 -1
  59. package/dist/src/agent/context/workspace-seed.js +3 -3
  60. package/dist/src/agent/embedded/index.d.ts +1 -2
  61. package/dist/src/agent/embedded/index.js +2 -3
  62. package/dist/src/agent/embedded/run-for-session.d.ts +2 -2
  63. package/dist/src/agent/embedded/run-for-session.js.map +1 -1
  64. package/dist/src/agent/embedded/runs.d.ts +32 -0
  65. package/dist/src/agent/embedded/runs.js +79 -19
  66. package/dist/src/agent/embedded/runs.js.map +1 -1
  67. package/dist/src/agent/embedded/session-manager-cache.d.ts +14 -0
  68. package/dist/src/agent/embedded/session-manager-cache.js +32 -11
  69. package/dist/src/agent/embedded/session-manager-cache.js.map +1 -1
  70. package/dist/src/agent/embedded/session-runner.d.ts +37 -7
  71. package/dist/src/agent/embedded/session-runner.js +184 -153
  72. package/dist/src/agent/embedded/session-runner.js.map +1 -1
  73. package/dist/src/agent/embedded/session-tool-result-guard.d.ts +57 -9
  74. package/dist/src/agent/embedded/session-tool-result-guard.js +159 -67
  75. package/dist/src/agent/embedded/session-tool-result-guard.js.map +1 -1
  76. package/dist/src/agent/goals/goal-run-store.js +4 -4
  77. package/dist/src/agent/goals/persistent-goal-service.d.ts +84 -0
  78. package/dist/src/agent/goals/persistent-goal-service.js +139 -0
  79. package/dist/src/agent/goals/persistent-goal-service.js.map +1 -0
  80. package/dist/src/agent/goals/post-turn.js +2 -2
  81. package/dist/src/agent/goals/state.d.ts +1 -1
  82. package/dist/src/agent/goals/state.js.map +1 -1
  83. package/dist/src/agent/image/load-image-media.js +1 -1
  84. package/dist/src/agent/inbound/inbound-loop.d.ts +77 -0
  85. package/dist/src/agent/inbound/inbound-loop.js +226 -0
  86. package/dist/src/agent/inbound/inbound-loop.js.map +1 -0
  87. package/dist/src/agent/inbound/turn-dispatcher.d.ts +80 -0
  88. package/dist/src/agent/inbound/turn-dispatcher.js +138 -0
  89. package/dist/src/agent/inbound/turn-dispatcher.js.map +1 -0
  90. package/dist/src/agent/ipc/bus.js +1 -1
  91. package/dist/src/agent/ipc/inbox.js +2 -2
  92. package/dist/src/agent/ipc/socket.js +1 -1
  93. package/dist/src/agent/lifecycle/handlers/compaction.d.ts +1 -1
  94. package/dist/src/agent/lifecycle/handlers/compaction.js.map +1 -1
  95. package/dist/src/agent/lifecycle/manager.d.ts +1 -1
  96. package/dist/src/agent/lifecycle/manager.js.map +1 -1
  97. package/dist/src/agent/lifecycle/types.d.ts +1 -1
  98. package/dist/src/agent/memory/builtin-memory-store.js +1 -1
  99. package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
  100. package/dist/src/agent/memory/dreaming/events.js +1 -1
  101. package/dist/src/agent/memory/dreaming/last-run.js +1 -1
  102. package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
  103. package/dist/src/agent/memory/dreaming/preview.js +1 -1
  104. package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
  105. package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
  106. package/dist/src/agent/memory/dreaming/utils.d.ts +12 -2
  107. package/dist/src/agent/memory/dreaming/utils.js +1 -1
  108. package/dist/src/agent/memory/dreaming/utils.js.map +1 -1
  109. package/dist/src/agent/memory/index.js +3 -3
  110. package/dist/src/agent/memory/plugin-discovery.js +1 -1
  111. package/dist/src/agent/memory/prefetch-coordinator.d.ts +37 -0
  112. package/dist/src/agent/memory/prefetch-coordinator.js +45 -0
  113. package/dist/src/agent/memory/prefetch-coordinator.js.map +1 -0
  114. package/dist/src/agent/messaging/command-handler.d.ts +5 -1
  115. package/dist/src/agent/messaging/command-handler.js +24 -96
  116. package/dist/src/agent/messaging/command-handler.js.map +1 -1
  117. package/dist/src/agent/messaging/index.d.ts +1 -0
  118. package/dist/src/agent/messaging/index.js +2 -1
  119. package/dist/src/agent/messaging/message-router.d.ts +1 -1
  120. package/dist/src/agent/messaging/message-router.js.map +1 -1
  121. package/dist/src/agent/messaging/outbound-coordinator.d.ts +82 -0
  122. package/dist/src/agent/messaging/outbound-coordinator.js +123 -0
  123. package/dist/src/agent/messaging/outbound-coordinator.js.map +1 -0
  124. package/dist/src/agent/models/manager.js +1 -1
  125. package/dist/src/agent/orchestration/agent-event-handler.d.ts +36 -33
  126. package/dist/src/agent/orchestration/agent-event-handler.js +212 -174
  127. package/dist/src/agent/orchestration/agent-event-handler.js.map +1 -1
  128. package/dist/src/agent/orchestration/agent-orchestrator.d.ts +4 -4
  129. package/dist/src/agent/orchestration/agent-orchestrator.js +4 -8
  130. package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
  131. package/dist/src/agent/orchestration/index.d.ts +1 -1
  132. package/dist/src/agent/orchestration/index.js +2 -2
  133. package/dist/src/agent/prompt/service-prompt-builder.js +4 -4
  134. package/dist/src/agent/reply/post-compaction-context.js +1 -1
  135. package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
  136. package/dist/src/agent/sandbox/path-policy.js +1 -1
  137. package/dist/src/agent/service/async-queue.d.ts +20 -0
  138. package/dist/src/agent/service/async-queue.js +53 -0
  139. package/dist/src/agent/service/async-queue.js.map +1 -0
  140. package/dist/src/agent/service/build-direct-message-content.d.ts +2 -2
  141. package/dist/src/agent/service/build-direct-message-content.js.map +1 -1
  142. package/dist/src/agent/service/direct-turn-helpers.d.ts +70 -0
  143. package/dist/src/agent/service/direct-turn-helpers.js +90 -0
  144. package/dist/src/agent/service/direct-turn-helpers.js.map +1 -0
  145. package/dist/src/agent/service/process-direct-one-shot.d.ts +3 -3
  146. package/dist/src/agent/service/process-direct-one-shot.js +17 -34
  147. package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
  148. package/dist/src/agent/service/process-direct-streaming.d.ts +2 -2
  149. package/dist/src/agent/service/process-direct-streaming.js +122 -168
  150. package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
  151. package/dist/src/agent/service/webchat-tts.d.ts +2 -2
  152. package/dist/src/agent/service/webchat-tts.js +1 -1
  153. package/dist/src/agent/service/webchat-tts.js.map +1 -1
  154. package/dist/src/agent/service.d.ts +62 -167
  155. package/dist/src/agent/service.js +177 -786
  156. package/dist/src/agent/service.js.map +1 -1
  157. package/dist/src/agent/session/index.d.ts +4 -0
  158. package/dist/src/agent/session/index.js +5 -1
  159. package/dist/src/agent/session/session-config-service.d.ts +68 -0
  160. package/dist/src/agent/session/session-config-service.js +172 -0
  161. package/dist/src/agent/session/session-config-service.js.map +1 -0
  162. package/dist/src/agent/session/session-context.d.ts +27 -19
  163. package/dist/src/agent/session/session-context.js +39 -24
  164. package/dist/src/agent/session/session-context.js.map +1 -1
  165. package/dist/src/agent/session/session-hydrator.d.ts +42 -0
  166. package/dist/src/agent/session/session-hydrator.js +66 -0
  167. package/dist/src/agent/session/session-hydrator.js.map +1 -0
  168. package/dist/src/agent/session/session-inspector.d.ts +80 -0
  169. package/dist/src/agent/session/session-inspector.js +119 -0
  170. package/dist/src/agent/session/session-inspector.js.map +1 -0
  171. package/dist/src/agent/session/session-state-bag.d.ts +83 -0
  172. package/dist/src/agent/session/session-state-bag.js +192 -0
  173. package/dist/src/agent/session/session-state-bag.js.map +1 -0
  174. package/dist/src/agent/skills/config.js +1 -1
  175. package/dist/src/agent/skills/hub-hash.js +2 -2
  176. package/dist/src/agent/skills/hub-lock.js +1 -1
  177. package/dist/src/agent/skills/hub-pull.js +2 -2
  178. package/dist/src/agent/skills/index.d.ts +0 -2
  179. package/dist/src/agent/skills/index.js +3 -5
  180. package/dist/src/agent/skills/index.js.map +1 -1
  181. package/dist/src/agent/skills/managed-store.js +1 -1
  182. package/dist/src/agent/skills/marketplace/adapters/clawhub/adapter.js +11 -6
  183. package/dist/src/agent/skills/marketplace/adapters/clawhub/adapter.js.map +1 -1
  184. package/dist/src/agent/skills/marketplace/adapters/skillhub/adapter.js +35 -7
  185. package/dist/src/agent/skills/marketplace/adapters/skillhub/adapter.js.map +1 -1
  186. package/dist/src/agent/skills/scanner.js +1 -1
  187. package/dist/src/agent/skills/skill-manage-ops.js +2 -2
  188. package/dist/src/agent/skills/skill-manager.js +1 -1
  189. package/dist/src/agent/tools/browser/tool/browser-use-tool.d.ts +7 -0
  190. package/dist/src/agent/tools/browser/tool/browser-use-tool.js +37 -0
  191. package/dist/src/agent/tools/browser/tool/browser-use-tool.js.map +1 -1
  192. package/dist/src/agent/tools/delegate-tool.d.ts +7 -0
  193. package/dist/src/agent/tools/delegate-tool.js +2 -1
  194. package/dist/src/agent/tools/delegate-tool.js.map +1 -1
  195. package/dist/src/agent/tools/dreaming-tool.js +1 -1
  196. package/dist/src/agent/tools/executor.d.ts +34 -15
  197. package/dist/src/agent/tools/executor.js +44 -79
  198. package/dist/src/agent/tools/executor.js.map +1 -1
  199. package/dist/src/agent/tools/factory.d.ts +6 -0
  200. package/dist/src/agent/tools/factory.js +63 -4
  201. package/dist/src/agent/tools/factory.js.map +1 -1
  202. package/dist/src/agent/tools/image-generate-tool.js +1 -1
  203. package/dist/src/agent/tools/send-media.js +1 -1
  204. package/dist/src/agent/tools/skill-manage-tool.js +1 -1
  205. package/dist/src/agent/tools/skills-tools.js +1 -1
  206. package/dist/src/agent/tools/tts-tool.js +1 -1
  207. package/dist/src/agent/tools/write.js +1 -1
  208. package/dist/src/agent/workspace-runtime/registry.d.ts +48 -0
  209. package/dist/src/agent/workspace-runtime/registry.js +59 -0
  210. package/dist/src/agent/workspace-runtime/registry.js.map +1 -0
  211. package/dist/src/auth/credentials.js +3 -3
  212. package/dist/src/auth/profiles/store.js +1 -1
  213. package/dist/src/auth/sync-provider-auth.js +1 -1
  214. package/dist/src/browser/cdp-local-launcher.js +4 -3
  215. package/dist/src/browser/cdp-local-launcher.js.map +1 -1
  216. package/dist/src/browser/index.d.ts +1 -0
  217. package/dist/src/browser/index.js +2 -1
  218. package/dist/src/browser/manager.js +3 -2
  219. package/dist/src/browser/manager.js.map +1 -1
  220. package/dist/src/browser/providers/browser-ext-install.js +4 -4
  221. package/dist/src/browser/providers/browser-use.js +2 -1
  222. package/dist/src/browser/providers/browser-use.js.map +1 -1
  223. package/dist/src/browser/providers/browserbase.js +2 -1
  224. package/dist/src/browser/providers/browserbase.js.map +1 -1
  225. package/dist/src/browser/providers/cloakbrowser.js +7 -6
  226. package/dist/src/browser/providers/cloakbrowser.js.map +1 -1
  227. package/dist/src/browser/providers/playwright-doctor.d.ts +2 -0
  228. package/dist/src/browser/providers/playwright-doctor.js +7 -3
  229. package/dist/src/browser/providers/playwright-doctor.js.map +1 -1
  230. package/dist/src/browser/readiness.d.ts +33 -0
  231. package/dist/src/browser/readiness.js +138 -0
  232. package/dist/src/browser/readiness.js.map +1 -0
  233. package/dist/src/browser/stealth.js +2 -2
  234. package/dist/src/channels/attachments/inbound-persist.js +1 -1
  235. package/dist/src/channels/attachments/outbound-tts-persist.js +1 -1
  236. package/dist/src/channels/channel-domain.d.ts +1 -1
  237. package/dist/src/channels/config-helpers.d.ts +1 -1
  238. package/dist/src/channels/config-helpers.js.map +1 -1
  239. package/dist/src/channels/heartbeat-scheduler.d.ts +40 -0
  240. package/dist/src/channels/heartbeat-scheduler.js +94 -0
  241. package/dist/src/channels/heartbeat-scheduler.js.map +1 -0
  242. package/dist/src/channels/lifecycle-supervisor.d.ts +81 -0
  243. package/dist/src/channels/lifecycle-supervisor.js +263 -0
  244. package/dist/src/channels/lifecycle-supervisor.js.map +1 -0
  245. package/dist/src/channels/manager.d.ts +34 -68
  246. package/dist/src/channels/manager.js +107 -477
  247. package/dist/src/channels/manager.js.map +1 -1
  248. package/dist/src/channels/outbound/deliver.d.ts +1 -1
  249. package/dist/src/channels/outbound/deliver.js.map +1 -1
  250. package/dist/src/channels/outbound/persist-store.js +1 -1
  251. package/dist/src/channels/outbound-sender.d.ts +51 -0
  252. package/dist/src/channels/outbound-sender.js +125 -0
  253. package/dist/src/channels/outbound-sender.js.map +1 -0
  254. package/dist/src/channels/pairing/allow-from-file.js +1 -1
  255. package/dist/src/channels/pairing/pairing-service.d.ts +3 -10
  256. package/dist/src/channels/pairing/pairing-service.js.map +1 -1
  257. package/dist/src/channels/pairing/pairing-store.js +2 -2
  258. package/dist/src/channels/pairing/pairing-types.d.ts +15 -0
  259. package/dist/src/channels/pairing/pairing-types.js +1 -0
  260. package/dist/src/channels/plugin-registry.d.ts +22 -0
  261. package/dist/src/channels/plugin-registry.js +44 -0
  262. package/dist/src/channels/plugin-registry.js.map +1 -0
  263. package/dist/src/channels/plugin-types.d.ts +1 -1
  264. package/dist/src/channels/plugins/types.adapters.d.ts +2 -2
  265. package/dist/src/channels/security-helpers.d.ts +1 -1
  266. package/dist/src/channels/security-helpers.js.map +1 -1
  267. package/dist/src/channels/setup-wizard.d.ts +1 -1
  268. package/dist/src/chat-commands/builtins/config.js +2 -2
  269. package/dist/src/chat-commands/context.js +1 -1
  270. package/dist/src/cli/command-catalog.js +110 -8
  271. package/dist/src/cli/command-catalog.js.map +1 -1
  272. package/dist/src/cli/command-loaders.js +2 -0
  273. package/dist/src/cli/command-loaders.js.map +1 -1
  274. package/dist/src/cli/command-manifest.js +9 -1
  275. package/dist/src/cli/command-manifest.js.map +1 -1
  276. package/dist/src/cli/commands/agent/stream-renderer.js +1 -1
  277. package/dist/src/cli/commands/agent/stream-renderer.js.map +1 -1
  278. package/dist/src/cli/commands/agent.js +4 -4
  279. package/dist/src/cli/commands/agent.js.map +1 -1
  280. package/dist/src/cli/commands/browser-cli-helpers.js +2 -1
  281. package/dist/src/cli/commands/browser-cli-helpers.js.map +1 -1
  282. package/dist/src/cli/commands/config.js +70 -19
  283. package/dist/src/cli/commands/config.js.map +1 -1
  284. package/dist/src/cli/commands/cron-cli.d.ts +2 -0
  285. package/dist/src/cli/commands/cron-cli.js +15 -0
  286. package/dist/src/cli/commands/cron-cli.js.map +1 -0
  287. package/dist/src/cli/commands/cron.d.ts +4 -1
  288. package/dist/src/cli/commands/cron.js +76 -41
  289. package/dist/src/cli/commands/cron.js.map +1 -1
  290. package/dist/src/cli/commands/doctor/checks/channel-config.js +1 -1
  291. package/dist/src/cli/commands/doctor/checks/channel-config.js.map +1 -1
  292. package/dist/src/cli/commands/doctor/checks/config-health.js +2 -2
  293. package/dist/src/cli/commands/doctor/checks/config-health.js.map +1 -1
  294. package/dist/src/cli/commands/doctor/checks/cron-health.js +1 -1
  295. package/dist/src/cli/commands/doctor/checks/cron-health.js.map +1 -1
  296. package/dist/src/cli/commands/doctor/checks/gateway-health.js +2 -2
  297. package/dist/src/cli/commands/doctor/checks/gateway-health.js.map +1 -1
  298. package/dist/src/cli/commands/doctor/checks/gateway-service.js +2 -2
  299. package/dist/src/cli/commands/doctor/checks/gateway-service.js.map +1 -1
  300. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  301. package/dist/src/cli/commands/doctor/checks/session-integrity.js +1 -1
  302. package/dist/src/cli/commands/doctor/checks/state-integrity.js +2 -2
  303. package/dist/src/cli/commands/doctor/checks/state-integrity.js.map +1 -1
  304. package/dist/src/cli/commands/doctor/checks/workspace-status.js +4 -4
  305. package/dist/src/cli/commands/doctor/checks/workspace-status.js.map +1 -1
  306. package/dist/src/cli/commands/extension-dev.js +2 -2
  307. package/dist/src/cli/commands/extension-dev.js.map +1 -1
  308. package/dist/src/cli/commands/extension-marketplace.js +2 -2
  309. package/dist/src/cli/commands/extension-marketplace.js.map +1 -1
  310. package/dist/src/cli/commands/extension-pack.js +1 -1
  311. package/dist/src/cli/commands/gateway/call.js +1 -1
  312. package/dist/src/cli/commands/gateway/call.js.map +1 -1
  313. package/dist/src/cli/commands/gateway/health.js +1 -1
  314. package/dist/src/cli/commands/gateway/health.js.map +1 -1
  315. package/dist/src/cli/commands/gateway/index.d.ts +1 -1
  316. package/dist/src/cli/commands/gateway/index.js +2 -2
  317. package/dist/src/cli/commands/gateway/lifecycle-core.d.ts +31 -12
  318. package/dist/src/cli/commands/gateway/lifecycle-core.js +167 -116
  319. package/dist/src/cli/commands/gateway/lifecycle-core.js.map +1 -1
  320. package/dist/src/cli/commands/gateway/lifecycle.d.ts +11 -0
  321. package/dist/src/cli/commands/gateway/lifecycle.js +102 -0
  322. package/dist/src/cli/commands/gateway/lifecycle.js.map +1 -0
  323. package/dist/src/cli/commands/gateway/logs.js +1 -1
  324. package/dist/src/cli/commands/gateway/logs.js.map +1 -1
  325. package/dist/src/cli/commands/gateway/probe.js +1 -1
  326. package/dist/src/cli/commands/gateway/probe.js.map +1 -1
  327. package/dist/src/cli/commands/gateway/restart-health.d.ts +12 -0
  328. package/dist/src/cli/commands/gateway/restart-health.js +45 -1
  329. package/dist/src/cli/commands/gateway/restart-health.js.map +1 -1
  330. package/dist/src/cli/commands/gateway/restart.js +3 -3
  331. package/dist/src/cli/commands/gateway/restart.js.map +1 -1
  332. package/dist/src/cli/commands/gateway/run-foreground.d.ts +0 -1
  333. package/dist/src/cli/commands/gateway/run-foreground.js +0 -35
  334. package/dist/src/cli/commands/gateway/run-foreground.js.map +1 -1
  335. package/dist/src/cli/commands/gateway/service.d.ts +4 -0
  336. package/dist/src/cli/commands/gateway/service.js +18 -3
  337. package/dist/src/cli/commands/gateway/service.js.map +1 -1
  338. package/dist/src/cli/commands/gateway/shared.d.ts +3 -0
  339. package/dist/src/cli/commands/gateway/shared.js +54 -0
  340. package/dist/src/cli/commands/gateway/shared.js.map +1 -0
  341. package/dist/src/cli/commands/gateway/status.js +1 -1
  342. package/dist/src/cli/commands/gateway/status.js.map +1 -1
  343. package/dist/src/cli/commands/gateway/stop.js +2 -2
  344. package/dist/src/cli/commands/gateway/stop.js.map +1 -1
  345. package/dist/src/cli/commands/gateway/subcommands.js +1 -4
  346. package/dist/src/cli/commands/gateway/subcommands.js.map +1 -1
  347. package/dist/src/cli/commands/gateway/token.js +1 -1
  348. package/dist/src/cli/commands/gateway/token.js.map +1 -1
  349. package/dist/src/cli/commands/gateway.js +5 -5
  350. package/dist/src/cli/commands/gateway.js.map +1 -1
  351. package/dist/src/cli/commands/image.js +2 -2
  352. package/dist/src/cli/commands/image.js.map +1 -1
  353. package/dist/src/cli/commands/init.js +31 -4
  354. package/dist/src/cli/commands/init.js.map +1 -1
  355. package/dist/src/cli/commands/models.d.ts +4 -1
  356. package/dist/src/cli/commands/models.js +87 -75
  357. package/dist/src/cli/commands/models.js.map +1 -1
  358. package/dist/src/cli/commands/onboard/gateway.d.ts +0 -8
  359. package/dist/src/cli/commands/onboard/gateway.js +48 -49
  360. package/dist/src/cli/commands/onboard/gateway.js.map +1 -1
  361. package/dist/src/cli/commands/onboard.js +11 -64
  362. package/dist/src/cli/commands/onboard.js.map +1 -1
  363. package/dist/src/cli/commands/profile.d.ts +3 -5
  364. package/dist/src/cli/commands/profile.js +31 -31
  365. package/dist/src/cli/commands/profile.js.map +1 -1
  366. package/dist/src/cli/commands/session/utils.js +1 -1
  367. package/dist/src/cli/commands/session/utils.js.map +1 -1
  368. package/dist/src/cli/commands/setup.js +6 -1
  369. package/dist/src/cli/commands/setup.js.map +1 -1
  370. package/dist/src/cli/commands/skills.js +1 -1
  371. package/dist/src/cli/commands/tailscale.js +1 -1
  372. package/dist/src/cli/commands/tailscale.js.map +1 -1
  373. package/dist/src/cli/context.d.ts +20 -0
  374. package/dist/src/cli/context.js +23 -0
  375. package/dist/src/cli/context.js.map +1 -0
  376. package/dist/src/cli/extension-cli-register.js +3 -3
  377. package/dist/src/cli/gateway-run-argv.js +16 -9
  378. package/dist/src/cli/gateway-run-argv.js.map +1 -1
  379. package/dist/src/cli/gateway-run-fast-path.js +1 -1
  380. package/dist/src/cli/gateway-run-fast-path.js.map +1 -1
  381. package/dist/src/cli/index.d.ts +1 -7
  382. package/dist/src/cli/index.js +4 -6
  383. package/dist/src/cli/index.js.map +1 -1
  384. package/dist/src/cli/utils/init-workspace-core.js +2 -2
  385. package/dist/src/config/commands.flags.d.ts +3 -0
  386. package/dist/src/config/commands.flags.js +11 -0
  387. package/dist/src/config/commands.flags.js.map +1 -0
  388. package/dist/src/config/index.d.ts +1 -0
  389. package/dist/src/config/index.js +6 -5
  390. package/dist/src/config/index.js.map +1 -1
  391. package/dist/src/config/loader.js +2 -2
  392. package/dist/src/config/models-json.js +2 -2
  393. package/dist/src/config/profile.js +2 -2
  394. package/dist/src/config/schema.d.ts +11 -4
  395. package/dist/src/config/schema.js +13 -12
  396. package/dist/src/config/schema.js.map +1 -1
  397. package/dist/src/config/workspace-path-helpers.d.ts +15 -0
  398. package/dist/src/config/workspace-path-helpers.js +14 -0
  399. package/dist/src/config/workspace-path-helpers.js.map +1 -0
  400. package/dist/src/cron/executor.js +4 -4
  401. package/dist/src/cron/executor.js.map +1 -1
  402. package/dist/src/cron/persistence.js +1 -1
  403. package/dist/src/cron/run-log-store.js +1 -1
  404. package/dist/src/daemon/index.d.ts +0 -1
  405. package/dist/src/daemon/index.js +1 -2
  406. package/dist/src/daemon/install-plan.js +3 -2
  407. package/dist/src/daemon/install-plan.js.map +1 -1
  408. package/dist/src/daemon/launchd.js +2 -2
  409. package/dist/src/daemon/systemd.js +2 -2
  410. package/dist/src/daemon/types.d.ts +0 -6
  411. package/dist/src/extensions/api.d.ts +1 -1
  412. package/dist/src/extensions/api.js +2 -2
  413. package/dist/src/extensions/api.js.map +1 -1
  414. package/dist/src/extensions/bundle-mcp.js +1 -1
  415. package/dist/src/extensions/discover-extensions.js +1 -1
  416. package/dist/src/extensions/extension-registry-impl.d.ts +51 -0
  417. package/dist/src/extensions/extension-registry-impl.js +117 -0
  418. package/dist/src/extensions/extension-registry-impl.js.map +1 -0
  419. package/dist/src/extensions/health.js +1 -1
  420. package/dist/src/extensions/index.js +3 -2
  421. package/dist/src/extensions/loader.d.ts +3 -43
  422. package/dist/src/extensions/loader.js +3 -110
  423. package/dist/src/extensions/loader.js.map +1 -1
  424. package/dist/src/extensions/lockfile.js +2 -2
  425. package/dist/src/extensions/sdk/index.js +2 -1
  426. package/dist/src/extensions/sdk/index.js.map +1 -1
  427. package/dist/src/extensions/types/events.d.ts +7 -1
  428. package/dist/src/gateway/agents-admin.js +2 -2
  429. package/dist/src/gateway/file-path-classifier.js +2 -2
  430. package/dist/src/gateway/heartbeat/service.js +1 -1
  431. package/dist/src/gateway/heartbeat/service.js.map +1 -1
  432. package/dist/src/gateway/hono/app.js +5 -53
  433. package/dist/src/gateway/hono/app.js.map +1 -1
  434. package/dist/src/gateway/hono/lib/extension-store.js +1 -1
  435. package/dist/src/gateway/hono/lib/static-ui.js +2 -2
  436. package/dist/src/gateway/hono/middleware/auth.d.ts +5 -14
  437. package/dist/src/gateway/hono/middleware/auth.js +89 -126
  438. package/dist/src/gateway/hono/middleware/auth.js.map +1 -1
  439. package/dist/src/gateway/hono/middleware/logger.js +1 -1
  440. package/dist/src/gateway/hono/middleware/logger.js.map +1 -1
  441. package/dist/src/gateway/hono/middleware/strict-rate-limit.d.ts +14 -0
  442. package/dist/src/gateway/hono/middleware/strict-rate-limit.js +62 -0
  443. package/dist/src/gateway/hono/middleware/strict-rate-limit.js.map +1 -0
  444. package/dist/src/gateway/hono/oauth.js +1 -1
  445. package/dist/src/gateway/hono/routes/auth-registry-extensions.js +4 -4
  446. package/dist/src/gateway/hono/routes/auth-registry-extensions.js.map +1 -1
  447. package/dist/src/gateway/hono/routes/browser.d.ts +20 -0
  448. package/dist/src/gateway/hono/routes/browser.js +626 -0
  449. package/dist/src/gateway/hono/routes/browser.js.map +1 -0
  450. package/dist/src/gateway/hono/routes/commands-skills.js +13 -13
  451. package/dist/src/gateway/hono/routes/commands-skills.js.map +1 -1
  452. package/dist/src/gateway/hono/routes/config-patch/agents.d.ts +18 -0
  453. package/dist/src/gateway/hono/routes/config-patch/agents.js +418 -0
  454. package/dist/src/gateway/hono/routes/config-patch/agents.js.map +1 -0
  455. package/dist/src/gateway/hono/routes/config-patch/channels.d.ts +12 -0
  456. package/dist/src/gateway/hono/routes/config-patch/channels.js +186 -0
  457. package/dist/src/gateway/hono/routes/config-patch/channels.js.map +1 -0
  458. package/dist/src/gateway/hono/routes/config-patch/gateway.d.ts +18 -0
  459. package/dist/src/gateway/hono/routes/config-patch/gateway.js +264 -0
  460. package/dist/src/gateway/hono/routes/config-patch/gateway.js.map +1 -0
  461. package/dist/src/gateway/hono/routes/config-patch/index.d.ts +9 -0
  462. package/dist/src/gateway/hono/routes/config-patch/index.js +6 -0
  463. package/dist/src/gateway/hono/routes/config-patch/misc.d.ts +23 -0
  464. package/dist/src/gateway/hono/routes/config-patch/misc.js +139 -0
  465. package/dist/src/gateway/hono/routes/config-patch/misc.js.map +1 -0
  466. package/dist/src/gateway/hono/routes/config-patch/result.d.ts +18 -0
  467. package/dist/src/gateway/hono/routes/config-patch/result.js +13 -0
  468. package/dist/src/gateway/hono/routes/config-patch/result.js.map +1 -0
  469. package/dist/src/gateway/hono/routes/config.js +20 -1764
  470. package/dist/src/gateway/hono/routes/config.js.map +1 -1
  471. package/dist/src/gateway/hono/routes/dreaming.js +2 -3
  472. package/dist/src/gateway/hono/routes/dreaming.js.map +1 -1
  473. package/dist/src/gateway/hono/routes/host-fs.js +1 -1
  474. package/dist/src/gateway/hono/routes/lazy-bundles.js +10 -5
  475. package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
  476. package/dist/src/gateway/hono/routes/mcp.js +1 -2
  477. package/dist/src/gateway/hono/routes/mcp.js.map +1 -1
  478. package/dist/src/gateway/hono/routes/models.js +1 -1
  479. package/dist/src/gateway/hono/routes/sessions.js +32 -32
  480. package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
  481. package/dist/src/gateway/hono/routes/shares.js +4 -4
  482. package/dist/src/gateway/hono/routes/shares.js.map +1 -1
  483. package/dist/src/gateway/hono/routes/tunnel.js +1 -1
  484. package/dist/src/gateway/hono/routes/tunnel.js.map +1 -1
  485. package/dist/src/gateway/hono/routes/workspace.js +6 -7
  486. package/dist/src/gateway/hono/routes/workspace.js.map +1 -1
  487. package/dist/src/gateway/hono/sse.js +2 -2
  488. package/dist/src/gateway/index.d.ts +1 -1
  489. package/dist/src/gateway/index.js +4 -2
  490. package/dist/src/gateway/lock.js +3 -3
  491. package/dist/src/gateway/rate-limit/auth-policy.d.ts +34 -0
  492. package/dist/src/gateway/rate-limit/auth-policy.js +49 -0
  493. package/dist/src/gateway/rate-limit/auth-policy.js.map +1 -0
  494. package/dist/src/gateway/rate-limit/buckets.d.ts +63 -0
  495. package/dist/src/gateway/rate-limit/buckets.js +143 -0
  496. package/dist/src/gateway/rate-limit/buckets.js.map +1 -0
  497. package/dist/src/gateway/rate-limit/env-flags.d.ts +13 -0
  498. package/dist/src/gateway/rate-limit/env-flags.js +16 -0
  499. package/dist/src/gateway/rate-limit/env-flags.js.map +1 -0
  500. package/dist/src/gateway/rate-limit/index.d.ts +3 -0
  501. package/dist/src/gateway/rate-limit/index.js +4 -0
  502. package/dist/src/gateway/run-loop.d.ts +1 -1
  503. package/dist/src/gateway/run-loop.js +24 -4
  504. package/dist/src/gateway/run-loop.js.map +1 -1
  505. package/dist/src/gateway/runtime-config.js +2 -1
  506. package/dist/src/gateway/runtime-config.js.map +1 -1
  507. package/dist/src/gateway/security/audit.js +2 -1
  508. package/dist/src/gateway/security/audit.js.map +1 -1
  509. package/dist/src/gateway/security/index.d.ts +0 -1
  510. package/dist/src/gateway/security/index.js +1 -2
  511. package/dist/src/gateway/security/loopback.d.ts +13 -0
  512. package/dist/src/gateway/security/loopback.js +45 -0
  513. package/dist/src/gateway/security/loopback.js.map +1 -0
  514. package/dist/src/gateway/service/agent-runner.d.ts +108 -0
  515. package/dist/src/gateway/service/agent-runner.js +184 -0
  516. package/dist/src/gateway/service/agent-runner.js.map +1 -0
  517. package/dist/src/gateway/service/config-coordinator.d.ts +119 -0
  518. package/dist/src/gateway/service/config-coordinator.js +351 -0
  519. package/dist/src/gateway/service/config-coordinator.js.map +1 -0
  520. package/dist/src/gateway/service/marketplace-service.d.ts +85 -0
  521. package/dist/src/gateway/service/marketplace-service.js +239 -0
  522. package/dist/src/gateway/service/marketplace-service.js.map +1 -0
  523. package/dist/src/gateway/service/run-gateway-agent.js +5 -5
  524. package/dist/src/gateway/service/run-gateway-agent.js.map +1 -1
  525. package/dist/src/gateway/service/sessions-api.d.ts +125 -0
  526. package/dist/src/gateway/service/sessions-api.js +135 -0
  527. package/dist/src/gateway/service/sessions-api.js.map +1 -0
  528. package/dist/src/gateway/service.d.ts +30 -360
  529. package/dist/src/gateway/service.js +122 -904
  530. package/dist/src/gateway/service.js.map +1 -1
  531. package/dist/src/gateway/workspace-fs-file-list.js +1 -1
  532. package/dist/src/gateway/workspace-heartbeat-path.js +1 -2
  533. package/dist/src/gateway/workspace-heartbeat-path.js.map +1 -1
  534. package/dist/src/infra/gateway-process-argv.d.ts +4 -0
  535. package/dist/src/infra/gateway-process-argv.js +26 -0
  536. package/dist/src/infra/gateway-process-argv.js.map +1 -0
  537. package/dist/src/infra/gateway-processes.d.ts +5 -0
  538. package/dist/src/infra/gateway-processes.js +65 -0
  539. package/dist/src/infra/gateway-processes.js.map +1 -0
  540. package/dist/src/infra/rate-limit/failure-limiter.d.ts +50 -0
  541. package/dist/src/infra/rate-limit/failure-limiter.js +100 -0
  542. package/dist/src/infra/rate-limit/failure-limiter.js.map +1 -0
  543. package/dist/src/infra/rate-limit/index.d.ts +5 -0
  544. package/dist/src/infra/rate-limit/index.js +3 -0
  545. package/dist/src/infra/rate-limit/keyed-store.d.ts +34 -0
  546. package/dist/src/infra/rate-limit/keyed-store.js +44 -0
  547. package/dist/src/infra/rate-limit/keyed-store.js.map +1 -0
  548. package/dist/src/infra/rate-limit/rate-limiter.d.ts +39 -0
  549. package/dist/src/infra/rate-limit/rate-limiter.js +65 -0
  550. package/dist/src/infra/rate-limit/rate-limiter.js.map +1 -0
  551. package/dist/src/infra/restart.d.ts +21 -0
  552. package/dist/src/infra/restart.js +122 -0
  553. package/dist/src/infra/restart.js.map +1 -0
  554. package/dist/src/infra/update-check.js +1 -1
  555. package/dist/src/infra/update-lock.js +3 -3
  556. package/dist/src/infra/update-runner.js +1 -1
  557. package/dist/src/infra/update-startup.js +2 -2
  558. package/dist/src/infra/write-file-atomic.js +2 -2
  559. package/dist/src/mcp/channel-bridge.d.ts +0 -6
  560. package/dist/src/mcp/channel-bridge.js +1 -5
  561. package/dist/src/mcp/channel-bridge.js.map +1 -1
  562. package/dist/src/media-shared/http/ssrf-guard.js +1 -1
  563. package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
  564. package/dist/src/providers/index.js +2 -2
  565. package/dist/src/providers/model-registry.js +1 -1
  566. package/dist/src/session/config-store.js +2 -2
  567. package/dist/src/session/parity/jsonl-transcript-io.js +2 -2
  568. package/dist/src/session/parity/sessions-json-file-read.d.ts +2 -1
  569. package/dist/src/session/parity/sessions-json-file-read.js.map +1 -1
  570. package/dist/src/session/parity/sessions-json-file.js +1 -1
  571. package/dist/src/session/parity/transcript-file-lock.js +2 -2
  572. package/dist/src/session/parity/transcript-paths.js +1 -1
  573. package/dist/src/session/search-index-cache.js +1 -1
  574. package/dist/src/session/search-index.js +1 -1
  575. package/dist/src/session/session-title.js +1 -1
  576. package/dist/src/session/store.js +5 -5
  577. package/dist/src/share/share-rate-limit.d.ts +10 -2
  578. package/dist/src/share/share-rate-limit.js +33 -42
  579. package/dist/src/share/share-rate-limit.js.map +1 -1
  580. package/dist/src/share/share-store.js +3 -3
  581. package/dist/src/tui/backends/embedded-backend.js +16 -12
  582. package/dist/src/tui/backends/embedded-backend.js.map +1 -1
  583. package/dist/src/tui/clipboard-image.js +2 -2
  584. package/dist/src/tui/extension-host/load-extensions.js +1 -1
  585. package/dist/src/tui/format-tui-hotkeys.js +1 -1
  586. package/dist/src/tui/theme-manager.js +1 -1
  587. package/dist/src/tui/tui-keybindings-file.js +1 -1
  588. package/dist/src/tui/tui-scoped-models.js +1 -1
  589. package/dist/src/tui/tui-settings.js +1 -1
  590. package/dist/src/tui/tui-skills-autocomplete.js +1 -1
  591. package/dist/src/tui/tui.js +1 -2
  592. package/dist/src/tui/tui.js.map +1 -1
  593. package/dist/src/tui/xopc-tui-keybindings.d.ts +0 -1
  594. package/dist/src/tui/xopc-tui-keybindings.js +1 -2
  595. package/dist/src/tui/xopc-tui-keybindings.js.map +1 -1
  596. package/dist/src/tunnel/frpc-binary.js +2 -2
  597. package/dist/src/tunnel/frpc-config.js +1 -1
  598. package/dist/src/tunnel/frpc-extract.js +1 -1
  599. package/dist/src/tunnel/pairing-rate-limit.d.ts +10 -2
  600. package/dist/src/tunnel/pairing-rate-limit.js +19 -15
  601. package/dist/src/tunnel/pairing-rate-limit.js.map +1 -1
  602. package/dist/src/tunnel/tunnel-rate-limit.d.ts +6 -3
  603. package/dist/src/tunnel/tunnel-rate-limit.js +11 -22
  604. package/dist/src/tunnel/tunnel-rate-limit.js.map +1 -1
  605. package/dist/src/tunnel/tunnel-state.js +1 -1
  606. package/dist/src/utils/logger/audit.js +1 -1
  607. package/dist/src/utils/logger/log-store.js +1 -1
  608. package/dist/src/utils/logger/rotation.js +1 -1
  609. package/dist/src/utils/logger/stats.d.ts +1 -1
  610. package/dist/src/voice/tts/audio.js +1 -1
  611. package/dist/src/voice/tts/factory.js +1 -1
  612. package/dist/src/voice/tts/index.js +2 -2
  613. package/dist/src/voice/tts/merge-config.js +1 -1
  614. package/dist/src/voice/tts/providers/edge-speech.js +1 -1
  615. package/dist/src/voice/tts/service.js +1 -1
  616. package/dist/src/voice/tts/service.js.map +1 -1
  617. package/dist/src/voice/tts/speak-core.js +1 -1
  618. package/package.json +10 -5
  619. package/dist/gateway/static/root/assets/agents-Cqh1ts38.js +0 -222
  620. package/dist/gateway/static/root/assets/channels-settings-wTiWStg9.js +0 -1
  621. package/dist/gateway/static/root/assets/fetch-BAAh_kXG.js +0 -3
  622. package/dist/gateway/static/root/assets/index-C8yHX-AA.css +0 -1
  623. package/dist/gateway/static/root/assets/sessions-page-BeiFm0Ms.js +0 -1
  624. package/dist/gateway/static/root/assets/settings-page-RPAz_Wg_.js +0 -3
  625. package/dist/gateway/static/root/assets/skills-page-Wu4aNWDx.js +0 -2
  626. package/dist/gateway/static/root/assets/voice-api-key-field-BxIGhhEL.js +0 -1
  627. package/dist/src/agent/embedded/session-raw-append-message.d.ts +0 -11
  628. package/dist/src/agent/embedded/session-raw-append-message.js +0 -15
  629. package/dist/src/agent/embedded/session-raw-append-message.js.map +0 -1
  630. package/dist/src/agent/embedded/session-tool-result-guard-wrapper.d.ts +0 -15
  631. package/dist/src/agent/embedded/session-tool-result-guard-wrapper.js +0 -24
  632. package/dist/src/agent/embedded/session-tool-result-guard-wrapper.js.map +0 -1
  633. package/dist/src/agent/embedded/session-tool-result-state.d.ts +0 -17
  634. package/dist/src/agent/embedded/session-tool-result-state.js +0 -26
  635. package/dist/src/agent/embedded/session-tool-result-state.js.map +0 -1
  636. package/dist/src/daemon/launchd-restart-handoff.d.ts +0 -25
  637. package/dist/src/daemon/launchd-restart-handoff.js +0 -132
  638. package/dist/src/daemon/launchd-restart-handoff.js.map +0 -1
  639. package/dist/src/gateway/auth-rate-limit.d.ts +0 -71
  640. package/dist/src/gateway/auth-rate-limit.js +0 -192
  641. package/dist/src/gateway/auth-rate-limit.js.map +0 -1
  642. package/dist/src/gateway/restart-handler.d.ts +0 -14
  643. package/dist/src/gateway/restart-handler.js +0 -64
  644. package/dist/src/gateway/restart-handler.js.map +0 -1
  645. package/dist/src/gateway/security/flood-guard.d.ts +0 -28
  646. package/dist/src/gateway/security/flood-guard.js +0 -42
  647. package/dist/src/gateway/security/flood-guard.js.map +0 -1
  648. package/dist/src/infra/rate-limit.d.ts +0 -38
  649. package/dist/src/infra/rate-limit.js +0 -60
  650. package/dist/src/infra/rate-limit.js.map +0 -1
  651. package/dist/src/infra/restart-intent.d.ts +0 -13
  652. package/dist/src/infra/restart-intent.js +0 -40
  653. package/dist/src/infra/restart-intent.js.map +0 -1
  654. package/dist/src/infra/restart-sentinel.d.ts +0 -23
  655. package/dist/src/infra/restart-sentinel.js +0 -75
  656. package/dist/src/infra/restart-sentinel.js.map +0 -1
  657. package/skills/creative/canvas-design/LICENSE.txt +0 -202
  658. package/skills/creative/canvas-design/SKILL-zh.md +0 -130
  659. package/skills/creative/canvas-design/SKILL.md +0 -130
  660. package/skills/creative/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +0 -93
  661. package/skills/creative/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
  662. package/skills/creative/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
  663. package/skills/creative/canvas-design/canvas-fonts/BigShoulders-OFL.txt +0 -93
  664. package/skills/creative/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
  665. package/skills/creative/canvas-design/canvas-fonts/Boldonse-OFL.txt +0 -93
  666. package/skills/creative/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
  667. package/skills/creative/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
  668. package/skills/creative/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +0 -93
  669. package/skills/creative/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
  670. package/skills/creative/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
  671. package/skills/creative/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
  672. package/skills/creative/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +0 -93
  673. package/skills/creative/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
  674. package/skills/creative/canvas-design/canvas-fonts/DMMono-OFL.txt +0 -93
  675. package/skills/creative/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
  676. package/skills/creative/canvas-design/canvas-fonts/EricaOne-OFL.txt +0 -94
  677. package/skills/creative/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
  678. package/skills/creative/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
  679. package/skills/creative/canvas-design/canvas-fonts/GeistMono-OFL.txt +0 -93
  680. package/skills/creative/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
  681. package/skills/creative/canvas-design/canvas-fonts/Gloock-OFL.txt +0 -93
  682. package/skills/creative/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
  683. package/skills/creative/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
  684. package/skills/creative/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +0 -93
  685. package/skills/creative/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
  686. package/skills/creative/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
  687. package/skills/creative/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
  688. package/skills/creative/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
  689. package/skills/creative/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
  690. package/skills/creative/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
  691. package/skills/creative/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
  692. package/skills/creative/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
  693. package/skills/creative/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +0 -93
  694. package/skills/creative/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
  695. package/skills/creative/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
  696. package/skills/creative/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
  697. package/skills/creative/canvas-design/canvas-fonts/Italiana-OFL.txt +0 -93
  698. package/skills/creative/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
  699. package/skills/creative/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
  700. package/skills/creative/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +0 -93
  701. package/skills/creative/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
  702. package/skills/creative/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
  703. package/skills/creative/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
  704. package/skills/creative/canvas-design/canvas-fonts/Jura-OFL.txt +0 -93
  705. package/skills/creative/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +0 -93
  706. package/skills/creative/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
  707. package/skills/creative/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
  708. package/skills/creative/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
  709. package/skills/creative/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
  710. package/skills/creative/canvas-design/canvas-fonts/Lora-OFL.txt +0 -93
  711. package/skills/creative/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
  712. package/skills/creative/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
  713. package/skills/creative/canvas-design/canvas-fonts/NationalPark-OFL.txt +0 -93
  714. package/skills/creative/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
  715. package/skills/creative/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +0 -93
  716. package/skills/creative/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
  717. package/skills/creative/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
  718. package/skills/creative/canvas-design/canvas-fonts/Outfit-OFL.txt +0 -93
  719. package/skills/creative/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
  720. package/skills/creative/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
  721. package/skills/creative/canvas-design/canvas-fonts/PixelifySans-OFL.txt +0 -93
  722. package/skills/creative/canvas-design/canvas-fonts/PoiretOne-OFL.txt +0 -93
  723. package/skills/creative/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
  724. package/skills/creative/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
  725. package/skills/creative/canvas-design/canvas-fonts/RedHatMono-OFL.txt +0 -93
  726. package/skills/creative/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
  727. package/skills/creative/canvas-design/canvas-fonts/Silkscreen-OFL.txt +0 -93
  728. package/skills/creative/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
  729. package/skills/creative/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
  730. package/skills/creative/canvas-design/canvas-fonts/SmoochSans-OFL.txt +0 -93
  731. package/skills/creative/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
  732. package/skills/creative/canvas-design/canvas-fonts/Tektur-OFL.txt +0 -93
  733. package/skills/creative/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
  734. package/skills/creative/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
  735. package/skills/creative/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
  736. package/skills/creative/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
  737. package/skills/creative/canvas-design/canvas-fonts/WorkSans-OFL.txt +0 -93
  738. package/skills/creative/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
  739. package/skills/creative/canvas-design/canvas-fonts/YoungSerif-OFL.txt +0 -93
  740. package/skills/creative/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
@@ -0,0 +1,192 @@
1
+ import { createLogger } from "../../utils/logger/index.js";
2
+ import { init_logger } from "../../utils/logger.js";
3
+ //#region src/agent/session/session-state-bag.ts
4
+ init_logger();
5
+ const log = createLogger("SessionStateBag");
6
+ const DEFAULT_TTL_MS = 3600 * 1e3;
7
+ const DEFAULT_SWEEP_INTERVAL_MS = 600 * 1e3;
8
+ const DEFAULT_MAX_ENTRIES = 5e3;
9
+ var SessionStateBag = class {
10
+ /** Webchat SSE publisher (register/unregister + TTL fallback). */
11
+ webchatPublishers = /* @__PURE__ */ new Map();
12
+ /** Last assistant plain text (TTL + LRU). */
13
+ lastAssistantText = /* @__PURE__ */ new Map();
14
+ /** Stream text for the in-flight embedded turn (managed by turn). */
15
+ embeddedStreamText = /* @__PURE__ */ new Map();
16
+ /** Persistent-goal stream outcome (take-and-delete). */
17
+ directStreamOutcome = /* @__PURE__ */ new Map();
18
+ /** Concurrent inbound turn depth (counter). */
19
+ inboundTurnDepth = /* @__PURE__ */ new Map();
20
+ /** Agent-event subscription tear-downs (run on dispose). */
21
+ sessionEventUnsubscribers = /* @__PURE__ */ new Map();
22
+ ttlMs;
23
+ maxEntries;
24
+ now;
25
+ sweepTimer;
26
+ constructor(opts = {}) {
27
+ this.ttlMs = opts.ttlMs ?? DEFAULT_TTL_MS;
28
+ this.maxEntries = opts.maxEntries ?? DEFAULT_MAX_ENTRIES;
29
+ this.now = opts.now ?? Date.now;
30
+ const sweepIntervalMs = opts.sweepIntervalMs ?? DEFAULT_SWEEP_INTERVAL_MS;
31
+ if (this.ttlMs > 0 && sweepIntervalMs > 0) {
32
+ this.sweepTimer = setInterval(() => this.sweepStaleEntries(), sweepIntervalMs);
33
+ this.sweepTimer.unref?.();
34
+ } else this.sweepTimer = null;
35
+ }
36
+ registerWebchatPublisher(sessionKey, publisher) {
37
+ this.webchatPublishers.set(sessionKey, {
38
+ value: publisher,
39
+ touchedAt: this.now()
40
+ });
41
+ this.enforceCap(this.webchatPublishers, "webchatPublishers");
42
+ }
43
+ unregisterWebchatPublisher(sessionKey) {
44
+ this.webchatPublishers.delete(sessionKey);
45
+ }
46
+ getWebchatPublisher(sessionKey) {
47
+ const entry = this.webchatPublishers.get(sessionKey);
48
+ if (!entry) return void 0;
49
+ entry.touchedAt = this.now();
50
+ return entry.value;
51
+ }
52
+ setLastAssistantText(sessionKey, text) {
53
+ const trimmed = text.trim();
54
+ if (!trimmed) return;
55
+ this.lastAssistantText.set(sessionKey, {
56
+ value: trimmed,
57
+ touchedAt: this.now()
58
+ });
59
+ this.enforceCap(this.lastAssistantText, "lastAssistantText");
60
+ }
61
+ getLastAssistantText(sessionKey) {
62
+ const entry = this.lastAssistantText.get(sessionKey);
63
+ if (!entry) return void 0;
64
+ entry.touchedAt = this.now();
65
+ return entry.value;
66
+ }
67
+ appendEmbeddedStreamText(sessionKey, chunk) {
68
+ const next = (this.embeddedStreamText.get(sessionKey) ?? "") + chunk;
69
+ this.embeddedStreamText.set(sessionKey, next);
70
+ return next;
71
+ }
72
+ clearEmbeddedStreamText(sessionKey) {
73
+ this.embeddedStreamText.delete(sessionKey);
74
+ }
75
+ recordPersistentGoalStreamOutcome(sessionKey, outcome) {
76
+ this.directStreamOutcome.set(sessionKey, outcome);
77
+ }
78
+ takePersistentGoalStreamOutcome(sessionKey) {
79
+ const v = this.directStreamOutcome.get(sessionKey);
80
+ this.directStreamOutcome.delete(sessionKey);
81
+ return v;
82
+ }
83
+ beginInboundTurn(sessionKey) {
84
+ this.inboundTurnDepth.set(sessionKey, (this.inboundTurnDepth.get(sessionKey) ?? 0) + 1);
85
+ }
86
+ endInboundTurn(sessionKey) {
87
+ const next = (this.inboundTurnDepth.get(sessionKey) ?? 1) - 1;
88
+ if (next <= 0) this.inboundTurnDepth.delete(sessionKey);
89
+ else this.inboundTurnDepth.set(sessionKey, next);
90
+ }
91
+ getInboundTurnDepth(sessionKey) {
92
+ return this.inboundTurnDepth.get(sessionKey) ?? 0;
93
+ }
94
+ setSessionEventUnsubscriber(sessionKey, unsubscribe) {
95
+ const previous = this.sessionEventUnsubscribers.get(sessionKey);
96
+ if (previous) try {
97
+ previous();
98
+ } catch (err) {
99
+ log.warn({
100
+ err,
101
+ sessionKey
102
+ }, "Previous session-event unsubscribe threw");
103
+ }
104
+ this.sessionEventUnsubscribers.set(sessionKey, unsubscribe);
105
+ }
106
+ hasSessionEventUnsubscriber(sessionKey) {
107
+ return this.sessionEventUnsubscribers.has(sessionKey);
108
+ }
109
+ /** Clear every slot for `sessionKey`, invoking the unsubscriber if registered. */
110
+ disposeSession(sessionKey) {
111
+ const unsub = this.sessionEventUnsubscribers.get(sessionKey);
112
+ if (unsub) {
113
+ try {
114
+ unsub();
115
+ } catch (err) {
116
+ log.warn({
117
+ err,
118
+ sessionKey
119
+ }, "Session event unsubscribe threw during dispose");
120
+ }
121
+ this.sessionEventUnsubscribers.delete(sessionKey);
122
+ }
123
+ this.webchatPublishers.delete(sessionKey);
124
+ this.lastAssistantText.delete(sessionKey);
125
+ this.embeddedStreamText.delete(sessionKey);
126
+ this.directStreamOutcome.delete(sessionKey);
127
+ this.inboundTurnDepth.delete(sessionKey);
128
+ }
129
+ /** Tear down every session (process stop / hot reload). */
130
+ disposeAll() {
131
+ for (const [sessionKey, unsub] of this.sessionEventUnsubscribers) try {
132
+ unsub();
133
+ } catch (err) {
134
+ log.warn({
135
+ err,
136
+ sessionKey
137
+ }, "Session event unsubscribe threw during disposeAll");
138
+ }
139
+ this.sessionEventUnsubscribers.clear();
140
+ this.webchatPublishers.clear();
141
+ this.lastAssistantText.clear();
142
+ this.embeddedStreamText.clear();
143
+ this.directStreamOutcome.clear();
144
+ this.inboundTurnDepth.clear();
145
+ if (this.sweepTimer) clearInterval(this.sweepTimer);
146
+ }
147
+ /** Test helper. */
148
+ size() {
149
+ return {
150
+ webchatPublishers: this.webchatPublishers.size,
151
+ lastAssistantText: this.lastAssistantText.size,
152
+ embeddedStreamText: this.embeddedStreamText.size,
153
+ directStreamOutcome: this.directStreamOutcome.size,
154
+ inboundTurnDepth: this.inboundTurnDepth.size,
155
+ sessionEventUnsubscribers: this.sessionEventUnsubscribers.size
156
+ };
157
+ }
158
+ sweepStaleEntries() {
159
+ const cutoff = this.now() - this.ttlMs;
160
+ let removed = 0;
161
+ for (const [k, entry] of this.webchatPublishers) if (entry.touchedAt < cutoff) {
162
+ this.webchatPublishers.delete(k);
163
+ removed += 1;
164
+ }
165
+ for (const [k, entry] of this.lastAssistantText) if (entry.touchedAt < cutoff) {
166
+ this.lastAssistantText.delete(k);
167
+ removed += 1;
168
+ }
169
+ if (removed > 0) log.debug({
170
+ removed,
171
+ ttlMs: this.ttlMs
172
+ }, "SessionStateBag TTL sweep");
173
+ }
174
+ enforceCap(map, slotName) {
175
+ if (map.size <= this.maxEntries) return;
176
+ const sorted = [...map.entries()].sort((a, b) => a[1].touchedAt - b[1].touchedAt);
177
+ let evict = map.size - this.maxEntries;
178
+ while (evict > 0 && sorted.length > 0) {
179
+ const oldest = sorted.shift();
180
+ map.delete(oldest[0]);
181
+ evict -= 1;
182
+ }
183
+ log.warn({
184
+ slot: slotName,
185
+ maxEntries: this.maxEntries
186
+ }, `SessionStateBag slot exceeded cap; evicted oldest entries`);
187
+ }
188
+ };
189
+ //#endregion
190
+ export { SessionStateBag };
191
+
192
+ //# sourceMappingURL=session-state-bag.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-state-bag.js","names":[],"sources":["../../../../src/agent/session/session-state-bag.ts"],"sourcesContent":["/**\n * SessionStateBag — typed container for the per-session state previously held\n * as private fields on `AgentService` (six `Map<sessionKey, …>` instances with\n * no shared cleanup path).\n *\n * Goals:\n * - Single `disposeSession(sessionKey)` entry that clears every slot for a key\n * (and runs the event unsubscriber, which was easy to forget previously).\n * - Optional TTL sweep for slots whose lifecycle is not bound to an explicit\n * register/unregister pair, so long-running Gateways do not accumulate stale\n * per-session entries from disconnected webchat clients or finished turns.\n * - Hard upper bound for the same TTL'd slots to bound worst-case memory.\n *\n * Slots whose lifetime is fully owned by explicit lifecycle calls\n * (`inboundTurnDepth`, `directStreamOutcome`, `embeddedStreamText`,\n * `sessionEventUnsubscribers`) are still cleared via `disposeSession`, but they\n * are NOT subject to TTL — sweeping them would race with their owners.\n */\n\nimport { createLogger } from '../../utils/logger.js';\n\nconst log = createLogger('SessionStateBag');\n\nexport type WebchatSsePublisher = (event: { type: string; [key: string]: unknown }) => void;\n\nexport interface PersistentGoalStreamOutcome {\n skipPersistentGoalPostTurn: boolean;\n}\n\nexport interface SessionStateBagOptions {\n /** Idle TTL for TTL-managed slots. Defaults to 1 hour. Set to 0 to disable sweeping. */\n ttlMs?: number;\n /** Sweep cadence. Defaults to 10 minutes. */\n sweepIntervalMs?: number;\n /** Hard upper bound on entries for TTL-managed slots. Defaults to 5000. */\n maxEntries?: number;\n /** Inject a clock for tests. */\n now?: () => number;\n}\n\nconst DEFAULT_TTL_MS = 60 * 60 * 1000;\nconst DEFAULT_SWEEP_INTERVAL_MS = 10 * 60 * 1000;\nconst DEFAULT_MAX_ENTRIES = 5_000;\n\ntype Touched<V> = { value: V; touchedAt: number };\n\nexport class SessionStateBag {\n /** Webchat SSE publisher (register/unregister + TTL fallback). */\n private readonly webchatPublishers = new Map<string, Touched<WebchatSsePublisher>>();\n /** Last assistant plain text (TTL + LRU). */\n private readonly lastAssistantText = new Map<string, Touched<string>>();\n\n /** Stream text for the in-flight embedded turn (managed by turn). */\n private readonly embeddedStreamText = new Map<string, string>();\n /** Persistent-goal stream outcome (take-and-delete). */\n private readonly directStreamOutcome = new Map<string, PersistentGoalStreamOutcome>();\n /** Concurrent inbound turn depth (counter). */\n private readonly inboundTurnDepth = new Map<string, number>();\n /** Agent-event subscription tear-downs (run on dispose). */\n private readonly sessionEventUnsubscribers = new Map<string, () => void>();\n\n private readonly ttlMs: number;\n private readonly maxEntries: number;\n private readonly now: () => number;\n private readonly sweepTimer: ReturnType<typeof setInterval> | null;\n\n constructor(opts: SessionStateBagOptions = {}) {\n this.ttlMs = opts.ttlMs ?? DEFAULT_TTL_MS;\n this.maxEntries = opts.maxEntries ?? DEFAULT_MAX_ENTRIES;\n this.now = opts.now ?? Date.now;\n\n const sweepIntervalMs = opts.sweepIntervalMs ?? DEFAULT_SWEEP_INTERVAL_MS;\n if (this.ttlMs > 0 && sweepIntervalMs > 0) {\n this.sweepTimer = setInterval(() => this.sweepStaleEntries(), sweepIntervalMs);\n this.sweepTimer.unref?.();\n } else {\n this.sweepTimer = null;\n }\n }\n\n // ── Webchat publishers ──────────────────────────────────────────────────\n\n registerWebchatPublisher(sessionKey: string, publisher: WebchatSsePublisher): void {\n this.webchatPublishers.set(sessionKey, { value: publisher, touchedAt: this.now() });\n this.enforceCap(this.webchatPublishers, 'webchatPublishers');\n }\n\n unregisterWebchatPublisher(sessionKey: string): void {\n this.webchatPublishers.delete(sessionKey);\n }\n\n getWebchatPublisher(sessionKey: string): WebchatSsePublisher | undefined {\n const entry = this.webchatPublishers.get(sessionKey);\n if (!entry) return undefined;\n entry.touchedAt = this.now();\n return entry.value;\n }\n\n // ── Last assistant plain text ───────────────────────────────────────────\n\n setLastAssistantText(sessionKey: string, text: string): void {\n const trimmed = text.trim();\n if (!trimmed) return;\n this.lastAssistantText.set(sessionKey, { value: trimmed, touchedAt: this.now() });\n this.enforceCap(this.lastAssistantText, 'lastAssistantText');\n }\n\n getLastAssistantText(sessionKey: string): string | undefined {\n const entry = this.lastAssistantText.get(sessionKey);\n if (!entry) return undefined;\n entry.touchedAt = this.now();\n return entry.value;\n }\n\n // ── Embedded stream text (turn-scoped) ──────────────────────────────────\n\n appendEmbeddedStreamText(sessionKey: string, chunk: string): string {\n const prev = this.embeddedStreamText.get(sessionKey) ?? '';\n const next = prev + chunk;\n this.embeddedStreamText.set(sessionKey, next);\n return next;\n }\n\n clearEmbeddedStreamText(sessionKey: string): void {\n this.embeddedStreamText.delete(sessionKey);\n }\n\n // ── Persistent-goal stream outcome (take-and-delete) ────────────────────\n\n recordPersistentGoalStreamOutcome(sessionKey: string, outcome: PersistentGoalStreamOutcome): void {\n this.directStreamOutcome.set(sessionKey, outcome);\n }\n\n takePersistentGoalStreamOutcome(sessionKey: string): PersistentGoalStreamOutcome | undefined {\n const v = this.directStreamOutcome.get(sessionKey);\n this.directStreamOutcome.delete(sessionKey);\n return v;\n }\n\n // ── Inbound turn depth (counter) ────────────────────────────────────────\n\n beginInboundTurn(sessionKey: string): void {\n this.inboundTurnDepth.set(sessionKey, (this.inboundTurnDepth.get(sessionKey) ?? 0) + 1);\n }\n\n endInboundTurn(sessionKey: string): void {\n const next = (this.inboundTurnDepth.get(sessionKey) ?? 1) - 1;\n if (next <= 0) {\n this.inboundTurnDepth.delete(sessionKey);\n } else {\n this.inboundTurnDepth.set(sessionKey, next);\n }\n }\n\n getInboundTurnDepth(sessionKey: string): number {\n return this.inboundTurnDepth.get(sessionKey) ?? 0;\n }\n\n // ── Session event unsubscribers ─────────────────────────────────────────\n\n setSessionEventUnsubscriber(sessionKey: string, unsubscribe: () => void): void {\n const previous = this.sessionEventUnsubscribers.get(sessionKey);\n if (previous) {\n try {\n previous();\n } catch (err) {\n log.warn({ err, sessionKey }, 'Previous session-event unsubscribe threw');\n }\n }\n this.sessionEventUnsubscribers.set(sessionKey, unsubscribe);\n }\n\n hasSessionEventUnsubscriber(sessionKey: string): boolean {\n return this.sessionEventUnsubscribers.has(sessionKey);\n }\n\n // ── Lifecycle / cleanup ─────────────────────────────────────────────────\n\n /** Clear every slot for `sessionKey`, invoking the unsubscriber if registered. */\n disposeSession(sessionKey: string): void {\n const unsub = this.sessionEventUnsubscribers.get(sessionKey);\n if (unsub) {\n try {\n unsub();\n } catch (err) {\n log.warn({ err, sessionKey }, 'Session event unsubscribe threw during dispose');\n }\n this.sessionEventUnsubscribers.delete(sessionKey);\n }\n\n this.webchatPublishers.delete(sessionKey);\n this.lastAssistantText.delete(sessionKey);\n this.embeddedStreamText.delete(sessionKey);\n this.directStreamOutcome.delete(sessionKey);\n this.inboundTurnDepth.delete(sessionKey);\n }\n\n /** Tear down every session (process stop / hot reload). */\n disposeAll(): void {\n for (const [sessionKey, unsub] of this.sessionEventUnsubscribers) {\n try {\n unsub();\n } catch (err) {\n log.warn({ err, sessionKey }, 'Session event unsubscribe threw during disposeAll');\n }\n }\n this.sessionEventUnsubscribers.clear();\n this.webchatPublishers.clear();\n this.lastAssistantText.clear();\n this.embeddedStreamText.clear();\n this.directStreamOutcome.clear();\n this.inboundTurnDepth.clear();\n\n if (this.sweepTimer) {\n clearInterval(this.sweepTimer);\n }\n }\n\n /** Test helper. */\n size(): {\n webchatPublishers: number;\n lastAssistantText: number;\n embeddedStreamText: number;\n directStreamOutcome: number;\n inboundTurnDepth: number;\n sessionEventUnsubscribers: number;\n } {\n return {\n webchatPublishers: this.webchatPublishers.size,\n lastAssistantText: this.lastAssistantText.size,\n embeddedStreamText: this.embeddedStreamText.size,\n directStreamOutcome: this.directStreamOutcome.size,\n inboundTurnDepth: this.inboundTurnDepth.size,\n sessionEventUnsubscribers: this.sessionEventUnsubscribers.size,\n };\n }\n\n // ── Internals ───────────────────────────────────────────────────────────\n\n private sweepStaleEntries(): void {\n const cutoff = this.now() - this.ttlMs;\n let removed = 0;\n for (const [k, entry] of this.webchatPublishers) {\n if (entry.touchedAt < cutoff) {\n this.webchatPublishers.delete(k);\n removed += 1;\n }\n }\n for (const [k, entry] of this.lastAssistantText) {\n if (entry.touchedAt < cutoff) {\n this.lastAssistantText.delete(k);\n removed += 1;\n }\n }\n if (removed > 0) {\n log.debug({ removed, ttlMs: this.ttlMs }, 'SessionStateBag TTL sweep');\n }\n }\n\n private enforceCap<V>(map: Map<string, Touched<V>>, slotName: string): void {\n if (map.size <= this.maxEntries) {\n return;\n }\n // Evict oldest entries (LRU on touchedAt) until under cap.\n const sorted = [...map.entries()].sort((a, b) => a[1].touchedAt - b[1].touchedAt);\n let evict = map.size - this.maxEntries;\n while (evict > 0 && sorted.length > 0) {\n const oldest = sorted.shift()!;\n map.delete(oldest[0]);\n evict -= 1;\n }\n log.warn(\n { slot: slotName, maxEntries: this.maxEntries },\n `SessionStateBag slot exceeded cap; evicted oldest entries`,\n );\n }\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { __toCommonJS } from "../../../_virtual/_rolldown/runtime.js";
2
+ import { init_write_file_atomic, writeTextAtomicSync } from "../../infra/write-file-atomic.js";
2
3
  import { createLogger } from "../../utils/logger/index.js";
3
4
  import { init_logger } from "../../utils/logger.js";
4
- import { init_write_file_atomic, writeTextAtomicSync } from "../../infra/write-file-atomic.js";
5
5
  import { init_installer, installer_exports } from "./installer.js";
6
6
  import { join } from "path";
7
7
  import { existsSync, readFileSync } from "fs";
@@ -1,6 +1,6 @@
1
- import { join, relative } from "node:path";
2
- import { createReadStream, existsSync, readFileSync, readdirSync, statSync } from "node:fs";
3
1
  import { createHash } from "node:crypto";
2
+ import { createReadStream, existsSync, readFileSync, readdirSync, statSync } from "node:fs";
3
+ import { join, relative } from "node:path";
4
4
  //#region src/agent/skills/hub-hash.ts
5
5
  /**
6
6
  * Deterministic content hash for a skill directory (for hub lock / drift detection).
@@ -1,5 +1,5 @@
1
- import { init_paths, resolveSkillsLockPath } from "../../config/paths.js";
2
1
  import { init_write_file_atomic, writeTextAtomicSync } from "../../infra/write-file-atomic.js";
2
+ import { init_paths, resolveSkillsLockPath } from "../../config/paths.js";
3
3
  import { existsSync, readFileSync } from "node:fs";
4
4
  //#region src/agent/skills/hub-lock.ts
5
5
  /**
@@ -4,12 +4,12 @@ import { formatScanSummary, scanSkillDirectory } from "./scanner.js";
4
4
  import { getSkillsLockEntry, recordSkillsHubInstall } from "./hub-lock.js";
5
5
  import { installSkillFromZip, isValidSkillId } from "./managed-store.js";
6
6
  import { computeSkillTreeHashSync } from "./hub-hash.js";
7
+ import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
7
8
  import { basename, join, normalize, resolve, sep } from "node:path";
8
9
  import { tmpdir } from "node:os";
9
- import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
10
+ import { fileURLToPath } from "node:url";
10
11
  import { execFileSync } from "node:child_process";
11
12
  import { fetch } from "undici";
12
- import { fileURLToPath } from "node:url";
13
13
  //#region src/agent/skills/hub-pull.ts
14
14
  /**
15
15
  * CLI / hub: install or update skills from git or archive (zip / tar.gz) into ~/.xopc/skills.
@@ -19,10 +19,8 @@ export interface SkillLoader {
19
19
  getEnabledSkills: (config?: Record<string, SkillConfig>) => Skill[];
20
20
  }
21
21
  export declare function createSkillLoader(): SkillLoader;
22
- export { SkillManager, type SkillDiagnostic, type SkillLoadResult } from './skill-manager.js';
23
22
  export type { Skill, SkillMetadata, SkillConfig, SkillInstallSpec, SkillInstallResult, SkillInstallRequest, LoadSkillsResult, SkillSnapshot, } from './types.js';
24
23
  export { installSkill, findInstallSpec, hasBinary, getDefaultInstallerPreferences, type InstallerPreferences, type InstallContext, } from './installer.js';
25
24
  export { scanSkillDirectory, formatScanSummary, collectSkillInstallWarnings, type ScanSummary, type SecurityFinding, type Severity, } from './scanner.js';
26
25
  export { resolveSkillConfig, applySkillEnvOverrides, getSkillEnvironment, createSkillConfigManager, isSkillEnabled, validateSkillConfig, type SkillConfigFile, } from './config.js';
27
- export { createSkillWatcher, createWatcherFromLoader, type SkillWatcher, type SkillWatcherOptions, } from './watcher.js';
28
26
  export { SkillTestFramework, SkillTestRunner, formatTestResults, formatTestResultsJson, formatTestResultsTap, type TestResult, type TestStatus, type SkillTestReport, type TestOptions, type TestRunnerOptions, } from './test-framework.js';
@@ -1,17 +1,15 @@
1
- import { resolveStateDir } from "../../config/paths-state.js";
2
1
  import { createLogger } from "../../utils/logger/index.js";
3
2
  import { init_logger } from "../../utils/logger.js";
3
+ import { resolveStateDir } from "../../config/paths-state.js";
4
4
  import { init_paths } from "../../config/paths.js";
5
5
  import { parseFrontmatter } from "../../markdown/frontmatter.js";
6
6
  import { findInstallSpec, getDefaultInstallerPreferences, hasBinary, init_installer, installSkill } from "./installer.js";
7
7
  import { applySkillEnvOverrides, createSkillConfigManager, getSkillEnvironment, isSkillEnabled, resolveSkillConfig, validateSkillConfig } from "./config.js";
8
8
  import { parseSkillToolConditions } from "./skill-tool-gating.js";
9
- import { formatSkillsForPrompt } from "./format-skills-prompt.js";
10
9
  import { parseRequiredEnvVarNames } from "./required-env-vars.js";
11
10
  import { parseSkillMetadata } from "./parse-skill-metadata.js";
12
- import { SkillManager } from "./skill-manager.js";
13
11
  import { collectSkillInstallWarnings, formatScanSummary, scanSkillDirectory } from "./scanner.js";
14
- import { createSkillWatcher, createWatcherFromLoader } from "./watcher.js";
12
+ import { formatSkillsForPrompt } from "./format-skills-prompt.js";
15
13
  import { SkillTestFramework, SkillTestRunner, formatTestResults, formatTestResultsJson, formatTestResultsTap } from "./test-framework.js";
16
14
  import { basename, dirname, join, relative, sep } from "path";
17
15
  import { existsSync, readFileSync, readdirSync } from "fs";
@@ -248,6 +246,6 @@ function createSkillLoader() {
248
246
  };
249
247
  }
250
248
  //#endregion
251
- export { SkillManager, SkillTestFramework, SkillTestRunner, applySkillEnvOverrides, collectSkillInstallWarnings, createSkillConfigManager, createSkillLoader, createSkillWatcher, createWatcherFromLoader, findInstallSpec, formatScanSummary, formatTestResults, formatTestResultsJson, formatTestResultsTap, getDefaultInstallerPreferences, getSkillEnvironment, hasBinary, installSkill, isSkillEnabled, loadSkills, resolveSkillConfig, scanSkillDirectory, validateSkillConfig };
249
+ export { SkillTestFramework, SkillTestRunner, applySkillEnvOverrides, collectSkillInstallWarnings, createSkillConfigManager, createSkillLoader, findInstallSpec, formatScanSummary, formatTestResults, formatTestResultsJson, formatTestResultsTap, getDefaultInstallerPreferences, getSkillEnvironment, hasBinary, installSkill, isSkillEnabled, loadSkills, resolveSkillConfig, scanSkillDirectory, validateSkillConfig };
252
250
 
253
251
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/agent/skills/index.ts"],"sourcesContent":["import { existsSync, readdirSync, readFileSync } from 'fs';\nimport { basename, dirname, join, relative, sep } from 'path';\nimport { parseFrontmatter } from '../../markdown/frontmatter.js';\nimport { resolveStateDir } from '../../config/paths.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { createSkillConfigManager, isSkillEnabled } from './config.js';\nimport { formatSkillsForPrompt } from './format-skills-prompt.js';\nimport { parseRequiredEnvVarNames } from './required-env-vars.js';\nimport { parseSkillMetadata } from './parse-skill-metadata.js';\nimport { parseSkillToolConditions } from './skill-tool-gating.js';\nimport type { Skill, SkillDiagnostic, LoadSkillsResult, SkillConfig, SkillsConfig } from './types.js';\n\nconst log = createLogger('SkillLoader');\n\nconst IGNORE_FILES = ['.gitignore', '.ignore', '.fdignore'];\n\nfunction toPosixPath(p: string): string {\n return p.split(sep).join('/');\n}\n\nfunction prefixIgnorePattern(line: string, prefix: string): string | null {\n const trimmed = line.trim();\n if (!trimmed) return null;\n if (trimmed.startsWith('#') && !trimmed.startsWith('\\\\#')) return null;\n\n let pattern = line;\n let negated = false;\n\n if (pattern.startsWith('!')) {\n negated = true;\n pattern = pattern.slice(1);\n } else if (pattern.startsWith('\\\\!')) {\n pattern = pattern.slice(1);\n }\n\n if (pattern.startsWith('/')) {\n pattern = pattern.slice(1);\n }\n\n const prefixed = prefix ? `${prefix}${pattern}` : pattern;\n return negated ? `!${prefixed}` : prefixed;\n}\n\nfunction loadIgnoreRules(dir: string, rootDir: string): Set<string> {\n const ignoredPaths = new Set<string>();\n const relativeDir = relative(rootDir, dir);\n const prefix = relativeDir ? `${toPosixPath(relativeDir)}/` : '';\n\n for (const filename of IGNORE_FILES) {\n const ignorePath = join(dir, filename);\n if (!existsSync(ignorePath)) continue;\n\n try {\n const content = readFileSync(ignorePath, 'utf-8');\n for (const line of content.split(/\\r?\\n/)) {\n const pattern = prefixIgnorePattern(line, prefix);\n if (pattern) {\n const fullPattern = pattern.startsWith('!')\n ? `!${prefix}${pattern.slice(1)}`\n : `${prefix}${pattern}`;\n ignoredPaths.add(fullPattern);\n }\n }\n } catch {}\n }\n\n return ignoredPaths;\n}\n\nfunction shouldIgnore(path: string, ignoredPaths: Set<string>): boolean {\n for (const pattern of ignoredPaths) {\n if (pattern.startsWith('!')) {\n const positive = pattern.slice(1);\n if (path === positive || path.startsWith(`${positive}/`)) {\n return false;\n }\n } else {\n if (path === pattern || path.startsWith(`${pattern}/`)) {\n return true;\n }\n }\n }\n return false;\n}\n\nfunction discoverSkills(dir: string, source: 'builtin' | 'workspace' | 'global'): Skill[] {\n const skills: Skill[] = [];\n if (!existsSync(dir)) return skills;\n\n function scan(currentDir: string, currentIgnoredPaths: Set<string>) {\n try {\n const entries = readdirSync(currentDir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (entry.name.startsWith('.') || entry.name === 'node_modules') continue;\n\n const fullPath = join(currentDir, entry.name);\n const relPath = toPosixPath(relative(dir, fullPath));\n\n if (shouldIgnore(relPath, currentIgnoredPaths)) continue;\n\n if (entry.isDirectory()) {\n const skillMdPath = join(fullPath, 'SKILL.md');\n const skillRelPath = `${relPath}/`;\n\n const subIgnoredPaths = new Set(currentIgnoredPaths);\n const subIgnoreFile = join(fullPath, '.gitignore');\n if (existsSync(subIgnoreFile)) {\n const subRules = loadIgnoreRules(fullPath, dir);\n for (const rule of subRules) {\n subIgnoredPaths.add(`${skillRelPath}${rule}`);\n }\n }\n\n if (existsSync(skillMdPath) && !shouldIgnore(skillRelPath, currentIgnoredPaths)) {\n const skill = loadSkillFromFile(skillMdPath, source, dir);\n if (skill) skills.push(skill);\n }\n\n scan(fullPath, subIgnoredPaths);\n }\n }\n } catch {}\n }\n\n scan(dir, loadIgnoreRules(dir, dir));\n return skills;\n}\n\nfunction loadSkillFromFile(filePath: string, source: 'builtin' | 'workspace' | 'global', rootDir?: string): Skill | null {\n try {\n const rawContent = readFileSync(filePath, 'utf-8');\n const { frontmatter, content } = parseFrontmatter(rawContent);\n const skillDir = dirname(filePath);\n const parentDirName = basename(skillDir);\n\n const name = (frontmatter.name as string | undefined) || parentDirName;\n const description = frontmatter.description as string | undefined;\n if (!description?.trim()) return null;\n\n // Derive category from directory path: skills/creative/algorithmic-art → 'creative'\n // Only assign a category when the skill is nested at least two levels below rootDir.\n let category: string | undefined;\n if (rootDir) {\n const relDir = toPosixPath(relative(rootDir, skillDir));\n const segments = relDir.split('/');\n if (segments.length > 1) {\n category = segments[0];\n }\n }\n\n const metadata = parseSkillMetadata(frontmatter);\n const toolConditions = parseSkillToolConditions(frontmatter);\n const requiredEnvVarNames = parseRequiredEnvVarNames(frontmatter);\n\n return {\n name,\n description: description.trim(),\n category,\n filePath,\n baseDir: skillDir,\n source,\n disableModelInvocation: frontmatter['disable-model-invocation'] === true,\n metadata,\n toolConditions,\n requiredEnvVarNames: requiredEnvVarNames.length > 0 ? requiredEnvVarNames : undefined,\n content,\n };\n } catch {\n return null;\n }\n}\n\nexport function loadSkills(options: {\n workspaceDir?: string;\n globalDir?: string;\n builtinDir?: string;\n extraDirs?: string[];\n}): LoadSkillsResult {\n const { workspaceDir, builtinDir, extraDirs = [] } = options;\n\n const skillMap = new Map<string, Skill>();\n const diagnostics: SkillDiagnostic[] = [];\n\n if (builtinDir) {\n for (const skill of discoverSkills(builtinDir, 'builtin')) {\n const existing = skillMap.get(skill.name);\n if (existing) {\n diagnostics.push({\n type: 'collision',\n skillName: skill.name,\n message: `Skill \"${skill.name}\" collision: ${existing.source} overrides ${skill.source}`,\n path: skill.filePath,\n });\n } else {\n skillMap.set(skill.name, skill);\n }\n }\n }\n\n const globalDirs = [\n options.globalDir,\n join(resolveStateDir(), 'skills'),\n ].filter((d): d is string => !!d && existsSync(d));\n\n for (const dir of globalDirs) {\n for (const skill of discoverSkills(dir, 'global')) {\n const existing = skillMap.get(skill.name);\n if (existing) {\n diagnostics.push({\n type: 'collision',\n skillName: skill.name,\n message: `Skill \"${skill.name}\" collision: ${skill.source} overrides ${existing.source}`,\n path: skill.filePath,\n });\n }\n // Global must win over bundled when names match (Workspace > Global > Bundled).\n skillMap.set(skill.name, skill);\n }\n }\n\n if (workspaceDir) {\n const workspaceSkills = discoverSkills(join(workspaceDir, 'skills'), 'workspace');\n for (const skill of workspaceSkills) {\n const existing = skillMap.get(skill.name);\n if (existing) {\n diagnostics.push({\n type: 'collision',\n skillName: skill.name,\n message: `Skill \"${skill.name}\" collision: ${skill.source} overrides ${existing.source}`,\n path: skill.filePath,\n });\n }\n skillMap.set(skill.name, skill);\n }\n }\n\n // Scan extra directories\n for (const extraDir of extraDirs) {\n if (existsSync(extraDir)) {\n for (const skill of discoverSkills(extraDir, 'global')) {\n const existing = skillMap.get(skill.name);\n if (existing) {\n diagnostics.push({\n type: 'collision',\n skillName: skill.name,\n message: `Skill \"${skill.name}\" collision: ${existing.source} overrides ${skill.source}`,\n path: skill.filePath,\n });\n } else {\n skillMap.set(skill.name, skill);\n }\n }\n }\n }\n\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n const merged = Array.from(skillMap.values());\n\n return {\n skills: merged,\n prompt: formatSkillsForPrompt(merged, skillsConfig),\n diagnostics,\n };\n}\n\nexport interface SkillLoader {\n init: (workspace: string, builtin: string | null) => LoadSkillsResult;\n load: () => LoadSkillsResult;\n reload: () => LoadSkillsResult;\n /** Recompute `<available_skills>` from disk-loaded skills and current ~/.xopc/skills.json (no filesystem rescan). */\n refreshPromptFromConfig: () => void;\n getSkills: () => Skill[];\n getPrompt: () => string;\n getDiagnostics: () => SkillDiagnostic[];\n getLastLoadTime: () => number;\n getSkillByName: (name: string) => Skill | undefined;\n getEnabledSkills: (config?: Record<string, SkillConfig>) => Skill[];\n}\n\nexport function createSkillLoader(): SkillLoader {\n let cachedSkills: Skill[] = [];\n let cachedPrompt: string = '';\n let cachedDiagnostics: SkillDiagnostic[] = [];\n let lastLoadTime = 0;\n let workspaceDir: string | undefined;\n let builtinDir: string | undefined;\n let extraDirs: string[] = [];\n\n function updateCache(result: LoadSkillsResult): LoadSkillsResult {\n cachedSkills = result.skills;\n cachedPrompt = result.prompt;\n cachedDiagnostics = result.diagnostics;\n lastLoadTime = Date.now();\n return result;\n }\n\n return {\n init: (workspace: string, builtin: string | null) => {\n workspaceDir = workspace;\n builtinDir = builtin || undefined;\n return updateCache(loadSkills({ workspaceDir, builtinDir, extraDirs }));\n },\n \n load: () => {\n return updateCache(loadSkills({ workspaceDir, builtinDir, extraDirs }));\n },\n \n reload: () => {\n log.info('Reloading skills');\n return updateCache(loadSkills({ workspaceDir, builtinDir, extraDirs }));\n },\n\n refreshPromptFromConfig: () => {\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n cachedPrompt = formatSkillsForPrompt(cachedSkills, skillsConfig);\n lastLoadTime = Date.now();\n },\n\n getSkills: () => cachedSkills,\n getPrompt: () => cachedPrompt,\n getDiagnostics: () => cachedDiagnostics,\n getLastLoadTime: () => lastLoadTime,\n \n getSkillByName: (name: string) => {\n return cachedSkills.find(s => s.name === name);\n },\n \n getEnabledSkills: (entries?: Record<string, SkillConfig>) => {\n const skillsConfig: SkillsConfig =\n entries !== undefined ? { entries } : createSkillConfigManager(resolveStateDir()).load();\n return cachedSkills.filter(\n (skill) => !skill.disableModelInvocation && isSkillEnabled(skill, skillsConfig),\n );\n },\n };\n}\n\n// Export SkillManager\nexport { SkillManager, type SkillDiagnostic, type SkillLoadResult } from './skill-manager.js';\n\n// Re-export types for convenience\nexport type { \n Skill, \n SkillMetadata, \n SkillConfig,\n SkillInstallSpec,\n SkillInstallResult,\n SkillInstallRequest,\n LoadSkillsResult,\n // Note: SkillDiagnostic is re-exported from skill-manager.ts above\n SkillSnapshot,\n} from './types.js';\n\n// Re-export installer\nexport { \n installSkill, \n findInstallSpec,\n hasBinary,\n getDefaultInstallerPreferences,\n type InstallerPreferences,\n type InstallContext,\n} from './installer.js';\n\n// Re-export scanner\nexport {\n scanSkillDirectory,\n formatScanSummary,\n collectSkillInstallWarnings,\n type ScanSummary,\n type SecurityFinding,\n type Severity,\n} from './scanner.js';\n\n// Re-export config manager\nexport {\n resolveSkillConfig,\n applySkillEnvOverrides,\n getSkillEnvironment,\n createSkillConfigManager,\n isSkillEnabled,\n validateSkillConfig,\n type SkillConfigFile,\n} from './config.js';\n\n// Re-export watcher\nexport {\n createSkillWatcher,\n createWatcherFromLoader,\n type SkillWatcher,\n type SkillWatcherOptions,\n} from './watcher.js';\n\n// Re-export test framework\nexport {\n SkillTestFramework,\n SkillTestRunner,\n formatTestResults,\n formatTestResultsJson,\n formatTestResultsTap,\n type TestResult,\n type TestStatus,\n type SkillTestReport,\n type TestOptions,\n type TestRunnerOptions,\n} from './test-framework.js';\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/agent/skills/index.ts"],"sourcesContent":["import { existsSync, readdirSync, readFileSync } from 'fs';\nimport { basename, dirname, join, relative, sep } from 'path';\nimport { parseFrontmatter } from '../../markdown/frontmatter.js';\nimport { resolveStateDir } from '../../config/paths.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { createSkillConfigManager, isSkillEnabled } from './config.js';\nimport { formatSkillsForPrompt } from './format-skills-prompt.js';\nimport { parseRequiredEnvVarNames } from './required-env-vars.js';\nimport { parseSkillMetadata } from './parse-skill-metadata.js';\nimport { parseSkillToolConditions } from './skill-tool-gating.js';\nimport type { Skill, SkillDiagnostic, LoadSkillsResult, SkillConfig, SkillsConfig } from './types.js';\n\nconst log = createLogger('SkillLoader');\n\nconst IGNORE_FILES = ['.gitignore', '.ignore', '.fdignore'];\n\nfunction toPosixPath(p: string): string {\n return p.split(sep).join('/');\n}\n\nfunction prefixIgnorePattern(line: string, prefix: string): string | null {\n const trimmed = line.trim();\n if (!trimmed) return null;\n if (trimmed.startsWith('#') && !trimmed.startsWith('\\\\#')) return null;\n\n let pattern = line;\n let negated = false;\n\n if (pattern.startsWith('!')) {\n negated = true;\n pattern = pattern.slice(1);\n } else if (pattern.startsWith('\\\\!')) {\n pattern = pattern.slice(1);\n }\n\n if (pattern.startsWith('/')) {\n pattern = pattern.slice(1);\n }\n\n const prefixed = prefix ? `${prefix}${pattern}` : pattern;\n return negated ? `!${prefixed}` : prefixed;\n}\n\nfunction loadIgnoreRules(dir: string, rootDir: string): Set<string> {\n const ignoredPaths = new Set<string>();\n const relativeDir = relative(rootDir, dir);\n const prefix = relativeDir ? `${toPosixPath(relativeDir)}/` : '';\n\n for (const filename of IGNORE_FILES) {\n const ignorePath = join(dir, filename);\n if (!existsSync(ignorePath)) continue;\n\n try {\n const content = readFileSync(ignorePath, 'utf-8');\n for (const line of content.split(/\\r?\\n/)) {\n const pattern = prefixIgnorePattern(line, prefix);\n if (pattern) {\n const fullPattern = pattern.startsWith('!')\n ? `!${prefix}${pattern.slice(1)}`\n : `${prefix}${pattern}`;\n ignoredPaths.add(fullPattern);\n }\n }\n } catch {}\n }\n\n return ignoredPaths;\n}\n\nfunction shouldIgnore(path: string, ignoredPaths: Set<string>): boolean {\n for (const pattern of ignoredPaths) {\n if (pattern.startsWith('!')) {\n const positive = pattern.slice(1);\n if (path === positive || path.startsWith(`${positive}/`)) {\n return false;\n }\n } else {\n if (path === pattern || path.startsWith(`${pattern}/`)) {\n return true;\n }\n }\n }\n return false;\n}\n\nfunction discoverSkills(dir: string, source: 'builtin' | 'workspace' | 'global'): Skill[] {\n const skills: Skill[] = [];\n if (!existsSync(dir)) return skills;\n\n function scan(currentDir: string, currentIgnoredPaths: Set<string>) {\n try {\n const entries = readdirSync(currentDir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (entry.name.startsWith('.') || entry.name === 'node_modules') continue;\n\n const fullPath = join(currentDir, entry.name);\n const relPath = toPosixPath(relative(dir, fullPath));\n\n if (shouldIgnore(relPath, currentIgnoredPaths)) continue;\n\n if (entry.isDirectory()) {\n const skillMdPath = join(fullPath, 'SKILL.md');\n const skillRelPath = `${relPath}/`;\n\n const subIgnoredPaths = new Set(currentIgnoredPaths);\n const subIgnoreFile = join(fullPath, '.gitignore');\n if (existsSync(subIgnoreFile)) {\n const subRules = loadIgnoreRules(fullPath, dir);\n for (const rule of subRules) {\n subIgnoredPaths.add(`${skillRelPath}${rule}`);\n }\n }\n\n if (existsSync(skillMdPath) && !shouldIgnore(skillRelPath, currentIgnoredPaths)) {\n const skill = loadSkillFromFile(skillMdPath, source, dir);\n if (skill) skills.push(skill);\n }\n\n scan(fullPath, subIgnoredPaths);\n }\n }\n } catch {}\n }\n\n scan(dir, loadIgnoreRules(dir, dir));\n return skills;\n}\n\nfunction loadSkillFromFile(filePath: string, source: 'builtin' | 'workspace' | 'global', rootDir?: string): Skill | null {\n try {\n const rawContent = readFileSync(filePath, 'utf-8');\n const { frontmatter, content } = parseFrontmatter(rawContent);\n const skillDir = dirname(filePath);\n const parentDirName = basename(skillDir);\n\n const name = (frontmatter.name as string | undefined) || parentDirName;\n const description = frontmatter.description as string | undefined;\n if (!description?.trim()) return null;\n\n // Derive category from directory path: skills/creative/algorithmic-art → 'creative'\n // Only assign a category when the skill is nested at least two levels below rootDir.\n let category: string | undefined;\n if (rootDir) {\n const relDir = toPosixPath(relative(rootDir, skillDir));\n const segments = relDir.split('/');\n if (segments.length > 1) {\n category = segments[0];\n }\n }\n\n const metadata = parseSkillMetadata(frontmatter);\n const toolConditions = parseSkillToolConditions(frontmatter);\n const requiredEnvVarNames = parseRequiredEnvVarNames(frontmatter);\n\n return {\n name,\n description: description.trim(),\n category,\n filePath,\n baseDir: skillDir,\n source,\n disableModelInvocation: frontmatter['disable-model-invocation'] === true,\n metadata,\n toolConditions,\n requiredEnvVarNames: requiredEnvVarNames.length > 0 ? requiredEnvVarNames : undefined,\n content,\n };\n } catch {\n return null;\n }\n}\n\nexport function loadSkills(options: {\n workspaceDir?: string;\n globalDir?: string;\n builtinDir?: string;\n extraDirs?: string[];\n}): LoadSkillsResult {\n const { workspaceDir, builtinDir, extraDirs = [] } = options;\n\n const skillMap = new Map<string, Skill>();\n const diagnostics: SkillDiagnostic[] = [];\n\n if (builtinDir) {\n for (const skill of discoverSkills(builtinDir, 'builtin')) {\n const existing = skillMap.get(skill.name);\n if (existing) {\n diagnostics.push({\n type: 'collision',\n skillName: skill.name,\n message: `Skill \"${skill.name}\" collision: ${existing.source} overrides ${skill.source}`,\n path: skill.filePath,\n });\n } else {\n skillMap.set(skill.name, skill);\n }\n }\n }\n\n const globalDirs = [\n options.globalDir,\n join(resolveStateDir(), 'skills'),\n ].filter((d): d is string => !!d && existsSync(d));\n\n for (const dir of globalDirs) {\n for (const skill of discoverSkills(dir, 'global')) {\n const existing = skillMap.get(skill.name);\n if (existing) {\n diagnostics.push({\n type: 'collision',\n skillName: skill.name,\n message: `Skill \"${skill.name}\" collision: ${skill.source} overrides ${existing.source}`,\n path: skill.filePath,\n });\n }\n // Global must win over bundled when names match (Workspace > Global > Bundled).\n skillMap.set(skill.name, skill);\n }\n }\n\n if (workspaceDir) {\n const workspaceSkills = discoverSkills(join(workspaceDir, 'skills'), 'workspace');\n for (const skill of workspaceSkills) {\n const existing = skillMap.get(skill.name);\n if (existing) {\n diagnostics.push({\n type: 'collision',\n skillName: skill.name,\n message: `Skill \"${skill.name}\" collision: ${skill.source} overrides ${existing.source}`,\n path: skill.filePath,\n });\n }\n skillMap.set(skill.name, skill);\n }\n }\n\n // Scan extra directories\n for (const extraDir of extraDirs) {\n if (existsSync(extraDir)) {\n for (const skill of discoverSkills(extraDir, 'global')) {\n const existing = skillMap.get(skill.name);\n if (existing) {\n diagnostics.push({\n type: 'collision',\n skillName: skill.name,\n message: `Skill \"${skill.name}\" collision: ${existing.source} overrides ${skill.source}`,\n path: skill.filePath,\n });\n } else {\n skillMap.set(skill.name, skill);\n }\n }\n }\n }\n\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n const merged = Array.from(skillMap.values());\n\n return {\n skills: merged,\n prompt: formatSkillsForPrompt(merged, skillsConfig),\n diagnostics,\n };\n}\n\nexport interface SkillLoader {\n init: (workspace: string, builtin: string | null) => LoadSkillsResult;\n load: () => LoadSkillsResult;\n reload: () => LoadSkillsResult;\n /** Recompute `<available_skills>` from disk-loaded skills and current ~/.xopc/skills.json (no filesystem rescan). */\n refreshPromptFromConfig: () => void;\n getSkills: () => Skill[];\n getPrompt: () => string;\n getDiagnostics: () => SkillDiagnostic[];\n getLastLoadTime: () => number;\n getSkillByName: (name: string) => Skill | undefined;\n getEnabledSkills: (config?: Record<string, SkillConfig>) => Skill[];\n}\n\nexport function createSkillLoader(): SkillLoader {\n let cachedSkills: Skill[] = [];\n let cachedPrompt: string = '';\n let cachedDiagnostics: SkillDiagnostic[] = [];\n let lastLoadTime = 0;\n let workspaceDir: string | undefined;\n let builtinDir: string | undefined;\n let extraDirs: string[] = [];\n\n function updateCache(result: LoadSkillsResult): LoadSkillsResult {\n cachedSkills = result.skills;\n cachedPrompt = result.prompt;\n cachedDiagnostics = result.diagnostics;\n lastLoadTime = Date.now();\n return result;\n }\n\n return {\n init: (workspace: string, builtin: string | null) => {\n workspaceDir = workspace;\n builtinDir = builtin || undefined;\n return updateCache(loadSkills({ workspaceDir, builtinDir, extraDirs }));\n },\n \n load: () => {\n return updateCache(loadSkills({ workspaceDir, builtinDir, extraDirs }));\n },\n \n reload: () => {\n log.info('Reloading skills');\n return updateCache(loadSkills({ workspaceDir, builtinDir, extraDirs }));\n },\n\n refreshPromptFromConfig: () => {\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n cachedPrompt = formatSkillsForPrompt(cachedSkills, skillsConfig);\n lastLoadTime = Date.now();\n },\n\n getSkills: () => cachedSkills,\n getPrompt: () => cachedPrompt,\n getDiagnostics: () => cachedDiagnostics,\n getLastLoadTime: () => lastLoadTime,\n \n getSkillByName: (name: string) => {\n return cachedSkills.find(s => s.name === name);\n },\n \n getEnabledSkills: (entries?: Record<string, SkillConfig>) => {\n const skillsConfig: SkillsConfig =\n entries !== undefined ? { entries } : createSkillConfigManager(resolveStateDir()).load();\n return cachedSkills.filter(\n (skill) => !skill.disableModelInvocation && isSkillEnabled(skill, skillsConfig),\n );\n },\n };\n}\n\n// `SkillManager` + sibling types removed from this barrel — `skill-manager.ts`\n// imports `createSkillLoader` from THIS file, so re-exporting it back here\n// formed a circular cycle. External callers should import directly from\n// `./skill-manager.js`.\n\n// Re-export types for convenience\nexport type { \n Skill, \n SkillMetadata, \n SkillConfig,\n SkillInstallSpec,\n SkillInstallResult,\n SkillInstallRequest,\n LoadSkillsResult,\n // Note: SkillDiagnostic is re-exported from skill-manager.ts above\n SkillSnapshot,\n} from './types.js';\n\n// Re-export installer\nexport { \n installSkill, \n findInstallSpec,\n hasBinary,\n getDefaultInstallerPreferences,\n type InstallerPreferences,\n type InstallContext,\n} from './installer.js';\n\n// Re-export scanner\nexport {\n scanSkillDirectory,\n formatScanSummary,\n collectSkillInstallWarnings,\n type ScanSummary,\n type SecurityFinding,\n type Severity,\n} from './scanner.js';\n\n// Re-export config manager\nexport {\n resolveSkillConfig,\n applySkillEnvOverrides,\n getSkillEnvironment,\n createSkillConfigManager,\n isSkillEnabled,\n validateSkillConfig,\n type SkillConfigFile,\n} from './config.js';\n\n// `watcher.ts` re-exports removed — it imports `SkillLoader` from THIS file, so\n// re-exporting back here formed a circular cycle. External callers should\n// import directly from `./watcher.js`.\n\n// Re-export test framework\nexport {\n SkillTestFramework,\n SkillTestRunner,\n formatTestResults,\n formatTestResultsJson,\n formatTestResultsTap,\n type TestResult,\n type TestStatus,\n type SkillTestReport,\n type TestOptions,\n type TestRunnerOptions,\n} from './test-framework.js';\n"],"mappings":";;;;;;;;;;;;;;;;YAGwD;aACH;gBAwW7B;AAhWxB,MAAM,MAAM,aAAa,cAAc;AAEvC,MAAM,eAAe;CAAC;CAAc;CAAW;CAAY;AAE3D,SAAS,YAAY,GAAmB;AACtC,QAAO,EAAE,MAAM,IAAI,CAAC,KAAK,IAAI;;AAG/B,SAAS,oBAAoB,MAAc,QAA+B;CACxE,MAAM,UAAU,KAAK,MAAM;AAC3B,KAAI,CAAC,QAAS,QAAO;AACrB,KAAI,QAAQ,WAAW,IAAI,IAAI,CAAC,QAAQ,WAAW,MAAM,CAAE,QAAO;CAElE,IAAI,UAAU;CACd,IAAI,UAAU;AAEd,KAAI,QAAQ,WAAW,IAAI,EAAE;AAC3B,YAAU;AACV,YAAU,QAAQ,MAAM,EAAE;YACjB,QAAQ,WAAW,MAAM,CAClC,WAAU,QAAQ,MAAM,EAAE;AAG5B,KAAI,QAAQ,WAAW,IAAI,CACzB,WAAU,QAAQ,MAAM,EAAE;CAG5B,MAAM,WAAW,SAAS,GAAG,SAAS,YAAY;AAClD,QAAO,UAAU,IAAI,aAAa;;AAGpC,SAAS,gBAAgB,KAAa,SAA8B;CAClE,MAAM,+BAAe,IAAI,KAAa;CACtC,MAAM,cAAc,SAAS,SAAS,IAAI;CAC1C,MAAM,SAAS,cAAc,GAAG,YAAY,YAAY,CAAC,KAAK;AAE9D,MAAK,MAAM,YAAY,cAAc;EACnC,MAAM,aAAa,KAAK,KAAK,SAAS;AACtC,MAAI,CAAC,WAAW,WAAW,CAAE;AAE7B,MAAI;GACF,MAAM,UAAU,aAAa,YAAY,QAAQ;AACjD,QAAK,MAAM,QAAQ,QAAQ,MAAM,QAAQ,EAAE;IACzC,MAAM,UAAU,oBAAoB,MAAM,OAAO;AACjD,QAAI,SAAS;KACX,MAAM,cAAc,QAAQ,WAAW,IAAI,GACvC,IAAI,SAAS,QAAQ,MAAM,EAAE,KAC7B,GAAG,SAAS;AAChB,kBAAa,IAAI,YAAY;;;UAG3B;;AAGV,QAAO;;AAGT,SAAS,aAAa,MAAc,cAAoC;AACtE,MAAK,MAAM,WAAW,aACpB,KAAI,QAAQ,WAAW,IAAI,EAAE;EAC3B,MAAM,WAAW,QAAQ,MAAM,EAAE;AACjC,MAAI,SAAS,YAAY,KAAK,WAAW,GAAG,SAAS,GAAG,CACtD,QAAO;YAGL,SAAS,WAAW,KAAK,WAAW,GAAG,QAAQ,GAAG,CACpD,QAAO;AAIb,QAAO;;AAGT,SAAS,eAAe,KAAa,QAAqD;CACxF,MAAM,SAAkB,EAAE;AAC1B,KAAI,CAAC,WAAW,IAAI,CAAE,QAAO;CAE7B,SAAS,KAAK,YAAoB,qBAAkC;AAClE,MAAI;GACF,MAAM,UAAU,YAAY,YAAY,EAAE,eAAe,MAAM,CAAC;AAEhE,QAAK,MAAM,SAAS,SAAS;AAC3B,QAAI,MAAM,KAAK,WAAW,IAAI,IAAI,MAAM,SAAS,eAAgB;IAEjE,MAAM,WAAW,KAAK,YAAY,MAAM,KAAK;IAC7C,MAAM,UAAU,YAAY,SAAS,KAAK,SAAS,CAAC;AAEpD,QAAI,aAAa,SAAS,oBAAoB,CAAE;AAEhD,QAAI,MAAM,aAAa,EAAE;KACvB,MAAM,cAAc,KAAK,UAAU,WAAW;KAC9C,MAAM,eAAe,GAAG,QAAQ;KAEhC,MAAM,kBAAkB,IAAI,IAAI,oBAAoB;AAEpD,SAAI,WADkB,KAAK,UAAU,aACT,CAAC,EAAE;MAC7B,MAAM,WAAW,gBAAgB,UAAU,IAAI;AAC/C,WAAK,MAAM,QAAQ,SACjB,iBAAgB,IAAI,GAAG,eAAe,OAAO;;AAIjD,SAAI,WAAW,YAAY,IAAI,CAAC,aAAa,cAAc,oBAAoB,EAAE;MAC/E,MAAM,QAAQ,kBAAkB,aAAa,QAAQ,IAAI;AACzD,UAAI,MAAO,QAAO,KAAK,MAAM;;AAG/B,UAAK,UAAU,gBAAgB;;;UAG7B;;AAGV,MAAK,KAAK,gBAAgB,KAAK,IAAI,CAAC;AACpC,QAAO;;AAGT,SAAS,kBAAkB,UAAkB,QAA4C,SAAgC;AACvH,KAAI;EAEF,MAAM,EAAE,aAAa,YAAY,iBADd,aAAa,UAAU,QACkB,CAAC;EAC7D,MAAM,WAAW,QAAQ,SAAS;EAClC,MAAM,gBAAgB,SAAS,SAAS;EAExC,MAAM,OAAQ,YAAY,QAA+B;EACzD,MAAM,cAAc,YAAY;AAChC,MAAI,CAAC,aAAa,MAAM,CAAE,QAAO;EAIjC,IAAI;AACJ,MAAI,SAAS;GAEX,MAAM,WADS,YAAY,SAAS,SAAS,SAAS,CAC/B,CAAC,MAAM,IAAI;AAClC,OAAI,SAAS,SAAS,EACpB,YAAW,SAAS;;EAIxB,MAAM,WAAW,mBAAmB,YAAY;EAChD,MAAM,iBAAiB,yBAAyB,YAAY;EAC5D,MAAM,sBAAsB,yBAAyB,YAAY;AAEjE,SAAO;GACL;GACA,aAAa,YAAY,MAAM;GAC/B;GACA;GACA,SAAS;GACT;GACA,wBAAwB,YAAY,gCAAgC;GACpE;GACA;GACA,qBAAqB,oBAAoB,SAAS,IAAI,sBAAsB,KAAA;GAC5E;GACD;SACK;AACN,SAAO;;;AAIX,SAAgB,WAAW,SAKN;CACnB,MAAM,EAAE,cAAc,YAAY,YAAY,EAAE,KAAK;CAErD,MAAM,2BAAW,IAAI,KAAoB;CACzC,MAAM,cAAiC,EAAE;AAEzC,KAAI,WACF,MAAK,MAAM,SAAS,eAAe,YAAY,UAAU,EAAE;EACzD,MAAM,WAAW,SAAS,IAAI,MAAM,KAAK;AACzC,MAAI,SACF,aAAY,KAAK;GACf,MAAM;GACN,WAAW,MAAM;GACjB,SAAS,UAAU,MAAM,KAAK,eAAe,SAAS,OAAO,aAAa,MAAM;GAChF,MAAM,MAAM;GACb,CAAC;MAEF,UAAS,IAAI,MAAM,MAAM,MAAM;;CAKrC,MAAM,aAAa,CACjB,QAAQ,WACR,KAAK,iBAAiB,EAAE,SAAS,CAClC,CAAC,QAAQ,MAAmB,CAAC,CAAC,KAAK,WAAW,EAAE,CAAC;AAElD,MAAK,MAAM,OAAO,WAChB,MAAK,MAAM,SAAS,eAAe,KAAK,SAAS,EAAE;EACjD,MAAM,WAAW,SAAS,IAAI,MAAM,KAAK;AACzC,MAAI,SACF,aAAY,KAAK;GACf,MAAM;GACN,WAAW,MAAM;GACjB,SAAS,UAAU,MAAM,KAAK,eAAe,MAAM,OAAO,aAAa,SAAS;GAChF,MAAM,MAAM;GACb,CAAC;AAGJ,WAAS,IAAI,MAAM,MAAM,MAAM;;AAInC,KAAI,cAAc;EAChB,MAAM,kBAAkB,eAAe,KAAK,cAAc,SAAS,EAAE,YAAY;AACjF,OAAK,MAAM,SAAS,iBAAiB;GACnC,MAAM,WAAW,SAAS,IAAI,MAAM,KAAK;AACzC,OAAI,SACF,aAAY,KAAK;IACf,MAAM;IACN,WAAW,MAAM;IACjB,SAAS,UAAU,MAAM,KAAK,eAAe,MAAM,OAAO,aAAa,SAAS;IAChF,MAAM,MAAM;IACb,CAAC;AAEJ,YAAS,IAAI,MAAM,MAAM,MAAM;;;AAKnC,MAAK,MAAM,YAAY,UACrB,KAAI,WAAW,SAAS,CACtB,MAAK,MAAM,SAAS,eAAe,UAAU,SAAS,EAAE;EACtD,MAAM,WAAW,SAAS,IAAI,MAAM,KAAK;AACzC,MAAI,SACF,aAAY,KAAK;GACf,MAAM;GACN,WAAW,MAAM;GACjB,SAAS,UAAU,MAAM,KAAK,eAAe,SAAS,OAAO,aAAa,MAAM;GAChF,MAAM,MAAM;GACb,CAAC;MAEF,UAAS,IAAI,MAAM,MAAM,MAAM;;CAMvC,MAAM,eAAe,yBAAyB,iBAAiB,CAAC,CAAC,MAAM;CACvE,MAAM,SAAS,MAAM,KAAK,SAAS,QAAQ,CAAC;AAE5C,QAAO;EACL,QAAQ;EACR,QAAQ,sBAAsB,QAAQ,aAAa;EACnD;EACD;;AAiBH,SAAgB,oBAAiC;CAC/C,IAAI,eAAwB,EAAE;CAC9B,IAAI,eAAuB;CAC3B,IAAI,oBAAuC,EAAE;CAC7C,IAAI,eAAe;CACnB,IAAI;CACJ,IAAI;CACJ,IAAI,YAAsB,EAAE;CAE5B,SAAS,YAAY,QAA4C;AAC/D,iBAAe,OAAO;AACtB,iBAAe,OAAO;AACtB,sBAAoB,OAAO;AAC3B,iBAAe,KAAK,KAAK;AACzB,SAAO;;AAGT,QAAO;EACL,OAAO,WAAmB,YAA2B;AACnD,kBAAe;AACf,gBAAa,WAAW,KAAA;AACxB,UAAO,YAAY,WAAW;IAAE;IAAc;IAAY;IAAW,CAAC,CAAC;;EAGzE,YAAY;AACV,UAAO,YAAY,WAAW;IAAE;IAAc;IAAY;IAAW,CAAC,CAAC;;EAGzE,cAAc;AACZ,OAAI,KAAK,mBAAmB;AAC5B,UAAO,YAAY,WAAW;IAAE;IAAc;IAAY;IAAW,CAAC,CAAC;;EAGzE,+BAA+B;GAC7B,MAAM,eAAe,yBAAyB,iBAAiB,CAAC,CAAC,MAAM;AACvE,kBAAe,sBAAsB,cAAc,aAAa;AAChE,kBAAe,KAAK,KAAK;;EAG3B,iBAAiB;EACjB,iBAAiB;EACjB,sBAAsB;EACtB,uBAAuB;EAEvB,iBAAiB,SAAiB;AAChC,UAAO,aAAa,MAAK,MAAK,EAAE,SAAS,KAAK;;EAGhD,mBAAmB,YAA0C;GAC3D,MAAM,eACJ,YAAY,KAAA,IAAY,EAAE,SAAS,GAAG,yBAAyB,iBAAiB,CAAC,CAAC,MAAM;AAC1F,UAAO,aAAa,QACjB,UAAU,CAAC,MAAM,0BAA0B,eAAe,OAAO,aAAa,CAChF;;EAEJ"}
@@ -1,8 +1,8 @@
1
1
  import { init_paths, resolveSkillsDir } from "../../config/paths.js";
2
2
  import { parseFrontmatter } from "../../markdown/frontmatter.js";
3
3
  import { loadSkillsLock } from "./hub-lock.js";
4
- import { dirname, join, resolve, sep } from "node:path";
5
4
  import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
5
+ import { dirname, join, resolve, sep } from "node:path";
6
6
  import AdmZip from "adm-zip";
7
7
  //#region src/agent/skills/managed-store.ts
8
8
  /**
@@ -186,21 +186,21 @@ function convertListItemToPackageItem(item) {
186
186
  sourceLabel: "ClawHub"
187
187
  };
188
188
  }
189
- function convertSearchResultToPackageItem(item) {
189
+ function convertSearchResultToPackageItem(item, enrichment) {
190
190
  return {
191
191
  id: item.slug,
192
192
  name: item.displayName || item.slug,
193
193
  type: "skill",
194
194
  description: item.summary || "",
195
- downloads: 0,
195
+ downloads: enrichment?.stats.downloads ?? 0,
196
196
  author: {
197
197
  username: item.owner?.handle ?? item.ownerHandle ?? "clawhub",
198
198
  avatarUrl: item.owner?.image ?? null
199
199
  },
200
- latestVersion: item.version ?? "1.0.0",
200
+ latestVersion: item.version ?? enrichment?.latestVersion?.version ?? "1.0.0",
201
201
  updatedAt: String(item.updatedAt),
202
- categories: [],
203
- stars: 0,
202
+ categories: enrichment?.metadata?.os ?? [],
203
+ stars: enrichment?.stats.stars ?? 0,
204
204
  sourceLabel: "ClawHub"
205
205
  };
206
206
  }
@@ -222,8 +222,13 @@ const clawHubMarketplaceAdapter = {
222
222
  const pageSize = params.pageSize ?? 20;
223
223
  const page = params.page ?? 1;
224
224
  if (params.q?.trim()) {
225
- let rows = (await cachedSearchClawHubSkills(params.q.trim(), LIST_BATCH_SIZE)).results.map(convertSearchResultToPackageItem);
225
+ const [searchResponse, listSettled] = await Promise.allSettled([cachedSearchClawHubSkills(params.q.trim(), LIST_BATCH_SIZE), cachedListClawHubSkills({ limit: LIST_BATCH_SIZE })]);
226
+ if (searchResponse.status === "rejected") throw searchResponse.reason;
227
+ const enrichmentBySlug = /* @__PURE__ */ new Map();
228
+ if (listSettled.status === "fulfilled") for (const it of listSettled.value.items) enrichmentBySlug.set(it.slug, it);
229
+ let rows = searchResponse.value.results.map((r) => convertSearchResultToPackageItem(r, enrichmentBySlug.get(r.slug)));
226
230
  if (params.sort === "downloads") rows = [...rows].sort((a, b) => b.downloads - a.downloads);
231
+ else if (params.sort === "newest") rows = [...rows].sort((a, b) => Number(b.updatedAt) - Number(a.updatedAt));
227
232
  const total = rows.length;
228
233
  const start = (page - 1) * pageSize;
229
234
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.js","names":[],"sources":["../../../../../../../src/agent/skills/marketplace/adapters/clawhub/adapter.ts"],"sourcesContent":["/**\n * ClawHub (clawhub.ai) skills marketplace adapter.\n */\n\nimport type { SkillsMarketplaceAdapter } from '../../adapter.types.js';\nimport { registerMarketplaceAdapter } from '../../registry.js';\n\n// ─── Constants ───────────────────────────────────────────────────────────────\n\nconst DEFAULT_CLAWHUB_BASE = 'https://clawhub.ai';\nconst MAX_CLAWHUB_FILE_BYTES = 512 * 1024;\nconst MAX_SKILL_ZIP_BYTES = 15 * 1024 * 1024;\nconst SKILL_ID_RE = /^[a-zA-Z0-9]([a-zA-Z0-9._-]{0,62})$/;\nconst LIST_BATCH_SIZE = 200;\n\nconst DEFAULT_CACHE_MS = 5 * 60 * 1000;\nconst MAX_LIST_CACHE_KEYS = 24;\nconst MAX_DETAIL_CACHE_KEYS = 48;\n\n// ─── Inline helpers ──────────────────────────────────────────────────────────\n\nfunction isValidSkillId(id: string): boolean {\n return SKILL_ID_RE.test(id);\n}\n\nfunction resolveClawHubBaseUrl(): string {\n const env = process.env.CLAWHUB_REGISTRY?.trim();\n if (env) {\n try {\n return new URL(env).toString().replace(/\\/$/, '');\n } catch {\n // fall through\n }\n }\n return DEFAULT_CLAWHUB_BASE;\n}\n\n// ─── ClawHub API types ───────────────────────────────────────────────────────\n\ninterface ClawHubSkillListItem {\n slug: string;\n displayName: string;\n summary: string;\n tags: Record<string, string>;\n stats: {\n comments: number;\n downloads: number;\n installsAllTime: number;\n installsCurrent: number;\n stars: number;\n versions: number;\n };\n createdAt: number;\n updatedAt: number;\n latestVersion: {\n version: string;\n createdAt: number;\n changelog: string | null;\n license: string | null;\n };\n metadata: { os: string[] | null; systems: string[] | null } | null;\n}\n\ninterface ClawHubSkillListResponse {\n items: ClawHubSkillListItem[];\n nextCursor: string | null;\n}\n\ninterface ClawHubSearchResultItem {\n score: number;\n slug: string;\n displayName: string;\n summary: string;\n version: string | null;\n updatedAt: number;\n ownerHandle: string;\n owner: {\n handle: string;\n displayName: string;\n image: string | null;\n };\n}\n\ninterface ClawHubSearchResponse {\n results: ClawHubSearchResultItem[];\n}\n\ninterface ClawHubSkillDetail {\n skill: {\n slug: string;\n displayName: string;\n summary: string;\n tags: Record<string, string>;\n stats: {\n comments: number;\n downloads: number;\n installsAllTime: number;\n installsCurrent: number;\n stars: number;\n versions: number;\n };\n createdAt: number;\n updatedAt: number;\n };\n latestVersion: {\n version: string;\n createdAt: number;\n changelog: string | null;\n license: string | null;\n };\n metadata: { os: string[] | null; systems: string[] | null } | null;\n owner: {\n handle: string;\n userId: string;\n displayName: string;\n image: string | null;\n };\n moderation: {\n isSuspicious: boolean;\n isMalwareBlocked: boolean;\n verdict: string;\n } | null;\n}\n\ninterface ClawHubVersionFile {\n path: string;\n size: number;\n sha256: string;\n contentType: string;\n}\n\ninterface ClawHubVersionDetail {\n skill: { slug: string; displayName: string };\n version: {\n version: string;\n createdAt: number;\n changelog: string | null;\n changelogSource: string | null;\n license: string | null;\n files: ClawHubVersionFile[];\n security: {\n status: string;\n hasWarnings: boolean;\n hasScanResult: boolean;\n } | null;\n };\n}\n\ntype ClawHubListSort = 'updated' | 'newest' | 'downloads' | 'stars' | 'trending';\n\ninterface ClawHubListParams {\n limit?: number;\n cursor?: string;\n sort?: ClawHubListSort;\n}\n\n// ─── ClawHub HTTP helpers ────────────────────────────────────────────────────\n\nasync function clawHubFetch(path: string, init?: { signal?: AbortSignal }): Promise<Response> {\n const base = resolveClawHubBaseUrl();\n const url = `${base}${path}`;\n const res = await fetch(url, {\n headers: { Accept: 'application/json' },\n signal: init?.signal,\n });\n return res as unknown as Response;\n}\n\nfunction assertOk(res: Response, context: string): void {\n if (!res.ok) {\n throw new Error(`ClawHub ${context} failed (${res.status})`);\n }\n}\n\nasync function listClawHubSkills(params?: ClawHubListParams): Promise<ClawHubSkillListResponse> {\n const sp = new URLSearchParams();\n if (params?.limit) sp.set('limit', String(params.limit));\n if (params?.cursor) sp.set('cursor', params.cursor);\n if (params?.sort) sp.set('sort', params.sort);\n sp.set('nonSuspiciousOnly', 'true');\n const qs = sp.toString();\n const res = await clawHubFetch(`/api/v1/skills${qs ? `?${qs}` : ''}`);\n assertOk(res, 'list skills');\n return (await res.json()) as ClawHubSkillListResponse;\n}\n\nasync function searchClawHubSkills(query: string, limit?: number): Promise<ClawHubSearchResponse> {\n const sp = new URLSearchParams({ q: query, nonSuspiciousOnly: 'true' });\n if (limit) sp.set('limit', String(limit));\n const res = await clawHubFetch(`/api/v1/search?${sp.toString()}`);\n assertOk(res, 'search');\n return (await res.json()) as ClawHubSearchResponse;\n}\n\nasync function getClawHubSkillDetail(slug: string): Promise<ClawHubSkillDetail> {\n const enc = encodeURIComponent(slug.trim());\n const res = await clawHubFetch(`/api/v1/skills/${enc}`);\n assertOk(res, `skill detail [${slug}]`);\n return (await res.json()) as ClawHubSkillDetail;\n}\n\nasync function getClawHubVersionDetail(slug: string, version: string): Promise<ClawHubVersionDetail> {\n const enc = encodeURIComponent(slug.trim());\n const ver = encodeURIComponent(version.trim());\n const res = await clawHubFetch(`/api/v1/skills/${enc}/versions/${ver}`);\n assertOk(res, `version detail [${slug}@${version}]`);\n return (await res.json()) as ClawHubVersionDetail;\n}\n\nasync function getClawHubSkillFileText(slug: string, filePath: string, version?: string): Promise<string> {\n const enc = encodeURIComponent(slug.trim());\n const sp = new URLSearchParams({ path: filePath });\n if (version?.trim()) sp.set('version', version.trim());\n const base = resolveClawHubBaseUrl();\n const url = `${base}/api/v1/skills/${enc}/file?${sp.toString()}`;\n const res = await fetch(url, { headers: { Accept: 'text/markdown,text/plain,*/*' } });\n if (!res.ok) {\n throw new Error(`ClawHub file fetch [${slug}/${filePath}] failed (${res.status})`);\n }\n const text = await res.text();\n return text.length > MAX_CLAWHUB_FILE_BYTES ? text.slice(0, MAX_CLAWHUB_FILE_BYTES) : text;\n}\n\nasync function downloadClawHubSkillZip(\n slug: string,\n version?: string,\n): Promise<{ buffer: Buffer; version: string }> {\n const enc = encodeURIComponent(slug.trim());\n const sp = version?.trim() ? `?version=${encodeURIComponent(version.trim())}` : '';\n const base = resolveClawHubBaseUrl();\n const url = `${base}/api/v1/packages/${enc}/download${sp}`;\n const res = await fetch(url, { redirect: 'follow' });\n if (!res.ok) {\n const body = await res.text().catch(() => '');\n throw new Error(`ClawHub download [${slug}] failed (${res.status}): ${body.slice(0, 200)}`);\n }\n const contentType = res.headers.get('content-type') ?? '';\n if (!contentType.includes('zip') && !contentType.includes('octet-stream')) {\n throw new Error(`ClawHub download [${slug}] unexpected content-type: ${contentType}`);\n }\n const arrayBuf = await res.arrayBuffer();\n if (arrayBuf.byteLength > MAX_SKILL_ZIP_BYTES) {\n throw new Error(\n `ClawHub download [${slug}] exceeds size limit (${arrayBuf.byteLength} > ${MAX_SKILL_ZIP_BYTES})`,\n );\n }\n return { buffer: Buffer.from(arrayBuf), version: version?.trim() || 'latest' };\n}\n\nfunction pickClawHubDocFilePath(files: ClawHubVersionFile[]): string | null {\n const rows = files.map((f) => ({\n path: f.path.replace(/\\\\/g, '/'),\n base: f.path.replace(/\\\\/g, '/').split('/').pop()?.toLowerCase() ?? '',\n }));\n const find = (name: string) => rows.find((r) => r.base === name.toLowerCase());\n const skillMd = find('SKILL.md') ?? find('skill.md');\n if (skillMd) return skillMd.path;\n const readme = find('README.md') ?? find('readme.md');\n if (readme) return readme.path;\n return null;\n}\n\n// ─── In-memory TTL cache ─────────────────────────────────────────────────────\n\ntype CacheEntry<T> = { value: T; expiresAt: number };\n\nfunction cacheTtlMs(): number {\n const raw = process.env.XOPC_CLAWHUB_CACHE_MS?.trim();\n if (raw === '0' || raw === 'false') return 0;\n const parsed = Number(raw);\n if (!Number.isFinite(parsed) || parsed < 0) return DEFAULT_CACHE_MS;\n return parsed;\n}\n\nfunction getFresh<T>(entry: CacheEntry<T> | undefined): T | undefined {\n if (!entry || entry.expiresAt <= Date.now()) return undefined;\n return entry.value;\n}\n\nfunction evictOldest<T>(map: Map<string, CacheEntry<T>>): void {\n const first = map.keys().next().value;\n if (first !== undefined) map.delete(first);\n}\n\nconst listCache = new Map<string, CacheEntry<ClawHubSkillListResponse>>();\nconst searchCache = new Map<string, CacheEntry<ClawHubSearchResponse>>();\nconst detailCache = new Map<string, CacheEntry<ClawHubSkillDetail>>();\n\nasync function cachedListClawHubSkills(params?: ClawHubListParams): Promise<ClawHubSkillListResponse> {\n const ttl = cacheTtlMs();\n const key = JSON.stringify(params ?? {});\n if (ttl > 0) {\n const hit = getFresh(listCache.get(key));\n if (hit) return hit;\n }\n const value = await listClawHubSkills(params);\n if (ttl > 0) {\n while (listCache.size >= MAX_LIST_CACHE_KEYS) evictOldest(listCache);\n listCache.set(key, { value, expiresAt: Date.now() + ttl });\n }\n return value;\n}\n\nasync function cachedSearchClawHubSkills(query: string, limit?: number): Promise<ClawHubSearchResponse> {\n const ttl = cacheTtlMs();\n const key = `${query}::${limit ?? ''}`;\n if (ttl > 0) {\n const hit = getFresh(searchCache.get(key));\n if (hit) return hit;\n }\n const value = await searchClawHubSkills(query, limit);\n if (ttl > 0) {\n while (searchCache.size >= MAX_LIST_CACHE_KEYS) evictOldest(searchCache);\n searchCache.set(key, { value, expiresAt: Date.now() + ttl });\n }\n return value;\n}\n\nasync function cachedGetClawHubSkillDetail(slug: string): Promise<ClawHubSkillDetail> {\n const ttl = cacheTtlMs();\n const key = slug.trim();\n if (ttl > 0) {\n const hit = getFresh(detailCache.get(key));\n if (hit) return hit;\n }\n const value = await getClawHubSkillDetail(slug);\n if (ttl > 0) {\n while (detailCache.size >= MAX_DETAIL_CACHE_KEYS) evictOldest(detailCache);\n detailCache.set(key, { value, expiresAt: Date.now() + ttl });\n }\n return value;\n}\n\n// ─── Adapter conversion helpers ──────────────────────────────────────────────\n\ninterface PackageListItem {\n id: string;\n name: string;\n type: string;\n description: string;\n downloads: number;\n author: { username: string; avatarUrl: string | null };\n latestVersion?: string;\n updatedAt: string;\n categories?: string[];\n stars?: number;\n sourceLabel?: string;\n}\n\nfunction convertListItemToPackageItem(item: ClawHubSkillListItem): PackageListItem {\n return {\n id: item.slug,\n name: item.displayName || item.slug,\n type: 'skill',\n description: item.summary || '',\n downloads: item.stats.downloads,\n author: { username: 'clawhub', avatarUrl: null },\n latestVersion: item.latestVersion?.version ?? item.tags.latest ?? '1.0.0',\n updatedAt: String(item.updatedAt),\n categories: item.metadata?.os ?? [],\n stars: item.stats.stars,\n sourceLabel: 'ClawHub',\n };\n}\n\nfunction convertSearchResultToPackageItem(item: ClawHubSearchResultItem): PackageListItem {\n return {\n id: item.slug,\n name: item.displayName || item.slug,\n type: 'skill',\n description: item.summary || '',\n downloads: 0,\n author: {\n username: item.owner?.handle ?? item.ownerHandle ?? 'clawhub',\n avatarUrl: item.owner?.image ?? null,\n },\n latestVersion: item.version ?? '1.0.0',\n updatedAt: String(item.updatedAt),\n categories: [],\n stars: 0,\n sourceLabel: 'ClawHub',\n };\n}\n\nfunction mapSortParam(sort?: string): ClawHubListSort | undefined {\n if (sort === 'downloads') return 'downloads';\n if (sort === 'newest') return 'newest';\n return undefined;\n}\n\nfunction fallbackReadmeMarkdown(detail: {\n skill: { slug: string; displayName: string; summary: string };\n latestVersion: { version: string };\n}): string {\n const title = detail.skill.displayName || detail.skill.slug;\n const body = detail.skill.summary || '_No description._';\n return `## ${title}\\n\\n**${detail.skill.slug}** · v${detail.latestVersion.version}\\n\\n${body}`;\n}\n\nexport const clawHubMarketplaceAdapter: SkillsMarketplaceAdapter = {\n id: 'clawhub',\n\n async listCategories() {\n return [];\n },\n\n async listPackages(_config, params) {\n const pageSize = params.pageSize ?? 20;\n const page = params.page ?? 1;\n\n if (params.q?.trim()) {\n const searchResponse = await cachedSearchClawHubSkills(params.q.trim(), LIST_BATCH_SIZE);\n let rows = searchResponse.results.map(convertSearchResultToPackageItem);\n if (params.sort === 'downloads') {\n rows = [...rows].sort((a, b) => b.downloads - a.downloads);\n }\n const total = rows.length;\n const start = (page - 1) * pageSize;\n const items = rows.slice(start, start + pageSize);\n const totalPages = Math.max(1, Math.ceil(total / pageSize));\n return { items, meta: { page, pageSize, total, totalPages }, provider: 'clawhub' };\n }\n\n const sort = mapSortParam(params.sort);\n const listResponse = await cachedListClawHubSkills({ limit: LIST_BATCH_SIZE, sort });\n const rows = listResponse.items.map(convertListItemToPackageItem);\n const total = rows.length;\n const start = (page - 1) * pageSize;\n const items = rows.slice(start, start + pageSize);\n const totalPages = Math.max(1, Math.ceil(total / pageSize));\n return { items, meta: { page, pageSize, total, totalPages }, provider: 'clawhub' };\n },\n\n async getPackageDetail(_config, packageName) {\n const detail = await cachedGetClawHubSkillDetail(packageName);\n const slug = detail.skill.slug;\n const version = detail.latestVersion.version;\n\n let readme: string | null = null;\n\n try {\n const versionDetail = await getClawHubVersionDetail(slug, version);\n const docPath = pickClawHubDocFilePath(versionDetail.version.files);\n if (docPath) {\n const rawText = await getClawHubSkillFileText(slug, docPath, version);\n const trimmed = rawText.trim();\n if (trimmed) readme = trimmed;\n }\n } catch {\n // version detail or file fetch failed — use fallback\n }\n\n if (!readme) {\n readme = fallbackReadmeMarkdown(detail);\n }\n\n const changelog = detail.latestVersion.changelog?.trim();\n if (changelog) {\n readme = `${readme}\\n\\n---\\n\\n## Changelog\\n\\n${changelog}`;\n }\n\n return {\n id: slug,\n name: slug,\n type: 'skill',\n description: detail.skill.summary || '',\n readme,\n downloads: detail.skill.stats.downloads,\n author: {\n username: detail.owner.handle,\n avatarUrl: detail.owner.image,\n },\n latestVersion: {\n version: detail.latestVersion.version,\n changelog: detail.latestVersion.changelog,\n publishedAt: String(detail.latestVersion.createdAt),\n },\n provider: 'clawhub',\n };\n },\n\n async downloadPackage(_config, packageName, version) {\n const slug = packageName.trim();\n const result = await downloadClawHubSkillZip(slug, version);\n return {\n buffer: result.buffer,\n skillId: isValidSkillId(slug) ? slug : 'unknown',\n version: result.version,\n };\n },\n};\n\nregisterMarketplaceAdapter({\n adapter: clawHubMarketplaceAdapter,\n displayName: 'ClawHub',\n});\n"],"mappings":";;AASA,MAAM,uBAAuB;AAC7B,MAAM,yBAAyB,MAAM;AACrC,MAAM,sBAAsB,KAAK,OAAO;AACxC,MAAM,cAAc;AACpB,MAAM,kBAAkB;AAExB,MAAM,mBAAmB,MAAS;AAClC,MAAM,sBAAsB;AAC5B,MAAM,wBAAwB;AAI9B,SAAS,eAAe,IAAqB;AAC3C,QAAO,YAAY,KAAK,GAAG;;AAG7B,SAAS,wBAAgC;CACvC,MAAM,MAAM,QAAQ,IAAI,kBAAkB,MAAM;AAChD,KAAI,IACF,KAAI;AACF,SAAO,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,OAAO,GAAG;SAC3C;AAIV,QAAO;;AA4HT,eAAe,aAAa,MAAc,MAAoD;CAE5F,MAAM,MAAM,GADC,uBACM,GAAG;AAKtB,QAAO,MAJW,MAAM,KAAK;EAC3B,SAAS,EAAE,QAAQ,oBAAoB;EACvC,QAAQ,MAAM;EACf,CAAC;;AAIJ,SAAS,SAAS,KAAe,SAAuB;AACtD,KAAI,CAAC,IAAI,GACP,OAAM,IAAI,MAAM,WAAW,QAAQ,WAAW,IAAI,OAAO,GAAG;;AAIhE,eAAe,kBAAkB,QAA+D;CAC9F,MAAM,KAAK,IAAI,iBAAiB;AAChC,KAAI,QAAQ,MAAO,IAAG,IAAI,SAAS,OAAO,OAAO,MAAM,CAAC;AACxD,KAAI,QAAQ,OAAQ,IAAG,IAAI,UAAU,OAAO,OAAO;AACnD,KAAI,QAAQ,KAAM,IAAG,IAAI,QAAQ,OAAO,KAAK;AAC7C,IAAG,IAAI,qBAAqB,OAAO;CACnC,MAAM,KAAK,GAAG,UAAU;CACxB,MAAM,MAAM,MAAM,aAAa,iBAAiB,KAAK,IAAI,OAAO,KAAK;AACrE,UAAS,KAAK,cAAc;AAC5B,QAAQ,MAAM,IAAI,MAAM;;AAG1B,eAAe,oBAAoB,OAAe,OAAgD;CAChG,MAAM,KAAK,IAAI,gBAAgB;EAAE,GAAG;EAAO,mBAAmB;EAAQ,CAAC;AACvE,KAAI,MAAO,IAAG,IAAI,SAAS,OAAO,MAAM,CAAC;CACzC,MAAM,MAAM,MAAM,aAAa,kBAAkB,GAAG,UAAU,GAAG;AACjE,UAAS,KAAK,SAAS;AACvB,QAAQ,MAAM,IAAI,MAAM;;AAG1B,eAAe,sBAAsB,MAA2C;CAE9E,MAAM,MAAM,MAAM,aAAa,kBADnB,mBAAmB,KAAK,MAAM,CACU,GAAG;AACvD,UAAS,KAAK,iBAAiB,KAAK,GAAG;AACvC,QAAQ,MAAM,IAAI,MAAM;;AAG1B,eAAe,wBAAwB,MAAc,SAAgD;CAGnG,MAAM,MAAM,MAAM,aAAa,kBAFnB,mBAAmB,KAAK,MAAM,CAEU,CAAC,YADzC,mBAAmB,QAAQ,MAAM,CACuB,GAAG;AACvE,UAAS,KAAK,mBAAmB,KAAK,GAAG,QAAQ,GAAG;AACpD,QAAQ,MAAM,IAAI,MAAM;;AAG1B,eAAe,wBAAwB,MAAc,UAAkB,SAAmC;CACxG,MAAM,MAAM,mBAAmB,KAAK,MAAM,CAAC;CAC3C,MAAM,KAAK,IAAI,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAClD,KAAI,SAAS,MAAM,CAAE,IAAG,IAAI,WAAW,QAAQ,MAAM,CAAC;CAEtD,MAAM,MAAM,GADC,uBACM,CAAC,iBAAiB,IAAI,QAAQ,GAAG,UAAU;CAC9D,MAAM,MAAM,MAAM,MAAM,KAAK,EAAE,SAAS,EAAE,QAAQ,gCAAgC,EAAE,CAAC;AACrF,KAAI,CAAC,IAAI,GACP,OAAM,IAAI,MAAM,uBAAuB,KAAK,GAAG,SAAS,YAAY,IAAI,OAAO,GAAG;CAEpF,MAAM,OAAO,MAAM,IAAI,MAAM;AAC7B,QAAO,KAAK,SAAS,yBAAyB,KAAK,MAAM,GAAG,uBAAuB,GAAG;;AAGxF,eAAe,wBACb,MACA,SAC8C;CAC9C,MAAM,MAAM,mBAAmB,KAAK,MAAM,CAAC;CAC3C,MAAM,KAAK,SAAS,MAAM,GAAG,YAAY,mBAAmB,QAAQ,MAAM,CAAC,KAAK;CAEhF,MAAM,MAAM,GADC,uBACM,CAAC,mBAAmB,IAAI,WAAW;CACtD,MAAM,MAAM,MAAM,MAAM,KAAK,EAAE,UAAU,UAAU,CAAC;AACpD,KAAI,CAAC,IAAI,IAAI;EACX,MAAM,OAAO,MAAM,IAAI,MAAM,CAAC,YAAY,GAAG;AAC7C,QAAM,IAAI,MAAM,qBAAqB,KAAK,YAAY,IAAI,OAAO,KAAK,KAAK,MAAM,GAAG,IAAI,GAAG;;CAE7F,MAAM,cAAc,IAAI,QAAQ,IAAI,eAAe,IAAI;AACvD,KAAI,CAAC,YAAY,SAAS,MAAM,IAAI,CAAC,YAAY,SAAS,eAAe,CACvE,OAAM,IAAI,MAAM,qBAAqB,KAAK,6BAA6B,cAAc;CAEvF,MAAM,WAAW,MAAM,IAAI,aAAa;AACxC,KAAI,SAAS,aAAa,oBACxB,OAAM,IAAI,MACR,qBAAqB,KAAK,wBAAwB,SAAS,WAAW,KAAK,oBAAoB,GAChG;AAEH,QAAO;EAAE,QAAQ,OAAO,KAAK,SAAS;EAAE,SAAS,SAAS,MAAM,IAAI;EAAU;;AAGhF,SAAS,uBAAuB,OAA4C;CAC1E,MAAM,OAAO,MAAM,KAAK,OAAO;EAC7B,MAAM,EAAE,KAAK,QAAQ,OAAO,IAAI;EAChC,MAAM,EAAE,KAAK,QAAQ,OAAO,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,aAAa,IAAI;EACrE,EAAE;CACH,MAAM,QAAQ,SAAiB,KAAK,MAAM,MAAM,EAAE,SAAS,KAAK,aAAa,CAAC;CAC9E,MAAM,UAAU,KAAK,WAAW,IAAI,KAAK,WAAW;AACpD,KAAI,QAAS,QAAO,QAAQ;CAC5B,MAAM,SAAS,KAAK,YAAY,IAAI,KAAK,YAAY;AACrD,KAAI,OAAQ,QAAO,OAAO;AAC1B,QAAO;;AAOT,SAAS,aAAqB;CAC5B,MAAM,MAAM,QAAQ,IAAI,uBAAuB,MAAM;AACrD,KAAI,QAAQ,OAAO,QAAQ,QAAS,QAAO;CAC3C,MAAM,SAAS,OAAO,IAAI;AAC1B,KAAI,CAAC,OAAO,SAAS,OAAO,IAAI,SAAS,EAAG,QAAO;AACnD,QAAO;;AAGT,SAAS,SAAY,OAAiD;AACpE,KAAI,CAAC,SAAS,MAAM,aAAa,KAAK,KAAK,CAAE,QAAO,KAAA;AACpD,QAAO,MAAM;;AAGf,SAAS,YAAe,KAAuC;CAC7D,MAAM,QAAQ,IAAI,MAAM,CAAC,MAAM,CAAC;AAChC,KAAI,UAAU,KAAA,EAAW,KAAI,OAAO,MAAM;;AAG5C,MAAM,4BAAY,IAAI,KAAmD;AACzE,MAAM,8BAAc,IAAI,KAAgD;AACxE,MAAM,8BAAc,IAAI,KAA6C;AAErE,eAAe,wBAAwB,QAA+D;CACpG,MAAM,MAAM,YAAY;CACxB,MAAM,MAAM,KAAK,UAAU,UAAU,EAAE,CAAC;AACxC,KAAI,MAAM,GAAG;EACX,MAAM,MAAM,SAAS,UAAU,IAAI,IAAI,CAAC;AACxC,MAAI,IAAK,QAAO;;CAElB,MAAM,QAAQ,MAAM,kBAAkB,OAAO;AAC7C,KAAI,MAAM,GAAG;AACX,SAAO,UAAU,QAAQ,oBAAqB,aAAY,UAAU;AACpE,YAAU,IAAI,KAAK;GAAE;GAAO,WAAW,KAAK,KAAK,GAAG;GAAK,CAAC;;AAE5D,QAAO;;AAGT,eAAe,0BAA0B,OAAe,OAAgD;CACtG,MAAM,MAAM,YAAY;CACxB,MAAM,MAAM,GAAG,MAAM,IAAI,SAAS;AAClC,KAAI,MAAM,GAAG;EACX,MAAM,MAAM,SAAS,YAAY,IAAI,IAAI,CAAC;AAC1C,MAAI,IAAK,QAAO;;CAElB,MAAM,QAAQ,MAAM,oBAAoB,OAAO,MAAM;AACrD,KAAI,MAAM,GAAG;AACX,SAAO,YAAY,QAAQ,oBAAqB,aAAY,YAAY;AACxE,cAAY,IAAI,KAAK;GAAE;GAAO,WAAW,KAAK,KAAK,GAAG;GAAK,CAAC;;AAE9D,QAAO;;AAGT,eAAe,4BAA4B,MAA2C;CACpF,MAAM,MAAM,YAAY;CACxB,MAAM,MAAM,KAAK,MAAM;AACvB,KAAI,MAAM,GAAG;EACX,MAAM,MAAM,SAAS,YAAY,IAAI,IAAI,CAAC;AAC1C,MAAI,IAAK,QAAO;;CAElB,MAAM,QAAQ,MAAM,sBAAsB,KAAK;AAC/C,KAAI,MAAM,GAAG;AACX,SAAO,YAAY,QAAQ,sBAAuB,aAAY,YAAY;AAC1E,cAAY,IAAI,KAAK;GAAE;GAAO,WAAW,KAAK,KAAK,GAAG;GAAK,CAAC;;AAE9D,QAAO;;AAmBT,SAAS,6BAA6B,MAA6C;AACjF,QAAO;EACL,IAAI,KAAK;EACT,MAAM,KAAK,eAAe,KAAK;EAC/B,MAAM;EACN,aAAa,KAAK,WAAW;EAC7B,WAAW,KAAK,MAAM;EACtB,QAAQ;GAAE,UAAU;GAAW,WAAW;GAAM;EAChD,eAAe,KAAK,eAAe,WAAW,KAAK,KAAK,UAAU;EAClE,WAAW,OAAO,KAAK,UAAU;EACjC,YAAY,KAAK,UAAU,MAAM,EAAE;EACnC,OAAO,KAAK,MAAM;EAClB,aAAa;EACd;;AAGH,SAAS,iCAAiC,MAAgD;AACxF,QAAO;EACL,IAAI,KAAK;EACT,MAAM,KAAK,eAAe,KAAK;EAC/B,MAAM;EACN,aAAa,KAAK,WAAW;EAC7B,WAAW;EACX,QAAQ;GACN,UAAU,KAAK,OAAO,UAAU,KAAK,eAAe;GACpD,WAAW,KAAK,OAAO,SAAS;GACjC;EACD,eAAe,KAAK,WAAW;EAC/B,WAAW,OAAO,KAAK,UAAU;EACjC,YAAY,EAAE;EACd,OAAO;EACP,aAAa;EACd;;AAGH,SAAS,aAAa,MAA4C;AAChE,KAAI,SAAS,YAAa,QAAO;AACjC,KAAI,SAAS,SAAU,QAAO;;AAIhC,SAAS,uBAAuB,QAGrB;CACT,MAAM,QAAQ,OAAO,MAAM,eAAe,OAAO,MAAM;CACvD,MAAM,OAAO,OAAO,MAAM,WAAW;AACrC,QAAO,MAAM,MAAM,QAAQ,OAAO,MAAM,KAAK,QAAQ,OAAO,cAAc,QAAQ,MAAM;;AAG1F,MAAa,4BAAsD;CACjE,IAAI;CAEJ,MAAM,iBAAiB;AACrB,SAAO,EAAE;;CAGX,MAAM,aAAa,SAAS,QAAQ;EAClC,MAAM,WAAW,OAAO,YAAY;EACpC,MAAM,OAAO,OAAO,QAAQ;AAE5B,MAAI,OAAO,GAAG,MAAM,EAAE;GAEpB,IAAI,QAAO,MADkB,0BAA0B,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAC9D,QAAQ,IAAI,iCAAiC;AACvE,OAAI,OAAO,SAAS,YAClB,QAAO,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,MAAM,EAAE,YAAY,EAAE,UAAU;GAE5D,MAAM,QAAQ,KAAK;GACnB,MAAM,SAAS,OAAO,KAAK;AAG3B,UAAO;IAAE,OAFK,KAAK,MAAM,OAAO,QAAQ,SAE1B;IAAE,MAAM;KAAE;KAAM;KAAU;KAAO,YAD5B,KAAK,IAAI,GAAG,KAAK,KAAK,QAAQ,SAAS,CACD;KAAE;IAAE,UAAU;IAAW;;EAKpF,MAAM,QAAO,MADc,wBAAwB;GAAE,OAAO;GAAiB,MADhE,aAAa,OAAO,KACgD;GAAE,CAAC,EAC1D,MAAM,IAAI,6BAA6B;EACjE,MAAM,QAAQ,KAAK;EACnB,MAAM,SAAS,OAAO,KAAK;AAG3B,SAAO;GAAE,OAFK,KAAK,MAAM,OAAO,QAAQ,SAE1B;GAAE,MAAM;IAAE;IAAM;IAAU;IAAO,YAD5B,KAAK,IAAI,GAAG,KAAK,KAAK,QAAQ,SAAS,CACD;IAAE;GAAE,UAAU;GAAW;;CAGpF,MAAM,iBAAiB,SAAS,aAAa;EAC3C,MAAM,SAAS,MAAM,4BAA4B,YAAY;EAC7D,MAAM,OAAO,OAAO,MAAM;EAC1B,MAAM,UAAU,OAAO,cAAc;EAErC,IAAI,SAAwB;AAE5B,MAAI;GAEF,MAAM,UAAU,wBAAuB,MADX,wBAAwB,MAAM,QAAQ,EACb,QAAQ,MAAM;AACnE,OAAI,SAAS;IAEX,MAAM,WAAU,MADM,wBAAwB,MAAM,SAAS,QAAQ,EAC7C,MAAM;AAC9B,QAAI,QAAS,UAAS;;UAElB;AAIR,MAAI,CAAC,OACH,UAAS,uBAAuB,OAAO;EAGzC,MAAM,YAAY,OAAO,cAAc,WAAW,MAAM;AACxD,MAAI,UACF,UAAS,GAAG,OAAO,6BAA6B;AAGlD,SAAO;GACL,IAAI;GACJ,MAAM;GACN,MAAM;GACN,aAAa,OAAO,MAAM,WAAW;GACrC;GACA,WAAW,OAAO,MAAM,MAAM;GAC9B,QAAQ;IACN,UAAU,OAAO,MAAM;IACvB,WAAW,OAAO,MAAM;IACzB;GACD,eAAe;IACb,SAAS,OAAO,cAAc;IAC9B,WAAW,OAAO,cAAc;IAChC,aAAa,OAAO,OAAO,cAAc,UAAU;IACpD;GACD,UAAU;GACX;;CAGH,MAAM,gBAAgB,SAAS,aAAa,SAAS;EACnD,MAAM,OAAO,YAAY,MAAM;EAC/B,MAAM,SAAS,MAAM,wBAAwB,MAAM,QAAQ;AAC3D,SAAO;GACL,QAAQ,OAAO;GACf,SAAS,eAAe,KAAK,GAAG,OAAO;GACvC,SAAS,OAAO;GACjB;;CAEJ;AAED,2BAA2B;CACzB,SAAS;CACT,aAAa;CACd,CAAC"}
1
+ {"version":3,"file":"adapter.js","names":[],"sources":["../../../../../../../src/agent/skills/marketplace/adapters/clawhub/adapter.ts"],"sourcesContent":["/**\n * ClawHub (clawhub.ai) skills marketplace adapter.\n */\n\nimport type { SkillsMarketplaceAdapter } from '../../adapter.types.js';\nimport { registerMarketplaceAdapter } from '../../registry.js';\n\n// ─── Constants ───────────────────────────────────────────────────────────────\n\nconst DEFAULT_CLAWHUB_BASE = 'https://clawhub.ai';\nconst MAX_CLAWHUB_FILE_BYTES = 512 * 1024;\nconst MAX_SKILL_ZIP_BYTES = 15 * 1024 * 1024;\nconst SKILL_ID_RE = /^[a-zA-Z0-9]([a-zA-Z0-9._-]{0,62})$/;\nconst LIST_BATCH_SIZE = 200;\n\nconst DEFAULT_CACHE_MS = 5 * 60 * 1000;\nconst MAX_LIST_CACHE_KEYS = 24;\nconst MAX_DETAIL_CACHE_KEYS = 48;\n\n// ─── Inline helpers ──────────────────────────────────────────────────────────\n\nfunction isValidSkillId(id: string): boolean {\n return SKILL_ID_RE.test(id);\n}\n\nfunction resolveClawHubBaseUrl(): string {\n const env = process.env.CLAWHUB_REGISTRY?.trim();\n if (env) {\n try {\n return new URL(env).toString().replace(/\\/$/, '');\n } catch {\n // fall through\n }\n }\n return DEFAULT_CLAWHUB_BASE;\n}\n\n// ─── ClawHub API types ───────────────────────────────────────────────────────\n\ninterface ClawHubSkillListItem {\n slug: string;\n displayName: string;\n summary: string;\n tags: Record<string, string>;\n stats: {\n comments: number;\n downloads: number;\n installsAllTime: number;\n installsCurrent: number;\n stars: number;\n versions: number;\n };\n createdAt: number;\n updatedAt: number;\n latestVersion: {\n version: string;\n createdAt: number;\n changelog: string | null;\n license: string | null;\n };\n metadata: { os: string[] | null; systems: string[] | null } | null;\n}\n\ninterface ClawHubSkillListResponse {\n items: ClawHubSkillListItem[];\n nextCursor: string | null;\n}\n\ninterface ClawHubSearchResultItem {\n score: number;\n slug: string;\n displayName: string;\n summary: string;\n version: string | null;\n updatedAt: number;\n ownerHandle: string;\n owner: {\n handle: string;\n displayName: string;\n image: string | null;\n };\n}\n\ninterface ClawHubSearchResponse {\n results: ClawHubSearchResultItem[];\n}\n\ninterface ClawHubSkillDetail {\n skill: {\n slug: string;\n displayName: string;\n summary: string;\n tags: Record<string, string>;\n stats: {\n comments: number;\n downloads: number;\n installsAllTime: number;\n installsCurrent: number;\n stars: number;\n versions: number;\n };\n createdAt: number;\n updatedAt: number;\n };\n latestVersion: {\n version: string;\n createdAt: number;\n changelog: string | null;\n license: string | null;\n };\n metadata: { os: string[] | null; systems: string[] | null } | null;\n owner: {\n handle: string;\n userId: string;\n displayName: string;\n image: string | null;\n };\n moderation: {\n isSuspicious: boolean;\n isMalwareBlocked: boolean;\n verdict: string;\n } | null;\n}\n\ninterface ClawHubVersionFile {\n path: string;\n size: number;\n sha256: string;\n contentType: string;\n}\n\ninterface ClawHubVersionDetail {\n skill: { slug: string; displayName: string };\n version: {\n version: string;\n createdAt: number;\n changelog: string | null;\n changelogSource: string | null;\n license: string | null;\n files: ClawHubVersionFile[];\n security: {\n status: string;\n hasWarnings: boolean;\n hasScanResult: boolean;\n } | null;\n };\n}\n\ntype ClawHubListSort = 'updated' | 'newest' | 'downloads' | 'stars' | 'trending';\n\ninterface ClawHubListParams {\n limit?: number;\n cursor?: string;\n sort?: ClawHubListSort;\n}\n\n// ─── ClawHub HTTP helpers ────────────────────────────────────────────────────\n\nasync function clawHubFetch(path: string, init?: { signal?: AbortSignal }): Promise<Response> {\n const base = resolveClawHubBaseUrl();\n const url = `${base}${path}`;\n const res = await fetch(url, {\n headers: { Accept: 'application/json' },\n signal: init?.signal,\n });\n return res as unknown as Response;\n}\n\nfunction assertOk(res: Response, context: string): void {\n if (!res.ok) {\n throw new Error(`ClawHub ${context} failed (${res.status})`);\n }\n}\n\nasync function listClawHubSkills(params?: ClawHubListParams): Promise<ClawHubSkillListResponse> {\n const sp = new URLSearchParams();\n if (params?.limit) sp.set('limit', String(params.limit));\n if (params?.cursor) sp.set('cursor', params.cursor);\n if (params?.sort) sp.set('sort', params.sort);\n sp.set('nonSuspiciousOnly', 'true');\n const qs = sp.toString();\n const res = await clawHubFetch(`/api/v1/skills${qs ? `?${qs}` : ''}`);\n assertOk(res, 'list skills');\n return (await res.json()) as ClawHubSkillListResponse;\n}\n\nasync function searchClawHubSkills(query: string, limit?: number): Promise<ClawHubSearchResponse> {\n const sp = new URLSearchParams({ q: query, nonSuspiciousOnly: 'true' });\n if (limit) sp.set('limit', String(limit));\n const res = await clawHubFetch(`/api/v1/search?${sp.toString()}`);\n assertOk(res, 'search');\n return (await res.json()) as ClawHubSearchResponse;\n}\n\nasync function getClawHubSkillDetail(slug: string): Promise<ClawHubSkillDetail> {\n const enc = encodeURIComponent(slug.trim());\n const res = await clawHubFetch(`/api/v1/skills/${enc}`);\n assertOk(res, `skill detail [${slug}]`);\n return (await res.json()) as ClawHubSkillDetail;\n}\n\nasync function getClawHubVersionDetail(slug: string, version: string): Promise<ClawHubVersionDetail> {\n const enc = encodeURIComponent(slug.trim());\n const ver = encodeURIComponent(version.trim());\n const res = await clawHubFetch(`/api/v1/skills/${enc}/versions/${ver}`);\n assertOk(res, `version detail [${slug}@${version}]`);\n return (await res.json()) as ClawHubVersionDetail;\n}\n\nasync function getClawHubSkillFileText(slug: string, filePath: string, version?: string): Promise<string> {\n const enc = encodeURIComponent(slug.trim());\n const sp = new URLSearchParams({ path: filePath });\n if (version?.trim()) sp.set('version', version.trim());\n const base = resolveClawHubBaseUrl();\n const url = `${base}/api/v1/skills/${enc}/file?${sp.toString()}`;\n const res = await fetch(url, { headers: { Accept: 'text/markdown,text/plain,*/*' } });\n if (!res.ok) {\n throw new Error(`ClawHub file fetch [${slug}/${filePath}] failed (${res.status})`);\n }\n const text = await res.text();\n return text.length > MAX_CLAWHUB_FILE_BYTES ? text.slice(0, MAX_CLAWHUB_FILE_BYTES) : text;\n}\n\nasync function downloadClawHubSkillZip(\n slug: string,\n version?: string,\n): Promise<{ buffer: Buffer; version: string }> {\n const enc = encodeURIComponent(slug.trim());\n const sp = version?.trim() ? `?version=${encodeURIComponent(version.trim())}` : '';\n const base = resolveClawHubBaseUrl();\n const url = `${base}/api/v1/packages/${enc}/download${sp}`;\n const res = await fetch(url, { redirect: 'follow' });\n if (!res.ok) {\n const body = await res.text().catch(() => '');\n throw new Error(`ClawHub download [${slug}] failed (${res.status}): ${body.slice(0, 200)}`);\n }\n const contentType = res.headers.get('content-type') ?? '';\n if (!contentType.includes('zip') && !contentType.includes('octet-stream')) {\n throw new Error(`ClawHub download [${slug}] unexpected content-type: ${contentType}`);\n }\n const arrayBuf = await res.arrayBuffer();\n if (arrayBuf.byteLength > MAX_SKILL_ZIP_BYTES) {\n throw new Error(\n `ClawHub download [${slug}] exceeds size limit (${arrayBuf.byteLength} > ${MAX_SKILL_ZIP_BYTES})`,\n );\n }\n return { buffer: Buffer.from(arrayBuf), version: version?.trim() || 'latest' };\n}\n\nfunction pickClawHubDocFilePath(files: ClawHubVersionFile[]): string | null {\n const rows = files.map((f) => ({\n path: f.path.replace(/\\\\/g, '/'),\n base: f.path.replace(/\\\\/g, '/').split('/').pop()?.toLowerCase() ?? '',\n }));\n const find = (name: string) => rows.find((r) => r.base === name.toLowerCase());\n const skillMd = find('SKILL.md') ?? find('skill.md');\n if (skillMd) return skillMd.path;\n const readme = find('README.md') ?? find('readme.md');\n if (readme) return readme.path;\n return null;\n}\n\n// ─── In-memory TTL cache ─────────────────────────────────────────────────────\n\ntype CacheEntry<T> = { value: T; expiresAt: number };\n\nfunction cacheTtlMs(): number {\n const raw = process.env.XOPC_CLAWHUB_CACHE_MS?.trim();\n if (raw === '0' || raw === 'false') return 0;\n const parsed = Number(raw);\n if (!Number.isFinite(parsed) || parsed < 0) return DEFAULT_CACHE_MS;\n return parsed;\n}\n\nfunction getFresh<T>(entry: CacheEntry<T> | undefined): T | undefined {\n if (!entry || entry.expiresAt <= Date.now()) return undefined;\n return entry.value;\n}\n\nfunction evictOldest<T>(map: Map<string, CacheEntry<T>>): void {\n const first = map.keys().next().value;\n if (first !== undefined) map.delete(first);\n}\n\nconst listCache = new Map<string, CacheEntry<ClawHubSkillListResponse>>();\nconst searchCache = new Map<string, CacheEntry<ClawHubSearchResponse>>();\nconst detailCache = new Map<string, CacheEntry<ClawHubSkillDetail>>();\n\nasync function cachedListClawHubSkills(params?: ClawHubListParams): Promise<ClawHubSkillListResponse> {\n const ttl = cacheTtlMs();\n const key = JSON.stringify(params ?? {});\n if (ttl > 0) {\n const hit = getFresh(listCache.get(key));\n if (hit) return hit;\n }\n const value = await listClawHubSkills(params);\n if (ttl > 0) {\n while (listCache.size >= MAX_LIST_CACHE_KEYS) evictOldest(listCache);\n listCache.set(key, { value, expiresAt: Date.now() + ttl });\n }\n return value;\n}\n\nasync function cachedSearchClawHubSkills(query: string, limit?: number): Promise<ClawHubSearchResponse> {\n const ttl = cacheTtlMs();\n const key = `${query}::${limit ?? ''}`;\n if (ttl > 0) {\n const hit = getFresh(searchCache.get(key));\n if (hit) return hit;\n }\n const value = await searchClawHubSkills(query, limit);\n if (ttl > 0) {\n while (searchCache.size >= MAX_LIST_CACHE_KEYS) evictOldest(searchCache);\n searchCache.set(key, { value, expiresAt: Date.now() + ttl });\n }\n return value;\n}\n\nasync function cachedGetClawHubSkillDetail(slug: string): Promise<ClawHubSkillDetail> {\n const ttl = cacheTtlMs();\n const key = slug.trim();\n if (ttl > 0) {\n const hit = getFresh(detailCache.get(key));\n if (hit) return hit;\n }\n const value = await getClawHubSkillDetail(slug);\n if (ttl > 0) {\n while (detailCache.size >= MAX_DETAIL_CACHE_KEYS) evictOldest(detailCache);\n detailCache.set(key, { value, expiresAt: Date.now() + ttl });\n }\n return value;\n}\n\n// ─── Adapter conversion helpers ──────────────────────────────────────────────\n\ninterface PackageListItem {\n id: string;\n name: string;\n type: string;\n description: string;\n downloads: number;\n author: { username: string; avatarUrl: string | null };\n latestVersion?: string;\n updatedAt: string;\n categories?: string[];\n stars?: number;\n sourceLabel?: string;\n}\n\nfunction convertListItemToPackageItem(item: ClawHubSkillListItem): PackageListItem {\n return {\n id: item.slug,\n name: item.displayName || item.slug,\n type: 'skill',\n description: item.summary || '',\n downloads: item.stats.downloads,\n author: { username: 'clawhub', avatarUrl: null },\n latestVersion: item.latestVersion?.version ?? item.tags.latest ?? '1.0.0',\n updatedAt: String(item.updatedAt),\n categories: item.metadata?.os ?? [],\n stars: item.stats.stars,\n sourceLabel: 'ClawHub',\n };\n}\n\nfunction convertSearchResultToPackageItem(\n item: ClawHubSearchResultItem,\n enrichment?: ClawHubSkillListItem,\n): PackageListItem {\n return {\n id: item.slug,\n name: item.displayName || item.slug,\n type: 'skill',\n description: item.summary || '',\n downloads: enrichment?.stats.downloads ?? 0,\n author: {\n username: item.owner?.handle ?? item.ownerHandle ?? 'clawhub',\n avatarUrl: item.owner?.image ?? null,\n },\n latestVersion: item.version ?? enrichment?.latestVersion?.version ?? '1.0.0',\n updatedAt: String(item.updatedAt),\n categories: enrichment?.metadata?.os ?? [],\n stars: enrichment?.stats.stars ?? 0,\n sourceLabel: 'ClawHub',\n };\n}\n\nfunction mapSortParam(sort?: string): ClawHubListSort | undefined {\n if (sort === 'downloads') return 'downloads';\n if (sort === 'newest') return 'newest';\n return undefined;\n}\n\nfunction fallbackReadmeMarkdown(detail: {\n skill: { slug: string; displayName: string; summary: string };\n latestVersion: { version: string };\n}): string {\n const title = detail.skill.displayName || detail.skill.slug;\n const body = detail.skill.summary || '_No description._';\n return `## ${title}\\n\\n**${detail.skill.slug}** · v${detail.latestVersion.version}\\n\\n${body}`;\n}\n\nexport const clawHubMarketplaceAdapter: SkillsMarketplaceAdapter = {\n id: 'clawhub',\n\n async listCategories() {\n return [];\n },\n\n async listPackages(_config, params) {\n const pageSize = params.pageSize ?? 20;\n const page = params.page ?? 1;\n\n if (params.q?.trim()) {\n // Search results from /search omit downloads/stars/metadata. We pull the cached list\n // snapshot in parallel and merge by slug — costs nothing when the list cache is hot\n // (which it is after any preceding browse), and adds at most one round-trip on a cold\n // cache. We still tolerate a list-fetch failure: enrichment becomes a no-op.\n const [searchResponse, listSettled] = await Promise.allSettled([\n cachedSearchClawHubSkills(params.q.trim(), LIST_BATCH_SIZE),\n cachedListClawHubSkills({ limit: LIST_BATCH_SIZE }),\n ]);\n if (searchResponse.status === 'rejected') throw searchResponse.reason;\n const enrichmentBySlug = new Map<string, ClawHubSkillListItem>();\n if (listSettled.status === 'fulfilled') {\n for (const it of listSettled.value.items) enrichmentBySlug.set(it.slug, it);\n }\n let rows = searchResponse.value.results.map((r) =>\n convertSearchResultToPackageItem(r, enrichmentBySlug.get(r.slug)),\n );\n if (params.sort === 'downloads') {\n rows = [...rows].sort((a, b) => b.downloads - a.downloads);\n } else if (params.sort === 'newest') {\n rows = [...rows].sort((a, b) => Number(b.updatedAt) - Number(a.updatedAt));\n }\n const total = rows.length;\n const start = (page - 1) * pageSize;\n const items = rows.slice(start, start + pageSize);\n const totalPages = Math.max(1, Math.ceil(total / pageSize));\n return { items, meta: { page, pageSize, total, totalPages }, provider: 'clawhub' };\n }\n\n const sort = mapSortParam(params.sort);\n const listResponse = await cachedListClawHubSkills({ limit: LIST_BATCH_SIZE, sort });\n const rows = listResponse.items.map(convertListItemToPackageItem);\n const total = rows.length;\n const start = (page - 1) * pageSize;\n const items = rows.slice(start, start + pageSize);\n const totalPages = Math.max(1, Math.ceil(total / pageSize));\n return { items, meta: { page, pageSize, total, totalPages }, provider: 'clawhub' };\n },\n\n async getPackageDetail(_config, packageName) {\n const detail = await cachedGetClawHubSkillDetail(packageName);\n const slug = detail.skill.slug;\n const version = detail.latestVersion.version;\n\n let readme: string | null = null;\n\n try {\n const versionDetail = await getClawHubVersionDetail(slug, version);\n const docPath = pickClawHubDocFilePath(versionDetail.version.files);\n if (docPath) {\n const rawText = await getClawHubSkillFileText(slug, docPath, version);\n const trimmed = rawText.trim();\n if (trimmed) readme = trimmed;\n }\n } catch {\n // version detail or file fetch failed — use fallback\n }\n\n if (!readme) {\n readme = fallbackReadmeMarkdown(detail);\n }\n\n const changelog = detail.latestVersion.changelog?.trim();\n if (changelog) {\n readme = `${readme}\\n\\n---\\n\\n## Changelog\\n\\n${changelog}`;\n }\n\n return {\n id: slug,\n name: slug,\n type: 'skill',\n description: detail.skill.summary || '',\n readme,\n downloads: detail.skill.stats.downloads,\n author: {\n username: detail.owner.handle,\n avatarUrl: detail.owner.image,\n },\n latestVersion: {\n version: detail.latestVersion.version,\n changelog: detail.latestVersion.changelog,\n publishedAt: String(detail.latestVersion.createdAt),\n },\n provider: 'clawhub',\n };\n },\n\n async downloadPackage(_config, packageName, version) {\n const slug = packageName.trim();\n const result = await downloadClawHubSkillZip(slug, version);\n return {\n buffer: result.buffer,\n skillId: isValidSkillId(slug) ? slug : 'unknown',\n version: result.version,\n };\n },\n};\n\nregisterMarketplaceAdapter({\n adapter: clawHubMarketplaceAdapter,\n displayName: 'ClawHub',\n});\n"],"mappings":"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"}