@kaelio/ktx 0.8.0 → 0.9.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 (83) hide show
  1. package/assets/python/{kaelio_ktx-0.8.0-py3-none-any.whl → kaelio_ktx-0.9.0-py3-none-any.whl} +0 -0
  2. package/assets/python/manifest.json +4 -4
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/cli-runtime.js +50 -3
  5. package/dist/commands/setup-commands.js +1 -1
  6. package/dist/connection-recovery.d.ts +34 -0
  7. package/dist/connection-recovery.js +82 -0
  8. package/dist/connection.js +3 -1
  9. package/dist/context/ingest/adapters/historic-sql/bigquery-query-history-reader.js +71 -20
  10. package/dist/context/ingest/adapters/historic-sql/chunk-unified.js +2 -1
  11. package/dist/context/ingest/adapters/historic-sql/connection-dialect.d.ts +9 -0
  12. package/dist/context/ingest/adapters/historic-sql/connection-dialect.js +15 -4
  13. package/dist/context/ingest/adapters/historic-sql/pattern-inputs.js +8 -2
  14. package/dist/context/ingest/adapters/historic-sql/query-history-filter-picker.d.ts +29 -0
  15. package/dist/context/ingest/adapters/historic-sql/query-history-filter-picker.js +190 -0
  16. package/dist/context/ingest/adapters/historic-sql/scope-floor.d.ts +18 -0
  17. package/dist/context/ingest/adapters/historic-sql/scope-floor.js +229 -0
  18. package/dist/context/ingest/adapters/historic-sql/scope-membership.d.ts +8 -0
  19. package/dist/context/ingest/adapters/historic-sql/scope-membership.js +29 -0
  20. package/dist/context/ingest/adapters/historic-sql/snowflake-query-history-reader.js +68 -19
  21. package/dist/context/ingest/adapters/historic-sql/stage-unified.js +57 -50
  22. package/dist/context/ingest/adapters/historic-sql/types.d.ts +36 -3
  23. package/dist/context/ingest/adapters/historic-sql/types.js +14 -2
  24. package/dist/context/ingest/context-evidence/sqlite-context-evidence-store.d.ts +1 -1
  25. package/dist/context/ingest/isolated-diff/patch-integrator.js +75 -5
  26. package/dist/context/ingest/local-adapters.js +21 -4
  27. package/dist/context/ingest/local-bundle-runtime.js +3 -2
  28. package/dist/context/llm/codex-exec-events.d.ts +20 -0
  29. package/dist/context/llm/codex-exec-events.js +155 -0
  30. package/dist/context/llm/codex-isolation.d.ts +3 -0
  31. package/dist/context/llm/codex-isolation.js +5 -0
  32. package/dist/context/llm/codex-mcp-runtime-server.d.ts +24 -0
  33. package/dist/context/llm/codex-mcp-runtime-server.js +51 -0
  34. package/dist/context/llm/codex-models.d.ts +2 -0
  35. package/dist/context/llm/codex-models.js +17 -0
  36. package/dist/context/llm/codex-runtime-config.d.ts +16 -0
  37. package/dist/context/llm/codex-runtime-config.js +19 -0
  38. package/dist/context/llm/codex-runtime.d.ts +37 -0
  39. package/dist/context/llm/codex-runtime.js +304 -0
  40. package/dist/context/llm/codex-sdk-runner.d.ts +21 -0
  41. package/dist/context/llm/codex-sdk-runner.js +63 -0
  42. package/dist/context/llm/local-config.d.ts +2 -0
  43. package/dist/context/llm/local-config.js +12 -1
  44. package/dist/context/project/config.d.ts +2 -0
  45. package/dist/context/project/config.js +2 -2
  46. package/dist/context/sql-analysis/http-sql-analysis-port.js +32 -2
  47. package/dist/context/sql-analysis/ports.d.ts +12 -2
  48. package/dist/context/tools/context-candidate-mark.tool.d.ts +2 -2
  49. package/dist/context-build-view.js +4 -32
  50. package/dist/io/buffered-command-io.d.ts +11 -0
  51. package/dist/io/buffered-command-io.js +28 -0
  52. package/dist/llm/types.d.ts +1 -1
  53. package/dist/local-adapters.d.ts +10 -2
  54. package/dist/local-adapters.js +19 -3
  55. package/dist/next-steps.js +1 -2
  56. package/dist/progress-port-adapter.d.ts +6 -0
  57. package/dist/progress-port-adapter.js +18 -0
  58. package/dist/public-ingest.d.ts +20 -1
  59. package/dist/public-ingest.js +178 -27
  60. package/dist/scan.js +3 -1
  61. package/dist/setup-context.d.ts +2 -0
  62. package/dist/setup-context.js +133 -27
  63. package/dist/setup-databases.d.ts +17 -1
  64. package/dist/setup-databases.js +358 -249
  65. package/dist/setup-models.d.ts +10 -1
  66. package/dist/setup-models.js +90 -2
  67. package/dist/setup-ready-menu.d.ts +16 -2
  68. package/dist/setup-ready-menu.js +37 -5
  69. package/dist/setup-sources.js +108 -28
  70. package/dist/setup.js +22 -10
  71. package/dist/status-project.d.ts +11 -0
  72. package/dist/status-project.js +50 -1
  73. package/dist/telemetry/command-hook.d.ts +1 -0
  74. package/dist/telemetry/command-hook.js +3 -1
  75. package/dist/telemetry/events.d.ts +11 -6
  76. package/dist/telemetry/events.js +10 -2
  77. package/dist/telemetry/identity.d.ts +0 -1
  78. package/dist/telemetry/identity.js +6 -6
  79. package/dist/telemetry/index.d.ts +12 -0
  80. package/dist/telemetry/index.js +13 -2
  81. package/dist/telemetry/scrubber.d.ts +10 -0
  82. package/dist/telemetry/scrubber.js +20 -0
  83. package/package.json +5 -4
