nextclaw 0.18.12-beta.9 → 0.18.12

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 (51) hide show
  1. package/dist/cli/app/index.js +300 -140
  2. package/package.json +17 -17
  3. package/ui-dist/assets/api-Dai6UR3J.js +15 -0
  4. package/ui-dist/assets/app-manager-provider-BZr5VxCe.js +1 -0
  5. package/ui-dist/assets/{app-navigation.config-CMoWvFEI.js → app-navigation.config-BjIj_FLm.js} +1 -1
  6. package/ui-dist/assets/channels-list-page-L6FFtRYn.js +8 -0
  7. package/ui-dist/assets/{chat-CA3aRmhx.js → chat-ZQIVJChB.js} +6 -6
  8. package/ui-dist/assets/{chat-page-gdSN6Pr6.js → chat-page-CR1yI96r.js} +1 -1
  9. package/ui-dist/assets/desktop-update-config-AXzb7OEa.js +1 -0
  10. package/ui-dist/assets/{dialog-csshWetU.js → dialog-DgybjpeU.js} +1 -1
  11. package/ui-dist/assets/{dist-Bl94Ahwx.js → dist-CxcPOISF.js} +1 -1
  12. package/ui-dist/assets/{es2015-JCM5-KtW.js → es2015-BVRlEE06.js} +1 -1
  13. package/ui-dist/assets/index-B7RsQ-ne.js +2 -0
  14. package/ui-dist/assets/index-D8MKmXtO.css +1 -0
  15. package/ui-dist/assets/marketplace-page-Bj55-6F2.js +1 -0
  16. package/ui-dist/assets/{marketplace-page-DxlxHCFm.js → marketplace-page-ClRW-W3g.js} +2 -2
  17. package/ui-dist/assets/mcp-marketplace-page-DtngnIi0.js +40 -0
  18. package/ui-dist/assets/mcp-marketplace-page-_Wu2VnHy.js +1 -0
  19. package/ui-dist/assets/{model-config-PccJ9XyH.js → model-config-D_y8F0j6.js} +1 -1
  20. package/ui-dist/assets/{notice-card-CCgk6FvF.js → notice-card-uzwjFyML.js} +1 -1
  21. package/ui-dist/assets/{popover-YAsxDBhY.js → popover-C8tMB7tR.js} +1 -1
  22. package/ui-dist/assets/{provider-scoped-model-input-CzpF7cug.js → provider-scoped-model-input-ORZutTDv.js} +1 -1
  23. package/ui-dist/assets/{providers-list-8qDMER8o.js → providers-list-DSc3d8me.js} +1 -1
  24. package/ui-dist/assets/remote-rWiu3cys.js +1 -0
  25. package/ui-dist/assets/runtime-config-page-B4uSax1I.js +1 -0
  26. package/ui-dist/assets/{search-config-D3a65l3r.js → search-config-CaqqlsdW.js} +1 -1
  27. package/ui-dist/assets/{secrets-config-CoMlR_7i.js → secrets-config-llf5ROde.js} +2 -2
  28. package/ui-dist/assets/{select-DIZrwsKU.js → select-uO-zhYsH.js} +1 -1
  29. package/ui-dist/assets/{sessions-config-page-Cc0TJStn.js → sessions-config-page-BqOXte9x.js} +2 -2
  30. package/ui-dist/assets/{setting-row-DiQyrE81.js → setting-row-BIiXR4hx.js} +1 -1
  31. package/ui-dist/assets/{tag-chip-C3wDBe_-.js → tag-chip-DVbgpsYW.js} +1 -1
  32. package/ui-dist/assets/theme-provider-BU77FNSB.js +1 -0
  33. package/ui-dist/assets/{tooltip-Dq5Xehpk.js → tooltip-CvAtG-kT.js} +1 -1
  34. package/ui-dist/assets/use-config-D2QgG7qc.js +1 -0
  35. package/ui-dist/assets/{use-confirm-dialog-DBoV5n5P.js → use-confirm-dialog-BBClFV8E.js} +1 -1
  36. package/ui-dist/assets/{use-infinite-scroll-loader-JAicqVC5.js → use-infinite-scroll-loader-CWzpUecQ.js} +1 -1
  37. package/ui-dist/assets/{use-viewport-layout-BX3XqzJ4.js → use-viewport-layout-C6EN0_eq.js} +1 -1
  38. package/ui-dist/index.html +16 -16
  39. package/ui-dist/assets/api-BcqDx0tm.js +0 -15
  40. package/ui-dist/assets/app-manager-provider-DVYBjif-.js +0 -1
  41. package/ui-dist/assets/channels-list-page-CsoI4OJm.js +0 -8
  42. package/ui-dist/assets/desktop-update-config-CD6-2PfI.js +0 -1
  43. package/ui-dist/assets/index-BTDFuKka.js +0 -2
  44. package/ui-dist/assets/index-CUmk8xFK.css +0 -1
  45. package/ui-dist/assets/marketplace-page-DJGDpTAo.js +0 -1
  46. package/ui-dist/assets/mcp-marketplace-page-5UjYRWOR.js +0 -40
  47. package/ui-dist/assets/mcp-marketplace-page-C1XaHZZO.js +0 -1
  48. package/ui-dist/assets/remote-D4TtLPAp.js +0 -1
  49. package/ui-dist/assets/runtime-config-page-D-4c5H5z.js +0 -1
  50. package/ui-dist/assets/theme-provider-aOmrJ9J6.js +0 -1
  51. package/ui-dist/assets/use-config-BQJjq1mP.js +0 -1
@@ -2,7 +2,7 @@
2
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;
@@ -5062,6 +5063,14 @@ function parseSessionKey(sessionKey) {
5062
5063
  };
5063
5064
  }
