@xopcai/xopc 0.0.20 → 0.0.22

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 (197) hide show
  1. package/dist/extensions/feishu/src/adapters/cli-login.d.ts +8 -0
  2. package/dist/extensions/feishu/src/adapters/cli-login.js +225 -0
  3. package/dist/extensions/feishu/src/adapters/cli-login.js.map +1 -0
  4. package/dist/extensions/feishu/src/adapters/onboard-cli.js +1 -105
  5. package/dist/extensions/feishu/src/adapters/onboard-cli.js.map +1 -1
  6. package/dist/extensions/feishu/src/auth/app-registration.d.ts +47 -0
  7. package/dist/extensions/feishu/src/auth/app-registration.js +122 -0
  8. package/dist/extensions/feishu/src/auth/app-registration.js.map +1 -0
  9. package/dist/extensions/feishu/src/plugin.d.ts +2 -0
  10. package/dist/extensions/feishu/src/plugin.js +2 -0
  11. package/dist/extensions/feishu/src/plugin.js.map +1 -1
  12. package/dist/extensions/telegram/src/inbound-processor.js +1 -1
  13. package/dist/extensions/telegram/src/plugin.d.ts +1 -1
  14. package/dist/extensions/telegram/src/plugin.js +1 -1
  15. package/dist/extensions/telegram/src/routing-integration.js +2 -2
  16. package/dist/extensions/telegram/xopc.extension.json +1 -1
  17. package/dist/extensions/weixin/src/plugin.js +1 -1
  18. package/dist/gateway/static/root/assets/{agents-DbLV2ldC.js → agents-BcLv59-r.js} +2 -2
  19. package/dist/gateway/static/root/assets/{agents-DbLV2ldC.js.map → agents-BcLv59-r.js.map} +1 -1
  20. package/dist/gateway/static/root/assets/{apps-page-CDRSbv3l.js → apps-page-Bl-yxbQo.js} +2 -2
  21. package/dist/gateway/static/root/assets/{apps-page-CDRSbv3l.js.map → apps-page-Bl-yxbQo.js.map} +1 -1
  22. package/dist/gateway/static/root/assets/channels-settings-BGueHxMv.js +9 -0
  23. package/dist/gateway/static/root/assets/channels-settings-BGueHxMv.js.map +1 -0
  24. package/dist/gateway/static/root/assets/{cron-page-D-fhl446.js → cron-page-DsVZzPqv.js} +2 -2
  25. package/dist/gateway/static/root/assets/{cron-page-D-fhl446.js.map → cron-page-DsVZzPqv.js.map} +1 -1
  26. package/dist/gateway/static/root/assets/{cron-utils-DqyPqEDr.js → cron-utils-zbRs2yND.js} +2 -2
  27. package/dist/gateway/static/root/assets/{cron-utils-DqyPqEDr.js.map → cron-utils-zbRs2yND.js.map} +1 -1
  28. package/dist/gateway/static/root/assets/{dist-BTNDXpKu.js → dist-CDA7gR_M.js} +2 -2
  29. package/dist/gateway/static/root/assets/{dist-BTNDXpKu.js.map → dist-CDA7gR_M.js.map} +1 -1
  30. package/dist/gateway/static/root/assets/{extension-debug-page-CiOtMG3X.js → extension-debug-page-CDLp4DAs.js} +2 -2
  31. package/dist/gateway/static/root/assets/{extension-debug-page-CiOtMG3X.js.map → extension-debug-page-CDLp4DAs.js.map} +1 -1
  32. package/dist/gateway/static/root/assets/{extension-page-a59AFw7Q.js → extension-page-DwSCjzHO.js} +2 -2
  33. package/dist/gateway/static/root/assets/{extension-page-a59AFw7Q.js.map → extension-page-DwSCjzHO.js.map} +1 -1
  34. package/dist/gateway/static/root/assets/{extension-settings-page-BQyLvxBY.js → extension-settings-page-Rdmxe24_.js} +2 -2
  35. package/dist/gateway/static/root/assets/{extension-settings-page-BQyLvxBY.js.map → extension-settings-page-Rdmxe24_.js.map} +1 -1
  36. package/dist/gateway/static/root/assets/index-D9Wmfh2f.css +1 -0
  37. package/dist/gateway/static/root/assets/index-DG8WvMbu.js +150 -0
  38. package/dist/gateway/static/root/assets/index-DG8WvMbu.js.map +1 -0
  39. package/dist/gateway/static/root/assets/{logs-page-DMSWW0-k.js → logs-page-ChJ0nsPh.js} +2 -2
  40. package/dist/gateway/static/root/assets/{logs-page-DMSWW0-k.js.map → logs-page-ChJ0nsPh.js.map} +1 -1
  41. package/dist/gateway/static/root/assets/{sessions-page-CL2E3nPk.js → sessions-page-Cle4fPla.js} +2 -2
  42. package/dist/gateway/static/root/assets/{sessions-page-CL2E3nPk.js.map → sessions-page-Cle4fPla.js.map} +1 -1
  43. package/dist/gateway/static/root/assets/settings-page-Dyo2NYdy.js +2 -0
  44. package/dist/gateway/static/root/assets/settings-page-Dyo2NYdy.js.map +1 -0
  45. package/dist/gateway/static/root/assets/{skills-page-0rmNu4AL.js → skills-page-B-smhcB2.js} +2 -2
  46. package/dist/gateway/static/root/assets/{skills-page-0rmNu4AL.js.map → skills-page-B-smhcB2.js.map} +1 -1
  47. package/dist/gateway/static/root/index.html +2 -2
  48. package/dist/package.js +1 -1
  49. package/dist/src/agent/agent-manager.js +6 -6
  50. package/dist/src/agent/context/workspace-seed.js +1 -1
  51. package/dist/src/agent/ipc/bus.js +1 -1
  52. package/dist/src/agent/ipc/inbox.js +1 -1
  53. package/dist/src/agent/ipc/socket.js +1 -1
  54. package/dist/src/agent/memory/builtin-memory-store.d.ts +2 -1
  55. package/dist/src/agent/memory/builtin-memory-store.js +7 -6
  56. package/dist/src/agent/memory/builtin-memory-store.js.map +1 -1
  57. package/dist/src/agent/models/manager.js +1 -1
  58. package/dist/src/agent/prompt/memory/index.d.ts +4 -2
  59. package/dist/src/agent/prompt/memory/index.js +22 -10
  60. package/dist/src/agent/prompt/memory/index.js.map +1 -1
  61. package/dist/src/agent/prompt/service-prompt-builder.js +1 -1
  62. package/dist/src/agent/service.js +5 -5
  63. package/dist/src/agent/skills/index.js +1 -1
  64. package/dist/src/agent/skills/scanner.js +1 -1
  65. package/dist/src/agent/skills/skill-manage-ops.js +1 -1
  66. package/dist/src/agent/skills/skill-manager.js +1 -1
  67. package/dist/src/agent/tools/factory.js +10 -3
  68. package/dist/src/agent/tools/factory.js.map +1 -1
  69. package/dist/src/agent/tools/index.d.ts +1 -1
  70. package/dist/src/agent/tools/memory-tool.d.ts +7 -2
  71. package/dist/src/agent/tools/memory-tool.js +11 -5
  72. package/dist/src/agent/tools/memory-tool.js.map +1 -1
  73. package/dist/src/agent/tools/send-media.js +1 -1
  74. package/dist/src/agent/tools/skill-manage-tool.js +1 -1
  75. package/dist/src/agent/tools/write.js +1 -1
  76. package/dist/src/auth/credentials.js +2 -2
  77. package/dist/src/auth/sync-provider-auth.js +1 -1
  78. package/dist/src/channels/attachments/inbound-persist.js +1 -1
  79. package/dist/src/channels/attachments/outbound-tts-persist.js +1 -1
  80. package/dist/src/channels/registry.d.ts +1 -1
  81. package/dist/src/channels/registry.js +25 -1
  82. package/dist/src/channels/registry.js.map +1 -1
  83. package/dist/src/chat-commands/builtins/config.js +3 -3
  84. package/dist/src/chat-commands/builtins/session.js +1 -1
  85. package/dist/src/chat-commands/context.js +1 -1
  86. package/dist/src/chat-commands/index.js +1 -1
  87. package/dist/src/chat-commands/processor.js +1 -1
  88. package/dist/src/cli/commands/agent.js +1 -1
  89. package/dist/src/cli/commands/channels.js +20 -2
  90. package/dist/src/cli/commands/channels.js.map +1 -1
  91. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  92. package/dist/src/cli/commands/gateway/call.d.ts +2 -0
  93. package/dist/src/cli/commands/gateway/call.js +90 -0
  94. package/dist/src/cli/commands/gateway/call.js.map +1 -0
  95. package/dist/src/cli/commands/gateway/health.d.ts +2 -0
  96. package/dist/src/cli/commands/gateway/health.js +77 -0
  97. package/dist/src/cli/commands/gateway/health.js.map +1 -0
  98. package/dist/src/cli/commands/gateway/index.d.ts +3 -0
  99. package/dist/src/cli/commands/gateway/index.js +4 -1
  100. package/dist/src/cli/commands/gateway/probe.d.ts +2 -0
  101. package/dist/src/cli/commands/gateway/probe.js +102 -0
  102. package/dist/src/cli/commands/gateway/probe.js.map +1 -0
  103. package/dist/src/cli/commands/gateway/status.d.ts +0 -3
  104. package/dist/src/cli/commands/gateway/status.js +107 -24
  105. package/dist/src/cli/commands/gateway/status.js.map +1 -1
  106. package/dist/src/cli/commands/gateway.js +7 -1
  107. package/dist/src/cli/commands/gateway.js.map +1 -1
  108. package/dist/src/cli/commands/init.js +3 -3
  109. package/dist/src/cli/commands/update.js +19 -1
  110. package/dist/src/cli/commands/update.js.map +1 -1
  111. package/dist/src/cli/utils/gateway-client.d.ts +28 -0
  112. package/dist/src/cli/utils/gateway-client.js +115 -0
  113. package/dist/src/cli/utils/gateway-client.js.map +1 -0
  114. package/dist/src/config/index.js +2 -2
  115. package/dist/src/config/loader.js +1 -1
  116. package/dist/src/config/models-json.js +1 -1
  117. package/dist/src/config/paths-state.d.ts +4 -0
  118. package/dist/src/config/paths-state.js +9 -1
  119. package/dist/src/config/paths-state.js.map +1 -1
  120. package/dist/src/config/profile.js +2 -2
  121. package/dist/src/config/reload.d.ts +2 -0
  122. package/dist/src/config/reload.js +9 -1
  123. package/dist/src/config/reload.js.map +1 -1
  124. package/dist/src/config/rules.js +12 -2
  125. package/dist/src/config/rules.js.map +1 -1
  126. package/dist/src/cron/executor.js +2 -2
  127. package/dist/src/cron/persistence.js +1 -1
  128. package/dist/src/cron/run-log-store.js +1 -1
  129. package/dist/src/extensions/api.d.ts +6 -1
  130. package/dist/src/extensions/api.js +52 -1
  131. package/dist/src/extensions/api.js.map +1 -1
  132. package/dist/src/extensions/health.js +1 -1
  133. package/dist/src/extensions/loader.d.ts +6 -1
  134. package/dist/src/extensions/loader.js +21 -2
  135. package/dist/src/extensions/loader.js.map +1 -1
  136. package/dist/src/extensions/lockfile.js +1 -1
  137. package/dist/src/extensions/normalize-manifest.js +33 -0
  138. package/dist/src/extensions/normalize-manifest.js.map +1 -1
  139. package/dist/src/extensions/sdk/index.d.ts +1 -1
  140. package/dist/src/extensions/sdk/index.js.map +1 -1
  141. package/dist/src/extensions/types/core.d.ts +35 -1
  142. package/dist/src/extensions/types/manifest.d.ts +14 -0
  143. package/dist/src/gateway/agents-admin.js +1 -1
  144. package/dist/src/gateway/hono/lib/config-payload.d.ts +3 -0
  145. package/dist/src/gateway/hono/lib/config-payload.js +1 -0
  146. package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
  147. package/dist/src/gateway/hono/oauth.js +1 -1
  148. package/dist/src/gateway/hono/routes/channels.js +111 -0
  149. package/dist/src/gateway/hono/routes/channels.js.map +1 -1
  150. package/dist/src/gateway/hono/routes/commands-skills.js +13 -2
  151. package/dist/src/gateway/hono/routes/commands-skills.js.map +1 -1
  152. package/dist/src/gateway/hono/routes/config.js +82 -1
  153. package/dist/src/gateway/hono/routes/config.js.map +1 -1
  154. package/dist/src/gateway/hono/routes/public-gateway.js +17 -0
  155. package/dist/src/gateway/hono/routes/public-gateway.js.map +1 -1
  156. package/dist/src/gateway/hono/routes/sessions.js +16 -0
  157. package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
  158. package/dist/src/gateway/hono/routes/status.js +31 -7
  159. package/dist/src/gateway/hono/routes/status.js.map +1 -1
  160. package/dist/src/gateway/hono/routes/update.js +118 -15
  161. package/dist/src/gateway/hono/routes/update.js.map +1 -1
  162. package/dist/src/gateway/hono/routes/workspace.js +2 -2
  163. package/dist/src/gateway/hono/sse.js +2 -2
  164. package/dist/src/gateway/index.js +1 -1
  165. package/dist/src/gateway/server.js +3 -0
  166. package/dist/src/gateway/server.js.map +1 -1
  167. package/dist/src/gateway/service.d.ts +23 -0
  168. package/dist/src/gateway/service.js +111 -4
  169. package/dist/src/gateway/service.js.map +1 -1
  170. package/dist/src/gateway/workspace-heartbeat-path.js +1 -1
  171. package/dist/src/infra/update-check.js +54 -21
  172. package/dist/src/infra/update-check.js.map +1 -1
  173. package/dist/src/infra/update-lock.d.ts +13 -0
  174. package/dist/src/infra/update-lock.js +67 -0
  175. package/dist/src/infra/update-lock.js.map +1 -0
  176. package/dist/src/infra/update-runner.d.ts +6 -5
  177. package/dist/src/infra/update-runner.js +93 -13
  178. package/dist/src/infra/update-runner.js.map +1 -1
  179. package/dist/src/infra/update-startup.js +37 -11
  180. package/dist/src/infra/update-startup.js.map +1 -1
  181. package/dist/src/providers/index.js +2 -2
  182. package/dist/src/providers/model-registry.js +1 -1
  183. package/dist/src/session/config-store.js +1 -1
  184. package/dist/src/session/session-title.js +1 -1
  185. package/dist/src/session/store.js +3 -3
  186. package/dist/src/utils/logger/audit.js +1 -1
  187. package/dist/src/utils/logger/log-store.js +1 -1
  188. package/dist/src/utils/logger/rotation.js +1 -1
  189. package/dist/src/voice/tts/audio.js +1 -1
  190. package/package.json +1 -1
  191. package/dist/gateway/static/root/assets/channels-settings-DyNnMN1-.js +0 -9
  192. package/dist/gateway/static/root/assets/channels-settings-DyNnMN1-.js.map +0 -1
  193. package/dist/gateway/static/root/assets/index-BQNdJlkw.css +0 -1
  194. package/dist/gateway/static/root/assets/index-fGYWcYhm.js +0 -144
  195. package/dist/gateway/static/root/assets/index-fGYWcYhm.js.map +0 -1
  196. package/dist/gateway/static/root/assets/settings-page-CSIVMAJE.js +0 -2
  197. package/dist/gateway/static/root/assets/settings-page-CSIVMAJE.js.map +0 -1
