@nextclaw/service 0.1.1

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 (242) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cli/commands/agent/agent-runtime.utils.d.ts +15 -0
  3. package/dist/cli/commands/agent/agent-runtime.utils.js +85 -0
  4. package/dist/cli/commands/agent/cli-agent-runner.utils.d.ts +21 -0
  5. package/dist/cli/commands/agent/cli-agent-runner.utils.js +89 -0
  6. package/dist/cli/commands/agent/index.d.ts +3 -0
  7. package/dist/cli/commands/agent/index.js +3 -0
  8. package/dist/cli/commands/agent/services/agent-commands.service.d.ts +17 -0
  9. package/dist/cli/commands/agent/services/agent-commands.service.js +112 -0
  10. package/dist/cli/commands/companion/index.d.ts +15 -0
  11. package/dist/cli/commands/companion/index.js +24 -0
  12. package/dist/cli/commands/companion/services/companion-process.service.d.ts +17 -0
  13. package/dist/cli/commands/companion/services/companion-process.service.js +49 -0
  14. package/dist/cli/commands/config/index.d.ts +2 -0
  15. package/dist/cli/commands/config/index.js +2 -0
  16. package/dist/cli/commands/config/services/config-commands.service.d.ts +18 -0
  17. package/dist/cli/commands/config/services/config-commands.service.js +133 -0
  18. package/dist/cli/commands/cron/index.d.ts +2 -0
  19. package/dist/cli/commands/cron/index.js +2 -0
  20. package/dist/cli/commands/cron/services/cron-commands.service.d.ts +22 -0
  21. package/dist/cli/commands/cron/services/cron-commands.service.js +107 -0
  22. package/dist/cli/commands/cron/services/cron-local.service.d.ts +25 -0
  23. package/dist/cli/commands/cron/services/cron-local.service.js +95 -0
  24. package/dist/cli/commands/cron/utils/cron-job.utils.d.ts +31 -0
  25. package/dist/cli/commands/cron/utils/cron-job.utils.js +15 -0
  26. package/dist/cli/commands/diagnostics/index.d.ts +2 -0
  27. package/dist/cli/commands/diagnostics/index.js +2 -0
  28. package/dist/cli/commands/diagnostics/services/diagnostics-commands.service.d.ts +22 -0
  29. package/dist/cli/commands/diagnostics/services/diagnostics-commands.service.js +319 -0
  30. package/dist/cli/commands/diagnostics/utils/diagnostics-render.utils.d.ts +23 -0
  31. package/dist/cli/commands/diagnostics/utils/diagnostics-render.utils.js +66 -0
  32. package/dist/cli/commands/gateway/index.d.ts +14 -0
  33. package/dist/cli/commands/gateway/index.js +15 -0
  34. package/dist/cli/commands/logs/index.d.ts +12 -0
  35. package/dist/cli/commands/logs/index.js +29 -0
  36. package/dist/cli/commands/mcp/index.d.ts +14 -0
  37. package/dist/cli/commands/mcp/index.js +193 -0
  38. package/dist/cli/commands/restart/index.d.ts +20 -0
  39. package/dist/cli/commands/restart/index.js +88 -0
  40. package/dist/cli/commands/secrets/index.d.ts +22 -0
  41. package/dist/cli/commands/secrets/index.js +280 -0
  42. package/dist/cli/commands/serve/index.d.ts +14 -0
  43. package/dist/cli/commands/serve/index.js +19 -0
  44. package/dist/cli/commands/skills/index.d.ts +26 -0
  45. package/dist/cli/commands/skills/index.js +147 -0
  46. package/dist/cli/commands/skills/marketplace-client.d.ts +31 -0
  47. package/dist/cli/commands/skills/marketplace-client.js +84 -0
  48. package/dist/cli/commands/skills/marketplace-command-options.utils.d.ts +25 -0
  49. package/dist/cli/commands/skills/marketplace-command-options.utils.js +31 -0
  50. package/dist/cli/commands/skills/marketplace-identity.utils.d.ts +14 -0
  51. package/dist/cli/commands/skills/marketplace-identity.utils.js +77 -0
  52. package/dist/cli/commands/skills/marketplace-network-retry.d.ts +4 -0
  53. package/dist/cli/commands/skills/marketplace-network-retry.js +32 -0
  54. package/dist/cli/commands/skills/marketplace.metadata.d.ts +29 -0
  55. package/dist/cli/commands/skills/marketplace.metadata.js +158 -0
  56. package/dist/cli/commands/skills/marketplace.service.d.ts +46 -0
  57. package/dist/cli/commands/skills/marketplace.service.js +238 -0
  58. package/dist/cli/commands/skills/skills-query.service.d.ts +141 -0
  59. package/dist/cli/commands/skills/skills-query.service.js +212 -0
  60. package/dist/cli/commands/start/index.d.ts +18 -0
  61. package/dist/cli/commands/start/index.js +25 -0
  62. package/dist/cli/commands/stop/index.d.ts +12 -0
  63. package/dist/cli/commands/stop/index.js +11 -0
  64. package/dist/cli/commands/ui/index.d.ts +14 -0
  65. package/dist/cli/commands/ui/index.js +17 -0
  66. package/dist/cli/commands/usage/index.d.ts +2 -0
  67. package/dist/cli/commands/usage/index.js +2 -0
  68. package/dist/cli/commands/usage/services/llm-usage-command.service.d.ts +22 -0
  69. package/dist/cli/commands/usage/services/llm-usage-command.service.js +160 -0
  70. package/dist/cli/commands/usage/services/llm-usage-query.service.d.ts +43 -0
  71. package/dist/cli/commands/usage/services/llm-usage-query.service.js +85 -0
  72. package/dist/commands/channel/channel-config-view.d.ts +7 -0
  73. package/dist/commands/channel/channel-config-view.js +7 -0
  74. package/dist/commands/channel/index.d.ts +28 -0
  75. package/dist/commands/channel/index.js +224 -0
  76. package/dist/commands/platform-auth/index.d.ts +2 -0
  77. package/dist/commands/platform-auth/index.js +2 -0
  78. package/dist/commands/platform-auth/services/account-status.service.d.ts +18 -0
  79. package/dist/commands/platform-auth/services/account-status.service.js +34 -0
  80. package/dist/commands/platform-auth/services/platform-auth-commands.service.d.ts +77 -0
  81. package/dist/commands/platform-auth/services/platform-auth-commands.service.js +295 -0
  82. package/dist/commands/platform-auth/utils/payload.utils.d.ts +28 -0
  83. package/dist/commands/platform-auth/utils/payload.utils.js +87 -0
  84. package/dist/commands/plugin/development-source/dev-plugin-overrides.utils.d.ts +18 -0
  85. package/dist/commands/plugin/development-source/dev-plugin-overrides.utils.js +111 -0
  86. package/dist/commands/plugin/development-source/first-party-plugin-load-paths.d.ts +9 -0
  87. package/dist/commands/plugin/development-source/first-party-plugin-load-paths.js +183 -0
  88. package/dist/commands/plugin/index.d.ts +30 -0
  89. package/dist/commands/plugin/index.js +266 -0
  90. package/dist/commands/plugin/plugin-command-utils.d.ts +13 -0
  91. package/dist/commands/plugin/plugin-command-utils.js +37 -0
  92. package/dist/commands/plugin/plugin-extension-registry.d.ts +10 -0
  93. package/dist/commands/plugin/plugin-extension-registry.js +35 -0
  94. package/dist/commands/plugin/plugin-mutation-actions.d.ts +15 -0
  95. package/dist/commands/plugin/plugin-mutation-actions.js +162 -0
  96. package/dist/commands/plugin/plugin-registry-loader.d.ts +15 -0
  97. package/dist/commands/plugin/plugin-registry-loader.js +43 -0
  98. package/dist/commands/plugin/plugin-reload.d.ts +13 -0
  99. package/dist/commands/plugin/plugin-reload.js +42 -0
  100. package/dist/commands/remote/index.d.ts +47 -0
  101. package/dist/commands/remote/index.js +174 -0
  102. package/dist/commands/remote/services/remote-access-host.service.d.ts +41 -0
  103. package/dist/commands/remote/services/remote-access-host.service.js +126 -0
  104. package/dist/commands/remote/services/remote-runtime-support.service.d.ts +15 -0
  105. package/dist/commands/remote/services/remote-runtime-support.service.js +79 -0
  106. package/dist/commands/remote/services/remote-service-control.service.d.ts +33 -0
  107. package/dist/commands/remote/services/remote-service-control.service.js +188 -0
  108. package/dist/commands/remote/utils/platform-api-base.utils.d.ts +14 -0
  109. package/dist/commands/remote/utils/platform-api-base.utils.js +39 -0
  110. package/dist/commands/service/index.d.ts +16 -0
  111. package/dist/commands/service/index.js +31 -0
  112. package/dist/commands/service/services/autostart/host-autostart-command.service.d.ts +29 -0
  113. package/dist/commands/service/services/autostart/host-autostart-command.service.js +158 -0
  114. package/dist/commands/service/services/autostart/host-autostart-runtime.service.d.ts +23 -0
  115. package/dist/commands/service/services/autostart/host-autostart-runtime.service.js +53 -0
  116. package/dist/commands/service/services/autostart/host-autostart.service.d.ts +41 -0
  117. package/dist/commands/service/services/autostart/host-autostart.service.js +48 -0
  118. package/dist/commands/service/services/autostart/linux-systemd-autostart.service.d.ts +48 -0
  119. package/dist/commands/service/services/autostart/linux-systemd-autostart.service.js +433 -0
  120. package/dist/commands/service/services/autostart/macos-launch-agent-autostart.service.d.ts +54 -0
  121. package/dist/commands/service/services/autostart/macos-launch-agent-autostart.service.js +405 -0
  122. package/dist/commands/service/services/autostart/windows-task-autostart.service.d.ts +54 -0
  123. package/dist/commands/service/services/autostart/windows-task-autostart.service.js +403 -0
  124. package/dist/commands/service/types/autostart/host-autostart.types.d.ts +64 -0
  125. package/dist/commands/service/types/autostart/host-autostart.types.js +1 -0
  126. package/dist/index.d.ts +4 -0
  127. package/dist/index.js +3 -0
  128. package/dist/launcher/npm-runtime-bundle-layout.store.d.ts +23 -0
  129. package/dist/launcher/npm-runtime-bundle-layout.store.js +37 -0
  130. package/dist/launcher/npm-runtime-bundle-manifest.service.d.ts +9 -0
  131. package/dist/launcher/npm-runtime-bundle-manifest.service.js +39 -0
  132. package/dist/launcher/npm-runtime-bundle.service.d.ts +47 -0
  133. package/dist/launcher/npm-runtime-bundle.service.js +150 -0
  134. package/dist/launcher/npm-runtime-bundle.types.d.ts +49 -0
  135. package/dist/launcher/npm-runtime-bundle.types.js +1 -0
  136. package/dist/launcher/npm-runtime-launcher.service.d.ts +19 -0
  137. package/dist/launcher/npm-runtime-launcher.service.js +57 -0
  138. package/dist/launcher/npm-runtime-update-command.service.d.ts +12 -0
  139. package/dist/launcher/npm-runtime-update-command.service.js +87 -0
  140. package/dist/launcher/npm-runtime-update-source.service.d.ts +19 -0
  141. package/dist/launcher/npm-runtime-update-source.service.js +57 -0
  142. package/dist/launcher/npm-runtime-update-state.store.d.ts +17 -0
  143. package/dist/launcher/npm-runtime-update-state.store.js +92 -0
  144. package/dist/launcher/npm-runtime-update.manager.d.ts +42 -0
  145. package/dist/launcher/npm-runtime-update.manager.js +179 -0
  146. package/dist/launcher/npm-runtime-update.service.d.ts +54 -0
  147. package/dist/launcher/npm-runtime-update.service.js +183 -0
  148. package/dist/service-runtime.service.d.ts +91 -0
  149. package/dist/service-runtime.service.js +392 -0
  150. package/dist/shared/controllers/gateway.controller.d.ts +61 -0
  151. package/dist/shared/controllers/gateway.controller.js +318 -0
  152. package/dist/shared/services/extensions/extension-lifecycle.service.d.ts +56 -0
  153. package/dist/shared/services/extensions/extension-lifecycle.service.js +143 -0
  154. package/dist/shared/services/extensions/service-extension-runtime.service.d.ts +51 -0
  155. package/dist/shared/services/extensions/service-extension-runtime.service.js +338 -0
  156. package/dist/shared/services/gateway/cron-job-handler.service.d.ts +26 -0
  157. package/dist/shared/services/gateway/cron-job-handler.service.js +100 -0
  158. package/dist/shared/services/gateway/gateway-restart-wake.service.d.ts +12 -0
  159. package/dist/shared/services/gateway/gateway-restart-wake.service.js +91 -0
  160. package/dist/shared/services/gateway/managers/gateway-plugin.manager.d.ts +37 -0
  161. package/dist/shared/services/gateway/managers/gateway-plugin.manager.js +218 -0
  162. package/dist/shared/services/gateway/managers/gateway-remote.manager.d.ts +20 -0
  163. package/dist/shared/services/gateway/managers/gateway-remote.manager.js +25 -0
  164. package/dist/shared/services/gateway/nextclaw-app.service.d.ts +22 -0
  165. package/dist/shared/services/gateway/nextclaw-app.service.js +53 -0
  166. package/dist/shared/services/gateway/nextclaw-gateway-runtime.service.d.ts +89 -0
  167. package/dist/shared/services/gateway/nextclaw-gateway-runtime.service.js +337 -0
  168. package/dist/shared/services/gateway/service-bootstrap-status.d.ts +33 -0
  169. package/dist/shared/services/gateway/service-bootstrap-status.js +152 -0
  170. package/dist/shared/services/gateway/service-startup-support.service.d.ts +42 -0
  171. package/dist/shared/services/gateway/service-startup-support.service.js +96 -0
  172. package/dist/shared/services/gateway/utils/gateway-runtime-lifecycle.utils.d.ts +9 -0
  173. package/dist/shared/services/gateway/utils/gateway-runtime-lifecycle.utils.js +10 -0
  174. package/dist/shared/services/marketplace/service-marketplace-installer.service.d.ts +31 -0
  175. package/dist/shared/services/marketplace/service-marketplace-installer.service.js +99 -0
  176. package/dist/shared/services/marketplace/service-mcp-marketplace-ops.d.ts +39 -0
  177. package/dist/shared/services/marketplace/service-mcp-marketplace-ops.js +67 -0
  178. package/dist/shared/services/plugin/utils/plugin-dev-hot-reload.utils.d.ts +24 -0
  179. package/dist/shared/services/plugin/utils/plugin-dev-hot-reload.utils.js +117 -0
  180. package/dist/shared/services/plugin/utils/plugin-runtime-bridge.utils.d.ts +6 -0
  181. package/dist/shared/services/plugin/utils/plugin-runtime-bridge.utils.js +96 -0
  182. package/dist/shared/services/restart/restart-coordinator.service.d.ts +30 -0
  183. package/dist/shared/services/restart/restart-coordinator.service.js +51 -0
  184. package/dist/shared/services/restart/restart-sentinel.service.d.ts +39 -0
  185. package/dist/shared/services/restart/restart-sentinel.service.js +88 -0
  186. package/dist/shared/services/restart/runtime-restart-request.service.d.ts +24 -0
  187. package/dist/shared/services/restart/runtime-restart-request.service.js +42 -0
  188. package/dist/shared/services/runtime/runtime-command.service.d.ts +37 -0
  189. package/dist/shared/services/runtime/runtime-command.service.js +163 -0
  190. package/dist/shared/services/runtime/runtime-config-init.service.d.ts +4 -0
  191. package/dist/shared/services/runtime/runtime-config-init.service.js +10 -0
  192. package/dist/shared/services/runtime/service-managed-startup.service.d.ts +146 -0
  193. package/dist/shared/services/runtime/service-managed-startup.service.js +426 -0
  194. package/dist/shared/services/runtime/service-remote-runtime.service.d.ts +53 -0
  195. package/dist/shared/services/runtime/service-remote-runtime.service.js +173 -0
  196. package/dist/shared/services/runtime/utils/skills-loader.utils.d.ts +12 -0
  197. package/dist/shared/services/runtime/utils/skills-loader.utils.js +9 -0
  198. package/dist/shared/services/session/service-deferred-ncp-agent.service.d.ts +14 -0
  199. package/dist/shared/services/session/service-deferred-ncp-agent.service.js +85 -0
  200. package/dist/shared/services/ui/companion-runtime.service.d.ts +33 -0
  201. package/dist/shared/services/ui/companion-runtime.service.js +145 -0
  202. package/dist/shared/services/ui/local-ui-discovery.service.d.ts +19 -0
  203. package/dist/shared/services/ui/local-ui-discovery.service.js +41 -0
  204. package/dist/shared/services/ui/npm-runtime-update-host.service.d.ts +40 -0
  205. package/dist/shared/services/ui/npm-runtime-update-host.service.js +181 -0
  206. package/dist/shared/services/ui/runtime-control-host.service.d.ts +28 -0
  207. package/dist/shared/services/ui/runtime-control-host.service.js +89 -0
  208. package/dist/shared/services/ui/service-remote-access.service.d.ts +25 -0
  209. package/dist/shared/services/ui/service-remote-access.service.js +38 -0
  210. package/dist/shared/services/ui/ui-bridge-api.service.d.ts +16 -0
  211. package/dist/shared/services/ui/ui-bridge-api.service.js +43 -0
  212. package/dist/shared/services/workspace/workspace-manager.service.d.ts +19 -0
  213. package/dist/shared/services/workspace/workspace-manager.service.js +135 -0
  214. package/dist/shared/stores/companion-runtime.store.d.ts +15 -0
  215. package/dist/shared/stores/companion-runtime.store.js +27 -0
  216. package/dist/shared/stores/local-ui-runtime.store.d.ts +25 -0
  217. package/dist/shared/stores/local-ui-runtime.store.js +54 -0
  218. package/dist/shared/stores/managed-service-state.store.d.ts +28 -0
  219. package/dist/shared/stores/managed-service-state.store.js +38 -0
  220. package/dist/shared/stores/pending-restart.store.d.ts +21 -0
  221. package/dist/shared/stores/pending-restart.store.js +35 -0
  222. package/dist/shared/types/cli.types.d.ts +295 -0
  223. package/dist/shared/types/cli.types.js +1 -0
  224. package/dist/shared/utils/cli.utils.d.ts +34 -0
  225. package/dist/shared/utils/cli.utils.js +262 -0
  226. package/dist/shared/utils/config-path.d.ts +15 -0
  227. package/dist/shared/utils/config-path.js +167 -0
  228. package/dist/shared/utils/marketplace/cli-subcommand-launch.utils.d.ts +16 -0
  229. package/dist/shared/utils/marketplace/cli-subcommand-launch.utils.js +46 -0
  230. package/dist/shared/utils/marketplace/service-marketplace-helpers.utils.d.ts +9 -0
  231. package/dist/shared/utils/marketplace/service-marketplace-helpers.utils.js +33 -0
  232. package/dist/shared/utils/package/package-manifest.utils.d.ts +8 -0
  233. package/dist/shared/utils/package/package-manifest.utils.js +48 -0
  234. package/dist/shared/utils/runtime-helpers.d.ts +14 -0
  235. package/dist/shared/utils/runtime-helpers.js +26 -0
  236. package/dist/shared/utils/service-port-probe.utils.d.ts +41 -0
  237. package/dist/shared/utils/service-port-probe.utils.js +164 -0
  238. package/dist/shared/utils/startup-trace.d.ts +7 -0
  239. package/dist/shared/utils/startup-trace.js +37 -0
  240. package/dist/shared/utils/top-level-nextclaw-command-env.utils.d.ts +4 -0
  241. package/dist/shared/utils/top-level-nextclaw-command-env.utils.js +10 -0
  242. package/package.json +68 -0
