@nextclaw/service 0.1.11 → 0.1.13

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 (72) hide show
  1. package/dist/cli/commands/agent/agent-runtime.utils.d.ts +1 -2
  2. package/dist/cli/commands/agent/agent-runtime.utils.js +6 -50
  3. package/dist/cli/commands/agent/cli-agent-runner.utils.d.ts +0 -2
  4. package/dist/cli/commands/agent/cli-agent-runner.utils.js +7 -9
  5. package/dist/cli/commands/agent/services/agent-commands.service.js +0 -1
  6. package/dist/cli/commands/cron/services/cron-local.service.d.ts +1 -2
  7. package/dist/cli/commands/skills/index.js +1 -1
  8. package/dist/cli/commands/skills/marketplace-client.d.ts +11 -1
  9. package/dist/cli/commands/skills/marketplace-client.js +39 -1
  10. package/dist/cli/commands/skills/marketplace-command-options.utils.d.ts +1 -1
  11. package/dist/cli/commands/skills/marketplace.metadata.d.ts +3 -12
  12. package/dist/cli/commands/skills/marketplace.metadata.js +1 -87
  13. package/dist/cli/commands/skills/{marketplace.service.d.ts → marketplace.utils.d.ts} +1 -1
  14. package/dist/cli/commands/skills/{marketplace.service.js → marketplace.utils.js} +11 -47
  15. package/dist/cli/commands/skills/skills-query.service.d.ts +4 -37
  16. package/dist/cli/commands/skills/skills-query.service.js +16 -98
  17. package/dist/cli/commands/usage/services/llm-usage-command.service.d.ts +3 -5
  18. package/dist/cli/commands/usage/services/llm-usage-command.service.js +16 -26
  19. package/dist/commands/channel/channel-list-view.service.d.ts +0 -1
  20. package/dist/commands/channel/channel-list-view.service.js +6 -23
  21. package/dist/commands/channel/index.js +0 -1
  22. package/dist/commands/plugin/index.d.ts +2 -4
  23. package/dist/commands/plugin/index.js +8 -20
  24. package/dist/commands/plugin/{plugin-command-utils.d.ts → plugin-command.utils.d.ts} +1 -2
  25. package/dist/commands/plugin/{plugin-command-utils.js → plugin-command.utils.js} +2 -4
  26. package/dist/commands/plugin/{plugin-mutation-actions.d.ts → plugin-mutation-actions.utils.d.ts} +1 -1
  27. package/dist/commands/plugin/{plugin-mutation-actions.js → plugin-mutation-actions.utils.js} +2 -2
  28. package/dist/commands/service/services/autostart/linux-systemd-autostart.service.js +1 -1
  29. package/dist/commands/service/services/autostart/macos-launch-agent-autostart.service.js +1 -1
  30. package/dist/commands/service/services/autostart/windows-task-autostart.service.js +1 -1
  31. package/dist/launcher/npm-runtime-launcher.service.js +1 -1
  32. package/dist/service-runtime.service.d.ts +1 -1
  33. package/dist/service-runtime.service.js +7 -15
  34. package/dist/shared/controllers/gateway.controller.d.ts +3 -11
  35. package/dist/shared/controllers/gateway.controller.js +24 -180
  36. package/dist/shared/services/gateway/managers/gateway-plugin.manager.d.ts +2 -9
  37. package/dist/shared/services/gateway/managers/gateway-plugin.manager.js +30 -88
  38. package/dist/shared/services/gateway/nextclaw-app.service.d.ts +2 -7
  39. package/dist/shared/services/gateway/nextclaw-app.service.js +6 -16
  40. package/dist/shared/services/gateway/nextclaw-gateway-runtime.service.d.ts +4 -9
  41. package/dist/shared/services/gateway/nextclaw-gateway-runtime.service.js +12 -46
  42. package/dist/shared/services/gateway/{cron-job-handler.service.d.ts → utils/cron-job-handler.utils.d.ts} +3 -6
  43. package/dist/shared/services/gateway/utils/cron-job-handler.utils.js +57 -0
  44. package/dist/shared/services/marketplace/service-marketplace-installer.service.js +3 -3
  45. package/dist/shared/services/plugin/utils/plugin-runtime-bridge.utils.js +1 -1
  46. package/dist/shared/services/runtime/runtime-command.service.js +2 -2
  47. package/dist/shared/services/runtime/service-managed-startup.service.js +1 -1
  48. package/dist/shared/services/ui/companion-runtime.service.js +1 -1
  49. package/dist/shared/services/workspace/workspace-manager.service.js +8 -10
  50. package/dist/shared/utils/cli.utils.js +1 -1
  51. package/package.json +20 -20
  52. package/dist/cli/commands/usage/services/llm-usage-query.service.d.ts +0 -43
  53. package/dist/cli/commands/usage/services/llm-usage-query.service.js +0 -85
  54. package/dist/commands/plugin/development-source/dev-plugin-overrides.utils.d.ts +0 -18
  55. package/dist/commands/plugin/development-source/dev-plugin-overrides.utils.js +0 -111
  56. package/dist/commands/plugin/development-source/first-party-plugin-load-paths.utils.d.ts +0 -9
  57. package/dist/commands/plugin/development-source/first-party-plugin-load-paths.utils.js +0 -183
  58. package/dist/commands/plugin/plugin-extension-registry.d.ts +0 -10
  59. package/dist/commands/plugin/plugin-extension-registry.js +0 -35
  60. package/dist/commands/plugin/plugin-registry-loader.utils.d.ts +0 -14
  61. package/dist/commands/plugin/plugin-registry-loader.utils.js +0 -43
  62. package/dist/commands/plugin/plugin-reload.d.ts +0 -13
  63. package/dist/commands/plugin/plugin-reload.js +0 -42
  64. package/dist/shared/services/extensions/extension-lifecycle.service.d.ts +0 -63
  65. package/dist/shared/services/extensions/extension-lifecycle.service.js +0 -174
  66. package/dist/shared/services/extensions/service-extension-runtime.service.d.ts +0 -52
  67. package/dist/shared/services/extensions/service-extension-runtime.service.js +0 -325
  68. package/dist/shared/services/gateway/cron-job-handler.service.js +0 -100
  69. package/dist/shared/services/runtime/utils/skills-loader.utils.d.ts +0 -12
  70. package/dist/shared/services/runtime/utils/skills-loader.utils.js +0 -9
  71. package/dist/shared/services/session/service-deferred-ncp-agent.service.d.ts +0 -14
  72. package/dist/shared/services/session/service-deferred-ncp-agent.service.js +0 -85
