nextclaw 0.18.12-beta.2 → 0.18.12-beta.20

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