@@ -0,0 +1,318 @@
1
+ import { getPackageVersion as getPackageVersion$1 } from "../utils/package/package-manifest.utils.js";
2
+ import "../utils/cli.utils.js";
3
+ import { NpmRuntimeUpdateCommandService } from "../../launcher/npm-runtime-update-command.service.js";
4
+ import { parseSessionKey, writeRestartSentinel } from "../services/restart/restart-sentinel.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";
8
+ //#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
+ var GatewayControllerImpl = class {
59
+ constructor(deps) {
60
+ this.deps = deps;
61
+ }
62
+ normalizeOptionalString = (value) => {
63
+ if (typeof value !== "string") return;
64
+ return value.trim() || void 0;
65
+ };
66
+ resolveDeliveryContext = (sessionKey) => {
67
+ const normalizedSessionKey = this.normalizeOptionalString(sessionKey);
68
+ const keyTarget = parseSessionKey(normalizedSessionKey);
69
+ const keyRoute = keyTarget && keyTarget.channel !== "agent" ? keyTarget : null;
70
+ const metadata = (normalizedSessionKey ? this.deps.sessionManager?.getIfExists(normalizedSessionKey) : null)?.metadata ?? {};
71
+ const rawContext = metadata.last_delivery_context;
72
+ const cachedContext = rawContext && typeof rawContext === "object" && !Array.isArray(rawContext) ? rawContext : null;
73
+ const cachedMetadataRaw = cachedContext?.metadata;
74
+ const cachedMetadata = cachedMetadataRaw && typeof cachedMetadataRaw === "object" && !Array.isArray(cachedMetadataRaw) ? { ...cachedMetadataRaw } : {};
75
+ const channel = this.normalizeOptionalString(cachedContext?.channel) ?? keyRoute?.channel;
76
+ const chatId = this.normalizeOptionalString(cachedContext?.chatId) ?? this.normalizeOptionalString(metadata.last_to) ?? keyRoute?.chatId;
77
+ const replyTo = this.normalizeOptionalString(cachedContext?.replyTo) ?? this.normalizeOptionalString(metadata.last_message_id);
78
+ const accountId = this.normalizeOptionalString(cachedContext?.accountId) ?? this.normalizeOptionalString(metadata.last_account_id);
79
+ if (!channel || !chatId) return;
80
+ if (accountId && !this.normalizeOptionalString(cachedMetadata.accountId)) cachedMetadata.accountId = accountId;
81
+ return {
82
+ channel,
83
+ chatId,
84
+ ...replyTo ? { replyTo } : {},
85
+ ...accountId ? { accountId } : {},
86
+ ...Object.keys(cachedMetadata).length > 0 ? { metadata: cachedMetadata } : {}
87
+ };
88
+ };
89
+ writeRestartSentinelPayload = async (params) => {
90
+ const sessionKey = this.normalizeOptionalString(params.sessionKey);
91
+ const deliveryContext = this.resolveDeliveryContext(sessionKey);
92
+ try {
93
+ return await writeRestartSentinel({
94
+ kind: params.kind,
95
+ status: params.status,
96
+ ts: Date.now(),
97
+ sessionKey,
98
+ deliveryContext,
99
+ message: params.note ?? null,
100
+ stats: {
101
+ reason: params.reason ?? null,
102
+ strategy: params.strategy ?? null
103
+ }
104
+ });
105
+ } catch {
106
+ return null;
107
+ }
108
+ };
109
+ requestRestart = async (options) => {
110
+ if (this.deps.requestRestart) {
111
+ await this.deps.requestRestart(options);
112
+ return;
113
+ }
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})` : ""}.`);
116
+ setTimeout(() => {
117
+ process.exit(0);
118
+ }, delay);
119
+ };
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
+ status = () => {
158
+ return {
159
+ channels: this.deps.channels.enabledChannels,
160
+ cron: this.deps.cron.status(),
161
+ configPath: this.deps.getConfigPath()
162
+ };
163
+ };
164
+ reloadConfig = async (reason) => {
165
+ return this.deps.configManager.reloadConfig(reason);
166
+ };
167
+ restart = async (options) => {
168
+ await this.writeRestartSentinelPayload({
169
+ kind: "restart",
170
+ status: "ok",
171
+ sessionKey: options?.sessionKey,
172
+ reason: options?.reason ?? "gateway.restart"
173
+ });
174
+ await this.requestRestart(options);
175
+ return "Restart scheduled";
176
+ };
177
+ 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
+ };
188
+ };
189
+ getConfigSchema = async () => {
190
+ return buildConfigSchema({ version: getPackageVersion$1() });
191
+ };
192
+ 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
228
+ });
229
+ };
230
+ 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
267
+ });
268
+ };
269
+ updateRun = async (params) => {
270
+ const versionBefore = getPackageVersion$1();
271
+ params.timeoutMs;
272
+ const updateCommand = new NpmRuntimeUpdateCommandService();
273
+ const downloadedSnapshot = await updateCommand.runManaged({ download: true });
274
+ const snapshot = downloadedSnapshot.status === "downloaded" ? await updateCommand.runManaged({ apply: true }) : downloadedSnapshot;
275
+ if (snapshot.status === "blocked" || snapshot.status === "failed") return {
276
+ ok: false,
277
+ error: snapshot.errorMessage ?? snapshot.blockReason ?? "update failed",
278
+ snapshot,
279
+ version: {
280
+ before: versionBefore,
281
+ after: getPackageVersion$1(),
282
+ changed: false
283
+ }
284
+ };
285
+ const versionAfter = getPackageVersion$1();
286
+ const delayMs = params.restartDelayMs ?? 0;
287
+ const sentinelPath = await this.writeRestartSentinelPayload({
288
+ kind: "update.run",
289
+ status: "ok",
290
+ sessionKey: params.sessionKey,
291
+ note: params.note,
292
+ reason: "update.run",
293
+ strategy: "runtime-bundle"
294
+ });
295
+ await this.requestRestart({
296
+ delayMs,
297
+ reason: "update.run"
298
+ });
299
+ return {
300
+ ok: true,
301
+ note: params.note ?? null,
302
+ restart: {
303
+ scheduled: true,
304
+ delayMs
305
+ },
306
+ strategy: "runtime-bundle",
307
+ snapshot,
308
+ version: {
309
+ before: versionBefore,
310
+ after: versionAfter,
311
+ changed: versionBefore !== versionAfter
312
+ },
313
+ sentinel: sentinelPath ? { path: sentinelPath } : null
314
+ };
315
+ };
316
+ };
317
+ //#endregion
318
+ export { GatewayControllerImpl };
@@ -0,0 +1,56 @@
1
+ import { ChildProcess, spawn } from "node:child_process";
2
+
3
+ //#region src/shared/services/extensions/extension-lifecycle.service.d.ts
4
+ type ExtensionServerConfig = {
5
+ type: "stdio";
6
+ command: string;
7
+ args?: string[];
8
+ env?: Record<string, string>;
9
+ };
10
+ type ExtensionManifest = {
11
+ id: string;
12
+ name?: string;
13
+ version?: string;
14
+ rootDir: string;
15
+ server: ExtensionServerConfig;
16
+ contributes?: {
17
+ channels?: Array<{
18
+ id: string;
19
+ name?: string;
20
+ description?: string;
21
+ meta?: Record<string, unknown>;
22
+ configSchema?: Record<string, unknown>;
23
+ configUiHints?: Record<string, Record<string, unknown>>;
24
+ auth?: boolean | Record<string, unknown>;
25
+ }>;
26
+ };
27
+ };
28
+ type RunningExtensionProcess = {
29
+ manifest: ExtensionManifest;
30
+ process: ChildProcess;
31
+ };
32
+ type ExtensionLifecycleServiceOptions = {
33
+ endpoint: string;
34
+ token: string;
35
+ spawnProcess?: typeof spawn;
36
+ logger?: Pick<Console, "warn">;
37
+ };
38
+ declare class ExtensionManifestDiscoveryService {
39
+ readonly discover: (roots: string[]) => Promise<ExtensionManifest[]>;
40
+ private readonly discoverRoot;
41
+ private readonly readManifestIfExists;
42
+ }
43
+ declare class ExtensionLifecycleService {
44
+ private readonly options;
45
+ private readonly processes;
46
+ private readonly spawnProcess;
47
+ private readonly logger;
48
+ constructor(options: ExtensionLifecycleServiceOptions);
49
+ readonly startAll: (manifests: ExtensionManifest[]) => Promise<RunningExtensionProcess[]>;
50
+ readonly start: (manifest: ExtensionManifest) => RunningExtensionProcess;
51
+ readonly stopAll: () => Promise<void>;
52
+ readonly list: () => RunningExtensionProcess[];
53
+ private readonly stopProcess;
54
+ }
55
+ //#endregion
56
+ export { ExtensionLifecycleService, ExtensionLifecycleServiceOptions, ExtensionManifest, ExtensionManifestDiscoveryService, ExtensionServerConfig, RunningExtensionProcess };
@@ -0,0 +1,143 @@
1
+ import { spawn } from "node:child_process";
2
+ import { dirname, join } from "node:path";
3
+ import { readFile, readdir } from "node:fs/promises";
4
+ //#region src/shared/services/extensions/extension-lifecycle.service.ts
5
+ const EXTENSION_MANIFEST_FILE = "nextclaw.extension.json";
6
+ function readString(value) {
7
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
8
+ }
9
+ function readStringArray(value) {
10
+ if (!Array.isArray(value)) return;
11
+ return value.every((item) => typeof item === "string") ? value : void 0;
12
+ }
13
+ function readStringRecord(value) {
14
+ if (!value || typeof value !== "object" || Array.isArray(value)) return;
15
+ const entries = Object.entries(value);
16
+ if (!entries.every(([, item]) => typeof item === "string")) return;
17
+ return Object.fromEntries(entries);
18
+ }
19
+ function sanitizeExtensionNodeOptions(value) {
20
+ if (!value?.trim()) return;
21
+ const tokens = value.split(/\s+/).filter(Boolean);
22
+ const sanitized = [];
23
+ for (let index = 0; index < tokens.length; index += 1) {
24
+ const token = tokens[index];
25
+ if (token === "--conditions=development" || token === "-C=development") continue;
26
+ if ((token === "--conditions" || token === "-C") && tokens[index + 1] === "development") {
27
+ index += 1;
28
+ continue;
29
+ }
30
+ sanitized.push(token);
31
+ }
32
+ return sanitized.length > 0 ? sanitized.join(" ") : void 0;
33
+ }
34
+ function toManifest(value, rootDir) {
35
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("extension manifest must be an object");
36
+ const record = value;
37
+ const server = record.server;
38
+ if (!server || typeof server !== "object" || Array.isArray(server)) throw new Error("extension manifest server is required");
39
+ const serverRecord = server;
40
+ const id = readString(record.id);
41
+ const command = readString(serverRecord.command);
42
+ if (!id) throw new Error("extension manifest id is required");
43
+ if (serverRecord.type !== "stdio") throw new Error("extension server.type must be stdio");
44
+ if (!command) throw new Error("extension server.command is required");
45
+ return {
46
+ id,
47
+ rootDir,
48
+ ...readString(record.name) ? { name: readString(record.name) } : {},
49
+ ...readString(record.version) ? { version: readString(record.version) } : {},
50
+ server: {
51
+ type: "stdio",
52
+ command,
53
+ ...readStringArray(serverRecord.args) ? { args: readStringArray(serverRecord.args) } : {},
54
+ ...readStringRecord(serverRecord.env) ? { env: readStringRecord(serverRecord.env) } : {}
55
+ },
56
+ ...record.contributes && typeof record.contributes === "object" && !Array.isArray(record.contributes) ? { contributes: record.contributes } : {}
57
+ };
58
+ }
59
+ var ExtensionManifestDiscoveryService = class {
60
+ discover = async (roots) => {
61
+ const manifests = [];
62
+ for (const root of roots) manifests.push(...await this.discoverRoot(root));
63
+ return manifests;
64
+ };
65
+ discoverRoot = async (root) => {
66
+ const directManifest = await this.readManifestIfExists(join(root, EXTENSION_MANIFEST_FILE));
67
+ if (directManifest) return [directManifest];
68
+ const entries = await readdir(root, { withFileTypes: true }).catch(() => []);
69
+ return (await Promise.all(entries.filter((entry) => entry.isDirectory()).map((entry) => this.readManifestIfExists(join(root, entry.name, EXTENSION_MANIFEST_FILE))))).filter((manifest) => Boolean(manifest));
70
+ };
71
+ readManifestIfExists = async (path) => {
72
+ try {
73
+ return toManifest(JSON.parse(await readFile(path, "utf-8")), dirname(path));
74
+ } catch (error) {
75
+ if (error.code === "ENOENT") return null;
76
+ throw error;
77
+ }
78
+ };
79
+ };
80
+ var ExtensionLifecycleService = class {
81
+ processes = /* @__PURE__ */ new Map();
82
+ spawnProcess;
83
+ logger;
84
+ constructor(options) {
85
+ this.options = options;
86
+ this.spawnProcess = options.spawnProcess ?? spawn;
87
+ this.logger = options.logger ?? console;
88
+ }
89
+ startAll = async (manifests) => {
90
+ const started = [];
91
+ for (const manifest of manifests) started.push(this.start(manifest));
92
+ return started;
93
+ };
94
+ start = (manifest) => {
95
+ const existing = this.processes.get(manifest.id);
96
+ if (existing) return existing;
97
+ const child = this.spawnProcess(manifest.server.command, manifest.server.args ?? [], {
98
+ cwd: manifest.rootDir,
99
+ env: {
100
+ ...process.env,
101
+ NODE_OPTIONS: sanitizeExtensionNodeOptions(process.env.NODE_OPTIONS),
102
+ ...manifest.server.env,
103
+ NEXTCLAW_EXTENSION_ID: manifest.id,
104
+ NEXTCLAW_EXTENSION_ENDPOINT: this.options.endpoint,
105
+ NEXTCLAW_EXTENSION_TOKEN: this.options.token
106
+ },
107
+ stdio: [
108
+ "ignore",
109
+ "ignore",
110
+ "inherit"
111
+ ]
112
+ });
113
+ const running = {
114
+ manifest,
115
+ process: child
116
+ };
117
+ this.processes.set(manifest.id, running);
118
+ child.once("exit", () => {
119
+ if (this.processes.get(manifest.id)?.process === child) this.processes.delete(manifest.id);
120
+ this.logger.warn(`Extension ${manifest.id} exited.`);
121
+ });
122
+ child.once("error", (error) => {
123
+ this.logger.warn(`Extension ${manifest.id} failed: ${error.message}`);
124
+ });
125
+ return running;
126
+ };
127
+ stopAll = async () => {
128
+ const running = Array.from(this.processes.values());
129
+ this.processes.clear();
130
+ await Promise.all(running.map((entry) => this.stopProcess(entry.process)));
131
+ };
132
+ list = () => Array.from(this.processes.values());
133
+ stopProcess = async (child) => {
134
+ if (child.exitCode !== null || child.signalCode !== null) return;
135
+ await new Promise((resolve) => {
136
+ child.once("exit", () => resolve());
137
+ child.kill();
138
+ setTimeout(resolve, 1e3).unref();
139
+ });
140
+ };
141
+ };
142
+ //#endregion
143
+ export { ExtensionLifecycleService, ExtensionManifestDiscoveryService };
@@ -0,0 +1,51 @@
1
+ import { ExtensionLifecycleService, ExtensionManifestDiscoveryService, RunningExtensionProcess } from "./extension-lifecycle.service.js";
2
+ import { NextclawGatewayRuntime } from "../gateway/nextclaw-gateway-runtime.service.js";
3
+ import * as NextclawCore from "@nextclaw/core";
4
+ import { Ingress } from "@nextclaw/shared";
5
+ import { PluginChannelBinding, PluginUiMetadata } from "@nextclaw/openclaw-compat";
6
+
7
+ //#region src/shared/services/extensions/service-extension-runtime.service.d.ts
8
+ type Config$1 = NextclawCore.Config;
9
+ type ExtensionRuntimeContributions = {
10
+ channelBindings: PluginChannelBinding[];
11
+ uiMetadata: PluginUiMetadata[];
12
+ };
13
+ declare function resolveBuiltinExtensionManifestRoots(): string[];
14
+ declare function resolveExtensionManifestRoots(params: {
15
+ config: Config$1;
16
+ workspace: string;
17
+ }): string[];
18
+ declare function startDiscoveredExtensions(params: {
19
+ config: Config$1;
20
+ workspace: string;
21
+ endpoint: string;
22
+ token: string;
23
+ discovery?: ExtensionManifestDiscoveryService;
24
+ lifecycle?: ExtensionLifecycleService;
25
+ }): Promise<{
26
+ lifecycle: ExtensionLifecycleService;
27
+ running: RunningExtensionProcess[];
28
+ }>;
29
+ declare class ServiceExtensionRuntime {
30
+ private readonly gateway;
31
+ readonly token: `${string}-${string}-${string}-${string}-${string}`;
32
+ private lifecycle;
33
+ private manifests;
34
+ private readonly pendingRequests;
35
+ constructor(gateway: NextclawGatewayRuntime);
36
+ readonly registerIngressHandlers: (ingress: Ingress) => void;
37
+ readonly loadContributions: () => Promise<ExtensionRuntimeContributions>;
38
+ readonly start: () => Promise<void>;
39
+ readonly stop: () => Promise<void>;
40
+ private readonly handleChannelConfigGet;
41
+ private readonly handleChannelMessageSubmit;
42
+ private readonly handleExtensionResponse;
43
+ private readonly discoverManifests;
44
+ private readonly toContributions;
45
+ private readonly readConfigUiHints;
46
+ private readonly createChannelAuth;
47
+ private readonly requestExtension;
48
+ private readonly assertAuthorized;
49
+ }
50
+ //#endregion
51
+ export { ServiceExtensionRuntime, resolveBuiltinExtensionManifestRoots, resolveExtensionManifestRoots, startDiscoveredExtensions };