@@ -0,0 +1,102 @@
1
+ import { init_paths, resolveConfigPath } from "../../../config/paths.js";
2
+ import { loadConfig } from "../../../config/loader.js";
3
+ import "../../../config/index.js";
4
+ import { addGatewayClientOptions, callGatewayApi, parseGatewayClientOptions, resolveGatewayToken } from "../../utils/gateway-client.js";
5
+ import { getContextWithOpts } from "../../index.js";
6
+ import { Command } from "commander";
7
+ //#region src/cli/commands/gateway/probe.ts
8
+ init_paths();
9
+ function resolveProbeTargets(opts) {
10
+ const targets = [];
11
+ const port = opts.port;
12
+ targets.push({
13
+ label: "localhost",
14
+ url: `http://127.0.0.1:${port}`
15
+ });
16
+ if (opts.url) {
17
+ const normalized = opts.url.replace(/\/+$/, "");
18
+ if (!normalized.includes("127.0.0.1") && !normalized.includes("localhost")) targets.push({
19
+ label: "remote",
20
+ url: normalized
21
+ });
22
+ }
23
+ return targets;
24
+ }
25
+ async function probeTarget(target, token, timeoutMs) {
26
+ const healthResult = await callGatewayApi("GET", "/api/health", {
27
+ url: target.url,
28
+ timeoutMs: timeoutMs ?? 5e3
29
+ });
30
+ if (!healthResult.ok) return {
31
+ label: target.label,
32
+ url: target.url,
33
+ reachable: false,
34
+ authenticated: false,
35
+ durationMs: healthResult.durationMs,
36
+ error: healthResult.error
37
+ };
38
+ let authenticated = false;
39
+ if (token) authenticated = (await callGatewayApi("GET", "/api/status", {
40
+ url: target.url,
41
+ token,
42
+ timeoutMs: timeoutMs ?? 5e3
43
+ })).ok;
44
+ return {
45
+ label: target.label,
46
+ url: target.url,
47
+ reachable: true,
48
+ authenticated,
49
+ durationMs: healthResult.durationMs,
50
+ version: healthResult.data?.version
51
+ };
52
+ }
53
+ function createProbeCommand() {
54
+ const cmd = new Command("probe").description("Probe gateway reachability and auth capability");
55
+ addGatewayClientOptions(cmd);
56
+ cmd.action(async (options) => {
57
+ const configPath = getContextWithOpts().configPath || resolveConfigPath();
58
+ const port = loadConfig(configPath)?.gateway?.port ?? 18790;
59
+ const clientOpts = {
60
+ ...parseGatewayClientOptions(options),
61
+ configPath
62
+ };
63
+ const token = resolveGatewayToken(clientOpts);
64
+ const targets = resolveProbeTargets({
65
+ url: clientOpts.url,
66
+ port
67
+ });
68
+ const results = [];
69
+ for (const target of targets) {
70
+ const result = await probeTarget(target, token, clientOpts.timeoutMs);
71
+ results.push(result);
72
+ }
73
+ if (clientOpts.json) {
74
+ console.log(JSON.stringify({ targets: results }, null, 2));
75
+ const anyReachable = results.some((r) => r.reachable);
76
+ process.exit(anyReachable ? 0 : 1);
77
+ }
78
+ console.log("🔍 Gateway Probe");
79
+ console.log("");
80
+ for (const result of results) {
81
+ if (result.reachable) {
82
+ console.log(`✅ ${result.label} (${result.url})`);
83
+ console.log(` Reachable: yes (${result.durationMs}ms)`);
84
+ console.log(` Auth: ${result.authenticated ? "✅ authenticated" : "🔒 not authenticated (pass --token)"}`);
85
+ if (result.version) console.log(` Version: ${result.version}`);
86
+ } else {
87
+ console.log(`❌ ${result.label} (${result.url})`);
88
+ console.log(" Reachable: no");
89
+ console.log(` Error: ${result.error}`);
90
+ }
91
+ console.log("");
92
+ }
93
+ const anyReachable = results.some((r) => r.reachable);
94
+ if (!anyReachable) console.log("💡 Is the gateway running? Try: xopc gateway");
95
+ process.exit(anyReachable ? 0 : 1);
96
+ });
97
+ return cmd;
98
+ }
99
+ //#endregion
100
+ export { createProbeCommand };
101
+
102
+ //# sourceMappingURL=probe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probe.js","names":[],"sources":["../../../../../src/cli/commands/gateway/probe.ts"],"sourcesContent":["import { Command } from 'commander';\n\nimport { loadConfig } from '../../../config/index.js';\nimport { resolveConfigPath } from '../../../config/paths.js';\nimport {\n callGatewayApi,\n addGatewayClientOptions,\n parseGatewayClientOptions,\n resolveGatewayToken,\n} from '../../utils/gateway-client.js';\nimport { getContextWithOpts } from '../../index.js';\n\ninterface ProbeTarget {\n label: string;\n url: string;\n}\n\ninterface ProbeResultEntry {\n label: string;\n url: string;\n reachable: boolean;\n authenticated: boolean;\n durationMs: number;\n version?: string;\n error?: string;\n}\n\nfunction resolveProbeTargets(opts: { url?: string; port: number }): ProbeTarget[] {\n const targets: ProbeTarget[] = [];\n const port = opts.port;\n targets.push({ label: 'localhost', url: `http://127.0.0.1:${port}` });\n\n if (opts.url) {\n const normalized = opts.url.replace(/\\/+$/, '');\n if (!normalized.includes('127.0.0.1') && !normalized.includes('localhost')) {\n targets.push({ label: 'remote', url: normalized });\n }\n }\n\n return targets;\n}\n\nasync function probeTarget(\n target: ProbeTarget,\n token?: string,\n timeoutMs?: number,\n): Promise<ProbeResultEntry> {\n const healthResult = await callGatewayApi<{ status: string; version?: string }>('GET', '/api/health', {\n url: target.url,\n timeoutMs: timeoutMs ?? 5000,\n });\n\n if (!healthResult.ok) {\n return {\n label: target.label,\n url: target.url,\n reachable: false,\n authenticated: false,\n durationMs: healthResult.durationMs,\n error: healthResult.error,\n };\n }\n\n let authenticated = false;\n if (token) {\n const statusResult = await callGatewayApi('GET', '/api/status', {\n url: target.url,\n token,\n timeoutMs: timeoutMs ?? 5000,\n });\n authenticated = statusResult.ok;\n }\n\n return {\n label: target.label,\n url: target.url,\n reachable: true,\n authenticated,\n durationMs: healthResult.durationMs,\n version: healthResult.data?.version,\n };\n}\n\nexport function createProbeCommand(): Command {\n const cmd = new Command('probe').description('Probe gateway reachability and auth capability');\n\n addGatewayClientOptions(cmd);\n\n cmd.action(async (options) => {\n const ctx = getContextWithOpts();\n const configPath = ctx.configPath || resolveConfigPath();\n const config = loadConfig(configPath);\n const port = config?.gateway?.port ?? 18790;\n\n const clientOpts = { ...parseGatewayClientOptions(options as Record<string, unknown>), configPath };\n const token = resolveGatewayToken(clientOpts);\n const targets = resolveProbeTargets({ url: clientOpts.url, port });\n const results: ProbeResultEntry[] = [];\n\n for (const target of targets) {\n const result = await probeTarget(target, token, clientOpts.timeoutMs);\n results.push(result);\n }\n\n if (clientOpts.json) {\n console.log(JSON.stringify({ targets: results }, null, 2));\n const anyReachable = results.some((r) => r.reachable);\n process.exit(anyReachable ? 0 : 1);\n }\n\n console.log('🔍 Gateway Probe');\n console.log('');\n\n for (const result of results) {\n if (result.reachable) {\n console.log(`✅ ${result.label} (${result.url})`);\n console.log(` Reachable: yes (${result.durationMs}ms)`);\n console.log(\n ` Auth: ${result.authenticated ? '✅ authenticated' : '🔒 not authenticated (pass --token)'}`,\n );\n if (result.version) {\n console.log(` Version: ${result.version}`);\n }\n } else {\n console.log(`❌ ${result.label} (${result.url})`);\n console.log(' Reachable: no');\n console.log(` Error: ${result.error}`);\n }\n console.log('');\n }\n\n const anyReachable = results.some((r) => r.reachable);\n if (!anyReachable) {\n console.log('💡 Is the gateway running? Try: xopc gateway');\n }\n process.exit(anyReachable ? 0 : 1);\n });\n\n return cmd;\n}\n"],"mappings":";;;;;;;YAG6D;AAwB7D,SAAS,oBAAoB,MAAqD;CAChF,MAAM,UAAyB,EAAE;CACjC,MAAM,OAAO,KAAK;AAClB,SAAQ,KAAK;EAAE,OAAO;EAAa,KAAK,oBAAoB;EAAQ,CAAC;AAErE,KAAI,KAAK,KAAK;EACZ,MAAM,aAAa,KAAK,IAAI,QAAQ,QAAQ,GAAG;AAC/C,MAAI,CAAC,WAAW,SAAS,YAAY,IAAI,CAAC,WAAW,SAAS,YAAY,CACxE,SAAQ,KAAK;GAAE,OAAO;GAAU,KAAK;GAAY,CAAC;;AAItD,QAAO;;AAGT,eAAe,YACb,QACA,OACA,WAC2B;CAC3B,MAAM,eAAe,MAAM,eAAqD,OAAO,eAAe;EACpG,KAAK,OAAO;EACZ,WAAW,aAAa;EACzB,CAAC;AAEF,KAAI,CAAC,aAAa,GAChB,QAAO;EACL,OAAO,OAAO;EACd,KAAK,OAAO;EACZ,WAAW;EACX,eAAe;EACf,YAAY,aAAa;EACzB,OAAO,aAAa;EACrB;CAGH,IAAI,gBAAgB;AACpB,KAAI,MAMF,kBAAgB,MALW,eAAe,OAAO,eAAe;EAC9D,KAAK,OAAO;EACZ;EACA,WAAW,aAAa;EACzB,CAAC,EAC2B;AAG/B,QAAO;EACL,OAAO,OAAO;EACd,KAAK,OAAO;EACZ,WAAW;EACX;EACA,YAAY,aAAa;EACzB,SAAS,aAAa,MAAM;EAC7B;;AAGH,SAAgB,qBAA8B;CAC5C,MAAM,MAAM,IAAI,QAAQ,QAAQ,CAAC,YAAY,iDAAiD;AAE9F,yBAAwB,IAAI;AAE5B,KAAI,OAAO,OAAO,YAAY;EAE5B,MAAM,aADM,oBACU,CAAC,cAAc,mBAAmB;EAExD,MAAM,OADS,WAAW,WACP,EAAE,SAAS,QAAQ;EAEtC,MAAM,aAAa;GAAE,GAAG,0BAA0B,QAAmC;GAAE;GAAY;EACnG,MAAM,QAAQ,oBAAoB,WAAW;EAC7C,MAAM,UAAU,oBAAoB;GAAE,KAAK,WAAW;GAAK;GAAM,CAAC;EAClE,MAAM,UAA8B,EAAE;AAEtC,OAAK,MAAM,UAAU,SAAS;GAC5B,MAAM,SAAS,MAAM,YAAY,QAAQ,OAAO,WAAW,UAAU;AACrE,WAAQ,KAAK,OAAO;;AAGtB,MAAI,WAAW,MAAM;AACnB,WAAQ,IAAI,KAAK,UAAU,EAAE,SAAS,SAAS,EAAE,MAAM,EAAE,CAAC;GAC1D,MAAM,eAAe,QAAQ,MAAM,MAAM,EAAE,UAAU;AACrD,WAAQ,KAAK,eAAe,IAAI,EAAE;;AAGpC,UAAQ,IAAI,mBAAmB;AAC/B,UAAQ,IAAI,GAAG;AAEf,OAAK,MAAM,UAAU,SAAS;AAC5B,OAAI,OAAO,WAAW;AACpB,YAAQ,IAAI,KAAK,OAAO,MAAM,IAAI,OAAO,IAAI,GAAG;AAChD,YAAQ,IAAI,sBAAsB,OAAO,WAAW,KAAK;AACzD,YAAQ,IACN,YAAY,OAAO,gBAAgB,oBAAoB,wCACxD;AACD,QAAI,OAAO,QACT,SAAQ,IAAI,eAAe,OAAO,UAAU;UAEzC;AACL,YAAQ,IAAI,KAAK,OAAO,MAAM,IAAI,OAAO,IAAI,GAAG;AAChD,YAAQ,IAAI,mBAAmB;AAC/B,YAAQ,IAAI,aAAa,OAAO,QAAQ;;AAE1C,WAAQ,IAAI,GAAG;;EAGjB,MAAM,eAAe,QAAQ,MAAM,MAAM,EAAE,UAAU;AACrD,MAAI,CAAC,aACH,SAAQ,IAAI,+CAA+C;AAE7D,UAAQ,KAAK,eAAe,IAAI,EAAE;GAClC;AAEF,QAAO"}
@@ -1,5 +1,2 @@
1
1
  import { Command } from 'commander';
