@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.
Files changed (147) hide show
  1. package/dist/extensions/feishu/src/adapters/cli-login.d.ts +8 -0
  2. package/dist/extensions/feishu/src/adapters/cli-login.js +225 -0
  3. package/dist/extensions/feishu/src/adapters/cli-login.js.map +1 -0
  4. package/dist/extensions/feishu/src/adapters/onboard-cli.js +1 -105
  5. package/dist/extensions/feishu/src/adapters/onboard-cli.js.map +1 -1
  6. package/dist/extensions/feishu/src/auth/app-registration.d.ts +47 -0
  7. package/dist/extensions/feishu/src/auth/app-registration.js +122 -0
  8. package/dist/extensions/feishu/src/auth/app-registration.js.map +1 -0
  9. package/dist/extensions/feishu/src/plugin.d.ts +2 -0
  10. package/dist/extensions/feishu/src/plugin.js +2 -0
  11. package/dist/extensions/feishu/src/plugin.js.map +1 -1
  12. package/dist/extensions/telegram/src/inbound-processor.js +1 -1
  13. package/dist/extensions/telegram/src/plugin.d.ts +1 -1
  14. package/dist/extensions/telegram/xopc.extension.json +1 -1
  15. package/dist/gateway/static/root/assets/{agents-ByiiWRbv.js → agents-MbH57-L9.js} +2 -2
  16. package/dist/gateway/static/root/assets/{agents-ByiiWRbv.js.map → agents-MbH57-L9.js.map} +1 -1
  17. package/dist/gateway/static/root/assets/{apps-page-BpR0gguZ.js → apps-page-3i3DvI7i.js} +2 -2
  18. package/dist/gateway/static/root/assets/{apps-page-BpR0gguZ.js.map → apps-page-3i3DvI7i.js.map} +1 -1
  19. package/dist/gateway/static/root/assets/channels-settings-CcuSzoB6.js +9 -0
  20. package/dist/gateway/static/root/assets/channels-settings-CcuSzoB6.js.map +1 -0
  21. package/dist/gateway/static/root/assets/{cron-page-D6wtd-hq.js → cron-page-Be1h9Yub.js} +2 -2
  22. package/dist/gateway/static/root/assets/{cron-page-D6wtd-hq.js.map → cron-page-Be1h9Yub.js.map} +1 -1
  23. package/dist/gateway/static/root/assets/{cron-utils-o-QI_XCC.js → cron-utils-CR97EvZS.js} +2 -2
  24. package/dist/gateway/static/root/assets/{cron-utils-o-QI_XCC.js.map → cron-utils-CR97EvZS.js.map} +1 -1
  25. package/dist/gateway/static/root/assets/{dist-D2Td6E_v.js → dist-r_Gy-XJv.js} +2 -2
  26. package/dist/gateway/static/root/assets/{dist-D2Td6E_v.js.map → dist-r_Gy-XJv.js.map} +1 -1
  27. package/dist/gateway/static/root/assets/{extension-debug-page-BIni4Qq4.js → extension-debug-page-QfYEYruq.js} +2 -2
  28. package/dist/gateway/static/root/assets/{extension-debug-page-BIni4Qq4.js.map → extension-debug-page-QfYEYruq.js.map} +1 -1
  29. package/dist/gateway/static/root/assets/{extension-page-BRLScNkx.js → extension-page-4FW-BmKG.js} +2 -2
  30. package/dist/gateway/static/root/assets/{extension-page-BRLScNkx.js.map → extension-page-4FW-BmKG.js.map} +1 -1
  31. package/dist/gateway/static/root/assets/{extension-settings-page-DjiK9Igx.js → extension-settings-page-E_Wq9LL8.js} +2 -2
  32. package/dist/gateway/static/root/assets/{extension-settings-page-DjiK9Igx.js.map → extension-settings-page-E_Wq9LL8.js.map} +1 -1
  33. package/dist/gateway/static/root/assets/{index-KGmhufWu.js → index-CcQtNJKo.js} +60 -54
  34. package/dist/gateway/static/root/assets/{index-KGmhufWu.js.map → index-CcQtNJKo.js.map} +1 -1
  35. package/dist/gateway/static/root/assets/index-D9Wmfh2f.css +1 -0
  36. package/dist/gateway/static/root/assets/{logs-page-C76F4Y0H.js → logs-page-DFhTU-kG.js} +2 -2
  37. package/dist/gateway/static/root/assets/{logs-page-C76F4Y0H.js.map → logs-page-DFhTU-kG.js.map} +1 -1
  38. package/dist/gateway/static/root/assets/{sessions-page-9jwUqGtS.js → sessions-page-wmnnIj6Z.js} +2 -2
  39. package/dist/gateway/static/root/assets/{sessions-page-9jwUqGtS.js.map → sessions-page-wmnnIj6Z.js.map} +1 -1
  40. package/dist/gateway/static/root/assets/settings-page-BTmUXY4s.js +2 -0
  41. package/dist/gateway/static/root/assets/settings-page-BTmUXY4s.js.map +1 -0
  42. package/dist/gateway/static/root/assets/{skills-page-BY1cLNEz.js → skills-page-D-fRbJG0.js} +2 -2
  43. package/dist/gateway/static/root/assets/{skills-page-BY1cLNEz.js.map → skills-page-D-fRbJG0.js.map} +1 -1
  44. package/dist/gateway/static/root/index.html +2 -2
  45. package/dist/package.js +1 -1
  46. package/dist/src/agent/memory/builtin-memory-store.d.ts +2 -1
  47. package/dist/src/agent/memory/builtin-memory-store.js +7 -6
  48. package/dist/src/agent/memory/builtin-memory-store.js.map +1 -1
  49. package/dist/src/agent/prompt/memory/index.d.ts +4 -2
  50. package/dist/src/agent/prompt/memory/index.js +22 -10
  51. package/dist/src/agent/prompt/memory/index.js.map +1 -1
  52. package/dist/src/agent/service.js +1 -1
  53. package/dist/src/agent/tools/factory.js +9 -2
  54. package/dist/src/agent/tools/factory.js.map +1 -1
  55. package/dist/src/agent/tools/index.d.ts +1 -1
  56. package/dist/src/agent/tools/memory-tool.d.ts +7 -2
  57. package/dist/src/agent/tools/memory-tool.js +11 -5
  58. package/dist/src/agent/tools/memory-tool.js.map +1 -1
  59. package/dist/src/channels/registry.d.ts +1 -1
  60. package/dist/src/channels/registry.js +25 -1
  61. package/dist/src/channels/registry.js.map +1 -1
  62. package/dist/src/chat-commands/builtins/config.js +1 -1
  63. package/dist/src/chat-commands/builtins/session.js +1 -1
  64. package/dist/src/chat-commands/index.js +1 -1
  65. package/dist/src/chat-commands/processor.js +1 -1
  66. package/dist/src/cli/commands/channels.js +20 -2
  67. package/dist/src/cli/commands/channels.js.map +1 -1
  68. package/dist/src/cli/commands/gateway/call.d.ts +2 -0
  69. package/dist/src/cli/commands/gateway/call.js +90 -0
  70. package/dist/src/cli/commands/gateway/call.js.map +1 -0
  71. package/dist/src/cli/commands/gateway/health.d.ts +2 -0
  72. package/dist/src/cli/commands/gateway/health.js +77 -0
  73. package/dist/src/cli/commands/gateway/health.js.map +1 -0
  74. package/dist/src/cli/commands/gateway/index.d.ts +3 -0
  75. package/dist/src/cli/commands/gateway/index.js +4 -1
  76. package/dist/src/cli/commands/gateway/probe.d.ts +2 -0
  77. package/dist/src/cli/commands/gateway/probe.js +102 -0
  78. package/dist/src/cli/commands/gateway/probe.js.map +1 -0
  79. package/dist/src/cli/commands/gateway/status.d.ts +0 -3
  80. package/dist/src/cli/commands/gateway/status.js +107 -24
  81. package/dist/src/cli/commands/gateway/status.js.map +1 -1
  82. package/dist/src/cli/commands/gateway.js +7 -1
  83. package/dist/src/cli/commands/gateway.js.map +1 -1
  84. package/dist/src/cli/commands/update.js +19 -1
  85. package/dist/src/cli/commands/update.js.map +1 -1
  86. package/dist/src/cli/utils/gateway-client.d.ts +28 -0
  87. package/dist/src/cli/utils/gateway-client.js +115 -0
  88. package/dist/src/cli/utils/gateway-client.js.map +1 -0
  89. package/dist/src/config/paths-state.d.ts +4 -0
  90. package/dist/src/config/paths-state.js +9 -1
  91. package/dist/src/config/paths-state.js.map +1 -1
  92. package/dist/src/config/reload.d.ts +2 -0
  93. package/dist/src/config/reload.js +9 -1
  94. package/dist/src/config/reload.js.map +1 -1
  95. package/dist/src/config/rules.js +12 -2
  96. package/dist/src/config/rules.js.map +1 -1
  97. package/dist/src/extensions/api.d.ts +6 -1
  98. package/dist/src/extensions/api.js +52 -1
  99. package/dist/src/extensions/api.js.map +1 -1
  100. package/dist/src/extensions/loader.d.ts +6 -1
  101. package/dist/src/extensions/loader.js +20 -1
  102. package/dist/src/extensions/loader.js.map +1 -1
  103. package/dist/src/extensions/normalize-manifest.js +33 -0
  104. package/dist/src/extensions/normalize-manifest.js.map +1 -1
  105. package/dist/src/extensions/sdk/index.d.ts +1 -1
  106. package/dist/src/extensions/sdk/index.js.map +1 -1
  107. package/dist/src/extensions/types/core.d.ts +35 -1
  108. package/dist/src/extensions/types/manifest.d.ts +14 -0
  109. package/dist/src/gateway/hono/lib/config-payload.d.ts +3 -0
  110. package/dist/src/gateway/hono/lib/config-payload.js +1 -0
  111. package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
  112. package/dist/src/gateway/hono/routes/channels.js +111 -0
  113. package/dist/src/gateway/hono/routes/channels.js.map +1 -1
  114. package/dist/src/gateway/hono/routes/commands-skills.js +13 -2
  115. package/dist/src/gateway/hono/routes/commands-skills.js.map +1 -1
  116. package/dist/src/gateway/hono/routes/config.js +81 -0
  117. package/dist/src/gateway/hono/routes/config.js.map +1 -1
  118. package/dist/src/gateway/hono/routes/public-gateway.js +17 -0
  119. package/dist/src/gateway/hono/routes/public-gateway.js.map +1 -1
  120. package/dist/src/gateway/hono/routes/sessions.js +16 -0
  121. package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
  122. package/dist/src/gateway/hono/routes/status.js +31 -7
  123. package/dist/src/gateway/hono/routes/status.js.map +1 -1
  124. package/dist/src/gateway/hono/routes/update.js +118 -15
  125. package/dist/src/gateway/hono/routes/update.js.map +1 -1
  126. package/dist/src/gateway/index.js +1 -1
  127. package/dist/src/gateway/server.js +3 -0
  128. package/dist/src/gateway/server.js.map +1 -1
  129. package/dist/src/gateway/service.d.ts +23 -0
  130. package/dist/src/gateway/service.js +107 -0
  131. package/dist/src/gateway/service.js.map +1 -1
  132. package/dist/src/infra/update-check.js +54 -21
  133. package/dist/src/infra/update-check.js.map +1 -1
  134. package/dist/src/infra/update-lock.d.ts +13 -0
  135. package/dist/src/infra/update-lock.js +67 -0
  136. package/dist/src/infra/update-lock.js.map +1 -0
  137. package/dist/src/infra/update-runner.d.ts +6 -5
  138. package/dist/src/infra/update-runner.js +93 -13
  139. package/dist/src/infra/update-runner.js.map +1 -1
  140. package/dist/src/infra/update-startup.js +37 -11
  141. package/dist/src/infra/update-startup.js.map +1 -1
  142. package/package.json +1 -1
  143. package/dist/gateway/static/root/assets/channels-settings-h3eQwIPi.js +0 -9
  144. package/dist/gateway/static/root/assets/channels-settings-h3eQwIPi.js.map +0 -1
  145. package/dist/gateway/static/root/assets/index-BQNdJlkw.css +0 -1
  146. package/dist/gateway/static/root/assets/settings-page-DNG3Zijx.js +0 -2
  147. 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", "weixin").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
