nextclaw 0.13.4 → 0.13.6
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 +219 -797
- package/package.json +8 -7
package/dist/cli/index.js
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli/index.ts
|
|
4
4
|
import { Command } from "commander";
|
|
5
|
-
import { APP_NAME as
|
|
5
|
+
import { APP_NAME as APP_NAME6, APP_TAGLINE } from "@nextclaw/core";
|
|
6
|
+
import { registerRemoteCommands } from "@nextclaw/remote";
|
|
6
7
|
|
|
7
8
|
// src/cli/runtime.ts
|
|
8
9
|
import {
|
|
9
|
-
loadConfig as
|
|
10
|
+
loadConfig as loadConfig14,
|
|
10
11
|
saveConfig as saveConfig10,
|
|
11
12
|
getConfigPath as getConfigPath7,
|
|
12
13
|
getDataDir as getDataDir9,
|
|
@@ -17,17 +18,18 @@ import {
|
|
|
17
18
|
AgentLoop,
|
|
18
19
|
ProviderManager as ProviderManager2,
|
|
19
20
|
resolveConfigSecrets as resolveConfigSecrets3,
|
|
20
|
-
APP_NAME as
|
|
21
|
+
APP_NAME as APP_NAME5,
|
|
21
22
|
DEFAULT_WORKSPACE_DIR,
|
|
22
23
|
DEFAULT_WORKSPACE_PATH
|
|
23
24
|
} from "@nextclaw/core";
|
|
25
|
+
import { RemoteRuntimeActions } from "@nextclaw/remote";
|
|
24
26
|
import {
|
|
25
27
|
getPluginChannelBindings as getPluginChannelBindings4,
|
|
26
28
|
resolvePluginChannelMessageToolHints as resolvePluginChannelMessageToolHints2,
|
|
27
29
|
setPluginRuntimeBridge as setPluginRuntimeBridge2
|
|
28
30
|
} from "@nextclaw/openclaw-compat";
|
|
29
|
-
import { existsSync as
|
|
30
|
-
import { join as
|
|
31
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync7, readFileSync as readFileSync10, writeFileSync as writeFileSync6 } from "fs";
|
|
32
|
+
import { join as join8, resolve as resolve12 } from "path";
|
|
31
33
|
import { createInterface as createInterface3 } from "readline";
|
|
32
34
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
33
35
|
import { spawn as spawn3 } from "child_process";
|
|
@@ -74,9 +76,9 @@ var RestartCoordinator = class {
|
|
|
74
76
|
message: "Restart already scheduled; skipping duplicate request."
|
|
75
77
|
};
|
|
76
78
|
}
|
|
77
|
-
const
|
|
79
|
+
const delay = typeof request.delayMs === "number" && Number.isFinite(request.delayMs) ? Math.max(0, Math.floor(request.delayMs)) : 100;
|
|
78
80
|
this.exitScheduled = true;
|
|
79
|
-
this.deps.scheduleProcessExit(
|
|
81
|
+
this.deps.scheduleProcessExit(delay, reason);
|
|
80
82
|
return {
|
|
81
83
|
status: "exit-scheduled",
|
|
82
84
|
message: `Restart scheduled (${reason}).`
|
|
@@ -3034,541 +3036,72 @@ var PlatformAuthCommands = class {
|
|
|
3034
3036
|
};
|
|
3035
3037
|
|
|
3036
3038
|
// src/cli/commands/remote.ts
|
|
3037
|
-
import { getConfigPath as getConfigPath4, loadConfig as
|
|
3038
|
-
import
|
|
3039
|
+
import { getConfigPath as getConfigPath4, loadConfig as loadConfig9, saveConfig as saveConfig7 } from "@nextclaw/core";
|
|
3040
|
+
import "@nextclaw/remote";
|
|
3041
|
+
import { hostname } from "os";
|
|
3039
3042
|
|
|
3040
|
-
// src/cli/
|
|
3041
|
-
import { ensureUiBridgeSecret } from "@nextclaw/server";
|
|
3042
|
-
function encodeBase64(bytes) {
|
|
3043
|
-
return Buffer.from(bytes).toString("base64");
|
|
3044
|
-
}
|
|
3045
|
-
function decodeBase64(base64) {
|
|
3046
|
-
if (!base64) {
|
|
3047
|
-
return new Uint8Array();
|
|
3048
|
-
}
|
|
3049
|
-
return new Uint8Array(Buffer.from(base64, "base64"));
|
|
3050
|
-
}
|
|
3051
|
-
var RemoteRelayBridge = class {
|
|
3052
|
-
constructor(localOrigin) {
|
|
3053
|
-
this.localOrigin = localOrigin;
|
|
3054
|
-
}
|
|
3055
|
-
async ensureLocalUiHealthy() {
|
|
3056
|
-
const response = await fetch(`${this.localOrigin}/api/health`);
|
|
3057
|
-
if (!response.ok) {
|
|
3058
|
-
throw new Error(`Local UI is not healthy at ${this.localOrigin}. Start NextClaw first.`);
|
|
3059
|
-
}
|
|
3060
|
-
}
|
|
3061
|
-
async forward(frame, socket) {
|
|
3062
|
-
const bridgeCookie = await this.requestBridgeCookie();
|
|
3063
|
-
const url = new URL(frame.path, this.localOrigin);
|
|
3064
|
-
const headers = this.createForwardHeaders(frame.headers, bridgeCookie);
|
|
3065
|
-
const response = await fetch(url, {
|
|
3066
|
-
method: frame.method,
|
|
3067
|
-
headers,
|
|
3068
|
-
body: frame.method === "GET" || frame.method === "HEAD" ? void 0 : decodeBase64(frame.bodyBase64)
|
|
3069
|
-
});
|
|
3070
|
-
const responseHeaders = Array.from(response.headers.entries()).filter(([key]) => {
|
|
3071
|
-
const lower = key.toLowerCase();
|
|
3072
|
-
return !["content-length", "connection", "transfer-encoding", "set-cookie"].includes(lower);
|
|
3073
|
-
});
|
|
3074
|
-
const contentType = response.headers.get("content-type")?.toLowerCase() ?? "";
|
|
3075
|
-
if (response.body && contentType.startsWith("text/event-stream")) {
|
|
3076
|
-
await this.sendStreamingResponse({ frame, response, responseHeaders, socket });
|
|
3077
|
-
return;
|
|
3078
|
-
}
|
|
3079
|
-
const responseBody = response.body ? new Uint8Array(await response.arrayBuffer()) : new Uint8Array();
|
|
3080
|
-
socket.send(JSON.stringify({
|
|
3081
|
-
type: "response",
|
|
3082
|
-
requestId: frame.requestId,
|
|
3083
|
-
status: response.status,
|
|
3084
|
-
headers: responseHeaders,
|
|
3085
|
-
bodyBase64: encodeBase64(responseBody)
|
|
3086
|
-
}));
|
|
3087
|
-
}
|
|
3088
|
-
createForwardHeaders(headersList, bridgeCookie) {
|
|
3089
|
-
const headers = new Headers();
|
|
3090
|
-
for (const [key, value] of headersList) {
|
|
3091
|
-
const lower = key.toLowerCase();
|
|
3092
|
-
if ([
|
|
3093
|
-
"host",
|
|
3094
|
-
"connection",
|
|
3095
|
-
"content-length",
|
|
3096
|
-
"cookie",
|
|
3097
|
-
"x-forwarded-for",
|
|
3098
|
-
"x-forwarded-proto",
|
|
3099
|
-
"cf-connecting-ip"
|
|
3100
|
-
].includes(lower)) {
|
|
3101
|
-
continue;
|
|
3102
|
-
}
|
|
3103
|
-
headers.set(key, value);
|
|
3104
|
-
}
|
|
3105
|
-
if (bridgeCookie) {
|
|
3106
|
-
headers.set("cookie", bridgeCookie);
|
|
3107
|
-
}
|
|
3108
|
-
return headers;
|
|
3109
|
-
}
|
|
3110
|
-
async requestBridgeCookie() {
|
|
3111
|
-
const response = await fetch(`${this.localOrigin}/api/auth/bridge`, {
|
|
3112
|
-
method: "POST",
|
|
3113
|
-
headers: {
|
|
3114
|
-
"x-nextclaw-ui-bridge-secret": ensureUiBridgeSecret()
|
|
3115
|
-
}
|
|
3116
|
-
});
|
|
3117
|
-
const payload = await response.json();
|
|
3118
|
-
if (!response.ok || !payload.ok) {
|
|
3119
|
-
throw new Error(payload.error?.message ?? `Failed to request local auth bridge (${response.status}).`);
|
|
3120
|
-
}
|
|
3121
|
-
return typeof payload.data?.cookie === "string" && payload.data.cookie.trim().length > 0 ? payload.data.cookie.trim() : null;
|
|
3122
|
-
}
|
|
3123
|
-
async sendStreamingResponse(params) {
|
|
3124
|
-
params.socket.send(JSON.stringify({
|
|
3125
|
-
type: "response.start",
|
|
3126
|
-
requestId: params.frame.requestId,
|
|
3127
|
-
status: params.response.status,
|
|
3128
|
-
headers: params.responseHeaders
|
|
3129
|
-
}));
|
|
3130
|
-
const reader = params.response.body?.getReader();
|
|
3131
|
-
if (!reader) {
|
|
3132
|
-
params.socket.send(JSON.stringify({
|
|
3133
|
-
type: "response.end",
|
|
3134
|
-
requestId: params.frame.requestId
|
|
3135
|
-
}));
|
|
3136
|
-
return;
|
|
3137
|
-
}
|
|
3138
|
-
try {
|
|
3139
|
-
while (true) {
|
|
3140
|
-
const { value, done } = await reader.read();
|
|
3141
|
-
if (done) {
|
|
3142
|
-
break;
|
|
3143
|
-
}
|
|
3144
|
-
if (value && value.length > 0) {
|
|
3145
|
-
params.socket.send(JSON.stringify({
|
|
3146
|
-
type: "response.chunk",
|
|
3147
|
-
requestId: params.frame.requestId,
|
|
3148
|
-
bodyBase64: encodeBase64(value)
|
|
3149
|
-
}));
|
|
3150
|
-
}
|
|
3151
|
-
}
|
|
3152
|
-
} finally {
|
|
3153
|
-
reader.releaseLock();
|
|
3154
|
-
}
|
|
3155
|
-
params.socket.send(JSON.stringify({
|
|
3156
|
-
type: "response.end",
|
|
3157
|
-
requestId: params.frame.requestId
|
|
3158
|
-
}));
|
|
3159
|
-
}
|
|
3160
|
-
};
|
|
3161
|
-
|
|
3162
|
-
// src/cli/remote/remote-platform-client.ts
|
|
3043
|
+
// src/cli/commands/remote-runtime-support.ts
|
|
3163
3044
|
import { getConfigPath as getConfigPath3, getDataDir as getDataDir4, loadConfig as loadConfig8 } from "@nextclaw/core";
|
|
3164
|
-
import {
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
}
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
}
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
if (typeof value !== "string") {
|
|
3193
|
-
return void 0;
|
|
3194
|
-
}
|
|
3195
|
-
const trimmed = value.trim();
|
|
3196
|
-
return trimmed.length > 0 ? trimmed : void 0;
|
|
3045
|
+
import {
|
|
3046
|
+
RemoteConnector,
|
|
3047
|
+
RemotePlatformClient,
|
|
3048
|
+
RemoteStatusStore,
|
|
3049
|
+
buildConfiguredRemoteState,
|
|
3050
|
+
resolveRemoteStatusSnapshot
|
|
3051
|
+
} from "@nextclaw/remote";
|
|
3052
|
+
function createNextclawRemotePlatformClient() {
|
|
3053
|
+
return new RemotePlatformClient({
|
|
3054
|
+
loadConfig: () => loadConfig8(getConfigPath3()),
|
|
3055
|
+
getDataDir: getDataDir4,
|
|
3056
|
+
getPackageVersion,
|
|
3057
|
+
resolvePlatformBase: (rawApiBase) => resolvePlatformApiBase({
|
|
3058
|
+
explicitApiBase: rawApiBase,
|
|
3059
|
+
requireConfigured: true
|
|
3060
|
+
}).platformBase,
|
|
3061
|
+
readManagedServiceState: () => {
|
|
3062
|
+
const state = readServiceState();
|
|
3063
|
+
if (!state) {
|
|
3064
|
+
return null;
|
|
3065
|
+
}
|
|
3066
|
+
return {
|
|
3067
|
+
pid: state.pid,
|
|
3068
|
+
uiPort: state.uiPort
|
|
3069
|
+
};
|
|
3070
|
+
},
|
|
3071
|
+
isProcessRunning
|
|
3072
|
+
});
|
|
3197
3073
|
}
|
|
3198
|
-
function
|
|
3199
|
-
return new
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
resolveDelay();
|
|
3203
|
-
}, ms);
|
|
3204
|
-
const onAbort = () => {
|
|
3205
|
-
clearTimeout(timer);
|
|
3206
|
-
rejectDelay(new Error("Remote connector aborted."));
|
|
3207
|
-
};
|
|
3208
|
-
if (signal) {
|
|
3209
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
3210
|
-
}
|
|
3074
|
+
function createNextclawRemoteConnector(params = {}) {
|
|
3075
|
+
return new RemoteConnector({
|
|
3076
|
+
platformClient: createNextclawRemotePlatformClient(),
|
|
3077
|
+
logger: params.logger
|
|
3211
3078
|
});
|
|
3212
3079
|
}
|
|
3213
|
-
function
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3080
|
+
function createNextclawRemoteStatusStore(mode) {
|
|
3081
|
+
return new RemoteStatusStore(mode, {
|
|
3082
|
+
writeRemoteState: (next) => {
|
|
3083
|
+
updateServiceState((state) => ({
|
|
3084
|
+
...state,
|
|
3085
|
+
remote: next
|
|
3086
|
+
}));
|
|
3219
3087
|
}
|
|
3220
|
-
|
|
3221
|
-
} catch {
|
|
3222
|
-
return url;
|
|
3223
|
-
}
|
|
3088
|
+
});
|
|
3224
3089
|
}
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
devicePath = join4(this.remoteDir, "device.json");
|
|
3228
|
-
resolveRunContext(opts) {
|
|
3229
|
-
const { platformBase, token, config: config2 } = this.resolvePlatformAccess(opts);
|
|
3230
|
-
return {
|
|
3231
|
-
config: config2,
|
|
3232
|
-
platformBase,
|
|
3233
|
-
token,
|
|
3234
|
-
localOrigin: this.resolveLocalOrigin(config2, opts),
|
|
3235
|
-
displayName: this.resolveDisplayName(config2, opts),
|
|
3236
|
-
deviceInstallId: this.ensureDeviceInstallId(),
|
|
3237
|
-
autoReconnect: opts.once ? false : opts.autoReconnect ?? config2.remote.autoReconnect
|
|
3238
|
-
};
|
|
3239
|
-
}
|
|
3240
|
-
async registerDevice(params) {
|
|
3241
|
-
const response = await fetch(`${params.platformBase}/platform/remote/devices/register`, {
|
|
3242
|
-
method: "POST",
|
|
3243
|
-
headers: {
|
|
3244
|
-
"content-type": "application/json",
|
|
3245
|
-
authorization: `Bearer ${params.token}`
|
|
3246
|
-
},
|
|
3247
|
-
body: JSON.stringify({
|
|
3248
|
-
deviceInstallId: params.deviceInstallId,
|
|
3249
|
-
displayName: params.displayName,
|
|
3250
|
-
platform: readPlatform(),
|
|
3251
|
-
appVersion: getPackageVersion(),
|
|
3252
|
-
localOrigin: params.localOrigin
|
|
3253
|
-
})
|
|
3254
|
-
});
|
|
3255
|
-
const payload = await response.json();
|
|
3256
|
-
if (!response.ok || !payload.ok || !payload.data?.device) {
|
|
3257
|
-
throw new Error(payload.error?.message ?? `Failed to register remote device (${response.status}).`);
|
|
3258
|
-
}
|
|
3259
|
-
return payload.data.device;
|
|
3260
|
-
}
|
|
3261
|
-
ensureDeviceInstallId() {
|
|
3262
|
-
const existing = readJsonFile2(this.devicePath);
|
|
3263
|
-
if (existing?.deviceInstallId?.trim()) {
|
|
3264
|
-
return existing.deviceInstallId.trim();
|
|
3265
|
-
}
|
|
3266
|
-
const deviceInstallId = crypto.randomUUID();
|
|
3267
|
-
ensureDir(this.remoteDir);
|
|
3268
|
-
writeJsonFile(this.devicePath, { deviceInstallId });
|
|
3269
|
-
return deviceInstallId;
|
|
3270
|
-
}
|
|
3271
|
-
resolvePlatformAccess(opts) {
|
|
3272
|
-
const config2 = loadConfig8(getConfigPath3());
|
|
3273
|
-
const providers = config2.providers;
|
|
3274
|
-
const nextclawProvider = providers.nextclaw;
|
|
3275
|
-
const token = typeof nextclawProvider?.apiKey === "string" ? nextclawProvider.apiKey.trim() : "";
|
|
3276
|
-
if (!token) {
|
|
3277
|
-
throw new Error('NextClaw platform token is missing. Run "nextclaw login" first.');
|
|
3278
|
-
}
|
|
3279
|
-
const configuredApiBase = normalizeOptionalString3(config2.remote.platformApiBase) ?? (typeof nextclawProvider?.apiBase === "string" ? nextclawProvider.apiBase.trim() : "");
|
|
3280
|
-
const rawApiBase = normalizeOptionalString3(opts.apiBase) ?? configuredApiBase;
|
|
3281
|
-
if (!rawApiBase) {
|
|
3282
|
-
throw new Error("Platform API base is missing. Pass --api-base, run nextclaw login, or set remote.platformApiBase.");
|
|
3283
|
-
}
|
|
3284
|
-
const { platformBase } = resolvePlatformApiBase({
|
|
3285
|
-
explicitApiBase: rawApiBase,
|
|
3286
|
-
requireConfigured: true
|
|
3287
|
-
});
|
|
3288
|
-
return { platformBase, token, config: config2 };
|
|
3289
|
-
}
|
|
3290
|
-
resolveLocalOrigin(config2, opts) {
|
|
3291
|
-
const explicitOrigin = normalizeOptionalString3(opts.localOrigin);
|
|
3292
|
-
if (explicitOrigin) {
|
|
3293
|
-
return explicitOrigin.replace(/\/$/, "");
|
|
3294
|
-
}
|
|
3295
|
-
const state = readServiceState();
|
|
3296
|
-
if (state && isProcessRunning(state.pid) && Number.isFinite(state.uiPort)) {
|
|
3297
|
-
return `http://127.0.0.1:${state.uiPort}`;
|
|
3298
|
-
}
|
|
3299
|
-
const configuredPort = typeof config2.ui?.port === "number" && Number.isFinite(config2.ui.port) ? config2.ui.port : 18791;
|
|
3300
|
-
return `http://127.0.0.1:${configuredPort}`;
|
|
3301
|
-
}
|
|
3302
|
-
resolveDisplayName(config2, opts) {
|
|
3303
|
-
return normalizeOptionalString3(opts.name) ?? normalizeOptionalString3(config2.remote.deviceName) ?? hostname();
|
|
3304
|
-
}
|
|
3305
|
-
};
|
|
3306
|
-
|
|
3307
|
-
// src/cli/remote/remote-connector.ts
|
|
3308
|
-
var RemoteConnector = class {
|
|
3309
|
-
constructor(logger = console) {
|
|
3310
|
-
this.logger = logger;
|
|
3311
|
-
}
|
|
3312
|
-
platformClient = new RemotePlatformClient();
|
|
3313
|
-
async connectOnce(params) {
|
|
3314
|
-
return await new Promise((resolve13, reject) => {
|
|
3315
|
-
const socket = new WebSocket(params.wsUrl);
|
|
3316
|
-
let settled = false;
|
|
3317
|
-
let aborted = false;
|
|
3318
|
-
const pingTimer = setInterval(() => {
|
|
3319
|
-
if (socket.readyState === WebSocket.OPEN) {
|
|
3320
|
-
socket.send(JSON.stringify({ type: "ping", at: (/* @__PURE__ */ new Date()).toISOString() }));
|
|
3321
|
-
}
|
|
3322
|
-
}, 15e3);
|
|
3323
|
-
const cleanup = () => {
|
|
3324
|
-
clearInterval(pingTimer);
|
|
3325
|
-
params.signal?.removeEventListener("abort", onAbort);
|
|
3326
|
-
};
|
|
3327
|
-
const finishResolve = (value) => {
|
|
3328
|
-
if (settled) {
|
|
3329
|
-
return;
|
|
3330
|
-
}
|
|
3331
|
-
settled = true;
|
|
3332
|
-
cleanup();
|
|
3333
|
-
resolve13(value);
|
|
3334
|
-
};
|
|
3335
|
-
const finishReject = (error) => {
|
|
3336
|
-
if (settled) {
|
|
3337
|
-
return;
|
|
3338
|
-
}
|
|
3339
|
-
settled = true;
|
|
3340
|
-
cleanup();
|
|
3341
|
-
reject(error);
|
|
3342
|
-
};
|
|
3343
|
-
const onAbort = () => {
|
|
3344
|
-
aborted = true;
|
|
3345
|
-
try {
|
|
3346
|
-
socket.close(1e3, "Remote connector aborted");
|
|
3347
|
-
} catch {
|
|
3348
|
-
finishResolve("aborted");
|
|
3349
|
-
}
|
|
3350
|
-
};
|
|
3351
|
-
if (params.signal) {
|
|
3352
|
-
if (params.signal.aborted) {
|
|
3353
|
-
onAbort();
|
|
3354
|
-
} else {
|
|
3355
|
-
params.signal.addEventListener("abort", onAbort, { once: true });
|
|
3356
|
-
}
|
|
3357
|
-
}
|
|
3358
|
-
socket.addEventListener("open", () => {
|
|
3359
|
-
params.statusStore?.write({
|
|
3360
|
-
enabled: true,
|
|
3361
|
-
state: "connected",
|
|
3362
|
-
deviceId: params.deviceId,
|
|
3363
|
-
deviceName: params.displayName,
|
|
3364
|
-
platformBase: params.platformBase,
|
|
3365
|
-
localOrigin: params.localOrigin,
|
|
3366
|
-
lastConnectedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3367
|
-
lastError: null
|
|
3368
|
-
});
|
|
3369
|
-
this.logger.info(`\u2713 Remote connector connected: ${redactWsUrl(params.wsUrl)}`);
|
|
3370
|
-
});
|
|
3371
|
-
socket.addEventListener("message", (event) => {
|
|
3372
|
-
this.handleSocketMessage({ data: event.data, relayBridge: params.relayBridge, socket });
|
|
3373
|
-
});
|
|
3374
|
-
socket.addEventListener("close", () => {
|
|
3375
|
-
finishResolve(aborted ? "aborted" : "closed");
|
|
3376
|
-
});
|
|
3377
|
-
socket.addEventListener("error", () => {
|
|
3378
|
-
if (aborted) {
|
|
3379
|
-
finishResolve("aborted");
|
|
3380
|
-
return;
|
|
3381
|
-
}
|
|
3382
|
-
finishReject(new Error("Remote connector websocket failed."));
|
|
3383
|
-
});
|
|
3384
|
-
});
|
|
3385
|
-
}
|
|
3386
|
-
handleSocketMessage(params) {
|
|
3387
|
-
void (async () => {
|
|
3388
|
-
const frame = this.parseRelayFrame(params.data);
|
|
3389
|
-
if (!frame) {
|
|
3390
|
-
return;
|
|
3391
|
-
}
|
|
3392
|
-
try {
|
|
3393
|
-
await params.relayBridge.forward(frame, params.socket);
|
|
3394
|
-
} catch (error) {
|
|
3395
|
-
params.socket.send(JSON.stringify({
|
|
3396
|
-
type: "response.error",
|
|
3397
|
-
requestId: frame.requestId,
|
|
3398
|
-
message: error instanceof Error ? error.message : String(error)
|
|
3399
|
-
}));
|
|
3400
|
-
}
|
|
3401
|
-
})();
|
|
3402
|
-
}
|
|
3403
|
-
parseRelayFrame(data) {
|
|
3404
|
-
try {
|
|
3405
|
-
const frame = JSON.parse(String(data ?? ""));
|
|
3406
|
-
return frame.type === "request" ? frame : null;
|
|
3407
|
-
} catch {
|
|
3408
|
-
return null;
|
|
3409
|
-
}
|
|
3410
|
-
}
|
|
3411
|
-
async ensureDevice(params) {
|
|
3412
|
-
if (params.device) {
|
|
3413
|
-
return params.device;
|
|
3414
|
-
}
|
|
3415
|
-
const device = await this.platformClient.registerDevice({
|
|
3416
|
-
platformBase: params.context.platformBase,
|
|
3417
|
-
token: params.context.token,
|
|
3418
|
-
deviceInstallId: params.context.deviceInstallId,
|
|
3419
|
-
displayName: params.context.displayName,
|
|
3420
|
-
localOrigin: params.context.localOrigin
|
|
3421
|
-
});
|
|
3422
|
-
this.logger.info(`\u2713 Remote device registered: ${device.displayName} (${device.id})`);
|
|
3423
|
-
this.logger.info(`\u2713 Local origin: ${params.context.localOrigin}`);
|
|
3424
|
-
this.logger.info(`\u2713 Platform: ${params.context.platformBase}`);
|
|
3425
|
-
return device;
|
|
3426
|
-
}
|
|
3427
|
-
writeRemoteState(statusStore, next) {
|
|
3428
|
-
statusStore?.write(next);
|
|
3429
|
-
}
|
|
3430
|
-
async runCycle(params) {
|
|
3431
|
-
try {
|
|
3432
|
-
this.writeRemoteState(params.opts.statusStore, {
|
|
3433
|
-
enabled: true,
|
|
3434
|
-
state: "connecting",
|
|
3435
|
-
deviceId: params.device?.id,
|
|
3436
|
-
deviceName: params.context.displayName,
|
|
3437
|
-
platformBase: params.context.platformBase,
|
|
3438
|
-
localOrigin: params.context.localOrigin,
|
|
3439
|
-
lastError: null
|
|
3440
|
-
});
|
|
3441
|
-
const device = await this.ensureDevice({ device: params.device, context: params.context });
|
|
3442
|
-
const wsUrl = `${params.context.platformBase.replace(/^http/i, "ws")}/platform/remote/connect?deviceId=${encodeURIComponent(device.id)}&token=${encodeURIComponent(params.context.token)}`;
|
|
3443
|
-
const outcome = await this.connectOnce({
|
|
3444
|
-
wsUrl,
|
|
3445
|
-
relayBridge: params.relayBridge,
|
|
3446
|
-
signal: params.opts.signal,
|
|
3447
|
-
statusStore: params.opts.statusStore,
|
|
3448
|
-
displayName: params.context.displayName,
|
|
3449
|
-
deviceId: device.id,
|
|
3450
|
-
platformBase: params.context.platformBase,
|
|
3451
|
-
localOrigin: params.context.localOrigin
|
|
3452
|
-
});
|
|
3453
|
-
if (outcome !== "aborted") {
|
|
3454
|
-
this.writeRemoteState(params.opts.statusStore, {
|
|
3455
|
-
enabled: true,
|
|
3456
|
-
state: "disconnected",
|
|
3457
|
-
deviceId: device.id,
|
|
3458
|
-
deviceName: params.context.displayName,
|
|
3459
|
-
platformBase: params.context.platformBase,
|
|
3460
|
-
localOrigin: params.context.localOrigin,
|
|
3461
|
-
lastError: null
|
|
3462
|
-
});
|
|
3463
|
-
}
|
|
3464
|
-
return { device, aborted: outcome === "aborted" };
|
|
3465
|
-
} catch (error) {
|
|
3466
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
3467
|
-
this.writeRemoteState(params.opts.statusStore, {
|
|
3468
|
-
enabled: true,
|
|
3469
|
-
state: "error",
|
|
3470
|
-
deviceId: params.device?.id,
|
|
3471
|
-
deviceName: params.context.displayName,
|
|
3472
|
-
platformBase: params.context.platformBase,
|
|
3473
|
-
localOrigin: params.context.localOrigin,
|
|
3474
|
-
lastError: message
|
|
3475
|
-
});
|
|
3476
|
-
this.logger.error(`Remote connector error: ${message}`);
|
|
3477
|
-
return { device: params.device, aborted: false };
|
|
3478
|
-
}
|
|
3479
|
-
}
|
|
3480
|
-
async run(opts = {}) {
|
|
3481
|
-
const context = this.platformClient.resolveRunContext(opts);
|
|
3482
|
-
const relayBridge = new RemoteRelayBridge(context.localOrigin);
|
|
3483
|
-
await relayBridge.ensureLocalUiHealthy();
|
|
3484
|
-
let device = null;
|
|
3485
|
-
while (!opts.signal?.aborted) {
|
|
3486
|
-
const cycle = await this.runCycle({ device, context, relayBridge, opts });
|
|
3487
|
-
device = cycle.device;
|
|
3488
|
-
if (cycle.aborted || !context.autoReconnect || opts.signal?.aborted) {
|
|
3489
|
-
break;
|
|
3490
|
-
}
|
|
3491
|
-
this.logger.warn("Remote connector disconnected. Reconnecting in 3s...");
|
|
3492
|
-
try {
|
|
3493
|
-
await delay(3e3, opts.signal);
|
|
3494
|
-
} catch {
|
|
3495
|
-
break;
|
|
3496
|
-
}
|
|
3497
|
-
}
|
|
3498
|
-
this.writeRemoteState(opts.statusStore, {
|
|
3499
|
-
enabled: opts.mode === "service" ? true : Boolean(context.config.remote.enabled),
|
|
3500
|
-
state: opts.signal?.aborted ? "disconnected" : "disabled",
|
|
3501
|
-
deviceId: device?.id,
|
|
3502
|
-
deviceName: context.displayName,
|
|
3503
|
-
platformBase: context.platformBase,
|
|
3504
|
-
localOrigin: context.localOrigin,
|
|
3505
|
-
lastError: null
|
|
3506
|
-
});
|
|
3507
|
-
}
|
|
3508
|
-
};
|
|
3509
|
-
|
|
3510
|
-
// src/cli/remote/remote-status-store.ts
|
|
3511
|
-
import { hostname as hostname2 } from "os";
|
|
3512
|
-
import { loadConfig as loadConfig9 } from "@nextclaw/core";
|
|
3513
|
-
function normalizeOptionalString4(value) {
|
|
3514
|
-
if (typeof value !== "string") {
|
|
3515
|
-
return void 0;
|
|
3516
|
-
}
|
|
3517
|
-
const trimmed = value.trim();
|
|
3518
|
-
return trimmed.length > 0 ? trimmed : void 0;
|
|
3090
|
+
function buildNextclawConfiguredRemoteState(config2) {
|
|
3091
|
+
return buildConfiguredRemoteState(config2);
|
|
3519
3092
|
}
|
|
3520
|
-
function
|
|
3521
|
-
|
|
3522
|
-
return {
|
|
3523
|
-
enabled: Boolean(remote.enabled),
|
|
3524
|
-
mode: "service",
|
|
3525
|
-
state: remote.enabled ? "disconnected" : "disabled",
|
|
3526
|
-
...normalizeOptionalString4(remote.deviceName) ? { deviceName: normalizeOptionalString4(remote.deviceName) } : {},
|
|
3527
|
-
...normalizeOptionalString4(remote.platformApiBase) ? { platformBase: normalizeOptionalString4(remote.platformApiBase) } : {},
|
|
3528
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3529
|
-
};
|
|
3093
|
+
function readCurrentNextclawRemoteRuntimeState() {
|
|
3094
|
+
return readServiceState()?.remote ?? null;
|
|
3530
3095
|
}
|
|
3531
|
-
function
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
runtime: serviceState.remote
|
|
3537
|
-
};
|
|
3538
|
-
}
|
|
3539
|
-
if (config2.remote.enabled) {
|
|
3540
|
-
return {
|
|
3541
|
-
configuredEnabled: true,
|
|
3542
|
-
runtime: {
|
|
3543
|
-
...buildConfiguredRemoteState(config2),
|
|
3544
|
-
deviceName: normalizeOptionalString4(config2.remote.deviceName) ?? hostname2()
|
|
3545
|
-
}
|
|
3546
|
-
};
|
|
3547
|
-
}
|
|
3548
|
-
return {
|
|
3549
|
-
configuredEnabled: false,
|
|
3550
|
-
runtime: null
|
|
3551
|
-
};
|
|
3096
|
+
function resolveNextclawRemoteStatusSnapshot(config2) {
|
|
3097
|
+
return resolveRemoteStatusSnapshot({
|
|
3098
|
+
config: config2,
|
|
3099
|
+
currentRemoteState: readCurrentNextclawRemoteRuntimeState()
|
|
3100
|
+
});
|
|
3552
3101
|
}
|
|
3553
|
-
var RemoteStatusStore = class {
|
|
3554
|
-
constructor(mode) {
|
|
3555
|
-
this.mode = mode;
|
|
3556
|
-
}
|
|
3557
|
-
write(next) {
|
|
3558
|
-
updateServiceState((state) => ({
|
|
3559
|
-
...state,
|
|
3560
|
-
remote: {
|
|
3561
|
-
...state.remote,
|
|
3562
|
-
...next,
|
|
3563
|
-
mode: this.mode,
|
|
3564
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3565
|
-
}
|
|
3566
|
-
}));
|
|
3567
|
-
}
|
|
3568
|
-
};
|
|
3569
3102
|
|
|
3570
3103
|
// src/cli/commands/remote.ts
|
|
3571
|
-
function
|
|
3104
|
+
function normalizeOptionalString3(value) {
|
|
3572
3105
|
if (typeof value !== "string") {
|
|
3573
3106
|
return void 0;
|
|
3574
3107
|
}
|
|
@@ -3599,14 +3132,14 @@ async function probeLocalUi(localOrigin) {
|
|
|
3599
3132
|
}
|
|
3600
3133
|
var RemoteCommands = class {
|
|
3601
3134
|
enableConfig(opts = {}) {
|
|
3602
|
-
const config2 =
|
|
3135
|
+
const config2 = loadConfig9(getConfigPath4());
|
|
3603
3136
|
const next = {
|
|
3604
3137
|
...config2,
|
|
3605
3138
|
remote: {
|
|
3606
3139
|
...config2.remote,
|
|
3607
3140
|
enabled: true,
|
|
3608
|
-
...
|
|
3609
|
-
...
|
|
3141
|
+
...normalizeOptionalString3(opts.apiBase) ? { platformApiBase: normalizeOptionalString3(opts.apiBase) ?? "" } : {},
|
|
3142
|
+
...normalizeOptionalString3(opts.name) ? { deviceName: normalizeOptionalString3(opts.name) ?? "" } : {}
|
|
3610
3143
|
}
|
|
3611
3144
|
};
|
|
3612
3145
|
saveConfig7(next);
|
|
@@ -3616,7 +3149,7 @@ var RemoteCommands = class {
|
|
|
3616
3149
|
};
|
|
3617
3150
|
}
|
|
3618
3151
|
disableConfig() {
|
|
3619
|
-
const config2 =
|
|
3152
|
+
const config2 = loadConfig9(getConfigPath4());
|
|
3620
3153
|
const next = {
|
|
3621
3154
|
...config2,
|
|
3622
3155
|
remote: {
|
|
@@ -3631,15 +3164,15 @@ var RemoteCommands = class {
|
|
|
3631
3164
|
};
|
|
3632
3165
|
}
|
|
3633
3166
|
async connect(opts = {}) {
|
|
3634
|
-
const connector =
|
|
3167
|
+
const connector = createNextclawRemoteConnector();
|
|
3635
3168
|
await connector.run({
|
|
3636
3169
|
...opts,
|
|
3637
3170
|
mode: "foreground"
|
|
3638
3171
|
});
|
|
3639
3172
|
}
|
|
3640
3173
|
async status(opts = {}) {
|
|
3641
|
-
const config2 =
|
|
3642
|
-
const snapshot =
|
|
3174
|
+
const config2 = loadConfig9(getConfigPath4());
|
|
3175
|
+
const snapshot = resolveNextclawRemoteStatusSnapshot(config2);
|
|
3643
3176
|
if (opts.json) {
|
|
3644
3177
|
console.log(JSON.stringify(snapshot, null, 2));
|
|
3645
3178
|
return;
|
|
@@ -3649,9 +3182,9 @@ var RemoteCommands = class {
|
|
|
3649
3182
|
console.log(`Enabled: ${snapshot.configuredEnabled ? "yes" : "no"}`);
|
|
3650
3183
|
console.log(`Mode: ${runtime2?.mode ?? "service"}`);
|
|
3651
3184
|
console.log(`State: ${runtime2?.state ?? "disabled"}`);
|
|
3652
|
-
console.log(`Device: ${runtime2?.deviceName ??
|
|
3185
|
+
console.log(`Device: ${runtime2?.deviceName ?? normalizeOptionalString3(config2.remote.deviceName) ?? hostname()}`);
|
|
3653
3186
|
console.log(
|
|
3654
|
-
`Platform: ${runtime2?.platformBase ??
|
|
3187
|
+
`Platform: ${runtime2?.platformBase ?? normalizeOptionalString3(config2.remote.platformApiBase) ?? normalizeOptionalString3(config2.providers.nextclaw?.apiBase) ?? "not set"}`
|
|
3655
3188
|
);
|
|
3656
3189
|
console.log(`Local origin: ${runtime2?.localOrigin ?? resolveConfiguredLocalOrigin(config2)}`);
|
|
3657
3190
|
if (runtime2?.deviceId) {
|
|
@@ -3665,12 +3198,12 @@ var RemoteCommands = class {
|
|
|
3665
3198
|
}
|
|
3666
3199
|
}
|
|
3667
3200
|
async doctor(opts = {}) {
|
|
3668
|
-
const config2 =
|
|
3669
|
-
const snapshot =
|
|
3201
|
+
const config2 = loadConfig9(getConfigPath4());
|
|
3202
|
+
const snapshot = resolveNextclawRemoteStatusSnapshot(config2);
|
|
3670
3203
|
const localOrigin = resolveConfiguredLocalOrigin(config2);
|
|
3671
3204
|
const localUi = await probeLocalUi(localOrigin);
|
|
3672
|
-
const token =
|
|
3673
|
-
const platformApiBase =
|
|
3205
|
+
const token = normalizeOptionalString3(config2.providers.nextclaw?.apiKey);
|
|
3206
|
+
const platformApiBase = normalizeOptionalString3(config2.remote.platformApiBase) ?? normalizeOptionalString3(config2.providers.nextclaw?.apiBase);
|
|
3674
3207
|
const checks = [
|
|
3675
3208
|
{
|
|
3676
3209
|
name: "remote-enabled",
|
|
@@ -3711,7 +3244,7 @@ var RemoteCommands = class {
|
|
|
3711
3244
|
|
|
3712
3245
|
// src/cli/commands/diagnostics.ts
|
|
3713
3246
|
import { createServer as createNetServer } from "net";
|
|
3714
|
-
import { existsSync as
|
|
3247
|
+
import { existsSync as existsSync6, readFileSync as readFileSync6 } from "fs";
|
|
3715
3248
|
import { resolve as resolve8 } from "path";
|
|
3716
3249
|
import {
|
|
3717
3250
|
APP_NAME as APP_NAME2,
|
|
@@ -3719,7 +3252,7 @@ import {
|
|
|
3719
3252
|
getDataDir as getDataDir5,
|
|
3720
3253
|
getWorkspacePath as getWorkspacePath4,
|
|
3721
3254
|
hasSecretRef,
|
|
3722
|
-
loadConfig as
|
|
3255
|
+
loadConfig as loadConfig10
|
|
3723
3256
|
} from "@nextclaw/core";
|
|
3724
3257
|
import { listBuiltinProviders } from "@nextclaw/runtime";
|
|
3725
3258
|
|
|
@@ -3905,7 +3438,7 @@ var DiagnosticsCommands = class {
|
|
|
3905
3438
|
}
|
|
3906
3439
|
async collectRuntimeStatus(params) {
|
|
3907
3440
|
const configPath = getConfigPath5();
|
|
3908
|
-
const config2 =
|
|
3441
|
+
const config2 = loadConfig10();
|
|
3909
3442
|
const workspacePath = getWorkspacePath4(config2.agents.defaults.workspace);
|
|
3910
3443
|
const serviceStatePath = resolve8(getDataDir5(), "run", "service.json");
|
|
3911
3444
|
const fixActions = [];
|
|
@@ -3925,7 +3458,7 @@ var DiagnosticsCommands = class {
|
|
|
3925
3458
|
const managedApiUrl = serviceState?.apiUrl ?? null;
|
|
3926
3459
|
const managedHealth = running && managedApiUrl ? await this.probeApiHealth(`${managedApiUrl}/health`) : { state: "unreachable", detail: "service not running" };
|
|
3927
3460
|
const configuredHealth = await this.probeApiHealth(`${configuredApiUrl}/health`, 900);
|
|
3928
|
-
const remote =
|
|
3461
|
+
const remote = resolveNextclawRemoteStatusSnapshot(config2);
|
|
3929
3462
|
const orphanSuspected = !running && configuredHealth.state === "ok";
|
|
3930
3463
|
const providers = this.listProviderStatuses(config2);
|
|
3931
3464
|
const issues = [];
|
|
@@ -3948,13 +3481,13 @@ var DiagnosticsCommands = class {
|
|
|
3948
3481
|
return {
|
|
3949
3482
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3950
3483
|
configPath,
|
|
3951
|
-
configExists:
|
|
3484
|
+
configExists: existsSync6(configPath),
|
|
3952
3485
|
workspacePath,
|
|
3953
|
-
workspaceExists:
|
|
3486
|
+
workspaceExists: existsSync6(workspacePath),
|
|
3954
3487
|
model: config2.agents.defaults.model,
|
|
3955
3488
|
providers,
|
|
3956
3489
|
serviceStatePath,
|
|
3957
|
-
serviceStateExists:
|
|
3490
|
+
serviceStateExists: existsSync6(serviceStatePath),
|
|
3958
3491
|
fixActions,
|
|
3959
3492
|
process: {
|
|
3960
3493
|
managedByState,
|
|
@@ -4026,11 +3559,11 @@ var DiagnosticsCommands = class {
|
|
|
4026
3559
|
});
|
|
4027
3560
|
}
|
|
4028
3561
|
collectRuntimeIssues(params) {
|
|
4029
|
-
if (!
|
|
3562
|
+
if (!existsSync6(params.configPath)) {
|
|
4030
3563
|
params.issues.push("Config file is missing.");
|
|
4031
3564
|
params.recommendations.push(`Run ${APP_NAME2} init to create config files.`);
|
|
4032
3565
|
}
|
|
4033
|
-
if (!
|
|
3566
|
+
if (!existsSync6(params.workspacePath)) {
|
|
4034
3567
|
params.issues.push("Workspace directory does not exist.");
|
|
4035
3568
|
params.recommendations.push(`Run ${APP_NAME2} init to create workspace templates.`);
|
|
4036
3569
|
}
|
|
@@ -4059,11 +3592,11 @@ var DiagnosticsCommands = class {
|
|
|
4059
3592
|
}
|
|
4060
3593
|
}
|
|
4061
3594
|
readLogTail(path2, maxLines = 25) {
|
|
4062
|
-
if (!
|
|
3595
|
+
if (!existsSync6(path2)) {
|
|
4063
3596
|
return [];
|
|
4064
3597
|
}
|
|
4065
3598
|
try {
|
|
4066
|
-
const lines =
|
|
3599
|
+
const lines = readFileSync6(path2, "utf-8").split(/\r?\n/).filter(Boolean);
|
|
4067
3600
|
if (lines.length <= maxLines) {
|
|
4068
3601
|
return lines;
|
|
4069
3602
|
}
|
|
@@ -4103,8 +3636,8 @@ import {
|
|
|
4103
3636
|
stopPluginChannelGateways as stopPluginChannelGateways2
|
|
4104
3637
|
} from "@nextclaw/openclaw-compat";
|
|
4105
3638
|
import { startUiServer } from "@nextclaw/server";
|
|
4106
|
-
import { appendFileSync, closeSync, cpSync as cpSync2, existsSync as
|
|
4107
|
-
import { dirname as
|
|
3639
|
+
import { appendFileSync, closeSync, cpSync as cpSync2, existsSync as existsSync10, mkdirSync as mkdirSync5, openSync } from "fs";
|
|
3640
|
+
import { dirname as dirname2, join as join6, resolve as resolve10 } from "path";
|
|
4108
3641
|
import { spawn as spawn2 } from "child_process";
|
|
4109
3642
|
import { request as httpRequest } from "http";
|
|
4110
3643
|
import { request as httpsRequest } from "https";
|
|
@@ -4113,7 +3646,7 @@ import chokidar from "chokidar";
|
|
|
4113
3646
|
|
|
4114
3647
|
// src/cli/gateway/controller.ts
|
|
4115
3648
|
import { createHash } from "crypto";
|
|
4116
|
-
import { existsSync as
|
|
3649
|
+
import { existsSync as existsSync7, readFileSync as readFileSync7 } from "fs";
|
|
4117
3650
|
import {
|
|
4118
3651
|
buildConfigSchema,
|
|
4119
3652
|
ConfigSchema,
|
|
@@ -4125,8 +3658,8 @@ var readConfigSnapshot = (getConfigPath8) => {
|
|
|
4125
3658
|
const path2 = getConfigPath8();
|
|
4126
3659
|
let raw = "";
|
|
4127
3660
|
let parsed = {};
|
|
4128
|
-
if (
|
|
4129
|
-
raw =
|
|
3661
|
+
if (existsSync7(path2)) {
|
|
3662
|
+
raw = readFileSync7(path2, "utf-8");
|
|
4130
3663
|
try {
|
|
4131
3664
|
parsed = JSON.parse(raw);
|
|
4132
3665
|
} catch {
|
|
@@ -4233,11 +3766,11 @@ var GatewayControllerImpl = class {
|
|
|
4233
3766
|
await this.deps.requestRestart(options);
|
|
4234
3767
|
return;
|
|
4235
3768
|
}
|
|
4236
|
-
const
|
|
3769
|
+
const delay = typeof options?.delayMs === "number" && Number.isFinite(options.delayMs) ? Math.max(0, options.delayMs) : 100;
|
|
4237
3770
|
console.log(`Gateway restart requested via tool${options?.reason ? ` (${options.reason})` : ""}.`);
|
|
4238
3771
|
setTimeout(() => {
|
|
4239
3772
|
process.exit(0);
|
|
4240
|
-
},
|
|
3773
|
+
}, delay);
|
|
4241
3774
|
}
|
|
4242
3775
|
status() {
|
|
4243
3776
|
return {
|
|
@@ -4583,9 +4116,9 @@ var MissingProvider = class extends LLMProvider {
|
|
|
4583
4116
|
};
|
|
4584
4117
|
|
|
4585
4118
|
// src/cli/commands/service-marketplace-installer.ts
|
|
4586
|
-
import { getWorkspacePath as getWorkspacePath5, loadConfig as
|
|
4587
|
-
import { existsSync as
|
|
4588
|
-
import { join as
|
|
4119
|
+
import { getWorkspacePath as getWorkspacePath5, loadConfig as loadConfig12 } from "@nextclaw/core";
|
|
4120
|
+
import { existsSync as existsSync8, rmSync as rmSync4 } from "fs";
|
|
4121
|
+
import { join as join4 } from "path";
|
|
4589
4122
|
|
|
4590
4123
|
// src/cli/commands/service-marketplace-helpers.ts
|
|
4591
4124
|
var containsAbsoluteFsPath = (line) => {
|
|
@@ -4633,7 +4166,7 @@ var buildMarketplaceSkillInstallArgs = (params) => {
|
|
|
4633
4166
|
};
|
|
4634
4167
|
|
|
4635
4168
|
// src/cli/commands/service-mcp-marketplace-ops.ts
|
|
4636
|
-
import { loadConfig as
|
|
4169
|
+
import { loadConfig as loadConfig11, saveConfig as saveConfig8 } from "@nextclaw/core";
|
|
4637
4170
|
import { McpDoctorFacade as McpDoctorFacade2, McpMutationService as McpMutationService2 } from "@nextclaw/mcp";
|
|
4638
4171
|
var ServiceMcpMarketplaceOps = class {
|
|
4639
4172
|
constructor(options) {
|
|
@@ -4701,13 +4234,13 @@ var ServiceMcpMarketplaceOps = class {
|
|
|
4701
4234
|
}
|
|
4702
4235
|
createMutationService() {
|
|
4703
4236
|
return new McpMutationService2({
|
|
4704
|
-
getConfig: () =>
|
|
4237
|
+
getConfig: () => loadConfig11(),
|
|
4705
4238
|
saveConfig: (config2) => saveConfig8(config2)
|
|
4706
4239
|
});
|
|
4707
4240
|
}
|
|
4708
4241
|
createDoctorFacade() {
|
|
4709
4242
|
return new McpDoctorFacade2({
|
|
4710
|
-
getConfig: () =>
|
|
4243
|
+
getConfig: () => loadConfig11()
|
|
4711
4244
|
});
|
|
4712
4245
|
}
|
|
4713
4246
|
};
|
|
@@ -4748,7 +4281,7 @@ var ServiceMarketplaceInstaller = class {
|
|
|
4748
4281
|
if (params.kind && params.kind !== "marketplace") {
|
|
4749
4282
|
throw new Error(`Unsupported marketplace skill kind: ${params.kind}`);
|
|
4750
4283
|
}
|
|
4751
|
-
const workspace = getWorkspacePath5(
|
|
4284
|
+
const workspace = getWorkspacePath5(loadConfig12().agents.defaults.workspace);
|
|
4752
4285
|
const args = buildMarketplaceSkillInstallArgs({
|
|
4753
4286
|
slug: params.slug,
|
|
4754
4287
|
workspace,
|
|
@@ -4787,9 +4320,9 @@ var ServiceMarketplaceInstaller = class {
|
|
|
4787
4320
|
return { message: result.message };
|
|
4788
4321
|
}
|
|
4789
4322
|
async uninstallSkill(slug) {
|
|
4790
|
-
const workspace = getWorkspacePath5(
|
|
4791
|
-
const targetDir =
|
|
4792
|
-
if (!
|
|
4323
|
+
const workspace = getWorkspacePath5(loadConfig12().agents.defaults.workspace);
|
|
4324
|
+
const targetDir = join4(workspace, "skills", slug);
|
|
4325
|
+
if (!existsSync8(targetDir)) {
|
|
4793
4326
|
throw new Error(`Skill not installed in workspace: ${slug}`);
|
|
4794
4327
|
}
|
|
4795
4328
|
rmSync4(targetDir, { recursive: true, force: true });
|
|
@@ -5922,7 +5455,7 @@ function resolveRequestedToolNames(metadata) {
|
|
|
5922
5455
|
)
|
|
5923
5456
|
);
|
|
5924
5457
|
}
|
|
5925
|
-
function
|
|
5458
|
+
function normalizeOptionalString4(value) {
|
|
5926
5459
|
return normalizeString(value) ?? void 0;
|
|
5927
5460
|
}
|
|
5928
5461
|
function readMetadataModel(metadata) {
|
|
@@ -6042,7 +5575,7 @@ var NextclawNcpContextBuilder = class {
|
|
|
6042
5575
|
if (inboundModel) {
|
|
6043
5576
|
session.metadata.preferred_model = inboundModel;
|
|
6044
5577
|
}
|
|
6045
|
-
const effectiveModel =
|
|
5578
|
+
const effectiveModel = normalizeOptionalString4(session.metadata.preferred_model) ?? profile.model;
|
|
6046
5579
|
const clearThinking = requestMetadata.clear_thinking === true || requestMetadata.reset_thinking === true;
|
|
6047
5580
|
if (clearThinking) {
|
|
6048
5581
|
delete session.metadata.preferred_thinking;
|
|
@@ -6059,8 +5592,8 @@ var NextclawNcpContextBuilder = class {
|
|
|
6059
5592
|
model: effectiveModel,
|
|
6060
5593
|
sessionThinkingLevel: parseThinkingLevel(session.metadata.preferred_thinking) ?? null
|
|
6061
5594
|
});
|
|
6062
|
-
const channel =
|
|
6063
|
-
const chatId =
|
|
5595
|
+
const channel = normalizeOptionalString4(requestMetadata.channel) ?? normalizeOptionalString4(session.metadata.last_channel) ?? "ui";
|
|
5596
|
+
const chatId = normalizeOptionalString4(requestMetadata.chatId) ?? normalizeOptionalString4(requestMetadata.chat_id) ?? normalizeOptionalString4(session.metadata.last_to) ?? "web-ui";
|
|
6064
5597
|
session.metadata.last_channel = channel;
|
|
6065
5598
|
session.metadata.last_to = chatId;
|
|
6066
5599
|
const requestedSkillNames = resolveRequestedSkillNames(requestMetadata);
|
|
@@ -6778,70 +6311,8 @@ async function createUiNcpAgent(params) {
|
|
|
6778
6311
|
};
|
|
6779
6312
|
}
|
|
6780
6313
|
|
|
6781
|
-
// src/cli/remote/remote-service-module.ts
|
|
6782
|
-
var RemoteServiceModule = class {
|
|
6783
|
-
constructor(deps) {
|
|
6784
|
-
this.deps = deps;
|
|
6785
|
-
}
|
|
6786
|
-
abortController = null;
|
|
6787
|
-
runTask = null;
|
|
6788
|
-
statusStore = new RemoteStatusStore("service");
|
|
6789
|
-
start() {
|
|
6790
|
-
if (!this.deps.config.remote.enabled) {
|
|
6791
|
-
this.statusStore.write({
|
|
6792
|
-
enabled: false,
|
|
6793
|
-
state: "disabled",
|
|
6794
|
-
deviceName: void 0,
|
|
6795
|
-
deviceId: void 0,
|
|
6796
|
-
platformBase: void 0,
|
|
6797
|
-
localOrigin: this.deps.localOrigin,
|
|
6798
|
-
lastError: null,
|
|
6799
|
-
lastConnectedAt: null
|
|
6800
|
-
});
|
|
6801
|
-
return null;
|
|
6802
|
-
}
|
|
6803
|
-
const logger = this.deps.logger ?? {
|
|
6804
|
-
info: (message) => console.log(`[remote] ${message}`),
|
|
6805
|
-
warn: (message) => console.warn(`[remote] ${message}`),
|
|
6806
|
-
error: (message) => console.error(`[remote] ${message}`)
|
|
6807
|
-
};
|
|
6808
|
-
this.abortController = new AbortController();
|
|
6809
|
-
const connector = new RemoteConnector(logger);
|
|
6810
|
-
this.runTask = connector.run({
|
|
6811
|
-
mode: "service",
|
|
6812
|
-
signal: this.abortController.signal,
|
|
6813
|
-
autoReconnect: this.deps.config.remote.autoReconnect,
|
|
6814
|
-
localOrigin: this.deps.localOrigin,
|
|
6815
|
-
statusStore: this.statusStore
|
|
6816
|
-
});
|
|
6817
|
-
void this.runTask.catch((error) => {
|
|
6818
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
6819
|
-
this.statusStore.write({
|
|
6820
|
-
enabled: true,
|
|
6821
|
-
state: "error",
|
|
6822
|
-
deviceName: this.deps.config.remote.deviceName || void 0,
|
|
6823
|
-
deviceId: void 0,
|
|
6824
|
-
platformBase: this.deps.config.remote.platformApiBase || void 0,
|
|
6825
|
-
localOrigin: this.deps.localOrigin,
|
|
6826
|
-
lastError: message
|
|
6827
|
-
});
|
|
6828
|
-
logger.error(message);
|
|
6829
|
-
});
|
|
6830
|
-
return this.runTask;
|
|
6831
|
-
}
|
|
6832
|
-
async stop() {
|
|
6833
|
-
this.abortController?.abort();
|
|
6834
|
-
try {
|
|
6835
|
-
await this.runTask;
|
|
6836
|
-
} catch {
|
|
6837
|
-
} finally {
|
|
6838
|
-
this.abortController = null;
|
|
6839
|
-
this.runTask = null;
|
|
6840
|
-
}
|
|
6841
|
-
}
|
|
6842
|
-
};
|
|
6843
|
-
|
|
6844
6314
|
// src/cli/commands/service-remote-runtime.ts
|
|
6315
|
+
import { RemoteServiceModule } from "@nextclaw/remote";
|
|
6845
6316
|
function createManagedRemoteModule(params) {
|
|
6846
6317
|
if (!params.config.ui.enabled) {
|
|
6847
6318
|
return null;
|
|
@@ -6849,6 +6320,8 @@ function createManagedRemoteModule(params) {
|
|
|
6849
6320
|
return new RemoteServiceModule({
|
|
6850
6321
|
config: params.config,
|
|
6851
6322
|
localOrigin: params.localOrigin,
|
|
6323
|
+
statusStore: createNextclawRemoteStatusStore("service"),
|
|
6324
|
+
createConnector: (logger) => createNextclawRemoteConnector({ logger }),
|
|
6852
6325
|
logger: {
|
|
6853
6326
|
info: (message) => console.log(`[remote] ${message}`),
|
|
6854
6327
|
warn: (message) => console.warn(`[remote] ${message}`),
|
|
@@ -6868,7 +6341,7 @@ function writeInitialManagedServiceState(params) {
|
|
|
6868
6341
|
startupLastProbeError: null,
|
|
6869
6342
|
startupTimeoutMs: params.readinessTimeoutMs,
|
|
6870
6343
|
startupCheckedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6871
|
-
...params.config.remote.enabled ? { remote:
|
|
6344
|
+
...params.config.remote.enabled ? { remote: buildNextclawConfiguredRemoteState(params.config) } : {}
|
|
6872
6345
|
});
|
|
6873
6346
|
}
|
|
6874
6347
|
function writeReadyManagedServiceState(params) {
|
|
@@ -6892,14 +6365,14 @@ function writeReadyManagedServiceState(params) {
|
|
|
6892
6365
|
}
|
|
6893
6366
|
|
|
6894
6367
|
// src/cli/commands/ui-chat-run-coordinator.ts
|
|
6895
|
-
import { existsSync as
|
|
6896
|
-
import { join as
|
|
6368
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync4, readdirSync as readdirSync2, readFileSync as readFileSync8, writeFileSync as writeFileSync4 } from "fs";
|
|
6369
|
+
import { join as join5 } from "path";
|
|
6897
6370
|
import {
|
|
6898
6371
|
getDataDir as getDataDir6,
|
|
6899
6372
|
parseAgentScopedSessionKey as parseAgentScopedSessionKey2,
|
|
6900
6373
|
safeFilename
|
|
6901
6374
|
} from "@nextclaw/core";
|
|
6902
|
-
var RUNS_DIR =
|
|
6375
|
+
var RUNS_DIR = join5(getDataDir6(), "runs");
|
|
6903
6376
|
var NON_TERMINAL_STATES = /* @__PURE__ */ new Set(["queued", "running"]);
|
|
6904
6377
|
var DEFAULT_SESSION_TYPE = "native";
|
|
6905
6378
|
var SESSION_TYPE_METADATA_KEY = "session_type";
|
|
@@ -6958,7 +6431,7 @@ function hasToolSessionEvent(run) {
|
|
|
6958
6431
|
var UiChatRunCoordinator = class {
|
|
6959
6432
|
constructor(options) {
|
|
6960
6433
|
this.options = options;
|
|
6961
|
-
|
|
6434
|
+
mkdirSync4(RUNS_DIR, { recursive: true });
|
|
6962
6435
|
this.loadPersistedRuns();
|
|
6963
6436
|
}
|
|
6964
6437
|
runs = /* @__PURE__ */ new Map();
|
|
@@ -7425,7 +6898,7 @@ var UiChatRunCoordinator = class {
|
|
|
7425
6898
|
};
|
|
7426
6899
|
}
|
|
7427
6900
|
getRunPath(runId) {
|
|
7428
|
-
return
|
|
6901
|
+
return join5(RUNS_DIR, `${safeFilename(runId)}.json`);
|
|
7429
6902
|
}
|
|
7430
6903
|
persistRun(run) {
|
|
7431
6904
|
const persisted = {
|
|
@@ -7443,20 +6916,20 @@ var UiChatRunCoordinator = class {
|
|
|
7443
6916
|
...typeof run.reply === "string" ? { reply: run.reply } : {},
|
|
7444
6917
|
events: run.events
|
|
7445
6918
|
};
|
|
7446
|
-
|
|
6919
|
+
writeFileSync4(this.getRunPath(run.runId), `${JSON.stringify(persisted, null, 2)}
|
|
7447
6920
|
`);
|
|
7448
6921
|
}
|
|
7449
6922
|
loadPersistedRuns() {
|
|
7450
|
-
if (!
|
|
6923
|
+
if (!existsSync9(RUNS_DIR)) {
|
|
7451
6924
|
return;
|
|
7452
6925
|
}
|
|
7453
6926
|
for (const entry of readdirSync2(RUNS_DIR, { withFileTypes: true })) {
|
|
7454
6927
|
if (!entry.isFile() || !entry.name.endsWith(".json")) {
|
|
7455
6928
|
continue;
|
|
7456
6929
|
}
|
|
7457
|
-
const path2 =
|
|
6930
|
+
const path2 = join5(RUNS_DIR, entry.name);
|
|
7458
6931
|
try {
|
|
7459
|
-
const parsed = JSON.parse(
|
|
6932
|
+
const parsed = JSON.parse(readFileSync8(path2, "utf-8"));
|
|
7460
6933
|
const runId = readOptionalString(parsed.runId);
|
|
7461
6934
|
const sessionKey = readOptionalString(parsed.sessionKey);
|
|
7462
6935
|
if (!runId || !sessionKey) {
|
|
@@ -7522,7 +6995,7 @@ var {
|
|
|
7522
6995
|
getWorkspacePath: getWorkspacePath9,
|
|
7523
6996
|
HeartbeatService,
|
|
7524
6997
|
LiteLLMProvider,
|
|
7525
|
-
loadConfig:
|
|
6998
|
+
loadConfig: loadConfig13,
|
|
7526
6999
|
MessageBus,
|
|
7527
7000
|
ProviderManager,
|
|
7528
7001
|
resolveConfigSecrets: resolveConfigSecrets2,
|
|
@@ -7547,7 +7020,7 @@ var ServiceCommands = class {
|
|
|
7547
7020
|
this.applyLiveConfigReload = null;
|
|
7548
7021
|
this.liveUiNcpAgent = null;
|
|
7549
7022
|
const runtimeConfigPath = getConfigPath6();
|
|
7550
|
-
const config2 = resolveConfigSecrets2(
|
|
7023
|
+
const config2 = resolveConfigSecrets2(loadConfig13(), { configPath: runtimeConfigPath });
|
|
7551
7024
|
const workspace = getWorkspacePath9(config2.agents.defaults.workspace);
|
|
7552
7025
|
let pluginRegistry = loadPluginRegistry(config2, workspace);
|
|
7553
7026
|
let extensionRegistry = toExtensionRegistry(pluginRegistry);
|
|
@@ -7560,7 +7033,7 @@ var ServiceCommands = class {
|
|
|
7560
7033
|
});
|
|
7561
7034
|
const sessionManager = new SessionManager(workspace);
|
|
7562
7035
|
let pluginGatewayHandles = [];
|
|
7563
|
-
const cronStorePath =
|
|
7036
|
+
const cronStorePath = join6(getDataDir7(), "cron", "jobs.json");
|
|
7564
7037
|
const cron2 = new CronService2(cronStorePath);
|
|
7565
7038
|
const uiConfig = resolveUiConfig(config2, options.uiOverrides);
|
|
7566
7039
|
const uiStaticDir = options.uiStaticDir === void 0 ? resolveUiStaticDir() : options.uiStaticDir;
|
|
@@ -7576,7 +7049,7 @@ var ServiceCommands = class {
|
|
|
7576
7049
|
sessionManager,
|
|
7577
7050
|
providerManager,
|
|
7578
7051
|
makeProvider: (nextConfig) => this.makeProvider(nextConfig, { allowMissing: true }) ?? this.makeMissingProvider(nextConfig),
|
|
7579
|
-
loadConfig: () => resolveConfigSecrets2(
|
|
7052
|
+
loadConfig: () => resolveConfigSecrets2(loadConfig13(), { configPath: runtimeConfigPath }),
|
|
7580
7053
|
getExtensionChannels: () => extensionRegistry.channels,
|
|
7581
7054
|
onRestartRequired: (paths) => {
|
|
7582
7055
|
void this.deps.requestRestart({
|
|
@@ -7587,7 +7060,7 @@ var ServiceCommands = class {
|
|
|
7587
7060
|
}
|
|
7588
7061
|
});
|
|
7589
7062
|
this.applyLiveConfigReload = async () => {
|
|
7590
|
-
await reloader.applyReloadPlan(resolveConfigSecrets2(
|
|
7063
|
+
await reloader.applyReloadPlan(resolveConfigSecrets2(loadConfig13(), { configPath: runtimeConfigPath }));
|
|
7591
7064
|
};
|
|
7592
7065
|
const gatewayController = new GatewayControllerImpl({
|
|
7593
7066
|
reloader,
|
|
@@ -7620,7 +7093,7 @@ var ServiceCommands = class {
|
|
|
7620
7093
|
resolveMessageToolHints: ({ channel, accountId }) => resolvePluginChannelMessageToolHints({
|
|
7621
7094
|
registry: pluginRegistry,
|
|
7622
7095
|
channel,
|
|
7623
|
-
cfg: resolveConfigSecrets2(
|
|
7096
|
+
cfg: resolveConfigSecrets2(loadConfig13(), { configPath: runtimeConfigPath }),
|
|
7624
7097
|
accountId
|
|
7625
7098
|
})
|
|
7626
7099
|
});
|
|
@@ -7653,12 +7126,12 @@ var ServiceCommands = class {
|
|
|
7653
7126
|
});
|
|
7654
7127
|
let pluginChannelBindings = getPluginChannelBindings3(pluginRegistry);
|
|
7655
7128
|
setPluginRuntimeBridge({
|
|
7656
|
-
loadConfig: () => toPluginConfigView(resolveConfigSecrets2(
|
|
7129
|
+
loadConfig: () => toPluginConfigView(resolveConfigSecrets2(loadConfig13(), { configPath: runtimeConfigPath }), pluginChannelBindings),
|
|
7657
7130
|
writeConfigFile: async (nextConfigView) => {
|
|
7658
7131
|
if (!nextConfigView || typeof nextConfigView !== "object" || Array.isArray(nextConfigView)) {
|
|
7659
7132
|
throw new Error("plugin runtime writeConfigFile expects an object config");
|
|
7660
7133
|
}
|
|
7661
|
-
const current =
|
|
7134
|
+
const current = loadConfig13();
|
|
7662
7135
|
const next = mergePluginConfigView(current, nextConfigView, pluginChannelBindings);
|
|
7663
7136
|
saveConfig9(next);
|
|
7664
7137
|
},
|
|
@@ -7734,12 +7207,12 @@ var ServiceCommands = class {
|
|
|
7734
7207
|
providerManager,
|
|
7735
7208
|
bus,
|
|
7736
7209
|
gatewayController,
|
|
7737
|
-
() => resolveConfigSecrets2(
|
|
7210
|
+
() => resolveConfigSecrets2(loadConfig13(), { configPath: runtimeConfigPath }),
|
|
7738
7211
|
() => extensionRegistry,
|
|
7739
7212
|
({ channel, accountId }) => resolvePluginChannelMessageToolHints({
|
|
7740
7213
|
registry: pluginRegistry,
|
|
7741
7214
|
channel,
|
|
7742
|
-
cfg: resolveConfigSecrets2(
|
|
7215
|
+
cfg: resolveConfigSecrets2(loadConfig13(), { configPath: runtimeConfigPath }),
|
|
7743
7216
|
accountId
|
|
7744
7217
|
})
|
|
7745
7218
|
);
|
|
@@ -7898,7 +7371,7 @@ var ServiceCommands = class {
|
|
|
7898
7371
|
});
|
|
7899
7372
|
}
|
|
7900
7373
|
async runForeground(options) {
|
|
7901
|
-
const config2 =
|
|
7374
|
+
const config2 = loadConfig13();
|
|
7902
7375
|
const uiConfig = resolveUiConfig(config2, options.uiOverrides);
|
|
7903
7376
|
const uiUrl = resolveUiApiBase(uiConfig.host, uiConfig.port);
|
|
7904
7377
|
if (options.open) {
|
|
@@ -7911,7 +7384,7 @@ var ServiceCommands = class {
|
|
|
7911
7384
|
});
|
|
7912
7385
|
}
|
|
7913
7386
|
async startService(options) {
|
|
7914
|
-
const config2 =
|
|
7387
|
+
const config2 = loadConfig13();
|
|
7915
7388
|
const uiConfig = resolveUiConfig(config2, options.uiOverrides);
|
|
7916
7389
|
const uiUrl = resolveUiApiBase(uiConfig.host, uiConfig.port);
|
|
7917
7390
|
const apiUrl = `${uiUrl}/api`;
|
|
@@ -7972,7 +7445,7 @@ var ServiceCommands = class {
|
|
|
7972
7445
|
}
|
|
7973
7446
|
const logPath = resolveServiceLogPath();
|
|
7974
7447
|
const logDir = resolve10(logPath, "..");
|
|
7975
|
-
|
|
7448
|
+
mkdirSync5(logDir, { recursive: true });
|
|
7976
7449
|
const logFd = openSync(logPath, "a");
|
|
7977
7450
|
const readinessTimeoutMs = this.resolveStartupTimeoutMs(options.startupTimeoutMs);
|
|
7978
7451
|
const quickPhaseTimeoutMs = Math.min(8e3, readinessTimeoutMs);
|
|
@@ -8534,10 +8007,10 @@ var ServiceCommands = class {
|
|
|
8534
8007
|
}
|
|
8535
8008
|
}
|
|
8536
8009
|
installBuiltinMarketplaceSkill(slug, force) {
|
|
8537
|
-
const workspace = getWorkspacePath9(
|
|
8538
|
-
const destination =
|
|
8539
|
-
const destinationSkillFile =
|
|
8540
|
-
if (
|
|
8010
|
+
const workspace = getWorkspacePath9(loadConfig13().agents.defaults.workspace);
|
|
8011
|
+
const destination = join6(workspace, "skills", slug);
|
|
8012
|
+
const destinationSkillFile = join6(destination, "SKILL.md");
|
|
8013
|
+
if (existsSync10(destinationSkillFile) && !force) {
|
|
8541
8014
|
return {
|
|
8542
8015
|
message: `${slug} is already installed`
|
|
8543
8016
|
};
|
|
@@ -8545,15 +8018,15 @@ var ServiceCommands = class {
|
|
|
8545
8018
|
const loader = createSkillsLoader(workspace);
|
|
8546
8019
|
const builtin = (loader?.listSkills(false) ?? []).find((skill) => skill.name === slug && skill.source === "builtin");
|
|
8547
8020
|
if (!builtin) {
|
|
8548
|
-
if (
|
|
8021
|
+
if (existsSync10(destinationSkillFile)) {
|
|
8549
8022
|
return {
|
|
8550
8023
|
message: `${slug} is already installed`
|
|
8551
8024
|
};
|
|
8552
8025
|
}
|
|
8553
8026
|
return null;
|
|
8554
8027
|
}
|
|
8555
|
-
|
|
8556
|
-
cpSync2(
|
|
8028
|
+
mkdirSync5(join6(workspace, "skills"), { recursive: true });
|
|
8029
|
+
cpSync2(dirname2(builtin.path), destination, { recursive: true, force: true });
|
|
8557
8030
|
return {
|
|
8558
8031
|
message: `Installed skill: ${slug}`
|
|
8559
8032
|
};
|
|
@@ -8611,58 +8084,12 @@ ${stderr}`.trim();
|
|
|
8611
8084
|
}
|
|
8612
8085
|
};
|
|
8613
8086
|
|
|
8614
|
-
// src/cli/remote/remote-runtime-actions.ts
|
|
8615
|
-
import { APP_NAME as APP_NAME4 } from "@nextclaw/core";
|
|
8616
|
-
var RemoteRuntimeActions = class {
|
|
8617
|
-
constructor(deps) {
|
|
8618
|
-
this.deps = deps;
|
|
8619
|
-
}
|
|
8620
|
-
async connect(opts = {}) {
|
|
8621
|
-
await this.deps.remoteCommands.connect(opts);
|
|
8622
|
-
}
|
|
8623
|
-
async enable(opts = {}) {
|
|
8624
|
-
await this.deps.initAuto("remote enable");
|
|
8625
|
-
const result = this.deps.remoteCommands.enableConfig(opts);
|
|
8626
|
-
console.log("\u2713 Remote access enabled");
|
|
8627
|
-
if (result.config.remote.deviceName.trim()) {
|
|
8628
|
-
console.log(`Device: ${result.config.remote.deviceName.trim()}`);
|
|
8629
|
-
}
|
|
8630
|
-
if (result.config.remote.platformApiBase.trim()) {
|
|
8631
|
-
console.log(`Platform: ${result.config.remote.platformApiBase.trim()}`);
|
|
8632
|
-
}
|
|
8633
|
-
if (this.hasRunningManagedService()) {
|
|
8634
|
-
await this.deps.restartBackgroundService("remote configuration updated");
|
|
8635
|
-
console.log("\u2713 Applied remote settings to running background service");
|
|
8636
|
-
return;
|
|
8637
|
-
}
|
|
8638
|
-
console.log(`Tip: Run "${APP_NAME4} start" to bring the managed remote connector online.`);
|
|
8639
|
-
}
|
|
8640
|
-
async disable() {
|
|
8641
|
-
const result = this.deps.remoteCommands.disableConfig();
|
|
8642
|
-
console.log(result.changed ? "\u2713 Remote access disabled" : "Remote access was already disabled");
|
|
8643
|
-
if (this.hasRunningManagedService()) {
|
|
8644
|
-
await this.deps.restartBackgroundService("remote access disabled");
|
|
8645
|
-
console.log("\u2713 Running background service restarted without remote access");
|
|
8646
|
-
}
|
|
8647
|
-
}
|
|
8648
|
-
async status(opts = {}) {
|
|
8649
|
-
await this.deps.remoteCommands.status(opts);
|
|
8650
|
-
}
|
|
8651
|
-
async doctor(opts = {}) {
|
|
8652
|
-
await this.deps.remoteCommands.doctor(opts);
|
|
8653
|
-
}
|
|
8654
|
-
hasRunningManagedService() {
|
|
8655
|
-
const state = readServiceState();
|
|
8656
|
-
return Boolean(state && isProcessRunning(state.pid));
|
|
8657
|
-
}
|
|
8658
|
-
};
|
|
8659
|
-
|
|
8660
8087
|
// src/cli/workspace.ts
|
|
8661
|
-
import { cpSync as cpSync3, existsSync as
|
|
8088
|
+
import { cpSync as cpSync3, existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as readFileSync9, readdirSync as readdirSync3, rmSync as rmSync5, writeFileSync as writeFileSync5 } from "fs";
|
|
8662
8089
|
import { createRequire as createRequire2 } from "module";
|
|
8663
|
-
import { dirname as
|
|
8090
|
+
import { dirname as dirname3, join as join7, resolve as resolve11 } from "path";
|
|
8664
8091
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
8665
|
-
import { APP_NAME as
|
|
8092
|
+
import { APP_NAME as APP_NAME4, getDataDir as getDataDir8 } from "@nextclaw/core";
|
|
8666
8093
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
8667
8094
|
var WorkspaceManager = class {
|
|
8668
8095
|
constructor(logo) {
|
|
@@ -8690,30 +8117,30 @@ var WorkspaceManager = class {
|
|
|
8690
8117
|
{ source: "memory/MEMORY.md", target: "memory/MEMORY.md" }
|
|
8691
8118
|
];
|
|
8692
8119
|
for (const entry of templateFiles) {
|
|
8693
|
-
const filePath =
|
|
8694
|
-
if (!force &&
|
|
8120
|
+
const filePath = join7(workspace, entry.target);
|
|
8121
|
+
if (!force && existsSync11(filePath)) {
|
|
8695
8122
|
continue;
|
|
8696
8123
|
}
|
|
8697
|
-
const templatePath =
|
|
8698
|
-
if (!
|
|
8124
|
+
const templatePath = join7(templateDir, entry.source);
|
|
8125
|
+
if (!existsSync11(templatePath)) {
|
|
8699
8126
|
console.warn(`Warning: Template file missing: ${templatePath}`);
|
|
8700
8127
|
continue;
|
|
8701
8128
|
}
|
|
8702
|
-
const raw =
|
|
8703
|
-
const content = raw.replace(/\$\{APP_NAME\}/g,
|
|
8704
|
-
|
|
8705
|
-
|
|
8129
|
+
const raw = readFileSync9(templatePath, "utf-8");
|
|
8130
|
+
const content = raw.replace(/\$\{APP_NAME\}/g, APP_NAME4);
|
|
8131
|
+
mkdirSync6(dirname3(filePath), { recursive: true });
|
|
8132
|
+
writeFileSync5(filePath, content);
|
|
8706
8133
|
created.push(entry.target);
|
|
8707
8134
|
}
|
|
8708
|
-
const memoryDir =
|
|
8709
|
-
if (!
|
|
8710
|
-
|
|
8711
|
-
created.push(
|
|
8135
|
+
const memoryDir = join7(workspace, "memory");
|
|
8136
|
+
if (!existsSync11(memoryDir)) {
|
|
8137
|
+
mkdirSync6(memoryDir, { recursive: true });
|
|
8138
|
+
created.push(join7("memory", ""));
|
|
8712
8139
|
}
|
|
8713
|
-
const skillsDir =
|
|
8714
|
-
if (!
|
|
8715
|
-
|
|
8716
|
-
created.push(
|
|
8140
|
+
const skillsDir = join7(workspace, "skills");
|
|
8141
|
+
if (!existsSync11(skillsDir)) {
|
|
8142
|
+
mkdirSync6(skillsDir, { recursive: true });
|
|
8143
|
+
created.push(join7("skills", ""));
|
|
8717
8144
|
}
|
|
8718
8145
|
const seeded = this.seedBuiltinSkills(skillsDir, { force });
|
|
8719
8146
|
if (seeded > 0) {
|
|
@@ -8732,12 +8159,12 @@ var WorkspaceManager = class {
|
|
|
8732
8159
|
if (!entry.isDirectory()) {
|
|
8733
8160
|
continue;
|
|
8734
8161
|
}
|
|
8735
|
-
const src =
|
|
8736
|
-
if (!
|
|
8162
|
+
const src = join7(sourceDir, entry.name);
|
|
8163
|
+
if (!existsSync11(join7(src, "SKILL.md"))) {
|
|
8737
8164
|
continue;
|
|
8738
8165
|
}
|
|
8739
|
-
const dest =
|
|
8740
|
-
if (!force &&
|
|
8166
|
+
const dest = join7(targetDir, entry.name);
|
|
8167
|
+
if (!force && existsSync11(dest)) {
|
|
8741
8168
|
continue;
|
|
8742
8169
|
}
|
|
8743
8170
|
try {
|
|
@@ -8754,13 +8181,13 @@ var WorkspaceManager = class {
|
|
|
8754
8181
|
try {
|
|
8755
8182
|
const require3 = createRequire2(import.meta.url);
|
|
8756
8183
|
const entry = require3.resolve("@nextclaw/core");
|
|
8757
|
-
const pkgRoot = resolve11(
|
|
8758
|
-
const distSkills =
|
|
8759
|
-
if (
|
|
8184
|
+
const pkgRoot = resolve11(dirname3(entry), "..");
|
|
8185
|
+
const distSkills = join7(pkgRoot, "dist", "skills");
|
|
8186
|
+
if (existsSync11(distSkills)) {
|
|
8760
8187
|
return distSkills;
|
|
8761
8188
|
}
|
|
8762
|
-
const srcSkills =
|
|
8763
|
-
if (
|
|
8189
|
+
const srcSkills = join7(pkgRoot, "src", "agent", "skills");
|
|
8190
|
+
if (existsSync11(srcSkills)) {
|
|
8764
8191
|
return srcSkills;
|
|
8765
8192
|
}
|
|
8766
8193
|
return null;
|
|
@@ -8775,17 +8202,17 @@ var WorkspaceManager = class {
|
|
|
8775
8202
|
}
|
|
8776
8203
|
const cliDir = resolve11(fileURLToPath4(new URL(".", import.meta.url)));
|
|
8777
8204
|
const pkgRoot = resolve11(cliDir, "..", "..");
|
|
8778
|
-
const candidates = [
|
|
8205
|
+
const candidates = [join7(pkgRoot, "templates")];
|
|
8779
8206
|
for (const candidate of candidates) {
|
|
8780
|
-
if (
|
|
8207
|
+
if (existsSync11(candidate)) {
|
|
8781
8208
|
return candidate;
|
|
8782
8209
|
}
|
|
8783
8210
|
}
|
|
8784
8211
|
return null;
|
|
8785
8212
|
}
|
|
8786
8213
|
getBridgeDir() {
|
|
8787
|
-
const userBridge =
|
|
8788
|
-
if (
|
|
8214
|
+
const userBridge = join7(getDataDir8(), "bridge");
|
|
8215
|
+
if (existsSync11(join7(userBridge, "dist", "index.js"))) {
|
|
8789
8216
|
return userBridge;
|
|
8790
8217
|
}
|
|
8791
8218
|
if (!which("npm")) {
|
|
@@ -8794,21 +8221,21 @@ var WorkspaceManager = class {
|
|
|
8794
8221
|
}
|
|
8795
8222
|
const cliDir = resolve11(fileURLToPath4(new URL(".", import.meta.url)));
|
|
8796
8223
|
const pkgRoot = resolve11(cliDir, "..", "..");
|
|
8797
|
-
const pkgBridge =
|
|
8798
|
-
const srcBridge =
|
|
8224
|
+
const pkgBridge = join7(pkgRoot, "bridge");
|
|
8225
|
+
const srcBridge = join7(pkgRoot, "..", "..", "bridge");
|
|
8799
8226
|
let source = null;
|
|
8800
|
-
if (
|
|
8227
|
+
if (existsSync11(join7(pkgBridge, "package.json"))) {
|
|
8801
8228
|
source = pkgBridge;
|
|
8802
|
-
} else if (
|
|
8229
|
+
} else if (existsSync11(join7(srcBridge, "package.json"))) {
|
|
8803
8230
|
source = srcBridge;
|
|
8804
8231
|
}
|
|
8805
8232
|
if (!source) {
|
|
8806
|
-
console.error(`Bridge source not found. Try reinstalling ${
|
|
8233
|
+
console.error(`Bridge source not found. Try reinstalling ${APP_NAME4}.`);
|
|
8807
8234
|
process.exit(1);
|
|
8808
8235
|
}
|
|
8809
8236
|
console.log(`${this.logo} Setting up bridge...`);
|
|
8810
|
-
|
|
8811
|
-
if (
|
|
8237
|
+
mkdirSync6(resolve11(userBridge, ".."), { recursive: true });
|
|
8238
|
+
if (existsSync11(userBridge)) {
|
|
8812
8239
|
rmSync5(userBridge, { recursive: true, force: true });
|
|
8813
8240
|
}
|
|
8814
8241
|
cpSync3(source, userBridge, {
|
|
@@ -8886,9 +8313,14 @@ var CliRuntime = class {
|
|
|
8886
8313
|
this.platformAuthCommands = new PlatformAuthCommands();
|
|
8887
8314
|
this.remoteCommands = new RemoteCommands();
|
|
8888
8315
|
this.remote = new RemoteRuntimeActions({
|
|
8316
|
+
appName: APP_NAME5,
|
|
8889
8317
|
initAuto: (source) => this.init({ source, auto: true }),
|
|
8890
8318
|
remoteCommands: this.remoteCommands,
|
|
8891
|
-
restartBackgroundService: (reason) => this.restartBackgroundService(reason)
|
|
8319
|
+
restartBackgroundService: (reason) => this.restartBackgroundService(reason),
|
|
8320
|
+
hasRunningManagedService: () => {
|
|
8321
|
+
const state = readServiceState();
|
|
8322
|
+
return Boolean(state && isProcessRunning(state.pid));
|
|
8323
|
+
}
|
|
8892
8324
|
});
|
|
8893
8325
|
this.diagnosticsCommands = new DiagnosticsCommands({ logo: this.logo });
|
|
8894
8326
|
this.restartCoordinator = new RestartCoordinator({
|
|
@@ -8920,7 +8352,7 @@ var CliRuntime = class {
|
|
|
8920
8352
|
const uiHost = FORCED_PUBLIC_UI_HOST;
|
|
8921
8353
|
const uiPort = typeof state.uiPort === "number" && Number.isFinite(state.uiPort) ? state.uiPort : 18791;
|
|
8922
8354
|
console.log(
|
|
8923
|
-
`Applying changes (${reason}): restarting ${
|
|
8355
|
+
`Applying changes (${reason}): restarting ${APP_NAME5} background service...`
|
|
8924
8356
|
);
|
|
8925
8357
|
await this.serviceCommands.stopService();
|
|
8926
8358
|
await this.serviceCommands.startService({
|
|
@@ -9075,7 +8507,7 @@ var CliRuntime = class {
|
|
|
9075
8507
|
}
|
|
9076
8508
|
async onboard() {
|
|
9077
8509
|
console.warn(
|
|
9078
|
-
`Warning: ${
|
|
8510
|
+
`Warning: ${APP_NAME5} onboard is deprecated. Use "${APP_NAME5} init" instead.`
|
|
9079
8511
|
);
|
|
9080
8512
|
await this.init({ source: "onboard" });
|
|
9081
8513
|
}
|
|
@@ -9085,16 +8517,16 @@ var CliRuntime = class {
|
|
|
9085
8517
|
const force = Boolean(options.force);
|
|
9086
8518
|
const configPath = getConfigPath7();
|
|
9087
8519
|
let createdConfig = false;
|
|
9088
|
-
if (!
|
|
8520
|
+
if (!existsSync12(configPath)) {
|
|
9089
8521
|
const config3 = ConfigSchema2.parse({});
|
|
9090
8522
|
saveConfig10(config3);
|
|
9091
8523
|
createdConfig = true;
|
|
9092
8524
|
}
|
|
9093
|
-
const config2 =
|
|
8525
|
+
const config2 = loadConfig14();
|
|
9094
8526
|
const workspaceSetting = config2.agents.defaults.workspace;
|
|
9095
|
-
const workspacePath = !workspaceSetting || workspaceSetting === DEFAULT_WORKSPACE_PATH ?
|
|
9096
|
-
const workspaceExisted =
|
|
9097
|
-
|
|
8527
|
+
const workspacePath = !workspaceSetting || workspaceSetting === DEFAULT_WORKSPACE_PATH ? join8(getDataDir9(), DEFAULT_WORKSPACE_DIR) : expandHome2(workspaceSetting);
|
|
8528
|
+
const workspaceExisted = existsSync12(workspacePath);
|
|
8529
|
+
mkdirSync7(workspacePath, { recursive: true });
|
|
9098
8530
|
const templateResult = this.workspaceManager.createWorkspaceTemplates(
|
|
9099
8531
|
workspacePath,
|
|
9100
8532
|
{ force }
|
|
@@ -9113,13 +8545,13 @@ var CliRuntime = class {
|
|
|
9113
8545
|
}
|
|
9114
8546
|
if (!options.auto) {
|
|
9115
8547
|
console.log(`
|
|
9116
|
-
${this.logo} ${
|
|
8548
|
+
${this.logo} ${APP_NAME5} is ready! (${source})`);
|
|
9117
8549
|
console.log("\nNext steps:");
|
|
9118
8550
|
console.log(` 1. Add your API key to ${configPath}`);
|
|
9119
|
-
console.log(` 2. Chat: ${
|
|
8551
|
+
console.log(` 2. Chat: ${APP_NAME5} agent -m "Hello!"`);
|
|
9120
8552
|
} else {
|
|
9121
8553
|
console.log(
|
|
9122
|
-
`Tip: Run "${
|
|
8554
|
+
`Tip: Run "${APP_NAME5} init${force ? " --force" : ""}" to re-run initialization if needed.`
|
|
9123
8555
|
);
|
|
9124
8556
|
}
|
|
9125
8557
|
}
|
|
@@ -9177,7 +8609,7 @@ ${this.logo} ${APP_NAME6} is ready! (${source})`);
|
|
|
9177
8609
|
await this.writeRestartSentinelFromExecContext("cli.restart");
|
|
9178
8610
|
const state = readServiceState();
|
|
9179
8611
|
if (state && isProcessRunning(state.pid)) {
|
|
9180
|
-
console.log(`Restarting ${
|
|
8612
|
+
console.log(`Restarting ${APP_NAME5}...`);
|
|
9181
8613
|
await this.serviceCommands.stopService();
|
|
9182
8614
|
} else if (state) {
|
|
9183
8615
|
clearServiceState();
|
|
@@ -9217,7 +8649,7 @@ ${this.logo} ${APP_NAME6} is ready! (${source})`);
|
|
|
9217
8649
|
}
|
|
9218
8650
|
async agent(opts) {
|
|
9219
8651
|
const configPath = getConfigPath7();
|
|
9220
|
-
const config2 = resolveConfigSecrets3(
|
|
8652
|
+
const config2 = resolveConfigSecrets3(loadConfig14(), { configPath });
|
|
9221
8653
|
const workspace = getWorkspacePath10(config2.agents.defaults.workspace);
|
|
9222
8654
|
const pluginRegistry = loadPluginRegistry(config2, workspace);
|
|
9223
8655
|
const extensionRegistry = toExtensionRegistry(pluginRegistry);
|
|
@@ -9225,7 +8657,7 @@ ${this.logo} ${APP_NAME6} is ready! (${source})`);
|
|
|
9225
8657
|
const pluginChannelBindings = getPluginChannelBindings4(pluginRegistry);
|
|
9226
8658
|
setPluginRuntimeBridge2({
|
|
9227
8659
|
loadConfig: () => toPluginConfigView(
|
|
9228
|
-
resolveConfigSecrets3(
|
|
8660
|
+
resolveConfigSecrets3(loadConfig14(), { configPath }),
|
|
9229
8661
|
pluginChannelBindings
|
|
9230
8662
|
),
|
|
9231
8663
|
writeConfigFile: async (nextConfigView) => {
|
|
@@ -9234,7 +8666,7 @@ ${this.logo} ${APP_NAME6} is ready! (${source})`);
|
|
|
9234
8666
|
"plugin runtime writeConfigFile expects an object config"
|
|
9235
8667
|
);
|
|
9236
8668
|
}
|
|
9237
|
-
const current =
|
|
8669
|
+
const current = loadConfig14();
|
|
9238
8670
|
const next = mergePluginConfigView(
|
|
9239
8671
|
current,
|
|
9240
8672
|
nextConfigView,
|
|
@@ -9266,7 +8698,7 @@ ${this.logo} ${APP_NAME6} is ready! (${source})`);
|
|
|
9266
8698
|
resolveMessageToolHints: ({ channel, accountId }) => resolvePluginChannelMessageToolHints2({
|
|
9267
8699
|
registry: pluginRegistry,
|
|
9268
8700
|
channel,
|
|
9269
|
-
cfg: resolveConfigSecrets3(
|
|
8701
|
+
cfg: resolveConfigSecrets3(loadConfig14(), { configPath }),
|
|
9270
8702
|
accountId
|
|
9271
8703
|
})
|
|
9272
8704
|
});
|
|
@@ -9285,10 +8717,10 @@ ${this.logo} ${APP_NAME6} is ready! (${source})`);
|
|
|
9285
8717
|
`${this.logo} Interactive mode (type exit or Ctrl+C to quit)
|
|
9286
8718
|
`
|
|
9287
8719
|
);
|
|
9288
|
-
const historyFile =
|
|
8720
|
+
const historyFile = join8(getDataDir9(), "history", "cli_history");
|
|
9289
8721
|
const historyDir = resolve12(historyFile, "..");
|
|
9290
|
-
|
|
9291
|
-
const history =
|
|
8722
|
+
mkdirSync7(historyDir, { recursive: true });
|
|
8723
|
+
const history = existsSync12(historyFile) ? readFileSync10(historyFile, "utf-8").split("\n").filter(Boolean) : [];
|
|
9292
8724
|
const rl = createInterface3({
|
|
9293
8725
|
input: process.stdin,
|
|
9294
8726
|
output: process.stdout
|
|
@@ -9297,7 +8729,7 @@ ${this.logo} ${APP_NAME6} is ready! (${source})`);
|
|
|
9297
8729
|
const merged = history.concat(
|
|
9298
8730
|
rl.history ?? []
|
|
9299
8731
|
);
|
|
9300
|
-
|
|
8732
|
+
writeFileSync6(historyFile, merged.join("\n"));
|
|
9301
8733
|
process.exit(0);
|
|
9302
8734
|
});
|
|
9303
8735
|
let running = true;
|
|
@@ -9367,7 +8799,7 @@ ${this.logo} ${APP_NAME6} is ready! (${source})`);
|
|
|
9367
8799
|
}
|
|
9368
8800
|
const state = readServiceState();
|
|
9369
8801
|
if (state && isProcessRunning(state.pid)) {
|
|
9370
|
-
console.log(`Tip: restart ${
|
|
8802
|
+
console.log(`Tip: restart ${APP_NAME5} to apply the update.`);
|
|
9371
8803
|
}
|
|
9372
8804
|
}
|
|
9373
8805
|
pluginsList(opts = {}) {
|
|
@@ -9461,7 +8893,7 @@ ${this.logo} ${APP_NAME6} is ready! (${source})`);
|
|
|
9461
8893
|
await this.diagnosticsCommands.doctor(opts);
|
|
9462
8894
|
}
|
|
9463
8895
|
async skillsInstall(options) {
|
|
9464
|
-
const config2 =
|
|
8896
|
+
const config2 = loadConfig14();
|
|
9465
8897
|
const workdir = resolveSkillsInstallWorkdir({
|
|
9466
8898
|
explicitWorkdir: options.workdir,
|
|
9467
8899
|
configuredWorkspace: config2.agents.defaults.workspace
|
|
@@ -9522,32 +8954,22 @@ ${this.logo} ${APP_NAME6} is ready! (${source})`);
|
|
|
9522
8954
|
}
|
|
9523
8955
|
};
|
|
9524
8956
|
|
|
9525
|
-
// src/cli/remote/register-remote-commands.ts
|
|
9526
|
-
function registerRemoteCommands(program2, runtime2) {
|
|
9527
|
-
const remote = program2.command("remote").description("Manage remote access");
|
|
9528
|
-
remote.command("enable").description("Enable service-managed remote access").option("--api-base <url>", "Platform API base (supports /v1 suffix)").option("--name <name>", "Device display name").action(async (opts) => runtime2.enable(opts));
|
|
9529
|
-
remote.command("disable").description("Disable service-managed remote access").action(async () => runtime2.disable());
|
|
9530
|
-
remote.command("status").description("Show remote access status").option("--json", "Print JSON").action(async (opts) => runtime2.status(opts));
|
|
9531
|
-
remote.command("doctor").description("Run remote access diagnostics").option("--json", "Print JSON").action(async (opts) => runtime2.doctor(opts));
|
|
9532
|
-
remote.command("connect").description("Foreground debug mode: register this machine 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) => runtime2.connect(opts));
|
|
9533
|
-
}
|
|
9534
|
-
|
|
9535
8957
|
// src/cli/index.ts
|
|
9536
8958
|
var program = new Command();
|
|
9537
8959
|
var runtime = new CliRuntime({ logo: LOGO });
|
|
9538
|
-
program.name(
|
|
9539
|
-
program.command("onboard").description(`Initialize ${
|
|
9540
|
-
program.command("init").description(`Initialize ${
|
|
8960
|
+
program.name(APP_NAME6).description(`${LOGO} ${APP_NAME6} - ${APP_TAGLINE}`).version(getPackageVersion(), "-v, --version", "show version");
|
|
8961
|
+
program.command("onboard").description(`Initialize ${APP_NAME6} configuration and workspace`).action(async () => runtime.onboard());
|
|
8962
|
+
program.command("init").description(`Initialize ${APP_NAME6} configuration and workspace`).option("-f, --force", "Overwrite existing template files").action(async (opts) => runtime.init({ force: Boolean(opts.force) }));
|
|
9541
8963
|
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));
|
|
9542
8964
|
registerRemoteCommands(program, runtime.remote);
|
|
9543
|
-
program.command("gateway").description(`Start the ${
|
|
9544
|
-
program.command("ui").description(`Start the ${
|
|
9545
|
-
program.command("start").description(`Start the ${
|
|
9546
|
-
program.command("restart").description(`Restart the ${
|
|
9547
|
-
program.command("serve").description(`Run the ${
|
|
9548
|
-
program.command("stop").description(`Stop the ${
|
|
8965
|
+
program.command("gateway").description(`Start the ${APP_NAME6} 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));
|
|
8966
|
+
program.command("ui").description(`Start the ${APP_NAME6} UI with gateway`).option("--port <port>", "UI port").option("--no-open", "Disable opening browser").action(async (opts) => runtime.ui(opts));
|
|
8967
|
+
program.command("start").description(`Start the ${APP_NAME6} 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));
|
|
8968
|
+
program.command("restart").description(`Restart the ${APP_NAME6} background service`).option("--ui-port <port>", "UI port").option("--start-timeout <ms>", "Maximum wait time for startup readiness in milliseconds").option("--open", "Open browser after restart", false).action(async (opts) => runtime.restart(opts));
|
|
8969
|
+
program.command("serve").description(`Run the ${APP_NAME6} gateway + UI in the foreground`).option("--ui-port <port>", "UI port").option("--open", "Open browser after start", false).action(async (opts) => runtime.serve(opts));
|
|
8970
|
+
program.command("stop").description(`Stop the ${APP_NAME6} background service`).action(async () => runtime.stop());
|
|
9549
8971
|
program.command("agent").description("Interact with the agent directly").option("-m, --message <message>", "Message to send to the agent").option("-s, --session <session>", "Session ID", "cli:default").option("--model <model>", "Session model override for this run").option("--no-markdown", "Disable Markdown rendering").action(async (opts) => runtime.agent(opts));
|
|
9550
|
-
program.command("update").description(`Update ${
|
|
8972
|
+
program.command("update").description(`Update ${APP_NAME6}`).option("--timeout <ms>", "Update command timeout in milliseconds").action(async (opts) => runtime.update(opts));
|
|
9551
8973
|
var skills = program.command("skills").description("Manage skills");
|
|
9552
8974
|
skills.command("install <slug>").description("Install a skill from NextClaw marketplace").option("--api-base <url>", "Marketplace API base URL").option("--workdir <dir>", "Workspace directory to install into").option("--dir <dir>", "Skills directory name (default: skills)").option("-f, --force", "Overwrite existing skill files", false).action(async (slug, opts) => runtime.skillsInstall({ slug, ...opts, apiBaseUrl: opts.apiBase }));
|
|
9553
8975
|
var withRepeatableTag = (value, previous = []) => [...previous, value];
|
|
@@ -9592,6 +9014,6 @@ cron.command("add").requiredOption("-n, --name <name>", "Job name").requiredOpti
|
|
|
9592
9014
|
cron.command("remove <jobId>").action((jobId) => runtime.cronRemove(jobId));
|
|
9593
9015
|
cron.command("enable <jobId>").option("--disable", "Disable instead of enable").action((jobId, opts) => runtime.cronEnable(jobId, opts));
|
|
9594
9016
|
cron.command("run <jobId>").option("-f, --force", "Run even if disabled").action(async (jobId, opts) => runtime.cronRun(jobId, opts));
|
|
9595
|
-
program.command("status").description(`Show ${
|
|
9596
|
-
program.command("doctor").description(`Run ${
|
|
9017
|
+
program.command("status").description(`Show ${APP_NAME6} status`).option("--json", "Output JSON", false).option("--verbose", "Show extra diagnostics", false).option("--fix", "Fix stale service state when safe", false).action(async (opts) => runtime.status(opts));
|
|
9018
|
+
program.command("doctor").description(`Run ${APP_NAME6} diagnostics`).option("--json", "Output JSON", false).option("--verbose", "Show extra diagnostics", false).option("--fix", "Fix stale service state when safe", false).action(async (opts) => runtime.doctor(opts));
|
|
9597
9019
|
program.parseAsync(process.argv);
|