@hypequery/cli 1.21.2 → 1.23.0

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 (185) hide show
  1. package/README.md +1 -0
  2. package/dist/bin/cli.js +77 -12
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +33 -15
  5. package/dist/commands/deploy.d.ts +5 -0
  6. package/dist/commands/deploy.d.ts.map +1 -1
  7. package/dist/commands/deploy.js +10 -0
  8. package/dist/commands/deployment-status.d.ts +16 -0
  9. package/dist/commands/deployment-status.d.ts.map +1 -0
  10. package/dist/commands/deployment-status.js +36 -0
  11. package/dist/commands/dev.d.ts.map +1 -1
  12. package/dist/commands/dev.js +25 -5
  13. package/dist/commands/generate-datasets.d.ts +0 -6
  14. package/dist/commands/generate-datasets.d.ts.map +1 -1
  15. package/dist/commands/generate-datasets.js +17 -1
  16. package/dist/commands/generate-manifest.d.ts.map +1 -1
  17. package/dist/commands/generate-manifest.js +4 -0
  18. package/dist/commands/generate.d.ts.map +1 -1
  19. package/dist/commands/generate.js +14 -1
  20. package/dist/commands/init.d.ts.map +1 -1
  21. package/dist/commands/init.js +80 -55
  22. package/dist/commands/live-source.d.ts.map +1 -1
  23. package/dist/commands/live-source.js +3 -21
  24. package/dist/commands/mcp.d.ts +10 -0
  25. package/dist/commands/mcp.d.ts.map +1 -1
  26. package/dist/commands/mcp.js +93 -8
  27. package/dist/commands/telemetry.d.ts +3 -0
  28. package/dist/commands/telemetry.d.ts.map +1 -0
  29. package/dist/commands/telemetry.js +19 -0
  30. package/dist/generators/chdb.d.ts +3 -0
  31. package/dist/generators/chdb.d.ts.map +1 -1
  32. package/dist/generators/chdb.js +2 -0
  33. package/dist/generators/clickhouse.d.ts +3 -1
  34. package/dist/generators/clickhouse.d.ts.map +1 -1
  35. package/dist/generators/clickhouse.js +2 -0
  36. package/dist/test-utils.d.ts +1 -1
  37. package/dist/typegen/generate-types.d.ts +3 -0
  38. package/dist/typegen/generate-types.d.ts.map +1 -1
  39. package/dist/typegen/generate-types.js +5 -1
  40. package/dist/typegen/type-parsing.d.ts +1 -1
  41. package/dist/typegen/type-parsing.d.ts.map +1 -1
  42. package/dist/typegen/type-parsing.js +11 -7
  43. package/dist/utils/chdb-gitignore-entry.d.ts +2 -0
  44. package/dist/utils/chdb-gitignore-entry.d.ts.map +1 -0
  45. package/dist/utils/chdb-gitignore-entry.js +17 -0
  46. package/dist/utils/cli-version.d.ts +2 -0
  47. package/dist/utils/cli-version.d.ts.map +1 -0
  48. package/dist/utils/cli-version.js +11 -0
  49. package/dist/utils/cloud-credential-store.d.ts.map +1 -1
  50. package/dist/utils/cloud-credential-store.js +2 -13
  51. package/dist/utils/command-exit.d.ts +13 -0
  52. package/dist/utils/command-exit.d.ts.map +1 -0
  53. package/dist/utils/command-exit.js +31 -0
  54. package/dist/utils/config-directory.d.ts +3 -0
  55. package/dist/utils/config-directory.d.ts.map +1 -0
  56. package/dist/utils/config-directory.js +14 -0
  57. package/dist/utils/deployment-target.d.ts +7 -0
  58. package/dist/utils/deployment-target.d.ts.map +1 -0
  59. package/dist/utils/deployment-target.js +19 -0
  60. package/dist/utils/detect-database-environment.d.ts +3 -0
  61. package/dist/utils/detect-database-environment.d.ts.map +1 -0
  62. package/dist/utils/detect-database-environment.js +8 -0
  63. package/dist/utils/detect-database.d.ts.map +1 -1
  64. package/dist/utils/detect-database.js +4 -8
  65. package/dist/utils/hosted-endpoints-output.d.ts +4 -0
  66. package/dist/utils/hosted-endpoints-output.d.ts.map +1 -0
  67. package/dist/utils/hosted-endpoints-output.js +27 -0
  68. package/dist/utils/hosted-endpoints.d.ts +37 -0
  69. package/dist/utils/hosted-endpoints.d.ts.map +1 -0
  70. package/dist/utils/hosted-endpoints.js +81 -0
  71. package/dist/utils/init-options.d.ts +11 -0
  72. package/dist/utils/init-options.d.ts.map +1 -0
  73. package/dist/utils/init-options.js +28 -0
  74. package/dist/utils/live-deployment.d.ts +6 -0
  75. package/dist/utils/live-deployment.d.ts.map +1 -1
  76. package/dist/utils/live-deployment.js +6 -1
  77. package/dist/utils/load-api.d.ts +2 -0
  78. package/dist/utils/load-api.d.ts.map +1 -1
  79. package/dist/utils/load-api.js +50 -51
  80. package/dist/utils/load-env-files.d.ts +10 -0
  81. package/dist/utils/load-env-files.d.ts.map +1 -0
  82. package/dist/utils/load-env-files.js +27 -0
  83. package/dist/utils/mcp-remote-check.d.ts +19 -0
  84. package/dist/utils/mcp-remote-check.d.ts.map +1 -0
  85. package/dist/utils/mcp-remote-check.js +96 -0
  86. package/dist/utils/mcp-response.d.ts +3 -0
  87. package/dist/utils/mcp-response.d.ts.map +1 -0
  88. package/dist/utils/mcp-response.js +58 -0
  89. package/dist/utils/project-root.d.ts +14 -0
  90. package/dist/utils/project-root.d.ts.map +1 -0
  91. package/dist/utils/project-root.js +41 -0
  92. package/dist/utils/telemetry/buckets.d.ts +5 -0
  93. package/dist/utils/telemetry/buckets.d.ts.map +1 -0
  94. package/dist/utils/telemetry/buckets.js +23 -0
  95. package/dist/utils/telemetry/catalog-docs.d.ts +3 -0
  96. package/dist/utils/telemetry/catalog-docs.d.ts.map +1 -0
  97. package/dist/utils/telemetry/catalog-docs.js +52 -0
  98. package/dist/utils/telemetry/catalog.d.ts +1124 -0
  99. package/dist/utils/telemetry/catalog.d.ts.map +1 -0
  100. package/dist/utils/telemetry/catalog.js +154 -0
  101. package/dist/utils/telemetry/command-context.d.ts +17 -0
  102. package/dist/utils/telemetry/command-context.d.ts.map +1 -0
  103. package/dist/utils/telemetry/command-context.js +30 -0
  104. package/dist/utils/telemetry/config-schema.d.ts +12 -0
  105. package/dist/utils/telemetry/config-schema.d.ts.map +1 -0
  106. package/dist/utils/telemetry/config-schema.js +33 -0
  107. package/dist/utils/telemetry/config-store.d.ts +35 -0
  108. package/dist/utils/telemetry/config-store.d.ts.map +1 -0
  109. package/dist/utils/telemetry/config-store.js +147 -0
  110. package/dist/utils/telemetry/delivery.d.ts +13 -0
  111. package/dist/utils/telemetry/delivery.d.ts.map +1 -0
  112. package/dist/utils/telemetry/delivery.js +26 -0
  113. package/dist/utils/telemetry/detached-dispatch.d.ts +12 -0
  114. package/dist/utils/telemetry/detached-dispatch.d.ts.map +1 -0
  115. package/dist/utils/telemetry/detached-dispatch.js +33 -0
  116. package/dist/utils/telemetry/detached-sender.d.ts +2 -0
  117. package/dist/utils/telemetry/detached-sender.d.ts.map +1 -0
  118. package/dist/utils/telemetry/detached-sender.js +31 -0
  119. package/dist/utils/telemetry/dev-session.d.ts +15 -0
  120. package/dist/utils/telemetry/dev-session.d.ts.map +1 -0
  121. package/dist/utils/telemetry/dev-session.js +25 -0
  122. package/dist/utils/telemetry/domains.d.ts +69 -0
  123. package/dist/utils/telemetry/domains.d.ts.map +1 -0
  124. package/dist/utils/telemetry/domains.js +64 -0
  125. package/dist/utils/telemetry/endpoint.d.ts +3 -0
  126. package/dist/utils/telemetry/endpoint.d.ts.map +1 -0
  127. package/dist/utils/telemetry/endpoint.js +15 -0
  128. package/dist/utils/telemetry/environment.d.ts +27 -0
  129. package/dist/utils/telemetry/environment.d.ts.map +1 -0
  130. package/dist/utils/telemetry/environment.js +95 -0
  131. package/dist/utils/telemetry/error-code.d.ts +4 -0
  132. package/dist/utils/telemetry/error-code.d.ts.map +1 -0
  133. package/dist/utils/telemetry/error-code.js +57 -0
  134. package/dist/utils/telemetry/flags.d.ts +5 -0
  135. package/dist/utils/telemetry/flags.d.ts.map +1 -0
  136. package/dist/utils/telemetry/flags.js +41 -0
  137. package/dist/utils/telemetry/generation-metrics.d.ts +15 -0
  138. package/dist/utils/telemetry/generation-metrics.d.ts.map +1 -0
  139. package/dist/utils/telemetry/generation-metrics.js +35 -0
  140. package/dist/utils/telemetry/identity.d.ts +12 -0
  141. package/dist/utils/telemetry/identity.d.ts.map +1 -0
  142. package/dist/utils/telemetry/identity.js +42 -0
  143. package/dist/utils/telemetry/init-funnel.d.ts +15 -0
  144. package/dist/utils/telemetry/init-funnel.d.ts.map +1 -0
  145. package/dist/utils/telemetry/init-funnel.js +25 -0
  146. package/dist/utils/telemetry/invocation.d.ts +22 -0
  147. package/dist/utils/telemetry/invocation.d.ts.map +1 -0
  148. package/dist/utils/telemetry/invocation.js +46 -0
  149. package/dist/utils/telemetry/lifecycle.d.ts +32 -0
  150. package/dist/utils/telemetry/lifecycle.d.ts.map +1 -0
  151. package/dist/utils/telemetry/lifecycle.js +99 -0
  152. package/dist/utils/telemetry/mcp-session.d.ts +10 -0
  153. package/dist/utils/telemetry/mcp-session.d.ts.map +1 -0
  154. package/dist/utils/telemetry/mcp-session.js +36 -0
  155. package/dist/utils/telemetry/notice.d.ts +11 -0
  156. package/dist/utils/telemetry/notice.d.ts.map +1 -0
  157. package/dist/utils/telemetry/notice.js +24 -0
  158. package/dist/utils/telemetry/opt-out.d.ts +16 -0
  159. package/dist/utils/telemetry/opt-out.d.ts.map +1 -0
  160. package/dist/utils/telemetry/opt-out.js +32 -0
  161. package/dist/utils/telemetry/post-json.d.ts +13 -0
  162. package/dist/utils/telemetry/post-json.d.ts.map +1 -0
  163. package/dist/utils/telemetry/post-json.js +32 -0
  164. package/dist/utils/telemetry/project-context.d.ts +15 -0
  165. package/dist/utils/telemetry/project-context.d.ts.map +1 -0
  166. package/dist/utils/telemetry/project-context.js +86 -0
  167. package/dist/utils/telemetry/schema.d.ts +72 -0
  168. package/dist/utils/telemetry/schema.d.ts.map +1 -0
  169. package/dist/utils/telemetry/schema.js +17 -0
  170. package/dist/utils/telemetry/session-config.d.ts +6 -0
  171. package/dist/utils/telemetry/session-config.d.ts.map +1 -0
  172. package/dist/utils/telemetry/session-config.js +17 -0
  173. package/dist/utils/telemetry/settings-lock.d.ts +36 -0
  174. package/dist/utils/telemetry/settings-lock.d.ts.map +1 -0
  175. package/dist/utils/telemetry/settings-lock.js +102 -0
  176. package/dist/utils/telemetry/transport.d.ts +25 -0
  177. package/dist/utils/telemetry/transport.d.ts.map +1 -0
  178. package/dist/utils/telemetry/transport.js +76 -0
  179. package/dist/utils/telemetry/validation.d.ts +10 -0
  180. package/dist/utils/telemetry/validation.d.ts.map +1 -0
  181. package/dist/utils/telemetry/validation.js +77 -0
  182. package/dist/utils/telemetry/value-formats.d.ts +30 -0
  183. package/dist/utils/telemetry/value-formats.d.ts.map +1 -0
  184. package/dist/utils/telemetry/value-formats.js +13 -0
  185. package/package.json +16 -12