+ 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 channelId = String(options.channel || "").trim() || "weixin";
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>', 'Channel id', 'weixin')\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 channelId = String(options.channel || '').trim() || 'weixin';\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;EACD,CAAC,CACH;AAEH,KACG,QAAQ,QAAQ,CAChB,YAAY,2DAA2D,CACvE,OAAO,kBAAkB,cAAc,SAAS,CAChD,OAAO,kBAAkB,sDAAsD,CAC/E,OAAO,kBAAkB,sCAAsC,SAAS,CACxE,OAAO,sBAAsB,iDAAiD,CAC9E,OAAO,OAAO,SAAS,YAAY;AAClC,+BAA6B;EAC7B,MAAM,YAAY,OAAO,QAAQ,WAAW,GAAG,CAAC,MAAM,IAAI;EAC1D,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"}
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,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function createCallCommand(): Command;
@@ -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,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function createHealthCommand(): Command;
@@ -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,2 @@
1
+ import { Command } from 'commander';
2
+ export declare function createProbeCommand(): Command;
@@ -0,0 +1,102 @@
1
+ import { init_paths, resolveConfigPath } from "../../../config/paths.js";
2
+ import { loadConfig } from "../../../config/loader.js";
3
+ import "../../../config/index.js";
4
+ import { addGatewayClientOptions, callGatewayApi, parseGatewayClientOptions, resolveGatewayToken } from "../../utils/gateway-client.js";
5
+ import { getContextWithOpts } from "../../index.js";
6
+ import { Command } from "commander";
7
+ //#region src/cli/commands/gateway/probe.ts
8
+ init_paths();
9
+ function resolveProbeTargets(opts) {
10
+ const targets = [];
11
+ const port = opts.port;
12
+ targets.push({
13
+ label: "localhost",
14
+ url: `http://127.0.0.1:${port}`
15
+ });
16
+ if (opts.url) {
17
+ const normalized = opts.url.replace(/\/+$/, "");
18
+ if (!normalized.includes("127.0.0.1") && !normalized.includes("localhost")) targets.push({
19
+ label: "remote",
20
+ url: normalized
21
+ });
22
+ }
23
+ return targets;
24
+ }
25
+ async function probeTarget(target, token, timeoutMs) {
26
+ const healthResult = await callGatewayApi("GET", "/api/health", {
27
+ url: target.url,
28
+ timeoutMs: timeoutMs ?? 5e3
29
+ });
30
+ if (!healthResult.ok) return {
31
+ label: target.label,
32
+ url: target.url,
33
+ reachable: false,
34
+ authenticated: false,
35
+ durationMs: healthResult.durationMs,
36
+ error: healthResult.error
37
+ };
38
+ let authenticated = false;
39
+ if (token) authenticated = (await callGatewayApi("GET", "/api/status", {
40
+ url: target.url,
41
+ token,
42
+ timeoutMs: timeoutMs ?? 5e3
43
+ })).ok;
44
+ return {
45
+ label: target.label,
46
+ url: target.url,
47
+ reachable: true,
48
+ authenticated,
49
+ durationMs: healthResult.durationMs,
50
+ version: healthResult.data?.version
51
+ };
52
+ }
53
+ function createProbeCommand() {
54
+ const cmd = new Command("probe").description("Probe gateway reachability and auth capability");
55
+ addGatewayClientOptions(cmd);
56
+ cmd.action(async (options) => {
57
+ const configPath = getContextWithOpts().configPath || resolveConfigPath();
58
+ const port = loadConfig(configPath)?.gateway?.port ?? 18790;
59
+ const clientOpts = {
60
+ ...parseGatewayClientOptions(options),
61
+ configPath
62
+ };
63
+ const token = resolveGatewayToken(clientOpts);
64
+ const targets = resolveProbeTargets({
65
+ url: clientOpts.url,
66
+ port
67
+ });
68
+ const results = [];
69
+ for (const target of targets) {
70
+ const result = await probeTarget(target, token, clientOpts.timeoutMs);
71
+ results.push(result);
72
+ }
73
+ if (clientOpts.json) {
74
+ console.log(JSON.stringify({ targets: results }, null, 2));
75
+ const anyReachable = results.some((r) => r.reachable);
76
+ process.exit(anyReachable ? 0 : 1);
77
+ }
78
+ console.log("🔍 Gateway Probe");
79
+ console.log("");
80
+ for (const result of results) {
81
+ if (result.reachable) {
82
+ console.log(`✅ ${result.label} (${result.url})`);
83
+ console.log(` Reachable: yes (${result.durationMs}ms)`);
84
+ console.log(` Auth: ${result.authenticated ? "✅ authenticated" : "🔒 not authenticated (pass --token)"}`);
85
+ if (result.version) console.log(` Version: ${result.version}`);
86
+ } else {
87
+ console.log(`❌ ${result.label} (${result.url})`);
88
+ console.log(" Reachable: no");
89
+ console.log(` Error: ${result.error}`);
90
+ }
91
+ console.log("");
92
+ }
93
+ const anyReachable = results.some((r) => r.reachable);
94
+ if (!anyReachable) console.log("💡 Is the gateway running? Try: xopc gateway");
95
+ process.exit(anyReachable ? 0 : 1);
96
+ });
97
+ return cmd;
98
+ }
99
+ //#endregion
100
+ export { createProbeCommand };
101
+
102
+ //# sourceMappingURL=probe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probe.js","names":[],"sources":["../../../../../src/cli/commands/gateway/probe.ts"],"sourcesContent":["import { Command } from 'commander';\n\nimport { loadConfig } from '../../../config/index.js';\nimport { resolveConfigPath } from '../../../config/paths.js';\nimport {\n callGatewayApi,\n addGatewayClientOptions,\n parseGatewayClientOptions,\n resolveGatewayToken,\n} from '../../utils/gateway-client.js';\nimport { getContextWithOpts } from '../../index.js';\n\ninterface ProbeTarget {\n label: string;\n url: string;\n}\n\ninterface ProbeResultEntry {\n label: string;\n url: string;\n reachable: boolean;\n authenticated: boolean;\n durationMs: number;\n version?: string;\n error?: string;\n}\n\nfunction resolveProbeTargets(opts: { url?: string; port: number }): ProbeTarget[] {\n const targets: ProbeTarget[] = [];\n const port = opts.port;\n targets.push({ label: 'localhost', url: `http://127.0.0.1:${port}` });\n\n if (opts.url) {\n const normalized = opts.url.replace(/\\/+$/, '');\n if (!normalized.includes('127.0.0.1') && !normalized.includes('localhost')) {\n targets.push({ label: 'remote', url: normalized });\n }\n }\n\n return targets;\n}\n\nasync function probeTarget(\n target: ProbeTarget,\n token?: string,\n timeoutMs?: number,\n): Promise<ProbeResultEntry> {\n const healthResult = await callGatewayApi<{ status: string; version?: string }>('GET', '/api/health', {\n url: target.url,\n timeoutMs: timeoutMs ?? 5000,\n });\n\n if (!healthResult.ok) {\n return {\n label: target.label,\n url: target.url,\n reachable: false,\n authenticated: false,\n durationMs: healthResult.durationMs,\n error: healthResult.error,\n };\n }\n\n let authenticated = false;\n if (token) {\n const statusResult = await callGatewayApi('GET', '/api/status', {\n url: target.url,\n token,\n timeoutMs: timeoutMs ?? 5000,\n });\n authenticated = statusResult.ok;\n }\n\n return {\n label: target.label,\n url: target.url,\n reachable: true,\n authenticated,\n durationMs: healthResult.durationMs,\n version: healthResult.data?.version,\n };\n}\n\nexport function createProbeCommand(): Command {\n const cmd = new Command('probe').description('Probe gateway reachability and auth capability');\n\n addGatewayClientOptions(cmd);\n\n cmd.action(async (options) => {\n const ctx = getContextWithOpts();\n const configPath = ctx.configPath || resolveConfigPath();\n const config = loadConfig(configPath);\n const port = config?.gateway?.port ?? 18790;\n\n const clientOpts = { ...parseGatewayClientOptions(options as Record<string, unknown>), configPath };\n const token = resolveGatewayToken(clientOpts);\n const targets = resolveProbeTargets({ url: clientOpts.url, port });\n const results: ProbeResultEntry[] = [];\n\n for (const target of targets) {\n const result = await probeTarget(target, token, clientOpts.timeoutMs);\n results.push(result);\n }\n\n if (clientOpts.json) {\n console.log(JSON.stringify({ targets: results }, null, 2));\n const anyReachable = results.some((r) => r.reachable);\n process.exit(anyReachable ? 0 : 1);\n }\n\n console.log('🔍 Gateway Probe');\n console.log('');\n\n for (const result of results) {\n if (result.reachable) {\n console.log(`✅ ${result.label} (${result.url})`);\n console.log(` Reachable: yes (${result.durationMs}ms)`);\n console.log(\n ` Auth: ${result.authenticated ? '✅ authenticated' : '🔒 not authenticated (pass --token)'}`,\n );\n if (result.version) {\n console.log(` Version: ${result.version}`);\n }\n } else {\n console.log(`❌ ${result.label} (${result.url})`);\n console.log(' Reachable: no');\n console.log(` Error: ${result.error}`);\n }\n console.log('');\n }\n\n const anyReachable = results.some((r) => r.reachable);\n if (!anyReachable) {\n console.log('💡 Is the gateway running? Try: xopc gateway');\n }\n process.exit(anyReachable ? 0 : 1);\n });\n\n return cmd;\n}\n"],"mappings":";;;;;;;YAG6D;AAwB7D,SAAS,oBAAoB,MAAqD;CAChF,MAAM,UAAyB,EAAE;CACjC,MAAM,OAAO,KAAK;AAClB,SAAQ,KAAK;EAAE,OAAO;EAAa,KAAK,oBAAoB;EAAQ,CAAC;AAErE,KAAI,KAAK,KAAK;EACZ,MAAM,aAAa,KAAK,IAAI,QAAQ,QAAQ,GAAG;AAC/C,MAAI,CAAC,WAAW,SAAS,YAAY,IAAI,CAAC,WAAW,SAAS,YAAY,CACxE,SAAQ,KAAK;GAAE,OAAO;GAAU,KAAK;GAAY,CAAC;;AAItD,QAAO;;AAGT,eAAe,YACb,QACA,OACA,WAC2B;CAC3B,MAAM,eAAe,MAAM,eAAqD,OAAO,eAAe;EACpG,KAAK,OAAO;EACZ,WAAW,aAAa;EACzB,CAAC;AAEF,KAAI,CAAC,aAAa,GAChB,QAAO;EACL,OAAO,OAAO;EACd,KAAK,OAAO;EACZ,WAAW;EACX,eAAe;EACf,YAAY,aAAa;EACzB,OAAO,aAAa;EACrB;CAGH,IAAI,gBAAgB;AACpB,KAAI,MAMF,kBAAgB,MALW,eAAe,OAAO,eAAe;EAC9D,KAAK,OAAO;EACZ;EACA,WAAW,aAAa;EACzB,CAAC,EAC2B;AAG/B,QAAO;EACL,OAAO,OAAO;EACd,KAAK,OAAO;EACZ,WAAW;EACX;EACA,YAAY,aAAa;EACzB,SAAS,aAAa,MAAM;EAC7B;;AAGH,SAAgB,qBAA8B;CAC5C,MAAM,MAAM,IAAI,QAAQ,QAAQ,CAAC,YAAY,iDAAiD;AAE9F,yBAAwB,IAAI;AAE5B,KAAI,OAAO,OAAO,YAAY;EAE5B,MAAM,aADM,oBACU,CAAC,cAAc,mBAAmB;EAExD,MAAM,OADS,WAAW,WACP,EAAE,SAAS,QAAQ;EAEtC,MAAM,aAAa;GAAE,GAAG,0BAA0B,QAAmC;GAAE;GAAY;EACnG,MAAM,QAAQ,oBAAoB,WAAW;EAC7C,MAAM,UAAU,oBAAoB;GAAE,KAAK,WAAW;GAAK;GAAM,CAAC;EAClE,MAAM,UAA8B,EAAE;AAEtC,OAAK,MAAM,UAAU,SAAS;GAC5B,MAAM,SAAS,MAAM,YAAY,QAAQ,OAAO,WAAW,UAAU;AACrE,WAAQ,KAAK,OAAO;;AAGtB,MAAI,WAAW,MAAM;AACnB,WAAQ,IAAI,KAAK,UAAU,EAAE,SAAS,SAAS,EAAE,MAAM,EAAE,CAAC;GAC1D,MAAM,eAAe,QAAQ,MAAM,MAAM,EAAE,UAAU;AACrD,WAAQ,KAAK,eAAe,IAAI,EAAE;;AAGpC,UAAQ,IAAI,mBAAmB;AAC/B,UAAQ,IAAI,GAAG;AAEf,OAAK,MAAM,UAAU,SAAS;AAC5B,OAAI,OAAO,WAAW;AACpB,YAAQ,IAAI,KAAK,OAAO,MAAM,IAAI,OAAO,IAAI,GAAG;AAChD,YAAQ,IAAI,sBAAsB,OAAO,WAAW,KAAK;AACzD,YAAQ,IACN,YAAY,OAAO,gBAAgB,oBAAoB,wCACxD;AACD,QAAI,OAAO,QACT,SAAQ,IAAI,eAAe,OAAO,UAAU;UAEzC;AACL,YAAQ,IAAI,KAAK,OAAO,MAAM,IAAI,OAAO,IAAI,GAAG;AAChD,YAAQ,IAAI,mBAAmB;AAC/B,YAAQ,IAAI,aAAa,OAAO,QAAQ;;AAE1C,WAAQ,IAAI,GAAG;;EAGjB,MAAM,eAAe,QAAQ,MAAM,MAAM,EAAE,UAAU;AACrD,MAAI,CAAC,aACH,SAAQ,IAAI,+CAA+C;AAE7D,UAAQ,KAAK,eAAe,IAAI,EAAE;GAClC;AAEF,QAAO"}
@@ -1,5 +1,2 @@
1
1
  import { Command } from 'commander';
