nextclaw 0.18.12-beta.0 → 0.18.12-beta.10

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.
Files changed (99) hide show
  1. package/dist/cli/app/index.js +870 -264
  2. package/dist/cli/launcher/index.js +8 -3
  3. package/dist/{npm-runtime-update-state.store-DaF0iDY9.js → npm-runtime-update-state.store-75vzvn0B.js} +200 -30
  4. package/package.json +17 -16
  5. package/resources/USAGE.md +41 -1
  6. package/ui-dist/assets/api-BcqDx0tm.js +15 -0
  7. package/ui-dist/assets/app-manager-provider-DVYBjif-.js +1 -0
  8. package/ui-dist/assets/app-navigation.config-CMoWvFEI.js +1 -0
  9. package/ui-dist/assets/{book-open-B4mOKdz8.js → book-open-DgLqYpNY.js} +1 -1
  10. package/ui-dist/assets/{channels-list-page-WJ7d4zMI.js → channels-list-page-CsoI4OJm.js} +2 -2
  11. package/ui-dist/assets/chat-CA3aRmhx.js +61 -0
  12. package/ui-dist/assets/chat-page-gdSN6Pr6.js +1 -0
  13. package/ui-dist/assets/chunk-JZWAC4HX-u4uYphxM.js +3 -0
  14. package/ui-dist/assets/{config-split-page-B3PRA_AV.js → config-split-page-BMRGuCJQ.js} +1 -1
  15. package/ui-dist/assets/{createLucideIcon-C_GFKVuW.js → createLucideIcon-BZkY6emz.js} +1 -1
  16. package/ui-dist/assets/desktop-update-config-CD6-2PfI.js +1 -0
  17. package/ui-dist/assets/{dialog-BHcaU6NE.js → dialog-csshWetU.js} +1 -1
  18. package/ui-dist/assets/{dist-DtBFqZ6_.js → dist-Bl94Ahwx.js} +1 -1
  19. package/ui-dist/assets/{doc-browser-CwgI7ipB.js → doc-browser-BUlCkZo2.js} +1 -1
  20. package/ui-dist/assets/doc-browser-CzCV73NJ.js +1 -0
  21. package/ui-dist/assets/doc-browser-Doh2541x.js +1 -0
  22. package/ui-dist/assets/{doc-browser-context-Dib9sS83.js → doc-browser-context-DfLHAWbG.js} +1 -1
  23. package/ui-dist/assets/{es2015-BlNhrQUG.js → es2015-JCM5-KtW.js} +1 -1
  24. package/ui-dist/assets/{external-link-DP2IJ7AM.js → external-link-Sw3ah_JD.js} +1 -1
  25. package/ui-dist/assets/{folder-BPwc278w.js → folder-D7-VTnkz.js} +1 -1
  26. package/ui-dist/assets/{hash-CvcvtMBq.js → hash-zajSTDXZ.js} +1 -1
  27. package/ui-dist/assets/i18n-C5Mibli1.js +1 -0
  28. package/ui-dist/assets/index-BTDFuKka.js +2 -0
  29. package/ui-dist/assets/index-CUmk8xFK.css +1 -0
  30. package/ui-dist/assets/{key-round-BQXmPSxD.js → key-round-CnI1mc9F.js} +1 -1
  31. package/ui-dist/assets/loader-circle-B5i8oMMY.js +1 -0
  32. package/ui-dist/assets/{logo-badge-uB4SwANR.js → logo-badge-BQgKnVtz.js} +1 -1
  33. package/ui-dist/assets/{logos-BcELLmYh.js → logos-CqVm0q0W.js} +1 -1
  34. package/ui-dist/assets/marketplace-page-DJGDpTAo.js +1 -0
  35. package/ui-dist/assets/{marketplace-page-DiqqX25V.js → marketplace-page-DxlxHCFm.js} +2 -2
  36. package/ui-dist/assets/mcp-marketplace-page-5UjYRWOR.js +40 -0
  37. package/ui-dist/assets/mcp-marketplace-page-C1XaHZZO.js +1 -0
  38. package/ui-dist/assets/message-square-D6Z4NwpG.js +1 -0
  39. package/ui-dist/assets/{model-config-B0L43HTL.js → model-config-PccJ9XyH.js} +1 -1
  40. package/ui-dist/assets/{notice-card-C9PFAR67.js → notice-card-CCgk6FvF.js} +1 -1
  41. package/ui-dist/assets/play-D8WJLnJe.js +1 -0
  42. package/ui-dist/assets/plus-Di0KAkiO.js +1 -0
  43. package/ui-dist/assets/{popover-B8msg2FQ.js → popover-YAsxDBhY.js} +1 -1
  44. package/ui-dist/assets/{provider-scoped-model-input-DeAo2Y65.js → provider-scoped-model-input-CzpF7cug.js} +1 -1
  45. package/ui-dist/assets/{providers-list-5_VShcn7.js → providers-list-8qDMER8o.js} +1 -1
  46. package/ui-dist/assets/{refresh-ccw-CeG203yU.js → refresh-ccw-Bii4w8aB.js} +1 -1
  47. package/ui-dist/assets/refresh-cw-BxojR62w.js +1 -0
  48. package/ui-dist/assets/remote-D4TtLPAp.js +1 -0
  49. package/ui-dist/assets/{rotate-cw-F7aThvYj.js → rotate-cw-1Xqa7LZ8.js} +1 -1
  50. package/ui-dist/assets/runtime-config-page-D-4c5H5z.js +1 -0
  51. package/ui-dist/assets/{save-7ztImRj7.js → save--BVI5wZX.js} +1 -1
  52. package/ui-dist/assets/search-config-D3a65l3r.js +1 -0
  53. package/ui-dist/assets/{search-DZSNKEGp.js → search-vChioOoe.js} +1 -1
  54. package/ui-dist/assets/{secrets-config-DKFeFii1.js → secrets-config-CoMlR_7i.js} +2 -2
  55. package/ui-dist/assets/{select-DRDejPLk.js → select-DIZrwsKU.js} +1 -1
  56. package/ui-dist/assets/{sessions-config-page-CZGqS32n.js → sessions-config-page-Cc0TJStn.js} +2 -2
  57. package/ui-dist/assets/{setting-row-BcF6eTW0.js → setting-row-DiQyrE81.js} +1 -1
  58. package/ui-dist/assets/{settings-DjvNMJde.js → settings-CiRChctQ.js} +1 -1
  59. package/ui-dist/assets/skeleton-CFQRIUzt.js +1 -0
  60. package/ui-dist/assets/{sparkles-CyDTgTM4.js → sparkles-D1ZKWdm4.js} +1 -1
  61. package/ui-dist/assets/{status-dot-aQU9Mia4.js → status-dot-Dv_hiUVa.js} +1 -1
  62. package/ui-dist/assets/{tabs-custom-C4P7g4vR.js → tabs-custom-CsACkVji.js} +1 -1
  63. package/ui-dist/assets/{tag-chip-CVIqyMv7.js → tag-chip-C3wDBe_-.js} +1 -1
  64. package/ui-dist/assets/theme-provider-aOmrJ9J6.js +1 -0
  65. package/ui-dist/assets/{tooltip-C6VPreZ7.js → tooltip-Dq5Xehpk.js} +1 -1
  66. package/ui-dist/assets/{trash-2-C1cdqL6V.js → trash-2-rY9ZteZX.js} +1 -1
  67. package/ui-dist/assets/use-config-BQJjq1mP.js +1 -0
  68. package/ui-dist/assets/{use-confirm-dialog-DvIbSUX3.js → use-confirm-dialog-DBoV5n5P.js} +1 -1
  69. package/ui-dist/assets/{use-infinite-scroll-loader-D8h0k-iL.js → use-infinite-scroll-loader-JAicqVC5.js} +1 -1
  70. package/ui-dist/assets/{use-viewport-layout-D-pjxsyz.js → use-viewport-layout-BX3XqzJ4.js} +1 -1
  71. package/ui-dist/assets/x-DpTzXQcX.js +1 -0
  72. package/ui-dist/index.html +40 -39
  73. package/ui-dist/assets/api-C51456xV.js +0 -15
  74. package/ui-dist/assets/app-manager-provider-D_cKqqRG.js +0 -1
  75. package/ui-dist/assets/app-navigation.config-Dve1W20Y.js +0 -1
  76. package/ui-dist/assets/chat-BxA-mw53.js +0 -58
  77. package/ui-dist/assets/chat-page-DLFTPfmu.js +0 -1
  78. package/ui-dist/assets/chunk-JZWAC4HX-ptDyT_1C.js +0 -3
  79. package/ui-dist/assets/desktop-update-config-CzGi43xw.js +0 -1
  80. package/ui-dist/assets/doc-browser-CoKIUCJj.js +0 -1
  81. package/ui-dist/assets/doc-browser-DYKpRqe-.js +0 -1
  82. package/ui-dist/assets/i18n-BnNAQpVM.js +0 -1
  83. package/ui-dist/assets/index-CAYF44Dz.js +0 -2
  84. package/ui-dist/assets/index-mRmSAB-e.css +0 -1
  85. package/ui-dist/assets/loader-circle-C6gg2m2a.js +0 -1
  86. package/ui-dist/assets/marketplace-page-0sEdt5sA.js +0 -1
  87. package/ui-dist/assets/mcp-marketplace-page-B8vmu9xe.js +0 -1
  88. package/ui-dist/assets/mcp-marketplace-page-C_akqPwv.js +0 -40
  89. package/ui-dist/assets/message-square-CLVODA23.js +0 -1
  90. package/ui-dist/assets/play-DeNVUA5C.js +0 -1
  91. package/ui-dist/assets/plus-BptLViq1.js +0 -1
  92. package/ui-dist/assets/remote-pzp4oLcL.js +0 -1
  93. package/ui-dist/assets/runtime-config-page-B-y_0HIS.js +0 -1
  94. package/ui-dist/assets/search-config-DJTm9Fno.js +0 -1
  95. package/ui-dist/assets/skeleton-5Mg6vZHN.js +0 -1
  96. package/ui-dist/assets/theme-provider-dHqcWU-j.js +0 -1
  97. package/ui-dist/assets/use-config-DFja1sda.js +0 -1
  98. package/ui-dist/assets/x-BjMO7v8q.js +0 -1
  99. /package/ui-dist/assets/{config-hints-CPNzbMEp.js → config-hints-MogHYQ8G.js} +0 -0
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { _ as waitForExit, a as findExecutableOnPath, c as isProcessRunning, d as prompt, f as resolvePublicIp, g as resolveUiStaticDir, h as resolveUiConfig, i as NpmRuntimeBundleLayoutStore, l as openBrowser, m as resolveUiApiBase, n as NpmRuntimeBundleService, o as getPackageVersion$1, p as resolveServiceLogPath, r as compareNpmRuntimeVersions, s as isLoopbackHost, t as NpmRuntimeUpdateStateStore, u as printAgentResponse } from "../../npm-runtime-update-state.store-DaF0iDY9.js";
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
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";
@@ -168,7 +168,7 @@ function maskToken(value) {
168
168
  if (value.length <= 12) return "<redacted>";
169
169
  return `${value.slice(0, 6)}...${value.slice(-4)}`;
170
170
  }