@@ -12,6 +12,7 @@ export interface CompletedCommandSpan {
12
12
  durationMs: number;
13
13
  outcome: CommandOutcome;
14
14
  errorClass?: string;
15
+ errorDetail?: string;
15
16
  flagsPresent: Record<string, boolean>;
16
17
  hasProject: boolean;
17
18
  projectDir?: string;
@@ -1,4 +1,4 @@
1
- import { scrubErrorClass } from './scrubber.js';
1
+ import { formatErrorDetail, scrubErrorClass } from './scrubber.js';
2
2
  let activeCommandSpan;
3
3
  export function beginCommandSpan(input) {
4
4
  activeCommandSpan = input;
@@ -10,11 +10,13 @@ export function completeCommandSpan(input) {
10
10
  return undefined;
11
11
  }
12
12
  const errorClass = input.error ? scrubErrorClass(input.error) : undefined;
13
+ const errorDetail = input.error ? formatErrorDetail(input.error) : undefined;
13
14
  return {
14
15
  commandPath: span.commandPath,
15
16
  durationMs: Math.max(0, input.completedAt - span.startedAt),
16
17
  outcome: input.outcome,
17
18
  ...(errorClass ? { errorClass } : {}),
19
+ ...(errorDetail ? { errorDetail } : {}),
18
20
  flagsPresent: span.flagsPresent,
19
21
  hasProject: span.hasProject,
20
22
  projectDir: span.projectDir,
@@ -44,6 +44,7 @@ export declare const telemetryEventSchemas: {
44
44
  aborted: "aborted";
45
45
  }>;
46
46
  errorClass: z.ZodOptional<z.ZodString>;
47
+ errorDetail: z.ZodOptional<z.ZodString>;
47
48
  flagsPresent: z.ZodRecord<z.ZodString, z.ZodBoolean>;
48
49
  hasProject: z.ZodBoolean;
49
50
  projectGroupAttached: z.ZodBoolean;
@@ -67,8 +68,8 @@ export declare const telemetryEventSchemas: {
67
68
  databases: "databases";
68
69
  context: "context";
69
70
  runtime: "runtime";
70
- agents: "agents";
71
71
  secrets: "secrets";
72
+ agents: "agents";
72
73
  "demo-tour": "demo-tour";
73
74
  }>;
74
75
  outcome: z.ZodEnum<{
@@ -77,6 +78,7 @@ export declare const telemetryEventSchemas: {
77
78
  abandoned: "abandoned";
78
79
  }>;
79
80
  durationMs: z.ZodNumber;
81
+ errorDetail: z.ZodOptional<z.ZodString>;
80
82
  }, z.core.$strict>;
81
83
  readonly connection_added: z.ZodObject<{
82
84
  cliVersion: z.ZodString;
@@ -110,6 +112,7 @@ export declare const telemetryEventSchemas: {
110
112
  error: "error";
111
113
  }>;
112
114
  errorClass: z.ZodOptional<z.ZodString>;
115
+ errorDetail: z.ZodOptional<z.ZodString>;
113
116
  durationMs: z.ZodNumber;
114
117
  serverVersion: z.ZodOptional<z.ZodString>;
115
118
  }, z.core.$strict>;
@@ -163,6 +166,7 @@ export declare const telemetryEventSchemas: {
163
166
  error: "error";
164
167
  }>;
165
168
  errorClass: z.ZodOptional<z.ZodString>;
169
+ errorDetail: z.ZodOptional<z.ZodString>;
166
170
  }, z.core.$strict>;
167
171
  readonly scan_completed: z.ZodObject<{
168
172
  cliVersion: z.ZodString;
@@ -186,6 +190,7 @@ export declare const telemetryEventSchemas: {
186
190
  error: "error";
187
191
  }>;
188
192
  errorClass: z.ZodOptional<z.ZodString>;
193
+ errorDetail: z.ZodOptional<z.ZodString>;
189
194
  }, z.core.$strict>;
190
195
  readonly sl_validate_completed: z.ZodObject<{
191
196
  cliVersion: z.ZodString;
@@ -390,11 +395,11 @@ export declare const telemetryEventCatalog: readonly [{
390
395
  }, {
391
396
  readonly name: "command";
392
397
  readonly description: "Emitted once for each Commander action that reaches preAction.";
393
- readonly fields: readonly ["commandPath", "durationMs", "outcome", "errorClass", "flagsPresent", "hasProject", "projectGroupAttached"];
398
+ readonly fields: readonly ["commandPath", "durationMs", "outcome", "errorClass", "errorDetail", "flagsPresent", "hasProject", "projectGroupAttached"];
394
399
  }, {
395
400
  readonly name: "setup_step";
396
401
  readonly description: "Emitted after an interactive setup step completes, skips, or aborts.";
397
- readonly fields: readonly ["step", "outcome", "durationMs"];
402
+ readonly fields: readonly ["step", "outcome", "durationMs", "errorDetail"];
398
403
  }, {
399
404
  readonly name: "connection_added";
400
405
  readonly description: "Emitted when setup writes a database, source, or demo connection.";
@@ -402,7 +407,7 @@ export declare const telemetryEventCatalog: readonly [{
402
407
  }, {
403
408
  readonly name: "connection_test";
404
409
  readonly description: "Emitted after ktx connection test completes.";
405
- readonly fields: readonly ["driver", "isDemoConnection", "outcome", "errorClass", "durationMs", "serverVersion"];
410
+ readonly fields: readonly ["driver", "isDemoConnection", "outcome", "errorClass", "errorDetail", "durationMs", "serverVersion"];
406
411
  }, {
407
412
  readonly name: "project_stack_snapshot";
408
413
  readonly description: "Emitted after commands that can summarize the local project stack.";
@@ -410,11 +415,11 @@ export declare const telemetryEventCatalog: readonly [{
410
415
  }, {
411
416
  readonly name: "ingest_completed";
412
417
  readonly description: "Emitted after a public ingest target completes.";
413
- readonly fields: readonly ["driver", "isDemoConnection", "schemaCount", "tableCount", "columnCount", "rowsBucket", "durationMs", "outcome", "errorClass"];
418
+ readonly fields: readonly ["driver", "isDemoConnection", "schemaCount", "tableCount", "columnCount", "rowsBucket", "durationMs", "outcome", "errorClass", "errorDetail"];
414
419
  }, {
415
420
  readonly name: "scan_completed";
416
421
  readonly description: "Emitted after schema scan or relationship inference completes.";
417
- readonly fields: readonly ["driver", "tableCount", "columnCount", "inferredFkCount", "declaredFkCount", "durationMs", "outcome", "errorClass"];
422
+ readonly fields: readonly ["driver", "tableCount", "columnCount", "inferredFkCount", "declaredFkCount", "durationMs", "outcome", "errorClass", "errorDetail"];
418
423
  }, {
419
424
  readonly name: "sl_validate_completed";
420
425
  readonly description: "Emitted after ktx sl validate completes.";
@@ -18,6 +18,7 @@ const commandSchema = telemetryCommonEnvelopeSchema
18
18
  durationMs: z.number().nonnegative(),
19
19
  outcome: z.enum(['ok', 'error', 'aborted']),
20
20
  errorClass: z.string().optional(),
21
+ errorDetail: z.string().max(1000).optional(),
21
22
  flagsPresent: z.record(z.string(), z.boolean()),
22
23
  hasProject: z.boolean(),
23
24
  projectGroupAttached: z.boolean(),
@@ -40,6 +41,7 @@ const setupStepSchema = telemetryCommonEnvelopeSchema
40
41
  ]),
41
42
  outcome: z.enum(['completed', 'skipped', 'abandoned']),
42
43
  durationMs: z.number().nonnegative(),
44
+ errorDetail: z.string().max(1000).optional(),
43
45
  })
44
46
  .strict();
45
47
  const connectionAddedSchema = telemetryCommonEnvelopeSchema
@@ -54,6 +56,7 @@ const connectionTestSchema = telemetryCommonEnvelopeSchema
54
56
  isDemoConnection: z.boolean(),
55
57
  outcome: outcomeSchema,
56
58
  errorClass: z.string().optional(),
59
+ errorDetail: z.string().max(1000).optional(),
57
60
  durationMs: z.number().nonnegative(),
58
61
  serverVersion: z.string().optional(),
59
62
  })
@@ -80,6 +83,7 @@ const ingestCompletedSchema = telemetryCommonEnvelopeSchema
80
83
  durationMs: z.number().nonnegative(),
81
84
  outcome: outcomeSchema,
82
85
  errorClass: z.string().optional(),
86
+ errorDetail: z.string().max(1000).optional(),
83
87
  })
84
88
  .strict();
85
89
  const scanCompletedSchema = telemetryCommonEnvelopeSchema
@@ -92,6 +96,7 @@ const scanCompletedSchema = telemetryCommonEnvelopeSchema
92
96
  durationMs: z.number().nonnegative(),
93
97
  outcome: outcomeSchema,
94
98
  errorClass: z.string().optional(),
99
+ errorDetail: z.string().max(1000).optional(),
95
100
  })
