@nextclaw/service 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (242) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cli/commands/agent/agent-runtime.utils.d.ts +15 -0
  3. package/dist/cli/commands/agent/agent-runtime.utils.js +85 -0
  4. package/dist/cli/commands/agent/cli-agent-runner.utils.d.ts +21 -0
  5. package/dist/cli/commands/agent/cli-agent-runner.utils.js +89 -0
  6. package/dist/cli/commands/agent/index.d.ts +3 -0
  7. package/dist/cli/commands/agent/index.js +3 -0
  8. package/dist/cli/commands/agent/services/agent-commands.service.d.ts +17 -0
  9. package/dist/cli/commands/agent/services/agent-commands.service.js +112 -0
  10. package/dist/cli/commands/companion/index.d.ts +15 -0
  11. package/dist/cli/commands/companion/index.js +24 -0
  12. package/dist/cli/commands/companion/services/companion-process.service.d.ts +17 -0
  13. package/dist/cli/commands/companion/services/companion-process.service.js +49 -0
  14. package/dist/cli/commands/config/index.d.ts +2 -0
  15. package/dist/cli/commands/config/index.js +2 -0
  16. package/dist/cli/commands/config/services/config-commands.service.d.ts +18 -0
  17. package/dist/cli/commands/config/services/config-commands.service.js +133 -0
  18. package/dist/cli/commands/cron/index.d.ts +2 -0
  19. package/dist/cli/commands/cron/index.js +2 -0
  20. package/dist/cli/commands/cron/services/cron-commands.service.d.ts +22 -0
  21. package/dist/cli/commands/cron/services/cron-commands.service.js +107 -0
  22. package/dist/cli/commands/cron/services/cron-local.service.d.ts +25 -0
  23. package/dist/cli/commands/cron/services/cron-local.service.js +95 -0
  24. package/dist/cli/commands/cron/utils/cron-job.utils.d.ts +31 -0
  25. package/dist/cli/commands/cron/utils/cron-job.utils.js +15 -0
  26. package/dist/cli/commands/diagnostics/index.d.ts +2 -0
  27. package/dist/cli/commands/diagnostics/index.js +2 -0
  28. package/dist/cli/commands/diagnostics/services/diagnostics-commands.service.d.ts +22 -0
  29. package/dist/cli/commands/diagnostics/services/diagnostics-commands.service.js +319 -0
  30. package/dist/cli/commands/diagnostics/utils/diagnostics-render.utils.d.ts +23 -0
  31. package/dist/cli/commands/diagnostics/utils/diagnostics-render.utils.js +66 -0
  32. package/dist/cli/commands/gateway/index.d.ts +14 -0
  33. package/dist/cli/commands/gateway/index.js +15 -0
  34. package/dist/cli/commands/logs/index.d.ts +12 -0
  35. package/dist/cli/commands/logs/index.js +29 -0
  36. package/dist/cli/commands/mcp/index.d.ts +14 -0
  37. package/dist/cli/commands/mcp/index.js +193 -0
  38. package/dist/cli/commands/restart/index.d.ts +20 -0
  39. package/dist/cli/commands/restart/index.js +88 -0
  40. package/dist/cli/commands/secrets/index.d.ts +22 -0
  41. package/dist/cli/commands/secrets/index.js +280 -0
  42. package/dist/cli/commands/serve/index.d.ts +14 -0
  43. package/dist/cli/commands/serve/index.js +19 -0
  44. package/dist/cli/commands/skills/index.d.ts +26 -0
  45. package/dist/cli/commands/skills/index.js +147 -0
  46. package/dist/cli/commands/skills/marketplace-client.d.ts +31 -0
  47. package/dist/cli/commands/skills/marketplace-client.js +84 -0
  48. package/dist/cli/commands/skills/marketplace-command-options.utils.d.ts +25 -0
  49. package/dist/cli/commands/skills/marketplace-command-options.utils.js +31 -0
  50. package/dist/cli/commands/skills/marketplace-identity.utils.d.ts +14 -0
  51. package/dist/cli/commands/skills/marketplace-identity.utils.js +77 -0
  52. package/dist/cli/commands/skills/marketplace-network-retry.d.ts +4 -0
  53. package/dist/cli/commands/skills/marketplace-network-retry.js +32 -0
  54. package/dist/cli/commands/skills/marketplace.metadata.d.ts +29 -0
  55. package/dist/cli/commands/skills/marketplace.metadata.js +158 -0
  56. package/dist/cli/commands/skills/marketplace.service.d.ts +46 -0
  57. package/dist/cli/commands/skills/marketplace.service.js +238 -0
  58. package/dist/cli/commands/skills/skills-query.service.d.ts +141 -0
  59. package/dist/cli/commands/skills/skills-query.service.js +212 -0
  60. package/dist/cli/commands/start/index.d.ts +18 -0
  61. package/dist/cli/commands/start/index.js +25 -0
  62. package/dist/cli/commands/stop/index.d.ts +12 -0
  63. package/dist/cli/commands/stop/index.js +11 -0
  64. package/dist/cli/commands/ui/index.d.ts +14 -0
  65. package/dist/cli/commands/ui/index.js +17 -0
  66. package/dist/cli/commands/usage/index.d.ts +2 -0
  67. package/dist/cli/commands/usage/index.js +2 -0
  68. package/dist/cli/commands/usage/services/llm-usage-command.service.d.ts +22 -0
  69. package/dist/cli/commands/usage/services/llm-usage-command.service.js +160 -0
  70. package/dist/cli/commands/usage/services/llm-usage-query.service.d.ts +43 -0
  71. package/dist/cli/commands/usage/services/llm-usage-query.service.js +85 -0
  72. package/dist/commands/channel/channel-config-view.d.ts +7 -0
  73. package/dist/commands/channel/channel-config-view.js +7 -0
  74. package/dist/commands/channel/index.d.ts +28 -0
  75. package/dist/commands/channel/index.js +224 -0
  76. package/dist/commands/platform-auth/index.d.ts +2 -0
  77. package/dist/commands/platform-auth/index.js +2 -0
  78. package/dist/commands/platform-auth/services/account-status.service.d.ts +18 -0
  79. package/dist/commands/platform-auth/services/account-status.service.js +34 -0
  80. package/dist/commands/platform-auth/services/platform-auth-commands.service.d.ts +77 -0
  81. package/dist/commands/platform-auth/services/platform-auth-commands.service.js +295 -0
  82. package/dist/commands/platform-auth/utils/payload.utils.d.ts +28 -0
  83. package/dist/commands/platform-auth/utils/payload.utils.js +87 -0
  84. package/dist/commands/plugin/development-source/dev-plugin-overrides.utils.d.ts +18 -0
  85. package/dist/commands/plugin/development-source/dev-plugin-overrides.utils.js +111 -0
  86. package/dist/commands/plugin/development-source/first-party-plugin-load-paths.d.ts +9 -0
  87. package/dist/commands/plugin/development-source/first-party-plugin-load-paths.js +183 -0
  88. package/dist/commands/plugin/index.d.ts +30 -0
  89. package/dist/commands/plugin/index.js +266 -0
  90. package/dist/commands/plugin/plugin-command-utils.d.ts +13 -0
  91. package/dist/commands/plugin/plugin-command-utils.js +37 -0
  92. package/dist/commands/plugin/plugin-extension-registry.d.ts +10 -0
  93. package/dist/commands/plugin/plugin-extension-registry.js +35 -0
  94. package/dist/commands/plugin/plugin-mutation-actions.d.ts +15 -0
  95. package/dist/commands/plugin/plugin-mutation-actions.js +162 -0
  96. package/dist/commands/plugin/plugin-registry-loader.d.ts +15 -0
  97. package/dist/commands/plugin/plugin-registry-loader.js +43 -0
  98. package/dist/commands/plugin/plugin-reload.d.ts +13 -0
  99. package/dist/commands/plugin/plugin-reload.js +42 -0
  100. package/dist/commands/remote/index.d.ts +47 -0
  101. package/dist/commands/remote/index.js +174 -0
  102. package/dist/commands/remote/services/remote-access-host.service.d.ts +41 -0
  103. package/dist/commands/remote/services/remote-access-host.service.js +126 -0
  104. package/dist/commands/remote/services/remote-runtime-support.service.d.ts +15 -0
  105. package/dist/commands/remote/services/remote-runtime-support.service.js +79 -0
  106. package/dist/commands/remote/services/remote-service-control.service.d.ts +33 -0
  107. package/dist/commands/remote/services/remote-service-control.service.js +188 -0
  108. package/dist/commands/remote/utils/platform-api-base.utils.d.ts +14 -0
  109. package/dist/commands/remote/utils/platform-api-base.utils.js +39 -0
  110. package/dist/commands/service/index.d.ts +16 -0
  111. package/dist/commands/service/index.js +31 -0
  112. package/dist/commands/service/services/autostart/host-autostart-command.service.d.ts +29 -0
  113. package/dist/commands/service/services/autostart/host-autostart-command.service.js +158 -0
  114. package/dist/commands/service/services/autostart/host-autostart-runtime.service.d.ts +23 -0
  115. package/dist/commands/service/services/autostart/host-autostart-runtime.service.js +53 -0
  116. package/dist/commands/service/services/autostart/host-autostart.service.d.ts +41 -0
  117. package/dist/commands/service/services/autostart/host-autostart.service.js +48 -0
  118. package/dist/commands/service/services/autostart/linux-systemd-autostart.service.d.ts +48 -0
  119. package/dist/commands/service/services/autostart/linux-systemd-autostart.service.js +433 -0
  120. package/dist/commands/service/services/autostart/macos-launch-agent-autostart.service.d.ts +54 -0
  121. package/dist/commands/service/services/autostart/macos-launch-agent-autostart.service.js +405 -0
  122. package/dist/commands/service/services/autostart/windows-task-autostart.service.d.ts +54 -0
  123. package/dist/commands/service/services/autostart/windows-task-autostart.service.js +403 -0
  124. package/dist/commands/service/types/autostart/host-autostart.types.d.ts +64 -0
  125. package/dist/commands/service/types/autostart/host-autostart.types.js +1 -0
  126. package/dist/index.d.ts +4 -0
  127. package/dist/index.js +3 -0
  128. package/dist/launcher/npm-runtime-bundle-layout.store.d.ts +23 -0
  129. package/dist/launcher/npm-runtime-bundle-layout.store.js +37 -0
  130. package/dist/launcher/npm-runtime-bundle-manifest.service.d.ts +9 -0
  131. package/dist/launcher/npm-runtime-bundle-manifest.service.js +39 -0
  132. package/dist/launcher/npm-runtime-bundle.service.d.ts +47 -0
  133. package/dist/launcher/npm-runtime-bundle.service.js +150 -0
  134. package/dist/launcher/npm-runtime-bundle.types.d.ts +49 -0
  135. package/dist/launcher/npm-runtime-bundle.types.js +1 -0
  136. package/dist/launcher/npm-runtime-launcher.service.d.ts +19 -0
  137. package/dist/launcher/npm-runtime-launcher.service.js +57 -0
  138. package/dist/launcher/npm-runtime-update-command.service.d.ts +12 -0
  139. package/dist/launcher/npm-runtime-update-command.service.js +87 -0
  140. package/dist/launcher/npm-runtime-update-source.service.d.ts +19 -0
  141. package/dist/launcher/npm-runtime-update-source.service.js +57 -0
  142. package/dist/launcher/npm-runtime-update-state.store.d.ts +17 -0
  143. package/dist/launcher/npm-runtime-update-state.store.js +92 -0
  144. package/dist/launcher/npm-runtime-update.manager.d.ts +42 -0
  145. package/dist/launcher/npm-runtime-update.manager.js +179 -0
  146. package/dist/launcher/npm-runtime-update.service.d.ts +54 -0
  147. package/dist/launcher/npm-runtime-update.service.js +183 -0
  148. package/dist/service-runtime.service.d.ts +91 -0
  149. package/dist/service-runtime.service.js +392 -0
  150. package/dist/shared/controllers/gateway.controller.d.ts +61 -0
  151. package/dist/shared/controllers/gateway.controller.js +318 -0
  152. package/dist/shared/services/extensions/extension-lifecycle.service.d.ts +56 -0
  153. package/dist/shared/services/extensions/extension-lifecycle.service.js +143 -0
  154. package/dist/shared/services/extensions/service-extension-runtime.service.d.ts +51 -0
  155. package/dist/shared/services/extensions/service-extension-runtime.service.js +338 -0
  156. package/dist/shared/services/gateway/cron-job-handler.service.d.ts +26 -0
  157. package/dist/shared/services/gateway/cron-job-handler.service.js +100 -0
  158. package/dist/shared/services/gateway/gateway-restart-wake.service.d.ts +12 -0
  159. package/dist/shared/services/gateway/gateway-restart-wake.service.js +91 -0
  160. package/dist/shared/services/gateway/managers/gateway-plugin.manager.d.ts +37 -0
  161. package/dist/shared/services/gateway/managers/gateway-plugin.manager.js +218 -0
  162. package/dist/shared/services/gateway/managers/gateway-remote.manager.d.ts +20 -0
  163. package/dist/shared/services/gateway/managers/gateway-remote.manager.js +25 -0
  164. package/dist/shared/services/gateway/nextclaw-app.service.d.ts +22 -0
  165. package/dist/shared/services/gateway/nextclaw-app.service.js +53 -0
  166. package/dist/shared/services/gateway/nextclaw-gateway-runtime.service.d.ts +89 -0
  167. package/dist/shared/services/gateway/nextclaw-gateway-runtime.service.js +337 -0
  168. package/dist/shared/services/gateway/service-bootstrap-status.d.ts +33 -0
  169. package/dist/shared/services/gateway/service-bootstrap-status.js +152 -0
  170. package/dist/shared/services/gateway/service-startup-support.service.d.ts +42 -0
  171. package/dist/shared/services/gateway/service-startup-support.service.js +96 -0
  172. package/dist/shared/services/gateway/utils/gateway-runtime-lifecycle.utils.d.ts +9 -0
  173. package/dist/shared/services/gateway/utils/gateway-runtime-lifecycle.utils.js +10 -0
  174. package/dist/shared/services/marketplace/service-marketplace-installer.service.d.ts +31 -0
  175. package/dist/shared/services/marketplace/service-marketplace-installer.service.js +99 -0
  176. package/dist/shared/services/marketplace/service-mcp-marketplace-ops.d.ts +39 -0
  177. package/dist/shared/services/marketplace/service-mcp-marketplace-ops.js +67 -0
  178. package/dist/shared/services/plugin/utils/plugin-dev-hot-reload.utils.d.ts +24 -0
  179. package/dist/shared/services/plugin/utils/plugin-dev-hot-reload.utils.js +117 -0
  180. package/dist/shared/services/plugin/utils/plugin-runtime-bridge.utils.d.ts +6 -0
  181. package/dist/shared/services/plugin/utils/plugin-runtime-bridge.utils.js +96 -0
  182. package/dist/shared/services/restart/restart-coordinator.service.d.ts +30 -0
  183. package/dist/shared/services/restart/restart-coordinator.service.js +51 -0
  184. package/dist/shared/services/restart/restart-sentinel.service.d.ts +39 -0
  185. package/dist/shared/services/restart/restart-sentinel.service.js +88 -0
  186. package/dist/shared/services/restart/runtime-restart-request.service.d.ts +24 -0
  187. package/dist/shared/services/restart/runtime-restart-request.service.js +42 -0
  188. package/dist/shared/services/runtime/runtime-command.service.d.ts +37 -0
  189. package/dist/shared/services/runtime/runtime-command.service.js +163 -0
  190. package/dist/shared/services/runtime/runtime-config-init.service.d.ts +4 -0
  191. package/dist/shared/services/runtime/runtime-config-init.service.js +10 -0
  192. package/dist/shared/services/runtime/service-managed-startup.service.d.ts +146 -0
  193. package/dist/shared/services/runtime/service-managed-startup.service.js +426 -0
  194. package/dist/shared/services/runtime/service-remote-runtime.service.d.ts +53 -0
  195. package/dist/shared/services/runtime/service-remote-runtime.service.js +173 -0
  196. package/dist/shared/services/runtime/utils/skills-loader.utils.d.ts +12 -0
  197. package/dist/shared/services/runtime/utils/skills-loader.utils.js +9 -0
  198. package/dist/shared/services/session/service-deferred-ncp-agent.service.d.ts +14 -0
  199. package/dist/shared/services/session/service-deferred-ncp-agent.service.js +85 -0
  200. package/dist/shared/services/ui/companion-runtime.service.d.ts +33 -0
  201. package/dist/shared/services/ui/companion-runtime.service.js +145 -0
  202. package/dist/shared/services/ui/local-ui-discovery.service.d.ts +19 -0
  203. package/dist/shared/services/ui/local-ui-discovery.service.js +41 -0
  204. package/dist/shared/services/ui/npm-runtime-update-host.service.d.ts +40 -0
  205. package/dist/shared/services/ui/npm-runtime-update-host.service.js +181 -0
  206. package/dist/shared/services/ui/runtime-control-host.service.d.ts +28 -0
  207. package/dist/shared/services/ui/runtime-control-host.service.js +89 -0
  208. package/dist/shared/services/ui/service-remote-access.service.d.ts +25 -0
  209. package/dist/shared/services/ui/service-remote-access.service.js +38 -0
  210. package/dist/shared/services/ui/ui-bridge-api.service.d.ts +16 -0
  211. package/dist/shared/services/ui/ui-bridge-api.service.js +43 -0
  212. package/dist/shared/services/workspace/workspace-manager.service.d.ts +19 -0
  213. package/dist/shared/services/workspace/workspace-manager.service.js +135 -0
  214. package/dist/shared/stores/companion-runtime.store.d.ts +15 -0
  215. package/dist/shared/stores/companion-runtime.store.js +27 -0
  216. package/dist/shared/stores/local-ui-runtime.store.d.ts +25 -0
  217. package/dist/shared/stores/local-ui-runtime.store.js +54 -0
  218. package/dist/shared/stores/managed-service-state.store.d.ts +28 -0
  219. package/dist/shared/stores/managed-service-state.store.js +38 -0
  220. package/dist/shared/stores/pending-restart.store.d.ts +21 -0
  221. package/dist/shared/stores/pending-restart.store.js +35 -0
  222. package/dist/shared/types/cli.types.d.ts +295 -0
  223. package/dist/shared/types/cli.types.js +1 -0
  224. package/dist/shared/utils/cli.utils.d.ts +34 -0
  225. package/dist/shared/utils/cli.utils.js +262 -0
  226. package/dist/shared/utils/config-path.d.ts +15 -0
  227. package/dist/shared/utils/config-path.js +167 -0
  228. package/dist/shared/utils/marketplace/cli-subcommand-launch.utils.d.ts +16 -0
  229. package/dist/shared/utils/marketplace/cli-subcommand-launch.utils.js +46 -0
  230. package/dist/shared/utils/marketplace/service-marketplace-helpers.utils.d.ts +9 -0
  231. package/dist/shared/utils/marketplace/service-marketplace-helpers.utils.js +33 -0
  232. package/dist/shared/utils/package/package-manifest.utils.d.ts +8 -0
  233. package/dist/shared/utils/package/package-manifest.utils.js +48 -0
  234. package/dist/shared/utils/runtime-helpers.d.ts +14 -0
  235. package/dist/shared/utils/runtime-helpers.js +26 -0
  236. package/dist/shared/utils/service-port-probe.utils.d.ts +41 -0
  237. package/dist/shared/utils/service-port-probe.utils.js +164 -0
  238. package/dist/shared/utils/startup-trace.d.ts +7 -0
  239. package/dist/shared/utils/startup-trace.js +37 -0
  240. package/dist/shared/utils/top-level-nextclaw-command-env.utils.d.ts +4 -0
  241. package/dist/shared/utils/top-level-nextclaw-command-env.utils.js +10 -0
  242. package/package.json +68 -0
