nextclaw 0.6.33 → 0.6.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -614,8 +614,7 @@ function mergePluginConfigView(baseConfig, pluginViewConfig, bindings) {
614
614
  return next;
615
615
  }
616
616
  var PluginCommands = class {
617
- constructor(deps) {
618
- this.deps = deps;
617
+ constructor() {
619
618
  }
620
619
  pluginsList(opts = {}) {
621
620
  const config2 = loadConfig();
@@ -745,19 +744,15 @@ var PluginCommands = class {
745
744
  const config2 = loadConfig();
746
745
  const next = enablePluginInConfig(config2, id);
747
746
  saveConfig(next);
748
- await this.deps.requestRestart({
749
- reason: `plugin enabled: ${id}`,
750
- manualMessage: `Enabled plugin "${id}". Restart the gateway to apply.`
751
- });
747
+ console.log(`Enabled plugin "${id}".`);
748
+ console.log("If gateway is running, plugin changes are hot-applied automatically.");
752
749
  }
753
750
  async pluginsDisable(id) {
754
751
  const config2 = loadConfig();
755
752
  const next = disablePluginInConfig(config2, id);
756
753
  saveConfig(next);
757
- await this.deps.requestRestart({
758
- reason: `plugin disabled: ${id}`,
759
- manualMessage: `Disabled plugin "${id}". Restart the gateway to apply.`
760
- });
754
+ console.log(`Disabled plugin "${id}".`);
755
+ console.log("If gateway is running, plugin changes are hot-applied automatically.");
761
756
  }
762
757
  async pluginsUninstall(id, opts = {}) {
763
758
  const config2 = loadConfig();
@@ -854,10 +849,7 @@ var PluginCommands = class {
854
849
  removed.push("directory");
855
850
  }
856
851
  console.log(`Uninstalled plugin "${pluginId}". Removed: ${removed.length > 0 ? removed.join(", ") : "nothing"}.`);
857
- await this.deps.requestRestart({
858
- reason: `plugin uninstalled: ${pluginId}`,
859
- manualMessage: "Restart the gateway to apply changes."
860
- });
852
+ console.log("If gateway is running, plugin changes are hot-applied automatically.");
861
853
  }
862
854
  async pluginsInstall(pathOrSpec, opts = {}) {
863
855
  const fileSpec = this.resolveFileNpmSpecToLocalPath(pathOrSpec);
@@ -886,10 +878,7 @@ var PluginCommands = class {
886
878
  });
887
879
  saveConfig(next3);
888
880
  console.log(`Linked plugin path: ${resolved}`);
889
- await this.deps.requestRestart({
890
- reason: `plugin linked: ${probe.pluginId}`,
891
- manualMessage: "Restart the gateway to load plugins."
892
- });
881
+ console.log("If gateway is running, plugin changes are hot-applied automatically.");
893
882
  return;
894
883
  }
895
884
  const result2 = await installPluginFromPath({
@@ -913,10 +902,7 @@ var PluginCommands = class {
913
902
  });
914
903
  saveConfig(next2);
915
904
  console.log(`Installed plugin: ${result2.pluginId}`);
916
- await this.deps.requestRestart({
917
- reason: `plugin installed: ${result2.pluginId}`,
918
- manualMessage: "Restart the gateway to load plugins."
919
- });
905
+ console.log("If gateway is running, plugin changes are hot-applied automatically.");
920
906
  return;
921
907
  }
922
908
  if (opts.link) {
@@ -948,10 +934,7 @@ var PluginCommands = class {
948
934
  });
949
935
  saveConfig(next);
950
936
  console.log(`Installed plugin: ${result.pluginId}`);
951
- await this.deps.requestRestart({
952
- reason: `plugin installed: ${result.pluginId}`,
953
- manualMessage: "Restart the gateway to load plugins."
954
- });
937
+ console.log("If gateway is running, plugin changes are hot-applied automatically.");
955
938
  }
956
939
  pluginsDoctor() {
957
940
  const config2 = loadConfig();
@@ -2194,6 +2177,9 @@ var ConfigReloader = class {
2194
2177
  setApplyAgentRuntimeConfig(callback) {
2195
2178
  this.options.applyAgentRuntimeConfig = callback;
2196
2179
  }
2180
+ setReloadPlugins(callback) {
2181
+ this.options.reloadPlugins = callback;
2182
+ }
2197
2183
  async applyReloadPlan(nextConfig) {
2198
2184
  const changedPaths = diffConfigPaths2(this.currentConfig, nextConfig);
2199
2185
  if (!changedPaths.length) {
@@ -2202,6 +2188,10 @@ var ConfigReloader = class {
2202
2188
  this.currentConfig = nextConfig;
2203
2189
  this.options.providerManager?.setConfig(nextConfig);
2204
2190
  const plan = buildReloadPlan2(changedPaths);
2191
+ if (plan.reloadPlugins) {
2192
+ await this.reloadPlugins(nextConfig);
2193
+ console.log("Config reload: plugins reloaded.");
2194
+ }
2205
2195
  if (plan.restartChannels) {
2206
2196
  await this.reloadChannels(nextConfig);
2207
2197
  console.log("Config reload: channels restarted.");
@@ -2297,6 +2287,12 @@ var ConfigReloader = class {
2297
2287
  this.providerReloadTask = null;
2298
2288
  }
2299
2289
  }
2290
+ async reloadPlugins(nextConfig) {
2291
+ if (!this.options.reloadPlugins) {
2292
+ return;
2293
+ }
2294
+ await this.options.reloadPlugins(nextConfig);
2295
+ }
2300
2296
  };
2301
2297
 
2302
2298
  // src/cli/missing-provider.ts
@@ -2381,6 +2377,10 @@ var GatewayAgentRuntimePool = class {
2381
2377
  this.routeResolver.updateConfig(config2);
2382
2378
  this.rebuild(config2);
2383
2379
  }
2380
+ applyExtensionRegistry(extensionRegistry) {
2381
+ this.options.extensionRegistry = extensionRegistry;
2382
+ this.rebuild(this.options.config);
2383
+ }
2384
2384
  async processDirect(params) {
2385
2385
  const message = {
2386
2386
  channel: params.channel ?? "cli",
@@ -2497,8 +2497,8 @@ var ServiceCommands = class {
2497
2497
  async startGateway(options = {}) {
2498
2498
  const config2 = loadConfig5();
2499
2499
  const workspace = getWorkspacePath5(config2.agents.defaults.workspace);
2500
- const pluginRegistry = loadPluginRegistry(config2, workspace);
2501
- const extensionRegistry = toExtensionRegistry(pluginRegistry);
2500
+ let pluginRegistry = loadPluginRegistry(config2, workspace);
2501
+ let extensionRegistry = toExtensionRegistry(pluginRegistry);
2502
2502
  logPluginDiagnostics(pluginRegistry);
2503
2503
  const bus = new MessageBus();
2504
2504
  const provider = options.allowMissingProvider === true ? this.makeProvider(config2, { allowMissing: true }) : this.makeProvider(config2);
@@ -2507,6 +2507,24 @@ var ServiceCommands = class {
2507
2507
  config: config2
2508
2508
  });
2509
2509
  const sessionManager = new SessionManager(workspace);
2510
+ let pluginGatewayHandles = [];
2511
+ const pluginGatewayLogger = {
2512
+ info: (message) => console.log(`[plugins] ${message}`),
2513
+ warn: (message) => console.warn(`[plugins] ${message}`),
2514
+ error: (message) => console.error(`[plugins] ${message}`),
2515
+ debug: (message) => console.debug(`[plugins] ${message}`)
2516
+ };
2517
+ const logPluginGatewayDiagnostics = (diagnostics) => {
2518
+ for (const diag of diagnostics) {
2519
+ const prefix = diag.pluginId ? `${diag.pluginId}: ` : "";
2520
+ const text = `${prefix}${diag.message}`;
2521
+ if (diag.level === "error") {
2522
+ console.error(`[plugins] ${text}`);
2523
+ } else {
2524
+ console.warn(`[plugins] ${text}`);
2525
+ }
2526
+ }
2527
+ };
2510
2528
  const cronStorePath = join4(getDataDir5(), "cron", "jobs.json");
2511
2529
  const cron2 = new CronService2(cronStorePath);
2512
2530
  const uiConfig = resolveUiConfig(config2, options.uiOverrides);
@@ -2568,7 +2586,26 @@ var ServiceCommands = class {
2568
2586
  })
2569
2587
  });
2570
2588
  reloader.setApplyAgentRuntimeConfig((nextConfig) => runtimePool.applyRuntimeConfig(nextConfig));
2571
- const pluginChannelBindings = getPluginChannelBindings2(pluginRegistry);
2589
+ reloader.setReloadPlugins(async (nextConfig) => {
2590
+ const nextWorkspace = getWorkspacePath5(nextConfig.agents.defaults.workspace);
2591
+ const nextPluginRegistry = loadPluginRegistry(nextConfig, nextWorkspace);
2592
+ const nextExtensionRegistry = toExtensionRegistry(nextPluginRegistry);
2593
+ logPluginDiagnostics(nextPluginRegistry);
2594
+ await stopPluginChannelGateways(pluginGatewayHandles);
2595
+ const startedPluginGateways = await startPluginChannelGateways({
2596
+ registry: nextPluginRegistry,
2597
+ logger: pluginGatewayLogger
2598
+ });
2599
+ pluginGatewayHandles = startedPluginGateways.handles;
2600
+ logPluginGatewayDiagnostics(startedPluginGateways.diagnostics);
2601
+ pluginRegistry = nextPluginRegistry;
2602
+ extensionRegistry = nextExtensionRegistry;
2603
+ pluginChannelBindings = getPluginChannelBindings2(nextPluginRegistry);
2604
+ runtimePool.applyExtensionRegistry(nextExtensionRegistry);
2605
+ runtimePool.applyRuntimeConfig(nextConfig);
2606
+ console.log("Config reload: plugin channel gateways restarted.");
2607
+ });
2608
+ let pluginChannelBindings = getPluginChannelBindings2(pluginRegistry);
2572
2609
  setPluginRuntimeBridge({
2573
2610
  loadConfig: () => toPluginConfigView(loadConfig5(), pluginChannelBindings),
2574
2611
  writeConfigFile: async (nextConfigView) => {
@@ -2658,27 +2695,13 @@ var ServiceCommands = class {
2658
2695
  watcher.on("unlink", () => reloader.scheduleReload("config unlink"));
2659
2696
  await cron2.start();
2660
2697
  await heartbeat.start();
2661
- let pluginGatewayHandles = [];
2662
2698
  try {
2663
2699
  const startedPluginGateways = await startPluginChannelGateways({
2664
2700
  registry: pluginRegistry,
2665
- logger: {
2666
- info: (message) => console.log(`[plugins] ${message}`),
2667
- warn: (message) => console.warn(`[plugins] ${message}`),
2668
- error: (message) => console.error(`[plugins] ${message}`),
2669
- debug: (message) => console.debug(`[plugins] ${message}`)
2670
- }
2701
+ logger: pluginGatewayLogger
2671
2702
  });
2672
2703
  pluginGatewayHandles = startedPluginGateways.handles;
2673
- for (const diag of startedPluginGateways.diagnostics) {
2674
- const prefix = diag.pluginId ? `${diag.pluginId}: ` : "";
2675
- const text = `${prefix}${diag.message}`;
2676
- if (diag.level === "error") {
2677
- console.error(`[plugins] ${text}`);
2678
- } else {
2679
- console.warn(`[plugins] ${text}`);
2680
- }
2681
- }
2704
+ logPluginGatewayDiagnostics(startedPluginGateways.diagnostics);
2682
2705
  await reloader.getChannels().startAll();
2683
2706
  await this.wakeFromRestartSentinel({ bus, sessionManager });
2684
2707
  await runtimePool.run();
@@ -3236,9 +3259,7 @@ var CliRuntime = class {
3236
3259
  this.configCommands = new ConfigCommands({
3237
3260
  requestRestart: (params) => this.requestRestart(params)
3238
3261
  });
3239
- this.pluginCommands = new PluginCommands({
3240
- requestRestart: (params) => this.requestRestart(params)
3241
- });
3262
+ this.pluginCommands = new PluginCommands();
3242
3263
  this.channelCommands = new ChannelCommands({
3243
3264
  logo: this.logo,
3244
3265
  getBridgeDir: () => this.workspaceManager.getBridgeDir(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nextclaw",
3
- "version": "0.6.33",
3
+ "version": "0.6.34",
4
4
  "description": "Lightweight personal AI assistant with CLI, multi-provider routing, and channel integrations.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -38,9 +38,9 @@
38
38
  "dependencies": {
39
39
  "chokidar": "^3.6.0",
40
40
  "commander": "^12.1.0",
41
- "@nextclaw/core": "^0.6.26",
42
- "@nextclaw/server": "^0.4.15",
43
- "@nextclaw/openclaw-compat": "^0.1.19"
41
+ "@nextclaw/core": "^0.6.27",
42
+ "@nextclaw/server": "^0.4.16",
43
+ "@nextclaw/openclaw-compat": "^0.1.20"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@types/node": "^20.17.6",
@@ -136,13 +136,13 @@ When the gateway is already running, config changes from the UI or `nextclaw con
136
136
  - `agents.defaults.contextTokens`
137
137
  - `agents.context.*`
138
138
  - `tools.*`
139
+ - `plugins.*` (v1 hot plugin runtime: plugin registry/channel gateways/channels are hot-reloaded)
139
140
 
140
141
  Restart is still required for:
141
142
 
142
143
  - UI bind port (`--port` / `--ui-port`)
143
- - `plugins.*`
144
144
 
145
- To confirm hot reload succeeded, check gateway console logs or `${NEXTCLAW_HOME:-~/.nextclaw}/logs/service.log` for messages like `Config reload: ... applied.`
145
+ To confirm hot reload succeeded, check gateway console logs or `${NEXTCLAW_HOME:-~/.nextclaw}/logs/service.log` for messages like `Config reload: plugins reloaded.` / `Config reload: plugin channel gateways restarted.` / `Config reload: channels restarted.`
146
146
 
147
147
  UI note: **Model** page save now persists both `agents.defaults.model` and `agents.defaults.maxTokens` (refresh should keep the updated max token value).
148
148