2
- /**
3
- * Create status subcommand
4
- */
5
2
  export declare function createStatusCommand(): Command;
@@ -1,51 +1,134 @@
1
- import { createLogger } from "../../../utils/logger/index.js";
2
- import { init_logger } from "../../../utils/logger.js";
3
1
  import { init_paths, resolveConfigPath } from "../../../config/paths.js";
4
2
  import { loadConfig } from "../../../config/loader.js";
5
3
  import "../../../config/index.js";
6
4
  import { GatewayLockError, acquireGatewayLock } from "../../../gateway/lock.js";
5
+ import { addGatewayClientOptions, callGatewayApi, parseGatewayClientOptions, resolveGatewayUrl } from "../../utils/gateway-client.js";
7
6
  import { getContextWithOpts } from "../../index.js";
8
7
  import { Command } from "commander";
9
8
  //#region src/cli/commands/gateway/status.ts
10
9
  init_paths();
11
- init_logger();
12
- createLogger("GatewayStatusCommand");
13
- /**
14
- * Create status subcommand
15
- */
10
+ function formatUptime(seconds) {
11
+ if (!seconds || seconds <= 0) return "unknown";
12
+ const days = Math.floor(seconds / 86400);
13
+ const hours = Math.floor(seconds % 86400 / 3600);
14
+ const minutes = Math.floor(seconds % 3600 / 60);
15
+ const parts = [];
16
+ if (days > 0) parts.push(`${days}d`);
17
+ if (hours > 0) parts.push(`${hours}h`);
18
+ parts.push(`${minutes}m`);
19
+ return parts.join(" ");
20
+ }
16
21
  function createStatusCommand() {
17
- return new Command("status").description("Check gateway status").action(async () => {
22
+ const cmd = new Command("status").description("Check gateway status with connectivity probe");
23
+ addGatewayClientOptions(cmd);
24
+ cmd.option("--no-probe", "Skip HTTP probe (only check lock file)");
25
+ cmd.action(async (options) => {
18
26
  const configPath = getContextWithOpts().configPath || resolveConfigPath();
19
27
  const config = loadConfig(configPath);
20
- const port = config?.gateway?.port || 18790;
28
+ const port = config?.gateway?.port ?? 18790;
29
+ const clientOpts = {
30
+ ...parseGatewayClientOptions(options),
31
+ configPath
32
+ };
33
+ const gatewayUrl = resolveGatewayUrl({
34
+ url: clientOpts.url,
35
+ configPath
36
+ });
37
+ let lockAlive = false;
38
+ let lockPid;
21
39
  try {
22
40
  await (await acquireGatewayLock(configPath, {
23
41
  timeoutMs: 100,
24
42
  port
25
43
  })).release();
26
- console.log("⚠️ Gateway is not running");
27
- console.log("\n💡 Start with: xopc gateway");
28
- process.exit(0);
44
+ lockAlive = false;
29
45
  } catch (err) {
30
46
  if (err instanceof GatewayLockError) {
31
- console.log("✅ Gateway is running");
32
- console.log(` Port: ${port}`);
33
- console.log("");
34
- console.log("🌐 Access:");
35
- console.log(` URL: http://localhost:${port}`);
36
- const token = config?.gateway?.auth?.token;
37
- if (token) console.log(` Token: ${token.slice(0, 8)}...${token.slice(-8)}`);
38
- console.log("");
39
- console.log("📝 Management:");
40
- console.log(" xopc gateway stop # Stop gateway");
41
- console.log(" xopc gateway restart # Restart gateway");
42
- process.exit(0);
47
+ lockAlive = true;
48
+ const pidMatch = err.message.match(/pid\s+(\d+)/);
49
+ if (pidMatch) lockPid = parseInt(pidMatch[1], 10);
43
50
  } else {
44
51
  console.error("❌ Failed to check status:", err);
45
52
  process.exit(1);
46
53
  }
47
54
  }
55
+ const shouldProbe = options.probe !== false;
56
+ let probeResult = null;
57
+ if (shouldProbe) {
58
+ const healthProbe = await callGatewayApi("GET", "/api/health", {
59
+ ...clientOpts,
60
+ timeoutMs: clientOpts.timeoutMs ?? 5e3
61
+ });
62
+ if (healthProbe.ok) {
63
+ const statusProbe = await callGatewayApi("GET", "/api/status", clientOpts);
64
+ probeResult = statusProbe.ok ? statusProbe : {
65
+ ok: true,
66
+ durationMs: healthProbe.durationMs,
67
+ data: { status: "ok" }
68
+ };
69
+ } else probeResult = {
70
+ ok: false,
71
+ error: healthProbe.error,
72
+ durationMs: healthProbe.durationMs
73
+ };
74
+ }
75
+ if (clientOpts.json) {
76
+ console.log(JSON.stringify({
77
+ running: lockAlive || (probeResult?.ok ?? false),
78
+ lock: {
79
+ alive: lockAlive,
80
+ pid: lockPid
81
+ },
82
+ probe: probeResult ? {
83
+ reachable: probeResult.ok,
84
+ durationMs: probeResult.durationMs,
85
+ ...probeResult.data ?? {},
86
+ ...probeResult.error ? { error: probeResult.error } : {}
87
+ } : null,
88
+ url: gatewayUrl,
89
+ port
90
+ }, null, 2));
91
+ process.exit(probeResult?.ok || lockAlive ? 0 : 1);
92
+ }
93
+ if (!(lockAlive || (probeResult?.ok ?? false))) {
94
+ console.log("⚠️ Gateway is not running");
95
+ if (probeResult && !probeResult.ok) console.log(` Probe: ${probeResult.error} (${probeResult.durationMs}ms)`);
96
+ console.log("");
97
+ console.log("💡 Start with: xopc gateway");
98
+ process.exit(1);
99
+ }
100
+ console.log("✅ Gateway is running");
101
+ console.log(` URL: ${gatewayUrl}`);
102
+ console.log(` Port: ${port}`);
103
+ if (lockPid) console.log(` PID: ${lockPid}`);
104
+ if (probeResult?.ok && probeResult.data) {
105
+ const data = probeResult.data;
106
+ console.log(` Probe: OK (${probeResult.durationMs}ms)`);
107
+ if (data.version) console.log(` Version: ${data.version}`);
108
+ if (data.uptime != null) console.log(` Uptime: ${formatUptime(data.uptime)}`);
109
+ if (data.channels && Object.keys(data.channels).length > 0) {
110
+ console.log("");
111
+ console.log("📡 Channels:");
112
+ for (const [name, info] of Object.entries(data.channels)) {
113
+ const icon = info.status === "connected" ? "✅" : info.status === "disabled" ? "⚪" : "❌";
114
+ console.log(` ${icon} ${name}: ${info.status}`);
115
+ }
116
+ }
117
+ } else if (probeResult && !probeResult.ok) console.log(` Probe: Failed (${probeResult.error})`);
118
+ else if (!shouldProbe) console.log(" Probe: skipped (--no-probe)");
119
+ const token = config?.gateway?.auth?.token;
120
+ if (token) {
121
+ console.log("");
122
+ console.log(`🔑 Token: ${token.slice(0, 8)}...${token.slice(-8)}`);
123
+ }
124
+ console.log("");
125
+ console.log("📝 Management:");
126
+ console.log(" xopc gateway stop # Stop gateway");
127
+ console.log(" xopc gateway restart # Restart gateway");
128
+ console.log(" xopc gateway health # Detailed health check");
129
+ process.exit(0);
48
130
  });
131
+ return cmd;
49
132
  }
50
133
  //#endregion
51
134
  export { createStatusCommand };
@@ -1 +1 @@
1
- {"version":3,"file":"status.js","names":[],"sources":["../../../../../src/cli/commands/gateway/status.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { loadConfig } from '../../../config/index.js';\nimport { resolveConfigPath } from '../../../config/paths.js';\nimport { createLogger } from '../../../utils/logger.js';\nimport { getContextWithOpts } from '../../index.js';\nimport { acquireGatewayLock, GatewayLockError } from '../../../gateway/lock.js';\n\nconst _log = createLogger('GatewayStatusCommand');\n\n/**\n * Create status subcommand\n */\nexport function createStatusCommand(): Command {\n return new Command('status')\n .description('Check gateway status')\n .action(async () => {\n const ctx = getContextWithOpts();\n const configPath = ctx.configPath || resolveConfigPath();\n const config = loadConfig(configPath);\n const port = config?.gateway?.port || 18790;\n\n try {\n // Try to acquire lock - if successful, gateway is not running\n const lock = await acquireGatewayLock(configPath, { timeoutMs: 100, port });\n await lock.release();\n console.log('⚠️ Gateway is not running');\n console.log('\\n💡 Start with: xopc gateway');\n process.exit(0);\n } catch (err) {\n if (err instanceof GatewayLockError) {\n console.log('✅ Gateway is running');\n console.log(` Port: ${port}`);\n\n // Try to get more info from lock file\n // This is a simplified version - could be enhanced\n console.log('');\n console.log('🌐 Access:');\n const host = 'localhost';\n console.log(` URL: http://${host}:${port}`);\n\n const token = config?.gateway?.auth?.token;\n if (token) {\n console.log(` Token: ${token.slice(0, 8)}...${token.slice(-8)}`);\n }\n\n console.log('');\n console.log('📝 Management:');\n console.log(' xopc gateway stop # Stop gateway');\n console.log(' xopc gateway restart # Restart gateway');\n process.exit(0);\n } else {\n console.error(' Failed to check status:', err);\n process.exit(1);\n }\n }\n });\n}\n"],"mappings":";;;;;;;;;YAE6D;aACL;AAI3C,aAAa,uBAAuB;;;;AAKjD,SAAgB,sBAA+B;AAC7C,QAAO,IAAI,QAAQ,SAAS,CACzB,YAAY,uBAAuB,CACnC,OAAO,YAAY;EAElB,MAAM,aADM,oBACU,CAAC,cAAc,mBAAmB;EACxD,MAAM,SAAS,WAAW,WAAW;EACrC,MAAM,OAAO,QAAQ,SAAS,QAAQ;AAEtC,MAAI;AAGF,UAAM,MADa,mBAAmB,YAAY;IAAE,WAAW;IAAK;IAAM,CAAC,EAChE,SAAS;AACpB,WAAQ,IAAI,6BAA6B;AACzC,WAAQ,IAAI,gCAAgC;AAC5C,WAAQ,KAAK,EAAE;WACR,KAAK;AACZ,OAAI,eAAe,kBAAkB;AACnC,YAAQ,IAAI,uBAAuB;AACnC,YAAQ,IAAI,YAAY,OAAO;AAI/B,YAAQ,IAAI,GAAG;AACf,YAAQ,IAAI,aAAa;AAEzB,YAAQ,IAAI,4BAA0B,OAAO;IAE7C,MAAM,QAAQ,QAAQ,SAAS,MAAM;AACrC,QAAI,MACF,SAAQ,IAAI,aAAa,MAAM,MAAM,GAAG,EAAE,CAAC,KAAK,MAAM,MAAM,GAAG,GAAG;AAGpE,YAAQ,IAAI,GAAG;AACf,YAAQ,IAAI,iBAAiB;AAC7B,YAAQ,IAAI,2CAA2C;AACvD,YAAQ,IAAI,8CAA8C;AAC1D,YAAQ,KAAK,EAAE;UACV;AACL,YAAQ,MAAM,6BAA6B,IAAI;AAC/C,YAAQ,KAAK,EAAE;;;GAGnB"}
1
+ {"version":3,"file":"status.js","names":["optsProbe"],"sources":["../../../../../src/cli/commands/gateway/status.ts"],"sourcesContent":["import { Command } from 'commander';\n\nimport { loadConfig } from '../../../config/index.js';\nimport { resolveConfigPath } from '../../../config/paths.js';\nimport { getContextWithOpts } from '../../index.js';\nimport { acquireGatewayLock, GatewayLockError } from '../../../gateway/lock.js';\nimport {\n callGatewayApi,\n addGatewayClientOptions,\n parseGatewayClientOptions,\n resolveGatewayUrl,\n} from '../../utils/gateway-client.js';\n\ninterface StatusResponse {\n status: string;\n version?: string;\n channels?: Record<string, { status: string }>;\n uptime?: number;\n}\n\nfunction formatUptime(seconds?: number): string {\n if (!seconds || seconds <= 0) return 'unknown';\n const days = Math.floor(seconds / 86400);\n const hours = Math.floor((seconds % 86400) / 3600);\n const minutes = Math.floor((seconds % 3600) / 60);\n const parts: string[] = [];\n if (days > 0) parts.push(`${days}d`);\n if (hours > 0) parts.push(`${hours}h`);\n parts.push(`${minutes}m`);\n return parts.join(' ');\n}\n\nexport function createStatusCommand(): Command {\n const cmd = new Command('status').description('Check gateway status with connectivity probe');\n\n addGatewayClientOptions(cmd);\n cmd.option('--no-probe', 'Skip HTTP probe (only check lock file)');\n\n cmd.action(async (options) => {\n const ctx = getContextWithOpts();\n const configPath = ctx.configPath || resolveConfigPath();\n const config = loadConfig(configPath);\n const port = config?.gateway?.port ?? 18790;\n const clientOpts = { ...parseGatewayClientOptions(options as Record<string, unknown>), configPath };\n const gatewayUrl = resolveGatewayUrl({ url: clientOpts.url, configPath });\n\n let lockAlive = false;\n let lockPid: number | undefined;\n\n try {\n const lock = await acquireGatewayLock(configPath, { timeoutMs: 100, port });\n await lock.release();\n lockAlive = false;\n } catch (err) {\n if (err instanceof GatewayLockError) {\n lockAlive = true;\n const pidMatch = err.message.match(/pid\\s+(\\d+)/);\n if (pidMatch) lockPid = parseInt(pidMatch[1], 10);\n } else {\n console.error(' Failed to check status:', err);\n process.exit(1);\n }\n }\n\n const optsProbe = options as { probe?: boolean };\n const shouldProbe = optsProbe.probe !== false;\n\n let probeResult: {\n ok: boolean;\n data?: StatusResponse;\n error?: string;\n durationMs: number;\n } | null = null;\n\n if (shouldProbe) {\n const healthProbe = await callGatewayApi<{ status: string }>('GET', '/api/health', {\n ...clientOpts,\n timeoutMs: clientOpts.timeoutMs ?? 5000,\n });\n\n if (healthProbe.ok) {\n const statusProbe = await callGatewayApi<StatusResponse>('GET', '/api/status', clientOpts);\n probeResult = statusProbe.ok\n ? statusProbe\n : { ok: true, durationMs: healthProbe.durationMs, data: { status: 'ok' } };\n } else {\n probeResult = { ok: false, error: healthProbe.error, durationMs: healthProbe.durationMs };\n }\n }\n\n if (clientOpts.json) {\n console.log(\n JSON.stringify(\n {\n running: lockAlive || (probeResult?.ok ?? false),\n lock: { alive: lockAlive, pid: lockPid },\n probe: probeResult\n ? {\n reachable: probeResult.ok,\n durationMs: probeResult.durationMs,\n ...(probeResult.data ?? {}),\n ...(probeResult.error ? { error: probeResult.error } : {}),\n }\n : null,\n url: gatewayUrl,\n port,\n },\n null,\n 2,\n ),\n );\n process.exit(probeResult?.ok || lockAlive ? 0 : 1);\n }\n\n const isRunning = lockAlive || (probeResult?.ok ?? false);\n\n if (!isRunning) {\n console.log('⚠️ Gateway is not running');\n if (probeResult && !probeResult.ok) {\n console.log(` Probe: ${probeResult.error} (${probeResult.durationMs}ms)`);\n }\n console.log('');\n console.log('💡 Start with: xopc gateway');\n process.exit(1);\n }\n\n console.log('✅ Gateway is running');\n console.log(` URL: ${gatewayUrl}`);\n console.log(` Port: ${port}`);\n if (lockPid) {\n console.log(` PID: ${lockPid}`);\n }\n\n if (probeResult?.ok && probeResult.data) {\n const data = probeResult.data;\n console.log(` Probe: OK (${probeResult.durationMs}ms)`);\n if (data.version) console.log(` Version: ${data.version}`);\n if (data.uptime != null) console.log(` Uptime: ${formatUptime(data.uptime)}`);\n\n if (data.channels && Object.keys(data.channels).length > 0) {\n console.log('');\n console.log('📡 Channels:');\n for (const [name, info] of Object.entries(data.channels)) {\n const icon = info.status === 'connected' ? '✅' : info.status === 'disabled' ? '⚪' : '❌';\n console.log(` ${icon} ${name}: ${info.status}`);\n }\n }\n } else if (probeResult && !probeResult.ok) {\n console.log(` Probe: Failed (${probeResult.error})`);\n } else if (!shouldProbe) {\n console.log(' Probe: skipped (--no-probe)');\n }\n\n const token = config?.gateway?.auth?.token;\n if (token) {\n console.log('');\n console.log(`🔑 Token: ${token.slice(0, 8)}...${token.slice(-8)}`);\n }\n\n console.log('');\n console.log('📝 Management:');\n console.log(' xopc gateway stop # Stop gateway');\n console.log(' xopc gateway restart # Restart gateway');\n console.log(' xopc gateway health # Detailed health check');\n process.exit(0);\n });\n\n return cmd;\n}\n"],"mappings":"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"}