nextclaw 0.12.6 → 0.13.0
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/cli/index.js +722 -299
- package/package.json +6 -6
- package/templates/USAGE.md +9 -0
- package/ui-dist/assets/{ChannelsList-DKD6Llid.js → ChannelsList-DH1Ur9XW.js} +1 -1
- package/ui-dist/assets/ChatPage-YTDcN7XS.js +38 -0
- package/ui-dist/assets/{DocBrowser-CVwUDJMO.js → DocBrowser-Bi-RpLIw.js} +1 -1
- package/ui-dist/assets/{LogoBadge-CYQ_b7jk.js → LogoBadge-BCR9CU7n.js} +1 -1
- package/ui-dist/assets/MarketplacePage-BgCdiku7.js +49 -0
- package/ui-dist/assets/McpMarketplacePage-nyCbiQH6.js +40 -0
- package/ui-dist/assets/{ModelConfig-CsX-_fyy.js → ModelConfig-Cf4AAYaB.js} +1 -1
- package/ui-dist/assets/{ProvidersList-CZstsyv7.js → ProvidersList-CfkfKQbw.js} +1 -1
- package/ui-dist/assets/{RuntimeConfig-CX2TGEG1.js → RuntimeConfig-BI-zClCl.js} +1 -1
- package/ui-dist/assets/{SearchConfig-C-WBTcWi.js → SearchConfig-MBmvco1J.js} +1 -1
- package/ui-dist/assets/{SecretsConfig-9kbR0ZCB.js → SecretsConfig-CC2B6pVQ.js} +1 -1
- package/ui-dist/assets/{SessionsConfig-Bohn3P1q.js → SessionsConfig-CTxJeVQs.js} +1 -1
- package/ui-dist/assets/{chat-message-AWIcksDK.js → chat-message-5OiyZViy.js} +1 -1
- package/ui-dist/assets/index-C2OKcVdN.css +1 -0
- package/ui-dist/assets/{index-CPDASUXh.js → index-ElnZdv5o.js} +1 -1
- package/ui-dist/assets/index-LgjZxLjc.js +8 -0
- package/ui-dist/assets/{label-DD61y-4v.js → label-CPdcDrir.js} +1 -1
- package/ui-dist/assets/marketplace-localization-Dk31LJJJ.js +1 -0
- package/ui-dist/assets/{page-layout-CfnoVycc.js → page-layout-B8V5_vM_.js} +1 -1
- package/ui-dist/assets/{popover-DsugZ6rp.js → popover-Bk53A74_.js} +1 -1
- package/ui-dist/assets/{security-config-DIrf2Z0O.js → security-config-BNjgoyo4.js} +1 -1
- package/ui-dist/assets/skeleton-NPxxR-L0.js +1 -0
- package/ui-dist/assets/{switch-NX5OmUXQ.js → switch-EowdzMK2.js} +1 -1
- package/ui-dist/assets/{tabs-custom-9ihB5Jem.js → tabs-custom-BjLv-uCT.js} +1 -1
- package/ui-dist/assets/{useConfirmDialog-BuQnVTeR.js → useConfirmDialog-TJcJQMfu.js} +2 -2
- package/ui-dist/assets/{vendor-DKBNiC31.js → vendor-425xp8cv.js} +1 -1
- package/ui-dist/index.html +3 -3
- package/ui-dist/assets/ChatPage-BK9X4Tin.js +0 -38
- package/ui-dist/assets/MarketplacePage-B_2z3ii_.js +0 -49
- package/ui-dist/assets/index-BEgClaDH.js +0 -8
- package/ui-dist/assets/index-C8GsgIUn.css +0 -1
- package/ui-dist/assets/skeleton-DJ-Wen2o.js +0 -1
package/dist/cli/index.js
CHANGED
|
@@ -6,12 +6,12 @@ import { APP_NAME as APP_NAME5, APP_TAGLINE } from "@nextclaw/core";
|
|
|
6
6
|
|
|
7
7
|
// src/cli/runtime.ts
|
|
8
8
|
import {
|
|
9
|
-
loadConfig as
|
|
10
|
-
saveConfig as
|
|
11
|
-
getConfigPath as
|
|
12
|
-
getDataDir as
|
|
9
|
+
loadConfig as loadConfig12,
|
|
10
|
+
saveConfig as saveConfig8,
|
|
11
|
+
getConfigPath as getConfigPath5,
|
|
12
|
+
getDataDir as getDataDir9,
|
|
13
13
|
ConfigSchema as ConfigSchema2,
|
|
14
|
-
getWorkspacePath as
|
|
14
|
+
getWorkspacePath as getWorkspacePath10,
|
|
15
15
|
expandHome as expandHome2,
|
|
16
16
|
MessageBus as MessageBus2,
|
|
17
17
|
AgentLoop,
|
|
@@ -26,8 +26,8 @@ import {
|
|
|
26
26
|
resolvePluginChannelMessageToolHints as resolvePluginChannelMessageToolHints2,
|
|
27
27
|
setPluginRuntimeBridge as setPluginRuntimeBridge2
|
|
28
28
|
} from "@nextclaw/openclaw-compat";
|
|
29
|
-
import { existsSync as
|
|
30
|
-
import { join as
|
|
29
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync11, writeFileSync as writeFileSync7 } from "fs";
|
|
30
|
+
import { join as join9, resolve as resolve12 } from "path";
|
|
31
31
|
import { createInterface as createInterface2 } from "readline";
|
|
32
32
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
33
33
|
import { spawn as spawn3 } from "child_process";
|
|
@@ -74,9 +74,9 @@ var RestartCoordinator = class {
|
|
|
74
74
|
message: "Restart already scheduled; skipping duplicate request."
|
|
75
75
|
};
|
|
76
76
|
}
|
|
77
|
-
const
|
|
77
|
+
const delay2 = typeof request.delayMs === "number" && Number.isFinite(request.delayMs) ? Math.max(0, Math.floor(request.delayMs)) : 100;
|
|
78
78
|
this.exitScheduled = true;
|
|
79
|
-
this.deps.scheduleProcessExit(
|
|
79
|
+
this.deps.scheduleProcessExit(delay2, reason);
|
|
80
80
|
return {
|
|
81
81
|
status: "exit-scheduled",
|
|
82
82
|
message: `Restart scheduled (${reason}).`
|
|
@@ -1486,6 +1486,7 @@ function toExtensionRegistry(pluginRegistry) {
|
|
|
1486
1486
|
kind: runtime2.kind,
|
|
1487
1487
|
label: runtime2.label,
|
|
1488
1488
|
createRuntime: runtime2.createRuntime,
|
|
1489
|
+
describeSessionType: runtime2.describeSessionType,
|
|
1489
1490
|
source: runtime2.source
|
|
1490
1491
|
})),
|
|
1491
1492
|
diagnostics: pluginRegistry.diagnostics.map((diag) => ({
|
|
@@ -2118,7 +2119,11 @@ var ConfigCommands = class {
|
|
|
2118
2119
|
|
|
2119
2120
|
// src/cli/commands/mcp.ts
|
|
2120
2121
|
import { loadConfig as loadConfig4, saveConfig as saveConfig3 } from "@nextclaw/core";
|
|
2121
|
-
import {
|
|
2122
|
+
import {
|
|
2123
|
+
McpDoctorFacade,
|
|
2124
|
+
McpMutationService,
|
|
2125
|
+
McpRegistryService
|
|
2126
|
+
} from "@nextclaw/mcp";
|
|
2122
2127
|
function normalizeOptionalString(value) {
|
|
2123
2128
|
if (typeof value !== "string") {
|
|
2124
2129
|
return void 0;
|
|
@@ -2155,12 +2160,12 @@ function parseTimeoutMs(value) {
|
|
|
2155
2160
|
function buildMcpServerDefinition(command, opts) {
|
|
2156
2161
|
const transport = (normalizeOptionalString(opts.transport) ?? "stdio").toLowerCase();
|
|
2157
2162
|
const disabled = Boolean(opts.disabled);
|
|
2158
|
-
const allAgents = Boolean(opts.allAgents);
|
|
2159
2163
|
const explicitAgents = Array.from(
|
|
2160
2164
|
new Set(
|
|
2161
2165
|
(opts.agent ?? []).map((agentId) => normalizeOptionalString(agentId)).filter((agentId) => Boolean(agentId))
|
|
2162
2166
|
)
|
|
2163
2167
|
);
|
|
2168
|
+
const allAgents = explicitAgents.length === 0 ? true : Boolean(opts.allAgents);
|
|
2164
2169
|
if (transport === "stdio") {
|
|
2165
2170
|
if (command.length === 0) {
|
|
2166
2171
|
throw new Error("stdio transport requires a command after --");
|
|
@@ -2177,11 +2182,15 @@ function buildMcpServerDefinition(command, opts) {
|
|
|
2177
2182
|
},
|
|
2178
2183
|
scope: {
|
|
2179
2184
|
allAgents,
|
|
2180
|
-
agents: explicitAgents
|
|
2185
|
+
agents: allAgents ? [] : explicitAgents
|
|
2181
2186
|
},
|
|
2182
2187
|
policy: {
|
|
2183
2188
|
trust: "explicit",
|
|
2184
2189
|
start: "eager"
|
|
2190
|
+
},
|
|
2191
|
+
metadata: {
|
|
2192
|
+
source: "manual",
|
|
2193
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2185
2194
|
}
|
|
2186
2195
|
};
|
|
2187
2196
|
}
|
|
@@ -2194,11 +2203,15 @@ function buildMcpServerDefinition(command, opts) {
|
|
|
2194
2203
|
enabled: !disabled,
|
|
2195
2204
|
scope: {
|
|
2196
2205
|
allAgents,
|
|
2197
|
-
agents: explicitAgents
|
|
2206
|
+
agents: allAgents ? [] : explicitAgents
|
|
2198
2207
|
},
|
|
2199
2208
|
policy: {
|
|
2200
2209
|
trust: "explicit",
|
|
2201
2210
|
start: "eager"
|
|
2211
|
+
},
|
|
2212
|
+
metadata: {
|
|
2213
|
+
source: "manual",
|
|
2214
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2202
2215
|
}
|
|
2203
2216
|
};
|
|
2204
2217
|
if (transport === "http") {
|
|
@@ -2257,26 +2270,28 @@ var McpCommands = class {
|
|
|
2257
2270
|
}
|
|
2258
2271
|
}
|
|
2259
2272
|
async mcpAdd(name, command, opts) {
|
|
2260
|
-
const
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2273
|
+
const mutation = new McpMutationService({
|
|
2274
|
+
getConfig: () => loadConfig4(),
|
|
2275
|
+
saveConfig: (config2) => saveConfig3(config2)
|
|
2276
|
+
});
|
|
2277
|
+
const result = mutation.addServer(name, buildMcpServerDefinition(command, opts));
|
|
2278
|
+
if (!result.changed) {
|
|
2279
|
+
reportUserInputIssue(result.message);
|
|
2264
2280
|
return;
|
|
2265
2281
|
}
|
|
2266
|
-
|
|
2267
|
-
saveConfig3(config2);
|
|
2268
|
-
console.log(`Added MCP server ${normalizedName}.`);
|
|
2282
|
+
console.log(result.message);
|
|
2269
2283
|
}
|
|
2270
2284
|
async mcpRemove(name) {
|
|
2271
|
-
const
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2285
|
+
const mutation = new McpMutationService({
|
|
2286
|
+
getConfig: () => loadConfig4(),
|
|
2287
|
+
saveConfig: (config2) => saveConfig3(config2)
|
|
2288
|
+
});
|
|
2289
|
+
const result = mutation.removeServer(name);
|
|
2290
|
+
if (!result.changed) {
|
|
2291
|
+
reportUserInputIssue(result.message);
|
|
2275
2292
|
return;
|
|
2276
2293
|
}
|
|
2277
|
-
|
|
2278
|
-
saveConfig3(config2);
|
|
2279
|
-
console.log(`Removed MCP server ${normalizedName}.`);
|
|
2294
|
+
console.log(result.message);
|
|
2280
2295
|
}
|
|
2281
2296
|
async mcpEnable(name) {
|
|
2282
2297
|
await this.toggleEnabled(name, true);
|
|
@@ -2288,7 +2303,7 @@ var McpCommands = class {
|
|
|
2288
2303
|
const registry = new McpRegistryService({
|
|
2289
2304
|
getConfig: () => loadConfig4()
|
|
2290
2305
|
});
|
|
2291
|
-
const doctor = new
|
|
2306
|
+
const doctor = new McpDoctorFacade({
|
|
2292
2307
|
getConfig: () => loadConfig4(),
|
|
2293
2308
|
registryService: registry
|
|
2294
2309
|
});
|
|
@@ -2314,16 +2329,16 @@ var McpCommands = class {
|
|
|
2314
2329
|
}
|
|
2315
2330
|
}
|
|
2316
2331
|
async toggleEnabled(name, enabled) {
|
|
2317
|
-
const
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2332
|
+
const mutation = new McpMutationService({
|
|
2333
|
+
getConfig: () => loadConfig4(),
|
|
2334
|
+
saveConfig: (config2) => saveConfig3(config2)
|
|
2335
|
+
});
|
|
2336
|
+
const result = mutation.toggleEnabled(name, enabled);
|
|
2337
|
+
if (!result.changed) {
|
|
2338
|
+
reportUserInputIssue(result.message);
|
|
2322
2339
|
return;
|
|
2323
2340
|
}
|
|
2324
|
-
|
|
2325
|
-
saveConfig3(config2);
|
|
2326
|
-
console.log(`${enabled ? "Enabled" : "Disabled"} MCP server ${normalizedName}.`);
|
|
2341
|
+
console.log(result.message);
|
|
2327
2342
|
}
|
|
2328
2343
|
};
|
|
2329
2344
|
function reportUserInputIssue(message) {
|
|
@@ -2844,17 +2859,281 @@ var CronCommands = class {
|
|
|
2844
2859
|
}
|
|
2845
2860
|
};
|
|
2846
2861
|
|
|
2862
|
+
// src/cli/commands/remote.ts
|
|
2863
|
+
import { getConfigPath as getConfigPath2, getDataDir as getDataDir4, loadConfig as loadConfig7 } from "@nextclaw/core";
|
|
2864
|
+
import { ensureUiBridgeSecret } from "@nextclaw/server";
|
|
2865
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
2866
|
+
import { dirname as dirname2, join as join4 } from "path";
|
|
2867
|
+
import { hostname, platform as readPlatform } from "os";
|
|
2868
|
+
function encodeBase64(bytes) {
|
|
2869
|
+
return Buffer.from(bytes).toString("base64");
|
|
2870
|
+
}
|
|
2871
|
+
function decodeBase64(base64) {
|
|
2872
|
+
if (!base64) {
|
|
2873
|
+
return new Uint8Array();
|
|
2874
|
+
}
|
|
2875
|
+
return new Uint8Array(Buffer.from(base64, "base64"));
|
|
2876
|
+
}
|
|
2877
|
+
function delay(ms) {
|
|
2878
|
+
return new Promise((resolveDelay) => setTimeout(resolveDelay, ms));
|
|
2879
|
+
}
|
|
2880
|
+
function ensureDir(path2) {
|
|
2881
|
+
mkdirSync4(path2, { recursive: true });
|
|
2882
|
+
}
|
|
2883
|
+
function readJsonFile2(path2) {
|
|
2884
|
+
if (!existsSync6(path2)) {
|
|
2885
|
+
return null;
|
|
2886
|
+
}
|
|
2887
|
+
try {
|
|
2888
|
+
return JSON.parse(readFileSync6(path2, "utf-8"));
|
|
2889
|
+
} catch {
|
|
2890
|
+
return null;
|
|
2891
|
+
}
|
|
2892
|
+
}
|
|
2893
|
+
function writeJsonFile(path2, value) {
|
|
2894
|
+
ensureDir(dirname2(path2));
|
|
2895
|
+
writeFileSync4(path2, `${JSON.stringify(value, null, 2)}
|
|
2896
|
+
`, "utf-8");
|
|
2897
|
+
}
|
|
2898
|
+
var RemoteCommands = class {
|
|
2899
|
+
remoteDir = join4(getDataDir4(), "remote");
|
|
2900
|
+
devicePath = join4(this.remoteDir, "device.json");
|
|
2901
|
+
ensureDeviceInstallId() {
|
|
2902
|
+
const existing = readJsonFile2(this.devicePath);
|
|
2903
|
+
if (existing?.deviceInstallId?.trim()) {
|
|
2904
|
+
return existing.deviceInstallId.trim();
|
|
2905
|
+
}
|
|
2906
|
+
const deviceInstallId = crypto.randomUUID();
|
|
2907
|
+
ensureDir(this.remoteDir);
|
|
2908
|
+
writeJsonFile(this.devicePath, { deviceInstallId });
|
|
2909
|
+
return deviceInstallId;
|
|
2910
|
+
}
|
|
2911
|
+
resolvePlatformAccess(opts) {
|
|
2912
|
+
const config2 = loadConfig7(getConfigPath2());
|
|
2913
|
+
const providers = config2.providers;
|
|
2914
|
+
const nextclawProvider = providers.nextclaw;
|
|
2915
|
+
const token = typeof nextclawProvider?.apiKey === "string" ? nextclawProvider.apiKey.trim() : "";
|
|
2916
|
+
if (!token) {
|
|
2917
|
+
throw new Error('NextClaw platform token is missing. Run "nextclaw login" first.');
|
|
2918
|
+
}
|
|
2919
|
+
const configuredApiBase = typeof nextclawProvider?.apiBase === "string" ? nextclawProvider.apiBase.trim() : "";
|
|
2920
|
+
const rawApiBase = typeof opts.apiBase === "string" && opts.apiBase.trim().length > 0 ? opts.apiBase.trim() : configuredApiBase;
|
|
2921
|
+
if (!rawApiBase) {
|
|
2922
|
+
throw new Error("Platform API base is missing. Pass --api-base or run nextclaw login.");
|
|
2923
|
+
}
|
|
2924
|
+
const platformBase = rawApiBase.replace(/\/v1\/?$/i, "");
|
|
2925
|
+
return { platformBase, token, config: config2 };
|
|
2926
|
+
}
|
|
2927
|
+
resolveLocalOrigin(config2, opts) {
|
|
2928
|
+
if (typeof opts.localOrigin === "string" && opts.localOrigin.trim().length > 0) {
|
|
2929
|
+
return opts.localOrigin.trim().replace(/\/$/, "");
|
|
2930
|
+
}
|
|
2931
|
+
const state = readServiceState();
|
|
2932
|
+
if (state && isProcessRunning(state.pid) && Number.isFinite(state.uiPort)) {
|
|
2933
|
+
return `http://127.0.0.1:${state.uiPort}`;
|
|
2934
|
+
}
|
|
2935
|
+
const configuredPort = typeof config2.ui?.port === "number" && Number.isFinite(config2.ui.port) ? config2.ui.port : 18791;
|
|
2936
|
+
return `http://127.0.0.1:${configuredPort}`;
|
|
2937
|
+
}
|
|
2938
|
+
async ensureLocalUiHealthy(localOrigin) {
|
|
2939
|
+
const response = await fetch(`${localOrigin}/api/health`);
|
|
2940
|
+
if (!response.ok) {
|
|
2941
|
+
throw new Error(`Local UI is not healthy at ${localOrigin}. Start NextClaw first.`);
|
|
2942
|
+
}
|
|
2943
|
+
}
|
|
2944
|
+
async registerDevice(params) {
|
|
2945
|
+
const response = await fetch(`${params.platformBase}/platform/remote/devices/register`, {
|
|
2946
|
+
method: "POST",
|
|
2947
|
+
headers: {
|
|
2948
|
+
"content-type": "application/json",
|
|
2949
|
+
authorization: `Bearer ${params.token}`
|
|
2950
|
+
},
|
|
2951
|
+
body: JSON.stringify({
|
|
2952
|
+
deviceInstallId: params.deviceInstallId,
|
|
2953
|
+
displayName: params.displayName,
|
|
2954
|
+
platform: readPlatform(),
|
|
2955
|
+
appVersion: getPackageVersion(),
|
|
2956
|
+
localOrigin: params.localOrigin
|
|
2957
|
+
})
|
|
2958
|
+
});
|
|
2959
|
+
const payload = await response.json();
|
|
2960
|
+
if (!response.ok || !payload.ok || !payload.data?.device) {
|
|
2961
|
+
throw new Error(payload.error?.message ?? `Failed to register remote device (${response.status}).`);
|
|
2962
|
+
}
|
|
2963
|
+
return payload.data.device;
|
|
2964
|
+
}
|
|
2965
|
+
async requestBridgeCookie(localOrigin) {
|
|
2966
|
+
const response = await fetch(`${localOrigin}/api/auth/bridge`, {
|
|
2967
|
+
method: "POST",
|
|
2968
|
+
headers: {
|
|
2969
|
+
"x-nextclaw-ui-bridge-secret": ensureUiBridgeSecret()
|
|
2970
|
+
}
|
|
2971
|
+
});
|
|
2972
|
+
const payload = await response.json();
|
|
2973
|
+
if (!response.ok || !payload.ok) {
|
|
2974
|
+
throw new Error(payload.error?.message ?? `Failed to request local auth bridge (${response.status}).`);
|
|
2975
|
+
}
|
|
2976
|
+
return typeof payload.data?.cookie === "string" && payload.data.cookie.trim().length > 0 ? payload.data.cookie.trim() : null;
|
|
2977
|
+
}
|
|
2978
|
+
async handleRelayRequest(params) {
|
|
2979
|
+
const bridgeCookie = await this.requestBridgeCookie(params.localOrigin);
|
|
2980
|
+
const url = new URL(params.frame.path, params.localOrigin);
|
|
2981
|
+
const headers = new Headers();
|
|
2982
|
+
for (const [key, value] of params.frame.headers) {
|
|
2983
|
+
const lower = key.toLowerCase();
|
|
2984
|
+
if ([
|
|
2985
|
+
"host",
|
|
2986
|
+
"connection",
|
|
2987
|
+
"content-length",
|
|
2988
|
+
"cookie",
|
|
2989
|
+
"x-forwarded-for",
|
|
2990
|
+
"x-forwarded-proto",
|
|
2991
|
+
"cf-connecting-ip"
|
|
2992
|
+
].includes(lower)) {
|
|
2993
|
+
continue;
|
|
2994
|
+
}
|
|
2995
|
+
headers.set(key, value);
|
|
2996
|
+
}
|
|
2997
|
+
if (bridgeCookie) {
|
|
2998
|
+
headers.set("cookie", bridgeCookie);
|
|
2999
|
+
}
|
|
3000
|
+
const bodyBytes = decodeBase64(params.frame.bodyBase64);
|
|
3001
|
+
const response = await fetch(url, {
|
|
3002
|
+
method: params.frame.method,
|
|
3003
|
+
headers,
|
|
3004
|
+
body: params.frame.method === "GET" || params.frame.method === "HEAD" ? void 0 : bodyBytes
|
|
3005
|
+
});
|
|
3006
|
+
const responseHeaders = Array.from(response.headers.entries()).filter(([key]) => {
|
|
3007
|
+
const lower = key.toLowerCase();
|
|
3008
|
+
return !["content-length", "connection", "transfer-encoding", "set-cookie"].includes(lower);
|
|
3009
|
+
});
|
|
3010
|
+
const contentType = response.headers.get("content-type")?.toLowerCase() ?? "";
|
|
3011
|
+
if (response.body && contentType.startsWith("text/event-stream")) {
|
|
3012
|
+
params.socket.send(JSON.stringify({
|
|
3013
|
+
type: "response.start",
|
|
3014
|
+
requestId: params.frame.requestId,
|
|
3015
|
+
status: response.status,
|
|
3016
|
+
headers: responseHeaders
|
|
3017
|
+
}));
|
|
3018
|
+
const reader = response.body.getReader();
|
|
3019
|
+
try {
|
|
3020
|
+
while (true) {
|
|
3021
|
+
const { value, done } = await reader.read();
|
|
3022
|
+
if (done) {
|
|
3023
|
+
break;
|
|
3024
|
+
}
|
|
3025
|
+
if (value && value.length > 0) {
|
|
3026
|
+
params.socket.send(JSON.stringify({
|
|
3027
|
+
type: "response.chunk",
|
|
3028
|
+
requestId: params.frame.requestId,
|
|
3029
|
+
bodyBase64: encodeBase64(value)
|
|
3030
|
+
}));
|
|
3031
|
+
}
|
|
3032
|
+
}
|
|
3033
|
+
} finally {
|
|
3034
|
+
reader.releaseLock();
|
|
3035
|
+
}
|
|
3036
|
+
params.socket.send(JSON.stringify({
|
|
3037
|
+
type: "response.end",
|
|
3038
|
+
requestId: params.frame.requestId
|
|
3039
|
+
}));
|
|
3040
|
+
return;
|
|
3041
|
+
}
|
|
3042
|
+
const responseBody = response.body ? new Uint8Array(await response.arrayBuffer()) : new Uint8Array();
|
|
3043
|
+
params.socket.send(JSON.stringify({
|
|
3044
|
+
type: "response",
|
|
3045
|
+
requestId: params.frame.requestId,
|
|
3046
|
+
status: response.status,
|
|
3047
|
+
headers: responseHeaders,
|
|
3048
|
+
bodyBase64: encodeBase64(responseBody)
|
|
3049
|
+
}));
|
|
3050
|
+
}
|
|
3051
|
+
async connectOnce(params) {
|
|
3052
|
+
await new Promise((resolve13, reject) => {
|
|
3053
|
+
const socket = new WebSocket(params.wsUrl);
|
|
3054
|
+
const pingTimer = setInterval(() => {
|
|
3055
|
+
if (socket.readyState === WebSocket.OPEN) {
|
|
3056
|
+
socket.send(JSON.stringify({ type: "ping", at: (/* @__PURE__ */ new Date()).toISOString() }));
|
|
3057
|
+
}
|
|
3058
|
+
}, 15e3);
|
|
3059
|
+
socket.addEventListener("open", () => {
|
|
3060
|
+
console.log(`\u2713 Remote connector connected: ${params.wsUrl}`);
|
|
3061
|
+
});
|
|
3062
|
+
socket.addEventListener("message", (event) => {
|
|
3063
|
+
void (async () => {
|
|
3064
|
+
let frame = null;
|
|
3065
|
+
try {
|
|
3066
|
+
frame = JSON.parse(String(event.data ?? ""));
|
|
3067
|
+
} catch {
|
|
3068
|
+
return;
|
|
3069
|
+
}
|
|
3070
|
+
if (!frame || frame.type !== "request") {
|
|
3071
|
+
return;
|
|
3072
|
+
}
|
|
3073
|
+
try {
|
|
3074
|
+
await this.handleRelayRequest({ frame, localOrigin: params.localOrigin, socket });
|
|
3075
|
+
} catch (error) {
|
|
3076
|
+
socket.send(JSON.stringify({
|
|
3077
|
+
type: "response.error",
|
|
3078
|
+
requestId: frame.requestId,
|
|
3079
|
+
message: error instanceof Error ? error.message : String(error)
|
|
3080
|
+
}));
|
|
3081
|
+
}
|
|
3082
|
+
})();
|
|
3083
|
+
});
|
|
3084
|
+
socket.addEventListener("close", () => {
|
|
3085
|
+
clearInterval(pingTimer);
|
|
3086
|
+
resolve13();
|
|
3087
|
+
});
|
|
3088
|
+
socket.addEventListener("error", () => {
|
|
3089
|
+
clearInterval(pingTimer);
|
|
3090
|
+
reject(new Error("Remote connector websocket failed."));
|
|
3091
|
+
});
|
|
3092
|
+
});
|
|
3093
|
+
}
|
|
3094
|
+
async connect(opts = {}) {
|
|
3095
|
+
const { platformBase, token, config: config2 } = this.resolvePlatformAccess(opts);
|
|
3096
|
+
const localOrigin = this.resolveLocalOrigin(config2, opts);
|
|
3097
|
+
await this.ensureLocalUiHealthy(localOrigin);
|
|
3098
|
+
const deviceInstallId = this.ensureDeviceInstallId();
|
|
3099
|
+
const displayName = typeof opts.name === "string" && opts.name.trim().length > 0 ? opts.name.trim() : hostname();
|
|
3100
|
+
const device = await this.registerDevice({
|
|
3101
|
+
platformBase,
|
|
3102
|
+
token,
|
|
3103
|
+
deviceInstallId,
|
|
3104
|
+
displayName,
|
|
3105
|
+
localOrigin
|
|
3106
|
+
});
|
|
3107
|
+
console.log(`\u2713 Remote device registered: ${device.displayName} (${device.id})`);
|
|
3108
|
+
console.log(`\u2713 Local origin: ${localOrigin}`);
|
|
3109
|
+
console.log(`\u2713 Platform: ${platformBase}`);
|
|
3110
|
+
const wsUrl = `${platformBase.replace(/^http/i, "ws")}/platform/remote/connect?deviceId=${encodeURIComponent(device.id)}&token=${encodeURIComponent(token)}`;
|
|
3111
|
+
do {
|
|
3112
|
+
try {
|
|
3113
|
+
await this.connectOnce({ wsUrl, localOrigin });
|
|
3114
|
+
} catch (error) {
|
|
3115
|
+
console.error(`Remote connector error: ${error instanceof Error ? error.message : String(error)}`);
|
|
3116
|
+
}
|
|
3117
|
+
if (opts.once) {
|
|
3118
|
+
break;
|
|
3119
|
+
}
|
|
3120
|
+
console.log("Remote connector disconnected. Reconnecting in 3s...");
|
|
3121
|
+
await delay(3e3);
|
|
3122
|
+
} while (!opts.once);
|
|
3123
|
+
}
|
|
3124
|
+
};
|
|
3125
|
+
|
|
2847
3126
|
// src/cli/commands/diagnostics.ts
|
|
2848
3127
|
import { createServer as createNetServer } from "net";
|
|
2849
|
-
import { existsSync as
|
|
3128
|
+
import { existsSync as existsSync7, readFileSync as readFileSync7 } from "fs";
|
|
2850
3129
|
import { resolve as resolve8 } from "path";
|
|
2851
3130
|
import {
|
|
2852
3131
|
APP_NAME,
|
|
2853
|
-
getConfigPath as
|
|
2854
|
-
getDataDir as
|
|
3132
|
+
getConfigPath as getConfigPath3,
|
|
3133
|
+
getDataDir as getDataDir5,
|
|
2855
3134
|
getWorkspacePath as getWorkspacePath4,
|
|
2856
3135
|
hasSecretRef,
|
|
2857
|
-
loadConfig as
|
|
3136
|
+
loadConfig as loadConfig8
|
|
2858
3137
|
} from "@nextclaw/core";
|
|
2859
3138
|
import { listBuiltinProviders } from "@nextclaw/runtime";
|
|
2860
3139
|
var DiagnosticsCommands = class {
|
|
@@ -3015,10 +3294,10 @@ var DiagnosticsCommands = class {
|
|
|
3015
3294
|
process.exitCode = exitCode;
|
|
3016
3295
|
}
|
|
3017
3296
|
async collectRuntimeStatus(params) {
|
|
3018
|
-
const configPath =
|
|
3019
|
-
const config2 =
|
|
3297
|
+
const configPath = getConfigPath3();
|
|
3298
|
+
const config2 = loadConfig8();
|
|
3020
3299
|
const workspacePath = getWorkspacePath4(config2.agents.defaults.workspace);
|
|
3021
|
-
const serviceStatePath = resolve8(
|
|
3300
|
+
const serviceStatePath = resolve8(getDataDir5(), "run", "service.json");
|
|
3022
3301
|
const fixActions = [];
|
|
3023
3302
|
let serviceState = readServiceState();
|
|
3024
3303
|
if (params.fix && serviceState && !isProcessRunning(serviceState.pid)) {
|
|
@@ -3058,11 +3337,11 @@ var DiagnosticsCommands = class {
|
|
|
3058
3337
|
});
|
|
3059
3338
|
const issues = [];
|
|
3060
3339
|
const recommendations = [];
|
|
3061
|
-
if (!
|
|
3340
|
+
if (!existsSync7(configPath)) {
|
|
3062
3341
|
issues.push("Config file is missing.");
|
|
3063
3342
|
recommendations.push(`Run ${APP_NAME} init to create config files.`);
|
|
3064
3343
|
}
|
|
3065
|
-
if (!
|
|
3344
|
+
if (!existsSync7(workspacePath)) {
|
|
3066
3345
|
issues.push("Workspace directory does not exist.");
|
|
3067
3346
|
recommendations.push(`Run ${APP_NAME} init to create workspace templates.`);
|
|
3068
3347
|
}
|
|
@@ -3095,13 +3374,13 @@ var DiagnosticsCommands = class {
|
|
|
3095
3374
|
return {
|
|
3096
3375
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3097
3376
|
configPath,
|
|
3098
|
-
configExists:
|
|
3377
|
+
configExists: existsSync7(configPath),
|
|
3099
3378
|
workspacePath,
|
|
3100
|
-
workspaceExists:
|
|
3379
|
+
workspaceExists: existsSync7(workspacePath),
|
|
3101
3380
|
model: config2.agents.defaults.model,
|
|
3102
3381
|
providers,
|
|
3103
3382
|
serviceStatePath,
|
|
3104
|
-
serviceStateExists:
|
|
3383
|
+
serviceStateExists: existsSync7(serviceStatePath),
|
|
3105
3384
|
fixActions,
|
|
3106
3385
|
process: {
|
|
3107
3386
|
managedByState,
|
|
@@ -3151,11 +3430,11 @@ var DiagnosticsCommands = class {
|
|
|
3151
3430
|
}
|
|
3152
3431
|
}
|
|
3153
3432
|
readLogTail(path2, maxLines = 25) {
|
|
3154
|
-
if (!
|
|
3433
|
+
if (!existsSync7(path2)) {
|
|
3155
3434
|
return [];
|
|
3156
3435
|
}
|
|
3157
3436
|
try {
|
|
3158
|
-
const lines =
|
|
3437
|
+
const lines = readFileSync7(path2, "utf-8").split(/\r?\n/).filter(Boolean);
|
|
3159
3438
|
if (lines.length <= maxLines) {
|
|
3160
3439
|
return lines;
|
|
3161
3440
|
}
|
|
@@ -3195,8 +3474,8 @@ import {
|
|
|
3195
3474
|
stopPluginChannelGateways as stopPluginChannelGateways2
|
|
3196
3475
|
} from "@nextclaw/openclaw-compat";
|
|
3197
3476
|
import { startUiServer } from "@nextclaw/server";
|
|
3198
|
-
import { appendFileSync, closeSync, cpSync as cpSync2, existsSync as
|
|
3199
|
-
import { dirname as
|
|
3477
|
+
import { appendFileSync, closeSync, cpSync as cpSync2, existsSync as existsSync11, mkdirSync as mkdirSync6, openSync } from "fs";
|
|
3478
|
+
import { dirname as dirname3, join as join7, resolve as resolve10 } from "path";
|
|
3200
3479
|
import { spawn as spawn2 } from "child_process";
|
|
3201
3480
|
import { request as httpRequest } from "http";
|
|
3202
3481
|
import { request as httpsRequest } from "https";
|
|
@@ -3205,7 +3484,7 @@ import chokidar from "chokidar";
|
|
|
3205
3484
|
|
|
3206
3485
|
// src/cli/gateway/controller.ts
|
|
3207
3486
|
import { createHash } from "crypto";
|
|
3208
|
-
import { existsSync as
|
|
3487
|
+
import { existsSync as existsSync8, readFileSync as readFileSync8 } from "fs";
|
|
3209
3488
|
import {
|
|
3210
3489
|
buildConfigSchema,
|
|
3211
3490
|
ConfigSchema,
|
|
@@ -3213,12 +3492,12 @@ import {
|
|
|
3213
3492
|
redactConfigObject
|
|
3214
3493
|
} from "@nextclaw/core";
|
|
3215
3494
|
var hashRaw = (raw) => createHash("sha256").update(raw).digest("hex");
|
|
3216
|
-
var readConfigSnapshot = (
|
|
3217
|
-
const path2 =
|
|
3495
|
+
var readConfigSnapshot = (getConfigPath6) => {
|
|
3496
|
+
const path2 = getConfigPath6();
|
|
3218
3497
|
let raw = "";
|
|
3219
3498
|
let parsed = {};
|
|
3220
|
-
if (
|
|
3221
|
-
raw =
|
|
3499
|
+
if (existsSync8(path2)) {
|
|
3500
|
+
raw = readFileSync8(path2, "utf-8");
|
|
3222
3501
|
try {
|
|
3223
3502
|
parsed = JSON.parse(raw);
|
|
3224
3503
|
} catch {
|
|
@@ -3325,11 +3604,11 @@ var GatewayControllerImpl = class {
|
|
|
3325
3604
|
await this.deps.requestRestart(options);
|
|
3326
3605
|
return;
|
|
3327
3606
|
}
|
|
3328
|
-
const
|
|
3607
|
+
const delay2 = typeof options?.delayMs === "number" && Number.isFinite(options.delayMs) ? Math.max(0, options.delayMs) : 100;
|
|
3329
3608
|
console.log(`Gateway restart requested via tool${options?.reason ? ` (${options.reason})` : ""}.`);
|
|
3330
3609
|
setTimeout(() => {
|
|
3331
3610
|
process.exit(0);
|
|
3332
|
-
},
|
|
3611
|
+
}, delay2);
|
|
3333
3612
|
}
|
|
3334
3613
|
status() {
|
|
3335
3614
|
return {
|
|
@@ -3674,8 +3953,242 @@ var MissingProvider = class extends LLMProvider {
|
|
|
3674
3953
|
}
|
|
3675
3954
|
};
|
|
3676
3955
|
|
|
3956
|
+
// src/cli/commands/service-marketplace-installer.ts
|
|
3957
|
+
import { getWorkspacePath as getWorkspacePath5, loadConfig as loadConfig10 } from "@nextclaw/core";
|
|
3958
|
+
import { existsSync as existsSync9, rmSync as rmSync4 } from "fs";
|
|
3959
|
+
import { join as join5 } from "path";
|
|
3960
|
+
|
|
3961
|
+
// src/cli/commands/service-marketplace-helpers.ts
|
|
3962
|
+
var containsAbsoluteFsPath = (line) => {
|
|
3963
|
+
const normalized = line.trim();
|
|
3964
|
+
if (!normalized) {
|
|
3965
|
+
return false;
|
|
3966
|
+
}
|
|
3967
|
+
const lowered = normalized.toLowerCase();
|
|
3968
|
+
if (lowered.includes("http://") || lowered.includes("https://")) {
|
|
3969
|
+
return false;
|
|
3970
|
+
}
|
|
3971
|
+
if (/^[A-Za-z]:\\/.test(normalized)) {
|
|
3972
|
+
return true;
|
|
3973
|
+
}
|
|
3974
|
+
return /(?:^|\s)(?:~\/|\/[^\s]+)/.test(normalized);
|
|
3975
|
+
};
|
|
3976
|
+
var pickUserFacingCommandSummary = (output, fallback) => {
|
|
3977
|
+
const lines = output.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
3978
|
+
if (lines.length === 0) {
|
|
3979
|
+
return fallback;
|
|
3980
|
+
}
|
|
3981
|
+
const visibleLines = lines.filter((line) => {
|
|
3982
|
+
if (/^(path|install path|source path|destination|location)\s*:/i.test(line)) {
|
|
3983
|
+
return false;
|
|
3984
|
+
}
|
|
3985
|
+
if (containsAbsoluteFsPath(line)) {
|
|
3986
|
+
return false;
|
|
3987
|
+
}
|
|
3988
|
+
return true;
|
|
3989
|
+
});
|
|
3990
|
+
if (visibleLines.length === 0) {
|
|
3991
|
+
return fallback;
|
|
3992
|
+
}
|
|
3993
|
+
const preferred = [...visibleLines].reverse().find(
|
|
3994
|
+
(line) => /\b(installed|enabled|disabled|uninstalled|published|updated|already installed|removed)\b/i.test(line)
|
|
3995
|
+
);
|
|
3996
|
+
return preferred ?? visibleLines[visibleLines.length - 1] ?? fallback;
|
|
3997
|
+
};
|
|
3998
|
+
var buildMarketplaceSkillInstallArgs = (params) => {
|
|
3999
|
+
const args = ["skills", "install", params.slug, "--workdir", params.workspace];
|
|
4000
|
+
if (params.force) {
|
|
4001
|
+
args.push("--force");
|
|
4002
|
+
}
|
|
4003
|
+
return args;
|
|
4004
|
+
};
|
|
4005
|
+
|
|
4006
|
+
// src/cli/commands/service-mcp-marketplace-ops.ts
|
|
4007
|
+
import { loadConfig as loadConfig9, saveConfig as saveConfig6 } from "@nextclaw/core";
|
|
4008
|
+
import { McpDoctorFacade as McpDoctorFacade2, McpMutationService as McpMutationService2 } from "@nextclaw/mcp";
|
|
4009
|
+
var ServiceMcpMarketplaceOps = class {
|
|
4010
|
+
constructor(options) {
|
|
4011
|
+
this.options = options;
|
|
4012
|
+
}
|
|
4013
|
+
async install(params) {
|
|
4014
|
+
if (!params.template) {
|
|
4015
|
+
throw new Error(`Missing MCP marketplace template for ${params.spec}`);
|
|
4016
|
+
}
|
|
4017
|
+
const template = params.template;
|
|
4018
|
+
const result = this.createMutationService().installFromTemplate({
|
|
4019
|
+
template,
|
|
4020
|
+
name: params.name,
|
|
4021
|
+
enabled: params.enabled,
|
|
4022
|
+
scope: {
|
|
4023
|
+
allAgents: params.allAgents ?? true,
|
|
4024
|
+
agents: params.allAgents === false ? params.agents ?? [] : []
|
|
4025
|
+
},
|
|
4026
|
+
inputs: params.inputs,
|
|
4027
|
+
metadata: {
|
|
4028
|
+
source: "marketplace",
|
|
4029
|
+
catalogSlug: params.spec,
|
|
4030
|
+
displayName: template.defaultName
|
|
4031
|
+
}
|
|
4032
|
+
});
|
|
4033
|
+
if (!result.changed) {
|
|
4034
|
+
throw new Error(result.message);
|
|
4035
|
+
}
|
|
4036
|
+
await this.options.applyLiveConfigReload?.();
|
|
4037
|
+
return {
|
|
4038
|
+
name: result.name,
|
|
4039
|
+
message: result.message
|
|
4040
|
+
};
|
|
4041
|
+
}
|
|
4042
|
+
async enable(name) {
|
|
4043
|
+
const result = this.createMutationService().toggleEnabled(name, true);
|
|
4044
|
+
if (!result.changed) {
|
|
4045
|
+
throw new Error(result.message);
|
|
4046
|
+
}
|
|
4047
|
+
await this.options.applyLiveConfigReload?.();
|
|
4048
|
+
return { message: result.message };
|
|
4049
|
+
}
|
|
4050
|
+
async disable(name) {
|
|
4051
|
+
const result = this.createMutationService().toggleEnabled(name, false);
|
|
4052
|
+
if (!result.changed) {
|
|
4053
|
+
throw new Error(result.message);
|
|
4054
|
+
}
|
|
4055
|
+
await this.options.applyLiveConfigReload?.();
|
|
4056
|
+
return { message: result.message };
|
|
4057
|
+
}
|
|
4058
|
+
async remove(name) {
|
|
4059
|
+
const result = this.createMutationService().removeServer(name);
|
|
4060
|
+
if (!result.changed) {
|
|
4061
|
+
throw new Error(result.message);
|
|
4062
|
+
}
|
|
4063
|
+
await this.options.applyLiveConfigReload?.();
|
|
4064
|
+
return { message: result.message };
|
|
4065
|
+
}
|
|
4066
|
+
async doctor(name) {
|
|
4067
|
+
const report = await this.createDoctorFacade().inspectOne(name);
|
|
4068
|
+
if (!report) {
|
|
4069
|
+
throw new Error(`Unknown MCP server: ${name}`);
|
|
4070
|
+
}
|
|
4071
|
+
return report;
|
|
4072
|
+
}
|
|
4073
|
+
createMutationService() {
|
|
4074
|
+
return new McpMutationService2({
|
|
4075
|
+
getConfig: () => loadConfig9(),
|
|
4076
|
+
saveConfig: (config2) => saveConfig6(config2)
|
|
4077
|
+
});
|
|
4078
|
+
}
|
|
4079
|
+
createDoctorFacade() {
|
|
4080
|
+
return new McpDoctorFacade2({
|
|
4081
|
+
getConfig: () => loadConfig9()
|
|
4082
|
+
});
|
|
4083
|
+
}
|
|
4084
|
+
};
|
|
4085
|
+
|
|
4086
|
+
// src/cli/commands/service-marketplace-installer.ts
|
|
4087
|
+
var ServiceMarketplaceInstaller = class {
|
|
4088
|
+
constructor(deps) {
|
|
4089
|
+
this.deps = deps;
|
|
4090
|
+
}
|
|
4091
|
+
createInstaller() {
|
|
4092
|
+
return {
|
|
4093
|
+
installPlugin: (spec) => this.installPlugin(spec),
|
|
4094
|
+
installSkill: (params) => this.installSkill(params),
|
|
4095
|
+
installMcp: (params) => this.installMcp(params),
|
|
4096
|
+
enablePlugin: (id) => this.enablePlugin(id),
|
|
4097
|
+
disablePlugin: (id) => this.disablePlugin(id),
|
|
4098
|
+
uninstallPlugin: (id) => this.uninstallPlugin(id),
|
|
4099
|
+
uninstallSkill: (slug) => this.uninstallSkill(slug),
|
|
4100
|
+
enableMcp: (name) => this.enableMcp(name),
|
|
4101
|
+
disableMcp: (name) => this.disableMcp(name),
|
|
4102
|
+
removeMcp: (name) => this.removeMcp(name),
|
|
4103
|
+
doctorMcp: (name) => this.doctorMcp(name)
|
|
4104
|
+
};
|
|
4105
|
+
}
|
|
4106
|
+
async installPlugin(spec) {
|
|
4107
|
+
const result = await installPluginMutation(spec);
|
|
4108
|
+
await this.deps.applyLiveConfigReload?.();
|
|
4109
|
+
return { message: result.message };
|
|
4110
|
+
}
|
|
4111
|
+
async installSkill(params) {
|
|
4112
|
+
if (params.kind === "builtin") {
|
|
4113
|
+
const result = this.deps.installBuiltinSkill(params.slug, params.force);
|
|
4114
|
+
if (!result) {
|
|
4115
|
+
throw new Error(`Builtin skill not found: ${params.slug}`);
|
|
4116
|
+
}
|
|
4117
|
+
return result;
|
|
4118
|
+
}
|
|
4119
|
+
if (params.kind && params.kind !== "marketplace") {
|
|
4120
|
+
throw new Error(`Unsupported marketplace skill kind: ${params.kind}`);
|
|
4121
|
+
}
|
|
4122
|
+
const workspace = getWorkspacePath5(loadConfig10().agents.defaults.workspace);
|
|
4123
|
+
const args = buildMarketplaceSkillInstallArgs({
|
|
4124
|
+
slug: params.slug,
|
|
4125
|
+
workspace,
|
|
4126
|
+
force: params.force
|
|
4127
|
+
});
|
|
4128
|
+
try {
|
|
4129
|
+
const output = await this.deps.runCliSubcommand(args);
|
|
4130
|
+
const summary = pickUserFacingCommandSummary(output, `Installed skill: ${params.slug}`);
|
|
4131
|
+
return { message: summary };
|
|
4132
|
+
} catch (error) {
|
|
4133
|
+
const fallback = this.deps.installBuiltinSkill(params.slug, params.force);
|
|
4134
|
+
if (!fallback) {
|
|
4135
|
+
throw error;
|
|
4136
|
+
}
|
|
4137
|
+
return fallback;
|
|
4138
|
+
}
|
|
4139
|
+
}
|
|
4140
|
+
async installMcp(params) {
|
|
4141
|
+
return await this.createMcpMarketplaceOps().install(params);
|
|
4142
|
+
}
|
|
4143
|
+
async enablePlugin(id) {
|
|
4144
|
+
const result = await enablePluginMutation(id);
|
|
4145
|
+
await this.deps.applyLiveConfigReload?.();
|
|
4146
|
+
return { message: result.message };
|
|
4147
|
+
}
|
|
4148
|
+
async disablePlugin(id) {
|
|
4149
|
+
const result = await disablePluginMutation(id);
|
|
4150
|
+
await this.deps.applyLiveConfigReload?.();
|
|
4151
|
+
return { message: result.message };
|
|
4152
|
+
}
|
|
4153
|
+
async uninstallPlugin(id) {
|
|
4154
|
+
await disablePluginMutation(id);
|
|
4155
|
+
await this.deps.applyLiveConfigReload?.();
|
|
4156
|
+
const result = await uninstallPluginMutation(id, { force: true });
|
|
4157
|
+
await this.deps.applyLiveConfigReload?.();
|
|
4158
|
+
return { message: result.message };
|
|
4159
|
+
}
|
|
4160
|
+
async uninstallSkill(slug) {
|
|
4161
|
+
const workspace = getWorkspacePath5(loadConfig10().agents.defaults.workspace);
|
|
4162
|
+
const targetDir = join5(workspace, "skills", slug);
|
|
4163
|
+
if (!existsSync9(targetDir)) {
|
|
4164
|
+
throw new Error(`Skill not installed in workspace: ${slug}`);
|
|
4165
|
+
}
|
|
4166
|
+
rmSync4(targetDir, { recursive: true, force: true });
|
|
4167
|
+
return {
|
|
4168
|
+
message: `Uninstalled skill: ${slug}`
|
|
4169
|
+
};
|
|
4170
|
+
}
|
|
4171
|
+
async enableMcp(name) {
|
|
4172
|
+
return await this.createMcpMarketplaceOps().enable(name);
|
|
4173
|
+
}
|
|
4174
|
+
async disableMcp(name) {
|
|
4175
|
+
return await this.createMcpMarketplaceOps().disable(name);
|
|
4176
|
+
}
|
|
4177
|
+
async removeMcp(name) {
|
|
4178
|
+
return await this.createMcpMarketplaceOps().remove(name);
|
|
4179
|
+
}
|
|
4180
|
+
async doctorMcp(name) {
|
|
4181
|
+
return await this.createMcpMarketplaceOps().doctor(name);
|
|
4182
|
+
}
|
|
4183
|
+
createMcpMarketplaceOps() {
|
|
4184
|
+
return new ServiceMcpMarketplaceOps({
|
|
4185
|
+
applyLiveConfigReload: this.deps.applyLiveConfigReload
|
|
4186
|
+
});
|
|
4187
|
+
}
|
|
4188
|
+
};
|
|
4189
|
+
|
|
3677
4190
|
// src/cli/commands/service-plugin-reload.ts
|
|
3678
|
-
import { getWorkspacePath as
|
|
4191
|
+
import { getWorkspacePath as getWorkspacePath6 } from "@nextclaw/core";
|
|
3679
4192
|
import {
|
|
3680
4193
|
getPluginChannelBindings as getPluginChannelBindings2,
|
|
3681
4194
|
startPluginChannelGateways,
|
|
@@ -3741,7 +4254,7 @@ function shouldRestartChannelsForPluginReload(params) {
|
|
|
3741
4254
|
|
|
3742
4255
|
// src/cli/commands/service-plugin-reload.ts
|
|
3743
4256
|
async function reloadServicePlugins(params) {
|
|
3744
|
-
const nextWorkspace =
|
|
4257
|
+
const nextWorkspace = getWorkspacePath6(params.nextConfig.agents.defaults.workspace);
|
|
3745
4258
|
const nextPluginRegistry = loadPluginRegistry(params.nextConfig, nextWorkspace);
|
|
3746
4259
|
const nextExtensionRegistry = toExtensionRegistry(nextPluginRegistry);
|
|
3747
4260
|
const nextPluginChannelBindings = getPluginChannelBindings2(nextPluginRegistry);
|
|
@@ -3779,7 +4292,7 @@ import {
|
|
|
3779
4292
|
createAssistantStreamDeltaControlMessage,
|
|
3780
4293
|
createAssistantStreamResetControlMessage,
|
|
3781
4294
|
AgentRouteResolver,
|
|
3782
|
-
getWorkspacePath as
|
|
4295
|
+
getWorkspacePath as getWorkspacePath7,
|
|
3783
4296
|
parseAgentScopedSessionKey
|
|
3784
4297
|
} from "@nextclaw/core";
|
|
3785
4298
|
function normalizeAgentId(value) {
|
|
@@ -3824,7 +4337,7 @@ function resolveAgentProfiles(config2) {
|
|
|
3824
4337
|
}
|
|
3825
4338
|
return Array.from(unique.values()).map((entry) => ({
|
|
3826
4339
|
id: entry.id,
|
|
3827
|
-
workspace:
|
|
4340
|
+
workspace: getWorkspacePath7(entry.workspace ?? defaults.workspace),
|
|
3828
4341
|
model: entry.model ?? defaults.model,
|
|
3829
4342
|
engine: normalizeEngineKind(entry.engine ?? defaults.engine),
|
|
3830
4343
|
engineConfig: entry.engineConfig ?? toRecord(defaults.engineConfig),
|
|
@@ -4089,7 +4602,7 @@ var GatewayAgentRuntimePool = class {
|
|
|
4089
4602
|
const normalizedAgentId = normalizeAgentId(agentId);
|
|
4090
4603
|
return this.resolvedProfiles.find((profile) => profile.id === normalizedAgentId) ?? this.resolvedProfiles.find((profile) => profile.id === this.defaultAgentId) ?? this.resolvedProfiles[0] ?? {
|
|
4091
4604
|
id: this.defaultAgentId,
|
|
4092
|
-
workspace:
|
|
4605
|
+
workspace: getWorkspacePath7(this.options.config.agents.defaults.workspace),
|
|
4093
4606
|
model: this.options.config.agents.defaults.model,
|
|
4094
4607
|
maxIterations: this.options.config.agents.defaults.maxToolIterations,
|
|
4095
4608
|
contextTokens: this.options.config.agents.defaults.contextTokens,
|
|
@@ -4297,7 +4810,7 @@ import { createAgentClientFromServer, DefaultNcpAgentBackend } from "@nextclaw/n
|
|
|
4297
4810
|
import {
|
|
4298
4811
|
ContextBuilder,
|
|
4299
4812
|
InputBudgetPruner,
|
|
4300
|
-
getWorkspacePath as
|
|
4813
|
+
getWorkspacePath as getWorkspacePath8,
|
|
4301
4814
|
parseThinkingLevel,
|
|
4302
4815
|
resolveThinkingLevel
|
|
4303
4816
|
} from "@nextclaw/core";
|
|
@@ -4795,7 +5308,7 @@ function resolvePrimaryAgentProfile(config2) {
|
|
|
4795
5308
|
const profile = config2.agents.list.find((entry) => entry.id.trim() === configuredDefaultAgentId);
|
|
4796
5309
|
return {
|
|
4797
5310
|
agentId: configuredDefaultAgentId,
|
|
4798
|
-
workspace:
|
|
5311
|
+
workspace: getWorkspacePath8(profile?.workspace ?? config2.agents.defaults.workspace),
|
|
4799
5312
|
model: profile?.model ?? config2.agents.defaults.model,
|
|
4800
5313
|
maxIterations: profile?.maxToolIterations ?? config2.agents.defaults.maxToolIterations,
|
|
4801
5314
|
contextTokens: profile?.contextTokens ?? config2.agents.defaults.contextTokens,
|
|
@@ -5427,22 +5940,33 @@ var UiNcpRuntimeRegistry = class {
|
|
|
5427
5940
|
sessionMetadata: nextSessionMetadata
|
|
5428
5941
|
});
|
|
5429
5942
|
}
|
|
5430
|
-
listSessionTypes() {
|
|
5431
|
-
const options =
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5943
|
+
async listSessionTypes() {
|
|
5944
|
+
const options = await Promise.all(
|
|
5945
|
+
[...this.registrations.values()].map(async (registration) => {
|
|
5946
|
+
const descriptor = await registration.describeSessionType?.();
|
|
5947
|
+
return {
|
|
5948
|
+
value: registration.kind,
|
|
5949
|
+
label: registration.label,
|
|
5950
|
+
ready: descriptor?.ready ?? true,
|
|
5951
|
+
reason: descriptor?.reason ?? null,
|
|
5952
|
+
reasonMessage: descriptor?.reasonMessage ?? null,
|
|
5953
|
+
recommendedModel: descriptor?.recommendedModel ?? null,
|
|
5954
|
+
cta: descriptor?.cta ?? null,
|
|
5955
|
+
...descriptor?.supportedModels ? { supportedModels: descriptor.supportedModels } : {}
|
|
5956
|
+
};
|
|
5957
|
+
})
|
|
5958
|
+
);
|
|
5443
5959
|
return {
|
|
5444
5960
|
defaultType: this.defaultKind,
|
|
5445
|
-
options
|
|
5961
|
+
options: options.sort((left, right) => {
|
|
5962
|
+
if (left.value === this.defaultKind) {
|
|
5963
|
+
return -1;
|
|
5964
|
+
}
|
|
5965
|
+
if (right.value === this.defaultKind) {
|
|
5966
|
+
return 1;
|
|
5967
|
+
}
|
|
5968
|
+
return left.value.localeCompare(right.value);
|
|
5969
|
+
})
|
|
5446
5970
|
};
|
|
5447
5971
|
}
|
|
5448
5972
|
};
|
|
@@ -5548,7 +6072,8 @@ async function createUiNcpAgent(params) {
|
|
|
5548
6072
|
scope.add(runtimeRegistry.register({
|
|
5549
6073
|
kind: registration.kind,
|
|
5550
6074
|
label: registration.label,
|
|
5551
|
-
createRuntime: registration.createRuntime
|
|
6075
|
+
createRuntime: registration.createRuntime,
|
|
6076
|
+
describeSessionType: registration.describeSessionType
|
|
5552
6077
|
}));
|
|
5553
6078
|
}
|
|
5554
6079
|
};
|
|
@@ -5595,60 +6120,15 @@ async function createUiNcpAgent(params) {
|
|
|
5595
6120
|
};
|
|
5596
6121
|
}
|
|
5597
6122
|
|
|
5598
|
-
// src/cli/commands/service-marketplace-helpers.ts
|
|
5599
|
-
var containsAbsoluteFsPath = (line) => {
|
|
5600
|
-
const normalized = line.trim();
|
|
5601
|
-
if (!normalized) {
|
|
5602
|
-
return false;
|
|
5603
|
-
}
|
|
5604
|
-
const lowered = normalized.toLowerCase();
|
|
5605
|
-
if (lowered.includes("http://") || lowered.includes("https://")) {
|
|
5606
|
-
return false;
|
|
5607
|
-
}
|
|
5608
|
-
if (/^[A-Za-z]:\\/.test(normalized)) {
|
|
5609
|
-
return true;
|
|
5610
|
-
}
|
|
5611
|
-
return /(?:^|\s)(?:~\/|\/[^\s]+)/.test(normalized);
|
|
5612
|
-
};
|
|
5613
|
-
var pickUserFacingCommandSummary = (output, fallback) => {
|
|
5614
|
-
const lines = output.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
5615
|
-
if (lines.length === 0) {
|
|
5616
|
-
return fallback;
|
|
5617
|
-
}
|
|
5618
|
-
const visibleLines = lines.filter((line) => {
|
|
5619
|
-
if (/^(path|install path|source path|destination|location)\s*:/i.test(line)) {
|
|
5620
|
-
return false;
|
|
5621
|
-
}
|
|
5622
|
-
if (containsAbsoluteFsPath(line)) {
|
|
5623
|
-
return false;
|
|
5624
|
-
}
|
|
5625
|
-
return true;
|
|
5626
|
-
});
|
|
5627
|
-
if (visibleLines.length === 0) {
|
|
5628
|
-
return fallback;
|
|
5629
|
-
}
|
|
5630
|
-
const preferred = [...visibleLines].reverse().find(
|
|
5631
|
-
(line) => /\b(installed|enabled|disabled|uninstalled|published|updated|already installed|removed)\b/i.test(line)
|
|
5632
|
-
);
|
|
5633
|
-
return preferred ?? visibleLines[visibleLines.length - 1] ?? fallback;
|
|
5634
|
-
};
|
|
5635
|
-
var buildMarketplaceSkillInstallArgs = (params) => {
|
|
5636
|
-
const args = ["skills", "install", params.slug, "--workdir", params.workspace];
|
|
5637
|
-
if (params.force) {
|
|
5638
|
-
args.push("--force");
|
|
5639
|
-
}
|
|
5640
|
-
return args;
|
|
5641
|
-
};
|
|
5642
|
-
|
|
5643
6123
|
// src/cli/commands/ui-chat-run-coordinator.ts
|
|
5644
|
-
import { existsSync as
|
|
5645
|
-
import { join as
|
|
6124
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync5, readdirSync as readdirSync2, readFileSync as readFileSync9, writeFileSync as writeFileSync5 } from "fs";
|
|
6125
|
+
import { join as join6 } from "path";
|
|
5646
6126
|
import {
|
|
5647
|
-
getDataDir as
|
|
6127
|
+
getDataDir as getDataDir6,
|
|
5648
6128
|
parseAgentScopedSessionKey as parseAgentScopedSessionKey2,
|
|
5649
6129
|
safeFilename
|
|
5650
6130
|
} from "@nextclaw/core";
|
|
5651
|
-
var RUNS_DIR =
|
|
6131
|
+
var RUNS_DIR = join6(getDataDir6(), "runs");
|
|
5652
6132
|
var NON_TERMINAL_STATES = /* @__PURE__ */ new Set(["queued", "running"]);
|
|
5653
6133
|
var DEFAULT_SESSION_TYPE = "native";
|
|
5654
6134
|
var SESSION_TYPE_METADATA_KEY = "session_type";
|
|
@@ -5707,7 +6187,7 @@ function hasToolSessionEvent(run) {
|
|
|
5707
6187
|
var UiChatRunCoordinator = class {
|
|
5708
6188
|
constructor(options) {
|
|
5709
6189
|
this.options = options;
|
|
5710
|
-
|
|
6190
|
+
mkdirSync5(RUNS_DIR, { recursive: true });
|
|
5711
6191
|
this.loadPersistedRuns();
|
|
5712
6192
|
}
|
|
5713
6193
|
runs = /* @__PURE__ */ new Map();
|
|
@@ -6174,7 +6654,7 @@ var UiChatRunCoordinator = class {
|
|
|
6174
6654
|
};
|
|
6175
6655
|
}
|
|
6176
6656
|
getRunPath(runId) {
|
|
6177
|
-
return
|
|
6657
|
+
return join6(RUNS_DIR, `${safeFilename(runId)}.json`);
|
|
6178
6658
|
}
|
|
6179
6659
|
persistRun(run) {
|
|
6180
6660
|
const persisted = {
|
|
@@ -6192,20 +6672,20 @@ var UiChatRunCoordinator = class {
|
|
|
6192
6672
|
...typeof run.reply === "string" ? { reply: run.reply } : {},
|
|
6193
6673
|
events: run.events
|
|
6194
6674
|
};
|
|
6195
|
-
|
|
6675
|
+
writeFileSync5(this.getRunPath(run.runId), `${JSON.stringify(persisted, null, 2)}
|
|
6196
6676
|
`);
|
|
6197
6677
|
}
|
|
6198
6678
|
loadPersistedRuns() {
|
|
6199
|
-
if (!
|
|
6679
|
+
if (!existsSync10(RUNS_DIR)) {
|
|
6200
6680
|
return;
|
|
6201
6681
|
}
|
|
6202
6682
|
for (const entry of readdirSync2(RUNS_DIR, { withFileTypes: true })) {
|
|
6203
6683
|
if (!entry.isFile() || !entry.name.endsWith(".json")) {
|
|
6204
6684
|
continue;
|
|
6205
6685
|
}
|
|
6206
|
-
const path2 =
|
|
6686
|
+
const path2 = join6(RUNS_DIR, entry.name);
|
|
6207
6687
|
try {
|
|
6208
|
-
const parsed = JSON.parse(
|
|
6688
|
+
const parsed = JSON.parse(readFileSync9(path2, "utf-8"));
|
|
6209
6689
|
const runId = readOptionalString(parsed.runId);
|
|
6210
6690
|
const sessionKey = readOptionalString(parsed.sessionKey);
|
|
6211
6691
|
if (!runId || !sessionKey) {
|
|
@@ -6264,18 +6744,18 @@ var {
|
|
|
6264
6744
|
ChannelManager: ChannelManager2,
|
|
6265
6745
|
CronService: CronService2,
|
|
6266
6746
|
getApiBase,
|
|
6267
|
-
getConfigPath:
|
|
6268
|
-
getDataDir:
|
|
6747
|
+
getConfigPath: getConfigPath4,
|
|
6748
|
+
getDataDir: getDataDir7,
|
|
6269
6749
|
getProvider,
|
|
6270
6750
|
getProviderName,
|
|
6271
|
-
getWorkspacePath:
|
|
6751
|
+
getWorkspacePath: getWorkspacePath9,
|
|
6272
6752
|
HeartbeatService,
|
|
6273
6753
|
LiteLLMProvider,
|
|
6274
|
-
loadConfig:
|
|
6754
|
+
loadConfig: loadConfig11,
|
|
6275
6755
|
MessageBus,
|
|
6276
6756
|
ProviderManager,
|
|
6277
6757
|
resolveConfigSecrets: resolveConfigSecrets2,
|
|
6278
|
-
saveConfig:
|
|
6758
|
+
saveConfig: saveConfig7,
|
|
6279
6759
|
SessionManager,
|
|
6280
6760
|
parseAgentScopedSessionKey: parseAgentScopedSessionKey3
|
|
6281
6761
|
} = NextclawCore;
|
|
@@ -6295,9 +6775,9 @@ var ServiceCommands = class {
|
|
|
6295
6775
|
async startGateway(options = {}) {
|
|
6296
6776
|
this.applyLiveConfigReload = null;
|
|
6297
6777
|
this.liveUiNcpAgent = null;
|
|
6298
|
-
const runtimeConfigPath =
|
|
6299
|
-
const config2 = resolveConfigSecrets2(
|
|
6300
|
-
const workspace =
|
|
6778
|
+
const runtimeConfigPath = getConfigPath4();
|
|
6779
|
+
const config2 = resolveConfigSecrets2(loadConfig11(), { configPath: runtimeConfigPath });
|
|
6780
|
+
const workspace = getWorkspacePath9(config2.agents.defaults.workspace);
|
|
6301
6781
|
let pluginRegistry = loadPluginRegistry(config2, workspace);
|
|
6302
6782
|
let extensionRegistry = toExtensionRegistry(pluginRegistry);
|
|
6303
6783
|
logPluginDiagnostics(pluginRegistry);
|
|
@@ -6326,7 +6806,7 @@ var ServiceCommands = class {
|
|
|
6326
6806
|
}
|
|
6327
6807
|
}
|
|
6328
6808
|
};
|
|
6329
|
-
const cronStorePath =
|
|
6809
|
+
const cronStorePath = join7(getDataDir7(), "cron", "jobs.json");
|
|
6330
6810
|
const cron2 = new CronService2(cronStorePath);
|
|
6331
6811
|
const uiConfig = resolveUiConfig(config2, options.uiOverrides);
|
|
6332
6812
|
const uiStaticDir = options.uiStaticDir === void 0 ? resolveUiStaticDir() : options.uiStaticDir;
|
|
@@ -6341,7 +6821,7 @@ var ServiceCommands = class {
|
|
|
6341
6821
|
sessionManager,
|
|
6342
6822
|
providerManager,
|
|
6343
6823
|
makeProvider: (nextConfig) => this.makeProvider(nextConfig, { allowMissing: true }) ?? this.makeMissingProvider(nextConfig),
|
|
6344
|
-
loadConfig: () => resolveConfigSecrets2(
|
|
6824
|
+
loadConfig: () => resolveConfigSecrets2(loadConfig11(), { configPath: runtimeConfigPath }),
|
|
6345
6825
|
getExtensionChannels: () => extensionRegistry.channels,
|
|
6346
6826
|
onRestartRequired: (paths) => {
|
|
6347
6827
|
void this.deps.requestRestart({
|
|
@@ -6352,14 +6832,14 @@ var ServiceCommands = class {
|
|
|
6352
6832
|
}
|
|
6353
6833
|
});
|
|
6354
6834
|
this.applyLiveConfigReload = async () => {
|
|
6355
|
-
await reloader.applyReloadPlan(resolveConfigSecrets2(
|
|
6835
|
+
await reloader.applyReloadPlan(resolveConfigSecrets2(loadConfig11(), { configPath: runtimeConfigPath }));
|
|
6356
6836
|
};
|
|
6357
6837
|
const gatewayController = new GatewayControllerImpl({
|
|
6358
6838
|
reloader,
|
|
6359
6839
|
cron: cron2,
|
|
6360
6840
|
sessionManager,
|
|
6361
|
-
getConfigPath:
|
|
6362
|
-
saveConfig:
|
|
6841
|
+
getConfigPath: getConfigPath4,
|
|
6842
|
+
saveConfig: saveConfig7,
|
|
6363
6843
|
requestRestart: async (options2) => {
|
|
6364
6844
|
await this.deps.requestRestart({
|
|
6365
6845
|
reason: options2?.reason ?? "gateway tool restart",
|
|
@@ -6385,7 +6865,7 @@ var ServiceCommands = class {
|
|
|
6385
6865
|
resolveMessageToolHints: ({ channel, accountId }) => resolvePluginChannelMessageToolHints({
|
|
6386
6866
|
registry: pluginRegistry,
|
|
6387
6867
|
channel,
|
|
6388
|
-
cfg: resolveConfigSecrets2(
|
|
6868
|
+
cfg: resolveConfigSecrets2(loadConfig11(), { configPath: runtimeConfigPath }),
|
|
6389
6869
|
accountId
|
|
6390
6870
|
})
|
|
6391
6871
|
});
|
|
@@ -6418,14 +6898,14 @@ var ServiceCommands = class {
|
|
|
6418
6898
|
});
|
|
6419
6899
|
let pluginChannelBindings = getPluginChannelBindings3(pluginRegistry);
|
|
6420
6900
|
setPluginRuntimeBridge({
|
|
6421
|
-
loadConfig: () => toPluginConfigView(resolveConfigSecrets2(
|
|
6901
|
+
loadConfig: () => toPluginConfigView(resolveConfigSecrets2(loadConfig11(), { configPath: runtimeConfigPath }), pluginChannelBindings),
|
|
6422
6902
|
writeConfigFile: async (nextConfigView) => {
|
|
6423
6903
|
if (!nextConfigView || typeof nextConfigView !== "object" || Array.isArray(nextConfigView)) {
|
|
6424
6904
|
throw new Error("plugin runtime writeConfigFile expects an object config");
|
|
6425
6905
|
}
|
|
6426
|
-
const current =
|
|
6906
|
+
const current = loadConfig11();
|
|
6427
6907
|
const next = mergePluginConfigView(current, nextConfigView, pluginChannelBindings);
|
|
6428
|
-
|
|
6908
|
+
saveConfig7(next);
|
|
6429
6909
|
},
|
|
6430
6910
|
dispatchReplyWithBufferedBlockDispatcher: async ({ ctx, dispatcherOptions }) => {
|
|
6431
6911
|
const bodyForAgent = typeof ctx.BodyForAgent === "string" ? ctx.BodyForAgent : "";
|
|
@@ -6499,12 +6979,12 @@ var ServiceCommands = class {
|
|
|
6499
6979
|
providerManager,
|
|
6500
6980
|
bus,
|
|
6501
6981
|
gatewayController,
|
|
6502
|
-
() => resolveConfigSecrets2(
|
|
6982
|
+
() => resolveConfigSecrets2(loadConfig11(), { configPath: runtimeConfigPath }),
|
|
6503
6983
|
() => extensionRegistry,
|
|
6504
6984
|
({ channel, accountId }) => resolvePluginChannelMessageToolHints({
|
|
6505
6985
|
registry: pluginRegistry,
|
|
6506
6986
|
channel,
|
|
6507
|
-
cfg: resolveConfigSecrets2(
|
|
6987
|
+
cfg: resolveConfigSecrets2(loadConfig11(), { configPath: runtimeConfigPath }),
|
|
6508
6988
|
accountId
|
|
6509
6989
|
})
|
|
6510
6990
|
);
|
|
@@ -6541,7 +7021,7 @@ var ServiceCommands = class {
|
|
|
6541
7021
|
return trimmed || void 0;
|
|
6542
7022
|
}
|
|
6543
7023
|
watchConfigFile(reloader) {
|
|
6544
|
-
const configPath = resolve10(
|
|
7024
|
+
const configPath = resolve10(getConfigPath4());
|
|
6545
7025
|
const watcher = chokidar.watch(configPath, {
|
|
6546
7026
|
ignoreInitial: true,
|
|
6547
7027
|
awaitWriteFinish: { stabilityThreshold: 200, pollInterval: 50 }
|
|
@@ -6662,7 +7142,7 @@ var ServiceCommands = class {
|
|
|
6662
7142
|
});
|
|
6663
7143
|
}
|
|
6664
7144
|
async runForeground(options) {
|
|
6665
|
-
const config2 =
|
|
7145
|
+
const config2 = loadConfig11();
|
|
6666
7146
|
const uiConfig = resolveUiConfig(config2, options.uiOverrides);
|
|
6667
7147
|
const uiUrl = resolveUiApiBase(uiConfig.host, uiConfig.port);
|
|
6668
7148
|
if (options.open) {
|
|
@@ -6675,7 +7155,7 @@ var ServiceCommands = class {
|
|
|
6675
7155
|
});
|
|
6676
7156
|
}
|
|
6677
7157
|
async startService(options) {
|
|
6678
|
-
const config2 =
|
|
7158
|
+
const config2 = loadConfig11();
|
|
6679
7159
|
const uiConfig = resolveUiConfig(config2, options.uiOverrides);
|
|
6680
7160
|
const uiUrl = resolveUiApiBase(uiConfig.host, uiConfig.port);
|
|
6681
7161
|
const apiUrl = `${uiUrl}/api`;
|
|
@@ -6736,7 +7216,7 @@ var ServiceCommands = class {
|
|
|
6736
7216
|
}
|
|
6737
7217
|
const logPath = resolveServiceLogPath();
|
|
6738
7218
|
const logDir = resolve10(logPath, "..");
|
|
6739
|
-
|
|
7219
|
+
mkdirSync6(logDir, { recursive: true });
|
|
6740
7220
|
const logFd = openSync(logPath, "a");
|
|
6741
7221
|
const readinessTimeoutMs = this.resolveStartupTimeoutMs(options.startupTimeoutMs);
|
|
6742
7222
|
const quickPhaseTimeoutMs = Math.min(8e3, readinessTimeoutMs);
|
|
@@ -7089,7 +7569,7 @@ var ServiceCommands = class {
|
|
|
7089
7569
|
return null;
|
|
7090
7570
|
}
|
|
7091
7571
|
console.error("Error: No API key configured.");
|
|
7092
|
-
console.error(`Set one in ${
|
|
7572
|
+
console.error(`Set one in ${getConfigPath4()} under providers section`);
|
|
7093
7573
|
process.exit(1);
|
|
7094
7574
|
}
|
|
7095
7575
|
return new LiteLLMProvider({
|
|
@@ -7208,23 +7688,21 @@ var ServiceCommands = class {
|
|
|
7208
7688
|
})
|
|
7209
7689
|
});
|
|
7210
7690
|
this.liveUiNcpAgent = ncpAgent;
|
|
7691
|
+
const marketplaceInstaller = new ServiceMarketplaceInstaller({
|
|
7692
|
+
applyLiveConfigReload: this.applyLiveConfigReload ?? void 0,
|
|
7693
|
+
runCliSubcommand: (args) => this.runCliSubcommand(args),
|
|
7694
|
+
installBuiltinSkill: (slug, force) => this.installBuiltinMarketplaceSkill(slug, force)
|
|
7695
|
+
}).createInstaller();
|
|
7211
7696
|
const uiServer = startUiServer({
|
|
7212
7697
|
host: uiConfig.host,
|
|
7213
7698
|
port: uiConfig.port,
|
|
7214
|
-
configPath:
|
|
7699
|
+
configPath: getConfigPath4(),
|
|
7215
7700
|
productVersion: getPackageVersion(),
|
|
7216
7701
|
staticDir: uiStaticDir ?? void 0,
|
|
7217
7702
|
cronService,
|
|
7218
7703
|
marketplace: {
|
|
7219
7704
|
apiBaseUrl: process.env.NEXTCLAW_MARKETPLACE_API_BASE,
|
|
7220
|
-
installer:
|
|
7221
|
-
installPlugin: (spec) => this.installMarketplacePlugin(spec),
|
|
7222
|
-
installSkill: (params) => this.installMarketplaceSkill(params),
|
|
7223
|
-
enablePlugin: (id) => this.enableMarketplacePlugin(id),
|
|
7224
|
-
disablePlugin: (id) => this.disableMarketplacePlugin(id),
|
|
7225
|
-
uninstallPlugin: (id) => this.uninstallMarketplacePlugin(id),
|
|
7226
|
-
uninstallSkill: (slug) => this.uninstallMarketplaceSkill(slug)
|
|
7227
|
-
}
|
|
7705
|
+
installer: marketplaceInstaller
|
|
7228
7706
|
},
|
|
7229
7707
|
ncpAgent,
|
|
7230
7708
|
chatRuntime: {
|
|
@@ -7305,73 +7783,11 @@ var ServiceCommands = class {
|
|
|
7305
7783
|
openBrowser(uiUrl);
|
|
7306
7784
|
}
|
|
7307
7785
|
}
|
|
7308
|
-
async installMarketplacePlugin(spec) {
|
|
7309
|
-
const result = await installPluginMutation(spec);
|
|
7310
|
-
await this.applyLiveConfigReload?.();
|
|
7311
|
-
return { message: result.message };
|
|
7312
|
-
}
|
|
7313
|
-
async installMarketplaceSkill(params) {
|
|
7314
|
-
if (params.kind === "builtin") {
|
|
7315
|
-
const result = this.installBuiltinMarketplaceSkill(params.slug, params.force);
|
|
7316
|
-
if (!result) {
|
|
7317
|
-
throw new Error(`Builtin skill not found: ${params.slug}`);
|
|
7318
|
-
}
|
|
7319
|
-
return result;
|
|
7320
|
-
}
|
|
7321
|
-
if (params.kind && params.kind !== "marketplace") {
|
|
7322
|
-
throw new Error(`Unsupported marketplace skill kind: ${params.kind}`);
|
|
7323
|
-
}
|
|
7324
|
-
const workspace = getWorkspacePath8(loadConfig8().agents.defaults.workspace);
|
|
7325
|
-
const args = buildMarketplaceSkillInstallArgs({
|
|
7326
|
-
slug: params.slug,
|
|
7327
|
-
workspace,
|
|
7328
|
-
force: params.force
|
|
7329
|
-
});
|
|
7330
|
-
try {
|
|
7331
|
-
const output = await this.runCliSubcommand(args);
|
|
7332
|
-
const summary = pickUserFacingCommandSummary(output, `Installed skill: ${params.slug}`);
|
|
7333
|
-
return { message: summary };
|
|
7334
|
-
} catch (error) {
|
|
7335
|
-
const fallback = this.installBuiltinMarketplaceSkill(params.slug, params.force);
|
|
7336
|
-
if (!fallback) {
|
|
7337
|
-
throw error;
|
|
7338
|
-
}
|
|
7339
|
-
return fallback;
|
|
7340
|
-
}
|
|
7341
|
-
}
|
|
7342
|
-
async enableMarketplacePlugin(id) {
|
|
7343
|
-
const result = await enablePluginMutation(id);
|
|
7344
|
-
await this.applyLiveConfigReload?.();
|
|
7345
|
-
return { message: result.message };
|
|
7346
|
-
}
|
|
7347
|
-
async disableMarketplacePlugin(id) {
|
|
7348
|
-
const result = await disablePluginMutation(id);
|
|
7349
|
-
await this.applyLiveConfigReload?.();
|
|
7350
|
-
return { message: result.message };
|
|
7351
|
-
}
|
|
7352
|
-
async uninstallMarketplacePlugin(id) {
|
|
7353
|
-
await disablePluginMutation(id);
|
|
7354
|
-
await this.applyLiveConfigReload?.();
|
|
7355
|
-
const result = await uninstallPluginMutation(id, { force: true });
|
|
7356
|
-
await this.applyLiveConfigReload?.();
|
|
7357
|
-
return { message: result.message };
|
|
7358
|
-
}
|
|
7359
|
-
async uninstallMarketplaceSkill(slug) {
|
|
7360
|
-
const workspace = getWorkspacePath8(loadConfig8().agents.defaults.workspace);
|
|
7361
|
-
const targetDir = join5(workspace, "skills", slug);
|
|
7362
|
-
if (!existsSync9(targetDir)) {
|
|
7363
|
-
throw new Error(`Skill not installed in workspace: ${slug}`);
|
|
7364
|
-
}
|
|
7365
|
-
rmSync4(targetDir, { recursive: true, force: true });
|
|
7366
|
-
return {
|
|
7367
|
-
message: `Uninstalled skill: ${slug}`
|
|
7368
|
-
};
|
|
7369
|
-
}
|
|
7370
7786
|
installBuiltinMarketplaceSkill(slug, force) {
|
|
7371
|
-
const workspace =
|
|
7372
|
-
const destination =
|
|
7373
|
-
const destinationSkillFile =
|
|
7374
|
-
if (
|
|
7787
|
+
const workspace = getWorkspacePath9(loadConfig11().agents.defaults.workspace);
|
|
7788
|
+
const destination = join7(workspace, "skills", slug);
|
|
7789
|
+
const destinationSkillFile = join7(destination, "SKILL.md");
|
|
7790
|
+
if (existsSync11(destinationSkillFile) && !force) {
|
|
7375
7791
|
return {
|
|
7376
7792
|
message: `${slug} is already installed`
|
|
7377
7793
|
};
|
|
@@ -7379,15 +7795,15 @@ var ServiceCommands = class {
|
|
|
7379
7795
|
const loader = createSkillsLoader(workspace);
|
|
7380
7796
|
const builtin = (loader?.listSkills(false) ?? []).find((skill) => skill.name === slug && skill.source === "builtin");
|
|
7381
7797
|
if (!builtin) {
|
|
7382
|
-
if (
|
|
7798
|
+
if (existsSync11(destinationSkillFile)) {
|
|
7383
7799
|
return {
|
|
7384
7800
|
message: `${slug} is already installed`
|
|
7385
7801
|
};
|
|
7386
7802
|
}
|
|
7387
7803
|
return null;
|
|
7388
7804
|
}
|
|
7389
|
-
|
|
7390
|
-
cpSync2(
|
|
7805
|
+
mkdirSync6(join7(workspace, "skills"), { recursive: true });
|
|
7806
|
+
cpSync2(dirname3(builtin.path), destination, { recursive: true, force: true });
|
|
7391
7807
|
return {
|
|
7392
7808
|
message: `Installed skill: ${slug}`
|
|
7393
7809
|
};
|
|
@@ -7446,11 +7862,11 @@ ${stderr}`.trim();
|
|
|
7446
7862
|
};
|
|
7447
7863
|
|
|
7448
7864
|
// src/cli/workspace.ts
|
|
7449
|
-
import { cpSync as cpSync3, existsSync as
|
|
7865
|
+
import { cpSync as cpSync3, existsSync as existsSync12, mkdirSync as mkdirSync7, readFileSync as readFileSync10, readdirSync as readdirSync3, rmSync as rmSync5, writeFileSync as writeFileSync6 } from "fs";
|
|
7450
7866
|
import { createRequire as createRequire2 } from "module";
|
|
7451
|
-
import { dirname as
|
|
7867
|
+
import { dirname as dirname4, join as join8, resolve as resolve11 } from "path";
|
|
7452
7868
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
7453
|
-
import { APP_NAME as APP_NAME3, getDataDir as
|
|
7869
|
+
import { APP_NAME as APP_NAME3, getDataDir as getDataDir8 } from "@nextclaw/core";
|
|
7454
7870
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
7455
7871
|
var WorkspaceManager = class {
|
|
7456
7872
|
constructor(logo) {
|
|
@@ -7478,30 +7894,30 @@ var WorkspaceManager = class {
|
|
|
7478
7894
|
{ source: "memory/MEMORY.md", target: "memory/MEMORY.md" }
|
|
7479
7895
|
];
|
|
7480
7896
|
for (const entry of templateFiles) {
|
|
7481
|
-
const filePath =
|
|
7482
|
-
if (!force &&
|
|
7897
|
+
const filePath = join8(workspace, entry.target);
|
|
7898
|
+
if (!force && existsSync12(filePath)) {
|
|
7483
7899
|
continue;
|
|
7484
7900
|
}
|
|
7485
|
-
const templatePath =
|
|
7486
|
-
if (!
|
|
7901
|
+
const templatePath = join8(templateDir, entry.source);
|
|
7902
|
+
if (!existsSync12(templatePath)) {
|
|
7487
7903
|
console.warn(`Warning: Template file missing: ${templatePath}`);
|
|
7488
7904
|
continue;
|
|
7489
7905
|
}
|
|
7490
|
-
const raw =
|
|
7906
|
+
const raw = readFileSync10(templatePath, "utf-8");
|
|
7491
7907
|
const content = raw.replace(/\$\{APP_NAME\}/g, APP_NAME3);
|
|
7492
|
-
|
|
7493
|
-
|
|
7908
|
+
mkdirSync7(dirname4(filePath), { recursive: true });
|
|
7909
|
+
writeFileSync6(filePath, content);
|
|
7494
7910
|
created.push(entry.target);
|
|
7495
7911
|
}
|
|
7496
|
-
const memoryDir =
|
|
7497
|
-
if (!
|
|
7498
|
-
|
|
7499
|
-
created.push(
|
|
7912
|
+
const memoryDir = join8(workspace, "memory");
|
|
7913
|
+
if (!existsSync12(memoryDir)) {
|
|
7914
|
+
mkdirSync7(memoryDir, { recursive: true });
|
|
7915
|
+
created.push(join8("memory", ""));
|
|
7500
7916
|
}
|
|
7501
|
-
const skillsDir =
|
|
7502
|
-
if (!
|
|
7503
|
-
|
|
7504
|
-
created.push(
|
|
7917
|
+
const skillsDir = join8(workspace, "skills");
|
|
7918
|
+
if (!existsSync12(skillsDir)) {
|
|
7919
|
+
mkdirSync7(skillsDir, { recursive: true });
|
|
7920
|
+
created.push(join8("skills", ""));
|
|
7505
7921
|
}
|
|
7506
7922
|
const seeded = this.seedBuiltinSkills(skillsDir, { force });
|
|
7507
7923
|
if (seeded > 0) {
|
|
@@ -7520,12 +7936,12 @@ var WorkspaceManager = class {
|
|
|
7520
7936
|
if (!entry.isDirectory()) {
|
|
7521
7937
|
continue;
|
|
7522
7938
|
}
|
|
7523
|
-
const src =
|
|
7524
|
-
if (!
|
|
7939
|
+
const src = join8(sourceDir, entry.name);
|
|
7940
|
+
if (!existsSync12(join8(src, "SKILL.md"))) {
|
|
7525
7941
|
continue;
|
|
7526
7942
|
}
|
|
7527
|
-
const dest =
|
|
7528
|
-
if (!force &&
|
|
7943
|
+
const dest = join8(targetDir, entry.name);
|
|
7944
|
+
if (!force && existsSync12(dest)) {
|
|
7529
7945
|
continue;
|
|
7530
7946
|
}
|
|
7531
7947
|
try {
|
|
@@ -7542,13 +7958,13 @@ var WorkspaceManager = class {
|
|
|
7542
7958
|
try {
|
|
7543
7959
|
const require3 = createRequire2(import.meta.url);
|
|
7544
7960
|
const entry = require3.resolve("@nextclaw/core");
|
|
7545
|
-
const pkgRoot = resolve11(
|
|
7546
|
-
const distSkills =
|
|
7547
|
-
if (
|
|
7961
|
+
const pkgRoot = resolve11(dirname4(entry), "..");
|
|
7962
|
+
const distSkills = join8(pkgRoot, "dist", "skills");
|
|
7963
|
+
if (existsSync12(distSkills)) {
|
|
7548
7964
|
return distSkills;
|
|
7549
7965
|
}
|
|
7550
|
-
const srcSkills =
|
|
7551
|
-
if (
|
|
7966
|
+
const srcSkills = join8(pkgRoot, "src", "agent", "skills");
|
|
7967
|
+
if (existsSync12(srcSkills)) {
|
|
7552
7968
|
return srcSkills;
|
|
7553
7969
|
}
|
|
7554
7970
|
return null;
|
|
@@ -7563,17 +7979,17 @@ var WorkspaceManager = class {
|
|
|
7563
7979
|
}
|
|
7564
7980
|
const cliDir = resolve11(fileURLToPath3(new URL(".", import.meta.url)));
|
|
7565
7981
|
const pkgRoot = resolve11(cliDir, "..", "..");
|
|
7566
|
-
const candidates = [
|
|
7982
|
+
const candidates = [join8(pkgRoot, "templates")];
|
|
7567
7983
|
for (const candidate of candidates) {
|
|
7568
|
-
if (
|
|
7984
|
+
if (existsSync12(candidate)) {
|
|
7569
7985
|
return candidate;
|
|
7570
7986
|
}
|
|
7571
7987
|
}
|
|
7572
7988
|
return null;
|
|
7573
7989
|
}
|
|
7574
7990
|
getBridgeDir() {
|
|
7575
|
-
const userBridge =
|
|
7576
|
-
if (
|
|
7991
|
+
const userBridge = join8(getDataDir8(), "bridge");
|
|
7992
|
+
if (existsSync12(join8(userBridge, "dist", "index.js"))) {
|
|
7577
7993
|
return userBridge;
|
|
7578
7994
|
}
|
|
7579
7995
|
if (!which("npm")) {
|
|
@@ -7582,12 +7998,12 @@ var WorkspaceManager = class {
|
|
|
7582
7998
|
}
|
|
7583
7999
|
const cliDir = resolve11(fileURLToPath3(new URL(".", import.meta.url)));
|
|
7584
8000
|
const pkgRoot = resolve11(cliDir, "..", "..");
|
|
7585
|
-
const pkgBridge =
|
|
7586
|
-
const srcBridge =
|
|
8001
|
+
const pkgBridge = join8(pkgRoot, "bridge");
|
|
8002
|
+
const srcBridge = join8(pkgRoot, "..", "..", "bridge");
|
|
7587
8003
|
let source = null;
|
|
7588
|
-
if (
|
|
8004
|
+
if (existsSync12(join8(pkgBridge, "package.json"))) {
|
|
7589
8005
|
source = pkgBridge;
|
|
7590
|
-
} else if (
|
|
8006
|
+
} else if (existsSync12(join8(srcBridge, "package.json"))) {
|
|
7591
8007
|
source = srcBridge;
|
|
7592
8008
|
}
|
|
7593
8009
|
if (!source) {
|
|
@@ -7595,8 +8011,8 @@ var WorkspaceManager = class {
|
|
|
7595
8011
|
process.exit(1);
|
|
7596
8012
|
}
|
|
7597
8013
|
console.log(`${this.logo} Setting up bridge...`);
|
|
7598
|
-
|
|
7599
|
-
if (
|
|
8014
|
+
mkdirSync7(resolve11(userBridge, ".."), { recursive: true });
|
|
8015
|
+
if (existsSync12(userBridge)) {
|
|
7600
8016
|
rmSync5(userBridge, { recursive: true, force: true });
|
|
7601
8017
|
}
|
|
7602
8018
|
cpSync3(source, userBridge, {
|
|
@@ -7632,7 +8048,7 @@ function resolveSkillsInstallWorkdir(params) {
|
|
|
7632
8048
|
if (params.explicitWorkdir) {
|
|
7633
8049
|
return expandHome2(params.explicitWorkdir);
|
|
7634
8050
|
}
|
|
7635
|
-
return
|
|
8051
|
+
return getWorkspacePath10(params.configuredWorkspace);
|
|
7636
8052
|
}
|
|
7637
8053
|
var CliRuntime = class {
|
|
7638
8054
|
logo;
|
|
@@ -7647,6 +8063,7 @@ var CliRuntime = class {
|
|
|
7647
8063
|
pluginCommands;
|
|
7648
8064
|
channelCommands;
|
|
7649
8065
|
cronCommands;
|
|
8066
|
+
remoteCommands;
|
|
7650
8067
|
diagnosticsCommands;
|
|
7651
8068
|
constructor(options = {}) {
|
|
7652
8069
|
this.logo = options.logo ?? LOGO;
|
|
@@ -7668,6 +8085,7 @@ var CliRuntime = class {
|
|
|
7668
8085
|
requestRestart: (params) => this.requestRestart(params)
|
|
7669
8086
|
});
|
|
7670
8087
|
this.cronCommands = new CronCommands();
|
|
8088
|
+
this.remoteCommands = new RemoteCommands();
|
|
7671
8089
|
this.diagnosticsCommands = new DiagnosticsCommands({ logo: this.logo });
|
|
7672
8090
|
this.restartCoordinator = new RestartCoordinator({
|
|
7673
8091
|
readServiceState,
|
|
@@ -7733,7 +8151,7 @@ var CliRuntime = class {
|
|
|
7733
8151
|
const delayMs = typeof params.delayMs === "number" && Number.isFinite(params.delayMs) ? Math.max(0, Math.floor(params.delayMs)) : 100;
|
|
7734
8152
|
const cliPath = process.env.NEXTCLAW_SELF_RELAUNCH_CLI?.trim() || fileURLToPath4(new URL("./index.js", import.meta.url));
|
|
7735
8153
|
const startArgs = [cliPath, "start", "--ui-port", String(uiPort)];
|
|
7736
|
-
const serviceStatePath = resolve12(
|
|
8154
|
+
const serviceStatePath = resolve12(getDataDir9(), "run", "service.json");
|
|
7737
8155
|
const helperScript = [
|
|
7738
8156
|
'const { spawnSync } = require("node:child_process");',
|
|
7739
8157
|
'const { readFileSync } = require("node:fs");',
|
|
@@ -7861,18 +8279,18 @@ var CliRuntime = class {
|
|
|
7861
8279
|
const source = options.source ?? "init";
|
|
7862
8280
|
const prefix = options.auto ? "Auto init" : "Init";
|
|
7863
8281
|
const force = Boolean(options.force);
|
|
7864
|
-
const configPath =
|
|
8282
|
+
const configPath = getConfigPath5();
|
|
7865
8283
|
let createdConfig = false;
|
|
7866
|
-
if (!
|
|
8284
|
+
if (!existsSync13(configPath)) {
|
|
7867
8285
|
const config3 = ConfigSchema2.parse({});
|
|
7868
|
-
|
|
8286
|
+
saveConfig8(config3);
|
|
7869
8287
|
createdConfig = true;
|
|
7870
8288
|
}
|
|
7871
|
-
const config2 =
|
|
8289
|
+
const config2 = loadConfig12();
|
|
7872
8290
|
const workspaceSetting = config2.agents.defaults.workspace;
|
|
7873
|
-
const workspacePath = !workspaceSetting || workspaceSetting === DEFAULT_WORKSPACE_PATH ?
|
|
7874
|
-
const workspaceExisted =
|
|
7875
|
-
|
|
8291
|
+
const workspacePath = !workspaceSetting || workspaceSetting === DEFAULT_WORKSPACE_PATH ? join9(getDataDir9(), DEFAULT_WORKSPACE_DIR) : expandHome2(workspaceSetting);
|
|
8292
|
+
const workspaceExisted = existsSync13(workspacePath);
|
|
8293
|
+
mkdirSync8(workspacePath, { recursive: true });
|
|
7876
8294
|
const templateResult = this.workspaceManager.createWorkspaceTemplates(
|
|
7877
8295
|
workspacePath,
|
|
7878
8296
|
{ force }
|
|
@@ -7903,8 +8321,8 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
7903
8321
|
}
|
|
7904
8322
|
async login(opts = {}) {
|
|
7905
8323
|
await this.init({ source: "login", auto: true });
|
|
7906
|
-
const configPath =
|
|
7907
|
-
const config2 =
|
|
8324
|
+
const configPath = getConfigPath5();
|
|
8325
|
+
const config2 = loadConfig12(configPath);
|
|
7908
8326
|
const providers = config2.providers;
|
|
7909
8327
|
const nextclawProvider = providers.nextclaw ?? {
|
|
7910
8328
|
displayName: "",
|
|
@@ -7966,11 +8384,14 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
7966
8384
|
nextclawProvider.apiBase = v1Base;
|
|
7967
8385
|
nextclawProvider.apiKey = token;
|
|
7968
8386
|
providers.nextclaw = nextclawProvider;
|
|
7969
|
-
|
|
8387
|
+
saveConfig8(config2, configPath);
|
|
7970
8388
|
console.log(`\u2713 Logged in to NextClaw platform (${platformBase})`);
|
|
7971
8389
|
console.log(`\u2713 Account: ${email} (${role})`);
|
|
7972
8390
|
console.log(`\u2713 Token saved into providers.nextclaw.apiKey`);
|
|
7973
8391
|
}
|
|
8392
|
+
async remoteConnect(opts = {}) {
|
|
8393
|
+
await this.remoteCommands.connect(opts);
|
|
8394
|
+
}
|
|
7974
8395
|
async gateway(opts) {
|
|
7975
8396
|
const uiOverrides = {
|
|
7976
8397
|
host: FORCED_PUBLIC_UI_HOST
|
|
@@ -8060,16 +8481,16 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
8060
8481
|
await this.serviceCommands.stopService();
|
|
8061
8482
|
}
|
|
8062
8483
|
async agent(opts) {
|
|
8063
|
-
const configPath =
|
|
8064
|
-
const config2 = resolveConfigSecrets3(
|
|
8065
|
-
const workspace =
|
|
8484
|
+
const configPath = getConfigPath5();
|
|
8485
|
+
const config2 = resolveConfigSecrets3(loadConfig12(), { configPath });
|
|
8486
|
+
const workspace = getWorkspacePath10(config2.agents.defaults.workspace);
|
|
8066
8487
|
const pluginRegistry = loadPluginRegistry(config2, workspace);
|
|
8067
8488
|
const extensionRegistry = toExtensionRegistry(pluginRegistry);
|
|
8068
8489
|
logPluginDiagnostics(pluginRegistry);
|
|
8069
8490
|
const pluginChannelBindings = getPluginChannelBindings4(pluginRegistry);
|
|
8070
8491
|
setPluginRuntimeBridge2({
|
|
8071
8492
|
loadConfig: () => toPluginConfigView(
|
|
8072
|
-
resolveConfigSecrets3(
|
|
8493
|
+
resolveConfigSecrets3(loadConfig12(), { configPath }),
|
|
8073
8494
|
pluginChannelBindings
|
|
8074
8495
|
),
|
|
8075
8496
|
writeConfigFile: async (nextConfigView) => {
|
|
@@ -8078,13 +8499,13 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
8078
8499
|
"plugin runtime writeConfigFile expects an object config"
|
|
8079
8500
|
);
|
|
8080
8501
|
}
|
|
8081
|
-
const current =
|
|
8502
|
+
const current = loadConfig12();
|
|
8082
8503
|
const next = mergePluginConfigView(
|
|
8083
8504
|
current,
|
|
8084
8505
|
nextConfigView,
|
|
8085
8506
|
pluginChannelBindings
|
|
8086
8507
|
);
|
|
8087
|
-
|
|
8508
|
+
saveConfig8(next);
|
|
8088
8509
|
}
|
|
8089
8510
|
});
|
|
8090
8511
|
try {
|
|
@@ -8110,7 +8531,7 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
8110
8531
|
resolveMessageToolHints: ({ channel, accountId }) => resolvePluginChannelMessageToolHints2({
|
|
8111
8532
|
registry: pluginRegistry,
|
|
8112
8533
|
channel,
|
|
8113
|
-
cfg: resolveConfigSecrets3(
|
|
8534
|
+
cfg: resolveConfigSecrets3(loadConfig12(), { configPath }),
|
|
8114
8535
|
accountId
|
|
8115
8536
|
})
|
|
8116
8537
|
});
|
|
@@ -8129,10 +8550,10 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
8129
8550
|
`${this.logo} Interactive mode (type exit or Ctrl+C to quit)
|
|
8130
8551
|
`
|
|
8131
8552
|
);
|
|
8132
|
-
const historyFile =
|
|
8553
|
+
const historyFile = join9(getDataDir9(), "history", "cli_history");
|
|
8133
8554
|
const historyDir = resolve12(historyFile, "..");
|
|
8134
|
-
|
|
8135
|
-
const history =
|
|
8555
|
+
mkdirSync8(historyDir, { recursive: true });
|
|
8556
|
+
const history = existsSync13(historyFile) ? readFileSync11(historyFile, "utf-8").split("\n").filter(Boolean) : [];
|
|
8136
8557
|
const rl = createInterface2({
|
|
8137
8558
|
input: process.stdin,
|
|
8138
8559
|
output: process.stdout
|
|
@@ -8141,7 +8562,7 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
8141
8562
|
const merged = history.concat(
|
|
8142
8563
|
rl.history ?? []
|
|
8143
8564
|
);
|
|
8144
|
-
|
|
8565
|
+
writeFileSync7(historyFile, merged.join("\n"));
|
|
8145
8566
|
process.exit(0);
|
|
8146
8567
|
});
|
|
8147
8568
|
let running = true;
|
|
@@ -8305,7 +8726,7 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
8305
8726
|
await this.diagnosticsCommands.doctor(opts);
|
|
8306
8727
|
}
|
|
8307
8728
|
async skillsInstall(options) {
|
|
8308
|
-
const config2 =
|
|
8729
|
+
const config2 = loadConfig12();
|
|
8309
8730
|
const workdir = resolveSkillsInstallWorkdir({
|
|
8310
8731
|
explicitWorkdir: options.workdir,
|
|
8311
8732
|
configuredWorkspace: config2.agents.defaults.workspace
|
|
@@ -8373,6 +8794,8 @@ program.name(APP_NAME5).description(`${LOGO} ${APP_NAME5} - ${APP_TAGLINE}`).ver
|
|
|
8373
8794
|
program.command("onboard").description(`Initialize ${APP_NAME5} configuration and workspace`).action(async () => runtime.onboard());
|
|
8374
8795
|
program.command("init").description(`Initialize ${APP_NAME5} configuration and workspace`).option("-f, --force", "Overwrite existing template files").action(async (opts) => runtime.init({ force: Boolean(opts.force) }));
|
|
8375
8796
|
program.command("login").description("Login to NextClaw platform and save token into providers.nextclaw.apiKey").option("--api-base <url>", "Platform API base (supports /v1 suffix)").option("--email <email>", "Login email").option("--password <password>", "Login password").option("--register", "Register first, then login", false).action(async (opts) => runtime.login(opts));
|
|
8797
|
+
var remote = program.command("remote").description("Manage remote access");
|
|
8798
|
+
remote.command("connect").description("Register this machine as a remote device and keep the connector online").option("--api-base <url>", "Platform API base (supports /v1 suffix)").option("--local-origin <url>", "Local NextClaw UI origin (default: active service or http://127.0.0.1:18791)").option("--name <name>", "Device display name").option("--once", "Connect once without auto-reconnect", false).action(async (opts) => runtime.remoteConnect(opts));
|
|
8376
8799
|
program.command("gateway").description(`Start the ${APP_NAME5} gateway`).option("-p, --port <port>", "Gateway port", "18790").option("-v, --verbose", "Verbose output", false).option("--ui", "Enable UI server", false).option("--ui-port <port>", "UI port").option("--ui-open", "Open browser when UI starts", false).action(async (opts) => runtime.gateway(opts));
|
|
8377
8800
|
program.command("ui").description(`Start the ${APP_NAME5} UI with gateway`).option("--port <port>", "UI port").option("--no-open", "Disable opening browser").action(async (opts) => runtime.ui(opts));
|
|
8378
8801
|
program.command("start").description(`Start the ${APP_NAME5} gateway + UI in the background`).option("--ui-port <port>", "UI port").option("--start-timeout <ms>", "Maximum wait time for startup readiness in milliseconds").option("--open", "Open browser after start", false).action(async (opts) => runtime.start(opts));
|