nextclaw 0.13.1 → 0.13.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 +622 -243
- package/package.json +8 -8
- package/templates/USAGE.md +9 -0
- package/ui-dist/assets/{ChannelsList-i00X_bon.js → ChannelsList-DH1Ur9XW.js} +1 -1
- package/ui-dist/assets/ChatPage-YTDcN7XS.js +38 -0
- package/ui-dist/assets/{DocBrowser-DhSfSjNp.js → DocBrowser-Bi-RpLIw.js} +1 -1
- package/ui-dist/assets/{LogoBadge-E8XCymGk.js → LogoBadge-BCR9CU7n.js} +1 -1
- package/ui-dist/assets/{MarketplacePage-DSa7G0ro.js → MarketplacePage-BgCdiku7.js} +1 -1
- package/ui-dist/assets/{McpMarketplacePage-bDGyqSad.js → McpMarketplacePage-nyCbiQH6.js} +1 -1
- package/ui-dist/assets/{ModelConfig-Dvsyt1Tg.js → ModelConfig-Cf4AAYaB.js} +1 -1
- package/ui-dist/assets/{ProvidersList-DMbXOYsb.js → ProvidersList-CfkfKQbw.js} +1 -1
- package/ui-dist/assets/{RuntimeConfig-ToBbIBNn.js → RuntimeConfig-BI-zClCl.js} +1 -1
- package/ui-dist/assets/{SearchConfig-BV_SO-L3.js → SearchConfig-MBmvco1J.js} +1 -1
- package/ui-dist/assets/{SecretsConfig-D5J_q_Za.js → SecretsConfig-CC2B6pVQ.js} +1 -1
- package/ui-dist/assets/{SessionsConfig-B8gi8Vbi.js → SessionsConfig-CTxJeVQs.js} +1 -1
- package/ui-dist/assets/{chat-message-v-cXhn7X.js → chat-message-5OiyZViy.js} +1 -1
- package/ui-dist/assets/index-C2OKcVdN.css +1 -0
- package/ui-dist/assets/{index-BXJPYlRo.js → index-LgjZxLjc.js} +2 -2
- package/ui-dist/assets/{label-352ph_Yg.js → label-CPdcDrir.js} +1 -1
- package/ui-dist/assets/{page-layout-BwIR7lB8.js → page-layout-B8V5_vM_.js} +1 -1
- package/ui-dist/assets/{popover-BdOI7aUv.js → popover-Bk53A74_.js} +1 -1
- package/ui-dist/assets/{security-config-BEhAoZux.js → security-config-BNjgoyo4.js} +1 -1
- package/ui-dist/assets/{skeleton-C3DLX_PO.js → skeleton-NPxxR-L0.js} +1 -1
- package/ui-dist/assets/{switch-CgUsIol7.js → switch-EowdzMK2.js} +1 -1
- package/ui-dist/assets/{tabs-custom-Dc_3h5fO.js → tabs-custom-BjLv-uCT.js} +1 -1
- package/ui-dist/assets/{useConfirmDialog-DSrny346.js → useConfirmDialog-TJcJQMfu.js} +1 -1
- package/ui-dist/index.html +2 -2
- package/ui-dist/assets/ChatPage-BEkVUTgU.js +0 -38
- package/ui-dist/assets/index-BoDFsNXm.css +0 -1
package/dist/cli/index.js
CHANGED
|
@@ -6,10 +6,10 @@ 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 loadConfig13,
|
|
10
|
+
saveConfig as saveConfig9,
|
|
11
|
+
getConfigPath as getConfigPath6,
|
|
12
|
+
getDataDir as getDataDir9,
|
|
13
13
|
ConfigSchema as ConfigSchema2,
|
|
14
14
|
getWorkspacePath as getWorkspacePath10,
|
|
15
15
|
expandHome as expandHome2,
|
|
@@ -26,9 +26,9 @@ 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
|
|
31
|
-
import { createInterface 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
|
+
import { createInterface as createInterface3 } from "readline";
|
|
32
32
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
33
33
|
import { spawn as spawn3 } from "child_process";
|
|
34
34
|
|
|
@@ -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}).`
|
|
@@ -1440,27 +1440,7 @@ async function installPluginMutation(pathOrSpec, opts = {}) {
|
|
|
1440
1440
|
};
|
|
1441
1441
|
}
|
|
1442
1442
|
|
|
1443
|
-
// src/cli/commands/
|
|
1444
|
-
function loadPluginRegistry(config2, workspaceDir) {
|
|
1445
|
-
const workspaceExtensionsDir = process.env.NEXTCLAW_DEV_FIRST_PARTY_PLUGIN_DIR;
|
|
1446
|
-
const configWithDevPluginPaths = applyDevFirstPartyPluginLoadPaths(
|
|
1447
|
-
config2,
|
|
1448
|
-
workspaceExtensionsDir
|
|
1449
|
-
);
|
|
1450
|
-
const excludedRoots = resolveDevFirstPartyPluginInstallRoots(config2, workspaceExtensionsDir);
|
|
1451
|
-
return loadOpenClawPlugins({
|
|
1452
|
-
config: configWithDevPluginPaths,
|
|
1453
|
-
workspaceDir,
|
|
1454
|
-
excludeRoots: excludedRoots,
|
|
1455
|
-
...buildReservedPluginLoadOptions(),
|
|
1456
|
-
logger: {
|
|
1457
|
-
info: (message) => console.log(message),
|
|
1458
|
-
warn: (message) => console.warn(message),
|
|
1459
|
-
error: (message) => console.error(message),
|
|
1460
|
-
debug: (message) => console.debug(message)
|
|
1461
|
-
}
|
|
1462
|
-
});
|
|
1463
|
-
}
|
|
1443
|
+
// src/cli/commands/plugin-extension-registry.ts
|
|
1464
1444
|
function toExtensionRegistry(pluginRegistry) {
|
|
1465
1445
|
return {
|
|
1466
1446
|
tools: pluginRegistry.tools.map((tool) => ({
|
|
@@ -1486,6 +1466,7 @@ function toExtensionRegistry(pluginRegistry) {
|
|
|
1486
1466
|
kind: runtime2.kind,
|
|
1487
1467
|
label: runtime2.label,
|
|
1488
1468
|
createRuntime: runtime2.createRuntime,
|
|
1469
|
+
describeSessionType: runtime2.describeSessionType,
|
|
1489
1470
|
source: runtime2.source
|
|
1490
1471
|
})),
|
|
1491
1472
|
diagnostics: pluginRegistry.diagnostics.map((diag) => ({
|
|
@@ -1496,6 +1477,28 @@ function toExtensionRegistry(pluginRegistry) {
|
|
|
1496
1477
|
}))
|
|
1497
1478
|
};
|
|
1498
1479
|
}
|
|
1480
|
+
|
|
1481
|
+
// src/cli/commands/plugins.ts
|
|
1482
|
+
function loadPluginRegistry(config2, workspaceDir) {
|
|
1483
|
+
const workspaceExtensionsDir = process.env.NEXTCLAW_DEV_FIRST_PARTY_PLUGIN_DIR;
|
|
1484
|
+
const configWithDevPluginPaths = applyDevFirstPartyPluginLoadPaths(
|
|
1485
|
+
config2,
|
|
1486
|
+
workspaceExtensionsDir
|
|
1487
|
+
);
|
|
1488
|
+
const excludedRoots = resolveDevFirstPartyPluginInstallRoots(config2, workspaceExtensionsDir);
|
|
1489
|
+
return loadOpenClawPlugins({
|
|
1490
|
+
config: configWithDevPluginPaths,
|
|
1491
|
+
workspaceDir,
|
|
1492
|
+
excludeRoots: excludedRoots,
|
|
1493
|
+
...buildReservedPluginLoadOptions(),
|
|
1494
|
+
logger: {
|
|
1495
|
+
info: (message) => console.log(message),
|
|
1496
|
+
warn: (message) => console.warn(message),
|
|
1497
|
+
error: (message) => console.error(message),
|
|
1498
|
+
debug: (message) => console.debug(message)
|
|
1499
|
+
}
|
|
1500
|
+
});
|
|
1501
|
+
}
|
|
1499
1502
|
function logPluginDiagnostics(registry) {
|
|
1500
1503
|
for (const diag of registry.diagnostics) {
|
|
1501
1504
|
const prefix = diag.pluginId ? `${diag.pluginId}: ` : "";
|
|
@@ -2858,17 +2861,438 @@ var CronCommands = class {
|
|
|
2858
2861
|
}
|
|
2859
2862
|
};
|
|
2860
2863
|
|
|
2864
|
+
// src/cli/commands/platform-auth.ts
|
|
2865
|
+
import { getConfigPath as getConfigPath2, loadConfig as loadConfig7, saveConfig as saveConfig6 } from "@nextclaw/core";
|
|
2866
|
+
import { createInterface as createInterface2 } from "readline";
|
|
2867
|
+
|
|
2868
|
+
// src/cli/commands/platform-api-base.ts
|
|
2869
|
+
var DEFAULT_PLATFORM_API_BASE = "https://ai-gateway-api.nextclaw.io/v1";
|
|
2870
|
+
var INVALID_PLATFORM_HINT = `Use ${DEFAULT_PLATFORM_API_BASE} or the platform root URL without a trailing path.`;
|
|
2871
|
+
function trimTrailingSlash(value) {
|
|
2872
|
+
return value.replace(/\/+$/, "");
|
|
2873
|
+
}
|
|
2874
|
+
function normalizeExplicitApiBase(rawApiBase) {
|
|
2875
|
+
const trimmed = trimTrailingSlash(rawApiBase.trim());
|
|
2876
|
+
if (!trimmed) {
|
|
2877
|
+
return "";
|
|
2878
|
+
}
|
|
2879
|
+
return trimmed.replace(/\/v1?$/i, "");
|
|
2880
|
+
}
|
|
2881
|
+
function resolvePlatformApiBase(params) {
|
|
2882
|
+
const explicitApiBase = typeof params.explicitApiBase === "string" ? params.explicitApiBase.trim() : "";
|
|
2883
|
+
const configuredApiBase = typeof params.configuredApiBase === "string" ? params.configuredApiBase.trim() : "";
|
|
2884
|
+
const fallbackApiBase = params.fallbackApiBase ?? DEFAULT_PLATFORM_API_BASE;
|
|
2885
|
+
const inputApiBase = explicitApiBase || configuredApiBase || (params.requireConfigured ? "" : fallbackApiBase);
|
|
2886
|
+
if (!inputApiBase) {
|
|
2887
|
+
throw new Error("Platform API base is missing. Pass --api-base or run nextclaw login.");
|
|
2888
|
+
}
|
|
2889
|
+
const platformBase = normalizeExplicitApiBase(inputApiBase);
|
|
2890
|
+
if (!platformBase) {
|
|
2891
|
+
throw new Error(`Invalid --api-base "${inputApiBase}". ${INVALID_PLATFORM_HINT}`);
|
|
2892
|
+
}
|
|
2893
|
+
let parsedUrl;
|
|
2894
|
+
try {
|
|
2895
|
+
parsedUrl = new URL(platformBase);
|
|
2896
|
+
} catch {
|
|
2897
|
+
throw new Error(`Invalid --api-base "${inputApiBase}". ${INVALID_PLATFORM_HINT}`);
|
|
2898
|
+
}
|
|
2899
|
+
if (parsedUrl.pathname !== "" && parsedUrl.pathname !== "/") {
|
|
2900
|
+
throw new Error(`Invalid --api-base "${inputApiBase}". ${INVALID_PLATFORM_HINT}`);
|
|
2901
|
+
}
|
|
2902
|
+
const normalizedPlatformBase = trimTrailingSlash(parsedUrl.toString());
|
|
2903
|
+
return {
|
|
2904
|
+
platformBase: normalizedPlatformBase,
|
|
2905
|
+
v1Base: `${normalizedPlatformBase}/v1`,
|
|
2906
|
+
inputApiBase
|
|
2907
|
+
};
|
|
2908
|
+
}
|
|
2909
|
+
function buildPlatformApiBaseErrorMessage(inputApiBase, rawMessage) {
|
|
2910
|
+
if (rawMessage.includes("Remote session cookie missing") || rawMessage.includes("endpoint not found") || rawMessage.includes("NOT_FOUND")) {
|
|
2911
|
+
return `Invalid --api-base "${inputApiBase}". ${INVALID_PLATFORM_HINT}`;
|
|
2912
|
+
}
|
|
2913
|
+
return rawMessage;
|
|
2914
|
+
}
|
|
2915
|
+
|
|
2916
|
+
// src/cli/commands/platform-auth.ts
|
|
2917
|
+
function resolveProviderConfig(opts) {
|
|
2918
|
+
const configPath = getConfigPath2();
|
|
2919
|
+
const config2 = loadConfig7(configPath);
|
|
2920
|
+
const providers = config2.providers;
|
|
2921
|
+
const nextclawProvider = providers.nextclaw ?? {
|
|
2922
|
+
displayName: "",
|
|
2923
|
+
apiKey: "",
|
|
2924
|
+
apiBase: null,
|
|
2925
|
+
extraHeaders: null,
|
|
2926
|
+
wireApi: "auto",
|
|
2927
|
+
models: []
|
|
2928
|
+
};
|
|
2929
|
+
const configuredApiBase = typeof nextclawProvider.apiBase === "string" && nextclawProvider.apiBase.trim().length > 0 ? nextclawProvider.apiBase.trim() : "https://ai-gateway-api.nextclaw.io/v1";
|
|
2930
|
+
const requestedApiBase = typeof opts.apiBase === "string" && opts.apiBase.trim().length > 0 ? opts.apiBase.trim() : configuredApiBase;
|
|
2931
|
+
const { platformBase, v1Base, inputApiBase } = resolvePlatformApiBase({
|
|
2932
|
+
explicitApiBase: requestedApiBase,
|
|
2933
|
+
fallbackApiBase: "https://ai-gateway-api.nextclaw.io/v1"
|
|
2934
|
+
});
|
|
2935
|
+
return {
|
|
2936
|
+
configPath,
|
|
2937
|
+
config: config2,
|
|
2938
|
+
providers,
|
|
2939
|
+
nextclawProvider,
|
|
2940
|
+
platformBase,
|
|
2941
|
+
v1Base,
|
|
2942
|
+
inputApiBase
|
|
2943
|
+
};
|
|
2944
|
+
}
|
|
2945
|
+
async function resolveCredentials(opts) {
|
|
2946
|
+
let email = typeof opts.email === "string" ? opts.email.trim() : "";
|
|
2947
|
+
let password = typeof opts.password === "string" ? opts.password : "";
|
|
2948
|
+
if (email && password) {
|
|
2949
|
+
return { email, password };
|
|
2950
|
+
}
|
|
2951
|
+
const rl = createInterface2({
|
|
2952
|
+
input: process.stdin,
|
|
2953
|
+
output: process.stdout
|
|
2954
|
+
});
|
|
2955
|
+
try {
|
|
2956
|
+
if (!email) {
|
|
2957
|
+
email = (await prompt(rl, "Email: ")).trim();
|
|
2958
|
+
}
|
|
2959
|
+
if (!password) {
|
|
2960
|
+
password = await prompt(rl, "Password: ");
|
|
2961
|
+
}
|
|
2962
|
+
} finally {
|
|
2963
|
+
rl.close();
|
|
2964
|
+
}
|
|
2965
|
+
if (!email || !password) {
|
|
2966
|
+
throw new Error("Email and password are required.");
|
|
2967
|
+
}
|
|
2968
|
+
return { email, password };
|
|
2969
|
+
}
|
|
2970
|
+
function readLoginPayload(raw) {
|
|
2971
|
+
let parsed = null;
|
|
2972
|
+
try {
|
|
2973
|
+
parsed = JSON.parse(raw);
|
|
2974
|
+
} catch {
|
|
2975
|
+
parsed = null;
|
|
2976
|
+
}
|
|
2977
|
+
const token = typeof parsed === "object" && parsed && "data" in parsed && typeof parsed.data?.token === "string" ? parsed.data.token : "";
|
|
2978
|
+
const role = typeof parsed === "object" && parsed && "data" in parsed && typeof parsed.data?.user?.role === "string" ? parsed.data.user.role : "user";
|
|
2979
|
+
if (!token) {
|
|
2980
|
+
throw new Error("Login succeeded but token is missing.");
|
|
2981
|
+
}
|
|
2982
|
+
return { token, role };
|
|
2983
|
+
}
|
|
2984
|
+
var PlatformAuthCommands = class {
|
|
2985
|
+
async login(opts = {}) {
|
|
2986
|
+
const { configPath, config: config2, providers, nextclawProvider, platformBase, v1Base, inputApiBase } = resolveProviderConfig(opts);
|
|
2987
|
+
const { email, password } = await resolveCredentials(opts);
|
|
2988
|
+
const endpoint = opts.register ? `${platformBase}/platform/auth/register` : `${platformBase}/platform/auth/login`;
|
|
2989
|
+
const response = await fetch(endpoint, {
|
|
2990
|
+
method: "POST",
|
|
2991
|
+
headers: {
|
|
2992
|
+
"Content-Type": "application/json"
|
|
2993
|
+
},
|
|
2994
|
+
body: JSON.stringify({ email, password })
|
|
2995
|
+
});
|
|
2996
|
+
const raw = await response.text();
|
|
2997
|
+
if (!response.ok) {
|
|
2998
|
+
let parsed = null;
|
|
2999
|
+
try {
|
|
3000
|
+
parsed = JSON.parse(raw);
|
|
3001
|
+
} catch {
|
|
3002
|
+
parsed = null;
|
|
3003
|
+
}
|
|
3004
|
+
const maybeMessage = typeof parsed === "object" && parsed && "error" in parsed && typeof parsed.error?.message === "string" ? parsed.error.message : raw || `Request failed (${response.status})`;
|
|
3005
|
+
throw new Error(buildPlatformApiBaseErrorMessage(inputApiBase, maybeMessage));
|
|
3006
|
+
}
|
|
3007
|
+
const { token, role } = readLoginPayload(raw);
|
|
3008
|
+
nextclawProvider.apiBase = v1Base;
|
|
3009
|
+
nextclawProvider.apiKey = token;
|
|
3010
|
+
providers.nextclaw = nextclawProvider;
|
|
3011
|
+
saveConfig6(config2, configPath);
|
|
3012
|
+
console.log(`\u2713 Logged in to NextClaw platform (${platformBase})`);
|
|
3013
|
+
console.log(`\u2713 Account: ${email} (${role})`);
|
|
3014
|
+
console.log(`\u2713 Token saved into providers.nextclaw.apiKey`);
|
|
3015
|
+
}
|
|
3016
|
+
};
|
|
3017
|
+
|
|
3018
|
+
// src/cli/commands/remote.ts
|
|
3019
|
+
import { getConfigPath as getConfigPath3, getDataDir as getDataDir4, loadConfig as loadConfig8 } from "@nextclaw/core";
|
|
3020
|
+
import { ensureUiBridgeSecret } from "@nextclaw/server";
|
|
3021
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
3022
|
+
import { dirname as dirname2, join as join4 } from "path";
|
|
3023
|
+
import { hostname, platform as readPlatform } from "os";
|
|
3024
|
+
function encodeBase64(bytes) {
|
|
3025
|
+
return Buffer.from(bytes).toString("base64");
|
|
3026
|
+
}
|
|
3027
|
+
function decodeBase64(base64) {
|
|
3028
|
+
if (!base64) {
|
|
3029
|
+
return new Uint8Array();
|
|
3030
|
+
}
|
|
3031
|
+
return new Uint8Array(Buffer.from(base64, "base64"));
|
|
3032
|
+
}
|
|
3033
|
+
function delay(ms) {
|
|
3034
|
+
return new Promise((resolveDelay) => setTimeout(resolveDelay, ms));
|
|
3035
|
+
}
|
|
3036
|
+
function ensureDir(path2) {
|
|
3037
|
+
mkdirSync4(path2, { recursive: true });
|
|
3038
|
+
}
|
|
3039
|
+
function readJsonFile2(path2) {
|
|
3040
|
+
if (!existsSync6(path2)) {
|
|
3041
|
+
return null;
|
|
3042
|
+
}
|
|
3043
|
+
try {
|
|
3044
|
+
return JSON.parse(readFileSync6(path2, "utf-8"));
|
|
3045
|
+
} catch {
|
|
3046
|
+
return null;
|
|
3047
|
+
}
|
|
3048
|
+
}
|
|
3049
|
+
function writeJsonFile(path2, value) {
|
|
3050
|
+
ensureDir(dirname2(path2));
|
|
3051
|
+
writeFileSync4(path2, `${JSON.stringify(value, null, 2)}
|
|
3052
|
+
`, "utf-8");
|
|
3053
|
+
}
|
|
3054
|
+
var RemoteCommands = class {
|
|
3055
|
+
remoteDir = join4(getDataDir4(), "remote");
|
|
3056
|
+
devicePath = join4(this.remoteDir, "device.json");
|
|
3057
|
+
ensureDeviceInstallId() {
|
|
3058
|
+
const existing = readJsonFile2(this.devicePath);
|
|
3059
|
+
if (existing?.deviceInstallId?.trim()) {
|
|
3060
|
+
return existing.deviceInstallId.trim();
|
|
3061
|
+
}
|
|
3062
|
+
const deviceInstallId = crypto.randomUUID();
|
|
3063
|
+
ensureDir(this.remoteDir);
|
|
3064
|
+
writeJsonFile(this.devicePath, { deviceInstallId });
|
|
3065
|
+
return deviceInstallId;
|
|
3066
|
+
}
|
|
3067
|
+
resolvePlatformAccess(opts) {
|
|
3068
|
+
const config2 = loadConfig8(getConfigPath3());
|
|
3069
|
+
const providers = config2.providers;
|
|
3070
|
+
const nextclawProvider = providers.nextclaw;
|
|
3071
|
+
const token = typeof nextclawProvider?.apiKey === "string" ? nextclawProvider.apiKey.trim() : "";
|
|
3072
|
+
if (!token) {
|
|
3073
|
+
throw new Error('NextClaw platform token is missing. Run "nextclaw login" first.');
|
|
3074
|
+
}
|
|
3075
|
+
const configuredApiBase = typeof nextclawProvider?.apiBase === "string" ? nextclawProvider.apiBase.trim() : "";
|
|
3076
|
+
const rawApiBase = typeof opts.apiBase === "string" && opts.apiBase.trim().length > 0 ? opts.apiBase.trim() : configuredApiBase;
|
|
3077
|
+
if (!rawApiBase) {
|
|
3078
|
+
throw new Error("Platform API base is missing. Pass --api-base or run nextclaw login.");
|
|
3079
|
+
}
|
|
3080
|
+
const { platformBase } = resolvePlatformApiBase({
|
|
3081
|
+
explicitApiBase: rawApiBase,
|
|
3082
|
+
requireConfigured: true
|
|
3083
|
+
});
|
|
3084
|
+
return { platformBase, token, config: config2 };
|
|
3085
|
+
}
|
|
3086
|
+
resolveLocalOrigin(config2, opts) {
|
|
3087
|
+
if (typeof opts.localOrigin === "string" && opts.localOrigin.trim().length > 0) {
|
|
3088
|
+
return opts.localOrigin.trim().replace(/\/$/, "");
|
|
3089
|
+
}
|
|
3090
|
+
const state = readServiceState();
|
|
3091
|
+
if (state && isProcessRunning(state.pid) && Number.isFinite(state.uiPort)) {
|
|
3092
|
+
return `http://127.0.0.1:${state.uiPort}`;
|
|
3093
|
+
}
|
|
3094
|
+
const configuredPort = typeof config2.ui?.port === "number" && Number.isFinite(config2.ui.port) ? config2.ui.port : 18791;
|
|
3095
|
+
return `http://127.0.0.1:${configuredPort}`;
|
|
3096
|
+
}
|
|
3097
|
+
async ensureLocalUiHealthy(localOrigin) {
|
|
3098
|
+
const response = await fetch(`${localOrigin}/api/health`);
|
|
3099
|
+
if (!response.ok) {
|
|
3100
|
+
throw new Error(`Local UI is not healthy at ${localOrigin}. Start NextClaw first.`);
|
|
3101
|
+
}
|
|
3102
|
+
}
|
|
3103
|
+
async registerDevice(params) {
|
|
3104
|
+
const response = await fetch(`${params.platformBase}/platform/remote/devices/register`, {
|
|
3105
|
+
method: "POST",
|
|
3106
|
+
headers: {
|
|
3107
|
+
"content-type": "application/json",
|
|
3108
|
+
authorization: `Bearer ${params.token}`
|
|
3109
|
+
},
|
|
3110
|
+
body: JSON.stringify({
|
|
3111
|
+
deviceInstallId: params.deviceInstallId,
|
|
3112
|
+
displayName: params.displayName,
|
|
3113
|
+
platform: readPlatform(),
|
|
3114
|
+
appVersion: getPackageVersion(),
|
|
3115
|
+
localOrigin: params.localOrigin
|
|
3116
|
+
})
|
|
3117
|
+
});
|
|
3118
|
+
const payload = await response.json();
|
|
3119
|
+
if (!response.ok || !payload.ok || !payload.data?.device) {
|
|
3120
|
+
throw new Error(payload.error?.message ?? `Failed to register remote device (${response.status}).`);
|
|
3121
|
+
}
|
|
3122
|
+
return payload.data.device;
|
|
3123
|
+
}
|
|
3124
|
+
async requestBridgeCookie(localOrigin) {
|
|
3125
|
+
const response = await fetch(`${localOrigin}/api/auth/bridge`, {
|
|
3126
|
+
method: "POST",
|
|
3127
|
+
headers: {
|
|
3128
|
+
"x-nextclaw-ui-bridge-secret": ensureUiBridgeSecret()
|
|
3129
|
+
}
|
|
3130
|
+
});
|
|
3131
|
+
const payload = await response.json();
|
|
3132
|
+
if (!response.ok || !payload.ok) {
|
|
3133
|
+
throw new Error(payload.error?.message ?? `Failed to request local auth bridge (${response.status}).`);
|
|
3134
|
+
}
|
|
3135
|
+
return typeof payload.data?.cookie === "string" && payload.data.cookie.trim().length > 0 ? payload.data.cookie.trim() : null;
|
|
3136
|
+
}
|
|
3137
|
+
async handleRelayRequest(params) {
|
|
3138
|
+
const bridgeCookie = await this.requestBridgeCookie(params.localOrigin);
|
|
3139
|
+
const url = new URL(params.frame.path, params.localOrigin);
|
|
3140
|
+
const headers = new Headers();
|
|
3141
|
+
for (const [key, value] of params.frame.headers) {
|
|
3142
|
+
const lower = key.toLowerCase();
|
|
3143
|
+
if ([
|
|
3144
|
+
"host",
|
|
3145
|
+
"connection",
|
|
3146
|
+
"content-length",
|
|
3147
|
+
"cookie",
|
|
3148
|
+
"x-forwarded-for",
|
|
3149
|
+
"x-forwarded-proto",
|
|
3150
|
+
"cf-connecting-ip"
|
|
3151
|
+
].includes(lower)) {
|
|
3152
|
+
continue;
|
|
3153
|
+
}
|
|
3154
|
+
headers.set(key, value);
|
|
3155
|
+
}
|
|
3156
|
+
if (bridgeCookie) {
|
|
3157
|
+
headers.set("cookie", bridgeCookie);
|
|
3158
|
+
}
|
|
3159
|
+
const bodyBytes = decodeBase64(params.frame.bodyBase64);
|
|
3160
|
+
const response = await fetch(url, {
|
|
3161
|
+
method: params.frame.method,
|
|
3162
|
+
headers,
|
|
3163
|
+
body: params.frame.method === "GET" || params.frame.method === "HEAD" ? void 0 : bodyBytes
|
|
3164
|
+
});
|
|
3165
|
+
const responseHeaders = Array.from(response.headers.entries()).filter(([key]) => {
|
|
3166
|
+
const lower = key.toLowerCase();
|
|
3167
|
+
return !["content-length", "connection", "transfer-encoding", "set-cookie"].includes(lower);
|
|
3168
|
+
});
|
|
3169
|
+
const contentType = response.headers.get("content-type")?.toLowerCase() ?? "";
|
|
3170
|
+
if (response.body && contentType.startsWith("text/event-stream")) {
|
|
3171
|
+
params.socket.send(JSON.stringify({
|
|
3172
|
+
type: "response.start",
|
|
3173
|
+
requestId: params.frame.requestId,
|
|
3174
|
+
status: response.status,
|
|
3175
|
+
headers: responseHeaders
|
|
3176
|
+
}));
|
|
3177
|
+
const reader = response.body.getReader();
|
|
3178
|
+
try {
|
|
3179
|
+
while (true) {
|
|
3180
|
+
const { value, done } = await reader.read();
|
|
3181
|
+
if (done) {
|
|
3182
|
+
break;
|
|
3183
|
+
}
|
|
3184
|
+
if (value && value.length > 0) {
|
|
3185
|
+
params.socket.send(JSON.stringify({
|
|
3186
|
+
type: "response.chunk",
|
|
3187
|
+
requestId: params.frame.requestId,
|
|
3188
|
+
bodyBase64: encodeBase64(value)
|
|
3189
|
+
}));
|
|
3190
|
+
}
|
|
3191
|
+
}
|
|
3192
|
+
} finally {
|
|
3193
|
+
reader.releaseLock();
|
|
3194
|
+
}
|
|
3195
|
+
params.socket.send(JSON.stringify({
|
|
3196
|
+
type: "response.end",
|
|
3197
|
+
requestId: params.frame.requestId
|
|
3198
|
+
}));
|
|
3199
|
+
return;
|
|
3200
|
+
}
|
|
3201
|
+
const responseBody = response.body ? new Uint8Array(await response.arrayBuffer()) : new Uint8Array();
|
|
3202
|
+
params.socket.send(JSON.stringify({
|
|
3203
|
+
type: "response",
|
|
3204
|
+
requestId: params.frame.requestId,
|
|
3205
|
+
status: response.status,
|
|
3206
|
+
headers: responseHeaders,
|
|
3207
|
+
bodyBase64: encodeBase64(responseBody)
|
|
3208
|
+
}));
|
|
3209
|
+
}
|
|
3210
|
+
async connectOnce(params) {
|
|
3211
|
+
await new Promise((resolve13, reject) => {
|
|
3212
|
+
const socket = new WebSocket(params.wsUrl);
|
|
3213
|
+
const pingTimer = setInterval(() => {
|
|
3214
|
+
if (socket.readyState === WebSocket.OPEN) {
|
|
3215
|
+
socket.send(JSON.stringify({ type: "ping", at: (/* @__PURE__ */ new Date()).toISOString() }));
|
|
3216
|
+
}
|
|
3217
|
+
}, 15e3);
|
|
3218
|
+
socket.addEventListener("open", () => {
|
|
3219
|
+
console.log(`\u2713 Remote connector connected: ${params.wsUrl}`);
|
|
3220
|
+
});
|
|
3221
|
+
socket.addEventListener("message", (event) => {
|
|
3222
|
+
void (async () => {
|
|
3223
|
+
let frame = null;
|
|
3224
|
+
try {
|
|
3225
|
+
frame = JSON.parse(String(event.data ?? ""));
|
|
3226
|
+
} catch {
|
|
3227
|
+
return;
|
|
3228
|
+
}
|
|
3229
|
+
if (!frame || frame.type !== "request") {
|
|
3230
|
+
return;
|
|
3231
|
+
}
|
|
3232
|
+
try {
|
|
3233
|
+
await this.handleRelayRequest({ frame, localOrigin: params.localOrigin, socket });
|
|
3234
|
+
} catch (error) {
|
|
3235
|
+
socket.send(JSON.stringify({
|
|
3236
|
+
type: "response.error",
|
|
3237
|
+
requestId: frame.requestId,
|
|
3238
|
+
message: error instanceof Error ? error.message : String(error)
|
|
3239
|
+
}));
|
|
3240
|
+
}
|
|
3241
|
+
})();
|
|
3242
|
+
});
|
|
3243
|
+
socket.addEventListener("close", () => {
|
|
3244
|
+
clearInterval(pingTimer);
|
|
3245
|
+
resolve13();
|
|
3246
|
+
});
|
|
3247
|
+
socket.addEventListener("error", () => {
|
|
3248
|
+
clearInterval(pingTimer);
|
|
3249
|
+
reject(new Error("Remote connector websocket failed."));
|
|
3250
|
+
});
|
|
3251
|
+
});
|
|
3252
|
+
}
|
|
3253
|
+
async connect(opts = {}) {
|
|
3254
|
+
const { platformBase, token, config: config2 } = this.resolvePlatformAccess(opts);
|
|
3255
|
+
const localOrigin = this.resolveLocalOrigin(config2, opts);
|
|
3256
|
+
await this.ensureLocalUiHealthy(localOrigin);
|
|
3257
|
+
const deviceInstallId = this.ensureDeviceInstallId();
|
|
3258
|
+
const displayName = typeof opts.name === "string" && opts.name.trim().length > 0 ? opts.name.trim() : hostname();
|
|
3259
|
+
const device = await this.registerDevice({
|
|
3260
|
+
platformBase,
|
|
3261
|
+
token,
|
|
3262
|
+
deviceInstallId,
|
|
3263
|
+
displayName,
|
|
3264
|
+
localOrigin
|
|
3265
|
+
});
|
|
3266
|
+
console.log(`\u2713 Remote device registered: ${device.displayName} (${device.id})`);
|
|
3267
|
+
console.log(`\u2713 Local origin: ${localOrigin}`);
|
|
3268
|
+
console.log(`\u2713 Platform: ${platformBase}`);
|
|
3269
|
+
const wsUrl = `${platformBase.replace(/^http/i, "ws")}/platform/remote/connect?deviceId=${encodeURIComponent(device.id)}&token=${encodeURIComponent(token)}`;
|
|
3270
|
+
do {
|
|
3271
|
+
try {
|
|
3272
|
+
await this.connectOnce({ wsUrl, localOrigin });
|
|
3273
|
+
} catch (error) {
|
|
3274
|
+
console.error(`Remote connector error: ${error instanceof Error ? error.message : String(error)}`);
|
|
3275
|
+
}
|
|
3276
|
+
if (opts.once) {
|
|
3277
|
+
break;
|
|
3278
|
+
}
|
|
3279
|
+
console.log("Remote connector disconnected. Reconnecting in 3s...");
|
|
3280
|
+
await delay(3e3);
|
|
3281
|
+
} while (!opts.once);
|
|
3282
|
+
}
|
|
3283
|
+
};
|
|
3284
|
+
|
|
2861
3285
|
// src/cli/commands/diagnostics.ts
|
|
2862
3286
|
import { createServer as createNetServer } from "net";
|
|
2863
|
-
import { existsSync as
|
|
3287
|
+
import { existsSync as existsSync7, readFileSync as readFileSync7 } from "fs";
|
|
2864
3288
|
import { resolve as resolve8 } from "path";
|
|
2865
3289
|
import {
|
|
2866
3290
|
APP_NAME,
|
|
2867
|
-
getConfigPath as
|
|
2868
|
-
getDataDir as
|
|
3291
|
+
getConfigPath as getConfigPath4,
|
|
3292
|
+
getDataDir as getDataDir5,
|
|
2869
3293
|
getWorkspacePath as getWorkspacePath4,
|
|
2870
3294
|
hasSecretRef,
|
|
2871
|
-
loadConfig as
|
|
3295
|
+
loadConfig as loadConfig9
|
|
2872
3296
|
} from "@nextclaw/core";
|
|
2873
3297
|
import { listBuiltinProviders } from "@nextclaw/runtime";
|
|
2874
3298
|
var DiagnosticsCommands = class {
|
|
@@ -3029,10 +3453,10 @@ var DiagnosticsCommands = class {
|
|
|
3029
3453
|
process.exitCode = exitCode;
|
|
3030
3454
|
}
|
|
3031
3455
|
async collectRuntimeStatus(params) {
|
|
3032
|
-
const configPath =
|
|
3033
|
-
const config2 =
|
|
3456
|
+
const configPath = getConfigPath4();
|
|
3457
|
+
const config2 = loadConfig9();
|
|
3034
3458
|
const workspacePath = getWorkspacePath4(config2.agents.defaults.workspace);
|
|
3035
|
-
const serviceStatePath = resolve8(
|
|
3459
|
+
const serviceStatePath = resolve8(getDataDir5(), "run", "service.json");
|
|
3036
3460
|
const fixActions = [];
|
|
3037
3461
|
let serviceState = readServiceState();
|
|
3038
3462
|
if (params.fix && serviceState && !isProcessRunning(serviceState.pid)) {
|
|
@@ -3072,11 +3496,11 @@ var DiagnosticsCommands = class {
|
|
|
3072
3496
|
});
|
|
3073
3497
|
const issues = [];
|
|
3074
3498
|
const recommendations = [];
|
|
3075
|
-
if (!
|
|
3499
|
+
if (!existsSync7(configPath)) {
|
|
3076
3500
|
issues.push("Config file is missing.");
|
|
3077
3501
|
recommendations.push(`Run ${APP_NAME} init to create config files.`);
|
|
3078
3502
|
}
|
|
3079
|
-
if (!
|
|
3503
|
+
if (!existsSync7(workspacePath)) {
|
|
3080
3504
|
issues.push("Workspace directory does not exist.");
|
|
3081
3505
|
recommendations.push(`Run ${APP_NAME} init to create workspace templates.`);
|
|
3082
3506
|
}
|
|
@@ -3109,13 +3533,13 @@ var DiagnosticsCommands = class {
|
|
|
3109
3533
|
return {
|
|
3110
3534
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3111
3535
|
configPath,
|
|
3112
|
-
configExists:
|
|
3536
|
+
configExists: existsSync7(configPath),
|
|
3113
3537
|
workspacePath,
|
|
3114
|
-
workspaceExists:
|
|
3538
|
+
workspaceExists: existsSync7(workspacePath),
|
|
3115
3539
|
model: config2.agents.defaults.model,
|
|
3116
3540
|
providers,
|
|
3117
3541
|
serviceStatePath,
|
|
3118
|
-
serviceStateExists:
|
|
3542
|
+
serviceStateExists: existsSync7(serviceStatePath),
|
|
3119
3543
|
fixActions,
|
|
3120
3544
|
process: {
|
|
3121
3545
|
managedByState,
|
|
@@ -3165,11 +3589,11 @@ var DiagnosticsCommands = class {
|
|
|
3165
3589
|
}
|
|
3166
3590
|
}
|
|
3167
3591
|
readLogTail(path2, maxLines = 25) {
|
|
3168
|
-
if (!
|
|
3592
|
+
if (!existsSync7(path2)) {
|
|
3169
3593
|
return [];
|
|
3170
3594
|
}
|
|
3171
3595
|
try {
|
|
3172
|
-
const lines =
|
|
3596
|
+
const lines = readFileSync7(path2, "utf-8").split(/\r?\n/).filter(Boolean);
|
|
3173
3597
|
if (lines.length <= maxLines) {
|
|
3174
3598
|
return lines;
|
|
3175
3599
|
}
|
|
@@ -3209,8 +3633,8 @@ import {
|
|
|
3209
3633
|
stopPluginChannelGateways as stopPluginChannelGateways2
|
|
3210
3634
|
} from "@nextclaw/openclaw-compat";
|
|
3211
3635
|
import { startUiServer } from "@nextclaw/server";
|
|
3212
|
-
import { appendFileSync, closeSync, cpSync as cpSync2, existsSync as
|
|
3213
|
-
import { dirname as
|
|
3636
|
+
import { appendFileSync, closeSync, cpSync as cpSync2, existsSync as existsSync11, mkdirSync as mkdirSync6, openSync } from "fs";
|
|
3637
|
+
import { dirname as dirname3, join as join7, resolve as resolve10 } from "path";
|
|
3214
3638
|
import { spawn as spawn2 } from "child_process";
|
|
3215
3639
|
import { request as httpRequest } from "http";
|
|
3216
3640
|
import { request as httpsRequest } from "https";
|
|
@@ -3219,7 +3643,7 @@ import chokidar from "chokidar";
|
|
|
3219
3643
|
|
|
3220
3644
|
// src/cli/gateway/controller.ts
|
|
3221
3645
|
import { createHash } from "crypto";
|
|
3222
|
-
import { existsSync as
|
|
3646
|
+
import { existsSync as existsSync8, readFileSync as readFileSync8 } from "fs";
|
|
3223
3647
|
import {
|
|
3224
3648
|
buildConfigSchema,
|
|
3225
3649
|
ConfigSchema,
|
|
@@ -3227,12 +3651,12 @@ import {
|
|
|
3227
3651
|
redactConfigObject
|
|
3228
3652
|
} from "@nextclaw/core";
|
|
3229
3653
|
var hashRaw = (raw) => createHash("sha256").update(raw).digest("hex");
|
|
3230
|
-
var readConfigSnapshot = (
|
|
3231
|
-
const path2 =
|
|
3654
|
+
var readConfigSnapshot = (getConfigPath7) => {
|
|
3655
|
+
const path2 = getConfigPath7();
|
|
3232
3656
|
let raw = "";
|
|
3233
3657
|
let parsed = {};
|
|
3234
|
-
if (
|
|
3235
|
-
raw =
|
|
3658
|
+
if (existsSync8(path2)) {
|
|
3659
|
+
raw = readFileSync8(path2, "utf-8");
|
|
3236
3660
|
try {
|
|
3237
3661
|
parsed = JSON.parse(raw);
|
|
3238
3662
|
} catch {
|
|
@@ -3339,11 +3763,11 @@ var GatewayControllerImpl = class {
|
|
|
3339
3763
|
await this.deps.requestRestart(options);
|
|
3340
3764
|
return;
|
|
3341
3765
|
}
|
|
3342
|
-
const
|
|
3766
|
+
const delay2 = typeof options?.delayMs === "number" && Number.isFinite(options.delayMs) ? Math.max(0, options.delayMs) : 100;
|
|
3343
3767
|
console.log(`Gateway restart requested via tool${options?.reason ? ` (${options.reason})` : ""}.`);
|
|
3344
3768
|
setTimeout(() => {
|
|
3345
3769
|
process.exit(0);
|
|
3346
|
-
},
|
|
3770
|
+
}, delay2);
|
|
3347
3771
|
}
|
|
3348
3772
|
status() {
|
|
3349
3773
|
return {
|
|
@@ -3689,9 +4113,9 @@ var MissingProvider = class extends LLMProvider {
|
|
|
3689
4113
|
};
|
|
3690
4114
|
|
|
3691
4115
|
// src/cli/commands/service-marketplace-installer.ts
|
|
3692
|
-
import { getWorkspacePath as getWorkspacePath5, loadConfig as
|
|
3693
|
-
import { existsSync as
|
|
3694
|
-
import { join as
|
|
4116
|
+
import { getWorkspacePath as getWorkspacePath5, loadConfig as loadConfig11 } from "@nextclaw/core";
|
|
4117
|
+
import { existsSync as existsSync9, rmSync as rmSync4 } from "fs";
|
|
4118
|
+
import { join as join5 } from "path";
|
|
3695
4119
|
|
|
3696
4120
|
// src/cli/commands/service-marketplace-helpers.ts
|
|
3697
4121
|
var containsAbsoluteFsPath = (line) => {
|
|
@@ -3739,7 +4163,7 @@ var buildMarketplaceSkillInstallArgs = (params) => {
|
|
|
3739
4163
|
};
|
|
3740
4164
|
|
|
3741
4165
|
// src/cli/commands/service-mcp-marketplace-ops.ts
|
|
3742
|
-
import { loadConfig as
|
|
4166
|
+
import { loadConfig as loadConfig10, saveConfig as saveConfig7 } from "@nextclaw/core";
|
|
3743
4167
|
import { McpDoctorFacade as McpDoctorFacade2, McpMutationService as McpMutationService2 } from "@nextclaw/mcp";
|
|
3744
4168
|
var ServiceMcpMarketplaceOps = class {
|
|
3745
4169
|
constructor(options) {
|
|
@@ -3807,13 +4231,13 @@ var ServiceMcpMarketplaceOps = class {
|
|
|
3807
4231
|
}
|
|
3808
4232
|
createMutationService() {
|
|
3809
4233
|
return new McpMutationService2({
|
|
3810
|
-
getConfig: () =>
|
|
3811
|
-
saveConfig: (config2) =>
|
|
4234
|
+
getConfig: () => loadConfig10(),
|
|
4235
|
+
saveConfig: (config2) => saveConfig7(config2)
|
|
3812
4236
|
});
|
|
3813
4237
|
}
|
|
3814
4238
|
createDoctorFacade() {
|
|
3815
4239
|
return new McpDoctorFacade2({
|
|
3816
|
-
getConfig: () =>
|
|
4240
|
+
getConfig: () => loadConfig10()
|
|
3817
4241
|
});
|
|
3818
4242
|
}
|
|
3819
4243
|
};
|
|
@@ -3854,7 +4278,7 @@ var ServiceMarketplaceInstaller = class {
|
|
|
3854
4278
|
if (params.kind && params.kind !== "marketplace") {
|
|
3855
4279
|
throw new Error(`Unsupported marketplace skill kind: ${params.kind}`);
|
|
3856
4280
|
}
|
|
3857
|
-
const workspace = getWorkspacePath5(
|
|
4281
|
+
const workspace = getWorkspacePath5(loadConfig11().agents.defaults.workspace);
|
|
3858
4282
|
const args = buildMarketplaceSkillInstallArgs({
|
|
3859
4283
|
slug: params.slug,
|
|
3860
4284
|
workspace,
|
|
@@ -3893,9 +4317,9 @@ var ServiceMarketplaceInstaller = class {
|
|
|
3893
4317
|
return { message: result.message };
|
|
3894
4318
|
}
|
|
3895
4319
|
async uninstallSkill(slug) {
|
|
3896
|
-
const workspace = getWorkspacePath5(
|
|
3897
|
-
const targetDir =
|
|
3898
|
-
if (!
|
|
4320
|
+
const workspace = getWorkspacePath5(loadConfig11().agents.defaults.workspace);
|
|
4321
|
+
const targetDir = join5(workspace, "skills", slug);
|
|
4322
|
+
if (!existsSync9(targetDir)) {
|
|
3899
4323
|
throw new Error(`Skill not installed in workspace: ${slug}`);
|
|
3900
4324
|
}
|
|
3901
4325
|
rmSync4(targetDir, { recursive: true, force: true });
|
|
@@ -5675,22 +6099,33 @@ var UiNcpRuntimeRegistry = class {
|
|
|
5675
6099
|
sessionMetadata: nextSessionMetadata
|
|
5676
6100
|
});
|
|
5677
6101
|
}
|
|
5678
|
-
listSessionTypes() {
|
|
5679
|
-
const options =
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
6102
|
+
async listSessionTypes() {
|
|
6103
|
+
const options = await Promise.all(
|
|
6104
|
+
[...this.registrations.values()].map(async (registration) => {
|
|
6105
|
+
const descriptor = await registration.describeSessionType?.();
|
|
6106
|
+
return {
|
|
6107
|
+
value: registration.kind,
|
|
6108
|
+
label: registration.label,
|
|
6109
|
+
ready: descriptor?.ready ?? true,
|
|
6110
|
+
reason: descriptor?.reason ?? null,
|
|
6111
|
+
reasonMessage: descriptor?.reasonMessage ?? null,
|
|
6112
|
+
recommendedModel: descriptor?.recommendedModel ?? null,
|
|
6113
|
+
cta: descriptor?.cta ?? null,
|
|
6114
|
+
...descriptor?.supportedModels ? { supportedModels: descriptor.supportedModels } : {}
|
|
6115
|
+
};
|
|
6116
|
+
})
|
|
6117
|
+
);
|
|
5691
6118
|
return {
|
|
5692
6119
|
defaultType: this.defaultKind,
|
|
5693
|
-
options
|
|
6120
|
+
options: options.sort((left, right) => {
|
|
6121
|
+
if (left.value === this.defaultKind) {
|
|
6122
|
+
return -1;
|
|
6123
|
+
}
|
|
6124
|
+
if (right.value === this.defaultKind) {
|
|
6125
|
+
return 1;
|
|
6126
|
+
}
|
|
6127
|
+
return left.value.localeCompare(right.value);
|
|
6128
|
+
})
|
|
5694
6129
|
};
|
|
5695
6130
|
}
|
|
5696
6131
|
};
|
|
@@ -5796,7 +6231,8 @@ async function createUiNcpAgent(params) {
|
|
|
5796
6231
|
scope.add(runtimeRegistry.register({
|
|
5797
6232
|
kind: registration.kind,
|
|
5798
6233
|
label: registration.label,
|
|
5799
|
-
createRuntime: registration.createRuntime
|
|
6234
|
+
createRuntime: registration.createRuntime,
|
|
6235
|
+
describeSessionType: registration.describeSessionType
|
|
5800
6236
|
}));
|
|
5801
6237
|
}
|
|
5802
6238
|
};
|
|
@@ -5844,14 +6280,14 @@ async function createUiNcpAgent(params) {
|
|
|
5844
6280
|
}
|
|
5845
6281
|
|
|
5846
6282
|
// src/cli/commands/ui-chat-run-coordinator.ts
|
|
5847
|
-
import { existsSync as
|
|
5848
|
-
import { join as
|
|
6283
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync5, readdirSync as readdirSync2, readFileSync as readFileSync9, writeFileSync as writeFileSync5 } from "fs";
|
|
6284
|
+
import { join as join6 } from "path";
|
|
5849
6285
|
import {
|
|
5850
|
-
getDataDir as
|
|
6286
|
+
getDataDir as getDataDir6,
|
|
5851
6287
|
parseAgentScopedSessionKey as parseAgentScopedSessionKey2,
|
|
5852
6288
|
safeFilename
|
|
5853
6289
|
} from "@nextclaw/core";
|
|
5854
|
-
var RUNS_DIR =
|
|
6290
|
+
var RUNS_DIR = join6(getDataDir6(), "runs");
|
|
5855
6291
|
var NON_TERMINAL_STATES = /* @__PURE__ */ new Set(["queued", "running"]);
|
|
5856
6292
|
var DEFAULT_SESSION_TYPE = "native";
|
|
5857
6293
|
var SESSION_TYPE_METADATA_KEY = "session_type";
|
|
@@ -5910,7 +6346,7 @@ function hasToolSessionEvent(run) {
|
|
|
5910
6346
|
var UiChatRunCoordinator = class {
|
|
5911
6347
|
constructor(options) {
|
|
5912
6348
|
this.options = options;
|
|
5913
|
-
|
|
6349
|
+
mkdirSync5(RUNS_DIR, { recursive: true });
|
|
5914
6350
|
this.loadPersistedRuns();
|
|
5915
6351
|
}
|
|
5916
6352
|
runs = /* @__PURE__ */ new Map();
|
|
@@ -6377,7 +6813,7 @@ var UiChatRunCoordinator = class {
|
|
|
6377
6813
|
};
|
|
6378
6814
|
}
|
|
6379
6815
|
getRunPath(runId) {
|
|
6380
|
-
return
|
|
6816
|
+
return join6(RUNS_DIR, `${safeFilename(runId)}.json`);
|
|
6381
6817
|
}
|
|
6382
6818
|
persistRun(run) {
|
|
6383
6819
|
const persisted = {
|
|
@@ -6395,20 +6831,20 @@ var UiChatRunCoordinator = class {
|
|
|
6395
6831
|
...typeof run.reply === "string" ? { reply: run.reply } : {},
|
|
6396
6832
|
events: run.events
|
|
6397
6833
|
};
|
|
6398
|
-
|
|
6834
|
+
writeFileSync5(this.getRunPath(run.runId), `${JSON.stringify(persisted, null, 2)}
|
|
6399
6835
|
`);
|
|
6400
6836
|
}
|
|
6401
6837
|
loadPersistedRuns() {
|
|
6402
|
-
if (!
|
|
6838
|
+
if (!existsSync10(RUNS_DIR)) {
|
|
6403
6839
|
return;
|
|
6404
6840
|
}
|
|
6405
6841
|
for (const entry of readdirSync2(RUNS_DIR, { withFileTypes: true })) {
|
|
6406
6842
|
if (!entry.isFile() || !entry.name.endsWith(".json")) {
|
|
6407
6843
|
continue;
|
|
6408
6844
|
}
|
|
6409
|
-
const path2 =
|
|
6845
|
+
const path2 = join6(RUNS_DIR, entry.name);
|
|
6410
6846
|
try {
|
|
6411
|
-
const parsed = JSON.parse(
|
|
6847
|
+
const parsed = JSON.parse(readFileSync9(path2, "utf-8"));
|
|
6412
6848
|
const runId = readOptionalString(parsed.runId);
|
|
6413
6849
|
const sessionKey = readOptionalString(parsed.sessionKey);
|
|
6414
6850
|
if (!runId || !sessionKey) {
|
|
@@ -6467,18 +6903,18 @@ var {
|
|
|
6467
6903
|
ChannelManager: ChannelManager2,
|
|
6468
6904
|
CronService: CronService2,
|
|
6469
6905
|
getApiBase,
|
|
6470
|
-
getConfigPath:
|
|
6471
|
-
getDataDir:
|
|
6906
|
+
getConfigPath: getConfigPath5,
|
|
6907
|
+
getDataDir: getDataDir7,
|
|
6472
6908
|
getProvider,
|
|
6473
6909
|
getProviderName,
|
|
6474
6910
|
getWorkspacePath: getWorkspacePath9,
|
|
6475
6911
|
HeartbeatService,
|
|
6476
6912
|
LiteLLMProvider,
|
|
6477
|
-
loadConfig:
|
|
6913
|
+
loadConfig: loadConfig12,
|
|
6478
6914
|
MessageBus,
|
|
6479
6915
|
ProviderManager,
|
|
6480
6916
|
resolveConfigSecrets: resolveConfigSecrets2,
|
|
6481
|
-
saveConfig:
|
|
6917
|
+
saveConfig: saveConfig8,
|
|
6482
6918
|
SessionManager,
|
|
6483
6919
|
parseAgentScopedSessionKey: parseAgentScopedSessionKey3
|
|
6484
6920
|
} = NextclawCore;
|
|
@@ -6498,8 +6934,8 @@ var ServiceCommands = class {
|
|
|
6498
6934
|
async startGateway(options = {}) {
|
|
6499
6935
|
this.applyLiveConfigReload = null;
|
|
6500
6936
|
this.liveUiNcpAgent = null;
|
|
6501
|
-
const runtimeConfigPath =
|
|
6502
|
-
const config2 = resolveConfigSecrets2(
|
|
6937
|
+
const runtimeConfigPath = getConfigPath5();
|
|
6938
|
+
const config2 = resolveConfigSecrets2(loadConfig12(), { configPath: runtimeConfigPath });
|
|
6503
6939
|
const workspace = getWorkspacePath9(config2.agents.defaults.workspace);
|
|
6504
6940
|
let pluginRegistry = loadPluginRegistry(config2, workspace);
|
|
6505
6941
|
let extensionRegistry = toExtensionRegistry(pluginRegistry);
|
|
@@ -6529,7 +6965,7 @@ var ServiceCommands = class {
|
|
|
6529
6965
|
}
|
|
6530
6966
|
}
|
|
6531
6967
|
};
|
|
6532
|
-
const cronStorePath =
|
|
6968
|
+
const cronStorePath = join7(getDataDir7(), "cron", "jobs.json");
|
|
6533
6969
|
const cron2 = new CronService2(cronStorePath);
|
|
6534
6970
|
const uiConfig = resolveUiConfig(config2, options.uiOverrides);
|
|
6535
6971
|
const uiStaticDir = options.uiStaticDir === void 0 ? resolveUiStaticDir() : options.uiStaticDir;
|
|
@@ -6544,7 +6980,7 @@ var ServiceCommands = class {
|
|
|
6544
6980
|
sessionManager,
|
|
6545
6981
|
providerManager,
|
|
6546
6982
|
makeProvider: (nextConfig) => this.makeProvider(nextConfig, { allowMissing: true }) ?? this.makeMissingProvider(nextConfig),
|
|
6547
|
-
loadConfig: () => resolveConfigSecrets2(
|
|
6983
|
+
loadConfig: () => resolveConfigSecrets2(loadConfig12(), { configPath: runtimeConfigPath }),
|
|
6548
6984
|
getExtensionChannels: () => extensionRegistry.channels,
|
|
6549
6985
|
onRestartRequired: (paths) => {
|
|
6550
6986
|
void this.deps.requestRestart({
|
|
@@ -6555,14 +6991,14 @@ var ServiceCommands = class {
|
|
|
6555
6991
|
}
|
|
6556
6992
|
});
|
|
6557
6993
|
this.applyLiveConfigReload = async () => {
|
|
6558
|
-
await reloader.applyReloadPlan(resolveConfigSecrets2(
|
|
6994
|
+
await reloader.applyReloadPlan(resolveConfigSecrets2(loadConfig12(), { configPath: runtimeConfigPath }));
|
|
6559
6995
|
};
|
|
6560
6996
|
const gatewayController = new GatewayControllerImpl({
|
|
6561
6997
|
reloader,
|
|
6562
6998
|
cron: cron2,
|
|
6563
6999
|
sessionManager,
|
|
6564
|
-
getConfigPath:
|
|
6565
|
-
saveConfig:
|
|
7000
|
+
getConfigPath: getConfigPath5,
|
|
7001
|
+
saveConfig: saveConfig8,
|
|
6566
7002
|
requestRestart: async (options2) => {
|
|
6567
7003
|
await this.deps.requestRestart({
|
|
6568
7004
|
reason: options2?.reason ?? "gateway tool restart",
|
|
@@ -6588,7 +7024,7 @@ var ServiceCommands = class {
|
|
|
6588
7024
|
resolveMessageToolHints: ({ channel, accountId }) => resolvePluginChannelMessageToolHints({
|
|
6589
7025
|
registry: pluginRegistry,
|
|
6590
7026
|
channel,
|
|
6591
|
-
cfg: resolveConfigSecrets2(
|
|
7027
|
+
cfg: resolveConfigSecrets2(loadConfig12(), { configPath: runtimeConfigPath }),
|
|
6592
7028
|
accountId
|
|
6593
7029
|
})
|
|
6594
7030
|
});
|
|
@@ -6621,14 +7057,14 @@ var ServiceCommands = class {
|
|
|
6621
7057
|
});
|
|
6622
7058
|
let pluginChannelBindings = getPluginChannelBindings3(pluginRegistry);
|
|
6623
7059
|
setPluginRuntimeBridge({
|
|
6624
|
-
loadConfig: () => toPluginConfigView(resolveConfigSecrets2(
|
|
7060
|
+
loadConfig: () => toPluginConfigView(resolveConfigSecrets2(loadConfig12(), { configPath: runtimeConfigPath }), pluginChannelBindings),
|
|
6625
7061
|
writeConfigFile: async (nextConfigView) => {
|
|
6626
7062
|
if (!nextConfigView || typeof nextConfigView !== "object" || Array.isArray(nextConfigView)) {
|
|
6627
7063
|
throw new Error("plugin runtime writeConfigFile expects an object config");
|
|
6628
7064
|
}
|
|
6629
|
-
const current =
|
|
7065
|
+
const current = loadConfig12();
|
|
6630
7066
|
const next = mergePluginConfigView(current, nextConfigView, pluginChannelBindings);
|
|
6631
|
-
|
|
7067
|
+
saveConfig8(next);
|
|
6632
7068
|
},
|
|
6633
7069
|
dispatchReplyWithBufferedBlockDispatcher: async ({ ctx, dispatcherOptions }) => {
|
|
6634
7070
|
const bodyForAgent = typeof ctx.BodyForAgent === "string" ? ctx.BodyForAgent : "";
|
|
@@ -6702,12 +7138,12 @@ var ServiceCommands = class {
|
|
|
6702
7138
|
providerManager,
|
|
6703
7139
|
bus,
|
|
6704
7140
|
gatewayController,
|
|
6705
|
-
() => resolveConfigSecrets2(
|
|
7141
|
+
() => resolveConfigSecrets2(loadConfig12(), { configPath: runtimeConfigPath }),
|
|
6706
7142
|
() => extensionRegistry,
|
|
6707
7143
|
({ channel, accountId }) => resolvePluginChannelMessageToolHints({
|
|
6708
7144
|
registry: pluginRegistry,
|
|
6709
7145
|
channel,
|
|
6710
|
-
cfg: resolveConfigSecrets2(
|
|
7146
|
+
cfg: resolveConfigSecrets2(loadConfig12(), { configPath: runtimeConfigPath }),
|
|
6711
7147
|
accountId
|
|
6712
7148
|
})
|
|
6713
7149
|
);
|
|
@@ -6744,7 +7180,7 @@ var ServiceCommands = class {
|
|
|
6744
7180
|
return trimmed || void 0;
|
|
6745
7181
|
}
|
|
6746
7182
|
watchConfigFile(reloader) {
|
|
6747
|
-
const configPath = resolve10(
|
|
7183
|
+
const configPath = resolve10(getConfigPath5());
|
|
6748
7184
|
const watcher = chokidar.watch(configPath, {
|
|
6749
7185
|
ignoreInitial: true,
|
|
6750
7186
|
awaitWriteFinish: { stabilityThreshold: 200, pollInterval: 50 }
|
|
@@ -6865,7 +7301,7 @@ var ServiceCommands = class {
|
|
|
6865
7301
|
});
|
|
6866
7302
|
}
|
|
6867
7303
|
async runForeground(options) {
|
|
6868
|
-
const config2 =
|
|
7304
|
+
const config2 = loadConfig12();
|
|
6869
7305
|
const uiConfig = resolveUiConfig(config2, options.uiOverrides);
|
|
6870
7306
|
const uiUrl = resolveUiApiBase(uiConfig.host, uiConfig.port);
|
|
6871
7307
|
if (options.open) {
|
|
@@ -6878,7 +7314,7 @@ var ServiceCommands = class {
|
|
|
6878
7314
|
});
|
|
6879
7315
|
}
|
|
6880
7316
|
async startService(options) {
|
|
6881
|
-
const config2 =
|
|
7317
|
+
const config2 = loadConfig12();
|
|
6882
7318
|
const uiConfig = resolveUiConfig(config2, options.uiOverrides);
|
|
6883
7319
|
const uiUrl = resolveUiApiBase(uiConfig.host, uiConfig.port);
|
|
6884
7320
|
const apiUrl = `${uiUrl}/api`;
|
|
@@ -6939,7 +7375,7 @@ var ServiceCommands = class {
|
|
|
6939
7375
|
}
|
|
6940
7376
|
const logPath = resolveServiceLogPath();
|
|
6941
7377
|
const logDir = resolve10(logPath, "..");
|
|
6942
|
-
|
|
7378
|
+
mkdirSync6(logDir, { recursive: true });
|
|
6943
7379
|
const logFd = openSync(logPath, "a");
|
|
6944
7380
|
const readinessTimeoutMs = this.resolveStartupTimeoutMs(options.startupTimeoutMs);
|
|
6945
7381
|
const quickPhaseTimeoutMs = Math.min(8e3, readinessTimeoutMs);
|
|
@@ -7292,7 +7728,7 @@ var ServiceCommands = class {
|
|
|
7292
7728
|
return null;
|
|
7293
7729
|
}
|
|
7294
7730
|
console.error("Error: No API key configured.");
|
|
7295
|
-
console.error(`Set one in ${
|
|
7731
|
+
console.error(`Set one in ${getConfigPath5()} under providers section`);
|
|
7296
7732
|
process.exit(1);
|
|
7297
7733
|
}
|
|
7298
7734
|
return new LiteLLMProvider({
|
|
@@ -7419,7 +7855,7 @@ var ServiceCommands = class {
|
|
|
7419
7855
|
const uiServer = startUiServer({
|
|
7420
7856
|
host: uiConfig.host,
|
|
7421
7857
|
port: uiConfig.port,
|
|
7422
|
-
configPath:
|
|
7858
|
+
configPath: getConfigPath5(),
|
|
7423
7859
|
productVersion: getPackageVersion(),
|
|
7424
7860
|
staticDir: uiStaticDir ?? void 0,
|
|
7425
7861
|
cronService,
|
|
@@ -7507,10 +7943,10 @@ var ServiceCommands = class {
|
|
|
7507
7943
|
}
|
|
7508
7944
|
}
|
|
7509
7945
|
installBuiltinMarketplaceSkill(slug, force) {
|
|
7510
|
-
const workspace = getWorkspacePath9(
|
|
7511
|
-
const destination =
|
|
7512
|
-
const destinationSkillFile =
|
|
7513
|
-
if (
|
|
7946
|
+
const workspace = getWorkspacePath9(loadConfig12().agents.defaults.workspace);
|
|
7947
|
+
const destination = join7(workspace, "skills", slug);
|
|
7948
|
+
const destinationSkillFile = join7(destination, "SKILL.md");
|
|
7949
|
+
if (existsSync11(destinationSkillFile) && !force) {
|
|
7514
7950
|
return {
|
|
7515
7951
|
message: `${slug} is already installed`
|
|
7516
7952
|
};
|
|
@@ -7518,15 +7954,15 @@ var ServiceCommands = class {
|
|
|
7518
7954
|
const loader = createSkillsLoader(workspace);
|
|
7519
7955
|
const builtin = (loader?.listSkills(false) ?? []).find((skill) => skill.name === slug && skill.source === "builtin");
|
|
7520
7956
|
if (!builtin) {
|
|
7521
|
-
if (
|
|
7957
|
+
if (existsSync11(destinationSkillFile)) {
|
|
7522
7958
|
return {
|
|
7523
7959
|
message: `${slug} is already installed`
|
|
7524
7960
|
};
|
|
7525
7961
|
}
|
|
7526
7962
|
return null;
|
|
7527
7963
|
}
|
|
7528
|
-
|
|
7529
|
-
cpSync2(
|
|
7964
|
+
mkdirSync6(join7(workspace, "skills"), { recursive: true });
|
|
7965
|
+
cpSync2(dirname3(builtin.path), destination, { recursive: true, force: true });
|
|
7530
7966
|
return {
|
|
7531
7967
|
message: `Installed skill: ${slug}`
|
|
7532
7968
|
};
|
|
@@ -7585,11 +8021,11 @@ ${stderr}`.trim();
|
|
|
7585
8021
|
};
|
|
7586
8022
|
|
|
7587
8023
|
// src/cli/workspace.ts
|
|
7588
|
-
import { cpSync as cpSync3, existsSync as
|
|
8024
|
+
import { cpSync as cpSync3, existsSync as existsSync12, mkdirSync as mkdirSync7, readFileSync as readFileSync10, readdirSync as readdirSync3, rmSync as rmSync5, writeFileSync as writeFileSync6 } from "fs";
|
|
7589
8025
|
import { createRequire as createRequire2 } from "module";
|
|
7590
|
-
import { dirname as
|
|
8026
|
+
import { dirname as dirname4, join as join8, resolve as resolve11 } from "path";
|
|
7591
8027
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
7592
|
-
import { APP_NAME as APP_NAME3, getDataDir as
|
|
8028
|
+
import { APP_NAME as APP_NAME3, getDataDir as getDataDir8 } from "@nextclaw/core";
|
|
7593
8029
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
7594
8030
|
var WorkspaceManager = class {
|
|
7595
8031
|
constructor(logo) {
|
|
@@ -7617,30 +8053,30 @@ var WorkspaceManager = class {
|
|
|
7617
8053
|
{ source: "memory/MEMORY.md", target: "memory/MEMORY.md" }
|
|
7618
8054
|
];
|
|
7619
8055
|
for (const entry of templateFiles) {
|
|
7620
|
-
const filePath =
|
|
7621
|
-
if (!force &&
|
|
8056
|
+
const filePath = join8(workspace, entry.target);
|
|
8057
|
+
if (!force && existsSync12(filePath)) {
|
|
7622
8058
|
continue;
|
|
7623
8059
|
}
|
|
7624
|
-
const templatePath =
|
|
7625
|
-
if (!
|
|
8060
|
+
const templatePath = join8(templateDir, entry.source);
|
|
8061
|
+
if (!existsSync12(templatePath)) {
|
|
7626
8062
|
console.warn(`Warning: Template file missing: ${templatePath}`);
|
|
7627
8063
|
continue;
|
|
7628
8064
|
}
|
|
7629
|
-
const raw =
|
|
8065
|
+
const raw = readFileSync10(templatePath, "utf-8");
|
|
7630
8066
|
const content = raw.replace(/\$\{APP_NAME\}/g, APP_NAME3);
|
|
7631
|
-
|
|
7632
|
-
|
|
8067
|
+
mkdirSync7(dirname4(filePath), { recursive: true });
|
|
8068
|
+
writeFileSync6(filePath, content);
|
|
7633
8069
|
created.push(entry.target);
|
|
7634
8070
|
}
|
|
7635
|
-
const memoryDir =
|
|
7636
|
-
if (!
|
|
7637
|
-
|
|
7638
|
-
created.push(
|
|
8071
|
+
const memoryDir = join8(workspace, "memory");
|
|
8072
|
+
if (!existsSync12(memoryDir)) {
|
|
8073
|
+
mkdirSync7(memoryDir, { recursive: true });
|
|
8074
|
+
created.push(join8("memory", ""));
|
|
7639
8075
|
}
|
|
7640
|
-
const skillsDir =
|
|
7641
|
-
if (!
|
|
7642
|
-
|
|
7643
|
-
created.push(
|
|
8076
|
+
const skillsDir = join8(workspace, "skills");
|
|
8077
|
+
if (!existsSync12(skillsDir)) {
|
|
8078
|
+
mkdirSync7(skillsDir, { recursive: true });
|
|
8079
|
+
created.push(join8("skills", ""));
|
|
7644
8080
|
}
|
|
7645
8081
|
const seeded = this.seedBuiltinSkills(skillsDir, { force });
|
|
7646
8082
|
if (seeded > 0) {
|
|
@@ -7659,12 +8095,12 @@ var WorkspaceManager = class {
|
|
|
7659
8095
|
if (!entry.isDirectory()) {
|
|
7660
8096
|
continue;
|
|
7661
8097
|
}
|
|
7662
|
-
const src =
|
|
7663
|
-
if (!
|
|
8098
|
+
const src = join8(sourceDir, entry.name);
|
|
8099
|
+
if (!existsSync12(join8(src, "SKILL.md"))) {
|
|
7664
8100
|
continue;
|
|
7665
8101
|
}
|
|
7666
|
-
const dest =
|
|
7667
|
-
if (!force &&
|
|
8102
|
+
const dest = join8(targetDir, entry.name);
|
|
8103
|
+
if (!force && existsSync12(dest)) {
|
|
7668
8104
|
continue;
|
|
7669
8105
|
}
|
|
7670
8106
|
try {
|
|
@@ -7681,13 +8117,13 @@ var WorkspaceManager = class {
|
|
|
7681
8117
|
try {
|
|
7682
8118
|
const require3 = createRequire2(import.meta.url);
|
|
7683
8119
|
const entry = require3.resolve("@nextclaw/core");
|
|
7684
|
-
const pkgRoot = resolve11(
|
|
7685
|
-
const distSkills =
|
|
7686
|
-
if (
|
|
8120
|
+
const pkgRoot = resolve11(dirname4(entry), "..");
|
|
8121
|
+
const distSkills = join8(pkgRoot, "dist", "skills");
|
|
8122
|
+
if (existsSync12(distSkills)) {
|
|
7687
8123
|
return distSkills;
|
|
7688
8124
|
}
|
|
7689
|
-
const srcSkills =
|
|
7690
|
-
if (
|
|
8125
|
+
const srcSkills = join8(pkgRoot, "src", "agent", "skills");
|
|
8126
|
+
if (existsSync12(srcSkills)) {
|
|
7691
8127
|
return srcSkills;
|
|
7692
8128
|
}
|
|
7693
8129
|
return null;
|
|
@@ -7702,17 +8138,17 @@ var WorkspaceManager = class {
|
|
|
7702
8138
|
}
|
|
7703
8139
|
const cliDir = resolve11(fileURLToPath3(new URL(".", import.meta.url)));
|
|
7704
8140
|
const pkgRoot = resolve11(cliDir, "..", "..");
|
|
7705
|
-
const candidates = [
|
|
8141
|
+
const candidates = [join8(pkgRoot, "templates")];
|
|
7706
8142
|
for (const candidate of candidates) {
|
|
7707
|
-
if (
|
|
8143
|
+
if (existsSync12(candidate)) {
|
|
7708
8144
|
return candidate;
|
|
7709
8145
|
}
|
|
7710
8146
|
}
|
|
7711
8147
|
return null;
|
|
7712
8148
|
}
|
|
7713
8149
|
getBridgeDir() {
|
|
7714
|
-
const userBridge =
|
|
7715
|
-
if (
|
|
8150
|
+
const userBridge = join8(getDataDir8(), "bridge");
|
|
8151
|
+
if (existsSync12(join8(userBridge, "dist", "index.js"))) {
|
|
7716
8152
|
return userBridge;
|
|
7717
8153
|
}
|
|
7718
8154
|
if (!which("npm")) {
|
|
@@ -7721,12 +8157,12 @@ var WorkspaceManager = class {
|
|
|
7721
8157
|
}
|
|
7722
8158
|
const cliDir = resolve11(fileURLToPath3(new URL(".", import.meta.url)));
|
|
7723
8159
|
const pkgRoot = resolve11(cliDir, "..", "..");
|
|
7724
|
-
const pkgBridge =
|
|
7725
|
-
const srcBridge =
|
|
8160
|
+
const pkgBridge = join8(pkgRoot, "bridge");
|
|
8161
|
+
const srcBridge = join8(pkgRoot, "..", "..", "bridge");
|
|
7726
8162
|
let source = null;
|
|
7727
|
-
if (
|
|
8163
|
+
if (existsSync12(join8(pkgBridge, "package.json"))) {
|
|
7728
8164
|
source = pkgBridge;
|
|
7729
|
-
} else if (
|
|
8165
|
+
} else if (existsSync12(join8(srcBridge, "package.json"))) {
|
|
7730
8166
|
source = srcBridge;
|
|
7731
8167
|
}
|
|
7732
8168
|
if (!source) {
|
|
@@ -7734,8 +8170,8 @@ var WorkspaceManager = class {
|
|
|
7734
8170
|
process.exit(1);
|
|
7735
8171
|
}
|
|
7736
8172
|
console.log(`${this.logo} Setting up bridge...`);
|
|
7737
|
-
|
|
7738
|
-
if (
|
|
8173
|
+
mkdirSync7(resolve11(userBridge, ".."), { recursive: true });
|
|
8174
|
+
if (existsSync12(userBridge)) {
|
|
7739
8175
|
rmSync5(userBridge, { recursive: true, force: true });
|
|
7740
8176
|
}
|
|
7741
8177
|
cpSync3(source, userBridge, {
|
|
@@ -7786,6 +8222,8 @@ var CliRuntime = class {
|
|
|
7786
8222
|
pluginCommands;
|
|
7787
8223
|
channelCommands;
|
|
7788
8224
|
cronCommands;
|
|
8225
|
+
platformAuthCommands;
|
|
8226
|
+
remoteCommands;
|
|
7789
8227
|
diagnosticsCommands;
|
|
7790
8228
|
constructor(options = {}) {
|
|
7791
8229
|
this.logo = options.logo ?? LOGO;
|
|
@@ -7807,6 +8245,8 @@ var CliRuntime = class {
|
|
|
7807
8245
|
requestRestart: (params) => this.requestRestart(params)
|
|
7808
8246
|
});
|
|
7809
8247
|
this.cronCommands = new CronCommands();
|
|
8248
|
+
this.platformAuthCommands = new PlatformAuthCommands();
|
|
8249
|
+
this.remoteCommands = new RemoteCommands();
|
|
7810
8250
|
this.diagnosticsCommands = new DiagnosticsCommands({ logo: this.logo });
|
|
7811
8251
|
this.restartCoordinator = new RestartCoordinator({
|
|
7812
8252
|
readServiceState,
|
|
@@ -7872,7 +8312,7 @@ var CliRuntime = class {
|
|
|
7872
8312
|
const delayMs = typeof params.delayMs === "number" && Number.isFinite(params.delayMs) ? Math.max(0, Math.floor(params.delayMs)) : 100;
|
|
7873
8313
|
const cliPath = process.env.NEXTCLAW_SELF_RELAUNCH_CLI?.trim() || fileURLToPath4(new URL("./index.js", import.meta.url));
|
|
7874
8314
|
const startArgs = [cliPath, "start", "--ui-port", String(uiPort)];
|
|
7875
|
-
const serviceStatePath = resolve12(
|
|
8315
|
+
const serviceStatePath = resolve12(getDataDir9(), "run", "service.json");
|
|
7876
8316
|
const helperScript = [
|
|
7877
8317
|
'const { spawnSync } = require("node:child_process");',
|
|
7878
8318
|
'const { readFileSync } = require("node:fs");',
|
|
@@ -8000,18 +8440,18 @@ var CliRuntime = class {
|
|
|
8000
8440
|
const source = options.source ?? "init";
|
|
8001
8441
|
const prefix = options.auto ? "Auto init" : "Init";
|
|
8002
8442
|
const force = Boolean(options.force);
|
|
8003
|
-
const configPath =
|
|
8443
|
+
const configPath = getConfigPath6();
|
|
8004
8444
|
let createdConfig = false;
|
|
8005
|
-
if (!
|
|
8445
|
+
if (!existsSync13(configPath)) {
|
|
8006
8446
|
const config3 = ConfigSchema2.parse({});
|
|
8007
|
-
|
|
8447
|
+
saveConfig9(config3);
|
|
8008
8448
|
createdConfig = true;
|
|
8009
8449
|
}
|
|
8010
|
-
const config2 =
|
|
8450
|
+
const config2 = loadConfig13();
|
|
8011
8451
|
const workspaceSetting = config2.agents.defaults.workspace;
|
|
8012
|
-
const workspacePath = !workspaceSetting || workspaceSetting === DEFAULT_WORKSPACE_PATH ?
|
|
8013
|
-
const workspaceExisted =
|
|
8014
|
-
|
|
8452
|
+
const workspacePath = !workspaceSetting || workspaceSetting === DEFAULT_WORKSPACE_PATH ? join9(getDataDir9(), DEFAULT_WORKSPACE_DIR) : expandHome2(workspaceSetting);
|
|
8453
|
+
const workspaceExisted = existsSync13(workspacePath);
|
|
8454
|
+
mkdirSync8(workspacePath, { recursive: true });
|
|
8015
8455
|
const templateResult = this.workspaceManager.createWorkspaceTemplates(
|
|
8016
8456
|
workspacePath,
|
|
8017
8457
|
{ force }
|
|
@@ -8042,73 +8482,10 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
8042
8482
|
}
|
|
8043
8483
|
async login(opts = {}) {
|
|
8044
8484
|
await this.init({ source: "login", auto: true });
|
|
8045
|
-
|
|
8046
|
-
|
|
8047
|
-
|
|
8048
|
-
|
|
8049
|
-
displayName: "",
|
|
8050
|
-
apiKey: "",
|
|
8051
|
-
apiBase: null,
|
|
8052
|
-
extraHeaders: null,
|
|
8053
|
-
wireApi: "auto",
|
|
8054
|
-
models: []
|
|
8055
|
-
};
|
|
8056
|
-
const configuredApiBase = typeof nextclawProvider.apiBase === "string" && nextclawProvider.apiBase.trim().length > 0 ? nextclawProvider.apiBase.trim() : "https://ai-gateway-api.nextclaw.io/v1";
|
|
8057
|
-
const requestedApiBase = typeof opts.apiBase === "string" && opts.apiBase.trim().length > 0 ? opts.apiBase.trim() : configuredApiBase;
|
|
8058
|
-
const platformBase = requestedApiBase.replace(/\/v1\/?$/i, "");
|
|
8059
|
-
const v1Base = `${platformBase}/v1`;
|
|
8060
|
-
let email = typeof opts.email === "string" ? opts.email.trim() : "";
|
|
8061
|
-
let password = typeof opts.password === "string" ? opts.password : "";
|
|
8062
|
-
if (!email || !password) {
|
|
8063
|
-
const rl = createInterface2({
|
|
8064
|
-
input: process.stdin,
|
|
8065
|
-
output: process.stdout
|
|
8066
|
-
});
|
|
8067
|
-
try {
|
|
8068
|
-
if (!email) {
|
|
8069
|
-
email = (await prompt(rl, "Email: ")).trim();
|
|
8070
|
-
}
|
|
8071
|
-
if (!password) {
|
|
8072
|
-
password = await prompt(rl, "Password: ");
|
|
8073
|
-
}
|
|
8074
|
-
} finally {
|
|
8075
|
-
rl.close();
|
|
8076
|
-
}
|
|
8077
|
-
}
|
|
8078
|
-
if (!email || !password) {
|
|
8079
|
-
throw new Error("Email and password are required.");
|
|
8080
|
-
}
|
|
8081
|
-
const endpoint = opts.register ? `${platformBase}/platform/auth/register` : `${platformBase}/platform/auth/login`;
|
|
8082
|
-
const response = await fetch(endpoint, {
|
|
8083
|
-
method: "POST",
|
|
8084
|
-
headers: {
|
|
8085
|
-
"Content-Type": "application/json"
|
|
8086
|
-
},
|
|
8087
|
-
body: JSON.stringify({ email, password })
|
|
8088
|
-
});
|
|
8089
|
-
const raw = await response.text();
|
|
8090
|
-
let parsed = null;
|
|
8091
|
-
try {
|
|
8092
|
-
parsed = JSON.parse(raw);
|
|
8093
|
-
} catch {
|
|
8094
|
-
parsed = null;
|
|
8095
|
-
}
|
|
8096
|
-
if (!response.ok) {
|
|
8097
|
-
const maybeMessage = typeof parsed === "object" && parsed && "error" in parsed && typeof parsed.error?.message === "string" ? parsed.error.message : raw || `Request failed (${response.status})`;
|
|
8098
|
-
throw new Error(maybeMessage);
|
|
8099
|
-
}
|
|
8100
|
-
const token = typeof parsed === "object" && parsed && "data" in parsed && typeof parsed.data?.token === "string" ? parsed.data.token : "";
|
|
8101
|
-
const role = typeof parsed === "object" && parsed && "data" in parsed && typeof parsed.data?.user?.role === "string" ? parsed.data.user.role : "user";
|
|
8102
|
-
if (!token) {
|
|
8103
|
-
throw new Error("Login succeeded but token is missing.");
|
|
8104
|
-
}
|
|
8105
|
-
nextclawProvider.apiBase = v1Base;
|
|
8106
|
-
nextclawProvider.apiKey = token;
|
|
8107
|
-
providers.nextclaw = nextclawProvider;
|
|
8108
|
-
saveConfig8(config2, configPath);
|
|
8109
|
-
console.log(`\u2713 Logged in to NextClaw platform (${platformBase})`);
|
|
8110
|
-
console.log(`\u2713 Account: ${email} (${role})`);
|
|
8111
|
-
console.log(`\u2713 Token saved into providers.nextclaw.apiKey`);
|
|
8485
|
+
await this.platformAuthCommands.login(opts);
|
|
8486
|
+
}
|
|
8487
|
+
async remoteConnect(opts = {}) {
|
|
8488
|
+
await this.remoteCommands.connect(opts);
|
|
8112
8489
|
}
|
|
8113
8490
|
async gateway(opts) {
|
|
8114
8491
|
const uiOverrides = {
|
|
@@ -8199,8 +8576,8 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
8199
8576
|
await this.serviceCommands.stopService();
|
|
8200
8577
|
}
|
|
8201
8578
|
async agent(opts) {
|
|
8202
|
-
const configPath =
|
|
8203
|
-
const config2 = resolveConfigSecrets3(
|
|
8579
|
+
const configPath = getConfigPath6();
|
|
8580
|
+
const config2 = resolveConfigSecrets3(loadConfig13(), { configPath });
|
|
8204
8581
|
const workspace = getWorkspacePath10(config2.agents.defaults.workspace);
|
|
8205
8582
|
const pluginRegistry = loadPluginRegistry(config2, workspace);
|
|
8206
8583
|
const extensionRegistry = toExtensionRegistry(pluginRegistry);
|
|
@@ -8208,7 +8585,7 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
8208
8585
|
const pluginChannelBindings = getPluginChannelBindings4(pluginRegistry);
|
|
8209
8586
|
setPluginRuntimeBridge2({
|
|
8210
8587
|
loadConfig: () => toPluginConfigView(
|
|
8211
|
-
resolveConfigSecrets3(
|
|
8588
|
+
resolveConfigSecrets3(loadConfig13(), { configPath }),
|
|
8212
8589
|
pluginChannelBindings
|
|
8213
8590
|
),
|
|
8214
8591
|
writeConfigFile: async (nextConfigView) => {
|
|
@@ -8217,13 +8594,13 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
8217
8594
|
"plugin runtime writeConfigFile expects an object config"
|
|
8218
8595
|
);
|
|
8219
8596
|
}
|
|
8220
|
-
const current =
|
|
8597
|
+
const current = loadConfig13();
|
|
8221
8598
|
const next = mergePluginConfigView(
|
|
8222
8599
|
current,
|
|
8223
8600
|
nextConfigView,
|
|
8224
8601
|
pluginChannelBindings
|
|
8225
8602
|
);
|
|
8226
|
-
|
|
8603
|
+
saveConfig9(next);
|
|
8227
8604
|
}
|
|
8228
8605
|
});
|
|
8229
8606
|
try {
|
|
@@ -8249,7 +8626,7 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
8249
8626
|
resolveMessageToolHints: ({ channel, accountId }) => resolvePluginChannelMessageToolHints2({
|
|
8250
8627
|
registry: pluginRegistry,
|
|
8251
8628
|
channel,
|
|
8252
|
-
cfg: resolveConfigSecrets3(
|
|
8629
|
+
cfg: resolveConfigSecrets3(loadConfig13(), { configPath }),
|
|
8253
8630
|
accountId
|
|
8254
8631
|
})
|
|
8255
8632
|
});
|
|
@@ -8268,11 +8645,11 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
8268
8645
|
`${this.logo} Interactive mode (type exit or Ctrl+C to quit)
|
|
8269
8646
|
`
|
|
8270
8647
|
);
|
|
8271
|
-
const historyFile =
|
|
8648
|
+
const historyFile = join9(getDataDir9(), "history", "cli_history");
|
|
8272
8649
|
const historyDir = resolve12(historyFile, "..");
|
|
8273
|
-
|
|
8274
|
-
const history =
|
|
8275
|
-
const rl =
|
|
8650
|
+
mkdirSync8(historyDir, { recursive: true });
|
|
8651
|
+
const history = existsSync13(historyFile) ? readFileSync11(historyFile, "utf-8").split("\n").filter(Boolean) : [];
|
|
8652
|
+
const rl = createInterface3({
|
|
8276
8653
|
input: process.stdin,
|
|
8277
8654
|
output: process.stdout
|
|
8278
8655
|
});
|
|
@@ -8280,7 +8657,7 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
8280
8657
|
const merged = history.concat(
|
|
8281
8658
|
rl.history ?? []
|
|
8282
8659
|
);
|
|
8283
|
-
|
|
8660
|
+
writeFileSync7(historyFile, merged.join("\n"));
|
|
8284
8661
|
process.exit(0);
|
|
8285
8662
|
});
|
|
8286
8663
|
let running = true;
|
|
@@ -8444,7 +8821,7 @@ ${this.logo} ${APP_NAME4} is ready! (${source})`);
|
|
|
8444
8821
|
await this.diagnosticsCommands.doctor(opts);
|
|
8445
8822
|
}
|
|
8446
8823
|
async skillsInstall(options) {
|
|
8447
|
-
const config2 =
|
|
8824
|
+
const config2 = loadConfig13();
|
|
8448
8825
|
const workdir = resolveSkillsInstallWorkdir({
|
|
8449
8826
|
explicitWorkdir: options.workdir,
|
|
8450
8827
|
configuredWorkspace: config2.agents.defaults.workspace
|
|
@@ -8512,6 +8889,8 @@ program.name(APP_NAME5).description(`${LOGO} ${APP_NAME5} - ${APP_TAGLINE}`).ver
|
|
|
8512
8889
|
program.command("onboard").description(`Initialize ${APP_NAME5} configuration and workspace`).action(async () => runtime.onboard());
|
|
8513
8890
|
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) }));
|
|
8514
8891
|
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));
|
|
8892
|
+
var remote = program.command("remote").description("Manage remote access");
|
|
8893
|
+
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));
|
|
8515
8894
|
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));
|
|
8516
8895
|
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));
|
|
8517
8896
|
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));
|