@nextclaw/service 0.2.3 → 0.2.5

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 (32) hide show
  1. package/dist/cli/commands/skills/index.d.ts +2 -1
  2. package/dist/cli/commands/skills/index.d.ts.map +1 -1
  3. package/dist/cli/commands/skills/index.js +22 -1
  4. package/dist/cli/commands/skills/index.js.map +1 -1
  5. package/dist/cli/commands/skills/marketplace-client.d.ts +10 -6
  6. package/dist/cli/commands/skills/marketplace-client.d.ts.map +1 -1
  7. package/dist/cli/commands/skills/marketplace-client.js +14 -1
  8. package/dist/cli/commands/skills/marketplace-client.js.map +1 -1
  9. package/dist/cli/commands/skills/marketplace.utils.d.ts +2 -15
  10. package/dist/cli/commands/skills/marketplace.utils.d.ts.map +1 -1
  11. package/dist/cli/commands/skills/marketplace.utils.js +6 -133
  12. package/dist/cli/commands/skills/marketplace.utils.js.map +1 -1
  13. package/dist/cli/commands/skills/stores/marketplace-install-state.store.d.ts +39 -0
  14. package/dist/cli/commands/skills/stores/marketplace-install-state.store.d.ts.map +1 -0
  15. package/dist/cli/commands/skills/stores/marketplace-install-state.store.js +60 -0
  16. package/dist/cli/commands/skills/stores/marketplace-install-state.store.js.map +1 -0
  17. package/dist/cli/commands/skills/utils/marketplace-skill-lifecycle.utils.d.ts +27 -0
  18. package/dist/cli/commands/skills/utils/marketplace-skill-lifecycle.utils.d.ts.map +1 -0
  19. package/dist/cli/commands/skills/utils/marketplace-skill-lifecycle.utils.js +206 -0
  20. package/dist/cli/commands/skills/utils/marketplace-skill-lifecycle.utils.js.map +1 -0
  21. package/dist/index.d.ts +2 -2
  22. package/dist/shared/services/marketplace/service-marketplace-installer.service.d.ts +1 -0
  23. package/dist/shared/services/marketplace/service-marketplace-installer.service.d.ts.map +1 -1
  24. package/dist/shared/services/marketplace/service-marketplace-installer.service.js +24 -11
  25. package/dist/shared/services/marketplace/service-marketplace-installer.service.js.map +1 -1
  26. package/dist/shared/types/cli.types.d.ts +8 -1
  27. package/dist/shared/types/cli.types.d.ts.map +1 -1
  28. package/dist/shared/utils/marketplace/service-marketplace-helpers.utils.d.ts +6 -1
  29. package/dist/shared/utils/marketplace/service-marketplace-helpers.utils.d.ts.map +1 -1
  30. package/dist/shared/utils/marketplace/service-marketplace-helpers.utils.js +13 -1
  31. package/dist/shared/utils/marketplace/service-marketplace-helpers.utils.js.map +1 -1
  32. package/package.json +25 -25
@@ -1,4 +1,4 @@
1
- import { MarketplaceSkillsRecommendCommandOptions, MarketplaceSkillsSearchCommandOptions, SkillsInfoCommandOptions, SkillsInstalledCommandOptions } from "../../../shared/types/cli.types.js";
1
+ import { MarketplaceSkillsRecommendCommandOptions, MarketplaceSkillsSearchCommandOptions, MarketplaceSkillsUpdateCommandOptions, SkillsInfoCommandOptions, SkillsInstalledCommandOptions } from "../../../shared/types/cli.types.js";
2
2
  import { MarketplacePublishCommandOptions } from "./marketplace-command-options.utils.js";
3
3
 
4
4
  //#region src/cli/commands/skills/index.d.ts
@@ -19,6 +19,7 @@ declare class SkillsCommands {
19
19
  json?: boolean;
20
20
  }) => Promise<void>;
21
21
  marketplaceRecommend: (options?: MarketplaceSkillsRecommendCommandOptions) => Promise<void>;
22
+ marketplaceUpdateInstalled: (slug: string, options?: MarketplaceSkillsUpdateCommandOptions) => Promise<void>;
22
23
  publish: (options: MarketplacePublishCommandOptions) => Promise<void>;
23
24
  update: (options: Omit<MarketplacePublishCommandOptions, "publishedAt">) => Promise<void>;
24
25
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../../src/cli/commands/skills/index.ts"],"mappings":";;;;cAWa,cAAA;EAAA,iBACM,kBAAA;EAEjB,SAAA,GAAmB,OAAA,GAAS,6BAAA,KAAqC,OAAA;EAiCjE,IAAA,GAAc,QAAA,UAAkB,OAAA,GAAS,wBAAA,KAAgC,OAAA;EA0BzE,OAAA,GAAiB,OAAA;IACf,IAAA;IACA,OAAA;IACA,GAAA;IACA,KAAA;IACA,UAAA;EAAA,MACE,OAAA;EAuBJ,iBAAA,GAA2B,OAAA,GAAS,qCAAA,KAA6C,OAAA;EA6BjF,eAAA,GAAyB,IAAA,UAAc,OAAA;IAAW,OAAA;IAAkB,IAAA;EAAA,MAAwB,OAAA;EAyB5F,oBAAA,GAA8B,OAAA,GAAS,wCAAA,KAAgD,OAAA;EAqBvF,OAAA,GAAiB,OAAA,EAAS,gCAAA,KAAmC,OAAA;EAK7D,MAAA,GAAgB,OAAA,EAAS,IAAA,CAAK,gCAAA,qBAAmD,OAAA;AAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../../src/cli/commands/skills/index.ts"],"mappings":";;;;cAqBa,cAAA;EAAA,iBACM,kBAAA;EAEjB,SAAA,GAAmB,OAAA,GAAS,6BAAA,KAAqC,OAAA;EAiCjE,IAAA,GAAc,QAAA,UAAkB,OAAA,GAAS,wBAAA,KAAgC,OAAA;EA0BzE,OAAA,GAAiB,OAAA;IACf,IAAA;IACA,OAAA;IACA,GAAA;IACA,KAAA;IACA,UAAA;EAAA,MACE,OAAA;EAuBJ,iBAAA,GAA2B,OAAA,GAAS,qCAAA,KAA6C,OAAA;EA6BjF,eAAA,GAAyB,IAAA,UAAc,OAAA;IAAW,OAAA;IAAkB,IAAA;EAAA,MAAwB,OAAA;EAyB5F,oBAAA,GAA8B,OAAA,GAAS,wCAAA,KAAgD,OAAA;EAqBvF,0BAAA,GACE,IAAA,UACA,OAAA,GAAS,qCAAA,KACR,OAAA;EA2BH,OAAA,GAAiB,OAAA,EAAS,gCAAA,KAAmC,OAAA;EAK7D,MAAA,GAAgB,OAAA,EAAS,IAAA,CAAK,gCAAA,qBAAmD,OAAA;AAAA"}
@@ -1,6 +1,7 @@
1
1
  import { resolveSkillsInstallWorkdir } from "../../../shared/utils/runtime-helpers.js";
2
2
  import { buildMarketplacePublishOptions, buildMarketplaceUpdateOptions } from "./marketplace-command-options.utils.js";
3
- import { installMarketplaceSkill, publishMarketplaceSkill } from "./marketplace.utils.js";
3
+ import { installMarketplaceSkill, updateInstalledMarketplaceSkill } from "./utils/marketplace-skill-lifecycle.utils.js";
4
+ import { publishMarketplaceSkill } from "./marketplace.utils.js";
4
5
  import { SkillsQueryService } from "./skills-query.service.js";
5
6
  import { loadConfig } from "@nextclaw/core";
6
7
  //#region src/cli/commands/skills/index.ts
@@ -132,6 +133,26 @@ var SkillsCommands = class {
132
133
  if (result.description) console.log(` ${result.description}`);
133
134
  for (const item of result.items) console.log(`- ${item.name} (${item.slug})`);
134
135
  };
