@nextclaw/server 0.6.3 → 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 +28 -9
- package/dist/index.js +74 -127
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -14,6 +14,10 @@ type ApiResponse<T> = {
|
|
|
14
14
|
ok: false;
|
|
15
15
|
error: ApiError;
|
|
16
16
|
};
|
|
17
|
+
type AppMetaView = {
|
|
18
|
+
name: string;
|
|
19
|
+
productVersion: string;
|
|
20
|
+
};
|
|
17
21
|
type ProviderConfigView = {
|
|
18
22
|
displayName?: string;
|
|
19
23
|
apiKeySet: boolean;
|
|
@@ -292,6 +296,21 @@ type ChatCapabilitiesView = {
|
|
|
292
296
|
stopSupported: boolean;
|
|
293
297
|
stopReason?: string;
|
|
294
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
|
+
};
|
|
295
314
|
type ChatTurnStopRequest = {
|
|
296
315
|
runId: string;
|
|
297
316
|
sessionKey?: string;
|
|
@@ -487,7 +506,9 @@ type ConfigActionExecuteResult = {
|
|
|
487
506
|
};
|
|
488
507
|
type MarketplaceItemType = "plugin" | "skill";
|
|
489
508
|
type MarketplaceSort = "relevance" | "updated";
|
|
490
|
-
type
|
|
509
|
+
type MarketplacePluginInstallKind = "npm";
|
|
510
|
+
type MarketplaceSkillInstallKind = "builtin" | "marketplace";
|
|
511
|
+
type MarketplaceInstallKind = MarketplacePluginInstallKind | MarketplaceSkillInstallKind;
|
|
491
512
|
type MarketplaceInstallSpec = {
|
|
492
513
|
kind: MarketplaceInstallKind;
|
|
493
514
|
spec: string;
|
|
@@ -518,7 +539,7 @@ type MarketplaceSkillContentView = {
|
|
|
518
539
|
slug: string;
|
|
519
540
|
name: string;
|
|
520
541
|
install: MarketplaceInstallSpec;
|
|
521
|
-
source: "
|
|
542
|
+
source: "builtin" | "marketplace" | "remote";
|
|
522
543
|
raw: string;
|
|
523
544
|
metadataRaw?: string;
|
|
524
545
|
bodyRaw: string;
|
|
@@ -574,11 +595,9 @@ type MarketplaceInstalledView = {
|
|
|
574
595
|
};
|
|
575
596
|
type MarketplaceInstallSkillParams = {
|
|
576
597
|
slug: string;
|
|
577
|
-
kind?:
|
|
598
|
+
kind?: MarketplaceSkillInstallKind;
|
|
578
599
|
skill?: string;
|
|
579
600
|
installPath?: string;
|
|
580
|
-
version?: string;
|
|
581
|
-
registry?: string;
|
|
582
601
|
force?: boolean;
|
|
583
602
|
};
|
|
584
603
|
type MarketplacePluginInstallRequest = {
|
|
@@ -588,11 +607,9 @@ type MarketplacePluginInstallRequest = {
|
|
|
588
607
|
type MarketplaceSkillInstallRequest = {
|
|
589
608
|
type?: "skill";
|
|
590
609
|
spec: string;
|
|
591
|
-
kind?:
|
|
610
|
+
kind?: MarketplaceSkillInstallKind;
|
|
592
611
|
skill?: string;
|
|
593
612
|
installPath?: string;
|
|
594
|
-
version?: string;
|
|
595
|
-
registry?: string;
|
|
596
613
|
force?: boolean;
|
|
597
614
|
};
|
|
598
615
|
type MarketplacePluginInstallResult = {
|
|
@@ -692,6 +709,7 @@ type UiServerOptions = {
|
|
|
692
709
|
host: string;
|
|
693
710
|
port: number;
|
|
694
711
|
configPath: string;
|
|
712
|
+
productVersion?: string;
|
|
695
713
|
corsOrigins?: string[] | "*";
|
|
696
714
|
staticDir?: string;
|
|
697
715
|
marketplace?: MarketplaceApiConfig;
|
|
@@ -709,6 +727,7 @@ declare function startUiServer(options: UiServerOptions): UiServerHandle;
|
|
|
709
727
|
|
|
710
728
|
type UiRouterOptions = {
|
|
711
729
|
configPath: string;
|
|
730
|
+
productVersion?: string;
|
|
712
731
|
publish: (event: UiServerEvent) => void;
|
|
713
732
|
marketplace?: MarketplaceApiConfig;
|
|
714
733
|
cronService?: InstanceType<typeof NextclawCore.CronService>;
|
|
@@ -752,4 +771,4 @@ declare function deleteSession(configPath: string, key: string): boolean;
|
|
|
752
771
|
declare function updateRuntime(configPath: string, patch: RuntimeConfigUpdate): Pick<ConfigView, "agents" | "bindings" | "session">;
|
|
753
772
|
declare function updateSecrets(configPath: string, patch: SecretsConfigUpdate): SecretsView;
|
|
754
773
|
|
|
755
|
-
export { type AgentBindingView, type AgentProfileView, type ApiError, type ApiResponse, 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
|
|
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
|
|
|
@@ -1351,6 +1350,13 @@ async function importProviderAuthFromCli(configPath, providerName) {
|
|
|
1351
1350
|
}
|
|
1352
1351
|
|
|
1353
1352
|
// src/ui/router.ts
|
|
1353
|
+
function buildAppMetaView(options) {
|
|
1354
|
+
const productVersion = options.productVersion?.trim();
|
|
1355
|
+
return {
|
|
1356
|
+
name: "NextClaw",
|
|
1357
|
+
productVersion: productVersion && productVersion.length > 0 ? productVersion : "0.0.0"
|
|
1358
|
+
};
|
|
1359
|
+
}
|
|
1354
1360
|
var DEFAULT_MARKETPLACE_API_BASE = "https://marketplace-api.nextclaw.io";
|
|
1355
1361
|
var NEXTCLAW_PLUGIN_NPM_PREFIX = "@nextclaw/channel-plugin-";
|
|
1356
1362
|
var CLAWBAY_CHANNEL_PLUGIN_NPM_SPEC = "@clawbay/clawbay-channel";
|
|
@@ -1992,98 +1998,23 @@ function isSupportedMarketplaceSkillItem(item, knownSkillNames) {
|
|
|
1992
1998
|
if (item.type !== "skill") {
|
|
1993
1999
|
return false;
|
|
1994
2000
|
}
|
|
1995
|
-
if (item.install.kind === "
|
|
2001
|
+
if (item.install.kind === "marketplace") {
|
|
1996
2002
|
return true;
|
|
1997
2003
|
}
|
|
1998
2004
|
return item.install.kind === "builtin" && knownSkillNames.has(item.install.spec);
|
|
1999
2005
|
}
|
|
2000
|
-
function
|
|
2001
|
-
const
|
|
2002
|
-
|
|
2003
|
-
if (!match) {
|
|
2004
|
-
return { bodyRaw: normalized };
|
|
2005
|
-
}
|
|
2006
|
-
return {
|
|
2007
|
-
metadataRaw: match[1]?.trim() || void 0,
|
|
2008
|
-
bodyRaw: match[2] ?? ""
|
|
2009
|
-
};
|
|
2010
|
-
}
|
|
2011
|
-
async function loadLocalSkillMarkdown(options, skillName) {
|
|
2012
|
-
const config = loadConfigOrDefault(options.configPath);
|
|
2013
|
-
const loader = createSkillsLoader(getWorkspacePathFromConfig3(config));
|
|
2014
|
-
if (!loader) {
|
|
2015
|
-
return null;
|
|
2016
|
-
}
|
|
2017
|
-
const skillInfo = loader.listSkills(false).find((skill) => skill.name === skillName);
|
|
2018
|
-
if (!skillInfo) {
|
|
2019
|
-
return null;
|
|
2020
|
-
}
|
|
2021
|
-
try {
|
|
2022
|
-
const raw = await readFile2(skillInfo.path, "utf-8");
|
|
2023
|
-
return {
|
|
2024
|
-
raw,
|
|
2025
|
-
source: skillInfo.source
|
|
2026
|
-
};
|
|
2027
|
-
} catch {
|
|
2028
|
-
return null;
|
|
2029
|
-
}
|
|
2030
|
-
}
|
|
2031
|
-
function parseGitSkillSpec(rawSpec) {
|
|
2032
|
-
const spec = rawSpec.trim();
|
|
2033
|
-
if (!spec) {
|
|
2034
|
-
return null;
|
|
2035
|
-
}
|
|
2036
|
-
const segments = spec.split("/").filter(Boolean);
|
|
2037
|
-
if (segments.length < 3) {
|
|
2038
|
-
return null;
|
|
2039
|
-
}
|
|
2040
|
-
return {
|
|
2041
|
-
owner: segments[0] ?? "",
|
|
2042
|
-
repo: segments[1] ?? "",
|
|
2043
|
-
skillPath: segments.slice(2).join("/")
|
|
2044
|
-
};
|
|
2045
|
-
}
|
|
2046
|
-
async function fetchTextWithFallback(urls) {
|
|
2047
|
-
for (const url of urls) {
|
|
2048
|
-
try {
|
|
2049
|
-
const response = await fetch(url, {
|
|
2050
|
-
method: "GET",
|
|
2051
|
-
headers: {
|
|
2052
|
-
Accept: "text/plain, text/markdown, application/json"
|
|
2053
|
-
}
|
|
2054
|
-
});
|
|
2055
|
-
if (!response.ok) {
|
|
2056
|
-
continue;
|
|
2057
|
-
}
|
|
2058
|
-
const text = await response.text();
|
|
2059
|
-
if (text.trim().length === 0) {
|
|
2060
|
-
continue;
|
|
2061
|
-
}
|
|
2062
|
-
return { text, url };
|
|
2063
|
-
} catch {
|
|
2006
|
+
function findUnsupportedSkillInstallKind(items) {
|
|
2007
|
+
for (const item of items) {
|
|
2008
|
+
if (item.type !== "skill") {
|
|
2064
2009
|
continue;
|
|
2065
2010
|
}
|
|
2011
|
+
const kind = item.install.kind;
|
|
2012
|
+
if (kind !== "builtin" && kind !== "marketplace") {
|
|
2013
|
+
return kind;
|
|
2014
|
+
}
|
|
2066
2015
|
}
|
|
2067
2016
|
return null;
|
|
2068
2017
|
}
|
|
2069
|
-
async function loadGitSkillMarkdownFromSpec(rawSpec) {
|
|
2070
|
-
const parsed = parseGitSkillSpec(rawSpec);
|
|
2071
|
-
if (!parsed) {
|
|
2072
|
-
return null;
|
|
2073
|
-
}
|
|
2074
|
-
const candidates = [
|
|
2075
|
-
`https://raw.githubusercontent.com/${parsed.owner}/${parsed.repo}/main/${parsed.skillPath}/SKILL.md`,
|
|
2076
|
-
`https://raw.githubusercontent.com/${parsed.owner}/${parsed.repo}/master/${parsed.skillPath}/SKILL.md`
|
|
2077
|
-
];
|
|
2078
|
-
const result = await fetchTextWithFallback(candidates);
|
|
2079
|
-
if (!result) {
|
|
2080
|
-
return null;
|
|
2081
|
-
}
|
|
2082
|
-
return {
|
|
2083
|
-
raw: result.text,
|
|
2084
|
-
sourceUrl: result.url
|
|
2085
|
-
};
|
|
2086
|
-
}
|
|
2087
2018
|
async function loadPluginReadmeFromNpm(spec) {
|
|
2088
2019
|
const encodedSpec = encodeURIComponent(spec);
|
|
2089
2020
|
const registryUrl = `https://registry.npmjs.org/${encodedSpec}`;
|
|
@@ -2117,40 +2048,6 @@ async function loadPluginReadmeFromNpm(spec) {
|
|
|
2117
2048
|
return null;
|
|
2118
2049
|
}
|
|
2119
2050
|
}
|
|
2120
|
-
async function buildSkillContentView(options, item) {
|
|
2121
|
-
const local = await loadLocalSkillMarkdown(options, item.install.spec);
|
|
2122
|
-
if (local) {
|
|
2123
|
-
const split = splitMarkdownFrontmatter(local.raw);
|
|
2124
|
-
return {
|
|
2125
|
-
type: "skill",
|
|
2126
|
-
slug: item.slug,
|
|
2127
|
-
name: item.name,
|
|
2128
|
-
install: item.install,
|
|
2129
|
-
source: local.source,
|
|
2130
|
-
raw: local.raw,
|
|
2131
|
-
metadataRaw: split.metadataRaw,
|
|
2132
|
-
bodyRaw: split.bodyRaw
|
|
2133
|
-
};
|
|
2134
|
-
}
|
|
2135
|
-
if (item.install.kind === "git") {
|
|
2136
|
-
const remote = await loadGitSkillMarkdownFromSpec(item.install.spec);
|
|
2137
|
-
if (remote) {
|
|
2138
|
-
const split = splitMarkdownFrontmatter(remote.raw);
|
|
2139
|
-
return {
|
|
2140
|
-
type: "skill",
|
|
2141
|
-
slug: item.slug,
|
|
2142
|
-
name: item.name,
|
|
2143
|
-
install: item.install,
|
|
2144
|
-
source: "git",
|
|
2145
|
-
raw: remote.raw,
|
|
2146
|
-
metadataRaw: split.metadataRaw,
|
|
2147
|
-
bodyRaw: split.bodyRaw,
|
|
2148
|
-
sourceUrl: remote.sourceUrl
|
|
2149
|
-
};
|
|
2150
|
-
}
|
|
2151
|
-
}
|
|
2152
|
-
return null;
|
|
2153
|
-
}
|
|
2154
2051
|
async function buildPluginContentView(item) {
|
|
2155
2052
|
if (item.install.kind === "npm") {
|
|
2156
2053
|
const npm = await loadPluginReadmeFromNpm(item.install.spec);
|
|
@@ -2269,8 +2166,6 @@ async function installMarketplaceSkill(params) {
|
|
|
2269
2166
|
kind: params.body.kind,
|
|
2270
2167
|
skill: params.body.skill,
|
|
2271
2168
|
installPath: params.body.installPath,
|
|
2272
|
-
version: params.body.version,
|
|
2273
|
-
registry: params.body.registry,
|
|
2274
2169
|
force: params.body.force
|
|
2275
2170
|
});
|
|
2276
2171
|
params.options.publish({ type: "config.updated", payload: { path: "skills" } });
|
|
@@ -2497,8 +2392,16 @@ function registerSkillMarketplaceRoutes(app, options, marketplaceBaseUrl) {
|
|
|
2497
2392
|
if (!result.ok) {
|
|
2498
2393
|
return c.json(err("MARKETPLACE_UNAVAILABLE", result.message), result.status);
|
|
2499
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
|
+
}
|
|
2500
2403
|
const knownSkillNames = collectKnownSkillNames(options);
|
|
2501
|
-
const filteredItems =
|
|
2404
|
+
const filteredItems = normalizedItems.filter((item) => isSupportedMarketplaceSkillItem(item, knownSkillNames));
|
|
2502
2405
|
const pageSize = Math.min(100, toPositiveInt(query.pageSize, 20));
|
|
2503
2406
|
const requestedPage = toPositiveInt(query.page, 1);
|
|
2504
2407
|
const totalPages = filteredItems.length === 0 ? 0 : Math.ceil(filteredItems.length / pageSize);
|
|
@@ -2524,6 +2427,13 @@ function registerSkillMarketplaceRoutes(app, options, marketplaceBaseUrl) {
|
|
|
2524
2427
|
}
|
|
2525
2428
|
const knownSkillNames = collectKnownSkillNames(options);
|
|
2526
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
|
+
}
|
|
2527
2437
|
if (!isSupportedMarketplaceSkillItem(sanitized, knownSkillNames)) {
|
|
2528
2438
|
return c.json(err("NOT_FOUND", "marketplace item not supported by nextclaw"), 404);
|
|
2529
2439
|
}
|
|
@@ -2540,14 +2450,24 @@ function registerSkillMarketplaceRoutes(app, options, marketplaceBaseUrl) {
|
|
|
2540
2450
|
}
|
|
2541
2451
|
const knownSkillNames = collectKnownSkillNames(options);
|
|
2542
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
|
+
}
|
|
2543
2460
|
if (!isSupportedMarketplaceSkillItem(sanitized, knownSkillNames)) {
|
|
2544
2461
|
return c.json(err("NOT_FOUND", "marketplace item not supported by nextclaw"), 404);
|
|
2545
2462
|
}
|
|
2546
|
-
const
|
|
2547
|
-
|
|
2548
|
-
|
|
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);
|
|
2549
2469
|
}
|
|
2550
|
-
return c.json(ok(
|
|
2470
|
+
return c.json(ok(contentResult.data));
|
|
2551
2471
|
});
|
|
2552
2472
|
app.post("/api/marketplace/skills/install", async (c) => {
|
|
2553
2473
|
const body = await readJson(c.req.raw);
|
|
@@ -2630,6 +2550,7 @@ function createUiRouter(options) {
|
|
|
2630
2550
|
const marketplaceBaseUrl = normalizeMarketplaceBaseUrl(options);
|
|
2631
2551
|
app.notFound((c) => c.json(err("NOT_FOUND", "endpoint not found"), 404));
|
|
2632
2552
|
app.get("/api/health", (c) => c.json(ok({ status: "ok" })));
|
|
2553
|
+
app.get("/api/app/meta", (c) => c.json(ok(buildAppMetaView(options))));
|
|
2633
2554
|
app.get("/api/config", (c) => {
|
|
2634
2555
|
const config = loadConfigOrDefault(options.configPath);
|
|
2635
2556
|
return c.json(ok(buildConfigView(config)));
|
|
@@ -2806,6 +2727,31 @@ function createUiRouter(options) {
|
|
|
2806
2727
|
return c.json(err("CHAT_RUNTIME_FAILED", String(error)), 500);
|
|
2807
2728
|
}
|
|
2808
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
|
+
});
|
|
2809
2755
|
app.post("/api/chat/turn", async (c) => {
|
|
2810
2756
|
if (!options.chatRuntime) {
|
|
2811
2757
|
return c.json(err("NOT_AVAILABLE", "chat runtime unavailable"), 503);
|
|
@@ -3394,6 +3340,7 @@ function startUiServer(options) {
|
|
|
3394
3340
|
"/",
|
|
3395
3341
|
createUiRouter({
|
|
3396
3342
|
configPath: options.configPath,
|
|
3343
|
+
productVersion: options.productVersion,
|
|
3397
3344
|
publish,
|
|
3398
3345
|
marketplace: options.marketplace,
|
|
3399
3346
|
cronService: options.cronService,
|
|
@@ -3410,7 +3357,7 @@ function startUiServer(options) {
|
|
|
3410
3357
|
join,
|
|
3411
3358
|
getContent: async (path) => {
|
|
3412
3359
|
try {
|
|
3413
|
-
return await
|
|
3360
|
+
return await readFile2(path);
|
|
3414
3361
|
} catch {
|
|
3415
3362
|
return null;
|
|
3416
3363
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/server",
|
|
3
|
-
"version": "0.6.
|
|
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.
|
|
22
|
+
"@nextclaw/core": "^0.7.2"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/node": "^20.17.6",
|