@xopcai/xopc 0.0.19 → 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/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{agents-ByiiWRbv.js → agents-MbH57-L9.js} +2 -2
- package/dist/gateway/static/root/assets/{agents-ByiiWRbv.js.map → agents-MbH57-L9.js.map} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-BpR0gguZ.js → apps-page-3i3DvI7i.js} +2 -2
- package/dist/gateway/static/root/assets/{apps-page-BpR0gguZ.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-D6wtd-hq.js → cron-page-Be1h9Yub.js} +2 -2
- package/dist/gateway/static/root/assets/{cron-page-D6wtd-hq.js.map → cron-page-Be1h9Yub.js.map} +1 -1
- package/dist/gateway/static/root/assets/{cron-utils-o-QI_XCC.js → cron-utils-CR97EvZS.js} +2 -2
- package/dist/gateway/static/root/assets/{cron-utils-o-QI_XCC.js.map → cron-utils-CR97EvZS.js.map} +1 -1
- package/dist/gateway/static/root/assets/{dist-D2Td6E_v.js → dist-r_Gy-XJv.js} +2 -2
- package/dist/gateway/static/root/assets/{dist-D2Td6E_v.js.map → dist-r_Gy-XJv.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-BIni4Qq4.js → extension-debug-page-QfYEYruq.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-debug-page-BIni4Qq4.js.map → extension-debug-page-QfYEYruq.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-BRLScNkx.js → extension-page-4FW-BmKG.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-page-BRLScNkx.js.map → extension-page-4FW-BmKG.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-DjiK9Igx.js → extension-settings-page-E_Wq9LL8.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-settings-page-DjiK9Igx.js.map → extension-settings-page-E_Wq9LL8.js.map} +1 -1
- package/dist/gateway/static/root/assets/{index-KGmhufWu.js → index-CcQtNJKo.js} +60 -54
- package/dist/gateway/static/root/assets/{index-KGmhufWu.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-C76F4Y0H.js → logs-page-DFhTU-kG.js} +2 -2
- package/dist/gateway/static/root/assets/{logs-page-C76F4Y0H.js.map → logs-page-DFhTU-kG.js.map} +1 -1
- package/dist/gateway/static/root/assets/{sessions-page-9jwUqGtS.js → sessions-page-wmnnIj6Z.js} +2 -2
- package/dist/gateway/static/root/assets/{sessions-page-9jwUqGtS.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-BY1cLNEz.js → skills-page-D-fRbJG0.js} +2 -2
- package/dist/gateway/static/root/assets/{skills-page-BY1cLNEz.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/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/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/service.js +1 -1
- package/dist/src/agent/tools/factory.js +9 -2
- 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/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 +1 -1
- package/dist/src/chat-commands/builtins/session.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/channels.js +20 -2
- package/dist/src/cli/commands/channels.js.map +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/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/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/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/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/loader.d.ts +6 -1
- package/dist/src/extensions/loader.js +20 -1
- package/dist/src/extensions/loader.js.map +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/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/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 +81 -0
- 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/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 +107 -0
- package/dist/src/gateway/service.js.map +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/package.json +1 -1
- package/dist/gateway/static/root/assets/channels-settings-h3eQwIPi.js +0 -9
- package/dist/gateway/static/root/assets/channels-settings-h3eQwIPi.js.map +0 -1
- package/dist/gateway/static/root/assets/index-BQNdJlkw.css +0 -1
- package/dist/gateway/static/root/assets/settings-page-DNG3Zijx.js +0 -2
- package/dist/gateway/static/root/assets/settings-page-DNG3Zijx.js.map +0 -1
|
@@ -16,11 +16,29 @@ function createChannelsCommand(ctx) {
|
|
|
16
16
|
const cmd = new Command("channels").description("Messaging channel login and credentials").addHelpText("after", formatExamples([
|
|
17
17
|
"xopc channels login",
|
|
18
18
|
"xopc channels login --channel weixin",
|
|
19
|
+
"xopc channels login --channel feishu",
|
|
19
20
|
"xopc channels login --account my-bot-id"
|
|
20
21
|
]));
|
|
21
|
-
cmd.command("login").description("Log in with QR code or channel-specific credentials flow").option("--channel <id>", "Channel id
|
|
22
|
+
cmd.command("login").description("Log in with QR code or channel-specific credentials flow").option("--channel <id>", "Channel id (auto-detected when only one login-capable channel is registered)").option("--account <id>", "Optional account id when re-logging an existing bot").option("--timeout <ms>", "Max wait for scan (default 480000)", "480000").option("--credentials-only", "Only save token files; do not update xopc.json").action(async (options, command) => {
|
|
22
23
|
ensureChannelRegistryForCli();
|
|
23
|
-
const
|
|
24
|
+
const explicitChannel = options.channel?.trim?.();
|
|
25
|
+
let channelId;
|
|
26
|
+
if (explicitChannel) channelId = explicitChannel;
|
|
27
|
+
else {
|
|
28
|
+
const loginCapable = listChannelPlugins().filter((p) => p.cliLogin);
|
|
29
|
+
if (loginCapable.length === 1) {
|
|
30
|
+
channelId = loginCapable[0].id;
|
|
31
|
+
console.log(`Auto-detected channel: ${channelId}`);
|
|
32
|
+
} else if (loginCapable.length === 0) {
|
|
33
|
+
console.error("No channels with login support found.");
|
|
34
|
+
process.exitCode = 1;
|
|
35
|
+
return;
|
|
36
|
+
} else {
|
|
37
|
+
console.error(`Multiple channels support login: ${loginCapable.map((p) => p.id).join(", ")}. Use --channel <id> to specify.`);
|
|
38
|
+
process.exitCode = 1;
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
24
42
|
const plugin = getChannelPlugin(channelId);
|
|
25
43
|
if (!plugin?.cliLogin) {
|
|
26
44
|
console.error(`Channel "${channelId}" does not support CLI login.`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channels.js","names":[],"sources":["../../../../src/cli/commands/channels.ts"],"sourcesContent":["import { Command } from 'commander';\n\nimport { resolveConfigPath } from '../../config/paths.js';\nimport {\n getChannelPlugin,\n listChannelPlugins,\n syncChannelPluginsFromManager,\n} from '../../channels/plugins/registry.js';\nimport { bundledChannelPlugins } from '../../generated/bundled-channel-plugins.js';\nimport { register, formatExamples, type CLIContext } from '../registry.js';\n\nfunction ensureChannelRegistryForCli(): void {\n if (listChannelPlugins().length === 0) {\n syncChannelPluginsFromManager(bundledChannelPlugins);\n }\n}\n\nfunction resolveConfigPathFromCommand(command: Command): string {\n const root =\n command.parent?.parent && command.parent.parent instanceof Command\n ? command.parent.parent\n : command.parent && command.parent instanceof Command\n ? command.parent\n : null;\n const globalOpts = (root && typeof root.opts === 'function'\n ? (root.opts() as { config?: string })\n : {}) as { config?: string };\n return (\n globalOpts.config?.trim() ||\n process.env.XOPC_CONFIG_PATH?.trim() ||\n process.env.XOPC_CONFIG?.trim() ||\n resolveConfigPath()\n );\n}\n\nfunction createChannelsCommand(ctx: CLIContext): Command {\n const cmd = new Command('channels')\n .description('Messaging channel login and credentials')\n .addHelpText(\n 'after',\n formatExamples([\n 'xopc channels login',\n 'xopc channels login --channel weixin',\n 'xopc channels login --account my-bot-id',\n ]),\n );\n\n cmd\n .command('login')\n .description('Log in with QR code or channel-specific credentials flow')\n .option('--channel <id>'
|
|
1
|
+
{"version":3,"file":"channels.js","names":[],"sources":["../../../../src/cli/commands/channels.ts"],"sourcesContent":["import { Command } from 'commander';\n\nimport { resolveConfigPath } from '../../config/paths.js';\nimport {\n getChannelPlugin,\n listChannelPlugins,\n syncChannelPluginsFromManager,\n} from '../../channels/plugins/registry.js';\nimport { bundledChannelPlugins } from '../../generated/bundled-channel-plugins.js';\nimport { register, formatExamples, type CLIContext } from '../registry.js';\n\nfunction ensureChannelRegistryForCli(): void {\n if (listChannelPlugins().length === 0) {\n syncChannelPluginsFromManager(bundledChannelPlugins);\n }\n}\n\nfunction resolveConfigPathFromCommand(command: Command): string {\n const root =\n command.parent?.parent && command.parent.parent instanceof Command\n ? command.parent.parent\n : command.parent && command.parent instanceof Command\n ? command.parent\n : null;\n const globalOpts = (root && typeof root.opts === 'function'\n ? (root.opts() as { config?: string })\n : {}) as { config?: string };\n return (\n globalOpts.config?.trim() ||\n process.env.XOPC_CONFIG_PATH?.trim() ||\n process.env.XOPC_CONFIG?.trim() ||\n resolveConfigPath()\n );\n}\n\nfunction createChannelsCommand(ctx: CLIContext): Command {\n const cmd = new Command('channels')\n .description('Messaging channel login and credentials')\n .addHelpText(\n 'after',\n formatExamples([\n 'xopc channels login',\n 'xopc channels login --channel weixin',\n 'xopc channels login --channel feishu',\n 'xopc channels login --account my-bot-id',\n ]),\n );\n\n cmd\n .command('login')\n .description('Log in with QR code or channel-specific credentials flow')\n .option(\n '--channel <id>',\n 'Channel id (auto-detected when only one login-capable channel is registered)',\n )\n .option('--account <id>', 'Optional account id when re-logging an existing bot')\n .option('--timeout <ms>', 'Max wait for scan (default 480000)', '480000')\n .option('--credentials-only', 'Only save token files; do not update xopc.json')\n .action(async (options, command) => {\n ensureChannelRegistryForCli();\n const explicitChannel = options.channel?.trim?.();\n let channelId: string;\n if (explicitChannel) {\n channelId = explicitChannel;\n } else {\n const loginCapable = listChannelPlugins().filter((p) => p.cliLogin);\n if (loginCapable.length === 1) {\n channelId = loginCapable[0].id;\n console.log(`Auto-detected channel: ${channelId}`);\n } else if (loginCapable.length === 0) {\n console.error('No channels with login support found.');\n process.exitCode = 1;\n return;\n } else {\n console.error(\n `Multiple channels support login: ${loginCapable.map((p) => p.id).join(', ')}. ` +\n 'Use --channel <id> to specify.',\n );\n process.exitCode = 1;\n return;\n }\n }\n const plugin = getChannelPlugin(channelId);\n if (!plugin?.cliLogin) {\n console.error(`Channel \"${channelId}\" does not support CLI login.`);\n const capable = listChannelPlugins()\n .filter((p) => p.cliLogin)\n .map((p) => p.id);\n if (capable.length > 0) {\n console.error(`Channels with login support: ${capable.join(', ')}`);\n }\n process.exitCode = 1;\n return;\n }\n\n const configPath = resolveConfigPathFromCommand(command);\n const timeoutMs = Math.max(60_000, Number.parseInt(String(options.timeout), 10) || 480_000);\n const verbose = ctx.isVerbose;\n\n const result = await plugin.cliLogin.runLogin({\n configPath,\n verbose,\n timeoutMs,\n accountId: options.account?.trim() || undefined,\n writeConfig: !options.credentialsOnly,\n });\n\n if (!result.ok) {\n console.error(result.message || 'Login failed');\n process.exitCode = 1;\n }\n });\n\n return cmd;\n}\n\nregister({\n id: 'channels',\n name: 'channels',\n description: 'Messaging channel login',\n factory: createChannelsCommand,\n metadata: {\n category: 'setup',\n examples: [\n 'xopc channels login',\n 'xopc channels login --account my-account-id',\n ],\n },\n});\n"],"mappings":";;;;;;YAE0D;AAS1D,SAAS,8BAAoC;AAC3C,KAAI,oBAAoB,CAAC,WAAW,EAClC,+BAA8B,sBAAsB;;AAIxD,SAAS,6BAA6B,SAA0B;CAC9D,MAAM,OACJ,QAAQ,QAAQ,UAAU,QAAQ,OAAO,kBAAkB,UACvD,QAAQ,OAAO,SACf,QAAQ,UAAU,QAAQ,kBAAkB,UAC1C,QAAQ,SACR;AAIR,SAHoB,QAAQ,OAAO,KAAK,SAAS,aAC5C,KAAK,MAAM,GACZ,EAAE,EAEO,QAAQ,MAAM,IACzB,QAAQ,IAAI,kBAAkB,MAAM,IACpC,QAAQ,IAAI,aAAa,MAAM,IAC/B,mBAAmB;;AAIvB,SAAS,sBAAsB,KAA0B;CACvD,MAAM,MAAM,IAAI,QAAQ,WAAW,CAChC,YAAY,0CAA0C,CACtD,YACC,SACA,eAAe;EACb;EACA;EACA;EACA;EACD,CAAC,CACH;AAEH,KACG,QAAQ,QAAQ,CAChB,YAAY,2DAA2D,CACvE,OACC,kBACA,+EACD,CACA,OAAO,kBAAkB,sDAAsD,CAC/E,OAAO,kBAAkB,sCAAsC,SAAS,CACxE,OAAO,sBAAsB,iDAAiD,CAC9E,OAAO,OAAO,SAAS,YAAY;AAClC,+BAA6B;EAC7B,MAAM,kBAAkB,QAAQ,SAAS,QAAQ;EACjD,IAAI;AACJ,MAAI,gBACF,aAAY;OACP;GACL,MAAM,eAAe,oBAAoB,CAAC,QAAQ,MAAM,EAAE,SAAS;AACnE,OAAI,aAAa,WAAW,GAAG;AAC7B,gBAAY,aAAa,GAAG;AAC5B,YAAQ,IAAI,0BAA0B,YAAY;cACzC,aAAa,WAAW,GAAG;AACpC,YAAQ,MAAM,wCAAwC;AACtD,YAAQ,WAAW;AACnB;UACK;AACL,YAAQ,MACN,oCAAoC,aAAa,KAAK,MAAM,EAAE,GAAG,CAAC,KAAK,KAAK,CAAC,kCAE9E;AACD,YAAQ,WAAW;AACnB;;;EAGJ,MAAM,SAAS,iBAAiB,UAAU;AAC1C,MAAI,CAAC,QAAQ,UAAU;AACrB,WAAQ,MAAM,YAAY,UAAU,+BAA+B;GACnE,MAAM,UAAU,oBAAoB,CACjC,QAAQ,MAAM,EAAE,SAAS,CACzB,KAAK,MAAM,EAAE,GAAG;AACnB,OAAI,QAAQ,SAAS,EACnB,SAAQ,MAAM,gCAAgC,QAAQ,KAAK,KAAK,GAAG;AAErE,WAAQ,WAAW;AACnB;;EAGF,MAAM,aAAa,6BAA6B,QAAQ;EACxD,MAAM,YAAY,KAAK,IAAI,KAAQ,OAAO,SAAS,OAAO,QAAQ,QAAQ,EAAE,GAAG,IAAI,KAAQ;EAC3F,MAAM,UAAU,IAAI;EAEpB,MAAM,SAAS,MAAM,OAAO,SAAS,SAAS;GAC5C;GACA;GACA;GACA,WAAW,QAAQ,SAAS,MAAM,IAAI,KAAA;GACtC,aAAa,CAAC,QAAQ;GACvB,CAAC;AAEF,MAAI,CAAC,OAAO,IAAI;AACd,WAAQ,MAAM,OAAO,WAAW,eAAe;AAC/C,WAAQ,WAAW;;GAErB;AAEJ,QAAO;;AAGT,SAAS;CACP,IAAI;CACJ,MAAM;CACN,aAAa;CACb,SAAS;CACT,UAAU;EACR,UAAU;EACV,UAAU,CACR,uBACA,8CACD;EACF;CACF,CAAC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { init_paths, resolveConfigPath } from "../../../config/paths.js";
|
|
2
|
+
import { addGatewayClientOptions, callGatewayApi, parseGatewayClientOptions } from "../../utils/gateway-client.js";
|
|
3
|
+
import { getContextWithOpts } from "../../index.js";
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
//#region src/cli/commands/gateway/call.ts
|
|
6
|
+
init_paths();
|
|
7
|
+
const METHOD_ALIASES = {
|
|
8
|
+
health: {
|
|
9
|
+
method: "GET",
|
|
10
|
+
path: "/api/health"
|
|
11
|
+
},
|
|
12
|
+
status: {
|
|
13
|
+
method: "GET",
|
|
14
|
+
path: "/api/status"
|
|
15
|
+
},
|
|
16
|
+
config: {
|
|
17
|
+
method: "GET",
|
|
18
|
+
path: "/api/config"
|
|
19
|
+
},
|
|
20
|
+
sessions: {
|
|
21
|
+
method: "GET",
|
|
22
|
+
path: "/api/sessions"
|
|
23
|
+
},
|
|
24
|
+
models: {
|
|
25
|
+
method: "GET",
|
|
26
|
+
path: "/api/models"
|
|
27
|
+
},
|
|
28
|
+
channels: {
|
|
29
|
+
method: "GET",
|
|
30
|
+
path: "/api/channels/status"
|
|
31
|
+
},
|
|
32
|
+
cron: {
|
|
33
|
+
method: "GET",
|
|
34
|
+
path: "/api/cron"
|
|
35
|
+
},
|
|
36
|
+
logs: {
|
|
37
|
+
method: "GET",
|
|
38
|
+
path: "/api/logs"
|
|
39
|
+
},
|
|
40
|
+
agents: {
|
|
41
|
+
method: "GET",
|
|
42
|
+
path: "/api/agents"
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
function createCallCommand() {
|
|
46
|
+
const cmd = new Command("call").description("Call a gateway API method").argument("<method>", `Method name or API path. Built-in aliases: ${Object.keys(METHOD_ALIASES).join(", ")}`).option("--params <json>", "JSON body for POST/PATCH/DELETE requests", "{}").option("--http-method <method>", "HTTP method when using a raw path", "GET");
|
|
47
|
+
addGatewayClientOptions(cmd);
|
|
48
|
+
cmd.action(async (methodArg, options) => {
|
|
49
|
+
const configPath = getContextWithOpts().configPath || resolveConfigPath();
|
|
50
|
+
const clientOpts = {
|
|
51
|
+
...parseGatewayClientOptions(options),
|
|
52
|
+
configPath
|
|
53
|
+
};
|
|
54
|
+
const alias = METHOD_ALIASES[methodArg.toLowerCase()];
|
|
55
|
+
let httpMethod;
|
|
56
|
+
let apiPath;
|
|
57
|
+
if (alias) {
|
|
58
|
+
httpMethod = alias.method;
|
|
59
|
+
apiPath = alias.path;
|
|
60
|
+
} else if (methodArg.startsWith("/")) {
|
|
61
|
+
httpMethod = options.httpMethod?.toUpperCase() ?? "GET";
|
|
62
|
+
apiPath = methodArg;
|
|
63
|
+
} else {
|
|
64
|
+
httpMethod = options.httpMethod?.toUpperCase() ?? "GET";
|
|
65
|
+
apiPath = `/api/${methodArg}`;
|
|
66
|
+
}
|
|
67
|
+
let body;
|
|
68
|
+
if (httpMethod !== "GET" && options.params && options.params !== "{}") try {
|
|
69
|
+
body = JSON.parse(options.params);
|
|
70
|
+
} catch {
|
|
71
|
+
console.error(`❌ Invalid JSON in --params: ${options.params}`);
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
const result = await callGatewayApi(httpMethod, apiPath, clientOpts, body);
|
|
75
|
+
if (clientOpts.json || result.ok) console.log(JSON.stringify(result.ok ? result.data : {
|
|
76
|
+
error: result.error,
|
|
77
|
+
status: result.status,
|
|
78
|
+
durationMs: result.durationMs
|
|
79
|
+
}, null, 2));
|
|
80
|
+
if (!result.ok) {
|
|
81
|
+
if (!clientOpts.json) console.error(`❌ Gateway call failed: ${result.error} (status ${result.status}, ${result.durationMs}ms)`);
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
return cmd;
|
|
86
|
+
}
|
|
87
|
+
//#endregion
|
|
88
|
+
export { createCallCommand };
|
|
89
|
+
|
|
90
|
+
//# sourceMappingURL=call.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"call.js","names":[],"sources":["../../../../../src/cli/commands/gateway/call.ts"],"sourcesContent":["import { Command } from 'commander';\n\nimport {\n callGatewayApi,\n addGatewayClientOptions,\n parseGatewayClientOptions,\n} from '../../utils/gateway-client.js';\nimport { getContextWithOpts } from '../../index.js';\nimport { resolveConfigPath } from '../../../config/paths.js';\n\nconst METHOD_ALIASES: Record<string, { method: 'GET' | 'POST'; path: string }> = {\n health: { method: 'GET', path: '/api/health' },\n status: { method: 'GET', path: '/api/status' },\n config: { method: 'GET', path: '/api/config' },\n sessions: { method: 'GET', path: '/api/sessions' },\n models: { method: 'GET', path: '/api/models' },\n channels: { method: 'GET', path: '/api/channels/status' },\n cron: { method: 'GET', path: '/api/cron' },\n logs: { method: 'GET', path: '/api/logs' },\n agents: { method: 'GET', path: '/api/agents' },\n};\n\nexport function createCallCommand(): Command {\n const cmd = new Command('call')\n .description('Call a gateway API method')\n .argument(\n '<method>',\n `Method name or API path. Built-in aliases: ${Object.keys(METHOD_ALIASES).join(', ')}`,\n )\n .option('--params <json>', 'JSON body for POST/PATCH/DELETE requests', '{}')\n .option('--http-method <method>', 'HTTP method when using a raw path', 'GET');\n\n addGatewayClientOptions(cmd);\n\n cmd.action(async (methodArg: string, options: { params?: string; httpMethod?: string }) => {\n const ctx = getContextWithOpts();\n const configPath = ctx.configPath || resolveConfigPath();\n const clientOpts = { ...parseGatewayClientOptions(options as Record<string, unknown>), configPath };\n\n const alias = METHOD_ALIASES[methodArg.toLowerCase()];\n let httpMethod: 'GET' | 'POST' | 'PATCH' | 'DELETE';\n let apiPath: string;\n\n if (alias) {\n httpMethod = alias.method;\n apiPath = alias.path;\n } else if (methodArg.startsWith('/')) {\n httpMethod = (options.httpMethod?.toUpperCase() ?? 'GET') as 'GET' | 'POST' | 'PATCH' | 'DELETE';\n apiPath = methodArg;\n } else {\n httpMethod = (options.httpMethod?.toUpperCase() ?? 'GET') as 'GET' | 'POST' | 'PATCH' | 'DELETE';\n apiPath = `/api/${methodArg}`;\n }\n\n let body: unknown | undefined;\n if (httpMethod !== 'GET' && options.params && options.params !== '{}') {\n try {\n body = JSON.parse(options.params);\n } catch {\n console.error(`❌ Invalid JSON in --params: ${options.params}`);\n process.exit(1);\n }\n }\n\n const result = await callGatewayApi(httpMethod, apiPath, clientOpts, body);\n\n if (clientOpts.json || result.ok) {\n console.log(\n JSON.stringify(\n result.ok\n ? result.data\n : { error: result.error, status: result.status, durationMs: result.durationMs },\n null,\n 2,\n ),\n );\n }\n\n if (!result.ok) {\n if (!clientOpts.json) {\n console.error(`❌ Gateway call failed: ${result.error} (status ${result.status}, ${result.durationMs}ms)`);\n }\n process.exit(1);\n }\n });\n\n return cmd;\n}\n"],"mappings":";;;;;YAQ6D;AAE7D,MAAM,iBAA2E;CAC/E,QAAQ;EAAE,QAAQ;EAAO,MAAM;EAAe;CAC9C,QAAQ;EAAE,QAAQ;EAAO,MAAM;EAAe;CAC9C,QAAQ;EAAE,QAAQ;EAAO,MAAM;EAAe;CAC9C,UAAU;EAAE,QAAQ;EAAO,MAAM;EAAiB;CAClD,QAAQ;EAAE,QAAQ;EAAO,MAAM;EAAe;CAC9C,UAAU;EAAE,QAAQ;EAAO,MAAM;EAAwB;CACzD,MAAM;EAAE,QAAQ;EAAO,MAAM;EAAa;CAC1C,MAAM;EAAE,QAAQ;EAAO,MAAM;EAAa;CAC1C,QAAQ;EAAE,QAAQ;EAAO,MAAM;EAAe;CAC/C;AAED,SAAgB,oBAA6B;CAC3C,MAAM,MAAM,IAAI,QAAQ,OAAO,CAC5B,YAAY,4BAA4B,CACxC,SACC,YACA,8CAA8C,OAAO,KAAK,eAAe,CAAC,KAAK,KAAK,GACrF,CACA,OAAO,mBAAmB,4CAA4C,KAAK,CAC3E,OAAO,0BAA0B,qCAAqC,MAAM;AAE/E,yBAAwB,IAAI;AAE5B,KAAI,OAAO,OAAO,WAAmB,YAAsD;EAEzF,MAAM,aADM,oBACU,CAAC,cAAc,mBAAmB;EACxD,MAAM,aAAa;GAAE,GAAG,0BAA0B,QAAmC;GAAE;GAAY;EAEnG,MAAM,QAAQ,eAAe,UAAU,aAAa;EACpD,IAAI;EACJ,IAAI;AAEJ,MAAI,OAAO;AACT,gBAAa,MAAM;AACnB,aAAU,MAAM;aACP,UAAU,WAAW,IAAI,EAAE;AACpC,gBAAc,QAAQ,YAAY,aAAa,IAAI;AACnD,aAAU;SACL;AACL,gBAAc,QAAQ,YAAY,aAAa,IAAI;AACnD,aAAU,QAAQ;;EAGpB,IAAI;AACJ,MAAI,eAAe,SAAS,QAAQ,UAAU,QAAQ,WAAW,KAC/D,KAAI;AACF,UAAO,KAAK,MAAM,QAAQ,OAAO;UAC3B;AACN,WAAQ,MAAM,+BAA+B,QAAQ,SAAS;AAC9D,WAAQ,KAAK,EAAE;;EAInB,MAAM,SAAS,MAAM,eAAe,YAAY,SAAS,YAAY,KAAK;AAE1E,MAAI,WAAW,QAAQ,OAAO,GAC5B,SAAQ,IACN,KAAK,UACH,OAAO,KACH,OAAO,OACP;GAAE,OAAO,OAAO;GAAO,QAAQ,OAAO;GAAQ,YAAY,OAAO;GAAY,EACjF,MACA,EACD,CACF;AAGH,MAAI,CAAC,OAAO,IAAI;AACd,OAAI,CAAC,WAAW,KACd,SAAQ,MAAM,0BAA0B,OAAO,MAAM,WAAW,OAAO,OAAO,IAAI,OAAO,WAAW,KAAK;AAE3G,WAAQ,KAAK,EAAE;;GAEjB;AAEF,QAAO"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { init_paths, resolveConfigPath } from "../../../config/paths.js";
|
|
2
|
+
import { addGatewayClientOptions, callGatewayApi, parseGatewayClientOptions } from "../../utils/gateway-client.js";
|
|
3
|
+
import { getContextWithOpts } from "../../index.js";
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
//#region src/cli/commands/gateway/health.ts
|
|
6
|
+
init_paths();
|
|
7
|
+
function formatUptime(seconds) {
|
|
8
|
+
if (!seconds || seconds <= 0) return "unknown";
|
|
9
|
+
const days = Math.floor(seconds / 86400);
|
|
10
|
+
const hours = Math.floor(seconds % 86400 / 3600);
|
|
11
|
+
const minutes = Math.floor(seconds % 3600 / 60);
|
|
12
|
+
const parts = [];
|
|
13
|
+
if (days > 0) parts.push(`${days}d`);
|
|
14
|
+
if (hours > 0) parts.push(`${hours}h`);
|
|
15
|
+
parts.push(`${minutes}m`);
|
|
16
|
+
return parts.join(" ");
|
|
17
|
+
}
|
|
18
|
+
function createHealthCommand() {
|
|
19
|
+
const cmd = new Command("health").description("Check gateway health and channel status");
|
|
20
|
+
addGatewayClientOptions(cmd);
|
|
21
|
+
cmd.action(async (options) => {
|
|
22
|
+
const configPath = getContextWithOpts().configPath || resolveConfigPath();
|
|
23
|
+
const clientOpts = {
|
|
24
|
+
...parseGatewayClientOptions(options),
|
|
25
|
+
configPath
|
|
26
|
+
};
|
|
27
|
+
const healthResult = await callGatewayApi("GET", "/api/health", {
|
|
28
|
+
...clientOpts,
|
|
29
|
+
timeoutMs: clientOpts.timeoutMs ?? 5e3
|
|
30
|
+
});
|
|
31
|
+
if (!healthResult.ok) {
|
|
32
|
+
if (clientOpts.json) console.log(JSON.stringify({
|
|
33
|
+
status: "unreachable",
|
|
34
|
+
error: healthResult.error,
|
|
35
|
+
durationMs: healthResult.durationMs
|
|
36
|
+
}, null, 2));
|
|
37
|
+
else {
|
|
38
|
+
console.error(`❌ Gateway unreachable: ${healthResult.error}`);
|
|
39
|
+
console.error("");
|
|
40
|
+
console.error("💡 Is the gateway running? Try: xopc gateway");
|
|
41
|
+
}
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
const statusResult = await callGatewayApi("GET", "/api/status", clientOpts);
|
|
45
|
+
if (clientOpts.json) {
|
|
46
|
+
console.log(JSON.stringify({
|
|
47
|
+
status: "ok",
|
|
48
|
+
durationMs: healthResult.durationMs,
|
|
49
|
+
health: healthResult.data,
|
|
50
|
+
...statusResult.ok ? { details: statusResult.data } : {}
|
|
51
|
+
}, null, 2));
|
|
52
|
+
process.exit(0);
|
|
53
|
+
}
|
|
54
|
+
console.log(`✅ Gateway Health: OK (${healthResult.durationMs}ms)`);
|
|
55
|
+
console.log("");
|
|
56
|
+
if (healthResult.data?.version) console.log(` Version: ${healthResult.data.version}`);
|
|
57
|
+
if (healthResult.data?.uptime != null) console.log(` Uptime: ${formatUptime(healthResult.data.uptime)}`);
|
|
58
|
+
if (statusResult.ok && statusResult.data?.channels) {
|
|
59
|
+
console.log("");
|
|
60
|
+
console.log("📡 Channels:");
|
|
61
|
+
for (const [name, info] of Object.entries(statusResult.data.channels)) {
|
|
62
|
+
const statusIcon = info.status === "connected" ? "✅" : info.status === "disabled" ? "⚪" : "❌";
|
|
63
|
+
const accountsLabel = info.accounts != null ? ` (${info.accounts} account(s))` : "";
|
|
64
|
+
console.log(` ${statusIcon} ${name}: ${info.status}${accountsLabel}`);
|
|
65
|
+
}
|
|
66
|
+
} else if (statusResult.status === 401) {
|
|
67
|
+
console.log("");
|
|
68
|
+
console.log("🔒 Detailed status requires authentication. Pass --token <token>.");
|
|
69
|
+
}
|
|
70
|
+
process.exit(0);
|
|
71
|
+
});
|
|
72
|
+
return cmd;
|
|
73
|
+
}
|
|
74
|
+
//#endregion
|
|
75
|
+
export { createHealthCommand };
|
|
76
|
+
|
|
77
|
+
//# sourceMappingURL=health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.js","names":[],"sources":["../../../../../src/cli/commands/gateway/health.ts"],"sourcesContent":["import { Command } from 'commander';\n\nimport {\n callGatewayApi,\n addGatewayClientOptions,\n parseGatewayClientOptions,\n} from '../../utils/gateway-client.js';\nimport { getContextWithOpts } from '../../index.js';\nimport { resolveConfigPath } from '../../../config/paths.js';\n\ninterface HealthResponse {\n status: string;\n version?: string;\n uptime?: number;\n}\n\ninterface StatusResponse {\n status: string;\n version?: string;\n channels?: Record<string, { status: string; accounts?: number }>;\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 createHealthCommand(): Command {\n const cmd = new Command('health').description('Check gateway health and channel status');\n\n addGatewayClientOptions(cmd);\n\n cmd.action(async (options) => {\n const ctx = getContextWithOpts();\n const configPath = ctx.configPath || resolveConfigPath();\n const clientOpts = { ...parseGatewayClientOptions(options as Record<string, unknown>), configPath };\n\n const healthResult = await callGatewayApi<HealthResponse>('GET', '/api/health', {\n ...clientOpts,\n timeoutMs: clientOpts.timeoutMs ?? 5000,\n });\n\n if (!healthResult.ok) {\n if (clientOpts.json) {\n console.log(\n JSON.stringify(\n {\n status: 'unreachable',\n error: healthResult.error,\n durationMs: healthResult.durationMs,\n },\n null,\n 2,\n ),\n );\n } else {\n console.error(`❌ Gateway unreachable: ${healthResult.error}`);\n console.error('');\n console.error('💡 Is the gateway running? Try: xopc gateway');\n }\n process.exit(1);\n }\n\n const statusResult = await callGatewayApi<StatusResponse>('GET', '/api/status', clientOpts);\n\n if (clientOpts.json) {\n console.log(\n JSON.stringify(\n {\n status: 'ok',\n durationMs: healthResult.durationMs,\n health: healthResult.data,\n ...(statusResult.ok ? { details: statusResult.data } : {}),\n },\n null,\n 2,\n ),\n );\n process.exit(0);\n }\n\n console.log(`✅ Gateway Health: OK (${healthResult.durationMs}ms)`);\n console.log('');\n\n if (healthResult.data?.version) {\n console.log(` Version: ${healthResult.data.version}`);\n }\n if (healthResult.data?.uptime != null) {\n console.log(` Uptime: ${formatUptime(healthResult.data.uptime)}`);\n }\n\n if (statusResult.ok && statusResult.data?.channels) {\n console.log('');\n console.log('📡 Channels:');\n for (const [name, info] of Object.entries(statusResult.data.channels)) {\n const statusIcon = info.status === 'connected' ? '✅' : info.status === 'disabled' ? '⚪' : '❌';\n const accountsLabel = info.accounts != null ? ` (${info.accounts} account(s))` : '';\n console.log(` ${statusIcon} ${name}: ${info.status}${accountsLabel}`);\n }\n } else if (statusResult.status === 401) {\n console.log('');\n console.log('🔒 Detailed status requires authentication. Pass --token <token>.');\n }\n\n process.exit(0);\n });\n\n return cmd;\n}\n"],"mappings":";;;;;YAQ6D;AAe7D,SAAS,aAAa,SAA0B;AAC9C,KAAI,CAAC,WAAW,WAAW,EAAG,QAAO;CACrC,MAAM,OAAO,KAAK,MAAM,UAAU,MAAM;CACxC,MAAM,QAAQ,KAAK,MAAO,UAAU,QAAS,KAAK;CAClD,MAAM,UAAU,KAAK,MAAO,UAAU,OAAQ,GAAG;CACjD,MAAM,QAAkB,EAAE;AAC1B,KAAI,OAAO,EAAG,OAAM,KAAK,GAAG,KAAK,GAAG;AACpC,KAAI,QAAQ,EAAG,OAAM,KAAK,GAAG,MAAM,GAAG;AACtC,OAAM,KAAK,GAAG,QAAQ,GAAG;AACzB,QAAO,MAAM,KAAK,IAAI;;AAGxB,SAAgB,sBAA+B;CAC7C,MAAM,MAAM,IAAI,QAAQ,SAAS,CAAC,YAAY,0CAA0C;AAExF,yBAAwB,IAAI;AAE5B,KAAI,OAAO,OAAO,YAAY;EAE5B,MAAM,aADM,oBACU,CAAC,cAAc,mBAAmB;EACxD,MAAM,aAAa;GAAE,GAAG,0BAA0B,QAAmC;GAAE;GAAY;EAEnG,MAAM,eAAe,MAAM,eAA+B,OAAO,eAAe;GAC9E,GAAG;GACH,WAAW,WAAW,aAAa;GACpC,CAAC;AAEF,MAAI,CAAC,aAAa,IAAI;AACpB,OAAI,WAAW,KACb,SAAQ,IACN,KAAK,UACH;IACE,QAAQ;IACR,OAAO,aAAa;IACpB,YAAY,aAAa;IAC1B,EACD,MACA,EACD,CACF;QACI;AACL,YAAQ,MAAM,0BAA0B,aAAa,QAAQ;AAC7D,YAAQ,MAAM,GAAG;AACjB,YAAQ,MAAM,+CAA+C;;AAE/D,WAAQ,KAAK,EAAE;;EAGjB,MAAM,eAAe,MAAM,eAA+B,OAAO,eAAe,WAAW;AAE3F,MAAI,WAAW,MAAM;AACnB,WAAQ,IACN,KAAK,UACH;IACE,QAAQ;IACR,YAAY,aAAa;IACzB,QAAQ,aAAa;IACrB,GAAI,aAAa,KAAK,EAAE,SAAS,aAAa,MAAM,GAAG,EAAE;IAC1D,EACD,MACA,EACD,CACF;AACD,WAAQ,KAAK,EAAE;;AAGjB,UAAQ,IAAI,yBAAyB,aAAa,WAAW,KAAK;AAClE,UAAQ,IAAI,GAAG;AAEf,MAAI,aAAa,MAAM,QACrB,SAAQ,IAAI,eAAe,aAAa,KAAK,UAAU;AAEzD,MAAI,aAAa,MAAM,UAAU,KAC/B,SAAQ,IAAI,eAAe,aAAa,aAAa,KAAK,OAAO,GAAG;AAGtE,MAAI,aAAa,MAAM,aAAa,MAAM,UAAU;AAClD,WAAQ,IAAI,GAAG;AACf,WAAQ,IAAI,eAAe;AAC3B,QAAK,MAAM,CAAC,MAAM,SAAS,OAAO,QAAQ,aAAa,KAAK,SAAS,EAAE;IACrE,MAAM,aAAa,KAAK,WAAW,cAAc,MAAM,KAAK,WAAW,aAAa,MAAM;IAC1F,MAAM,gBAAgB,KAAK,YAAY,OAAO,KAAK,KAAK,SAAS,gBAAgB;AACjF,YAAQ,IAAI,MAAM,WAAW,GAAG,KAAK,IAAI,KAAK,SAAS,gBAAgB;;aAEhE,aAAa,WAAW,KAAK;AACtC,WAAQ,IAAI,GAAG;AACf,WAAQ,IAAI,oEAAoE;;AAGlF,UAAQ,KAAK,EAAE;GACf;AAEF,QAAO"}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export { createTokenCommand } from './token.js';
|
|
2
2
|
export { createStatusCommand } from './status.js';
|
|
3
|
+
export { createHealthCommand } from './health.js';
|
|
4
|
+
export { createCallCommand } from './call.js';
|
|
5
|
+
export { createProbeCommand } from './probe.js';
|
|
3
6
|
export { createStopCommand } from './stop.js';
|
|
4
7
|
export { createRestartCommand } from './restart.js';
|
|
5
8
|
export { createLogsCommand } from './logs.js';
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { createTokenCommand } from "./token.js";
|
|
2
2
|
import { createStatusCommand } from "./status.js";
|
|
3
|
+
import { createHealthCommand } from "./health.js";
|
|
4
|
+
import { createCallCommand } from "./call.js";
|
|
5
|
+
import { createProbeCommand } from "./probe.js";
|
|
3
6
|
import { createStopCommand } from "./stop.js";
|
|
4
7
|
import { createRestartCommand } from "./restart.js";
|
|
5
8
|
import { createLogsCommand } from "./logs.js";
|
|
6
9
|
import { createInstallCommand, createServiceStartCommand, createServiceStatusCommand, createUninstallCommand } from "./service.js";
|
|
7
|
-
export { createInstallCommand, createLogsCommand, createRestartCommand, createServiceStartCommand, createServiceStatusCommand, createStatusCommand, createStopCommand, createTokenCommand, createUninstallCommand };
|
|
10
|
+
export { createCallCommand, createHealthCommand, createInstallCommand, createLogsCommand, createProbeCommand, createRestartCommand, createServiceStartCommand, createServiceStatusCommand, createStatusCommand, createStopCommand, createTokenCommand, createUninstallCommand };
|
|
@@ -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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"}
|