@xopcai/xopc 0.0.127 → 0.0.129

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 (334) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/xopc.extension.json +1 -1
  3. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-CgGgO4OV.js → agent-avatar-dicebear-DHzfg5D-.js} +1 -1
  4. package/dist/gateway/static/root/assets/agents-CMxKKFQD.js +2 -0
  5. package/dist/gateway/static/root/assets/app-management-settings-panel-ptk9c5BN.js +1 -0
  6. package/dist/gateway/static/root/assets/{appearance-settings-BnHQW7Hv.js → appearance-settings-bYeEj3IW.js} +1 -1
  7. package/dist/gateway/static/root/assets/apps-page-DdZvDf5B.js +1 -0
  8. package/dist/gateway/static/root/assets/{archive-plugin-5NXT7Zqv.js → archive-plugin-Dy6lsTHw.js} +1 -1
  9. package/dist/gateway/static/root/assets/{attachment-load-DghwhYe0.js → attachment-load-qOtBYR6Y.js} +1 -1
  10. package/dist/gateway/static/root/assets/{automation-suggestion-card-DYmESgwl.js → automation-suggestion-card-BFH-RfaV.js} +1 -1
  11. package/dist/gateway/static/root/assets/automations-page-B8JTjkCr.js +4 -0
  12. package/dist/gateway/static/root/assets/{binary-plugins-DSbPKdWX.js → binary-plugins-DJvi_thc.js} +1 -1
  13. package/dist/gateway/static/root/assets/{block-editor-CoZ-_np-.js → block-editor-DlMnizlt.js} +4 -4
  14. package/dist/gateway/static/root/assets/browser-settings-page-slHLiZgi.js +8 -0
  15. package/dist/gateway/static/root/assets/capability-presets-api-D4q7vHVJ.js +1 -0
  16. package/dist/gateway/static/root/assets/capability-presets-settings-panel-Dng8Grpv.js +1 -0
  17. package/dist/gateway/static/root/assets/channel-recipient-api-BrW5Kcgc.js +1 -0
  18. package/dist/gateway/static/root/assets/channels-settings-KIsISXw0.js +1 -0
  19. package/dist/gateway/static/root/assets/{code-editor-gbRgS14t.js → code-editor--tMO38Tr.js} +1 -1
  20. package/dist/gateway/static/root/assets/connectors-page-C5fx4Qs9.js +2 -0
  21. package/dist/gateway/static/root/assets/desktop-pet-Jmdn6q47.js +1 -0
  22. package/dist/gateway/static/root/assets/{desktop-pet-settings-npJ0Oh5p.js → desktop-pet-settings-B-u63N4e.js} +1 -1
  23. package/dist/gateway/static/root/assets/{directory-picker-path-field-BR2ItBuf.js → directory-picker-path-field-8p1ehIHn.js} +1 -1
  24. package/dist/gateway/static/root/assets/dreaming-settings-CCkKP-I4.js +3 -0
  25. package/dist/gateway/static/root/assets/{extension-debug-page-Tl0f1rNv.js → extension-debug-page-DJ1ABK95.js} +1 -1
  26. package/dist/gateway/static/root/assets/{extension-page-Ck7QuwE3.js → extension-page-CP9P2lGM.js} +1 -1
  27. package/dist/gateway/static/root/assets/extension-settings-page-DnhU-tx0.js +1 -0
  28. package/dist/gateway/static/root/assets/fetch-BMjlW0g1.js +1 -0
  29. package/dist/gateway/static/root/assets/gateway-config-api-CjxDn46s.js +1 -0
  30. package/dist/gateway/static/root/assets/gateway-settings-TING7224.js +1 -0
  31. package/dist/gateway/static/root/assets/{gateway-startup-retry-Yh8h3hkj.js → gateway-startup-retry-CY5W2Pp4.js} +1 -1
  32. package/dist/gateway/static/root/assets/goal-create-dialog-2lPbGfp3.js +1 -0
  33. package/dist/gateway/static/root/assets/goal-detail-page-DHWVRafk.js +4 -0
  34. package/dist/gateway/static/root/assets/goals-config-api-BqhuxG8P.js +1 -0
  35. package/dist/gateway/static/root/assets/goals-page-CMk-9ZYN.js +2 -0
  36. package/dist/gateway/static/root/assets/goals-settings-BHzOAU_l.js +1 -0
  37. package/dist/gateway/static/root/assets/heartbeat-settings-BQIm0P3V.js +1 -0
  38. package/dist/gateway/static/root/assets/{html-workspace-editor-DV90ddkE.js → html-workspace-editor-COqmtESs.js} +1 -1
  39. package/dist/gateway/static/root/assets/index-C4k6QSXw.js +257 -0
  40. package/dist/gateway/static/root/assets/index-EKmpPvZj.css +1 -0
  41. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-CfQrt_Rb.js → keyboard-shortcuts-settings-BrENZzM7.js} +1 -1
  42. package/dist/gateway/static/root/assets/logs-page-BiL302Ve.js +2 -0
  43. package/dist/gateway/static/root/assets/{markdown-editor-BFOjBBla.js → markdown-editor-jD1LPiP-.js} +2 -2
  44. package/dist/gateway/static/root/assets/{markdown-split-BwiMdCf_.js → markdown-split-BYF4ReGM.js} +1 -1
  45. package/dist/gateway/static/root/assets/{media-plugins-DhoizyZv.js → media-plugins-CpQDz-QJ.js} +1 -1
  46. package/dist/gateway/static/root/assets/messages-YzjnURPJ.js +3 -0
  47. package/dist/gateway/static/root/assets/models-hub-panel-CFPpl3Cq.js +2 -0
  48. package/dist/gateway/static/root/assets/notes-page-BurgcdVZ.js +1 -0
  49. package/dist/gateway/static/root/assets/notes-workbench-BAELRM_O.js +2 -0
  50. package/dist/gateway/static/root/assets/{page-tabs-DDC2t4Z8.js → page-tabs-RnYYOIWO.js} +1 -1
  51. package/dist/gateway/static/root/assets/{preview-open-alternatives-BTmk-XDM.js → preview-open-alternatives-CTRt06Ri.js} +1 -1
  52. package/dist/gateway/static/root/assets/project-detail-page-iXX1Ceo2.js +1 -0
  53. package/dist/gateway/static/root/assets/projects-page-GDVTFAY7.js +1 -0
  54. package/dist/gateway/static/root/assets/remote-access-hub-BUrbUnwv.js +1 -0
  55. package/dist/gateway/static/root/assets/{save-bar-controls-DqU-yKIh.js → save-bar-controls-c4pZeikq.js} +1 -1
  56. package/dist/gateway/static/root/assets/{schedule-field-CUttkoSB.js → schedule-field-Cb6R7iuP.js} +1 -1
  57. package/dist/gateway/static/root/assets/{schema-form-CVSQA9nI.js → schema-form-BqET_hEP.js} +1 -1
  58. package/dist/gateway/static/root/assets/sessions-page-CiOreA2k.js +1 -0
  59. package/dist/gateway/static/root/assets/settings-advanced-gate-C-qvptlu.js +1 -0
  60. package/dist/gateway/static/root/assets/{settings-collapsible-section-CK7ogS-P.js → settings-collapsible-section-DuOvqNsI.js} +1 -1
  61. package/dist/gateway/static/root/assets/{settings-form-section-Bugp38Fa.js → settings-form-section-DptSsbWd.js} +1 -1
  62. package/dist/gateway/static/root/assets/settings-loading-skeleton-BlVfBCb9.js +1 -0
  63. package/dist/gateway/static/root/assets/{settings-page-layout-DBRWwdhh.js → settings-page-layout-DVt69dJJ.js} +1 -1
  64. package/dist/gateway/static/root/assets/settings-page-xQx2Pkg5.js +1 -0
  65. package/dist/gateway/static/root/assets/setup-status-panel-DWB8VdLK.js +1 -0
  66. package/dist/gateway/static/root/assets/share-preview-page-8m_ACH0z.js +2 -0
  67. package/dist/gateway/static/root/assets/shares-settings-CgxfhNxI.js +1 -0
  68. package/dist/gateway/static/root/assets/skill-reload-api-BBFUOxmf.js +1 -0
  69. package/dist/gateway/static/root/assets/skills-page-bo695odu.js +2 -0
  70. package/dist/gateway/static/root/assets/{system-settings-panel-DJ6YuLqR.js → system-settings-panel-CW22OkZ4.js} +1 -1
  71. package/dist/gateway/static/root/assets/{typed-models-lib-B0T7N8Km.js → typed-models-lib-BqpGAKxV.js} +1 -1
  72. package/dist/gateway/static/root/assets/url-DFGNSBNT.js +1 -0
  73. package/dist/gateway/static/root/assets/use-channel-catalog-CPdJ0o0i.js +1 -0
  74. package/dist/gateway/static/root/assets/user-profile-settings-panel-CERVLuaW.js +1 -0
  75. package/dist/gateway/static/root/assets/{utils-CehXcWAY.js → utils-BnmysurA.js} +1 -1
  76. package/dist/gateway/static/root/assets/vendor-codemirror-C1WKjCk5.js +45 -0
  77. package/dist/gateway/static/root/assets/voice-api-key-field-Jr3jvPcB.js +1 -0
  78. package/dist/gateway/static/root/assets/work-item-detail-page-B-8rex4u.js +1 -0
  79. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-c4jeaohQ.js → workflow-run-setup-panel-Ci9GSPnS.js} +2 -2
  80. package/dist/gateway/static/root/assets/{workflow-start-dialog-ENRHjoqa.js → workflow-start-dialog-BhDj8pqH.js} +1 -1
  81. package/dist/gateway/static/root/assets/workflows-page-Brb3UGvs.js +18 -0
  82. package/dist/gateway/static/root/index.html +7 -6
  83. package/dist/package.js +1 -1
  84. package/dist/src/agent/agent-manager.d.ts +3 -0
  85. package/dist/src/agent/agent-manager.js +14 -6
  86. package/dist/src/agent/agent-manager.js.map +1 -1
  87. package/dist/src/agent/capabilities/definitions.d.ts +14 -0
  88. package/dist/src/agent/capabilities/definitions.js +19 -0
  89. package/dist/src/agent/capabilities/definitions.js.map +1 -1
  90. package/dist/src/agent/goals/post-turn.js +23 -2
  91. package/dist/src/agent/goals/post-turn.js.map +1 -1
  92. package/dist/src/agent/messaging/command-handler.d.ts +4 -0
  93. package/dist/src/agent/messaging/command-handler.js +6 -0
  94. package/dist/src/agent/messaging/command-handler.js.map +1 -1
  95. package/dist/src/agent/service.d.ts +2 -0
  96. package/dist/src/agent/service.js +23 -0
  97. package/dist/src/agent/service.js.map +1 -1
  98. package/dist/src/agent/skills/hub-lock.d.ts +5 -5
  99. package/dist/src/agent/skills/hub-lock.js +12 -12
  100. package/dist/src/agent/skills/hub-lock.js.map +1 -1
  101. package/dist/src/agent/skills/hub-pull.d.ts +15 -0
  102. package/dist/src/agent/skills/hub-pull.js +299 -24
  103. package/dist/src/agent/skills/hub-pull.js.map +1 -1
  104. package/dist/src/agent/skills/index.js +4 -40
  105. package/dist/src/agent/skills/index.js.map +1 -1
  106. package/dist/src/agent/skills/install-target.d.ts +3 -0
  107. package/dist/src/agent/skills/install-target.js +11 -0
  108. package/dist/src/agent/skills/install-target.js.map +1 -0
  109. package/dist/src/agent/skills/managed-store.d.ts +5 -3
  110. package/dist/src/agent/skills/managed-store.js +10 -9
  111. package/dist/src/agent/skills/managed-store.js.map +1 -1
  112. package/dist/src/agent/skills/marketplace/adapters/store/adapter.js +5 -3
  113. package/dist/src/agent/skills/marketplace/adapters/store/adapter.js.map +1 -1
  114. package/dist/src/agent/skills/marketplace/adapters/store/store-api-client.d.ts +21 -1
  115. package/dist/src/agent/skills/marketplace/adapters/store/store-api-client.js +62 -6
  116. package/dist/src/agent/skills/marketplace/adapters/store/store-api-client.js.map +1 -1
  117. package/dist/src/agent/skills/marketplace/resolve-adapter.js +1 -1
  118. package/dist/src/agent/skills/marketplace/resolve-adapter.js.map +1 -1
  119. package/dist/src/agent/skills/skill-manage-ops.js +2 -2
  120. package/dist/src/agent/skills/skill-manage-ops.js.map +1 -1
  121. package/dist/src/agent/skills/skill-manager.js +1 -6
  122. package/dist/src/agent/skills/skill-manager.js.map +1 -1
  123. package/dist/src/agent/skills/workspace-skills-dir.d.ts +1 -0
  124. package/dist/src/agent/skills/workspace-skills-dir.js +5 -1
  125. package/dist/src/agent/skills/workspace-skills-dir.js.map +1 -1
  126. package/dist/src/agent/tools/automation-tool.d.ts +6 -6
  127. package/dist/src/agent/tools/browser/tool/schemas.d.ts +20 -20
  128. package/dist/src/agent/tools/composio-tool.d.ts +3 -3
  129. package/dist/src/agent/tools/desktop-pet-tool.d.ts +7 -7
  130. package/dist/src/agent/tools/factory.d.ts +3 -0
  131. package/dist/src/agent/tools/factory.js +6 -1
  132. package/dist/src/agent/tools/factory.js.map +1 -1
  133. package/dist/src/agent/tools/goal-tool.d.ts +16 -16
  134. package/dist/src/agent/tools/index.d.ts +1 -0
  135. package/dist/src/agent/tools/index.js +2 -1
  136. package/dist/src/agent/tools/skill-install-tool.d.ts +28 -0
  137. package/dist/src/agent/tools/skill-install-tool.js +81 -0
  138. package/dist/src/agent/tools/skill-install-tool.js.map +1 -0
  139. package/dist/src/agent/tools/skill-manage-tool.js +3 -6
  140. package/dist/src/agent/tools/skill-manage-tool.js.map +1 -1
  141. package/dist/src/agent/tools/tool-manual-tool.d.ts +2 -2
  142. package/dist/src/agent/tools/xopc-use-tool.d.ts +5 -5
  143. package/dist/src/automations/domain/types.d.ts +1 -0
  144. package/dist/src/automations/draft/automation-draft-service.js +1 -1
  145. package/dist/src/automations/service/automation-service.js +9 -0
  146. package/dist/src/automations/service/automation-service.js.map +1 -1
  147. package/dist/src/browser/schemas.d.ts +52 -52
  148. package/dist/src/capabilities/store-connector.d.ts +17 -0
  149. package/dist/src/capabilities/store-connector.js +191 -0
  150. package/dist/src/capabilities/store-connector.js.map +1 -0
  151. package/dist/src/chat-commands/builtins/skill.d.ts +1 -0
  152. package/dist/src/chat-commands/builtins/skill.js +132 -0
  153. package/dist/src/chat-commands/builtins/skill.js.map +1 -0
  154. package/dist/src/chat-commands/context.d.ts +3 -0
  155. package/dist/src/chat-commands/context.js +2 -0
  156. package/dist/src/chat-commands/context.js.map +1 -1
  157. package/dist/src/chat-commands/index.d.ts +1 -0
  158. package/dist/src/chat-commands/index.js +3 -1
  159. package/dist/src/chat-commands/index.js.map +1 -1
  160. package/dist/src/chat-commands/types.d.ts +17 -0
  161. package/dist/src/cli/command-loaders.js +1 -0
  162. package/dist/src/cli/command-loaders.js.map +1 -1
  163. package/dist/src/cli/command-manifest.js +4 -0
  164. package/dist/src/cli/command-manifest.js.map +1 -1
  165. package/dist/src/cli/commands/agent.js +2 -2
  166. package/dist/src/cli/commands/connectors.d.ts +4 -0
  167. package/dist/src/cli/commands/connectors.js +96 -0
  168. package/dist/src/cli/commands/connectors.js.map +1 -0
  169. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  170. package/dist/src/cli/commands/extension-marketplace.js +1 -1
  171. package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
  172. package/dist/src/cli/commands/models.js +1 -1
  173. package/dist/src/cli/commands/onboard.js +1 -1
  174. package/dist/src/cli/commands/profile.js +1 -1
  175. package/dist/src/cli/commands/skills.js +1 -1
  176. package/dist/src/cli/commands/tunnel.js +1 -1
  177. package/dist/src/cli/commands/update.js +1 -1
  178. package/dist/src/cli/extension-cli-register.js +1 -1
  179. package/dist/src/config/agent-profile.js +1 -1
  180. package/dist/src/config/index.js +1 -1
  181. package/dist/src/config/schema.js +2 -2
  182. package/dist/src/config/schema.js.map +1 -1
  183. package/dist/src/connectors/health.js +1 -1
  184. package/dist/src/connectors/install.js +3 -1
  185. package/dist/src/connectors/install.js.map +1 -1
  186. package/dist/src/connectors/materialize.js +2 -0
  187. package/dist/src/connectors/materialize.js.map +1 -1
  188. package/dist/src/connectors/types.d.ts +19 -1
  189. package/dist/src/extensions/install.js +1 -1
  190. package/dist/src/extensions/types/manifest.d.ts +1 -1
  191. package/dist/src/extensions/update.js +5 -3
  192. package/dist/src/extensions/update.js.map +1 -1
  193. package/dist/src/gateway/agents-admin.js +1 -1
  194. package/dist/src/gateway/chat-stream/mapper.js +5 -1
  195. package/dist/src/gateway/chat-stream/mapper.js.map +1 -1
  196. package/dist/src/gateway/chat-stream/protocol.d.ts +2 -0
  197. package/dist/src/gateway/hono/lib/config-payload.js +1 -1
  198. package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
  199. package/dist/src/gateway/hono/middleware/auth.d.ts +2 -2
  200. package/dist/src/gateway/hono/middleware/logger.d.ts +1 -1
  201. package/dist/src/gateway/hono/middleware/route-errors.d.ts +1 -1
  202. package/dist/src/gateway/hono/middleware/strict-rate-limit.d.ts +2 -2
  203. package/dist/src/gateway/hono/routes/capabilities.d.ts +3 -0
  204. package/dist/src/gateway/hono/routes/capabilities.js +79 -0
  205. package/dist/src/gateway/hono/routes/capabilities.js.map +1 -0
  206. package/dist/src/gateway/hono/routes/commands-skills.js +81 -3
  207. package/dist/src/gateway/hono/routes/commands-skills.js.map +1 -1
  208. package/dist/src/gateway/hono/routes/connectors.js +2 -2
  209. package/dist/src/gateway/hono/routes/goals.js +212 -3
  210. package/dist/src/gateway/hono/routes/goals.js.map +1 -1
  211. package/dist/src/gateway/hono/routes/index.js +2 -0
  212. package/dist/src/gateway/hono/routes/index.js.map +1 -1
  213. package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
  214. package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
  215. package/dist/src/gateway/hono/routes/mcp.js +1 -1
  216. package/dist/src/gateway/hono/routes/mobile.d.ts +3 -0
  217. package/dist/src/gateway/hono/routes/mobile.js +113 -0
  218. package/dist/src/gateway/hono/routes/mobile.js.map +1 -0
  219. package/dist/src/gateway/hono/routes/projects.js +17 -0
  220. package/dist/src/gateway/hono/routes/projects.js.map +1 -1
  221. package/dist/src/gateway/hono/routes/workspace.js +4 -1
  222. package/dist/src/gateway/hono/routes/workspace.js.map +1 -1
  223. package/dist/src/gateway/hono/sse.d.ts +3 -3
  224. package/dist/src/gateway/run-loop.js +1 -1
  225. package/dist/src/gateway/service/marketplace-service.d.ts +23 -1
  226. package/dist/src/gateway/service/marketplace-service.js +57 -6
  227. package/dist/src/gateway/service/marketplace-service.js.map +1 -1
  228. package/dist/src/gateway/service.d.ts +2 -0
  229. package/dist/src/gateway/service.js +12 -2
  230. package/dist/src/gateway/service.js.map +1 -1
  231. package/dist/src/goals/goal-contract-draft.d.ts +15 -0
  232. package/dist/src/goals/goal-contract-draft.js +114 -0
  233. package/dist/src/goals/goal-contract-draft.js.map +1 -0
  234. package/dist/src/goals/goal-evidence-review.d.ts +15 -0
  235. package/dist/src/goals/goal-evidence-review.js +91 -0
  236. package/dist/src/goals/goal-evidence-review.js.map +1 -0
  237. package/dist/src/goals/goal-runner.js +3 -1
  238. package/dist/src/goals/goal-runner.js.map +1 -1
  239. package/dist/src/goals/goal-service.d.ts +17 -1
  240. package/dist/src/goals/goal-service.js +44 -3
  241. package/dist/src/goals/goal-service.js.map +1 -1
  242. package/dist/src/goals/goal-store.d.ts +18 -1
  243. package/dist/src/goals/goal-store.js +190 -1
  244. package/dist/src/goals/goal-store.js.map +1 -1
  245. package/dist/src/goals/index.d.ts +4 -0
  246. package/dist/src/goals/index.js +3 -1
  247. package/dist/src/goals/types.d.ts +42 -0
  248. package/dist/src/mcp/channel-bridge.js +1 -1
  249. package/dist/src/mobile/notification-service.d.ts +8 -0
  250. package/dist/src/mobile/notification-service.js +139 -0
  251. package/dist/src/mobile/notification-service.js.map +1 -0
  252. package/dist/src/mobile/notification-store.d.ts +28 -0
  253. package/dist/src/mobile/notification-store.js +134 -0
  254. package/dist/src/mobile/notification-store.js.map +1 -0
  255. package/dist/src/mobile/notification-types.d.ts +37 -0
  256. package/dist/src/mobile/notification-types.js +11 -0
  257. package/dist/src/mobile/notification-types.js.map +1 -0
  258. package/dist/src/storage/sqlite/migrations/026_goal_contracts.sql +10 -0
  259. package/dist/src/storage/sqlite/migrations/027_mobile_notifications.sql +43 -0
  260. package/dist/src/storage/sqlite/migrations/028_goal_evidence_requirements.sql +47 -0
  261. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  262. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  263. package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
  264. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  265. package/dist/src/storage/sqlite/schema.js +1 -1
  266. package/dist/src/storage/sqlite/schema.sql +44 -0
  267. package/dist/src/tui/tui-startup-resources.js +1 -1
  268. package/package.json +1 -1
  269. package/skills/THIRD_PARTY_NOTICES.md +16 -0
  270. package/skills/creative/algorithmic-art/SKILL.md +37 -0
  271. package/skills/creative/algorithmic-art/templates/generator-template.js +27 -0
  272. package/skills/creative/algorithmic-art/templates/viewer.html +27 -0
  273. package/skills/documents/doc-coauthoring/SKILL.md +40 -0
  274. package/skills/documents/doc-coauthoring/references/reader-review.md +9 -0
  275. package/skills/documents/docx/SKILL.md +40 -0
  276. package/skills/documents/docx/references/editing-checklist.md +8 -0
  277. package/skills/documents/docx/scripts/inspect_ooxml.py +36 -0
  278. package/skills/documents/docx/scripts/render_docx.py +33 -0
  279. package/skills/documents/pdf/SKILL.md +47 -0
  280. package/skills/documents/pdf/references/operations.md +16 -0
  281. package/skills/documents/pdf/scripts/inspect_pdf.py +41 -0
  282. package/skills/documents/pdf/scripts/render_pdf.py +32 -0
  283. package/skills/documents/pptx/SKILL.md +41 -0
  284. package/skills/documents/pptx/references/qa-checklist.md +6 -0
  285. package/skills/documents/pptx/scripts/inspect_ooxml.py +34 -0
  286. package/skills/documents/pptx/scripts/render_pptx.py +33 -0
  287. package/skills/engineering/define-goal/SKILL.md +41 -0
  288. package/skills/engineering/define-goal/references/objective-rubric.md +12 -0
  289. package/dist/gateway/static/root/assets/agents-k59l7NMb.js +0 -2
  290. package/dist/gateway/static/root/assets/app-management-settings-panel-DeQsTsyy.js +0 -1
  291. package/dist/gateway/static/root/assets/apps-page-BG9b4abG.js +0 -1
  292. package/dist/gateway/static/root/assets/automations-page-De8mVutL.js +0 -4
  293. package/dist/gateway/static/root/assets/browser-settings-page-C_ZRa4LF.js +0 -8
  294. package/dist/gateway/static/root/assets/capability-presets-api-hny224j-.js +0 -1
  295. package/dist/gateway/static/root/assets/capability-presets-settings-panel-Drc0qLsw.js +0 -1
  296. package/dist/gateway/static/root/assets/channel-recipient-api-DAlOHxKJ.js +0 -1
  297. package/dist/gateway/static/root/assets/channels-settings-CA20zBV9.js +0 -1
  298. package/dist/gateway/static/root/assets/connectors-page-qMyMB5te.js +0 -2
  299. package/dist/gateway/static/root/assets/desktop-pet-XG6Vb_fZ.js +0 -1
  300. package/dist/gateway/static/root/assets/dreaming-settings-CkUZ997f.js +0 -3
  301. package/dist/gateway/static/root/assets/extension-settings-page-3RMhQtZ3.js +0 -1
  302. package/dist/gateway/static/root/assets/fetch-pg2ErdAk.js +0 -1
  303. package/dist/gateway/static/root/assets/gateway-config-api-DbG97ia2.js +0 -1
  304. package/dist/gateway/static/root/assets/gateway-settings-B8cyqKk-.js +0 -1
  305. package/dist/gateway/static/root/assets/goal-create-dialog-DmeW7Zz3.js +0 -1
  306. package/dist/gateway/static/root/assets/goal-detail-page-DrTyGbVD.js +0 -1
  307. package/dist/gateway/static/root/assets/goals-config-api-CxCWGIBB.js +0 -1
  308. package/dist/gateway/static/root/assets/goals-page-DV1bJhIh.js +0 -2
  309. package/dist/gateway/static/root/assets/goals-settings-9DrfOkP5.js +0 -1
  310. package/dist/gateway/static/root/assets/heartbeat-settings-KaDpZrv0.js +0 -1
  311. package/dist/gateway/static/root/assets/index-C2F0Clvm.js +0 -256
  312. package/dist/gateway/static/root/assets/index-COQSX5d_.css +0 -1
  313. package/dist/gateway/static/root/assets/logs-page-C9dpiNTF.js +0 -2
  314. package/dist/gateway/static/root/assets/messages-DmnbiNxU.js +0 -3
  315. package/dist/gateway/static/root/assets/models-hub-panel-zdCdmBmH.js +0 -2
  316. package/dist/gateway/static/root/assets/notes-page-MpGeFfPt.js +0 -1
  317. package/dist/gateway/static/root/assets/notes-workbench-DYCM3yd2.js +0 -2
  318. package/dist/gateway/static/root/assets/project-detail-page-Cu0ElRnS.js +0 -1
  319. package/dist/gateway/static/root/assets/projects-page-DakNaUjZ.js +0 -1
  320. package/dist/gateway/static/root/assets/remote-access-hub-DYKjt7L9.js +0 -1
  321. package/dist/gateway/static/root/assets/sessions-page-CcGHDsz1.js +0 -1
  322. package/dist/gateway/static/root/assets/settings-advanced-gate-CuFdeKNu.js +0 -1
  323. package/dist/gateway/static/root/assets/settings-page-0AJoUvxi.js +0 -1
  324. package/dist/gateway/static/root/assets/setup-status-panel-D6a_hEk7.js +0 -1
  325. package/dist/gateway/static/root/assets/share-preview-page-BtsuETKF.js +0 -2
  326. package/dist/gateway/static/root/assets/shares-settings-CcEFT7S9.js +0 -1
  327. package/dist/gateway/static/root/assets/skill-reload-api-BcN_RuTD.js +0 -1
  328. package/dist/gateway/static/root/assets/skills-page-BbRZZZA5.js +0 -2
  329. package/dist/gateway/static/root/assets/use-channel-catalog-C6vrxdzZ.js +0 -1
  330. package/dist/gateway/static/root/assets/user-profile-settings-panel-DZ0nKMgj.js +0 -1
  331. package/dist/gateway/static/root/assets/vendor-codemirror-BvNgyE1Q.js +0 -45
  332. package/dist/gateway/static/root/assets/voice-api-key-field-2QKflCx8.js +0 -1
  333. package/dist/gateway/static/root/assets/work-item-detail-page-DfJnuWq1.js +0 -1
  334. package/dist/gateway/static/root/assets/workflows-page-BJwwFTm_.js +0 -18