171
- function normalizeOptionalString$10(value) {
171
+ function normalizeOptionalString$9(value) {
172
172
  if (typeof value !== "string") return;
173
173
  const trimmed = value.trim();
174
174
  return trimmed.length > 0 ? trimmed : void 0;
@@ -266,8 +266,8 @@ var RemotePlatformClient = class {
266
266
  if (tokenState.reason === "missing") throw new Error("NextClaw platform token is missing. Run \"nextclaw login\" first.");
267
267
  if (tokenState.reason === "expired") throw new Error("NextClaw platform token expired. Run \"nextclaw login\" or browser sign-in again.");
268
268
  if (tokenState.reason === "malformed") throw new Error("NextClaw platform token is invalid. Run \"nextclaw login\" again.");
269
- const configuredApiBase = normalizeOptionalString$10(config.remote.platformApiBase) ?? (typeof nextclawProvider?.apiBase === "string" ? nextclawProvider.apiBase.trim() : "");
270
- const rawApiBase = normalizeOptionalString$10(opts.apiBase) ?? configuredApiBase;
269
+ const configuredApiBase = normalizeOptionalString$9(config.remote.platformApiBase) ?? (typeof nextclawProvider?.apiBase === "string" ? nextclawProvider.apiBase.trim() : "");
270
+ const rawApiBase = normalizeOptionalString$9(opts.apiBase) ?? configuredApiBase;
271
271
  if (!rawApiBase) throw new Error("Platform API base is missing. Pass --api-base, run nextclaw login, or set remote.platformApiBase.");
272
272
  return {
273
273
  platformBase: this.deps.resolvePlatformBase(rawApiBase),
@@ -276,14 +276,14 @@ var RemotePlatformClient = class {
276
276
  };
277
277
  }
278
278
  resolveLocalOrigin(config, opts) {
279
- const explicitOrigin = normalizeOptionalString$10(opts.localOrigin);
279
+ const explicitOrigin = normalizeOptionalString$9(opts.localOrigin);
280
280
  if (explicitOrigin) return explicitOrigin.replace(/\/$/, "");
281
281
  const state = this.deps.readManagedServiceState?.();
282
282
  if (state && this.deps.isProcessRunning?.(state.pid) && Number.isFinite(state.uiPort)) return `http://127.0.0.1:${state.uiPort}`;
283
283
  return `http://127.0.0.1:${typeof config.ui?.port === "number" && Number.isFinite(config.ui.port) ? config.ui.port : 55667}`;
284
284
  }
285
285
  resolveDisplayName(config, opts) {
286
- return normalizeOptionalString$10(opts.name) ?? normalizeOptionalString$10(config.remote.deviceName) ?? hostname();
286
+ return normalizeOptionalString$9(opts.name) ?? normalizeOptionalString$9(config.remote.deviceName) ?? hostname();
287
287
  }
288
288
  };
289
289
  //#endregion
@@ -4493,7 +4493,7 @@ var RemoteConnector = class {
4493
4493
  };
4494
4494
  //#endregion
4495
4495
  //#region ../nextclaw-remote/src/remote-status-store.ts
4496
- function normalizeOptionalString$9(value) {
4496
+ function normalizeOptionalString$8(value) {
4497
4497
  if (typeof value !== "string") return;
4498
4498
  const trimmed = value.trim();
4499
4499
  return trimmed.length > 0 ? trimmed : void 0;
@@ -4504,8 +4504,8 @@ function buildConfiguredRemoteState(config) {
4504
4504
  enabled: Boolean(remote.enabled),
4505
4505
  mode: "service",
4506
4506
  state: remote.enabled ? "disconnected" : "disabled",
4507
- ...normalizeOptionalString$9(remote.deviceName) ? { deviceName: normalizeOptionalString$9(remote.deviceName) } : {},
4508
- ...normalizeOptionalString$9(remote.platformApiBase) ? { platformBase: normalizeOptionalString$9(remote.platformApiBase) } : {},
4507
+ ...normalizeOptionalString$8(remote.deviceName) ? { deviceName: normalizeOptionalString$8(remote.deviceName) } : {},
4508
+ ...normalizeOptionalString$8(remote.platformApiBase) ? { platformBase: normalizeOptionalString$8(remote.platformApiBase) } : {},
4509
4509
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
4510
4510
  };
4511
4511
  }
@@ -4518,7 +4518,7 @@ function resolveRemoteStatusSnapshot(params) {
4518
4518
  configuredEnabled: true,
4519
4519
  runtime: {
4520
4520
  ...buildConfiguredRemoteState(params.config),
4521
- deviceName: normalizeOptionalString$9(params.config.remote.deviceName) ?? normalizeOptionalString$9(params.fallbackDeviceName) ?? hostname()
4521
+ deviceName: normalizeOptionalString$8(params.config.remote.deviceName) ?? normalizeOptionalString$8(params.fallbackDeviceName) ?? hostname()
4522
4522
  }
4523
4523
  };
4524
4524
  return {
@@ -5062,30 +5062,6 @@ function parseSessionKey(sessionKey) {
5062
5062
  };
5063
5063
  }
5064
5064
  //#endregion
5065
- //#region src/cli/shared/utils/runtime-helpers.ts
5066
- function resolveSkillsInstallWorkdir(params) {
5067
- if (params.explicitWorkdir) return expandHome(params.explicitWorkdir);
5068
- return getWorkspacePath(params.configuredWorkspace);
5069
- }
5070
- function parseStartTimeoutMs(value) {
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;
5087
- }
5088
- //#endregion
5089
5065
  //#region src/cli/shared/utils/startup-trace.ts
5090
5066
  const STARTUP_TRACE_ENABLED = process.env.NEXTCLAW_STARTUP_TRACE === "1";
5091
5067
  const STARTUP_TRACE_ORIGIN_MS = Date.now();
@@ -5260,10 +5236,14 @@ var NpmRuntimeUpdateManager = class {
5260
5236
  };
5261
5237
  syncStateFromCurrentPointer = () => {
5262
5238
  const currentPointer = this.options.layout.readCurrentPointer();
5263
- if (!currentPointer) return;
5239
+ const effectiveCurrentVersion = resolveEffectiveNpmRuntimeVersion({
5240
+ launcherVersion: this.launcherVersion,
5241
+ currentBundleVersion: currentPointer?.version ?? null
5242
+ });
5243
+ if (!effectiveCurrentVersion) return;
5264
5244
  this.options.stateStore.update((state) => ({
5265
5245
  ...state,
5266
- currentVersion: state.currentVersion ?? currentPointer.version
5246
+ currentVersion: effectiveCurrentVersion
5267
5247
  }));
5268
5248
  };
5269
5249
  toSnapshotFromState = (state, patch) => {
@@ -5467,49 +5447,6 @@ function readDirectoryNames(directory) {
5467
5447
  return readdirSync(directory, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
5468
5448
  }
5469
5449
  //#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
5450
  //#region src/cli/launcher/npm-runtime-update-command.service.ts
5514
5451
  var NpmRuntimeUpdateCommandService = class {
5515
5452
  run = async (opts) => {
@@ -5520,11 +5457,11 @@ var NpmRuntimeUpdateCommandService = class {
5520
5457
  };
5521
5458
  runManaged = async (opts) => {
5522
5459
  const source = new NpmRuntimeUpdateSourceService();
5523
- const channel = source.resolveChannel(opts.channel);
5460
+ const launcherVersion = getPackageVersion$1();
5461
+ const channel = source.resolveChannel(opts.channel, launcherVersion);
5524
5462
  const manifestUrl = source.resolveManifestUrl(channel, opts.manifestUrl);
5525
5463
  const layout = new NpmRuntimeBundleLayoutStore();
5526
- const stateStore = new NpmRuntimeUpdateStateStore(layout.getStatePath());
5527
- const launcherVersion = getPackageVersion$1();
5464
+ const stateStore = new NpmRuntimeUpdateStateStore(layout.getStatePath(), { defaultChannel: channel });
5528
5465
  const bundleService = new NpmRuntimeBundleService({
5529
5466
  layout,
5530
5467
  stateStore,
@@ -5748,11 +5685,9 @@ const readInstalledFirstPartyPluginMatches = (workspaceExtensionsDir) => {
5748
5685
  const workspacePackage = workspacePackageByName.get(packageName);
5749
5686
  if (!workspacePackage) continue;
5750
5687
  matches.push({
5751
- pluginId: workspacePackage.pluginId,
5752
5688
  packageName,
5753
5689
  workspaceDir: workspacePackage.dir,
5754
- installPath: packageDir,
5755
- supportsDevelopmentSource: workspacePackage.supportsDevelopmentSource
5690
+ installPath: packageDir
5756
5691
  });
5757
5692
  }
5758
5693
  return matches;
@@ -5772,35 +5707,6 @@ const findWorkspacePackageForInstallRecord = (installRecord, workspacePackages,
5772
5707
  if (installPathCandidates.size === 0) return;
5773
5708
  return workspacePackages.find((workspacePackage) => installPathCandidates.has(path.resolve(workspacePackage.dir)));
5774
5709
  };
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
5710
  const resolveDevFirstPartyPluginLoadPaths = (config, workspaceExtensionsDir) => {
5805
5711
  const rootDir = resolveDevFirstPartyPluginDir(workspaceExtensionsDir);
5806
5712
  if (!rootDir) return [];
@@ -5850,18 +5756,15 @@ const resolveDevFirstPartyPluginInstallRoots = (config, workspaceExtensionsDir)
5850
5756
  const applyDevFirstPartyPluginLoadPaths = (config, workspaceExtensionsDir) => {
5851
5757
  const rootDir = resolveDevFirstPartyPluginDir(workspaceExtensionsDir);
5852
5758
  if (!rootDir) return config;
5853
- const workspacePackages = readWorkspacePluginPackages(rootDir);
5854
- if (workspacePackages.length === 0) return config;
5855
- const installedPluginMatches = readInstalledFirstPartyPluginMatches(rootDir);
5759
+ if (readWorkspacePluginPackages(rootDir).length === 0) return config;
5760
+ readInstalledFirstPartyPluginMatches(rootDir);
5856
5761
  const devLoadPaths = resolveDevFirstPartyPluginLoadPaths(config, rootDir);
5857
5762
  if (devLoadPaths.length === 0) return config;
5858
5763
  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
5764
  return {
5861
5765
  ...config,
5862
5766
  plugins: {
5863
5767
  ...config.plugins,
5864
- entries: didDefaultDevelopmentSource ? nextEntries : config.plugins.entries,
5865
5768
  load: {
5866
5769
  ...config.plugins.load,
5867
5770
  paths: mergedLoadPaths
@@ -5872,10 +5775,10 @@ const applyDevFirstPartyPluginLoadPaths = (config, workspaceExtensionsDir) => {
5872
5775
  //#endregion
5873
5776
  //#region src/cli/commands/plugin/development-source/dev-plugin-overrides.utils.ts
5874
5777
  const DEV_PLUGIN_OVERRIDES_ENV = "NEXTCLAW_DEV_PLUGIN_OVERRIDES";
5875
- function isRecord$6(value) {
5778
+ function isRecord$7(value) {
5876
5779
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
5877
5780
  }
5878
- function readOptionalString$6(value) {
5781
+ function readOptionalString$7(value) {
5879
5782
  if (typeof value !== "string") return;
5880
5783
  return value.trim() || void 0;
5881
5784
  }
@@ -5901,9 +5804,9 @@ function assertOverridePluginReadable(override) {
5901
5804
  }
5902
5805
  }
5903
5806
  function readOverrideRecord(value, index) {
5904
- if (!isRecord$6(value)) throw new Error(`[dev-plugin-override] override[${index}] must be an object`);
5905
- const pluginId = readOptionalString$6(value.pluginId);
5906
- const pluginPath = readOptionalString$6(value.pluginPath);
5807
+ if (!isRecord$7(value)) throw new Error(`[dev-plugin-override] override[${index}] must be an object`);
5808
+ const pluginId = readOptionalString$7(value.pluginId);
5809
+ const pluginPath = readOptionalString$7(value.pluginPath);
5907
5810
  const source = value.source === "development" ? "development" : "production";
5908
5811
  if (!pluginId || !pluginPath) throw new Error(`[dev-plugin-override] override[${index}] requires pluginId and pluginPath`);
5909
5812
  const normalized = {
@@ -5960,7 +5863,7 @@ function resolveDevPluginOverrideInstallRoots(config, overrides) {
5960
5863
  const installRoots = [];
5961
5864
  for (const override of overrides) {
5962
5865
  const installRecord = config.plugins.installs?.[override.pluginId];
5963
- const installPath = readOptionalString$6(installRecord?.installPath);
5866
+ const installPath = readOptionalString$7(installRecord?.installPath);
5964
5867
  if (!installPath || installRoots.includes(installPath)) continue;
5965
5868
  installRoots.push(installPath);
5966
5869
  }
@@ -8423,13 +8326,13 @@ var AgentCommands = class {
8423
8326
  };
8424
8327
  //#endregion
8425
8328
  //#region src/cli/commands/ncp/features/runtime/ncp-asset-tools.ts
8426
- function readOptionalString$5(value) {
8329
+ function readOptionalString$6(value) {
8427
8330
  if (typeof value !== "string") return null;
8428
8331
  const trimmed = value.trim();
8429
8332
  return trimmed.length > 0 ? trimmed : null;
8430
8333
  }
8431
8334
  function readOptionalBase64Bytes(value) {
8432
- const base64 = readOptionalString$5(value);
8335
+ const base64 = readOptionalString$6(value);
8433
8336
  if (!base64) return null;
8434
8337
  try {
8435
8338
  return Buffer.from(base64, "base64");
@@ -8480,18 +8383,18 @@ var AssetPutTool = class {
8480
8383
  this.contentBasePath = contentBasePath;
8481
8384
  }
8482
8385
  validateArgs = (args) => {
8483
- const path = readOptionalString$5(args.path);
8484
- const bytesBase64 = readOptionalString$5(args.bytesBase64);
8485
- const fileName = readOptionalString$5(args.fileName);
8386
+ const path = readOptionalString$6(args.path);
8387
+ const bytesBase64 = readOptionalString$6(args.bytesBase64);
8388
+ const fileName = readOptionalString$6(args.fileName);
8486
8389
  if (path && bytesBase64) return ["Provide either path, or bytesBase64 + fileName, not both."];
8487
8390
  if (path) return [];
8488
8391
  if (bytesBase64) return fileName ? [] : ["fileName is required when using bytesBase64."];
8489
8392
  return ["Provide either path, or bytesBase64 + fileName."];
8490
8393
  };
8491
8394
  execute = async (args) => {
8492
- const path = readOptionalString$5(args?.path);
8493
- const fileName = readOptionalString$5(args?.fileName);
8494
- const mimeType = readOptionalString$5(args?.mimeType);
8395
+ const path = readOptionalString$6(args?.path);
8396
+ const fileName = readOptionalString$6(args?.fileName);
8397
+ const mimeType = readOptionalString$6(args?.mimeType);
8495
8398
  const bytes = readOptionalBase64Bytes(args?.bytesBase64);
8496
8399
  if (path) return {
8497
8400
  ok: true,
@@ -8534,8 +8437,8 @@ var AssetExportTool = class {
8534
8437
  this.assetStore = assetStore;
8535
8438
  }
8536
8439
  execute = async (args) => {
8537
- const assetUri = readOptionalString$5(args?.assetUri);
8538
- const targetPath = readOptionalString$5(args?.targetPath);
8440
+ const assetUri = readOptionalString$6(args?.assetUri);
8441
+ const targetPath = readOptionalString$6(args?.targetPath);
8539
8442
  if (!assetUri || !targetPath) throw new Error("asset_export requires assetUri and targetPath.");
8540
8443
  return {
8541
8444
  ok: true,
@@ -8561,7 +8464,7 @@ var AssetStatTool = class {
8561
8464
  this.contentBasePath = contentBasePath;
8562
8465
  }
8563
8466
  execute = async (args) => {
8564
- const assetUri = readOptionalString$5(args?.assetUri);
8467
+ const assetUri = readOptionalString$6(args?.assetUri);
8565
8468
  if (!assetUri) throw new Error("asset_stat requires assetUri.");
8566
8469
  const record = await this.assetStore.statRecord(assetUri);
8567
8470
  if (!record) return {
@@ -8593,11 +8496,11 @@ function normalizeString(value) {
8593
8496
  const trimmed = value.trim();
8594
8497
  return trimmed.length > 0 ? trimmed : null;
8595
8498
  }
8596
- function isRecord$5(value) {
8499
+ function isRecord$6(value) {
8597
8500
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
8598
8501
  }
8599
8502
  function cloneMetadata(value) {
8600
- return isRecord$5(value) ? structuredClone(value) : void 0;
8503
+ return isRecord$6(value) ? structuredClone(value) : void 0;
8601
8504
  }
8602
8505
  function readStringArray(value) {
8603
8506
  if (!Array.isArray(value)) return null;
@@ -9088,7 +8991,7 @@ function readRequiredString$1(params, key) {
9088
8991
  if (typeof value !== "string" || value.trim().length === 0) throw new Error(`${key} must be a non-empty string.`);
9089
8992
  return value.trim();
9090
8993
  }
9091
- function readOptionalString$4(params, key) {
8994
+ function readOptionalString$5(params, key) {
9092
8995
  const value = params[key];
9093
8996
  if (typeof value !== "string") return;
9094
8997
  const trimmed = value.trim();
@@ -9149,14 +9052,14 @@ var SessionRequestTool = class extends Tool {
9149
9052
  const target = params.target;
9150
9053
  if (!target || typeof target !== "object" || Array.isArray(target)) throw new Error("target must be an object.");
9151
9054
  const task = readRequiredString$1(params, "task");
9152
- const notifyMode = readOptionalString$4(params, "notify")?.toLowerCase();
9055
+ const notifyMode = readOptionalString$5(params, "notify")?.toLowerCase();
9153
9056
  if (notifyMode !== "none" && notifyMode !== "final_reply") throw new Error("notify must be \"none\" or \"final_reply\".");
9154
9057
  return this.broker.requestSession({
9155
9058
  sourceSessionId: this.sourceSessionId,
9156
9059
  sourceToolCallId: toolCallId,
9157
9060
  targetSessionId: readRequiredString$1(target, "session_id"),
9158
9061
  task,
9159
- title: readOptionalString$4(params, "title"),
9062
+ title: readOptionalString$5(params, "title"),
9160
9063
  notify: notifyMode,
9161
9064
  handoffDepth: this.handoffDepth
9162
9065
  });
@@ -9168,13 +9071,13 @@ function readRequiredString(value, key) {
9168
9071
  if (typeof value !== "string" || value.trim().length === 0) throw new Error(`${key} must be a non-empty string.`);
9169
9072
  return value.trim();
9170
9073
  }
9171
- function readOptionalString$3(value) {
9074
+ function readOptionalString$4(value) {
9172
9075
  if (typeof value !== "string") return;
9173
9076
  const trimmed = value.trim();
9174
9077
  return trimmed.length > 0 ? trimmed : void 0;
9175
9078
  }
9176
9079
  function readSpawnScope(value) {
9177
- const normalized = readOptionalString$3(value)?.toLowerCase();
9080
+ const normalized = readOptionalString$4(value)?.toLowerCase();
9178
9081
  if (!normalized || normalized === "standalone") return "standalone";
9179
9082
  if (normalized === "child") return "child";
9180
9083
  throw new Error("scope must be \"standalone\" or \"child\".");
@@ -9182,7 +9085,7 @@ function readSpawnScope(value) {
9182
9085
  function readSpawnRequestOptions(value) {
9183
9086
  if (typeof value === "undefined") return;
9184
9087
  if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("request must be an object.");
9185
- const notifyMode = readOptionalString$3(value.notify)?.toLowerCase();
9088
+ const notifyMode = readOptionalString$4(value.notify)?.toLowerCase();
9186
9089
  if (notifyMode === "none" || notifyMode === "final_reply") return { notify: notifyMode };
9187
9090
  throw new Error("request.notify must be \"none\" or \"final_reply\".");
9188
9091
  }
@@ -9260,21 +9163,21 @@ var SessionSpawnTool = class extends Tool {
9260
9163
  sourceToolCallId: toolCallId,
9261
9164
  sourceSessionMetadata: this.sourceSessionMetadata,
9262
9165
  task,
9263
- title: readOptionalString$3(rawTitle),
9264
- agentId: readOptionalString$3(rawAgentId),
9265
- model: readOptionalString$3(rawModel),
9266
- runtime: readOptionalString$3(rawRuntime),
9166
+ title: readOptionalString$4(rawTitle),
9167
+ agentId: readOptionalString$4(rawAgentId),
9168
+ model: readOptionalString$4(rawModel),
9169
+ runtime: readOptionalString$4(rawRuntime),
9267
9170
  handoffDepth: this.handoffDepth,
9268
9171
  ...parentSessionId ? { parentSessionId } : {},
9269
9172
  notify: request.notify
9270
9173
  });
9271
9174
  const session = this.sessionCreationService.createSession({
9272
9175
  task,
9273
- title: readOptionalString$3(rawTitle),
9176
+ title: readOptionalString$4(rawTitle),
9274
9177
  sourceSessionMetadata: this.sourceSessionMetadata,
9275
- agentId: readOptionalString$3(rawAgentId),
9276
- model: readOptionalString$3(rawModel),
9277
- runtime: readOptionalString$3(rawRuntime),
9178
+ agentId: readOptionalString$4(rawAgentId),
9179
+ model: readOptionalString$4(rawModel),
9180
+ runtime: readOptionalString$4(rawRuntime),
9278
9181
  ...parentSessionId ? { parentSessionId } : {}
9279
9182
  });
9280
9183
  return {
@@ -9298,10 +9201,10 @@ var SessionSpawnTool = class extends Tool {
9298
9201
  //#endregion
9299
9202
  //#region src/cli/commands/ncp/nextclaw-ncp-tool-registry.ts
9300
9203
  function toToolParams(args) {
9301
- if (isRecord$5(args)) return args;
9204
+ if (isRecord$6(args)) return args;
9302
9205
  if (typeof args === "string") try {
9303
9206
  const parsed = JSON.parse(args);
9304
- return isRecord$5(parsed) ? parsed : {};
9207
+ return isRecord$6(parsed) ? parsed : {};
9305
9208
  } catch {
9306
9209
  return {};
9307
9210
  }
@@ -9479,14 +9382,14 @@ function readAccountIdForHints(metadata, sessionMetadata) {
9479
9382
  //#endregion
9480
9383
  //#region src/cli/commands/ncp/nextclaw-ncp-context-builder.ts
9481
9384
  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$4(value) {
9385
+ function isRecord$5(value) {
9483
9386
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
9484
9387
  }
9485
9388
  function mergeInputMetadata(input) {
9486
- const messageMetadata = input.messages.slice().reverse().find((message) => isRecord$4(message.metadata))?.metadata;
9389
+ const messageMetadata = input.messages.slice().reverse().find((message) => isRecord$5(message.metadata))?.metadata;
9487
9390
  return {
9488
- ...isRecord$4(messageMetadata) ? structuredClone(messageMetadata) : {},
9489
- ...isRecord$4(input.metadata) ? structuredClone(input.metadata) : {}
9391
+ ...isRecord$5(messageMetadata) ? structuredClone(messageMetadata) : {},
9392
+ ...isRecord$5(input.metadata) ? structuredClone(input.metadata) : {}
9490
9393
  };
9491
9394
  }
9492
9395
  const REQUESTED_SKILLS_METADATA_READER = new RequestedSkillsMetadataReader();
@@ -10110,7 +10013,7 @@ const CHILD_SESSION_PARENT_METADATA_KEY = "parent_session_id";
10110
10013
  const CHILD_SESSION_REQUEST_METADATA_KEY = "spawned_by_request_id";
10111
10014
  const CHILD_SESSION_LIFECYCLE_METADATA_KEY = "session_lifecycle";
10112
10015
  const CHILD_SESSION_PROMOTED_METADATA_KEY = "child_session_promoted";
10113
- function readOptionalString$2(value) {
10016
+ function readOptionalString$3(value) {
10114
10017
  if (typeof value !== "string") return null;
10115
10018
  const trimmed = value.trim();
10116
10019
  return trimmed.length > 0 ? trimmed : null;
@@ -10150,14 +10053,14 @@ function buildSessionId() {
10150
10053
  return `ncp-${Date.now().toString(36)}-${randomUUID().replace(/-/g, "").slice(0, 8)}`;
10151
10054
  }
10152
10055
  function resolveSessionAgentId(params) {
10153
- return readOptionalString$2(params.agentId) ?? resolveDefaultAgentProfileId(params.getConfig());
10056
+ return readOptionalString$3(params.agentId) ?? resolveDefaultAgentProfileId(params.getConfig());
10154
10057
  }
10155
10058
  function resolveSessionTitle(params) {
10156
- return readOptionalString$2(params.title) ?? summarizeTask(params.task);
10059
+ return readOptionalString$3(params.title) ?? summarizeTask(params.task);
10157
10060
  }
10158
10061
  function resolveSessionType(params) {
10159
10062
  const { metadata, runtime, sessionType } = params;
10160
- return readOptionalString$2(runtime) ?? readOptionalString$2(metadata.runtime) ?? readOptionalString$2(sessionType) ?? readOptionalString$2(metadata.session_type) ?? DEFAULT_SESSION_TYPE;
10063
+ return readOptionalString$3(runtime) ?? readOptionalString$3(metadata.runtime) ?? readOptionalString$3(sessionType) ?? readOptionalString$3(metadata.session_type) ?? DEFAULT_SESSION_TYPE;
10161
10064
  }
10162
10065
  function applySessionOverrides(params) {
10163
10066
  const { lifecycle, metadata, model, parentSessionId, projectRoot, requestId, sessionType, thinkingLevel, title } = params;
@@ -10170,15 +10073,15 @@ function applySessionOverrides(params) {
10170
10073
  metadata[CHILD_SESSION_PROMOTED_METADATA_KEY] = false;
10171
10074
  }
10172
10075
  if (requestId) metadata[CHILD_SESSION_REQUEST_METADATA_KEY] = requestId;
10173
- if (readOptionalString$2(model)) {
10076
+ if (readOptionalString$3(model)) {
10174
10077
  metadata.model = model?.trim();
10175
10078
  metadata.preferred_model = model?.trim();
10176
10079
  }
10177
- if (readOptionalString$2(thinkingLevel)) {
10080
+ if (readOptionalString$3(thinkingLevel)) {
10178
10081
  metadata.thinking = thinkingLevel?.trim();
10179
10082
  metadata.preferred_thinking = thinkingLevel?.trim();
10180
10083
  }
10181
- if (readOptionalString$2(projectRoot)) metadata.project_root = projectRoot?.trim();
10084
+ if (readOptionalString$3(projectRoot)) metadata.project_root = projectRoot?.trim();
10182
10085
  }
10183
10086
  var SessionCreationService = class {
10184
10087
  constructor(sessionManager, getConfig, onSessionUpdated) {
@@ -10200,8 +10103,8 @@ var SessionCreationService = class {
10200
10103
  task
10201
10104
  });
10202
10105
  const metadata = cloneInheritedMetadata(sourceSessionMetadata);
10203
- const parentSessionId = readOptionalString$2(rawParentSessionId);
10204
- const requestId = readOptionalString$2(rawRequestId);
10106
+ const parentSessionId = readOptionalString$3(rawParentSessionId);
10107
+ const requestId = readOptionalString$3(rawRequestId);
10205
10108
  const sessionType = resolveSessionType({
10206
10109
  runtime,
10207
10110
  sessionType: requestedSessionType,
@@ -10254,12 +10157,12 @@ var SessionCreationService = class {
10254
10157
  return true;
10255
10158
  };
10256
10159
  isChildSessionRecord = (metadata) => {
10257
- return Boolean(readOptionalString$2(metadata?.[CHILD_SESSION_PARENT_METADATA_KEY]));
10160
+ return Boolean(readOptionalString$3(metadata?.[CHILD_SESSION_PARENT_METADATA_KEY]));
10258
10161
  };
10259
10162
  };
10260
10163
  //#endregion
10261
10164
  //#region src/cli/commands/ncp/session-request/session-request-result.ts
10262
- function readOptionalString$1(value) {
10165
+ function readOptionalString$2(value) {
10263
10166
  if (typeof value !== "string") return null;
10264
10167
  const trimmed = value.trim();
10265
10168
  return trimmed.length > 0 ? trimmed : null;
@@ -10280,7 +10183,7 @@ function extractSessionMessageText(message) {
10280
10183
  return parts.join("\n\n");
10281
10184
  }
10282
10185
  function readParentSessionId(metadata) {
10283
- return readOptionalString$1(metadata?.["parent_session_id"]) ?? void 0;
10186
+ return readOptionalString$2(metadata?.["parent_session_id"]) ?? void 0;
10284
10187
  }
10285
10188
  function buildSessionRequestToolResult(params) {
10286
10189
  const { request, task, title, agentId, isChildSession, parentSessionId, spawnedByRequestId, message } = params;
@@ -10419,7 +10322,7 @@ var SessionRequestBroker = class {
10419
10322
  sourceToolCallId,
10420
10323
  targetSessionId: normalizedTargetSessionId,
10421
10324
  task,
10422
- title: readOptionalString$1(title) ?? readOptionalString$1(targetSummary.metadata?.label) ?? summarizeSessionRequestTask(task),
10325
+ title: readOptionalString$2(title) ?? readOptionalString$2(targetSummary.metadata?.label) ?? summarizeSessionRequestTask(task),
10423
10326
  handoffDepth: handoffDepth ?? 0,
10424
10327
  notify,
10425
10328
  agentId: targetSummary.agentId,
@@ -10955,7 +10858,7 @@ var SessionSearchStoreService = class {
10955
10858
  };
10956
10859
  //#endregion
10957
10860
  //#region src/cli/commands/ncp/session-search/session-search-tool.service.ts
10958
- function isRecord$3(value) {
10861
+ function isRecord$4(value) {
10959
10862
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
10960
10863
  }
10961
10864
  function readOptionalInteger(value) {
@@ -11005,7 +10908,7 @@ var SessionSearchTool = class {
11005
10908
  return issues;
11006
10909
  };
11007
10910
  execute = async (args) => {
11008
- if (!isRecord$3(args)) throw new Error("session_search requires an object argument.");
10911
+ if (!isRecord$4(args)) throw new Error("session_search requires an object argument.");
11009
10912
  const issues = this.validateArgs(args);
11010
10913
  if (issues.length > 0) throw new Error(issues.join(" "));
11011
10914
  return this.queryService.search({
@@ -11937,12 +11840,12 @@ function createContextWindowUpdatedEvent(params) {
11937
11840
  }
11938
11841
  };
11939
11842
  }
11940
- function isRecord$2(value) {
11843
+ function isRecord$3(value) {
11941
11844
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
11942
11845
  }
11943
11846
  function resolveNativeReasoningNormalizationMode(params) {
11944
11847
  const runtimeEntry = params.config.agents.runtimes.entries.native?.config ?? params.config.ui.ncp.runtimes.native;
11945
- const runtimeMetadata = isRecord$2(runtimeEntry) ? runtimeEntry : {};
11848
+ const runtimeMetadata = isRecord$3(runtimeEntry) ? runtimeEntry : {};
11946
11849
  return readAssistantReasoningNormalizationModeFromMetadata(params.sessionMetadata) ?? readAssistantReasoningNormalizationMode(runtimeMetadata.reasoningNormalization) ?? readAssistantReasoningNormalizationMode(runtimeMetadata.reasoning_normalization) ?? readAssistantReasoningNormalizationMode(runtimeMetadata.reasoningNormalizationMode) ?? readAssistantReasoningNormalizationMode(runtimeMetadata.reasoning_normalization_mode) ?? "think-tags";
11947
11850
  }
11948
11851
  function createMcpRuntimeSupport(getConfig) {
@@ -14004,7 +13907,7 @@ var ServiceMarketplaceInstaller = class {
14004
13907
  };
14005
13908
  //#endregion
14006
13909
  //#region src/cli/shared/utils/marketplace/cli-subcommand-launch.utils.ts
14007
- const require$2 = createRequire(import.meta.url);
13910
+ const require$3 = createRequire(import.meta.url);
14008
13911
  const TYPESCRIPT_EXTENSIONS$1 = new Set([
14009
13912
  ".ts",
14010
13913
  ".tsx",
@@ -14012,7 +13915,7 @@ const TYPESCRIPT_EXTENSIONS$1 = new Set([
14012
13915
  ".cts"
14013
13916
  ]);
14014
13917
  const isTypeScriptEntry = (entry) => TYPESCRIPT_EXTENSIONS$1.has(extname(entry).toLowerCase());
14015
- const resolveTsxCliEntry = () => require$2.resolve("tsx/cli");
13918
+ const resolveTsxCliEntry = () => require$3.resolve("tsx/cli");
14016
13919
  const resolveCliAppEntryFromImportMeta$1 = (importMetaUrl) => {
14017
13920
  const modulePath = fileURLToPath(importMetaUrl);
14018
13921
  const cliRootIndex = modulePath.replace(/\\/g, "/").lastIndexOf("/cli/");
@@ -14369,6 +14272,13 @@ async function describeUnmanagedHealthyTargetMessage(params) {
14369
14272
  //#endregion
14370
14273
  //#region src/cli/shared/services/runtime/service-managed-startup.service.ts
14371
14274
  const { APP_NAME: APP_NAME$1, loadConfig: loadConfig$4 } = NextclawCore;
14275
+ function resolveLauncherCliEntry(importMetaUrl) {
14276
+ const modulePath = fileURLToPath(importMetaUrl);
14277
+ const cliRootIndex = modulePath.replace(/\\/g, "/").lastIndexOf("/cli/");
14278
+ if (cliRootIndex === -1) return fileURLToPath(new URL("../../../launcher/index.js", importMetaUrl));
14279
+ const extension = extname(modulePath) || ".js";
14280
+ return resolve(modulePath.slice(0, cliRootIndex + 5), "launcher", `index${extension}`);
14281
+ }
14372
14282
  function toObjectRecord(value) {
14373
14283
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
14374
14284
  return value;
@@ -14420,7 +14330,7 @@ function spawnManagedService(params) {
14420
14330
  appendStartupStage(logPath, `start requested: ui=${uiConfig.host}:${uiConfig.port}, readinessTimeoutMs=${readinessTimeoutMs}`);
14421
14331
  console.log(`Starting ${appName} background service (readiness timeout ${Math.ceil(readinessTimeoutMs / 1e3)}s)...`);
14422
14332
  const cliLaunch = resolveCliSubcommandLaunch({
14423
- argvEntry: process.argv[1],
14333
+ argvEntry: resolveLauncherCliEntry(import.meta.url),
14424
14334
  importMetaUrl: import.meta.url,
14425
14335
  cliArgs: [
14426
14336
  "serve",
@@ -15199,6 +15109,173 @@ function createRemoteAccessHost(params) {
15199
15109
  });
15200
15110
  }
15201
15111
  //#endregion
15112
+ //#region src/cli/shared/services/ui/npm-runtime-update-host.service.ts
15113
+ const INITIAL_DOWNLOAD_PROGRESS = {
15114
+ downloadedBytes: 0,
15115
+ totalBytes: null,
15116
+ percent: null
15117
+ };
15118
+ var NpmRuntimeUpdateHost = class {
15119
+ source = new NpmRuntimeUpdateSourceService();
15120
+ layout = new NpmRuntimeBundleLayoutStore();
15121
+ launcherVersion = getPackageVersion$1();
15122
+ stateStore = new NpmRuntimeUpdateStateStore(this.layout.getStatePath(), { defaultChannel: this.source.resolveChannel(void 0, this.launcherVersion) });
15123
+ bundleService = new NpmRuntimeBundleService({
15124
+ layout: this.layout,
15125
+ stateStore: this.stateStore,
15126
+ launcherVersion: this.launcherVersion
15127
+ });
15128
+ updateService = new NpmRuntimeUpdateService({
15129
+ layout: this.layout,
15130
+ bundleService: this.bundleService,
15131
+ launcherVersion: this.launcherVersion,
15132
+ bundlePublicKey: this.source.resolveBundlePublicKey() ?? void 0
15133
+ });
15134
+ snapshot;
15135
+ activeTask = null;
15136
+ automaticSyncStarted = false;
15137
+ constructor(deps) {
15138
+ this.deps = deps;
15139
+ this.snapshot = this.createManager().getSnapshot();
15140
+ this.startAutomaticSync();
15141
+ }
15142
+ getState = async () => {
15143
+ this.startAutomaticSync();
15144
+ return this.snapshot;
15145
+ };
15146
+ checkForUpdates = async () => {
15147
+ return this.startCheck({ autoDownload: false });
15148
+ };
15149
+ downloadUpdate = async () => {
15150
+ return this.startDownload();
15151
+ };
15152
+ applyDownloadedUpdate = async () => {
15153
+ if (this.activeTask) return this.snapshot;
15154
+ this.snapshot = {
15155
+ ...this.snapshot,
15156
+ status: "applying",
15157
+ progress: null,
15158
+ errorMessage: null
15159
+ };
15160
+ try {
15161
+ const snapshot = this.createManager().applyDownloadedUpdate();
15162
+ this.snapshot = this.deps.applyRestartMode === "managed-service-restart" ? snapshot : {
15163
+ ...snapshot,
15164
+ recoveryCommand: "Restart this NextClaw process to launch the downloaded runtime."
15165
+ };
15166
+ if (this.deps.applyRestartMode === "managed-service-restart") await requestManagedServiceRestart(this.deps.requestRestart, {
15167
+ reason: "runtime update apply",
15168
+ uiPort: this.deps.uiConfig.port
15169
+ });
15170
+ return this.snapshot;
15171
+ } catch (error) {
15172
+ this.snapshot = this.toFailedSnapshot(error);
15173
+ throw error;
15174
+ }
15175
+ };
15176
+ updatePreferences = async (preferences) => {
15177
+ const nextState = this.stateStore.update((current) => ({
15178
+ ...current,
15179
+ updatePreferences: {
15180
+ ...current.updatePreferences,
15181
+ ...preferences
15182
+ }
15183
+ }));
15184
+ this.snapshot = this.createManager(nextState.channel).getSnapshot();
15185
+ if (nextState.updatePreferences.automaticChecks) this.startAutomaticSync({ force: true });
15186
+ return this.snapshot;
15187
+ };
15188
+ updateChannel = async (channel) => {
15189
+ const nextState = this.stateStore.update((current) => ({
15190
+ ...current,
15191
+ channel
15192
+ }));
15193
+ this.snapshot = this.createManager(nextState.channel).getSnapshot();
15194
+ if (nextState.updatePreferences.automaticChecks) return this.startCheck({ autoDownload: nextState.updatePreferences.autoDownload });
15195
+ return this.snapshot;
15196
+ };
15197
+ startAutomaticSync = (options = {}) => {
15198
+ if (this.activeTask) return;
15199
+ if (this.automaticSyncStarted && !options.force) return;
15200
+ this.automaticSyncStarted = true;
15201
+ const state = this.stateStore.read();
15202
+ if (!state.updatePreferences.automaticChecks || state.downloadedVersion) return;
15203
+ this.startCheck({ autoDownload: state.updatePreferences.autoDownload });
15204
+ };
15205
+ startCheck = async (options) => {
15206
+ if (this.activeTask) return this.snapshot;
15207
+ this.snapshot = {
15208
+ ...this.createManager().getSnapshot(),
15209
+ status: "checking",
15210
+ progress: null,
15211
+ errorMessage: null
15212
+ };
15213
+ this.activeTask = (async () => {
15214
+ try {
15215
+ const checkedSnapshot = await this.createManager().checkForUpdate();
15216
+ this.snapshot = checkedSnapshot;
15217
+ if (options.autoDownload && checkedSnapshot.status === "update-available") await this.runDownloadTask();
15218
+ } catch (error) {
15219
+ this.snapshot = this.toFailedSnapshot(error);
15220
+ } finally {
15221
+ this.activeTask = null;
15222
+ }
15223
+ })();
15224
+ return this.snapshot;
15225
+ };
15226
+ startDownload = async () => {
15227
+ if (this.activeTask) return this.snapshot;
15228
+ this.snapshot = {
15229
+ ...this.createManager().getSnapshot(),
15230
+ status: "downloading",
15231
+ progress: INITIAL_DOWNLOAD_PROGRESS,
15232
+ errorMessage: null
15233
+ };
15234
+ this.activeTask = (async () => {
15235
+ try {
15236
+ await this.runDownloadTask();
15237
+ } catch (error) {
15238
+ this.snapshot = this.toFailedSnapshot(error);
15239
+ } finally {
15240
+ this.activeTask = null;
15241
+ }
15242
+ })();
15243
+ return this.snapshot;
15244
+ };
15245
+ runDownloadTask = async () => {
15246
+ this.snapshot = await this.createManager().downloadUpdate((progress) => {
15247
+ this.snapshot = {
15248
+ ...this.snapshot,
15249
+ status: "downloading",
15250
+ progress,
15251
+ errorMessage: null
15252
+ };
15253
+ });
15254
+ };
15255
+ createManager = (channel = this.stateStore.read().channel) => {
15256
+ return new NpmRuntimeUpdateManager({
15257
+ layout: this.layout,
15258
+ stateStore: this.stateStore,
15259
+ bundleService: this.bundleService,
15260
+ updateService: this.updateService,
15261
+ resolveManifestUrl: (resolvedChannel) => this.source.resolveManifestUrl(resolvedChannel),
15262
+ launcherVersion: this.launcherVersion,
15263
+ channel
15264
+ });
15265
+ };
15266
+ toFailedSnapshot = (error) => {
15267
+ return {
15268
+ ...this.createManager().getSnapshot(),
15269
+ status: "failed",
15270
+ progress: null,
15271
+ errorMessage: error instanceof Error ? error.message : String(error ?? "Unknown error")
15272
+ };
15273
+ };
15274
+ };
15275
+ function createNpmRuntimeUpdateHost(params) {
15276
+ return new NpmRuntimeUpdateHost(params);
15277
+ }
15278
+ //#endregion
15202
15279
  //#region src/cli/shared/stores/pending-restart.store.ts
15203
15280
  const clonePendingRestartState = (state) => {
15204
15281
  if (!state) return null;
@@ -15320,12 +15397,19 @@ function createRuntimeControlHost(params) {
15320
15397
  //#endregion
15321
15398
  //#region src/cli/shared/services/ui/service-ui-hosts.service.ts
15322
15399
  function createServiceUiHosts(params) {
15400
+ const { requestRestart, serviceCommands, uiConfig } = params;
15401
+ const applyRestartMode = managedServiceStateStore.read()?.pid === process.pid ? "managed-service-restart" : "manual-process-restart";
15323
15402
  return {
15324
15403
  remoteAccess: createRemoteAccessHost(params),
15325
15404
  runtimeControl: createRuntimeControlHost({
15326
- serviceCommands: params.serviceCommands,
15327
- requestRestart: params.requestRestart,
15328
- uiConfig: params.uiConfig
15405
+ serviceCommands,
15406
+ requestRestart,
15407
+ uiConfig
15408
+ }),
15409
+ runtimeUpdate: process.env.NEXTCLAW_DISABLE_RUNTIME_UPDATE_HOST === "1" ? void 0 : createNpmRuntimeUpdateHost({
15410
+ applyRestartMode,
15411
+ requestRestart,
15412
+ uiConfig
15329
15413
  })
15330
15414
  };
15331
15415
  }
@@ -15665,6 +15749,9 @@ var ConfigReloader = class {
15665
15749
  setReloadMcp(callback) {
15666
15750
  this.options.reloadMcp = callback;
15667
15751
  }
15752
+ setReloadCompanion(callback) {
15753
+ this.options.reloadCompanion = callback;
15754
+ }
15668
15755
  async applyReloadPlan(nextConfig) {
15669
15756
  const changedPaths = diffConfigPaths(this.currentConfig, nextConfig);
15670
15757
  if (!changedPaths.length) return;
@@ -15686,6 +15773,13 @@ var ConfigReloader = class {
15686
15773
  });
15687
15774
  console.log("Config reload: MCP servers reloaded.");
15688
15775
  }
15776
+ if (plan.reloadCompanion) {
15777
+ await this.reloadCompanion({
15778
+ config: nextConfig,
15779
+ changedPaths
15780
+ });
15781
+ console.log("Config reload: companion setting applied.");
15782
+ }
15689
15783
  if (plan.restartChannels || reloadPluginsResult?.restartChannels) {
15690
15784
  await this.reloadChannels(nextConfig, { start: true });
15691
15785
  console.log("Config reload: channels restarted.");
@@ -15781,6 +15875,10 @@ var ConfigReloader = class {
15781
15875
  if (!this.options.reloadMcp) return;
15782
15876
  await this.options.reloadMcp(params);
15783
15877
  }
15878
+ async reloadCompanion(params) {
15879
+ if (!this.options.reloadCompanion) return;
15880
+ await this.options.reloadCompanion(params);
15881
+ }
15784
15882
  };
15785
15883
  //#endregion
15786
15884
  //#region src/cli/shared/services/gateway/cron-job-handler.service.ts
@@ -16161,11 +16259,11 @@ function createSystemSessionUpdatedPublisher(params) {
16161
16259
  }
16162
16260
  async function startUiShell(params) {
16163
16261
  logStartupTrace("service.start_ui_shell.begin");
16164
- const { applyLiveConfigReload, configPath, cronService, getBootstrapStatus, getPluginChannelBindings, getPluginUiMetadata, initializeAgentHomeDirectory, marketplace, ncpSessionService, openBrowserWindow, productVersion, remoteAccess, runtimeControl, uiConfig, uiStaticDir } = params;
16262
+ const { applyLiveConfigReload, configPath, cronService, getBootstrapStatus, getPluginChannelBindings, getPluginUiMetadata, initializeAgentHomeDirectory, marketplace, ncpSessionService, openBrowserWindow, productVersion, remoteAccess, runtimeControl, runtimeUpdate, uiConfig, uiStaticDir } = params;
16165
16263
  if (!uiConfig.enabled) return null;
16166
16264
  let publishUiEvent = null;
16167
16265
  const deferredNcpAgent = createDeferredUiNcpAgent();
16168
- const uiServer = startUiServer({
16266
+ const uiServer = await startUiServer({
16169
16267
  host: uiConfig.host,
16170
16268
  port: uiConfig.port,
16171
16269
  configPath,
@@ -16177,6 +16275,7 @@ async function startUiShell(params) {
16177
16275
  marketplace,
16178
16276
  remoteAccess,
16179
16277
  runtimeControl,
16278
+ runtimeUpdate,
16180
16279
  getBootstrapStatus,
16181
16280
  getPluginChannelBindings,
16182
16281
  getPluginUiMetadata,
@@ -16779,17 +16878,17 @@ function readStringList(value) {
16779
16878
  if (!Array.isArray(value)) return [];
16780
16879
  return value.map((entry) => typeof entry === "string" ? entry.trim() : "").filter(Boolean);
16781
16880
  }
16782
- function readOptionalString(value) {
16881
+ function readOptionalString$1(value) {
16783
16882
  if (typeof value !== "string") return;
16784
16883
  return value.trim() || void 0;
16785
16884
  }
16786
16885
  function resolvePluginRuntimeAttachments(ctx) {
16787
16886
  const mediaPaths = readStringList(ctx.MediaPaths);
16788
16887
  const mediaUrls = readStringList(ctx.MediaUrls);
16789
- const fallbackPath = readOptionalString(ctx.MediaPath);
16790
- const fallbackUrl = readOptionalString(ctx.MediaUrl);
16888
+ const fallbackPath = readOptionalString$1(ctx.MediaPath);
16889
+ const fallbackUrl = readOptionalString$1(ctx.MediaUrl);
16791
16890
  const mediaTypes = readStringList(ctx.MediaTypes);
16792
- const fallbackType = readOptionalString(ctx.MediaType);
16891
+ const fallbackType = readOptionalString$1(ctx.MediaType);
16793
16892
  const entryCount = Math.max(mediaPaths.length, mediaUrls.length, fallbackPath ? 1 : 0, fallbackUrl ? 1 : 0);
16794
16893
  const attachments = [];
16795
16894
  for (let index = 0; index < entryCount; index += 1) {
@@ -16812,7 +16911,7 @@ function resolvePluginRuntimeAttachments(ctx) {
16812
16911
  //#region src/cli/shared/services/plugin/service-plugin-reload.service.ts
16813
16912
  async function reloadServicePlugins(params) {
16814
16913
  const nextWorkspace = getWorkspacePath(params.nextConfig.agents.defaults.workspace);
16815
- const nextPluginRegistry = loadPluginRegistry(params.nextConfig, nextWorkspace);
16914
+ const nextPluginRegistry = await loadPluginRegistryProgressively(params.nextConfig, nextWorkspace);
16816
16915
  const nextExtensionRegistry = toExtensionRegistry(nextPluginRegistry);
16817
16916
  const nextPluginChannelBindings = getPluginChannelBindings(nextPluginRegistry);
16818
16917
  const shouldRestartChannels = shouldRestartChannelsForPluginReload({
@@ -16868,30 +16967,52 @@ function applyGatewayRuntimeCapabilityState(params) {
16868
16967
  params.state.extensionRegistry = params.next.extensionRegistry;
16869
16968
  params.state.pluginChannelBindings = params.next.pluginChannelBindings;
16870
16969
  }
16970
+ async function applyGatewayPluginReload(params) {
16971
+ const result = await reloadServicePlugins({
16972
+ nextConfig: params.nextConfig,
16973
+ changedPaths: params.changedPaths,
16974
+ pluginRegistry: params.state.pluginRegistry,
16975
+ extensionRegistry: params.state.extensionRegistry,
16976
+ pluginChannelBindings: params.state.pluginChannelBindings,
16977
+ pluginGatewayHandles: params.state.pluginGatewayHandles,
16978
+ pluginGatewayLogger,
16979
+ logPluginGatewayDiagnostics
16980
+ });
16981
+ applyGatewayRuntimeCapabilityState({
16982
+ gateway: params.gateway,
16983
+ state: params.state,
16984
+ next: {
16985
+ pluginRegistry: result.pluginRegistry,
16986
+ extensionRegistry: result.extensionRegistry,
16987
+ pluginChannelBindings: result.pluginChannelBindings
16988
+ }
16989
+ });
16990
+ params.state.pluginUiMetadata = getPluginUiMetadataFromRegistry(result.pluginRegistry);
16991
+ params.state.pluginGatewayHandles = result.pluginGatewayHandles;
16992
+ params.getLiveUiNcpAgent()?.applyExtensionRegistry?.(result.extensionRegistry);
16993
+ return { restartChannels: result.restartChannels };
16994
+ }
16995
+ async function reloadGatewayPluginRuntimeForChanges(params) {
16996
+ const nextConfig = resolveConfigSecrets$2(loadConfig$2(), { configPath: params.gateway.runtimeConfigPath });
16997
+ const result = await applyGatewayPluginReload({
16998
+ gateway: params.gateway,
16999
+ state: params.state,
17000
+ getLiveUiNcpAgent: params.getLiveUiNcpAgent,
17001
+ nextConfig,
17002
+ changedPaths: params.changedPaths
17003
+ });
17004
+ if (result.restartChannels) await params.gateway.reloader.rebuildChannels(nextConfig, { start: true });
17005
+ return result;
17006
+ }
16871
17007
  function configureGatewayPluginRuntime(params) {
16872
17008
  params.gateway.reloader.setReloadPlugins(async ({ config: nextConfig, changedPaths }) => {
16873
- const result = await reloadServicePlugins({
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({
17009
+ const result = await applyGatewayPluginReload({
16884
17010
  gateway: params.gateway,
16885
17011
  state: params.state,
16886
- next: {
16887
- pluginRegistry: result.pluginRegistry,
16888
- extensionRegistry: result.extensionRegistry,
16889
- pluginChannelBindings: result.pluginChannelBindings
16890
- }
17012
+ getLiveUiNcpAgent: params.getLiveUiNcpAgent,
17013
+ nextConfig,
17014
+ changedPaths
16891
17015
  });
16892
- params.state.pluginUiMetadata = getPluginUiMetadataFromRegistry(result.pluginRegistry);
16893
- params.state.pluginGatewayHandles = result.pluginGatewayHandles;
16894
- params.getLiveUiNcpAgent()?.applyExtensionRegistry?.(result.extensionRegistry);
16895
17016
  if (result.restartChannels) console.log("Config reload: plugin channel gateways restarted.");
16896
17017
  return { restartChannels: result.restartChannels };
16897
17018
  });
@@ -16962,8 +17083,282 @@ async function cleanupGatewayRuntime(params) {
16962
17083
  setPluginRuntimeBridge(null);
16963
17084
  }
16964
17085
  //#endregion
17086
+ //#region src/cli/shared/services/plugin/service-plugin-dev-hot-reload.service.ts
17087
+ const DEV_PLUGIN_HOT_RELOAD_TARGETS_ENV = "NEXTCLAW_DEV_PLUGIN_HOT_RELOAD_TARGETS";
17088
+ function isRecord$2(value) {
17089
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
17090
+ }
17091
+ function readOptionalString(value) {
17092
+ if (typeof value !== "string") return null;
17093
+ const trimmed = value.trim();
17094
+ return trimmed.length > 0 ? trimmed : null;
17095
+ }
17096
+ function normalizeWatchPaths(value) {
17097
+ if (!Array.isArray(value)) return [];
17098
+ const watchPaths = [];
17099
+ for (const entry of value) {
17100
+ const normalized = readOptionalString(entry);
17101
+ if (!normalized) continue;
17102
+ const resolvedPath = resolve(normalized);
17103
+ if (!watchPaths.includes(resolvedPath)) watchPaths.push(resolvedPath);
17104
+ }
17105
+ return watchPaths;
17106
+ }
17107
+ function resolveDevPluginHotReloadTargets(rawValue = process.env[DEV_PLUGIN_HOT_RELOAD_TARGETS_ENV]) {
17108
+ if (typeof rawValue !== "string" || rawValue.trim().length === 0) return [];
17109
+ let parsed;
17110
+ try {
17111
+ parsed = JSON.parse(rawValue);
17112
+ } catch (error) {
17113
+ throw new Error(`[dev-plugin-hot-reload] failed to parse ${DEV_PLUGIN_HOT_RELOAD_TARGETS_ENV}: ${error instanceof Error ? error.message : String(error)}`);
17114
+ }
17115
+ if (!Array.isArray(parsed)) throw new Error(`[dev-plugin-hot-reload] ${DEV_PLUGIN_HOT_RELOAD_TARGETS_ENV} must be a JSON array`);
17116
+ const seenPluginIds = /* @__PURE__ */ new Set();
17117
+ const targets = [];
17118
+ for (const entry of parsed) {
17119
+ if (!isRecord$2(entry)) continue;
17120
+ const pluginId = readOptionalString(entry.pluginId);
17121
+ const pluginPath = readOptionalString(entry.pluginPath);
17122
+ const watchPaths = normalizeWatchPaths(entry.watchPaths);
17123
+ if (!pluginId || !pluginPath || watchPaths.length === 0) continue;
17124
+ if (seenPluginIds.has(pluginId)) throw new Error(`[dev-plugin-hot-reload] duplicate plugin target for "${pluginId}"`);
17125
+ seenPluginIds.add(pluginId);
17126
+ targets.push({
17127
+ pluginId,
17128
+ pluginPath: resolve(pluginPath),
17129
+ watchPaths
17130
+ });
17131
+ }
17132
+ return targets;
17133
+ }
17134
+ function startDevPluginHotReloadWatcher(params) {
17135
+ const targets = params.targets ?? resolveDevPluginHotReloadTargets();
17136
+ if (targets.length === 0) return;
17137
+ const pendingPluginIds = /* @__PURE__ */ new Set();
17138
+ let flushTimer = null;
17139
+ let reloadRunning = false;
17140
+ let reloadPending = false;
17141
+ const flushReload = async () => {
17142
+ if (reloadRunning) {
17143
+ reloadPending = true;
17144
+ return;
17145
+ }
17146
+ const pluginIds = [...pendingPluginIds];
17147
+ pendingPluginIds.clear();
17148
+ if (pluginIds.length === 0) return;
17149
+ reloadRunning = true;
17150
+ try {
17151
+ console.log(`[dev] Plugin dist updated: ${pluginIds.join(", ")}`);
17152
+ await params.reloadPlugins(pluginIds);
17153
+ console.log(`[dev] Plugin hot reload applied: ${pluginIds.join(", ")}`);
17154
+ } catch (error) {
17155
+ console.error(`[dev] Plugin hot reload failed: ${error instanceof Error ? error.message : String(error)}`);
17156
+ } finally {
17157
+ reloadRunning = false;
17158
+ if (reloadPending || pendingPluginIds.size > 0) {
17159
+ reloadPending = false;
17160
+ await flushReload();
17161
+ }
17162
+ }
17163
+ };
17164
+ const scheduleReload = (pluginId) => {
17165
+ pendingPluginIds.add(pluginId);
17166
+ if (flushTimer) clearTimeout(flushTimer);
17167
+ flushTimer = setTimeout(() => {
17168
+ flushTimer = null;
17169
+ flushReload();
17170
+ }, 150);
17171
+ };
17172
+ const watcher = chokidar.watch(targets.flatMap((entry) => entry.watchPaths), {
17173
+ ignoreInitial: true,
17174
+ awaitWriteFinish: {
17175
+ stabilityThreshold: 200,
17176
+ pollInterval: 50
17177
+ }
17178
+ });
17179
+ params.watcherRegistry.remember(watcher);
17180
+ watcher.on("all", (_event, changedPath) => {
17181
+ const normalizedChangedPath = resolve(changedPath);
17182
+ for (const target of targets) if (target.watchPaths.some((watchPath) => normalizedChangedPath === watchPath || normalizedChangedPath.startsWith(`${watchPath}${sep}`))) scheduleReload(target.pluginId);
17183
+ });
17184
+ console.log(`[dev] Plugin hot reload watcher: ${targets.map((entry) => entry.pluginId).join(", ")}`);
17185
+ }
17186
+ function wrapStartChannelsWithDevPluginHotReload(params) {
17187
+ return async () => {
17188
+ await params.startChannels();
17189
+ console.log(`[dev] Plugin hot reload watcher will arm after ${params.startupSettleMs}ms startup settle window.`);
17190
+ setTimeout(() => {
17191
+ if (!params.isRuntimeActive()) return;
17192
+ startDevPluginHotReloadWatcher({
17193
+ watcherRegistry: params.watcherRegistry,
17194
+ reloadPlugins: params.reloadPlugins
17195
+ });
17196
+ }, params.startupSettleMs).unref?.();
17197
+ };
17198
+ }
17199
+ //#endregion
17200
+ //#region src/cli/shared/stores/companion-runtime.store.ts
17201
+ var CompanionRuntimeStore = class {
17202
+ get path() {
17203
+ return resolve(getDataDir(), "run", "companion.json");
17204
+ }
17205
+ read = () => {
17206
+ if (!existsSync(this.path)) return null;
17207
+ try {
17208
+ return JSON.parse(readFileSync(this.path, "utf-8"));
17209
+ } catch {
17210
+ return null;
17211
+ }
17212
+ };
17213
+ write = (state) => {
17214
+ mkdirSync(resolve(this.path, ".."), { recursive: true });
17215
+ writeFileSync(this.path, JSON.stringify(state, null, 2));
17216
+ };
17217
+ clear = () => {
17218
+ if (existsSync(this.path)) rmSync(this.path, { force: true });
17219
+ };
17220
+ };
17221
+ const companionRuntimeStore = new CompanionRuntimeStore();
17222
+ //#endregion
17223
+ //#region src/cli/shared/services/ui/companion-runtime.service.ts
17224
+ const require$2 = createRequire(import.meta.url);
17225
+ var CompanionRuntimeService = class {
17226
+ constructor(runtimeStore = companionRuntimeStore, uiDiscoveryService = localUiDiscoveryService) {
17227
+ this.runtimeStore = runtimeStore;
17228
+ this.uiDiscoveryService = uiDiscoveryService;
17229
+ }
17230
+ getRunningState = () => {
17231
+ const state = this.runtimeStore.read();
17232
+ if (!state) return null;
17233
+ if (!isProcessRunning(state.pid)) {
17234
+ this.runtimeStore.clear();
17235
+ return null;
17236
+ }
17237
+ return state;
17238
+ };
17239
+ resolveDiscoveredBaseUrl = () => {
17240
+ return this.uiDiscoveryService.resolveApiBase();
17241
+ };
17242
+ applyConfig = async (config) => {
17243
+ if (!config.companion.enabled) {
17244
+ await this.ensureStopped();
17245
+ return;
17246
+ }
17247
+ await this.ensureStarted({ baseUrl: this.uiDiscoveryService.resolveLocalOrigin(config) });
17248
+ };
17249
+ updateEnabled = async (enabled, options = {}) => {
17250
+ const config = loadConfig(getConfigPath());
17251
+ const next = {
17252
+ ...config,
17253
+ companion: {
17254
+ ...config.companion,
17255
+ enabled
17256
+ }
17257
+ };
17258
+ saveConfig(next, getConfigPath());
17259
+ if (enabled) {
17260
+ const explicitBaseUrl = options.baseUrl?.trim();
17261
+ if (explicitBaseUrl) {
17262
+ await this.ensureStarted({ baseUrl: explicitBaseUrl });
17263
+ return next;
17264
+ }
17265
+ const discoveredBaseUrl = this.uiDiscoveryService.resolveApiBase();
17266
+ if (discoveredBaseUrl) await this.ensureStarted({ baseUrl: discoveredBaseUrl });
17267
+ return next;
17268
+ }
17269
+ await this.ensureStopped();
17270
+ return next;
17271
+ };
17272
+ ensureStarted = async (options) => {
17273
+ const baseUrl = options.baseUrl.trim().replace(/\/+$/, "");
17274
+ const runningState = this.getRunningState();
17275
+ if (runningState?.baseUrl === baseUrl) return runningState;
17276
+ if (runningState) {
17277
+ this.killProcess(runningState.pid, false);
17278
+ this.runtimeStore.clear();
17279
+ }
17280
+ const launchSpec = this.resolveLaunchSpec();
17281
+ const child = spawn(launchSpec.command, [
17282
+ ...launchSpec.args,
17283
+ "--base-url",
17284
+ baseUrl
17285
+ ], {
17286
+ detached: true,
17287
+ stdio: "ignore",
17288
+ env: {
17289
+ ...process.env,
17290
+ NEXTCLAW_COMPANION_RUNTIME_STATE_PATH: this.runtimeStore.path
17291
+ }
17292
+ });
17293
+ child.unref();
17294
+ return await this.waitForRunningState(baseUrl, child.pid ?? -1);
17295
+ };
17296
+ ensureStopped = async (options = {}) => {
17297
+ const state = this.runtimeStore.read();
17298
+ if (!state) return false;
17299
+ if (!isProcessRunning(state.pid)) {
17300
+ this.runtimeStore.clear();
17301
+ return false;
17302
+ }
17303
+ this.killProcess(state.pid, options.force === true);
17304
+ this.runtimeStore.clear();
17305
+ return true;
17306
+ };
17307
+ printStatus = (options = {}) => {
17308
+ const runningState = this.getRunningState();
17309
+ const config = loadConfig(getConfigPath());
17310
+ const view = runningState ? {
17311
+ configuredEnabled: config.companion.enabled,
17312
+ running: true,
17313
+ ...runningState
17314
+ } : {
17315
+ configuredEnabled: config.companion.enabled,
17316
+ running: false
17317
+ };
17318
+ if (options.json) {
17319
+ console.log(JSON.stringify(view, null, 2));
17320
+ return;
17321
+ }
17322
+ if (!runningState) {
17323
+ console.log(config.companion.enabled ? "Companion is enabled in config but is not running." : "Companion is disabled and not running.");
17324
+ return;
17325
+ }
17326
+ console.log(`Companion is running (pid ${runningState.pid}) at ${runningState.baseUrl}. Configured enabled: ${config.companion.enabled ? "yes" : "no"}.`);
17327
+ };
17328
+ printStarted = (state) => {
17329
+ console.log(`Started ${APP_NAME} companion (pid ${state.pid}) using ${state.baseUrl}.`);
17330
+ };
17331
+ printStopped = (stopped) => {
17332
+ console.log(stopped ? "Stopped companion process." : "Companion is not running.");
17333
+ };
17334
+ killProcess = (pid, force) => {
17335
+ process.kill(pid, force ? "SIGKILL" : "SIGTERM");
17336
+ };
17337
+ resolveLaunchSpec = () => {
17338
+ const packageJsonPath = require$2.resolve("@nextclaw/companion/package.json");
17339
+ const packageRoot = dirname(packageJsonPath);
17340
+ const mainPath = resolve(packageRoot, "dist", "src", "main.js");
17341
+ if (!existsSync(mainPath)) throw new Error(`Companion app build is missing at ${mainPath}. Build @nextclaw/companion first.`);
17342
+ return {
17343
+ command: createRequire(packageJsonPath)("electron"),
17344
+ args: [packageRoot]
17345
+ };
17346
+ };
17347
+ waitForRunningState = async (baseUrl, fallbackPid) => {
17348
+ const timeoutAt = Date.now() + 5e3;
17349
+ while (Date.now() < timeoutAt) {
17350
+ const state = this.getRunningState();
17351
+ if (state?.baseUrl === baseUrl) return state;
17352
+ await new Promise((resolvePromise) => setTimeout(resolvePromise, 100));
17353
+ }
17354
+ 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.");
17355
+ };
17356
+ };
17357
+ const companionRuntimeService = new CompanionRuntimeService();
17358
+ //#endregion
16965
17359
  //#region src/cli/shared/services/runtime/runtime-command.service.ts
16966
17360
  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;
17361
+ const DEV_PLUGIN_HOT_RELOAD_STARTUP_SETTLE_MS = 5e3;
16967
17362
  function createSkillsLoader(workspace) {
16968
17363
  const ctor = NextclawCore.SkillsLoader;
16969
17364
  if (!ctor) return null;
@@ -17008,38 +17403,16 @@ var RuntimeCommandService = class {
17008
17403
  runCliSubcommand: (args) => this.runCliSubcommand(args),
17009
17404
  installBuiltinSkill: (slug, force) => this.installBuiltinMarketplaceSkill(slug, force)
17010
17405
  }).createInstaller();
17011
- const { remoteAccess, runtimeControl } = createServiceUiHosts({
17012
- serviceCommands: this,
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,
17406
+ const uiStartup = await this.startGatewayUiShell({
17407
+ shellContext,
17034
17408
  applyLiveConfigReload,
17035
- ncpSessionService: ncpSessionRealtimeBridge.sessionService,
17036
- initializeAgentHomeDirectory: this.deps.initializeAgentHomeDirectory
17037
- }));
17038
- finalizeLocalUiStartup({
17039
- uiStartup,
17040
- setUiEventPublisher: (publish) => ncpSessionRealtimeBridge.setUiEventPublisher(publish),
17041
- uiConfig: shellContext.uiConfig
17409
+ bootstrapStatus,
17410
+ marketplaceInstaller,
17411
+ ncpSessionRealtimeBridge,
17412
+ getRuntimeConfig,
17413
+ getRuntimeState: () => runtimeState
17042
17414
  });
17415
+ await companionRuntimeService.applyConfig(shellContext.config);
17043
17416
  bootstrapStatus.markShellReady();
17044
17417
  await setImmediate$1();
17045
17418
  const gateway = measureStartupSync("service.create_gateway_startup_context", () => createGatewayStartupContext({
@@ -17057,33 +17430,14 @@ var RuntimeCommandService = class {
17057
17430
  const loadGatewayConfig = () => resolveConfigSecrets$1(loadConfig$1(), { configPath: gateway.runtimeConfigPath });
17058
17431
  const gatewayRuntimeState = createGatewayRuntimeState(gateway);
17059
17432
  runtimeState = gatewayRuntimeState;
17060
- uiStartup?.publish({
17061
- type: "config.updated",
17062
- payload: { path: "channels" }
17063
- });
17064
- uiStartup?.publish({
17065
- type: "config.updated",
17066
- payload: { path: "plugins" }
17433
+ gateway.reloader.setReloadCompanion(async ({ config: nextConfig }) => {
17434
+ await companionRuntimeService.applyConfig(nextConfig);
17067
17435
  });
17068
- configureGatewayPluginRuntime({
17436
+ await this.hydrateGatewayRuntime({
17069
17437
  gateway,
17070
- state: gatewayRuntimeState,
17071
- getLiveUiNcpAgent: () => this.liveUiNcpAgent
17438
+ gatewayRuntimeState,
17439
+ uiStartup
17072
17440
  });
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
17441
  const deferredGatewayStartupHooks = createDeferredGatewayStartupHooks({
17088
17442
  uiStartup,
17089
17443
  gateway,
@@ -17098,6 +17452,20 @@ var RuntimeCommandService = class {
17098
17452
  sessionManager: gateway.sessionManager
17099
17453
  })
17100
17454
  });
17455
+ deferredGatewayStartupHooks.startChannels = wrapStartChannelsWithDevPluginHotReload({
17456
+ startChannels: deferredGatewayStartupHooks.startChannels,
17457
+ watcherRegistry: this.fileWatchers,
17458
+ isRuntimeActive: () => Boolean(this.applyLiveConfigReload),
17459
+ reloadPlugins: async (pluginIds) => {
17460
+ await reloadGatewayPluginRuntimeForChanges({
17461
+ gateway,
17462
+ state: gatewayRuntimeState,
17463
+ getLiveUiNcpAgent: () => this.liveUiNcpAgent,
17464
+ changedPaths: pluginIds.map((pluginId) => `plugins.entries.${pluginId}.source`)
17465
+ });
17466
+ },
17467
+ startupSettleMs: DEV_PLUGIN_HOT_RELOAD_STARTUP_SETTLE_MS
17468
+ });
17101
17469
  await runConfiguredGatewayRuntime({
17102
17470
  uiStartup,
17103
17471
  bootstrapStatus,
@@ -17125,14 +17493,84 @@ var RuntimeCommandService = class {
17125
17493
  this.applyLiveConfigReload = null;
17126
17494
  this.liveUiNcpAgent = null;
17127
17495
  },
17128
- clearRealtimeBridge: () => ncpSessionRealtimeBridge.clear(),
17496
+ clearRealtimeBridge: () => {
17497
+ ncpSessionRealtimeBridge.clear();
17498
+ },
17129
17499
  uiStartup,
17130
17500
  remoteModule: gateway.remoteModule,
17131
17501
  runtimeState
17132
17502
  })
17133
17503
  });
17504
+ await companionRuntimeService.ensureStopped();
17134
17505
  logStartupTrace("service.start_gateway.end");
17135
17506
  };
17507
+ startGatewayUiShell = async (params) => {
17508
+ const { applyLiveConfigReload, bootstrapStatus, getRuntimeConfig, getRuntimeState, marketplaceInstaller, ncpSessionRealtimeBridge, shellContext } = params;
17509
+ const { remoteAccess, runtimeControl, runtimeUpdate } = createServiceUiHosts({
17510
+ serviceCommands: this,
17511
+ requestRestart: this.deps.requestRestart,
17512
+ uiConfig: shellContext.uiConfig,
17513
+ remoteModule: shellContext.remoteModule
17514
+ });
17515
+ const uiStartup = await measureStartupAsync("service.start_ui_shell", async () => await startUiShell({
17516
+ uiConfig: shellContext.uiConfig,
17517
+ uiStaticDir: shellContext.uiStaticDir,
17518
+ cronService: shellContext.cron,
17519
+ getConfig: getRuntimeConfig,
17520
+ configPath: getConfigPath$1(),
17521
+ productVersion: getPackageVersion$1(),
17522
+ getPluginChannelBindings: () => getRuntimeState()?.pluginChannelBindings ?? [],
17523
+ getPluginUiMetadata: () => getRuntimeState()?.pluginUiMetadata ?? [],
17524
+ marketplace: {
17525
+ apiBaseUrl: process.env.NEXTCLAW_MARKETPLACE_API_BASE,
17526
+ installer: marketplaceInstaller
17527
+ },
17528
+ remoteAccess,
17529
+ runtimeControl,
17530
+ runtimeUpdate,
17531
+ getBootstrapStatus: () => bootstrapStatus.getStatus(),
17532
+ openBrowserWindow: shellContext.uiConfig.open,
17533
+ applyLiveConfigReload,
17534
+ ncpSessionService: ncpSessionRealtimeBridge.sessionService,
17535
+ initializeAgentHomeDirectory: this.deps.initializeAgentHomeDirectory
17536
+ }));
17537
+ finalizeLocalUiStartup({
17538
+ uiStartup,
17539
+ setUiEventPublisher: (publish) => ncpSessionRealtimeBridge.setUiEventPublisher(publish),
17540
+ uiConfig: shellContext.uiConfig
17541
+ });
17542
+ return uiStartup;
17543
+ };
17544
+ hydrateGatewayRuntime = async (params) => {
17545
+ const { gateway, gatewayRuntimeState, uiStartup } = params;
17546
+ uiStartup?.publish({
17547
+ type: "config.updated",
17548
+ payload: { path: "channels" }
17549
+ });
17550
+ uiStartup?.publish({
17551
+ type: "config.updated",
17552
+ payload: { path: "plugins" }
17553
+ });
17554
+ configureGatewayPluginRuntime({
17555
+ gateway,
17556
+ state: gatewayRuntimeState,
17557
+ getLiveUiNcpAgent: () => this.liveUiNcpAgent
17558
+ });
17559
+ console.log("✓ Capability hydration: scheduled in background");
17560
+ await measureStartupAsync("service.start_gateway_support_services", async () => await startGatewayRuntimeSupport({
17561
+ cronJobs: gateway.cron.status().jobs,
17562
+ remoteModule: gateway.remoteModule,
17563
+ watchConfigFile: () => watchServiceConfigFile({
17564
+ configPath: resolve(getConfigPath$1()),
17565
+ watcherRegistry: this.fileWatchers,
17566
+ scheduleReload: (reason) => gateway.reloader.scheduleReload(reason)
17567
+ }),
17568
+ startCron: () => gateway.cron.start(),
17569
+ cronStorePath: resolve(join(NextclawCore.getDataDir(), "cron", "jobs.json")),
17570
+ reloadCronStore: () => gateway.cron.reloadFromStore(),
17571
+ watcherRegistry: this.fileWatchers
17572
+ }));
17573
+ };
17136
17574
  normalizeOptionalString = (value) => {
17137
17575
  if (typeof value !== "string") return;
17138
17576
  return value.trim() || void 0;
@@ -18167,7 +18605,7 @@ var MacosLaunchAgentAutostartService = class {
18167
18605
  ` <string>${this.escapeXml(homeDir)}</string>`,
18168
18606
  " </dict>",
18169
18607
  " <key>RunAtLoad</key><true/>",
18170
- " <key>KeepAlive</key><true/>",
18608
+ " <key>KeepAlive</key><false/>",
18171
18609
  ` <key>StandardOutPath</key><string>${this.escapeXml(stdoutPath)}</string>`,
18172
18610
  ` <key>StandardErrorPath</key><string>${this.escapeXml(stderrPath)}</string>`,
18173
18611
  "</dict>",
@@ -19035,6 +19473,30 @@ var RuntimeRestartRequestService = class {
19035
19473
  };
19036
19474
  };
19037
19475
  //#endregion
19476
+ //#region src/cli/shared/utils/runtime-helpers.ts
19477
+ function resolveSkillsInstallWorkdir(params) {
19478
+ if (params.explicitWorkdir) return expandHome(params.explicitWorkdir);
19479
+ return getWorkspacePath(params.configuredWorkspace);
19480
+ }
19481
+ function parseStartTimeoutMs(value) {
19482
+ if (value === void 0) return;
19483
+ const parsed = Number(value);
19484
+ if (!Number.isFinite(parsed) || parsed <= 0) {
19485
+ console.error("Invalid --start-timeout value. Provide milliseconds (e.g. 45000).");
19486
+ process.exit(1);
19487
+ }
19488
+ return Math.floor(parsed);
19489
+ }
19490
+ function resolveManagedServiceUiOverrides(params) {
19491
+ const uiOverrides = {
19492
+ enabled: true,
19493
+ host: params.forcedPublicHost,
19494
+ open: false
19495
+ };
19496
+ if (params.uiPort) uiOverrides.port = Number(params.uiPort);
19497
+ return uiOverrides;
19498
+ }
19499
+ //#endregion
19038
19500
  //#region src/cli/commands/skills/marketplace-command-options.utils.ts
19039
19501
  function buildMarketplacePublishOptions(options) {
19040
19502
  const { apiBaseUrl, author, description, dir, homepage, meta, name, packageName, publishedAt, scope, slug, sourceRepo, summary, tag, token, updatedAt } = options;
@@ -20079,17 +20541,31 @@ var RestartCommands = class {
20079
20541
  uiPort: opts.uiPort,
20080
20542
  forcedPublicHost: this.deps.forcedPublicHost
20081
20543
  });
20544
+ const targetUi = resolveUiConfig(loadConfig(), uiOverrides);
20082
20545
  const state = managedServiceStateStore.read();
20083
20546
  if (state && isProcessRunning(state.pid)) {
20084
20547
  console.log(`Restarting ${APP_NAME}...`);
20085
20548
  await this.deps.runtimeCommandService.stopService();
20086
20549
  } else {
20550
+ const foregroundRuntime = localUiRuntimeStore.read();
20551
+ const foregroundMatchesTarget = Boolean(foregroundRuntime && isProcessRunning(foregroundRuntime.pid) && foregroundRuntime.uiPort === targetUi.port);
20552
+ if (foregroundRuntime && foregroundMatchesTarget) {
20553
+ if (!await this.restartForegroundRuntime(foregroundRuntime.pid)) return;
20554
+ await this.deps.startCommands.run(opts);
20555
+ return;
20556
+ }
20087
20557
  if (state) {
20088
20558
  managedServiceStateStore.clear();
20089
20559
  console.log("Service state was stale and has been cleaned up.");
20090
20560
  }
20091
20561
  const unmanagedHealthyServiceMessage = await describeUnmanagedHealthyTargetMessage({ uiOverrides });
20092
20562
  if (unmanagedHealthyServiceMessage) {
20563
+ const adoptedRuntimePid = this.resolveAdoptableForegroundRuntimePid(targetUi.port);
20564
+ if (adoptedRuntimePid) {
20565
+ if (!await this.restartForegroundRuntime(adoptedRuntimePid)) return;
20566
+ await this.deps.startCommands.run(opts);
20567
+ return;
20568
+ }
20093
20569
  console.error(`Error: Cannot restart ${APP_NAME} because the target UI/API port is already served by a healthy unmanaged instance.`);
20094
20570
  console.error(unmanagedHealthyServiceMessage);
20095
20571
  return;
@@ -20098,6 +20574,40 @@ var RestartCommands = class {
20098
20574
  }
20099
20575
  await this.deps.startCommands.run(opts);
20100
20576
  };
20577
+ restartForegroundRuntime = async (pid) => {
20578
+ console.log(`Restarting ${APP_NAME} foreground runtime (PID ${pid})...`);
20579
+ try {
20580
+ process.kill(pid, "SIGTERM");
20581
+ } catch (error) {
20582
+ console.error(`Failed to stop foreground runtime: ${String(error)}`);
20583
+ return false;
20584
+ }
20585
+ if (!await waitForExit(pid, 3e3)) {
20586
+ try {
20587
+ process.kill(pid, "SIGKILL");
20588
+ } catch (error) {
20589
+ console.error(`Failed to force stop foreground runtime: ${String(error)}`);
20590
+ return false;
20591
+ }
20592
+ if (!await waitForExit(pid, 2e3)) {
20593
+ console.error(`Failed to stop foreground runtime PID ${pid}.`);
20594
+ return false;
20595
+ }
20596
+ }
20597
+ localUiRuntimeStore.clearIfOwnedByProcess(pid);
20598
+ console.log(`✓ ${APP_NAME} foreground runtime stopped`);
20599
+ return true;
20600
+ };
20601
+ resolveAdoptableForegroundRuntimePid = (port) => {
20602
+ const listeningProcess = findListeningProcessByPort(port);
20603
+ if (!listeningProcess || !isProcessRunning(listeningProcess.pid)) return null;
20604
+ return this.isAdoptableNextclawRuntimeCommand(listeningProcess.command) ? listeningProcess.pid : null;
20605
+ };
20606
+ isAdoptableNextclawRuntimeCommand = (command) => {
20607
+ const normalized = command?.trim() ?? "";
20608
+ if (!normalized) return false;
20609
+ 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"));
20610
+ };
20101
20611
  };
20102
20612
  //#endregion
20103
20613
  //#region src/cli/commands/serve/index.ts
@@ -20127,6 +20637,74 @@ var StopCommands = class {
20127
20637
  };
20128
20638
  };
20129
20639
  //#endregion
20640
+ //#region src/cli/commands/companion/services/companion-process.service.ts
20641
+ var CompanionProcessService = class {
20642
+ constructor(runtimeService = companionRuntimeService) {
20643
+ this.runtimeService = runtimeService;
20644
+ }
20645
+ start = async (options = {}) => {
20646
+ const state = await this.runtimeService.ensureStarted({ baseUrl: this.resolveBaseUrl(options) });
20647
+ this.runtimeService.printStarted(state);
20648
+ };
20649
+ status = async (options = {}) => {
20650
+ this.runtimeService.printStatus(options);
20651
+ };
20652
+ stop = async (options = {}) => {
20653
+ const stopped = await this.runtimeService.ensureStopped(options);
20654
+ this.runtimeService.printStopped(stopped);
20655
+ };
20656
+ enable = async (options = {}) => {
20657
+ const nextConfig = await this.runtimeService.updateEnabled(true, options);
20658
+ this.printConfigEnabled(nextConfig, options.baseUrl);
20659
+ };
20660
+ disable = async (_options = {}) => {
20661
+ const nextConfig = await this.runtimeService.updateEnabled(false);
20662
+ console.log(nextConfig.companion.enabled ? "Companion remains enabled." : "Companion feature disabled. It will stay off until you enable it again.");
20663
+ };
20664
+ resolveBaseUrl = (options) => {
20665
+ const explicitBaseUrl = options.baseUrl?.trim();
20666
+ if (explicitBaseUrl) return explicitBaseUrl.replace(/\/+$/, "");
20667
+ const discoveredBaseUrl = this.runtimeService.resolveDiscoveredBaseUrl();
20668
+ if (discoveredBaseUrl) return discoveredBaseUrl;
20669
+ const runningState = this.runtimeService.getRunningState();
20670
+ if (runningState) return runningState.baseUrl;
20671
+ throw new Error("Cannot resolve NextClaw UI base URL. Start NextClaw first or pass --base-url.");
20672
+ };
20673
+ printConfigEnabled = (config, baseUrl) => {
20674
+ if (this.runtimeService.getRunningState()) {
20675
+ console.log("Companion feature enabled and companion started.");
20676
+ return;
20677
+ }
20678
+ if (baseUrl?.trim()) {
20679
+ console.log("Companion feature enabled.");
20680
+ return;
20681
+ }
20682
+ 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.");
20683
+ };
20684
+ };
20685
+ //#endregion
20686
+ //#region src/cli/commands/companion/index.ts
20687
+ var CompanionCommands = class {
20688
+ constructor(companionProcessService = new CompanionProcessService()) {
20689
+ this.companionProcessService = companionProcessService;
20690
+ }
20691
+ start = async (options = {}) => {
20692
+ await this.companionProcessService.start(options);
20693
+ };
20694
+ enable = async (options = {}) => {
20695
+ await this.companionProcessService.enable(options);
20696
+ };
20697
+ disable = async (options = {}) => {
20698
+ await this.companionProcessService.disable(options);
20699
+ };
20700
+ status = async (options = {}) => {
20701
+ await this.companionProcessService.status(options);
20702
+ };
20703
+ stop = async (options = {}) => {
20704
+ await this.companionProcessService.stop(options);
20705
+ };
20706
+ };
20707
+ //#endregion
20130
20708
  //#region src/cli/app/runtime.ts
20131
20709
  const LOGO = "🤖";
20132
20710
  const FORCED_PUBLIC_UI_HOST = "0.0.0.0";
@@ -20158,6 +20736,7 @@ var CliRuntime = class {
20158
20736
  restartCommands;
20159
20737
  serveCommands;
20160
20738
  stopCommands;
20739
+ companionCommands;
20161
20740
  constructor(options = {}) {
20162
20741
  logStartupTrace("cli.runtime.constructor.begin");
20163
20742
  this.logo = options.logo ?? "🤖";
@@ -20190,6 +20769,7 @@ var CliRuntime = class {
20190
20769
  forcedPublicHost: FORCED_PUBLIC_UI_HOST
20191
20770
  }));
20192
20771
  this.stopCommands = measureStartupSync("cli.runtime.stop_commands", () => new StopCommands({ runtimeCommandService: this.runtimeCommandService }));
20772
+ this.companionCommands = measureStartupSync("cli.runtime.companion_commands", () => new CompanionCommands());
20193
20773
  this.serviceCommands = measureStartupSync("cli.runtime.service_commands", () => new ServiceCommands());
20194
20774
  this.configCommands = measureStartupSync("cli.runtime.config_commands", () => new ConfigCommands({ requestRestart: (params) => this.requestRestart(params) }));
20195
20775
  this.mcpCommands = measureStartupSync("cli.runtime.mcp_commands", () => new McpCommands());
@@ -20422,6 +21002,21 @@ var CliRuntime = class {
20422
21002
  stop = async () => {
20423
21003
  await this.stopCommands.run();
20424
21004
  };
21005
+ companionStart = async (opts = {}) => {
21006
+ await this.companionCommands.start(opts);
21007
+ };
21008
+ companionEnable = async (opts = {}) => {
21009
+ await this.companionCommands.enable(opts);
21010
+ };
21011
+ companionDisable = async (opts = {}) => {
21012
+ await this.companionCommands.disable(opts);
21013
+ };
21014
+ companionStatus = async (opts = {}) => {
21015
+ await this.companionCommands.status(opts);
21016
+ };
21017
+ companionStop = async (opts = {}) => {
21018
+ await this.companionCommands.stop(opts);
21019
+ };
20425
21020
  agent = async (opts) => {
20426
21021
  const configPath = getConfigPath();
20427
21022
  const config = resolveConfigSecrets(loadConfig(), { configPath });
@@ -20594,6 +21189,16 @@ function registerAgentsCommands(program, runtime) {
20594
21189
  agents.command("remove <agentId>").description("Remove an agent").option("--json", "Output JSON", false).action(async (agentId, opts) => runtime.agentsRemove(agentId, opts));
20595
21190
  }
20596
21191
  //#endregion
21192
+ //#region src/cli/app/register-companion-commands.ts
21193
+ function registerCompanionCommands(program, runtime) {
21194
+ const companion = program.command("companion").description("Manage the standalone NextClaw companion shell");
21195
+ 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));
21196
+ 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));
21197
+ companion.command("disable").description("Disable the companion feature and stop any running companion process").action(async (opts) => runtime.companionDisable(opts));
21198
+ companion.command("status").description("Show companion process status").option("--json", "Output JSON", false).action(async (opts) => runtime.companionStatus(opts));
21199
+ companion.command("stop").description("Stop the companion process").option("--force", "Force kill the companion process", false).action(async (opts) => runtime.companionStop(opts));
21200
+ }
21201
+ //#endregion
20597
21202
  //#region src/cli/app/service-command-registration.service.ts
20598
21203
  const registerServiceCommands = ({ program, getServiceCommands }) => {
20599
21204
  const service = program.command("service").description("Manage host service integrations");
@@ -20649,6 +21254,7 @@ program.command("start").description(`Start the ${APP_NAME} gateway + UI in the
20649
21254
  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
21255
  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
21256
  program.command("stop").description(`Stop the ${APP_NAME} background service`).action(async () => runtime.stop());
21257
+ registerCompanionCommands(program, runtime);
20652
21258
  registerServiceCommands({
20653
21259
  program,
20654
21260
  getServiceCommands
@@ -20699,6 +21305,6 @@ const logs = program.command("logs").description("Inspect local runtime logs");
20699
21305
  logs.command("path").description("Show local log file paths").action(() => runtime.logsPath());
20700
21306
  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
21307
  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);
21308
+ await program.parseAsync(process.argv);
20703
21309
  //#endregion
20704
21310
  export {};