@nextclaw/service 0.1.11 → 0.1.13

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 (72) hide show
  1. package/dist/cli/commands/agent/agent-runtime.utils.d.ts +1 -2
  2. package/dist/cli/commands/agent/agent-runtime.utils.js +6 -50
  3. package/dist/cli/commands/agent/cli-agent-runner.utils.d.ts +0 -2
  4. package/dist/cli/commands/agent/cli-agent-runner.utils.js +7 -9
  5. package/dist/cli/commands/agent/services/agent-commands.service.js +0 -1
  6. package/dist/cli/commands/cron/services/cron-local.service.d.ts +1 -2
  7. package/dist/cli/commands/skills/index.js +1 -1
  8. package/dist/cli/commands/skills/marketplace-client.d.ts +11 -1
  9. package/dist/cli/commands/skills/marketplace-client.js +39 -1
  10. package/dist/cli/commands/skills/marketplace-command-options.utils.d.ts +1 -1
  11. package/dist/cli/commands/skills/marketplace.metadata.d.ts +3 -12
  12. package/dist/cli/commands/skills/marketplace.metadata.js +1 -87
  13. package/dist/cli/commands/skills/{marketplace.service.d.ts → marketplace.utils.d.ts} +1 -1
  14. package/dist/cli/commands/skills/{marketplace.service.js → marketplace.utils.js} +11 -47
  15. package/dist/cli/commands/skills/skills-query.service.d.ts +4 -37
  16. package/dist/cli/commands/skills/skills-query.service.js +16 -98
  17. package/dist/cli/commands/usage/services/llm-usage-command.service.d.ts +3 -5
  18. package/dist/cli/commands/usage/services/llm-usage-command.service.js +16 -26
  19. package/dist/commands/channel/channel-list-view.service.d.ts +0 -1
  20. package/dist/commands/channel/channel-list-view.service.js +6 -23
  21. package/dist/commands/channel/index.js +0 -1
  22. package/dist/commands/plugin/index.d.ts +2 -4
  23. package/dist/commands/plugin/index.js +8 -20
  24. package/dist/commands/plugin/{plugin-command-utils.d.ts → plugin-command.utils.d.ts} +1 -2
  25. package/dist/commands/plugin/{plugin-command-utils.js → plugin-command.utils.js} +2 -4
  26. package/dist/commands/plugin/{plugin-mutation-actions.d.ts → plugin-mutation-actions.utils.d.ts} +1 -1
  27. package/dist/commands/plugin/{plugin-mutation-actions.js → plugin-mutation-actions.utils.js} +2 -2
  28. package/dist/commands/service/services/autostart/linux-systemd-autostart.service.js +1 -1
  29. package/dist/commands/service/services/autostart/macos-launch-agent-autostart.service.js +1 -1
  30. package/dist/commands/service/services/autostart/windows-task-autostart.service.js +1 -1
  31. package/dist/launcher/npm-runtime-launcher.service.js +1 -1
  32. package/dist/service-runtime.service.d.ts +1 -1
  33. package/dist/service-runtime.service.js +7 -15
  34. package/dist/shared/controllers/gateway.controller.d.ts +3 -11
  35. package/dist/shared/controllers/gateway.controller.js +24 -180
  36. package/dist/shared/services/gateway/managers/gateway-plugin.manager.d.ts +2 -9
  37. package/dist/shared/services/gateway/managers/gateway-plugin.manager.js +30 -88
  38. package/dist/shared/services/gateway/nextclaw-app.service.d.ts +2 -7
  39. package/dist/shared/services/gateway/nextclaw-app.service.js +6 -16
  40. package/dist/shared/services/gateway/nextclaw-gateway-runtime.service.d.ts +4 -9
  41. package/dist/shared/services/gateway/nextclaw-gateway-runtime.service.js +12 -46
  42. package/dist/shared/services/gateway/{cron-job-handler.service.d.ts → utils/cron-job-handler.utils.d.ts} +3 -6
  43. package/dist/shared/services/gateway/utils/cron-job-handler.utils.js +57 -0
  44. package/dist/shared/services/marketplace/service-marketplace-installer.service.js +3 -3
  45. package/dist/shared/services/plugin/utils/plugin-runtime-bridge.utils.js +1 -1
  46. package/dist/shared/services/runtime/runtime-command.service.js +2 -2
  47. package/dist/shared/services/runtime/service-managed-startup.service.js +1 -1
  48. package/dist/shared/services/ui/companion-runtime.service.js +1 -1
  49. package/dist/shared/services/workspace/workspace-manager.service.js +8 -10
  50. package/dist/shared/utils/cli.utils.js +1 -1
  51. package/package.json +20 -20
  52. package/dist/cli/commands/usage/services/llm-usage-query.service.d.ts +0 -43
  53. package/dist/cli/commands/usage/services/llm-usage-query.service.js +0 -85
  54. package/dist/commands/plugin/development-source/dev-plugin-overrides.utils.d.ts +0 -18
  55. package/dist/commands/plugin/development-source/dev-plugin-overrides.utils.js +0 -111
  56. package/dist/commands/plugin/development-source/first-party-plugin-load-paths.utils.d.ts +0 -9
  57. package/dist/commands/plugin/development-source/first-party-plugin-load-paths.utils.js +0 -183
  58. package/dist/commands/plugin/plugin-extension-registry.d.ts +0 -10
  59. package/dist/commands/plugin/plugin-extension-registry.js +0 -35
  60. package/dist/commands/plugin/plugin-registry-loader.utils.d.ts +0 -14
  61. package/dist/commands/plugin/plugin-registry-loader.utils.js +0 -43
  62. package/dist/commands/plugin/plugin-reload.d.ts +0 -13
  63. package/dist/commands/plugin/plugin-reload.js +0 -42
  64. package/dist/shared/services/extensions/extension-lifecycle.service.d.ts +0 -63
  65. package/dist/shared/services/extensions/extension-lifecycle.service.js +0 -174
  66. package/dist/shared/services/extensions/service-extension-runtime.service.d.ts +0 -52
  67. package/dist/shared/services/extensions/service-extension-runtime.service.js +0 -325
  68. package/dist/shared/services/gateway/cron-job-handler.service.js +0 -100
  69. package/dist/shared/services/runtime/utils/skills-loader.utils.d.ts +0 -12
  70. package/dist/shared/services/runtime/utils/skills-loader.utils.js +0 -9
  71. package/dist/shared/services/session/service-deferred-ncp-agent.service.d.ts +0 -14
  72. package/dist/shared/services/session/service-deferred-ncp-agent.service.js +0 -85
