nextclaw 0.18.12-beta.2 → 0.18.12-beta.21
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/app/index.js +908 -266
- package/dist/cli/launcher/index.js +8 -3
- package/dist/{npm-runtime-update-state.store-DaF0iDY9.js → npm-runtime-update-state.store-75vzvn0B.js} +200 -30
- package/package.json +17 -16
- package/resources/USAGE.md +41 -1
- package/ui-dist/assets/api-Dai6UR3J.js +15 -0
- package/ui-dist/assets/app-manager-provider-BZr5VxCe.js +1 -0
- package/ui-dist/assets/app-navigation.config-BjIj_FLm.js +1 -0
- package/ui-dist/assets/{book-open-C5p9re7m.js → book-open-DgLqYpNY.js} +1 -1
- package/ui-dist/assets/channels-list-page-L6FFtRYn.js +8 -0
- package/ui-dist/assets/{chat-a-_X0PmT.js → chat-ZQIVJChB.js} +7 -7
- package/ui-dist/assets/chat-page-CR1yI96r.js +1 -0
- package/ui-dist/assets/chunk-JZWAC4HX-u4uYphxM.js +3 -0
- package/ui-dist/assets/{config-split-page-YB7xRSn7.js → config-split-page-BMRGuCJQ.js} +1 -1
- package/ui-dist/assets/{createLucideIcon-D48LQ7_3.js → createLucideIcon-BZkY6emz.js} +1 -1
- package/ui-dist/assets/desktop-update-config-AXzb7OEa.js +1 -0
- package/ui-dist/assets/{dialog-BNdeIVqc.js → dialog-DgybjpeU.js} +1 -1
- package/ui-dist/assets/{dist-BjUfmI6n.js → dist-CxcPOISF.js} +1 -1
- package/ui-dist/assets/{doc-browser-CX_BvO6R.js → doc-browser-BUlCkZo2.js} +1 -1
- package/ui-dist/assets/{doc-browser-CLdhFEsz.js → doc-browser-CzCV73NJ.js} +1 -1
- package/ui-dist/assets/doc-browser-Doh2541x.js +1 -0
- package/ui-dist/assets/{doc-browser-context-5mbkyvid.js → doc-browser-context-DfLHAWbG.js} +1 -1
- package/ui-dist/assets/{es2015-Db-PtAnL.js → es2015-BVRlEE06.js} +1 -1
- package/ui-dist/assets/{external-link-BwNyDSMe.js → external-link-Sw3ah_JD.js} +1 -1
- package/ui-dist/assets/{folder-BSLCUICp.js → folder-D7-VTnkz.js} +1 -1
- package/ui-dist/assets/{hash-DpL5u6Fu.js → hash-zajSTDXZ.js} +1 -1
- package/ui-dist/assets/i18n-C5Mibli1.js +1 -0
- package/ui-dist/assets/index-B7RsQ-ne.js +2 -0
- package/ui-dist/assets/index-D8MKmXtO.css +1 -0
- package/ui-dist/assets/{key-round-BNTFD7Jk.js → key-round-CnI1mc9F.js} +1 -1
- package/ui-dist/assets/loader-circle-B5i8oMMY.js +1 -0
- package/ui-dist/assets/{logo-badge-a-OsoTKw.js → logo-badge-BQgKnVtz.js} +1 -1
- package/ui-dist/assets/{logos--4c27B_Z.js → logos-CqVm0q0W.js} +1 -1
- package/ui-dist/assets/marketplace-page-Bj55-6F2.js +1 -0
- package/ui-dist/assets/{marketplace-page-PA3qcNzv.js → marketplace-page-ClRW-W3g.js} +2 -2
- package/ui-dist/assets/mcp-marketplace-page-DtngnIi0.js +40 -0
- package/ui-dist/assets/mcp-marketplace-page-_Wu2VnHy.js +1 -0
- package/ui-dist/assets/message-square-D6Z4NwpG.js +1 -0
- package/ui-dist/assets/{model-config-C3-m1Sua.js → model-config-D_y8F0j6.js} +1 -1
- package/ui-dist/assets/{notice-card-DE4jOEXF.js → notice-card-uzwjFyML.js} +1 -1
- package/ui-dist/assets/play-D8WJLnJe.js +1 -0
- package/ui-dist/assets/plus-Di0KAkiO.js +1 -0
- package/ui-dist/assets/{popover-B6dtrFF5.js → popover-C8tMB7tR.js} +1 -1
- package/ui-dist/assets/{provider-scoped-model-input-BkpcdlQB.js → provider-scoped-model-input-ORZutTDv.js} +1 -1
- package/ui-dist/assets/{providers-list-EzKC5s0y.js → providers-list-DSc3d8me.js} +1 -1
- package/ui-dist/assets/refresh-ccw-Bii4w8aB.js +1 -0
- package/ui-dist/assets/refresh-cw-BxojR62w.js +1 -0
- package/ui-dist/assets/remote-rWiu3cys.js +1 -0
- package/ui-dist/assets/{rotate-cw-CeTNbfMs.js → rotate-cw-1Xqa7LZ8.js} +1 -1
- package/ui-dist/assets/runtime-config-page-B4uSax1I.js +1 -0
- package/ui-dist/assets/{save-B8Rym7bl.js → save--BVI5wZX.js} +1 -1
- package/ui-dist/assets/{search-config-CNh9FS_N.js → search-config-CaqqlsdW.js} +1 -1
- package/ui-dist/assets/{search-BUGoDsjN.js → search-vChioOoe.js} +1 -1
- package/ui-dist/assets/{secrets-config-Bau56GeM.js → secrets-config-llf5ROde.js} +2 -2
- package/ui-dist/assets/{select-BuXrS7g3.js → select-uO-zhYsH.js} +1 -1
- package/ui-dist/assets/{sessions-config-page-BDF04GaS.js → sessions-config-page-BqOXte9x.js} +2 -2
- package/ui-dist/assets/{setting-row-CifMdz8g.js → setting-row-BIiXR4hx.js} +1 -1
- package/ui-dist/assets/settings-CiRChctQ.js +1 -0
- package/ui-dist/assets/skeleton-CFQRIUzt.js +1 -0
- package/ui-dist/assets/{sparkles-Bo0DxmaB.js → sparkles-D1ZKWdm4.js} +1 -1
- package/ui-dist/assets/{status-dot-CS7yRd9c.js → status-dot-Dv_hiUVa.js} +1 -1
- package/ui-dist/assets/{tabs-custom-HBN-j_Kn.js → tabs-custom-CsACkVji.js} +1 -1
- package/ui-dist/assets/{tag-chip-BZSHb3cE.js → tag-chip-DVbgpsYW.js} +1 -1
- package/ui-dist/assets/theme-provider-BU77FNSB.js +1 -0
- package/ui-dist/assets/{tooltip-BMz2ki-V.js → tooltip-CvAtG-kT.js} +1 -1
- package/ui-dist/assets/{trash-2-gWTb2oNS.js → trash-2-rY9ZteZX.js} +1 -1
- package/ui-dist/assets/use-config-D2QgG7qc.js +1 -0
- package/ui-dist/assets/{use-confirm-dialog-DLVARUvb.js → use-confirm-dialog-BBClFV8E.js} +1 -1
- package/ui-dist/assets/{use-infinite-scroll-loader-BdGMvR3y.js → use-infinite-scroll-loader-CWzpUecQ.js} +1 -1
- package/ui-dist/assets/{use-viewport-layout-DOqJ0LPT.js → use-viewport-layout-C6EN0_eq.js} +1 -1
- package/ui-dist/assets/x-DpTzXQcX.js +1 -0
- package/ui-dist/index.html +40 -36
- package/ui-dist/assets/api-BsY-53_V.js +0 -15
- package/ui-dist/assets/app-manager-provider-DTrWjVLB.js +0 -1
- package/ui-dist/assets/channels-list-page-CZAdoJ3s.js +0 -8
- package/ui-dist/assets/chat-page-BCypc4bi.js +0 -1
- package/ui-dist/assets/chunk-JZWAC4HX-CD1w8mri.js +0 -3
- package/ui-dist/assets/desktop-B9azAgEh.js +0 -2
- package/ui-dist/assets/desktop-update-config-Dm_cedSL.js +0 -1
- package/ui-dist/assets/doc-browser-eF2QWInq.js +0 -1
- package/ui-dist/assets/i18n-jGA3YQz4.js +0 -1
- package/ui-dist/assets/index-CUmk8xFK.css +0 -1
- package/ui-dist/assets/index-o_M3x0GR.js +0 -2
- package/ui-dist/assets/loader-circle-C3XJNZy7.js +0 -1
- package/ui-dist/assets/marketplace-page-DvmfPCAY.js +0 -1
- package/ui-dist/assets/mcp-marketplace-page-Dl8wdAtD.js +0 -1
- package/ui-dist/assets/mcp-marketplace-page-DukryaOq.js +0 -40
- package/ui-dist/assets/play-DGBx1fWI.js +0 -1
- package/ui-dist/assets/plus-CUuByV8j.js +0 -1
- package/ui-dist/assets/remote-Xzy42m-0.js +0 -1
- package/ui-dist/assets/runtime-config-page-DAMnv5Xp.js +0 -1
- package/ui-dist/assets/settings-COxdZHdu.js +0 -1
- package/ui-dist/assets/skeleton-DW5F83p8.js +0 -1
- package/ui-dist/assets/use-config-Ds7DyaYQ.js +0 -1
- package/ui-dist/assets/x-CxanI1fH.js +0 -1
- /package/ui-dist/assets/{config-hints-fDrYfl0l.js → config-hints-MogHYQ8G.js} +0 -0
package/dist/cli/app/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { S as waitForExit, _ as resolvePublicIp, a as compareNpmRuntimeVersions, b as resolveUiConfig, c as NpmRuntimeBundleLayoutStore, d as getPackageVersion$1, f as isLoopbackHost, g as prompt, h as printAgentResponse, i as NpmRuntimeBundleService, l as findExecutableOnPath, m as openBrowser, n as NpmRuntimeUpdateSourceService, o as resolveEffectiveNpmRuntimeVersion, p as isProcessRunning, t as NpmRuntimeUpdateStateStore, u as findListeningProcessByPort, v as resolveServiceLogPath, x as resolveUiStaticDir, y as resolveUiApiBase } from "../../npm-runtime-update-state.store-75vzvn0B.js";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import * as NextclawCore from "@nextclaw/core";
|
|
5
|
-
import { APP_NAME, APP_TAGLINE, AgentRouteResolver, BUILTIN_MAIN_AGENT_ID, ChannelManager, CommandRegistry, ConfigSchema, ContextBuilder, CronService, CronTool, DEFAULT_WORKSPACE_DIR, DEFAULT_WORKSPACE_PATH, DisposableStore, EditFileTool, ExecTool, ExtensionToolAdapter, FileLogSink, GatewayTool, InputBudgetPruner, LLMProvider, ListDirTool, MemoryGetTool, MemorySearchTool, MessageBus, MessageTool, ProviderManager, ReadFileTool, RequestedSkillsMetadataReader, SessionManager, SessionsHistoryTool, SessionsListTool, SkillsLoader, Tool, ToolRegistry, WebFetchTool, WebSearchTool, WriteFileTool, buildConfigSchema, buildMinimalSystemExecutionPrompt, buildReloadPlan, buildToolCatalogEntries, createAgentProfile, createAssistantStreamDeltaControlMessage, createAssistantStreamResetControlMessage, createGlobalTypedEventBus, createTypedEventKey, createTypingStopControlMessage, diffConfigPaths, expandHome, findEffectiveAgentProfile, getAppLogger, getConfigPath, getDataDir, getDataPath, getLoggingRuntime, getWorkspacePath, hasSecretRef, loadConfig, normalizeInlineSecretRefs, parseAgentScopedSessionKey, parseThinkingLevel, readSessionProjectRoot, redactConfigObject, removeAgentProfile, resolveAppLogPath, resolveConfigSecrets, resolveDefaultAgentProfileId, resolveEffectiveAgentProfiles, resolveLocalUiBaseUrl, resolveProviderRuntime, resolveSessionWorkspacePath, resolveThinkingLevel, saveConfig, toDisposable, updateAgentProfile } from "@nextclaw/core";
|
|
5
|
+
import { APP_NAME, APP_TAGLINE, AgentRouteResolver, BUILTIN_MAIN_AGENT_ID, ChannelManager, CommandRegistry, ConfigSchema, ContextBuilder, CronService, CronTool, DEFAULT_WORKSPACE_DIR, DEFAULT_WORKSPACE_PATH, DisposableStore, EditFileTool, ExecTool, ExtensionToolAdapter, FileLogSink, GatewayTool, InputBudgetPruner, LLMProvider, ListDirTool, MemoryGetTool, MemorySearchTool, MessageBus, MessageTool, ProviderManager, ReadFileTool, RequestedSkillsMetadataReader, SessionManager, SessionsHistoryTool, SessionsListTool, SkillsLoader, Tool, ToolRegistry, WebFetchTool, WebSearchTool, WriteFileTool, buildConfigSchema, buildMinimalSystemExecutionPrompt, buildReloadPlan, buildToolCatalogEntries, createAgentProfile, createAssistantStreamDeltaControlMessage, createAssistantStreamResetControlMessage, createExternalCommandEnv, createGlobalTypedEventBus, createTypedEventKey, createTypingStopControlMessage, diffConfigPaths, expandHome, findEffectiveAgentProfile, getAppLogger, getConfigPath, getDataDir, getDataPath, getLoggingRuntime, getWorkspacePath, hasSecretRef, loadConfig, normalizeInlineSecretRefs, parseAgentScopedSessionKey, parseThinkingLevel, readSessionProjectRoot, redactConfigObject, removeAgentProfile, resolveAppLogPath, resolveConfigSecrets, resolveDefaultAgentProfileId, resolveEffectiveAgentProfiles, resolveLocalUiBaseUrl, resolveProviderRuntime, resolveSessionWorkspacePath, resolveThinkingLevel, saveConfig, toDisposable, updateAgentProfile } from "@nextclaw/core";
|
|
6
6
|
import { Command } from "commander";
|
|
7
7
|
import fs, { appendFileSync, closeSync, constants, cpSync, existsSync, mkdirSync, openSync, readFileSync, readdirSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
|
|
8
8
|
import path, { basename, delimiter, dirname, extname, isAbsolute, join, relative, resolve, sep, win32 } from "node:path";
|
|
@@ -30,6 +30,7 @@ import { setImmediate as setImmediate$1, setTimeout as setTimeout$1 } from "node
|
|
|
30
30
|
import { request } from "node:http";
|
|
31
31
|
import { request as request$1 } from "node:https";
|
|
32
32
|
import chokidar from "chokidar";
|
|
33
|
+
import { eventKeys, nextclaw } from "@nextclaw/kernel";
|
|
33
34
|
import { parse } from "yaml";
|
|
34
35
|
//#region \0rolldown/runtime.js
|
|
35
36
|
var __create = Object.create;
|
|
@@ -168,7 +169,7 @@ function maskToken(value) {
|
|
|
168
169
|
if (value.length <= 12) return "<redacted>";
|
|
169
170
|
return `${value.slice(0, 6)}...${value.slice(-4)}`;
|
|
170
171
|
}
|
|
171
|
-
function normalizeOptionalString$
|
|
172
|
+
function normalizeOptionalString$9(value) {
|
|
172
173
|
if (typeof value !== "string") return;
|
|
173
174
|
const trimmed = value.trim();
|
|
174
175
|
return trimmed.length > 0 ? trimmed : void 0;
|
|
@@ -266,8 +267,8 @@ var RemotePlatformClient = class {
|
|
|
266
267
|
if (tokenState.reason === "missing") throw new Error("NextClaw platform token is missing. Run \"nextclaw login\" first.");
|
|
267
268
|
if (tokenState.reason === "expired") throw new Error("NextClaw platform token expired. Run \"nextclaw login\" or browser sign-in again.");
|
|
268
269
|
if (tokenState.reason === "malformed") throw new Error("NextClaw platform token is invalid. Run \"nextclaw login\" again.");
|
|
269
|
-
const configuredApiBase = normalizeOptionalString$
|
|
270
|
-
const rawApiBase = normalizeOptionalString$
|
|
270
|
+
const configuredApiBase = normalizeOptionalString$9(config.remote.platformApiBase) ?? (typeof nextclawProvider?.apiBase === "string" ? nextclawProvider.apiBase.trim() : "");
|
|
271
|
+
const rawApiBase = normalizeOptionalString$9(opts.apiBase) ?? configuredApiBase;
|
|
271
272
|
if (!rawApiBase) throw new Error("Platform API base is missing. Pass --api-base, run nextclaw login, or set remote.platformApiBase.");
|
|
272
273
|
return {
|
|
273
274
|
platformBase: this.deps.resolvePlatformBase(rawApiBase),
|
|
@@ -276,14 +277,14 @@ var RemotePlatformClient = class {
|
|
|
276
277
|
};
|
|
277
278
|
}
|
|
278
279
|
resolveLocalOrigin(config, opts) {
|
|
279
|
-
const explicitOrigin = normalizeOptionalString$
|
|
280
|
+
const explicitOrigin = normalizeOptionalString$9(opts.localOrigin);
|
|
280
281
|
if (explicitOrigin) return explicitOrigin.replace(/\/$/, "");
|
|
281
282
|
const state = this.deps.readManagedServiceState?.();
|
|
282
283
|
if (state && this.deps.isProcessRunning?.(state.pid) && Number.isFinite(state.uiPort)) return `http://127.0.0.1:${state.uiPort}`;
|
|
283
284
|
return `http://127.0.0.1:${typeof config.ui?.port === "number" && Number.isFinite(config.ui.port) ? config.ui.port : 55667}`;
|
|
284
285
|
}
|
|
285
286
|
resolveDisplayName(config, opts) {
|
|
286
|
-
return normalizeOptionalString$
|
|
287
|
+
return normalizeOptionalString$9(opts.name) ?? normalizeOptionalString$9(config.remote.deviceName) ?? hostname();
|
|
287
288
|
}
|
|
288
289
|
};
|
|
289
290
|
//#endregion
|
|
@@ -4493,7 +4494,7 @@ var RemoteConnector = class {
|
|
|
4493
4494
|
};
|
|
4494
4495
|
//#endregion
|
|
4495
4496
|
//#region ../nextclaw-remote/src/remote-status-store.ts
|
|
4496
|
-
function normalizeOptionalString$
|
|
4497
|
+
function normalizeOptionalString$8(value) {
|
|
4497
4498
|
if (typeof value !== "string") return;
|
|
4498
4499
|
const trimmed = value.trim();
|
|
4499
4500
|
return trimmed.length > 0 ? trimmed : void 0;
|
|
@@ -4504,8 +4505,8 @@ function buildConfiguredRemoteState(config) {
|
|
|
4504
4505
|
enabled: Boolean(remote.enabled),
|
|
4505
4506
|
mode: "service",
|
|
4506
4507
|
state: remote.enabled ? "disconnected" : "disabled",
|
|
4507
|
-
...normalizeOptionalString$
|
|
4508
|
-
...normalizeOptionalString$
|
|
4508
|
+
...normalizeOptionalString$8(remote.deviceName) ? { deviceName: normalizeOptionalString$8(remote.deviceName) } : {},
|
|
4509
|
+
...normalizeOptionalString$8(remote.platformApiBase) ? { platformBase: normalizeOptionalString$8(remote.platformApiBase) } : {},
|
|
4509
4510
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4510
4511
|
};
|
|
4511
4512
|
}
|
|
@@ -4518,7 +4519,7 @@ function resolveRemoteStatusSnapshot(params) {
|
|
|
4518
4519
|
configuredEnabled: true,
|
|
4519
4520
|
runtime: {
|
|
4520
4521
|
...buildConfiguredRemoteState(params.config),
|
|
4521
|
-
deviceName: normalizeOptionalString$
|
|
4522
|
+
deviceName: normalizeOptionalString$8(params.config.remote.deviceName) ?? normalizeOptionalString$8(params.fallbackDeviceName) ?? hostname()
|
|
4522
4523
|
}
|
|
4523
4524
|
};
|
|
4524
4525
|
return {
|
|
@@ -5062,28 +5063,12 @@ function parseSessionKey(sessionKey) {
|
|
|
5062
5063
|
};
|
|
5063
5064
|
}
|
|
5064
5065
|
//#endregion
|
|
5065
|
-
//#region src/cli/shared/utils/
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
if (value === void 0) return;
|
|
5072
|
-
const parsed = Number(value);
|
|
5073
|
-
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
5074
|
-
console.error("Invalid --start-timeout value. Provide milliseconds (e.g. 45000).");
|
|
5075
|
-
process.exit(1);
|
|
5076
|
-
}
|
|
5077
|
-
return Math.floor(parsed);
|
|
5078
|
-
}
|
|
5079
|
-
function resolveManagedServiceUiOverrides(params) {
|
|
5080
|
-
const uiOverrides = {
|
|
5081
|
-
enabled: true,
|
|
5082
|
-
host: params.forcedPublicHost,
|
|
5083
|
-
open: false
|
|
5084
|
-
};
|
|
5085
|
-
if (params.uiPort) uiOverrides.port = Number(params.uiPort);
|
|
5086
|
-
return uiOverrides;
|
|
5066
|
+
//#region src/cli/shared/utils/top-level-nextclaw-command-env.utils.ts
|
|
5067
|
+
const NEXTCLAW_RUNTIME_BUNDLE_ENV_KEYS = ["NEXTCLAW_RUNTIME_BUNDLE_CHILD", "NEXTCLAW_DISABLE_RUNTIME_BUNDLE_LAUNCHER"];
|
|
5068
|
+
function createTopLevelNextclawCommandEnv(baseEnv = process.env, extraEnv = {}) {
|
|
5069
|
+
const env = createExternalCommandEnv(baseEnv, extraEnv);
|
|
5070
|
+
for (const key of NEXTCLAW_RUNTIME_BUNDLE_ENV_KEYS) delete env[key];
|
|
5071
|
+
return env;
|
|
5087
5072
|
}
|
|
5088
5073
|
//#endregion
|
|
5089
5074
|
//#region src/cli/shared/utils/startup-trace.ts
|
|
@@ -5260,10 +5245,14 @@ var NpmRuntimeUpdateManager = class {
|
|
|
5260
5245
|
};
|
|
5261
5246
|
syncStateFromCurrentPointer = () => {
|
|
5262
5247
|
const currentPointer = this.options.layout.readCurrentPointer();
|
|
5263
|
-
|
|
5248
|
+
const effectiveCurrentVersion = resolveEffectiveNpmRuntimeVersion({
|
|
5249
|
+
launcherVersion: this.launcherVersion,
|
|
5250
|
+
currentBundleVersion: currentPointer?.version ?? null
|
|
5251
|
+
});
|
|
5252
|
+
if (!effectiveCurrentVersion) return;
|
|
5264
5253
|
this.options.stateStore.update((state) => ({
|
|
5265
5254
|
...state,
|
|
5266
|
-
currentVersion:
|
|
5255
|
+
currentVersion: effectiveCurrentVersion
|
|
5267
5256
|
}));
|
|
5268
5257
|
};
|
|
5269
5258
|
toSnapshotFromState = (state, patch) => {
|
|
@@ -5467,49 +5456,6 @@ function readDirectoryNames(directory) {
|
|
|
5467
5456
|
return readdirSync(directory, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
5468
5457
|
}
|
|
5469
5458
|
//#endregion
|
|
5470
|
-
//#region src/cli/launcher/npm-runtime-update-source.service.ts
|
|
5471
|
-
const DEFAULT_NPM_RUNTIME_UPDATE_BASE_URL = "https://Peiiii.github.io/nextclaw/npm-runtime-updates";
|
|
5472
|
-
function normalizeOptionalString$8(value) {
|
|
5473
|
-
if (typeof value !== "string") return null;
|
|
5474
|
-
const trimmed = value.trim();
|
|
5475
|
-
return trimmed ? trimmed : null;
|
|
5476
|
-
}
|
|
5477
|
-
function normalizeChannel(value) {
|
|
5478
|
-
return typeof value === "string" && value.trim().toLowerCase() === "beta" ? "beta" : "stable";
|
|
5479
|
-
}
|
|
5480
|
-
function resolvePackagedPublicKeyPath() {
|
|
5481
|
-
return resolve(dirname(fileURLToPath(import.meta.url)), "../../..", "resources", "update-bundle-public.pem");
|
|
5482
|
-
}
|
|
5483
|
-
var NpmRuntimeUpdateSourceService = class {
|
|
5484
|
-
env;
|
|
5485
|
-
platform;
|
|
5486
|
-
arch;
|
|
5487
|
-
constructor(options = {}) {
|
|
5488
|
-
this.env = options.env ?? process.env;
|
|
5489
|
-
this.platform = options.platform ?? process.platform;
|
|
5490
|
-
this.arch = options.arch ?? process.arch;
|
|
5491
|
-
}
|
|
5492
|
-
resolveChannel = (explicitChannel) => {
|
|
5493
|
-
return normalizeChannel(explicitChannel ?? this.env.NEXTCLAW_UPDATE_CHANNEL);
|
|
5494
|
-
};
|
|
5495
|
-
resolveManifestUrl = (channel, explicitManifestUrl) => {
|
|
5496
|
-
const manifestUrl = normalizeOptionalString$8(explicitManifestUrl) ?? normalizeOptionalString$8(this.env.NEXTCLAW_UPDATE_MANIFEST_URL);
|
|
5497
|
-
if (manifestUrl) return manifestUrl;
|
|
5498
|
-
const baseUrl = normalizeOptionalString$8(this.env.NEXTCLAW_UPDATE_MANIFEST_BASE_URL) ?? DEFAULT_NPM_RUNTIME_UPDATE_BASE_URL;
|
|
5499
|
-
return new URL(`${channel}/manifest-${channel}-${this.platform}-${this.arch}.json`, `${baseUrl.replace(/\/+$/, "")}/`).toString();
|
|
5500
|
-
};
|
|
5501
|
-
resolveBundlePublicKey = () => {
|
|
5502
|
-
const explicitPublicKey = normalizeOptionalString$8(this.env.NEXTCLAW_UPDATE_BUNDLE_PUBLIC_KEY);
|
|
5503
|
-
if (explicitPublicKey) return explicitPublicKey;
|
|
5504
|
-
const publicKeyPath = normalizeOptionalString$8(this.env.NEXTCLAW_UPDATE_BUNDLE_PUBLIC_KEY_PATH);
|
|
5505
|
-
if (!publicKeyPath || !existsSync(publicKeyPath)) {
|
|
5506
|
-
const packagedPublicKeyPath = resolvePackagedPublicKeyPath();
|
|
5507
|
-
return existsSync(packagedPublicKeyPath) ? readFileSync(packagedPublicKeyPath, "utf8").trim() : null;
|
|
5508
|
-
}
|
|
5509
|
-
return readFileSync(publicKeyPath, "utf8").trim();
|
|
5510
|
-
};
|
|
5511
|
-
};
|
|
5512
|
-
//#endregion
|
|
5513
5459
|
//#region src/cli/launcher/npm-runtime-update-command.service.ts
|
|
5514
5460
|
var NpmRuntimeUpdateCommandService = class {
|
|
5515
5461
|
run = async (opts) => {
|
|
@@ -5520,11 +5466,11 @@ var NpmRuntimeUpdateCommandService = class {
|
|
|
5520
5466
|
};
|
|
5521
5467
|
runManaged = async (opts) => {
|
|
5522
5468
|
const source = new NpmRuntimeUpdateSourceService();
|
|
5523
|
-
const
|
|
5469
|
+
const launcherVersion = getPackageVersion$1();
|
|
5470
|
+
const channel = source.resolveChannel(opts.channel, launcherVersion);
|
|
5524
5471
|
const manifestUrl = source.resolveManifestUrl(channel, opts.manifestUrl);
|
|
5525
5472
|
const layout = new NpmRuntimeBundleLayoutStore();
|
|
5526
|
-
const stateStore = new NpmRuntimeUpdateStateStore(layout.getStatePath());
|
|
5527
|
-
const launcherVersion = getPackageVersion$1();
|
|
5473
|
+
const stateStore = new NpmRuntimeUpdateStateStore(layout.getStatePath(), { defaultChannel: channel });
|
|
5528
5474
|
const bundleService = new NpmRuntimeBundleService({
|
|
5529
5475
|
layout,
|
|
5530
5476
|
stateStore,
|
|
@@ -5748,11 +5694,9 @@ const readInstalledFirstPartyPluginMatches = (workspaceExtensionsDir) => {
|
|
|
5748
5694
|
const workspacePackage = workspacePackageByName.get(packageName);
|
|
5749
5695
|
if (!workspacePackage) continue;
|
|
5750
5696
|
matches.push({
|
|
5751
|
-
pluginId: workspacePackage.pluginId,
|
|
5752
5697
|
packageName,
|
|
5753
5698
|
workspaceDir: workspacePackage.dir,
|
|
5754
|
-
installPath: packageDir
|
|
5755
|
-
supportsDevelopmentSource: workspacePackage.supportsDevelopmentSource
|
|
5699
|
+
installPath: packageDir
|
|
5756
5700
|
});
|
|
5757
5701
|
}
|
|
5758
5702
|
return matches;
|
|
@@ -5772,35 +5716,6 @@ const findWorkspacePackageForInstallRecord = (installRecord, workspacePackages,
|
|
|
5772
5716
|
if (installPathCandidates.size === 0) return;
|
|
5773
5717
|
return workspacePackages.find((workspacePackage) => installPathCandidates.has(path.resolve(workspacePackage.dir)));
|
|
5774
5718
|
};
|
|
5775
|
-
const buildDevelopmentSourceEntryDefaults = (config, workspacePackages, installedPluginMatches) => {
|
|
5776
|
-
const packageByName = new Map(workspacePackages.map((entry) => [entry.packageName, entry]));
|
|
5777
|
-
const nextEntries = { ...config.plugins.entries ?? {} };
|
|
5778
|
-
let didDefaultDevelopmentSource = false;
|
|
5779
|
-
for (const installedPlugin of installedPluginMatches) {
|
|
5780
|
-
if (!installedPlugin.supportsDevelopmentSource) continue;
|
|
5781
|
-
const existingEntry = nextEntries[installedPlugin.pluginId];
|
|
5782
|
-
if (existingEntry?.source) continue;
|
|
5783
|
-
nextEntries[installedPlugin.pluginId] = {
|
|
5784
|
-
...existingEntry,
|
|
5785
|
-
source: "development"
|
|
5786
|
-
};
|
|
5787
|
-
didDefaultDevelopmentSource = true;
|
|
5788
|
-
}
|
|
5789
|
-
for (const [pluginId, installRecord] of Object.entries(config.plugins.installs ?? {})) {
|
|
5790
|
-
if (!findWorkspacePackageForInstallRecord(installRecord, workspacePackages, packageByName)?.supportsDevelopmentSource) continue;
|
|
5791
|
-
const existingEntry = nextEntries[pluginId];
|
|
5792
|
-
if (existingEntry?.source) continue;
|
|
5793
|
-
nextEntries[pluginId] = {
|
|
5794
|
-
...existingEntry,
|
|
5795
|
-
source: "development"
|
|
5796
|
-
};
|
|
5797
|
-
didDefaultDevelopmentSource = true;
|
|
5798
|
-
}
|
|
5799
|
-
return {
|
|
5800
|
-
didDefaultDevelopmentSource,
|
|
5801
|
-
nextEntries
|
|
5802
|
-
};
|
|
5803
|
-
};
|
|
5804
5719
|
const resolveDevFirstPartyPluginLoadPaths = (config, workspaceExtensionsDir) => {
|
|
5805
5720
|
const rootDir = resolveDevFirstPartyPluginDir(workspaceExtensionsDir);
|
|
5806
5721
|
if (!rootDir) return [];
|
|
@@ -5850,18 +5765,15 @@ const resolveDevFirstPartyPluginInstallRoots = (config, workspaceExtensionsDir)
|
|
|
5850
5765
|
const applyDevFirstPartyPluginLoadPaths = (config, workspaceExtensionsDir) => {
|
|
5851
5766
|
const rootDir = resolveDevFirstPartyPluginDir(workspaceExtensionsDir);
|
|
5852
5767
|
if (!rootDir) return config;
|
|
5853
|
-
|
|
5854
|
-
|
|
5855
|
-
const installedPluginMatches = readInstalledFirstPartyPluginMatches(rootDir);
|
|
5768
|
+
if (readWorkspacePluginPackages(rootDir).length === 0) return config;
|
|
5769
|
+
readInstalledFirstPartyPluginMatches(rootDir);
|
|
5856
5770
|
const devLoadPaths = resolveDevFirstPartyPluginLoadPaths(config, rootDir);
|
|
5857
5771
|
if (devLoadPaths.length === 0) return config;
|
|
5858
5772
|
const mergedLoadPaths = mergeLoadPaths$1(Array.isArray(config.plugins.load?.paths) ? config.plugins.load.paths.filter((entry) => typeof entry === "string" && entry.trim().length > 0) : [], devLoadPaths);
|
|
5859
|
-
const { didDefaultDevelopmentSource, nextEntries } = buildDevelopmentSourceEntryDefaults(config, workspacePackages, installedPluginMatches);
|
|
5860
5773
|
return {
|
|
5861
5774
|
...config,
|
|
5862
5775
|
plugins: {
|
|
5863
5776
|
...config.plugins,
|
|
5864
|
-
entries: didDefaultDevelopmentSource ? nextEntries : config.plugins.entries,
|
|
5865
5777
|
load: {
|
|
5866
5778
|
...config.plugins.load,
|
|
5867
5779
|
paths: mergedLoadPaths
|
|
@@ -5872,10 +5784,10 @@ const applyDevFirstPartyPluginLoadPaths = (config, workspaceExtensionsDir) => {
|
|
|
5872
5784
|
//#endregion
|
|
5873
5785
|
//#region src/cli/commands/plugin/development-source/dev-plugin-overrides.utils.ts
|
|
5874
5786
|
const DEV_PLUGIN_OVERRIDES_ENV = "NEXTCLAW_DEV_PLUGIN_OVERRIDES";
|
|
5875
|
-
function isRecord$
|
|
5787
|
+
function isRecord$7(value) {
|
|
5876
5788
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
5877
5789
|
}
|
|
5878
|
-
function readOptionalString$
|
|
5790
|
+
function readOptionalString$7(value) {
|
|
5879
5791
|
if (typeof value !== "string") return;
|
|
5880
5792
|
return value.trim() || void 0;
|
|
5881
5793
|
}
|
|
@@ -5901,9 +5813,9 @@ function assertOverridePluginReadable(override) {
|
|
|
5901
5813
|
}
|
|
5902
5814
|
}
|
|
5903
5815
|
function readOverrideRecord(value, index) {
|
|
5904
|
-
if (!isRecord$
|
|
5905
|
-
const pluginId = readOptionalString$
|
|
5906
|
-
const pluginPath = readOptionalString$
|
|
5816
|
+
if (!isRecord$7(value)) throw new Error(`[dev-plugin-override] override[${index}] must be an object`);
|
|
5817
|
+
const pluginId = readOptionalString$7(value.pluginId);
|
|
5818
|
+
const pluginPath = readOptionalString$7(value.pluginPath);
|
|
5907
5819
|
const source = value.source === "development" ? "development" : "production";
|
|
5908
5820
|
if (!pluginId || !pluginPath) throw new Error(`[dev-plugin-override] override[${index}] requires pluginId and pluginPath`);
|
|
5909
5821
|
const normalized = {
|
|
@@ -5960,7 +5872,7 @@ function resolveDevPluginOverrideInstallRoots(config, overrides) {
|
|
|
5960
5872
|
const installRoots = [];
|
|
5961
5873
|
for (const override of overrides) {
|
|
5962
5874
|
const installRecord = config.plugins.installs?.[override.pluginId];
|
|
5963
|
-
const installPath = readOptionalString$
|
|
5875
|
+
const installPath = readOptionalString$7(installRecord?.installPath);
|
|
5964
5876
|
if (!installPath || installRoots.includes(installPath)) continue;
|
|
5965
5877
|
installRoots.push(installPath);
|
|
5966
5878
|
}
|
|
@@ -8423,13 +8335,13 @@ var AgentCommands = class {
|
|
|
8423
8335
|
};
|
|
8424
8336
|
//#endregion
|
|
8425
8337
|
//#region src/cli/commands/ncp/features/runtime/ncp-asset-tools.ts
|
|
8426
|
-
function readOptionalString$
|
|
8338
|
+
function readOptionalString$6(value) {
|
|
8427
8339
|
if (typeof value !== "string") return null;
|
|
8428
8340
|
const trimmed = value.trim();
|
|
8429
8341
|
return trimmed.length > 0 ? trimmed : null;
|
|
8430
8342
|
}
|
|
8431
8343
|
function readOptionalBase64Bytes(value) {
|
|
8432
|
-
const base64 = readOptionalString$
|
|
8344
|
+
const base64 = readOptionalString$6(value);
|
|
8433
8345
|
if (!base64) return null;
|
|
8434
8346
|
try {
|
|
8435
8347
|
return Buffer.from(base64, "base64");
|
|
@@ -8480,18 +8392,18 @@ var AssetPutTool = class {
|
|
|
8480
8392
|
this.contentBasePath = contentBasePath;
|
|
8481
8393
|
}
|
|
8482
8394
|
validateArgs = (args) => {
|
|
8483
|
-
const path = readOptionalString$
|
|
8484
|
-
const bytesBase64 = readOptionalString$
|
|
8485
|
-
const fileName = readOptionalString$
|
|
8395
|
+
const path = readOptionalString$6(args.path);
|
|
8396
|
+
const bytesBase64 = readOptionalString$6(args.bytesBase64);
|
|
8397
|
+
const fileName = readOptionalString$6(args.fileName);
|
|
8486
8398
|
if (path && bytesBase64) return ["Provide either path, or bytesBase64 + fileName, not both."];
|
|
8487
8399
|
if (path) return [];
|
|
8488
8400
|
if (bytesBase64) return fileName ? [] : ["fileName is required when using bytesBase64."];
|
|
8489
8401
|
return ["Provide either path, or bytesBase64 + fileName."];
|
|
8490
8402
|
};
|
|
8491
8403
|
execute = async (args) => {
|
|
8492
|
-
const path = readOptionalString$
|
|
8493
|
-
const fileName = readOptionalString$
|
|
8494
|
-
const mimeType = readOptionalString$
|
|
8404
|
+
const path = readOptionalString$6(args?.path);
|
|
8405
|
+
const fileName = readOptionalString$6(args?.fileName);
|
|
8406
|
+
const mimeType = readOptionalString$6(args?.mimeType);
|
|
8495
8407
|
const bytes = readOptionalBase64Bytes(args?.bytesBase64);
|
|
8496
8408
|
if (path) return {
|
|
8497
8409
|
ok: true,
|
|
@@ -8534,8 +8446,8 @@ var AssetExportTool = class {
|
|
|
8534
8446
|
this.assetStore = assetStore;
|
|
8535
8447
|
}
|
|
8536
8448
|
execute = async (args) => {
|
|
8537
|
-
const assetUri = readOptionalString$
|
|
8538
|
-
const targetPath = readOptionalString$
|
|
8449
|
+
const assetUri = readOptionalString$6(args?.assetUri);
|
|
8450
|
+
const targetPath = readOptionalString$6(args?.targetPath);
|
|
8539
8451
|
if (!assetUri || !targetPath) throw new Error("asset_export requires assetUri and targetPath.");
|
|
8540
8452
|
return {
|
|
8541
8453
|
ok: true,
|
|
@@ -8561,7 +8473,7 @@ var AssetStatTool = class {
|
|
|
8561
8473
|
this.contentBasePath = contentBasePath;
|
|
8562
8474
|
}
|
|
8563
8475
|
execute = async (args) => {
|
|
8564
|
-
const assetUri = readOptionalString$
|
|
8476
|
+
const assetUri = readOptionalString$6(args?.assetUri);
|
|
8565
8477
|
if (!assetUri) throw new Error("asset_stat requires assetUri.");
|
|
8566
8478
|
const record = await this.assetStore.statRecord(assetUri);
|
|
8567
8479
|
if (!record) return {
|
|
@@ -8593,11 +8505,11 @@ function normalizeString(value) {
|
|
|
8593
8505
|
const trimmed = value.trim();
|
|
8594
8506
|
return trimmed.length > 0 ? trimmed : null;
|
|
8595
8507
|
}
|
|
8596
|
-
function isRecord$
|
|
8508
|
+
function isRecord$6(value) {
|
|
8597
8509
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
8598
8510
|
}
|
|
8599
8511
|
function cloneMetadata(value) {
|
|
8600
|
-
return isRecord$
|
|
8512
|
+
return isRecord$6(value) ? structuredClone(value) : void 0;
|
|
8601
8513
|
}
|
|
8602
8514
|
function readStringArray(value) {
|
|
8603
8515
|
if (!Array.isArray(value)) return null;
|
|
@@ -9088,7 +9000,7 @@ function readRequiredString$1(params, key) {
|
|
|
9088
9000
|
if (typeof value !== "string" || value.trim().length === 0) throw new Error(`${key} must be a non-empty string.`);
|
|
9089
9001
|
return value.trim();
|
|
9090
9002
|
}
|
|
9091
|
-
function readOptionalString$
|
|
9003
|
+
function readOptionalString$5(params, key) {
|
|
9092
9004
|
const value = params[key];
|
|
9093
9005
|
if (typeof value !== "string") return;
|
|
9094
9006
|
const trimmed = value.trim();
|
|
@@ -9149,14 +9061,14 @@ var SessionRequestTool = class extends Tool {
|
|
|
9149
9061
|
const target = params.target;
|
|
9150
9062
|
if (!target || typeof target !== "object" || Array.isArray(target)) throw new Error("target must be an object.");
|
|
9151
9063
|
const task = readRequiredString$1(params, "task");
|
|
9152
|
-
const notifyMode = readOptionalString$
|
|
9064
|
+
const notifyMode = readOptionalString$5(params, "notify")?.toLowerCase();
|
|
9153
9065
|
if (notifyMode !== "none" && notifyMode !== "final_reply") throw new Error("notify must be \"none\" or \"final_reply\".");
|
|
9154
9066
|
return this.broker.requestSession({
|
|
9155
9067
|
sourceSessionId: this.sourceSessionId,
|
|
9156
9068
|
sourceToolCallId: toolCallId,
|
|
9157
9069
|
targetSessionId: readRequiredString$1(target, "session_id"),
|
|
9158
9070
|
task,
|
|
9159
|
-
title: readOptionalString$
|
|
9071
|
+
title: readOptionalString$5(params, "title"),
|
|
9160
9072
|
notify: notifyMode,
|
|
9161
9073
|
handoffDepth: this.handoffDepth
|
|
9162
9074
|
});
|
|
@@ -9168,13 +9080,13 @@ function readRequiredString(value, key) {
|
|
|
9168
9080
|
if (typeof value !== "string" || value.trim().length === 0) throw new Error(`${key} must be a non-empty string.`);
|
|
9169
9081
|
return value.trim();
|
|
9170
9082
|
}
|
|
9171
|
-
function readOptionalString$
|
|
9083
|
+
function readOptionalString$4(value) {
|
|
9172
9084
|
if (typeof value !== "string") return;
|
|
9173
9085
|
const trimmed = value.trim();
|
|
9174
9086
|
return trimmed.length > 0 ? trimmed : void 0;
|
|
9175
9087
|
}
|
|
9176
9088
|
function readSpawnScope(value) {
|
|
9177
|
-
const normalized = readOptionalString$
|
|
9089
|
+
const normalized = readOptionalString$4(value)?.toLowerCase();
|
|
9178
9090
|
if (!normalized || normalized === "standalone") return "standalone";
|
|
9179
9091
|
if (normalized === "child") return "child";
|
|
9180
9092
|
throw new Error("scope must be \"standalone\" or \"child\".");
|
|
@@ -9182,7 +9094,7 @@ function readSpawnScope(value) {
|
|
|
9182
9094
|
function readSpawnRequestOptions(value) {
|
|
9183
9095
|
if (typeof value === "undefined") return;
|
|
9184
9096
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("request must be an object.");
|
|
9185
|
-
const notifyMode = readOptionalString$
|
|
9097
|
+
const notifyMode = readOptionalString$4(value.notify)?.toLowerCase();
|
|
9186
9098
|
if (notifyMode === "none" || notifyMode === "final_reply") return { notify: notifyMode };
|
|
9187
9099
|
throw new Error("request.notify must be \"none\" or \"final_reply\".");
|
|
9188
9100
|
}
|
|
@@ -9260,21 +9172,21 @@ var SessionSpawnTool = class extends Tool {
|
|
|
9260
9172
|
sourceToolCallId: toolCallId,
|
|
9261
9173
|
sourceSessionMetadata: this.sourceSessionMetadata,
|
|
9262
9174
|
task,
|
|
9263
|
-
title: readOptionalString$
|
|
9264
|
-
agentId: readOptionalString$
|
|
9265
|
-
model: readOptionalString$
|
|
9266
|
-
runtime: readOptionalString$
|
|
9175
|
+
title: readOptionalString$4(rawTitle),
|
|
9176
|
+
agentId: readOptionalString$4(rawAgentId),
|
|
9177
|
+
model: readOptionalString$4(rawModel),
|
|
9178
|
+
runtime: readOptionalString$4(rawRuntime),
|
|
9267
9179
|
handoffDepth: this.handoffDepth,
|
|
9268
9180
|
...parentSessionId ? { parentSessionId } : {},
|
|
9269
9181
|
notify: request.notify
|
|
9270
9182
|
});
|
|
9271
9183
|
const session = this.sessionCreationService.createSession({
|
|
9272
9184
|
task,
|
|
9273
|
-
title: readOptionalString$
|
|
9185
|
+
title: readOptionalString$4(rawTitle),
|
|
9274
9186
|
sourceSessionMetadata: this.sourceSessionMetadata,
|
|
9275
|
-
agentId: readOptionalString$
|
|
9276
|
-
model: readOptionalString$
|
|
9277
|
-
runtime: readOptionalString$
|
|
9187
|
+
agentId: readOptionalString$4(rawAgentId),
|
|
9188
|
+
model: readOptionalString$4(rawModel),
|
|
9189
|
+
runtime: readOptionalString$4(rawRuntime),
|
|
9278
9190
|
...parentSessionId ? { parentSessionId } : {}
|
|
9279
9191
|
});
|
|
9280
9192
|
return {
|
|
@@ -9298,10 +9210,10 @@ var SessionSpawnTool = class extends Tool {
|
|
|
9298
9210
|
//#endregion
|
|
9299
9211
|
//#region src/cli/commands/ncp/nextclaw-ncp-tool-registry.ts
|
|
9300
9212
|
function toToolParams(args) {
|
|
9301
|
-
if (isRecord$
|
|
9213
|
+
if (isRecord$6(args)) return args;
|
|
9302
9214
|
if (typeof args === "string") try {
|
|
9303
9215
|
const parsed = JSON.parse(args);
|
|
9304
|
-
return isRecord$
|
|
9216
|
+
return isRecord$6(parsed) ? parsed : {};
|
|
9305
9217
|
} catch {
|
|
9306
9218
|
return {};
|
|
9307
9219
|
}
|
|
@@ -9479,14 +9391,14 @@ function readAccountIdForHints(metadata, sessionMetadata) {
|
|
|
9479
9391
|
//#endregion
|
|
9480
9392
|
//#region src/cli/commands/ncp/nextclaw-ncp-context-builder.ts
|
|
9481
9393
|
const TIME_HINT_TRIGGER_PATTERNS = [/\b(now|right now|current time|what time|today|tonight|tomorrow|yesterday|this morning|this afternoon|this evening|date)\b/i, /(现在|此刻|当前时间|现在几点|几点了|今天|今晚|今早|今晨|明天|昨天|日期)/];
|
|
9482
|
-
function isRecord$
|
|
9394
|
+
function isRecord$5(value) {
|
|
9483
9395
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
9484
9396
|
}
|
|
9485
9397
|
function mergeInputMetadata(input) {
|
|
9486
|
-
const messageMetadata = input.messages.slice().reverse().find((message) => isRecord$
|
|
9398
|
+
const messageMetadata = input.messages.slice().reverse().find((message) => isRecord$5(message.metadata))?.metadata;
|
|
9487
9399
|
return {
|
|
9488
|
-
...isRecord$
|
|
9489
|
-
...isRecord$
|
|
9400
|
+
...isRecord$5(messageMetadata) ? structuredClone(messageMetadata) : {},
|
|
9401
|
+
...isRecord$5(input.metadata) ? structuredClone(input.metadata) : {}
|
|
9490
9402
|
};
|
|
9491
9403
|
}
|
|
9492
9404
|
const REQUESTED_SKILLS_METADATA_READER = new RequestedSkillsMetadataReader();
|
|
@@ -10110,7 +10022,7 @@ const CHILD_SESSION_PARENT_METADATA_KEY = "parent_session_id";
|
|
|
10110
10022
|
const CHILD_SESSION_REQUEST_METADATA_KEY = "spawned_by_request_id";
|
|
10111
10023
|
const CHILD_SESSION_LIFECYCLE_METADATA_KEY = "session_lifecycle";
|
|
10112
10024
|
const CHILD_SESSION_PROMOTED_METADATA_KEY = "child_session_promoted";
|
|
10113
|
-
function readOptionalString$
|
|
10025
|
+
function readOptionalString$3(value) {
|
|
10114
10026
|
if (typeof value !== "string") return null;
|
|
10115
10027
|
const trimmed = value.trim();
|
|
10116
10028
|
return trimmed.length > 0 ? trimmed : null;
|
|
@@ -10150,14 +10062,14 @@ function buildSessionId() {
|
|
|
10150
10062
|
return `ncp-${Date.now().toString(36)}-${randomUUID().replace(/-/g, "").slice(0, 8)}`;
|
|
10151
10063
|
}
|
|
10152
10064
|
function resolveSessionAgentId(params) {
|
|
10153
|
-
return readOptionalString$
|
|
10065
|
+
return readOptionalString$3(params.agentId) ?? resolveDefaultAgentProfileId(params.getConfig());
|
|
10154
10066
|
}
|
|
10155
10067
|
function resolveSessionTitle(params) {
|
|
10156
|
-
return readOptionalString$
|
|
10068
|
+
return readOptionalString$3(params.title) ?? summarizeTask(params.task);
|
|
10157
10069
|
}
|
|
10158
10070
|
function resolveSessionType(params) {
|
|
10159
10071
|
const { metadata, runtime, sessionType } = params;
|
|
10160
|
-
return readOptionalString$
|
|
10072
|
+
return readOptionalString$3(runtime) ?? readOptionalString$3(metadata.runtime) ?? readOptionalString$3(sessionType) ?? readOptionalString$3(metadata.session_type) ?? DEFAULT_SESSION_TYPE;
|
|
10161
10073
|
}
|
|
10162
10074
|
function applySessionOverrides(params) {
|
|
10163
10075
|
const { lifecycle, metadata, model, parentSessionId, projectRoot, requestId, sessionType, thinkingLevel, title } = params;
|
|
@@ -10170,15 +10082,15 @@ function applySessionOverrides(params) {
|
|
|
10170
10082
|
metadata[CHILD_SESSION_PROMOTED_METADATA_KEY] = false;
|
|
10171
10083
|
}
|
|
10172
10084
|
if (requestId) metadata[CHILD_SESSION_REQUEST_METADATA_KEY] = requestId;
|
|
10173
|
-
if (readOptionalString$
|
|
10085
|
+
if (readOptionalString$3(model)) {
|
|
10174
10086
|
metadata.model = model?.trim();
|
|
10175
10087
|
metadata.preferred_model = model?.trim();
|
|
10176
10088
|
}
|
|
10177
|
-
if (readOptionalString$
|
|
10089
|
+
if (readOptionalString$3(thinkingLevel)) {
|
|
10178
10090
|
metadata.thinking = thinkingLevel?.trim();
|
|
10179
10091
|
metadata.preferred_thinking = thinkingLevel?.trim();
|
|
10180
10092
|
}
|
|
10181
|
-
if (readOptionalString$
|
|
10093
|
+
if (readOptionalString$3(projectRoot)) metadata.project_root = projectRoot?.trim();
|
|
10182
10094
|
}
|
|
10183
10095
|
var SessionCreationService = class {
|
|
10184
10096
|
constructor(sessionManager, getConfig, onSessionUpdated) {
|
|
@@ -10200,8 +10112,8 @@ var SessionCreationService = class {
|
|
|
10200
10112
|
task
|
|
10201
10113
|
});
|
|
10202
10114
|
const metadata = cloneInheritedMetadata(sourceSessionMetadata);
|
|
10203
|
-
const parentSessionId = readOptionalString$
|
|
10204
|
-
const requestId = readOptionalString$
|
|
10115
|
+
const parentSessionId = readOptionalString$3(rawParentSessionId);
|
|
10116
|
+
const requestId = readOptionalString$3(rawRequestId);
|
|
10205
10117
|
const sessionType = resolveSessionType({
|
|
10206
10118
|
runtime,
|
|
10207
10119
|
sessionType: requestedSessionType,
|
|
@@ -10254,12 +10166,12 @@ var SessionCreationService = class {
|
|
|
10254
10166
|
return true;
|
|
10255
10167
|
};
|
|
10256
10168
|
isChildSessionRecord = (metadata) => {
|
|
10257
|
-
return Boolean(readOptionalString$
|
|
10169
|
+
return Boolean(readOptionalString$3(metadata?.[CHILD_SESSION_PARENT_METADATA_KEY]));
|
|
10258
10170
|
};
|
|
10259
10171
|
};
|
|
10260
10172
|
//#endregion
|
|
10261
10173
|
//#region src/cli/commands/ncp/session-request/session-request-result.ts
|
|
10262
|
-
function readOptionalString$
|
|
10174
|
+
function readOptionalString$2(value) {
|
|
10263
10175
|
if (typeof value !== "string") return null;
|
|
10264
10176
|
const trimmed = value.trim();
|
|
10265
10177
|
return trimmed.length > 0 ? trimmed : null;
|
|
@@ -10280,7 +10192,7 @@ function extractSessionMessageText(message) {
|
|
|
10280
10192
|
return parts.join("\n\n");
|
|
10281
10193
|
}
|
|
10282
10194
|
function readParentSessionId(metadata) {
|
|
10283
|
-
return readOptionalString$
|
|
10195
|
+
return readOptionalString$2(metadata?.["parent_session_id"]) ?? void 0;
|
|
10284
10196
|
}
|
|
10285
10197
|
function buildSessionRequestToolResult(params) {
|
|
10286
10198
|
const { request, task, title, agentId, isChildSession, parentSessionId, spawnedByRequestId, message } = params;
|
|
@@ -10419,7 +10331,7 @@ var SessionRequestBroker = class {
|
|
|
10419
10331
|
sourceToolCallId,
|
|
10420
10332
|
targetSessionId: normalizedTargetSessionId,
|
|
10421
10333
|
task,
|
|
10422
|
-
title: readOptionalString$
|
|
10334
|
+
title: readOptionalString$2(title) ?? readOptionalString$2(targetSummary.metadata?.label) ?? summarizeSessionRequestTask(task),
|
|
10423
10335
|
handoffDepth: handoffDepth ?? 0,
|
|
10424
10336
|
notify,
|
|
10425
10337
|
agentId: targetSummary.agentId,
|
|
@@ -10955,7 +10867,7 @@ var SessionSearchStoreService = class {
|
|
|
10955
10867
|
};
|
|
10956
10868
|
//#endregion
|
|
10957
10869
|
//#region src/cli/commands/ncp/session-search/session-search-tool.service.ts
|
|
10958
|
-
function isRecord$
|
|
10870
|
+
function isRecord$4(value) {
|
|
10959
10871
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
10960
10872
|
}
|
|
10961
10873
|
function readOptionalInteger(value) {
|
|
@@ -11005,7 +10917,7 @@ var SessionSearchTool = class {
|
|
|
11005
10917
|
return issues;
|
|
11006
10918
|
};
|
|
11007
10919
|
execute = async (args) => {
|
|
11008
|
-
if (!isRecord$
|
|
10920
|
+
if (!isRecord$4(args)) throw new Error("session_search requires an object argument.");
|
|
11009
10921
|
const issues = this.validateArgs(args);
|
|
11010
10922
|
if (issues.length > 0) throw new Error(issues.join(" "));
|
|
11011
10923
|
return this.queryService.search({
|
|
@@ -11937,12 +11849,12 @@ function createContextWindowUpdatedEvent(params) {
|
|
|
11937
11849
|
}
|
|
11938
11850
|
};
|
|
11939
11851
|
}
|
|
11940
|
-
function isRecord$
|
|
11852
|
+
function isRecord$3(value) {
|
|
11941
11853
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
11942
11854
|
}
|
|
11943
11855
|
function resolveNativeReasoningNormalizationMode(params) {
|
|
11944
11856
|
const runtimeEntry = params.config.agents.runtimes.entries.native?.config ?? params.config.ui.ncp.runtimes.native;
|
|
11945
|
-
const runtimeMetadata = isRecord$
|
|
11857
|
+
const runtimeMetadata = isRecord$3(runtimeEntry) ? runtimeEntry : {};
|
|
11946
11858
|
return readAssistantReasoningNormalizationModeFromMetadata(params.sessionMetadata) ?? readAssistantReasoningNormalizationMode(runtimeMetadata.reasoningNormalization) ?? readAssistantReasoningNormalizationMode(runtimeMetadata.reasoning_normalization) ?? readAssistantReasoningNormalizationMode(runtimeMetadata.reasoningNormalizationMode) ?? readAssistantReasoningNormalizationMode(runtimeMetadata.reasoning_normalization_mode) ?? "think-tags";
|
|
11947
11859
|
}
|
|
11948
11860
|
function createMcpRuntimeSupport(getConfig) {
|
|
@@ -14004,7 +13916,7 @@ var ServiceMarketplaceInstaller = class {
|
|
|
14004
13916
|
};
|
|
14005
13917
|
//#endregion
|
|
14006
13918
|
//#region src/cli/shared/utils/marketplace/cli-subcommand-launch.utils.ts
|
|
14007
|
-
const require$
|
|
13919
|
+
const require$3 = createRequire(import.meta.url);
|
|
14008
13920
|
const TYPESCRIPT_EXTENSIONS$1 = new Set([
|
|
14009
13921
|
".ts",
|
|
14010
13922
|
".tsx",
|
|
@@ -14012,7 +13924,7 @@ const TYPESCRIPT_EXTENSIONS$1 = new Set([
|
|
|
14012
13924
|
".cts"
|
|
14013
13925
|
]);
|
|
14014
13926
|
const isTypeScriptEntry = (entry) => TYPESCRIPT_EXTENSIONS$1.has(extname(entry).toLowerCase());
|
|
14015
|
-
const resolveTsxCliEntry = () => require$
|
|
13927
|
+
const resolveTsxCliEntry = () => require$3.resolve("tsx/cli");
|
|
14016
13928
|
const resolveCliAppEntryFromImportMeta$1 = (importMetaUrl) => {
|
|
14017
13929
|
const modulePath = fileURLToPath(importMetaUrl);
|
|
14018
13930
|
const cliRootIndex = modulePath.replace(/\\/g, "/").lastIndexOf("/cli/");
|
|
@@ -14369,6 +14281,27 @@ async function describeUnmanagedHealthyTargetMessage(params) {
|
|
|
14369
14281
|
//#endregion
|
|
14370
14282
|
//#region src/cli/shared/services/runtime/service-managed-startup.service.ts
|
|
14371
14283
|
const { APP_NAME: APP_NAME$1, loadConfig: loadConfig$4 } = NextclawCore;
|
|
14284
|
+
function resolveManagedServiceReadySnapshot(params) {
|
|
14285
|
+
const { snapshot, readLocalUiRuntimeState, isProcessRunningFn: providedIsProcessRunningFn } = params;
|
|
14286
|
+
const localUiRuntimeState = (readLocalUiRuntimeState ?? localUiRuntimeStore.read)();
|
|
14287
|
+
const isProcessRunningFn = providedIsProcessRunningFn ?? isProcessRunning;
|
|
14288
|
+
if (!localUiRuntimeState || typeof localUiRuntimeState.pid !== "number" || !Number.isFinite(localUiRuntimeState.pid) || localUiRuntimeState.uiPort !== snapshot.uiPort || !isProcessRunningFn(localUiRuntimeState.pid)) return snapshot;
|
|
14289
|
+
return {
|
|
14290
|
+
...snapshot,
|
|
14291
|
+
pid: localUiRuntimeState.pid,
|
|
14292
|
+
uiUrl: localUiRuntimeState.uiUrl,
|
|
14293
|
+
apiUrl: localUiRuntimeState.apiUrl,
|
|
14294
|
+
uiHost: localUiRuntimeState.uiHost ?? snapshot.uiHost,
|
|
14295
|
+
uiPort: localUiRuntimeState.uiPort ?? snapshot.uiPort
|
|
14296
|
+
};
|
|
14297
|
+
}
|
|
14298
|
+
function resolveLauncherCliEntry(importMetaUrl) {
|
|
14299
|
+
const modulePath = fileURLToPath(importMetaUrl);
|
|
14300
|
+
const cliRootIndex = modulePath.replace(/\\/g, "/").lastIndexOf("/cli/");
|
|
14301
|
+
if (cliRootIndex === -1) return fileURLToPath(new URL("../../../launcher/index.js", importMetaUrl));
|
|
14302
|
+
const extension = extname(modulePath) || ".js";
|
|
14303
|
+
return resolve(modulePath.slice(0, cliRootIndex + 5), "launcher", `index${extension}`);
|
|
14304
|
+
}
|
|
14372
14305
|
function toObjectRecord(value) {
|
|
14373
14306
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
14374
14307
|
return value;
|
|
@@ -14420,7 +14353,7 @@ function spawnManagedService(params) {
|
|
|
14420
14353
|
appendStartupStage(logPath, `start requested: ui=${uiConfig.host}:${uiConfig.port}, readinessTimeoutMs=${readinessTimeoutMs}`);
|
|
14421
14354
|
console.log(`Starting ${appName} background service (readiness timeout ${Math.ceil(readinessTimeoutMs / 1e3)}s)...`);
|
|
14422
14355
|
const cliLaunch = resolveCliSubcommandLaunch({
|
|
14423
|
-
argvEntry:
|
|
14356
|
+
argvEntry: resolveLauncherCliEntry(import.meta.url),
|
|
14424
14357
|
importMetaUrl: import.meta.url,
|
|
14425
14358
|
cliArgs: [
|
|
14426
14359
|
"serve",
|
|
@@ -14432,7 +14365,7 @@ function spawnManagedService(params) {
|
|
|
14432
14365
|
const childArgs = [...process.execArgv, ...cliLaunch.args];
|
|
14433
14366
|
appendStartupStage(logPath, `spawning background process: ${cliLaunch.command} ${childArgs.join(" ")}`);
|
|
14434
14367
|
const child = spawn(cliLaunch.command, childArgs, {
|
|
14435
|
-
env: process.env,
|
|
14368
|
+
env: createTopLevelNextclawCommandEnv(process.env),
|
|
14436
14369
|
stdio: "ignore",
|
|
14437
14370
|
detached: true
|
|
14438
14371
|
});
|
|
@@ -14691,12 +14624,13 @@ var ManagedServiceCommandService = class {
|
|
|
14691
14624
|
return;
|
|
14692
14625
|
}
|
|
14693
14626
|
startup.child.unref();
|
|
14627
|
+
const readySnapshot = resolveManagedServiceReadySnapshot({ snapshot: startup.snapshot });
|
|
14694
14628
|
await reportManagedServiceStart({
|
|
14695
14629
|
appName: APP_NAME$1,
|
|
14696
14630
|
state: writeReadyManagedServiceState({
|
|
14697
14631
|
readinessTimeoutMs: startup.readinessTimeoutMs,
|
|
14698
14632
|
readiness,
|
|
14699
|
-
snapshot:
|
|
14633
|
+
snapshot: readySnapshot
|
|
14700
14634
|
}),
|
|
14701
14635
|
uiConfig,
|
|
14702
14636
|
uiUrl,
|
|
@@ -15199,6 +15133,179 @@ function createRemoteAccessHost(params) {
|
|
|
15199
15133
|
});
|
|
15200
15134
|
}
|
|
15201
15135
|
//#endregion
|
|
15136
|
+
//#region src/cli/shared/services/ui/npm-runtime-update-host.service.ts
|
|
15137
|
+
const INITIAL_DOWNLOAD_PROGRESS = {
|
|
15138
|
+
downloadedBytes: 0,
|
|
15139
|
+
totalBytes: null,
|
|
15140
|
+
percent: null
|
|
15141
|
+
};
|
|
15142
|
+
var NpmRuntimeUpdateHost = class {
|
|
15143
|
+
source = new NpmRuntimeUpdateSourceService();
|
|
15144
|
+
layout = new NpmRuntimeBundleLayoutStore();
|
|
15145
|
+
launcherVersion = getPackageVersion$1();
|
|
15146
|
+
stateStore = new NpmRuntimeUpdateStateStore(this.layout.getStatePath(), { defaultChannel: this.source.resolveChannel(void 0, this.launcherVersion) });
|
|
15147
|
+
bundleService = new NpmRuntimeBundleService({
|
|
15148
|
+
layout: this.layout,
|
|
15149
|
+
stateStore: this.stateStore,
|
|
15150
|
+
launcherVersion: this.launcherVersion
|
|
15151
|
+
});
|
|
15152
|
+
updateService = new NpmRuntimeUpdateService({
|
|
15153
|
+
layout: this.layout,
|
|
15154
|
+
bundleService: this.bundleService,
|
|
15155
|
+
launcherVersion: this.launcherVersion,
|
|
15156
|
+
bundlePublicKey: this.source.resolveBundlePublicKey() ?? void 0
|
|
15157
|
+
});
|
|
15158
|
+
snapshot;
|
|
15159
|
+
activeTask = null;
|
|
15160
|
+
automaticSyncStarted = false;
|
|
15161
|
+
constructor(deps) {
|
|
15162
|
+
this.deps = deps;
|
|
15163
|
+
this.snapshot = this.createManager().getSnapshot();
|
|
15164
|
+
this.startAutomaticSync();
|
|
15165
|
+
}
|
|
15166
|
+
getState = async () => {
|
|
15167
|
+
this.startAutomaticSync();
|
|
15168
|
+
return this.snapshot;
|
|
15169
|
+
};
|
|
15170
|
+
checkForUpdates = async () => {
|
|
15171
|
+
return this.startCheck({ autoDownload: false });
|
|
15172
|
+
};
|
|
15173
|
+
downloadUpdate = async () => {
|
|
15174
|
+
return this.startDownload();
|
|
15175
|
+
};
|
|
15176
|
+
applyDownloadedUpdate = async () => {
|
|
15177
|
+
if (this.activeTask) return this.snapshot;
|
|
15178
|
+
this.setSnapshot({
|
|
15179
|
+
...this.snapshot,
|
|
15180
|
+
status: "applying",
|
|
15181
|
+
progress: null,
|
|
15182
|
+
errorMessage: null
|
|
15183
|
+
});
|
|
15184
|
+
try {
|
|
15185
|
+
const snapshot = this.createManager().applyDownloadedUpdate();
|
|
15186
|
+
this.setSnapshot(this.deps.applyRestartMode === "managed-service-restart" ? snapshot : {
|
|
15187
|
+
...snapshot,
|
|
15188
|
+
recoveryCommand: "Restart this NextClaw process to launch the downloaded runtime."
|
|
15189
|
+
});
|
|
15190
|
+
if (this.deps.applyRestartMode === "managed-service-restart") await requestManagedServiceRestart(this.deps.requestRestart, {
|
|
15191
|
+
reason: "runtime update apply",
|
|
15192
|
+
uiPort: this.deps.uiConfig.port
|
|
15193
|
+
});
|
|
15194
|
+
return this.snapshot;
|
|
15195
|
+
} catch (error) {
|
|
15196
|
+
this.setSnapshot(this.toFailedSnapshot(error));
|
|
15197
|
+
throw error;
|
|
15198
|
+
}
|
|
15199
|
+
};
|
|
15200
|
+
updatePreferences = async (preferences) => {
|
|
15201
|
+
const nextState = this.stateStore.update((current) => ({
|
|
15202
|
+
...current,
|
|
15203
|
+
updatePreferences: {
|
|
15204
|
+
...current.updatePreferences,
|
|
15205
|
+
...preferences
|
|
15206
|
+
}
|
|
15207
|
+
}));
|
|
15208
|
+
this.setSnapshot(this.createManager(nextState.channel).getSnapshot());
|
|
15209
|
+
if (nextState.updatePreferences.automaticChecks) this.startAutomaticSync({ force: true });
|
|
15210
|
+
return this.snapshot;
|
|
15211
|
+
};
|
|
15212
|
+
updateChannel = async (channel) => {
|
|
15213
|
+
const nextState = this.stateStore.update((current) => ({
|
|
15214
|
+
...current,
|
|
15215
|
+
channel
|
|
15216
|
+
}));
|
|
15217
|
+
this.setSnapshot(this.createManager(nextState.channel).getSnapshot());
|
|
15218
|
+
if (nextState.updatePreferences.automaticChecks) return this.startCheck({ autoDownload: nextState.updatePreferences.autoDownload });
|
|
15219
|
+
return this.snapshot;
|
|
15220
|
+
};
|
|
15221
|
+
startAutomaticSync = (options = {}) => {
|
|
15222
|
+
if (this.activeTask) return;
|
|
15223
|
+
if (this.automaticSyncStarted && !options.force) return;
|
|
15224
|
+
this.automaticSyncStarted = true;
|
|
15225
|
+
const state = this.stateStore.read();
|
|
15226
|
+
if (!state.updatePreferences.automaticChecks || state.downloadedVersion) return;
|
|
15227
|
+
this.startCheck({ autoDownload: state.updatePreferences.autoDownload });
|
|
15228
|
+
};
|
|
15229
|
+
startCheck = async (options) => {
|
|
15230
|
+
if (this.activeTask) return this.snapshot;
|
|
15231
|
+
this.setSnapshot({
|
|
15232
|
+
...this.createManager().getSnapshot(),
|
|
15233
|
+
status: "checking",
|
|
15234
|
+
progress: null,
|
|
15235
|
+
errorMessage: null
|
|
15236
|
+
});
|
|
15237
|
+
this.activeTask = (async () => {
|
|
15238
|
+
try {
|
|
15239
|
+
const checkedSnapshot = await this.createManager().checkForUpdate();
|
|
15240
|
+
this.setSnapshot(checkedSnapshot);
|
|
15241
|
+
if (options.autoDownload && checkedSnapshot.status === "update-available") await this.runDownloadTask();
|
|
15242
|
+
} catch (error) {
|
|
15243
|
+
this.setSnapshot(this.toFailedSnapshot(error));
|
|
15244
|
+
} finally {
|
|
15245
|
+
this.activeTask = null;
|
|
15246
|
+
}
|
|
15247
|
+
})();
|
|
15248
|
+
return this.snapshot;
|
|
15249
|
+
};
|
|
15250
|
+
startDownload = async () => {
|
|
15251
|
+
if (this.activeTask) return this.snapshot;
|
|
15252
|
+
this.setSnapshot({
|
|
15253
|
+
...this.createManager().getSnapshot(),
|
|
15254
|
+
status: "downloading",
|
|
15255
|
+
progress: INITIAL_DOWNLOAD_PROGRESS,
|
|
15256
|
+
errorMessage: null
|
|
15257
|
+
});
|
|
15258
|
+
this.activeTask = (async () => {
|
|
15259
|
+
try {
|
|
15260
|
+
await this.runDownloadTask();
|
|
15261
|
+
} catch (error) {
|
|
15262
|
+
this.setSnapshot(this.toFailedSnapshot(error));
|
|
15263
|
+
} finally {
|
|
15264
|
+
this.activeTask = null;
|
|
15265
|
+
}
|
|
15266
|
+
})();
|
|
15267
|
+
return this.snapshot;
|
|
15268
|
+
};
|
|
15269
|
+
runDownloadTask = async () => {
|
|
15270
|
+
const downloadedSnapshot = await this.createManager().downloadUpdate((progress) => {
|
|
15271
|
+
this.setSnapshot({
|
|
15272
|
+
...this.snapshot,
|
|
15273
|
+
status: "downloading",
|
|
15274
|
+
progress,
|
|
15275
|
+
errorMessage: null
|
|
15276
|
+
});
|
|
15277
|
+
});
|
|
15278
|
+
this.setSnapshot(downloadedSnapshot);
|
|
15279
|
+
};
|
|
15280
|
+
createManager = (channel = this.stateStore.read().channel) => {
|
|
15281
|
+
return new NpmRuntimeUpdateManager({
|
|
15282
|
+
layout: this.layout,
|
|
15283
|
+
stateStore: this.stateStore,
|
|
15284
|
+
bundleService: this.bundleService,
|
|
15285
|
+
updateService: this.updateService,
|
|
15286
|
+
resolveManifestUrl: (resolvedChannel) => this.source.resolveManifestUrl(resolvedChannel),
|
|
15287
|
+
launcherVersion: this.launcherVersion,
|
|
15288
|
+
channel
|
|
15289
|
+
});
|
|
15290
|
+
};
|
|
15291
|
+
toFailedSnapshot = (error) => {
|
|
15292
|
+
return {
|
|
15293
|
+
...this.createManager().getSnapshot(),
|
|
15294
|
+
status: "failed",
|
|
15295
|
+
progress: null,
|
|
15296
|
+
errorMessage: error instanceof Error ? error.message : String(error ?? "Unknown error")
|
|
15297
|
+
};
|
|
15298
|
+
};
|
|
15299
|
+
setSnapshot = (snapshot) => {
|
|
15300
|
+
this.snapshot = snapshot;
|
|
15301
|
+
nextclaw.eventBus.emit(eventKeys.runtimeUpdateSnapshot, snapshot, { source: "backend" });
|
|
15302
|
+
return snapshot;
|
|
15303
|
+
};
|
|
15304
|
+
};
|
|
15305
|
+
function createNpmRuntimeUpdateHost(params) {
|
|
15306
|
+
return new NpmRuntimeUpdateHost(params);
|
|
15307
|
+
}
|
|
15308
|
+
//#endregion
|
|
15202
15309
|
//#region src/cli/shared/stores/pending-restart.store.ts
|
|
15203
15310
|
const clonePendingRestartState = (state) => {
|
|
15204
15311
|
if (!state) return null;
|
|
@@ -15319,13 +15426,26 @@ function createRuntimeControlHost(params) {
|
|
|
15319
15426
|
}
|
|
15320
15427
|
//#endregion
|
|
15321
15428
|
//#region src/cli/shared/services/ui/service-ui-hosts.service.ts
|
|
15429
|
+
function resolveApplyRestartMode(uiPort) {
|
|
15430
|
+
const serviceState = managedServiceStateStore.read();
|
|
15431
|
+
if (serviceState?.pid === process.pid) return "managed-service-restart";
|
|
15432
|
+
if (process.env.NEXTCLAW_RUNTIME_BUNDLE_CHILD === "1" && typeof serviceState?.uiPort === "number" && serviceState.uiPort === uiPort) return "managed-service-restart";
|
|
15433
|
+
return "manual-process-restart";
|
|
15434
|
+
}
|
|
15322
15435
|
function createServiceUiHosts(params) {
|
|
15436
|
+
const { requestRestart, serviceCommands, uiConfig } = params;
|
|
15437
|
+
const applyRestartMode = resolveApplyRestartMode(uiConfig.port);
|
|
15323
15438
|
return {
|
|
15324
15439
|
remoteAccess: createRemoteAccessHost(params),
|
|
15325
15440
|
runtimeControl: createRuntimeControlHost({
|
|
15326
|
-
serviceCommands
|
|
15327
|
-
requestRestart
|
|
15328
|
-
uiConfig
|
|
15441
|
+
serviceCommands,
|
|
15442
|
+
requestRestart,
|
|
15443
|
+
uiConfig
|
|
15444
|
+
}),
|
|
15445
|
+
runtimeUpdate: process.env.NEXTCLAW_DISABLE_RUNTIME_UPDATE_HOST === "1" ? void 0 : createNpmRuntimeUpdateHost({
|
|
15446
|
+
applyRestartMode,
|
|
15447
|
+
requestRestart,
|
|
15448
|
+
uiConfig
|
|
15329
15449
|
})
|
|
15330
15450
|
};
|
|
15331
15451
|
}
|
|
@@ -15665,6 +15785,9 @@ var ConfigReloader = class {
|
|
|
15665
15785
|
setReloadMcp(callback) {
|
|
15666
15786
|
this.options.reloadMcp = callback;
|
|
15667
15787
|
}
|
|
15788
|
+
setReloadCompanion(callback) {
|
|
15789
|
+
this.options.reloadCompanion = callback;
|
|
15790
|
+
}
|
|
15668
15791
|
async applyReloadPlan(nextConfig) {
|
|
15669
15792
|
const changedPaths = diffConfigPaths(this.currentConfig, nextConfig);
|
|
15670
15793
|
if (!changedPaths.length) return;
|
|
@@ -15686,6 +15809,13 @@ var ConfigReloader = class {
|
|
|
15686
15809
|
});
|
|
15687
15810
|
console.log("Config reload: MCP servers reloaded.");
|
|
15688
15811
|
}
|
|
15812
|
+
if (plan.reloadCompanion) {
|
|
15813
|
+
await this.reloadCompanion({
|
|
15814
|
+
config: nextConfig,
|
|
15815
|
+
changedPaths
|
|
15816
|
+
});
|
|
15817
|
+
console.log("Config reload: companion setting applied.");
|
|
15818
|
+
}
|
|
15689
15819
|
if (plan.restartChannels || reloadPluginsResult?.restartChannels) {
|
|
15690
15820
|
await this.reloadChannels(nextConfig, { start: true });
|
|
15691
15821
|
console.log("Config reload: channels restarted.");
|
|
@@ -15781,6 +15911,10 @@ var ConfigReloader = class {
|
|
|
15781
15911
|
if (!this.options.reloadMcp) return;
|
|
15782
15912
|
await this.options.reloadMcp(params);
|
|
15783
15913
|
}
|
|
15914
|
+
async reloadCompanion(params) {
|
|
15915
|
+
if (!this.options.reloadCompanion) return;
|
|
15916
|
+
await this.options.reloadCompanion(params);
|
|
15917
|
+
}
|
|
15784
15918
|
};
|
|
15785
15919
|
//#endregion
|
|
15786
15920
|
//#region src/cli/shared/services/gateway/cron-job-handler.service.ts
|
|
@@ -16161,11 +16295,11 @@ function createSystemSessionUpdatedPublisher(params) {
|
|
|
16161
16295
|
}
|
|
16162
16296
|
async function startUiShell(params) {
|
|
16163
16297
|
logStartupTrace("service.start_ui_shell.begin");
|
|
16164
|
-
const { applyLiveConfigReload, configPath, cronService, getBootstrapStatus, getPluginChannelBindings, getPluginUiMetadata, initializeAgentHomeDirectory, marketplace, ncpSessionService, openBrowserWindow, productVersion, remoteAccess, runtimeControl, uiConfig, uiStaticDir } = params;
|
|
16298
|
+
const { applyLiveConfigReload, configPath, cronService, getBootstrapStatus, getPluginChannelBindings, getPluginUiMetadata, initializeAgentHomeDirectory, marketplace, ncpSessionService, openBrowserWindow, productVersion, remoteAccess, runtimeControl, runtimeUpdate, uiConfig, uiStaticDir } = params;
|
|
16165
16299
|
if (!uiConfig.enabled) return null;
|
|
16166
16300
|
let publishUiEvent = null;
|
|
16167
16301
|
const deferredNcpAgent = createDeferredUiNcpAgent();
|
|
16168
|
-
const uiServer = startUiServer({
|
|
16302
|
+
const uiServer = await startUiServer({
|
|
16169
16303
|
host: uiConfig.host,
|
|
16170
16304
|
port: uiConfig.port,
|
|
16171
16305
|
configPath,
|
|
@@ -16177,6 +16311,7 @@ async function startUiShell(params) {
|
|
|
16177
16311
|
marketplace,
|
|
16178
16312
|
remoteAccess,
|
|
16179
16313
|
runtimeControl,
|
|
16314
|
+
runtimeUpdate,
|
|
16180
16315
|
getBootstrapStatus,
|
|
16181
16316
|
getPluginChannelBindings,
|
|
16182
16317
|
getPluginUiMetadata,
|
|
@@ -16779,17 +16914,17 @@ function readStringList(value) {
|
|
|
16779
16914
|
if (!Array.isArray(value)) return [];
|
|
16780
16915
|
return value.map((entry) => typeof entry === "string" ? entry.trim() : "").filter(Boolean);
|
|
16781
16916
|
}
|
|
16782
|
-
function readOptionalString(value) {
|
|
16917
|
+
function readOptionalString$1(value) {
|
|
16783
16918
|
if (typeof value !== "string") return;
|
|
16784
16919
|
return value.trim() || void 0;
|
|
16785
16920
|
}
|
|
16786
16921
|
function resolvePluginRuntimeAttachments(ctx) {
|
|
16787
16922
|
const mediaPaths = readStringList(ctx.MediaPaths);
|
|
16788
16923
|
const mediaUrls = readStringList(ctx.MediaUrls);
|
|
16789
|
-
const fallbackPath = readOptionalString(ctx.MediaPath);
|
|
16790
|
-
const fallbackUrl = readOptionalString(ctx.MediaUrl);
|
|
16924
|
+
const fallbackPath = readOptionalString$1(ctx.MediaPath);
|
|
16925
|
+
const fallbackUrl = readOptionalString$1(ctx.MediaUrl);
|
|
16791
16926
|
const mediaTypes = readStringList(ctx.MediaTypes);
|
|
16792
|
-
const fallbackType = readOptionalString(ctx.MediaType);
|
|
16927
|
+
const fallbackType = readOptionalString$1(ctx.MediaType);
|
|
16793
16928
|
const entryCount = Math.max(mediaPaths.length, mediaUrls.length, fallbackPath ? 1 : 0, fallbackUrl ? 1 : 0);
|
|
16794
16929
|
const attachments = [];
|
|
16795
16930
|
for (let index = 0; index < entryCount; index += 1) {
|
|
@@ -16812,7 +16947,7 @@ function resolvePluginRuntimeAttachments(ctx) {
|
|
|
16812
16947
|
//#region src/cli/shared/services/plugin/service-plugin-reload.service.ts
|
|
16813
16948
|
async function reloadServicePlugins(params) {
|
|
16814
16949
|
const nextWorkspace = getWorkspacePath(params.nextConfig.agents.defaults.workspace);
|
|
16815
|
-
const nextPluginRegistry =
|
|
16950
|
+
const nextPluginRegistry = await loadPluginRegistryProgressively(params.nextConfig, nextWorkspace);
|
|
16816
16951
|
const nextExtensionRegistry = toExtensionRegistry(nextPluginRegistry);
|
|
16817
16952
|
const nextPluginChannelBindings = getPluginChannelBindings(nextPluginRegistry);
|
|
16818
16953
|
const shouldRestartChannels = shouldRestartChannelsForPluginReload({
|
|
@@ -16868,30 +17003,52 @@ function applyGatewayRuntimeCapabilityState(params) {
|
|
|
16868
17003
|
params.state.extensionRegistry = params.next.extensionRegistry;
|
|
16869
17004
|
params.state.pluginChannelBindings = params.next.pluginChannelBindings;
|
|
16870
17005
|
}
|
|
17006
|
+
async function applyGatewayPluginReload(params) {
|
|
17007
|
+
const result = await reloadServicePlugins({
|
|
17008
|
+
nextConfig: params.nextConfig,
|
|
17009
|
+
changedPaths: params.changedPaths,
|
|
17010
|
+
pluginRegistry: params.state.pluginRegistry,
|
|
17011
|
+
extensionRegistry: params.state.extensionRegistry,
|
|
17012
|
+
pluginChannelBindings: params.state.pluginChannelBindings,
|
|
17013
|
+
pluginGatewayHandles: params.state.pluginGatewayHandles,
|
|
17014
|
+
pluginGatewayLogger,
|
|
17015
|
+
logPluginGatewayDiagnostics
|
|
17016
|
+
});
|
|
17017
|
+
applyGatewayRuntimeCapabilityState({
|
|
17018
|
+
gateway: params.gateway,
|
|
17019
|
+
state: params.state,
|
|
17020
|
+
next: {
|
|
17021
|
+
pluginRegistry: result.pluginRegistry,
|
|
17022
|
+
extensionRegistry: result.extensionRegistry,
|
|
17023
|
+
pluginChannelBindings: result.pluginChannelBindings
|
|
17024
|
+
}
|
|
17025
|
+
});
|
|
17026
|
+
params.state.pluginUiMetadata = getPluginUiMetadataFromRegistry(result.pluginRegistry);
|
|
17027
|
+
params.state.pluginGatewayHandles = result.pluginGatewayHandles;
|
|
17028
|
+
params.getLiveUiNcpAgent()?.applyExtensionRegistry?.(result.extensionRegistry);
|
|
17029
|
+
return { restartChannels: result.restartChannels };
|
|
17030
|
+
}
|
|
17031
|
+
async function reloadGatewayPluginRuntimeForChanges(params) {
|
|
17032
|
+
const nextConfig = resolveConfigSecrets$2(loadConfig$2(), { configPath: params.gateway.runtimeConfigPath });
|
|
17033
|
+
const result = await applyGatewayPluginReload({
|
|
17034
|
+
gateway: params.gateway,
|
|
17035
|
+
state: params.state,
|
|
17036
|
+
getLiveUiNcpAgent: params.getLiveUiNcpAgent,
|
|
17037
|
+
nextConfig,
|
|
17038
|
+
changedPaths: params.changedPaths
|
|
17039
|
+
});
|
|
17040
|
+
if (result.restartChannels) await params.gateway.reloader.rebuildChannels(nextConfig, { start: true });
|
|
17041
|
+
return result;
|
|
17042
|
+
}
|
|
16871
17043
|
function configureGatewayPluginRuntime(params) {
|
|
16872
17044
|
params.gateway.reloader.setReloadPlugins(async ({ config: nextConfig, changedPaths }) => {
|
|
16873
|
-
const result = await
|
|
16874
|
-
nextConfig,
|
|
16875
|
-
changedPaths,
|
|
16876
|
-
pluginRegistry: params.state.pluginRegistry,
|
|
16877
|
-
extensionRegistry: params.state.extensionRegistry,
|
|
16878
|
-
pluginChannelBindings: params.state.pluginChannelBindings,
|
|
16879
|
-
pluginGatewayHandles: params.state.pluginGatewayHandles,
|
|
16880
|
-
pluginGatewayLogger,
|
|
16881
|
-
logPluginGatewayDiagnostics
|
|
16882
|
-
});
|
|
16883
|
-
applyGatewayRuntimeCapabilityState({
|
|
17045
|
+
const result = await applyGatewayPluginReload({
|
|
16884
17046
|
gateway: params.gateway,
|
|
16885
17047
|
state: params.state,
|
|
16886
|
-
|
|
16887
|
-
|
|
16888
|
-
|
|
16889
|
-
pluginChannelBindings: result.pluginChannelBindings
|
|
16890
|
-
}
|
|
17048
|
+
getLiveUiNcpAgent: params.getLiveUiNcpAgent,
|
|
17049
|
+
nextConfig,
|
|
17050
|
+
changedPaths
|
|
16891
17051
|
});
|
|
16892
|
-
params.state.pluginUiMetadata = getPluginUiMetadataFromRegistry(result.pluginRegistry);
|
|
16893
|
-
params.state.pluginGatewayHandles = result.pluginGatewayHandles;
|
|
16894
|
-
params.getLiveUiNcpAgent()?.applyExtensionRegistry?.(result.extensionRegistry);
|
|
16895
17052
|
if (result.restartChannels) console.log("Config reload: plugin channel gateways restarted.");
|
|
16896
17053
|
return { restartChannels: result.restartChannels };
|
|
16897
17054
|
});
|
|
@@ -16962,8 +17119,282 @@ async function cleanupGatewayRuntime(params) {
|
|
|
16962
17119
|
setPluginRuntimeBridge(null);
|
|
16963
17120
|
}
|
|
16964
17121
|
//#endregion
|
|
17122
|
+
//#region src/cli/shared/services/plugin/service-plugin-dev-hot-reload.service.ts
|
|
17123
|
+
const DEV_PLUGIN_HOT_RELOAD_TARGETS_ENV = "NEXTCLAW_DEV_PLUGIN_HOT_RELOAD_TARGETS";
|
|
17124
|
+
function isRecord$2(value) {
|
|
17125
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
17126
|
+
}
|
|
17127
|
+
function readOptionalString(value) {
|
|
17128
|
+
if (typeof value !== "string") return null;
|
|
17129
|
+
const trimmed = value.trim();
|
|
17130
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
17131
|
+
}
|
|
17132
|
+
function normalizeWatchPaths(value) {
|
|
17133
|
+
if (!Array.isArray(value)) return [];
|
|
17134
|
+
const watchPaths = [];
|
|
17135
|
+
for (const entry of value) {
|
|
17136
|
+
const normalized = readOptionalString(entry);
|
|
17137
|
+
if (!normalized) continue;
|
|
17138
|
+
const resolvedPath = resolve(normalized);
|
|
17139
|
+
if (!watchPaths.includes(resolvedPath)) watchPaths.push(resolvedPath);
|
|
17140
|
+
}
|
|
17141
|
+
return watchPaths;
|
|
17142
|
+
}
|
|
17143
|
+
function resolveDevPluginHotReloadTargets(rawValue = process.env[DEV_PLUGIN_HOT_RELOAD_TARGETS_ENV]) {
|
|
17144
|
+
if (typeof rawValue !== "string" || rawValue.trim().length === 0) return [];
|
|
17145
|
+
let parsed;
|
|
17146
|
+
try {
|
|
17147
|
+
parsed = JSON.parse(rawValue);
|
|
17148
|
+
} catch (error) {
|
|
17149
|
+
throw new Error(`[dev-plugin-hot-reload] failed to parse ${DEV_PLUGIN_HOT_RELOAD_TARGETS_ENV}: ${error instanceof Error ? error.message : String(error)}`);
|
|
17150
|
+
}
|
|
17151
|
+
if (!Array.isArray(parsed)) throw new Error(`[dev-plugin-hot-reload] ${DEV_PLUGIN_HOT_RELOAD_TARGETS_ENV} must be a JSON array`);
|
|
17152
|
+
const seenPluginIds = /* @__PURE__ */ new Set();
|
|
17153
|
+
const targets = [];
|
|
17154
|
+
for (const entry of parsed) {
|
|
17155
|
+
if (!isRecord$2(entry)) continue;
|
|
17156
|
+
const pluginId = readOptionalString(entry.pluginId);
|
|
17157
|
+
const pluginPath = readOptionalString(entry.pluginPath);
|
|
17158
|
+
const watchPaths = normalizeWatchPaths(entry.watchPaths);
|
|
17159
|
+
if (!pluginId || !pluginPath || watchPaths.length === 0) continue;
|
|
17160
|
+
if (seenPluginIds.has(pluginId)) throw new Error(`[dev-plugin-hot-reload] duplicate plugin target for "${pluginId}"`);
|
|
17161
|
+
seenPluginIds.add(pluginId);
|
|
17162
|
+
targets.push({
|
|
17163
|
+
pluginId,
|
|
17164
|
+
pluginPath: resolve(pluginPath),
|
|
17165
|
+
watchPaths
|
|
17166
|
+
});
|
|
17167
|
+
}
|
|
17168
|
+
return targets;
|
|
17169
|
+
}
|
|
17170
|
+
function startDevPluginHotReloadWatcher(params) {
|
|
17171
|
+
const targets = params.targets ?? resolveDevPluginHotReloadTargets();
|
|
17172
|
+
if (targets.length === 0) return;
|
|
17173
|
+
const pendingPluginIds = /* @__PURE__ */ new Set();
|
|
17174
|
+
let flushTimer = null;
|
|
17175
|
+
let reloadRunning = false;
|
|
17176
|
+
let reloadPending = false;
|
|
17177
|
+
const flushReload = async () => {
|
|
17178
|
+
if (reloadRunning) {
|
|
17179
|
+
reloadPending = true;
|
|
17180
|
+
return;
|
|
17181
|
+
}
|
|
17182
|
+
const pluginIds = [...pendingPluginIds];
|
|
17183
|
+
pendingPluginIds.clear();
|
|
17184
|
+
if (pluginIds.length === 0) return;
|
|
17185
|
+
reloadRunning = true;
|
|
17186
|
+
try {
|
|
17187
|
+
console.log(`[dev] Plugin dist updated: ${pluginIds.join(", ")}`);
|
|
17188
|
+
await params.reloadPlugins(pluginIds);
|
|
17189
|
+
console.log(`[dev] Plugin hot reload applied: ${pluginIds.join(", ")}`);
|
|
17190
|
+
} catch (error) {
|
|
17191
|
+
console.error(`[dev] Plugin hot reload failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
17192
|
+
} finally {
|
|
17193
|
+
reloadRunning = false;
|
|
17194
|
+
if (reloadPending || pendingPluginIds.size > 0) {
|
|
17195
|
+
reloadPending = false;
|
|
17196
|
+
await flushReload();
|
|
17197
|
+
}
|
|
17198
|
+
}
|
|
17199
|
+
};
|
|
17200
|
+
const scheduleReload = (pluginId) => {
|
|
17201
|
+
pendingPluginIds.add(pluginId);
|
|
17202
|
+
if (flushTimer) clearTimeout(flushTimer);
|
|
17203
|
+
flushTimer = setTimeout(() => {
|
|
17204
|
+
flushTimer = null;
|
|
17205
|
+
flushReload();
|
|
17206
|
+
}, 150);
|
|
17207
|
+
};
|
|
17208
|
+
const watcher = chokidar.watch(targets.flatMap((entry) => entry.watchPaths), {
|
|
17209
|
+
ignoreInitial: true,
|
|
17210
|
+
awaitWriteFinish: {
|
|
17211
|
+
stabilityThreshold: 200,
|
|
17212
|
+
pollInterval: 50
|
|
17213
|
+
}
|
|
17214
|
+
});
|
|
17215
|
+
params.watcherRegistry.remember(watcher);
|
|
17216
|
+
watcher.on("all", (_event, changedPath) => {
|
|
17217
|
+
const normalizedChangedPath = resolve(changedPath);
|
|
17218
|
+
for (const target of targets) if (target.watchPaths.some((watchPath) => normalizedChangedPath === watchPath || normalizedChangedPath.startsWith(`${watchPath}${sep}`))) scheduleReload(target.pluginId);
|
|
17219
|
+
});
|
|
17220
|
+
console.log(`[dev] Plugin hot reload watcher: ${targets.map((entry) => entry.pluginId).join(", ")}`);
|
|
17221
|
+
}
|
|
17222
|
+
function wrapStartChannelsWithDevPluginHotReload(params) {
|
|
17223
|
+
return async () => {
|
|
17224
|
+
await params.startChannels();
|
|
17225
|
+
console.log(`[dev] Plugin hot reload watcher will arm after ${params.startupSettleMs}ms startup settle window.`);
|
|
17226
|
+
setTimeout(() => {
|
|
17227
|
+
if (!params.isRuntimeActive()) return;
|
|
17228
|
+
startDevPluginHotReloadWatcher({
|
|
17229
|
+
watcherRegistry: params.watcherRegistry,
|
|
17230
|
+
reloadPlugins: params.reloadPlugins
|
|
17231
|
+
});
|
|
17232
|
+
}, params.startupSettleMs).unref?.();
|
|
17233
|
+
};
|
|
17234
|
+
}
|
|
17235
|
+
//#endregion
|
|
17236
|
+
//#region src/cli/shared/stores/companion-runtime.store.ts
|
|
17237
|
+
var CompanionRuntimeStore = class {
|
|
17238
|
+
get path() {
|
|
17239
|
+
return resolve(getDataDir(), "run", "companion.json");
|
|
17240
|
+
}
|
|
17241
|
+
read = () => {
|
|
17242
|
+
if (!existsSync(this.path)) return null;
|
|
17243
|
+
try {
|
|
17244
|
+
return JSON.parse(readFileSync(this.path, "utf-8"));
|
|
17245
|
+
} catch {
|
|
17246
|
+
return null;
|
|
17247
|
+
}
|
|
17248
|
+
};
|
|
17249
|
+
write = (state) => {
|
|
17250
|
+
mkdirSync(resolve(this.path, ".."), { recursive: true });
|
|
17251
|
+
writeFileSync(this.path, JSON.stringify(state, null, 2));
|
|
17252
|
+
};
|
|
17253
|
+
clear = () => {
|
|
17254
|
+
if (existsSync(this.path)) rmSync(this.path, { force: true });
|
|
17255
|
+
};
|
|
17256
|
+
};
|
|
17257
|
+
const companionRuntimeStore = new CompanionRuntimeStore();
|
|
17258
|
+
//#endregion
|
|
17259
|
+
//#region src/cli/shared/services/ui/companion-runtime.service.ts
|
|
17260
|
+
const require$2 = createRequire(import.meta.url);
|
|
17261
|
+
var CompanionRuntimeService = class {
|
|
17262
|
+
constructor(runtimeStore = companionRuntimeStore, uiDiscoveryService = localUiDiscoveryService) {
|
|
17263
|
+
this.runtimeStore = runtimeStore;
|
|
17264
|
+
this.uiDiscoveryService = uiDiscoveryService;
|
|
17265
|
+
}
|
|
17266
|
+
getRunningState = () => {
|
|
17267
|
+
const state = this.runtimeStore.read();
|
|
17268
|
+
if (!state) return null;
|
|
17269
|
+
if (!isProcessRunning(state.pid)) {
|
|
17270
|
+
this.runtimeStore.clear();
|
|
17271
|
+
return null;
|
|
17272
|
+
}
|
|
17273
|
+
return state;
|
|
17274
|
+
};
|
|
17275
|
+
resolveDiscoveredBaseUrl = () => {
|
|
17276
|
+
return this.uiDiscoveryService.resolveApiBase();
|
|
17277
|
+
};
|
|
17278
|
+
applyConfig = async (config) => {
|
|
17279
|
+
if (!config.companion.enabled) {
|
|
17280
|
+
await this.ensureStopped();
|
|
17281
|
+
return;
|
|
17282
|
+
}
|
|
17283
|
+
await this.ensureStarted({ baseUrl: this.uiDiscoveryService.resolveLocalOrigin(config) });
|
|
17284
|
+
};
|
|
17285
|
+
updateEnabled = async (enabled, options = {}) => {
|
|
17286
|
+
const config = loadConfig(getConfigPath());
|
|
17287
|
+
const next = {
|
|
17288
|
+
...config,
|
|
17289
|
+
companion: {
|
|
17290
|
+
...config.companion,
|
|
17291
|
+
enabled
|
|
17292
|
+
}
|
|
17293
|
+
};
|
|
17294
|
+
saveConfig(next, getConfigPath());
|
|
17295
|
+
if (enabled) {
|
|
17296
|
+
const explicitBaseUrl = options.baseUrl?.trim();
|
|
17297
|
+
if (explicitBaseUrl) {
|
|
17298
|
+
await this.ensureStarted({ baseUrl: explicitBaseUrl });
|
|
17299
|
+
return next;
|
|
17300
|
+
}
|
|
17301
|
+
const discoveredBaseUrl = this.uiDiscoveryService.resolveApiBase();
|
|
17302
|
+
if (discoveredBaseUrl) await this.ensureStarted({ baseUrl: discoveredBaseUrl });
|
|
17303
|
+
return next;
|
|
17304
|
+
}
|
|
17305
|
+
await this.ensureStopped();
|
|
17306
|
+
return next;
|
|
17307
|
+
};
|
|
17308
|
+
ensureStarted = async (options) => {
|
|
17309
|
+
const baseUrl = options.baseUrl.trim().replace(/\/+$/, "");
|
|
17310
|
+
const runningState = this.getRunningState();
|
|
17311
|
+
if (runningState?.baseUrl === baseUrl) return runningState;
|
|
17312
|
+
if (runningState) {
|
|
17313
|
+
this.killProcess(runningState.pid, false);
|
|
17314
|
+
this.runtimeStore.clear();
|
|
17315
|
+
}
|
|
17316
|
+
const launchSpec = this.resolveLaunchSpec();
|
|
17317
|
+
const child = spawn(launchSpec.command, [
|
|
17318
|
+
...launchSpec.args,
|
|
17319
|
+
"--base-url",
|
|
17320
|
+
baseUrl
|
|
17321
|
+
], {
|
|
17322
|
+
detached: true,
|
|
17323
|
+
stdio: "ignore",
|
|
17324
|
+
env: {
|
|
17325
|
+
...process.env,
|
|
17326
|
+
NEXTCLAW_COMPANION_RUNTIME_STATE_PATH: this.runtimeStore.path
|
|
17327
|
+
}
|
|
17328
|
+
});
|
|
17329
|
+
child.unref();
|
|
17330
|
+
return await this.waitForRunningState(baseUrl, child.pid ?? -1);
|
|
17331
|
+
};
|
|
17332
|
+
ensureStopped = async (options = {}) => {
|
|
17333
|
+
const state = this.runtimeStore.read();
|
|
17334
|
+
if (!state) return false;
|
|
17335
|
+
if (!isProcessRunning(state.pid)) {
|
|
17336
|
+
this.runtimeStore.clear();
|
|
17337
|
+
return false;
|
|
17338
|
+
}
|
|
17339
|
+
this.killProcess(state.pid, options.force === true);
|
|
17340
|
+
this.runtimeStore.clear();
|
|
17341
|
+
return true;
|
|
17342
|
+
};
|
|
17343
|
+
printStatus = (options = {}) => {
|
|
17344
|
+
const runningState = this.getRunningState();
|
|
17345
|
+
const config = loadConfig(getConfigPath());
|
|
17346
|
+
const view = runningState ? {
|
|
17347
|
+
configuredEnabled: config.companion.enabled,
|
|
17348
|
+
running: true,
|
|
17349
|
+
...runningState
|
|
17350
|
+
} : {
|
|
17351
|
+
configuredEnabled: config.companion.enabled,
|
|
17352
|
+
running: false
|
|
17353
|
+
};
|
|
17354
|
+
if (options.json) {
|
|
17355
|
+
console.log(JSON.stringify(view, null, 2));
|
|
17356
|
+
return;
|
|
17357
|
+
}
|
|
17358
|
+
if (!runningState) {
|
|
17359
|
+
console.log(config.companion.enabled ? "Companion is enabled in config but is not running." : "Companion is disabled and not running.");
|
|
17360
|
+
return;
|
|
17361
|
+
}
|
|
17362
|
+
console.log(`Companion is running (pid ${runningState.pid}) at ${runningState.baseUrl}. Configured enabled: ${config.companion.enabled ? "yes" : "no"}.`);
|
|
17363
|
+
};
|
|
17364
|
+
printStarted = (state) => {
|
|
17365
|
+
console.log(`Started ${APP_NAME} companion (pid ${state.pid}) using ${state.baseUrl}.`);
|
|
17366
|
+
};
|
|
17367
|
+
printStopped = (stopped) => {
|
|
17368
|
+
console.log(stopped ? "Stopped companion process." : "Companion is not running.");
|
|
17369
|
+
};
|
|
17370
|
+
killProcess = (pid, force) => {
|
|
17371
|
+
process.kill(pid, force ? "SIGKILL" : "SIGTERM");
|
|
17372
|
+
};
|
|
17373
|
+
resolveLaunchSpec = () => {
|
|
17374
|
+
const packageJsonPath = require$2.resolve("@nextclaw/companion/package.json");
|
|
17375
|
+
const packageRoot = dirname(packageJsonPath);
|
|
17376
|
+
const mainPath = resolve(packageRoot, "dist", "src", "main.js");
|
|
17377
|
+
if (!existsSync(mainPath)) throw new Error(`Companion app build is missing at ${mainPath}. Build @nextclaw/companion first.`);
|
|
17378
|
+
return {
|
|
17379
|
+
command: createRequire(packageJsonPath)("electron"),
|
|
17380
|
+
args: [packageRoot]
|
|
17381
|
+
};
|
|
17382
|
+
};
|
|
17383
|
+
waitForRunningState = async (baseUrl, fallbackPid) => {
|
|
17384
|
+
const timeoutAt = Date.now() + 5e3;
|
|
17385
|
+
while (Date.now() < timeoutAt) {
|
|
17386
|
+
const state = this.getRunningState();
|
|
17387
|
+
if (state?.baseUrl === baseUrl) return state;
|
|
17388
|
+
await new Promise((resolvePromise) => setTimeout(resolvePromise, 100));
|
|
17389
|
+
}
|
|
17390
|
+
throw new Error(fallbackPid > 0 ? `Companion started but did not report a live runtime state (launcher pid ${fallbackPid}).` : "Companion started but did not report a live runtime state.");
|
|
17391
|
+
};
|
|
17392
|
+
};
|
|
17393
|
+
const companionRuntimeService = new CompanionRuntimeService();
|
|
17394
|
+
//#endregion
|
|
16965
17395
|
//#region src/cli/shared/services/runtime/runtime-command.service.ts
|
|
16966
17396
|
const { getApiBase, getConfigPath: getConfigPath$1, getProvider, getProviderName, getWorkspacePath: getWorkspacePath$1, loadConfig: loadConfig$1, LiteLLMProvider, MessageBus: MessageBus$1, resolveConfigSecrets: resolveConfigSecrets$1, SessionManager: SessionManager$1, parseAgentScopedSessionKey: parseAgentScopedSessionKey$1 } = NextclawCore;
|
|
17397
|
+
const DEV_PLUGIN_HOT_RELOAD_STARTUP_SETTLE_MS = 5e3;
|
|
16967
17398
|
function createSkillsLoader(workspace) {
|
|
16968
17399
|
const ctor = NextclawCore.SkillsLoader;
|
|
16969
17400
|
if (!ctor) return null;
|
|
@@ -17008,38 +17439,16 @@ var RuntimeCommandService = class {
|
|
|
17008
17439
|
runCliSubcommand: (args) => this.runCliSubcommand(args),
|
|
17009
17440
|
installBuiltinSkill: (slug, force) => this.installBuiltinMarketplaceSkill(slug, force)
|
|
17010
17441
|
}).createInstaller();
|
|
17011
|
-
const
|
|
17012
|
-
|
|
17013
|
-
requestRestart: this.deps.requestRestart,
|
|
17014
|
-
uiConfig: shellContext.uiConfig,
|
|
17015
|
-
remoteModule: shellContext.remoteModule
|
|
17016
|
-
});
|
|
17017
|
-
const uiStartup = await measureStartupAsync("service.start_ui_shell", async () => await startUiShell({
|
|
17018
|
-
uiConfig: shellContext.uiConfig,
|
|
17019
|
-
uiStaticDir: shellContext.uiStaticDir,
|
|
17020
|
-
cronService: shellContext.cron,
|
|
17021
|
-
getConfig: getRuntimeConfig,
|
|
17022
|
-
configPath: getConfigPath$1(),
|
|
17023
|
-
productVersion: getPackageVersion$1(),
|
|
17024
|
-
getPluginChannelBindings: () => runtimeState?.pluginChannelBindings ?? [],
|
|
17025
|
-
getPluginUiMetadata: () => runtimeState?.pluginUiMetadata ?? [],
|
|
17026
|
-
marketplace: {
|
|
17027
|
-
apiBaseUrl: process.env.NEXTCLAW_MARKETPLACE_API_BASE,
|
|
17028
|
-
installer: marketplaceInstaller
|
|
17029
|
-
},
|
|
17030
|
-
remoteAccess,
|
|
17031
|
-
runtimeControl,
|
|
17032
|
-
getBootstrapStatus: () => bootstrapStatus.getStatus(),
|
|
17033
|
-
openBrowserWindow: shellContext.uiConfig.open,
|
|
17442
|
+
const uiStartup = await this.startGatewayUiShell({
|
|
17443
|
+
shellContext,
|
|
17034
17444
|
applyLiveConfigReload,
|
|
17035
|
-
|
|
17036
|
-
|
|
17037
|
-
|
|
17038
|
-
|
|
17039
|
-
|
|
17040
|
-
setUiEventPublisher: (publish) => ncpSessionRealtimeBridge.setUiEventPublisher(publish),
|
|
17041
|
-
uiConfig: shellContext.uiConfig
|
|
17445
|
+
bootstrapStatus,
|
|
17446
|
+
marketplaceInstaller,
|
|
17447
|
+
ncpSessionRealtimeBridge,
|
|
17448
|
+
getRuntimeConfig,
|
|
17449
|
+
getRuntimeState: () => runtimeState
|
|
17042
17450
|
});
|
|
17451
|
+
await companionRuntimeService.applyConfig(shellContext.config);
|
|
17043
17452
|
bootstrapStatus.markShellReady();
|
|
17044
17453
|
await setImmediate$1();
|
|
17045
17454
|
const gateway = measureStartupSync("service.create_gateway_startup_context", () => createGatewayStartupContext({
|
|
@@ -17057,33 +17466,14 @@ var RuntimeCommandService = class {
|
|
|
17057
17466
|
const loadGatewayConfig = () => resolveConfigSecrets$1(loadConfig$1(), { configPath: gateway.runtimeConfigPath });
|
|
17058
17467
|
const gatewayRuntimeState = createGatewayRuntimeState(gateway);
|
|
17059
17468
|
runtimeState = gatewayRuntimeState;
|
|
17060
|
-
|
|
17061
|
-
|
|
17062
|
-
payload: { path: "channels" }
|
|
17469
|
+
gateway.reloader.setReloadCompanion(async ({ config: nextConfig }) => {
|
|
17470
|
+
await companionRuntimeService.applyConfig(nextConfig);
|
|
17063
17471
|
});
|
|
17064
|
-
|
|
17065
|
-
type: "config.updated",
|
|
17066
|
-
payload: { path: "plugins" }
|
|
17067
|
-
});
|
|
17068
|
-
configureGatewayPluginRuntime({
|
|
17472
|
+
await this.hydrateGatewayRuntime({
|
|
17069
17473
|
gateway,
|
|
17070
|
-
|
|
17071
|
-
|
|
17474
|
+
gatewayRuntimeState,
|
|
17475
|
+
uiStartup
|
|
17072
17476
|
});
|
|
17073
|
-
console.log("✓ Capability hydration: scheduled in background");
|
|
17074
|
-
await measureStartupAsync("service.start_gateway_support_services", async () => await startGatewayRuntimeSupport({
|
|
17075
|
-
cronJobs: gateway.cron.status().jobs,
|
|
17076
|
-
remoteModule: gateway.remoteModule,
|
|
17077
|
-
watchConfigFile: () => watchServiceConfigFile({
|
|
17078
|
-
configPath: resolve(getConfigPath$1()),
|
|
17079
|
-
watcherRegistry: this.fileWatchers,
|
|
17080
|
-
scheduleReload: (reason) => gateway.reloader.scheduleReload(reason)
|
|
17081
|
-
}),
|
|
17082
|
-
startCron: () => gateway.cron.start(),
|
|
17083
|
-
cronStorePath: resolve(join(NextclawCore.getDataDir(), "cron", "jobs.json")),
|
|
17084
|
-
reloadCronStore: () => gateway.cron.reloadFromStore(),
|
|
17085
|
-
watcherRegistry: this.fileWatchers
|
|
17086
|
-
}));
|
|
17087
17477
|
const deferredGatewayStartupHooks = createDeferredGatewayStartupHooks({
|
|
17088
17478
|
uiStartup,
|
|
17089
17479
|
gateway,
|
|
@@ -17098,6 +17488,20 @@ var RuntimeCommandService = class {
|
|
|
17098
17488
|
sessionManager: gateway.sessionManager
|
|
17099
17489
|
})
|
|
17100
17490
|
});
|
|
17491
|
+
deferredGatewayStartupHooks.startChannels = wrapStartChannelsWithDevPluginHotReload({
|
|
17492
|
+
startChannels: deferredGatewayStartupHooks.startChannels,
|
|
17493
|
+
watcherRegistry: this.fileWatchers,
|
|
17494
|
+
isRuntimeActive: () => Boolean(this.applyLiveConfigReload),
|
|
17495
|
+
reloadPlugins: async (pluginIds) => {
|
|
17496
|
+
await reloadGatewayPluginRuntimeForChanges({
|
|
17497
|
+
gateway,
|
|
17498
|
+
state: gatewayRuntimeState,
|
|
17499
|
+
getLiveUiNcpAgent: () => this.liveUiNcpAgent,
|
|
17500
|
+
changedPaths: pluginIds.map((pluginId) => `plugins.entries.${pluginId}.source`)
|
|
17501
|
+
});
|
|
17502
|
+
},
|
|
17503
|
+
startupSettleMs: DEV_PLUGIN_HOT_RELOAD_STARTUP_SETTLE_MS
|
|
17504
|
+
});
|
|
17101
17505
|
await runConfiguredGatewayRuntime({
|
|
17102
17506
|
uiStartup,
|
|
17103
17507
|
bootstrapStatus,
|
|
@@ -17125,14 +17529,84 @@ var RuntimeCommandService = class {
|
|
|
17125
17529
|
this.applyLiveConfigReload = null;
|
|
17126
17530
|
this.liveUiNcpAgent = null;
|
|
17127
17531
|
},
|
|
17128
|
-
clearRealtimeBridge: () =>
|
|
17532
|
+
clearRealtimeBridge: () => {
|
|
17533
|
+
ncpSessionRealtimeBridge.clear();
|
|
17534
|
+
},
|
|
17129
17535
|
uiStartup,
|
|
17130
17536
|
remoteModule: gateway.remoteModule,
|
|
17131
17537
|
runtimeState
|
|
17132
17538
|
})
|
|
17133
17539
|
});
|
|
17540
|
+
await companionRuntimeService.ensureStopped();
|
|
17134
17541
|
logStartupTrace("service.start_gateway.end");
|
|
17135
17542
|
};
|
|
17543
|
+
startGatewayUiShell = async (params) => {
|
|
17544
|
+
const { applyLiveConfigReload, bootstrapStatus, getRuntimeConfig, getRuntimeState, marketplaceInstaller, ncpSessionRealtimeBridge, shellContext } = params;
|
|
17545
|
+
const { remoteAccess, runtimeControl, runtimeUpdate } = createServiceUiHosts({
|
|
17546
|
+
serviceCommands: this,
|
|
17547
|
+
requestRestart: this.deps.requestRestart,
|
|
17548
|
+
uiConfig: shellContext.uiConfig,
|
|
17549
|
+
remoteModule: shellContext.remoteModule
|
|
17550
|
+
});
|
|
17551
|
+
const uiStartup = await measureStartupAsync("service.start_ui_shell", async () => await startUiShell({
|
|
17552
|
+
uiConfig: shellContext.uiConfig,
|
|
17553
|
+
uiStaticDir: shellContext.uiStaticDir,
|
|
17554
|
+
cronService: shellContext.cron,
|
|
17555
|
+
getConfig: getRuntimeConfig,
|
|
17556
|
+
configPath: getConfigPath$1(),
|
|
17557
|
+
productVersion: getPackageVersion$1(),
|
|
17558
|
+
getPluginChannelBindings: () => getRuntimeState()?.pluginChannelBindings ?? [],
|
|
17559
|
+
getPluginUiMetadata: () => getRuntimeState()?.pluginUiMetadata ?? [],
|
|
17560
|
+
marketplace: {
|
|
17561
|
+
apiBaseUrl: process.env.NEXTCLAW_MARKETPLACE_API_BASE,
|
|
17562
|
+
installer: marketplaceInstaller
|
|
17563
|
+
},
|
|
17564
|
+
remoteAccess,
|
|
17565
|
+
runtimeControl,
|
|
17566
|
+
runtimeUpdate,
|
|
17567
|
+
getBootstrapStatus: () => bootstrapStatus.getStatus(),
|
|
17568
|
+
openBrowserWindow: shellContext.uiConfig.open,
|
|
17569
|
+
applyLiveConfigReload,
|
|
17570
|
+
ncpSessionService: ncpSessionRealtimeBridge.sessionService,
|
|
17571
|
+
initializeAgentHomeDirectory: this.deps.initializeAgentHomeDirectory
|
|
17572
|
+
}));
|
|
17573
|
+
finalizeLocalUiStartup({
|
|
17574
|
+
uiStartup,
|
|
17575
|
+
setUiEventPublisher: (publish) => ncpSessionRealtimeBridge.setUiEventPublisher(publish),
|
|
17576
|
+
uiConfig: shellContext.uiConfig
|
|
17577
|
+
});
|
|
17578
|
+
return uiStartup;
|
|
17579
|
+
};
|
|
17580
|
+
hydrateGatewayRuntime = async (params) => {
|
|
17581
|
+
const { gateway, gatewayRuntimeState, uiStartup } = params;
|
|
17582
|
+
uiStartup?.publish({
|
|
17583
|
+
type: "config.updated",
|
|
17584
|
+
payload: { path: "channels" }
|
|
17585
|
+
});
|
|
17586
|
+
uiStartup?.publish({
|
|
17587
|
+
type: "config.updated",
|
|
17588
|
+
payload: { path: "plugins" }
|
|
17589
|
+
});
|
|
17590
|
+
configureGatewayPluginRuntime({
|
|
17591
|
+
gateway,
|
|
17592
|
+
state: gatewayRuntimeState,
|
|
17593
|
+
getLiveUiNcpAgent: () => this.liveUiNcpAgent
|
|
17594
|
+
});
|
|
17595
|
+
console.log("✓ Capability hydration: scheduled in background");
|
|
17596
|
+
await measureStartupAsync("service.start_gateway_support_services", async () => await startGatewayRuntimeSupport({
|
|
17597
|
+
cronJobs: gateway.cron.status().jobs,
|
|
17598
|
+
remoteModule: gateway.remoteModule,
|
|
17599
|
+
watchConfigFile: () => watchServiceConfigFile({
|
|
17600
|
+
configPath: resolve(getConfigPath$1()),
|
|
17601
|
+
watcherRegistry: this.fileWatchers,
|
|
17602
|
+
scheduleReload: (reason) => gateway.reloader.scheduleReload(reason)
|
|
17603
|
+
}),
|
|
17604
|
+
startCron: () => gateway.cron.start(),
|
|
17605
|
+
cronStorePath: resolve(join(NextclawCore.getDataDir(), "cron", "jobs.json")),
|
|
17606
|
+
reloadCronStore: () => gateway.cron.reloadFromStore(),
|
|
17607
|
+
watcherRegistry: this.fileWatchers
|
|
17608
|
+
}));
|
|
17609
|
+
};
|
|
17136
17610
|
normalizeOptionalString = (value) => {
|
|
17137
17611
|
if (typeof value !== "string") return;
|
|
17138
17612
|
return value.trim() || void 0;
|
|
@@ -18167,7 +18641,7 @@ var MacosLaunchAgentAutostartService = class {
|
|
|
18167
18641
|
` <string>${this.escapeXml(homeDir)}</string>`,
|
|
18168
18642
|
" </dict>",
|
|
18169
18643
|
" <key>RunAtLoad</key><true/>",
|
|
18170
|
-
" <key>KeepAlive</key><
|
|
18644
|
+
" <key>KeepAlive</key><false/>",
|
|
18171
18645
|
` <key>StandardOutPath</key><string>${this.escapeXml(stdoutPath)}</string>`,
|
|
18172
18646
|
` <key>StandardErrorPath</key><string>${this.escapeXml(stderrPath)}</string>`,
|
|
18173
18647
|
"</dict>",
|
|
@@ -19035,6 +19509,30 @@ var RuntimeRestartRequestService = class {
|
|
|
19035
19509
|
};
|
|
19036
19510
|
};
|
|
19037
19511
|
//#endregion
|
|
19512
|
+
//#region src/cli/shared/utils/runtime-helpers.ts
|
|
19513
|
+
function resolveSkillsInstallWorkdir(params) {
|
|
19514
|
+
if (params.explicitWorkdir) return expandHome(params.explicitWorkdir);
|
|
19515
|
+
return getWorkspacePath(params.configuredWorkspace);
|
|
19516
|
+
}
|
|
19517
|
+
function parseStartTimeoutMs(value) {
|
|
19518
|
+
if (value === void 0) return;
|
|
19519
|
+
const parsed = Number(value);
|
|
19520
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
19521
|
+
console.error("Invalid --start-timeout value. Provide milliseconds (e.g. 45000).");
|
|
19522
|
+
process.exit(1);
|
|
19523
|
+
}
|
|
19524
|
+
return Math.floor(parsed);
|
|
19525
|
+
}
|
|
19526
|
+
function resolveManagedServiceUiOverrides(params) {
|
|
19527
|
+
const uiOverrides = {
|
|
19528
|
+
enabled: true,
|
|
19529
|
+
host: params.forcedPublicHost,
|
|
19530
|
+
open: false
|
|
19531
|
+
};
|
|
19532
|
+
if (params.uiPort) uiOverrides.port = Number(params.uiPort);
|
|
19533
|
+
return uiOverrides;
|
|
19534
|
+
}
|
|
19535
|
+
//#endregion
|
|
19038
19536
|
//#region src/cli/commands/skills/marketplace-command-options.utils.ts
|
|
19039
19537
|
function buildMarketplacePublishOptions(options) {
|
|
19040
19538
|
const { apiBaseUrl, author, description, dir, homepage, meta, name, packageName, publishedAt, scope, slug, sourceRepo, summary, tag, token, updatedAt } = options;
|
|
@@ -20079,17 +20577,31 @@ var RestartCommands = class {
|
|
|
20079
20577
|
uiPort: opts.uiPort,
|
|
20080
20578
|
forcedPublicHost: this.deps.forcedPublicHost
|
|
20081
20579
|
});
|
|
20580
|
+
const targetUi = resolveUiConfig(loadConfig(), uiOverrides);
|
|
20082
20581
|
const state = managedServiceStateStore.read();
|
|
20083
20582
|
if (state && isProcessRunning(state.pid)) {
|
|
20084
20583
|
console.log(`Restarting ${APP_NAME}...`);
|
|
20085
20584
|
await this.deps.runtimeCommandService.stopService();
|
|
20086
20585
|
} else {
|
|
20586
|
+
const foregroundRuntime = localUiRuntimeStore.read();
|
|
20587
|
+
const foregroundMatchesTarget = Boolean(foregroundRuntime && isProcessRunning(foregroundRuntime.pid) && foregroundRuntime.uiPort === targetUi.port);
|
|
20588
|
+
if (foregroundRuntime && foregroundMatchesTarget) {
|
|
20589
|
+
if (!await this.restartForegroundRuntime(foregroundRuntime.pid)) return;
|
|
20590
|
+
await this.deps.startCommands.run(opts);
|
|
20591
|
+
return;
|
|
20592
|
+
}
|
|
20087
20593
|
if (state) {
|
|
20088
20594
|
managedServiceStateStore.clear();
|
|
20089
20595
|
console.log("Service state was stale and has been cleaned up.");
|
|
20090
20596
|
}
|
|
20091
20597
|
const unmanagedHealthyServiceMessage = await describeUnmanagedHealthyTargetMessage({ uiOverrides });
|
|
20092
20598
|
if (unmanagedHealthyServiceMessage) {
|
|
20599
|
+
const adoptedRuntimePid = this.resolveAdoptableForegroundRuntimePid(targetUi.port);
|
|
20600
|
+
if (adoptedRuntimePid) {
|
|
20601
|
+
if (!await this.restartForegroundRuntime(adoptedRuntimePid)) return;
|
|
20602
|
+
await this.deps.startCommands.run(opts);
|
|
20603
|
+
return;
|
|
20604
|
+
}
|
|
20093
20605
|
console.error(`Error: Cannot restart ${APP_NAME} because the target UI/API port is already served by a healthy unmanaged instance.`);
|
|
20094
20606
|
console.error(unmanagedHealthyServiceMessage);
|
|
20095
20607
|
return;
|
|
@@ -20098,6 +20610,40 @@ var RestartCommands = class {
|
|
|
20098
20610
|
}
|
|
20099
20611
|
await this.deps.startCommands.run(opts);
|
|
20100
20612
|
};
|
|
20613
|
+
restartForegroundRuntime = async (pid) => {
|
|
20614
|
+
console.log(`Restarting ${APP_NAME} foreground runtime (PID ${pid})...`);
|
|
20615
|
+
try {
|
|
20616
|
+
process.kill(pid, "SIGTERM");
|
|
20617
|
+
} catch (error) {
|
|
20618
|
+
console.error(`Failed to stop foreground runtime: ${String(error)}`);
|
|
20619
|
+
return false;
|
|
20620
|
+
}
|
|
20621
|
+
if (!await waitForExit(pid, 3e3)) {
|
|
20622
|
+
try {
|
|
20623
|
+
process.kill(pid, "SIGKILL");
|
|
20624
|
+
} catch (error) {
|
|
20625
|
+
console.error(`Failed to force stop foreground runtime: ${String(error)}`);
|
|
20626
|
+
return false;
|
|
20627
|
+
}
|
|
20628
|
+
if (!await waitForExit(pid, 2e3)) {
|
|
20629
|
+
console.error(`Failed to stop foreground runtime PID ${pid}.`);
|
|
20630
|
+
return false;
|
|
20631
|
+
}
|
|
20632
|
+
}
|
|
20633
|
+
localUiRuntimeStore.clearIfOwnedByProcess(pid);
|
|
20634
|
+
console.log(`✓ ${APP_NAME} foreground runtime stopped`);
|
|
20635
|
+
return true;
|
|
20636
|
+
};
|
|
20637
|
+
resolveAdoptableForegroundRuntimePid = (port) => {
|
|
20638
|
+
const listeningProcess = findListeningProcessByPort(port);
|
|
20639
|
+
if (!listeningProcess || !isProcessRunning(listeningProcess.pid)) return null;
|
|
20640
|
+
return this.isAdoptableNextclawRuntimeCommand(listeningProcess.command) ? listeningProcess.pid : null;
|
|
20641
|
+
};
|
|
20642
|
+
isAdoptableNextclawRuntimeCommand = (command) => {
|
|
20643
|
+
const normalized = command?.trim() ?? "";
|
|
20644
|
+
if (!normalized) return false;
|
|
20645
|
+
return /\bserve\b/.test(normalized) && (normalized.includes("/dist/cli/app/index.js") || normalized.includes("/src/cli/app/index.js") || normalized.includes("/runtime/dist/cli/app/index.js"));
|
|
20646
|
+
};
|
|
20101
20647
|
};
|
|
20102
20648
|
//#endregion
|
|
20103
20649
|
//#region src/cli/commands/serve/index.ts
|
|
@@ -20127,6 +20673,74 @@ var StopCommands = class {
|
|
|
20127
20673
|
};
|
|
20128
20674
|
};
|
|
20129
20675
|
//#endregion
|
|
20676
|
+
//#region src/cli/commands/companion/services/companion-process.service.ts
|
|
20677
|
+
var CompanionProcessService = class {
|
|
20678
|
+
constructor(runtimeService = companionRuntimeService) {
|
|
20679
|
+
this.runtimeService = runtimeService;
|
|
20680
|
+
}
|
|
20681
|
+
start = async (options = {}) => {
|
|
20682
|
+
const state = await this.runtimeService.ensureStarted({ baseUrl: this.resolveBaseUrl(options) });
|
|
20683
|
+
this.runtimeService.printStarted(state);
|
|
20684
|
+
};
|
|
20685
|
+
status = async (options = {}) => {
|
|
20686
|
+
this.runtimeService.printStatus(options);
|
|
20687
|
+
};
|
|
20688
|
+
stop = async (options = {}) => {
|
|
20689
|
+
const stopped = await this.runtimeService.ensureStopped(options);
|
|
20690
|
+
this.runtimeService.printStopped(stopped);
|
|
20691
|
+
};
|
|
20692
|
+
enable = async (options = {}) => {
|
|
20693
|
+
const nextConfig = await this.runtimeService.updateEnabled(true, options);
|
|
20694
|
+
this.printConfigEnabled(nextConfig, options.baseUrl);
|
|
20695
|
+
};
|
|
20696
|
+
disable = async (_options = {}) => {
|
|
20697
|
+
const nextConfig = await this.runtimeService.updateEnabled(false);
|
|
20698
|
+
console.log(nextConfig.companion.enabled ? "Companion remains enabled." : "Companion feature disabled. It will stay off until you enable it again.");
|
|
20699
|
+
};
|
|
20700
|
+
resolveBaseUrl = (options) => {
|
|
20701
|
+
const explicitBaseUrl = options.baseUrl?.trim();
|
|
20702
|
+
if (explicitBaseUrl) return explicitBaseUrl.replace(/\/+$/, "");
|
|
20703
|
+
const discoveredBaseUrl = this.runtimeService.resolveDiscoveredBaseUrl();
|
|
20704
|
+
if (discoveredBaseUrl) return discoveredBaseUrl;
|
|
20705
|
+
const runningState = this.runtimeService.getRunningState();
|
|
20706
|
+
if (runningState) return runningState.baseUrl;
|
|
20707
|
+
throw new Error("Cannot resolve NextClaw UI base URL. Start NextClaw first or pass --base-url.");
|
|
20708
|
+
};
|
|
20709
|
+
printConfigEnabled = (config, baseUrl) => {
|
|
20710
|
+
if (this.runtimeService.getRunningState()) {
|
|
20711
|
+
console.log("Companion feature enabled and companion started.");
|
|
20712
|
+
return;
|
|
20713
|
+
}
|
|
20714
|
+
if (baseUrl?.trim()) {
|
|
20715
|
+
console.log("Companion feature enabled.");
|
|
20716
|
+
return;
|
|
20717
|
+
}
|
|
20718
|
+
console.log(config.companion.enabled ? "Companion feature enabled. It will auto-start the next time a local NextClaw runtime is available." : "Companion feature is not enabled.");
|
|
20719
|
+
};
|
|
20720
|
+
};
|
|
20721
|
+
//#endregion
|
|
20722
|
+
//#region src/cli/commands/companion/index.ts
|
|
20723
|
+
var CompanionCommands = class {
|
|
20724
|
+
constructor(companionProcessService = new CompanionProcessService()) {
|
|
20725
|
+
this.companionProcessService = companionProcessService;
|
|
20726
|
+
}
|
|
20727
|
+
start = async (options = {}) => {
|
|
20728
|
+
await this.companionProcessService.start(options);
|
|
20729
|
+
};
|
|
20730
|
+
enable = async (options = {}) => {
|
|
20731
|
+
await this.companionProcessService.enable(options);
|
|
20732
|
+
};
|
|
20733
|
+
disable = async (options = {}) => {
|
|
20734
|
+
await this.companionProcessService.disable(options);
|
|
20735
|
+
};
|
|
20736
|
+
status = async (options = {}) => {
|
|
20737
|
+
await this.companionProcessService.status(options);
|
|
20738
|
+
};
|
|
20739
|
+
stop = async (options = {}) => {
|
|
20740
|
+
await this.companionProcessService.stop(options);
|
|
20741
|
+
};
|
|
20742
|
+
};
|
|
20743
|
+
//#endregion
|
|
20130
20744
|
//#region src/cli/app/runtime.ts
|
|
20131
20745
|
const LOGO = "🤖";
|
|
20132
20746
|
const FORCED_PUBLIC_UI_HOST = "0.0.0.0";
|
|
@@ -20158,6 +20772,7 @@ var CliRuntime = class {
|
|
|
20158
20772
|
restartCommands;
|
|
20159
20773
|
serveCommands;
|
|
20160
20774
|
stopCommands;
|
|
20775
|
+
companionCommands;
|
|
20161
20776
|
constructor(options = {}) {
|
|
20162
20777
|
logStartupTrace("cli.runtime.constructor.begin");
|
|
20163
20778
|
this.logo = options.logo ?? "🤖";
|
|
@@ -20190,6 +20805,7 @@ var CliRuntime = class {
|
|
|
20190
20805
|
forcedPublicHost: FORCED_PUBLIC_UI_HOST
|
|
20191
20806
|
}));
|
|
20192
20807
|
this.stopCommands = measureStartupSync("cli.runtime.stop_commands", () => new StopCommands({ runtimeCommandService: this.runtimeCommandService }));
|
|
20808
|
+
this.companionCommands = measureStartupSync("cli.runtime.companion_commands", () => new CompanionCommands());
|
|
20193
20809
|
this.serviceCommands = measureStartupSync("cli.runtime.service_commands", () => new ServiceCommands());
|
|
20194
20810
|
this.configCommands = measureStartupSync("cli.runtime.config_commands", () => new ConfigCommands({ requestRestart: (params) => this.requestRestart(params) }));
|
|
20195
20811
|
this.mcpCommands = measureStartupSync("cli.runtime.mcp_commands", () => new McpCommands());
|
|
@@ -20341,7 +20957,7 @@ var CliRuntime = class {
|
|
|
20341
20957
|
spawn(process.execPath, ["-e", helperScript], {
|
|
20342
20958
|
detached: true,
|
|
20343
20959
|
stdio: "ignore",
|
|
20344
|
-
env: process.env
|
|
20960
|
+
env: createTopLevelNextclawCommandEnv(process.env)
|
|
20345
20961
|
}).unref();
|
|
20346
20962
|
this.selfRelaunchArmed = true;
|
|
20347
20963
|
console.warn(`Gateway self-restart armed (${reason}).`);
|
|
@@ -20422,6 +21038,21 @@ var CliRuntime = class {
|
|
|
20422
21038
|
stop = async () => {
|
|
20423
21039
|
await this.stopCommands.run();
|
|
20424
21040
|
};
|
|
21041
|
+
companionStart = async (opts = {}) => {
|
|
21042
|
+
await this.companionCommands.start(opts);
|
|
21043
|
+
};
|
|
21044
|
+
companionEnable = async (opts = {}) => {
|
|
21045
|
+
await this.companionCommands.enable(opts);
|
|
21046
|
+
};
|
|
21047
|
+
companionDisable = async (opts = {}) => {
|
|
21048
|
+
await this.companionCommands.disable(opts);
|
|
21049
|
+
};
|
|
21050
|
+
companionStatus = async (opts = {}) => {
|
|
21051
|
+
await this.companionCommands.status(opts);
|
|
21052
|
+
};
|
|
21053
|
+
companionStop = async (opts = {}) => {
|
|
21054
|
+
await this.companionCommands.stop(opts);
|
|
21055
|
+
};
|
|
20425
21056
|
agent = async (opts) => {
|
|
20426
21057
|
const configPath = getConfigPath();
|
|
20427
21058
|
const config = resolveConfigSecrets(loadConfig(), { configPath });
|
|
@@ -20594,6 +21225,16 @@ function registerAgentsCommands(program, runtime) {
|
|
|
20594
21225
|
agents.command("remove <agentId>").description("Remove an agent").option("--json", "Output JSON", false).action(async (agentId, opts) => runtime.agentsRemove(agentId, opts));
|
|
20595
21226
|
}
|
|
20596
21227
|
//#endregion
|
|
21228
|
+
//#region src/cli/app/register-companion-commands.ts
|
|
21229
|
+
function registerCompanionCommands(program, runtime) {
|
|
21230
|
+
const companion = program.command("companion").description("Manage the standalone NextClaw companion shell");
|
|
21231
|
+
companion.command("start").description("Start the companion shell in the background").option("--base-url <url>", "Explicit NextClaw UI base URL").action(async (opts) => runtime.companionStart(opts));
|
|
21232
|
+
companion.command("enable").description("Enable the companion feature and start it when a local runtime is available").option("--base-url <url>", "Explicit NextClaw UI base URL").action(async (opts) => runtime.companionEnable(opts));
|
|
21233
|
+
companion.command("disable").description("Disable the companion feature and stop any running companion process").action(async (opts) => runtime.companionDisable(opts));
|
|
21234
|
+
companion.command("status").description("Show companion process status").option("--json", "Output JSON", false).action(async (opts) => runtime.companionStatus(opts));
|
|
21235
|
+
companion.command("stop").description("Stop the companion process").option("--force", "Force kill the companion process", false).action(async (opts) => runtime.companionStop(opts));
|
|
21236
|
+
}
|
|
21237
|
+
//#endregion
|
|
20597
21238
|
//#region src/cli/app/service-command-registration.service.ts
|
|
20598
21239
|
const registerServiceCommands = ({ program, getServiceCommands }) => {
|
|
20599
21240
|
const service = program.command("service").description("Manage host service integrations");
|
|
@@ -20649,6 +21290,7 @@ program.command("start").description(`Start the ${APP_NAME} gateway + UI in the
|
|
|
20649
21290
|
program.command("restart").description(`Restart the ${APP_NAME} 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));
|
|
20650
21291
|
program.command("serve").description(`Run the ${APP_NAME} gateway + UI in the foreground`).option("--ui-port <port>", "UI port").option("--open", "Open browser after start", false).action(async (opts) => runtime.serve(opts));
|
|
20651
21292
|
program.command("stop").description(`Stop the ${APP_NAME} background service`).action(async () => runtime.stop());
|
|
21293
|
+
registerCompanionCommands(program, runtime);
|
|
20652
21294
|
registerServiceCommands({
|
|
20653
21295
|
program,
|
|
20654
21296
|
getServiceCommands
|
|
@@ -20699,6 +21341,6 @@ const logs = program.command("logs").description("Inspect local runtime logs");
|
|
|
20699
21341
|
logs.command("path").description("Show local log file paths").action(() => runtime.logsPath());
|
|
20700
21342
|
logs.command("tail").description("Show recent local log entries").option("--lines <n>", "Number of lines to show", "40").option("--crash", "Tail crash.log instead of service.log", false).action((opts) => runtime.logsTail(opts));
|
|
20701
21343
|
program.command("usage").description("Show observed LLM usage snapshots, history, and prompt cache stats").option("--history", "Show recent usage history", false).option("--stats", "Show aggregated usage stats from local history", false).option("--limit <n>", "Maximum number of history records to show", "10").option("--json", "Output JSON", false).action(async (opts) => llmUsageCommands.show(opts));
|
|
20702
|
-
program.parseAsync(process.argv);
|
|
21344
|
+
await program.parseAsync(process.argv);
|
|
20703
21345
|
//#endregion
|
|
20704
21346
|
export {};
|