@@ -3,8 +3,7 @@ import { AgentRuntimeSessionTypeDescribeParams, AgentRuntimeSessionTypeOption }
3
3
  //#region src/cli/commands/agent/agent-runtime.utils.d.ts
4
4
  type AgentRuntimeListEntry = AgentRuntimeSessionTypeOption & {
5
5
  default: boolean;
6
- source: "builtin" | "plugin";
7
- pluginId?: string;
6
+ source: "builtin";
8
7
  };
9
8
  type AgentRuntimeListResult = {
10
9
  defaultRuntime: string;
@@ -1,37 +1,11 @@
1
- import { buildReservedPluginLoadOptions } from "../../../commands/plugin/plugin-command-utils.js";
2
- import { resolveDevFirstPartyPluginDir } from "../../../commands/plugin/development-source/first-party-plugin-load-paths.utils.js";
3
- import { resolveDevPluginLoadingContext } from "../../../commands/plugin/development-source/dev-plugin-overrides.utils.js";
4
- import { toExtensionRegistry } from "../../../commands/plugin/plugin-extension-registry.js";
5
- import { logPluginDiagnostics } from "../../../commands/plugin/index.js";
6
- import { getWorkspacePath, loadConfig } from "@nextclaw/core";
7
- import { AgentRuntimeRegistry, BuiltinNarpRuntimeRegistrationService, DEFAULT_AGENT_RUNTIME_ENTRY_ID, NARP_HTTP_RUNTIME_KIND, NARP_STDIO_RUNTIME_KIND, resolveAgentRuntimeEntries } from "@nextclaw/kernel";
8
- import { loadOpenClawPlugins } from "@nextclaw/openclaw-compat";
1
+ import { loadConfig } from "@nextclaw/core";
2
+ import { AgentRuntimeRegistry, BuiltinNarpRuntimeProviderService, DEFAULT_AGENT_RUNTIME_ENTRY_ID, resolveAgentRuntimeEntries } from "@nextclaw/kernel";
9
3
  //#region src/cli/commands/agent/agent-runtime.utils.ts
10
4
  function createUnusedRuntime(_params) {
11
5
  throw new Error("runtime creation is not available during runtime listing");
12
6
  }
13
- function loadRuntimeOnlyPluginRegistry(config, workspaceDir) {
14
- const { configWithDevPluginOverrides, excludedRoots } = resolveDevPluginLoadingContext(config, resolveDevFirstPartyPluginDir(process.env.NEXTCLAW_DEV_FIRST_PARTY_PLUGIN_DIR));
15
- return loadOpenClawPlugins({
16
- config: configWithDevPluginOverrides,
17
- workspaceDir,
18
- includeBundled: false,
19
- kinds: ["agent-runtime"],
20
- excludeRoots: excludedRoots,
21
- ...buildReservedPluginLoadOptions(),
22
- logger: {
23
- info: (message) => console.log(message),
24
- warn: (message) => console.warn(message),
25
- error: (message) => console.error(message),
26
- debug: (message) => console.debug(message)
27
- }
28
- });
29
- }
30
7
  async function listAvailableAgentRuntimes(params) {
31
8
  const config = loadConfig();
32
- const pluginRegistry = loadRuntimeOnlyPluginRegistry(config, getWorkspacePath(config.agents.defaults.workspace));
33
- logPluginDiagnostics(pluginRegistry);
34
- const extensionRegistry = toExtensionRegistry(pluginRegistry);
35
9
  const runtimeRegistry = new AgentRuntimeRegistry();
36
10
  const runtimeSourceByKind = /* @__PURE__ */ new Map();
37
11
  const runtimeSourceByEntryId = /* @__PURE__ */ new Map();
@@ -41,31 +15,14 @@ async function listAvailableAgentRuntimes(params) {
41
15
  createRuntime: createUnusedRuntime
42
16
  });
43
17
  runtimeSourceByKind.set(DEFAULT_AGENT_RUNTIME_ENTRY_ID, { source: "builtin" });
44
- new BuiltinNarpRuntimeRegistrationService(() => config).registerInto(runtimeRegistry);
18
+ for (const provider of new BuiltinNarpRuntimeProviderService(() => config).createProviders()) runtimeRegistry.register(provider);
45
19
  runtimeSourceByKind.set("narp-http", { source: "builtin" });
46
20
  runtimeSourceByKind.set("narp-stdio", { source: "builtin" });
47
- for (const registration of extensionRegistry.ncpAgentRuntimes) {
48
- const normalizedKind = registration.kind.trim().toLowerCase();
49
- if (normalizedKind === NARP_HTTP_RUNTIME_KIND || normalizedKind === NARP_STDIO_RUNTIME_KIND) continue;
50
- runtimeRegistry.register({
51
- kind: registration.kind,
52
- label: registration.label,
53
- createRuntime: registration.createRuntime,
54
- describeSessionType: registration.describeSessionType
55
- });
56
- runtimeSourceByKind.set(registration.kind, {
57
- source: "plugin",
58
- pluginId: registration.pluginId
59
- });
60
- }
61
- const resolvedEntries = resolveAgentRuntimeEntries({
62
- config,
63
- providerKinds: runtimeRegistry.listProviderKinds()
64
- });
21
+ const resolvedEntries = resolveAgentRuntimeEntries({ config });
65
22
  runtimeRegistry.applyEntries(resolvedEntries);
66
23
  for (const entry of resolvedEntries.entries) {
67
24
  const source = runtimeSourceByKind.get(entry.type);
68
- runtimeSourceByEntryId.set(entry.id, source ?? { source: entry.id === DEFAULT_AGENT_RUNTIME_ENTRY_ID ? "builtin" : "plugin" });
25
+ runtimeSourceByEntryId.set(entry.id, source ?? { source: "builtin" });
69
26
  }
70
27
  const listed = await runtimeRegistry.listSessionTypes(params);
71
28
  return {
@@ -75,8 +32,7 @@ async function listAvailableAgentRuntimes(params) {
75
32
  return {
76
33
  ...runtime,
77
34
  default: runtime.value === listed.defaultType,
78
- source: source?.source ?? "plugin",
79
- ...source?.pluginId ? { pluginId: source.pluginId } : {}
35
+ source: source?.source ?? "builtin"
80
36
  };
81
37
  })
82
38
  };