package/README.md CHANGED
@@ -39,6 +39,7 @@ npx hypequery init \
39
39
  | `hypequery generate:datasets` | Dataset definitions scaffolded from tables |
40
40
  | `hypequery generate:manifest` | A browser-safe route manifest for React hooks |
41
41
  | `hypequery pull` / `diff` | Live source inspection and comparison |
42
+ | `hypequery deployment:status` | Live release and Cloud-provided connection URLs |
42
43
 
43
44
  Non-interactive ClickHouse commands read `CLICKHOUSE_URL`, `CLICKHOUSE_DATABASE`, `CLICKHOUSE_USERNAME`, and `CLICKHOUSE_PASSWORD`.
44
45
 
package/dist/bin/cli.js CHANGED
@@ -1,6 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import { program } from '../cli.js';
3
- import { envFiles } from '../utils/env-files.js';
3
+ import { loadEnvFiles } from '../utils/load-env-files.js';
4
+ import { CommandExit, finishAndExit, installCommandExitFinalizer } from '../utils/command-exit.js';
5
+ import { CommandLifecycle } from '../utils/telemetry/lifecycle.js';
6
+ import { telemetryErrorCode } from '../utils/telemetry/error-code.js';
7
+ import { cleanupLoadedApiArtifacts } from '../utils/load-api.js';
8
+ import { withCommandTelemetry } from '../utils/telemetry/command-context.js';
9
+ import { settleTelemetrySettings } from '../utils/telemetry/config-store.js';
4
10
  async function loadEnv() {
5
11
  try {
6
12
  const dotenvx = await import('@dotenvx/dotenvx');
@@ -14,19 +20,78 @@ async function loadEnv() {
14
20
  catch {
15
21
  // Optional dependency, ignore if missing
16
22
  }
17
- try {
18
- const { config } = await import('dotenv');
19
- for (const path of envFiles(process.env.NODE_ENV)) {
20
- // Missing files are a no-op.
21
- config({ path });
22
- }
23
- }
24
- catch {
25
- // dotenv is optional; continue if not available
26
- }
23
+ await loadEnvFiles(process.cwd());
27
24
  }
28
25
  async function main() {
29
26
  await loadEnv();
30
- program.parse(process.argv);
27
+ const args = process.argv.slice(2);
28
+ const requested = args.find(arg => !arg.startsWith('-'));
29
+ const lifecycle = new CommandLifecycle(args, {
30
+ telemetry: args.includes('--no-telemetry') ? false : undefined,
31
+ });
32
+ let selected;
33
+ let finishing;
34
+ const finish = (exit) => {
35
+ finishing ??= (async () => {
36
+ // finish() never rejects; the guard keeps cleanup independent of telemetry.
37
+ await lifecycle.finish(exit, selected?.name() === 'help' ? selected.args[0] : undefined).catch(() => undefined);
38
+ // Signals end in process.exit(), which skips finally blocks: let any
39
+ // settings write release its lock first (bounded).
40
+ await settleTelemetrySettings();
41
+ await cleanupLoadedApiArtifacts();
42
+ })();
43
+ return finishing;
44
+ };
45
+ installCommandExitFinalizer(finish);
46
+ const crash = (error) => lifecycle.crash(error);
47
+ process.on('uncaughtExceptionMonitor', crash);
48
+ program.exitOverride();
49
+ for (const command of program.commands)
50
+ command.exitOverride();
51
+ program.hook('preAction', async (_root, command) => {
52
+ selected = command;
53
+ await lifecycle.begin(command.name(), command.opts().database);
54
+ });
55
+ const observeSignal = (signal) => {
56
+ lifecycle.markInterrupted();
57
+ // dev and mcp own asynchronous server teardown once their handlers exist.
58
+ // During startup, or for short commands, the executable owns shutdown.
59
+ if ((lifecycle.command === 'dev' || lifecycle.command === 'mcp') && process.listenerCount(signal) > 1)
60
+ return;
61
+ void finishAndExit(lifecycle.command === 'dev' || lifecycle.command === 'mcp' ? 0 : signal === 'SIGINT' ? 130 : 143, 'interrupted');
62
+ };
63
+ process.on('SIGINT', () => observeSignal('SIGINT'));
64
+ process.on('SIGTERM', () => observeSignal('SIGTERM'));
65
+ try {
66
+ await withCommandTelemetry(lifecycle, () => program.parseAsync(process.argv));
67
+ if (lifecycle.command === 'dev')
68
+ return; // Its shutdown handler finalizes after teardown.
69
+ await finish(new CommandExit(Number(process.exitCode ?? 0), process.exitCode ? 'failure' : 'success', process.exitCode ? 'unknown' : undefined));
70
+ }
71
+ catch (error) {
72
+ const commander = error;
73
+ if (commander.code === 'commander.helpDisplayed' || commander.code === 'commander.help') {
74
+ const topic = selected?.name() === 'help' ? selected.args[0] : selected?.name()
75
+ ?? program.commands.find(command => requested === command.name())?.name();
76
+ await lifecycle.begin('help');
77
+ const code = commander.exitCode ?? 0;
78
+ await lifecycle.finish(new CommandExit(code, code ? 'failure' : 'success', code ? 'validation_failed' : undefined), topic)
79
+ .catch(() => undefined);
80
+ process.exitCode = code;
81
+ await settleTelemetrySettings();
82
+ await cleanupLoadedApiArtifacts();
83
+ return;
84
+ }
85
+ if (commander.code === 'commander.version') {
86
+ await lifecycle.begin('version');
87
+ await finish(new CommandExit(0, 'success'));
88
+ return;
89
+ }
90
+ if (!selected)
91
+ await lifecycle.begin(['unknown_command', 'unknown_option'].includes(telemetryErrorCode(error)) ? 'unknown' : requested ?? 'unknown');
92
+ const exit = error instanceof CommandExit ? error
93
+ : new CommandExit(commander.exitCode ?? 1, 'failure', telemetryErrorCode(error));
94
+ await finishAndExit(exit.exitCode, exit.outcome, exit.errorCode);
95
+ }
31
96
  }
32
97
  main();
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiCpC,QAAA,MAAM,OAAO,SAAgB,CAAC;AAa9B,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;EAKpE;AAqQD,OAAO,EAAE,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAyCpC,QAAA,MAAM,OAAO,SAAgB,CAAC;AAE9B,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;EAKpE;AA8RD,OAAO,EAAE,OAAO,EAAE,CAAC"}
package/dist/cli.js CHANGED
@@ -1,5 +1,3 @@
1
- import { readFileSync } from 'node:fs';
2
- import { fileURLToPath } from 'node:url';
3
1
  import { Command } from 'commander';
4
2
  import { initCommand } from './commands/init.js';
5
3
  import { mcpCommand } from './commands/mcp.js';
@@ -9,19 +7,15 @@ import { generateDatasetsCommand } from './commands/generate-datasets.js';
9
7
  import { generateManifestCommand } from './commands/generate-manifest.js';
10
8
  import { buildDeploymentCommand, prepareDeploymentReleaseCommand, validateDeploymentCommand, } from './commands/deployment.js';
11
9
  import { deployCommand, submitDeploymentCommand, } from './commands/deploy.js';
10
+ import { deploymentStatusCommand, } from './commands/deployment-status.js';
12
11
  import { loginCommand, logoutCommand, } from './commands/login.js';
13
12
  import { diffCommand, pullCommand, } from './commands/live-source.js';
14
13
  import { isPromptCancelled } from './utils/prompts.js';
14
+ import { telemetryCommand } from './commands/telemetry.js';
15
+ import { getCliVersion } from './utils/cli-version.js';
16
+ import { CommandExit } from './utils/command-exit.js';
17
+ import { telemetryErrorCode } from './utils/telemetry/error-code.js';
15
18
  const program = new Command();
16
- function getCliVersion() {
17
- try {
18
- const pkg = JSON.parse(readFileSync(fileURLToPath(new URL('../package.json', import.meta.url)), 'utf8'));
19
- return pkg.version ?? '0.0.0';
20
- }
21
- catch {
22
- return '0.0.0';
23
- }
24
- }
25
19
  export function normalizeInitOptions(options) {
26
20
  return {
27
21
  ...options,
@@ -31,7 +25,14 @@ export function normalizeInitOptions(options) {
31
25
  program
32
26
  .name('hypequery')
33
27
  .description('Type-safe analytics layer for ClickHouse')
34
- .version(getCliVersion());
28
+ .version(getCliVersion())
29
+ .option('--no-telemetry', 'Disable anonymous usage telemetry for this invocation');
30
+ program
31
+ .command('telemetry [action]')
32
+ .description('Show or change anonymous usage telemetry settings (status|enable|disable)')
33
+ .action(runCommand(async (action) => {
34
+ await telemetryCommand(action, { telemetry: program.opts().telemetry });
35
+ }));
35
36
  program
36
37
  .command('login')
37
38
  .description('Authorize this machine with Hypequery Cloud')
@@ -71,14 +72,16 @@ function runCommand(action) {
71
72
  await action(...args);
72
73
  }
73
74
  catch (error) {
75
+ if (error instanceof CommandExit)
76
+ throw error;
74
77
  // Ctrl+C at a prompt is a deliberate abort, not a failure: report it as
75
78
  // the interrupt it is instead of dumping an error and exiting 1.
76
79
  if (isPromptCancelled(error)) {
77
80
  console.log('\nCancelled.');
78
- process.exit(130);
81
+ throw new CommandExit(130, 'cancelled', 'prompt_cancelled');
79
82
  }
80
83
  console.error(error instanceof Error ? error.message : error);
81
- process.exit(1);
84
+ throw new CommandExit(1, 'failure', telemetryErrorCode(error));
82
85
  }
83
86
  };
84
87
  }
@@ -133,6 +136,7 @@ program
133
136
  .option('--path <path>', 'Analytics directory (loads <path>/api.ts or <path>/queries.ts)')
134
137
  .option('--tenant <id>', 'Trusted tenant applied to every tenant-scoped dataset')
135
138
  .option('--self-test', 'Check the entrypoint and exit without speaking MCP')
139
+ .option('--url <url>', 'With --self-test: check a hosted MCP endpoint (key from HYPEQUERY_API_KEY)')
136
140
  .action(runCommand(async (file, options) => {
137
141
  await mcpCommand(file, options);
138
142
  }));
@@ -198,6 +202,16 @@ program
198
202
  .action(runCommand(async (bundle, options) => {
199
203
  await submitDeploymentCommand(bundle, options);
200
204
  }));
205
+ program
206
+ .command('deployment:status')
207
+ .description('Show the live release and hosted connection details for a Cloud target')
208
+ .option('--project <project>', 'Target project identifier (advanced override)')
209
+ .option('--environment <environment>', 'Target environment identifier (advanced override)')
210
+ .option('--endpoint <url>', 'HTTPS submission endpoint; requires HYPEQUERY_API_TOKEN')
211
+ .option('--mcp-config', 'Also print MCP client configuration for the hosted endpoint')
212
+ .action(runCommand(async (options) => {
213
+ await deploymentStatusCommand(options);
214
+ }));
201
215
  program
202
216
  .command('deploy <source>')
203
217
  .description('Build, prepare, and deploy a dataset-only Cloud publication')
@@ -208,6 +222,7 @@ program
208
222
  .option('--no-source', 'Exclude project source files from the deployment bundle')
209
223
  .option('--endpoint <url>', 'HTTPS submission endpoint; requires HYPEQUERY_API_TOKEN')
210
224
  .option('--replace-restored', 'Intentionally replace a restored live release')
225
+ .option('--mcp-config', 'Also print MCP client configuration for the hosted endpoint')
211
226
  .action(runCommand(async (source, options) => {
212
227
  await deployCommand(source, options);
213
228
  }));
@@ -223,7 +238,7 @@ program
223
238
  }
224
239
  else {
225
240
  console.error(`Unknown command: ${command}`);
226
- process.exit(1);
241
+ throw new CommandExit(1, 'failure', 'unknown_command');
227
242
  }
228
243
  }
229
244
  else {
@@ -234,6 +249,9 @@ program
234
249
  program.on('--help', () => {
235
250
  console.log('');
236
251
  console.log('Examples:');
252
+ console.log(' hypequery telemetry status');
253
+ console.log(' hypequery telemetry disable');
254
+ console.log(' hypequery --no-telemetry init');
237
255
  console.log(' hypequery login');
238
256
  console.log(' hypequery logout');
239
257
  console.log(' hypequery init');
@@ -1,11 +1,14 @@
1
1
  import { createHttpDeploymentUploadTransport, type DeploymentSubmissionResponse } from '../utils/deployment-upload.js';
2
2
  import { type StoredCloudCredential } from '../utils/cloud-credential-store.js';
3
3
  import { fetchLiveDeployment } from '../utils/live-deployment.js';
4
+ import { fetchHostedEndpoints } from '../utils/hosted-endpoints.js';
4
5
  import { buildDeploymentCommand, prepareDeploymentReleaseCommand } from './deployment.js';
5
6
  export interface SubmitDeploymentOptions {
6
7
  release?: string;
7
8
  endpoint?: string;
8
9
  replaceRestored?: boolean;
10
+ /** Also print MCP client configuration for the hosted endpoint. */
11
+ mcpConfig?: boolean;
9
12
  }
10
13
  export interface DeployOptions {
11
14
  endpoint?: string;
@@ -15,12 +18,14 @@ export interface DeployOptions {
15
18
  bundleOutput?: string;
16
19
  releaseOutput?: string;
17
20
  source?: boolean;
21
+ mcpConfig?: boolean;
18
22
  }
19
23
  export interface SubmitDeploymentDependencies {
20
24
  readonly env?: Readonly<Record<string, string | undefined>>;
21
25
  readonly createTransport?: typeof createHttpDeploymentUploadTransport;
22
26
  readonly loadCredential?: () => Promise<StoredCloudCredential | null>;
23
27
  readonly fetchLive?: typeof fetchLiveDeployment;
28
+ readonly fetchEndpoints?: typeof fetchHostedEndpoints;
24
29
  }
25
30
  export interface DeployDependencies extends SubmitDeploymentDependencies {
26
31
  readonly buildDeployment?: typeof buildDeploymentCommand;
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AASA,OAAO,EACL,mCAAmC,EAEnC,KAAK,4BAA4B,EAElC,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EACL,KAAK,qBAAqB,EAC3B,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EACL,sBAAsB,EACtB,+BAA+B,EAChC,MAAM,iBAAiB,CAAC;AAMzB,MAAM,WAAW,uBAAuB;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IAC5D,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,mCAAmC,CAAC;IACtE,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAAC;IACtE,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,mBAAmB,CAAC;CACjD;AAED,MAAM,WAAW,kBAAmB,SAAQ,4BAA4B;IACtE,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,sBAAsB,CAAC;IACzD,QAAQ,CAAC,wBAAwB,CAAC,EAAE,OAAO,+BAA+B,CAAC;IAC3E,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,uBAAuB,CAAC;CAC5D;AA4DD,wBAAsB,uBAAuB,CAC3C,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,OAAO,GAAE,uBAA4B,EACrC,YAAY,GAAE,4BAAiC,GAC9C,OAAO,CAAC,4BAA4B,CAAC,CA0EvC;AAsBD,wBAAsB,aAAa,CACjC,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,OAAO,GAAE,aAAkB,EAC3B,YAAY,GAAE,kBAAuB,GACpC,OAAO,CAAC,4BAA4B,CAAC,CAuCvC"}
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AASA,OAAO,EACL,mCAAmC,EAEnC,KAAK,4BAA4B,EAElC,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EACL,KAAK,qBAAqB,EAC3B,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EACL,oBAAoB,EACrB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EACL,sBAAsB,EACtB,+BAA+B,EAChC,MAAM,iBAAiB,CAAC;AAMzB,MAAM,WAAW,uBAAuB;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,mEAAmE;IACnE,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IAC5D,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,mCAAmC,CAAC;IACtE,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAAC;IACtE,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,mBAAmB,CAAC;IAChD,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,oBAAoB,CAAC;CACvD;AAED,MAAM,WAAW,kBAAmB,SAAQ,4BAA4B;IACtE,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,sBAAsB,CAAC;IACzD,QAAQ,CAAC,wBAAwB,CAAC,EAAE,OAAO,+BAA+B,CAAC;IAC3E,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,uBAAuB,CAAC;CAC5D;AA4DD,wBAAsB,uBAAuB,CAC3C,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,OAAO,GAAE,uBAA4B,EACrC,YAAY,GAAE,4BAAiC,GAC9C,OAAO,CAAC,4BAA4B,CAAC,CAiFvC;AAsBD,wBAAsB,aAAa,CACjC,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,OAAO,GAAE,aAAkB,EAC3B,YAAY,GAAE,kBAAuB,GACpC,OAAO,CAAC,4BAA4B,CAAC,CAwCvC"}
@@ -6,6 +6,8 @@ import { createHttpDeploymentUploadTransport, DeploymentUploadError, } from '../
6
6
  import { logger } from '../utils/logger.js';
7
7
  import { resolveDeploymentCredential } from '../utils/cloud-deployment-access.js';
8
8
  import { fetchLiveDeployment } from '../utils/live-deployment.js';
9
+ import { fetchHostedEndpoints, } from '../utils/hosted-endpoints.js';
10
+ import { printHostedEndpoints } from '../utils/hosted-endpoints-output.js';
9
11
  import { buildDeploymentCommand, prepareDeploymentReleaseCommand, } from './deployment.js';
10
12
  const MAX_RELEASE_FILE_BYTES = 16 * 1024;
11
13
  const DEFAULT_BUNDLE_PATH = 'analytics/hypequery-deployment';
@@ -120,6 +122,13 @@ export async function submitDeploymentCommand(bundlePath, options = {}, dependen
120
122
  : 'Deployment release already exists');
121
123
  logger.info(`Release identity: ${result.releaseIdentity}`);
122
124
  logger.info(`Bundle identity: ${result.bundleIdentity}`);
125
+ const endpoints = await (dependencies.fetchEndpoints ?? fetchHostedEndpoints)({
126
+ endpoint: deploymentEndpoint,
127
+ token,
128
+ target: release.release.target,
129
+ });
130
+ if (endpoints)
131
+ printHostedEndpoints(endpoints, options.mcpConfig === true);
123
132
  return result;
124
133
  }
125
134
  /**
@@ -172,5 +181,6 @@ export async function deployCommand(sourcePath, options = {}, dependencies = {})
172
181
  release: releasePath,
173
182
  endpoint: options.endpoint,
174
183
  replaceRestored: options.replaceRestored,
184
+ mcpConfig: options.mcpConfig,
175
185
  }, dependencies);
176
186
  }
@@ -0,0 +1,16 @@
1
+ import { type CloudDeploymentAccessDependencies } from '../utils/cloud-deployment-access.js';
2
+ import { fetchHostedEndpoints } from '../utils/hosted-endpoints.js';
3
+ import { fetchLiveDeployment } from '../utils/live-deployment.js';
4
+ export interface DeploymentStatusOptions {
5
+ readonly endpoint?: string;
6
+ readonly project?: string;
7
+ readonly environment?: string;
8
+ readonly mcpConfig?: boolean;
9
+ }
10
+ export interface DeploymentStatusDependencies extends CloudDeploymentAccessDependencies {
11
+ readonly fetchLive?: typeof fetchLiveDeployment;
12
+ readonly fetchEndpoints?: typeof fetchHostedEndpoints;
13
+ }
14
+ /** Read the current target and its hosted connection details without deploying. */
15
+ export declare function deploymentStatusCommand(options?: DeploymentStatusOptions, dependencies?: DeploymentStatusDependencies): Promise<void>;
16
+ //# sourceMappingURL=deployment-status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deployment-status.d.ts","sourceRoot":"","sources":["../../src/commands/deployment-status.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,iCAAiC,EACvC,MAAM,qCAAqC,CAAC;AAE7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAEpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAGlE,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,4BAA6B,SAAQ,iCAAiC;IACrF,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,mBAAmB,CAAC;IAChD,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,oBAAoB,CAAC;CACvD;AAED,mFAAmF;AACnF,wBAAsB,uBAAuB,CAC3C,OAAO,GAAE,uBAA4B,EACrC,YAAY,GAAE,4BAAiC,GAC9C,OAAO,CAAC,IAAI,CAAC,CAyBf"}
@@ -0,0 +1,36 @@
1
+ import { resolveDeploymentCredential, } from '../utils/cloud-deployment-access.js';
2
+ import { deploymentTargetFromOptions } from '../utils/deployment-target.js';
3
+ import { fetchHostedEndpoints } from '../utils/hosted-endpoints.js';
4
+ import { printHostedEndpoints } from '../utils/hosted-endpoints-output.js';
5
+ import { fetchLiveDeployment } from '../utils/live-deployment.js';
6
+ import { logger } from '../utils/logger.js';
7
+ /** Read the current target and its hosted connection details without deploying. */
8
+ export async function deploymentStatusCommand(options = {}, dependencies = {}) {
9
+ const access = await resolveDeploymentCredential(options.endpoint, dependencies);
10
+ const target = deploymentTargetFromOptions(options, access.storedCredential);
11
+ const live = await (dependencies.fetchLive ?? fetchLiveDeployment)({
12
+ endpoint: access.endpoint,
13
+ token: access.token,
14
+ target,
15
+ resource: 'state',
16
+ });
17
+ logger.info(`Target: ${target.project} / ${target.environment}`);
18
+ if (live?.active) {
19
+ logger.success(`Live release: ${live.active.releaseIdentity}`);
20
+ logger.info(`Activated: ${live.active.activatedAt}`);
21
+ if (live.active.restored)
22
+ logger.info('This release was restored from history.');
23
+ }
24
+ else {
25
+ logger.info('No live release yet.');
26
+ }
27
+ const endpoints = await (dependencies.fetchEndpoints ?? fetchHostedEndpoints)({
28
+ endpoint: access.endpoint,
29
+ token: access.token,
30
+ target,
31
+ });
32
+ if (endpoints)
33
+ printHostedEndpoints(endpoints, options.mcpConfig === true);
34
+ else
35
+ logger.warn('Cloud did not return hosted endpoint details.');
36
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AA8BA,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,iBAiOvE"}
1
+ {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AAkCA,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,iBA2OvE"}
@@ -1,3 +1,7 @@
1
+ import { exitWith, finishAndExit } from '../utils/command-exit.js';
2
+ import { telemetryErrorCode } from '../utils/telemetry/error-code.js';
3
+ import { DevSession } from '../utils/telemetry/dev-session.js';
4
+ import { setCommandTelemetryError } from '../utils/telemetry/command-context.js';
1
5
  import { watch } from 'node:fs';
2
6
  import path from 'node:path';
3
7
  import ora from 'ora';
@@ -27,6 +31,7 @@ function displayQueriesFileNotFoundError(commandName) {
27
31
  logger.newline();
28
32
  }
29
33
  export async function devCommand(file, options = {}) {
34
+ const telemetry = new DevSession();
30
35
  // Step 1: Find queries file
31
36
  const queriesFile = file
32
37
  ? await findQueriesFile(file)
@@ -35,10 +40,11 @@ export async function devCommand(file, options = {}) {
35
40
  : await findQueriesFile();
36
41
  if (!queriesFile) {
37
42
  displayQueriesFileNotFoundError('dev');
38
- process.exit(1);
43
+ exitWith(1, 'failure', 'entrypoint_not_found');
39
44
  }
40
45
  logger.info(`Found: ${path.relative(process.cwd(), queriesFile)}`);
41
46
  logger.newline();
47
+ telemetry.start(queriesFile, file, options);
42
48
  let currentServer = null;
43
49
  let lifecycleOperation = Promise.resolve();
44
50
  let shutdownRequested = false;
@@ -61,9 +67,11 @@ export async function devCommand(file, options = {}) {
61
67
  // Loading spinners for slow operations
62
68
  const compileSpinner = ora('Compiling queries...').start();
63
69
  const dbSpinner = ora('Connecting to ClickHouse...').start();
70
+ let loading = true;
64
71
  try {
65
72
  // Load the API module
66
73
  const api = await loadApiModule(queriesFile);
74
+ loading = false;
67
75
  compileSpinner.succeed('Compiled queries');
68
76
  // Get table count for display
69
77
  let tableCount = 0;
@@ -125,8 +133,10 @@ export async function devCommand(file, options = {}) {
125
133
  logger.indent(`Visit: ${baseUrl}`);
126
134
  }
127
135
  }
136
+ return true;
128
137
  }
129
138
  catch (error) {
139
+ const code = loading ? telemetry.loadFailed(error) : telemetryErrorCode(error);
130
140
  // If server startup or later setup fails, tear down any resources
131
141
  // acquired by this attempt before retrying or exiting.
132
142
  try {
@@ -158,21 +168,31 @@ export async function devCommand(file, options = {}) {
158
168
  }
159
169
  logger.newline();
160
170
  if (!shouldWatch) {
161
- process.exit(1);
171
+ setCommandTelemetryError(code);
172
+ exitWith(1, 'failure', code);
162
173
  }
174
+ return false;
163
175
  }
164
176
  };
165
177
  const restartServer = () => queueLifecycleOperation(async () => {
166
178
  if (shutdownRequested)
167
179
  return;
180
+ telemetry.reload();
168
181
  if (currentServer) {
169
182
  logger.newline();
170
183
  logger.reload('File changed, restarting...');
171
184
  logger.newline();
172
- await stopCurrentRuntime();
185
+ try {
186
+ await stopCurrentRuntime();
187
+ }
188
+ catch (error) {
189
+ telemetry.reloadFailed();
190
+ throw error;
191
+ }
173
192
  }
174
193
  if (!shutdownRequested) {
175
- await startServer();
194
+ if (!await startServer())
195
+ telemetry.reloadFailed();
176
196
  }
177
197
  });
178
198
  const shutdown = () => {
@@ -183,7 +203,7 @@ export async function devCommand(file, options = {}) {
183
203
  logger.info('Shutting down dev server...');
184
204
  return queueLifecycleOperation(async () => {
185
205
  await stopCurrentRuntime();
186
- process.exit(0);
206
+ await finishAndExit(0, 'interrupted');
187
207
  });
188
208
  };
189
209
  // Start initial server
@@ -1,9 +1,3 @@
1
- /**
2
- * Generate Datasets Command
3
- *
4
- * Auto-generates dataset definitions from ClickHouse schema.
5
- * Reduces quickstart friction by scaffolding the semantic layer.
6
- */
7
1
  export interface GenerateDatasetsOptions {
8
2
  output?: string;
9
3
  path?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"generate-datasets.d.ts","sourceRoot":"","sources":["../../src/commands/generate-datasets.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAYH,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AA2BD,wBAAsB,uBAAuB,CAAC,OAAO,GAAE,uBAA4B,iBAqKlF"}
1
+ {"version":3,"file":"generate-datasets.d.ts","sourceRoot":"","sources":["../../src/commands/generate-datasets.ts"],"names":[],"mappings":"AAsBA,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AA2BD,wBAAsB,uBAAuB,CAAC,OAAO,GAAE,uBAA4B,iBA+KlF"}
@@ -1,3 +1,5 @@
1
+ import { exitWith } from '../utils/command-exit.js';
2
+ import { telemetryErrorCode } from '../utils/telemetry/error-code.js';
1
3
  /**
2
4
  * Generate Datasets Command
3
5
  *
@@ -13,6 +15,9 @@ import { redactConnectionUrl } from '../utils/redact-connection-url.js';
13
15
  import { logDatasetGenerationWarnings } from '../utils/dataset-generation-warnings.js';
14
16
  import { formatGeneratedFileDiff } from '../utils/generated-file-diff.js';
15
17
  import { readGeneratedFile, writeGeneratedFileAtomically } from '../utils/generated-file.js';
18
+ import { updateCommandTelemetry, setCommandTelemetryError } from '../utils/telemetry/command-context.js';
19
+ import { countBucket } from '../utils/telemetry/buckets.js';
20
+ import { warningBuckets } from '../utils/telemetry/generation-metrics.js';
16
21
  /**
17
22
  * Turns the written path into something pasteable into an import statement:
18
23
  * strips the `.ts` extension and makes it explicitly relative.
@@ -35,6 +40,8 @@ function parseTableList(value) {
35
40
  return parsed && parsed.length > 0 ? parsed : undefined;
36
41
  }
37
42
  export async function generateDatasetsCommand(options = {}) {
43
+ updateCommandTelemetry('generate:datasets', { mode: options.check ? 'check' : options.diff ? 'diff' : 'write', force: !!options.force,
44
+ tenant_column_used: !!options.tenantColumn, tables_filter_used: !!options.tables, exclude_filter_used: !!options.excludeTables });
38
45
  // Determine output path
39
46
  let outputPath;
40
47
  if (options.output) {
@@ -52,6 +59,7 @@ export async function generateDatasetsCommand(options = {}) {
52
59
  const excludedTables = parseTableList(options.excludeTables);
53
60
  if (options.force && (options.check || options.diff)) {
54
61
  logger.error('--force cannot be combined with --check or --diff.');
62
+ setCommandTelemetryError('validation_failed');
55
63
  process.exitCode = 1;
56
64
  return;
57
65
  }
@@ -80,9 +88,16 @@ export async function generateDatasetsCommand(options = {}) {
80
88
  const generatedCount = generatedTables.length || tableCount;
81
89
  datasetSpinner.succeed(`Generated dataset definitions for ${generatedCount} ${generatedCount === 1 ? 'table' : 'tables'}`);
82
90
  logDatasetGenerationWarnings(generated?.warnings);
91
+ updateCommandTelemetry('generate:datasets', { datasets_generated_bucket: countBucket(generated.tables.length), warning_counts: warningBuckets(generated.warnings) });
83
92
  const relativeOutput = path.relative(process.cwd(), outputPath);
84
93
  const currentContents = await readGeneratedFile(outputPath);
85
94
  const contentsMatch = currentContents === generated.contents;
95
+ if (options.check) {
96
+ const result = contentsMatch ? 'up_to_date' : currentContents === undefined ? 'missing' : 'out_of_date';
97
+ updateCommandTelemetry('generate:datasets', { check_result: result });
98
+ if (!contentsMatch)
99
+ setCommandTelemetryError(currentContents === undefined ? 'output_missing' : 'output_out_of_date');
100
+ }
86
101
  if (contentsMatch) {
87
102
  logger.success(options.check || options.diff
88
103
  ? `Dataset definitions are up to date: ${relativeOutput}`
@@ -92,6 +107,7 @@ export async function generateDatasetsCommand(options = {}) {
92
107
  }
93
108
  }
94
109
  else if (options.diff) {
110
+ setCommandTelemetryError('output_out_of_date');
95
111
  logger.raw(formatGeneratedFileDiff(currentContents ?? '', generated.contents, relativeOutput));
96
112
  logger.error(`Generated dataset definitions differ: ${relativeOutput}`);
97
113
  process.exitCode = 1;
@@ -173,6 +189,6 @@ export async function generateDatasetsCommand(options = {}) {
173
189
  logger.error(String(error));
174
190
  }
175
191
  logger.newline();
176
- process.exit(1);
192
+ exitWith(1, 'failure', telemetryErrorCode(error));
177
193
  }
178
194
  }
@@ -1 +1 @@
1
- {"version":3,"file":"generate-manifest.d.ts","sourceRoot":"","sources":["../../src/commands/generate-manifest.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,OAAO,GAAE,uBAA4B,iBAyBtC"}
1
+ {"version":3,"file":"generate-manifest.d.ts","sourceRoot":"","sources":["../../src/commands/generate-manifest.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,OAAO,GAAE,uBAA4B,iBA2BtC"}
@@ -2,7 +2,10 @@ import { mkdir, writeFile } from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import { loadApiModule } from '../utils/load-api.js';
4
4
  import { logger } from '../utils/logger.js';
5
+ import { updateCommandTelemetry } from '../utils/telemetry/command-context.js';
6
+ import { manifestMetrics } from '../utils/telemetry/generation-metrics.js';
5
7
  export async function generateManifestCommand(apiPath, options = {}) {
8
+ updateCommandTelemetry('generate:manifest', { custom_output: options.output !== undefined });
6
9
  if (!apiPath) {
7
10
  throw new Error('Missing API module path.\n\n' +
8
11
  'Usage: hypequery generate:manifest analytics/api.ts --output analytics/hypequery-manifest.json');
@@ -15,6 +18,7 @@ export async function generateManifestCommand(apiPath, options = {}) {
15
18
  `Export the value returned by createAPI() or initServe(...).serve(...).`);
16
19
  }
17
20
  const manifest = api.manifest();
21
+ updateCommandTelemetry('generate:manifest', manifestMetrics(api, manifest));
18
22
  await mkdir(path.dirname(outputPath), { recursive: true });
19
23
  await writeFile(outputPath, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8');
20
24
  logger.success(`Manifest written to ${outputPath}`);
@@ -1 +1 @@
1
- {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"AAIA,OAAO,EAAiC,KAAK,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAK/F,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAsB,eAAe,CAAC,OAAO,GAAE,eAAoB,iBA6JlE"}
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"AAMA,OAAO,EAAiC,KAAK,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAQ/F,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAsB,eAAe,CAAC,OAAO,GAAE,eAAoB,iBAqKlE"}
@@ -1,3 +1,5 @@
1
+ import { exitWith } from '../utils/command-exit.js';
2
+ import { telemetryErrorCode } from '../utils/telemetry/error-code.js';
1
3
  import path from 'node:path';
2
4
  import ora from 'ora';
3
5
  import { logger } from '../utils/logger.js';
@@ -6,7 +8,13 @@ import { detectDatabase, getTableCount } from '../utils/detect-database.js';
6
8
  import { ensureChdbInstalled } from '../utils/chdb-client.js';
7
9
  import { getTypeGenerator } from '../generators/index.js';
8
10
  import { redactConnectionUrl } from '../utils/redact-connection-url.js';
11
+ import { updateCommandTelemetry } from '../utils/telemetry/command-context.js';
12
+ import { countBucket } from '../utils/telemetry/buckets.js';
13
+ import { TypeGenerationMetrics } from '../utils/telemetry/generation-metrics.js';
9
14
  export async function generateCommand(options = {}) {
15
+ const command = options.commandName === 'hypequery generate:types' ? 'generate:types' : 'generate';
16
+ const metrics = new TypeGenerationMetrics();
17
+ updateCommandTelemetry(command, { custom_output: !!(options.output || options.path), tables_filter_used: !!options.tables, chdb_path_given: !!options.chdbPath });
10
18
  // Determine output path
11
19
  let outputPath;
12
20
  if (options.output) {
@@ -35,6 +43,7 @@ export async function generateCommand(options = {}) {
35
43
  const requestedDbType = options.database;
36
44
  const dbType = requestedDbType ?? (await detectDatabase());
37
45
  const chdbPath = dbType === 'chdb' ? options.chdbPath : undefined;
46
+ updateCommandTelemetry(command, { database: dbType === 'clickhouse' || dbType === 'chdb' || dbType === 'bigquery' ? dbType : 'unknown', chdb_path_given: !!chdbPath });
38
47
  if (dbType === 'chdb' && !requestedDbType) {
39
48
  throw new Error('chDB generation must be explicit. Re-run with --database chdb and add --chdb-path <dir> for persistent storage.');
40
49
  }
@@ -68,10 +77,13 @@ export async function generateCommand(options = {}) {
68
77
  outputPath,
69
78
  includeTables: parsedTables,
70
79
  chdbPath,
80
+ onColumn: () => metrics.column(),
81
+ onUnsupportedType: type => metrics.fallback(type),
71
82
  });
72
83
  // The generator returns what it actually wrote after applying filters.
73
84
  // Requested names may contain duplicates or tables that do not exist.
74
85
  const generatedCount = generatedTables.length;
86
+ updateCommandTelemetry(command, { ...metrics.snapshot(), table_count_bucket: countBucket(generatedCount) });
75
87
  typeSpinner.succeed(`Generated types for ${generatedCount} ${generatedCount === 1 ? 'table' : 'tables'}`);
76
88
  logger.success(`Updated ${path.relative(process.cwd(), outputPath)}`);
77
89
  logger.newline();
@@ -79,6 +91,7 @@ export async function generateCommand(options = {}) {
79
91
  logger.newline();
80
92
  }
81
93
  catch (error) {
94
+ updateCommandTelemetry(command, metrics.snapshot());
82
95
  activeSpinner.fail(failureMessage);
83
96
  logger.newline();
84
97
  if (error instanceof Error) {
@@ -140,6 +153,6 @@ export async function generateCommand(options = {}) {
140
153
  logger.error(String(error));
141
154
  }
142
155
  logger.newline();
143
- process.exit(1);
156
+ exitWith(1, 'failure', telemetryErrorCode(error));
144
157
  }
145
158
  }
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAIA,OAAO,EAcL,KAAK,SAAS,EACf,MAAM,qBAAqB,CAAC;AAe7B,OAAO,EAA2B,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAYzF,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,IAAI,CAAC,EAAE,gBAAgB,CAAC;CACzB;AAqKD,wBAAsB,WAAW,CAAC,OAAO,GAAE,WAAgB,iBAsb1D"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAUA,OAAO,EAcL,KAAK,SAAS,EACf,MAAM,qBAAqB,CAAC;AAc7B,OAAO,EAA2B,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAYzF,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,IAAI,CAAC,EAAE,gBAAgB,CAAC;CACzB;AA6GD,wBAAsB,WAAW,CAAC,OAAO,GAAE,WAAgB,iBAY1D"}