@xopcai/xopc 0.0.172 → 0.0.174

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 (223) 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/{activity-store-C3Y-bESI.js → activity-store-CyEDJeIt.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-CPyev9P7.js → agent-avatar-dicebear-DF7Bol6I.js} +1 -1
  5. package/dist/gateway/static/root/assets/agents-BVxEFPQ5.js +2 -0
  6. package/dist/gateway/static/root/assets/{api-B7qEr_Rw.js → api-DYunqroX.js} +1 -1
  7. package/dist/gateway/static/root/assets/api-DwyUxpgY.js +1 -0
  8. package/dist/gateway/static/root/assets/{app-management-settings-panel-Br_9-7fs.js → app-management-settings-panel-B4xJyvDu.js} +1 -1
  9. package/dist/gateway/static/root/assets/{appearance-settings-uyLcRPai.js → appearance-settings-B2PQxRiu.js} +1 -1
  10. package/dist/gateway/static/root/assets/apps-page-BtIgd82S.js +1 -0
  11. package/dist/gateway/static/root/assets/{archive-plugin-B19REnR5.js → archive-plugin-DWhBmmjD.js} +1 -1
  12. package/dist/gateway/static/root/assets/{attachment-load-DLWCC4Yi.js → attachment-load-BOpZfa_I.js} +1 -1
  13. package/dist/gateway/static/root/assets/{automation-suggestion-card-ky5S5lly.js → automation-suggestion-card-Byu3I7Rs.js} +1 -1
  14. package/dist/gateway/static/root/assets/automations-page-CG_SCH5b.js +6 -0
  15. package/dist/gateway/static/root/assets/{binary-plugins-CtPEzLlo.js → binary-plugins-6AG1qatz.js} +1 -1
  16. package/dist/gateway/static/root/assets/{block-editor-CQVR4Xij.js → block-editor-CJhrn98_.js} +5 -5
  17. package/dist/gateway/static/root/assets/browser-settings-page-CfLqPWZC.js +8 -0
  18. package/dist/gateway/static/root/assets/{browser-workflow-inputs-CimCGbhq.js → browser-workflow-inputs-CBVb4mt9.js} +1 -1
  19. package/dist/gateway/static/root/assets/{browser-workflows-page-DewuCw3p.js → browser-workflows-page-Cq4XUKbu.js} +2 -2
  20. package/dist/gateway/static/root/assets/capabilities-settings-panel-DCJmm6cR.js +7 -0
  21. package/dist/gateway/static/root/assets/{capability-presets-api-B5RTs-Az.js → capability-presets-api-hbW4NAKO.js} +1 -1
  22. package/dist/gateway/static/root/assets/capability-presets-settings-panel-CnkAYvWI.js +1 -0
  23. package/dist/gateway/static/root/assets/{channel-recipient-api-Czu0YzIZ.js → channel-recipient-api-CzMjHb17.js} +1 -1
  24. package/dist/gateway/static/root/assets/channels-settings-DtqqFpDn.js +1 -0
  25. package/dist/gateway/static/root/assets/channels-status-swr-C-5yHbc0.js +1 -0
  26. package/dist/gateway/static/root/assets/{connector-logo-Di3gnR_D.js → connector-logo-B9Au6gMZ.js} +1 -1
  27. package/dist/gateway/static/root/assets/connectors-page-CaHfs8YF.js +2 -0
  28. package/dist/gateway/static/root/assets/copy-VueTIC2x.js +1 -0
  29. package/dist/gateway/static/root/assets/desktop-pet-CvFMKYdb.js +1 -0
  30. package/dist/gateway/static/root/assets/{desktop-pet-settings-C3L6AI8_.js → desktop-pet-settings-CNff5TFb.js} +1 -1
  31. package/dist/gateway/static/root/assets/{directory-picker-path-field-Dvq4iG6P.js → directory-picker-path-field-Bf956uo-.js} +1 -1
  32. package/dist/gateway/static/root/assets/dreaming-settings-CHM8FE1g.js +3 -0
  33. package/dist/gateway/static/root/assets/{extension-debug-page-BecQjU0J.js → extension-debug-page-ZqM_0eUs.js} +1 -1
  34. package/dist/gateway/static/root/assets/{extension-page-BeVkPSm-.js → extension-page-D4hvXOMM.js} +1 -1
  35. package/dist/gateway/static/root/assets/{extension-settings-page-DMoo2mKx.js → extension-settings-page-GsqxaJjA.js} +1 -1
  36. package/dist/gateway/static/root/assets/focus-detail-page-CE6uwrl1.js +1 -0
  37. package/dist/gateway/static/root/assets/{gateway-config-api-Bthb3_6v.js → gateway-config-api-B4THmgnS.js} +1 -1
  38. package/dist/gateway/static/root/assets/{gateway-settings-Bh8nPvJQ.js → gateway-settings-CPv-MxGE.js} +1 -1
  39. package/dist/gateway/static/root/assets/{gateway-startup-retry-D3USVm9D.js → gateway-startup-retry-MP3K71pP.js} +1 -1
  40. package/dist/gateway/static/root/assets/goal-create-dialog-DAeb82xP.js +1 -0
  41. package/dist/gateway/static/root/assets/goal-detail-page-CwLSp01r.js +4 -0
  42. package/dist/gateway/static/root/assets/{goals-config-api-C_2QWBtb.js → goals-config-api-DCcDuIjG.js} +1 -1
  43. package/dist/gateway/static/root/assets/goals-page-DvJQ6_4M.js +2 -0
  44. package/dist/gateway/static/root/assets/{goals-settings-DhL643tc.js → goals-settings-o9QMXvNq.js} +1 -1
  45. package/dist/gateway/static/root/assets/{heartbeat-settings-COVFwp7C.js → heartbeat-settings-DixwpXnH.js} +1 -1
  46. package/dist/gateway/static/root/assets/{image-generation-api-BNQlnwpU.js → image-generation-api-BOGH9FGi.js} +1 -1
  47. package/dist/gateway/static/root/assets/index-CfXiRNN5.css +1 -0
  48. package/dist/gateway/static/root/assets/index-eyttVNS_.js +212 -0
  49. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-DfdJRJVy.js → keyboard-shortcuts-settings-D4o4ZPF6.js} +1 -1
  50. package/dist/gateway/static/root/assets/local-app-workbench-page-CPcfqn_A.js +2 -0
  51. package/dist/gateway/static/root/assets/{local-apps-page-BvCPOgoi.js → local-apps-page-GzMmpO7G.js} +1 -1
  52. package/dist/gateway/static/root/assets/{locale-store-BP0vD37A.js → locale-store-CAuhEGCn.js} +1 -1
  53. package/dist/gateway/static/root/assets/logs-page-DXABWCZp.js +7 -0
  54. package/dist/gateway/static/root/assets/{markdown-split-YO1rDk9m.js → markdown-split-CIX8D1pv.js} +1 -1
  55. package/dist/gateway/static/root/assets/{media-plugins-CU_RRf-q.js → media-plugins-Bp3eIA45.js} +1 -1
  56. package/dist/gateway/static/root/assets/messages-BiBdO1-O.js +3 -0
  57. package/dist/gateway/static/root/assets/{notes-page-CeFiOK3S.js → notes-page-RVFiYAoO.js} +1 -1
  58. package/dist/gateway/static/root/assets/notes-workbench-DgJzZRX3.js +4 -0
  59. package/dist/gateway/static/root/assets/{page-tabs-tiHmRJUA.js → page-tabs-BGAYH3Ef.js} +1 -1
  60. package/dist/gateway/static/root/assets/{preview-open-alternatives-CU6XgaCz.js → preview-open-alternatives-BM6pDkHp.js} +1 -1
  61. package/dist/gateway/static/root/assets/{product-open-page-Dn4_qor4.js → product-open-page-BiMetEmn.js} +1 -1
  62. package/dist/gateway/static/root/assets/project-detail-page-DF7F70Vg.js +1 -0
  63. package/dist/gateway/static/root/assets/projects-page-Cw3jyi5s.js +1 -0
  64. package/dist/gateway/static/root/assets/remote-access-hub-ChAJsaNY.js +1 -0
  65. package/dist/gateway/static/root/assets/{save-bar-controls-edDUIbXo.js → save-bar-controls-BdjV8MK5.js} +1 -1
  66. package/dist/gateway/static/root/assets/{schedule-field-DqJO_5Yb.js → schedule-field-ChlqXU46.js} +1 -1
  67. package/dist/gateway/static/root/assets/{schema-form-CMh0jzy5.js → schema-form-DDKf5ZSH.js} +1 -1
  68. package/dist/gateway/static/root/assets/sessions-page-BxZIxt7z.js +1 -0
  69. package/dist/gateway/static/root/assets/settings-advanced-gate-DcDLS0xV.js +1 -0
  70. package/dist/gateway/static/root/assets/{settings-form-section-Bb0Bc3nJ.js → settings-form-section-CPG0KGVs.js} +1 -1
  71. package/dist/gateway/static/root/assets/{settings-loading-skeleton-DQhADvz1.js → settings-loading-skeleton-DRSDHucM.js} +1 -1
  72. package/dist/gateway/static/root/assets/{settings-page-b0M5HukN.js → settings-page-CeB7_xD0.js} +1 -1
  73. package/dist/gateway/static/root/assets/{settings-page-layout-hvjtIjvh.js → settings-page-layout-BENrkwd0.js} +1 -1
  74. package/dist/gateway/static/root/assets/setup-status-panel-4Xa9NA7v.js +1 -0
  75. package/dist/gateway/static/root/assets/{share-preview-page-rbeaOpTg.js → share-preview-page-DIzczJkG.js} +1 -1
  76. package/dist/gateway/static/root/assets/shares-settings-BpN0o5Cf.js +1 -0
  77. package/dist/gateway/static/root/assets/skill-reload-api-DvF2UAaL.js +1 -0
  78. package/dist/gateway/static/root/assets/skills-page-CGKXpNfy.js +2 -0
  79. package/dist/gateway/static/root/assets/{system-settings-panel-BHo_hgnL.js → system-settings-panel-Dp4d5Q1B.js} +1 -1
  80. package/dist/gateway/static/root/assets/{theme-store-C3KnnjcU.js → theme-store-CbGc1laW.js} +1 -1
  81. package/dist/gateway/static/root/assets/{time-picker-D-G-uwVJ.js → time-picker-BhgCeDuO.js} +1 -1
  82. package/dist/gateway/static/root/assets/{typed-models-lib-DtRnG-YI.js → typed-models-lib-DwPk3OPL.js} +1 -1
  83. package/dist/gateway/static/root/assets/{use-channel-catalog-CWWItX2g.js → use-channel-catalog-CXrEu2dw.js} +1 -1
  84. package/dist/gateway/static/root/assets/user-context-page-Dy_fKAK_.js +1 -0
  85. package/dist/gateway/static/root/assets/{voice-api-key-field-BTnltQHZ.js → voice-api-key-field-DFoA79LB.js} +1 -1
  86. package/dist/gateway/static/root/assets/work-discovery-page-BWkjb1NK.js +1 -0
  87. package/dist/gateway/static/root/assets/work-item-detail-page-DLBNFse5.js +1 -0
  88. package/dist/gateway/static/root/assets/work-page-Bn5RXMIE.js +1 -0
  89. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-D7vKChFZ.js → workflow-run-setup-panel-BuniGPO0.js} +2 -2
  90. package/dist/gateway/static/root/assets/workflows-page-_vFhRrAl.js +11 -0
  91. package/dist/gateway/static/root/index.html +7 -7
  92. package/dist/package.js +1 -1
  93. package/dist/src/agent/agent-manager.d.ts +3 -1
  94. package/dist/src/agent/agent-manager.js +4 -3
  95. package/dist/src/agent/capabilities/definitions.d.ts +2 -1
  96. package/dist/src/agent/capabilities/definitions.js +3 -1
  97. package/dist/src/agent/prompt/sections/tooling.js +4 -0
  98. package/dist/src/agent/service.d.ts +2 -1
  99. package/dist/src/agent/service.js +26 -0
  100. package/dist/src/agent/skills/hub-pull.js +1 -1
  101. package/dist/src/agent/skills/index.js +1 -1
  102. package/dist/src/agent/skills/install-target.js +1 -1
  103. package/dist/src/agent/skills/marketplace/adapters/clawhub/adapter.d.ts +64 -0
  104. package/dist/src/agent/skills/marketplace/adapters/clawhub/adapter.js +27 -18
  105. package/dist/src/agent/skills/marketplace/adapters/store/adapter.js +1 -1
  106. package/dist/src/agent/skills/marketplace/adapters/store/store-api-client.js +1 -1
  107. package/dist/src/agent/skills/marketplace/search.d.ts +46 -0
  108. package/dist/src/agent/skills/marketplace/search.js +193 -0
  109. package/dist/src/agent/skills/skill-tool-gating.js +2 -1
  110. package/dist/src/agent/tools/delegate-tool.js +2 -0
  111. package/dist/src/agent/tools/factory.d.ts +4 -2
  112. package/dist/src/agent/tools/factory.js +11 -5
  113. package/dist/src/agent/tools/index.d.ts +2 -1
  114. package/dist/src/agent/tools/index.js +2 -1
  115. package/dist/src/agent/tools/skill-install-tool.d.ts +17 -0
  116. package/dist/src/agent/tools/skill-install-tool.js +76 -8
  117. package/dist/src/agent/tools/skills-marketplace-search-tool.d.ts +17 -0
  118. package/dist/src/agent/tools/skills-marketplace-search-tool.js +77 -0
  119. package/dist/src/browser/providers/cloakbrowser.js +1 -1
  120. package/dist/src/capabilities/store-connector.js +1 -1
  121. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  122. package/dist/src/config/agent-profile.js +1 -1
  123. package/dist/src/extensions/api.js +1 -1
  124. package/dist/src/extensions/install.js +1 -1
  125. package/dist/src/focuses/candidate-repository.d.ts +15 -0
  126. package/dist/src/focuses/candidate-repository.js +91 -0
  127. package/dist/src/focuses/index.d.ts +7 -0
  128. package/dist/src/focuses/index.js +7 -0
  129. package/dist/src/focuses/insight-repository.d.ts +22 -0
  130. package/dist/src/focuses/insight-repository.js +77 -0
  131. package/dist/src/focuses/prompts.d.ts +2 -0
  132. package/dist/src/focuses/prompts.js +18 -0
  133. package/dist/src/focuses/reconciler.d.ts +5 -0
  134. package/dist/src/focuses/reconciler.js +26 -0
  135. package/dist/src/focuses/repository.d.ts +61 -0
  136. package/dist/src/focuses/repository.js +214 -0
  137. package/dist/src/focuses/run-processor.d.ts +18 -0
  138. package/dist/src/focuses/run-processor.js +162 -0
  139. package/dist/src/focuses/service.d.ts +42 -0
  140. package/dist/src/focuses/service.js +241 -0
  141. package/dist/src/focuses/types.d.ts +89 -0
  142. package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
  143. package/dist/src/gateway/agent-builtin-tools.js +2 -0
  144. package/dist/src/gateway/agents-admin.js +1 -1
  145. package/dist/src/gateway/hono/routes/commands-skills.js +2 -2
  146. package/dist/src/gateway/hono/routes/focuses.d.ts +3 -0
  147. package/dist/src/gateway/hono/routes/focuses.js +319 -0
  148. package/dist/src/gateway/hono/routes/home.js +15 -17
  149. package/dist/src/gateway/hono/routes/index.js +2 -0
  150. package/dist/src/gateway/hono/routes/projects.js +2 -103
  151. package/dist/src/gateway/hono/routes/work-discovery.js +0 -239
  152. package/dist/src/gateway/service/marketplace-service.js +1 -1
  153. package/dist/src/gateway/service.d.ts +1 -1
  154. package/dist/src/gateway/service.js +15 -11
  155. package/dist/src/storage/sqlite/migrations/066_first_class_focuses.sql +126 -0
  156. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  157. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  158. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  159. package/dist/src/storage/sqlite/schema.js +1 -1
  160. package/dist/src/work-discovery/index.d.ts +0 -2
  161. package/dist/src/work-discovery/index.js +1 -3
  162. package/dist/src/work-discovery/service.d.ts +0 -30
  163. package/dist/src/work-discovery/service.js +1 -35
  164. package/dist/src/work-discovery/thread-service.d.ts +5 -0
  165. package/dist/src/work-discovery/thread-service.js +36 -88
  166. package/package.json +1 -1
  167. package/skills/tools/find-skills/SKILL.md +18 -428
  168. package/dist/gateway/static/root/assets/agents-Bf_kK2Ay.js +0 -2
  169. package/dist/gateway/static/root/assets/apps-page-DXFCP5-1.js +0 -1
  170. package/dist/gateway/static/root/assets/automations-page-D8pT1o2O.js +0 -6
  171. package/dist/gateway/static/root/assets/browser-settings-page-Bav_skKN.js +0 -8
  172. package/dist/gateway/static/root/assets/capabilities-settings-panel-BHaYYo9E.js +0 -7
  173. package/dist/gateway/static/root/assets/capability-presets-settings-panel-BgchTh81.js +0 -1
  174. package/dist/gateway/static/root/assets/channels-settings-BP0e62wt.js +0 -1
  175. package/dist/gateway/static/root/assets/channels-status-swr-DBWKfeGe.js +0 -1
  176. package/dist/gateway/static/root/assets/connectors-page-CC5kh0de.js +0 -2
  177. package/dist/gateway/static/root/assets/desktop-pet-D-ZUNHhn.js +0 -1
  178. package/dist/gateway/static/root/assets/dreaming-settings-D9i54kWO.js +0 -3
  179. package/dist/gateway/static/root/assets/goal-create-dialog-Dp0AyDHI.js +0 -1
  180. package/dist/gateway/static/root/assets/goal-detail-page-CNt7nrdS.js +0 -4
  181. package/dist/gateway/static/root/assets/goals-page-Bm_NZFiZ.js +0 -2
  182. package/dist/gateway/static/root/assets/index-C_XSKOH6.css +0 -1
  183. package/dist/gateway/static/root/assets/index-DUasAutC.js +0 -212
  184. package/dist/gateway/static/root/assets/local-app-workbench-page-DZwkD1co.js +0 -2
  185. package/dist/gateway/static/root/assets/logs-page-dNL0Y1dA.js +0 -7
  186. package/dist/gateway/static/root/assets/messages-BWtP5TFz.js +0 -3
  187. package/dist/gateway/static/root/assets/notes-workbench-B8MKxpZb.js +0 -4
  188. package/dist/gateway/static/root/assets/project-detail-page-CWBuuX-S.js +0 -1
  189. package/dist/gateway/static/root/assets/projects-page-BJSsLsXH.js +0 -1
  190. package/dist/gateway/static/root/assets/remote-access-hub-DXJDb8vB.js +0 -1
  191. package/dist/gateway/static/root/assets/sessions-page-DeHpWgxM.js +0 -1
  192. package/dist/gateway/static/root/assets/settings-advanced-gate-Cf-TEYUd.js +0 -1
  193. package/dist/gateway/static/root/assets/setup-status-panel-BFyfed_g.js +0 -1
  194. package/dist/gateway/static/root/assets/shares-settings-CYnH9sTt.js +0 -1
  195. package/dist/gateway/static/root/assets/skill-reload-api-Cr8_m-jS.js +0 -1
  196. package/dist/gateway/static/root/assets/skills-page-Chtc1xDO.js +0 -2
  197. package/dist/gateway/static/root/assets/user-context-page-D7qMR26X.js +0 -1
  198. package/dist/gateway/static/root/assets/work-discovery-page-CpqFZze9.js +0 -1
  199. package/dist/gateway/static/root/assets/work-item-detail-page-t4dXpGC0.js +0 -1
  200. package/dist/gateway/static/root/assets/work-page-BXwDKiMZ.js +0 -1
  201. package/dist/gateway/static/root/assets/workflows-page-Bos9HyqT.js +0 -11
  202. package/dist/src/proactive/calendar-signals.d.ts +0 -4
  203. package/dist/src/proactive/calendar-signals.js +0 -120
  204. package/dist/src/proactive/focus-service.d.ts +0 -62
  205. package/dist/src/proactive/focus-service.js +0 -173
  206. package/dist/src/proactive/index.d.ts +0 -7
  207. package/dist/src/proactive/index.js +0 -7
  208. package/dist/src/proactive/insight-repository.d.ts +0 -21
  209. package/dist/src/proactive/insight-repository.js +0 -109
  210. package/dist/src/proactive/run-processor.d.ts +0 -19
  211. package/dist/src/proactive/run-processor.js +0 -146
  212. package/dist/src/proactive/trial-expiry-reconciler.d.ts +0 -5
  213. package/dist/src/proactive/trial-expiry-reconciler.js +0 -30
  214. package/dist/src/proactive/types.d.ts +0 -66
  215. package/dist/src/proactive/value-score.d.ts +0 -13
  216. package/dist/src/proactive/value-score.js +0 -30
  217. package/dist/src/proactive/watch-repository.d.ts +0 -28
  218. package/dist/src/proactive/watch-repository.js +0 -129
  219. package/dist/src/work-discovery/governance.d.ts +0 -25
  220. package/dist/src/work-discovery/governance.js +0 -96
  221. package/dist/src/work-discovery/thread-repository.d.ts +0 -34
  222. package/dist/src/work-discovery/thread-repository.js +0 -112
  223. /package/dist/src/{proactive → focuses}/types.js +0 -0