@@ -13,8 +13,8 @@ function emptyLock() {
13
13
  entries: {}
14
14
  };
15
15
  }
16
- function loadSkillsLock() {
17
- const p = resolveSkillsLockPath();
16
+ function loadSkillsLock(lockPath = resolveSkillsLockPath()) {
17
+ const p = lockPath;
18
18
  if (!existsSync(p)) return emptyLock();
19
19
  try {
20
20
  const raw = readFileSync(p, "utf-8");
@@ -28,12 +28,12 @@ function loadSkillsLock() {
28
28
  return emptyLock();
29
29
  }
30
30
  }
31
- function saveSkillsLock(lock) {
32
- writeTextAtomicSync(resolveSkillsLockPath(), `${JSON.stringify(lock, null, 2)}\n`);
31
+ function saveSkillsLock(lock, lockPath = resolveSkillsLockPath()) {
32
+ writeTextAtomicSync(lockPath, `${JSON.stringify(lock, null, 2)}\n`);
33
33
  }
34
34
  /** Record or replace hub metadata for a managed skill directory id (folder name under ~/.xopc/skills). */
35
- function recordSkillsHubInstall(skillId, meta, contentHash) {
36
- const lock = loadSkillsLock();
35
+ function recordSkillsHubInstall(skillId, meta, contentHash, lockPath) {
36
+ const lock = loadSkillsLock(lockPath);
37
37
  const now = (/* @__PURE__ */ new Date()).toISOString();
38
38
  const prev = lock.entries[skillId];
39
39
  lock.entries[skillId] = {
@@ -45,16 +45,16 @@ function recordSkillsHubInstall(skillId, meta, contentHash) {
45
45
  installedAt: prev?.installedAt ?? now,
46
46
  updatedAt: now
47
47
  };
48
- saveSkillsLock(lock);
48
+ saveSkillsLock(lock, lockPath);
49
49
  }
50
- function removeSkillsLockEntry(skillId) {
51
- const lock = loadSkillsLock();
50
+ function removeSkillsLockEntry(skillId, lockPath) {
51
+ const lock = loadSkillsLock(lockPath);
52
52
  if (!lock.entries[skillId]) return;
53
53
  delete lock.entries[skillId];
54
- saveSkillsLock(lock);
54
+ saveSkillsLock(lock, lockPath);
55
55
  }
56
- function getSkillsLockEntry(skillId) {
57
- return loadSkillsLock().entries[skillId];
56
+ function getSkillsLockEntry(skillId, lockPath) {
57
+ return loadSkillsLock(lockPath).entries[skillId];
58
58
  }
59
59
  //#endregion
60
60
  export { getSkillsLockEntry, loadSkillsLock, recordSkillsHubInstall, removeSkillsLockEntry, saveSkillsLock };
@@ -1 +1 @@
1
- {"version":3,"file":"hub-lock.js","names":[],"sources":["../../../../src/agent/skills/hub-lock.ts"],"sourcesContent":["/**\n * Skills hub lock (~/.xopc/skills-lock.json): records install source + tree hash per managed skill id.\n */\n\nimport { existsSync, readFileSync } from 'node:fs';\n\nimport { resolveSkillsLockPath } from '../../config/paths.js';\nimport { writeTextAtomicSync } from '../../infra/write-file-atomic.js';\n\nexport type SkillHubKind = 'git' | 'archive';\n\nexport interface SkillHubLockEntry {\n kind: SkillHubKind;\n /** Clone URL, tarball URL, or file path (as given at install time). */\n source: string;\n /** Git branch / tag / ref (optional). */\n ref?: string;\n /** Path inside the cloned repo (POSIX, no leading slash). */\n subpath?: string;\n /** Deterministic tree hash from {@link computeSkillTreeHash}. */\n contentHash: string;\n installedAt: string;\n updatedAt: string;\n}\n\nexport interface SkillsLockFile {\n version: 1;\n entries: Record<string, SkillHubLockEntry>;\n}\n\nfunction emptyLock(): SkillsLockFile {\n return { version: 1, entries: {} };\n}\n\nexport function loadSkillsLock(): SkillsLockFile {\n const p = resolveSkillsLockPath();\n if (!existsSync(p)) return emptyLock();\n try {\n const raw = readFileSync(p, 'utf-8');\n const j = JSON.parse(raw) as Partial<SkillsLockFile>;\n if (j.version !== 1 || !j.entries || typeof j.entries !== 'object') {\n return emptyLock();\n }\n return { version: 1, entries: { ...j.entries } };\n } catch {\n return emptyLock();\n }\n}\n\nexport function saveSkillsLock(lock: SkillsLockFile): void {\n const p = resolveSkillsLockPath();\n writeTextAtomicSync(p, `${JSON.stringify(lock, null, 2)}\\n`);\n}\n\n/** Record or replace hub metadata for a managed skill directory id (folder name under ~/.xopc/skills). */\nexport function recordSkillsHubInstall(\n skillId: string,\n meta: Pick<SkillHubLockEntry, 'kind' | 'source' | 'ref' | 'subpath'>,\n contentHash: string,\n): void {\n const lock = loadSkillsLock();\n const now = new Date().toISOString();\n const prev = lock.entries[skillId];\n lock.entries[skillId] = {\n kind: meta.kind,\n source: meta.source,\n ref: meta.ref,\n subpath: meta.subpath,\n contentHash,\n installedAt: prev?.installedAt ?? now,\n updatedAt: now,\n };\n saveSkillsLock(lock);\n}\n\nexport function removeSkillsLockEntry(skillId: string): void {\n const lock = loadSkillsLock();\n if (!lock.entries[skillId]) return;\n delete lock.entries[skillId];\n saveSkillsLock(lock);\n}\n\nexport function getSkillsLockEntry(skillId: string): SkillHubLockEntry | undefined {\n return loadSkillsLock().entries[skillId];\n}\n"],"mappings":";;;;;;;YAM8D;wBACS;AAuBvE,SAAS,YAA4B;AACnC,QAAO;EAAE,SAAS;EAAG,SAAS,EAAE;EAAE;;AAGpC,SAAgB,iBAAiC;CAC/C,MAAM,IAAI,uBAAuB;AACjC,KAAI,CAAC,WAAW,EAAE,CAAE,QAAO,WAAW;AACtC,KAAI;EACF,MAAM,MAAM,aAAa,GAAG,QAAQ;EACpC,MAAM,IAAI,KAAK,MAAM,IAAI;AACzB,MAAI,EAAE,YAAY,KAAK,CAAC,EAAE,WAAW,OAAO,EAAE,YAAY,SACxD,QAAO,WAAW;AAEpB,SAAO;GAAE,SAAS;GAAG,SAAS,EAAE,GAAG,EAAE,SAAS;GAAE;SAC1C;AACN,SAAO,WAAW;;;AAItB,SAAgB,eAAe,MAA4B;AAEzD,qBADU,uBACW,EAAE,GAAG,KAAK,UAAU,MAAM,MAAM,EAAE,CAAC,IAAI;;;AAI9D,SAAgB,uBACd,SACA,MACA,aACM;CACN,MAAM,OAAO,gBAAgB;CAC7B,MAAM,uBAAM,IAAI,MAAM,EAAC,aAAa;CACpC,MAAM,OAAO,KAAK,QAAQ;AAC1B,MAAK,QAAQ,WAAW;EACtB,MAAM,KAAK;EACX,QAAQ,KAAK;EACb,KAAK,KAAK;EACV,SAAS,KAAK;EACd;EACA,aAAa,MAAM,eAAe;EAClC,WAAW;EACZ;AACD,gBAAe,KAAK;;AAGtB,SAAgB,sBAAsB,SAAuB;CAC3D,MAAM,OAAO,gBAAgB;AAC7B,KAAI,CAAC,KAAK,QAAQ,SAAU;AAC5B,QAAO,KAAK,QAAQ;AACpB,gBAAe,KAAK;;AAGtB,SAAgB,mBAAmB,SAAgD;AACjF,QAAO,gBAAgB,CAAC,QAAQ"}
1
+ {"version":3,"file":"hub-lock.js","names":["p"],"sources":["../../../../src/agent/skills/hub-lock.ts"],"sourcesContent":["/**\n * Skills hub lock (~/.xopc/skills-lock.json): records install source + tree hash per managed skill id.\n */\n\nimport { existsSync, readFileSync } from 'node:fs';\n\nimport { resolveSkillsLockPath } from '../../config/paths.js';\nimport { writeTextAtomicSync } from '../../infra/write-file-atomic.js';\n\nexport type SkillHubKind = 'git' | 'archive';\n\nexport interface SkillHubLockEntry {\n kind: SkillHubKind;\n /** Clone URL, tarball URL, or file path (as given at install time). */\n source: string;\n /** Git branch / tag / ref (optional). */\n ref?: string;\n /** Path inside the cloned repo (POSIX, no leading slash). */\n subpath?: string;\n /** Deterministic tree hash from {@link computeSkillTreeHash}. */\n contentHash: string;\n installedAt: string;\n updatedAt: string;\n}\n\nexport interface SkillsLockFile {\n version: 1;\n entries: Record<string, SkillHubLockEntry>;\n}\n\nfunction emptyLock(): SkillsLockFile {\n return { version: 1, entries: {} };\n}\n\nexport function loadSkillsLock(lockPath = resolveSkillsLockPath()): SkillsLockFile {\n const p = lockPath;\n if (!existsSync(p)) return emptyLock();\n try {\n const raw = readFileSync(p, 'utf-8');\n const j = JSON.parse(raw) as Partial<SkillsLockFile>;\n if (j.version !== 1 || !j.entries || typeof j.entries !== 'object') {\n return emptyLock();\n }\n return { version: 1, entries: { ...j.entries } };\n } catch {\n return emptyLock();\n }\n}\n\nexport function saveSkillsLock(lock: SkillsLockFile, lockPath = resolveSkillsLockPath()): void {\n const p = lockPath;\n writeTextAtomicSync(p, `${JSON.stringify(lock, null, 2)}\\n`);\n}\n\n/** Record or replace hub metadata for a managed skill directory id (folder name under ~/.xopc/skills). */\nexport function recordSkillsHubInstall(\n skillId: string,\n meta: Pick<SkillHubLockEntry, 'kind' | 'source' | 'ref' | 'subpath'>,\n contentHash: string,\n lockPath?: string,\n): void {\n const lock = loadSkillsLock(lockPath);\n const now = new Date().toISOString();\n const prev = lock.entries[skillId];\n lock.entries[skillId] = {\n kind: meta.kind,\n source: meta.source,\n ref: meta.ref,\n subpath: meta.subpath,\n contentHash,\n installedAt: prev?.installedAt ?? now,\n updatedAt: now,\n };\n saveSkillsLock(lock, lockPath);\n}\n\nexport function removeSkillsLockEntry(skillId: string, lockPath?: string): void {\n const lock = loadSkillsLock(lockPath);\n if (!lock.entries[skillId]) return;\n delete lock.entries[skillId];\n saveSkillsLock(lock, lockPath);\n}\n\nexport function getSkillsLockEntry(skillId: string, lockPath?: string): SkillHubLockEntry | undefined {\n return loadSkillsLock(lockPath).entries[skillId];\n}\n"],"mappings":";;;;;;;YAM8D;wBACS;AAuBvE,SAAS,YAA4B;AACnC,QAAO;EAAE,SAAS;EAAG,SAAS,EAAE;EAAE;;AAGpC,SAAgB,eAAe,WAAW,uBAAuB,EAAkB;CACjF,MAAM,IAAI;AACV,KAAI,CAAC,WAAW,EAAE,CAAE,QAAO,WAAW;AACtC,KAAI;EACF,MAAM,MAAM,aAAa,GAAG,QAAQ;EACpC,MAAM,IAAI,KAAK,MAAM,IAAI;AACzB,MAAI,EAAE,YAAY,KAAK,CAAC,EAAE,WAAW,OAAO,EAAE,YAAY,SACxD,QAAO,WAAW;AAEpB,SAAO;GAAE,SAAS;GAAG,SAAS,EAAE,GAAG,EAAE,SAAS;GAAE;SAC1C;AACN,SAAO,WAAW;;;AAItB,SAAgB,eAAe,MAAsB,WAAW,uBAAuB,EAAQ;AAE7F,qBAAoBA,UAAG,GAAG,KAAK,UAAU,MAAM,MAAM,EAAE,CAAC,IAAI;;;AAI9D,SAAgB,uBACd,SACA,MACA,aACA,UACM;CACN,MAAM,OAAO,eAAe,SAAS;CACrC,MAAM,uBAAM,IAAI,MAAM,EAAC,aAAa;CACpC,MAAM,OAAO,KAAK,QAAQ;AAC1B,MAAK,QAAQ,WAAW;EACtB,MAAM,KAAK;EACX,QAAQ,KAAK;EACb,KAAK,KAAK;EACV,SAAS,KAAK;EACd;EACA,aAAa,MAAM,eAAe;EAClC,WAAW;EACZ;AACD,gBAAe,MAAM,SAAS;;AAGhC,SAAgB,sBAAsB,SAAiB,UAAyB;CAC9E,MAAM,OAAO,eAAe,SAAS;AACrC,KAAI,CAAC,KAAK,QAAQ,SAAU;AAC5B,QAAO,KAAK,QAAQ;AACpB,gBAAe,MAAM,SAAS;;AAGhC,SAAgB,mBAAmB,SAAiB,UAAkD;AACpG,QAAO,eAAe,SAAS,CAAC,QAAQ"}
@@ -7,6 +7,10 @@ export interface HubPullOptions {
7
7
  ref?: string;
8
8
  subpath?: string;
9
9
  force?: boolean;
10
+ /** Destination skills root. Defaults to the global managed skills directory. */
11
+ installRoot?: string;
12
+ /** Hub lock path. Defaults to the global skills-lock.json. */
13
+ lockPath?: string;
10
14
  /** When true, critical scanner findings fail the install. */
11
15
  strictScan?: boolean;
12
16
  }
@@ -17,6 +21,16 @@ export interface HubPullResult {
17
21
  kind: SkillHubKind;
18
22
  source: string;
19
23
  }
24
+ interface GitHubSkillSource {
25
+ owner: string;
26
+ repo: string;
27
+ cloneUrl: string;
28
+ sourceLabel: string;
29
+ ref?: string;
30
+ subpath?: string;
31
+ treePathParts?: string[];
32
+ }
33
+ export declare function parseGitHubSkillSource(raw: string, options?: Pick<HubPullOptions, 'ref' | 'subpath'>): GitHubSkillSource | undefined;
20
34
  export declare function classifyHubSource(raw: string): 'git' | 'archive';
21
35
  export declare function findSkillRoot(repoRoot: string, subpath?: string): string;
22
36
  /**
@@ -25,3 +39,4 @@ export declare function findSkillRoot(repoRoot: string, subpath?: string): strin
25
39
  export declare function pullSkillFromSource(source: string, options?: HubPullOptions): Promise<HubPullResult>;
26
40
  /** Re-install from the source recorded in ~/.xopc/skills-lock.json for this skill id. */
27
41
  export declare function updateSkillFromLock(skillId: string, options?: Pick<HubPullOptions, 'strictScan'>): Promise<HubPullResult>;
42
+ export {};
@@ -1,18 +1,101 @@
1
1
  import { parseFrontmatter } from "../../markdown/frontmatter.js";
2
2
  import { formatScanSummary, scanSkillDirectory } from "./scanner.js";
3
3
  import { getSkillsLockEntry, recordSkillsHubInstall } from "./hub-lock.js";
4
- import { installSkillFromZip, isValidSkillId, prepareManagedSkillTempDir, promoteManagedSkillTempDir } from "./managed-store.js";
4
+ import { installSkillFromZip, isIgnorableZipEntry, isValidSkillId, prepareManagedSkillTempDir, promoteManagedSkillTempDir } from "./managed-store.js";
5
5
  import { computeSkillTreeHashSync } from "./hub-hash.js";
6
6
  import { tmpdir } from "node:os";
7
- import { basename, join, normalize, resolve } from "node:path";
7
+ import { basename, dirname, join, normalize, resolve, sep } from "node:path";
8
8
  import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
9
9
  import { fileURLToPath } from "node:url";
10
10
  import { execFileSync } from "node:child_process";
11
11
  import { fetch } from "undici";
12
+ import AdmZip from "adm-zip";
12
13
  //#region src/agent/skills/hub-pull.ts
13
14
  /**
14
15
  * CLI / hub: install or update skills from git or archive (zip / tar.gz) into ~/.xopc/skills.
15
16
  */
17
+ var GitHubArchiveDownloadError = class extends Error {
18
+ constructor(message, status) {
19
+ super(message);
20
+ this.status = status;
21
+ this.name = "GitHubArchiveDownloadError";
22
+ }
23
+ };
24
+ function githubHeaders() {
25
+ const headers = {
26
+ Accept: "application/vnd.github+json",
27
+ "User-Agent": "xopc-skill-installer"
28
+ };
29
+ const token = process.env.GITHUB_TOKEN || process.env.GH_TOKEN;
30
+ if (token?.trim()) headers.Authorization = `Bearer ${token.trim()}`;
31
+ return headers;
32
+ }
33
+ function normalizeSourceSubpath(subpath) {
34
+ const raw = subpath?.trim().replace(/\\/g, "/").replace(/^\/+/, "");
35
+ if (!raw || raw === ".") return void 0;
36
+ if (/^[a-zA-Z]:/.test(raw)) throw new Error(`Invalid source path: ${subpath}`);
37
+ const normalized = normalize(raw);
38
+ if (normalized === ".." || normalized.startsWith(`..${sep}`) || resolve("/", normalized) === resolve("/")) throw new Error(`Invalid source path: ${subpath}`);
39
+ return normalized.replace(/\\/g, "/");
40
+ }
41
+ function decodeUrlPathPart(value) {
42
+ try {
43
+ return decodeURIComponent(value);
44
+ } catch {
45
+ return value;
46
+ }
47
+ }
48
+ function parseSshGitHubSource(raw, optionRef, optionSubpath) {
49
+ const ssh = raw.match(/^git@github\.com:([^/]+)\/(.+?)(?:\.git)?$/i);
50
+ if (!ssh) return void 0;
51
+ const owner = ssh[1];
52
+ const repo = ssh[2].replace(/\.git$/i, "");
53
+ return {
54
+ owner,
55
+ repo,
56
+ cloneUrl: `https://github.com/${owner}/${repo}.git`,
57
+ sourceLabel: raw,
58
+ ref: optionRef,
59
+ subpath: optionSubpath
60
+ };
61
+ }
62
+ function parseGitHubSkillSource(raw, options = {}) {
63
+ const optionRef = options.ref?.trim() || void 0;
64
+ const optionSubpath = normalizeSourceSubpath(options.subpath);
65
+ const sshSource = parseSshGitHubSource(raw, optionRef, optionSubpath);
66
+ if (sshSource) return sshSource;
67
+ let url;
68
+ try {
69
+ url = new URL(raw);
70
+ } catch {
71
+ return;
72
+ }
73
+ if (url.protocol !== "https:" && url.protocol !== "http:") return void 0;
74
+ if (url.hostname.toLowerCase() !== "github.com") return void 0;
75
+ const parts = url.pathname.split("/").filter(Boolean).map(decodeUrlPathPart);
76
+ if (parts.length < 2) return void 0;
77
+ const owner = parts[0];
78
+ const repo = parts[1].replace(/\.git$/i, "");
79
+ if (!owner || !repo) return void 0;
80
+ let ref;
81
+ let subpath;
82
+ let treePathParts;
83
+ const marker = parts[2]?.toLowerCase();
84
+ if ((marker === "tree" || marker === "blob") && parts[3]) {
85
+ treePathParts = parts.slice(3);
86
+ ref = treePathParts[0];
87
+ subpath = normalizeSourceSubpath(treePathParts.slice(1).join("/"));
88
+ } else if (parts.length > 2 && !parts[1].toLowerCase().endsWith(".git")) subpath = normalizeSourceSubpath(parts.slice(2).join("/"));
89
+ return {
90
+ owner,
91
+ repo,
92
+ cloneUrl: `https://github.com/${owner}/${repo}.git`,
93
+ sourceLabel: raw,
94
+ ref: optionRef || ref,
95
+ subpath: optionSubpath || subpath,
96
+ treePathParts
97
+ };
98
+ }
16
99
  function classifyHubSource(raw) {
17
100
  const s = raw.trim();
18
101
  const lower = s.toLowerCase();
@@ -39,8 +122,10 @@ function classifyHubSource(raw) {
39
122
  return "git";
40
123
  }
41
124
  function findSkillRoot(repoRoot, subpath) {
42
- const sub = subpath?.trim() ? normalize(subpath.trim()).replace(/^[/\\]+/, "") : "";
43
- const base = sub ? resolve(repoRoot, sub) : resolve(repoRoot);
125
+ const sub = normalizeSourceSubpath(subpath) || "";
126
+ const root = resolve(repoRoot);
127
+ const base = sub ? resolve(root, sub) : root;
128
+ if (base !== root && !base.startsWith(root + sep)) throw new Error(`Invalid source path: ${subpath}`);
44
129
  if (!existsSync(base)) throw new Error(`Path not found in source: ${sub || "."}`);
45
130
  if (existsSync(join(base, "SKILL.md"))) return base;
46
131
  const entries = readdirSync(base, { withFileTypes: true }).filter((e) => e.isDirectory());
@@ -68,7 +153,7 @@ async function copySkillTreeToManaged(skillRoot, ctx) {
68
153
  const targetId = ctx.skillId?.trim() || inferSkillIdFromSkillMd(skillRoot);
69
154
  if (!targetId) throw new Error("Could not determine skill id: pass --id <name> (must match managed id rules)");
70
155
  if (!isValidSkillId(targetId)) throw new Error(`Invalid skill id "${targetId}" (letters, digits, ._-; max 63 chars after first)`);
71
- const { destDir, tempDir } = prepareManagedSkillTempDir(targetId);
156
+ const { destDir, tempDir } = prepareManagedSkillTempDir(targetId, ctx.installRoot);
72
157
  try {
73
158
  if (existsSync(destDir) && !ctx.force) throw new Error(`Skill "${targetId}" already exists. Use --force to replace.`);
74
159
  cpSync(skillRoot, tempDir, { recursive: true });
@@ -77,7 +162,8 @@ async function copySkillTreeToManaged(skillRoot, ctx) {
77
162
  const promoted = promoteManagedSkillTempDir({
78
163
  skillId: targetId,
79
164
  tempDir,
80
- overwrite: ctx.force
165
+ overwrite: ctx.force,
166
+ rootDir: ctx.installRoot
81
167
  });
82
168
  const hash = computeSkillTreeHashSync(promoted.path);
83
169
  recordSkillsHubInstall(targetId, {
@@ -85,7 +171,7 @@ async function copySkillTreeToManaged(skillRoot, ctx) {
85
171
  source: ctx.source,
86
172
  ref: ctx.kind === "git" ? ctx.ref : void 0,
87
173
  subpath: ctx.kind === "git" ? ctx.subpath : void 0
88
- }, hash);
174
+ }, hash, ctx.lockPath);
89
175
  return {
90
176
  skillId: targetId,
91
177
  path: promoted.path,
@@ -104,13 +190,14 @@ async function copySkillTreeToManaged(skillRoot, ctx) {
104
190
  async function pullSkillFromZipBuffer(buf, sourceLabel, options) {
105
191
  const r = installSkillFromZip(buf, {
106
192
  skillId: options.skillId,
107
- overwrite: options.force ?? false
193
+ overwrite: options.force ?? false,
194
+ rootDir: options.installRoot
108
195
  });
109
196
  const hash = computeSkillTreeHashSync(r.path);
110
197
  recordSkillsHubInstall(r.skillId, {
111
198
  kind: "archive",
112
199
  source: sourceLabel
113
- }, hash);
200
+ }, hash, options.lockPath);
114
201
  await runScan(r.path, options.strictScan);
115
202
  return {
116
203
  skillId: r.skillId,
@@ -144,6 +231,188 @@ async function pullSkillFromTarFile(archivePath, sourceLabel, options) {
144
231
  });
145
232
  }
146
233
  }
234
+ function isSafeArchivePath(name) {
235
+ if (!name) return false;
236
+ const normalized = name.replace(/\\/g, "/").replace(/\/+$/, "");
237
+ if (normalized.startsWith("/") || /^[a-zA-Z]:/.test(normalized)) return false;
238
+ return normalized.split("/").every((part) => part && part !== "..");
239
+ }
240
+ function extractZipBufferToTempDir(buf, tmpRoot) {
241
+ const zip = new AdmZip(buf);
242
+ const rootResolved = resolve(tmpRoot);
243
+ for (const entry of zip.getEntries()) {
244
+ const normalized = entry.entryName.replace(/\\/g, "/");
245
+ if (!normalized || isIgnorableZipEntry(normalized)) continue;
246
+ if (!isSafeArchivePath(normalized)) throw new Error(`Unsafe zip entry path: ${entry.entryName}`);
247
+ const target = join(tmpRoot, normalized);
248
+ const targetResolved = resolve(target);
249
+ if (targetResolved !== rootResolved && !targetResolved.startsWith(rootResolved + sep)) throw new Error(`Unsafe zip entry path: ${entry.entryName}`);
250
+ if (entry.isDirectory) {
251
+ mkdirSync(target, { recursive: true });
252
+ continue;
253
+ }
254
+ mkdirSync(dirname(target), { recursive: true });
255
+ writeFileSync(target, entry.getData());
256
+ }
257
+ }
258
+ function findExtractedRepositoryRoot(tmpRoot) {
259
+ const entries = readdirSync(tmpRoot, { withFileTypes: true }).filter((entry) => !entry.name.startsWith("."));
260
+ const dirs = entries.filter((entry) => entry.isDirectory());
261
+ const files = entries.filter((entry) => entry.isFile());
262
+ if (dirs.length === 1 && files.length === 0) return join(tmpRoot, dirs[0].name);
263
+ return tmpRoot;
264
+ }
265
+ async function resolveGitHubDefaultBranch(source) {
266
+ const apiUrl = `https://api.github.com/repos/${source.owner}/${source.repo}`;
267
+ try {
268
+ const res = await fetch(apiUrl, { headers: githubHeaders() });
269
+ if (!res.ok) return void 0;
270
+ const body = await res.json();
271
+ return (typeof body.default_branch === "string" ? body.default_branch.trim() : "") || void 0;
272
+ } catch {
273
+ return;
274
+ }
275
+ }
276
+ async function githubRefExists(source, namespace, ref) {
277
+ const url = `https://api.github.com/repos/${source.owner}/${source.repo}/git/ref/${namespace}/${encodeURI(ref)}`;
278
+ try {
279
+ return (await fetch(url, { headers: githubHeaders() })).ok;
280
+ } catch {
281
+ return false;
282
+ }
283
+ }
284
+ async function resolveGitHubTreeRefAndSubpath(source, options) {
285
+ const optionRef = options.ref?.trim() || void 0;
286
+ const optionSubpath = options.subpath || void 0;
287
+ if (optionRef || !source.treePathParts?.length) return {
288
+ ref: optionRef || source.ref,
289
+ subpath: optionSubpath || source.subpath
290
+ };
291
+ for (let i = source.treePathParts.length; i >= 1; i -= 1) {
292
+ const candidate = source.treePathParts.slice(0, i).join("/");
293
+ if (await githubRefExists(source, "heads", candidate) || await githubRefExists(source, "tags", candidate)) return {
294
+ ref: candidate,
295
+ subpath: optionSubpath || normalizeSourceSubpath(source.treePathParts.slice(i).join("/"))
296
+ };
297
+ }
298
+ return {
299
+ ref: source.ref,
300
+ subpath: optionSubpath || source.subpath
301
+ };
302
+ }
303
+ async function pullSkillFromGitHubArchive(source, options) {
304
+ const ref = options.ref?.trim() || await resolveGitHubDefaultBranch(source) || "main";
305
+ const res = await fetch(`https://codeload.github.com/${source.owner}/${source.repo}/zip/${encodeURI(ref)}`, { headers: githubHeaders() });
306
+ if (!res.ok) throw new GitHubArchiveDownloadError(`HTTP ${res.status} while fetching GitHub archive`, res.status);
307
+ const tmpRoot = mkdtempSync(join(tmpdir(), "xopc-github-zip-"));
308
+ try {
309
+ extractZipBufferToTempDir(Buffer.from(await res.arrayBuffer()), tmpRoot);
310
+ const repoRoot = findExtractedRepositoryRoot(tmpRoot);
311
+ const effectiveOptions = {
312
+ ...options,
313
+ ref,
314
+ subpath: options.subpath || source.subpath
315
+ };
316
+ return await copySkillTreeToManaged(findSkillRoot(repoRoot, effectiveOptions.subpath), {
317
+ ...effectiveOptions,
318
+ kind: "git",
319
+ source: source.sourceLabel
320
+ });
321
+ } finally {
322
+ rmSync(tmpRoot, {
323
+ recursive: true,
324
+ force: true
325
+ });
326
+ }
327
+ }
328
+ async function pullSkillFromGitHubSparse(source, options) {
329
+ const subpath = normalizeSourceSubpath(options.subpath || source.subpath);
330
+ if (!subpath) return pullSkillFromGit(source.cloneUrl, options, source.sourceLabel);
331
+ const tmpRoot = mkdtempSync(join(tmpdir(), "xopc-github-sparse-"));
332
+ const cloneDir = join(tmpRoot, "clone");
333
+ let clonedRef = options.ref?.trim() || void 0;
334
+ try {
335
+ const args = [
336
+ "clone",
337
+ "--depth",
338
+ "1",
339
+ "--filter=blob:none",
340
+ "--sparse"
341
+ ];
342
+ if (clonedRef) args.push("--branch", clonedRef);
343
+ args.push(source.cloneUrl, cloneDir);
344
+ try {
345
+ execFileSync("git", args, {
346
+ stdio: "pipe",
347
+ encoding: "utf-8"
348
+ });
349
+ } catch {
350
+ if (!clonedRef) throw new Error(`git clone failed for ${source.cloneUrl}`);
351
+ clonedRef = void 0;
352
+ execFileSync("git", [
353
+ "clone",
354
+ "--depth",
355
+ "1",
356
+ "--filter=blob:none",
357
+ "--sparse",
358
+ source.cloneUrl,
359
+ cloneDir
360
+ ], {
361
+ stdio: "pipe",
362
+ encoding: "utf-8"
363
+ });
364
+ }
365
+ execFileSync("git", [
366
+ "-C",
367
+ cloneDir,
368
+ "sparse-checkout",
369
+ "set",
370
+ "--no-cone",
371
+ subpath
372
+ ], {
373
+ stdio: "pipe",
374
+ encoding: "utf-8"
375
+ });
376
+ const effectiveOptions = {
377
+ ...options,
378
+ subpath,
379
+ ref: clonedRef
380
+ };
381
+ return await copySkillTreeToManaged(findSkillRoot(cloneDir, subpath), {
382
+ ...effectiveOptions,
383
+ kind: "git",
384
+ source: source.sourceLabel
385
+ });
386
+ } catch (e) {
387
+ const msg = e instanceof Error ? e.message : String(e);
388
+ if (msg.includes("ENOENT") || msg.includes("git clone failed")) throw new Error(`Git operation failed (${msg}). Ensure git is installed and the repository URL is valid.`);
389
+ throw e;
390
+ } finally {
391
+ rmSync(tmpRoot, {
392
+ recursive: true,
393
+ force: true
394
+ });
395
+ }
396
+ }
397
+ async function pullSkillFromGitHub(source, options) {
398
+ const resolved = await resolveGitHubTreeRefAndSubpath(source, options);
399
+ const effectiveOptions = {
400
+ ...options,
401
+ ref: resolved.ref,
402
+ subpath: resolved.subpath
403
+ };
404
+ try {
405
+ return await pullSkillFromGitHubArchive(source, effectiveOptions);
406
+ } catch (archiveErr) {
407
+ try {
408
+ return await pullSkillFromGitHubSparse(source, effectiveOptions);
409
+ } catch (gitErr) {
410
+ const archiveMsg = archiveErr instanceof Error ? archiveErr.message : String(archiveErr);
411
+ const gitMsg = gitErr instanceof Error ? gitErr.message : String(gitErr);
412
+ throw new Error(`GitHub archive install failed (${archiveMsg}); git fallback failed (${gitMsg})`);
413
+ }
414
+ }
415
+ }
147
416
  async function pullSkillFromLocalPath(absPath, options) {
148
417
  const resolved = resolve(absPath);
149
418
  if (!existsSync(resolved)) throw new Error(`Not found: ${resolved}`);
@@ -153,16 +422,17 @@ async function pullSkillFromLocalPath(absPath, options) {
153
422
  if (lower.endsWith(".tar.gz") || lower.endsWith(".tgz")) return pullSkillFromTarFile(resolved, resolved, options);
154
423
  throw new Error("Unsupported file type (expected .zip, .tar.gz, or .tgz)");
155
424
  }
156
- async function pullSkillFromGit(url, options) {
425
+ async function pullSkillFromGit(url, options, sourceLabel = url) {
157
426
  const tmpRoot = mkdtempSync(join(tmpdir(), "xopc-hub-"));
158
427
  const cloneDir = join(tmpRoot, "clone");
428
+ let clonedRef = options.ref?.trim() || void 0;
159
429
  try {
160
430
  const args = [
161
431
  "clone",
162
432
  "--depth",
163
433
  "1"
164
434
  ];
165
- if (options.ref?.trim()) args.push("--branch", options.ref.trim());
435
+ if (clonedRef) args.push("--branch", clonedRef);
166
436
  args.push(url, cloneDir);
167
437
  try {
168
438
  execFileSync("git", args, {
@@ -170,22 +440,25 @@ async function pullSkillFromGit(url, options) {
170
440
  encoding: "utf-8"
171
441
  });
172
442
  } catch {
173
- if (options.ref?.trim()) execFileSync("git", [
174
- "clone",
175
- "--depth",
176
- "1",
177
- url,
178
- cloneDir
179
- ], {
180
- stdio: "pipe",
181
- encoding: "utf-8"
182
- });
183
- else throw new Error(`git clone failed for ${url}`);
443
+ if (clonedRef) {
444
+ clonedRef = void 0;
445
+ execFileSync("git", [
446
+ "clone",
447
+ "--depth",
448
+ "1",
449
+ url,
450
+ cloneDir
451
+ ], {
452
+ stdio: "pipe",
453
+ encoding: "utf-8"
454
+ });
455
+ } else throw new Error(`git clone failed for ${url}`);
184
456
  }
185
457
  return await copySkillTreeToManaged(findSkillRoot(cloneDir, options.subpath), {
186
458
  ...options,
459
+ ref: clonedRef,
187
460
  kind: "git",
188
- source: url
461
+ source: sourceLabel
189
462
  });
190
463
  } catch (e) {
191
464
  const msg = e instanceof Error ? e.message : String(e);
@@ -206,6 +479,8 @@ async function pullSkillFromSource(source, options = {}) {
206
479
  if (!trimmed) throw new Error("Missing source URL or path");
207
480
  if (trimmed.startsWith("file:")) return pullSkillFromLocalPath(fileURLToPath(trimmed), options);
208
481
  if (!/^[a-zA-Z][a-zA-Z+.-]*:\/\//.test(trimmed) && existsSync(trimmed)) return pullSkillFromLocalPath(resolve(trimmed), options);
482
+ const githubSource = parseGitHubSkillSource(trimmed, options);
483
+ if (githubSource) return pullSkillFromGitHub(githubSource, options);
209
484
  if (classifyHubSource(trimmed) === "archive") {
210
485
  const res = await fetch(trimmed);
211
486
  if (!res.ok) throw new Error(`HTTP ${res.status} while fetching archive`);
@@ -242,6 +517,6 @@ async function updateSkillFromLock(skillId, options = {}) {
242
517
  });
243
518
  }
244
519
  //#endregion
245
- export { classifyHubSource, findSkillRoot, pullSkillFromSource, updateSkillFromLock };
520
+ export { classifyHubSource, findSkillRoot, parseGitHubSkillSource, pullSkillFromSource, updateSkillFromLock };
246
521
 
247
522
  //# sourceMappingURL=hub-pull.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hub-pull.js","names":[],"sources":["../../../../src/agent/skills/hub-pull.ts"],"sourcesContent":["/**\n * CLI / hub: install or update skills from git or archive (zip / tar.gz) into ~/.xopc/skills.\n */\n\nimport { execFileSync } from 'node:child_process';\nimport {\n cpSync,\n existsSync,\n mkdtempSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n rmSync,\n statSync,\n writeFileSync,\n} from 'node:fs';\nimport { basename, join, normalize, resolve } from 'node:path';\nimport { tmpdir } from 'node:os';\nimport { fileURLToPath } from 'node:url';\n\nimport { fetch } from 'undici';\n\nimport { parseFrontmatter } from '../../markdown/frontmatter.js';\nimport { computeSkillTreeHashSync } from './hub-hash.js';\nimport { getSkillsLockEntry, recordSkillsHubInstall } from './hub-lock.js';\nimport type { SkillHubKind } from './hub-lock.js';\nimport {\n installSkillFromZip,\n isValidSkillId,\n prepareManagedSkillTempDir,\n promoteManagedSkillTempDir,\n} from './managed-store.js';\nimport { formatScanSummary, scanSkillDirectory } from './scanner.js';\n\nexport interface HubPullOptions {\n skillId?: string;\n ref?: string;\n subpath?: string;\n force?: boolean;\n /** When true, critical scanner findings fail the install. */\n strictScan?: boolean;\n}\n\nexport interface HubPullResult {\n skillId: string;\n path: string;\n contentHash: string;\n kind: SkillHubKind;\n source: string;\n}\n\nexport function classifyHubSource(raw: string): 'git' | 'archive' {\n const s = raw.trim();\n const lower = s.toLowerCase();\n\n try {\n if (s.startsWith('file:')) {\n const p = fileURLToPath(s);\n const pl = p.toLowerCase();\n if (pl.endsWith('.zip')) return 'archive';\n if (pl.endsWith('.tar.gz') || pl.endsWith('.tgz')) return 'archive';\n return 'git';\n }\n } catch {\n // ignore invalid file URL\n }\n\n if (/^[a-zA-Z]:[\\\\/]/.test(s) || (s.startsWith('/') && !s.startsWith('//'))) {\n if (lower.endsWith('.zip')) return 'archive';\n if (lower.endsWith('.tar.gz') || lower.endsWith('.tgz')) return 'archive';\n return 'git';\n }\n\n try {\n const u = new URL(s);\n const path = u.pathname.toLowerCase();\n if (path.endsWith('.zip')) return 'archive';\n if (path.endsWith('.tar.gz') || path.endsWith('.tgz')) return 'archive';\n } catch {\n // not a URL\n }\n\n if (lower.endsWith('.zip')) return 'archive';\n if (lower.endsWith('.tar.gz') || lower.endsWith('.tgz')) return 'archive';\n return 'git';\n}\n\nexport function findSkillRoot(repoRoot: string, subpath?: string): string {\n const sub = subpath?.trim()\n ? normalize(subpath.trim()).replace(/^[/\\\\]+/, '')\n : '';\n const base = sub ? resolve(repoRoot, sub) : resolve(repoRoot);\n if (!existsSync(base)) {\n throw new Error(`Path not found in source: ${sub || '.'}`);\n }\n if (existsSync(join(base, 'SKILL.md'))) {\n return base;\n }\n const entries = readdirSync(base, { withFileTypes: true }).filter((e) => e.isDirectory());\n if (entries.length === 1) {\n const one = join(base, entries[0].name);\n if (existsSync(join(one, 'SKILL.md'))) {\n return one;\n }\n }\n throw new Error(\n 'Could not locate SKILL.md (expected at root, under --path, or in a single child folder)',\n );\n}\n\nfunction inferSkillIdFromSkillMd(skillRoot: string): string {\n const raw = readFileSync(join(skillRoot, 'SKILL.md'), 'utf-8');\n const { frontmatter } = parseFrontmatter(raw);\n const n = String(frontmatter.name || '').trim();\n if (n && isValidSkillId(n)) {\n return n;\n }\n const dirName = basename(skillRoot);\n if (isValidSkillId(dirName)) {\n return dirName;\n }\n return '';\n}\n\nasync function runScan(dir: string, strict: boolean | undefined): Promise<void> {\n const summary = await scanSkillDirectory(dir);\n const label = basename(dir);\n if (summary.critical > 0 && strict) {\n throw new Error(\n `Security scan reported ${summary.critical} critical finding(s). ${formatScanSummary(summary, label)}`,\n );\n }\n if (summary.critical > 0 || summary.warn > 0) {\n console.warn(formatScanSummary(summary, label));\n }\n}\n\nasync function copySkillTreeToManaged(\n skillRoot: string,\n ctx: HubPullOptions & { kind: SkillHubKind; source: string },\n): Promise<HubPullResult> {\n const targetId = ctx.skillId?.trim() || inferSkillIdFromSkillMd(skillRoot);\n if (!targetId) {\n throw new Error('Could not determine skill id: pass --id <name> (must match managed id rules)');\n }\n if (!isValidSkillId(targetId)) {\n throw new Error(`Invalid skill id \"${targetId}\" (letters, digits, ._-; max 63 chars after first)`);\n }\n\n const { destDir, tempDir } = prepareManagedSkillTempDir(targetId);\n try {\n if (existsSync(destDir) && !ctx.force) {\n throw new Error(`Skill \"${targetId}\" already exists. Use --force to replace.`);\n }\n\n cpSync(skillRoot, tempDir, { recursive: true });\n\n if (!existsSync(join(tempDir, 'SKILL.md'))) {\n throw new Error('Installed tree is missing SKILL.md');\n }\n\n await runScan(tempDir, ctx.strictScan);\n const promoted = promoteManagedSkillTempDir({\n skillId: targetId,\n tempDir,\n overwrite: ctx.force,\n });\n const hash = computeSkillTreeHashSync(promoted.path);\n recordSkillsHubInstall(\n targetId,\n {\n kind: ctx.kind,\n source: ctx.source,\n ref: ctx.kind === 'git' ? ctx.ref : undefined,\n subpath: ctx.kind === 'git' ? ctx.subpath : undefined,\n },\n hash,\n );\n\n return {\n skillId: targetId,\n path: promoted.path,\n contentHash: hash,\n kind: ctx.kind,\n source: ctx.source,\n };\n } catch (err) {\n rmSync(tempDir, { recursive: true, force: true });\n throw err;\n }\n}\n\nasync function pullSkillFromZipBuffer(\n buf: Buffer,\n sourceLabel: string,\n options: HubPullOptions,\n): Promise<HubPullResult> {\n const r = installSkillFromZip(buf, {\n skillId: options.skillId,\n overwrite: options.force ?? false,\n });\n const hash = computeSkillTreeHashSync(r.path);\n recordSkillsHubInstall(r.skillId, { kind: 'archive', source: sourceLabel }, hash);\n await runScan(r.path, options.strictScan);\n return {\n skillId: r.skillId,\n path: r.path,\n contentHash: hash,\n kind: 'archive',\n source: sourceLabel,\n };\n}\n\nasync function pullSkillFromTarFile(\n archivePath: string,\n sourceLabel: string,\n options: HubPullOptions,\n): Promise<HubPullResult> {\n const tmpRoot = mkdtempSync(join(tmpdir(), 'xopc-tar-'));\n try {\n execFileSync('tar', ['-xzf', archivePath, '-C', tmpRoot], {\n stdio: 'pipe',\n encoding: 'utf-8',\n });\n const skillRoot = findSkillRoot(tmpRoot);\n return await copySkillTreeToManaged(skillRoot, { ...options, kind: 'archive', source: sourceLabel });\n } finally {\n rmSync(tmpRoot, { recursive: true, force: true });\n }\n}\n\nasync function pullSkillFromLocalPath(absPath: string, options: HubPullOptions): Promise<HubPullResult> {\n const resolved = resolve(absPath);\n if (!existsSync(resolved)) {\n throw new Error(`Not found: ${resolved}`);\n }\n const st = statSync(resolved);\n if (!st.isFile()) {\n throw new Error('Expected a path to a .zip or .tar.gz file (directories are not supported here)');\n }\n const lower = resolved.toLowerCase();\n if (lower.endsWith('.zip')) {\n const buf = readFileSync(resolved);\n return pullSkillFromZipBuffer(buf, resolved, options);\n }\n if (lower.endsWith('.tar.gz') || lower.endsWith('.tgz')) {\n return pullSkillFromTarFile(resolved, resolved, options);\n }\n throw new Error('Unsupported file type (expected .zip, .tar.gz, or .tgz)');\n}\n\nasync function pullSkillFromGit(url: string, options: HubPullOptions): Promise<HubPullResult> {\n const tmpRoot = mkdtempSync(join(tmpdir(), 'xopc-hub-'));\n const cloneDir = join(tmpRoot, 'clone');\n try {\n const args = ['clone', '--depth', '1'];\n if (options.ref?.trim()) {\n args.push('--branch', options.ref.trim());\n }\n args.push(url, cloneDir);\n try {\n execFileSync('git', args, { stdio: 'pipe', encoding: 'utf-8' });\n } catch {\n if (options.ref?.trim()) {\n execFileSync('git', ['clone', '--depth', '1', url, cloneDir], {\n stdio: 'pipe',\n encoding: 'utf-8',\n });\n } else {\n throw new Error(`git clone failed for ${url}`);\n }\n }\n const skillRoot = findSkillRoot(cloneDir, options.subpath);\n return await copySkillTreeToManaged(skillRoot, { ...options, kind: 'git', source: url });\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n if (msg.includes('ENOENT') || msg.includes('git clone failed')) {\n throw new Error(\n `Git operation failed (${msg}). Ensure git is installed and the repository URL is valid.`,\n );\n }\n throw e;\n } finally {\n rmSync(tmpRoot, { recursive: true, force: true });\n }\n}\n\n/**\n * Install or replace a skill from a git URL, http(s) archive URL, file:// URL, or local archive path.\n */\nexport async function pullSkillFromSource(\n source: string,\n options: HubPullOptions = {},\n): Promise<HubPullResult> {\n const trimmed = source.trim();\n if (!trimmed) {\n throw new Error('Missing source URL or path');\n }\n\n if (trimmed.startsWith('file:')) {\n return pullSkillFromLocalPath(fileURLToPath(trimmed), options);\n }\n\n if (!/^[a-zA-Z][a-zA-Z+.-]*:\\/\\//.test(trimmed) && existsSync(trimmed)) {\n return pullSkillFromLocalPath(resolve(trimmed), options);\n }\n\n const kind = classifyHubSource(trimmed);\n if (kind === 'archive') {\n const res = await fetch(trimmed);\n if (!res.ok) {\n throw new Error(`HTTP ${res.status} while fetching archive`);\n }\n const buf = Buffer.from(await res.arrayBuffer());\n const lower = trimmed.toLowerCase();\n if (lower.endsWith('.tar.gz') || lower.endsWith('.tgz')) {\n const tmpRoot = mkdtempSync(join(tmpdir(), 'xopc-fetch-tar-'));\n const f = join(tmpRoot, 'archive.tgz');\n try {\n mkdirSync(tmpRoot, { recursive: true });\n writeFileSync(f, buf);\n return await pullSkillFromTarFile(f, trimmed, options);\n } finally {\n rmSync(tmpRoot, { recursive: true, force: true });\n }\n }\n return pullSkillFromZipBuffer(buf, trimmed, options);\n }\n\n return pullSkillFromGit(trimmed, options);\n}\n\n/** Re-install from the source recorded in ~/.xopc/skills-lock.json for this skill id. */\nexport async function updateSkillFromLock(\n skillId: string,\n options: Pick<HubPullOptions, 'strictScan'> = {},\n): Promise<HubPullResult> {\n const e = getSkillsLockEntry(skillId);\n if (!e) {\n throw new Error(\n `No hub lock entry for \"${skillId}\". Install with: xopc skills pull <git-or-archive-url>`,\n );\n }\n return pullSkillFromSource(e.source, {\n skillId,\n ref: e.ref,\n subpath: e.subpath,\n force: true,\n strictScan: options.strictScan,\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"hub-pull.js","names":[],"sources":["../../../../src/agent/skills/hub-pull.ts"],"sourcesContent":["/**\n * CLI / hub: install or update skills from git or archive (zip / tar.gz) into ~/.xopc/skills.\n */\n\nimport { execFileSync } from 'node:child_process';\nimport AdmZip from 'adm-zip';\nimport {\n cpSync,\n existsSync,\n mkdtempSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n rmSync,\n statSync,\n writeFileSync,\n} from 'node:fs';\nimport { basename, dirname, join, normalize, resolve, sep } from 'node:path';\nimport { tmpdir } from 'node:os';\nimport { fileURLToPath } from 'node:url';\n\nimport { fetch } from 'undici';\n\nimport { parseFrontmatter } from '../../markdown/frontmatter.js';\nimport { computeSkillTreeHashSync } from './hub-hash.js';\nimport { getSkillsLockEntry, recordSkillsHubInstall } from './hub-lock.js';\nimport type { SkillHubKind } from './hub-lock.js';\nimport {\n installSkillFromZip,\n isIgnorableZipEntry,\n isValidSkillId,\n prepareManagedSkillTempDir,\n promoteManagedSkillTempDir,\n} from './managed-store.js';\nimport { formatScanSummary, scanSkillDirectory } from './scanner.js';\n\nexport interface HubPullOptions {\n skillId?: string;\n ref?: string;\n subpath?: string;\n force?: boolean;\n /** Destination skills root. Defaults to the global managed skills directory. */\n installRoot?: string;\n /** Hub lock path. Defaults to the global skills-lock.json. */\n lockPath?: string;\n /** When true, critical scanner findings fail the install. */\n strictScan?: boolean;\n}\n\nexport interface HubPullResult {\n skillId: string;\n path: string;\n contentHash: string;\n kind: SkillHubKind;\n source: string;\n}\n\ninterface GitHubSkillSource {\n owner: string;\n repo: string;\n cloneUrl: string;\n sourceLabel: string;\n ref?: string;\n subpath?: string;\n treePathParts?: string[];\n}\n\nclass GitHubArchiveDownloadError extends Error {\n constructor(\n message: string,\n readonly status?: number,\n ) {\n super(message);\n this.name = 'GitHubArchiveDownloadError';\n }\n}\n\nfunction githubHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n Accept: 'application/vnd.github+json',\n 'User-Agent': 'xopc-skill-installer',\n };\n const token = process.env.GITHUB_TOKEN || process.env.GH_TOKEN;\n if (token?.trim()) {\n headers.Authorization = `Bearer ${token.trim()}`;\n }\n return headers;\n}\n\nfunction normalizeSourceSubpath(subpath?: string): string | undefined {\n const raw = subpath?.trim().replace(/\\\\/g, '/').replace(/^\\/+/, '');\n if (!raw || raw === '.') return undefined;\n if (/^[a-zA-Z]:/.test(raw)) {\n throw new Error(`Invalid source path: ${subpath}`);\n }\n const normalized = normalize(raw);\n if (normalized === '..' || normalized.startsWith(`..${sep}`) || resolve('/', normalized) === resolve('/')) {\n throw new Error(`Invalid source path: ${subpath}`);\n }\n return normalized.replace(/\\\\/g, '/');\n}\n\nfunction decodeUrlPathPart(value: string): string {\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n}\n\nfunction parseSshGitHubSource(\n raw: string,\n optionRef?: string,\n optionSubpath?: string,\n): GitHubSkillSource | undefined {\n const ssh = raw.match(/^git@github\\.com:([^/]+)\\/(.+?)(?:\\.git)?$/i);\n if (!ssh) return undefined;\n const owner = ssh[1];\n const repo = ssh[2].replace(/\\.git$/i, '');\n return {\n owner,\n repo,\n cloneUrl: `https://github.com/${owner}/${repo}.git`,\n sourceLabel: raw,\n ref: optionRef,\n subpath: optionSubpath,\n };\n}\n\nexport function parseGitHubSkillSource(\n raw: string,\n options: Pick<HubPullOptions, 'ref' | 'subpath'> = {},\n): GitHubSkillSource | undefined {\n const optionRef = options.ref?.trim() || undefined;\n const optionSubpath = normalizeSourceSubpath(options.subpath);\n const sshSource = parseSshGitHubSource(raw, optionRef, optionSubpath);\n if (sshSource) return sshSource;\n\n let url: URL;\n try {\n url = new URL(raw);\n } catch {\n return undefined;\n }\n if (url.protocol !== 'https:' && url.protocol !== 'http:') return undefined;\n if (url.hostname.toLowerCase() !== 'github.com') return undefined;\n\n const parts = url.pathname.split('/').filter(Boolean).map(decodeUrlPathPart);\n if (parts.length < 2) return undefined;\n\n const owner = parts[0];\n const repo = parts[1].replace(/\\.git$/i, '');\n if (!owner || !repo) return undefined;\n\n let ref: string | undefined;\n let subpath: string | undefined;\n let treePathParts: string[] | undefined;\n const marker = parts[2]?.toLowerCase();\n if ((marker === 'tree' || marker === 'blob') && parts[3]) {\n treePathParts = parts.slice(3);\n ref = treePathParts[0];\n subpath = normalizeSourceSubpath(treePathParts.slice(1).join('/'));\n } else if (parts.length > 2 && !parts[1].toLowerCase().endsWith('.git')) {\n subpath = normalizeSourceSubpath(parts.slice(2).join('/'));\n }\n\n return {\n owner,\n repo,\n cloneUrl: `https://github.com/${owner}/${repo}.git`,\n sourceLabel: raw,\n ref: optionRef || ref,\n subpath: optionSubpath || subpath,\n treePathParts,\n };\n}\n\nexport function classifyHubSource(raw: string): 'git' | 'archive' {\n const s = raw.trim();\n const lower = s.toLowerCase();\n\n try {\n if (s.startsWith('file:')) {\n const p = fileURLToPath(s);\n const pl = p.toLowerCase();\n if (pl.endsWith('.zip')) return 'archive';\n if (pl.endsWith('.tar.gz') || pl.endsWith('.tgz')) return 'archive';\n return 'git';\n }\n } catch {\n // ignore invalid file URL\n }\n\n if (/^[a-zA-Z]:[\\\\/]/.test(s) || (s.startsWith('/') && !s.startsWith('//'))) {\n if (lower.endsWith('.zip')) return 'archive';\n if (lower.endsWith('.tar.gz') || lower.endsWith('.tgz')) return 'archive';\n return 'git';\n }\n\n try {\n const u = new URL(s);\n const path = u.pathname.toLowerCase();\n if (path.endsWith('.zip')) return 'archive';\n if (path.endsWith('.tar.gz') || path.endsWith('.tgz')) return 'archive';\n } catch {\n // not a URL\n }\n\n if (lower.endsWith('.zip')) return 'archive';\n if (lower.endsWith('.tar.gz') || lower.endsWith('.tgz')) return 'archive';\n return 'git';\n}\n\nexport function findSkillRoot(repoRoot: string, subpath?: string): string {\n const sub = normalizeSourceSubpath(subpath) || '';\n const root = resolve(repoRoot);\n const base = sub ? resolve(root, sub) : root;\n if (base !== root && !base.startsWith(root + sep)) {\n throw new Error(`Invalid source path: ${subpath}`);\n }\n if (!existsSync(base)) {\n throw new Error(`Path not found in source: ${sub || '.'}`);\n }\n if (existsSync(join(base, 'SKILL.md'))) {\n return base;\n }\n const entries = readdirSync(base, { withFileTypes: true }).filter((e) => e.isDirectory());\n if (entries.length === 1) {\n const one = join(base, entries[0].name);\n if (existsSync(join(one, 'SKILL.md'))) {\n return one;\n }\n }\n throw new Error(\n 'Could not locate SKILL.md (expected at root, under --path, or in a single child folder)',\n );\n}\n\nfunction inferSkillIdFromSkillMd(skillRoot: string): string {\n const raw = readFileSync(join(skillRoot, 'SKILL.md'), 'utf-8');\n const { frontmatter } = parseFrontmatter(raw);\n const n = String(frontmatter.name || '').trim();\n if (n && isValidSkillId(n)) {\n return n;\n }\n const dirName = basename(skillRoot);\n if (isValidSkillId(dirName)) {\n return dirName;\n }\n return '';\n}\n\nasync function runScan(dir: string, strict: boolean | undefined): Promise<void> {\n const summary = await scanSkillDirectory(dir);\n const label = basename(dir);\n if (summary.critical > 0 && strict) {\n throw new Error(\n `Security scan reported ${summary.critical} critical finding(s). ${formatScanSummary(summary, label)}`,\n );\n }\n if (summary.critical > 0 || summary.warn > 0) {\n console.warn(formatScanSummary(summary, label));\n }\n}\n\nasync function copySkillTreeToManaged(\n skillRoot: string,\n ctx: HubPullOptions & { kind: SkillHubKind; source: string },\n): Promise<HubPullResult> {\n const targetId = ctx.skillId?.trim() || inferSkillIdFromSkillMd(skillRoot);\n if (!targetId) {\n throw new Error('Could not determine skill id: pass --id <name> (must match managed id rules)');\n }\n if (!isValidSkillId(targetId)) {\n throw new Error(`Invalid skill id \"${targetId}\" (letters, digits, ._-; max 63 chars after first)`);\n }\n\n const { destDir, tempDir } = prepareManagedSkillTempDir(targetId, ctx.installRoot);\n try {\n if (existsSync(destDir) && !ctx.force) {\n throw new Error(`Skill \"${targetId}\" already exists. Use --force to replace.`);\n }\n\n cpSync(skillRoot, tempDir, { recursive: true });\n\n if (!existsSync(join(tempDir, 'SKILL.md'))) {\n throw new Error('Installed tree is missing SKILL.md');\n }\n\n await runScan(tempDir, ctx.strictScan);\n const promoted = promoteManagedSkillTempDir({\n skillId: targetId,\n tempDir,\n overwrite: ctx.force,\n rootDir: ctx.installRoot,\n });\n const hash = computeSkillTreeHashSync(promoted.path);\n recordSkillsHubInstall(\n targetId,\n {\n kind: ctx.kind,\n source: ctx.source,\n ref: ctx.kind === 'git' ? ctx.ref : undefined,\n subpath: ctx.kind === 'git' ? ctx.subpath : undefined,\n },\n hash,\n ctx.lockPath,\n );\n\n return {\n skillId: targetId,\n path: promoted.path,\n contentHash: hash,\n kind: ctx.kind,\n source: ctx.source,\n };\n } catch (err) {\n rmSync(tempDir, { recursive: true, force: true });\n throw err;\n }\n}\n\nasync function pullSkillFromZipBuffer(\n buf: Buffer,\n sourceLabel: string,\n options: HubPullOptions,\n): Promise<HubPullResult> {\n const r = installSkillFromZip(buf, {\n skillId: options.skillId,\n overwrite: options.force ?? false,\n rootDir: options.installRoot,\n });\n const hash = computeSkillTreeHashSync(r.path);\n recordSkillsHubInstall(r.skillId, { kind: 'archive', source: sourceLabel }, hash, options.lockPath);\n await runScan(r.path, options.strictScan);\n return {\n skillId: r.skillId,\n path: r.path,\n contentHash: hash,\n kind: 'archive',\n source: sourceLabel,\n };\n}\n\nasync function pullSkillFromTarFile(\n archivePath: string,\n sourceLabel: string,\n options: HubPullOptions,\n): Promise<HubPullResult> {\n const tmpRoot = mkdtempSync(join(tmpdir(), 'xopc-tar-'));\n try {\n execFileSync('tar', ['-xzf', archivePath, '-C', tmpRoot], {\n stdio: 'pipe',\n encoding: 'utf-8',\n });\n const skillRoot = findSkillRoot(tmpRoot);\n return await copySkillTreeToManaged(skillRoot, { ...options, kind: 'archive', source: sourceLabel });\n } finally {\n rmSync(tmpRoot, { recursive: true, force: true });\n }\n}\n\nfunction isSafeArchivePath(name: string): boolean {\n if (!name) return false;\n const normalized = name.replace(/\\\\/g, '/').replace(/\\/+$/, '');\n if (normalized.startsWith('/') || /^[a-zA-Z]:/.test(normalized)) return false;\n return normalized.split('/').every((part) => part && part !== '..');\n}\n\nfunction extractZipBufferToTempDir(buf: Buffer, tmpRoot: string): void {\n const zip = new AdmZip(buf);\n const rootResolved = resolve(tmpRoot);\n for (const entry of zip.getEntries()) {\n const normalized = entry.entryName.replace(/\\\\/g, '/');\n if (!normalized || isIgnorableZipEntry(normalized)) continue;\n if (!isSafeArchivePath(normalized)) {\n throw new Error(`Unsafe zip entry path: ${entry.entryName}`);\n }\n\n const target = join(tmpRoot, normalized);\n const targetResolved = resolve(target);\n if (targetResolved !== rootResolved && !targetResolved.startsWith(rootResolved + sep)) {\n throw new Error(`Unsafe zip entry path: ${entry.entryName}`);\n }\n\n if (entry.isDirectory) {\n mkdirSync(target, { recursive: true });\n continue;\n }\n mkdirSync(dirname(target), { recursive: true });\n writeFileSync(target, entry.getData());\n }\n}\n\nfunction findExtractedRepositoryRoot(tmpRoot: string): string {\n const entries = readdirSync(tmpRoot, { withFileTypes: true }).filter((entry) => !entry.name.startsWith('.'));\n const dirs = entries.filter((entry) => entry.isDirectory());\n const files = entries.filter((entry) => entry.isFile());\n if (dirs.length === 1 && files.length === 0) {\n return join(tmpRoot, dirs[0].name);\n }\n return tmpRoot;\n}\n\nasync function resolveGitHubDefaultBranch(source: GitHubSkillSource): Promise<string | undefined> {\n const apiUrl = `https://api.github.com/repos/${source.owner}/${source.repo}`;\n try {\n const res = await fetch(apiUrl, { headers: githubHeaders() });\n if (!res.ok) return undefined;\n const body = (await res.json()) as { default_branch?: unknown };\n const branch = typeof body.default_branch === 'string' ? body.default_branch.trim() : '';\n return branch || undefined;\n } catch {\n return undefined;\n }\n}\n\nasync function githubRefExists(\n source: GitHubSkillSource,\n namespace: 'heads' | 'tags',\n ref: string,\n): Promise<boolean> {\n const url = `https://api.github.com/repos/${source.owner}/${source.repo}/git/ref/${namespace}/${encodeURI(ref)}`;\n try {\n const res = await fetch(url, { headers: githubHeaders() });\n return res.ok;\n } catch {\n return false;\n }\n}\n\nasync function resolveGitHubTreeRefAndSubpath(\n source: GitHubSkillSource,\n options: HubPullOptions,\n): Promise<{ ref?: string; subpath?: string }> {\n const optionRef = options.ref?.trim() || undefined;\n const optionSubpath = options.subpath || undefined;\n if (optionRef || !source.treePathParts?.length) {\n return {\n ref: optionRef || source.ref,\n subpath: optionSubpath || source.subpath,\n };\n }\n\n for (let i = source.treePathParts.length; i >= 1; i -= 1) {\n const candidate = source.treePathParts.slice(0, i).join('/');\n if (\n (await githubRefExists(source, 'heads', candidate)) ||\n (await githubRefExists(source, 'tags', candidate))\n ) {\n return {\n ref: candidate,\n subpath: optionSubpath || normalizeSourceSubpath(source.treePathParts.slice(i).join('/')),\n };\n }\n }\n\n return {\n ref: source.ref,\n subpath: optionSubpath || source.subpath,\n };\n}\n\nasync function pullSkillFromGitHubArchive(\n source: GitHubSkillSource,\n options: HubPullOptions,\n): Promise<HubPullResult> {\n const ref = options.ref?.trim() || (await resolveGitHubDefaultBranch(source)) || 'main';\n const zipUrl = `https://codeload.github.com/${source.owner}/${source.repo}/zip/${encodeURI(ref)}`;\n const res = await fetch(zipUrl, { headers: githubHeaders() });\n if (!res.ok) {\n throw new GitHubArchiveDownloadError(`HTTP ${res.status} while fetching GitHub archive`, res.status);\n }\n\n const tmpRoot = mkdtempSync(join(tmpdir(), 'xopc-github-zip-'));\n try {\n const buf = Buffer.from(await res.arrayBuffer());\n extractZipBufferToTempDir(buf, tmpRoot);\n const repoRoot = findExtractedRepositoryRoot(tmpRoot);\n const effectiveOptions = { ...options, ref, subpath: options.subpath || source.subpath };\n const skillRoot = findSkillRoot(repoRoot, effectiveOptions.subpath);\n return await copySkillTreeToManaged(skillRoot, {\n ...effectiveOptions,\n kind: 'git',\n source: source.sourceLabel,\n });\n } finally {\n rmSync(tmpRoot, { recursive: true, force: true });\n }\n}\n\nasync function pullSkillFromGitHubSparse(\n source: GitHubSkillSource,\n options: HubPullOptions,\n): Promise<HubPullResult> {\n const subpath = normalizeSourceSubpath(options.subpath || source.subpath);\n if (!subpath) {\n return pullSkillFromGit(source.cloneUrl, options, source.sourceLabel);\n }\n\n const tmpRoot = mkdtempSync(join(tmpdir(), 'xopc-github-sparse-'));\n const cloneDir = join(tmpRoot, 'clone');\n let clonedRef = options.ref?.trim() || undefined;\n try {\n const args = ['clone', '--depth', '1', '--filter=blob:none', '--sparse'];\n if (clonedRef) {\n args.push('--branch', clonedRef);\n }\n args.push(source.cloneUrl, cloneDir);\n try {\n execFileSync('git', args, { stdio: 'pipe', encoding: 'utf-8' });\n } catch {\n if (!clonedRef) throw new Error(`git clone failed for ${source.cloneUrl}`);\n clonedRef = undefined;\n execFileSync(\n 'git',\n ['clone', '--depth', '1', '--filter=blob:none', '--sparse', source.cloneUrl, cloneDir],\n { stdio: 'pipe', encoding: 'utf-8' },\n );\n }\n\n execFileSync('git', ['-C', cloneDir, 'sparse-checkout', 'set', '--no-cone', subpath], {\n stdio: 'pipe',\n encoding: 'utf-8',\n });\n const effectiveOptions = { ...options, subpath, ref: clonedRef };\n const skillRoot = findSkillRoot(cloneDir, subpath);\n return await copySkillTreeToManaged(skillRoot, {\n ...effectiveOptions,\n kind: 'git',\n source: source.sourceLabel,\n });\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n if (msg.includes('ENOENT') || msg.includes('git clone failed')) {\n throw new Error(\n `Git operation failed (${msg}). Ensure git is installed and the repository URL is valid.`,\n );\n }\n throw e;\n } finally {\n rmSync(tmpRoot, { recursive: true, force: true });\n }\n}\n\nasync function pullSkillFromGitHub(\n source: GitHubSkillSource,\n options: HubPullOptions,\n): Promise<HubPullResult> {\n const resolved = await resolveGitHubTreeRefAndSubpath(source, options);\n const effectiveOptions = {\n ...options,\n ref: resolved.ref,\n subpath: resolved.subpath,\n };\n try {\n return await pullSkillFromGitHubArchive(source, effectiveOptions);\n } catch (archiveErr) {\n try {\n return await pullSkillFromGitHubSparse(source, effectiveOptions);\n } catch (gitErr) {\n const archiveMsg = archiveErr instanceof Error ? archiveErr.message : String(archiveErr);\n const gitMsg = gitErr instanceof Error ? gitErr.message : String(gitErr);\n throw new Error(`GitHub archive install failed (${archiveMsg}); git fallback failed (${gitMsg})`);\n }\n }\n}\n\nasync function pullSkillFromLocalPath(absPath: string, options: HubPullOptions): Promise<HubPullResult> {\n const resolved = resolve(absPath);\n if (!existsSync(resolved)) {\n throw new Error(`Not found: ${resolved}`);\n }\n const st = statSync(resolved);\n if (!st.isFile()) {\n throw new Error('Expected a path to a .zip or .tar.gz file (directories are not supported here)');\n }\n const lower = resolved.toLowerCase();\n if (lower.endsWith('.zip')) {\n const buf = readFileSync(resolved);\n return pullSkillFromZipBuffer(buf, resolved, options);\n }\n if (lower.endsWith('.tar.gz') || lower.endsWith('.tgz')) {\n return pullSkillFromTarFile(resolved, resolved, options);\n }\n throw new Error('Unsupported file type (expected .zip, .tar.gz, or .tgz)');\n}\n\nasync function pullSkillFromGit(\n url: string,\n options: HubPullOptions,\n sourceLabel = url,\n): Promise<HubPullResult> {\n const tmpRoot = mkdtempSync(join(tmpdir(), 'xopc-hub-'));\n const cloneDir = join(tmpRoot, 'clone');\n let clonedRef = options.ref?.trim() || undefined;\n try {\n const args = ['clone', '--depth', '1'];\n if (clonedRef) {\n args.push('--branch', clonedRef);\n }\n args.push(url, cloneDir);\n try {\n execFileSync('git', args, { stdio: 'pipe', encoding: 'utf-8' });\n } catch {\n if (clonedRef) {\n clonedRef = undefined;\n execFileSync('git', ['clone', '--depth', '1', url, cloneDir], {\n stdio: 'pipe',\n encoding: 'utf-8',\n });\n } else {\n throw new Error(`git clone failed for ${url}`);\n }\n }\n const skillRoot = findSkillRoot(cloneDir, options.subpath);\n return await copySkillTreeToManaged(skillRoot, {\n ...options,\n ref: clonedRef,\n kind: 'git',\n source: sourceLabel,\n });\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n if (msg.includes('ENOENT') || msg.includes('git clone failed')) {\n throw new Error(\n `Git operation failed (${msg}). Ensure git is installed and the repository URL is valid.`,\n );\n }\n throw e;\n } finally {\n rmSync(tmpRoot, { recursive: true, force: true });\n }\n}\n\n/**\n * Install or replace a skill from a git URL, http(s) archive URL, file:// URL, or local archive path.\n */\nexport async function pullSkillFromSource(\n source: string,\n options: HubPullOptions = {},\n): Promise<HubPullResult> {\n const trimmed = source.trim();\n if (!trimmed) {\n throw new Error('Missing source URL or path');\n }\n\n if (trimmed.startsWith('file:')) {\n return pullSkillFromLocalPath(fileURLToPath(trimmed), options);\n }\n\n if (!/^[a-zA-Z][a-zA-Z+.-]*:\\/\\//.test(trimmed) && existsSync(trimmed)) {\n return pullSkillFromLocalPath(resolve(trimmed), options);\n }\n\n const githubSource = parseGitHubSkillSource(trimmed, options);\n if (githubSource) {\n return pullSkillFromGitHub(githubSource, options);\n }\n\n const kind = classifyHubSource(trimmed);\n if (kind === 'archive') {\n const res = await fetch(trimmed);\n if (!res.ok) {\n throw new Error(`HTTP ${res.status} while fetching archive`);\n }\n const buf = Buffer.from(await res.arrayBuffer());\n const lower = trimmed.toLowerCase();\n if (lower.endsWith('.tar.gz') || lower.endsWith('.tgz')) {\n const tmpRoot = mkdtempSync(join(tmpdir(), 'xopc-fetch-tar-'));\n const f = join(tmpRoot, 'archive.tgz');\n try {\n mkdirSync(tmpRoot, { recursive: true });\n writeFileSync(f, buf);\n return await pullSkillFromTarFile(f, trimmed, options);\n } finally {\n rmSync(tmpRoot, { recursive: true, force: true });\n }\n }\n return pullSkillFromZipBuffer(buf, trimmed, options);\n }\n\n return pullSkillFromGit(trimmed, options);\n}\n\n/** Re-install from the source recorded in ~/.xopc/skills-lock.json for this skill id. */\nexport async function updateSkillFromLock(\n skillId: string,\n options: Pick<HubPullOptions, 'strictScan'> = {},\n): Promise<HubPullResult> {\n const e = getSkillsLockEntry(skillId);\n if (!e) {\n throw new Error(\n `No hub lock entry for \"${skillId}\". Install with: xopc skills pull <git-or-archive-url>`,\n );\n }\n return pullSkillFromSource(e.source, {\n skillId,\n ref: e.ref,\n subpath: e.subpath,\n force: true,\n strictScan: options.strictScan,\n });\n}\n"],"mappings":"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"}