nextclaw 0.12.2 → 0.12.3
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 +395 -85
- package/package.json +9 -7
- package/ui-dist/assets/{ChannelsList-B-6m17e8.js → ChannelsList-DhvjpZcs.js} +1 -1
- package/ui-dist/assets/ChatPage-B8VBaMQm.js +38 -0
- package/ui-dist/assets/{DocBrowser-B3Mn7Pr1.js → DocBrowser-LpzGe8An.js} +1 -1
- package/ui-dist/assets/{LogoBadge-DunBd0Md.js → LogoBadge-Be4lktJN.js} +1 -1
- package/ui-dist/assets/{MarketplacePage-GfyaFoSx.js → MarketplacePage-Cx9AI3_h.js} +2 -2
- package/ui-dist/assets/{ModelConfig-BQHpKPOV.js → ModelConfig-DuImUHIX.js} +1 -1
- package/ui-dist/assets/{ProvidersList-a_cTcyUa.js → ProvidersList-Ccleg25k.js} +1 -1
- package/ui-dist/assets/{RuntimeConfig-ocF1z2ge.js → RuntimeConfig-C6iqpJR_.js} +1 -1
- package/ui-dist/assets/{SearchConfig-CuVwE1pL.js → SearchConfig-Dvp1TAXu.js} +1 -1
- package/ui-dist/assets/{SecretsConfig-BNNNBC9B.js → SecretsConfig-D5Ymlvt9.js} +2 -2
- package/ui-dist/assets/{SessionsConfig-NLh9dU5C.js → SessionsConfig-CIA_jA1P.js} +2 -2
- package/ui-dist/assets/{chat-message-D6cd8Vub.js → chat-message-B60Fh9kI.js} +1 -1
- package/ui-dist/assets/{index-DhtQmFvo.js → index-BiPDnzv0.js} +3 -3
- package/ui-dist/assets/index-C8GsgIUn.css +1 -0
- package/ui-dist/assets/{index-DUrka-gK.js → index-CPDASUXh.js} +1 -1
- package/ui-dist/assets/{label-UZ6h2eks.js → label-D4fGx6Wb.js} +1 -1
- package/ui-dist/assets/{page-layout-C4opEYpL.js → page-layout-twy8gmBE.js} +1 -1
- package/ui-dist/assets/{popover-CBwaT0q5.js → popover-DYbYpt1j.js} +1 -1
- package/ui-dist/assets/{security-config-C2x64Ori.js → security-config-BcIZ4rpb.js} +1 -1
- package/ui-dist/assets/skeleton-DypBy7jp.js +1 -0
- package/ui-dist/assets/{switch-CP4z7NJz.js → switch-DqA6r5XR.js} +1 -1
- package/ui-dist/assets/{tabs-custom-yiwRX4b7.js → tabs-custom-C6enKKs1.js} +1 -1
- package/ui-dist/assets/{useConfirmDialog-DOu_1Piu.js → useConfirmDialog-CHBf5Of7.js} +2 -2
- package/ui-dist/assets/{vendor-CAtZFO3x.js → vendor-DKBNiC31.js} +65 -70
- package/ui-dist/index.html +3 -3
- package/ui-dist/assets/ChatPage-BZ6B6_pW.js +0 -38
- package/ui-dist/assets/index-C98Y7H0s.css +0 -1
- package/ui-dist/assets/skeleton-C56NStvY.js +0 -1
package/dist/cli/index.js
CHANGED
|
@@ -6,8 +6,8 @@ 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
|
|
9
|
+
loadConfig as loadConfig9,
|
|
10
|
+
saveConfig as saveConfig7,
|
|
11
11
|
getConfigPath as getConfigPath4,
|
|
12
12
|
getDataDir as getDataDir8,
|
|
13
13
|
ConfigSchema as ConfigSchema2,
|
|
@@ -2116,15 +2116,230 @@ var ConfigCommands = class {
|
|
|
2116
2116
|
}
|
|
2117
2117
|
};
|
|
2118
2118
|
|
|
2119
|
+
// src/cli/commands/mcp.ts
|
|
2120
|
+
import { loadConfig as loadConfig4, saveConfig as saveConfig3 } from "@nextclaw/core";
|
|
2121
|
+
import { McpDoctorService, McpRegistryService, normalizeMcpServerName } from "@nextclaw/mcp";
|
|
2122
|
+
function normalizeOptionalString(value) {
|
|
2123
|
+
if (typeof value !== "string") {
|
|
2124
|
+
return void 0;
|
|
2125
|
+
}
|
|
2126
|
+
const trimmed = value.trim();
|
|
2127
|
+
return trimmed || void 0;
|
|
2128
|
+
}
|
|
2129
|
+
function parsePairs(values, label) {
|
|
2130
|
+
const output = {};
|
|
2131
|
+
for (const raw of values ?? []) {
|
|
2132
|
+
const index = raw.indexOf("=");
|
|
2133
|
+
if (index <= 0) {
|
|
2134
|
+
throw new Error(`Invalid ${label} entry: ${raw}. Expected key=value.`);
|
|
2135
|
+
}
|
|
2136
|
+
const key = raw.slice(0, index).trim();
|
|
2137
|
+
const value = raw.slice(index + 1);
|
|
2138
|
+
if (!key) {
|
|
2139
|
+
throw new Error(`Invalid ${label} entry: ${raw}. Expected key=value.`);
|
|
2140
|
+
}
|
|
2141
|
+
output[key] = value;
|
|
2142
|
+
}
|
|
2143
|
+
return output;
|
|
2144
|
+
}
|
|
2145
|
+
function parseTimeoutMs(value) {
|
|
2146
|
+
if (value === void 0 || value === null || value === "") {
|
|
2147
|
+
return void 0;
|
|
2148
|
+
}
|
|
2149
|
+
const parsed = Number(value);
|
|
2150
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
2151
|
+
throw new Error(`Invalid timeout: ${String(value)}`);
|
|
2152
|
+
}
|
|
2153
|
+
return Math.trunc(parsed);
|
|
2154
|
+
}
|
|
2155
|
+
function buildMcpServerDefinition(command, opts) {
|
|
2156
|
+
const transport = (normalizeOptionalString(opts.transport) ?? "stdio").toLowerCase();
|
|
2157
|
+
const disabled = Boolean(opts.disabled);
|
|
2158
|
+
const allAgents = Boolean(opts.allAgents);
|
|
2159
|
+
const explicitAgents = Array.from(
|
|
2160
|
+
new Set(
|
|
2161
|
+
(opts.agent ?? []).map((agentId) => normalizeOptionalString(agentId)).filter((agentId) => Boolean(agentId))
|
|
2162
|
+
)
|
|
2163
|
+
);
|
|
2164
|
+
if (transport === "stdio") {
|
|
2165
|
+
if (command.length === 0) {
|
|
2166
|
+
throw new Error("stdio transport requires a command after --");
|
|
2167
|
+
}
|
|
2168
|
+
return {
|
|
2169
|
+
enabled: !disabled,
|
|
2170
|
+
transport: {
|
|
2171
|
+
type: "stdio",
|
|
2172
|
+
command: command[0],
|
|
2173
|
+
args: command.slice(1),
|
|
2174
|
+
cwd: normalizeOptionalString(opts.cwd),
|
|
2175
|
+
env: parsePairs(opts.env, "env"),
|
|
2176
|
+
stderr: normalizeOptionalString(opts.stderr) ?? "pipe"
|
|
2177
|
+
},
|
|
2178
|
+
scope: {
|
|
2179
|
+
allAgents,
|
|
2180
|
+
agents: explicitAgents
|
|
2181
|
+
},
|
|
2182
|
+
policy: {
|
|
2183
|
+
trust: "explicit",
|
|
2184
|
+
start: "eager"
|
|
2185
|
+
}
|
|
2186
|
+
};
|
|
2187
|
+
}
|
|
2188
|
+
const url = normalizeOptionalString(opts.url);
|
|
2189
|
+
if (!url) {
|
|
2190
|
+
throw new Error(`${transport} transport requires --url`);
|
|
2191
|
+
}
|
|
2192
|
+
const timeoutMs = parseTimeoutMs(opts.timeoutMs);
|
|
2193
|
+
const shared = {
|
|
2194
|
+
enabled: !disabled,
|
|
2195
|
+
scope: {
|
|
2196
|
+
allAgents,
|
|
2197
|
+
agents: explicitAgents
|
|
2198
|
+
},
|
|
2199
|
+
policy: {
|
|
2200
|
+
trust: "explicit",
|
|
2201
|
+
start: "eager"
|
|
2202
|
+
}
|
|
2203
|
+
};
|
|
2204
|
+
if (transport === "http") {
|
|
2205
|
+
return {
|
|
2206
|
+
...shared,
|
|
2207
|
+
transport: {
|
|
2208
|
+
type: "http",
|
|
2209
|
+
url,
|
|
2210
|
+
headers: parsePairs(opts.header, "header"),
|
|
2211
|
+
timeoutMs: timeoutMs ?? 15e3,
|
|
2212
|
+
verifyTls: !opts.insecure
|
|
2213
|
+
}
|
|
2214
|
+
};
|
|
2215
|
+
}
|
|
2216
|
+
if (transport === "sse") {
|
|
2217
|
+
return {
|
|
2218
|
+
...shared,
|
|
2219
|
+
transport: {
|
|
2220
|
+
type: "sse",
|
|
2221
|
+
url,
|
|
2222
|
+
headers: parsePairs(opts.header, "header"),
|
|
2223
|
+
timeoutMs: timeoutMs ?? 15e3,
|
|
2224
|
+
verifyTls: !opts.insecure,
|
|
2225
|
+
reconnect: {
|
|
2226
|
+
enabled: true,
|
|
2227
|
+
initialDelayMs: 1e3,
|
|
2228
|
+
maxDelayMs: 3e4
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
};
|
|
2232
|
+
}
|
|
2233
|
+
throw new Error(`Unsupported MCP transport: ${transport}`);
|
|
2234
|
+
}
|
|
2235
|
+
var McpCommands = class {
|
|
2236
|
+
mcpList(opts = {}) {
|
|
2237
|
+
const registry = new McpRegistryService({
|
|
2238
|
+
getConfig: () => loadConfig4()
|
|
2239
|
+
});
|
|
2240
|
+
const servers = registry.listServers().map((server) => ({
|
|
2241
|
+
name: server.name,
|
|
2242
|
+
enabled: server.definition.enabled,
|
|
2243
|
+
transport: server.definition.transport.type,
|
|
2244
|
+
scope: server.definition.scope
|
|
2245
|
+
}));
|
|
2246
|
+
if (opts.json) {
|
|
2247
|
+
console.log(JSON.stringify({ servers }, null, 2));
|
|
2248
|
+
return;
|
|
2249
|
+
}
|
|
2250
|
+
if (servers.length === 0) {
|
|
2251
|
+
console.log("No MCP servers configured.");
|
|
2252
|
+
return;
|
|
2253
|
+
}
|
|
2254
|
+
for (const server of servers) {
|
|
2255
|
+
const scope = server.scope.allAgents ? "all-agents" : server.scope.agents.length > 0 ? `agents=${server.scope.agents.join(",")}` : "default-agent";
|
|
2256
|
+
console.log(`${server.enabled ? "ENABLED " : "DISABLED"} ${server.name} (${server.transport}, ${scope})`);
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
async mcpAdd(name, command, opts) {
|
|
2260
|
+
const normalizedName = normalizeMcpServerName(name);
|
|
2261
|
+
const config2 = loadConfig4();
|
|
2262
|
+
if (config2.mcp.servers[normalizedName]) {
|
|
2263
|
+
reportUserInputIssue(`MCP server already exists: ${normalizedName}. Use 'mcp list' or remove it first.`);
|
|
2264
|
+
return;
|
|
2265
|
+
}
|
|
2266
|
+
config2.mcp.servers[normalizedName] = buildMcpServerDefinition(command, opts);
|
|
2267
|
+
saveConfig3(config2);
|
|
2268
|
+
console.log(`Added MCP server ${normalizedName}.`);
|
|
2269
|
+
}
|
|
2270
|
+
async mcpRemove(name) {
|
|
2271
|
+
const normalizedName = normalizeMcpServerName(name);
|
|
2272
|
+
const config2 = loadConfig4();
|
|
2273
|
+
if (!config2.mcp.servers[normalizedName]) {
|
|
2274
|
+
reportUserInputIssue(`Unknown MCP server: ${normalizedName}`);
|
|
2275
|
+
return;
|
|
2276
|
+
}
|
|
2277
|
+
delete config2.mcp.servers[normalizedName];
|
|
2278
|
+
saveConfig3(config2);
|
|
2279
|
+
console.log(`Removed MCP server ${normalizedName}.`);
|
|
2280
|
+
}
|
|
2281
|
+
async mcpEnable(name) {
|
|
2282
|
+
await this.toggleEnabled(name, true);
|
|
2283
|
+
}
|
|
2284
|
+
async mcpDisable(name) {
|
|
2285
|
+
await this.toggleEnabled(name, false);
|
|
2286
|
+
}
|
|
2287
|
+
async mcpDoctor(name, opts = {}) {
|
|
2288
|
+
const registry = new McpRegistryService({
|
|
2289
|
+
getConfig: () => loadConfig4()
|
|
2290
|
+
});
|
|
2291
|
+
const doctor = new McpDoctorService({
|
|
2292
|
+
getConfig: () => loadConfig4(),
|
|
2293
|
+
registryService: registry
|
|
2294
|
+
});
|
|
2295
|
+
try {
|
|
2296
|
+
const reports = await doctor.inspect(name);
|
|
2297
|
+
if (opts.json) {
|
|
2298
|
+
console.log(JSON.stringify({ reports }, null, 2));
|
|
2299
|
+
return;
|
|
2300
|
+
}
|
|
2301
|
+
if (reports.length === 0) {
|
|
2302
|
+
console.log("No MCP servers matched.");
|
|
2303
|
+
return;
|
|
2304
|
+
}
|
|
2305
|
+
for (const report of reports) {
|
|
2306
|
+
const status = report.error ? "ERROR" : "OK";
|
|
2307
|
+
const detail = report.error ? ` (${report.error})` : "";
|
|
2308
|
+
console.log(
|
|
2309
|
+
`[${status}] ${report.name} enabled=${report.enabled} transport=${report.transport} tools=${report.toolCount}${detail}`
|
|
2310
|
+
);
|
|
2311
|
+
}
|
|
2312
|
+
} finally {
|
|
2313
|
+
await registry.close();
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
async toggleEnabled(name, enabled) {
|
|
2317
|
+
const normalizedName = normalizeMcpServerName(name);
|
|
2318
|
+
const config2 = loadConfig4();
|
|
2319
|
+
const current = config2.mcp.servers[normalizedName];
|
|
2320
|
+
if (!current) {
|
|
2321
|
+
reportUserInputIssue(`Unknown MCP server: ${normalizedName}`);
|
|
2322
|
+
return;
|
|
2323
|
+
}
|
|
2324
|
+
current.enabled = enabled;
|
|
2325
|
+
saveConfig3(config2);
|
|
2326
|
+
console.log(`${enabled ? "Enabled" : "Disabled"} MCP server ${normalizedName}.`);
|
|
2327
|
+
}
|
|
2328
|
+
};
|
|
2329
|
+
function reportUserInputIssue(message) {
|
|
2330
|
+
console.error(message);
|
|
2331
|
+
process.exitCode = 1;
|
|
2332
|
+
}
|
|
2333
|
+
|
|
2119
2334
|
// src/cli/commands/secrets.ts
|
|
2120
2335
|
import { readFileSync as readFileSync5 } from "fs";
|
|
2121
2336
|
import {
|
|
2122
2337
|
buildReloadPlan as buildReloadPlan2,
|
|
2123
2338
|
diffConfigPaths as diffConfigPaths2,
|
|
2124
2339
|
getConfigPath,
|
|
2125
|
-
loadConfig as
|
|
2340
|
+
loadConfig as loadConfig5,
|
|
2126
2341
|
resolveConfigSecrets,
|
|
2127
|
-
saveConfig as
|
|
2342
|
+
saveConfig as saveConfig4
|
|
2128
2343
|
} from "@nextclaw/core";
|
|
2129
2344
|
var SECRET_SOURCES = ["env", "file", "exec"];
|
|
2130
2345
|
function normalizeSecretSource(value) {
|
|
@@ -2134,14 +2349,14 @@ function normalizeSecretSource(value) {
|
|
|
2134
2349
|
const normalized = value.trim().toLowerCase();
|
|
2135
2350
|
return SECRET_SOURCES.includes(normalized) ? normalized : null;
|
|
2136
2351
|
}
|
|
2137
|
-
function
|
|
2352
|
+
function normalizeOptionalString2(value) {
|
|
2138
2353
|
if (typeof value !== "string") {
|
|
2139
2354
|
return void 0;
|
|
2140
2355
|
}
|
|
2141
2356
|
const trimmed = value.trim();
|
|
2142
2357
|
return trimmed || void 0;
|
|
2143
2358
|
}
|
|
2144
|
-
function
|
|
2359
|
+
function parseTimeoutMs2(value) {
|
|
2145
2360
|
if (value === void 0 || value === null || value === "") {
|
|
2146
2361
|
return void 0;
|
|
2147
2362
|
}
|
|
@@ -2152,11 +2367,11 @@ function parseTimeoutMs(value) {
|
|
|
2152
2367
|
return Math.trunc(parsed);
|
|
2153
2368
|
}
|
|
2154
2369
|
function inferProviderAlias(config2, ref) {
|
|
2155
|
-
const explicit =
|
|
2370
|
+
const explicit = normalizeOptionalString2(ref.provider);
|
|
2156
2371
|
if (explicit) {
|
|
2157
2372
|
return explicit;
|
|
2158
2373
|
}
|
|
2159
|
-
const defaultAlias =
|
|
2374
|
+
const defaultAlias = normalizeOptionalString2(config2.secrets.defaults[ref.source]);
|
|
2160
2375
|
if (defaultAlias) {
|
|
2161
2376
|
return defaultAlias;
|
|
2162
2377
|
}
|
|
@@ -2180,8 +2395,8 @@ function parseRefsPatch(raw) {
|
|
|
2180
2395
|
throw new Error(`invalid ref for ${path2}`);
|
|
2181
2396
|
}
|
|
2182
2397
|
const source = normalizeSecretSource(value.source);
|
|
2183
|
-
const id =
|
|
2184
|
-
const provider =
|
|
2398
|
+
const id = normalizeOptionalString2(value.id);
|
|
2399
|
+
const provider = normalizeOptionalString2(value.provider);
|
|
2185
2400
|
if (!source || !id) {
|
|
2186
2401
|
throw new Error(`invalid ref for ${path2}: source/id is required`);
|
|
2187
2402
|
}
|
|
@@ -2218,7 +2433,7 @@ var SecretsCommands = class {
|
|
|
2218
2433
|
this.deps = deps;
|
|
2219
2434
|
}
|
|
2220
2435
|
secretsAudit(opts = {}) {
|
|
2221
|
-
const config2 =
|
|
2436
|
+
const config2 = loadConfig5();
|
|
2222
2437
|
const configPath = getConfigPath();
|
|
2223
2438
|
const refs = config2.secrets.refs;
|
|
2224
2439
|
const items = [];
|
|
@@ -2282,11 +2497,11 @@ var SecretsCommands = class {
|
|
|
2282
2497
|
}
|
|
2283
2498
|
}
|
|
2284
2499
|
async secretsConfigure(opts) {
|
|
2285
|
-
const alias =
|
|
2500
|
+
const alias = normalizeOptionalString2(opts.provider);
|
|
2286
2501
|
if (!alias) {
|
|
2287
2502
|
throw new Error("provider alias is required");
|
|
2288
2503
|
}
|
|
2289
|
-
const prevConfig =
|
|
2504
|
+
const prevConfig = loadConfig5();
|
|
2290
2505
|
const nextConfig = structuredClone(prevConfig);
|
|
2291
2506
|
const remove = Boolean(opts.remove);
|
|
2292
2507
|
if (remove) {
|
|
@@ -2304,10 +2519,10 @@ var SecretsCommands = class {
|
|
|
2304
2519
|
if (source === "env") {
|
|
2305
2520
|
nextConfig.secrets.providers[alias] = {
|
|
2306
2521
|
source,
|
|
2307
|
-
...
|
|
2522
|
+
...normalizeOptionalString2(opts.prefix) ? { prefix: normalizeOptionalString2(opts.prefix) } : {}
|
|
2308
2523
|
};
|
|
2309
2524
|
} else if (source === "file") {
|
|
2310
|
-
const path2 =
|
|
2525
|
+
const path2 = normalizeOptionalString2(opts.path);
|
|
2311
2526
|
if (!path2) {
|
|
2312
2527
|
throw new Error("file source requires --path");
|
|
2313
2528
|
}
|
|
@@ -2317,7 +2532,7 @@ var SecretsCommands = class {
|
|
|
2317
2532
|
format: "json"
|
|
2318
2533
|
};
|
|
2319
2534
|
} else {
|
|
2320
|
-
const command =
|
|
2535
|
+
const command = normalizeOptionalString2(opts.command);
|
|
2321
2536
|
if (!command) {
|
|
2322
2537
|
throw new Error("exec source requires --command");
|
|
2323
2538
|
}
|
|
@@ -2325,8 +2540,8 @@ var SecretsCommands = class {
|
|
|
2325
2540
|
source,
|
|
2326
2541
|
command,
|
|
2327
2542
|
args: Array.isArray(opts.arg) ? opts.arg : [],
|
|
2328
|
-
...
|
|
2329
|
-
timeoutMs:
|
|
2543
|
+
...normalizeOptionalString2(opts.cwd) ? { cwd: normalizeOptionalString2(opts.cwd) } : {},
|
|
2544
|
+
timeoutMs: parseTimeoutMs2(opts.timeoutMs) ?? 5e3
|
|
2330
2545
|
};
|
|
2331
2546
|
}
|
|
2332
2547
|
if (opts.setDefault) {
|
|
@@ -2334,7 +2549,7 @@ var SecretsCommands = class {
|
|
|
2334
2549
|
}
|
|
2335
2550
|
}
|
|
2336
2551
|
resolveConfigSecrets(nextConfig, { configPath: getConfigPath() });
|
|
2337
|
-
|
|
2552
|
+
saveConfig4(nextConfig);
|
|
2338
2553
|
await this.requestRestartForConfigDiff({
|
|
2339
2554
|
prevConfig,
|
|
2340
2555
|
nextConfig,
|
|
@@ -2348,7 +2563,7 @@ var SecretsCommands = class {
|
|
|
2348
2563
|
console.log(`Secrets provider ${remove ? "removed" : "configured"}: ${alias}`);
|
|
2349
2564
|
}
|
|
2350
2565
|
async secretsApply(opts) {
|
|
2351
|
-
const prevConfig =
|
|
2566
|
+
const prevConfig = loadConfig5();
|
|
2352
2567
|
const nextConfig = structuredClone(prevConfig);
|
|
2353
2568
|
if (opts.enable && opts.disable) {
|
|
2354
2569
|
throw new Error("cannot set --enable and --disable at the same time");
|
|
@@ -2384,11 +2599,11 @@ var SecretsCommands = class {
|
|
|
2384
2599
|
delete nextConfig.secrets.refs[path2];
|
|
2385
2600
|
} else {
|
|
2386
2601
|
const source = normalizeSecretSource(opts.source);
|
|
2387
|
-
const id =
|
|
2602
|
+
const id = normalizeOptionalString2(opts.id);
|
|
2388
2603
|
if (!source || !id) {
|
|
2389
2604
|
throw new Error("apply single ref requires --source and --id");
|
|
2390
2605
|
}
|
|
2391
|
-
const provider =
|
|
2606
|
+
const provider = normalizeOptionalString2(opts.provider);
|
|
2392
2607
|
nextConfig.secrets.refs[path2] = {
|
|
2393
2608
|
source,
|
|
2394
2609
|
id,
|
|
@@ -2399,7 +2614,7 @@ var SecretsCommands = class {
|
|
|
2399
2614
|
throw new Error("--remove requires --path");
|
|
2400
2615
|
}
|
|
2401
2616
|
resolveConfigSecrets(nextConfig, { configPath: getConfigPath() });
|
|
2402
|
-
|
|
2617
|
+
saveConfig4(nextConfig);
|
|
2403
2618
|
await this.requestRestartForConfigDiff({
|
|
2404
2619
|
prevConfig,
|
|
2405
2620
|
nextConfig,
|
|
@@ -2413,10 +2628,10 @@ var SecretsCommands = class {
|
|
|
2413
2628
|
console.log("Secrets applied.");
|
|
2414
2629
|
}
|
|
2415
2630
|
async secretsReload(opts = {}) {
|
|
2416
|
-
const config2 =
|
|
2631
|
+
const config2 = loadConfig5();
|
|
2417
2632
|
const configPath = getConfigPath();
|
|
2418
2633
|
resolveConfigSecrets(config2, { configPath });
|
|
2419
|
-
|
|
2634
|
+
saveConfig4(config2);
|
|
2420
2635
|
if (opts.json) {
|
|
2421
2636
|
console.log(JSON.stringify({ ok: true, message: "secrets reload signal emitted" }, null, 2));
|
|
2422
2637
|
return;
|
|
@@ -2441,7 +2656,7 @@ var SecretsCommands = class {
|
|
|
2441
2656
|
|
|
2442
2657
|
// src/cli/commands/channels.ts
|
|
2443
2658
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
2444
|
-
import { getWorkspacePath as getWorkspacePath3, loadConfig as
|
|
2659
|
+
import { getWorkspacePath as getWorkspacePath3, loadConfig as loadConfig6, saveConfig as saveConfig5 } from "@nextclaw/core";
|
|
2445
2660
|
import { BUILTIN_CHANNEL_PLUGIN_IDS, builtinProviderIds as builtinProviderIds2 } from "@nextclaw/runtime";
|
|
2446
2661
|
import { buildPluginStatusReport as buildPluginStatusReport3, enablePluginInConfig as enablePluginInConfig2, getPluginChannelBindings } from "@nextclaw/openclaw-compat";
|
|
2447
2662
|
var CHANNEL_LABELS = {
|
|
@@ -2462,7 +2677,7 @@ var ChannelCommands = class {
|
|
|
2462
2677
|
this.deps = deps;
|
|
2463
2678
|
}
|
|
2464
2679
|
channelsStatus() {
|
|
2465
|
-
const config2 =
|
|
2680
|
+
const config2 = loadConfig6();
|
|
2466
2681
|
console.log("Channel Status");
|
|
2467
2682
|
const channelConfig = config2.channels;
|
|
2468
2683
|
for (const channelId of BUILTIN_CHANNEL_PLUGIN_IDS) {
|
|
@@ -2501,7 +2716,7 @@ var ChannelCommands = class {
|
|
|
2501
2716
|
console.error("--channel is required");
|
|
2502
2717
|
process.exit(1);
|
|
2503
2718
|
}
|
|
2504
|
-
const config2 =
|
|
2719
|
+
const config2 = loadConfig6();
|
|
2505
2720
|
const workspaceDir = getWorkspacePath3(config2.agents.defaults.workspace);
|
|
2506
2721
|
const pluginRegistry = loadPluginRegistry(config2, workspaceDir);
|
|
2507
2722
|
const bindings = getPluginChannelBindings(pluginRegistry);
|
|
@@ -2544,7 +2759,7 @@ var ChannelCommands = class {
|
|
|
2544
2759
|
}
|
|
2545
2760
|
let next = mergePluginConfigView(config2, nextView, bindings);
|
|
2546
2761
|
next = enablePluginInConfig2(next, binding.pluginId);
|
|
2547
|
-
|
|
2762
|
+
saveConfig5(next);
|
|
2548
2763
|
console.log(`Configured channel "${binding.channelId}" via plugin "${binding.pluginId}".`);
|
|
2549
2764
|
await this.deps.requestRestart({
|
|
2550
2765
|
reason: `channel configured via plugin: ${binding.pluginId}`,
|
|
@@ -2639,7 +2854,7 @@ import {
|
|
|
2639
2854
|
getDataDir as getDataDir4,
|
|
2640
2855
|
getWorkspacePath as getWorkspacePath4,
|
|
2641
2856
|
hasSecretRef,
|
|
2642
|
-
loadConfig as
|
|
2857
|
+
loadConfig as loadConfig7
|
|
2643
2858
|
} from "@nextclaw/core";
|
|
2644
2859
|
import { listBuiltinProviders } from "@nextclaw/runtime";
|
|
2645
2860
|
var DiagnosticsCommands = class {
|
|
@@ -2801,7 +3016,7 @@ var DiagnosticsCommands = class {
|
|
|
2801
3016
|
}
|
|
2802
3017
|
async collectRuntimeStatus(params) {
|
|
2803
3018
|
const configPath = getConfigPath2();
|
|
2804
|
-
const config2 =
|
|
3019
|
+
const config2 = loadConfig7();
|
|
2805
3020
|
const workspacePath = getWorkspacePath4(config2.agents.defaults.workspace);
|
|
2806
3021
|
const serviceStatePath = resolve8(getDataDir4(), "run", "service.json");
|
|
2807
3022
|
const fixActions = [];
|
|
@@ -3306,6 +3521,9 @@ var ConfigReloader = class {
|
|
|
3306
3521
|
setReloadPlugins(callback) {
|
|
3307
3522
|
this.options.reloadPlugins = callback;
|
|
3308
3523
|
}
|
|
3524
|
+
setReloadMcp(callback) {
|
|
3525
|
+
this.options.reloadMcp = callback;
|
|
3526
|
+
}
|
|
3309
3527
|
async applyReloadPlan(nextConfig) {
|
|
3310
3528
|
const changedPaths = diffConfigPaths3(this.currentConfig, nextConfig);
|
|
3311
3529
|
if (!changedPaths.length) {
|
|
@@ -3322,6 +3540,13 @@ var ConfigReloader = class {
|
|
|
3322
3540
|
});
|
|
3323
3541
|
console.log("Config reload: plugins reloaded.");
|
|
3324
3542
|
}
|
|
3543
|
+
if (plan.reloadMcp) {
|
|
3544
|
+
await this.reloadMcp({
|
|
3545
|
+
config: nextConfig,
|
|
3546
|
+
changedPaths
|
|
3547
|
+
});
|
|
3548
|
+
console.log("Config reload: MCP servers reloaded.");
|
|
3549
|
+
}
|
|
3325
3550
|
if (plan.restartChannels || reloadPluginsResult?.restartChannels) {
|
|
3326
3551
|
await this.reloadChannels(nextConfig);
|
|
3327
3552
|
console.log("Config reload: channels restarted.");
|
|
@@ -3423,6 +3648,12 @@ var ConfigReloader = class {
|
|
|
3423
3648
|
}
|
|
3424
3649
|
return await this.options.reloadPlugins(params);
|
|
3425
3650
|
}
|
|
3651
|
+
async reloadMcp(params) {
|
|
3652
|
+
if (!this.options.reloadMcp) {
|
|
3653
|
+
return;
|
|
3654
|
+
}
|
|
3655
|
+
await this.options.reloadMcp(params);
|
|
3656
|
+
}
|
|
3426
3657
|
};
|
|
3427
3658
|
|
|
3428
3659
|
// src/cli/missing-provider.ts
|
|
@@ -4052,7 +4283,9 @@ var resolveCliSubcommandEntry = (params) => {
|
|
|
4052
4283
|
import {
|
|
4053
4284
|
DisposableStore
|
|
4054
4285
|
} from "@nextclaw/core";
|
|
4286
|
+
import { McpRegistryService as McpRegistryService2, McpServerLifecycleManager } from "@nextclaw/mcp";
|
|
4055
4287
|
import { DefaultNcpAgentRuntime } from "@nextclaw/ncp-agent-runtime";
|
|
4288
|
+
import { McpNcpToolRegistryAdapter } from "@nextclaw/ncp-mcp";
|
|
4056
4289
|
import {
|
|
4057
4290
|
readAssistantReasoningNormalizationMode,
|
|
4058
4291
|
readAssistantReasoningNormalizationModeFromMetadata,
|
|
@@ -4346,6 +4579,7 @@ var NextclawNcpToolRegistry = class {
|
|
|
4346
4579
|
this.tools.clear();
|
|
4347
4580
|
this.registerDefaultTools(context);
|
|
4348
4581
|
this.registerExtensionTools(context);
|
|
4582
|
+
this.registerAdditionalTools(context);
|
|
4349
4583
|
}
|
|
4350
4584
|
listTools() {
|
|
4351
4585
|
return [...this.tools.values()];
|
|
@@ -4361,7 +4595,10 @@ var NextclawNcpToolRegistry = class {
|
|
|
4361
4595
|
}));
|
|
4362
4596
|
}
|
|
4363
4597
|
async execute(toolCallId, toolName, args) {
|
|
4364
|
-
|
|
4598
|
+
if (this.registry.has(toolName)) {
|
|
4599
|
+
return this.registry.execute(toolName, toToolParams(args), toolCallId);
|
|
4600
|
+
}
|
|
4601
|
+
return this.tools.get(toolName)?.execute(args);
|
|
4365
4602
|
}
|
|
4366
4603
|
registerDefaultTools(context) {
|
|
4367
4604
|
const allowedDir = context.restrictToWorkspace ? context.workspace : void 0;
|
|
@@ -4450,6 +4687,15 @@ var NextclawNcpToolRegistry = class {
|
|
|
4450
4687
|
new CoreToolNcpAdapter(tool, async (toolName, args) => this.registry.execute(toolName, toToolParams(args)))
|
|
4451
4688
|
);
|
|
4452
4689
|
}
|
|
4690
|
+
registerAdditionalTools(context) {
|
|
4691
|
+
const tools = this.options.getAdditionalTools?.(context) ?? [];
|
|
4692
|
+
for (const tool of tools) {
|
|
4693
|
+
if (this.tools.has(tool.name)) {
|
|
4694
|
+
continue;
|
|
4695
|
+
}
|
|
4696
|
+
this.tools.set(tool.name, tool);
|
|
4697
|
+
}
|
|
4698
|
+
}
|
|
4453
4699
|
};
|
|
4454
4700
|
function resolveAgentHandoffDepth(metadata) {
|
|
4455
4701
|
const rawDepth = Number(metadata.agent_handoff_depth ?? 0);
|
|
@@ -4505,7 +4751,7 @@ function resolveRequestedToolNames(metadata) {
|
|
|
4505
4751
|
)
|
|
4506
4752
|
);
|
|
4507
4753
|
}
|
|
4508
|
-
function
|
|
4754
|
+
function normalizeOptionalString3(value) {
|
|
4509
4755
|
return normalizeString(value) ?? void 0;
|
|
4510
4756
|
}
|
|
4511
4757
|
function readMetadataModel(metadata) {
|
|
@@ -4625,7 +4871,7 @@ var NextclawNcpContextBuilder = class {
|
|
|
4625
4871
|
if (inboundModel) {
|
|
4626
4872
|
session.metadata.preferred_model = inboundModel;
|
|
4627
4873
|
}
|
|
4628
|
-
const effectiveModel =
|
|
4874
|
+
const effectiveModel = normalizeOptionalString3(session.metadata.preferred_model) ?? profile.model;
|
|
4629
4875
|
const clearThinking = requestMetadata.clear_thinking === true || requestMetadata.reset_thinking === true;
|
|
4630
4876
|
if (clearThinking) {
|
|
4631
4877
|
delete session.metadata.preferred_thinking;
|
|
@@ -4642,8 +4888,8 @@ var NextclawNcpContextBuilder = class {
|
|
|
4642
4888
|
model: effectiveModel,
|
|
4643
4889
|
sessionThinkingLevel: parseThinkingLevel(session.metadata.preferred_thinking) ?? null
|
|
4644
4890
|
});
|
|
4645
|
-
const channel =
|
|
4646
|
-
const chatId =
|
|
4891
|
+
const channel = normalizeOptionalString3(requestMetadata.channel) ?? normalizeOptionalString3(session.metadata.last_channel) ?? "ui";
|
|
4892
|
+
const chatId = normalizeOptionalString3(requestMetadata.chatId) ?? normalizeOptionalString3(requestMetadata.chat_id) ?? normalizeOptionalString3(session.metadata.last_to) ?? "web-ui";
|
|
4647
4893
|
session.metadata.last_channel = channel;
|
|
4648
4894
|
session.metadata.last_to = chatId;
|
|
4649
4895
|
const requestedSkillNames = resolveRequestedSkillNames(requestMetadata);
|
|
@@ -5222,6 +5468,21 @@ function buildPluginRuntimeSnapshotKey(extensionRegistry) {
|
|
|
5222
5468
|
async function createUiNcpAgent(params) {
|
|
5223
5469
|
const sessionStore = new NextclawAgentSessionStore(params.sessionManager);
|
|
5224
5470
|
const runtimeRegistry = new UiNcpRuntimeRegistry();
|
|
5471
|
+
let currentMcpConfig = params.getConfig();
|
|
5472
|
+
const mcpLifecycleManager = new McpServerLifecycleManager({
|
|
5473
|
+
getConfig: () => currentMcpConfig
|
|
5474
|
+
});
|
|
5475
|
+
const mcpRegistryService = new McpRegistryService2({
|
|
5476
|
+
getConfig: () => currentMcpConfig,
|
|
5477
|
+
lifecycleManager: mcpLifecycleManager
|
|
5478
|
+
});
|
|
5479
|
+
const mcpPrewarmResults = await mcpRegistryService.prewarmEnabledServers();
|
|
5480
|
+
for (const result of mcpPrewarmResults) {
|
|
5481
|
+
if (!result.ok) {
|
|
5482
|
+
console.warn(`[mcp] Failed to warm ${result.name}: ${result.error}`);
|
|
5483
|
+
}
|
|
5484
|
+
}
|
|
5485
|
+
const mcpToolRegistryAdapter = new McpNcpToolRegistryAdapter(mcpRegistryService);
|
|
5225
5486
|
runtimeRegistry.register({
|
|
5226
5487
|
kind: "native",
|
|
5227
5488
|
label: "Native",
|
|
@@ -5245,7 +5506,10 @@ async function createUiNcpAgent(params) {
|
|
|
5245
5506
|
cronService: params.cronService,
|
|
5246
5507
|
gatewayController: params.gatewayController,
|
|
5247
5508
|
getConfig: params.getConfig,
|
|
5248
|
-
getExtensionRegistry: params.getExtensionRegistry
|
|
5509
|
+
getExtensionRegistry: params.getExtensionRegistry,
|
|
5510
|
+
getAdditionalTools: (context) => mcpToolRegistryAdapter.listToolsForRun({
|
|
5511
|
+
agentId: context.agentId
|
|
5512
|
+
})
|
|
5249
5513
|
});
|
|
5250
5514
|
return new DefaultNcpAgentRuntime({
|
|
5251
5515
|
contextBuilder: new NextclawNcpContextBuilder({
|
|
@@ -5314,6 +5578,19 @@ async function createUiNcpAgent(params) {
|
|
|
5314
5578
|
applyExtensionRegistry: (extensionRegistry) => {
|
|
5315
5579
|
activeExtensionRegistry = extensionRegistry;
|
|
5316
5580
|
syncPluginRuntimeRegistrations(extensionRegistry);
|
|
5581
|
+
},
|
|
5582
|
+
applyMcpConfig: async (config2) => {
|
|
5583
|
+
const previousConfig = currentMcpConfig;
|
|
5584
|
+
currentMcpConfig = config2;
|
|
5585
|
+
const reconcileResult = await mcpRegistryService.reconcileConfig({
|
|
5586
|
+
prevConfig: previousConfig,
|
|
5587
|
+
nextConfig: config2
|
|
5588
|
+
});
|
|
5589
|
+
for (const warmResult of reconcileResult.warmed) {
|
|
5590
|
+
if (!warmResult.ok) {
|
|
5591
|
+
console.warn(`[mcp] Failed to warm ${warmResult.name}: ${warmResult.error}`);
|
|
5592
|
+
}
|
|
5593
|
+
}
|
|
5317
5594
|
}
|
|
5318
5595
|
};
|
|
5319
5596
|
}
|
|
@@ -5994,11 +6271,11 @@ var {
|
|
|
5994
6271
|
getWorkspacePath: getWorkspacePath8,
|
|
5995
6272
|
HeartbeatService,
|
|
5996
6273
|
LiteLLMProvider,
|
|
5997
|
-
loadConfig:
|
|
6274
|
+
loadConfig: loadConfig8,
|
|
5998
6275
|
MessageBus,
|
|
5999
6276
|
ProviderManager,
|
|
6000
6277
|
resolveConfigSecrets: resolveConfigSecrets2,
|
|
6001
|
-
saveConfig:
|
|
6278
|
+
saveConfig: saveConfig6,
|
|
6002
6279
|
SessionManager,
|
|
6003
6280
|
parseAgentScopedSessionKey: parseAgentScopedSessionKey3
|
|
6004
6281
|
} = NextclawCore;
|
|
@@ -6019,7 +6296,7 @@ var ServiceCommands = class {
|
|
|
6019
6296
|
this.applyLiveConfigReload = null;
|
|
6020
6297
|
this.liveUiNcpAgent = null;
|
|
6021
6298
|
const runtimeConfigPath = getConfigPath3();
|
|
6022
|
-
const config2 = resolveConfigSecrets2(
|
|
6299
|
+
const config2 = resolveConfigSecrets2(loadConfig8(), { configPath: runtimeConfigPath });
|
|
6023
6300
|
const workspace = getWorkspacePath8(config2.agents.defaults.workspace);
|
|
6024
6301
|
let pluginRegistry = loadPluginRegistry(config2, workspace);
|
|
6025
6302
|
let extensionRegistry = toExtensionRegistry(pluginRegistry);
|
|
@@ -6064,7 +6341,7 @@ var ServiceCommands = class {
|
|
|
6064
6341
|
sessionManager,
|
|
6065
6342
|
providerManager,
|
|
6066
6343
|
makeProvider: (nextConfig) => this.makeProvider(nextConfig, { allowMissing: true }) ?? this.makeMissingProvider(nextConfig),
|
|
6067
|
-
loadConfig: () => resolveConfigSecrets2(
|
|
6344
|
+
loadConfig: () => resolveConfigSecrets2(loadConfig8(), { configPath: runtimeConfigPath }),
|
|
6068
6345
|
getExtensionChannels: () => extensionRegistry.channels,
|
|
6069
6346
|
onRestartRequired: (paths) => {
|
|
6070
6347
|
void this.deps.requestRestart({
|
|
@@ -6075,14 +6352,14 @@ var ServiceCommands = class {
|
|
|
6075
6352
|
}
|
|
6076
6353
|
});
|
|
6077
6354
|
this.applyLiveConfigReload = async () => {
|
|
6078
|
-
await reloader.applyReloadPlan(resolveConfigSecrets2(
|
|
6355
|
+
await reloader.applyReloadPlan(resolveConfigSecrets2(loadConfig8(), { configPath: runtimeConfigPath }));
|
|
6079
6356
|
};
|
|
6080
6357
|
const gatewayController = new GatewayControllerImpl({
|
|
6081
6358
|
reloader,
|
|
6082
6359
|
cron: cron2,
|
|
6083
6360
|
sessionManager,
|
|
6084
6361
|
getConfigPath: getConfigPath3,
|
|
6085
|
-
saveConfig:
|
|
6362
|
+
saveConfig: saveConfig6,
|
|
6086
6363
|
requestRestart: async (options2) => {
|
|
6087
6364
|
await this.deps.requestRestart({
|
|
6088
6365
|
reason: options2?.reason ?? "gateway tool restart",
|
|
@@ -6108,7 +6385,7 @@ var ServiceCommands = class {
|
|
|
6108
6385
|
resolveMessageToolHints: ({ channel, accountId }) => resolvePluginChannelMessageToolHints({
|
|
6109
6386
|
registry: pluginRegistry,
|
|
6110
6387
|
channel,
|
|
6111
|
-
cfg: resolveConfigSecrets2(
|
|
6388
|
+
cfg: resolveConfigSecrets2(loadConfig8(), { configPath: runtimeConfigPath }),
|
|
6112
6389
|
accountId
|
|
6113
6390
|
})
|
|
6114
6391
|
});
|
|
@@ -6136,16 +6413,19 @@ var ServiceCommands = class {
|
|
|
6136
6413
|
}
|
|
6137
6414
|
return { restartChannels: result.restartChannels };
|
|
6138
6415
|
});
|
|
6416
|
+
reloader.setReloadMcp(async ({ config: nextConfig }) => {
|
|
6417
|
+
await this.liveUiNcpAgent?.applyMcpConfig?.(nextConfig);
|
|
6418
|
+
});
|
|
6139
6419
|
let pluginChannelBindings = getPluginChannelBindings3(pluginRegistry);
|
|
6140
6420
|
setPluginRuntimeBridge({
|
|
6141
|
-
loadConfig: () => toPluginConfigView(resolveConfigSecrets2(
|
|
6421
|
+
loadConfig: () => toPluginConfigView(resolveConfigSecrets2(loadConfig8(), { configPath: runtimeConfigPath }), pluginChannelBindings),
|
|
6142
6422
|
writeConfigFile: async (nextConfigView) => {
|
|
6143
6423
|
if (!nextConfigView || typeof nextConfigView !== "object" || Array.isArray(nextConfigView)) {
|
|
6144
6424
|
throw new Error("plugin runtime writeConfigFile expects an object config");
|
|
6145
6425
|
}
|
|
6146
|
-
const current =
|
|
6426
|
+
const current = loadConfig8();
|
|
6147
6427
|
const next = mergePluginConfigView(current, nextConfigView, pluginChannelBindings);
|
|
6148
|
-
|
|
6428
|
+
saveConfig6(next);
|
|
6149
6429
|
},
|
|
6150
6430
|
dispatchReplyWithBufferedBlockDispatcher: async ({ ctx, dispatcherOptions }) => {
|
|
6151
6431
|
const bodyForAgent = typeof ctx.BodyForAgent === "string" ? ctx.BodyForAgent : "";
|
|
@@ -6219,12 +6499,12 @@ var ServiceCommands = class {
|
|
|
6219
6499
|
providerManager,
|
|
6220
6500
|
bus,
|
|
6221
6501
|
gatewayController,
|
|
6222
|
-
() => resolveConfigSecrets2(
|
|
6502
|
+
() => resolveConfigSecrets2(loadConfig8(), { configPath: runtimeConfigPath }),
|
|
6223
6503
|
() => extensionRegistry,
|
|
6224
6504
|
({ channel, accountId }) => resolvePluginChannelMessageToolHints({
|
|
6225
6505
|
registry: pluginRegistry,
|
|
6226
6506
|
channel,
|
|
6227
|
-
cfg: resolveConfigSecrets2(
|
|
6507
|
+
cfg: resolveConfigSecrets2(loadConfig8(), { configPath: runtimeConfigPath }),
|
|
6228
6508
|
accountId
|
|
6229
6509
|
})
|
|
6230
6510
|
);
|
|
@@ -6233,27 +6513,7 @@ var ServiceCommands = class {
|
|
|
6233
6513
|
console.log(`\u2713 Cron: ${cronStatus.jobs} scheduled jobs`);
|
|
6234
6514
|
}
|
|
6235
6515
|
console.log("\u2713 Heartbeat: every 30m");
|
|
6236
|
-
|
|
6237
|
-
const watcher = chokidar.watch(configPath, {
|
|
6238
|
-
ignoreInitial: true,
|
|
6239
|
-
awaitWriteFinish: { stabilityThreshold: 200, pollInterval: 50 }
|
|
6240
|
-
});
|
|
6241
|
-
watcher.on("all", (event, changedPath) => {
|
|
6242
|
-
if (resolve10(changedPath) !== configPath) {
|
|
6243
|
-
return;
|
|
6244
|
-
}
|
|
6245
|
-
if (event === "add") {
|
|
6246
|
-
reloader.scheduleReload("config add");
|
|
6247
|
-
return;
|
|
6248
|
-
}
|
|
6249
|
-
if (event === "change") {
|
|
6250
|
-
reloader.scheduleReload("config change");
|
|
6251
|
-
return;
|
|
6252
|
-
}
|
|
6253
|
-
if (event === "unlink") {
|
|
6254
|
-
reloader.scheduleReload("config unlink");
|
|
6255
|
-
}
|
|
6256
|
-
});
|
|
6516
|
+
this.watchConfigFile(reloader);
|
|
6257
6517
|
await cron2.start();
|
|
6258
6518
|
await heartbeat.start();
|
|
6259
6519
|
try {
|
|
@@ -6280,6 +6540,29 @@ var ServiceCommands = class {
|
|
|
6280
6540
|
const trimmed = value.trim();
|
|
6281
6541
|
return trimmed || void 0;
|
|
6282
6542
|
}
|
|
6543
|
+
watchConfigFile(reloader) {
|
|
6544
|
+
const configPath = resolve10(getConfigPath3());
|
|
6545
|
+
const watcher = chokidar.watch(configPath, {
|
|
6546
|
+
ignoreInitial: true,
|
|
6547
|
+
awaitWriteFinish: { stabilityThreshold: 200, pollInterval: 50 }
|
|
6548
|
+
});
|
|
6549
|
+
watcher.on("all", (event, changedPath) => {
|
|
6550
|
+
if (resolve10(changedPath) !== configPath) {
|
|
6551
|
+
return;
|
|
6552
|
+
}
|
|
6553
|
+
if (event === "add") {
|
|
6554
|
+
reloader.scheduleReload("config add");
|
|
6555
|
+
return;
|
|
6556
|
+
}
|
|
6557
|
+
if (event === "change") {
|
|
6558
|
+
reloader.scheduleReload("config change");
|
|
6559
|
+
return;
|
|
6560
|
+
}
|
|
6561
|
+
if (event === "unlink") {
|
|
6562
|
+
reloader.scheduleReload("config unlink");
|
|
6563
|
+
}
|
|
6564
|
+
});
|
|
6565
|
+
}
|
|
6283
6566
|
resolveMostRecentRoutableSessionKey(sessionManager) {
|
|
6284
6567
|
const sessions = sessionManager.listSessions();
|
|
6285
6568
|
let best = null;
|
|
@@ -6379,7 +6662,7 @@ var ServiceCommands = class {
|
|
|
6379
6662
|
});
|
|
6380
6663
|
}
|
|
6381
6664
|
async runForeground(options) {
|
|
6382
|
-
const config2 =
|
|
6665
|
+
const config2 = loadConfig8();
|
|
6383
6666
|
const uiConfig = resolveUiConfig(config2, options.uiOverrides);
|
|
6384
6667
|
const uiUrl = resolveUiApiBase(uiConfig.host, uiConfig.port);
|
|
6385
6668
|
if (options.open) {
|
|
@@ -6392,7 +6675,7 @@ var ServiceCommands = class {
|
|
|
6392
6675
|
});
|
|
6393
6676
|
}
|
|
6394
6677
|
async startService(options) {
|
|
6395
|
-
const config2 =
|
|
6678
|
+
const config2 = loadConfig8();
|
|
6396
6679
|
const uiConfig = resolveUiConfig(config2, options.uiOverrides);
|
|
6397
6680
|
const uiUrl = resolveUiApiBase(uiConfig.host, uiConfig.port);
|
|
6398
6681
|
const apiUrl = `${uiUrl}/api`;
|
|
@@ -7038,7 +7321,7 @@ var ServiceCommands = class {
|
|
|
7038
7321
|
if (params.kind && params.kind !== "marketplace") {
|
|
7039
7322
|
throw new Error(`Unsupported marketplace skill kind: ${params.kind}`);
|
|
7040
7323
|
}
|
|
7041
|
-
const workspace = getWorkspacePath8(
|
|
7324
|
+
const workspace = getWorkspacePath8(loadConfig8().agents.defaults.workspace);
|
|
7042
7325
|
const args = buildMarketplaceSkillInstallArgs({
|
|
7043
7326
|
slug: params.slug,
|
|
7044
7327
|
workspace,
|
|
@@ -7074,7 +7357,7 @@ var ServiceCommands = class {
|
|
|
7074
7357
|
return { message: result.message };
|
|
7075
7358
|
}
|
|
7076
7359
|
async uninstallMarketplaceSkill(slug) {
|
|
7077
|
-
const workspace = getWorkspacePath8(
|
|
7360
|
+
const workspace = getWorkspacePath8(loadConfig8().agents.defaults.workspace);
|
|
7078
7361
|
const targetDir = join5(workspace, "skills", slug);
|
|
7079
7362
|
if (!existsSync9(targetDir)) {
|
|
7080
7363
|
throw new Error(`Skill not installed in workspace: ${slug}`);
|
|
@@ -7085,7 +7368,7 @@ var ServiceCommands = class {
|
|
|
7085
7368
|
};
|
|
7086
7369
|
}
|
|
7087
7370
|
installBuiltinMarketplaceSkill(slug, force) {
|
|
7088
|
-
const workspace = getWorkspacePath8(
|
|
7371
|
+
const workspace = getWorkspacePath8(loadConfig8().agents.defaults.workspace);
|
|
7089
7372
|
const destination = join5(workspace, "skills", slug);
|
|
7090
7373
|
const destinationSkillFile = join5(destination, "SKILL.md");
|
|
7091
7374
|
if (existsSync9(destinationSkillFile) && !force) {
|
|
@@ -7359,6 +7642,7 @@ var CliRuntime = class {
|
|
|
7359
7642
|
workspaceManager;
|
|
7360
7643
|
serviceCommands;
|
|
7361
7644
|
configCommands;
|
|
7645
|
+
mcpCommands;
|
|
7362
7646
|
secretsCommands;
|
|
7363
7647
|
pluginCommands;
|
|
7364
7648
|
channelCommands;
|
|
@@ -7373,6 +7657,7 @@ var CliRuntime = class {
|
|
|
7373
7657
|
this.configCommands = new ConfigCommands({
|
|
7374
7658
|
requestRestart: (params) => this.requestRestart(params)
|
|
7375
7659
|
});
|
|
7660
|
+
this.mcpCommands = new McpCommands();
|
|
7376
7661
|
this.secretsCommands = new SecretsCommands({
|
|
7377
7662
|
requestRestart: (params) => this.requestRestart(params)
|
|
7378
7663
|
});
|
|
@@ -7580,10 +7865,10 @@ var CliRuntime = class {
|
|
|
7580
7865
|
let createdConfig = false;
|
|
7581
7866
|
if (!existsSync11(configPath)) {
|
|
7582
7867
|
const config3 = ConfigSchema2.parse({});
|
|
7583
|
-
|
|
7868
|
+
saveConfig7(config3);
|
|
7584
7869
|
createdConfig = true;
|
|
7585
7870
|
}
|
|
7586
|
-
const config2 =
|
|
7871
|
+
const config2 = loadConfig9();
|
|
7587
7872
|
const workspaceSetting = config2.agents.defaults.workspace;
|
|
7588
7873
|
const workspacePath = !workspaceSetting || workspaceSetting === DEFAULT_WORKSPACE_PATH ? join7(getDataDir8(), DEFAULT_WORKSPACE_DIR) : expandHome2(workspaceSetting);
|
|
7589
7874
|
const workspaceExisted = existsSync11(workspacePath);
|
|
@@ -7619,7 +7904,7 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
7619
7904
|
async login(opts = {}) {
|
|
7620
7905
|
await this.init({ source: "login", auto: true });
|
|
7621
7906
|
const configPath = getConfigPath4();
|
|
7622
|
-
const config2 =
|
|
7907
|
+
const config2 = loadConfig9(configPath);
|
|
7623
7908
|
const providers = config2.providers;
|
|
7624
7909
|
const nextclawProvider = providers.nextclaw ?? {
|
|
7625
7910
|
displayName: "",
|
|
@@ -7681,7 +7966,7 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
7681
7966
|
nextclawProvider.apiBase = v1Base;
|
|
7682
7967
|
nextclawProvider.apiKey = token;
|
|
7683
7968
|
providers.nextclaw = nextclawProvider;
|
|
7684
|
-
|
|
7969
|
+
saveConfig7(config2, configPath);
|
|
7685
7970
|
console.log(`\u2713 Logged in to NextClaw platform (${platformBase})`);
|
|
7686
7971
|
console.log(`\u2713 Account: ${email} (${role})`);
|
|
7687
7972
|
console.log(`\u2713 Token saved into providers.nextclaw.apiKey`);
|
|
@@ -7776,7 +8061,7 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
7776
8061
|
}
|
|
7777
8062
|
async agent(opts) {
|
|
7778
8063
|
const configPath = getConfigPath4();
|
|
7779
|
-
const config2 = resolveConfigSecrets3(
|
|
8064
|
+
const config2 = resolveConfigSecrets3(loadConfig9(), { configPath });
|
|
7780
8065
|
const workspace = getWorkspacePath9(config2.agents.defaults.workspace);
|
|
7781
8066
|
const pluginRegistry = loadPluginRegistry(config2, workspace);
|
|
7782
8067
|
const extensionRegistry = toExtensionRegistry(pluginRegistry);
|
|
@@ -7784,7 +8069,7 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
7784
8069
|
const pluginChannelBindings = getPluginChannelBindings4(pluginRegistry);
|
|
7785
8070
|
setPluginRuntimeBridge2({
|
|
7786
8071
|
loadConfig: () => toPluginConfigView(
|
|
7787
|
-
resolveConfigSecrets3(
|
|
8072
|
+
resolveConfigSecrets3(loadConfig9(), { configPath }),
|
|
7788
8073
|
pluginChannelBindings
|
|
7789
8074
|
),
|
|
7790
8075
|
writeConfigFile: async (nextConfigView) => {
|
|
@@ -7793,13 +8078,13 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
7793
8078
|
"plugin runtime writeConfigFile expects an object config"
|
|
7794
8079
|
);
|
|
7795
8080
|
}
|
|
7796
|
-
const current =
|
|
8081
|
+
const current = loadConfig9();
|
|
7797
8082
|
const next = mergePluginConfigView(
|
|
7798
8083
|
current,
|
|
7799
8084
|
nextConfigView,
|
|
7800
8085
|
pluginChannelBindings
|
|
7801
8086
|
);
|
|
7802
|
-
|
|
8087
|
+
saveConfig7(next);
|
|
7803
8088
|
}
|
|
7804
8089
|
});
|
|
7805
8090
|
try {
|
|
@@ -7825,7 +8110,7 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
7825
8110
|
resolveMessageToolHints: ({ channel, accountId }) => resolvePluginChannelMessageToolHints2({
|
|
7826
8111
|
registry: pluginRegistry,
|
|
7827
8112
|
channel,
|
|
7828
|
-
cfg: resolveConfigSecrets3(
|
|
8113
|
+
cfg: resolveConfigSecrets3(loadConfig9(), { configPath }),
|
|
7829
8114
|
accountId
|
|
7830
8115
|
})
|
|
7831
8116
|
});
|
|
@@ -7959,6 +8244,24 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
7959
8244
|
async configUnset(pathExpr) {
|
|
7960
8245
|
await this.configCommands.configUnset(pathExpr);
|
|
7961
8246
|
}
|
|
8247
|
+
mcpList(opts = {}) {
|
|
8248
|
+
this.mcpCommands.mcpList(opts);
|
|
8249
|
+
}
|
|
8250
|
+
async mcpAdd(name, command, opts = {}) {
|
|
8251
|
+
await this.mcpCommands.mcpAdd(name, command, opts);
|
|
8252
|
+
}
|
|
8253
|
+
async mcpRemove(name) {
|
|
8254
|
+
await this.mcpCommands.mcpRemove(name);
|
|
8255
|
+
}
|
|
8256
|
+
async mcpEnable(name) {
|
|
8257
|
+
await this.mcpCommands.mcpEnable(name);
|
|
8258
|
+
}
|
|
8259
|
+
async mcpDisable(name) {
|
|
8260
|
+
await this.mcpCommands.mcpDisable(name);
|
|
8261
|
+
}
|
|
8262
|
+
async mcpDoctor(name, opts = {}) {
|
|
8263
|
+
await this.mcpCommands.mcpDoctor(name, opts);
|
|
8264
|
+
}
|
|
7962
8265
|
secretsAudit(opts = {}) {
|
|
7963
8266
|
this.secretsCommands.secretsAudit(opts);
|
|
7964
8267
|
}
|
|
@@ -8002,7 +8305,7 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
8002
8305
|
await this.diagnosticsCommands.doctor(opts);
|
|
8003
8306
|
}
|
|
8004
8307
|
async skillsInstall(options) {
|
|
8005
|
-
const config2 =
|
|
8308
|
+
const config2 = loadConfig9();
|
|
8006
8309
|
const workdir = resolveSkillsInstallWorkdir({
|
|
8007
8310
|
explicitWorkdir: options.workdir,
|
|
8008
8311
|
configuredWorkspace: config2.agents.defaults.workspace
|
|
@@ -8095,6 +8398,13 @@ var config = program.command("config").description("Manage config values");
|
|
|
8095
8398
|
config.command("get <path>").description("Get a config value by dot path").option("--json", "Output JSON", false).action((path2, opts) => runtime.configGet(path2, opts));
|
|
8096
8399
|
config.command("set <path> <value>").description("Set a config value by dot path").option("--json", "Parse value as JSON", false).action((path2, value, opts) => runtime.configSet(path2, value, opts));
|
|
8097
8400
|
config.command("unset <path>").description("Remove a config value by dot path").action((path2) => runtime.configUnset(path2));
|
|
8401
|
+
var mcp = program.command("mcp").description("Manage MCP servers");
|
|
8402
|
+
mcp.command("list").description("List configured MCP servers").option("--json", "Output JSON", false).action((opts) => runtime.mcpList(opts));
|
|
8403
|
+
mcp.command("add <name> [command...]").description("Add an MCP server (stdio by default, or use --transport http|sse)").allowUnknownOption(true).option("--transport <type>", "Transport type: stdio|http|sse", "stdio").option("--url <url>", "HTTP/SSE endpoint URL").option("--header <key=value>", "Transport header (repeatable)", withRepeatableTag, []).option("--env <key=value>", "stdio env var (repeatable)", withRepeatableTag, []).option("--cwd <dir>", "stdio working directory").option("--timeout-ms <ms>", "HTTP/SSE timeout in milliseconds").option("--stderr <mode>", "stdio stderr handling: inherit|pipe|ignore", "pipe").option("--disabled", "Create the server in disabled state", false).option("--all-agents", "Expose this server to all agents", false).option("--agent <id>", "Expose to an agent id (repeatable)", withRepeatableTag, []).option("--insecure", "Disable TLS verification for HTTP/SSE", false).action(async (name, command, opts) => runtime.mcpAdd(name, command ?? [], opts));
|
|
8404
|
+
mcp.command("remove <name>").description("Remove an MCP server").action(async (name) => runtime.mcpRemove(name));
|
|
8405
|
+
mcp.command("enable <name>").description("Enable an MCP server").action(async (name) => runtime.mcpEnable(name));
|
|
8406
|
+
mcp.command("disable <name>").description("Disable an MCP server").action(async (name) => runtime.mcpDisable(name));
|
|
8407
|
+
mcp.command("doctor [name]").description("Check MCP server connectivity and tool discovery").option("--json", "Output JSON", false).action(async (name, opts) => runtime.mcpDoctor(name, opts));
|
|
8098
8408
|
var secrets = program.command("secrets").description("Manage secrets refs/providers");
|
|
8099
8409
|
secrets.command("audit").description("Audit secret refs resolution status").option("--json", "Output JSON", false).option("--strict", "Exit non-zero when unresolved refs exist", false).action((opts) => runtime.secretsAudit(opts));
|
|
8100
8410
|
secrets.command("configure").description("Configure a secret provider alias").requiredOption("--provider <alias>", "Provider alias").option("--source <source>", "Provider source (env|file|exec)").option("--prefix <prefix>", "Env key prefix (env source)").option("--path <path>", "Secret JSON file path (file source)").option("--command <command>", "Command for exec source").option(
|