@@ -0,0 +1,193 @@
1
+ import { searchClawHubFederatedSkills } from "./adapters/clawhub/adapter.js";
2
+ import { listMarketplacePackages } from "../skills-marketplace.js";
3
+ //#region src/agent/skills/marketplace/search.ts
4
+ const SKILL_MARKETPLACE_SEARCH_SOURCES = [
5
+ "store",
6
+ "clawhub",
7
+ "skills-sh"
8
+ ];
9
+ function boundedNumber(value) {
10
+ const parsed = Number(value);
11
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
12
+ }
13
+ function normalizeDate(value) {
14
+ if (value === void 0 || value === null || value === "") return null;
15
+ const numeric = typeof value === "number" ? value : typeof value === "string" && /^\d+(?:\.\d+)?$/.test(value.trim()) ? Number(value) : null;
16
+ const timestamp = numeric !== null && Number.isFinite(numeric) ? Math.abs(numeric) < 0xe8d4a51000 ? numeric * 1e3 : numeric : value;
17
+ const date = new Date(timestamp);
18
+ return Number.isNaN(date.getTime()) ? null : date.toISOString();
19
+ }
20
+ function scannerStatus(value) {
21
+ const normalized = String(value ?? "").trim().toLowerCase();
22
+ if (normalized === "pass") return "pass";
23
+ if (normalized === "warn" || normalized === "warning" || normalized === "review") return "warn";
24
+ if (normalized === "fail" || normalized === "failed" || normalized === "block") return "fail";
25
+ return "unknown";
26
+ }
27
+ function securityFromClawHub(item) {
28
+ const scanners = Object.entries(item.trust?.upstreamScanners ?? {}).map(([name, evidence]) => ({
29
+ name,
30
+ status: scannerStatus(evidence.status),
31
+ checkedAt: normalizeDate(evidence.sourceCheckedAt),
32
+ url: evidence.sourceUrl ?? null
33
+ }));
34
+ const statuses = scanners.map((scanner) => scanner.status);
35
+ return {
36
+ status: statuses.includes("fail") ? "fail" : statuses.includes("warn") ? "warn" : statuses.length > 0 && statuses.every((value) => value === "pass") ? "pass" : scannerStatus(item.trust?.clawHubVerdict),
37
+ scanners
38
+ };
39
+ }
40
+ function absoluteClawHubUrl(value) {
41
+ if (!value) return null;
42
+ try {
43
+ const base = process.env.CLAWHUB_REGISTRY?.trim() || "https://clawhub.ai";
44
+ return new URL(value, base).toString();
45
+ } catch {
46
+ return null;
47
+ }
48
+ }
49
+ function relevanceScore(query, result) {
50
+ const terms = query.toLowerCase().split(/[^a-z0-9]+/).filter((term) => term.length > 1);
51
+ if (terms.length === 0) return 0;
52
+ const name = result.name.toLowerCase();
53
+ const description = result.description.toLowerCase();
54
+ const matched = terms.reduce((score, term) => {
55
+ if (name === term) return score + 3;
56
+ if (name.includes(term)) return score + 2;
57
+ if (description.includes(term)) return score + 1;
58
+ return score;
59
+ }, 0);
60
+ return Math.min(35, Math.round(matched / (terms.length * 3) * 35));
61
+ }
62
+ function valueScore(query, result) {
63
+ const relevance = relevanceScore(query, result);
64
+ const adoption = Math.min(30, Math.log10(result.downloads + 1) * 7);
65
+ const endorsement = Math.min(15, Math.log10(result.stars + 1) * 6);
66
+ const updatedMs = result.updatedAt ? Date.parse(result.updatedAt) : 0;
67
+ const ageDays = updatedMs > 0 ? (Date.now() - updatedMs) / 864e5 : Number.POSITIVE_INFINITY;
68
+ const freshness = ageDays <= 90 ? 15 : ageDays <= 365 ? 10 : ageDays <= 730 ? 5 : 0;
69
+ const provenance = result.canonicalUrl && result.install.reference ? 5 : 0;
70
+ const security = result.security.status === "pass" ? 5 : result.security.status === "warn" ? -20 : result.security.status === "fail" ? -100 : 0;
71
+ return Math.round((relevance + adoption + endorsement + freshness + provenance + security) * 10) / 10;
72
+ }
73
+ function fromClawHub(item) {
74
+ const source = item.source === "skills-sh" ? "skills-sh" : "clawhub";
75
+ const owner = item.publisher?.handle ?? item.sourceIdentity?.owner ?? item.owner?.handle ?? item.ownerHandle ?? source;
76
+ const reference = item.install?.reference ?? (source === "clawhub" && owner !== "clawhub" ? `${owner}/${item.slug}` : item.slug);
77
+ return {
78
+ id: item.id ?? `${source}:${reference}`,
79
+ provider: "clawhub",
80
+ source,
81
+ name: item.displayName || item.slug,
82
+ description: item.summary || "",
83
+ author: owner,
84
+ downloads: boundedNumber(item.downloads ?? item.native?.skill?.stats?.downloads),
85
+ stars: boundedNumber(item.native?.skill?.stats?.stars ?? item.metrics?.bookmarks),
86
+ updatedAt: normalizeDate(item.metrics?.updatedAt ?? item.updatedAt),
87
+ canonicalUrl: absoluteClawHubUrl(item.canonicalUrl ?? item.links?.canonical),
88
+ install: {
89
+ kind: item.install?.kind ?? source,
90
+ reference,
91
+ sourceUrl: item.install?.sourceUrl ?? item.links?.source ?? null
92
+ },
93
+ security: securityFromClawHub(item),
94
+ valueScore: 0
95
+ };
96
+ }
97
+ function dedupeAndRank(query, rows) {
98
+ const unique = /* @__PURE__ */ new Map();
99
+ for (const row of rows) {
100
+ const key = `${row.source}:${row.install.reference || row.id}`.toLowerCase();
101
+ const scored = {
102
+ ...row,
103
+ valueScore: valueScore(query, row)
104
+ };
105
+ const current = unique.get(key);
106
+ if (!current || scored.valueScore > current.valueScore) unique.set(key, scored);
107
+ }
108
+ return [...unique.values()].sort((a, b) => b.valueScore - a.valueScore || b.downloads - a.downloads || a.name.localeCompare(b.name));
109
+ }
110
+ async function searchSkillMarketplaces(params) {
111
+ const requested = new Set(params.sources?.length ? params.sources : SKILL_MARKETPLACE_SEARCH_SOURCES);
112
+ const fetchLimit = Math.min(100, Math.max(params.limit ?? 10, 20));
113
+ const rows = [];
114
+ const statuses = [];
115
+ const jobs = [];
116
+ if (requested.has("store")) jobs.push((async () => {
117
+ try {
118
+ const response = await listMarketplacePackages(params.config, {
119
+ q: params.query,
120
+ page: 1,
121
+ pageSize: fetchLimit,
122
+ sort: "downloads"
123
+ }, "store");
124
+ for (const item of response.items) rows.push({
125
+ id: item.id,
126
+ provider: "store",
127
+ source: "store",
128
+ name: item.name,
129
+ description: item.description,
130
+ author: item.author.username,
131
+ downloads: boundedNumber(item.downloads),
132
+ stars: boundedNumber(item.stars),
133
+ updatedAt: normalizeDate(item.updatedAt),
134
+ canonicalUrl: null,
135
+ install: {
136
+ kind: "store",
137
+ reference: item.name,
138
+ sourceUrl: null
139
+ },
140
+ security: {
141
+ status: "unknown",
142
+ scanners: []
143
+ },
144
+ valueScore: 0
145
+ });
146
+ statuses.push({
147
+ source: "store",
148
+ ok: true,
149
+ count: response.items.length
150
+ });
151
+ } catch (error) {
152
+ statuses.push({
153
+ source: "store",
154
+ ok: false,
155
+ count: 0,
156
+ error: String(error)
157
+ });
158
+ }
159
+ })());
160
+ if (requested.has("clawhub") || requested.has("skills-sh")) jobs.push((async () => {
161
+ try {
162
+ const converted = (await searchClawHubFederatedSkills(params.query, fetchLimit)).results.map(fromClawHub);
163
+ for (const source of ["clawhub", "skills-sh"]) {
164
+ if (!requested.has(source)) continue;
165
+ const matches = converted.filter((row) => row.source === source);
166
+ rows.push(...matches);
167
+ statuses.push({
168
+ source,
169
+ ok: true,
170
+ count: matches.length,
171
+ ...source === "skills-sh" ? { via: "clawhub" } : {}
172
+ });
173
+ }
174
+ } catch (error) {
175
+ for (const source of ["clawhub", "skills-sh"]) if (requested.has(source)) statuses.push({
176
+ source,
177
+ ok: false,
178
+ count: 0,
179
+ error: String(error),
180
+ ...source === "skills-sh" ? { via: "clawhub" } : {}
181
+ });
182
+ }
183
+ })());
184
+ await Promise.all(jobs);
185
+ const limit = Math.min(20, Math.max(1, params.limit ?? 10));
186
+ const orderedStatuses = SKILL_MARKETPLACE_SEARCH_SOURCES.filter((source) => requested.has(source)).map((source) => statuses.find((status) => status.source === source)).filter(Boolean);
187
+ return {
188
+ results: dedupeAndRank(params.query, rows).slice(0, limit),
189
+ sources: orderedStatuses
190
+ };
191
+ }
192
+ //#endregion
193
+ export { SKILL_MARKETPLACE_SEARCH_SOURCES, searchSkillMarketplaces };
@@ -14,7 +14,8 @@ const SKILL_TOOLSET_TOOLS = {
14
14
  "skills_list",
15
15
  "skill_view",
16
16
  "skill_manage"
17
- ]
17
+ ],
18
+ skill_marketplaces: ["skills_marketplace_search"]
18
19
  };
