@nextclaw/server 0.5.13 → 0.5.14
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 +41 -17
- package/dist/index.js +341 -180
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -324,9 +324,8 @@ type MarketplaceInstalledView = {
|
|
|
324
324
|
specs: string[];
|
|
325
325
|
records: MarketplaceInstalledRecord[];
|
|
326
326
|
};
|
|
327
|
-
type
|
|
328
|
-
|
|
329
|
-
spec: string;
|
|
327
|
+
type MarketplaceInstallSkillParams = {
|
|
328
|
+
slug: string;
|
|
330
329
|
kind?: MarketplaceInstallKind;
|
|
331
330
|
skill?: string;
|
|
332
331
|
installPath?: string;
|
|
@@ -334,14 +333,13 @@ type MarketplaceInstallRequest = {
|
|
|
334
333
|
registry?: string;
|
|
335
334
|
force?: boolean;
|
|
336
335
|
};
|
|
337
|
-
type
|
|
338
|
-
type
|
|
336
|
+
type MarketplacePluginInstallRequest = {
|
|
337
|
+
type?: "plugin";
|
|
339
338
|
spec: string;
|
|
340
|
-
message: string;
|
|
341
|
-
output?: string;
|
|
342
339
|
};
|
|
343
|
-
type
|
|
344
|
-
|
|
340
|
+
type MarketplaceSkillInstallRequest = {
|
|
341
|
+
type?: "skill";
|
|
342
|
+
spec: string;
|
|
345
343
|
kind?: MarketplaceInstallKind;
|
|
346
344
|
skill?: string;
|
|
347
345
|
installPath?: string;
|
|
@@ -349,16 +347,42 @@ type MarketplaceInstallSkillParams = {
|
|
|
349
347
|
registry?: string;
|
|
350
348
|
force?: boolean;
|
|
351
349
|
};
|
|
352
|
-
type
|
|
353
|
-
type
|
|
354
|
-
|
|
355
|
-
|
|
350
|
+
type MarketplacePluginInstallResult = {
|
|
351
|
+
type: "plugin";
|
|
352
|
+
spec: string;
|
|
353
|
+
message: string;
|
|
354
|
+
output?: string;
|
|
355
|
+
};
|
|
356
|
+
type MarketplaceSkillInstallResult = {
|
|
357
|
+
type: "skill";
|
|
358
|
+
spec: string;
|
|
359
|
+
message: string;
|
|
360
|
+
output?: string;
|
|
361
|
+
};
|
|
362
|
+
type MarketplacePluginManageAction = "enable" | "disable" | "uninstall";
|
|
363
|
+
type MarketplaceSkillManageAction = "uninstall";
|
|
364
|
+
type MarketplacePluginManageRequest = {
|
|
365
|
+
type?: "plugin";
|
|
366
|
+
action: MarketplacePluginManageAction;
|
|
356
367
|
id?: string;
|
|
357
368
|
spec?: string;
|
|
358
369
|
};
|
|
359
|
-
type
|
|
360
|
-
type
|
|
361
|
-
action:
|
|
370
|
+
type MarketplaceSkillManageRequest = {
|
|
371
|
+
type?: "skill";
|
|
372
|
+
action: MarketplaceSkillManageAction;
|
|
373
|
+
id?: string;
|
|
374
|
+
spec?: string;
|
|
375
|
+
};
|
|
376
|
+
type MarketplacePluginManageResult = {
|
|
377
|
+
type: "plugin";
|
|
378
|
+
action: MarketplacePluginManageAction;
|
|
379
|
+
id: string;
|
|
380
|
+
message: string;
|
|
381
|
+
output?: string;
|
|
382
|
+
};
|
|
383
|
+
type MarketplaceSkillManageResult = {
|
|
384
|
+
type: "skill";
|
|
385
|
+
action: MarketplaceSkillManageAction;
|
|
362
386
|
id: string;
|
|
363
387
|
message: string;
|
|
364
388
|
output?: string;
|
|
@@ -467,4 +491,4 @@ declare function patchSession(configPath: string, key: string, patch: SessionPat
|
|
|
467
491
|
declare function deleteSession(configPath: string, key: string): boolean;
|
|
468
492
|
declare function updateRuntime(configPath: string, patch: RuntimeConfigUpdate): Pick<ConfigView, "agents" | "bindings" | "session">;
|
|
469
493
|
|
|
470
|
-
export { type AgentBindingView, type AgentProfileView, type ApiError, type ApiResponse, type BindingPeerView, type ChannelSpecView, 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
|
|
494
|
+
export { type AgentBindingView, type AgentProfileView, type ApiError, type ApiResponse, type BindingPeerView, type ChannelSpecView, 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 MarketplacePluginInstallRequest, type MarketplacePluginInstallResult, type MarketplacePluginManageAction, type MarketplacePluginManageRequest, type MarketplacePluginManageResult, type MarketplaceRecommendationView, type MarketplaceSkillInstallRequest, type MarketplaceSkillInstallResult, type MarketplaceSkillManageAction, type MarketplaceSkillManageRequest, type MarketplaceSkillManageResult, type MarketplaceSort, type ProviderConfigUpdate, type ProviderConfigView, type ProviderSpecView, type RuntimeConfigUpdate, type SessionConfigView, type SessionEntryView, type SessionHistoryView, type SessionMessageView, type SessionPatchUpdate, type SessionsListView, type UiServerEvent, type UiServerHandle, type UiServerOptions, buildConfigMeta, buildConfigSchemaView, buildConfigView, createUiRouter, deleteSession, executeConfigAction, getSessionHistory, listSessions, loadConfigOrDefault, patchSession, startUiServer, updateChannel, updateModel, updateProvider, updateRuntime };
|
package/dist/index.js
CHANGED
|
@@ -931,10 +931,19 @@ function collectInstalledSkillRecords(options) {
|
|
|
931
931
|
records
|
|
932
932
|
};
|
|
933
933
|
}
|
|
934
|
-
function
|
|
935
|
-
const installed =
|
|
934
|
+
function collectPluginMarketplaceInstalledView(options) {
|
|
935
|
+
const installed = collectInstalledPluginRecords(options);
|
|
936
936
|
return {
|
|
937
|
-
type,
|
|
937
|
+
type: "plugin",
|
|
938
|
+
total: installed.records.length,
|
|
939
|
+
specs: installed.specs,
|
|
940
|
+
records: installed.records
|
|
941
|
+
};
|
|
942
|
+
}
|
|
943
|
+
function collectSkillMarketplaceInstalledView(options) {
|
|
944
|
+
const installed = collectInstalledSkillRecords(options);
|
|
945
|
+
return {
|
|
946
|
+
type: "skill",
|
|
938
947
|
total: installed.records.length,
|
|
939
948
|
specs: installed.specs,
|
|
940
949
|
records: installed.records
|
|
@@ -993,9 +1002,12 @@ function collectKnownSkillNames(options) {
|
|
|
993
1002
|
const loader = createSkillsLoader(getWorkspacePathFromConfig3(config));
|
|
994
1003
|
return new Set((loader?.listSkills(false) ?? []).map((skill) => skill.name));
|
|
995
1004
|
}
|
|
996
|
-
function
|
|
997
|
-
|
|
998
|
-
|
|
1005
|
+
function isSupportedMarketplacePluginItem(item) {
|
|
1006
|
+
return item.type === "plugin" && item.install.kind === "npm" && isSupportedMarketplacePluginSpec(item.install.spec);
|
|
1007
|
+
}
|
|
1008
|
+
function isSupportedMarketplaceSkillItem(item, knownSkillNames) {
|
|
1009
|
+
if (item.type !== "skill") {
|
|
1010
|
+
return false;
|
|
999
1011
|
}
|
|
1000
1012
|
if (item.install.kind === "git") {
|
|
1001
1013
|
return true;
|
|
@@ -1036,228 +1048,377 @@ async function fetchAllMarketplaceItems(params) {
|
|
|
1036
1048
|
}
|
|
1037
1049
|
};
|
|
1038
1050
|
}
|
|
1039
|
-
async function
|
|
1040
|
-
|
|
1051
|
+
async function fetchAllPluginMarketplaceItems(params) {
|
|
1052
|
+
return await fetchAllMarketplaceItems({
|
|
1053
|
+
baseUrl: params.baseUrl,
|
|
1054
|
+
segment: "plugins",
|
|
1055
|
+
query: params.query
|
|
1056
|
+
});
|
|
1057
|
+
}
|
|
1058
|
+
async function fetchAllSkillMarketplaceItems(params) {
|
|
1059
|
+
return await fetchAllMarketplaceItems({
|
|
1060
|
+
baseUrl: params.baseUrl,
|
|
1061
|
+
segment: "skills",
|
|
1062
|
+
query: params.query
|
|
1063
|
+
});
|
|
1064
|
+
}
|
|
1065
|
+
async function installMarketplacePlugin(params) {
|
|
1041
1066
|
const spec = typeof params.body.spec === "string" ? params.body.spec.trim() : "";
|
|
1042
|
-
if (
|
|
1043
|
-
throw new Error("INVALID_BODY:
|
|
1067
|
+
if (!spec) {
|
|
1068
|
+
throw new Error("INVALID_BODY:non-empty spec is required");
|
|
1044
1069
|
}
|
|
1045
1070
|
const installer = params.options.marketplace?.installer;
|
|
1046
1071
|
if (!installer) {
|
|
1047
1072
|
throw new Error("NOT_AVAILABLE:marketplace installer is not configured");
|
|
1048
1073
|
}
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
if (!installer.installPlugin) {
|
|
1052
|
-
throw new Error("NOT_AVAILABLE:plugin installer is not configured");
|
|
1053
|
-
}
|
|
1054
|
-
result = await installer.installPlugin(spec);
|
|
1055
|
-
} else {
|
|
1056
|
-
if (!installer.installSkill) {
|
|
1057
|
-
throw new Error("NOT_AVAILABLE:skill installer is not configured");
|
|
1058
|
-
}
|
|
1059
|
-
result = await installer.installSkill({
|
|
1060
|
-
slug: spec,
|
|
1061
|
-
kind: params.body.kind,
|
|
1062
|
-
skill: params.body.skill,
|
|
1063
|
-
installPath: params.body.installPath,
|
|
1064
|
-
version: params.body.version,
|
|
1065
|
-
registry: params.body.registry,
|
|
1066
|
-
force: params.body.force
|
|
1067
|
-
});
|
|
1074
|
+
if (!installer.installPlugin) {
|
|
1075
|
+
throw new Error("NOT_AVAILABLE:plugin installer is not configured");
|
|
1068
1076
|
}
|
|
1069
|
-
|
|
1077
|
+
const result = await installer.installPlugin(spec);
|
|
1078
|
+
params.options.publish({ type: "config.updated", payload: { path: "plugins" } });
|
|
1070
1079
|
return {
|
|
1071
|
-
type,
|
|
1080
|
+
type: "plugin",
|
|
1072
1081
|
spec,
|
|
1073
1082
|
message: result.message,
|
|
1074
1083
|
output: result.output
|
|
1075
1084
|
};
|
|
1076
1085
|
}
|
|
1077
|
-
async function
|
|
1078
|
-
const
|
|
1086
|
+
async function installMarketplaceSkill(params) {
|
|
1087
|
+
const spec = typeof params.body.spec === "string" ? params.body.spec.trim() : "";
|
|
1088
|
+
if (!spec) {
|
|
1089
|
+
throw new Error("INVALID_BODY:non-empty spec is required");
|
|
1090
|
+
}
|
|
1091
|
+
const installer = params.options.marketplace?.installer;
|
|
1092
|
+
if (!installer) {
|
|
1093
|
+
throw new Error("NOT_AVAILABLE:marketplace installer is not configured");
|
|
1094
|
+
}
|
|
1095
|
+
if (!installer.installSkill) {
|
|
1096
|
+
throw new Error("NOT_AVAILABLE:skill installer is not configured");
|
|
1097
|
+
}
|
|
1098
|
+
const result = await installer.installSkill({
|
|
1099
|
+
slug: spec,
|
|
1100
|
+
kind: params.body.kind,
|
|
1101
|
+
skill: params.body.skill,
|
|
1102
|
+
installPath: params.body.installPath,
|
|
1103
|
+
version: params.body.version,
|
|
1104
|
+
registry: params.body.registry,
|
|
1105
|
+
force: params.body.force
|
|
1106
|
+
});
|
|
1107
|
+
params.options.publish({ type: "config.updated", payload: { path: "skills" } });
|
|
1108
|
+
return {
|
|
1109
|
+
type: "skill",
|
|
1110
|
+
spec,
|
|
1111
|
+
message: result.message,
|
|
1112
|
+
output: result.output
|
|
1113
|
+
};
|
|
1114
|
+
}
|
|
1115
|
+
async function manageMarketplacePlugin(params) {
|
|
1079
1116
|
const action = params.body.action;
|
|
1080
1117
|
const requestedTargetId = typeof params.body.id === "string" && params.body.id.trim().length > 0 ? params.body.id.trim() : typeof params.body.spec === "string" && params.body.spec.trim().length > 0 ? params.body.spec.trim() : "";
|
|
1081
1118
|
const rawSpec = typeof params.body.spec === "string" ? params.body.spec.trim() : "";
|
|
1082
|
-
const targetId =
|
|
1083
|
-
if (
|
|
1084
|
-
throw new Error("INVALID_BODY:
|
|
1119
|
+
const targetId = resolvePluginManageTargetId(params.options, requestedTargetId, rawSpec);
|
|
1120
|
+
if (action !== "enable" && action !== "disable" && action !== "uninstall" || !targetId) {
|
|
1121
|
+
throw new Error("INVALID_BODY:action and non-empty id/spec are required");
|
|
1085
1122
|
}
|
|
1086
1123
|
const installer = params.options.marketplace?.installer;
|
|
1087
1124
|
if (!installer) {
|
|
1088
1125
|
throw new Error("NOT_AVAILABLE:marketplace installer is not configured");
|
|
1089
1126
|
}
|
|
1090
1127
|
let result;
|
|
1091
|
-
if (
|
|
1092
|
-
if (
|
|
1093
|
-
|
|
1094
|
-
throw new Error("NOT_AVAILABLE:plugin enable is not configured");
|
|
1095
|
-
}
|
|
1096
|
-
result = await installer.enablePlugin(targetId);
|
|
1097
|
-
} else if (action === "disable") {
|
|
1098
|
-
if (!installer.disablePlugin) {
|
|
1099
|
-
throw new Error("NOT_AVAILABLE:plugin disable is not configured");
|
|
1100
|
-
}
|
|
1101
|
-
result = await installer.disablePlugin(targetId);
|
|
1102
|
-
} else {
|
|
1103
|
-
if (!installer.uninstallPlugin) {
|
|
1104
|
-
throw new Error("NOT_AVAILABLE:plugin uninstall is not configured");
|
|
1105
|
-
}
|
|
1106
|
-
result = await installer.uninstallPlugin(targetId);
|
|
1128
|
+
if (action === "enable") {
|
|
1129
|
+
if (!installer.enablePlugin) {
|
|
1130
|
+
throw new Error("NOT_AVAILABLE:plugin enable is not configured");
|
|
1107
1131
|
}
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1132
|
+
result = await installer.enablePlugin(targetId);
|
|
1133
|
+
} else if (action === "disable") {
|
|
1134
|
+
if (!installer.disablePlugin) {
|
|
1135
|
+
throw new Error("NOT_AVAILABLE:plugin disable is not configured");
|
|
1111
1136
|
}
|
|
1112
|
-
|
|
1113
|
-
|
|
1137
|
+
result = await installer.disablePlugin(targetId);
|
|
1138
|
+
} else {
|
|
1139
|
+
if (!installer.uninstallPlugin) {
|
|
1140
|
+
throw new Error("NOT_AVAILABLE:plugin uninstall is not configured");
|
|
1114
1141
|
}
|
|
1115
|
-
result = await installer.
|
|
1142
|
+
result = await installer.uninstallPlugin(targetId);
|
|
1116
1143
|
}
|
|
1117
|
-
params.options.publish({ type: "config.updated", payload: { path:
|
|
1144
|
+
params.options.publish({ type: "config.updated", payload: { path: "plugins" } });
|
|
1118
1145
|
return {
|
|
1119
|
-
type,
|
|
1146
|
+
type: "plugin",
|
|
1120
1147
|
action,
|
|
1121
1148
|
id: targetId,
|
|
1122
1149
|
message: result.message,
|
|
1123
1150
|
output: result.output
|
|
1124
1151
|
};
|
|
1125
1152
|
}
|
|
1126
|
-
function
|
|
1127
|
-
const
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1153
|
+
async function manageMarketplaceSkill(params) {
|
|
1154
|
+
const action = params.body.action;
|
|
1155
|
+
const targetId = typeof params.body.id === "string" && params.body.id.trim().length > 0 ? params.body.id.trim() : typeof params.body.spec === "string" && params.body.spec.trim().length > 0 ? params.body.spec.trim() : "";
|
|
1156
|
+
if (action !== "uninstall" || !targetId) {
|
|
1157
|
+
throw new Error("INVALID_BODY:skill manage requires uninstall action and non-empty id/spec");
|
|
1158
|
+
}
|
|
1159
|
+
const installer = params.options.marketplace?.installer;
|
|
1160
|
+
if (!installer) {
|
|
1161
|
+
throw new Error("NOT_AVAILABLE:marketplace installer is not configured");
|
|
1162
|
+
}
|
|
1163
|
+
if (!installer.uninstallSkill) {
|
|
1164
|
+
throw new Error("NOT_AVAILABLE:skill uninstall is not configured");
|
|
1165
|
+
}
|
|
1166
|
+
const result = await installer.uninstallSkill(targetId);
|
|
1167
|
+
params.options.publish({ type: "config.updated", payload: { path: "skills" } });
|
|
1168
|
+
return {
|
|
1169
|
+
type: "skill",
|
|
1170
|
+
action,
|
|
1171
|
+
id: targetId,
|
|
1172
|
+
message: result.message,
|
|
1173
|
+
output: result.output
|
|
1174
|
+
};
|
|
1175
|
+
}
|
|
1176
|
+
function registerPluginMarketplaceRoutes(app, options, marketplaceBaseUrl) {
|
|
1177
|
+
app.get("/api/marketplace/plugins/installed", (c) => {
|
|
1178
|
+
return c.json(ok(collectPluginMarketplaceInstalledView(options)));
|
|
1179
|
+
});
|
|
1180
|
+
app.get("/api/marketplace/plugins/items", async (c) => {
|
|
1181
|
+
const query = c.req.query();
|
|
1182
|
+
const result = await fetchAllPluginMarketplaceItems({
|
|
1183
|
+
baseUrl: marketplaceBaseUrl,
|
|
1184
|
+
query: {
|
|
1185
|
+
q: query.q,
|
|
1186
|
+
tag: query.tag,
|
|
1187
|
+
sort: query.sort,
|
|
1188
|
+
page: query.page,
|
|
1189
|
+
pageSize: query.pageSize
|
|
1150
1190
|
}
|
|
1151
|
-
const knownSkillNames = collectKnownSkillNames(options);
|
|
1152
|
-
const filteredItems = result.data.items.map((item) => sanitizeMarketplaceItem(item)).filter((item) => isSupportedMarketplaceItem(item, knownSkillNames));
|
|
1153
|
-
const pageSize = Math.min(100, toPositiveInt(query.pageSize, 20));
|
|
1154
|
-
const requestedPage = toPositiveInt(query.page, 1);
|
|
1155
|
-
const totalPages = filteredItems.length === 0 ? 0 : Math.ceil(filteredItems.length / pageSize);
|
|
1156
|
-
const currentPage = totalPages === 0 ? 1 : Math.min(requestedPage, totalPages);
|
|
1157
|
-
return c.json(ok({
|
|
1158
|
-
total: filteredItems.length,
|
|
1159
|
-
page: currentPage,
|
|
1160
|
-
pageSize,
|
|
1161
|
-
totalPages,
|
|
1162
|
-
sort: result.data.sort,
|
|
1163
|
-
query: result.data.query,
|
|
1164
|
-
items: filteredItems.slice((currentPage - 1) * pageSize, currentPage * pageSize)
|
|
1165
|
-
}));
|
|
1166
1191
|
});
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1192
|
+
if (!result.ok) {
|
|
1193
|
+
return c.json(err("MARKETPLACE_UNAVAILABLE", result.message), result.status);
|
|
1194
|
+
}
|
|
1195
|
+
const filteredItems = result.data.items.map((item) => sanitizeMarketplaceItem(item)).filter((item) => isSupportedMarketplacePluginItem(item));
|
|
1196
|
+
const pageSize = Math.min(100, toPositiveInt(query.pageSize, 20));
|
|
1197
|
+
const requestedPage = toPositiveInt(query.page, 1);
|
|
1198
|
+
const totalPages = filteredItems.length === 0 ? 0 : Math.ceil(filteredItems.length / pageSize);
|
|
1199
|
+
const currentPage = totalPages === 0 ? 1 : Math.min(requestedPage, totalPages);
|
|
1200
|
+
return c.json(ok({
|
|
1201
|
+
total: filteredItems.length,
|
|
1202
|
+
page: currentPage,
|
|
1203
|
+
pageSize,
|
|
1204
|
+
totalPages,
|
|
1205
|
+
sort: result.data.sort,
|
|
1206
|
+
query: result.data.query,
|
|
1207
|
+
items: filteredItems.slice((currentPage - 1) * pageSize, currentPage * pageSize)
|
|
1208
|
+
}));
|
|
1209
|
+
});
|
|
1210
|
+
app.get("/api/marketplace/plugins/items/:slug", async (c) => {
|
|
1211
|
+
const slug = encodeURIComponent(c.req.param("slug"));
|
|
1212
|
+
const result = await fetchMarketplaceData({
|
|
1213
|
+
baseUrl: marketplaceBaseUrl,
|
|
1214
|
+
path: `/api/v1/plugins/items/${slug}`
|
|
1215
|
+
});
|
|
1216
|
+
if (!result.ok) {
|
|
1217
|
+
return c.json(err("MARKETPLACE_UNAVAILABLE", result.message), result.status);
|
|
1218
|
+
}
|
|
1219
|
+
const sanitized = sanitizeMarketplaceItem(result.data);
|
|
1220
|
+
if (!isSupportedMarketplacePluginItem(sanitized)) {
|
|
1221
|
+
return c.json(err("NOT_FOUND", "marketplace item not supported by nextclaw"), 404);
|
|
1222
|
+
}
|
|
1223
|
+
return c.json(ok(sanitized));
|
|
1224
|
+
});
|
|
1225
|
+
app.post("/api/marketplace/plugins/install", async (c) => {
|
|
1226
|
+
const body = await readJson(c.req.raw);
|
|
1227
|
+
if (!body.ok || !body.data || typeof body.data !== "object") {
|
|
1228
|
+
return c.json(err("INVALID_BODY", "invalid json body"), 400);
|
|
1229
|
+
}
|
|
1230
|
+
if (body.data.type && body.data.type !== "plugin") {
|
|
1231
|
+
return c.json(err("INVALID_BODY", "body.type does not match route type"), 400);
|
|
1232
|
+
}
|
|
1233
|
+
try {
|
|
1234
|
+
const payload = await installMarketplacePlugin({
|
|
1235
|
+
options,
|
|
1236
|
+
body: body.data
|
|
1172
1237
|
});
|
|
1173
|
-
|
|
1174
|
-
|
|
1238
|
+
return c.json(ok(payload));
|
|
1239
|
+
} catch (error) {
|
|
1240
|
+
const message = String(error);
|
|
1241
|
+
if (message.startsWith("INVALID_BODY:")) {
|
|
1242
|
+
return c.json(err("INVALID_BODY", message.slice("INVALID_BODY:".length)), 400);
|
|
1175
1243
|
}
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
if (!isSupportedMarketplaceItem(sanitized, knownSkillNames)) {
|
|
1179
|
-
return c.json(err("NOT_FOUND", "marketplace item not supported by nextclaw"), 404);
|
|
1244
|
+
if (message.startsWith("NOT_AVAILABLE:")) {
|
|
1245
|
+
return c.json(err("NOT_AVAILABLE", message.slice("NOT_AVAILABLE:".length)), 503);
|
|
1180
1246
|
}
|
|
1181
|
-
return c.json(
|
|
1182
|
-
}
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1247
|
+
return c.json(err("INSTALL_FAILED", message), 400);
|
|
1248
|
+
}
|
|
1249
|
+
});
|
|
1250
|
+
app.post("/api/marketplace/plugins/manage", async (c) => {
|
|
1251
|
+
const body = await readJson(c.req.raw);
|
|
1252
|
+
if (!body.ok || !body.data || typeof body.data !== "object") {
|
|
1253
|
+
return c.json(err("INVALID_BODY", "invalid json body"), 400);
|
|
1254
|
+
}
|
|
1255
|
+
if (body.data.type && body.data.type !== "plugin") {
|
|
1256
|
+
return c.json(err("INVALID_BODY", "body.type does not match route type"), 400);
|
|
1257
|
+
}
|
|
1258
|
+
try {
|
|
1259
|
+
const payload = await manageMarketplacePlugin({
|
|
1260
|
+
options,
|
|
1261
|
+
body: body.data
|
|
1262
|
+
});
|
|
1263
|
+
return c.json(ok(payload));
|
|
1264
|
+
} catch (error) {
|
|
1265
|
+
const message = String(error);
|
|
1266
|
+
if (message.startsWith("INVALID_BODY:")) {
|
|
1267
|
+
return c.json(err("INVALID_BODY", message.slice("INVALID_BODY:".length)), 400);
|
|
1187
1268
|
}
|
|
1188
|
-
if (
|
|
1189
|
-
return c.json(err("
|
|
1269
|
+
if (message.startsWith("NOT_AVAILABLE:")) {
|
|
1270
|
+
return c.json(err("NOT_AVAILABLE", message.slice("NOT_AVAILABLE:".length)), 503);
|
|
1190
1271
|
}
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
if (message.startsWith("INVALID_BODY:")) {
|
|
1203
|
-
return c.json(err("INVALID_BODY", message.slice("INVALID_BODY:".length)), 400);
|
|
1204
|
-
}
|
|
1205
|
-
if (message.startsWith("NOT_AVAILABLE:")) {
|
|
1206
|
-
return c.json(err("NOT_AVAILABLE", message.slice("NOT_AVAILABLE:".length)), 503);
|
|
1207
|
-
}
|
|
1208
|
-
return c.json(err("INSTALL_FAILED", message), 400);
|
|
1272
|
+
return c.json(err("MANAGE_FAILED", message), 400);
|
|
1273
|
+
}
|
|
1274
|
+
});
|
|
1275
|
+
app.get("/api/marketplace/plugins/recommendations", async (c) => {
|
|
1276
|
+
const query = c.req.query();
|
|
1277
|
+
const result = await fetchMarketplaceData({
|
|
1278
|
+
baseUrl: marketplaceBaseUrl,
|
|
1279
|
+
path: "/api/v1/plugins/recommendations",
|
|
1280
|
+
query: {
|
|
1281
|
+
scene: query.scene,
|
|
1282
|
+
limit: query.limit
|
|
1209
1283
|
}
|
|
1210
1284
|
});
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1285
|
+
if (!result.ok) {
|
|
1286
|
+
return c.json(err("MARKETPLACE_UNAVAILABLE", result.message), result.status);
|
|
1287
|
+
}
|
|
1288
|
+
const filteredItems = result.data.items.map((item) => sanitizeMarketplaceItem(item)).filter((item) => isSupportedMarketplacePluginItem(item));
|
|
1289
|
+
return c.json(ok({
|
|
1290
|
+
...result.data,
|
|
1291
|
+
total: filteredItems.length,
|
|
1292
|
+
items: filteredItems
|
|
1293
|
+
}));
|
|
1294
|
+
});
|
|
1295
|
+
}
|
|
1296
|
+
function registerSkillMarketplaceRoutes(app, options, marketplaceBaseUrl) {
|
|
1297
|
+
app.get("/api/marketplace/skills/installed", (c) => {
|
|
1298
|
+
return c.json(ok(collectSkillMarketplaceInstalledView(options)));
|
|
1299
|
+
});
|
|
1300
|
+
app.get("/api/marketplace/skills/items", async (c) => {
|
|
1301
|
+
const query = c.req.query();
|
|
1302
|
+
const result = await fetchAllSkillMarketplaceItems({
|
|
1303
|
+
baseUrl: marketplaceBaseUrl,
|
|
1304
|
+
query: {
|
|
1305
|
+
q: query.q,
|
|
1306
|
+
tag: query.tag,
|
|
1307
|
+
sort: query.sort,
|
|
1308
|
+
page: query.page,
|
|
1309
|
+
pageSize: query.pageSize
|
|
1215
1310
|
}
|
|
1216
|
-
|
|
1217
|
-
|
|
1311
|
+
});
|
|
1312
|
+
if (!result.ok) {
|
|
1313
|
+
return c.json(err("MARKETPLACE_UNAVAILABLE", result.message), result.status);
|
|
1314
|
+
}
|
|
1315
|
+
const knownSkillNames = collectKnownSkillNames(options);
|
|
1316
|
+
const filteredItems = result.data.items.map((item) => sanitizeMarketplaceItem(item)).filter((item) => isSupportedMarketplaceSkillItem(item, knownSkillNames));
|
|
1317
|
+
const pageSize = Math.min(100, toPositiveInt(query.pageSize, 20));
|
|
1318
|
+
const requestedPage = toPositiveInt(query.page, 1);
|
|
1319
|
+
const totalPages = filteredItems.length === 0 ? 0 : Math.ceil(filteredItems.length / pageSize);
|
|
1320
|
+
const currentPage = totalPages === 0 ? 1 : Math.min(requestedPage, totalPages);
|
|
1321
|
+
return c.json(ok({
|
|
1322
|
+
total: filteredItems.length,
|
|
1323
|
+
page: currentPage,
|
|
1324
|
+
pageSize,
|
|
1325
|
+
totalPages,
|
|
1326
|
+
sort: result.data.sort,
|
|
1327
|
+
query: result.data.query,
|
|
1328
|
+
items: filteredItems.slice((currentPage - 1) * pageSize, currentPage * pageSize)
|
|
1329
|
+
}));
|
|
1330
|
+
});
|
|
1331
|
+
app.get("/api/marketplace/skills/items/:slug", async (c) => {
|
|
1332
|
+
const slug = encodeURIComponent(c.req.param("slug"));
|
|
1333
|
+
const result = await fetchMarketplaceData({
|
|
1334
|
+
baseUrl: marketplaceBaseUrl,
|
|
1335
|
+
path: `/api/v1/skills/items/${slug}`
|
|
1336
|
+
});
|
|
1337
|
+
if (!result.ok) {
|
|
1338
|
+
return c.json(err("MARKETPLACE_UNAVAILABLE", result.message), result.status);
|
|
1339
|
+
}
|
|
1340
|
+
const knownSkillNames = collectKnownSkillNames(options);
|
|
1341
|
+
const sanitized = sanitizeMarketplaceItem(result.data);
|
|
1342
|
+
if (!isSupportedMarketplaceSkillItem(sanitized, knownSkillNames)) {
|
|
1343
|
+
return c.json(err("NOT_FOUND", "marketplace item not supported by nextclaw"), 404);
|
|
1344
|
+
}
|
|
1345
|
+
return c.json(ok(sanitized));
|
|
1346
|
+
});
|
|
1347
|
+
app.post("/api/marketplace/skills/install", async (c) => {
|
|
1348
|
+
const body = await readJson(c.req.raw);
|
|
1349
|
+
if (!body.ok || !body.data || typeof body.data !== "object") {
|
|
1350
|
+
return c.json(err("INVALID_BODY", "invalid json body"), 400);
|
|
1351
|
+
}
|
|
1352
|
+
if (body.data.type && body.data.type !== "skill") {
|
|
1353
|
+
return c.json(err("INVALID_BODY", "body.type does not match route type"), 400);
|
|
1354
|
+
}
|
|
1355
|
+
try {
|
|
1356
|
+
const payload = await installMarketplaceSkill({
|
|
1357
|
+
options,
|
|
1358
|
+
body: body.data
|
|
1359
|
+
});
|
|
1360
|
+
return c.json(ok(payload));
|
|
1361
|
+
} catch (error) {
|
|
1362
|
+
const message = String(error);
|
|
1363
|
+
if (message.startsWith("INVALID_BODY:")) {
|
|
1364
|
+
return c.json(err("INVALID_BODY", message.slice("INVALID_BODY:".length)), 400);
|
|
1218
1365
|
}
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
options,
|
|
1222
|
-
body: {
|
|
1223
|
-
...body.data,
|
|
1224
|
-
type: route.type
|
|
1225
|
-
}
|
|
1226
|
-
});
|
|
1227
|
-
return c.json(ok(payload));
|
|
1228
|
-
} catch (error) {
|
|
1229
|
-
const message = String(error);
|
|
1230
|
-
if (message.startsWith("INVALID_BODY:")) {
|
|
1231
|
-
return c.json(err("INVALID_BODY", message.slice("INVALID_BODY:".length)), 400);
|
|
1232
|
-
}
|
|
1233
|
-
if (message.startsWith("NOT_AVAILABLE:")) {
|
|
1234
|
-
return c.json(err("NOT_AVAILABLE", message.slice("NOT_AVAILABLE:".length)), 503);
|
|
1235
|
-
}
|
|
1236
|
-
return c.json(err("MANAGE_FAILED", message), 400);
|
|
1366
|
+
if (message.startsWith("NOT_AVAILABLE:")) {
|
|
1367
|
+
return c.json(err("NOT_AVAILABLE", message.slice("NOT_AVAILABLE:".length)), 503);
|
|
1237
1368
|
}
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1369
|
+
return c.json(err("INSTALL_FAILED", message), 400);
|
|
1370
|
+
}
|
|
1371
|
+
});
|
|
1372
|
+
app.post("/api/marketplace/skills/manage", async (c) => {
|
|
1373
|
+
const body = await readJson(c.req.raw);
|
|
1374
|
+
if (!body.ok || !body.data || typeof body.data !== "object") {
|
|
1375
|
+
return c.json(err("INVALID_BODY", "invalid json body"), 400);
|
|
1376
|
+
}
|
|
1377
|
+
if (body.data.type && body.data.type !== "skill") {
|
|
1378
|
+
return c.json(err("INVALID_BODY", "body.type does not match route type"), 400);
|
|
1379
|
+
}
|
|
1380
|
+
try {
|
|
1381
|
+
const payload = await manageMarketplaceSkill({
|
|
1382
|
+
options,
|
|
1383
|
+
body: body.data
|
|
1248
1384
|
});
|
|
1249
|
-
|
|
1250
|
-
|
|
1385
|
+
return c.json(ok(payload));
|
|
1386
|
+
} catch (error) {
|
|
1387
|
+
const message = String(error);
|
|
1388
|
+
if (message.startsWith("INVALID_BODY:")) {
|
|
1389
|
+
return c.json(err("INVALID_BODY", message.slice("INVALID_BODY:".length)), 400);
|
|
1390
|
+
}
|
|
1391
|
+
if (message.startsWith("NOT_AVAILABLE:")) {
|
|
1392
|
+
return c.json(err("NOT_AVAILABLE", message.slice("NOT_AVAILABLE:".length)), 503);
|
|
1393
|
+
}
|
|
1394
|
+
return c.json(err("MANAGE_FAILED", message), 400);
|
|
1395
|
+
}
|
|
1396
|
+
});
|
|
1397
|
+
app.get("/api/marketplace/skills/recommendations", async (c) => {
|
|
1398
|
+
const query = c.req.query();
|
|
1399
|
+
const result = await fetchMarketplaceData({
|
|
1400
|
+
baseUrl: marketplaceBaseUrl,
|
|
1401
|
+
path: "/api/v1/skills/recommendations",
|
|
1402
|
+
query: {
|
|
1403
|
+
scene: query.scene,
|
|
1404
|
+
limit: query.limit
|
|
1251
1405
|
}
|
|
1252
|
-
const knownSkillNames = collectKnownSkillNames(options);
|
|
1253
|
-
const filteredItems = result.data.items.map((item) => sanitizeMarketplaceItem(item)).filter((item) => isSupportedMarketplaceItem(item, knownSkillNames));
|
|
1254
|
-
return c.json(ok({
|
|
1255
|
-
...result.data,
|
|
1256
|
-
total: filteredItems.length,
|
|
1257
|
-
items: filteredItems
|
|
1258
|
-
}));
|
|
1259
1406
|
});
|
|
1260
|
-
|
|
1407
|
+
if (!result.ok) {
|
|
1408
|
+
return c.json(err("MARKETPLACE_UNAVAILABLE", result.message), result.status);
|
|
1409
|
+
}
|
|
1410
|
+
const knownSkillNames = collectKnownSkillNames(options);
|
|
1411
|
+
const filteredItems = result.data.items.map((item) => sanitizeMarketplaceItem(item)).filter((item) => isSupportedMarketplaceSkillItem(item, knownSkillNames));
|
|
1412
|
+
return c.json(ok({
|
|
1413
|
+
...result.data,
|
|
1414
|
+
total: filteredItems.length,
|
|
1415
|
+
items: filteredItems
|
|
1416
|
+
}));
|
|
1417
|
+
});
|
|
1418
|
+
}
|
|
1419
|
+
function registerMarketplaceRoutes(app, options, marketplaceBaseUrl) {
|
|
1420
|
+
registerPluginMarketplaceRoutes(app, options, marketplaceBaseUrl);
|
|
1421
|
+
registerSkillMarketplaceRoutes(app, options, marketplaceBaseUrl);
|
|
1261
1422
|
}
|
|
1262
1423
|
function createUiRouter(options) {
|
|
1263
1424
|
const app = new Hono();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/server",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.14",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Nextclaw UI/API server.",
|
|
6
6
|
"type": "module",
|
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
],
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@hono/node-server": "^1.13.3",
|
|
18
|
-
"@nextclaw/openclaw-compat": "^0.1.
|
|
18
|
+
"@nextclaw/openclaw-compat": "^0.1.27",
|
|
19
19
|
"hono": "^4.6.2",
|
|
20
20
|
"ws": "^8.18.0",
|
|
21
|
-
"@nextclaw/core": "^0.6.
|
|
21
|
+
"@nextclaw/core": "^0.6.33"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@types/node": "^20.17.6",
|