136
+ marketplaceUpdateInstalled = async (slug, options = {}) => {
137
+ const config = loadConfig();
138
+ const result = await updateInstalledMarketplaceSkill({
139
+ slug,
140
+ workdir: resolveSkillsInstallWorkdir({
141
+ explicitWorkdir: options.workdir,
142
+ configuredWorkspace: config.agents.defaults.workspace
143
+ }),
144
+ dir: options.dir,
145
+ force: options.force,
146
+ apiBaseUrl: options.apiBase
147
+ });
148
+ if (options.json) {
149
+ console.log(JSON.stringify(result, null, 2));
150
+ return;
151
+ }
152
+ if (result.updated) console.log(`✓ Updated ${result.slug}`);
153
+ else console.log(`✓ ${result.slug} is already up to date`);
154
+ console.log(` Path: ${result.destinationDir}`);
155
+ };
135
156
  publish = async (options) => {
136
157
  const result = await publishMarketplaceSkill(buildMarketplacePublishOptions(options));
137
158
  console.log(`${result.created ? `✓ Published new skill: ${result.packageName}` : `✓ Updated skill: ${result.packageName}`}\n Alias: ${result.slug}\n Files: ${result.fileCount}`);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/cli/commands/skills/index.ts"],"sourcesContent":["import { loadConfig } from \"@nextclaw/core\";\nimport { resolveSkillsInstallWorkdir } from \"@nextclaw-service/shared/utils/runtime-helpers.js\";\nimport {\n buildMarketplacePublishOptions,\n buildMarketplaceUpdateOptions,\n type MarketplacePublishCommandOptions,\n} from \"./marketplace-command-options.utils.js\";\nimport { installMarketplaceSkill, publishMarketplaceSkill } from \"./marketplace.utils.js\";\nimport { SkillsQueryService } from \"./skills-query.service.js\";\nimport type { MarketplaceSkillsRecommendCommandOptions, MarketplaceSkillsSearchCommandOptions, SkillsInfoCommandOptions, SkillsInstalledCommandOptions } from \"@nextclaw-service/shared/types/cli.types.js\";\n\nexport class SkillsCommands {\n private readonly skillsQueryService = new SkillsQueryService();\n\n installed = async (options: SkillsInstalledCommandOptions = {}): Promise<void> => {\n const config = loadConfig();\n const workdir = resolveSkillsInstallWorkdir({\n explicitWorkdir: options.workdir,\n configuredWorkspace: config.agents.defaults.workspace,\n });\n const result = this.skillsQueryService.listInstalled({\n workdir,\n scope: options.scope,\n query: options.query,\n });\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n if (result.skills.length === 0) {\n console.log(\"No installed skills found.\");\n return;\n }\n\n for (const skill of result.skills) {\n console.log(`${skill.name} (${skill.scope})`);\n console.log(` ref: ${skill.ref}`);\n console.log(` path: ${skill.path}`);\n console.log(` summary: ${skill.summary ?? \"-\"}`);\n console.log(` description: ${skill.description ?? \"-\"}`);\n console.log(` tags: ${skill.tags.join(\", \") || \"-\"}`);\n console.log(` always: ${skill.always ? \"yes\" : \"no\"}`);\n }\n };\n\n info = async (selector: string, options: SkillsInfoCommandOptions = {}): Promise<void> => {\n const config = loadConfig();\n const workdir = resolveSkillsInstallWorkdir({\n explicitWorkdir: options.workdir,\n configuredWorkspace: config.agents.defaults.workspace,\n });\n const result = this.skillsQueryService.getInstalledInfo({\n workdir,\n selector,\n });\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n console.log(`${result.name} (${result.scope})`);\n console.log(` ref: ${result.ref}`);\n console.log(` path: ${result.path}`);\n console.log(` summary: ${result.summary ?? \"-\"}`);\n console.log(` description: ${result.description ?? \"-\"}`);\n console.log(` author: ${result.author ?? \"-\"}`);\n console.log(` tags: ${result.tags.join(\", \") || \"-\"}`);\n console.log(` always: ${result.always ? \"yes\" : \"no\"}`);\n };\n\n install = async (options: {\n slug: string;\n workdir?: string;\n dir?: string;\n force?: boolean;\n apiBaseUrl?: string;\n }): Promise<void> => {\n const { apiBaseUrl, dir, force, slug, workdir: explicitWorkdir } = options;\n const config = loadConfig();\n const workdir = resolveSkillsInstallWorkdir({\n explicitWorkdir,\n configuredWorkspace: config.agents.defaults.workspace,\n });\n const result = await installMarketplaceSkill({\n slug,\n workdir,\n dir,\n force,\n apiBaseUrl,\n });\n\n if (result.alreadyInstalled) {\n console.log(`✓ ${result.slug} is already installed`);\n } else {\n console.log(`✓ Installed ${result.slug} (${result.source})`);\n }\n console.log(` Path: ${result.destinationDir}`);\n };\n\n marketplaceSearch = async (options: MarketplaceSkillsSearchCommandOptions = {}): Promise<void> => {\n const result = await this.skillsQueryService.searchMarketplaceSkills({\n apiBaseUrl: options.apiBase,\n query: options.query,\n tag: options.tag,\n sort: options.sort,\n page: options.page,\n pageSize: options.pageSize,\n });\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n if (result.items.length === 0) {\n console.log(\"No marketplace skills found.\");\n return;\n }\n\n for (const item of result.items) {\n console.log(`${item.name} (${item.slug})`);\n console.log(` summary: ${item.summary}`);\n console.log(` author: ${item.author}`);\n console.log(` tags: ${item.tags.join(\", \") || \"-\"}`);\n console.log(` install: ${item.install.command}`);\n }\n };\n\n marketplaceInfo = async (slug: string, options: { apiBase?: string; json?: boolean } = {}): Promise<void> => {\n const result = await this.skillsQueryService.getMarketplaceSkillInfo({\n apiBaseUrl: options.apiBase,\n slug,\n });\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n console.log(`${result.item.name} (${result.item.slug})`);\n console.log(` summary: ${result.item.summary}`);\n console.log(` description: ${result.item.description ?? \"-\"}`);\n console.log(` author: ${result.item.author}`);\n console.log(` tags: ${result.item.tags.join(\", \") || \"-\"}`);\n console.log(` install: ${result.item.install.command}`);\n console.log(` content: ${result.content ? \"available\" : \"unavailable\"}`);\n if (result.content) {\n console.log(` source: ${result.content.source}`);\n } else if (result.contentUnavailableReason) {\n console.log(` reason: ${result.contentUnavailableReason}`);\n }\n };\n\n marketplaceRecommend = async (options: MarketplaceSkillsRecommendCommandOptions = {}): Promise<void> => {\n const result = await this.skillsQueryService.recommendMarketplaceSkills({\n apiBaseUrl: options.apiBase,\n scene: options.scene,\n limit: options.limit,\n });\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n console.log(`${result.title} (${result.sceneId})`);\n if (result.description) {\n console.log(` ${result.description}`);\n }\n for (const item of result.items) {\n console.log(`- ${item.name} (${item.slug})`);\n }\n };\n\n publish = async (options: MarketplacePublishCommandOptions): Promise<void> => {\n const result = await publishMarketplaceSkill(buildMarketplacePublishOptions(options));\n console.log(`${result.created ? `✓ Published new skill: ${result.packageName}` : `✓ Updated skill: ${result.packageName}`}\\n Alias: ${result.slug}\\n Files: ${result.fileCount}`);\n };\n\n update = async (options: Omit<MarketplacePublishCommandOptions, \"publishedAt\">): Promise<void> => {\n const result = await publishMarketplaceSkill(buildMarketplaceUpdateOptions(options));\n console.log(`✓ Updated skill: ${result.packageName}`);\n console.log(` Alias: ${result.slug}`);\n console.log(` Files: ${result.fileCount}`);\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/cli/commands/skills/index.ts"],"sourcesContent":["import { loadConfig } from \"@nextclaw/core\";\nimport { resolveSkillsInstallWorkdir } from \"@nextclaw-service/shared/utils/runtime-helpers.js\";\nimport {\n buildMarketplacePublishOptions,\n buildMarketplaceUpdateOptions,\n type MarketplacePublishCommandOptions,\n} from \"./marketplace-command-options.utils.js\";\nimport {\n installMarketplaceSkill,\n publishMarketplaceSkill,\n updateInstalledMarketplaceSkill\n} from \"./marketplace.utils.js\";\nimport { SkillsQueryService } from \"./skills-query.service.js\";\nimport type {\n MarketplaceSkillsRecommendCommandOptions,\n MarketplaceSkillsSearchCommandOptions,\n MarketplaceSkillsUpdateCommandOptions,\n SkillsInfoCommandOptions,\n SkillsInstalledCommandOptions\n} from \"@nextclaw-service/shared/types/cli.types.js\";\n\nexport class SkillsCommands {\n private readonly skillsQueryService = new SkillsQueryService();\n\n installed = async (options: SkillsInstalledCommandOptions = {}): Promise<void> => {\n const config = loadConfig();\n const workdir = resolveSkillsInstallWorkdir({\n explicitWorkdir: options.workdir,\n configuredWorkspace: config.agents.defaults.workspace,\n });\n const result = this.skillsQueryService.listInstalled({\n workdir,\n scope: options.scope,\n query: options.query,\n });\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n if (result.skills.length === 0) {\n console.log(\"No installed skills found.\");\n return;\n }\n\n for (const skill of result.skills) {\n console.log(`${skill.name} (${skill.scope})`);\n console.log(` ref: ${skill.ref}`);\n console.log(` path: ${skill.path}`);\n console.log(` summary: ${skill.summary ?? \"-\"}`);\n console.log(` description: ${skill.description ?? \"-\"}`);\n console.log(` tags: ${skill.tags.join(\", \") || \"-\"}`);\n console.log(` always: ${skill.always ? \"yes\" : \"no\"}`);\n }\n };\n\n info = async (selector: string, options: SkillsInfoCommandOptions = {}): Promise<void> => {\n const config = loadConfig();\n const workdir = resolveSkillsInstallWorkdir({\n explicitWorkdir: options.workdir,\n configuredWorkspace: config.agents.defaults.workspace,\n });\n const result = this.skillsQueryService.getInstalledInfo({\n workdir,\n selector,\n });\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n console.log(`${result.name} (${result.scope})`);\n console.log(` ref: ${result.ref}`);\n console.log(` path: ${result.path}`);\n console.log(` summary: ${result.summary ?? \"-\"}`);\n console.log(` description: ${result.description ?? \"-\"}`);\n console.log(` author: ${result.author ?? \"-\"}`);\n console.log(` tags: ${result.tags.join(\", \") || \"-\"}`);\n console.log(` always: ${result.always ? \"yes\" : \"no\"}`);\n };\n\n install = async (options: {\n slug: string;\n workdir?: string;\n dir?: string;\n force?: boolean;\n apiBaseUrl?: string;\n }): Promise<void> => {\n const { apiBaseUrl, dir, force, slug, workdir: explicitWorkdir } = options;\n const config = loadConfig();\n const workdir = resolveSkillsInstallWorkdir({\n explicitWorkdir,\n configuredWorkspace: config.agents.defaults.workspace,\n });\n const result = await installMarketplaceSkill({\n slug,\n workdir,\n dir,\n force,\n apiBaseUrl,\n });\n\n if (result.alreadyInstalled) {\n console.log(`✓ ${result.slug} is already installed`);\n } else {\n console.log(`✓ Installed ${result.slug} (${result.source})`);\n }\n console.log(` Path: ${result.destinationDir}`);\n };\n\n marketplaceSearch = async (options: MarketplaceSkillsSearchCommandOptions = {}): Promise<void> => {\n const result = await this.skillsQueryService.searchMarketplaceSkills({\n apiBaseUrl: options.apiBase,\n query: options.query,\n tag: options.tag,\n sort: options.sort,\n page: options.page,\n pageSize: options.pageSize,\n });\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n if (result.items.length === 0) {\n console.log(\"No marketplace skills found.\");\n return;\n }\n\n for (const item of result.items) {\n console.log(`${item.name} (${item.slug})`);\n console.log(` summary: ${item.summary}`);\n console.log(` author: ${item.author}`);\n console.log(` tags: ${item.tags.join(\", \") || \"-\"}`);\n console.log(` install: ${item.install.command}`);\n }\n };\n\n marketplaceInfo = async (slug: string, options: { apiBase?: string; json?: boolean } = {}): Promise<void> => {\n const result = await this.skillsQueryService.getMarketplaceSkillInfo({\n apiBaseUrl: options.apiBase,\n slug,\n });\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n console.log(`${result.item.name} (${result.item.slug})`);\n console.log(` summary: ${result.item.summary}`);\n console.log(` description: ${result.item.description ?? \"-\"}`);\n console.log(` author: ${result.item.author}`);\n console.log(` tags: ${result.item.tags.join(\", \") || \"-\"}`);\n console.log(` install: ${result.item.install.command}`);\n console.log(` content: ${result.content ? \"available\" : \"unavailable\"}`);\n if (result.content) {\n console.log(` source: ${result.content.source}`);\n } else if (result.contentUnavailableReason) {\n console.log(` reason: ${result.contentUnavailableReason}`);\n }\n };\n\n marketplaceRecommend = async (options: MarketplaceSkillsRecommendCommandOptions = {}): Promise<void> => {\n const result = await this.skillsQueryService.recommendMarketplaceSkills({\n apiBaseUrl: options.apiBase,\n scene: options.scene,\n limit: options.limit,\n });\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n console.log(`${result.title} (${result.sceneId})`);\n if (result.description) {\n console.log(` ${result.description}`);\n }\n for (const item of result.items) {\n console.log(`- ${item.name} (${item.slug})`);\n }\n };\n\n marketplaceUpdateInstalled = async (\n slug: string,\n options: MarketplaceSkillsUpdateCommandOptions = {}\n ): Promise<void> => {\n const config = loadConfig();\n const workdir = resolveSkillsInstallWorkdir({\n explicitWorkdir: options.workdir,\n configuredWorkspace: config.agents.defaults.workspace,\n });\n const result = await updateInstalledMarketplaceSkill({\n slug,\n workdir,\n dir: options.dir,\n force: options.force,\n apiBaseUrl: options.apiBase,\n });\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n if (result.updated) {\n console.log(`✓ Updated ${result.slug}`);\n } else {\n console.log(`✓ ${result.slug} is already up to date`);\n }\n console.log(` Path: ${result.destinationDir}`);\n };\n\n publish = async (options: MarketplacePublishCommandOptions): Promise<void> => {\n const result = await publishMarketplaceSkill(buildMarketplacePublishOptions(options));\n console.log(`${result.created ? `✓ Published new skill: ${result.packageName}` : `✓ Updated skill: ${result.packageName}`}\\n Alias: ${result.slug}\\n Files: ${result.fileCount}`);\n };\n\n update = async (options: Omit<MarketplacePublishCommandOptions, \"publishedAt\">): Promise<void> => {\n const result = await publishMarketplaceSkill(buildMarketplaceUpdateOptions(options));\n console.log(`✓ Updated skill: ${result.packageName}`);\n console.log(` Alias: ${result.slug}`);\n console.log(` Files: ${result.fileCount}`);\n };\n}\n"],"mappings":"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"}
@@ -1,3 +1,5 @@
1
+ import { MarketplaceSkillInstallStateFileEntry } from "./stores/marketplace-install-state.store.js";
2
+
1
3
  //#region src/cli/commands/skills/marketplace-client.d.ts
2
4
  type MarketplaceEnvelope<T> = {
3
5
  ok: boolean;
@@ -13,15 +15,17 @@ type MarketplaceSkillFileManifestEntry = {
13
15
  downloadPath?: string;
14
16
  contentBase64?: string;
15
17
  };
16
- declare function resolveMarketplaceApiBase(explicitBase: string | undefined): string;
17
- declare function resolveMarketplaceAdminToken(explicitToken: string | undefined): string | undefined;
18
- declare function fetchMarketplaceSkillItem(apiBase: string, slug: string): Promise<{
18
+ type MarketplaceSkillItem = {
19
19
  slug: string;
20
20
  packageName?: string;
21
+ updatedAt?: string;
21
22
  install: {
22
23
  kind: MarketplaceSkillInstallKind;
23
24
  };
24
- }>;
25
+ };
26
+ declare function resolveMarketplaceApiBase(explicitBase: string | undefined): string;
27
+ declare function resolveMarketplaceAdminToken(explicitToken: string | undefined): string | undefined;
28
+ declare function fetchMarketplaceSkillItem(apiBase: string, slug: string): Promise<MarketplaceSkillItem>;
25
29
  declare function fetchMarketplaceSkillFiles(apiBase: string, slug: string): Promise<{
26
30
  files: MarketplaceSkillFileManifestEntry[];
27
31
  }>;
@@ -35,8 +39,8 @@ declare function writeMarketplaceSkillFiles(params: {
35
39
  files: MarketplaceSkillFileManifestEntry[];
36
40
  apiBase: string;
37
41
  slug: string;
38
- }): Promise<void>;
42
+ }): Promise<MarketplaceSkillInstallStateFileEntry[]>;
39
43
  declare function readMarketplaceEnvelope<T>(response: Response): Promise<MarketplaceEnvelope<T>>;