96
101
  .strict();
97
102
  const slValidateCompletedSchema = telemetryCommonEnvelopeSchema
@@ -215,6 +220,7 @@ export const telemetryEventCatalog = [
215
220
  'durationMs',
216
221
  'outcome',
217
222
  'errorClass',
223
+ 'errorDetail',
218
224
  'flagsPresent',
219
225
  'hasProject',
220
226
  'projectGroupAttached',
@@ -223,7 +229,7 @@ export const telemetryEventCatalog = [
223
229
  {
224
230
  name: 'setup_step',
225
231
  description: 'Emitted after an interactive setup step completes, skips, or aborts.',
226
- fields: ['step', 'outcome', 'durationMs'],
232
+ fields: ['step', 'outcome', 'durationMs', 'errorDetail'],
227
233
  },
228
234
  {
229
235
  name: 'connection_added',
@@ -233,7 +239,7 @@ export const telemetryEventCatalog = [
233
239
  {
234
240
  name: 'connection_test',
235
241
  description: 'Emitted after ktx connection test completes.',
236
- fields: ['driver', 'isDemoConnection', 'outcome', 'errorClass', 'durationMs', 'serverVersion'],
242
+ fields: ['driver', 'isDemoConnection', 'outcome', 'errorClass', 'errorDetail', 'durationMs', 'serverVersion'],
237
243
  },
238
244
  {
239
245
  name: 'project_stack_snapshot',
@@ -253,6 +259,7 @@ export const telemetryEventCatalog = [
253
259
  'durationMs',
254
260
  'outcome',
255
261
  'errorClass',
262
+ 'errorDetail',
256
263
  ],
257
264
  },
258
265
  {
@@ -267,6 +274,7 @@ export const telemetryEventCatalog = [
267
274
  'durationMs',
268
275
  'outcome',
269
276
  'errorClass',
277
+ 'errorDetail',
270
278
  ],
271
279
  },
272
280
  {
@@ -11,7 +11,6 @@ export interface TelemetryIdentityEnv {
11
11
  export interface LoadTelemetryIdentityOptions {
12
12
  homeDir?: string;
13
13
  env?: TelemetryIdentityEnv;
14
- stdoutIsTTY: boolean;
15
14
  stderr: {
16
15
  write(chunk: string): void;
17
16
  };
@@ -58,12 +58,12 @@ export async function loadTelemetryIdentity(options) {
58
58
  path,
59
59
  };
60
60
  }
61
- // No identity yet. Minting one means showing the one-time opt-out notice, so
62
- // first-run creation requires an interactive surface; a headless first run
63
- // stays disabled and defers enablement until the next interactive run.
64
- if (options.stdoutIsTTY !== true) {
65
- return { enabled: false, createdFile: false, noticeShown: false, path };
66
- }
61
+ // No identity yet mint one regardless of surface. Telemetry is opt-out, so
62
+ // a fresh install is counted even when its first run is headless (an
63
+ // IDE-launched `ktx mcp stdio`, a scripted invocation); otherwise those
64
+ // installs would be permanently invisible. Opt-out env vars are honored
65
+ // above. The one-time notice is written to stderr — safe even under MCP
66
+ // stdio, which reserves stdout for its JSON-RPC protocol.
67
67
  const timestamp = (options.now ?? (() => new Date()))().toISOString();
68
68
  const next = {
69
69
  installId: randomUUID(),
@@ -25,3 +25,15 @@ export declare function emitCompletedCommand(input: {
25
25
  packageInfo: KtxCliPackageInfo;
26
26
  io: KtxCliIo;
27
27
  }): Promise<void>;
28
+ /**
29
+ * Flush telemetry when the process is interrupted (Ctrl-C / kill). The normal
30
+ * `command` emit + flush lives in a `finally` that a signal skips, so without
31
+ * this an interrupted long-running command (ingest, `mcp stdio`) loses its
32
+ * `command` event and any queued events. Marks the active command span as
33
+ * `aborted`, emits it, and drains the emitter. Best-effort and idempotent: if
34
+ * the span was already completed (normal exit racing a signal) the emit no-ops.
35
+ */
36
+ export declare function emitAbortedCommandAndShutdown(input: {
37
+ packageInfo: KtxCliPackageInfo;
38
+ io: KtxCliIo;
39
+ }): Promise<void>;
@@ -8,7 +8,6 @@ import { buildProjectStackSnapshotFields } from './project-snapshot.js';
8
8
  export { beginCommandSpan, completeCommandSpan, shutdownTelemetryEmitter };
9
9
  export async function showTelemetryNoticeIfNeeded(io, packageInfo) {
10
10
  const identity = await loadTelemetryIdentity({
11
- stdoutIsTTY: io.stdout.isTTY === true,
12
11
  stderr: io.stderr,
13
12
  env: process.env,
14
13
  });
@@ -45,7 +44,6 @@ export function mcpTelemetrySampleRate() {
45
44
  export async function emitTelemetryEvent(input) {
46
45
  const debug = telemetryDebugEnabled();
47
46
  const identity = await loadTelemetryIdentity({
48
- stdoutIsTTY: input.io.stdout.isTTY === true,
49
47
  stderr: input.io.stderr,
50
48
  env: process.env,
51
49
  });
@@ -100,3 +98,16 @@ export async function emitCompletedCommand(input) {
100
98
  packageInfo: input.packageInfo,
101
99
  });
102
100
  }
101
+ /**
102
+ * Flush telemetry when the process is interrupted (Ctrl-C / kill). The normal
103
+ * `command` emit + flush lives in a `finally` that a signal skips, so without
104
+ * this an interrupted long-running command (ingest, `mcp stdio`) loses its
105
+ * `command` event and any queued events. Marks the active command span as
106
+ * `aborted`, emits it, and drains the emitter. Best-effort and idempotent: if
107
+ * the span was already completed (normal exit racing a signal) the emit no-ops.
108
+ */
109
+ export async function emitAbortedCommandAndShutdown(input) {
110
+ const completed = completeCommandSpan({ completedAt: performance.now(), outcome: 'aborted' });
111
+ await emitCompletedCommand({ completed, packageInfo: input.packageInfo, io: input.io });
112
+ await shutdownTelemetryEmitter();
113
+ }
@@ -1 +1,11 @@
1
1
  export declare function scrubErrorClass(error: unknown): string | undefined;
2
+ /**
3
+ * Human-readable failure detail for telemetry: the error's `.code` (when
4
+ * present) prefixed onto its `message`, collapsed to a single line and
5
+ * length-capped. Captures the message only — never the stack.
6
+ *
7
+ * This intentionally forwards raw error text, which can include identifiers from
8
+ * the user's environment (table/column names, hostnames, usernames), so that
9
+ * funnel failures are diagnosable. Callers must gate it to the failure path.
10
+ */
11
+ export declare function formatErrorDetail(error: unknown): string | undefined;
@@ -20,3 +20,23 @@ export function scrubErrorClass(error) {
20
20
  }
21
21
  return constructorName;
22
22
  }
23
+ const MAX_ERROR_DETAIL_LENGTH = 1000;
24
+ /**
25
+ * Human-readable failure detail for telemetry: the error's `.code` (when
26
+ * present) prefixed onto its `message`, collapsed to a single line and
27
+ * length-capped. Captures the message only — never the stack.
28
+ *
29
+ * This intentionally forwards raw error text, which can include identifiers from
30
+ * the user's environment (table/column names, hostnames, usernames), so that
31
+ * funnel failures are diagnosable. Callers must gate it to the failure path.
32
+ */
33
+ export function formatErrorDetail(error) {
34
+ if (error === undefined || error === null) {
35
+ return undefined;
36
+ }
37
+ const code = error.code;
38
+ const message = error instanceof Error ? error.message : String(error);
39
+ const prefix = typeof code === 'string' || typeof code === 'number' ? `${code}: ` : '';
40
+ const detail = `${prefix}${message}`.replace(/\s+/g, ' ').trim();
41
+ return detail.length > 0 ? detail.slice(0, MAX_ERROR_DETAIL_LENGTH) : undefined;
42
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaelio/ktx",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Standalone ktx context layer for data agents",
5
5
  "type": "module",
6
6
  "engines": {
@@ -41,6 +41,7 @@
41
41
  "@looker/sdk-rtl": "^21.6.5",
42
42
  "@modelcontextprotocol/sdk": "^1.29.0",
43
43
  "@notionhq/client": "^5.22.0",
44
+ "@openai/codex-sdk": "^0.133.0",
44
45
  "ai": "^6.0.188",
45
46
  "better-sqlite3": "^12.10.0",
46
47
  "commander": "14.0.3",
@@ -78,13 +79,13 @@
78
79
  "license": "Apache-2.0",
79
80
  "repository": {
80
81
  "type": "git",
81
- "url": "https://github.com/Kaelio/ktx-ai-data-agents-context",
82
+ "url": "https://github.com/Kaelio/ktx",
82
83
  "directory": "packages/cli"
83
84
  },
84
85
  "bugs": {
85
- "url": "https://github.com/Kaelio/ktx-ai-data-agents-context/issues"
86
+ "url": "https://github.com/Kaelio/ktx/issues"
86
87
  },
87
- "homepage": "https://github.com/Kaelio/ktx-ai-data-agents-context#readme",
88
+ "homepage": "https://github.com/Kaelio/ktx#readme",
88
89
  "scripts": {
89
90
  "assets:demo": "node scripts/build-demo-assets.mjs",
90
91
  "build": "tsc -p tsconfig.json && node dist/telemetry/schema-writer.js src/telemetry/events.schema.json ../../python/ktx-daemon/src/ktx_daemon/telemetry/events.schema.json && node scripts/copy-runtime-assets.mjs && node ../../scripts/prepare-cli-bin.mjs",