5064
5065
  //#endregion
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;
5072
+ }
5073
+ //#endregion
5065
5074
  //#region src/cli/shared/utils/startup-trace.ts
5066
5075
  const STARTUP_TRACE_ENABLED = process.env.NEXTCLAW_STARTUP_TRACE === "1";
5067
5076
  const STARTUP_TRACE_ORIGIN_MS = Date.now();
@@ -5685,11 +5694,9 @@ const readInstalledFirstPartyPluginMatches = (workspaceExtensionsDir) => {
5685
5694
  const workspacePackage = workspacePackageByName.get(packageName);
5686
5695
  if (!workspacePackage) continue;
5687
5696
  matches.push({
5688
- pluginId: workspacePackage.pluginId,
5689
5697
  packageName,
5690
5698
  workspaceDir: workspacePackage.dir,
5691
- installPath: packageDir,
5692
- supportsDevelopmentSource: workspacePackage.supportsDevelopmentSource
5699
+ installPath: packageDir
5693
5700
  });
5694
5701
  }
5695
5702
  return matches;
@@ -5709,35 +5716,6 @@ const findWorkspacePackageForInstallRecord = (installRecord, workspacePackages,
5709
5716
  if (installPathCandidates.size === 0) return;
5710
5717
  return workspacePackages.find((workspacePackage) => installPathCandidates.has(path.resolve(workspacePackage.dir)));
5711
5718
  };
