@xopcai/xopc 0.0.20 → 0.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/extensions/feishu/src/adapters/cli-login.d.ts +8 -0
- package/dist/extensions/feishu/src/adapters/cli-login.js +225 -0
- package/dist/extensions/feishu/src/adapters/cli-login.js.map +1 -0
- package/dist/extensions/feishu/src/adapters/onboard-cli.js +1 -105
- package/dist/extensions/feishu/src/adapters/onboard-cli.js.map +1 -1
- package/dist/extensions/feishu/src/auth/app-registration.d.ts +47 -0
- package/dist/extensions/feishu/src/auth/app-registration.js +122 -0
- package/dist/extensions/feishu/src/auth/app-registration.js.map +1 -0
- package/dist/extensions/feishu/src/plugin.d.ts +2 -0
- package/dist/extensions/feishu/src/plugin.js +2 -0
- package/dist/extensions/feishu/src/plugin.js.map +1 -1
- package/dist/extensions/telegram/src/inbound-processor.js +1 -1
- package/dist/extensions/telegram/src/plugin.d.ts +1 -1
- package/dist/extensions/telegram/src/plugin.js +1 -1
- package/dist/extensions/telegram/src/routing-integration.js +2 -2
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/extensions/weixin/src/plugin.js +1 -1
- package/dist/gateway/static/root/assets/{agents-DbLV2ldC.js → agents-MbH57-L9.js} +2 -2
- package/dist/gateway/static/root/assets/{agents-DbLV2ldC.js.map → agents-MbH57-L9.js.map} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-CDRSbv3l.js → apps-page-3i3DvI7i.js} +2 -2
- package/dist/gateway/static/root/assets/{apps-page-CDRSbv3l.js.map → apps-page-3i3DvI7i.js.map} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-CcuSzoB6.js +9 -0
- package/dist/gateway/static/root/assets/channels-settings-CcuSzoB6.js.map +1 -0
- package/dist/gateway/static/root/assets/{cron-page-D-fhl446.js → cron-page-Be1h9Yub.js} +2 -2
- package/dist/gateway/static/root/assets/{cron-page-D-fhl446.js.map → cron-page-Be1h9Yub.js.map} +1 -1
- package/dist/gateway/static/root/assets/{cron-utils-DqyPqEDr.js → cron-utils-CR97EvZS.js} +2 -2
- package/dist/gateway/static/root/assets/{cron-utils-DqyPqEDr.js.map → cron-utils-CR97EvZS.js.map} +1 -1
- package/dist/gateway/static/root/assets/{dist-BTNDXpKu.js → dist-r_Gy-XJv.js} +2 -2
- package/dist/gateway/static/root/assets/{dist-BTNDXpKu.js.map → dist-r_Gy-XJv.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-CiOtMG3X.js → extension-debug-page-QfYEYruq.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-debug-page-CiOtMG3X.js.map → extension-debug-page-QfYEYruq.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-a59AFw7Q.js → extension-page-4FW-BmKG.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-page-a59AFw7Q.js.map → extension-page-4FW-BmKG.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-BQyLvxBY.js → extension-settings-page-E_Wq9LL8.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-settings-page-BQyLvxBY.js.map → extension-settings-page-E_Wq9LL8.js.map} +1 -1
- package/dist/gateway/static/root/assets/{index-fGYWcYhm.js → index-CcQtNJKo.js} +60 -54
- package/dist/gateway/static/root/assets/{index-fGYWcYhm.js.map → index-CcQtNJKo.js.map} +1 -1
- package/dist/gateway/static/root/assets/index-D9Wmfh2f.css +1 -0
- package/dist/gateway/static/root/assets/{logs-page-DMSWW0-k.js → logs-page-DFhTU-kG.js} +2 -2
- package/dist/gateway/static/root/assets/{logs-page-DMSWW0-k.js.map → logs-page-DFhTU-kG.js.map} +1 -1
- package/dist/gateway/static/root/assets/{sessions-page-CL2E3nPk.js → sessions-page-wmnnIj6Z.js} +2 -2
- package/dist/gateway/static/root/assets/{sessions-page-CL2E3nPk.js.map → sessions-page-wmnnIj6Z.js.map} +1 -1
- package/dist/gateway/static/root/assets/settings-page-BTmUXY4s.js +2 -0
- package/dist/gateway/static/root/assets/settings-page-BTmUXY4s.js.map +1 -0
- package/dist/gateway/static/root/assets/{skills-page-0rmNu4AL.js → skills-page-D-fRbJG0.js} +2 -2
- package/dist/gateway/static/root/assets/{skills-page-0rmNu4AL.js.map → skills-page-D-fRbJG0.js.map} +1 -1
- package/dist/gateway/static/root/index.html +2 -2
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.js +6 -6
- package/dist/src/agent/context/workspace-seed.js +1 -1
- package/dist/src/agent/ipc/bus.js +1 -1
- package/dist/src/agent/ipc/inbox.js +1 -1
- package/dist/src/agent/ipc/socket.js +1 -1
- package/dist/src/agent/memory/builtin-memory-store.d.ts +2 -1
- package/dist/src/agent/memory/builtin-memory-store.js +7 -6
- package/dist/src/agent/memory/builtin-memory-store.js.map +1 -1
- package/dist/src/agent/models/manager.js +1 -1
- package/dist/src/agent/prompt/memory/index.d.ts +4 -2
- package/dist/src/agent/prompt/memory/index.js +22 -10
- package/dist/src/agent/prompt/memory/index.js.map +1 -1
- package/dist/src/agent/prompt/service-prompt-builder.js +1 -1
- package/dist/src/agent/service.js +5 -5
- package/dist/src/agent/skills/index.js +1 -1
- package/dist/src/agent/skills/scanner.js +1 -1
- package/dist/src/agent/skills/skill-manage-ops.js +1 -1
- package/dist/src/agent/skills/skill-manager.js +1 -1
- package/dist/src/agent/tools/factory.js +10 -3
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/index.d.ts +1 -1
- package/dist/src/agent/tools/memory-tool.d.ts +7 -2
- package/dist/src/agent/tools/memory-tool.js +11 -5
- package/dist/src/agent/tools/memory-tool.js.map +1 -1
- package/dist/src/agent/tools/send-media.js +1 -1
- package/dist/src/agent/tools/skill-manage-tool.js +1 -1
- package/dist/src/agent/tools/write.js +1 -1
- package/dist/src/auth/credentials.js +2 -2
- package/dist/src/auth/sync-provider-auth.js +1 -1
- package/dist/src/channels/attachments/inbound-persist.js +1 -1
- package/dist/src/channels/attachments/outbound-tts-persist.js +1 -1
- package/dist/src/channels/registry.d.ts +1 -1
- package/dist/src/channels/registry.js +25 -1
- package/dist/src/channels/registry.js.map +1 -1
- package/dist/src/chat-commands/builtins/config.js +3 -3
- package/dist/src/chat-commands/builtins/session.js +1 -1
- package/dist/src/chat-commands/context.js +1 -1
- package/dist/src/chat-commands/index.js +1 -1
- package/dist/src/chat-commands/processor.js +1 -1
- package/dist/src/cli/commands/agent.js +1 -1
- package/dist/src/cli/commands/channels.js +20 -2
- package/dist/src/cli/commands/channels.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
- package/dist/src/cli/commands/gateway/call.d.ts +2 -0
- package/dist/src/cli/commands/gateway/call.js +90 -0
- package/dist/src/cli/commands/gateway/call.js.map +1 -0
- package/dist/src/cli/commands/gateway/health.d.ts +2 -0
- package/dist/src/cli/commands/gateway/health.js +77 -0
- package/dist/src/cli/commands/gateway/health.js.map +1 -0
- package/dist/src/cli/commands/gateway/index.d.ts +3 -0
- package/dist/src/cli/commands/gateway/index.js +4 -1
- package/dist/src/cli/commands/gateway/probe.d.ts +2 -0
- package/dist/src/cli/commands/gateway/probe.js +102 -0
- package/dist/src/cli/commands/gateway/probe.js.map +1 -0
- package/dist/src/cli/commands/gateway/status.d.ts +0 -3
- package/dist/src/cli/commands/gateway/status.js +107 -24
- package/dist/src/cli/commands/gateway/status.js.map +1 -1
- package/dist/src/cli/commands/gateway.js +7 -1
- package/dist/src/cli/commands/gateway.js.map +1 -1
- package/dist/src/cli/commands/init.js +3 -3
- package/dist/src/cli/commands/update.js +19 -1
- package/dist/src/cli/commands/update.js.map +1 -1
- package/dist/src/cli/utils/gateway-client.d.ts +28 -0
- package/dist/src/cli/utils/gateway-client.js +115 -0
- package/dist/src/cli/utils/gateway-client.js.map +1 -0
- package/dist/src/config/index.js +2 -2
- package/dist/src/config/loader.js +1 -1
- package/dist/src/config/models-json.js +1 -1
- package/dist/src/config/paths-state.d.ts +4 -0
- package/dist/src/config/paths-state.js +9 -1
- package/dist/src/config/paths-state.js.map +1 -1
- package/dist/src/config/profile.js +2 -2
- package/dist/src/config/reload.d.ts +2 -0
- package/dist/src/config/reload.js +9 -1
- package/dist/src/config/reload.js.map +1 -1
- package/dist/src/config/rules.js +12 -2
- package/dist/src/config/rules.js.map +1 -1
- package/dist/src/cron/executor.js +2 -2
- package/dist/src/cron/persistence.js +1 -1
- package/dist/src/cron/run-log-store.js +1 -1
- package/dist/src/extensions/api.d.ts +6 -1
- package/dist/src/extensions/api.js +52 -1
- package/dist/src/extensions/api.js.map +1 -1
- package/dist/src/extensions/health.js +1 -1
- package/dist/src/extensions/loader.d.ts +6 -1
- package/dist/src/extensions/loader.js +21 -2
- package/dist/src/extensions/loader.js.map +1 -1
- package/dist/src/extensions/lockfile.js +1 -1
- package/dist/src/extensions/normalize-manifest.js +33 -0
- package/dist/src/extensions/normalize-manifest.js.map +1 -1
- package/dist/src/extensions/sdk/index.d.ts +1 -1
- package/dist/src/extensions/sdk/index.js.map +1 -1
- package/dist/src/extensions/types/core.d.ts +35 -1
- package/dist/src/extensions/types/manifest.d.ts +14 -0
- package/dist/src/gateway/agents-admin.js +1 -1
- package/dist/src/gateway/hono/lib/config-payload.d.ts +3 -0
- package/dist/src/gateway/hono/lib/config-payload.js +1 -0
- package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
- package/dist/src/gateway/hono/oauth.js +1 -1
- package/dist/src/gateway/hono/routes/channels.js +111 -0
- package/dist/src/gateway/hono/routes/channels.js.map +1 -1
- package/dist/src/gateway/hono/routes/commands-skills.js +13 -2
- package/dist/src/gateway/hono/routes/commands-skills.js.map +1 -1
- package/dist/src/gateway/hono/routes/config.js +82 -1
- package/dist/src/gateway/hono/routes/config.js.map +1 -1
- package/dist/src/gateway/hono/routes/public-gateway.js +17 -0
- package/dist/src/gateway/hono/routes/public-gateway.js.map +1 -1
- package/dist/src/gateway/hono/routes/sessions.js +16 -0
- package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
- package/dist/src/gateway/hono/routes/status.js +31 -7
- package/dist/src/gateway/hono/routes/status.js.map +1 -1
- package/dist/src/gateway/hono/routes/update.js +118 -15
- package/dist/src/gateway/hono/routes/update.js.map +1 -1
- package/dist/src/gateway/hono/routes/workspace.js +2 -2
- package/dist/src/gateway/hono/sse.js +2 -2
- package/dist/src/gateway/index.js +1 -1
- package/dist/src/gateway/server.js +3 -0
- package/dist/src/gateway/server.js.map +1 -1
- package/dist/src/gateway/service.d.ts +23 -0
- package/dist/src/gateway/service.js +111 -4
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/workspace-heartbeat-path.js +1 -1
- package/dist/src/infra/update-check.js +54 -21
- package/dist/src/infra/update-check.js.map +1 -1
- package/dist/src/infra/update-lock.d.ts +13 -0
- package/dist/src/infra/update-lock.js +67 -0
- package/dist/src/infra/update-lock.js.map +1 -0
- package/dist/src/infra/update-runner.d.ts +6 -5
- package/dist/src/infra/update-runner.js +93 -13
- package/dist/src/infra/update-runner.js.map +1 -1
- package/dist/src/infra/update-startup.js +37 -11
- package/dist/src/infra/update-startup.js.map +1 -1
- package/dist/src/providers/index.js +2 -2
- package/dist/src/providers/model-registry.js +1 -1
- package/dist/src/session/config-store.js +1 -1
- package/dist/src/session/session-title.js +1 -1
- package/dist/src/session/store.js +3 -3
- package/dist/src/utils/logger/audit.js +1 -1
- package/dist/src/utils/logger/log-store.js +1 -1
- package/dist/src/utils/logger/rotation.js +1 -1
- package/dist/src/voice/tts/audio.js +1 -1
- package/package.json +1 -1
- package/dist/gateway/static/root/assets/channels-settings-DyNnMN1-.js +0 -9
- package/dist/gateway/static/root/assets/channels-settings-DyNnMN1-.js.map +0 -1
- package/dist/gateway/static/root/assets/index-BQNdJlkw.css +0 -1
- package/dist/gateway/static/root/assets/settings-page-CSIVMAJE.js +0 -2
- 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,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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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 {
|
|
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
|
|
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;
|