@nextclaw/server 0.6.4 → 0.6.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.
package/dist/index.d.ts CHANGED
@@ -296,6 +296,21 @@ type ChatCapabilitiesView = {
296
296
  stopSupported: boolean;
297
297
  stopReason?: string;
298
298
  };
299
+ type ChatCommandOptionView = {
300
+ name: string;
301
+ description: string;
302
+ type: "string" | "boolean" | "number";
303
+ required?: boolean;
304
+ };
305
+ type ChatCommandView = {
306
+ name: string;
307
+ description: string;
308
+ options?: ChatCommandOptionView[];
309
+ };
310
+ type ChatCommandsView = {
311
+ commands: ChatCommandView[];
312
+ total: number;
313
+ };
299
314
  type ChatTurnStopRequest = {
300
315
  runId: string;
301
316
  sessionKey?: string;
@@ -491,7 +506,9 @@ type ConfigActionExecuteResult = {
491
506
  };
492
507
  type MarketplaceItemType = "plugin" | "skill";
493
508
  type MarketplaceSort = "relevance" | "updated";
494
- type MarketplaceInstallKind = "npm" | "clawhub" | "git" | "builtin";
509
+ type MarketplacePluginInstallKind = "npm";
510
+ type MarketplaceSkillInstallKind = "builtin" | "marketplace";
511
+ type MarketplaceInstallKind = MarketplacePluginInstallKind | MarketplaceSkillInstallKind;
495
512
  type MarketplaceInstallSpec = {
496
513
  kind: MarketplaceInstallKind;
497
514
  spec: string;
@@ -522,7 +539,7 @@ type MarketplaceSkillContentView = {
522
539
  slug: string;
523
540
  name: string;
524
541
  install: MarketplaceInstallSpec;
525
- source: "workspace" | "builtin" | "git" | "remote";
542
+ source: "builtin" | "marketplace" | "remote";
526
543
  raw: string;
527
544
  metadataRaw?: string;
528
545
  bodyRaw: string;
@@ -578,11 +595,9 @@ type MarketplaceInstalledView = {
578
595
  };
579
596
  type MarketplaceInstallSkillParams = {
580
597
  slug: string;
581
- kind?: MarketplaceInstallKind;
598
+ kind?: MarketplaceSkillInstallKind;
582
599
  skill?: string;
583
600
  installPath?: string;
584
- version?: string;
585
- registry?: string;
586
601
  force?: boolean;
587
602
  };
588
603
  type MarketplacePluginInstallRequest = {
@@ -592,11 +607,9 @@ type MarketplacePluginInstallRequest = {
592
607
  type MarketplaceSkillInstallRequest = {
593
608
  type?: "skill";
594
609
  spec: string;
595
- kind?: MarketplaceInstallKind;
610
+ kind?: MarketplaceSkillInstallKind;
596
611
  skill?: string;
597
612
  installPath?: string;
598
- version?: string;
599
- registry?: string;
600
613
  force?: boolean;
601
614
  };
602
615
  type MarketplacePluginInstallResult = {
@@ -758,4 +771,4 @@ declare function deleteSession(configPath: string, key: string): boolean;
758
771
  declare function updateRuntime(configPath: string, patch: RuntimeConfigUpdate): Pick<ConfigView, "agents" | "bindings" | "session">;
759
772
  declare function updateSecrets(configPath: string, patch: SecretsConfigUpdate): SecretsView;
760
773
 
761
- export { type AgentBindingView, type AgentProfileView, type ApiError, type ApiResponse, type AppMetaView, type BindingPeerView, type ChannelSpecView, type ChatCapabilitiesView, type ChatRunListView, type ChatRunState, type ChatRunView, type ChatTurnRequest, type ChatTurnResult, type ChatTurnStopRequest, type ChatTurnStopResult, type ChatTurnStreamEvent, type ChatTurnView, type ConfigActionExecuteRequest, type ConfigActionExecuteResult, type ConfigActionManifest, type ConfigActionType, type ConfigMetaView, type ConfigSchemaResponse, type ConfigUiHint, type ConfigUiHints, type ConfigView, type CronActionResult, type CronEnableRequest, type CronJobStateView, type CronJobView, type CronListView, type CronPayloadView, type CronRunRequest, type CronScheduleView, type MarketplaceApiConfig, type MarketplaceInstallKind, type MarketplaceInstallSkillParams, type MarketplaceInstallSpec, type MarketplaceInstalledRecord, type MarketplaceInstalledView, type MarketplaceInstaller, type MarketplaceItemSummary, type MarketplaceItemType, type MarketplaceItemView, type MarketplaceListView, type MarketplaceLocalizedTextMap, type MarketplacePluginContentView, type MarketplacePluginInstallRequest, type MarketplacePluginInstallResult, type MarketplacePluginManageAction, type MarketplacePluginManageRequest, type MarketplacePluginManageResult, type MarketplaceRecommendationView, type MarketplaceSkillContentView, type MarketplaceSkillInstallRequest, type MarketplaceSkillInstallResult, type MarketplaceSkillManageAction, type MarketplaceSkillManageRequest, type MarketplaceSkillManageResult, type MarketplaceSort, type ProviderAuthImportResult, type ProviderAuthPollRequest, type ProviderAuthPollResult, type ProviderAuthStartResult, type ProviderConfigUpdate, type ProviderConfigView, type ProviderConnectionTestRequest, type ProviderConnectionTestResult, type ProviderCreateRequest, type ProviderCreateResult, type ProviderDeleteResult, type ProviderSpecView, type RuntimeConfigUpdate, type SecretProviderEnvView, type SecretProviderExecView, type SecretProviderFileView, type SecretProviderView, type SecretRefView, type SecretSourceView, type SecretsConfigUpdate, type SecretsView, type SessionConfigView, type SessionEntryView, type SessionEventView, type SessionHistoryView, type SessionMessageView, type SessionPatchUpdate, type SessionsListView, type UiChatRuntime, type UiServerEvent, type UiServerHandle, type UiServerOptions, buildConfigMeta, buildConfigSchemaView, buildConfigView, createCustomProvider, createUiRouter, deleteCustomProvider, deleteSession, executeConfigAction, getSessionHistory, listSessions, loadConfigOrDefault, patchSession, startUiServer, testProviderConnection, updateChannel, updateModel, updateProvider, updateRuntime, updateSecrets };
774
+ export { type AgentBindingView, type AgentProfileView, type ApiError, type ApiResponse, type AppMetaView, type BindingPeerView, type ChannelSpecView, type ChatCapabilitiesView, type ChatCommandOptionView, type ChatCommandView, type ChatCommandsView, type ChatRunListView, type ChatRunState, type ChatRunView, type ChatTurnRequest, type ChatTurnResult, type ChatTurnStopRequest, type ChatTurnStopResult, type ChatTurnStreamEvent, type ChatTurnView, type ConfigActionExecuteRequest, type ConfigActionExecuteResult, type ConfigActionManifest, type ConfigActionType, type ConfigMetaView, type ConfigSchemaResponse, type ConfigUiHint, type ConfigUiHints, type ConfigView, type CronActionResult, type CronEnableRequest, type CronJobStateView, type CronJobView, type CronListView, type CronPayloadView, type CronRunRequest, type CronScheduleView, type MarketplaceApiConfig, type MarketplaceInstallKind, type MarketplaceInstallSkillParams, type MarketplaceInstallSpec, type MarketplaceInstalledRecord, type MarketplaceInstalledView, type MarketplaceInstaller, type MarketplaceItemSummary, type MarketplaceItemType, type MarketplaceItemView, type MarketplaceListView, type MarketplaceLocalizedTextMap, type MarketplacePluginContentView, type MarketplacePluginInstallKind, type MarketplacePluginInstallRequest, type MarketplacePluginInstallResult, type MarketplacePluginManageAction, type MarketplacePluginManageRequest, type MarketplacePluginManageResult, type MarketplaceRecommendationView, type MarketplaceSkillContentView, type MarketplaceSkillInstallKind, type MarketplaceSkillInstallRequest, type MarketplaceSkillInstallResult, type MarketplaceSkillManageAction, type MarketplaceSkillManageRequest, type MarketplaceSkillManageResult, type MarketplaceSort, type ProviderAuthImportResult, type ProviderAuthPollRequest, type ProviderAuthPollResult, type ProviderAuthStartResult, type ProviderConfigUpdate, type ProviderConfigView, type ProviderConnectionTestRequest, type ProviderConnectionTestResult, type ProviderCreateRequest, type ProviderCreateResult, type ProviderDeleteResult, type ProviderSpecView, type RuntimeConfigUpdate, type SecretProviderEnvView, type SecretProviderExecView, type SecretProviderFileView, type SecretProviderView, type SecretRefView, type SecretSourceView, type SecretsConfigUpdate, type SecretsView, type SessionConfigView, type SessionEntryView, type SessionEventView, type SessionHistoryView, type SessionMessageView, type SessionPatchUpdate, type SessionsListView, type UiChatRuntime, type UiServerEvent, type UiServerHandle, type UiServerOptions, buildConfigMeta, buildConfigSchemaView, buildConfigView, createCustomProvider, createUiRouter, deleteCustomProvider, deleteSession, executeConfigAction, getSessionHistory, listSessions, loadConfigOrDefault, patchSession, startUiServer, testProviderConnection, updateChannel, updateModel, updateProvider, updateRuntime, updateSecrets };
package/dist/index.js CHANGED
@@ -5,12 +5,11 @@ import { cors } from "hono/cors";
5
5
  import { serve } from "@hono/node-server";
6
6
  import { WebSocketServer, WebSocket } from "ws";
7
7
  import { existsSync, readFileSync } from "fs";
8
- import { readFile as readFile3, stat } from "fs/promises";
8
+ import { readFile as readFile2, stat } from "fs/promises";
9
9
  import { join } from "path";
10
10
 
11
11
  // src/ui/router.ts
12
12
  import { Hono } from "hono";
13
- import { readFile as readFile2 } from "fs/promises";
14
13
  import * as NextclawCore from "@nextclaw/core";
15
14
  import { buildPluginStatusReport } from "@nextclaw/openclaw-compat";
16
15
 
@@ -1999,98 +1998,23 @@ function isSupportedMarketplaceSkillItem(item, knownSkillNames) {
1999
1998
  if (item.type !== "skill") {
2000
1999
  return false;
2001
2000
  }
2002
- if (item.install.kind === "git") {
2001
+ if (item.install.kind === "marketplace") {
2003
2002
  return true;
2004
2003
  }
2005
2004
  return item.install.kind === "builtin" && knownSkillNames.has(item.install.spec);
2006
2005
  }
2007
- function splitMarkdownFrontmatter(raw) {
2008
- const normalized = raw.replace(/\r\n/g, "\n");
2009
- const match = normalized.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
2010
- if (!match) {
2011
- return { bodyRaw: normalized };
2012
- }
2013
- return {
2014
- metadataRaw: match[1]?.trim() || void 0,
2015
- bodyRaw: match[2] ?? ""
2016
- };
2017
- }
2018
- async function loadLocalSkillMarkdown(options, skillName) {
2019
- const config = loadConfigOrDefault(options.configPath);
2020
- const loader = createSkillsLoader(getWorkspacePathFromConfig3(config));
2021
- if (!loader) {
2022
- return null;
2023
- }
2024
- const skillInfo = loader.listSkills(false).find((skill) => skill.name === skillName);
2025
- if (!skillInfo) {
2026
- return null;
2027
- }
2028
- try {
2029
- const raw = await readFile2(skillInfo.path, "utf-8");
2030
- return {
2031
- raw,
2032
- source: skillInfo.source
2033
- };
2034
- } catch {
2035
- return null;
2036
- }
2037
- }
2038
- function parseGitSkillSpec(rawSpec) {
2039
- const spec = rawSpec.trim();
2040
- if (!spec) {
2041
- return null;
2042
- }
2043
- const segments = spec.split("/").filter(Boolean);
2044
- if (segments.length < 3) {
2045
- return null;
2046
- }
2047
- return {
2048
- owner: segments[0] ?? "",
2049
- repo: segments[1] ?? "",
2050
- skillPath: segments.slice(2).join("/")
2051
- };
2052
- }
2053
- async function fetchTextWithFallback(urls) {
2054
- for (const url of urls) {
2055
- try {
2056
- const response = await fetch(url, {
2057
- method: "GET",
2058
- headers: {
2059
- Accept: "text/plain, text/markdown, application/json"
2060
- }
2061
- });
2062
- if (!response.ok) {
2063
- continue;
2064
- }
2065
- const text = await response.text();
2066
- if (text.trim().length === 0) {
2067
- continue;
2068
- }
2069
- return { text, url };
2070
- } catch {
2006
+ function findUnsupportedSkillInstallKind(items) {
2007
+ for (const item of items) {
2008
+ if (item.type !== "skill") {
2071
2009
  continue;
2072
2010
  }
2011
+ const kind = item.install.kind;
2012
+ if (kind !== "builtin" && kind !== "marketplace") {
2013
+ return kind;
2014
+ }
2073
2015
  }
2074
2016
  return null;
2075
2017
  }
2076
- async function loadGitSkillMarkdownFromSpec(rawSpec) {
2077
- const parsed = parseGitSkillSpec(rawSpec);
2078
- if (!parsed) {
2079
- return null;
2080
- }
2081
- const candidates = [
2082
- `https://raw.githubusercontent.com/${parsed.owner}/${parsed.repo}/main/${parsed.skillPath}/SKILL.md`,
2083
- `https://raw.githubusercontent.com/${parsed.owner}/${parsed.repo}/master/${parsed.skillPath}/SKILL.md`
2084
- ];
2085
- const result = await fetchTextWithFallback(candidates);
2086
- if (!result) {
2087
- return null;
2088
- }
2089
- return {
2090
- raw: result.text,
2091
- sourceUrl: result.url
2092
- };
2093
- }
2094
2018
  async function loadPluginReadmeFromNpm(spec) {
2095
2019
  const encodedSpec = encodeURIComponent(spec);
2096
2020
  const registryUrl = `https://registry.npmjs.org/${encodedSpec}`;
@@ -2124,40 +2048,6 @@ async function loadPluginReadmeFromNpm(spec) {
2124
2048
  return null;
2125
2049
  }
2126
2050
  }
2127
- async function buildSkillContentView(options, item) {
2128
- const local = await loadLocalSkillMarkdown(options, item.install.spec);
2129
- if (local) {
2130
- const split = splitMarkdownFrontmatter(local.raw);
2131
- return {
2132
- type: "skill",
2133
- slug: item.slug,
2134
- name: item.name,
2135
- install: item.install,
2136
- source: local.source,
2137
- raw: local.raw,
2138
- metadataRaw: split.metadataRaw,
2139
- bodyRaw: split.bodyRaw
2140
- };
2141
- }
2142
- if (item.install.kind === "git") {
2143
- const remote = await loadGitSkillMarkdownFromSpec(item.install.spec);
2144
- if (remote) {
2145
- const split = splitMarkdownFrontmatter(remote.raw);
2146
- return {
2147
- type: "skill",
2148
- slug: item.slug,
2149
- name: item.name,
2150
- install: item.install,
2151
- source: "git",
2152
- raw: remote.raw,
2153
- metadataRaw: split.metadataRaw,
2154
- bodyRaw: split.bodyRaw,
2155
- sourceUrl: remote.sourceUrl
2156
- };
2157
- }
2158
- }
2159
- return null;
2160
- }
2161
2051
  async function buildPluginContentView(item) {
2162
2052
  if (item.install.kind === "npm") {
2163
2053
  const npm = await loadPluginReadmeFromNpm(item.install.spec);
@@ -2276,8 +2166,6 @@ async function installMarketplaceSkill(params) {
2276
2166
  kind: params.body.kind,
2277
2167
  skill: params.body.skill,
2278
2168
  installPath: params.body.installPath,
2279
- version: params.body.version,
2280
- registry: params.body.registry,
2281
2169
  force: params.body.force
2282
2170
  });
2283
2171
  params.options.publish({ type: "config.updated", payload: { path: "skills" } });
@@ -2504,8 +2392,16 @@ function registerSkillMarketplaceRoutes(app, options, marketplaceBaseUrl) {
2504
2392
  if (!result.ok) {
2505
2393
  return c.json(err("MARKETPLACE_UNAVAILABLE", result.message), result.status);
2506
2394
  }
2395
+ const normalizedItems = result.data.items.map((item) => normalizeMarketplaceItemForUi(sanitizeMarketplaceItem(item)));
2396
+ const unsupportedKind = findUnsupportedSkillInstallKind(normalizedItems);
2397
+ if (unsupportedKind) {
2398
+ return c.json(
2399
+ err("MARKETPLACE_CONTRACT_MISMATCH", `unsupported skill install kind from marketplace api: ${unsupportedKind}`),
2400
+ 502
2401
+ );
2402
+ }
2507
2403
  const knownSkillNames = collectKnownSkillNames(options);
2508
- const filteredItems = result.data.items.map((item) => normalizeMarketplaceItemForUi(sanitizeMarketplaceItem(item))).filter((item) => isSupportedMarketplaceSkillItem(item, knownSkillNames));
2404
+ const filteredItems = normalizedItems.filter((item) => isSupportedMarketplaceSkillItem(item, knownSkillNames));
2509
2405
  const pageSize = Math.min(100, toPositiveInt(query.pageSize, 20));
2510
2406
  const requestedPage = toPositiveInt(query.page, 1);
2511
2407
  const totalPages = filteredItems.length === 0 ? 0 : Math.ceil(filteredItems.length / pageSize);
@@ -2531,6 +2427,13 @@ function registerSkillMarketplaceRoutes(app, options, marketplaceBaseUrl) {
2531
2427
  }
2532
2428
  const knownSkillNames = collectKnownSkillNames(options);
2533
2429
  const sanitized = normalizeMarketplaceItemForUi(sanitizeMarketplaceItem(result.data));
2430
+ const unsupportedKind = findUnsupportedSkillInstallKind([sanitized]);
2431
+ if (unsupportedKind) {
2432
+ return c.json(
2433
+ err("MARKETPLACE_CONTRACT_MISMATCH", `unsupported skill install kind from marketplace api: ${unsupportedKind}`),
2434
+ 502
2435
+ );
2436
+ }
2534
2437
  if (!isSupportedMarketplaceSkillItem(sanitized, knownSkillNames)) {
2535
2438
  return c.json(err("NOT_FOUND", "marketplace item not supported by nextclaw"), 404);
2536
2439
  }
@@ -2547,14 +2450,24 @@ function registerSkillMarketplaceRoutes(app, options, marketplaceBaseUrl) {
2547
2450
  }
2548
2451
  const knownSkillNames = collectKnownSkillNames(options);
2549
2452
  const sanitized = normalizeMarketplaceItemForUi(sanitizeMarketplaceItem(result.data));
2453
+ const unsupportedKind = findUnsupportedSkillInstallKind([sanitized]);
2454
+ if (unsupportedKind) {
2455
+ return c.json(
2456
+ err("MARKETPLACE_CONTRACT_MISMATCH", `unsupported skill install kind from marketplace api: ${unsupportedKind}`),
2457
+ 502
2458
+ );
2459
+ }
2550
2460
  if (!isSupportedMarketplaceSkillItem(sanitized, knownSkillNames)) {
2551
2461
  return c.json(err("NOT_FOUND", "marketplace item not supported by nextclaw"), 404);
2552
2462
  }
2553
- const content = await buildSkillContentView(options, sanitized);
2554
- if (!content) {
2555
- return c.json(err("NOT_FOUND", "skill markdown content not found"), 404);
2463
+ const contentResult = await fetchMarketplaceData({
2464
+ baseUrl: marketplaceBaseUrl,
2465
+ path: `/api/v1/skills/items/${slug}/content`
2466
+ });
2467
+ if (!contentResult.ok) {
2468
+ return c.json(err("MARKETPLACE_UNAVAILABLE", contentResult.message), contentResult.status);
2556
2469
  }
2557
- return c.json(ok(content));
2470
+ return c.json(ok(contentResult.data));
2558
2471
  });
2559
2472
  app.post("/api/marketplace/skills/install", async (c) => {
2560
2473
  const body = await readJson(c.req.raw);
@@ -2814,6 +2727,31 @@ function createUiRouter(options) {
2814
2727
  return c.json(err("CHAT_RUNTIME_FAILED", String(error)), 500);
2815
2728
  }
2816
2729
  });
2730
+ app.get("/api/chat/commands", async (c) => {
2731
+ try {
2732
+ const config = loadConfigOrDefault(options.configPath);
2733
+ const registry = new NextclawCore.CommandRegistry(config);
2734
+ const commands = registry.listSlashCommands().map((command) => ({
2735
+ name: command.name,
2736
+ description: command.description,
2737
+ ...Array.isArray(command.options) && command.options.length > 0 ? {
2738
+ options: command.options.map((option) => ({
2739
+ name: option.name,
2740
+ description: option.description,
2741
+ type: option.type,
2742
+ ...option.required === true ? { required: true } : {}
2743
+ }))
2744
+ } : {}
2745
+ }));
2746
+ const payload = {
2747
+ commands,
2748
+ total: commands.length
2749
+ };
2750
+ return c.json(ok(payload));
2751
+ } catch (error) {
2752
+ return c.json(err("CHAT_COMMANDS_FAILED", String(error)), 500);
2753
+ }
2754
+ });
2817
2755
  app.post("/api/chat/turn", async (c) => {
2818
2756
  if (!options.chatRuntime) {
2819
2757
  return c.json(err("NOT_AVAILABLE", "chat runtime unavailable"), 503);
@@ -3419,7 +3357,7 @@ function startUiServer(options) {
3419
3357
  join,
3420
3358
  getContent: async (path) => {
3421
3359
  try {
3422
- return await readFile3(path);
3360
+ return await readFile2(path);
3423
3361
  } catch {
3424
3362
  return null;
3425
3363
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextclaw/server",
3
- "version": "0.6.4",
3
+ "version": "0.6.5",
4
4
  "private": false,
5
5
  "description": "Nextclaw UI/API server.",
6
6
  "type": "module",
@@ -19,7 +19,7 @@
19
19
  "@nextclaw/runtime": "^0.1.1",
20
20
  "hono": "^4.6.2",
21
21
  "ws": "^8.18.0",
22
- "@nextclaw/core": "^0.7.1"
22
+ "@nextclaw/core": "^0.7.2"
23
23
  },
24
24
  "devDependencies": {
25
25
  "@types/node": "^20.17.6",