5712
- const buildDevelopmentSourceEntryDefaults = (config, workspacePackages, installedPluginMatches) => {
5713
- const packageByName = new Map(workspacePackages.map((entry) => [entry.packageName, entry]));
5714
- const nextEntries = { ...config.plugins.entries ?? {} };
5715
- let didDefaultDevelopmentSource = false;
5716
- for (const installedPlugin of installedPluginMatches) {
5717
- if (!installedPlugin.supportsDevelopmentSource) continue;
5718
- const existingEntry = nextEntries[installedPlugin.pluginId];
5719
- if (existingEntry?.source) continue;
5720
- nextEntries[installedPlugin.pluginId] = {
5721
- ...existingEntry,
5722
- source: "development"
5723
- };
5724
- didDefaultDevelopmentSource = true;
5725
- }
5726
- for (const [pluginId, installRecord] of Object.entries(config.plugins.installs ?? {})) {
5727
- if (!findWorkspacePackageForInstallRecord(installRecord, workspacePackages, packageByName)?.supportsDevelopmentSource) continue;
5728
- const existingEntry = nextEntries[pluginId];
5729
- if (existingEntry?.source) continue;
5730
- nextEntries[pluginId] = {
5731
- ...existingEntry,
5732
- source: "development"
5733
- };
5734
- didDefaultDevelopmentSource = true;
5735
- }
5736
- return {
5737
- didDefaultDevelopmentSource,
5738
- nextEntries
5739
- };
5740
- };
5741
5719
  const resolveDevFirstPartyPluginLoadPaths = (config, workspaceExtensionsDir) => {
5742
5720
  const rootDir = resolveDevFirstPartyPluginDir(workspaceExtensionsDir);
5743
5721
  if (!rootDir) return [];
@@ -5787,18 +5765,15 @@ const resolveDevFirstPartyPluginInstallRoots = (config, workspaceExtensionsDir)
5787
5765
  const applyDevFirstPartyPluginLoadPaths = (config, workspaceExtensionsDir) => {
5788
5766
  const rootDir = resolveDevFirstPartyPluginDir(workspaceExtensionsDir);
5789
5767
  if (!rootDir) return config;
5790
- const workspacePackages = readWorkspacePluginPackages(rootDir);
5791
- if (workspacePackages.length === 0) return config;
5792
- const installedPluginMatches = readInstalledFirstPartyPluginMatches(rootDir);
5768
+ if (readWorkspacePluginPackages(rootDir).length === 0) return config;
5769
+ readInstalledFirstPartyPluginMatches(rootDir);
5793
5770
  const devLoadPaths = resolveDevFirstPartyPluginLoadPaths(config, rootDir);
5794
5771
  if (devLoadPaths.length === 0) return config;
5795
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);
5796
- const { didDefaultDevelopmentSource, nextEntries } = buildDevelopmentSourceEntryDefaults(config, workspacePackages, installedPluginMatches);
5797
5773
  return {
5798
5774
  ...config,
5799
5775
  plugins: {
5800
5776
  ...config.plugins,
5801
- entries: didDefaultDevelopmentSource ? nextEntries : config.plugins.entries,
5802
5777
  load: {
5803
5778
  ...config.plugins.load,
5804
5779
  paths: mergedLoadPaths
@@ -5809,10 +5784,10 @@ const applyDevFirstPartyPluginLoadPaths = (config, workspaceExtensionsDir) => {
5809
5784
  //#endregion
5810
5785
  //#region src/cli/commands/plugin/development-source/dev-plugin-overrides.utils.ts
5811
5786
  const DEV_PLUGIN_OVERRIDES_ENV = "NEXTCLAW_DEV_PLUGIN_OVERRIDES";
5812
- function isRecord$6(value) {
5787
+ function isRecord$7(value) {
5813
5788
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
5814
5789
  }
5815
- function readOptionalString$6(value) {
5790
+ function readOptionalString$7(value) {
5816
5791
  if (typeof value !== "string") return;
5817
5792
  return value.trim() || void 0;
5818
5793
  }
@@ -5838,9 +5813,9 @@ function assertOverridePluginReadable(override) {
5838
5813
  }
5839
5814
  }
5840
5815
  function readOverrideRecord(value, index) {
5841
- if (!isRecord$6(value)) throw new Error(`[dev-plugin-override] override[${index}] must be an object`);
5842
- const pluginId = readOptionalString$6(value.pluginId);
5843
- 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);
5844
5819
  const source = value.source === "development" ? "development" : "production";
5845
5820
  if (!pluginId || !pluginPath) throw new Error(`[dev-plugin-override] override[${index}] requires pluginId and pluginPath`);
5846
5821
  const normalized = {
@@ -5897,7 +5872,7 @@ function resolveDevPluginOverrideInstallRoots(config, overrides) {
5897
5872
  const installRoots = [];
5898
5873
  for (const override of overrides) {
5899
5874
  const installRecord = config.plugins.installs?.[override.pluginId];
5900
- const installPath = readOptionalString$6(installRecord?.installPath);
5875
+ const installPath = readOptionalString$7(installRecord?.installPath);
5901
5876
  if (!installPath || installRoots.includes(installPath)) continue;
5902
5877
  installRoots.push(installPath);
5903
5878
  }
@@ -8360,13 +8335,13 @@ var AgentCommands = class {
8360
8335
  };
8361
8336
  //#endregion
8362
8337
  //#region src/cli/commands/ncp/features/runtime/ncp-asset-tools.ts
8363
- function readOptionalString$5(value) {
8338
+ function readOptionalString$6(value) {
8364
8339
  if (typeof value !== "string") return null;
8365
8340
  const trimmed = value.trim();
8366
8341
  return trimmed.length > 0 ? trimmed : null;
8367
8342
  }
8368
8343
  function readOptionalBase64Bytes(value) {
8369
- const base64 = readOptionalString$5(value);
8344
+ const base64 = readOptionalString$6(value);
8370
8345
  if (!base64) return null;
8371
8346
  try {
8372
8347
  return Buffer.from(base64, "base64");
@@ -8417,18 +8392,18 @@ var AssetPutTool = class {
8417
8392
  this.contentBasePath = contentBasePath;
8418
8393
  }
8419
8394
  validateArgs = (args) => {
8420
- const path = readOptionalString$5(args.path);
8421
- const bytesBase64 = readOptionalString$5(args.bytesBase64);
8422
- 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);
8423
8398
  if (path && bytesBase64) return ["Provide either path, or bytesBase64 + fileName, not both."];
8424
8399
  if (path) return [];
8425
8400
  if (bytesBase64) return fileName ? [] : ["fileName is required when using bytesBase64."];
8426
8401
  return ["Provide either path, or bytesBase64 + fileName."];
8427
8402
  };
8428
8403
  execute = async (args) => {
8429
- const path = readOptionalString$5(args?.path);
8430
- const fileName = readOptionalString$5(args?.fileName);
8431
- 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);
8432
8407
  const bytes = readOptionalBase64Bytes(args?.bytesBase64);
8433
8408
  if (path) return {
8434
8409
  ok: true,
@@ -8471,8 +8446,8 @@ var AssetExportTool = class {
8471
8446
  this.assetStore = assetStore;
8472
8447
  }
8473
8448
  execute = async (args) => {
8474
- const assetUri = readOptionalString$5(args?.assetUri);
8475
- const targetPath = readOptionalString$5(args?.targetPath);
8449
+ const assetUri = readOptionalString$6(args?.assetUri);
8450
+ const targetPath = readOptionalString$6(args?.targetPath);
8476
8451
  if (!assetUri || !targetPath) throw new Error("asset_export requires assetUri and targetPath.");
8477
8452
  return {
8478
8453
  ok: true,
@@ -8498,7 +8473,7 @@ var AssetStatTool = class {
8498
8473
  this.contentBasePath = contentBasePath;
8499
8474
  }
8500
8475
  execute = async (args) => {
8501
- const assetUri = readOptionalString$5(args?.assetUri);
8476
+ const assetUri = readOptionalString$6(args?.assetUri);
8502
8477
  if (!assetUri) throw new Error("asset_stat requires assetUri.");
8503
8478
  const record = await this.assetStore.statRecord(assetUri);
8504
8479
  if (!record) return {
@@ -8530,11 +8505,11 @@ function normalizeString(value) {
8530
8505
  const trimmed = value.trim();
8531
8506
  return trimmed.length > 0 ? trimmed : null;
8532
8507
  }
8533
- function isRecord$5(value) {
8508
+ function isRecord$6(value) {
8534
8509
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
8535
8510
  }
8536
8511
  function cloneMetadata(value) {
8537
- return isRecord$5(value) ? structuredClone(value) : void 0;
8512
+ return isRecord$6(value) ? structuredClone(value) : void 0;
8538
8513
  }
8539
8514
  function readStringArray(value) {
8540
8515
  if (!Array.isArray(value)) return null;
@@ -9025,7 +9000,7 @@ function readRequiredString$1(params, key) {
9025
9000
  if (typeof value !== "string" || value.trim().length === 0) throw new Error(`${key} must be a non-empty string.`);
9026
9001
  return value.trim();
9027
9002
  }
9028
- function readOptionalString$4(params, key) {
9003
+ function readOptionalString$5(params, key) {
9029
9004
  const value = params[key];
9030
9005
  if (typeof value !== "string") return;
9031
9006
  const trimmed = value.trim();
@@ -9086,14 +9061,14 @@ var SessionRequestTool = class extends Tool {
9086
9061
  const target = params.target;
9087
9062
  if (!target || typeof target !== "object" || Array.isArray(target)) throw new Error("target must be an object.");
9088
9063
  const task = readRequiredString$1(params, "task");
9089
- const notifyMode = readOptionalString$4(params, "notify")?.toLowerCase();
9064
+ const notifyMode = readOptionalString$5(params, "notify")?.toLowerCase();
9090
9065
  if (notifyMode !== "none" && notifyMode !== "final_reply") throw new Error("notify must be \"none\" or \"final_reply\".");
9091
9066
  return this.broker.requestSession({
9092
9067
  sourceSessionId: this.sourceSessionId,
9093
9068
  sourceToolCallId: toolCallId,
9094
9069
  targetSessionId: readRequiredString$1(target, "session_id"),
9095
9070
  task,
9096
- title: readOptionalString$4(params, "title"),
9071
+ title: readOptionalString$5(params, "title"),
9097
9072
  notify: notifyMode,
9098
9073
  handoffDepth: this.handoffDepth
9099
9074
  });
@@ -9105,13 +9080,13 @@ function readRequiredString(value, key) {
9105
9080
  if (typeof value !== "string" || value.trim().length === 0) throw new Error(`${key} must be a non-empty string.`);
9106
9081
  return value.trim();
9107
9082
  }
9108
- function readOptionalString$3(value) {
9083
+ function readOptionalString$4(value) {
9109
9084
  if (typeof value !== "string") return;
9110
9085
  const trimmed = value.trim();
9111
9086
  return trimmed.length > 0 ? trimmed : void 0;
9112
9087
  }
9113
9088
  function readSpawnScope(value) {
9114
- const normalized = readOptionalString$3(value)?.toLowerCase();
9089
+ const normalized = readOptionalString$4(value)?.toLowerCase();
9115
9090
  if (!normalized || normalized === "standalone") return "standalone";
9116
9091
  if (normalized === "child") return "child";
9117
9092
  throw new Error("scope must be \"standalone\" or \"child\".");
@@ -9119,7 +9094,7 @@ function readSpawnScope(value) {
9119
9094
  function readSpawnRequestOptions(value) {
9120
9095
  if (typeof value === "undefined") return;
9121
9096
  if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("request must be an object.");
9122
- const notifyMode = readOptionalString$3(value.notify)?.toLowerCase();
9097
+ const notifyMode = readOptionalString$4(value.notify)?.toLowerCase();
9123
9098
  if (notifyMode === "none" || notifyMode === "final_reply") return { notify: notifyMode };
9124
9099
  throw new Error("request.notify must be \"none\" or \"final_reply\".");
9125
9100
  }
@@ -9197,21 +9172,21 @@ var SessionSpawnTool = class extends Tool {
9197
9172
  sourceToolCallId: toolCallId,
9198
9173
  sourceSessionMetadata: this.sourceSessionMetadata,
9199
9174
  task,
9200
- title: readOptionalString$3(rawTitle),
9201
- agentId: readOptionalString$3(rawAgentId),
9202
- model: readOptionalString$3(rawModel),
9203
- runtime: readOptionalString$3(rawRuntime),
9175
+ title: readOptionalString$4(rawTitle),
9176
+ agentId: readOptionalString$4(rawAgentId),
9177
+ model: readOptionalString$4(rawModel),
9178
+ runtime: readOptionalString$4(rawRuntime),
9204
9179
  handoffDepth: this.handoffDepth,
9205
9180
  ...parentSessionId ? { parentSessionId } : {},
9206
9181
  notify: request.notify
9207
9182
  });
9208
9183
  const session = this.sessionCreationService.createSession({
9209
9184
  task,
9210
- title: readOptionalString$3(rawTitle),
9185
+ title: readOptionalString$4(rawTitle),
9211
9186
  sourceSessionMetadata: this.sourceSessionMetadata,
9212
- agentId: readOptionalString$3(rawAgentId),
9213
- model: readOptionalString$3(rawModel),
9214
- runtime: readOptionalString$3(rawRuntime),
9187
+ agentId: readOptionalString$4(rawAgentId),
9188
+ model: readOptionalString$4(rawModel),
9189
+ runtime: readOptionalString$4(rawRuntime),
9215
9190
  ...parentSessionId ? { parentSessionId } : {}
9216
9191
  });
9217
9192
  return {
@@ -9235,10 +9210,10 @@ var SessionSpawnTool = class extends Tool {
9235
9210
  //#endregion
9236
9211
  //#region src/cli/commands/ncp/nextclaw-ncp-tool-registry.ts
9237
9212
  function toToolParams(args) {
9238
- if (isRecord$5(args)) return args;
9213
+ if (isRecord$6(args)) return args;
9239
9214
  if (typeof args === "string") try {
9240
9215
  const parsed = JSON.parse(args);
9241
- return isRecord$5(parsed) ? parsed : {};
9216
+ return isRecord$6(parsed) ? parsed : {};
9242
9217
  } catch {
9243
9218
  return {};
9244
9219
  }
@@ -9416,14 +9391,14 @@ function readAccountIdForHints(metadata, sessionMetadata) {
9416
9391
  //#endregion
9417
9392
  //#region src/cli/commands/ncp/nextclaw-ncp-context-builder.ts
9418
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, /(现在|此刻|当前时间|现在几点|几点了|今天|今晚|今早|今晨|明天|昨天|日期)/];
9419
- function isRecord$4(value) {
9394
+ function isRecord$5(value) {
9420
9395
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
9421
9396
  }
9422
9397
  function mergeInputMetadata(input) {
9423
- 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;
9424
9399
  return {
9425
- ...isRecord$4(messageMetadata) ? structuredClone(messageMetadata) : {},
9426
- ...isRecord$4(input.metadata) ? structuredClone(input.metadata) : {}
9400
+ ...isRecord$5(messageMetadata) ? structuredClone(messageMetadata) : {},
9401
+ ...isRecord$5(input.metadata) ? structuredClone(input.metadata) : {}
9427
9402
  };
9428
9403
  }
9429
9404
  const REQUESTED_SKILLS_METADATA_READER = new RequestedSkillsMetadataReader();
@@ -10047,7 +10022,7 @@ const CHILD_SESSION_PARENT_METADATA_KEY = "parent_session_id";
10047
10022
  const CHILD_SESSION_REQUEST_METADATA_KEY = "spawned_by_request_id";
10048
10023
  const CHILD_SESSION_LIFECYCLE_METADATA_KEY = "session_lifecycle";
10049
10024
  const CHILD_SESSION_PROMOTED_METADATA_KEY = "child_session_promoted";
10050
- function readOptionalString$2(value) {
10025
+ function readOptionalString$3(value) {
10051
10026
  if (typeof value !== "string") return null;
10052
10027
  const trimmed = value.trim();
10053
10028
  return trimmed.length > 0 ? trimmed : null;
@@ -10087,14 +10062,14 @@ function buildSessionId() {
10087
10062
  return `ncp-${Date.now().toString(36)}-${randomUUID().replace(/-/g, "").slice(0, 8)}`;
10088
10063
  }
10089
10064
  function resolveSessionAgentId(params) {
10090
- return readOptionalString$2(params.agentId) ?? resolveDefaultAgentProfileId(params.getConfig());
10065
+ return readOptionalString$3(params.agentId) ?? resolveDefaultAgentProfileId(params.getConfig());
10091
10066
  }
10092
10067
  function resolveSessionTitle(params) {
10093
- return readOptionalString$2(params.title) ?? summarizeTask(params.task);
10068
+ return readOptionalString$3(params.title) ?? summarizeTask(params.task);
10094
10069
  }
10095
10070
  function resolveSessionType(params) {
10096
10071
  const { metadata, runtime, sessionType } = params;
10097
- 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;
10098
10073
  }
10099
10074
  function applySessionOverrides(params) {
10100
10075
  const { lifecycle, metadata, model, parentSessionId, projectRoot, requestId, sessionType, thinkingLevel, title } = params;
@@ -10107,15 +10082,15 @@ function applySessionOverrides(params) {
10107
10082
  metadata[CHILD_SESSION_PROMOTED_METADATA_KEY] = false;
10108
10083
  }
10109
10084
  if (requestId) metadata[CHILD_SESSION_REQUEST_METADATA_KEY] = requestId;
10110
- if (readOptionalString$2(model)) {
10085
+ if (readOptionalString$3(model)) {
10111
10086
  metadata.model = model?.trim();
10112
10087
  metadata.preferred_model = model?.trim();
10113
10088
  }
10114
- if (readOptionalString$2(thinkingLevel)) {
10089
+ if (readOptionalString$3(thinkingLevel)) {
10115
10090
  metadata.thinking = thinkingLevel?.trim();
10116
10091
  metadata.preferred_thinking = thinkingLevel?.trim();
10117
10092
  }
10118
- if (readOptionalString$2(projectRoot)) metadata.project_root = projectRoot?.trim();
10093
+ if (readOptionalString$3(projectRoot)) metadata.project_root = projectRoot?.trim();
10119
10094
  }
10120
10095
  var SessionCreationService = class {
10121
10096
  constructor(sessionManager, getConfig, onSessionUpdated) {
@@ -10137,8 +10112,8 @@ var SessionCreationService = class {
10137
10112
  task
10138
10113
  });
10139
10114
  const metadata = cloneInheritedMetadata(sourceSessionMetadata);
10140
- const parentSessionId = readOptionalString$2(rawParentSessionId);
10141
- const requestId = readOptionalString$2(rawRequestId);
10115
+ const parentSessionId = readOptionalString$3(rawParentSessionId);
10116
+ const requestId = readOptionalString$3(rawRequestId);
10142
10117
  const sessionType = resolveSessionType({
10143
10118
  runtime,
10144
10119
  sessionType: requestedSessionType,
@@ -10191,12 +10166,12 @@ var SessionCreationService = class {
10191
10166
  return true;
10192
10167
  };
10193
10168
  isChildSessionRecord = (metadata) => {
10194
- return Boolean(readOptionalString$2(metadata?.[CHILD_SESSION_PARENT_METADATA_KEY]));
10169
+ return Boolean(readOptionalString$3(metadata?.[CHILD_SESSION_PARENT_METADATA_KEY]));
10195
10170
  };
10196
10171
  };
10197
10172
  //#endregion
10198
10173
  //#region src/cli/commands/ncp/session-request/session-request-result.ts
10199
- function readOptionalString$1(value) {
10174
+ function readOptionalString$2(value) {
10200
10175
  if (typeof value !== "string") return null;
10201
10176
  const trimmed = value.trim();
10202
10177
  return trimmed.length > 0 ? trimmed : null;
@@ -10217,7 +10192,7 @@ function extractSessionMessageText(message) {
10217
10192
  return parts.join("\n\n");
10218
10193
  }
10219
10194
  function readParentSessionId(metadata) {
10220
- return readOptionalString$1(metadata?.["parent_session_id"]) ?? void 0;
10195
+ return readOptionalString$2(metadata?.["parent_session_id"]) ?? void 0;
10221
10196
  }
10222
10197
  function buildSessionRequestToolResult(params) {
10223
10198
  const { request, task, title, agentId, isChildSession, parentSessionId, spawnedByRequestId, message } = params;
@@ -10356,7 +10331,7 @@ var SessionRequestBroker = class {
10356
10331
  sourceToolCallId,
10357
10332
  targetSessionId: normalizedTargetSessionId,
10358
10333
  task,
10359
- title: readOptionalString$1(title) ?? readOptionalString$1(targetSummary.metadata?.label) ?? summarizeSessionRequestTask(task),
10334
+ title: readOptionalString$2(title) ?? readOptionalString$2(targetSummary.metadata?.label) ?? summarizeSessionRequestTask(task),
10360
10335
  handoffDepth: handoffDepth ?? 0,
10361
10336
  notify,
10362
10337
  agentId: targetSummary.agentId,
@@ -10892,7 +10867,7 @@ var SessionSearchStoreService = class {
10892
10867
  };
10893
10868
  //#endregion
10894
10869
  //#region src/cli/commands/ncp/session-search/session-search-tool.service.ts
10895
- function isRecord$3(value) {
10870
+ function isRecord$4(value) {
10896
10871
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
10897
10872
  }
10898
10873
  function readOptionalInteger(value) {
@@ -10942,7 +10917,7 @@ var SessionSearchTool = class {
10942
10917
  return issues;
10943
10918
  };
10944
10919
  execute = async (args) => {
10945
- 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.");
10946
10921
  const issues = this.validateArgs(args);
10947
10922
  if (issues.length > 0) throw new Error(issues.join(" "));
10948
10923
  return this.queryService.search({
@@ -11874,12 +11849,12 @@ function createContextWindowUpdatedEvent(params) {
11874
11849
  }
11875
11850
  };
11876
11851
  }
11877
- function isRecord$2(value) {
11852
+ function isRecord$3(value) {
11878
11853
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
11879
11854
  }
11880
11855
  function resolveNativeReasoningNormalizationMode(params) {
11881
11856
  const runtimeEntry = params.config.agents.runtimes.entries.native?.config ?? params.config.ui.ncp.runtimes.native;
11882
- const runtimeMetadata = isRecord$2(runtimeEntry) ? runtimeEntry : {};
11857
+ const runtimeMetadata = isRecord$3(runtimeEntry) ? runtimeEntry : {};
11883
11858
  return readAssistantReasoningNormalizationModeFromMetadata(params.sessionMetadata) ?? readAssistantReasoningNormalizationMode(runtimeMetadata.reasoningNormalization) ?? readAssistantReasoningNormalizationMode(runtimeMetadata.reasoning_normalization) ?? readAssistantReasoningNormalizationMode(runtimeMetadata.reasoningNormalizationMode) ?? readAssistantReasoningNormalizationMode(runtimeMetadata.reasoning_normalization_mode) ?? "think-tags";
11884
11859
  }
11885
11860
  function createMcpRuntimeSupport(getConfig) {
@@ -14306,6 +14281,27 @@ async function describeUnmanagedHealthyTargetMessage(params) {
14306
14281
  //#endregion
14307
14282
  //#region src/cli/shared/services/runtime/service-managed-startup.service.ts
14308
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
+ }
14309
14305
  function toObjectRecord(value) {
14310
14306
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
14311
14307
  return value;
@@ -14357,7 +14353,7 @@ function spawnManagedService(params) {
14357
14353
  appendStartupStage(logPath, `start requested: ui=${uiConfig.host}:${uiConfig.port}, readinessTimeoutMs=${readinessTimeoutMs}`);
14358
14354
  console.log(`Starting ${appName} background service (readiness timeout ${Math.ceil(readinessTimeoutMs / 1e3)}s)...`);
14359
14355
  const cliLaunch = resolveCliSubcommandLaunch({
14360
- argvEntry: process.argv[1],
14356
+ argvEntry: resolveLauncherCliEntry(import.meta.url),
14361
14357
  importMetaUrl: import.meta.url,
14362
14358
  cliArgs: [
14363
14359
  "serve",
@@ -14369,7 +14365,7 @@ function spawnManagedService(params) {
14369
14365
  const childArgs = [...process.execArgv, ...cliLaunch.args];
14370
14366
  appendStartupStage(logPath, `spawning background process: ${cliLaunch.command} ${childArgs.join(" ")}`);
14371
14367
  const child = spawn(cliLaunch.command, childArgs, {
14372
- env: process.env,
14368
+ env: createTopLevelNextclawCommandEnv(process.env),
14373
14369
  stdio: "ignore",
14374
14370
  detached: true
14375
14371
  });
@@ -14628,12 +14624,13 @@ var ManagedServiceCommandService = class {
14628
14624
  return;
14629
14625
  }
14630
14626
  startup.child.unref();
14627
+ const readySnapshot = resolveManagedServiceReadySnapshot({ snapshot: startup.snapshot });
14631
14628
  await reportManagedServiceStart({
14632
14629
  appName: APP_NAME$1,
14633
14630
  state: writeReadyManagedServiceState({
14634
14631
  readinessTimeoutMs: startup.readinessTimeoutMs,
14635
14632
  readiness,
14636
- snapshot: startup.snapshot
14633
+ snapshot: readySnapshot
14637
14634
  }),
14638
14635
  uiConfig,
14639
14636
  uiUrl,
@@ -15178,25 +15175,25 @@ var NpmRuntimeUpdateHost = class {
15178
15175
  };
15179
15176
  applyDownloadedUpdate = async () => {
15180
15177
  if (this.activeTask) return this.snapshot;
15181
- this.snapshot = {
15178
+ this.setSnapshot({
15182
15179
  ...this.snapshot,
15183
15180
  status: "applying",
15184
15181
  progress: null,
15185
15182
  errorMessage: null
15186
- };
15183
+ });
15187
15184
  try {
15188
15185
  const snapshot = this.createManager().applyDownloadedUpdate();
15189
- this.snapshot = this.deps.applyRestartMode === "managed-service-restart" ? snapshot : {
15186
+ this.setSnapshot(this.deps.applyRestartMode === "managed-service-restart" ? snapshot : {
15190
15187
  ...snapshot,
15191
15188
  recoveryCommand: "Restart this NextClaw process to launch the downloaded runtime."
15192
- };
15189
+ });
15193
15190
  if (this.deps.applyRestartMode === "managed-service-restart") await requestManagedServiceRestart(this.deps.requestRestart, {
15194
15191
  reason: "runtime update apply",
15195
15192
  uiPort: this.deps.uiConfig.port
15196
15193
  });
15197
15194
  return this.snapshot;
15198
15195
  } catch (error) {
15199
- this.snapshot = this.toFailedSnapshot(error);
15196
+ this.setSnapshot(this.toFailedSnapshot(error));
15200
15197
  throw error;
15201
15198
  }
15202
15199
  };
@@ -15208,7 +15205,7 @@ var NpmRuntimeUpdateHost = class {
15208
15205
  ...preferences
15209
15206
  }
15210
15207
  }));
15211
- this.snapshot = this.createManager(nextState.channel).getSnapshot();
15208
+ this.setSnapshot(this.createManager(nextState.channel).getSnapshot());
15212
15209
  if (nextState.updatePreferences.automaticChecks) this.startAutomaticSync({ force: true });
15213
15210
  return this.snapshot;
15214
15211
  };
@@ -15217,7 +15214,7 @@ var NpmRuntimeUpdateHost = class {
15217
15214
  ...current,
15218
15215
  channel
15219
15216
  }));
15220
- this.snapshot = this.createManager(nextState.channel).getSnapshot();
15217
+ this.setSnapshot(this.createManager(nextState.channel).getSnapshot());
15221
15218
  if (nextState.updatePreferences.automaticChecks) return this.startCheck({ autoDownload: nextState.updatePreferences.autoDownload });
15222
15219
  return this.snapshot;
15223
15220
  };
@@ -15231,19 +15228,19 @@ var NpmRuntimeUpdateHost = class {
15231
15228
  };
15232
15229
  startCheck = async (options) => {
15233
15230
  if (this.activeTask) return this.snapshot;
15234
- this.snapshot = {
15231
+ this.setSnapshot({
15235
15232
  ...this.createManager().getSnapshot(),
15236
15233
  status: "checking",
15237
15234
  progress: null,
15238
15235
  errorMessage: null
15239
- };
15236
+ });
15240
15237
  this.activeTask = (async () => {
15241
15238
  try {
15242
15239
  const checkedSnapshot = await this.createManager().checkForUpdate();
15243
- this.snapshot = checkedSnapshot;
15240
+ this.setSnapshot(checkedSnapshot);
15244
15241
  if (options.autoDownload && checkedSnapshot.status === "update-available") await this.runDownloadTask();
15245
15242
  } catch (error) {
15246
- this.snapshot = this.toFailedSnapshot(error);
15243
+ this.setSnapshot(this.toFailedSnapshot(error));
15247
15244
  } finally {
15248
15245
  this.activeTask = null;
15249
15246
  }
@@ -15252,17 +15249,17 @@ var NpmRuntimeUpdateHost = class {
15252
15249
  };
15253
15250
  startDownload = async () => {
15254
15251
  if (this.activeTask) return this.snapshot;
15255
- this.snapshot = {
15252
+ this.setSnapshot({
15256
15253
  ...this.createManager().getSnapshot(),
15257
15254
  status: "downloading",
15258
15255
  progress: INITIAL_DOWNLOAD_PROGRESS,
15259
15256
  errorMessage: null
15260
- };
15257
+ });
15261
15258
  this.activeTask = (async () => {
15262
15259
  try {
15263
15260
  await this.runDownloadTask();
15264
15261
  } catch (error) {
15265
- this.snapshot = this.toFailedSnapshot(error);
15262
+ this.setSnapshot(this.toFailedSnapshot(error));
15266
15263
  } finally {
15267
15264
  this.activeTask = null;
15268
15265
  }
@@ -15270,14 +15267,15 @@ var NpmRuntimeUpdateHost = class {
15270
15267
  return this.snapshot;
15271
15268
  };
15272
15269
  runDownloadTask = async () => {
15273
- this.snapshot = await this.createManager().downloadUpdate((progress) => {
15274
- this.snapshot = {
15270
+ const downloadedSnapshot = await this.createManager().downloadUpdate((progress) => {
15271
+ this.setSnapshot({
15275
15272
  ...this.snapshot,
15276
15273
  status: "downloading",
15277
15274
  progress,
15278
15275
  errorMessage: null
15279
- };
15276
+ });
15280
15277
  });
15278
+ this.setSnapshot(downloadedSnapshot);
15281
15279
  };
15282
15280
  createManager = (channel = this.stateStore.read().channel) => {
15283
15281
  return new NpmRuntimeUpdateManager({
@@ -15298,6 +15296,11 @@ var NpmRuntimeUpdateHost = class {
15298
15296
  errorMessage: error instanceof Error ? error.message : String(error ?? "Unknown error")
15299
15297
  };
15300
15298
  };
15299
+ setSnapshot = (snapshot) => {
15300
+ this.snapshot = snapshot;
15301
+ nextclaw.eventBus.emit(eventKeys.runtimeUpdateSnapshot, snapshot, { source: "backend" });
15302
+ return snapshot;
15303
+ };
15301
15304
  };
15302
15305
  function createNpmRuntimeUpdateHost(params) {
15303
15306
  return new NpmRuntimeUpdateHost(params);
@@ -15423,9 +15426,15 @@ function createRuntimeControlHost(params) {
15423
15426
  }
15424
15427
  //#endregion
15425
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
+ }
15426
15435
  function createServiceUiHosts(params) {
15427
15436
  const { requestRestart, serviceCommands, uiConfig } = params;
15428
- const applyRestartMode = managedServiceStateStore.read()?.pid === process.pid ? "managed-service-restart" : "manual-process-restart";
15437
+ const applyRestartMode = resolveApplyRestartMode(uiConfig.port);
15429
15438
  return {
15430
15439
  remoteAccess: createRemoteAccessHost(params),
15431
15440
  runtimeControl: createRuntimeControlHost({
@@ -16905,17 +16914,17 @@ function readStringList(value) {
16905
16914
  if (!Array.isArray(value)) return [];
16906
16915
  return value.map((entry) => typeof entry === "string" ? entry.trim() : "").filter(Boolean);
16907
16916
  }
16908
- function readOptionalString(value) {
16917
+ function readOptionalString$1(value) {
16909
16918
  if (typeof value !== "string") return;
16910
16919
  return value.trim() || void 0;
16911
16920
  }
16912
16921
  function resolvePluginRuntimeAttachments(ctx) {
16913
16922
  const mediaPaths = readStringList(ctx.MediaPaths);
16914
16923
  const mediaUrls = readStringList(ctx.MediaUrls);
16915
- const fallbackPath = readOptionalString(ctx.MediaPath);
16916
- const fallbackUrl = readOptionalString(ctx.MediaUrl);
16924
+ const fallbackPath = readOptionalString$1(ctx.MediaPath);
16925
+ const fallbackUrl = readOptionalString$1(ctx.MediaUrl);
16917
16926
  const mediaTypes = readStringList(ctx.MediaTypes);
16918
- const fallbackType = readOptionalString(ctx.MediaType);
16927
+ const fallbackType = readOptionalString$1(ctx.MediaType);
16919
16928
  const entryCount = Math.max(mediaPaths.length, mediaUrls.length, fallbackPath ? 1 : 0, fallbackUrl ? 1 : 0);
16920
16929
  const attachments = [];
16921
16930
  for (let index = 0; index < entryCount; index += 1) {
@@ -16938,7 +16947,7 @@ function resolvePluginRuntimeAttachments(ctx) {
16938
16947
  //#region src/cli/shared/services/plugin/service-plugin-reload.service.ts
16939
16948
  async function reloadServicePlugins(params) {
16940
16949
  const nextWorkspace = getWorkspacePath(params.nextConfig.agents.defaults.workspace);
16941
- const nextPluginRegistry = loadPluginRegistry(params.nextConfig, nextWorkspace);
16950
+ const nextPluginRegistry = await loadPluginRegistryProgressively(params.nextConfig, nextWorkspace);
16942
16951
  const nextExtensionRegistry = toExtensionRegistry(nextPluginRegistry);
16943
16952
  const nextPluginChannelBindings = getPluginChannelBindings(nextPluginRegistry);
16944
16953
  const shouldRestartChannels = shouldRestartChannelsForPluginReload({
@@ -16994,30 +17003,52 @@ function applyGatewayRuntimeCapabilityState(params) {
16994
17003
  params.state.extensionRegistry = params.next.extensionRegistry;
16995
17004
  params.state.pluginChannelBindings = params.next.pluginChannelBindings;
16996
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
+ }
16997
17043
  function configureGatewayPluginRuntime(params) {
16998
17044
  params.gateway.reloader.setReloadPlugins(async ({ config: nextConfig, changedPaths }) => {
16999
- const result = await reloadServicePlugins({
17000
- nextConfig,
17001
- changedPaths,
17002
- pluginRegistry: params.state.pluginRegistry,
17003
- extensionRegistry: params.state.extensionRegistry,
17004
- pluginChannelBindings: params.state.pluginChannelBindings,
17005
- pluginGatewayHandles: params.state.pluginGatewayHandles,
17006
- pluginGatewayLogger,
17007
- logPluginGatewayDiagnostics
17008
- });
17009
- applyGatewayRuntimeCapabilityState({
17045
+ const result = await applyGatewayPluginReload({
17010
17046
  gateway: params.gateway,
17011
17047
  state: params.state,
17012
- next: {
17013
- pluginRegistry: result.pluginRegistry,
17014
- extensionRegistry: result.extensionRegistry,
17015
- pluginChannelBindings: result.pluginChannelBindings
17016
- }
17048
+ getLiveUiNcpAgent: params.getLiveUiNcpAgent,
17049
+ nextConfig,
17050
+ changedPaths
17017
17051
  });
17018
- params.state.pluginUiMetadata = getPluginUiMetadataFromRegistry(result.pluginRegistry);
17019
- params.state.pluginGatewayHandles = result.pluginGatewayHandles;
17020
- params.getLiveUiNcpAgent()?.applyExtensionRegistry?.(result.extensionRegistry);
17021
17052
  if (result.restartChannels) console.log("Config reload: plugin channel gateways restarted.");
17022
17053
  return { restartChannels: result.restartChannels };
17023
17054
  });
@@ -17088,6 +17119,120 @@ async function cleanupGatewayRuntime(params) {
17088
17119
  setPluginRuntimeBridge(null);
17089
17120
  }
17090
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
17091
17236
  //#region src/cli/shared/stores/companion-runtime.store.ts
17092
17237
  var CompanionRuntimeStore = class {
17093
17238
  get path() {
@@ -17249,6 +17394,7 @@ const companionRuntimeService = new CompanionRuntimeService();
17249
17394
  //#endregion
17250
17395
  //#region src/cli/shared/services/runtime/runtime-command.service.ts
17251
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;
17252
17398
  function createSkillsLoader(workspace) {
17253
17399
  const ctor = NextclawCore.SkillsLoader;
17254
17400
  if (!ctor) return null;
@@ -17342,6 +17488,20 @@ var RuntimeCommandService = class {
17342
17488
  sessionManager: gateway.sessionManager
17343
17489
  })
17344
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
+ });
17345
17505
  await runConfiguredGatewayRuntime({
17346
17506
  uiStartup,
17347
17507
  bootstrapStatus,
@@ -20797,7 +20957,7 @@ var CliRuntime = class {
20797
20957
  spawn(process.execPath, ["-e", helperScript], {
20798
20958
  detached: true,
20799
20959
  stdio: "ignore",
20800
- env: process.env
20960
+ env: createTopLevelNextclawCommandEnv(process.env)
20801
20961
  }).unref();
20802
20962
  this.selfRelaunchArmed = true;
20803
20963
  console.warn(`Gateway self-restart armed (${reason}).`);