@@ -2,59 +2,8 @@ import { parseSessionKey, writeRestartSentinel } from "../services/restart/resta
2
2
  import { getPackageVersion as getPackageVersion$1 } from "../utils/package/package-manifest.utils.js";
3
3
  import "../utils/cli.utils.js";
4
4
  import { NpmRuntimeUpdateCommandService } from "../../launcher/npm-runtime-update-command.service.js";
5
- import { ConfigSchema, buildConfigSchema, buildReloadPlan, diffConfigPaths, normalizeInlineSecretRefs, redactConfigObject } from "@nextclaw/core";
6
- import { existsSync, readFileSync } from "node:fs";
7
- import { createHash } from "node:crypto";
5
+ import "@nextclaw/core";
8
6
  //#region src/shared/controllers/gateway.controller.ts
9
- const hashRaw = (raw) => createHash("sha256").update(raw).digest("hex");
10
- const readConfigSnapshot = (getConfigPath) => {
11
- const path = getConfigPath();
12
- let raw = "";
13
- let parsed = {};
14
- if (existsSync(path)) {
15
- raw = readFileSync(path, "utf-8");
16
- try {
17
- parsed = JSON.parse(raw);
18
- } catch {
19
- parsed = {};
20
- }
21
- }
22
- let config;
23
- let valid = true;
24
- try {
25
- config = ConfigSchema.parse(normalizeInlineSecretRefs(parsed));
26
- } catch {
27
- config = ConfigSchema.parse({});
28
- valid = false;
29
- }
30
- if (!raw) raw = JSON.stringify(config, null, 2);
31
- const hash = hashRaw(raw);
32
- const schema = buildConfigSchema({ version: getPackageVersion$1() });
33
- const redacted = redactConfigObject(config, schema.uiHints);
34
- return {
35
- raw: valid ? JSON.stringify(redacted, null, 2) : null,
36
- hash: valid ? hash : null,
37
- config,
38
- redacted,
39
- valid
40
- };
41
- };
42
- const redactValue = (value) => {
43
- return redactConfigObject(value, buildConfigSchema({ version: getPackageVersion$1() }).uiHints);
44
- };
45
- const mergeDeep = (base, patch) => {
46
- const next = { ...base };
47
- for (const [key, value] of Object.entries(patch)) if (value && typeof value === "object" && !Array.isArray(value)) {
48
- const baseVal = base[key];
49
- if (baseVal && typeof baseVal === "object" && !Array.isArray(baseVal)) next[key] = mergeDeep(baseVal, value);
50
- else next[key] = mergeDeep({}, value);
51
- } else next[key] = value;
52
- return next;
53
- };
54
- const buildPendingRestartMessage = (paths) => {
55
- if (paths.length === 0) return "Config saved. Restart manually to apply changes.";
56
- return `Config saved. Restart manually to apply: ${paths.join(", ")}.`;
57
- };
58
7
  var GatewayControllerImpl = class {
59
8
  constructor(deps) {
60
9
  this.deps = deps;
@@ -87,19 +36,20 @@ var GatewayControllerImpl = class {
87
36
  };
88
37
  };
89
38
  writeRestartSentinelPayload = async (params) => {
90
- const sessionKey = this.normalizeOptionalString(params.sessionKey);
39
+ const { kind, note, reason, sessionKey: rawSessionKey, status, strategy } = params;
40
+ const sessionKey = this.normalizeOptionalString(rawSessionKey);
91
41
  const deliveryContext = this.resolveDeliveryContext(sessionKey);
92
42
  try {
93
43
  return await writeRestartSentinel({
94
- kind: params.kind,
95
- status: params.status,
44
+ kind,
45
+ status,
96
46
  ts: Date.now(),
97
47
  sessionKey,
98
48
  deliveryContext,
99
- message: params.note ?? null,
49
+ message: note ?? null,
100
50
  stats: {
101
- reason: params.reason ?? null,
102
- strategy: params.strategy ?? null
51
+ reason: reason ?? null,
52
+ strategy: strategy ?? null
103
53
  }
104
54
  });
105
55
  } catch {
@@ -107,58 +57,22 @@ var GatewayControllerImpl = class {
107
57
  }
108
58
  };
109
59
  requestRestart = async (options) => {
60
+ const { delayMs, reason } = options ?? {};
110
61
  if (this.deps.requestRestart) {
111
62
  await this.deps.requestRestart(options);
112
63
  return;
113
64
  }
114
- const delay = typeof options?.delayMs === "number" && Number.isFinite(options.delayMs) ? Math.max(0, options.delayMs) : 100;
115
- console.log(`Gateway restart requested via tool${options?.reason ? ` (${options.reason})` : ""}.`);
65
+ const delay = typeof delayMs === "number" && Number.isFinite(delayMs) ? Math.max(0, delayMs) : 100;
66
+ console.log(`Gateway restart requested via tool${reason ? ` (${reason})` : ""}.`);
116
67
  setTimeout(() => {
117
68
  process.exit(0);
118
69
  }, delay);
119
70
  };
120
- createConfigMutationResult = (params) => {
121
- const pendingRestart = params.plan.restartRequired.length > 0 ? {
122
- required: true,
123
- automatic: false,
124
- changedPaths: [...params.plan.restartRequired],
125
- message: buildPendingRestartMessage(params.plan.restartRequired)
126
- } : null;
127
- const message = params.changedPaths.length === 0 ? "Config already matched the requested state." : pendingRestart ? params.changedPaths.length > params.plan.restartRequired.length ? "Config saved. Supported changes were applied immediately; restart manually to apply the rest." : "Config saved. Restart manually to apply changes." : "Config saved and applied.";
128
- return {
129
- ok: true,
130
- note: params.note ?? null,
131
- path: this.deps.getConfigPath(),
132
- config: redactValue(params.config),
133
- changedPaths: [...params.changedPaths],
134
- message,
135
- pendingRestart
136
- };
137
- };
138
- applyConfigChange = async (params) => {
139
- const { nextConfig, note } = params;
140
- const changedPaths = diffConfigPaths(readConfigSnapshot(this.deps.getConfigPath).config, nextConfig);
141
- const plan = buildReloadPlan(changedPaths);
142
- if (changedPaths.length === 0) return this.createConfigMutationResult({
143
- changedPaths,
144
- config: nextConfig,
145
- note,
146
- plan
147
- });
148
- this.deps.saveConfig(nextConfig);
149
- await this.deps.configManager.applyReloadPlan(nextConfig);
150
- return this.createConfigMutationResult({
151
- changedPaths,
152
- config: nextConfig,
153
- note,
154
- plan
155
- });
156
- };
157
71
  status = () => {
158
72
  return {
159
73
  channels: this.deps.channels.enabledChannels,
160
74
  cron: this.deps.cron.status(),
161
- configPath: this.deps.getConfigPath()
75
+ configPath: this.deps.configManager.configPath
162
76
  };
163
77
  };
164
78
  reloadConfig = async (reason) => {
@@ -175,95 +89,25 @@ var GatewayControllerImpl = class {
175
89
  return "Restart scheduled";
176
90
  };
177
91
  getConfig = async () => {
178
- const snapshot = readConfigSnapshot(this.deps.getConfigPath);
179
- return {
180
- raw: snapshot.raw,
181
- hash: snapshot.hash,
182
- path: this.deps.getConfigPath(),
183
- config: snapshot.redacted,
184
- parsed: snapshot.redacted,
185
- resolved: snapshot.redacted,
186
- valid: snapshot.valid
187
- };
92
+ return this.deps.configManager.getConfigSnapshot({ version: getPackageVersion$1() });
188
93
  };
189
94
  getConfigSchema = async () => {
190
- return buildConfigSchema({ version: getPackageVersion$1() });
95
+ return this.deps.configManager.getConfigSchema({ version: getPackageVersion$1() });
191
96
  };
192
97
  applyConfig = async (params) => {
193
- const snapshot = readConfigSnapshot(this.deps.getConfigPath);
194
- if (!params.baseHash) return {
195
- ok: false,
196
- error: "config base hash required; re-run config.get and retry"
197
- };
198
- if (!snapshot.valid || !snapshot.hash) return {
199
- ok: false,
200
- error: "config base hash unavailable; re-run config.get and retry"
201
- };
202
- if (params.baseHash !== snapshot.hash) return {
203
- ok: false,
204
- error: "config changed since last load; re-run config.get and retry"
205
- };
206
- let parsedRaw;
207
- try {
208
- parsedRaw = JSON.parse(params.raw);
209
- } catch {
210
- return {
211
- ok: false,
212
- error: "invalid JSON in raw config"
213
- };
214
- }
215
- let validated;
216
- try {
217
- validated = ConfigSchema.parse(normalizeInlineSecretRefs(parsedRaw));
218
- } catch (err) {
219
- return {
220
- ok: false,
221
- error: `invalid config: ${String(err)}`
222
- };
223
- }
224
- return this.applyConfigChange({
225
- kind: "config.apply",
226
- nextConfig: validated,
227
- note: params.note
98
+ return this.deps.configManager.applyRawConfig({
99
+ raw: params.raw,
100
+ baseHash: params.baseHash,
101
+ note: params.note,
102
+ version: getPackageVersion$1()
228
103
  });
229
104
  };
230
105
  patchConfig = async (params) => {
231
- const snapshot = readConfigSnapshot(this.deps.getConfigPath);
232
- if (!params.baseHash) return {
233
- ok: false,
234
- error: "config base hash required; re-run config.get and retry"
235
- };
236
- if (!snapshot.valid || !snapshot.hash) return {
237
- ok: false,
238
- error: "config base hash unavailable; re-run config.get and retry"
239
- };
240
- if (params.baseHash !== snapshot.hash) return {
241
- ok: false,
242
- error: "config changed since last load; re-run config.get and retry"
243
- };
244
- let patch;
245
- try {
246
- patch = JSON.parse(params.raw);
247
- } catch {
248
- return {
249
- ok: false,
250
- error: "invalid JSON in raw config"
251
- };
252
- }
253
- const merged = mergeDeep(snapshot.config, patch);
254
- let validated;
255
- try {
256
- validated = ConfigSchema.parse(normalizeInlineSecretRefs(merged));
257
- } catch (err) {
258
- return {
259
- ok: false,
260
- error: `invalid config: ${String(err)}`
261
- };
262
- }
263
- return this.applyConfigChange({
264
- kind: "config.patch",
265
- nextConfig: validated,
266
- note: params.note
106
+ return this.deps.configManager.patchRawConfig({
107
+ raw: params.raw,
108
+ baseHash: params.baseHash,
109
+ note: params.note,
110
+ version: getPackageVersion$1()
267
111
  });
268
112
  };
269
113
  updateRun = async (params) => {
@@ -1,19 +1,14 @@
1
- import { NextclawExtensionRegistry } from "../../../../commands/plugin/plugin-extension-registry.js";
2
1
  import { NextclawGatewayRuntime } from "../nextclaw-gateway-runtime.service.js";
3
2
  import { Config } from "@nextclaw/core";
4
- import { PluginChannelBinding, PluginRegistry, PluginUiMetadata } from "@nextclaw/openclaw-compat";
3
+ import { PluginChannelBinding } from "@nextclaw/openclaw-compat";
5
4
 
6
5
  //#region src/shared/services/gateway/managers/gateway-plugin.manager.d.ts
7
6
  declare class GatewayPluginManager {
8
7
  private readonly gateway;
9
- private extensionContributions;
10
- private snapshot;
11
8
  private gatewayHandles;
12
9
  constructor(gateway: NextclawGatewayRuntime);
13
- getRegistry: () => PluginRegistry;
14
- getExtensionRegistry: () => NextclawExtensionRegistry;
15
10
  getChannelBindings: () => PluginChannelBinding[];
16
- getUiMetadata: () => PluginUiMetadata[];
11
+ getUiMetadata: () => any;
17
12
  load: () => Promise<void>;
18
13
  reloadForConfigChange: (params: {
19
14
  config: Config;
@@ -30,8 +25,6 @@ declare class GatewayPluginManager {
30
25
  private resolveGatewayAccountIds;
31
26
  private reportGatewayStartFailure;
32
27
  private isChannelEnabled;
33
- private replaceSnapshot;
34
- private loadKernelExtensionContributions;
35
28
  }
36
29
  //#endregion
37
30
  export { GatewayPluginManager };
@@ -1,76 +1,38 @@
1
- import { toExtensionRegistry } from "../../../../commands/plugin/plugin-extension-registry.js";
2
- import { createEmptyPluginRegistry, discoverPluginRegistryStatus, loadPluginRegistryProgressively } from "../../../../commands/plugin/plugin-registry-loader.utils.js";
3
1
  import { logPluginDiagnostics } from "../../../../commands/plugin/index.js";
4
- import { shouldRestartChannelsForPluginReload } from "../../../../commands/plugin/plugin-reload.js";
5
2
  import { logPluginGatewayDiagnostics, pluginGatewayLogger } from "../service-startup-support.service.js";
6
- import { getWorkspacePath } from "@nextclaw/core";
7
- import { getPluginChannelBindings, getPluginUiMetadataFromRegistry, toPluginConfigView } from "@nextclaw/openclaw-compat";
3
+ import { toPluginConfigView } from "@nextclaw/openclaw-compat";
8
4
  import { eventKeys } from "@nextclaw/shared";
9
5
  //#region src/shared/services/gateway/managers/gateway-plugin.manager.ts
10
- function toManifestChannelRegistrations(channelBindings) {
11
- return channelBindings.map((binding) => ({
12
- extensionId: binding.pluginId,
13
- channel: binding.channel,
14
- source: "extension-manifest"
15
- }));
16
- }
17
- function buildSnapshot(registry, extensionContributions) {
18
- const extensionChannelIds = new Set(extensionContributions.channelBindings.map((binding) => binding.channelId));
19
- const extensionPluginIds = new Set(extensionContributions.uiMetadata.map((metadata) => metadata.id));
20
- const registryExtensionRegistry = toExtensionRegistry(registry);
21
- return {
22
- registry,
23
- extensionRegistry: {
24
- ...registryExtensionRegistry,
25
- channels: [...registryExtensionRegistry.channels.filter((registration) => {
26
- const channelId = registration.channel.id?.trim();
27
- return !channelId || !extensionChannelIds.has(channelId);
28
- }), ...toManifestChannelRegistrations(extensionContributions.channelBindings)]
29
- },
30
- channelBindings: [...getPluginChannelBindings(registry).filter((binding) => !extensionChannelIds.has(binding.channelId)), ...extensionContributions.channelBindings],
31
- uiMetadata: [...getPluginUiMetadataFromRegistry(registry).filter((metadata) => !extensionPluginIds.has(metadata.id)), ...extensionContributions.uiMetadata]
32
- };
33
- }
34
- function countEnabledPlugins(config, workspaceDir) {
35
- return discoverPluginRegistryStatus(config, workspaceDir).plugins.filter((plugin) => plugin.enabled).length;
36
- }
37
6
  var GatewayPluginManager = class {
38
- extensionContributions = {
39
- channelBindings: [],
40
- uiMetadata: []
41
- };
42
- snapshot = buildSnapshot(createEmptyPluginRegistry(), this.extensionContributions);
43
7
  gatewayHandles = [];
44
8
  constructor(gateway) {
45
9
  this.gateway = gateway;
46
10
  }
47
- getRegistry = () => this.snapshot.registry;
48
- getExtensionRegistry = () => this.snapshot.extensionRegistry;
49
- getChannelBindings = () => this.snapshot.channelBindings;
50
- getUiMetadata = () => this.snapshot.uiMetadata;
11
+ getChannelBindings = () => this.gateway.kernel.extensions.getChannelBindings();
12
+ getUiMetadata = () => this.gateway.kernel.extensions.getUiMetadata();
51
13
  load = async () => {
52
14
  const config = this.gateway.configManager.loadConfig();
53
- const workspace = getWorkspacePath(config.agents.defaults.workspace);
54
- const totalPluginCount = countEnabledPlugins(config, workspace);
55
- let loadedPluginCount = 0;
56
- this.gateway.bootstrapStatus.markPluginHydrationRunning({ totalPluginCount });
15
+ let totalPluginCount = 0;
57
16
  this.gateway.bootstrapStatus.markChannelsPending();
58
17
  try {
59
- const registry = await loadPluginRegistryProgressively(config, workspace, { onPluginProcessed: ({ loadedPluginCount: nextCount }) => {
60
- loadedPluginCount = nextCount;
61
- this.gateway.bootstrapStatus.markPluginHydrationProgress({
62
- loadedPluginCount: nextCount,
63
- totalPluginCount
64
- });
65
- } });
66
- this.extensionContributions = await this.gateway.extensions.loadContributions();
67
- const shouldRebuildChannels = this.replaceSnapshot(registry, []);
68
- this.loadKernelExtensionContributions(registry);
69
- logPluginDiagnostics(registry);
70
- if (shouldRebuildChannels) await this.gateway.configManager.rebuildChannels(config, { start: false });
18
+ const result = await this.gateway.kernel.extensions.load({
19
+ config,
20
+ onLoadStart: ({ totalPluginCount: nextTotalPluginCount }) => {
21
+ totalPluginCount = nextTotalPluginCount;
22
+ this.gateway.bootstrapStatus.markPluginHydrationRunning({ totalPluginCount: nextTotalPluginCount });
23
+ },
24
+ onPluginProcessed: ({ loadedPluginCount: nextCount }) => {
25
+ this.gateway.bootstrapStatus.markPluginHydrationProgress({
26
+ loadedPluginCount: nextCount,
27
+ totalPluginCount
28
+ });
29
+ }
30
+ });
31
+ logPluginDiagnostics({ diagnostics: result.diagnostics });
32
+ if (result.shouldRestartChannels) await this.gateway.configManager.rebuildChannels(config, { start: false });
71
33
  this.publishConfigChanges();
72
34
  this.gateway.bootstrapStatus.markPluginHydrationReady({
73
- loadedPluginCount: loadedPluginCount || totalPluginCount,
35
+ loadedPluginCount: result.loadedPluginCount,
74
36
  totalPluginCount
75
37
  });
76
38
  } catch (error) {
@@ -79,15 +41,14 @@ var GatewayPluginManager = class {
79
41
  }
80
42
  };
81
43
  reloadForConfigChange = async (params) => {
82
- const workspace = getWorkspacePath(params.config.agents.defaults.workspace);
83
- const registry = await loadPluginRegistryProgressively(params.config, workspace);
84
- this.extensionContributions = await this.gateway.extensions.loadContributions();
85
- const restartChannels = this.replaceSnapshot(registry, params.changedPaths);
86
- this.loadKernelExtensionContributions(registry);
87
- logPluginDiagnostics(registry);
88
- if (restartChannels) await this.restartGateways();
44
+ const result = await this.gateway.kernel.extensions.reloadForConfigChange({
45
+ config: params.config,
46
+ changedPaths: params.changedPaths
47
+ });
48
+ logPluginDiagnostics({ diagnostics: result.diagnostics });
49
+ if (result.shouldRestartChannels) await this.restartGateways();
89
50
  this.publishConfigChanges();
90
- return { restartChannels };
51
+ return { restartChannels: result.shouldRestartChannels };
91
52
  };
92
53
  reloadForDevHotReload = async (changedPaths) => {
93
54
  const config = this.gateway.configManager.loadConfig();
@@ -100,8 +61,9 @@ var GatewayPluginManager = class {
100
61
  const config = this.gateway.configManager.loadConfig();
101
62
  const diagnostics = [];
102
63
  const handles = [];
103
- const configView = toPluginConfigView(config, this.snapshot.channelBindings);
104
- for (const binding of this.snapshot.channelBindings) {
64
+ const channelBindings = this.gateway.kernel.extensions.getChannelBindings();
65
+ const configView = toPluginConfigView(config, channelBindings);
66
+ for (const binding of channelBindings) {
105
67
  if (!this.isChannelEnabled(binding.channelId, configView)) continue;
106
68
  await this.startChannelGateways({
107
69
  binding,
@@ -207,26 +169,6 @@ var GatewayPluginManager = class {
207
169
  if (!channelConfig || typeof channelConfig !== "object" || Array.isArray(channelConfig)) return false;
208
170
  return channelConfig.enabled === true;
209
171
  };
210
- replaceSnapshot = (registry, changedPaths) => {
211
- const nextSnapshot = buildSnapshot(registry, this.extensionContributions);
212
- const shouldRestartChannels = shouldRestartChannelsForPluginReload({
213
- changedPaths,
214
- currentPluginChannelBindings: this.snapshot.channelBindings,
215
- nextPluginChannelBindings: nextSnapshot.channelBindings,
216
- currentExtensionChannels: this.snapshot.extensionRegistry.channels,
217
- nextExtensionChannels: nextSnapshot.extensionRegistry.channels
218
- });
219
- this.snapshot = nextSnapshot;
220
- return shouldRestartChannels;
221
- };
222
- loadKernelExtensionContributions = (registry) => {
223
- this.gateway.kernel.extensions.loadContributions({
224
- registry,
225
- extensionRegistry: this.snapshot.extensionRegistry,
226
- channelBindings: this.snapshot.channelBindings,
227
- uiMetadata: this.snapshot.uiMetadata
228
- });
229
- };
230
172
  };
231
173
  //#endregion
232
174
  export { GatewayPluginManager };
@@ -1,21 +1,16 @@
1
- import { DeferredUiNcpAgentController } from "../session/service-deferred-ncp-agent.service.js";
2
1
  import { NextclawGatewayRuntime } from "./nextclaw-gateway-runtime.service.js";
3
- import { NextclawKernel } from "@nextclaw/kernel";
4
2
 
5
3
  //#region src/shared/services/gateway/nextclaw-app.service.d.ts
6
4
  type UiStartupHandle = {
7
- deferredNcpAgent: DeferredUiNcpAgentController;
8
5
  endpoint: string;
9
6
  };
10
- type NextclawAppKernel = Pick<NextclawKernel, "agentRuntimeManager" | "start">;
11
7
  declare class NextclawApp {
12
8
  private readonly gateway;
13
9
  private readonly kernel;
14
- private kernelReady;
15
- constructor(gateway: NextclawGatewayRuntime, kernel?: NextclawAppKernel);
10
+ constructor(gateway: NextclawGatewayRuntime);
16
11
  start: () => Promise<void>;
17
12
  bootstrapKernel: () => Promise<void>;
18
- warmDerivedCapabilities: () => Promise<void>;
13
+ startDeferredRuntimeServices: () => Promise<void>;
19
14
  private readonly handleKernelStartupError;
20
15
  }
21
16
  //#endregion
@@ -2,10 +2,9 @@ import { logStartupTrace, measureStartupAsync } from "../../utils/startup-trace.
2
2
  //#region src/shared/services/gateway/nextclaw-app.service.ts
3
3
  var NextclawApp = class {
4
4
  kernel;
5
- kernelReady = false;
6
- constructor(gateway, kernel) {
5
+ constructor(gateway) {
7
6
  this.gateway = gateway;
8
- this.kernel = kernel ?? gateway.kernel;
7
+ this.kernel = gateway.kernel;
9
8
  }
10
9
  start = async () => {
11
10
  logStartupTrace("service.deferred_startup.begin");
@@ -14,35 +13,26 @@ var NextclawApp = class {
14
13
  } catch (error) {
15
14
  this.handleKernelStartupError(error);
16
15
  }
17
- await this.warmDerivedCapabilities();
16
+ await this.startDeferredRuntimeServices();
18
17
  console.log("✓ Deferred startup: plugin gateways and channels settled");
19
18
  logStartupTrace("service.deferred_startup.end");
20
19
  };
21
20
  bootstrapKernel = async () => {
22
21
  this.gateway.bootstrapStatus.markNcpAgentRunning();
23
22
  await measureStartupAsync("service.deferred_startup.bootstrap_kernel", async () => await this.kernel.start());
24
- const ncpAgent = this.kernel.agentRuntimeManager.currentHandle;
25
- if (!ncpAgent) throw new Error("Kernel start completed without an agent runtime handle.");
26
- this.gateway.activateAgentRuntime(ncpAgent);
27
- this.kernelReady = true;
23
+ this.gateway.bootstrapStatus.markNcpAgentReady();
28
24
  if (this.gateway.uiConfig.enabled) {
29
25
  console.log("✓ UI NCP agent: ready");
30
26
  return;
31
27
  }
32
28
  console.log("✓ Service NCP agent: ready");
33
29
  };
34
- warmDerivedCapabilities = async () => {
30
+ startDeferredRuntimeServices = async () => {
35
31
  await measureStartupAsync("service.deferred_startup.load_plugins", this.gateway.plugins.load);
36
32
  await measureStartupAsync("service.deferred_startup.start_plugin_gateways", this.gateway.plugins.startGateways);
37
- await measureStartupAsync("service.deferred_startup.start_extensions", this.gateway.extensions.start);
33
+ await measureStartupAsync("service.deferred_startup.start_extensions", async () => await this.kernel.extensions.start({ endpoint: this.gateway.uiStartup.endpoint }));
38
34
  await measureStartupAsync("service.deferred_startup.start_channels", this.gateway.startDeferredChannels);
39
35
  await measureStartupAsync("service.deferred_startup.wake_restart_sentinel", this.gateway.restartWake.wakeFromRestartSentinel);
40
- if (!this.kernelReady) return;
41
- setTimeout(() => {
42
- measureStartupAsync("service.deferred_startup.warm_ncp_capabilities", async () => await this.kernel.agentRuntimeManager.warmDerivedCapabilities()).catch((error) => {
43
- console.warn(`UI NCP derived capability warmup failed: ${error instanceof Error ? error.message : String(error)}`);
44
- });
45
- }, 0).unref?.();
46
36
  };
47
37
  handleKernelStartupError = (error) => {
48
38
  this.gateway.bootstrapStatus.markNcpAgentError(error instanceof Error ? error.message : String(error));
@@ -3,14 +3,13 @@ import { NextclawDistribution } from "../../types/distribution.types.js";
3
3
  import { GatewayControllerImpl } from "../../controllers/gateway.controller.js";
4
4
  import { GatewayPluginManager } from "./managers/gateway-plugin.manager.js";
5
5
  import { GatewayRemoteManager } from "./managers/gateway-remote.manager.js";
6
- import { GatewayRestartWakeService } from "./gateway-restart-wake.service.js";
7
6
  import { UiStartupHandle } from "./nextclaw-app.service.js";
8
7
  import { ServiceBootstrapStatusStore } from "./service-bootstrap-status.service.js";
9
8
  import { ServiceFileWatcherRegistry } from "./service-startup-support.service.js";
10
- import { ServiceExtensionRuntime } from "../extensions/service-extension-runtime.service.js";
9
+ import { GatewayRestartWakeService } from "./gateway-restart-wake.service.js";
11
10
  import * as NextclawCore from "@nextclaw/core";
12
- import { AgentRuntimeHandle, AutomationManager, ConfigManager, LlmProviderManager, NextclawKernel } from "@nextclaw/kernel";
13
- import { MarketplaceApiConfig, UiNcpAgent, UiRuntimeControlHost, UiRuntimeUpdateHost } from "@nextclaw/server";
11
+ import { AutomationManager, ConfigManager, LlmProviderManager, NextclawKernel } from "@nextclaw/kernel";
12
+ import { MarketplaceApiConfig, UiRuntimeControlHost, UiRuntimeUpdateHost } from "@nextclaw/server";
14
13
  import { EventBus, Ingress } from "@nextclaw/shared";
15
14
 
16
15
  //#region src/shared/services/gateway/nextclaw-gateway-runtime.service.d.ts
@@ -60,15 +59,11 @@ declare class NextclawGatewayRuntime {
60
59
  readonly restartWake: GatewayRestartWakeService;
61
60
  bootstrapStatus: ServiceBootstrapStatusStore;
62
61
  uiStartup: UiStartupHandle;
63
- readonly extensions: ServiceExtensionRuntime;
64
- liveAgentRuntime: AgentRuntimeHandle | null;
65
62
  readonly fileWatchers: ServiceFileWatcherRegistry;
66
63
  private deferredChannelStarter;
67
64
  constructor(deps: GatewayRuntimeDeps, options: GatewayRuntimeOptions);
68
65
  start: () => Promise<void>;
69
66
  private reset;
70
- get ncpAgent(): UiNcpAgent;
71
- activateAgentRuntime: (ncpAgent: AgentRuntimeHandle) => void;
72
67
  private createBootstrapStatus;
73
68
  private createDisabledUiStartup;
74
69
  private startUiRuntime;
@@ -84,7 +79,7 @@ declare class NextclawGatewayRuntime {
84
79
  private createGatewayController;
85
80
  private startSupportServices;
86
81
  private configurePluginRuntime;
87
- private installConfigRuntimeHooks;
82
+ private installConfigHostHooks;
88
83
  private configureIngressHandlers;
89
84
  }
90
85
  //#endregion