19
20
  function emptyConditions(c) {
20
21
  if (!c) return true;
@@ -28,6 +28,8 @@ const DELEGATE_BLOCKED_TOOLS = new Set([
28
28
  "skills_list",
29
29
  "skill_view",
30
30
  "skill_manage",
31
+ "skills_marketplace_search",
32
+ "skill_install",
31
33
  "bundle-mcp"
32
34
  ]);
33
35
  const DelegateTaskSchema = Type.Object({
@@ -10,7 +10,7 @@ import type { AgentTool } from '@earendil-works/pi-agent-core';
10
10
  import type { Model, Api } from '@earendil-works/pi-ai';
11
11
  import type { Config } from '../../config/schema.js';
12
12
  import type { MessageBus } from '../../infra/bus/index.js';
13
- import { type SkillInstallToolOptions, type SkillInstallToolResult } from './index.js';
13
+ import { type SkillInstallToolOptions, type SkillInstallToolResult, type MarketplaceSkillInstallToolOptions, type MarketplaceSkillInstallToolResult } from './index.js';
14
14
  import type { MemoryManager } from '../memory/manager.js';
15
15
  import type { SessionStore } from '../../session/store.js';
16
16
  import type { GatewayClarifyRequestFn } from './clarify-tool.js';
@@ -70,6 +70,8 @@ export interface ToolFactoryDeps {
70
70
  registerSkillEnvPassthrough?: (names: string[]) => void;
71
71
  /** Install managed skills from explicit sources when a capability/tool enables it. */
72
72
  installSkillFromSource?: (opts: SkillInstallToolOptions) => Promise<SkillInstallToolResult>;
73
+ /** Install a managed skill from a built-in marketplace provider. */
74
+ installSkillFromMarketplace?: (opts: MarketplaceSkillInstallToolOptions) => Promise<MarketplaceSkillInstallToolResult>;
73
75
  /** Workspace-scoped structural code intelligence runtime. */
74
76
  getCodeIntelligenceRuntime?: (workspace: string) => CodeIntelligenceRuntimeLike;
75
77
  }
@@ -86,7 +88,7 @@ export interface CreateCoreToolsOptions {
86
88
  /** Shared user memories directory used for dreaming state (`user/memories`). */
87
89
  dreamingRoot?: string;
88
90
  agentId?: string;
89
- /** When set, registers `skills_list` and `skill_view` bound to this workspace\'s skills. */
91
+ /** When set, registers local skill tools plus marketplace discovery for this workspace. */
90
92
  getSkillManager?: () => SkillManager;
91
93
  }
92
94
  export declare class AgentToolsFactory {
@@ -38,6 +38,7 @@ import { createGoalTool } from "./goal-tool.js";
38
38
  import { createXopcUseTool } from "./xopc-use-tool.js";
39
39
  import { createSkillViewTool, createSkillsListTool } from "./skills-tools.js";
40
40
  import { createSkillManageTool } from "./skill-manage-tool.js";
41
+ import { createSkillsMarketplaceSearchTool } from "./skills-marketplace-search-tool.js";
41
42
  import { createSkillInstallTool } from "./skill-install-tool.js";
42
43
  import { createToolManualTool } from "./tool-manual-tool.js";
43
44
  import { createDesktopPetTool } from "./desktop-pet-tool.js";
@@ -234,6 +235,15 @@ var AgentToolsFactory = class {
234
235
  onSkillsFilesystemMutate: this.deps.onSkillsFilesystemMutate
235
236
  })
236
237
  ] : [],
238
+ createSkillsMarketplaceSearchTool({
239
+ getConfig: () => this.deps.getConfig?.(),
240
+ getSkillManager: getSkillMgr
241
+ }),
242
+ ...this.deps.installSkillFromSource || this.deps.installSkillFromMarketplace ? [createSkillInstallTool({
243
+ installSkillFromSource: this.deps.installSkillFromSource,
244
+ installSkillFromMarketplace: this.deps.installSkillFromMarketplace,
245
+ getSessionKey: () => this.deps.getCurrentContext()?.sessionKey
246
+ })] : [],
237
247
  readTool,
238
248
  ...codeIntelligenceTools,
239
249
  writeTool,
@@ -328,15 +338,11 @@ var AgentToolsFactory = class {
328
338
  if (disabled?.has(toolName) || toolNames.has(toolName)) continue;
329
339
  toolNames.add(toolName);
330
340
  if (toolName === "create_desktop_pet") raw.push(createDesktopPetTool());
331
- if (toolName === "skill_install") raw.push(createSkillInstallTool({
332
- installSkillFromSource: this.deps.installSkillFromSource,
333
- getSessionKey: () => this.deps.getCurrentContext()?.sessionKey
334
- }));
335
341
  }
336
342
  return wrapToolsWithProtection(raw, this.deps.toolExecutorConfig);
337
343
  }
338
344
  getLazyCapabilityToolNames() {
339
- return ["create_desktop_pet", ...this.deps.installSkillFromSource ? ["skill_install"] : []];
345
+ return ["create_desktop_pet"];
340
346
  }
341
347
  createAllTools(coreOptions) {
342
348
  const coreTools = this.createCoreTools(coreOptions);
@@ -32,7 +32,8 @@ export { createGoalTool, type GoalToolOptions } from './goal-tool.js';
32
32
  export { createXopcUseTool, type XopcUseToolDeps, type XopcUseToolInput } from './xopc-use-tool.js';
33
33
  export { createSkillsListTool, createSkillViewTool, type SkillsToolsDeps } from './skills-tools.js';
34
34
  export { createSkillManageTool, type SkillManageToolDeps } from './skill-manage-tool.js';
35
- export { createSkillInstallTool, type SkillInstallToolDeps, type SkillInstallToolOptions, type SkillInstallToolResult, } from './skill-install-tool.js';
35
+ export { createSkillsMarketplaceSearchTool, type SkillsMarketplaceSearchToolDeps, } from './skills-marketplace-search-tool.js';
36
+ export { createSkillInstallTool, type SkillInstallToolDeps, type SkillInstallToolOptions, type SkillInstallToolResult, type MarketplaceSkillInstallToolOptions, type MarketplaceSkillInstallToolResult, } from './skill-install-tool.js';
36
37
  export { createToolManualTool } from './tool-manual-tool.js';
37
38
  export { createDesktopPetTool, type DesktopPetCreateDetails } from './desktop-pet-tool.js';
38
39
  export { createCodeIntelligenceTools } from '../code-intelligence/tools.js';
@@ -36,6 +36,7 @@ import { createGoalTool } from "./goal-tool.js";
36
36
  import { createXopcUseTool } from "./xopc-use-tool.js";
37
37
  import { createSkillViewTool, createSkillsListTool } from "./skills-tools.js";
38
38
  import { createSkillManageTool } from "./skill-manage-tool.js";
39
+ import { createSkillsMarketplaceSearchTool } from "./skills-marketplace-search-tool.js";
39
40
  import { createSkillInstallTool } from "./skill-install-tool.js";
40
41
  import { createToolManualTool } from "./tool-manual-tool.js";
41
42
  import { createDesktopPetTool } from "./desktop-pet-tool.js";
@@ -43,4 +44,4 @@ import { createCodeIntelligenceTools } from "../code-intelligence/tools.js";
43
44
  import { resolveImageModelConfigForTool } from "../image/tool-model-config.js";
44
45
  import { createImageTool } from "./image-tool.js";
45
46
  import { createImageGenerateTool, resolveImageGenerationModelConfigForTool } from "./image-generate-tool.js";
46
- export { BrowserManager, DEFAULT_DELEGATE_TOOLS, DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, DEFAULT_TOOL_METADATA, DEFAULT_WEB_EXTRACT_MAX_LENGTH, DELEGATE_BLOCKED_TOOLS, GREP_MAX_LINE_LENGTH, MAX_RAW_HTML_CHARS_FOR_WEB_EXTRACT, SANDBOX_ALLOWED_TOOLS, TodoStore, ToolConcurrencyController, assertBrowserUrlAllowed, buildSandboxToolMap, createApplyPatchTool, createAutomationTool, createBrowserRecipeTool, createClarifyTool, createCodeIntelligenceTools, createComposioTools, createCreateShareTool, createCuratedMemoryTool, createDelegateTool, createDesktopPetTool, createDreamingTool, createExecCommandTool, createExecuteCodeTool, createFindTool, createGoalTool, createGrepTool, createImageGenerateTool, createImageTool, createListDirTool, createMemoryGetTool, createMemorySearchTool, createMessageTool, createReadFileTool, createReadMediaTool, createSendMediaTool, createSessionSearchTool, createSessionStatusTool, createSkillInstallTool, createSkillManageTool, createSkillViewTool, createSkillsListTool, createTodoTool, createToolManualTool, createUpdatePlanTool, createWebExtractTool, createWebFetchTool, createWebSearchTool, createWorkflowTool, createWriteFileTool, createXopcUseTool, findTool, formatSize, fuzzyFindText, generateDiffString, getToolMetadata, grepTool, isShareToolAvailable, listDirTool, normalizeForFuzzyMatch, normalizeToLF, resolveImageGenerationModelConfigForTool, resolveImageModelConfigForTool, resolveToolLockMode, restoreLineEndings, stripBom, stripHtmlBoilerplate, truncateHead, truncateLine, truncateTail, writeFileTool };
47
+ export { BrowserManager, DEFAULT_DELEGATE_TOOLS, DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, DEFAULT_TOOL_METADATA, DEFAULT_WEB_EXTRACT_MAX_LENGTH, DELEGATE_BLOCKED_TOOLS, GREP_MAX_LINE_LENGTH, MAX_RAW_HTML_CHARS_FOR_WEB_EXTRACT, SANDBOX_ALLOWED_TOOLS, TodoStore, ToolConcurrencyController, assertBrowserUrlAllowed, buildSandboxToolMap, createApplyPatchTool, createAutomationTool, createBrowserRecipeTool, createClarifyTool, createCodeIntelligenceTools, createComposioTools, createCreateShareTool, createCuratedMemoryTool, createDelegateTool, createDesktopPetTool, createDreamingTool, createExecCommandTool, createExecuteCodeTool, createFindTool, createGoalTool, createGrepTool, createImageGenerateTool, createImageTool, createListDirTool, createMemoryGetTool, createMemorySearchTool, createMessageTool, createReadFileTool, createReadMediaTool, createSendMediaTool, createSessionSearchTool, createSessionStatusTool, createSkillInstallTool, createSkillManageTool, createSkillViewTool, createSkillsListTool, createSkillsMarketplaceSearchTool, createTodoTool, createToolManualTool, createUpdatePlanTool, createWebExtractTool, createWebFetchTool, createWebSearchTool, createWorkflowTool, createWriteFileTool, createXopcUseTool, findTool, formatSize, fuzzyFindText, generateDiffString, getToolMetadata, grepTool, isShareToolAvailable, listDirTool, normalizeForFuzzyMatch, normalizeToLF, resolveImageGenerationModelConfigForTool, resolveImageModelConfigForTool, resolveToolLockMode, restoreLineEndings, stripBom, stripHtmlBoilerplate, truncateHead, truncateLine, truncateTail, writeFileTool };
@@ -21,8 +21,25 @@ export interface SkillInstallToolResult {
21
21
  contentHash: string;
22
22
  target?: SkillInstallTarget;
23
23
  }
24
+ export interface MarketplaceSkillInstallToolOptions {
25
+ provider: 'store' | 'clawhub';
26
+ name: string;
27
+ version?: string;
28
+ target?: SkillInstallTarget;
29
+ sessionKey?: string;
30
+ force?: boolean;
31
+ }
32
+ export interface MarketplaceSkillInstallToolResult {
33
+ skillId: string;
34
+ path: string;
35
+ provider: 'store' | 'clawhub';
36
+ name: string;
37
+ version?: string;
38
+ target?: SkillInstallTarget;
39
+ }
24
40
  export interface SkillInstallToolDeps {
25
41
  installSkillFromSource?: (opts: SkillInstallToolOptions) => Promise<SkillInstallToolResult>;
42
+ installSkillFromMarketplace?: (opts: MarketplaceSkillInstallToolOptions) => Promise<MarketplaceSkillInstallToolResult>;
26
43
  getSessionKey?: () => string | undefined;
27
44
  }
28
45
  export declare function createSkillInstallTool(deps: SkillInstallToolDeps): AgentTool;
@@ -2,11 +2,14 @@ import { isSkillInstallTarget } from "../skills/install-target.js";
2
2
  import { Type } from "@sinclair/typebox";
3
3
  //#region src/agent/tools/skill-install-tool.ts
4
4
  const SkillInstallSchema = Type.Object({
5
- source: Type.String({ description: "Explicit skill source: Git URL, GitHub repository URL, https .zip/.tar.gz URL, file:// URL, or local archive/path." }),
5
+ source: Type.Optional(Type.String({ description: "Explicit source install: Git URL, GitHub repository URL, https .zip/.tar.gz URL, file:// URL, or local archive/path." })),
6
+ provider: Type.Optional(Type.Union([Type.Literal("store"), Type.Literal("clawhub")], { description: "Marketplace provider. Use with name; copy it from skills_marketplace_search." })),
7
+ name: Type.Optional(Type.String({ description: "Marketplace package name or install.reference. For ClawHub prefer owner/slug to disambiguate publishers." })),
8
+ version: Type.Optional(Type.String({ description: "Optional marketplace package version." })),
6
9
  ref: Type.Optional(Type.String({ description: "Optional Git branch/tag/ref." })),
7
10
  path: Type.Optional(Type.String({ description: "Optional subdirectory inside the source that contains SKILL.md." })),
8
- skillId: Type.Optional(Type.String({ description: "Optional target managed skill id under the current workspace .xopc/skills." })),
9
- target: Type.Optional(Type.Union([Type.Literal("workspace"), Type.Literal("global")], { description: "Install target. Defaults to workspace. Use global only when the user explicitly asks for a global/personal install." })),
11
+ skillId: Type.Optional(Type.String({ description: "Optional target managed skill id under the selected global or workspace skills root." })),
12
+ target: Type.Optional(Type.Union([Type.Literal("workspace"), Type.Literal("global")], { description: "Install target. Defaults to global (~/.xopc/skills). Use workspace only when the user explicitly asks to scope the skill to the current agent workspace." })),
10
13
  force: Type.Optional(Type.Boolean({ description: "Replace an existing managed skill with the same id." })),
11
14
  strictScan: Type.Optional(Type.Boolean({ description: "Fail when the current scanner reports critical findings." }))
12
15
  });
@@ -17,9 +20,70 @@ function createSkillInstallTool(deps) {
17
20
  return {
18
21
  name: "skill_install",
19
22
  label: "Install skill",
20
- description: "Install an xopc skill from an explicit user-provided source. Use only when the user clearly asks to install or update a skill; do not install from a URL the user merely pasted without installation intent.",
23
+ description: "Install an xopc skill from a Store/ClawHub marketplace result or an explicit source. Use only when the user clearly asks to install or update a skill; never treat search or a pasted URL as installation consent.",
21
24
  parameters: SkillInstallSchema,
22
25
  async execute(_toolCallId, params) {
26
+ const provider = clean(params.provider);
27
+ const name = clean(params.name);
28
+ const target = isSkillInstallTarget(params.target) ? params.target : "global";
29
+ const sessionKey = deps.getSessionKey?.();
30
+ if (provider || name) {
31
+ if (provider !== "store" && provider !== "clawhub") return {
32
+ content: [{
33
+ type: "text",
34
+ text: "Marketplace installs require provider: store or clawhub."
35
+ }],
36
+ details: { errorCode: "missing_provider" }
37
+ };
38
+ if (!name) return {
39
+ content: [{
40
+ type: "text",
41
+ text: "Marketplace installs require name from the search result."
42
+ }],
43
+ details: { errorCode: "missing_name" }
44
+ };
45
+ if (!deps.installSkillFromMarketplace) return {
46
+ content: [{
47
+ type: "text",
48
+ text: "Marketplace skill installation is not available in this runtime context."
49
+ }],
50
+ details: { errorCode: "marketplace_install_unavailable" }
51
+ };
52
+ try {
53
+ const result = await deps.installSkillFromMarketplace({
54
+ provider,
55
+ name,
56
+ version: clean(params.version),
57
+ target,
58
+ sessionKey,
59
+ force: params.force === true
60
+ });
61
+ return {
62
+ content: [{
63
+ type: "text",
64
+ text: [
65
+ `Installed skill "${result.skillId}" from ${result.provider}.`,
66
+ `Package: ${result.name}${result.version ? `@${result.version}` : ""}`,
67
+ `Target: ${result.target ?? target}`,
68
+ `Path: ${result.path}`
69
+ ].join("\n")
70
+ }],
71
+ details: { result }
72
+ };
73
+ } catch (err) {
74
+ const message = err instanceof Error ? err.message : String(err);
75
+ return {
76
+ content: [{
77
+ type: "text",
78
+ text: `Marketplace skill install failed: ${message}`
79
+ }],
80
+ details: {
81
+ errorCode: "install_failed",
82
+ errorMessage: message
83
+ }
84
+ };
85
+ }
86
+ }
23
87
  if (!deps.installSkillFromSource) return {
24
88
  content: [{
25
89
  type: "text",
@@ -41,8 +105,8 @@ function createSkillInstallTool(deps) {
41
105
  ref: clean(params.ref),
42
106
  path: clean(params.path),
43
107
  skillId: clean(params.skillId),
44
- target: isSkillInstallTarget(params.target) ? params.target : void 0,
45
- sessionKey: deps.getSessionKey?.(),
108
+ target,
109
+ sessionKey,
46
110
  force: params.force === true,
47
111
  strictScan: params.strictScan === true
48
112
  });
@@ -51,7 +115,7 @@ function createSkillInstallTool(deps) {
51
115
  type: "text",
52
116
  text: [
53
117
  `Installed skill "${result.skillId}".`,
54
- `Target: ${result.target ?? "workspace"}`,
118
+ `Target: ${result.target ?? target}`,
55
119
  `Source: ${result.source} (${result.kind})`,
56
120
  `Path: ${result.path}`,
57
121
  `Tree hash: ${result.contentHash.slice(0, 16)}`
@@ -72,7 +136,11 @@ function createSkillInstallTool(deps) {
72
136
  }
73
137
  };
74
138
  }
75
- }
139
+ },
140
+ mutatesWorkspace: true,
141
+ mutationScope: "unknown",
142
+ idempotent: false,
143
+ finalGuardRelevant: true
76
144
  };
77
145
  }
78
146
  //#endregion
@@ -0,0 +1,17 @@
1
+ import type { AgentTool } from '@earendil-works/pi-agent-core';
2
+ import type { Config } from '../../config/schema.js';
3
+ import type { SkillManager } from '../skills/skill-manager.js';
4
+ import { searchSkillMarketplaces, type SkillsMarketplaceSearchSource } from '../skills/marketplace/search.js';
5
+ type SearchResponse = Awaited<ReturnType<typeof searchSkillMarketplaces>>;
6
+ export interface SkillsMarketplaceSearchToolDeps {
7
+ getConfig: () => Config | undefined;
8
+ getSkillManager?: () => SkillManager | undefined;
9
+ search?: (params: {
10
+ config: Config;
11
+ query: string;
12
+ sources?: SkillsMarketplaceSearchSource[];
13
+ limit?: number;
14
+ }) => Promise<SearchResponse>;
15
+ }
16
+ export declare function createSkillsMarketplaceSearchTool(deps: SkillsMarketplaceSearchToolDeps): AgentTool;
17
+ export {};
@@ -0,0 +1,77 @@
1
+ import { searchSkillMarketplaces } from "../skills/marketplace/search.js";
2
+ import { Type } from "@sinclair/typebox";
3
+ //#region src/agent/tools/skills-marketplace-search-tool.ts
4
+ const SkillsMarketplaceSearchSchema = Type.Object({
5
+ query: Type.String({
6
+ minLength: 2,
7
+ description: "Capability or task to search for, using concise English keywords when possible"
8
+ }),
9
+ sources: Type.Optional(Type.Array(Type.Union([
10
+ Type.Literal("store"),
11
+ Type.Literal("clawhub"),
12
+ Type.Literal("skills-sh")
13
+ ]), {
14
+ minItems: 1,
15
+ maxItems: 3,
16
+ uniqueItems: true
17
+ })),
18
+ limit: Type.Optional(Type.Integer({
19
+ minimum: 1,
20
+ maximum: 20,
21
+ default: 10
22
+ }))
23
+ });
24
+ function jsonResult(payload) {
25
+ return {
26
+ content: [{
27
+ type: "text",
28
+ text: JSON.stringify(payload, null, 2)
29
+ }],
30
+ details: {}
31
+ };
32
+ }
33
+ function createSkillsMarketplaceSearchTool(deps) {
34
+ return {
35
+ name: "skills_marketplace_search",
36
+ label: "🔎 Find skills",
37
+ description: "Search the XOPC Store, native ClawHub catalog, and skills.sh results federated by ClawHub. Returns normalized provenance, install references, adoption metrics, partial-source errors, and a heuristic value score. Read-only; never installs a skill.",
38
+ parameters: SkillsMarketplaceSearchSchema,
39
+ mutatesWorkspace: false,
40
+ mutationScope: "none",
41
+ supportsParallel: true,
42
+ idempotent: true,
43
+ async execute(_toolCallId, params) {
44
+ const config = deps.getConfig();
45
+ if (!config) return jsonResult({
46
+ success: false,
47
+ error: "XOPC config is not available in this runtime context."
48
+ });
49
+ const query = params.query.trim();
50
+ if (query.length < 2) return jsonResult({
51
+ success: false,
52
+ error: "query must contain at least 2 characters."
53
+ });
54
+ const response = await (deps.search ?? searchSkillMarketplaces)({
55
+ config,
56
+ query,
57
+ sources: params.sources,
58
+ limit: params.limit
59
+ });
60
+ const manager = deps.getSkillManager?.();
61
+ const results = response.results.map((result) => ({
62
+ ...result,
63
+ installed: Boolean(manager?.findSkill(result.name))
64
+ }));
65
+ return jsonResult({
66
+ success: true,
67
+ query,
68
+ scoreIsHeuristic: true,
69
+ sources: response.sources,
70
+ results,
71
+ installationRequiresConfirmation: true
72
+ });
73
+ }
74
+ };
75
+ }
76
+ //#endregion
77
+ export { createSkillsMarketplaceSearchTool };
@@ -11,8 +11,8 @@ import { createReadStream, createWriteStream } from "node:fs";
11
11
  import { spawn } from "node:child_process";
12
12
  import { createHash } from "node:crypto";
13
13
  import { mkdir, mkdtemp, rm, stat } from "node:fs/promises";
14
- import { Readable, Transform } from "node:stream";
15
14
  import AdmZip from "adm-zip";
15
+ import { Readable, Transform } from "node:stream";
16
16
  import { pipeline } from "node:stream/promises";
17
17
  //#region src/browser/providers/cloakbrowser.ts
18
18
  /**
@@ -1,5 +1,5 @@
1
- import { installConnectorDefinition } from "../connectors/install.js";
2
1
  import { downloadConnectorStoreZipBuffer, fetchStoreConnectorPackageDetail, listConnectorPackages, resolveSkillsStoreBaseUrl } from "../agent/skills/marketplace/adapters/store/store-api-client.js";
2
+ import { installConnectorDefinition } from "../connectors/install.js";
3
3
  import { createHash } from "node:crypto";
4
4
  import { isIP } from "node:net";
5
5
  import AdmZip from "adm-zip";
@@ -52,7 +52,7 @@ async function checkDatabaseSchema(ctx) {
52
52
  id: "database-schema",
53
53
  label: "Database schema",
54
54
  status: "pass",
55
- message: `SQLite schema v${status.dbVersion} (current release v65).`,
55
+ message: `SQLite schema v${status.dbVersion} (current release v66).`,
56
56
  hints: []
57
57
  };
58
58
  }
@@ -1,6 +1,6 @@
1
- import { init_agent_scope, normalizeAgentId, resolveAgentWorkspaceDir } from "../agent/agent-scope.js";
2
1
  import { resolveEffectiveAgentManifest } from "../agent-manifest/resolver.js";
3
2
  import "../agent-manifest/index.js";
3
+ import { init_agent_scope, normalizeAgentId, resolveAgentWorkspaceDir } from "../agent/agent-scope.js";
4
4
  import { init_session_key, parseSessionKey } from "../routing/session-key.js";
5
5
  import { agentExists, getDefaultAgentId, init_resolve_route } from "../routing/resolve-route.js";
6
6
  //#region src/config/agent-profile.ts
@@ -1,11 +1,11 @@
1
1
  import { createLogger } from "../utils/logger/index.js";
2
2
  import { init_logger } from "../utils/logger.js";
3
+ import { registerMarketplaceAdapter, unregisterMarketplaceAdapter } from "../agent/skills/marketplace/registry.js";
3
4
  import { registerSpeechProvider } from "../voice/tts/speech-registry.js";
4
5
  import { HOOK_EXECUTION_MODES } from "./types/hooks.js";
5
6
  import { commandRegistry } from "../chat-commands/registry.js";
6
7
  import { TypedEventBus } from "./typed-event-bus.js";
7
8
  import { ExtensionRegistryImpl } from "./extension-registry-impl.js";
8
- import { registerMarketplaceAdapter, unregisterMarketplaceAdapter } from "../agent/skills/marketplace/registry.js";
9
9
  import { registerMediaUnderstandingProvider } from "../media-understanding/registry.js";
10
10
  import { registerMigration } from "../migrations/registry.js";
11
11
  import { isAbsolute, resolve } from "path";
@@ -2,8 +2,8 @@ import { PACKAGE_VERSION, init_package_version } from "../package-version.js";
2
2
  import { createLogger } from "../utils/logger/index.js";
3
3
  import { init_logger } from "../utils/logger.js";
4
4
  import { init_paths, resolveBundledExtensionsDir, resolveExtensionsDir as resolveExtensionsDir$1 } from "../config/paths.js";
5
- import { checkEngineCompatibility } from "./engine-check.js";
6
5
  import { MAX_EXTENSION_STORE_ZIP_BYTES } from "./store-zip-limits.js";
6
+ import { checkEngineCompatibility } from "./engine-check.js";
7
7
  import { collectExtensionPackageDependencyIssues } from "./package-contract.js";
8
8
  import { dirname, isAbsolute, join, resolve, sep } from "path";
9
9
  import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from "fs";
@@ -0,0 +1,15 @@
1
+ import type { FocusCandidate, FocusCandidateStatus, FocusEvidence } from './types.js';
2
+ import type { Focus } from './types.js';
3
+ export declare function getFocusCandidate(id: string): FocusCandidate | null;
4
+ export declare function listFocusCandidates(status?: FocusCandidateStatus, limit?: number): FocusCandidate[];
5
+ export declare function upsertFocusCandidate(input: {
6
+ canonicalKey: string;
7
+ title: string;
8
+ summary: string;
9
+ confidence: number;
10
+ evidence?: FocusEvidence[];
11
+ projectIds?: string[];
12
+ nowMs?: number;
13
+ }): FocusCandidate;
14
+ export declare function setFocusCandidateStatus(id: string, status: FocusCandidateStatus, nowMs?: number): FocusCandidate | null;
15
+ export declare function acceptFocusCandidate(id: string, nowMs?: number): Focus | null;