@kaelio/ktx 0.13.0 → 0.14.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 (243) hide show
  1. package/assets/python/{kaelio_ktx-0.13.0-py3-none-any.whl → kaelio_ktx-0.14.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-program.js +1 -1
  5. package/dist/commands/ingest-commands.d.ts +9 -0
  6. package/dist/commands/ingest-commands.js +37 -1
  7. package/dist/commands/knowledge-commands.js +3 -0
  8. package/dist/commands/setup-commands.js +14 -1
  9. package/dist/connection-drivers.d.ts +2 -0
  10. package/dist/connection-drivers.js +7 -3
  11. package/dist/connection.d.ts +3 -0
  12. package/dist/connection.js +27 -0
  13. package/dist/connectors/bigquery/connector.d.ts +17 -6
  14. package/dist/connectors/bigquery/connector.js +152 -76
  15. package/dist/connectors/bigquery/dialect.d.ts +2 -2
  16. package/dist/connectors/clickhouse/connector.d.ts +1 -0
  17. package/dist/connectors/clickhouse/connector.js +45 -16
  18. package/dist/connectors/clickhouse/dialect.d.ts +2 -2
  19. package/dist/connectors/mongodb/connector.d.ts +69 -0
  20. package/dist/connectors/mongodb/connector.js +307 -0
  21. package/dist/connectors/mongodb/dialect.d.ts +17 -0
  22. package/dist/connectors/mongodb/dialect.js +50 -0
  23. package/dist/connectors/mongodb/live-database-introspection.d.ts +10 -0
  24. package/dist/connectors/mongodb/live-database-introspection.js +24 -0
  25. package/dist/connectors/mongodb/schema-inference.d.ts +20 -0
  26. package/dist/connectors/mongodb/schema-inference.js +110 -0
  27. package/dist/connectors/mysql/connector.d.ts +1 -0
  28. package/dist/connectors/mysql/connector.js +18 -2
  29. package/dist/connectors/mysql/dialect.d.ts +2 -2
  30. package/dist/connectors/postgres/connector.d.ts +1 -0
  31. package/dist/connectors/postgres/connector.js +20 -3
  32. package/dist/connectors/postgres/dialect.d.ts +2 -2
  33. package/dist/connectors/snowflake/connector.d.ts +1 -0
  34. package/dist/connectors/snowflake/connector.js +27 -3
  35. package/dist/connectors/snowflake/dialect.d.ts +2 -2
  36. package/dist/connectors/sqlite/connector.d.ts +11 -1
  37. package/dist/connectors/sqlite/connector.js +120 -17
  38. package/dist/connectors/sqlite/dialect.d.ts +2 -2
  39. package/dist/connectors/sqlite/read-query-child.d.ts +1 -0
  40. package/dist/connectors/sqlite/read-query-child.js +23 -0
  41. package/dist/connectors/sqlserver/connector.d.ts +2 -0
  42. package/dist/connectors/sqlserver/connector.js +23 -5
  43. package/dist/connectors/sqlserver/dialect.d.ts +2 -2
  44. package/dist/context/cache/content-result-cache.d.ts +36 -0
  45. package/dist/context/cache/content-result-cache.js +14 -0
  46. package/dist/context/cache/sqlite-content-result-cache.d.ts +18 -0
  47. package/dist/context/cache/sqlite-content-result-cache.js +223 -0
  48. package/dist/context/connections/bigquery-identifiers.d.ts +1 -0
  49. package/dist/context/connections/bigquery-identifiers.js +7 -0
  50. package/dist/context/connections/configured-connections.d.ts +9 -0
  51. package/dist/context/connections/configured-connections.js +18 -0
  52. package/dist/context/connections/dialects.d.ts +30 -4
  53. package/dist/context/connections/dialects.js +38 -11
  54. package/dist/context/connections/drivers.js +21 -0
  55. package/dist/context/connections/gdrive-config.d.ts +19 -0
  56. package/dist/context/connections/gdrive-config.js +57 -0
  57. package/dist/context/connections/query-deadline.d.ts +31 -0
  58. package/dist/context/connections/query-deadline.js +37 -0
  59. package/dist/context/connections/read-only-sql.d.ts +5 -0
  60. package/dist/context/connections/read-only-sql.js +139 -1
  61. package/dist/context/ingest/adapters/gdrive/chunk.d.ts +3 -0
  62. package/dist/context/ingest/adapters/gdrive/chunk.js +74 -0
  63. package/dist/context/ingest/adapters/gdrive/detect.d.ts +1 -0
  64. package/dist/context/ingest/adapters/gdrive/detect.js +20 -0
  65. package/dist/context/ingest/adapters/gdrive/fetch.d.ts +6 -0
  66. package/dist/context/ingest/adapters/gdrive/fetch.js +95 -0
  67. package/dist/context/ingest/adapters/gdrive/gdrive-client.d.ts +30 -0
  68. package/dist/context/ingest/adapters/gdrive/gdrive-client.js +132 -0
  69. package/dist/context/ingest/adapters/gdrive/gdrive.adapter.d.ts +11 -0
  70. package/dist/context/ingest/adapters/gdrive/gdrive.adapter.js +27 -0
  71. package/dist/context/ingest/adapters/gdrive/normalize.d.ts +2 -0
  72. package/dist/context/ingest/adapters/gdrive/normalize.js +256 -0
  73. package/dist/context/ingest/adapters/gdrive/types.d.ts +153 -0
  74. package/dist/context/ingest/adapters/gdrive/types.js +36 -0
  75. package/dist/context/ingest/adapters/live-database/daemon-introspection.js +24 -0
  76. package/dist/context/ingest/adapters/live-database/fetch-report.d.ts +8 -0
  77. package/dist/context/ingest/adapters/live-database/fetch-report.js +37 -0
  78. package/dist/context/ingest/adapters/live-database/live-database.adapter.d.ts +2 -1
  79. package/dist/context/ingest/adapters/live-database/live-database.adapter.js +9 -2
  80. package/dist/context/ingest/adapters/live-database/manifest.d.ts +2 -0
  81. package/dist/context/ingest/adapters/live-database/manifest.js +8 -4
  82. package/dist/context/ingest/adapters/live-database/scan-outcome.d.ts +17 -0
  83. package/dist/context/ingest/adapters/live-database/scan-outcome.js +40 -0
  84. package/dist/context/ingest/adapters/live-database/stage.js +5 -5
  85. package/dist/context/ingest/adapters/metabase/types.d.ts +1 -1
  86. package/dist/context/ingest/adapters/metabase/types.js +1 -1
  87. package/dist/context/ingest/artifact-gates.d.ts +32 -1
  88. package/dist/context/ingest/artifact-gates.js +85 -18
  89. package/dist/context/ingest/final-gate-prune.d.ts +35 -0
  90. package/dist/context/ingest/final-gate-prune.js +229 -0
  91. package/dist/context/ingest/ingest-bundle.runner.d.ts +3 -0
  92. package/dist/context/ingest/ingest-bundle.runner.js +459 -240
  93. package/dist/context/ingest/isolated-diff/patch-integrator.d.ts +0 -11
  94. package/dist/context/ingest/isolated-diff/patch-integrator.js +0 -44
  95. package/dist/context/ingest/isolated-diff/work-unit-executor.d.ts +1 -0
  96. package/dist/context/ingest/isolated-diff/work-unit-executor.js +13 -4
  97. package/dist/context/ingest/local-adapters.js +6 -0
  98. package/dist/context/ingest/local-bundle-runtime.js +7 -2
  99. package/dist/context/ingest/local-ingest.js +1 -1
  100. package/dist/context/ingest/local-stage-ingest.d.ts +3 -1
  101. package/dist/context/ingest/local-stage-ingest.js +3 -1
  102. package/dist/context/ingest/ports.d.ts +3 -0
  103. package/dist/context/ingest/report-snapshot.js +13 -3
  104. package/dist/context/ingest/reports.d.ts +3 -3
  105. package/dist/context/ingest/reports.js +3 -1
  106. package/dist/context/ingest/stages/build-wu-context.d.ts +1 -0
  107. package/dist/context/ingest/stages/build-wu-context.js +2 -1
  108. package/dist/context/ingest/stages/stage-3-work-units.d.ts +2 -1
  109. package/dist/context/ingest/stages/stage-3-work-units.js +4 -10
  110. package/dist/context/ingest/stages/validate-wu-sources.d.ts +12 -0
  111. package/dist/context/ingest/stages/validate-wu-sources.js +23 -8
  112. package/dist/context/ingest/tools/read-raw-file.tool.js +10 -5
  113. package/dist/context/ingest/tools/read-raw-span.tool.js +10 -5
  114. package/dist/context/ingest/tools/warehouse-verification/discover-data.tool.js +1 -1
  115. package/dist/context/ingest/tools/warehouse-verification/entity-details.tool.js +1 -1
  116. package/dist/context/ingest/tools/warehouse-verification/sql-execution.tool.js +1 -1
  117. package/dist/context/ingest/types.d.ts +3 -0
  118. package/dist/context/ingest/wiki-body-refs.d.ts +28 -0
  119. package/dist/context/ingest/wiki-body-refs.js +37 -8
  120. package/dist/context/ingest/wiki-sl-ref-repair.d.ts +1 -0
  121. package/dist/context/ingest/wiki-sl-ref-repair.js +4 -0
  122. package/dist/context/ingest/work-unit-cache.d.ts +67 -0
  123. package/dist/context/ingest/work-unit-cache.js +230 -0
  124. package/dist/context/llm/ai-sdk-runtime.d.ts +1 -0
  125. package/dist/context/llm/ai-sdk-runtime.js +5 -0
  126. package/dist/context/llm/claude-code-runtime.d.ts +4 -1
  127. package/dist/context/llm/claude-code-runtime.js +38 -8
  128. package/dist/context/llm/codex-runtime.d.ts +4 -1
  129. package/dist/context/llm/codex-runtime.js +48 -35
  130. package/dist/context/llm/runtime-port.d.ts +26 -0
  131. package/dist/context/llm/subprocess-generate-object-child.d.ts +1 -0
  132. package/dist/context/llm/subprocess-generate-object-child.js +34 -0
  133. package/dist/context/llm/subprocess-generate-object.d.ts +42 -0
  134. package/dist/context/llm/subprocess-generate-object.js +122 -0
  135. package/dist/context/mcp/context-tools.d.ts +2 -0
  136. package/dist/context/mcp/context-tools.js +111 -17
  137. package/dist/context/mcp/local-project-ports.d.ts +7 -0
  138. package/dist/context/mcp/local-project-ports.js +29 -0
  139. package/dist/context/mcp/logger.d.ts +24 -0
  140. package/dist/context/mcp/logger.js +49 -0
  141. package/dist/context/mcp/server.js +2 -0
  142. package/dist/context/mcp/types.d.ts +17 -0
  143. package/dist/context/memory/memory-agent.service.js +1 -1
  144. package/dist/context/project/config.d.ts +42 -0
  145. package/dist/context/project/config.js +5 -0
  146. package/dist/context/project/driver-schemas.d.ts +20 -0
  147. package/dist/context/project/driver-schemas.js +50 -1
  148. package/dist/context/project/project.js +1 -1
  149. package/dist/context/project/setup-config.js +1 -0
  150. package/dist/context/scan/description-generation.d.ts +4 -0
  151. package/dist/context/scan/description-generation.js +100 -13
  152. package/dist/context/scan/enabled-tables.d.ts +5 -0
  153. package/dist/context/scan/enabled-tables.js +13 -1
  154. package/dist/context/scan/enrichment-state.d.ts +50 -7
  155. package/dist/context/scan/enrichment-state.js +30 -13
  156. package/dist/context/scan/local-enrichment-artifacts.d.ts +41 -0
  157. package/dist/context/scan/local-enrichment-artifacts.js +155 -32
  158. package/dist/context/scan/local-enrichment.d.ts +39 -4
  159. package/dist/context/scan/local-enrichment.js +345 -92
  160. package/dist/context/scan/local-scan.d.ts +4 -1
  161. package/dist/context/scan/local-scan.js +54 -13
  162. package/dist/context/scan/local-structural-artifacts.d.ts +3 -1
  163. package/dist/context/scan/local-structural-artifacts.js +5 -0
  164. package/dist/context/scan/object-introspection.d.ts +21 -0
  165. package/dist/context/scan/object-introspection.js +35 -0
  166. package/dist/context/scan/relationship-benchmarks.js +5 -3
  167. package/dist/context/scan/relationship-composite-candidates.d.ts +6 -3
  168. package/dist/context/scan/relationship-composite-candidates.js +13 -1
  169. package/dist/context/scan/relationship-detection-budget.d.ts +35 -0
  170. package/dist/context/scan/relationship-detection-budget.js +53 -0
  171. package/dist/context/scan/relationship-diagnostics.d.ts +5 -0
  172. package/dist/context/scan/relationship-diagnostics.js +2 -0
  173. package/dist/context/scan/relationship-discovery.d.ts +9 -3
  174. package/dist/context/scan/relationship-discovery.js +27 -4
  175. package/dist/context/scan/relationship-llm-proposal.js +36 -27
  176. package/dist/context/scan/relationship-profiling.d.ts +7 -3
  177. package/dist/context/scan/relationship-profiling.js +53 -41
  178. package/dist/context/scan/relationship-validation.d.ts +6 -4
  179. package/dist/context/scan/relationship-validation.js +46 -32
  180. package/dist/context/scan/sqlite-local-enrichment-state-store.d.ts +8 -1
  181. package/dist/context/scan/sqlite-local-enrichment-state-store.js +71 -159
  182. package/dist/context/scan/types.d.ts +5 -3
  183. package/dist/context/scan/types.js +2 -0
  184. package/dist/context/sl/local-query.js +5 -0
  185. package/dist/context/sl/pglite-sl-search-prototype.js +1 -1
  186. package/dist/context/sl/semantic-layer.service.js +1 -1
  187. package/dist/context/sl/source-files.d.ts +5 -0
  188. package/dist/context/sl/source-files.js +17 -11
  189. package/dist/context/sl/tools/connection-id-schema.js +1 -1
  190. package/dist/context/sql-analysis/dialect-notes.d.ts +9 -0
  191. package/dist/context/sql-analysis/dialect-notes.js +40 -0
  192. package/dist/context/sql-analysis/dialects/bigquery.md +13 -0
  193. package/dist/context/sql-analysis/dialects/clickhouse.md +9 -0
  194. package/dist/context/sql-analysis/dialects/mysql.md +9 -0
  195. package/dist/context/sql-analysis/dialects/postgres.md +10 -0
  196. package/dist/context/sql-analysis/dialects/snowflake.md +10 -0
  197. package/dist/context/sql-analysis/dialects/sqlite.md +11 -0
  198. package/dist/context/sql-analysis/dialects/tsql.md +10 -0
  199. package/dist/context/wiki/keys.js +1 -1
  200. package/dist/context/wiki/knowledge-wiki.service.d.ts +4 -4
  201. package/dist/context/wiki/knowledge-wiki.service.js +2 -1
  202. package/dist/context/wiki/local-knowledge.d.ts +13 -0
  203. package/dist/context/wiki/local-knowledge.js +50 -6
  204. package/dist/context/wiki/sqlite-knowledge-index.d.ts +2 -0
  205. package/dist/context/wiki/sqlite-knowledge-index.js +21 -5
  206. package/dist/context/wiki/tools/wiki-write.tool.d.ts +2 -0
  207. package/dist/context/wiki/tools/wiki-write.tool.js +27 -0
  208. package/dist/context/wiki/types.d.ts +6 -0
  209. package/dist/context-build-view.d.ts +3 -0
  210. package/dist/context-build-view.js +1 -0
  211. package/dist/knowledge.d.ts +2 -0
  212. package/dist/knowledge.js +12 -1
  213. package/dist/local-adapters.js +11 -0
  214. package/dist/mcp-http-server.js +15 -1
  215. package/dist/mcp-server-factory.d.ts +2 -0
  216. package/dist/mcp-server-factory.js +15 -1
  217. package/dist/mcp-stdio-server.js +10 -2
  218. package/dist/notion-page-picker.js +1 -1
  219. package/dist/prompts/memory_agent_external_ingest.md +2 -0
  220. package/dist/public-ingest.d.ts +3 -1
  221. package/dist/public-ingest.js +3 -0
  222. package/dist/scan.d.ts +3 -1
  223. package/dist/scan.js +7 -0
  224. package/dist/setup-databases.d.ts +1 -1
  225. package/dist/setup-databases.js +43 -1
  226. package/dist/setup-sources.d.ts +5 -1
  227. package/dist/setup-sources.js +124 -48
  228. package/dist/setup.d.ts +3 -0
  229. package/dist/setup.js +6 -1
  230. package/dist/skills/analytics/SKILL.md +200 -2
  231. package/dist/skills/gdrive_synthesize/SKILL.md +97 -0
  232. package/dist/skills/wiki_capture/SKILL.md +24 -0
  233. package/dist/sql.js +4 -0
  234. package/dist/status-project.d.ts +4 -0
  235. package/dist/status-project.js +54 -2
  236. package/dist/telemetry/events.d.ts +2 -2
  237. package/dist/text-ingest.d.ts +4 -0
  238. package/dist/text-ingest.js +58 -29
  239. package/dist/verbatim-ingest.d.ts +46 -0
  240. package/dist/verbatim-ingest.js +193 -0
  241. package/package.json +5 -1
  242. package/dist/context/ingest/final-gate-repair.d.ts +0 -28
  243. package/dist/context/ingest/final-gate-repair.js +0 -91
@@ -1,6 +1,9 @@
1
1
  import { KtxExpectedError, KtxQueryError, isNativeProgrammingFault } from '../../errors.js';
2
+ import { isDatabaseDriver, normalizeConnectionDriver } from '../../connection-drivers.js';
3
+ import { sqlDialectNotes } from '../../context/sql-analysis/dialect-notes.js';
2
4
  import { executeProjectReadOnlySql } from '../../context/connections/project-sql-executor.js';
3
5
  import { FEDERATED_CONNECTION_ID, federatedConnectionListing } from '../../context/connections/federation.js';
6
+ import { assertSqlQueryableConnection } from '../../context/connections/dialects.js';
4
7
  import { resolveConfiguredConnection } from '../../context/connections/resolve-connection.js';
5
8
  import { localConnectionInfoFromConfig, } from '../../context/connections/local-warehouse-descriptor.js';
6
9
  import { createKtxEntityDetailsService } from '../../context/scan/entity-details.js';
@@ -10,6 +13,7 @@ import { compileLocalSlQuery } from '../../context/sl/local-query.js';
10
13
  import { createKtxDictionarySearchService } from '../../context/sl/dictionary-search.js';
11
14
  import { readLocalSlSource } from '../../context/sl/local-sl.js';
12
15
  import { assertSafeConnectionId } from '../../context/sl/source-files.js';
16
+ import { assertConfiguredConnectionId } from '../../context/connections/configured-connections.js';
13
17
  import { readLocalKnowledgePage, searchLocalKnowledgePages } from '../wiki/local-knowledge.js';
14
18
  async function executeValidatedReadOnlySql(project, options, input, onProgress) {
15
19
  await onProgress?.({ progress: 0, message: 'Validating SQL' });
@@ -23,6 +27,9 @@ async function executeValidatedReadOnlySql(project, options, input, onProgress)
23
27
  const isFederated = input.connectionId === FEDERATED_CONNECTION_ID;
24
28
  const connectionId = isFederated ? input.connectionId : assertSafeConnectionId(input.connectionId);
25
29
  const connection = isFederated ? undefined : resolveConfiguredConnection(project.config, connectionId);
30
+ if (!isFederated) {
31
+ assertSqlQueryableConnection(connectionId, connection.driver);
32
+ }
26
33
  const dialect = sqlAnalysisDialectForDriver(isFederated ? 'duckdb' : connection.driver);
27
34
  const validation = await options.sqlAnalysis.validateReadOnly(input.sql, dialect);
28
35
  if (!validation.ok) {
@@ -62,6 +69,18 @@ async function executeValidatedReadOnlySql(project, options, input, onProgress)
62
69
  await onProgress?.({ progress: 1, message: `Fetched ${response.rowCount} rows` });
63
70
  return response;
64
71
  }
72
+ /** @internal Resolves a connection's dialect SQL notes; throws KtxExpectedError for an unknown or non-SQL-warehouse connection. */
73
+ export function resolveDialectNotesForConnection(connectionId, connection) {
74
+ if (!connection) {
75
+ throw new KtxExpectedError(`Connection "${connectionId}" is not configured in ktx.yaml`);
76
+ }
77
+ const driver = normalizeConnectionDriver(connection);
78
+ if (!isDatabaseDriver(driver)) {
79
+ throw new KtxExpectedError(`Connection "${connectionId}" uses the "${driver}" context source, not a SQL warehouse; sql_dialect_notes applies only to SQL database connections.`);
80
+ }
81
+ const dialect = sqlAnalysisDialectForDriver(driver);
82
+ return { connectionId, dialect, notes: sqlDialectNotes(dialect) };
83
+ }
65
84
  export function createLocalProjectMcpContextPorts(project, options) {
66
85
  const embeddingService = options.embeddingService;
67
86
  const ports = {
@@ -86,11 +105,15 @@ export function createLocalProjectMcpContextPorts(project, options) {
86
105
  },
87
106
  knowledge: {
88
107
  async search(input) {
108
+ const connectionId = input.connectionId === undefined
109
+ ? undefined
110
+ : assertConfiguredConnectionId(project.config.connections, input.connectionId);
89
111
  const results = await searchLocalKnowledgePages(project, {
90
112
  query: input.query,
91
113
  userId: input.userId,
92
114
  limit: input.limit,
93
115
  embeddingService,
116
+ ...(connectionId !== undefined ? { connectionId } : {}),
94
117
  });
95
118
  return {
96
119
  results: results.slice(0, input.limit).map((result) => ({
@@ -161,6 +184,12 @@ export function createLocalProjectMcpContextPorts(project, options) {
161
184
  return createKtxDiscoverDataService(project, { userId: 'local', embeddingService }).search(input);
162
185
  },
163
186
  },
187
+ dialectNotes: {
188
+ async read(input) {
189
+ const connectionId = assertSafeConnectionId(input.connectionId);
190
+ return resolveDialectNotesForConnection(connectionId, project.config.connections[connectionId]);
191
+ },
192
+ },
164
193
  };
165
194
  if (options.sqlAnalysis && options.localScan?.createConnector) {
166
195
  ports.sqlExecution = {
@@ -0,0 +1,24 @@
1
+ import { type Logger } from 'pino';
2
+ import type { KtxCliIo } from '../../cli-runtime.js';
3
+ export type KtxMcpLogger = Logger;
4
+ /** @internal */
5
+ export declare function mcpLogLevel(env?: NodeJS.ProcessEnv): string;
6
+ /** @internal */
7
+ export declare function mcpSlowToolMs(env?: NodeJS.ProcessEnv): number;
8
+ /**
9
+ * Serialize an error for a structured `err` field. Genuine `Error`s get pino's
10
+ * standard serializer (type + message + stack); everything else is reduced to a
11
+ * message — the in-band tool-error path has already lost the original stack.
12
+ */
13
+ export declare function serializeMcpError(error: unknown): Record<string, unknown>;
14
+ /**
15
+ * One synchronous pino logger per MCP server process, written to the `io.stderr`
16
+ * sink. stderr is the only universally-correct sink: the stdio transport reserves
17
+ * stdout for JSON-RPC, and the HTTP daemon redirects stderr into `.ktx/logs/mcp.log`.
18
+ * Synchronous writes are load-bearing — a `tool.start` line must reach the fd before
19
+ * a blocking handler runs, so a runaway query still leaves its start record on disk.
20
+ * Format follows the terminal, not a flag: pretty for a TTY, plain JSON otherwise.
21
+ */
22
+ export declare function createMcpLogger(io: KtxCliIo, options?: {
23
+ isTTY?: boolean;
24
+ }): KtxMcpLogger;
@@ -0,0 +1,49 @@
1
+ import { Writable } from 'node:stream';
2
+ import pino from 'pino';
3
+ import PinoPretty from 'pino-pretty';
4
+ const LOG_LEVELS = new Set(['trace', 'debug', 'info', 'warn', 'error', 'fatal', 'silent']);
5
+ const DEFAULT_LEVEL = 'info';
6
+ const DEFAULT_SLOW_TOOL_MS = 10_000;
7
+ /** @internal */
8
+ export function mcpLogLevel(env = process.env) {
9
+ const raw = env.KTX_MCP_LOG_LEVEL?.trim().toLowerCase();
10
+ return raw && LOG_LEVELS.has(raw) ? raw : DEFAULT_LEVEL;
11
+ }
12
+ /** @internal */
13
+ export function mcpSlowToolMs(env = process.env) {
14
+ const raw = Number(env.KTX_MCP_SLOW_TOOL_MS);
15
+ return Number.isFinite(raw) && raw >= 0 ? raw : DEFAULT_SLOW_TOOL_MS;
16
+ }
17
+ /**
18
+ * Serialize an error for a structured `err` field. Genuine `Error`s get pino's
19
+ * standard serializer (type + message + stack); everything else is reduced to a
20
+ * message — the in-band tool-error path has already lost the original stack.
21
+ */
22
+ export function serializeMcpError(error) {
23
+ if (error instanceof Error) {
24
+ return { ...pino.stdSerializers.err(error) };
25
+ }
26
+ return { message: typeof error === 'string' ? error : String(error) };
27
+ }
28
+ /**
29
+ * One synchronous pino logger per MCP server process, written to the `io.stderr`
30
+ * sink. stderr is the only universally-correct sink: the stdio transport reserves
31
+ * stdout for JSON-RPC, and the HTTP daemon redirects stderr into `.ktx/logs/mcp.log`.
32
+ * Synchronous writes are load-bearing — a `tool.start` line must reach the fd before
33
+ * a blocking handler runs, so a runaway query still leaves its start record on disk.
34
+ * Format follows the terminal, not a flag: pretty for a TTY, plain JSON otherwise.
35
+ */
36
+ export function createMcpLogger(io, options = {}) {
37
+ const level = mcpLogLevel();
38
+ const isTTY = options.isTTY ?? process.stderr.isTTY === true;
39
+ if (isTTY) {
40
+ const sink = new Writable({
41
+ write(chunk, _encoding, callback) {
42
+ io.stderr.write(typeof chunk === 'string' ? chunk : chunk.toString('utf8'));
43
+ callback();
44
+ },
45
+ });
46
+ return pino({ level }, PinoPretty({ colorize: true, sync: true, destination: sink }));
47
+ }
48
+ return pino({ level }, io.stderr);
49
+ }
@@ -9,6 +9,7 @@ export function createKtxMcpServer(deps) {
9
9
  userContext: deps.userContext,
10
10
  projectDir: deps.projectDir,
11
11
  io: deps.io,
12
+ logger: deps.logger,
12
13
  getClientInfo: deps.getClientInfo,
13
14
  });
14
15
  }
@@ -25,6 +26,7 @@ export function createDefaultKtxMcpServer(deps) {
25
26
  contextTools: deps.contextTools,
26
27
  projectDir: deps.projectDir,
27
28
  io: deps.io,
29
+ logger: deps.logger,
28
30
  // The SDK populates the client identity after the initialize handshake, so
29
31
  // read it lazily at emit time rather than at registration (undefined here).
30
32
  getClientInfo: () => server.server.getClientVersion(),
@@ -1,5 +1,6 @@
1
1
  import type { MemoryIngestService } from '../../context/memory/memory-runs.js';
2
2
  import type { KtxCliIo } from '../../cli-runtime.js';
3
+ import type { KtxMcpLogger } from './logger.js';
3
4
  import type { KtxEntityDetailsInput, KtxEntityDetailsResponse } from '../scan/entity-details.js';
4
5
  import type { KtxDiscoverDataInput, KtxDiscoverDataResponse } from '../../context/search/discover.js';
5
6
  import type { KtxDictionarySearchInput, KtxDictionarySearchResponse } from '../../context/sl/dictionary-search.js';
@@ -24,6 +25,8 @@ interface KtxMcpProgressEvent {
24
25
  }
25
26
  export type KtxMcpProgressCallback = (event: KtxMcpProgressEvent) => void | Promise<void>;
26
27
  export interface KtxMcpToolHandlerContext {
28
+ /** Present for the HTTP StreamableHTTP transport (one per session); absent for stdio. */
29
+ sessionId?: string;
27
30
  _meta?: {
28
31
  progressToken?: string | number;
29
32
  [key: string]: unknown;
@@ -102,6 +105,7 @@ export interface KtxKnowledgeMcpPort {
102
105
  userId: string;
103
106
  query: string;
104
107
  limit: number;
108
+ connectionId?: string;
105
109
  }): Promise<KtxKnowledgeSearchResponse>;
106
110
  read(input: {
107
111
  userId: string;
@@ -163,6 +167,16 @@ export interface KtxSqlExecutionMcpPort {
163
167
  onProgress?: KtxMcpProgressCallback;
164
168
  }): Promise<KtxSqlExecutionResponse>;
165
169
  }
170
+ /** @internal */
171
+ export interface KtxDialectNotesMcpPort {
172
+ read(input: {
173
+ connectionId: string;
174
+ }): Promise<{
175
+ connectionId: string;
176
+ dialect: string;
177
+ notes: string;
178
+ }>;
179
+ }
166
180
  export interface KtxMcpContextPorts {
167
181
  connections?: KtxConnectionsMcpPort;
168
182
  knowledge?: KtxKnowledgeMcpPort;
@@ -171,6 +185,7 @@ export interface KtxMcpContextPorts {
171
185
  dictionarySearch?: KtxDictionarySearchMcpPort;
172
186
  discover?: KtxDiscoverDataMcpPort;
173
187
  sqlExecution?: KtxSqlExecutionMcpPort;
188
+ dialectNotes?: KtxDialectNotesMcpPort;
174
189
  memoryIngest?: MemoryIngestPort;
175
190
  }
176
191
  export interface KtxMcpServerDeps {
@@ -179,6 +194,8 @@ export interface KtxMcpServerDeps {
179
194
  contextTools?: KtxMcpContextPorts;
180
195
  projectDir?: string;
181
196
  io?: KtxCliIo;
197
+ /** Shared per-process logger for tool-call observability; tool-call logging is off when absent. */
198
+ logger?: KtxMcpLogger;
182
199
  /** Reads the connected client's identity once the initialize handshake completes. */
183
200
  getClientInfo?: () => KtxMcpClientInfo | undefined;
184
201
  }
@@ -131,7 +131,7 @@ export class MemoryAgentService {
131
131
  : '';
132
132
  const prompt = [
133
133
  `# Wiki Index\n\n${wikiIndex}`,
134
- hasSL ? `\n# Semantic Layer Sources\n\n${slIndex}` : '',
134
+ hasSL ? `\n# Semantic Layer Sources (connectionId: ${input.connectionId})\n\n${slIndex}` : '',
135
135
  '\n---\n',
136
136
  assistantSection,
137
137
  `\n## User Message\n\n${input.userMessage.trim()}`,
@@ -102,35 +102,51 @@ declare const scanRelationshipsSchema: z.ZodObject<{
102
102
  profileConcurrency: z.ZodDefault<z.ZodInt>;
103
103
  validationConcurrency: z.ZodDefault<z.ZodInt>;
104
104
  validationBudget: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"all">, z.ZodInt]>>;
105
+ detectionBudgetMs: z.ZodDefault<z.ZodInt>;
105
106
  }, z.core.$strict>;
106
107
  declare const connectionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
107
108
  driver: z.ZodLiteral<"postgres">;
108
109
  url: z.ZodOptional<z.ZodString>;
109
110
  enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
111
+ query_timeout_ms: z.ZodOptional<z.ZodNumber>;
110
112
  }, z.core.$loose>, z.ZodObject<{
111
113
  driver: z.ZodLiteral<"mysql">;
112
114
  url: z.ZodOptional<z.ZodString>;
113
115
  enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
116
+ query_timeout_ms: z.ZodOptional<z.ZodNumber>;
114
117
  }, z.core.$loose>, z.ZodObject<{
115
118
  driver: z.ZodLiteral<"snowflake">;
116
119
  url: z.ZodOptional<z.ZodString>;
117
120
  enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
121
+ query_timeout_ms: z.ZodOptional<z.ZodNumber>;
118
122
  }, z.core.$loose>, z.ZodObject<{
119
123
  driver: z.ZodLiteral<"bigquery">;
120
124
  url: z.ZodOptional<z.ZodString>;
121
125
  enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
126
+ query_timeout_ms: z.ZodOptional<z.ZodNumber>;
122
127
  }, z.core.$loose>, z.ZodObject<{
123
128
  driver: z.ZodLiteral<"sqlite">;
124
129
  url: z.ZodOptional<z.ZodString>;
125
130
  enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
131
+ query_timeout_ms: z.ZodOptional<z.ZodNumber>;
126
132
  }, z.core.$loose>, z.ZodObject<{
127
133
  driver: z.ZodLiteral<"clickhouse">;
128
134
  url: z.ZodOptional<z.ZodString>;
129
135
  enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
136
+ query_timeout_ms: z.ZodOptional<z.ZodNumber>;
130
137
  }, z.core.$loose>, z.ZodObject<{
131
138
  driver: z.ZodLiteral<"sqlserver">;
132
139
  url: z.ZodOptional<z.ZodString>;
133
140
  enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
141
+ query_timeout_ms: z.ZodOptional<z.ZodNumber>;
142
+ }, z.core.$loose>, z.ZodObject<{
143
+ driver: z.ZodLiteral<"mongodb">;
144
+ url: z.ZodString;
145
+ database: z.ZodOptional<z.ZodString>;
146
+ databases: z.ZodOptional<z.ZodArray<z.ZodString>>;
147
+ enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
148
+ sample_size: z.ZodOptional<z.ZodNumber>;
149
+ order_by: z.ZodOptional<z.ZodString>;
134
150
  }, z.core.$loose>, z.ZodObject<{
135
151
  driver: z.ZodLiteral<"metabase">;
136
152
  api_url: z.ZodString;
@@ -184,6 +200,11 @@ declare const connectionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
184
200
  max_pages_per_run: z.ZodOptional<z.ZodNumber>;
185
201
  max_knowledge_creates_per_run: z.ZodOptional<z.ZodNumber>;
186
202
  max_knowledge_updates_per_run: z.ZodOptional<z.ZodNumber>;
203
+ }, z.core.$loose>, z.ZodObject<{
204
+ driver: z.ZodLiteral<"gdrive">;
205
+ service_account_key_ref: z.ZodString;
206
+ folder_id: z.ZodString;
207
+ recursive: z.ZodOptional<z.ZodBoolean>;
187
208
  }, z.core.$loose>, z.ZodObject<{
188
209
  driver: z.ZodLiteral<"dbt">;
189
210
  source_dir: z.ZodOptional<z.ZodString>;
@@ -211,30 +232,45 @@ declare const ktxProjectConfigSchema: z.ZodObject<{
211
232
  driver: z.ZodLiteral<"postgres">;
212
233
  url: z.ZodOptional<z.ZodString>;
213
234
  enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
235
+ query_timeout_ms: z.ZodOptional<z.ZodNumber>;
214
236
  }, z.core.$loose>, z.ZodObject<{
215
237
  driver: z.ZodLiteral<"mysql">;
216
238
  url: z.ZodOptional<z.ZodString>;
217
239
  enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
240
+ query_timeout_ms: z.ZodOptional<z.ZodNumber>;
218
241
  }, z.core.$loose>, z.ZodObject<{
219
242
  driver: z.ZodLiteral<"snowflake">;
220
243
  url: z.ZodOptional<z.ZodString>;
221
244
  enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
245
+ query_timeout_ms: z.ZodOptional<z.ZodNumber>;
222
246
  }, z.core.$loose>, z.ZodObject<{
223
247
  driver: z.ZodLiteral<"bigquery">;
224
248
  url: z.ZodOptional<z.ZodString>;
225
249
  enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
250
+ query_timeout_ms: z.ZodOptional<z.ZodNumber>;
226
251
  }, z.core.$loose>, z.ZodObject<{
227
252
  driver: z.ZodLiteral<"sqlite">;
228
253
  url: z.ZodOptional<z.ZodString>;
229
254
  enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
255
+ query_timeout_ms: z.ZodOptional<z.ZodNumber>;
230
256
  }, z.core.$loose>, z.ZodObject<{
231
257
  driver: z.ZodLiteral<"clickhouse">;
232
258
  url: z.ZodOptional<z.ZodString>;
233
259
  enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
260
+ query_timeout_ms: z.ZodOptional<z.ZodNumber>;
234
261
  }, z.core.$loose>, z.ZodObject<{
235
262
  driver: z.ZodLiteral<"sqlserver">;
236
263
  url: z.ZodOptional<z.ZodString>;
237
264
  enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
265
+ query_timeout_ms: z.ZodOptional<z.ZodNumber>;
266
+ }, z.core.$loose>, z.ZodObject<{
267
+ driver: z.ZodLiteral<"mongodb">;
268
+ url: z.ZodString;
269
+ database: z.ZodOptional<z.ZodString>;
270
+ databases: z.ZodOptional<z.ZodArray<z.ZodString>>;
271
+ enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
272
+ sample_size: z.ZodOptional<z.ZodNumber>;
273
+ order_by: z.ZodOptional<z.ZodString>;
238
274
  }, z.core.$loose>, z.ZodObject<{
239
275
  driver: z.ZodLiteral<"metabase">;
240
276
  api_url: z.ZodString;
@@ -288,6 +324,11 @@ declare const ktxProjectConfigSchema: z.ZodObject<{
288
324
  max_pages_per_run: z.ZodOptional<z.ZodNumber>;
289
325
  max_knowledge_creates_per_run: z.ZodOptional<z.ZodNumber>;
290
326
  max_knowledge_updates_per_run: z.ZodOptional<z.ZodNumber>;
327
+ }, z.core.$loose>, z.ZodObject<{
328
+ driver: z.ZodLiteral<"gdrive">;
329
+ service_account_key_ref: z.ZodString;
330
+ folder_id: z.ZodString;
331
+ recursive: z.ZodOptional<z.ZodBoolean>;
291
332
  }, z.core.$loose>, z.ZodObject<{
292
333
  driver: z.ZodLiteral<"dbt">;
293
334
  source_dir: z.ZodOptional<z.ZodString>;
@@ -455,6 +496,7 @@ declare const ktxProjectConfigSchema: z.ZodObject<{
455
496
  profileConcurrency: z.ZodDefault<z.ZodInt>;
456
497
  validationConcurrency: z.ZodDefault<z.ZodInt>;
457
498
  validationBudget: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"all">, z.ZodInt]>>;
499
+ detectionBudgetMs: z.ZodDefault<z.ZodInt>;
458
500
  }, z.core.$strict>>;
459
501
  }, z.core.$strict>>;
460
502
  }, z.core.$strict>;
@@ -187,6 +187,11 @@ const scanRelationshipsSchema = z
187
187
  .union([z.literal('all'), z.int().nonnegative()])
188
188
  .optional()
189
189
  .describe('Cap on validation queries per scan run. Use "all" for unlimited, an integer for a hard cap, or omit for the runtime default.'),
190
+ detectionBudgetMs: z
191
+ .int()
192
+ .positive()
193
+ .default(600_000)
194
+ .describe('Wall-clock budget (ms) for the whole relationship-detection stage. Checked at table-profile, LLM-proposal, candidate-validation, and composite-probe boundaries; above the per-query deadline. On exhaustion the stage stops scheduling new work and returns the relationships found so far, marked partial. Raise it to trigger a fresher, fuller run.'),
190
195
  })
191
196
  .describe('Schema-scan relationship discovery and validation tunables.');
192
197
  const scanSchema = z
@@ -3,30 +3,45 @@ export declare const connectionConfigSchema: z.ZodDiscriminatedUnion<[z.ZodObjec
3
3
  driver: z.ZodLiteral<"postgres">;
4
4
  url: z.ZodOptional<z.ZodString>;
5
5
  enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
6
+ query_timeout_ms: z.ZodOptional<z.ZodNumber>;
6
7
  }, z.core.$loose>, z.ZodObject<{
7
8
  driver: z.ZodLiteral<"mysql">;
8
9
  url: z.ZodOptional<z.ZodString>;
9
10
  enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
11
+ query_timeout_ms: z.ZodOptional<z.ZodNumber>;
10
12
  }, z.core.$loose>, z.ZodObject<{
11
13
  driver: z.ZodLiteral<"snowflake">;
12
14
  url: z.ZodOptional<z.ZodString>;
13
15
  enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
16
+ query_timeout_ms: z.ZodOptional<z.ZodNumber>;
14
17
  }, z.core.$loose>, z.ZodObject<{
15
18
  driver: z.ZodLiteral<"bigquery">;
16
19
  url: z.ZodOptional<z.ZodString>;
17
20
  enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
21
+ query_timeout_ms: z.ZodOptional<z.ZodNumber>;
18
22
  }, z.core.$loose>, z.ZodObject<{
19
23
  driver: z.ZodLiteral<"sqlite">;
20
24
  url: z.ZodOptional<z.ZodString>;
21
25
  enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
26
+ query_timeout_ms: z.ZodOptional<z.ZodNumber>;
22
27
  }, z.core.$loose>, z.ZodObject<{
23
28
  driver: z.ZodLiteral<"clickhouse">;
24
29
  url: z.ZodOptional<z.ZodString>;
25
30
  enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
31
+ query_timeout_ms: z.ZodOptional<z.ZodNumber>;
26
32
  }, z.core.$loose>, z.ZodObject<{
27
33
  driver: z.ZodLiteral<"sqlserver">;
28
34
  url: z.ZodOptional<z.ZodString>;
29
35
  enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
36
+ query_timeout_ms: z.ZodOptional<z.ZodNumber>;
37
+ }, z.core.$loose>, z.ZodObject<{
38
+ driver: z.ZodLiteral<"mongodb">;
39
+ url: z.ZodString;
40
+ database: z.ZodOptional<z.ZodString>;
41
+ databases: z.ZodOptional<z.ZodArray<z.ZodString>>;
42
+ enabled_tables: z.ZodOptional<z.ZodArray<z.ZodString>>;
43
+ sample_size: z.ZodOptional<z.ZodNumber>;
44
+ order_by: z.ZodOptional<z.ZodString>;
30
45
  }, z.core.$loose>, z.ZodObject<{
31
46
  driver: z.ZodLiteral<"metabase">;
32
47
  api_url: z.ZodString;
@@ -80,6 +95,11 @@ export declare const connectionConfigSchema: z.ZodDiscriminatedUnion<[z.ZodObjec
80
95
  max_pages_per_run: z.ZodOptional<z.ZodNumber>;
81
96
  max_knowledge_creates_per_run: z.ZodOptional<z.ZodNumber>;
82
97
  max_knowledge_updates_per_run: z.ZodOptional<z.ZodNumber>;
98
+ }, z.core.$loose>, z.ZodObject<{
99
+ driver: z.ZodLiteral<"gdrive">;
100
+ service_account_key_ref: z.ZodString;
101
+ folder_id: z.ZodString;
102
+ recursive: z.ZodOptional<z.ZodBoolean>;
83
103
  }, z.core.$loose>, z.ZodObject<{
84
104
  driver: z.ZodLiteral<"dbt">;
85
105
  source_dir: z.ZodOptional<z.ZodString>;
@@ -21,7 +21,13 @@ function warehouseConnectionSchema(driver) {
21
21
  enabled_tables: z
22
22
  .array(z.string().min(1))
23
23
  .optional()
24
- .describe('Optional allowlist of fully-qualified table names ("schema.table") to ingest. When set, live-database ingest discards any table whose schema-qualified name is not in this list. Useful for smoke-testing ingest on a single table.'),
24
+ .describe('Optional allowlist of object names to ingest. Accepted forms: "catalog.db.name", "db.name" (schema-qualified), or bare "name". When set, live-database ingest restricts the scan to the listed objects and fails with a clear error if none match. For SQLite, "main.<name>" and the bare "<name>" are equivalent (SQLite exposes a single "main" schema). Useful for smoke-testing ingest on a single table.'),
25
+ query_timeout_ms: z
26
+ .number()
27
+ .int()
28
+ .positive()
29
+ .optional()
30
+ .describe('Maximum execution time for a single read-only query, in milliseconds (default 30000). Enforced as a server-side statement timeout for remote engines and by SIGKILL-ing a forked query subprocess for in-process SQLite. A query exceeding it is cancelled and returns a "query exceeded Ns" error so the agent can revise.'),
25
31
  })
26
32
  .describe(`${driver} warehouse connection. Additional driver-tunable fields (e.g. context.queryHistory) are accepted and passed through.`);
27
33
  }
@@ -34,6 +40,36 @@ const warehouseConnectionSchemas = [
34
40
  warehouseConnectionSchema('clickhouse'),
35
41
  warehouseConnectionSchema('sqlserver'),
36
42
  ];
43
+ const mongodbConnectionSchema = z
44
+ .looseObject({
45
+ driver: z.literal('mongodb'),
46
+ url: z
47
+ .string()
48
+ .min(1)
49
+ .describe('MongoDB connection string (mongodb:// or mongodb+srv://, including TLS/Atlas); may contain a reference like env:MONGO_URL.'),
50
+ database: z.string().min(1).optional().describe('Single database to introspect when not using databases or a URL path.'),
51
+ databases: z
52
+ .array(z.string().min(1))
53
+ .optional()
54
+ .describe('Databases whose collections ktx introspects as tables. Falls back to the URL path database.'),
55
+ enabled_tables: z
56
+ .array(z.string().min(1))
57
+ .optional()
58
+ .describe('Optional allowlist of "database.collection" names to introspect.'),
59
+ sample_size: z
60
+ .number()
61
+ .int()
62
+ .min(1)
63
+ .optional()
64
+ .describe('How many recent documents to sample per collection when inferring the schema (default 1000).'),
65
+ order_by: z
66
+ .string()
67
+ .min(1)
68
+ .optional()
69
+ .describe('Field to sort by descending when sampling. Defaults to _id; set this when _id is not an ObjectId. ' +
70
+ 'Should be indexed — an unindexed sort hits MongoDB\'s in-memory sort limit on large collections.'),
71
+ })
72
+ .describe('MongoDB primary-source connection. Schema is inferred by sampling the most recent documents.');
37
73
  const positiveIntKeyMessage = (field) => `${field} keys must be positive-integer strings (e.g. "1", "42")`;
38
74
  const positiveIntKeyRegex = /^[1-9]\d*$/;
39
75
  const metabaseMappingsStrictSchema = metabaseMappingsSchema.superRefine((value, ctx) => {
@@ -145,6 +181,17 @@ const notionConnectionSchema = z
145
181
  .describe('Maximum existing wiki pages updated per run.'),
146
182
  })
147
183
  .describe('Notion context-source connection.');
184
+ const gdriveConnectionSchema = z
185
+ .looseObject({
186
+ driver: z.literal('gdrive'),
187
+ service_account_key_ref: z
188
+ .string()
189
+ .min(1)
190
+ .describe('Reference to a Google service-account JSON key file. Must use file:/absolute/path/to/key.json.'),
191
+ folder_id: z.string().min(1).describe('Google Drive folder ID to ingest.'),
192
+ recursive: z.boolean().optional().describe('When true, recursively traverse subfolders beneath folder_id.'),
193
+ })
194
+ .describe('Google Drive Google Docs context-source connection.');
148
195
  const dbtConnectionSchema = z
149
196
  .looseObject({
150
197
  driver: z.literal('dbt'),
@@ -173,10 +220,12 @@ const metricflowConnectionSchema = z
173
220
  .describe('MetricFlow / SL context-source connection.');
174
221
  export const connectionConfigSchema = z.discriminatedUnion('driver', [
175
222
  ...warehouseConnectionSchemas,
223
+ mongodbConnectionSchema,
176
224
  metabaseConnectionSchema,
177
225
  lookerConnectionSchema,
178
226
  lookmlConnectionSchema,
179
227
  notionConnectionSchema,
228
+ gdriveConnectionSchema,
180
229
  dbtConnectionSchema,
181
230
  metricflowConnectionSchema,
182
231
  ]);
@@ -7,7 +7,7 @@ import { LocalGitFileStore } from './local-git-file-store.js';
7
7
  const TRACKED_SCAFFOLD_FILES = [
8
8
  {
9
9
  path: '.ktx/.gitignore',
10
- content: 'cache/\ndb.sqlite\ndb.sqlite-*\ningest-transcripts/\nsecrets/\nsetup/\nagents/\n',
10
+ content: 'cache/\ndb.sqlite\ndb.sqlite-*\ningest-transcripts/\nlogs/\nsecrets/\nsetup/\nagents/\n',
11
11
  },
12
12
  { path: '.ktx/prompts/.gitkeep', content: '' },
13
13
  { path: '.ktx/skills/.gitkeep', content: '' },
@@ -15,6 +15,7 @@ const SETUP_GITIGNORE_ENTRIES = [
15
15
  'db.sqlite',
16
16
  'db.sqlite-*',
17
17
  'ingest-transcripts/',
18
+ 'logs/',
18
19
  'secrets/',
19
20
  'setup/',
20
21
  'agents/',
@@ -1,3 +1,4 @@
1
+ import type { ChildProcess } from 'node:child_process';
1
2
  import type { KtxLlmRuntimePort } from '../../context/llm/runtime-port.js';
2
3
  import type { KtxColumnSampleInput, KtxColumnSampleResult, KtxScanContext, KtxScanLoggerPort, KtxScanWarning, KtxTableRef, KtxTableSampleInput, KtxTableSampleResult } from './types.js';
3
4
  interface KtxDescriptionTableColumn {
@@ -113,6 +114,8 @@ export interface KtxDescriptionGeneratorOptions {
113
114
  logger?: KtxScanLoggerPort;
114
115
  onWarning?: (warning: KtxScanWarning) => void;
115
116
  settings: KtxDescriptionGenerationSettings;
117
+ /** @internal Test seam: spawn the kill-boundary child for subprocess backends. */
118
+ spawnSubprocessGenerateChild?: () => ChildProcess;
116
119
  }
117
120
  export interface KtxDescriptionPrompt {
118
121
  system: string;
@@ -136,6 +139,7 @@ export declare class KtxDescriptionGenerator {
136
139
  private readonly logger?;
137
140
  private readonly onWarning?;
138
141
  private readonly settings;
142
+ private readonly spawnSubprocessGenerateChild?;
139
143
  constructor(options: KtxDescriptionGeneratorOptions);
140
144
  generateColumnDescriptions(input: KtxGenerateColumnDescriptionsInput): Promise<KtxColumnAnalysisResult>;
141
145
  generateTableDescription(input: KtxGenerateTableDescriptionInput): Promise<string | null>;