@@ -0,0 +1,77 @@
1
+ //#region src/cli/commands/skills/marketplace-identity.utils.ts
2
+ function resolvePublishPackageName(params) {
3
+ const { explicitPackageName, explicitScope, slug, adminTokenPresent, currentUser } = params;
4
+ const normalizedExplicitPackageName = explicitPackageName?.trim();
5
+ if (normalizedExplicitPackageName) return resolveExplicitPackageName(normalizedExplicitPackageName, adminTokenPresent, currentUser);
6
+ const normalizedScope = explicitScope?.trim().toLowerCase();
7
+ if (normalizedScope) return resolveScopedPackageName(normalizedScope, slug, adminTokenPresent, currentUser);
8
+ return resolveDefaultPackageName(slug, adminTokenPresent, currentUser);
9
+ }
10
+ function resolveExplicitPackageName(packageName, adminTokenPresent, currentUser) {
11
+ const parsed = parsePackageName(packageName, "packageName");
12
+ if (parsed.scope === "nextclaw") {
13
+ assertOfficialScopeAllowed(adminTokenPresent, currentUser);
14
+ return packageName;
15
+ }
16
+ assertPersonalScopeAllowed(parsed.scope, currentUser);
17
+ return packageName;
18
+ }
19
+ function resolveScopedPackageName(scope, slug, adminTokenPresent, currentUser) {
20
+ if (scope === "nextclaw") {
21
+ assertOfficialScopeAllowed(adminTokenPresent, currentUser);
22
+ return `@nextclaw/${slug}`;
23
+ }
24
+ assertPersonalScopeAllowed(scope, currentUser);
25
+ return `@${scope}/${slug}`;
26
+ }
27
+ function resolveDefaultPackageName(slug, adminTokenPresent, currentUser) {
28
+ if (adminTokenPresent) return `@nextclaw/${slug}`;
29
+ return `@${requirePlatformUsername(currentUser)}/${slug}`;
30
+ }
31
+ function validateSkillSlug(raw, fieldName) {
32
+ if (!/^[A-Za-z0-9._-]+$/.test(raw)) throw new Error(`Invalid ${fieldName}: ${raw}`);
33
+ return raw;
34
+ }
35
+ function validateSkillSelector(raw, fieldName) {
36
+ if (raw.startsWith("@")) {
37
+ parsePackageName(raw, fieldName);
38
+ return raw;
39
+ }
40
+ return validateSkillSlug(raw, fieldName);
41
+ }
42
+ function normalizeTags(rawTags) {
43
+ const seen = /* @__PURE__ */ new Set();
44
+ const output = [];
45
+ for (const rawTag of rawTags ?? []) {
46
+ const tag = rawTag.trim();
47
+ if (!tag || seen.has(tag)) continue;
48
+ seen.add(tag);
49
+ output.push(tag);
50
+ }
51
+ return output.length > 0 ? output : ["skill"];
52
+ }
53
+ function canPublishOfficialScope(adminTokenPresent, currentUser) {
54
+ return adminTokenPresent || currentUser?.user.role === "admin";
55
+ }
56
+ function assertOfficialScopeAllowed(adminTokenPresent, currentUser) {
57
+ if (!canPublishOfficialScope(adminTokenPresent, currentUser)) throw new Error("Publishing to @nextclaw/* requires admin permission.");
58
+ }
59
+ function assertPersonalScopeAllowed(scope, currentUser) {
60
+ const username = requirePlatformUsername(currentUser);
61
+ if (scope !== username) throw new Error(`Personal publish scope must match your username: @${username}/*`);
62
+ }
63
+ function requirePlatformUsername(currentUser) {
64
+ const username = currentUser?.user.username;
65
+ if (!username) throw new Error("Set your NextClaw username before publishing personal skills. Open NextClaw Web account settings: https://platform.nextclaw.io/account or run `nextclaw account set-username <username>`.");
66
+ return username;
67
+ }
68
+ function parsePackageName(raw, fieldName) {
69
+ const match = raw.match(/^@([a-z0-9](?:[a-z0-9-]{1,30}[a-z0-9])?)\/([A-Za-z0-9._-]+)$/);
70
+ if (!match) throw new Error(`Invalid ${fieldName}: ${raw}`);
71
+ return {
72
+ scope: match[1],
73
+ name: match[2]
74
+ };
75
+ }
76
+ //#endregion
77
+ export { normalizeTags, resolvePublishPackageName, validateSkillSelector, validateSkillSlug };
@@ -0,0 +1,4 @@
1
+ //#region src/cli/commands/skills/marketplace-network-retry.d.ts
2
+ declare function runWithMarketplaceNetworkRetry<T>(action: () => Promise<T>): Promise<T>;
3
+ //#endregion
4
+ export { runWithMarketplaceNetworkRetry };
@@ -0,0 +1,32 @@
1
+ //#region src/cli/commands/skills/marketplace-network-retry.ts
2
+ const MARKETPLACE_NETWORK_RETRY_ATTEMPTS = 5;
3
+ const MARKETPLACE_NETWORK_RETRY_BASE_MS = 350;
4
+ function sleepMs(ms) {
5
+ return new Promise((resolve) => {
6
+ setTimeout(resolve, ms);
7
+ });
8
+ }
9
+ function isRetryableMarketplaceNetworkError(error) {
10
+ if (!(error instanceof Error)) return false;
11
+ if (error.name === "AbortError") return false;
12
+ const cause = error.cause;
13
+ if (cause && typeof cause === "object" && cause !== null && "code" in cause) {
14
+ const code = cause.code;
15
+ if (code === "ECONNRESET" || code === "ECONNREFUSED" || code === "ETIMEDOUT" || code === "EPIPE" || code === "ENOTFOUND" || code === "EAI_AGAIN") return true;
16
+ }
17
+ if (error instanceof TypeError && error.message === "fetch failed") return true;
18
+ return false;
19
+ }
20
+ async function runWithMarketplaceNetworkRetry(action) {
21
+ let last;
22
+ for (let attempt = 1; attempt <= MARKETPLACE_NETWORK_RETRY_ATTEMPTS; attempt++) try {
23
+ return await action();
24
+ } catch (error) {
25
+ last = error;
26
+ if (attempt === MARKETPLACE_NETWORK_RETRY_ATTEMPTS || !isRetryableMarketplaceNetworkError(error)) throw error;
27
+ await sleepMs(MARKETPLACE_NETWORK_RETRY_BASE_MS * 2 ** (attempt - 1));
28
+ }
29
+ throw last;
30
+ }
31
+ //#endregion
32
+ export { runWithMarketplaceNetworkRetry };
@@ -0,0 +1,29 @@
1
+ //#region src/cli/commands/skills/marketplace.metadata.d.ts
2
+ type LocalizedTextMap = Record<string, string>;
3
+ type MarketplaceSkillPublishMetadata = {
4
+ slug?: string;
5
+ name?: string;
6
+ summary?: string;
7
+ summaryI18n?: LocalizedTextMap;
8
+ description?: string;
9
+ descriptionI18n?: LocalizedTextMap;
10
+ author?: string;
11
+ tags?: string[];
12
+ sourceRepo?: string;
13
+ homepage?: string;
14
+ publishedAt?: string;
15
+ updatedAt?: string;
16
+ };
17
+ declare function parseSkillFrontmatter(raw: string): {
18
+ name?: string;
19
+ summary?: string;
20
+ summaryI18n?: LocalizedTextMap;
21
+ description?: string;
22
+ descriptionI18n?: LocalizedTextMap;
23
+ author?: string;
24
+ tags?: string[];
25
+ };
26
+ declare function buildLocalizedTextMap(englishText: string, ...maps: Array<LocalizedTextMap | Partial<LocalizedTextMap> | undefined>): LocalizedTextMap;
27
+ declare function readMarketplaceMetadataFile(skillDir: string, explicitMetaFile?: string): MarketplaceSkillPublishMetadata;
28
+ //#endregion
29
+ export { LocalizedTextMap, MarketplaceSkillPublishMetadata, buildLocalizedTextMap, parseSkillFrontmatter, readMarketplaceMetadataFile };
@@ -0,0 +1,158 @@
1
+ import { resolve } from "node:path";
2
+ import { existsSync, readFileSync } from "node:fs";
3
+ import { parse } from "yaml";
4
+ //#region src/cli/commands/skills/marketplace.metadata.ts
5
+ const DEFAULT_MARKETPLACE_META_FILENAME = "marketplace.json";
6
+ function parseSkillFrontmatter(raw) {
7
+ const match = raw.replace(/\r\n/g, "\n").match(/^---\n([\s\S]*?)\n---/);
8
+ if (!match || !match[1]) return {};
9
+ let parsed;
10
+ try {
11
+ parsed = parse(match[1]);
12
+ } catch (error) {
13
+ const message = error instanceof Error ? error.message : String(error);
14
+ throw new Error(`Invalid SKILL.md frontmatter: ${message}`);
15
+ }
16
+ if (!isRecord(parsed)) return {};
17
+ const summaryI18n = readLocalizedTextMapField(parsed, [["summaryi18n"], ["summary_i18n"]]);
18
+ const descriptionI18n = readLocalizedTextMapField(parsed, [["descriptioni18n"], ["description_i18n"]]);
19
+ const summaryZh = readFrontmatterStringField(parsed, [["summaryzh"], ["summary_zh"]]);
20
+ const descriptionZh = readFrontmatterStringField(parsed, [["descriptionzh"], ["description_zh"]]);
21
+ return {
22
+ name: readFrontmatterStringField(parsed, [["name"]]),
23
+ summary: readFrontmatterStringField(parsed, [["summary"]]),
24
+ summaryI18n: mergeLocalizedTextMap(summaryI18n, { zh: summaryZh }),
25
+ description: readFrontmatterStringField(parsed, [["description"]]),
26
+ descriptionI18n: mergeLocalizedTextMap(descriptionI18n, { zh: descriptionZh }),
27
+ author: readFrontmatterStringField(parsed, [["author"]]),
28
+ tags: readFrontmatterTags(parsed)
29
+ };
30
+ }
31
+ function buildLocalizedTextMap(englishText, ...maps) {
32
+ return {
33
+ ...mergeLocalizedTextMap(...maps) ?? {},
34
+ en: englishText
35
+ };
36
+ }
37
+ function readMarketplaceMetadataFile(skillDir, explicitMetaFile) {
38
+ const metadataPath = resolveMarketplaceMetadataPath(skillDir, explicitMetaFile);
39
+ if (!metadataPath) return {};
40
+ let parsed;
41
+ try {
42
+ parsed = JSON.parse(readFileSync(metadataPath, "utf8"));
43
+ } catch (error) {
44
+ const message = error instanceof Error ? error.message : String(error);
45
+ throw new Error(`Invalid marketplace metadata file: ${metadataPath} (${message})`);
46
+ }
47
+ if (!isRecord(parsed)) throw new Error(`Invalid marketplace metadata file: ${metadataPath} (root must be an object)`);
48
+ return {
49
+ slug: readMetadataString(parsed, "slug"),
50
+ name: readMetadataString(parsed, "name"),
51
+ summary: readMetadataString(parsed, "summary"),
52
+ summaryI18n: readMetadataLocalizedTextMap(parsed, "summaryI18n"),
53
+ description: readMetadataString(parsed, "description"),
54
+ descriptionI18n: readMetadataLocalizedTextMap(parsed, "descriptionI18n"),
55
+ author: readMetadataString(parsed, "author"),
56
+ tags: readMetadataStringArray(parsed, "tags"),
57
+ sourceRepo: readMetadataString(parsed, "sourceRepo"),
58
+ homepage: readMetadataString(parsed, "homepage"),
59
+ publishedAt: readMetadataString(parsed, "publishedAt"),
60
+ updatedAt: readMetadataString(parsed, "updatedAt")
61
+ };
62
+ }
63
+ function resolveMarketplaceMetadataPath(skillDir, explicitMetaFile) {
64
+ const resolved = explicitMetaFile?.trim() ? resolve(explicitMetaFile) : resolve(skillDir, DEFAULT_MARKETPLACE_META_FILENAME);
65
+ return existsSync(resolved) ? resolved : void 0;
66
+ }
67
+ function mergeLocalizedTextMap(...maps) {
68
+ const localized = {};
69
+ for (const map of maps) for (const [locale, text] of Object.entries(map ?? {})) {
70
+ const normalizedText = typeof text === "string" ? text.trim() : "";
71
+ if (!normalizedText) continue;
72
+ localized[normalizeLocaleTag(locale)] = normalizedText;
73
+ }
74
+ return Object.keys(localized).length > 0 ? localized : void 0;
75
+ }
76
+ function readMetadataString(record, fieldName) {
77
+ const value = record[fieldName];
78
+ if (value == null) return;
79
+ if (typeof value !== "string") throw new Error(`Invalid marketplace metadata field: ${fieldName} must be a string`);
80
+ return value.trim() || void 0;
81
+ }
82
+ function readMetadataStringArray(record, fieldName) {
83
+ const value = record[fieldName];
84
+ if (value == null) return;
85
+ if (!Array.isArray(value)) throw new Error(`Invalid marketplace metadata field: ${fieldName} must be an array`);
86
+ const tags = value.map((entry, index) => {
87
+ if (typeof entry !== "string") throw new Error(`Invalid marketplace metadata field: ${fieldName}[${index}] must be a string`);
88
+ return entry.trim();
89
+ }).filter(Boolean);
90
+ return tags.length > 0 ? tags : void 0;
91
+ }
92
+ function readMetadataLocalizedTextMap(record, fieldName) {
93
+ const value = record[fieldName];
94
+ if (value == null) return;
95
+ if (!isRecord(value)) throw new Error(`Invalid marketplace metadata field: ${fieldName} must be an object`);
96
+ const localized = {};
97
+ for (const [locale, text] of Object.entries(value)) {
98
+ if (typeof text !== "string") throw new Error(`Invalid marketplace metadata field: ${fieldName}.${locale} must be a string`);
99
+ const normalized = text.trim();
100
+ if (!normalized) continue;
101
+ localized[normalizeLocaleTag(locale)] = normalized;
102
+ }
103
+ return Object.keys(localized).length > 0 ? localized : void 0;
104
+ }
105
+ function readFrontmatterStringField(record, keyPaths) {
106
+ for (const keyPath of keyPaths) {
107
+ const value = readNestedFrontmatterValue(record, keyPath);
108
+ if (typeof value !== "string") continue;
109
+ const normalized = value.trim();
110
+ if (normalized) return normalized;
111
+ }
112
+ }
113
+ function readLocalizedTextMapField(record, keyPaths) {
114
+ for (const keyPath of keyPaths) {
115
+ const value = readNestedFrontmatterValue(record, keyPath);
116
+ if (!isRecord(value)) continue;
117
+ const normalized = {};
118
+ for (const [locale, text] of Object.entries(value)) {
119
+ if (typeof text !== "string") continue;
120
+ const trimmed = text.trim();
121
+ if (!trimmed) continue;
122
+ normalized[normalizeLocaleTag(locale)] = trimmed;
123
+ }
124
+ if (Object.keys(normalized).length > 0) return normalized;
125
+ }
126
+ }
127
+ function readFrontmatterTags(record) {
128
+ const rawTags = readNestedFrontmatterValue(record, ["tags"]);
129
+ if (Array.isArray(rawTags)) {
130
+ const tags = rawTags.filter((entry) => typeof entry === "string").map((entry) => entry.trim()).filter(Boolean);
131
+ return tags.length > 0 ? tags : void 0;
132
+ }
133
+ if (typeof rawTags !== "string") return;
134
+ const tags = rawTags.split(",").map((entry) => entry.trim()).filter(Boolean);
135
+ return tags.length > 0 ? tags : void 0;
136
+ }
137
+ function readNestedFrontmatterValue(record, keyPath) {
138
+ let current = record;
139
+ for (const rawKey of keyPath) {
140
+ if (!isRecord(current)) return;
141
+ const normalizedKey = normalizeFrontmatterKey(rawKey);
142
+ const matchingKey = Object.keys(current).find((candidate) => normalizeFrontmatterKey(candidate) === normalizedKey);
143
+ if (!matchingKey) return;
144
+ current = current[matchingKey];
145
+ }
146
+ return current;
147
+ }
148
+ function normalizeFrontmatterKey(raw) {
149
+ return raw.replace(/[-_]/g, "").toLowerCase();
150
+ }
151
+ function normalizeLocaleTag(raw) {
152
+ return raw.trim().toLowerCase();
153
+ }
154
+ function isRecord(value) {
155
+ return typeof value === "object" && value !== null && !Array.isArray(value);
156
+ }
157
+ //#endregion
158
+ export { buildLocalizedTextMap, parseSkillFrontmatter, readMarketplaceMetadataFile };
@@ -0,0 +1,46 @@
1
+ import { LocalizedTextMap } from "./marketplace.metadata.js";
2
+
3
+ //#region src/cli/commands/skills/marketplace.service.d.ts
4
+ type MarketplaceSkillInstallKind = "builtin" | "marketplace";
5
+ type MarketplaceSkillInstallOptions = {
6
+ slug: string;
7
+ workdir: string;
8
+ dir?: string;
9
+ force?: boolean;
10
+ apiBaseUrl?: string;
11
+ };
12
+ type MarketplaceSkillPublishOptions = {
13
+ skillDir: string;
14
+ metaFile?: string;
15
+ slug?: string;
16
+ packageName?: string;
17
+ scope?: string;
18
+ name?: string;
19
+ summary?: string;
20
+ summaryI18n?: LocalizedTextMap;
21
+ description?: string;
22
+ descriptionI18n?: LocalizedTextMap;
23
+ author?: string;
24
+ tags?: string[];
25
+ sourceRepo?: string;
26
+ homepage?: string;
27
+ publishedAt?: string;
28
+ updatedAt?: string;
29
+ apiBaseUrl?: string;
30
+ token?: string;
31
+ requireExisting?: boolean;
32
+ };
33
+ declare function installMarketplaceSkill(options: MarketplaceSkillInstallOptions): Promise<{
34
+ slug: string;
35
+ destinationDir: string;
36
+ alreadyInstalled?: boolean;
37
+ source: MarketplaceSkillInstallKind;
38
+ }>;
39
+ declare function publishMarketplaceSkill(options: MarketplaceSkillPublishOptions): Promise<{
40
+ created: boolean;
41
+ slug: string;
42
+ packageName: string;
43
+ fileCount: number;
44
+ }>;
45
+ //#endregion
46
+ export { MarketplaceSkillInstallOptions, MarketplaceSkillPublishOptions, installMarketplaceSkill, publishMarketplaceSkill };
@@ -0,0 +1,238 @@
1
+ import { PlatformAuthCommands } from "../../../commands/platform-auth/services/platform-auth-commands.service.js";
2
+ import "../../../commands/platform-auth/index.js";
3
+ import { normalizeTags, resolvePublishPackageName, validateSkillSelector, validateSkillSlug } from "./marketplace-identity.utils.js";
4
+ import { buildLocalizedTextMap, parseSkillFrontmatter, readMarketplaceMetadataFile } from "./marketplace.metadata.js";
5
+ import { runWithMarketplaceNetworkRetry } from "./marketplace-network-retry.js";
6
+ import { fetchMarketplaceSkillFileBlob, fetchMarketplaceSkillFiles, fetchMarketplaceSkillItem, readMarketplaceEnvelope, resolveMarketplaceAdminToken, resolveMarketplaceApiBase } from "./marketplace-client.js";
7
+ import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
8
+ import { SkillsLoader } from "@nextclaw/core";
9
+ import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
10
+ //#region src/cli/commands/skills/marketplace.service.ts
11
+ async function installMarketplaceSkill(options) {
12
+ const { slug, workdir: rawWorkdir, dir, force, apiBaseUrl } = options;
13
+ const selector = validateSkillSelector(slug.trim(), "slug");
14
+ const workdir = resolve(rawWorkdir);
15
+ if (!existsSync(workdir)) throw new Error(`Workdir does not exist: ${workdir}`);
16
+ const apiBase = resolveMarketplaceApiBase(apiBaseUrl);
17
+ const item = await fetchMarketplaceSkillItem(apiBase, selector);
18
+ const installSlug = item.slug;
19
+ const resolvedSlug = item.packageName || item.slug;
20
+ const destinationDir = resolveMarketplaceSkillDestinationDir({
21
+ workdir,
22
+ slug: installSlug,
23
+ dir
24
+ });
25
+ if (item.install.kind === "builtin") {
26
+ const builtinResult = resolveBuiltinMarketplaceInstallResult({
27
+ workdir,
28
+ slug: installSlug
29
+ });
30
+ builtinResult.slug = resolvedSlug;
31
+ return builtinResult;
32
+ }
33
+ const filesPayload = await fetchMarketplaceSkillFiles(apiBase, selector);
34
+ const existingInstall = prepareMarketplaceSkillDestinationDir({
35
+ destinationDir,
36
+ files: filesPayload.files,
37
+ force,
38
+ slug: installSlug
39
+ });
40
+ if (existingInstall) {
41
+ existingInstall.slug = resolvedSlug;
42
+ return existingInstall;
43
+ }
44
+ await writeMarketplaceSkillFiles({
45
+ destinationDir,
46
+ files: filesPayload.files,
47
+ apiBase,
48
+ slug: selector
49
+ });
50
+ ensureInstalledMarketplaceSkill(destinationDir, installSlug);
51
+ return buildMarketplaceInstallResult(resolvedSlug, destinationDir);
52
+ }
53
+ function resolveMarketplaceSkillDestinationDir(params) {
54
+ const { workdir, slug, dir } = params;
55
+ const dirName = dir?.trim() || "skills";
56
+ return isAbsolute(dirName) ? resolve(dirName, slug) : resolve(workdir, dirName, slug);
57
+ }
58
+ function resolveBuiltinMarketplaceInstallResult(params) {
59
+ return {
60
+ slug: params.slug,
61
+ destinationDir: resolveBuiltinSkillDir(params.workdir, params.slug),
62
+ alreadyInstalled: true,
63
+ source: "builtin"
64
+ };
65
+ }
66
+ function prepareMarketplaceSkillDestinationDir(params) {
67
+ const { destinationDir, files, force, slug } = params;
68
+ if (!force && existsSync(destinationDir)) {
69
+ const existingDirState = inspectMarketplaceSkillDirectory(destinationDir, files);
70
+ if (existingDirState === "installed") return {
71
+ slug,
72
+ destinationDir,
73
+ alreadyInstalled: true,
74
+ source: "marketplace"
75
+ };
76
+ if (existingDirState !== "recoverable") throw new Error(`Skill directory already exists: ${destinationDir} (use --force)`);
77
+ rmSync(destinationDir, {
78
+ recursive: true,
79
+ force: true
80
+ });
81
+ }
82
+ if (force && existsSync(destinationDir)) rmSync(destinationDir, {
83
+ recursive: true,
84
+ force: true
85
+ });
86
+ mkdirSync(destinationDir, { recursive: true });
87
+ return null;
88
+ }
89
+ async function writeMarketplaceSkillFiles(params) {
90
+ const { destinationDir, files, apiBase, slug } = params;
91
+ for (const file of files) {
92
+ const targetPath = resolve(destinationDir, ...file.path.split("/"));
93
+ const rel = relative(destinationDir, targetPath);
94
+ if (rel.startsWith("..") || isAbsolute(rel)) throw new Error(`Invalid marketplace file path: ${file.path}`);
95
+ mkdirSync(dirname(targetPath), { recursive: true });
96
+ writeFileSync(targetPath, file.contentBase64 ? decodeMarketplaceFileContent(file.path, file.contentBase64) : await fetchMarketplaceSkillFileBlob(apiBase, slug, file));
97
+ }
98
+ }
99
+ function ensureInstalledMarketplaceSkill(destinationDir, slug) {
100
+ if (!existsSync(join(destinationDir, "SKILL.md"))) throw new Error(`Marketplace skill ${slug} does not include SKILL.md`);
101
+ }
102
+ function buildMarketplaceInstallResult(slug, destinationDir) {
103
+ return {
104
+ slug,
105
+ destinationDir,
106
+ source: "marketplace"
107
+ };
108
+ }
109
+ function inspectMarketplaceSkillDirectory(destinationDir, files) {
110
+ if (existsSync(join(destinationDir, "SKILL.md"))) return "installed";
111
+ const discoveredFiles = collectRelativeFiles(destinationDir);
112
+ if (discoveredFiles === null) return "conflict";
113
+ const relevantFiles = discoveredFiles.filter((file) => !isIgnorableMarketplaceResidue(file));
114
+ if (relevantFiles.length === 0) return "recoverable";
115
+ const manifestPaths = new Set(files.map((file) => normalizeMarketplaceRelativePath(file.path)));
116
+ return relevantFiles.every((file) => manifestPaths.has(normalizeMarketplaceRelativePath(file))) ? "recoverable" : "conflict";
117
+ }
118
+ function collectRelativeFiles(rootDir) {
119
+ const output = [];
120
+ const walk = (dir) => {
121
+ const entries = readdirSync(dir, { withFileTypes: true });
122
+ for (const entry of entries) {
123
+ const absolute = join(dir, entry.name);
124
+ if (entry.isDirectory()) {
125
+ if (!walk(absolute)) return false;
126
+ continue;
127
+ }
128
+ if (!entry.isFile()) return false;
129
+ const relativePath = relative(rootDir, absolute);
130
+ output.push(normalizeMarketplaceRelativePath(relativePath));
131
+ }
132
+ return true;
133
+ };
134
+ return walk(rootDir) ? output : null;
135
+ }
136
+ function normalizeMarketplaceRelativePath(path) {
137
+ return path.replace(/\\/g, "/");
138
+ }
139
+ function isIgnorableMarketplaceResidue(path) {
140
+ return path === ".DS_Store";
141
+ }
142
+ async function publishMarketplaceSkill(options) {
143
+ const { skillDir: rawSkillDir, slug: explicitSlug, metaFile, packageName: explicitPackageName, scope: explicitScope, name: explicitName, summary: explicitSummary, summaryI18n: explicitSummaryI18n, description: explicitDescription, descriptionI18n: explicitDescriptionI18n, tags: explicitTags, sourceRepo: explicitSourceRepo, homepage: explicitHomepage, publishedAt: explicitPublishedAt, updatedAt: explicitUpdatedAt, apiBaseUrl, token: explicitToken, requireExisting } = options;
144
+ const skillDir = resolve(rawSkillDir);
145
+ if (!existsSync(skillDir)) throw new Error(`Skill directory not found: ${skillDir}`);
146
+ const files = collectFiles(skillDir);
147
+ if (!files.some((file) => file.path === "SKILL.md")) throw new Error(`Skill directory must include SKILL.md: ${skillDir}`);
148
+ const parsedFrontmatter = parseSkillFrontmatter(readFileSync(join(skillDir, "SKILL.md"), "utf8"));
149
+ const metadata = readMarketplaceMetadataFile(skillDir, metaFile);
150
+ const slug = validateSkillSlug(explicitSlug?.trim() || metadata.slug || basename(skillDir), "slug");
151
+ const name = explicitName?.trim() || metadata.name || parsedFrontmatter.name || slug;
152
+ const description = explicitDescription?.trim() || metadata.description || metadata.descriptionI18n?.en || parsedFrontmatter.description;
153
+ const summary = explicitSummary?.trim() || metadata.summary || metadata.summaryI18n?.en || parsedFrontmatter.summary || description || `${slug} skill`;
154
+ const summaryI18n = buildLocalizedTextMap(summary, parsedFrontmatter.summaryI18n, metadata.summaryI18n, explicitSummaryI18n);
155
+ const descriptionI18n = description ? buildLocalizedTextMap(description, parsedFrontmatter.descriptionI18n, metadata.descriptionI18n, explicitDescriptionI18n) : void 0;
156
+ const tags = normalizeTags(explicitTags && explicitTags.length > 0 ? explicitTags : metadata.tags ?? parsedFrontmatter.tags);
157
+ const apiBase = resolveMarketplaceApiBase(apiBaseUrl);
158
+ const adminToken = resolveMarketplaceAdminToken(explicitToken);
159
+ const platformAuth = new PlatformAuthCommands();
160
+ const currentUser = adminToken ? null : await platformAuth.me();
161
+ const packageName = resolvePublishPackageName({
162
+ explicitPackageName,
163
+ explicitScope,
164
+ slug,
165
+ adminTokenPresent: Boolean(adminToken),
166
+ currentUser
167
+ });
168
+ const authToken = adminToken ?? currentUser?.token;
169
+ if (!authToken) throw new Error("Publishing requires either a marketplace admin token or an active NextClaw platform login.");
170
+ const response = await runWithMarketplaceNetworkRetry(() => fetch(`${apiBase}/api/v1/skills/publish`, {
171
+ method: "POST",
172
+ headers: {
173
+ "content-type": "application/json",
174
+ Authorization: `Bearer ${authToken}`
175
+ },
176
+ body: JSON.stringify({
177
+ slug,
178
+ packageName,
179
+ name,
180
+ summary,
181
+ summaryI18n,
182
+ description,
183
+ descriptionI18n,
184
+ tags,
185
+ sourceRepo: explicitSourceRepo?.trim() || metadata.sourceRepo,
186
+ homepage: explicitHomepage?.trim() || metadata.homepage,
187
+ publishedAt: explicitPublishedAt?.trim() || metadata.publishedAt,
188
+ updatedAt: explicitUpdatedAt?.trim() || metadata.updatedAt,
189
+ requireExisting,
190
+ files
191
+ })
192
+ }));
193
+ const payload = await readMarketplaceEnvelope(response);
194
+ if (!payload.ok || !payload.data) {
195
+ const message = payload.error?.message || `marketplace publish failed: HTTP ${response.status}`;
196
+ throw new Error(message);
197
+ }
198
+ return {
199
+ created: payload.data.created,
200
+ slug: payload.data.item?.slug || slug,
201
+ packageName: payload.data.item?.packageName || packageName,
202
+ fileCount: payload.data.fileCount
203
+ };
204
+ }
205
+ function collectFiles(rootDir) {
206
+ const output = [];
207
+ const walk = (dir, prefix) => {
208
+ const entries = readdirSync(dir, { withFileTypes: true });
209
+ for (const entry of entries) {
210
+ const absolute = join(dir, entry.name);
211
+ const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
212
+ if (entry.isDirectory()) {
213
+ walk(absolute, relativePath);
214
+ continue;
215
+ }
216
+ if (!entry.isFile()) continue;
217
+ const content = readFileSync(absolute);
218
+ output.push({
219
+ path: relativePath,
220
+ contentBase64: content.toString("base64")
221
+ });
222
+ }
223
+ };
224
+ walk(rootDir, "");
225
+ return output;
226
+ }
227
+ function resolveBuiltinSkillDir(workdir, skillName) {
228
+ const builtinSkill = new SkillsLoader(workdir).listSkills(false).find((skill) => skill.name === skillName && skill.source === "builtin");
229
+ if (!builtinSkill) throw new Error(`Built-in skill not found in local installation: ${skillName}`);
230
+ return dirname(builtinSkill.path);
231
+ }
232
+ function decodeMarketplaceFileContent(path, contentBase64) {
233
+ const normalized = contentBase64.replace(/\s+/g, "");
234
+ if (!normalized || normalized.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(normalized)) throw new Error(`Invalid marketplace file contentBase64 for path: ${path}`);
235
+ return Buffer.from(normalized, "base64");
236
+ }
237
+ //#endregion
238
+ export { installMarketplaceSkill, publishMarketplaceSkill };