40
44
  //#endregion
41
- export { MarketplaceSkillFileManifestEntry, collectMarketplaceSkillFiles, fetchMarketplaceSkillFileBlob, fetchMarketplaceSkillFiles, fetchMarketplaceSkillItem, readMarketplaceEnvelope, resolveMarketplaceAdminToken, resolveMarketplaceApiBase, writeMarketplaceSkillFiles };
45
+ export { MarketplaceSkillFileManifestEntry, MarketplaceSkillItem, collectMarketplaceSkillFiles, fetchMarketplaceSkillFileBlob, fetchMarketplaceSkillFiles, fetchMarketplaceSkillItem, readMarketplaceEnvelope, resolveMarketplaceAdminToken, resolveMarketplaceApiBase, writeMarketplaceSkillFiles };
42
46
  //# sourceMappingURL=marketplace-client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"marketplace-client.d.ts","names":[],"sources":["../../../../src/cli/commands/skills/marketplace-client.ts"],"mappings":";KAMK,mBAAA;EACH,EAAA;EACA,IAAA,GAAO,CAAA;EACP,KAAA;IACE,IAAA;IACA,OAAA;EAAA;AAAA;AAAA,KAIC,2BAAA;AAAA,KAEO,iCAAA;EACV,IAAA;EACA,YAAA;EACA,aAAA;AAAA;AAAA,iBAGc,yBAAA,CAA0B,YAAA;AAAA,iBAO1B,4BAAA,CAA6B,aAAA;AAAA,iBAKvB,yBAAA,CACpB,OAAA,UACA,IAAA,WACC,OAAA;EAAU,IAAA;EAAc,WAAA;EAAsB,OAAA;IAAW,IAAA,EAAM,2BAAA;EAAA;AAAA;AAAA,iBAqC5C,0BAAA,CACpB,OAAA,UACA,IAAA,WACC,OAAA;EAAU,KAAA,EAAO,iCAAA;AAAA;AAAA,iBAsCE,6BAAA,CACpB,OAAA,UACA,IAAA,UACA,IAAA,EAAM,iCAAA,GACL,OAAA,CAAQ,MAAA;AAAA,iBAiBK,4BAAA,CAA6B,OAAA,WAAkB,KAAA;EAAQ,IAAA;EAAc,aAAA;AAAA;AAAA,iBA0B/D,0BAAA,CAA2B,MAAA;EAC/C,cAAA;EACA,KAAA,EAAO,iCAAA;EACP,OAAA;EACA,IAAA;AAAA,IACE,OAAA;AAAA,iBAiBkB,uBAAA,GAAA,CAA2B,QAAA,EAAU,QAAA,GAAW,OAAA,CAAQ,mBAAA,CAAoB,CAAA"}
1
+ {"version":3,"file":"marketplace-client.d.ts","names":[],"sources":["../../../../src/cli/commands/skills/marketplace-client.ts"],"mappings":";;;KAWK,mBAAA;EACH,EAAA;EACA,IAAA,GAAO,CAAA;EACP,KAAA;IACE,IAAA;IACA,OAAA;EAAA;AAAA;AAAA,KAIC,2BAAA;AAAA,KAEO,iCAAA;EACV,IAAA;EACA,YAAA;EACA,aAAA;AAAA;AAAA,KAGU,oBAAA;EACV,IAAA;EACA,WAAA;EACA,SAAA;EACA,OAAA;IAAW,IAAA,EAAM,2BAAA;EAAA;AAAA;AAAA,iBAGH,yBAAA,CAA0B,YAAA;AAAA,iBAO1B,4BAAA,CAA6B,aAAA;AAAA,iBAKvB,yBAAA,CACpB,OAAA,UACA,IAAA,WACC,OAAA,CAAQ,oBAAA;AAAA,iBAyCW,0BAAA,CACpB,OAAA,UACA,IAAA,WACC,OAAA;EAAU,KAAA,EAAO,iCAAA;AAAA;AAAA,iBAsCE,6BAAA,CACpB,OAAA,UACA,IAAA,UACA,IAAA,EAAM,iCAAA,GACL,OAAA,CAAQ,MAAA;AAAA,iBAiBK,4BAAA,CAA6B,OAAA,WAAkB,KAAA;EAAQ,IAAA;EAAc,aAAA;AAAA;AAAA,iBA6B/D,0BAAA,CAA2B,MAAA;EAC/C,cAAA;EACA,KAAA,EAAO,iCAAA;EACP,OAAA;EACA,IAAA;AAAA,IACE,OAAA,CAAQ,qCAAA;AAAA,iBAuBU,uBAAA,GAAA,CAA2B,QAAA,EAAU,QAAA,GAAW,OAAA,CAAQ,mBAAA,CAAoB,CAAA"}
@@ -1,4 +1,5 @@
1
1
  import { runWithMarketplaceNetworkRetry } from "./marketplace-network-retry.js";
2
+ import { hashMarketplaceFileBytes, isLocalMarketplaceInstallStateFile } from "./stores/marketplace-install-state.store.js";
2
3
  import { mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
3
4
  import { dirname, isAbsolute, join, relative, resolve } from "node:path";
4
5
  //#region src/cli/commands/skills/marketplace-client.ts
@@ -23,6 +24,7 @@ async function fetchMarketplaceSkillItem(apiBase, slug) {
23
24
  return {
24
25
  slug: typeof payload.data.slug === "string" && payload.data.slug.trim() ? payload.data.slug.trim() : slug,
25
26
  packageName: typeof payload.data.packageName === "string" && payload.data.packageName.trim() ? payload.data.packageName.trim() : void 0,
27
+ updatedAt: typeof payload.data.updatedAt === "string" && payload.data.updatedAt.trim() ? payload.data.updatedAt.trim() : void 0,
26
28
  install: { kind }
27
29
  };
28
30
  });
@@ -68,6 +70,7 @@ function collectMarketplaceSkillFiles(rootDir) {
68
70
  continue;
69
71
  }
70
72
  if (!entry.isFile()) continue;