@@ -1,5 +1,4 @@
1
1
  import { AgentCommandOptions } from "../../../shared/types/cli.types.js";
2
- import { NextclawExtensionRegistry } from "../../../commands/plugin/plugin-extension-registry.js";
3
2
  import { Config } from "@nextclaw/core";
4
3
  import { LlmProviderRuntime, NextclawKernel } from "@nextclaw/kernel";
5
4
 
@@ -10,7 +9,6 @@ declare function runCliAgentCommand(params: {
10
9
  config: Config;
11
10
  kernel: NextclawKernel;
12
11
  providerManager: LlmProviderRuntime;
13
- extensionRegistry: NextclawExtensionRegistry;
14
12
  }): Promise<void>;
15
13
  //#endregion
16
14
  export { runCliAgentCommand };
@@ -30,7 +30,7 @@ function createCliHistoryInterface() {
30
30
  return rl;
31
31
  }
32
32
  async function runCliInteractiveLoop(params) {
33
- const { config, logo, metadata, ncpAgent, sessionKey, sessionManager } = params;
33
+ const { agentRunRequests, config, logo, metadata, sessionKey, sessionManager } = params;
34
34
  console.log(`${logo} Interactive mode (type exit or Ctrl+C to quit)\n`);
35
35
  const rl = createCliHistoryInterface();
36
36
  let running = true;
@@ -45,7 +45,7 @@ async function runCliInteractiveLoop(params) {
45
45
  printAgentResponse(await dispatchPromptOverNcp({
46
46
  config,
47
47
  sessionManager,
48
- resolveNcpAgent: () => ncpAgent,
48
+ agentRunRequests,
49
49
  sessionKey,
50
50
  content: trimmed,
51
51
  metadata
@@ -53,12 +53,10 @@ async function runCliInteractiveLoop(params) {
53
53
  }
54
54
  }
55
55
  async function runCliAgentCommand(params) {
56
- const { config, extensionRegistry, kernel, logo, opts } = params;
56
+ const { config, kernel, logo, opts } = params;
57
57
  const sessionManager = kernel.sessions;
58
- kernel.extensions.loadExtensionRegistry(extensionRegistry);
58
+ await kernel.extensions.load({ config });
59
59
  await kernel.start();
60
- const ncpAgent = kernel.agentRuntimeManager.currentHandle;
61
- if (!ncpAgent) throw new Error("Kernel start completed without an agent runtime handle.");
62
60
  try {
63
61
  const sessionKey = opts.session ?? "cli:default";
64
62
  const sharedMetadata = buildCliSharedMetadata(opts);
@@ -66,7 +64,7 @@ async function runCliAgentCommand(params) {
66
64
  printAgentResponse(await dispatchPromptOverNcp({
67
65
  config,
68
66
  sessionManager,
69
- resolveNcpAgent: () => ncpAgent,
67
+ agentRunRequests: kernel.agentRunRequestManager,
70
68
  sessionKey,
71
69
  content: opts.message,
72
70
  metadata: sharedMetadata
@@ -77,12 +75,12 @@ async function runCliAgentCommand(params) {
77
75
  logo,
78
76
  config,
79
77
  sessionManager,
80
- ncpAgent,
78
+ agentRunRequests: kernel.agentRunRequestManager,
81
79
  sessionKey,
82
80
  metadata: sharedMetadata
83
81
  });
84
82
  } finally {
85
- await ncpAgent.dispose?.();
83
+ await kernel.dispose();
86
84
  }
87
85
  }
88
86
  //#endregion
@@ -37,7 +37,6 @@ var AgentCommands = class {
37
37
  console.log(head);
38
38
  console.log(` label: ${runtime.label}`);
39
39
  console.log(` source: ${runtime.source}`);
40
- if (runtime.pluginId) console.log(` pluginId: ${runtime.pluginId}`);
41
40
  console.log(` ready: ${runtime.ready === false ? "no" : "yes"}`);
42
41
  console.log(` reason: ${runtime.reason ?? "-"}`);
43
42
  console.log(` reasonMessage: ${runtime.reasonMessage ?? "-"}`);
@@ -1,6 +1,5 @@
1
1
  import { CronAddOptions } from "../../../../shared/types/cli.types.js";
2
2
  import { CronJobView } from "../utils/cron-job.utils.js";
3
- import { AutomationManager } from "@nextclaw/kernel";
4
3
  import { CronCreateRequest } from "@nextclaw/server";
5
4
 
6
5
  //#region src/cli/commands/cron/services/cron-local.service.d.ts
@@ -10,7 +9,7 @@ declare function createCronCreateRequest(opts: CronAddOptions): {
10
9
  };
11
10
  declare class CronLocalService {
12
11
  private readonly automation;
13
- constructor(automation?: AutomationManager);
12
+ constructor(automation?: any);
14
13
  readonly list: (all: boolean) => CronJobView[];
15
14
  readonly addRequest: (request: CronCreateRequest) => CronJobView;
16
15
  readonly add: (opts: CronAddOptions) => {
@@ -1,6 +1,6 @@
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.service.js";
3
+ import { installMarketplaceSkill, publishMarketplaceSkill } from "./marketplace.utils.js";
4
4
  import { SkillsQueryService } from "./skills-query.service.js";
5
5
  import { loadConfig } from "@nextclaw/core";
6
6
  //#region src/cli/commands/skills/index.ts
@@ -26,6 +26,16 @@ declare function fetchMarketplaceSkillFiles(apiBase: string, slug: string): Prom
26
26
  files: MarketplaceSkillFileManifestEntry[];
27
27
  }>;
28
28
  declare function fetchMarketplaceSkillFileBlob(apiBase: string, slug: string, file: MarketplaceSkillFileManifestEntry): Promise<Buffer>;
29
+ declare function collectMarketplaceSkillFiles(rootDir: string): Array<{
30
+ path: string;
31
+ contentBase64: string;
32
+ }>;
33
+ declare function writeMarketplaceSkillFiles(params: {
34
+ destinationDir: string;
35
+ files: MarketplaceSkillFileManifestEntry[];
36
+ apiBase: string;
37
+ slug: string;
38
+ }): Promise<void>;
29
39
  declare function readMarketplaceEnvelope<T>(response: Response): Promise<MarketplaceEnvelope<T>>;
30
40
  //#endregion
31
- export { MarketplaceSkillFileManifestEntry, fetchMarketplaceSkillFileBlob, fetchMarketplaceSkillFiles, fetchMarketplaceSkillItem, readMarketplaceEnvelope, resolveMarketplaceAdminToken, resolveMarketplaceApiBase };
41
+ export { MarketplaceSkillFileManifestEntry, collectMarketplaceSkillFiles, fetchMarketplaceSkillFileBlob, fetchMarketplaceSkillFiles, fetchMarketplaceSkillItem, readMarketplaceEnvelope, resolveMarketplaceAdminToken, resolveMarketplaceApiBase, writeMarketplaceSkillFiles };
@@ -1,4 +1,6 @@
1
1
  import { runWithMarketplaceNetworkRetry } from "./marketplace-network-retry.js";
2
+ import { mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
3
+ import { dirname, isAbsolute, join, relative, resolve } from "node:path";
2
4
  //#region src/cli/commands/skills/marketplace-client.ts
3
5
  const DEFAULT_MARKETPLACE_API_BASE = "https://marketplace-api.nextclaw.io";
4
6
  function resolveMarketplaceApiBase(explicitBase) {
@@ -54,6 +56,37 @@ async function fetchMarketplaceSkillFileBlob(apiBase, slug, file) {
54
56
  return Buffer.from(await response.arrayBuffer());
55
57
  });
56
58
  }
59
+ function collectMarketplaceSkillFiles(rootDir) {
60
+ const output = [];
61
+ const walk = (dir, prefix) => {
62
+ const entries = readdirSync(dir, { withFileTypes: true });
63
+ for (const entry of entries) {
64
+ const absolute = join(dir, entry.name);
65
+ const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
66
+ if (entry.isDirectory()) {
67
+ walk(absolute, relativePath);
68
+ continue;
69
+ }
70
+ if (!entry.isFile()) continue;
71
+ output.push({
72
+ path: relativePath,
73
+ contentBase64: readFileSync(absolute).toString("base64")
74
+ });
75
+ }
76
+ };
77
+ walk(rootDir, "");
78
+ return output;
79
+ }
80
+ async function writeMarketplaceSkillFiles(params) {
81
+ const { destinationDir, files, apiBase, slug } = params;
82
+ for (const file of files) {
83
+ const targetPath = resolve(destinationDir, ...file.path.split("/"));
84
+ const rel = relative(destinationDir, targetPath);
85
+ if (rel.startsWith("..") || isAbsolute(rel)) throw new Error(`Invalid marketplace file path: ${file.path}`);
86
+ mkdirSync(dirname(targetPath), { recursive: true });
87
+ writeFileSync(targetPath, file.contentBase64 ? decodeMarketplaceFileContent(file.path, file.contentBase64) : await fetchMarketplaceSkillFileBlob(apiBase, slug, file));
88
+ }
89
+ }
57
90
  async function readMarketplaceEnvelope(response) {
58
91
  const raw = await response.text();
59
92
  let payload;
@@ -77,8 +110,13 @@ function extractMarketplaceErrorMessage(raw, fallbackStatus) {
77
110
  return raw || `Request failed (${fallbackStatus})`;
78
111
  }
79
112
  }
113
+ function decodeMarketplaceFileContent(path, contentBase64) {
114
+ const normalized = contentBase64.replace(/\s+/g, "");
115
+ 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
+ return Buffer.from(normalized, "base64");
117
+ }
80
118
  function isRecord(value) {
81
119
  return typeof value === "object" && value !== null && !Array.isArray(value);
82
120
  }
83
121
  //#endregion
84
- export { fetchMarketplaceSkillFileBlob, fetchMarketplaceSkillFiles, fetchMarketplaceSkillItem, readMarketplaceEnvelope, resolveMarketplaceAdminToken, resolveMarketplaceApiBase };
122
+ export { collectMarketplaceSkillFiles, fetchMarketplaceSkillFileBlob, fetchMarketplaceSkillFiles, fetchMarketplaceSkillItem, readMarketplaceEnvelope, resolveMarketplaceAdminToken, resolveMarketplaceApiBase, writeMarketplaceSkillFiles };
@@ -1,4 +1,4 @@
1
- import { MarketplaceSkillPublishOptions } from "./marketplace.service.js";
1
+ import { MarketplaceSkillPublishOptions } from "./marketplace.utils.js";
2
2
 
3
3
  //#region src/cli/commands/skills/marketplace-command-options.utils.d.ts
4
4
  type MarketplacePublishCommandOptions = {
@@ -1,5 +1,6 @@
1
+ import { LocalizedTextMap, buildLocalizedTextMap, parseSkillFrontmatter } from "@nextclaw/kernel";
2
+
1
3
  //#region src/cli/commands/skills/marketplace.metadata.d.ts
2
- type LocalizedTextMap = Record<string, string>;
3
4
  type MarketplaceSkillPublishMetadata = {
4
5
  slug?: string;
5
6
  name?: string;
@@ -14,16 +15,6 @@ type MarketplaceSkillPublishMetadata = {
14
15
  publishedAt?: string;
15
16
  updatedAt?: string;
16
17
  };
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
18
  declare function readMarketplaceMetadataFile(skillDir: string, explicitMetaFile?: string): MarketplaceSkillPublishMetadata;
28
19
  //#endregion
29
- export { LocalizedTextMap, MarketplaceSkillPublishMetadata, buildLocalizedTextMap, parseSkillFrontmatter, readMarketplaceMetadataFile };
20
+ export { type LocalizedTextMap, MarketplaceSkillPublishMetadata, buildLocalizedTextMap, parseSkillFrontmatter, readMarketplaceMetadataFile };
@@ -1,39 +1,8 @@
1
+ import { buildLocalizedTextMap, parseSkillFrontmatter } from "@nextclaw/kernel";
1
2
  import { existsSync, readFileSync } from "node:fs";
2
3
  import { resolve } from "node:path";
3
- import { parse } from "yaml";
4
4
  //#region src/cli/commands/skills/marketplace.metadata.ts
5
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
6
  function readMarketplaceMetadataFile(skillDir, explicitMetaFile) {
38
7
  const metadataPath = resolveMarketplaceMetadataPath(skillDir, explicitMetaFile);
39
8
  if (!metadataPath) return {};
@@ -64,15 +33,6 @@ function resolveMarketplaceMetadataPath(skillDir, explicitMetaFile) {
64
33
  const resolved = explicitMetaFile?.trim() ? resolve(explicitMetaFile) : resolve(skillDir, DEFAULT_MARKETPLACE_META_FILENAME);
65
34
  return existsSync(resolved) ? resolved : void 0;
66
35
  }
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
36
  function readMetadataString(record, fieldName) {
77
37
  const value = record[fieldName];
78
38
  if (value == null) return;
@@ -102,52 +62,6 @@ function readMetadataLocalizedTextMap(record, fieldName) {
102
62
  }
103
63
  return Object.keys(localized).length > 0 ? localized : void 0;
104
64
  }
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
65
  function normalizeLocaleTag(raw) {
152
66
  return raw.trim().toLowerCase();
153
67
  }
@@ -1,6 +1,6 @@
1
1
  import { LocalizedTextMap } from "./marketplace.metadata.js";
2
2
 
3
- //#region src/cli/commands/skills/marketplace.service.d.ts
3
+ //#region src/cli/commands/skills/marketplace.utils.d.ts
4
4
  type MarketplaceSkillInstallKind = "builtin" | "marketplace";
5
5
  type MarketplaceSkillInstallOptions = {
6
6
  slug: string;
@@ -2,12 +2,13 @@ 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 { fetchMarketplaceSkillFileBlob, fetchMarketplaceSkillFiles, fetchMarketplaceSkillItem, readMarketplaceEnvelope, resolveMarketplaceAdminToken, resolveMarketplaceApiBase } from "./marketplace-client.js";
5
+ import { collectMarketplaceSkillFiles, fetchMarketplaceSkillFiles, fetchMarketplaceSkillItem, readMarketplaceEnvelope, resolveMarketplaceAdminToken, resolveMarketplaceApiBase, writeMarketplaceSkillFiles } from "./marketplace-client.js";
6
6
  import { normalizeTags, resolvePublishPackageName, validateSkillSelector, validateSkillSlug } from "./marketplace-identity.utils.js";
7
- import { SkillsLoader } from "@nextclaw/core";
8
- import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
9
- import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
10
- //#region src/cli/commands/skills/marketplace.service.ts
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";
11
+ //#region src/cli/commands/skills/marketplace.utils.ts
11
12
  async function installMarketplaceSkill(options) {
12
13
  const { slug, workdir: rawWorkdir, dir, force, apiBaseUrl } = options;
13
14
  const selector = validateSkillSelector(slug.trim(), "slug");
@@ -52,7 +53,7 @@ async function installMarketplaceSkill(options) {
52
53
  }
53
54
  function resolveMarketplaceSkillDestinationDir(params) {
54
55
  const { workdir, slug, dir } = params;
55
- const dirName = dir?.trim() || "skills";
56
+ const dirName = dir?.trim() || DEFAULT_SKILLS_DIR;
56
57
  return isAbsolute(dirName) ? resolve(dirName, slug) : resolve(workdir, dirName, slug);
57
58
  }
58
59
  function resolveBuiltinMarketplaceInstallResult(params) {
@@ -86,16 +87,6 @@ function prepareMarketplaceSkillDestinationDir(params) {
86
87
  mkdirSync(destinationDir, { recursive: true });
87
88
  return null;
88
89
  }
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
90
  function ensureInstalledMarketplaceSkill(destinationDir, slug) {
100
91
  if (!existsSync(join(destinationDir, "SKILL.md"))) throw new Error(`Marketplace skill ${slug} does not include SKILL.md`);
101
92
  }
@@ -143,7 +134,7 @@ async function publishMarketplaceSkill(options) {
143
134
  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
135
  const skillDir = resolve(rawSkillDir);
145
136
  if (!existsSync(skillDir)) throw new Error(`Skill directory not found: ${skillDir}`);
146
- const files = collectFiles(skillDir);
137
+ const files = collectMarketplaceSkillFiles(skillDir);
147
138
  if (!files.some((file) => file.path === "SKILL.md")) throw new Error(`Skill directory must include SKILL.md: ${skillDir}`);
148
139
  const parsedFrontmatter = parseSkillFrontmatter(readFileSync(join(skillDir, "SKILL.md"), "utf8"));
149
140
  const metadata = readMarketplaceMetadataFile(skillDir, metaFile);
@@ -202,37 +193,10 @@ async function publishMarketplaceSkill(options) {
202
193
  fileCount: payload.data.fileCount
203
194
  };
204
195
  }
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
196
  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");
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;
236
200
  }
237
201
  //#endregion
238
202
  export { installMarketplaceSkill, publishMarketplaceSkill };
@@ -1,5 +1,4 @@
1
- import { LocalizedTextMap } from "./marketplace.metadata.js";
2
- import { SkillScope } from "@nextclaw/core";
1
+ import { LocalizedTextMap } from "@nextclaw/kernel";
3
2
 
4
3
  //#region src/cli/commands/skills/skills-query.service.d.ts
5
4
  type MarketplaceSkillSort = "relevance" | "updated";
@@ -56,31 +55,6 @@ type MarketplaceSkillRecommendationView = {
56
55
  total: number;
57
56
  items: MarketplaceSkillItemSummary[];
58
57
  };
59
- type InstalledSkillSummaryView = {
60
- ref: string;
61
- name: string;
62
- path: string;
63
- relativePath: string | null;
64
- scope: SkillScope;
65
- source: SkillScope;
66
- summary: string | null;
67
- summaryI18n: LocalizedTextMap | null;
68
- description: string | null;
69
- descriptionI18n: LocalizedTextMap | null;
70
- author: string | null;
71
- tags: string[];
72
- always: boolean;
73
- };
74
- type InstalledSkillDetailView = InstalledSkillSummaryView & {
75
- metadata: Record<string, string> | null;
76
- raw: string;
77
- bodyRaw: string;
78
- };
79
- type InstalledSkillsListView = {
80
- workspace: string;
81
- total: number;
82
- skills: InstalledSkillSummaryView[];
83
- };
84
58
  type MarketplaceSkillsSearchView = MarketplaceSkillListView & {
85
59
  apiBaseUrl: string;
86
60
  };
@@ -98,11 +72,11 @@ declare class SkillsQueryService {
98
72
  workdir: string;
99
73
  query?: string;
100
74
  scope?: string;
101
- }) => InstalledSkillsListView;
75
+ }) => any;
102
76
  getInstalledInfo: (params: {
103
77
  workdir: string;
104
78
  selector: string;
105
- }) => InstalledSkillDetailView;
79
+ }) => any;
106
80
  searchMarketplaceSkills: (params: {
107
81
  apiBaseUrl?: string;
108
82
  query?: string;
@@ -120,17 +94,10 @@ declare class SkillsQueryService {
120
94
  scene?: string;
121
95
  limit?: string | number;
122
96
  }) => Promise<MarketplaceSkillsRecommendationResultView>;
123
- private buildInstalledSkillSummary;
124
- private buildInstalledSkillDetail;
125
- private matchesInstalledSkillQuery;
126
- private stripFrontmatter;
127
- private readAlwaysFlag;
128
- private buildRelativePath;
129
97
  private normalizeMarketplaceSummary;
130
98
  private normalizeMarketplaceItem;
131
99
  private normalizeMarketplaceContent;
132
100
  private normalizeMarketplaceInstallSpec;
133
- private normalizeInstalledScope;
134
101
  private normalizeMarketplaceSort;
135
102
  private normalizePositiveInteger;
136
103
  private normalizeRequiredString;
@@ -138,4 +105,4 @@ declare class SkillsQueryService {
138
105
  private fetchMarketplaceView;
139
106
  }
140
107
  //#endregion
141
- export { InstalledSkillDetailView, InstalledSkillSummaryView, InstalledSkillsListView, MarketplaceSkillInfoView, MarketplaceSkillsRecommendationResultView, MarketplaceSkillsSearchView, SkillsQueryService };
108
+ export { MarketplaceSkillInfoView, MarketplaceSkillsRecommendationResultView, MarketplaceSkillsSearchView, SkillsQueryService };