2
- /**
3
- * Create status subcommand
4
- */
5
2
  export declare function createStatusCommand(): Command;
@@ -1,51 +1,134 @@
1
- import { createLogger } from "../../../utils/logger/index.js";
2
- import { init_logger } from "../../../utils/logger.js";
3
1
  import { init_paths, resolveConfigPath } from "../../../config/paths.js";
4
2
  import { loadConfig } from "../../../config/loader.js";
5
3
  import "../../../config/index.js";
6
4
  import { GatewayLockError, acquireGatewayLock } from "../../../gateway/lock.js";
5
+ import { addGatewayClientOptions, callGatewayApi, parseGatewayClientOptions, resolveGatewayUrl } from "../../utils/gateway-client.js";
7
6
  import { getContextWithOpts } from "../../index.js";
8
7
  import { Command } from "commander";
9
8
  //#region src/cli/commands/gateway/status.ts
10
9
  init_paths();
11
- init_logger();
12
- createLogger("GatewayStatusCommand");
13
- /**
14
- * Create status subcommand
15
- */
10
+ function formatUptime(seconds) {
11
+ if (!seconds || seconds <= 0) return "unknown";
12
+ const days = Math.floor(seconds / 86400);
13
+ const hours = Math.floor(seconds % 86400 / 3600);
14
+ const minutes = Math.floor(seconds % 3600 / 60);
15
+ const parts = [];
16
+ if (days > 0) parts.push(`${days}d`);
17
+ if (hours > 0) parts.push(`${hours}h`);
18
+ parts.push(`${minutes}m`);
19
+ return parts.join(" ");
20
+ }
16
21
  function createStatusCommand() {
17
- return new Command("status").description("Check gateway status").action(async () => {
22
+ const cmd = new Command("status").description("Check gateway status with connectivity probe");
23
+ addGatewayClientOptions(cmd);
24
+ cmd.option("--no-probe", "Skip HTTP probe (only check lock file)");
25
+ cmd.action(async (options) => {
18
26
  const configPath = getContextWithOpts().configPath || resolveConfigPath();
19
27
  const config = loadConfig(configPath);
20
- const port = config?.gateway?.port || 18790;
28
+ const port = config?.gateway?.port ?? 18790;
29
+ const clientOpts = {
30
+ ...parseGatewayClientOptions(options),
31
+ configPath
32
+ };
33
+ const gatewayUrl = resolveGatewayUrl({
34
+ url: clientOpts.url,
35
+ configPath
36
+ });
37
+ let lockAlive = false;
38
+ let lockPid;
21
39
  try {
22
40
  await (await acquireGatewayLock(configPath, {
23
41
  timeoutMs: 100,
24
42
  port
25
43
  })).release();
26
- console.log("⚠️ Gateway is not running");
27
- console.log("\n💡 Start with: xopc gateway");
28
- process.exit(0);
44
+ lockAlive = false;
29
45
  } catch (err) {
30
46
  if (err instanceof GatewayLockError) {
31
- console.log("✅ Gateway is running");
32
- console.log(` Port: ${port}`);
33
- console.log("");
34
- console.log("🌐 Access:");
35
- console.log(` URL: http://localhost:${port}`);
36
- const token = config?.gateway?.auth?.token;
37
- if (token) console.log(` Token: ${token.slice(0, 8)}...${token.slice(-8)}`);
38
- console.log("");
39
- console.log("📝 Management:");
40
- console.log(" xopc gateway stop # Stop gateway");
41
- console.log(" xopc gateway restart # Restart gateway");
42
- process.exit(0);
47
+ lockAlive = true;
48
+ const pidMatch = err.message.match(/pid\s+(\d+)/);
49
+ if (pidMatch) lockPid = parseInt(pidMatch[1], 10);
43
50
  } else {
44
51
  console.error("❌ Failed to check status:", err);
45
52
  process.exit(1);
46
53
  }
47
54
  }
55
+ const shouldProbe = options.probe !== false;
56
+ let probeResult = null;
57
+ if (shouldProbe) {
58
+ const healthProbe = await callGatewayApi("GET", "/api/health", {
59
+ ...clientOpts,
60
+ timeoutMs: clientOpts.timeoutMs ?? 5e3
61
+ });
62
+ if (healthProbe.ok) {
63
+ const statusProbe = await callGatewayApi("GET", "/api/status", clientOpts);
64
+ probeResult = statusProbe.ok ? statusProbe : {
65
+ ok: true,
66
+ durationMs: healthProbe.durationMs,
67
+ data: { status: "ok" }
68
+ };
69
+ } else probeResult = {
70
+ ok: false,
71
+ error: healthProbe.error,
72
+ durationMs: healthProbe.durationMs
73
+ };
74
+ }
75
+ if (clientOpts.json) {
76
+ console.log(JSON.stringify({
77
+ running: lockAlive || (probeResult?.ok ?? false),
78
+ lock: {
79
+ alive: lockAlive,
80
+ pid: lockPid
81
+ },
82
+ probe: probeResult ? {
83
+ reachable: probeResult.ok,
84
+ durationMs: probeResult.durationMs,
85
+ ...probeResult.data ?? {},
86
+ ...probeResult.error ? { error: probeResult.error } : {}
87
+ } : null,
88
+ url: gatewayUrl,
89
+ port
90
+ }, null, 2));
91
+ process.exit(probeResult?.ok || lockAlive ? 0 : 1);
92
+ }
93
+ if (!(lockAlive || (probeResult?.ok ?? false))) {
94
+ console.log("⚠️ Gateway is not running");
95
+ if (probeResult && !probeResult.ok) console.log(` Probe: ${probeResult.error} (${probeResult.durationMs}ms)`);
96
+ console.log("");
97
+ console.log("💡 Start with: xopc gateway");
98
+ process.exit(1);
99
+ }
100
+ console.log("✅ Gateway is running");
101
+ console.log(` URL: ${gatewayUrl}`);
102
+ console.log(` Port: ${port}`);
103
+ if (lockPid) console.log(` PID: ${lockPid}`);
104
+ if (probeResult?.ok && probeResult.data) {
105
+ const data = probeResult.data;
106
+ console.log(` Probe: OK (${probeResult.durationMs}ms)`);
107
+ if (data.version) console.log(` Version: ${data.version}`);
108
+ if (data.uptime != null) console.log(` Uptime: ${formatUptime(data.uptime)}`);
109
+ if (data.channels && Object.keys(data.channels).length > 0) {
110
+ console.log("");
111
+ console.log("📡 Channels:");
112
+ for (const [name, info] of Object.entries(data.channels)) {
113
+ const icon = info.status === "connected" ? "✅" : info.status === "disabled" ? "⚪" : "❌";
114
+ console.log(` ${icon} ${name}: ${info.status}`);
115
+ }
116
+ }
117
+ } else if (probeResult && !probeResult.ok) console.log(` Probe: Failed (${probeResult.error})`);
118
+ else if (!shouldProbe) console.log(" Probe: skipped (--no-probe)");
119
+ const token = config?.gateway?.auth?.token;
120
+ if (token) {
121
+ console.log("");
122
+ console.log(`🔑 Token: ${token.slice(0, 8)}...${token.slice(-8)}`);
123
+ }
124
+ console.log("");
125
+ console.log("📝 Management:");
126
+ console.log(" xopc gateway stop # Stop gateway");
127
+ console.log(" xopc gateway restart # Restart gateway");
128
+ console.log(" xopc gateway health # Detailed health check");
129
+ process.exit(0);
48
130
  });
131
+ return cmd;
49
132
  }
50
133
  //#endregion
51
134
  export { createStatusCommand };
@@ -1 +1 @@
1
- {"version":3,"file":"status.js","names":[],"sources":["../../../../../src/cli/commands/gateway/status.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { loadConfig } from '../../../config/index.js';\nimport { resolveConfigPath } from '../../../config/paths.js';\nimport { createLogger } from '../../../utils/logger.js';\nimport { getContextWithOpts } from '../../index.js';\nimport { acquireGatewayLock, GatewayLockError } from '../../../gateway/lock.js';\n\nconst _log = createLogger('GatewayStatusCommand');\n\n/**\n * Create status subcommand\n */\nexport function createStatusCommand(): Command {\n return new Command('status')\n .description('Check gateway status')\n .action(async () => {\n const ctx = getContextWithOpts();\n const configPath = ctx.configPath || resolveConfigPath();\n const config = loadConfig(configPath);\n const port = config?.gateway?.port || 18790;\n\n try {\n // Try to acquire lock - if successful, gateway is not running\n const lock = await acquireGatewayLock(configPath, { timeoutMs: 100, port });\n await lock.release();\n console.log('⚠️ Gateway is not running');\n console.log('\\n💡 Start with: xopc gateway');\n process.exit(0);\n } catch (err) {\n if (err instanceof GatewayLockError) {\n console.log('✅ Gateway is running');\n console.log(` Port: ${port}`);\n\n // Try to get more info from lock file\n // This is a simplified version - could be enhanced\n console.log('');\n console.log('🌐 Access:');\n const host = 'localhost';\n console.log(` URL: http://${host}:${port}`);\n\n const token = config?.gateway?.auth?.token;\n if (token) {\n console.log(` Token: ${token.slice(0, 8)}...${token.slice(-8)}`);\n }\n\n console.log('');\n console.log('📝 Management:');\n console.log(' xopc gateway stop # Stop gateway');\n console.log(' xopc gateway restart # Restart gateway');\n process.exit(0);\n } else {\n console.error(' Failed to check status:', err);\n process.exit(1);\n }\n }\n });\n}\n"],"mappings":";;;;;;;;;YAE6D;aACL;AAI3C,aAAa,uBAAuB;;;;AAKjD,SAAgB,sBAA+B;AAC7C,QAAO,IAAI,QAAQ,SAAS,CACzB,YAAY,uBAAuB,CACnC,OAAO,YAAY;EAElB,MAAM,aADM,oBACU,CAAC,cAAc,mBAAmB;EACxD,MAAM,SAAS,WAAW,WAAW;EACrC,MAAM,OAAO,QAAQ,SAAS,QAAQ;AAEtC,MAAI;AAGF,UAAM,MADa,mBAAmB,YAAY;IAAE,WAAW;IAAK;IAAM,CAAC,EAChE,SAAS;AACpB,WAAQ,IAAI,6BAA6B;AACzC,WAAQ,IAAI,gCAAgC;AAC5C,WAAQ,KAAK,EAAE;WACR,KAAK;AACZ,OAAI,eAAe,kBAAkB;AACnC,YAAQ,IAAI,uBAAuB;AACnC,YAAQ,IAAI,YAAY,OAAO;AAI/B,YAAQ,IAAI,GAAG;AACf,YAAQ,IAAI,aAAa;AAEzB,YAAQ,IAAI,4BAA0B,OAAO;IAE7C,MAAM,QAAQ,QAAQ,SAAS,MAAM;AACrC,QAAI,MACF,SAAQ,IAAI,aAAa,MAAM,MAAM,GAAG,EAAE,CAAC,KAAK,MAAM,MAAM,GAAG,GAAG;AAGpE,YAAQ,IAAI,GAAG;AACf,YAAQ,IAAI,iBAAiB;AAC7B,YAAQ,IAAI,2CAA2C;AACvD,YAAQ,IAAI,8CAA8C;AAC1D,YAAQ,KAAK,EAAE;UACV;AACL,YAAQ,MAAM,6BAA6B,IAAI;AAC/C,YAAQ,KAAK,EAAE;;;GAGnB"}
1
+ {"version":3,"file":"status.js","names":["optsProbe"],"sources":["../../../../../src/cli/commands/gateway/status.ts"],"sourcesContent":["import { Command } from 'commander';\n\nimport { loadConfig } from '../../../config/index.js';\nimport { resolveConfigPath } from '../../../config/paths.js';\nimport { getContextWithOpts } from '../../index.js';\nimport { acquireGatewayLock, GatewayLockError } from '../../../gateway/lock.js';\nimport {\n callGatewayApi,\n addGatewayClientOptions,\n parseGatewayClientOptions,\n resolveGatewayUrl,\n} from '../../utils/gateway-client.js';\n\ninterface StatusResponse {\n status: string;\n version?: string;\n channels?: Record<string, { status: string }>;\n uptime?: number;\n}\n\nfunction formatUptime(seconds?: number): string {\n if (!seconds || seconds <= 0) return 'unknown';\n const days = Math.floor(seconds / 86400);\n const hours = Math.floor((seconds % 86400) / 3600);\n const minutes = Math.floor((seconds % 3600) / 60);\n const parts: string[] = [];\n if (days > 0) parts.push(`${days}d`);\n if (hours > 0) parts.push(`${hours}h`);\n parts.push(`${minutes}m`);\n return parts.join(' ');\n}\n\nexport function createStatusCommand(): Command {\n const cmd = new Command('status').description('Check gateway status with connectivity probe');\n\n addGatewayClientOptions(cmd);\n cmd.option('--no-probe', 'Skip HTTP probe (only check lock file)');\n\n cmd.action(async (options) => {\n const ctx = getContextWithOpts();\n const configPath = ctx.configPath || resolveConfigPath();\n const config = loadConfig(configPath);\n const port = config?.gateway?.port ?? 18790;\n const clientOpts = { ...parseGatewayClientOptions(options as Record<string, unknown>), configPath };\n const gatewayUrl = resolveGatewayUrl({ url: clientOpts.url, configPath });\n\n let lockAlive = false;\n let lockPid: number | undefined;\n\n try {\n const lock = await acquireGatewayLock(configPath, { timeoutMs: 100, port });\n await lock.release();\n lockAlive = false;\n } catch (err) {\n if (err instanceof GatewayLockError) {\n lockAlive = true;\n const pidMatch = err.message.match(/pid\\s+(\\d+)/);\n if (pidMatch) lockPid = parseInt(pidMatch[1], 10);\n } else {\n console.error(' Failed to check status:', err);\n process.exit(1);\n }\n }\n\n const optsProbe = options as { probe?: boolean };\n const shouldProbe = optsProbe.probe !== false;\n\n let probeResult: {\n ok: boolean;\n data?: StatusResponse;\n error?: string;\n durationMs: number;\n } | null = null;\n\n if (shouldProbe) {\n const healthProbe = await callGatewayApi<{ status: string }>('GET', '/api/health', {\n ...clientOpts,\n timeoutMs: clientOpts.timeoutMs ?? 5000,\n });\n\n if (healthProbe.ok) {\n const statusProbe = await callGatewayApi<StatusResponse>('GET', '/api/status', clientOpts);\n probeResult = statusProbe.ok\n ? statusProbe\n : { ok: true, durationMs: healthProbe.durationMs, data: { status: 'ok' } };\n } else {\n probeResult = { ok: false, error: healthProbe.error, durationMs: healthProbe.durationMs };\n }\n }\n\n if (clientOpts.json) {\n console.log(\n JSON.stringify(\n {\n running: lockAlive || (probeResult?.ok ?? false),\n lock: { alive: lockAlive, pid: lockPid },\n probe: probeResult\n ? {\n reachable: probeResult.ok,\n durationMs: probeResult.durationMs,\n ...(probeResult.data ?? {}),\n ...(probeResult.error ? { error: probeResult.error } : {}),\n }\n : null,\n url: gatewayUrl,\n port,\n },\n null,\n 2,\n ),\n );\n process.exit(probeResult?.ok || lockAlive ? 0 : 1);\n }\n\n const isRunning = lockAlive || (probeResult?.ok ?? false);\n\n if (!isRunning) {\n console.log('⚠️ Gateway is not running');\n if (probeResult && !probeResult.ok) {\n console.log(` Probe: ${probeResult.error} (${probeResult.durationMs}ms)`);\n }\n console.log('');\n console.log('💡 Start with: xopc gateway');\n process.exit(1);\n }\n\n console.log('✅ Gateway is running');\n console.log(` URL: ${gatewayUrl}`);\n console.log(` Port: ${port}`);\n if (lockPid) {\n console.log(` PID: ${lockPid}`);\n }\n\n if (probeResult?.ok && probeResult.data) {\n const data = probeResult.data;\n console.log(` Probe: OK (${probeResult.durationMs}ms)`);\n if (data.version) console.log(` Version: ${data.version}`);\n if (data.uptime != null) console.log(` Uptime: ${formatUptime(data.uptime)}`);\n\n if (data.channels && Object.keys(data.channels).length > 0) {\n console.log('');\n console.log('📡 Channels:');\n for (const [name, info] of Object.entries(data.channels)) {\n const icon = info.status === 'connected' ? '✅' : info.status === 'disabled' ? '⚪' : '❌';\n console.log(` ${icon} ${name}: ${info.status}`);\n }\n }\n } else if (probeResult && !probeResult.ok) {\n console.log(` Probe: Failed (${probeResult.error})`);\n } else if (!shouldProbe) {\n console.log(' Probe: skipped (--no-probe)');\n }\n\n const token = config?.gateway?.auth?.token;\n if (token) {\n console.log('');\n console.log(`🔑 Token: ${token.slice(0, 8)}...${token.slice(-8)}`);\n }\n\n console.log('');\n console.log('📝 Management:');\n console.log(' xopc gateway stop # Stop gateway');\n console.log(' xopc gateway restart # Restart gateway');\n console.log(' xopc gateway health # Detailed health check');\n process.exit(0);\n });\n\n return cmd;\n}\n"],"mappings":"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"}
@@ -12,6 +12,9 @@ import { checkPortAvailable, forceFreePortAndWait } from "../../gateway/ports.js
12
12
  import "../../gateway/index.js";
13
13
  import { createTokenCommand } from "./gateway/token.js";
14
14
  import { createStatusCommand } from "./gateway/status.js";
15
+ import { createHealthCommand } from "./gateway/health.js";
16
+ import { createCallCommand } from "./gateway/call.js";
17
+ import { createProbeCommand } from "./gateway/probe.js";
15
18
  import { createStopCommand } from "./gateway/stop.js";
16
19
  import { createRestartCommand } from "./gateway/restart.js";
17
20
  import { createLogsCommand } from "./gateway/logs.js";
@@ -54,10 +57,13 @@ function createGatewayCommand(_ctx) {
54
57
  "xopc gateway stop # Stop gateway",
55
58
  "xopc gateway restart # Restart gateway",
56
59
  "xopc gateway status # Check gateway status",
60
+ "xopc gateway health # Check gateway health",
61
+ "xopc gateway call status # Call gateway API (alias)",
62
+ "xopc gateway probe # Probe reachability / auth",
57
63
  "xopc gateway logs # View recent logs",
58
64
  "xopc gateway token # Show current token",
59
65
  "xopc gateway token --generate # Generate new token"
60
- ])).option("--host <address>", "Host to bind to", "127.0.0.1").option("--port <number>", "Port to listen on", "18790").option("--token <token>", "Authentication token").option("--force", "Force kill existing process on port", false).option("--no-hot-reload", "Disable config hot reload").option("--foreground", "Start gateway in foreground mode (blocks terminal)", true).option("--background", "Start gateway in background mode (detached)", false).addCommand(createTokenCommand()).addCommand(createStatusCommand()).addCommand(createStopCommand()).addCommand(createRestartCommand()).addCommand(createLogsCommand()).addCommand(createInstallCommand()).addCommand(createUninstallCommand()).addCommand(createServiceStartCommand()).addCommand(createServiceStatusCommand()).action(async (options) => {
66
+ ])).option("--host <address>", "Host to bind to", "127.0.0.1").option("--port <number>", "Port to listen on", "18790").option("--token <token>", "Authentication token").option("--force", "Force kill existing process on port", false).option("--no-hot-reload", "Disable config hot reload").option("--foreground", "Start gateway in foreground mode (blocks terminal)", true).option("--background", "Start gateway in background mode (detached)", false).addCommand(createTokenCommand()).addCommand(createStatusCommand()).addCommand(createHealthCommand()).addCommand(createCallCommand()).addCommand(createProbeCommand()).addCommand(createStopCommand()).addCommand(createRestartCommand()).addCommand(createLogsCommand()).addCommand(createInstallCommand()).addCommand(createUninstallCommand()).addCommand(createServiceStartCommand()).addCommand(createServiceStatusCommand()).action(async (options) => {
61
67
  const ctx = getContextWithOpts();
62
68
  const port = parseInt(options.port, 10);
63
69
  const host = options.host;
@@ -1 +1 @@
1
- {"version":3,"file":"gateway.js","names":[],"sources":["../../../../src/cli/commands/gateway.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { spawn } from 'child_process';\nimport { GatewayServer } from '../../gateway/index.js';\nimport { loadConfig } from '../../config/index.js';\nimport { resolveConfigPath } from '../../config/paths.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { register, formatExamples, type CLIContext } from '../registry.js';\nimport { getContextWithOpts } from '../index.js';\nimport { runGatewayLoop } from '../../gateway/run-loop.js';\nimport { forceFreePortAndWait, checkPortAvailable } from '../../gateway/ports.js';\nimport { seedMainAgentBootstrap } from '../../agent/context/workspace-seed.js';\nimport { initWorkspace } from '../utils/init-workspace.js';\nimport {\n createTokenCommand,\n createStatusCommand,\n createStopCommand,\n createRestartCommand,\n createLogsCommand,\n createInstallCommand,\n createUninstallCommand,\n createServiceStartCommand,\n createServiceStatusCommand,\n} from './gateway/index.js';\n\nconst _log = createLogger('GatewayCommand');\n\nasync function ensureGatewayReady(\n configPath: string,\n workspacePath: string,\n gatewayHost: string,\n gatewayPort: number,\n): Promise<void> {\n const result = await initWorkspace({\n configPath,\n workspacePath,\n gatewayHost,\n gatewayPort,\n });\n\n if (result.configCreated || result.workspaceCreated) {\n console.log('');\n console.log('👋 Welcome to xopc! Running first-time setup before starting the gateway...');\n console.log('');\n console.log('✅ First-time setup complete!');\n console.log(` Config: ${configPath}`);\n console.log(` Workspace: ${workspacePath}`);\n console.log(` Token: ${result.token.slice(0, 8)}...${result.token.slice(-8)}`);\n console.log('');\n console.log('💡 Tip: run `xopc onboard` anytime to configure models, channels, and more.');\n console.log('');\n seedMainAgentBootstrap(result.config);\n }\n}\n\nfunction createGatewayCommand(_ctx: CLIContext): Command {\n const cmd = new Command('gateway')\n .description('Start the xopc gateway server')\n .addHelpText(\n 'after',\n formatExamples([\n 'xopc gateway # Start gateway (foreground, default)',\n 'xopc gateway --background # Start gateway in background',\n 'xopc gateway --port 8080 # Custom port',\n 'xopc gateway --force # Force kill existing process',\n 'xopc gateway stop # Stop gateway',\n 'xopc gateway restart # Restart gateway',\n 'xopc gateway status # Check gateway status',\n 'xopc gateway logs # View recent logs',\n 'xopc gateway token # Show current token',\n 'xopc gateway token --generate # Generate new token',\n ])\n )\n .option('--host <address>', 'Host to bind to', '127.0.0.1')\n .option('--port <number>', 'Port to listen on', '18790')\n .option('--token <token>', 'Authentication token')\n .option('--force', 'Force kill existing process on port', false)\n .option('--no-hot-reload', 'Disable config hot reload')\n .option('--foreground', 'Start gateway in foreground mode (blocks terminal)', true)\n .option('--background', 'Start gateway in background mode (detached)', false)\n .addCommand(createTokenCommand())\n .addCommand(createStatusCommand())\n .addCommand(createStopCommand())\n .addCommand(createRestartCommand())\n .addCommand(createLogsCommand())\n .addCommand(createInstallCommand())\n .addCommand(createUninstallCommand())\n .addCommand(createServiceStartCommand())\n .addCommand(createServiceStatusCommand())\n .action(async (options) => {\n const ctx = getContextWithOpts();\n const port = parseInt(options.port, 10);\n const host = options.host;\n\n await ensureGatewayReady(ctx.configPath, ctx.workspacePath, host, port);\n const config = loadConfig(ctx.configPath);\n\n // --force: Force free port\n if (options.force) {\n try {\n const result = await forceFreePortAndWait(port, {\n timeoutMs: 2000,\n sigtermTimeoutMs: 700,\n });\n if (result.killed.length > 0) {\n console.log(`Force killed ${result.killed.length} process(es) on port ${port}`);\n if (result.escalatedToSigkill) {\n console.log('Escalated to SIGKILL');\n }\n }\n } catch (err) {\n console.error(`Failed to free port ${port}: ${String(err)}`);\n process.exit(1);\n }\n }\n\n // Check if port is available\n const portAvailable = await checkPortAvailable(port, host);\n if (!portAvailable) {\n console.error(`Port ${port} is already in use. Use --force to kill existing process.`);\n process.exit(1);\n }\n\n // Determine if background mode (default is foreground, --background overrides)\n const isBackground = options.background === true;\n\n // Background mode: spawn detached process\n if (isBackground) {\n console.log('🚀 Starting xopc gateway in background...');\n console.log(` Host: ${host}`);\n console.log(` Port: ${port}`);\n console.log('');\n\n const args = [\n ...process.execArgv,\n ...process.argv.slice(1).filter(arg => arg !== '--background'),\n '--foreground', // Force foreground mode in child to prevent infinite spawn loop\n ];\n\n const child = spawn(process.execPath, args, {\n detached: true,\n stdio: 'ignore',\n env: process.env,\n });\n\n child.unref();\n\n // Wait a moment to check if process started successfully\n await new Promise(resolve => setTimeout(resolve, 500));\n\n if (child.pid && !child.killed) {\n const displayHost = host === '0.0.0.0' ? 'localhost' : host;\n console.log('✅ Gateway started in background');\n console.log(` PID: ${child.pid}`);\n console.log(` URL: http://${displayHost}:${port}`);\n const token = options.token || config?.gateway?.auth?.token;\n if (token) {\n console.log(` Token: ${token.slice(0, 8)}...${token.slice(-8)}`);\n }\n console.log('');\n console.log('📝 Management commands:');\n console.log(` xopc gateway status # Check status`);\n console.log(` xopc gateway stop # Stop gateway`);\n console.log(` xopc gateway restart # Restart gateway`);\n process.exit(0);\n } else {\n console.error('❌ Failed to start gateway in background');\n process.exit(1);\n }\n return;\n }\n\n // Foreground mode: Start gateway with run loop\n console.log('🚀 Starting xopc gateway...');\n console.log(` Host: ${host}`);\n console.log(` Port: ${port}`);\n console.log('');\n console.log('Press Ctrl+C to stop');\n console.log('');\n\n await runGatewayLoop({\n configPath: ctx.configPath || resolveConfigPath(),\n port,\n start: async () => {\n const server = new GatewayServer({\n host,\n port,\n token: options.token || config?.gateway?.auth?.token,\n verbose: ctx.isVerbose,\n configPath: ctx.configPath,\n enableHotReload: options.hotReload,\n });\n await server.start();\n\n const displayHost = host === '0.0.0.0' ? 'localhost' : host;\n const token = options.token || config?.gateway?.auth?.token;\n console.log('✅ Gateway started');\n console.log(` URL: http://${displayHost}:${port}`);\n if (token) {\n console.log(` Token: ${token.slice(0, 8)}...${token.slice(-8)}`);\n }\n console.log('');\n\n return server;\n },\n });\n });\n\n return cmd;\n}\n\nregister({\n id: 'gateway',\n name: 'gateway',\n description: 'Start the xopc gateway server',\n factory: createGatewayCommand,\n metadata: {\n category: 'runtime',\n examples: [\n 'xopc gateway',\n 'xopc gateway --background',\n 'xopc gateway --port 8080',\n ],\n },\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"gateway.js","names":[],"sources":["../../../../src/cli/commands/gateway.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { spawn } from 'child_process';\nimport { GatewayServer } from '../../gateway/index.js';\nimport { loadConfig } from '../../config/index.js';\nimport { resolveConfigPath } from '../../config/paths.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { register, formatExamples, type CLIContext } from '../registry.js';\nimport { getContextWithOpts } from '../index.js';\nimport { runGatewayLoop } from '../../gateway/run-loop.js';\nimport { forceFreePortAndWait, checkPortAvailable } from '../../gateway/ports.js';\nimport { seedMainAgentBootstrap } from '../../agent/context/workspace-seed.js';\nimport { initWorkspace } from '../utils/init-workspace.js';\nimport {\n createTokenCommand,\n createStatusCommand,\n createHealthCommand,\n createCallCommand,\n createProbeCommand,\n createStopCommand,\n createRestartCommand,\n createLogsCommand,\n createInstallCommand,\n createUninstallCommand,\n createServiceStartCommand,\n createServiceStatusCommand,\n} from './gateway/index.js';\n\nconst _log = createLogger('GatewayCommand');\n\nasync function ensureGatewayReady(\n configPath: string,\n workspacePath: string,\n gatewayHost: string,\n gatewayPort: number,\n): Promise<void> {\n const result = await initWorkspace({\n configPath,\n workspacePath,\n gatewayHost,\n gatewayPort,\n });\n\n if (result.configCreated || result.workspaceCreated) {\n console.log('');\n console.log('👋 Welcome to xopc! Running first-time setup before starting the gateway...');\n console.log('');\n console.log('✅ First-time setup complete!');\n console.log(` Config: ${configPath}`);\n console.log(` Workspace: ${workspacePath}`);\n console.log(` Token: ${result.token.slice(0, 8)}...${result.token.slice(-8)}`);\n console.log('');\n console.log('💡 Tip: run `xopc onboard` anytime to configure models, channels, and more.');\n console.log('');\n seedMainAgentBootstrap(result.config);\n }\n}\n\nfunction createGatewayCommand(_ctx: CLIContext): Command {\n const cmd = new Command('gateway')\n .description('Start the xopc gateway server')\n .addHelpText(\n 'after',\n formatExamples([\n 'xopc gateway # Start gateway (foreground, default)',\n 'xopc gateway --background # Start gateway in background',\n 'xopc gateway --port 8080 # Custom port',\n 'xopc gateway --force # Force kill existing process',\n 'xopc gateway stop # Stop gateway',\n 'xopc gateway restart # Restart gateway',\n 'xopc gateway status # Check gateway status',\n 'xopc gateway health # Check gateway health',\n 'xopc gateway call status # Call gateway API (alias)',\n 'xopc gateway probe # Probe reachability / auth',\n 'xopc gateway logs # View recent logs',\n 'xopc gateway token # Show current token',\n 'xopc gateway token --generate # Generate new token',\n ])\n )\n .option('--host <address>', 'Host to bind to', '127.0.0.1')\n .option('--port <number>', 'Port to listen on', '18790')\n .option('--token <token>', 'Authentication token')\n .option('--force', 'Force kill existing process on port', false)\n .option('--no-hot-reload', 'Disable config hot reload')\n .option('--foreground', 'Start gateway in foreground mode (blocks terminal)', true)\n .option('--background', 'Start gateway in background mode (detached)', false)\n .addCommand(createTokenCommand())\n .addCommand(createStatusCommand())\n .addCommand(createHealthCommand())\n .addCommand(createCallCommand())\n .addCommand(createProbeCommand())\n .addCommand(createStopCommand())\n .addCommand(createRestartCommand())\n .addCommand(createLogsCommand())\n .addCommand(createInstallCommand())\n .addCommand(createUninstallCommand())\n .addCommand(createServiceStartCommand())\n .addCommand(createServiceStatusCommand())\n .action(async (options) => {\n const ctx = getContextWithOpts();\n const port = parseInt(options.port, 10);\n const host = options.host;\n\n await ensureGatewayReady(ctx.configPath, ctx.workspacePath, host, port);\n const config = loadConfig(ctx.configPath);\n\n // --force: Force free port\n if (options.force) {\n try {\n const result = await forceFreePortAndWait(port, {\n timeoutMs: 2000,\n sigtermTimeoutMs: 700,\n });\n if (result.killed.length > 0) {\n console.log(`Force killed ${result.killed.length} process(es) on port ${port}`);\n if (result.escalatedToSigkill) {\n console.log('Escalated to SIGKILL');\n }\n }\n } catch (err) {\n console.error(`Failed to free port ${port}: ${String(err)}`);\n process.exit(1);\n }\n }\n\n // Check if port is available\n const portAvailable = await checkPortAvailable(port, host);\n if (!portAvailable) {\n console.error(`Port ${port} is already in use. Use --force to kill existing process.`);\n process.exit(1);\n }\n\n // Determine if background mode (default is foreground, --background overrides)\n const isBackground = options.background === true;\n\n // Background mode: spawn detached process\n if (isBackground) {\n console.log('🚀 Starting xopc gateway in background...');\n console.log(` Host: ${host}`);\n console.log(` Port: ${port}`);\n console.log('');\n\n const args = [\n ...process.execArgv,\n ...process.argv.slice(1).filter(arg => arg !== '--background'),\n '--foreground', // Force foreground mode in child to prevent infinite spawn loop\n ];\n\n const child = spawn(process.execPath, args, {\n detached: true,\n stdio: 'ignore',\n env: process.env,\n });\n\n child.unref();\n\n // Wait a moment to check if process started successfully\n await new Promise(resolve => setTimeout(resolve, 500));\n\n if (child.pid && !child.killed) {\n const displayHost = host === '0.0.0.0' ? 'localhost' : host;\n console.log('✅ Gateway started in background');\n console.log(` PID: ${child.pid}`);\n console.log(` URL: http://${displayHost}:${port}`);\n const token = options.token || config?.gateway?.auth?.token;\n if (token) {\n console.log(` Token: ${token.slice(0, 8)}...${token.slice(-8)}`);\n }\n console.log('');\n console.log('📝 Management commands:');\n console.log(` xopc gateway status # Check status`);\n console.log(` xopc gateway stop # Stop gateway`);\n console.log(` xopc gateway restart # Restart gateway`);\n process.exit(0);\n } else {\n console.error('❌ Failed to start gateway in background');\n process.exit(1);\n }\n return;\n }\n\n // Foreground mode: Start gateway with run loop\n console.log('🚀 Starting xopc gateway...');\n console.log(` Host: ${host}`);\n console.log(` Port: ${port}`);\n console.log('');\n console.log('Press Ctrl+C to stop');\n console.log('');\n\n await runGatewayLoop({\n configPath: ctx.configPath || resolveConfigPath(),\n port,\n start: async () => {\n const server = new GatewayServer({\n host,\n port,\n token: options.token || config?.gateway?.auth?.token,\n verbose: ctx.isVerbose,\n configPath: ctx.configPath,\n enableHotReload: options.hotReload,\n });\n await server.start();\n\n const displayHost = host === '0.0.0.0' ? 'localhost' : host;\n const token = options.token || config?.gateway?.auth?.token;\n console.log('✅ Gateway started');\n console.log(` URL: http://${displayHost}:${port}`);\n if (token) {\n console.log(` Token: ${token.slice(0, 8)}...${token.slice(-8)}`);\n }\n console.log('');\n\n return server;\n },\n });\n });\n\n return cmd;\n}\n\nregister({\n id: 'gateway',\n name: 'gateway',\n description: 'Start the xopc gateway server',\n factory: createGatewayCommand,\n metadata: {\n category: 'runtime',\n examples: [\n 'xopc gateway',\n 'xopc gateway --background',\n 'xopc gateway --port 8080',\n ],\n },\n});\n"],"mappings":"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"}
@@ -1,12 +1,12 @@
1
- import { createLogger } from "../../utils/logger/index.js";
2
- import { init_logger } from "../../utils/logger.js";
3
1
  import { resolveStateDir } from "../../config/paths-state.js";
4
2
  import { resolveAgentBootstrapDir, resolveAgentWorkspaceDir } from "../../agent/agent-scope.js";
3
+ import { createLogger } from "../../utils/logger/index.js";
4
+ import { init_logger } from "../../utils/logger.js";
5
5
  import { WORKSPACE_FILES, init_paths, resolveAgentDir, resolveAgentHomeDir, resolveAgentMetadataPath, resolveBinDir, resolveConfigPath, resolveCredentialsDir, resolveCronDir, resolveExtensionsDir, resolveInboxDir, resolveInboxPendingDir, resolveInboxProcessedDir, resolveLogsDir, resolveSessionsDir, resolveSkillsDir, resolveToolsDir, resolveWorkspaceStateDir, resolveWorkspaceStatePath } from "../../config/paths.js";
6
6
  import { init_loader, loadConfig, saveConfig } from "../../config/loader.js";
7
- import { mkdir, writeFile } from "fs/promises";
8
7
  import { join } from "path";
9
8
  import { existsSync } from "fs";
9
+ import { mkdir, writeFile } from "fs/promises";
10
10
  //#region src/cli/commands/init.ts
11
11
  init_logger();
12
12
  init_paths();
@@ -89,7 +89,25 @@ function createUpdateCommand(_ctx) {
89
89
  const packageManager = detectGlobalPackageManager();
90
90
  const spec = `@xopcai/xopc@${resolved.version}`;
91
91
  if (!options.json) console.log(`Installing ${spec} via ${packageManager}...`);
92
- const exitCode = await runInstallCommand(buildInstallArgs(packageManager, spec));
92
+ const installArgs = buildInstallArgs(packageManager, spec);
93
+ const { acquireUpdateLock } = await import("../../infra/update-lock.js");
94
+ const lock = await acquireUpdateLock("cli");
95
+ if (!lock) {
96
+ const message = "Another update is already in progress. Try again later.";
97
+ if (options.json) console.log(JSON.stringify({
98
+ status: "error",
99
+ reason: "lock-held",
100
+ message
101
+ }));
102
+ else console.error(`❌ ${message}`);
103
+ process.exit(1);
104
+ }
105
+ let exitCode;
106
+ try {
107
+ exitCode = await runInstallCommand(installArgs);
108
+ } finally {
109
+ await lock.release();
110
+ }
93
111
  if (exitCode === 0) if (options.json) console.log(JSON.stringify({
94
112
  status: "ok",
95
113
  previousVersion: PACKAGE_VERSION,
@@ -1 +1 @@
1
- {"version":3,"file":"update.js","names":[],"sources":["../../../../src/cli/commands/update.ts"],"sourcesContent":["// src/cli/commands/update.ts\n\nimport { Command } from 'commander';\nimport { spawn } from 'node:child_process';\n\nimport { loadConfig } from '../../config/index.js';\nimport { PACKAGE_VERSION } from '../../package-version.js';\nimport { register, formatExamples, type CLIContext } from '../registry.js';\nimport { normalizeUpdateChannel, DEFAULT_PACKAGE_CHANNEL } from '../../infra/update-channels.js';\nimport {\n resolveNpmChannelTag,\n compareSemver,\n detectInstallKind,\n resolvePackageRoot,\n} from '../../infra/update-check.js';\n\nfunction createUpdateCommand(_ctx: CLIContext): Command {\n return new Command('update')\n .description('Check for and install xopc updates')\n .option('--check', 'Only check for updates without installing')\n .option('--yes', 'Skip confirmation prompts')\n .option('--channel <channel>', 'Update channel: stable, beta, or dev (default: from config, else stable)')\n .option('--json', 'Output results as JSON')\n .addHelpText(\n 'after',\n formatExamples([\n 'xopc update',\n 'xopc update --check',\n 'xopc update --channel beta',\n 'xopc update --yes',\n 'xopc update --json',\n ]),\n )\n .action(\n async (options: { check?: boolean; yes?: boolean; channel?: string; json?: boolean }) => {\n const fromCli = options.channel;\n const fromConfig = (() => {\n try {\n return loadConfig().update?.channel;\n } catch {\n return undefined;\n }\n })();\n const channel = normalizeUpdateChannel(fromCli ?? fromConfig) ?? DEFAULT_PACKAGE_CHANNEL;\n\n // Check current install kind\n const root = await resolvePackageRoot();\n if (root) {\n const installKind = await detectInstallKind(root);\n if (installKind === 'git') {\n const message = 'Running from a git checkout. Use `git pull` to update instead.';\n if (options.json) {\n console.log(JSON.stringify({ status: 'skipped', reason: 'git-checkout', message }));\n } else {\n console.log(message);\n }\n return;\n }\n }\n\n if (!options.json) {\n console.log(`Checking for updates (channel: ${channel})...`);\n }\n\n const resolved = await resolveNpmChannelTag({ channel });\n if (!resolved.version) {\n const message = 'Could not reach npm registry. Check your network connection.';\n if (options.json) {\n console.log(JSON.stringify({ status: 'error', reason: 'registry-unreachable', message }));\n } else {\n console.error(message);\n }\n process.exit(1);\n }\n\n const comparison = compareSemver(PACKAGE_VERSION, resolved.version);\n if (comparison === null || comparison >= 0) {\n const message = `Already up to date: v${PACKAGE_VERSION} (${resolved.tag}: v${resolved.version})`;\n if (options.json) {\n console.log(\n JSON.stringify({\n status: 'up-to-date',\n currentVersion: PACKAGE_VERSION,\n latestVersion: resolved.version,\n channel: resolved.tag,\n }),\n );\n } else {\n console.log(`✅ ${message}`);\n }\n return;\n }\n\n if (options.check) {\n const message = `Update available: v${PACKAGE_VERSION} → v${resolved.version} (${resolved.tag})`;\n if (options.json) {\n console.log(\n JSON.stringify({\n status: 'update-available',\n currentVersion: PACKAGE_VERSION,\n latestVersion: resolved.version,\n channel: resolved.tag,\n }),\n );\n } else {\n console.log(`📦 ${message}`);\n console.log('Run `xopc update` to install.');\n }\n return;\n }\n\n if (!options.yes && !process.env.XOPC_AUTO_UPDATE) {\n const { confirm } = await import('@inquirer/prompts');\n const shouldUpdate = await confirm({\n message: `Update from v${PACKAGE_VERSION} to v${resolved.version} (${resolved.tag})?`,\n default: true,\n });\n if (!shouldUpdate) {\n console.log('Update cancelled.');\n return;\n }\n }\n\n const packageManager = detectGlobalPackageManager();\n const spec = `@xopcai/xopc@${resolved.version}`;\n\n if (!options.json) {\n console.log(`Installing ${spec} via ${packageManager}...`);\n }\n\n const installArgs = buildInstallArgs(packageManager, spec);\n const exitCode = await runInstallCommand(installArgs);\n\n if (exitCode === 0) {\n if (options.json) {\n console.log(\n JSON.stringify({\n status: 'ok',\n previousVersion: PACKAGE_VERSION,\n installedVersion: resolved.version,\n channel: resolved.tag,\n packageManager,\n }),\n );\n } else {\n console.log(`✅ Updated to v${resolved.version}`);\n console.log('Restart the gateway to use the new version: xopc gateway restart');\n }\n } else {\n if (options.json) {\n console.log(\n JSON.stringify({\n status: 'error',\n reason: 'install-failed',\n exitCode,\n packageManager,\n }),\n );\n } else {\n console.error(`❌ Update failed (exit code ${exitCode})`);\n console.error(`Try manually: ${packageManager} install -g ${spec}`);\n }\n process.exit(1);\n }\n },\n );\n}\n\n/**\n * Detect which package manager was used to install xopc globally.\n * Checks common indicators: npm_config_user_agent, process.env, argv paths.\n */\nfunction detectGlobalPackageManager(): 'npm' | 'pnpm' {\n const userAgent = process.env.npm_config_user_agent ?? '';\n if (userAgent.startsWith('pnpm/')) return 'pnpm';\n return 'npm';\n}\n\nfunction buildInstallArgs(manager: 'npm' | 'pnpm', spec: string): string[] {\n if (manager === 'pnpm') {\n return ['pnpm', 'add', '-g', spec];\n }\n return ['npm', 'install', '-g', spec, '--no-fund', '--no-audit'];\n}\n\nfunction runInstallCommand(argv: string[]): Promise<number> {\n return new Promise((resolve) => {\n const child = spawn(argv[0], argv.slice(1), {\n stdio: 'inherit',\n env: process.env,\n });\n child.on('error', () => resolve(1));\n child.on('exit', (code) => resolve(code ?? 1));\n });\n}\n\nregister({\n id: 'update',\n name: 'update',\n description: 'Check for and install xopc updates',\n factory: createUpdateCommand,\n metadata: {\n category: 'maintenance',\n examples: [\n 'xopc update',\n 'xopc update --check',\n 'xopc update --channel beta',\n 'xopc update --yes --json',\n ],\n },\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"update.js","names":[],"sources":["../../../../src/cli/commands/update.ts"],"sourcesContent":["// src/cli/commands/update.ts\n\nimport { Command } from 'commander';\nimport { spawn } from 'node:child_process';\n\nimport { loadConfig } from '../../config/index.js';\nimport { PACKAGE_VERSION } from '../../package-version.js';\nimport { register, formatExamples, type CLIContext } from '../registry.js';\nimport { normalizeUpdateChannel, DEFAULT_PACKAGE_CHANNEL } from '../../infra/update-channels.js';\nimport {\n resolveNpmChannelTag,\n compareSemver,\n detectInstallKind,\n resolvePackageRoot,\n} from '../../infra/update-check.js';\n\nfunction createUpdateCommand(_ctx: CLIContext): Command {\n return new Command('update')\n .description('Check for and install xopc updates')\n .option('--check', 'Only check for updates without installing')\n .option('--yes', 'Skip confirmation prompts')\n .option('--channel <channel>', 'Update channel: stable, beta, or dev (default: from config, else stable)')\n .option('--json', 'Output results as JSON')\n .addHelpText(\n 'after',\n formatExamples([\n 'xopc update',\n 'xopc update --check',\n 'xopc update --channel beta',\n 'xopc update --yes',\n 'xopc update --json',\n ]),\n )\n .action(\n async (options: { check?: boolean; yes?: boolean; channel?: string; json?: boolean }) => {\n const fromCli = options.channel;\n const fromConfig = (() => {\n try {\n return loadConfig().update?.channel;\n } catch {\n return undefined;\n }\n })();\n const channel = normalizeUpdateChannel(fromCli ?? fromConfig) ?? DEFAULT_PACKAGE_CHANNEL;\n\n // Check current install kind\n const root = await resolvePackageRoot();\n if (root) {\n const installKind = await detectInstallKind(root);\n if (installKind === 'git') {\n const message = 'Running from a git checkout. Use `git pull` to update instead.';\n if (options.json) {\n console.log(JSON.stringify({ status: 'skipped', reason: 'git-checkout', message }));\n } else {\n console.log(message);\n }\n return;\n }\n }\n\n if (!options.json) {\n console.log(`Checking for updates (channel: ${channel})...`);\n }\n\n const resolved = await resolveNpmChannelTag({ channel });\n if (!resolved.version) {\n const message = 'Could not reach npm registry. Check your network connection.';\n if (options.json) {\n console.log(JSON.stringify({ status: 'error', reason: 'registry-unreachable', message }));\n } else {\n console.error(message);\n }\n process.exit(1);\n }\n\n const comparison = compareSemver(PACKAGE_VERSION, resolved.version);\n if (comparison === null || comparison >= 0) {\n const message = `Already up to date: v${PACKAGE_VERSION} (${resolved.tag}: v${resolved.version})`;\n if (options.json) {\n console.log(\n JSON.stringify({\n status: 'up-to-date',\n currentVersion: PACKAGE_VERSION,\n latestVersion: resolved.version,\n channel: resolved.tag,\n }),\n );\n } else {\n console.log(`✅ ${message}`);\n }\n return;\n }\n\n if (options.check) {\n const message = `Update available: v${PACKAGE_VERSION} → v${resolved.version} (${resolved.tag})`;\n if (options.json) {\n console.log(\n JSON.stringify({\n status: 'update-available',\n currentVersion: PACKAGE_VERSION,\n latestVersion: resolved.version,\n channel: resolved.tag,\n }),\n );\n } else {\n console.log(`📦 ${message}`);\n console.log('Run `xopc update` to install.');\n }\n return;\n }\n\n if (!options.yes && !process.env.XOPC_AUTO_UPDATE) {\n const { confirm } = await import('@inquirer/prompts');\n const shouldUpdate = await confirm({\n message: `Update from v${PACKAGE_VERSION} to v${resolved.version} (${resolved.tag})?`,\n default: true,\n });\n if (!shouldUpdate) {\n console.log('Update cancelled.');\n return;\n }\n }\n\n const packageManager = detectGlobalPackageManager();\n const spec = `@xopcai/xopc@${resolved.version}`;\n\n if (!options.json) {\n console.log(`Installing ${spec} via ${packageManager}...`);\n }\n\n const installArgs = buildInstallArgs(packageManager, spec);\n\n const { acquireUpdateLock } = await import('../../infra/update-lock.js');\n const lock = await acquireUpdateLock('cli');\n if (!lock) {\n const message = 'Another update is already in progress. Try again later.';\n if (options.json) {\n console.log(JSON.stringify({ status: 'error', reason: 'lock-held', message }));\n } else {\n console.error(`❌ ${message}`);\n }\n process.exit(1);\n }\n\n let exitCode: number;\n try {\n exitCode = await runInstallCommand(installArgs);\n } finally {\n await lock.release();\n }\n\n if (exitCode === 0) {\n if (options.json) {\n console.log(\n JSON.stringify({\n status: 'ok',\n previousVersion: PACKAGE_VERSION,\n installedVersion: resolved.version,\n channel: resolved.tag,\n packageManager,\n }),\n );\n } else {\n console.log(`✅ Updated to v${resolved.version}`);\n console.log('Restart the gateway to use the new version: xopc gateway restart');\n }\n } else {\n if (options.json) {\n console.log(\n JSON.stringify({\n status: 'error',\n reason: 'install-failed',\n exitCode,\n packageManager,\n }),\n );\n } else {\n console.error(`❌ Update failed (exit code ${exitCode})`);\n console.error(`Try manually: ${packageManager} install -g ${spec}`);\n }\n process.exit(1);\n }\n },\n );\n}\n\n/**\n * Detect which package manager was used to install xopc globally.\n * Checks common indicators: npm_config_user_agent, process.env, argv paths.\n */\nfunction detectGlobalPackageManager(): 'npm' | 'pnpm' {\n const userAgent = process.env.npm_config_user_agent ?? '';\n if (userAgent.startsWith('pnpm/')) return 'pnpm';\n return 'npm';\n}\n\nfunction buildInstallArgs(manager: 'npm' | 'pnpm', spec: string): string[] {\n if (manager === 'pnpm') {\n return ['pnpm', 'add', '-g', spec];\n }\n return ['npm', 'install', '-g', spec, '--no-fund', '--no-audit'];\n}\n\nfunction runInstallCommand(argv: string[]): Promise<number> {\n return new Promise((resolve) => {\n const child = spawn(argv[0], argv.slice(1), {\n stdio: 'inherit',\n env: process.env,\n });\n child.on('error', () => resolve(1));\n child.on('exit', (code) => resolve(code ?? 1));\n });\n}\n\nregister({\n id: 'update',\n name: 'update',\n description: 'Check for and install xopc updates',\n factory: createUpdateCommand,\n metadata: {\n category: 'maintenance',\n examples: [\n 'xopc update',\n 'xopc update --check',\n 'xopc update --channel beta',\n 'xopc update --yes --json',\n ],\n },\n});\n"],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Gateway API client — CLI-side HTTP client for gateway REST routes.
3
+ */
4
+ import type { Command } from 'commander';
5
+ export interface GatewayClientOptions {
6
+ url?: string;
7
+ token?: string;
8
+ timeoutMs?: number;
9
+ json?: boolean;
10
+ }
11
+ export interface GatewayCallResult<T = unknown> {
12
+ ok: boolean;
13
+ status: number;
14
+ data?: T;
15
+ error?: string;
16
+ durationMs: number;
17
+ }
18
+ export declare function resolveGatewayUrl(opts?: {
19
+ url?: string;
20
+ configPath?: string;
21
+ }): string;
22
+ export declare function resolveGatewayToken(opts?: {
23
+ token?: string;
24
+ configPath?: string;
25
+ }): string | undefined;
26
+ export declare function callGatewayApi<T = unknown>(method: 'GET' | 'POST' | 'PATCH' | 'DELETE', path: string, opts?: GatewayClientOptions, body?: unknown): Promise<GatewayCallResult<T>>;
27
+ export declare function addGatewayClientOptions(cmd: Command): Command;
28
+ export declare function parseGatewayClientOptions(opts: Record<string, unknown>): GatewayClientOptions;