73
+ if (isLocalMarketplaceInstallStateFile(relativePath)) continue;
71
74
  output.push({
72
75
  path: relativePath,
73
76
  contentBase64: readFileSync(absolute).toString("base64")
@@ -79,13 +82,20 @@ function collectMarketplaceSkillFiles(rootDir) {
79
82
  }
80
83
  async function writeMarketplaceSkillFiles(params) {
81
84
  const { destinationDir, files, apiBase, slug } = params;
85
+ const writtenFiles = [];
82
86
  for (const file of files) {
83
87
  const targetPath = resolve(destinationDir, ...file.path.split("/"));
84
88
  const rel = relative(destinationDir, targetPath);
85
89
  if (rel.startsWith("..") || isAbsolute(rel)) throw new Error(`Invalid marketplace file path: ${file.path}`);
86
90
  mkdirSync(dirname(targetPath), { recursive: true });
87
- writeFileSync(targetPath, file.contentBase64 ? decodeMarketplaceFileContent(file.path, file.contentBase64) : await fetchMarketplaceSkillFileBlob(apiBase, slug, file));
91
+ const bytes = file.contentBase64 ? decodeMarketplaceFileContent(file.path, file.contentBase64) : await fetchMarketplaceSkillFileBlob(apiBase, slug, file);
92
+ writeFileSync(targetPath, bytes);
93
+ writtenFiles.push({
94
+ path: normalizeMarketplaceRelativePath(file.path),
95
+ sha256: hashMarketplaceFileBytes(bytes)
96
+ });
88
97
  }
98
+ return writtenFiles;
89
99
  }
90
100
  async function readMarketplaceEnvelope(response) {
91
101
  const raw = await response.text();
@@ -115,6 +125,9 @@ function decodeMarketplaceFileContent(path, contentBase64) {
115
125
  if (!normalized || normalized.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(normalized)) throw new Error(`Invalid marketplace file contentBase64 for path: ${path}`);
116
126
  return Buffer.from(normalized, "base64");
117
127
  }
128
+ function normalizeMarketplaceRelativePath(path) {
129
+ return path.replace(/\\/g, "/");
130
+ }
118
131
  function isRecord(value) {
119
132
  return typeof value === "object" && value !== null && !Array.isArray(value);
120
133
  }
@@ -1 +1 @@
1
- {"version":3,"file":"marketplace-client.js","names":[],"sources":["../../../../src/cli/commands/skills/marketplace-client.ts"],"sourcesContent":["import { mkdirSync, readdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, isAbsolute, join, relative, resolve } from \"node:path\";\nimport { runWithMarketplaceNetworkRetry } from \"./marketplace-network-retry.js\";\n\nconst DEFAULT_MARKETPLACE_API_BASE = \"https://marketplace-api.nextclaw.io\";\n\ntype MarketplaceEnvelope<T> = {\n ok: boolean;\n data?: T;\n error?: {\n code?: string;\n message?: string;\n };\n};\n\ntype MarketplaceSkillInstallKind = \"builtin\" | \"marketplace\";\n\nexport type MarketplaceSkillFileManifestEntry = {\n path: string;\n downloadPath?: string;\n contentBase64?: string;\n};\n\nexport function resolveMarketplaceApiBase(explicitBase: string | undefined): string {\n const raw = explicitBase?.trim()\n || process.env.NEXTCLAW_MARKETPLACE_API_BASE?.trim()\n || DEFAULT_MARKETPLACE_API_BASE;\n return raw.replace(/\\/+$/, \"\");\n}\n\nexport function resolveMarketplaceAdminToken(explicitToken: string | undefined): string | undefined {\n const token = explicitToken?.trim() || process.env.NEXTCLAW_MARKETPLACE_ADMIN_TOKEN?.trim();\n return token && token.length > 0 ? token : undefined;\n}\n\nexport async function fetchMarketplaceSkillItem(\n apiBase: string,\n slug: string\n): Promise<{ slug: string; packageName?: string; install: { kind: MarketplaceSkillInstallKind } }> {\n return runWithMarketplaceNetworkRetry(async () => {\n const response = await fetch(`${apiBase}/api/v1/skills/items/${encodeURIComponent(slug)}`, {\n headers: {\n Accept: \"application/json\"\n }\n });\n const payload = await readMarketplaceEnvelope<{\n slug?: string;\n packageName?: string;\n install: { kind: MarketplaceSkillInstallKind | string };\n }>(response);\n\n if (!payload.ok || !payload.data) {\n const message = payload.error?.message || `marketplace skill fetch failed: ${response.status}`;\n throw new Error(message);\n }\n\n const kind = payload.data.install?.kind;\n if (kind !== \"builtin\" && kind !== \"marketplace\") {\n throw new Error(`Unsupported skill install kind from marketplace: ${String(kind)}`);\n }\n\n return {\n slug: typeof payload.data.slug === \"string\" && payload.data.slug.trim()\n ? payload.data.slug.trim()\n : slug,\n packageName: typeof payload.data.packageName === \"string\" && payload.data.packageName.trim()\n ? payload.data.packageName.trim()\n : undefined,\n install: {\n kind\n }\n };\n });\n}\n\nexport async function fetchMarketplaceSkillFiles(\n apiBase: string,\n slug: string\n): Promise<{ files: MarketplaceSkillFileManifestEntry[] }> {\n return runWithMarketplaceNetworkRetry(async () => {\n const response = await fetch(`${apiBase}/api/v1/skills/items/${encodeURIComponent(slug)}/files`, {\n headers: {\n Accept: \"application/json\"\n }\n });\n\n const payload = await readMarketplaceEnvelope<{ files: unknown }>(response);\n if (!payload.ok || !payload.data) {\n const message = payload.error?.message || `marketplace skill file fetch failed: ${response.status}`;\n throw new Error(message);\n }\n\n if (!isRecord(payload.data) || !Array.isArray(payload.data.files)) {\n throw new Error(\"Invalid marketplace skill file manifest response\");\n }\n\n const files = payload.data.files.map((entry, index) => {\n if (!isRecord(entry) || typeof entry.path !== \"string\" || entry.path.trim().length === 0) {\n throw new Error(`Invalid marketplace skill file manifest at index ${index}`);\n }\n const normalized: MarketplaceSkillFileManifestEntry = {\n path: entry.path.trim()\n };\n if (typeof entry.downloadPath === \"string\" && entry.downloadPath.trim().length > 0) {\n normalized.downloadPath = entry.downloadPath.trim();\n }\n if (typeof entry.contentBase64 === \"string\" && entry.contentBase64.trim().length > 0) {\n normalized.contentBase64 = entry.contentBase64.trim();\n }\n return normalized;\n });\n\n return { files };\n });\n}\n\nexport async function fetchMarketplaceSkillFileBlob(\n apiBase: string,\n slug: string,\n file: MarketplaceSkillFileManifestEntry\n): Promise<Buffer> {\n const downloadUrl = resolveSkillFileDownloadUrl(apiBase, slug, file);\n return runWithMarketplaceNetworkRetry(async () => {\n const response = await fetch(downloadUrl, {\n headers: {\n Accept: \"application/octet-stream\"\n }\n });\n if (!response.ok) {\n const message = extractMarketplaceErrorMessage(await response.text(), response.status)\n || `marketplace skill file download failed: ${response.status}`;\n throw new Error(message);\n }\n return Buffer.from(await response.arrayBuffer());\n });\n}\n\nexport function collectMarketplaceSkillFiles(rootDir: string): Array<{ path: string; contentBase64: string }> {\n const output: Array<{ path: string; contentBase64: string }> = [];\n\n const walk = (dir: string, prefix: string): void => {\n const entries = readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n const absolute = join(dir, entry.name);\n const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;\n if (entry.isDirectory()) {\n walk(absolute, relativePath);\n continue;\n }\n if (!entry.isFile()) {\n continue;\n }\n output.push({\n path: relativePath,\n contentBase64: readFileSync(absolute).toString(\"base64\"),\n });\n }\n };\n\n walk(rootDir, \"\");\n return output;\n}\n\nexport async function writeMarketplaceSkillFiles(params: {\n destinationDir: string;\n files: MarketplaceSkillFileManifestEntry[];\n apiBase: string;\n slug: string;\n}): Promise<void> {\n const { destinationDir, files, apiBase, slug } = params;\n for (const file of files) {\n const targetPath = resolve(destinationDir, ...file.path.split(\"/\"));\n const rel = relative(destinationDir, targetPath);\n if (rel.startsWith(\"..\") || isAbsolute(rel)) {\n throw new Error(`Invalid marketplace file path: ${file.path}`);\n }\n\n mkdirSync(dirname(targetPath), { recursive: true });\n const bytes = file.contentBase64\n ? decodeMarketplaceFileContent(file.path, file.contentBase64)\n : await fetchMarketplaceSkillFileBlob(apiBase, slug, file);\n writeFileSync(targetPath, bytes);\n }\n}\n\nexport async function readMarketplaceEnvelope<T>(response: Response): Promise<MarketplaceEnvelope<T>> {\n const raw = await response.text();\n let payload: unknown;\n try {\n payload = raw.length > 0 ? JSON.parse(raw) : null;\n } catch {\n throw new Error(`Invalid marketplace response: ${response.status}`);\n }\n\n if (!isRecord(payload) || typeof payload.ok !== \"boolean\") {\n throw new Error(`Invalid marketplace response shape: ${response.status}`);\n }\n\n return payload as MarketplaceEnvelope<T>;\n}\n\nfunction resolveSkillFileDownloadUrl(\n apiBase: string,\n slug: string,\n file: MarketplaceSkillFileManifestEntry\n): string {\n if (file.downloadPath) {\n return file.downloadPath.startsWith(\"http://\") || file.downloadPath.startsWith(\"https://\")\n ? file.downloadPath\n : `${apiBase}${file.downloadPath}`;\n }\n return `${apiBase}/api/v1/skills/items/${encodeURIComponent(slug)}/files/blob?path=${encodeURIComponent(file.path)}`;\n}\n\nfunction extractMarketplaceErrorMessage(raw: string, fallbackStatus: number): string | undefined {\n if (!raw) {\n return undefined;\n }\n try {\n const payload = JSON.parse(raw) as MarketplaceEnvelope<unknown>;\n return payload.error?.message;\n } catch {\n return raw || `Request failed (${fallbackStatus})`;\n }\n}\n\nfunction decodeMarketplaceFileContent(path: string, contentBase64: string): Buffer {\n const normalized = contentBase64.replace(/\\s+/g, \"\");\n if (!normalized || normalized.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(normalized)) {\n throw new Error(`Invalid marketplace file contentBase64 for path: ${path}`);\n }\n return Buffer.from(normalized, \"base64\");\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"marketplace-client.js","names":[],"sources":["../../../../src/cli/commands/skills/marketplace-client.ts"],"sourcesContent":["import { mkdirSync, readdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, isAbsolute, join, relative, resolve } from \"node:path\";\nimport { runWithMarketplaceNetworkRetry } from \"./marketplace-network-retry.js\";\nimport {\n hashMarketplaceFileBytes,\n isLocalMarketplaceInstallStateFile,\n type MarketplaceSkillInstallStateFileEntry\n} from \"./stores/marketplace-install-state.store.js\";\n\nconst DEFAULT_MARKETPLACE_API_BASE = \"https://marketplace-api.nextclaw.io\";\n\ntype MarketplaceEnvelope<T> = {\n ok: boolean;\n data?: T;\n error?: {\n code?: string;\n message?: string;\n };\n};\n\ntype MarketplaceSkillInstallKind = \"builtin\" | \"marketplace\";\n\nexport type MarketplaceSkillFileManifestEntry = {\n path: string;\n downloadPath?: string;\n contentBase64?: string;\n};\n\nexport type MarketplaceSkillItem = {\n slug: string;\n packageName?: string;\n updatedAt?: string;\n install: { kind: MarketplaceSkillInstallKind };\n};\n\nexport function resolveMarketplaceApiBase(explicitBase: string | undefined): string {\n const raw = explicitBase?.trim()\n || process.env.NEXTCLAW_MARKETPLACE_API_BASE?.trim()\n || DEFAULT_MARKETPLACE_API_BASE;\n return raw.replace(/\\/+$/, \"\");\n}\n\nexport function resolveMarketplaceAdminToken(explicitToken: string | undefined): string | undefined {\n const token = explicitToken?.trim() || process.env.NEXTCLAW_MARKETPLACE_ADMIN_TOKEN?.trim();\n return token && token.length > 0 ? token : undefined;\n}\n\nexport async function fetchMarketplaceSkillItem(\n apiBase: string,\n slug: string\n): Promise<MarketplaceSkillItem> {\n return runWithMarketplaceNetworkRetry(async () => {\n const response = await fetch(`${apiBase}/api/v1/skills/items/${encodeURIComponent(slug)}`, {\n headers: {\n Accept: \"application/json\"\n }\n });\n const payload = await readMarketplaceEnvelope<{\n slug?: string;\n packageName?: string;\n updatedAt?: string;\n install: { kind: MarketplaceSkillInstallKind | string };\n }>(response);\n\n if (!payload.ok || !payload.data) {\n const message = payload.error?.message || `marketplace skill fetch failed: ${response.status}`;\n throw new Error(message);\n }\n\n const kind = payload.data.install?.kind;\n if (kind !== \"builtin\" && kind !== \"marketplace\") {\n throw new Error(`Unsupported skill install kind from marketplace: ${String(kind)}`);\n }\n\n return {\n slug: typeof payload.data.slug === \"string\" && payload.data.slug.trim()\n ? payload.data.slug.trim()\n : slug,\n packageName: typeof payload.data.packageName === \"string\" && payload.data.packageName.trim()\n ? payload.data.packageName.trim()\n : undefined,\n updatedAt: typeof payload.data.updatedAt === \"string\" && payload.data.updatedAt.trim()\n ? payload.data.updatedAt.trim()\n : undefined,\n install: {\n kind\n }\n };\n });\n}\n\nexport async function fetchMarketplaceSkillFiles(\n apiBase: string,\n slug: string\n): Promise<{ files: MarketplaceSkillFileManifestEntry[] }> {\n return runWithMarketplaceNetworkRetry(async () => {\n const response = await fetch(`${apiBase}/api/v1/skills/items/${encodeURIComponent(slug)}/files`, {\n headers: {\n Accept: \"application/json\"\n }\n });\n\n const payload = await readMarketplaceEnvelope<{ files: unknown }>(response);\n if (!payload.ok || !payload.data) {\n const message = payload.error?.message || `marketplace skill file fetch failed: ${response.status}`;\n throw new Error(message);\n }\n\n if (!isRecord(payload.data) || !Array.isArray(payload.data.files)) {\n throw new Error(\"Invalid marketplace skill file manifest response\");\n }\n\n const files = payload.data.files.map((entry, index) => {\n if (!isRecord(entry) || typeof entry.path !== \"string\" || entry.path.trim().length === 0) {\n throw new Error(`Invalid marketplace skill file manifest at index ${index}`);\n }\n const normalized: MarketplaceSkillFileManifestEntry = {\n path: entry.path.trim()\n };\n if (typeof entry.downloadPath === \"string\" && entry.downloadPath.trim().length > 0) {\n normalized.downloadPath = entry.downloadPath.trim();\n }\n if (typeof entry.contentBase64 === \"string\" && entry.contentBase64.trim().length > 0) {\n normalized.contentBase64 = entry.contentBase64.trim();\n }\n return normalized;\n });\n\n return { files };\n });\n}\n\nexport async function fetchMarketplaceSkillFileBlob(\n apiBase: string,\n slug: string,\n file: MarketplaceSkillFileManifestEntry\n): Promise<Buffer> {\n const downloadUrl = resolveSkillFileDownloadUrl(apiBase, slug, file);\n return runWithMarketplaceNetworkRetry(async () => {\n const response = await fetch(downloadUrl, {\n headers: {\n Accept: \"application/octet-stream\"\n }\n });\n if (!response.ok) {\n const message = extractMarketplaceErrorMessage(await response.text(), response.status)\n || `marketplace skill file download failed: ${response.status}`;\n throw new Error(message);\n }\n return Buffer.from(await response.arrayBuffer());\n });\n}\n\nexport function collectMarketplaceSkillFiles(rootDir: string): Array<{ path: string; contentBase64: string }> {\n const output: Array<{ path: string; contentBase64: string }> = [];\n\n const walk = (dir: string, prefix: string): void => {\n const entries = readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n const absolute = join(dir, entry.name);\n const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;\n if (entry.isDirectory()) {\n walk(absolute, relativePath);\n continue;\n }\n if (!entry.isFile()) {\n continue;\n }\n if (isLocalMarketplaceInstallStateFile(relativePath)) {\n continue;\n }\n output.push({\n path: relativePath,\n contentBase64: readFileSync(absolute).toString(\"base64\"),\n });\n }\n };\n\n walk(rootDir, \"\");\n return output;\n}\n\nexport async function writeMarketplaceSkillFiles(params: {\n destinationDir: string;\n files: MarketplaceSkillFileManifestEntry[];\n apiBase: string;\n slug: string;\n}): Promise<MarketplaceSkillInstallStateFileEntry[]> {\n const { destinationDir, files, apiBase, slug } = params;\n const writtenFiles: MarketplaceSkillInstallStateFileEntry[] = [];\n for (const file of files) {\n const targetPath = resolve(destinationDir, ...file.path.split(\"/\"));\n const rel = relative(destinationDir, targetPath);\n if (rel.startsWith(\"..\") || isAbsolute(rel)) {\n throw new Error(`Invalid marketplace file path: ${file.path}`);\n }\n\n mkdirSync(dirname(targetPath), { recursive: true });\n const bytes = file.contentBase64\n ? decodeMarketplaceFileContent(file.path, file.contentBase64)\n : await fetchMarketplaceSkillFileBlob(apiBase, slug, file);\n writeFileSync(targetPath, bytes);\n writtenFiles.push({\n path: normalizeMarketplaceRelativePath(file.path),\n sha256: hashMarketplaceFileBytes(bytes),\n });\n }\n return writtenFiles;\n}\n\nexport async function readMarketplaceEnvelope<T>(response: Response): Promise<MarketplaceEnvelope<T>> {\n const raw = await response.text();\n let payload: unknown;\n try {\n payload = raw.length > 0 ? JSON.parse(raw) : null;\n } catch {\n throw new Error(`Invalid marketplace response: ${response.status}`);\n }\n\n if (!isRecord(payload) || typeof payload.ok !== \"boolean\") {\n throw new Error(`Invalid marketplace response shape: ${response.status}`);\n }\n\n return payload as MarketplaceEnvelope<T>;\n}\n\nfunction resolveSkillFileDownloadUrl(\n apiBase: string,\n slug: string,\n file: MarketplaceSkillFileManifestEntry\n): string {\n if (file.downloadPath) {\n return file.downloadPath.startsWith(\"http://\") || file.downloadPath.startsWith(\"https://\")\n ? file.downloadPath\n : `${apiBase}${file.downloadPath}`;\n }\n return `${apiBase}/api/v1/skills/items/${encodeURIComponent(slug)}/files/blob?path=${encodeURIComponent(file.path)}`;\n}\n\nfunction extractMarketplaceErrorMessage(raw: string, fallbackStatus: number): string | undefined {\n if (!raw) {\n return undefined;\n }\n try {\n const payload = JSON.parse(raw) as MarketplaceEnvelope<unknown>;\n return payload.error?.message;\n } catch {\n return raw || `Request failed (${fallbackStatus})`;\n }\n}\n\nfunction decodeMarketplaceFileContent(path: string, contentBase64: string): Buffer {\n const normalized = contentBase64.replace(/\\s+/g, \"\");\n if (!normalized || normalized.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(normalized)) {\n throw new Error(`Invalid marketplace file contentBase64 for path: ${path}`);\n }\n return Buffer.from(normalized, \"base64\");\n}\n\nfunction normalizeMarketplaceRelativePath(path: string): string {\n return path.replace(/\\\\/g, \"/\");\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n"],"mappings":";;;;;AASA,MAAM,+BAA+B;AA0BrC,SAAgB,0BAA0B,cAA0C;AAIlF,SAHY,cAAc,MAAM,IAC3B,QAAQ,IAAI,+BAA+B,MAAM,IACjD,8BACM,QAAQ,QAAQ,GAAG;;AAGhC,SAAgB,6BAA6B,eAAuD;CAClG,MAAM,QAAQ,eAAe,MAAM,IAAI,QAAQ,IAAI,kCAAkC,MAAM;AAC3F,QAAO,SAAS,MAAM,SAAS,IAAI,QAAQ,KAAA;;AAG7C,eAAsB,0BACpB,SACA,MAC+B;AAC/B,QAAO,+BAA+B,YAAY;EAChD,MAAM,WAAW,MAAM,MAAM,GAAG,QAAQ,uBAAuB,mBAAmB,KAAK,IAAI,EACzF,SAAS,EACP,QAAQ,oBACT,EACF,CAAC;EACF,MAAM,UAAU,MAAM,wBAKnB,SAAS;AAEZ,MAAI,CAAC,QAAQ,MAAM,CAAC,QAAQ,MAAM;GAChC,MAAM,UAAU,QAAQ,OAAO,WAAW,mCAAmC,SAAS;AACtF,SAAM,IAAI,MAAM,QAAQ;;EAG1B,MAAM,OAAO,QAAQ,KAAK,SAAS;AACnC,MAAI,SAAS,aAAa,SAAS,cACjC,OAAM,IAAI,MAAM,oDAAoD,OAAO,KAAK,GAAG;AAGrF,SAAO;GACL,MAAM,OAAO,QAAQ,KAAK,SAAS,YAAY,QAAQ,KAAK,KAAK,MAAM,GACnE,QAAQ,KAAK,KAAK,MAAM,GACxB;GACJ,aAAa,OAAO,QAAQ,KAAK,gBAAgB,YAAY,QAAQ,KAAK,YAAY,MAAM,GACxF,QAAQ,KAAK,YAAY,MAAM,GAC/B,KAAA;GACJ,WAAW,OAAO,QAAQ,KAAK,cAAc,YAAY,QAAQ,KAAK,UAAU,MAAM,GAClF,QAAQ,KAAK,UAAU,MAAM,GAC7B,KAAA;GACJ,SAAS,EACP,MACD;GACF;GACD;;AAGJ,eAAsB,2BACpB,SACA,MACyD;AACzD,QAAO,+BAA+B,YAAY;EAChD,MAAM,WAAW,MAAM,MAAM,GAAG,QAAQ,uBAAuB,mBAAmB,KAAK,CAAC,SAAS,EAC/F,SAAS,EACP,QAAQ,oBACT,EACF,CAAC;EAEF,MAAM,UAAU,MAAM,wBAA4C,SAAS;AAC3E,MAAI,CAAC,QAAQ,MAAM,CAAC,QAAQ,MAAM;GAChC,MAAM,UAAU,QAAQ,OAAO,WAAW,wCAAwC,SAAS;AAC3F,SAAM,IAAI,MAAM,QAAQ;;AAG1B,MAAI,CAAC,SAAS,QAAQ,KAAK,IAAI,CAAC,MAAM,QAAQ,QAAQ,KAAK,MAAM,CAC/D,OAAM,IAAI,MAAM,mDAAmD;AAmBrE,SAAO,EAAE,OAhBK,QAAQ,KAAK,MAAM,KAAK,OAAO,UAAU;AACrD,OAAI,CAAC,SAAS,MAAM,IAAI,OAAO,MAAM,SAAS,YAAY,MAAM,KAAK,MAAM,CAAC,WAAW,EACrF,OAAM,IAAI,MAAM,oDAAoD,QAAQ;GAE9E,MAAM,aAAgD,EACpD,MAAM,MAAM,KAAK,MAAM,EACxB;AACD,OAAI,OAAO,MAAM,iBAAiB,YAAY,MAAM,aAAa,MAAM,CAAC,SAAS,EAC/E,YAAW,eAAe,MAAM,aAAa,MAAM;AAErD,OAAI,OAAO,MAAM,kBAAkB,YAAY,MAAM,cAAc,MAAM,CAAC,SAAS,EACjF,YAAW,gBAAgB,MAAM,cAAc,MAAM;AAEvD,UAAO;IACP,EAEc;GAChB;;AAGJ,eAAsB,8BACpB,SACA,MACA,MACiB;CACjB,MAAM,cAAc,4BAA4B,SAAS,MAAM,KAAK;AACpE,QAAO,+BAA+B,YAAY;EAChD,MAAM,WAAW,MAAM,MAAM,aAAa,EACxC,SAAS,EACP,QAAQ,4BACT,EACF,CAAC;AACF,MAAI,CAAC,SAAS,IAAI;GAChB,MAAM,UAAU,+BAA+B,MAAM,SAAS,MAAM,EAAE,SAAS,OAAO,IACjF,2CAA2C,SAAS;AACzD,SAAM,IAAI,MAAM,QAAQ;;AAE1B,SAAO,OAAO,KAAK,MAAM,SAAS,aAAa,CAAC;GAChD;;AAGJ,SAAgB,6BAA6B,SAAiE;CAC5G,MAAM,SAAyD,EAAE;CAEjE,MAAM,QAAQ,KAAa,WAAyB;EAClD,MAAM,UAAU,YAAY,KAAK,EAAE,eAAe,MAAM,CAAC;AACzD,OAAK,MAAM,SAAS,SAAS;GAC3B,MAAM,WAAW,KAAK,KAAK,MAAM,KAAK;GACtC,MAAM,eAAe,SAAS,GAAG,OAAO,GAAG,MAAM,SAAS,MAAM;AAChE,OAAI,MAAM,aAAa,EAAE;AACvB,SAAK,UAAU,aAAa;AAC5B;;AAEF,OAAI,CAAC,MAAM,QAAQ,CACjB;AAEF,OAAI,mCAAmC,aAAa,CAClD;AAEF,UAAO,KAAK;IACV,MAAM;IACN,eAAe,aAAa,SAAS,CAAC,SAAS,SAAS;IACzD,CAAC;;;AAIN,MAAK,SAAS,GAAG;AACjB,QAAO;;AAGT,eAAsB,2BAA2B,QAKI;CACnD,MAAM,EAAE,gBAAgB,OAAO,SAAS,SAAS;CACjD,MAAM,eAAwD,EAAE;AAChE,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,aAAa,QAAQ,gBAAgB,GAAG,KAAK,KAAK,MAAM,IAAI,CAAC;EACnE,MAAM,MAAM,SAAS,gBAAgB,WAAW;AAChD,MAAI,IAAI,WAAW,KAAK,IAAI,WAAW,IAAI,CACzC,OAAM,IAAI,MAAM,kCAAkC,KAAK,OAAO;AAGhE,YAAU,QAAQ,WAAW,EAAE,EAAE,WAAW,MAAM,CAAC;EACnD,MAAM,QAAQ,KAAK,gBACf,6BAA6B,KAAK,MAAM,KAAK,cAAc,GAC3D,MAAM,8BAA8B,SAAS,MAAM,KAAK;AAC5D,gBAAc,YAAY,MAAM;AAChC,eAAa,KAAK;GAChB,MAAM,iCAAiC,KAAK,KAAK;GACjD,QAAQ,yBAAyB,MAAM;GACxC,CAAC;;AAEJ,QAAO;;AAGT,eAAsB,wBAA2B,UAAqD;CACpG,MAAM,MAAM,MAAM,SAAS,MAAM;CACjC,IAAI;AACJ,KAAI;AACF,YAAU,IAAI,SAAS,IAAI,KAAK,MAAM,IAAI,GAAG;SACvC;AACN,QAAM,IAAI,MAAM,iCAAiC,SAAS,SAAS;;AAGrE,KAAI,CAAC,SAAS,QAAQ,IAAI,OAAO,QAAQ,OAAO,UAC9C,OAAM,IAAI,MAAM,uCAAuC,SAAS,SAAS;AAG3E,QAAO;;AAGT,SAAS,4BACP,SACA,MACA,MACQ;AACR,KAAI,KAAK,aACP,QAAO,KAAK,aAAa,WAAW,UAAU,IAAI,KAAK,aAAa,WAAW,WAAW,GACtF,KAAK,eACL,GAAG,UAAU,KAAK;AAExB,QAAO,GAAG,QAAQ,uBAAuB,mBAAmB,KAAK,CAAC,mBAAmB,mBAAmB,KAAK,KAAK;;AAGpH,SAAS,+BAA+B,KAAa,gBAA4C;AAC/F,KAAI,CAAC,IACH;AAEF,KAAI;AAEF,SADgB,KAAK,MAAM,IAAI,CAChB,OAAO;SAChB;AACN,SAAO,OAAO,mBAAmB,eAAe;;;AAIpD,SAAS,6BAA6B,MAAc,eAA+B;CACjF,MAAM,aAAa,cAAc,QAAQ,QAAQ,GAAG;AACpD,KAAI,CAAC,cAAc,WAAW,SAAS,MAAM,KAAK,CAAC,yBAAyB,KAAK,WAAW,CAC1F,OAAM,IAAI,MAAM,oDAAoD,OAAO;AAE7E,QAAO,OAAO,KAAK,YAAY,SAAS;;AAG1C,SAAS,iCAAiC,MAAsB;AAC9D,QAAO,KAAK,QAAQ,OAAO,IAAI;;AAGjC,SAAS,SAAS,OAAkD;AAClE,QAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM"}
@@ -1,14 +1,7 @@
1
1
  import { LocalizedTextMap } from "./marketplace.metadata.js";
2
+ import { MarketplaceSkillInstallOptions, installMarketplaceSkill, updateInstalledMarketplaceSkill } from "./utils/marketplace-skill-lifecycle.utils.js";
2
3
 
3
4
  //#region src/cli/commands/skills/marketplace.utils.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
5
  type MarketplaceSkillPublishOptions = {
13
6
  skillDir: string;
14
7
  metaFile?: string;
@@ -30,12 +23,6 @@ type MarketplaceSkillPublishOptions = {
30
23
  token?: string;
31
24
  requireExisting?: boolean;
32
25
  };
33
- declare function installMarketplaceSkill(options: MarketplaceSkillInstallOptions): Promise<{
34
- slug: string;
35
- destinationDir: string;
36
- alreadyInstalled?: boolean;
37
- source: MarketplaceSkillInstallKind;
38
- }>;
39
26
  declare function publishMarketplaceSkill(options: MarketplaceSkillPublishOptions): Promise<{
40
27
  created: boolean;
41
28
  slug: string;
@@ -43,5 +30,5 @@ declare function publishMarketplaceSkill(options: MarketplaceSkillPublishOptions
43
30
  fileCount: number;
44
31
  }>;
45
32
  //#endregion
46
- export { MarketplaceSkillInstallOptions, MarketplaceSkillPublishOptions, installMarketplaceSkill, publishMarketplaceSkill };
33
+ export { type MarketplaceSkillInstallOptions, MarketplaceSkillPublishOptions, installMarketplaceSkill, publishMarketplaceSkill, updateInstalledMarketplaceSkill };
47
34
  //# sourceMappingURL=marketplace.utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"marketplace.utils.d.ts","names":[],"sources":["../../../../src/cli/commands/skills/marketplace.utils.ts"],"mappings":";;;KA6BK,2BAAA;AAAA,KAEO,8BAAA;EACV,IAAA;EACA,OAAA;EACA,GAAA;EACA,KAAA;EACA,UAAA;AAAA;AAAA,KAGU,8BAAA;EACV,QAAA;EACA,QAAA;EACA,IAAA;EACA,WAAA;EACA,KAAA;EACA,IAAA;EACA,OAAA;EACA,WAAA,GAAc,gBAAA;EACd,WAAA;EACA,eAAA,GAAkB,gBAAA;EAClB,MAAA;EACA,IAAA;EACA,UAAA;EACA,QAAA;EACA,WAAA;EACA,SAAA;EACA,UAAA;EACA,KAAA;EACA,eAAA;AAAA;AAAA,iBAGoB,uBAAA,CAAwB,OAAA,EAAS,8BAAA,GAAiC,OAAA;EACtF,IAAA;EACA,cAAA;EACA,gBAAA;EACA,MAAA,EAAQ,2BAAA;AAAA;AAAA,iBA4LY,uBAAA,CAAwB,OAAA,EAAS,8BAAA,GAAiC,OAAA;EACtF,OAAA;EACA,IAAA;EACA,WAAA;EACA,SAAA;AAAA"}
1
+ {"version":3,"file":"marketplace.utils.d.ts","names":[],"sources":["../../../../src/cli/commands/skills/marketplace.utils.ts"],"mappings":";;;;KA2BY,8BAAA;EACV,QAAA;EACA,QAAA;EACA,IAAA;EACA,WAAA;EACA,KAAA;EACA,IAAA;EACA,OAAA;EACA,WAAA,GAAc,gBAAA;EACd,WAAA;EACA,eAAA,GAAkB,gBAAA;EAClB,MAAA;EACA,IAAA;EACA,UAAA;EACA,QAAA;EACA,WAAA;EACA,SAAA;EACA,UAAA;EACA,KAAA;EACA,eAAA;AAAA;AAAA,iBAGoB,uBAAA,CAAwB,OAAA,EAAS,8BAAA,GAAiC,OAAA;EACtF,OAAA;EACA,IAAA;EACA,WAAA;EACA,SAAA;AAAA"}
@@ -2,134 +2,12 @@ import { PlatformAuthCommands } from "../../../commands/platform-auth/services/p
2
2
  import "../../../commands/platform-auth/index.js";
3
3
  import { buildLocalizedTextMap, parseSkillFrontmatter, readMarketplaceMetadataFile } from "./marketplace.metadata.js";
4
4
  import { runWithMarketplaceNetworkRetry } from "./marketplace-network-retry.js";
5
- import { collectMarketplaceSkillFiles, fetchMarketplaceSkillFiles, fetchMarketplaceSkillItem, readMarketplaceEnvelope, resolveMarketplaceAdminToken, resolveMarketplaceApiBase, writeMarketplaceSkillFiles } from "./marketplace-client.js";
6
- import { normalizeTags, resolvePublishPackageName, validateSkillSelector, validateSkillSlug } from "./marketplace-identity.utils.js";
7
- import { DEFAULT_SKILLS_DIR } from "@nextclaw/core";
8
- import { SkillManager } from "@nextclaw/kernel";
9
- import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync } from "node:fs";
10
- import { basename, isAbsolute, join, relative, resolve } from "node:path";
5
+ import { collectMarketplaceSkillFiles, readMarketplaceEnvelope, resolveMarketplaceAdminToken, resolveMarketplaceApiBase } from "./marketplace-client.js";
6
+ import { normalizeTags, resolvePublishPackageName, validateSkillSlug } from "./marketplace-identity.utils.js";
7
+ import { installMarketplaceSkill, updateInstalledMarketplaceSkill } from "./utils/marketplace-skill-lifecycle.utils.js";
8
+ import { existsSync, readFileSync } from "node:fs";
9
+ import { basename, join, resolve } from "node:path";
11
10
  //#region src/cli/commands/skills/marketplace.utils.ts
12
- async function installMarketplaceSkill(options) {
13
- const { slug, workdir: rawWorkdir, dir, force, apiBaseUrl } = options;
14
- const selector = validateSkillSelector(slug.trim(), "slug");
15
- const workdir = resolve(rawWorkdir);
16
- if (!existsSync(workdir)) throw new Error(`Workdir does not exist: ${workdir}`);
17
- const apiBase = resolveMarketplaceApiBase(apiBaseUrl);
18
- const item = await fetchMarketplaceSkillItem(apiBase, selector);
19
- const installSlug = item.slug;
20
- const resolvedSlug = item.packageName || item.slug;
21
- const destinationDir = resolveMarketplaceSkillDestinationDir({
22
- workdir,
23
- slug: installSlug,
24
- dir
25
- });
26
- if (item.install.kind === "builtin") {
27
- const builtinResult = resolveBuiltinMarketplaceInstallResult({
28
- workdir,
29
- slug: installSlug
30
- });
31
- builtinResult.slug = resolvedSlug;
32
- return builtinResult;
33
- }
34
- const filesPayload = await fetchMarketplaceSkillFiles(apiBase, selector);
35
- const existingInstall = prepareMarketplaceSkillDestinationDir({
36
- destinationDir,
37
- files: filesPayload.files,
38
- force,
39
- slug: installSlug
40
- });
41
- if (existingInstall) {
42
- existingInstall.slug = resolvedSlug;
43
- return existingInstall;
44
- }
45
- await writeMarketplaceSkillFiles({
46
- destinationDir,
47
- files: filesPayload.files,
48
- apiBase,
49
- slug: selector
50
- });
51
- ensureInstalledMarketplaceSkill(destinationDir, installSlug);
52
- return buildMarketplaceInstallResult(resolvedSlug, destinationDir);
53
- }
54
- function resolveMarketplaceSkillDestinationDir(params) {
55
- const { workdir, slug, dir } = params;
56
- const dirName = dir?.trim() || DEFAULT_SKILLS_DIR;
57
- return isAbsolute(dirName) ? resolve(dirName, slug) : resolve(workdir, dirName, slug);
58
- }
59
- function resolveBuiltinMarketplaceInstallResult(params) {
60
- return {
61
- slug: params.slug,
62
- destinationDir: resolveBuiltinSkillDir(params.workdir, params.slug),
63
- alreadyInstalled: true,
64
- source: "builtin"
65
- };
66
- }
67
- function prepareMarketplaceSkillDestinationDir(params) {
68
- const { destinationDir, files, force, slug } = params;
69
- if (!force && existsSync(destinationDir)) {
70
- const existingDirState = inspectMarketplaceSkillDirectory(destinationDir, files);
71
- if (existingDirState === "installed") return {
72
- slug,
73
- destinationDir,
74
- alreadyInstalled: true,
75
- source: "marketplace"
76
- };
77
- if (existingDirState !== "recoverable") throw new Error(`Skill directory already exists: ${destinationDir} (use --force)`);
78
- rmSync(destinationDir, {
79
- recursive: true,
80
- force: true
81
- });
82
- }
83
- if (force && existsSync(destinationDir)) rmSync(destinationDir, {
84
- recursive: true,
85
- force: true
86
- });
87
- mkdirSync(destinationDir, { recursive: true });
88
- return null;
89
- }
90
- function ensureInstalledMarketplaceSkill(destinationDir, slug) {
91
- if (!existsSync(join(destinationDir, "SKILL.md"))) throw new Error(`Marketplace skill ${slug} does not include SKILL.md`);
92
- }
93
- function buildMarketplaceInstallResult(slug, destinationDir) {
94
- return {
95
- slug,
96
- destinationDir,
97
- source: "marketplace"
98
- };
99
- }
100
- function inspectMarketplaceSkillDirectory(destinationDir, files) {
101
- if (existsSync(join(destinationDir, "SKILL.md"))) return "installed";
102
- const discoveredFiles = collectRelativeFiles(destinationDir);
103
- if (discoveredFiles === null) return "conflict";
104
- const relevantFiles = discoveredFiles.filter((file) => !isIgnorableMarketplaceResidue(file));
105
- if (relevantFiles.length === 0) return "recoverable";
106
- const manifestPaths = new Set(files.map((file) => normalizeMarketplaceRelativePath(file.path)));
107
- return relevantFiles.every((file) => manifestPaths.has(normalizeMarketplaceRelativePath(file))) ? "recoverable" : "conflict";
108
- }
109
- function collectRelativeFiles(rootDir) {
110
- const output = [];
111
- const walk = (dir) => {
112
- const entries = readdirSync(dir, { withFileTypes: true });
113
- for (const entry of entries) {
114
- const absolute = join(dir, entry.name);
115
- if (entry.isDirectory()) {
116
- if (!walk(absolute)) return false;
117
- continue;
118
- }
119
- if (!entry.isFile()) return false;
120
- const relativePath = relative(rootDir, absolute);
121
- output.push(normalizeMarketplaceRelativePath(relativePath));
122
- }
123
- return true;
124
- };
125
- return walk(rootDir) ? output : null;
126
- }
127
- function normalizeMarketplaceRelativePath(path) {
128
- return path.replace(/\\/g, "/");
129
- }
130
- function isIgnorableMarketplaceResidue(path) {
131
- return path === ".DS_Store";
132
- }
133
11
  async function publishMarketplaceSkill(options) {
134
12
  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;
135
13
  const skillDir = resolve(rawSkillDir);
@@ -193,12 +71,7 @@ async function publishMarketplaceSkill(options) {
193
71
  fileCount: payload.data.fileCount
194
72
  };
195
73
  }
196
- function resolveBuiltinSkillDir(workdir, skillName) {
197
- const skillDir = new SkillManager({ workspace: workdir }).resolveBuiltinSkillDir(skillName);
198
- if (!skillDir) throw new Error(`Built-in skill not found in local installation: ${skillName}`);
199
- return skillDir;
200
- }
201
74
  //#endregion
202
- export { installMarketplaceSkill, publishMarketplaceSkill };
75
+ export { installMarketplaceSkill, publishMarketplaceSkill, updateInstalledMarketplaceSkill };
203
76
 
204
77
  //# sourceMappingURL=marketplace.utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"marketplace.utils.js","names":[],"sources":["../../../../src/cli/commands/skills/marketplace.utils.ts"],"sourcesContent":["import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync } from \"node:fs\";\nimport { basename, isAbsolute, join, relative, resolve } from \"node:path\";\nimport { DEFAULT_SKILLS_DIR } from \"@nextclaw/core\";\nimport { SkillManager } from \"@nextclaw/kernel\";\nimport {\n buildLocalizedTextMap,\n parseSkillFrontmatter,\n readMarketplaceMetadataFile,\n type LocalizedTextMap\n} from \"./marketplace.metadata.js\";\nimport { PlatformAuthCommands } from \"@nextclaw-service/commands/platform-auth/index.js\";\nimport {\n fetchMarketplaceSkillFiles,\n fetchMarketplaceSkillItem,\n collectMarketplaceSkillFiles,\n type MarketplaceSkillFileManifestEntry,\n readMarketplaceEnvelope,\n resolveMarketplaceAdminToken,\n resolveMarketplaceApiBase,\n writeMarketplaceSkillFiles\n} from \"./marketplace-client.js\";\nimport {\n normalizeTags,\n resolvePublishPackageName,\n validateSkillSelector,\n validateSkillSlug\n} from \"./marketplace-identity.utils.js\";\nimport { runWithMarketplaceNetworkRetry } from \"./marketplace-network-retry.js\";\n\ntype MarketplaceSkillInstallKind = \"builtin\" | \"marketplace\";\n\nexport type MarketplaceSkillInstallOptions = {\n slug: string;\n workdir: string;\n dir?: string;\n force?: boolean;\n apiBaseUrl?: string;\n};\n\nexport type MarketplaceSkillPublishOptions = {\n skillDir: string;\n metaFile?: string;\n slug?: string;\n packageName?: string;\n scope?: string;\n name?: string;\n summary?: string;\n summaryI18n?: LocalizedTextMap;\n description?: string;\n descriptionI18n?: LocalizedTextMap;\n author?: string;\n tags?: string[];\n sourceRepo?: string;\n homepage?: string;\n publishedAt?: string;\n updatedAt?: string;\n apiBaseUrl?: string;\n token?: string;\n requireExisting?: boolean;\n};\n\nexport async function installMarketplaceSkill(options: MarketplaceSkillInstallOptions): Promise<{\n slug: string;\n destinationDir: string;\n alreadyInstalled?: boolean;\n source: MarketplaceSkillInstallKind;\n}> {\n const { slug, workdir: rawWorkdir, dir, force, apiBaseUrl } = options;\n const selector = validateSkillSelector(slug.trim(), \"slug\");\n const workdir = resolve(rawWorkdir);\n if (!existsSync(workdir)) {\n throw new Error(`Workdir does not exist: ${workdir}`);\n }\n\n const apiBase = resolveMarketplaceApiBase(apiBaseUrl);\n const item = await fetchMarketplaceSkillItem(apiBase, selector);\n const installSlug = item.slug;\n const resolvedSlug = item.packageName || item.slug;\n const destinationDir = resolveMarketplaceSkillDestinationDir({\n workdir,\n slug: installSlug,\n dir,\n });\n\n if (item.install.kind === \"builtin\") {\n const builtinResult = resolveBuiltinMarketplaceInstallResult({\n workdir,\n slug: installSlug,\n });\n builtinResult.slug = resolvedSlug;\n return builtinResult;\n }\n\n const filesPayload = await fetchMarketplaceSkillFiles(apiBase, selector);\n const existingInstall = prepareMarketplaceSkillDestinationDir({\n destinationDir,\n files: filesPayload.files,\n force,\n slug: installSlug,\n });\n if (existingInstall) {\n existingInstall.slug = resolvedSlug;\n return existingInstall;\n }\n await writeMarketplaceSkillFiles({\n destinationDir,\n files: filesPayload.files,\n apiBase,\n slug: selector,\n });\n ensureInstalledMarketplaceSkill(destinationDir, installSlug);\n return buildMarketplaceInstallResult(resolvedSlug, destinationDir);\n}\n\nfunction resolveMarketplaceSkillDestinationDir(params: {\n workdir: string;\n slug: string;\n dir?: string;\n}): string {\n const { workdir, slug, dir } = params;\n const dirName = dir?.trim() || DEFAULT_SKILLS_DIR;\n return isAbsolute(dirName)\n ? resolve(dirName, slug)\n : resolve(workdir, dirName, slug);\n}\n\nfunction resolveBuiltinMarketplaceInstallResult(params: {\n workdir: string;\n slug: string;\n}): {\n slug: string;\n destinationDir: string;\n alreadyInstalled: true;\n source: \"builtin\";\n} {\n return {\n slug: params.slug,\n destinationDir: resolveBuiltinSkillDir(params.workdir, params.slug),\n alreadyInstalled: true,\n source: \"builtin\",\n };\n}\n\nfunction prepareMarketplaceSkillDestinationDir(params: {\n destinationDir: string;\n files: MarketplaceSkillFileManifestEntry[];\n force?: boolean;\n slug: string;\n}): {\n slug: string;\n destinationDir: string;\n alreadyInstalled: true;\n source: \"marketplace\";\n} | null {\n const { destinationDir, files, force, slug } = params;\n if (!force && existsSync(destinationDir)) {\n const existingDirState = inspectMarketplaceSkillDirectory(destinationDir, files);\n if (existingDirState === \"installed\") {\n return {\n slug,\n destinationDir,\n alreadyInstalled: true,\n source: \"marketplace\",\n };\n }\n if (existingDirState !== \"recoverable\") {\n throw new Error(`Skill directory already exists: ${destinationDir} (use --force)`);\n }\n rmSync(destinationDir, { recursive: true, force: true });\n }\n\n if (force && existsSync(destinationDir)) {\n rmSync(destinationDir, { recursive: true, force: true });\n }\n\n mkdirSync(destinationDir, { recursive: true });\n return null;\n}\n\nfunction ensureInstalledMarketplaceSkill(destinationDir: string, slug: string): void {\n if (!existsSync(join(destinationDir, \"SKILL.md\"))) {\n throw new Error(`Marketplace skill ${slug} does not include SKILL.md`);\n }\n}\n\nfunction buildMarketplaceInstallResult(slug: string, destinationDir: string): {\n slug: string;\n destinationDir: string;\n source: \"marketplace\";\n} {\n return {\n slug,\n destinationDir,\n source: \"marketplace\",\n };\n}\n\nfunction inspectMarketplaceSkillDirectory(\n destinationDir: string,\n files: MarketplaceSkillFileManifestEntry[]\n): \"installed\" | \"recoverable\" | \"conflict\" {\n if (existsSync(join(destinationDir, \"SKILL.md\"))) {\n return \"installed\";\n }\n\n const discoveredFiles = collectRelativeFiles(destinationDir);\n if (discoveredFiles === null) {\n return \"conflict\";\n }\n\n const relevantFiles = discoveredFiles.filter((file) => !isIgnorableMarketplaceResidue(file));\n if (relevantFiles.length === 0) {\n return \"recoverable\";\n }\n\n const manifestPaths = new Set(files.map((file) => normalizeMarketplaceRelativePath(file.path)));\n return relevantFiles.every((file) => manifestPaths.has(normalizeMarketplaceRelativePath(file)))\n ? \"recoverable\"\n : \"conflict\";\n}\n\nfunction collectRelativeFiles(rootDir: string): string[] | null {\n const output: string[] = [];\n const walk = (dir: string): boolean => {\n const entries = readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n const absolute = join(dir, entry.name);\n if (entry.isDirectory()) {\n if (!walk(absolute)) {\n return false;\n }\n continue;\n }\n if (!entry.isFile()) {\n return false;\n }\n const relativePath = relative(rootDir, absolute);\n output.push(normalizeMarketplaceRelativePath(relativePath));\n }\n return true;\n };\n\n return walk(rootDir) ? output : null;\n}\n\nfunction normalizeMarketplaceRelativePath(path: string): string {\n return path.replace(/\\\\/g, \"/\");\n}\n\nfunction isIgnorableMarketplaceResidue(path: string): boolean {\n return path === \".DS_Store\";\n}\n\nexport async function publishMarketplaceSkill(options: MarketplaceSkillPublishOptions): Promise<{\n created: boolean;\n slug: string;\n packageName: string;\n fileCount: number;\n}> {\n const {\n skillDir: rawSkillDir,\n slug: explicitSlug,\n metaFile,\n packageName: explicitPackageName,\n scope: explicitScope,\n name: explicitName,\n summary: explicitSummary,\n summaryI18n: explicitSummaryI18n,\n description: explicitDescription,\n descriptionI18n: explicitDescriptionI18n,\n tags: explicitTags,\n sourceRepo: explicitSourceRepo,\n homepage: explicitHomepage,\n publishedAt: explicitPublishedAt,\n updatedAt: explicitUpdatedAt,\n apiBaseUrl,\n token: explicitToken,\n requireExisting\n } = options;\n const skillDir = resolve(rawSkillDir);\n if (!existsSync(skillDir)) {\n throw new Error(`Skill directory not found: ${skillDir}`);\n }\n\n const files = collectMarketplaceSkillFiles(skillDir);\n if (!files.some((file) => file.path === \"SKILL.md\")) {\n throw new Error(`Skill directory must include SKILL.md: ${skillDir}`);\n }\n\n const parsedFrontmatter = parseSkillFrontmatter(readFileSync(join(skillDir, \"SKILL.md\"), \"utf8\"));\n const metadata = readMarketplaceMetadataFile(skillDir, metaFile);\n const slug = validateSkillSlug(explicitSlug?.trim() || metadata.slug || basename(skillDir), \"slug\");\n const name = explicitName?.trim() || metadata.name || parsedFrontmatter.name || slug;\n const description = explicitDescription?.trim()\n || metadata.description\n || metadata.descriptionI18n?.en\n || parsedFrontmatter.description;\n const summary = explicitSummary?.trim()\n || metadata.summary\n || metadata.summaryI18n?.en\n || parsedFrontmatter.summary\n || description\n || `${slug} skill`;\n const summaryI18n = buildLocalizedTextMap(summary, parsedFrontmatter.summaryI18n, metadata.summaryI18n, explicitSummaryI18n);\n const descriptionI18n = description\n ? buildLocalizedTextMap(description, parsedFrontmatter.descriptionI18n, metadata.descriptionI18n, explicitDescriptionI18n)\n : undefined;\n const tags = normalizeTags(explicitTags && explicitTags.length > 0 ? explicitTags : (metadata.tags ?? parsedFrontmatter.tags));\n\n const apiBase = resolveMarketplaceApiBase(apiBaseUrl);\n const adminToken = resolveMarketplaceAdminToken(explicitToken);\n const platformAuth = new PlatformAuthCommands();\n const currentUser = adminToken ? null : await platformAuth.me();\n const packageName = resolvePublishPackageName({\n explicitPackageName,\n explicitScope,\n slug,\n adminTokenPresent: Boolean(adminToken),\n currentUser\n });\n const authToken = adminToken ?? currentUser?.token;\n if (!authToken) {\n throw new Error(\"Publishing requires either a marketplace admin token or an active NextClaw platform login.\");\n }\n\n const response = await runWithMarketplaceNetworkRetry(() =>\n fetch(`${apiBase}/api/v1/skills/publish`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n Authorization: `Bearer ${authToken}`\n },\n body: JSON.stringify({\n slug,\n packageName,\n name,\n summary,\n summaryI18n,\n description,\n descriptionI18n,\n tags,\n sourceRepo: explicitSourceRepo?.trim() || metadata.sourceRepo,\n homepage: explicitHomepage?.trim() || metadata.homepage,\n publishedAt: explicitPublishedAt?.trim() || metadata.publishedAt,\n updatedAt: explicitUpdatedAt?.trim() || metadata.updatedAt,\n requireExisting,\n files\n })\n })\n );\n\n const payload = await readMarketplaceEnvelope<{\n created: boolean;\n fileCount: number;\n item?: {\n slug?: string;\n packageName?: string;\n };\n }>(response);\n\n if (!payload.ok || !payload.data) {\n const message = payload.error?.message || `marketplace publish failed: HTTP ${response.status}`;\n throw new Error(message);\n }\n\n return {\n created: payload.data.created,\n slug: payload.data.item?.slug || slug,\n packageName: payload.data.item?.packageName || packageName,\n fileCount: payload.data.fileCount\n };\n}\n\nfunction resolveBuiltinSkillDir(workdir: string, skillName: string): string {\n const skillDir = new SkillManager({ workspace: workdir }).resolveBuiltinSkillDir(skillName);\n if (!skillDir) {\n throw new Error(`Built-in skill not found in local installation: ${skillName}`);\n }\n return skillDir;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"marketplace.utils.js","names":[],"sources":["../../../../src/cli/commands/skills/marketplace.utils.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { basename, join, resolve } from \"node:path\";\nimport {\n buildLocalizedTextMap,\n parseSkillFrontmatter,\n readMarketplaceMetadataFile,\n type LocalizedTextMap\n} from \"./marketplace.metadata.js\";\nimport { PlatformAuthCommands } from \"@nextclaw-service/commands/platform-auth/index.js\";\nimport {\n collectMarketplaceSkillFiles,\n readMarketplaceEnvelope,\n resolveMarketplaceAdminToken,\n resolveMarketplaceApiBase,\n} from \"./marketplace-client.js\";\nimport {\n normalizeTags,\n resolvePublishPackageName,\n validateSkillSlug\n} from \"./marketplace-identity.utils.js\";\nimport { runWithMarketplaceNetworkRetry } from \"./marketplace-network-retry.js\";\nexport {\n installMarketplaceSkill,\n updateInstalledMarketplaceSkill,\n type MarketplaceSkillInstallOptions\n} from \"./utils/marketplace-skill-lifecycle.utils.js\";\n\nexport type MarketplaceSkillPublishOptions = {\n skillDir: string;\n metaFile?: string;\n slug?: string;\n packageName?: string;\n scope?: string;\n name?: string;\n summary?: string;\n summaryI18n?: LocalizedTextMap;\n description?: string;\n descriptionI18n?: LocalizedTextMap;\n author?: string;\n tags?: string[];\n sourceRepo?: string;\n homepage?: string;\n publishedAt?: string;\n updatedAt?: string;\n apiBaseUrl?: string;\n token?: string;\n requireExisting?: boolean;\n};\n\nexport async function publishMarketplaceSkill(options: MarketplaceSkillPublishOptions): Promise<{\n created: boolean;\n slug: string;\n packageName: string;\n fileCount: number;\n}> {\n const {\n skillDir: rawSkillDir,\n slug: explicitSlug,\n metaFile,\n packageName: explicitPackageName,\n scope: explicitScope,\n name: explicitName,\n summary: explicitSummary,\n summaryI18n: explicitSummaryI18n,\n description: explicitDescription,\n descriptionI18n: explicitDescriptionI18n,\n tags: explicitTags,\n sourceRepo: explicitSourceRepo,\n homepage: explicitHomepage,\n publishedAt: explicitPublishedAt,\n updatedAt: explicitUpdatedAt,\n apiBaseUrl,\n token: explicitToken,\n requireExisting\n } = options;\n const skillDir = resolve(rawSkillDir);\n if (!existsSync(skillDir)) {\n throw new Error(`Skill directory not found: ${skillDir}`);\n }\n\n const files = collectMarketplaceSkillFiles(skillDir);\n if (!files.some((file) => file.path === \"SKILL.md\")) {\n throw new Error(`Skill directory must include SKILL.md: ${skillDir}`);\n }\n\n const parsedFrontmatter = parseSkillFrontmatter(readFileSync(join(skillDir, \"SKILL.md\"), \"utf8\"));\n const metadata = readMarketplaceMetadataFile(skillDir, metaFile);\n const slug = validateSkillSlug(explicitSlug?.trim() || metadata.slug || basename(skillDir), \"slug\");\n const name = explicitName?.trim() || metadata.name || parsedFrontmatter.name || slug;\n const description = explicitDescription?.trim()\n || metadata.description\n || metadata.descriptionI18n?.en\n || parsedFrontmatter.description;\n const summary = explicitSummary?.trim()\n || metadata.summary\n || metadata.summaryI18n?.en\n || parsedFrontmatter.summary\n || description\n || `${slug} skill`;\n const summaryI18n = buildLocalizedTextMap(summary, parsedFrontmatter.summaryI18n, metadata.summaryI18n, explicitSummaryI18n);\n const descriptionI18n = description\n ? buildLocalizedTextMap(description, parsedFrontmatter.descriptionI18n, metadata.descriptionI18n, explicitDescriptionI18n)\n : undefined;\n const tags = normalizeTags(explicitTags && explicitTags.length > 0 ? explicitTags : (metadata.tags ?? parsedFrontmatter.tags));\n\n const apiBase = resolveMarketplaceApiBase(apiBaseUrl);\n const adminToken = resolveMarketplaceAdminToken(explicitToken);\n const platformAuth = new PlatformAuthCommands();\n const currentUser = adminToken ? null : await platformAuth.me();\n const packageName = resolvePublishPackageName({\n explicitPackageName,\n explicitScope,\n slug,\n adminTokenPresent: Boolean(adminToken),\n currentUser\n });\n const authToken = adminToken ?? currentUser?.token;\n if (!authToken) {\n throw new Error(\"Publishing requires either a marketplace admin token or an active NextClaw platform login.\");\n }\n\n const response = await runWithMarketplaceNetworkRetry(() =>\n fetch(`${apiBase}/api/v1/skills/publish`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n Authorization: `Bearer ${authToken}`\n },\n body: JSON.stringify({\n slug,\n packageName,\n name,\n summary,\n summaryI18n,\n description,\n descriptionI18n,\n tags,\n sourceRepo: explicitSourceRepo?.trim() || metadata.sourceRepo,\n homepage: explicitHomepage?.trim() || metadata.homepage,\n publishedAt: explicitPublishedAt?.trim() || metadata.publishedAt,\n updatedAt: explicitUpdatedAt?.trim() || metadata.updatedAt,\n requireExisting,\n files\n })\n })\n );\n\n const payload = await readMarketplaceEnvelope<{\n created: boolean;\n fileCount: number;\n item?: {\n slug?: string;\n packageName?: string;\n };\n }>(response);\n\n if (!payload.ok || !payload.data) {\n const message = payload.error?.message || `marketplace publish failed: HTTP ${response.status}`;\n throw new Error(message);\n }\n\n return {\n created: payload.data.created,\n slug: payload.data.item?.slug || slug,\n packageName: payload.data.item?.packageName || packageName,\n fileCount: payload.data.fileCount\n };\n}\n"],"mappings":";;;;;;;;;;AAiDA,eAAsB,wBAAwB,SAK3C;CACD,MAAM,EACJ,UAAU,aACV,MAAM,cACN,UACA,aAAa,qBACb,OAAO,eACP,MAAM,cACN,SAAS,iBACT,aAAa,qBACb,aAAa,qBACb,iBAAiB,yBACjB,MAAM,cACN,YAAY,oBACZ,UAAU,kBACV,aAAa,qBACb,WAAW,mBACX,YACA,OAAO,eACP,oBACE;CACJ,MAAM,WAAW,QAAQ,YAAY;AACrC,KAAI,CAAC,WAAW,SAAS,CACvB,OAAM,IAAI,MAAM,8BAA8B,WAAW;CAG3D,MAAM,QAAQ,6BAA6B,SAAS;AACpD,KAAI,CAAC,MAAM,MAAM,SAAS,KAAK,SAAS,WAAW,CACjD,OAAM,IAAI,MAAM,0CAA0C,WAAW;CAGvE,MAAM,oBAAoB,sBAAsB,aAAa,KAAK,UAAU,WAAW,EAAE,OAAO,CAAC;CACjG,MAAM,WAAW,4BAA4B,UAAU,SAAS;CAChE,MAAM,OAAO,kBAAkB,cAAc,MAAM,IAAI,SAAS,QAAQ,SAAS,SAAS,EAAE,OAAO;CACnG,MAAM,OAAO,cAAc,MAAM,IAAI,SAAS,QAAQ,kBAAkB,QAAQ;CAChF,MAAM,cAAc,qBAAqB,MAAM,IAC1C,SAAS,eACT,SAAS,iBAAiB,MAC1B,kBAAkB;CACvB,MAAM,UAAU,iBAAiB,MAAM,IAClC,SAAS,WACT,SAAS,aAAa,MACtB,kBAAkB,WAClB,eACA,GAAG,KAAK;CACb,MAAM,cAAc,sBAAsB,SAAS,kBAAkB,aAAa,SAAS,aAAa,oBAAoB;CAC5H,MAAM,kBAAkB,cACpB,sBAAsB,aAAa,kBAAkB,iBAAiB,SAAS,iBAAiB,wBAAwB,GACxH,KAAA;CACJ,MAAM,OAAO,cAAc,gBAAgB,aAAa,SAAS,IAAI,eAAgB,SAAS,QAAQ,kBAAkB,KAAM;CAE9H,MAAM,UAAU,0BAA0B,WAAW;CACrD,MAAM,aAAa,6BAA6B,cAAc;CAC9D,MAAM,eAAe,IAAI,sBAAsB;CAC/C,MAAM,cAAc,aAAa,OAAO,MAAM,aAAa,IAAI;CAC/D,MAAM,cAAc,0BAA0B;EAC5C;EACA;EACA;EACA,mBAAmB,QAAQ,WAAW;EACtC;EACD,CAAC;CACF,MAAM,YAAY,cAAc,aAAa;AAC7C,KAAI,CAAC,UACH,OAAM,IAAI,MAAM,6FAA6F;CAG/G,MAAM,WAAW,MAAM,qCACrB,MAAM,GAAG,QAAQ,yBAAyB;EACxC,QAAQ;EACR,SAAS;GACP,gBAAgB;GAChB,eAAe,UAAU;GAC1B;EACD,MAAM,KAAK,UAAU;GACnB;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA,YAAY,oBAAoB,MAAM,IAAI,SAAS;GACnD,UAAU,kBAAkB,MAAM,IAAI,SAAS;GAC/C,aAAa,qBAAqB,MAAM,IAAI,SAAS;GACrD,WAAW,mBAAmB,MAAM,IAAI,SAAS;GACjD;GACA;GACD,CAAC;EACH,CAAC,CACH;CAED,MAAM,UAAU,MAAM,wBAOnB,SAAS;AAEZ,KAAI,CAAC,QAAQ,MAAM,CAAC,QAAQ,MAAM;EAChC,MAAM,UAAU,QAAQ,OAAO,WAAW,oCAAoC,SAAS;AACvF,QAAM,IAAI,MAAM,QAAQ;;AAG1B,QAAO;EACL,SAAS,QAAQ,KAAK;EACtB,MAAM,QAAQ,KAAK,MAAM,QAAQ;EACjC,aAAa,QAAQ,KAAK,MAAM,eAAe;EAC/C,WAAW,QAAQ,KAAK;EACzB"}
@@ -0,0 +1,39 @@
1
+ //#region src/cli/commands/skills/stores/marketplace-install-state.store.d.ts
2
+ type MarketplaceSkillUpdateStatus = "outdated" | "up-to-date" | "unknown";
3
+ declare const MARKETPLACE_INSTALL_STATE_FILE = ".nextclaw-install.json";
4
+ type MarketplaceSkillInstallStateFileEntry = {
5
+ path: string;
6
+ sha256: string;
7
+ };
8
+ type MarketplaceSkillInstallState = {
9
+ schemaVersion: 1;
10
+ type: "skill";
11
+ source: "marketplace";
12
+ slug: string;
13
+ packageName?: string;
14
+ apiBaseUrl: string;
15
+ installedAt: string;
16
+ marketplaceUpdatedAt?: string;
17
+ files: MarketplaceSkillInstallStateFileEntry[];
18
+ };
19
+ declare function hashMarketplaceFileBytes(bytes: Buffer): string;
20
+ declare function isLocalMarketplaceInstallStateFile(path: string): boolean;
21
+ declare function buildMarketplaceSkillInstallState(params: {
22
+ item: {
23
+ slug: string;
24
+ packageName?: string;
25
+ updatedAt?: string;
26
+ };
27
+ apiBase: string;
28
+ files: MarketplaceSkillInstallStateFileEntry[];
29
+ }): MarketplaceSkillInstallState;
30
+ declare function writeMarketplaceSkillInstallState(params: {
31
+ destinationDir: string;
32
+ state: MarketplaceSkillInstallState;
33
+ }): void;
34
+ declare function readMarketplaceSkillInstallState(destinationDir: string): MarketplaceSkillInstallState | null;
35
+ declare function hasLocalMarketplaceSkillDrift(destinationDir: string, state: MarketplaceSkillInstallState): boolean;
36
+ declare function resolveMarketplaceSkillUpdateStatus(state: MarketplaceSkillInstallState | null, remoteUpdatedAt: string | undefined): MarketplaceSkillUpdateStatus;
37
+ //#endregion
38
+ export { MARKETPLACE_INSTALL_STATE_FILE, MarketplaceSkillInstallState, MarketplaceSkillInstallStateFileEntry, MarketplaceSkillUpdateStatus, buildMarketplaceSkillInstallState, hasLocalMarketplaceSkillDrift, hashMarketplaceFileBytes, isLocalMarketplaceInstallStateFile, readMarketplaceSkillInstallState, resolveMarketplaceSkillUpdateStatus, writeMarketplaceSkillInstallState };
39
+ //# sourceMappingURL=marketplace-install-state.store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"marketplace-install-state.store.d.ts","names":[],"sources":["../../../../../src/cli/commands/skills/stores/marketplace-install-state.store.ts"],"mappings":";KAIY,4BAAA;AAAA,cAEC,8BAAA;AAAA,KAGD,qCAAA;EACV,IAAA;EACA,MAAA;AAAA;AAAA,KAGU,4BAAA;EACV,aAAA;EACA,IAAA;EACA,MAAA;EACA,IAAA;EACA,WAAA;EACA,UAAA;EACA,WAAA;EACA,oBAAA;EACA,KAAA,EAAO,qCAAA;AAAA;AAAA,iBAGO,wBAAA,CAAyB,KAAA,EAAO,MAAA;AAAA,iBAIhC,kCAAA,CAAmC,IAAA;AAAA,iBAKnC,iCAAA,CAAkC,MAAA;EAChD,IAAA;IACE,IAAA;IACA,WAAA;IACA,SAAA;EAAA;EAEF,OAAA;EACA,KAAA,EAAO,qCAAA;AAAA,IACL,4BAAA;AAAA,iBAeY,iCAAA,CAAkC,MAAA;EAChD,cAAA;EACA,KAAA,EAAO,4BAAA;AAAA;AAAA,iBASO,gCAAA,CAAiC,cAAA,WAAyB,4BAAA;AAAA,iBAyB1D,6BAAA,CAA8B,cAAA,UAAwB,KAAA,EAAO,4BAAA;AAAA,iBAU7D,mCAAA,CACd,KAAA,EAAO,4BAAA,SACP,eAAA,uBACC,4BAAA"}