@kaelio/ktx 0.13.1 → 0.15.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 (261) hide show
  1. package/assets/python/{kaelio_ktx-0.13.1-py3-none-any.whl → kaelio_ktx-0.15.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 +15 -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 +20 -3
  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/ingest/adapters/gdrive/chunk.d.ts +3 -0
  60. package/dist/context/ingest/adapters/gdrive/chunk.js +74 -0
  61. package/dist/context/ingest/adapters/gdrive/detect.d.ts +1 -0
  62. package/dist/context/ingest/adapters/gdrive/detect.js +20 -0
  63. package/dist/context/ingest/adapters/gdrive/fetch.d.ts +6 -0
  64. package/dist/context/ingest/adapters/gdrive/fetch.js +95 -0
  65. package/dist/context/ingest/adapters/gdrive/gdrive-client.d.ts +30 -0
  66. package/dist/context/ingest/adapters/gdrive/gdrive-client.js +132 -0
  67. package/dist/context/ingest/adapters/gdrive/gdrive.adapter.d.ts +11 -0
  68. package/dist/context/ingest/adapters/gdrive/gdrive.adapter.js +27 -0
  69. package/dist/context/ingest/adapters/gdrive/normalize.d.ts +2 -0
  70. package/dist/context/ingest/adapters/gdrive/normalize.js +256 -0
  71. package/dist/context/ingest/adapters/gdrive/types.d.ts +153 -0
  72. package/dist/context/ingest/adapters/gdrive/types.js +36 -0
  73. package/dist/context/ingest/adapters/live-database/daemon-introspection.js +24 -0
  74. package/dist/context/ingest/adapters/live-database/fetch-report.d.ts +8 -0
  75. package/dist/context/ingest/adapters/live-database/fetch-report.js +37 -0
  76. package/dist/context/ingest/adapters/live-database/live-database.adapter.d.ts +2 -1
  77. package/dist/context/ingest/adapters/live-database/live-database.adapter.js +9 -2
  78. package/dist/context/ingest/adapters/live-database/manifest.d.ts +2 -0
  79. package/dist/context/ingest/adapters/live-database/manifest.js +8 -4
  80. package/dist/context/ingest/adapters/live-database/scan-outcome.d.ts +17 -0
  81. package/dist/context/ingest/adapters/live-database/scan-outcome.js +40 -0
  82. package/dist/context/ingest/adapters/live-database/stage.js +5 -5
  83. package/dist/context/ingest/adapters/metabase/types.d.ts +1 -1
  84. package/dist/context/ingest/adapters/metabase/types.js +1 -1
  85. package/dist/context/ingest/adapters/sigma/chunk.d.ts +6 -0
  86. package/dist/context/ingest/adapters/sigma/chunk.js +119 -0
  87. package/dist/context/ingest/adapters/sigma/client-port.d.ts +45 -0
  88. package/dist/context/ingest/adapters/sigma/client-port.js +1 -0
  89. package/dist/context/ingest/adapters/sigma/client.d.ts +33 -0
  90. package/dist/context/ingest/adapters/sigma/client.js +176 -0
  91. package/dist/context/ingest/adapters/sigma/detect.d.ts +1 -0
  92. package/dist/context/ingest/adapters/sigma/detect.js +23 -0
  93. package/dist/context/ingest/adapters/sigma/fetch.d.ts +14 -0
  94. package/dist/context/ingest/adapters/sigma/fetch.js +191 -0
  95. package/dist/context/ingest/adapters/sigma/local-sigma.adapter.d.ts +17 -0
  96. package/dist/context/ingest/adapters/sigma/local-sigma.adapter.js +41 -0
  97. package/dist/context/ingest/adapters/sigma/project.d.ts +8 -0
  98. package/dist/context/ingest/adapters/sigma/project.js +186 -0
  99. package/dist/context/ingest/adapters/sigma/sigma.adapter.d.ts +18 -0
  100. package/dist/context/ingest/adapters/sigma/sigma.adapter.js +43 -0
  101. package/dist/context/ingest/adapters/sigma/types.d.ts +80 -0
  102. package/dist/context/ingest/adapters/sigma/types.js +82 -0
  103. package/dist/context/ingest/artifact-gates.d.ts +32 -1
  104. package/dist/context/ingest/artifact-gates.js +85 -18
  105. package/dist/context/ingest/final-gate-prune.d.ts +35 -0
  106. package/dist/context/ingest/final-gate-prune.js +229 -0
  107. package/dist/context/ingest/ingest-bundle.runner.d.ts +3 -0
  108. package/dist/context/ingest/ingest-bundle.runner.js +459 -240
  109. package/dist/context/ingest/isolated-diff/patch-integrator.d.ts +0 -11
  110. package/dist/context/ingest/isolated-diff/patch-integrator.js +0 -44
  111. package/dist/context/ingest/isolated-diff/work-unit-executor.d.ts +1 -0
  112. package/dist/context/ingest/isolated-diff/work-unit-executor.js +13 -4
  113. package/dist/context/ingest/local-adapters.d.ts +2 -1
  114. package/dist/context/ingest/local-adapters.js +28 -0
  115. package/dist/context/ingest/local-bundle-runtime.js +7 -2
  116. package/dist/context/ingest/local-ingest.js +1 -1
  117. package/dist/context/ingest/local-stage-ingest.d.ts +3 -1
  118. package/dist/context/ingest/local-stage-ingest.js +3 -1
  119. package/dist/context/ingest/ports.d.ts +3 -0
  120. package/dist/context/ingest/report-snapshot.js +13 -3
  121. package/dist/context/ingest/reports.d.ts +3 -3
  122. package/dist/context/ingest/reports.js +3 -1
  123. package/dist/context/ingest/stages/build-wu-context.d.ts +1 -0
  124. package/dist/context/ingest/stages/build-wu-context.js +2 -1
  125. package/dist/context/ingest/stages/stage-3-work-units.d.ts +2 -1
  126. package/dist/context/ingest/stages/stage-3-work-units.js +4 -10
  127. package/dist/context/ingest/stages/validate-wu-sources.d.ts +12 -0
  128. package/dist/context/ingest/stages/validate-wu-sources.js +23 -8
  129. package/dist/context/ingest/tools/read-raw-file.tool.js +10 -5
  130. package/dist/context/ingest/tools/read-raw-span.tool.js +10 -5
  131. package/dist/context/ingest/tools/warehouse-verification/discover-data.tool.js +1 -1
  132. package/dist/context/ingest/tools/warehouse-verification/entity-details.tool.js +1 -1
  133. package/dist/context/ingest/tools/warehouse-verification/sql-execution.tool.js +1 -1
  134. package/dist/context/ingest/types.d.ts +3 -0
  135. package/dist/context/ingest/wiki-body-refs.d.ts +28 -0
  136. package/dist/context/ingest/wiki-body-refs.js +37 -8
  137. package/dist/context/ingest/wiki-sl-ref-repair.d.ts +1 -0
  138. package/dist/context/ingest/wiki-sl-ref-repair.js +4 -0
  139. package/dist/context/ingest/work-unit-cache.d.ts +67 -0
  140. package/dist/context/ingest/work-unit-cache.js +230 -0
  141. package/dist/context/llm/ai-sdk-runtime.d.ts +1 -0
  142. package/dist/context/llm/ai-sdk-runtime.js +5 -0
  143. package/dist/context/llm/claude-code-runtime.d.ts +4 -1
  144. package/dist/context/llm/claude-code-runtime.js +38 -8
  145. package/dist/context/llm/codex-runtime.d.ts +4 -1
  146. package/dist/context/llm/codex-runtime.js +48 -35
  147. package/dist/context/llm/runtime-port.d.ts +26 -0
  148. package/dist/context/llm/subprocess-generate-object-child.d.ts +1 -0
  149. package/dist/context/llm/subprocess-generate-object-child.js +34 -0
  150. package/dist/context/llm/subprocess-generate-object.d.ts +42 -0
  151. package/dist/context/llm/subprocess-generate-object.js +122 -0
  152. package/dist/context/mcp/context-tools.d.ts +2 -0
  153. package/dist/context/mcp/context-tools.js +111 -17
  154. package/dist/context/mcp/local-project-ports.d.ts +7 -0
  155. package/dist/context/mcp/local-project-ports.js +29 -0
  156. package/dist/context/mcp/logger.d.ts +24 -0
  157. package/dist/context/mcp/logger.js +49 -0
  158. package/dist/context/mcp/server.js +2 -0
  159. package/dist/context/mcp/types.d.ts +17 -0
  160. package/dist/context/memory/memory-agent.service.js +1 -1
  161. package/dist/context/project/config.d.ts +72 -0
  162. package/dist/context/project/config.js +5 -0
  163. package/dist/context/project/driver-schemas.d.ts +35 -0
  164. package/dist/context/project/driver-schemas.js +89 -1
  165. package/dist/context/project/project.js +1 -1
  166. package/dist/context/project/setup-config.js +1 -0
  167. package/dist/context/scan/description-generation.d.ts +4 -0
  168. package/dist/context/scan/description-generation.js +100 -13
  169. package/dist/context/scan/enabled-tables.d.ts +5 -0
  170. package/dist/context/scan/enabled-tables.js +13 -1
  171. package/dist/context/scan/enrichment-state.d.ts +50 -7
  172. package/dist/context/scan/enrichment-state.js +30 -13
  173. package/dist/context/scan/local-enrichment-artifacts.d.ts +41 -0
  174. package/dist/context/scan/local-enrichment-artifacts.js +155 -32
  175. package/dist/context/scan/local-enrichment.d.ts +39 -4
  176. package/dist/context/scan/local-enrichment.js +345 -92
  177. package/dist/context/scan/local-scan.d.ts +4 -1
  178. package/dist/context/scan/local-scan.js +54 -13
  179. package/dist/context/scan/local-structural-artifacts.d.ts +3 -1
  180. package/dist/context/scan/local-structural-artifacts.js +5 -0
  181. package/dist/context/scan/object-introspection.d.ts +21 -0
  182. package/dist/context/scan/object-introspection.js +35 -0
  183. package/dist/context/scan/relationship-benchmarks.js +5 -3
  184. package/dist/context/scan/relationship-composite-candidates.d.ts +6 -3
  185. package/dist/context/scan/relationship-composite-candidates.js +13 -1
  186. package/dist/context/scan/relationship-detection-budget.d.ts +35 -0
  187. package/dist/context/scan/relationship-detection-budget.js +53 -0
  188. package/dist/context/scan/relationship-diagnostics.d.ts +5 -0
  189. package/dist/context/scan/relationship-diagnostics.js +2 -0
  190. package/dist/context/scan/relationship-discovery.d.ts +9 -3
  191. package/dist/context/scan/relationship-discovery.js +27 -4
  192. package/dist/context/scan/relationship-llm-proposal.js +36 -27
  193. package/dist/context/scan/relationship-profiling.d.ts +7 -3
  194. package/dist/context/scan/relationship-profiling.js +53 -41
  195. package/dist/context/scan/relationship-validation.d.ts +6 -4
  196. package/dist/context/scan/relationship-validation.js +46 -32
  197. package/dist/context/scan/sqlite-local-enrichment-state-store.d.ts +8 -1
  198. package/dist/context/scan/sqlite-local-enrichment-state-store.js +71 -159
  199. package/dist/context/scan/types.d.ts +5 -3
  200. package/dist/context/scan/types.js +2 -0
  201. package/dist/context/sl/local-query.js +5 -0
  202. package/dist/context/sl/pglite-sl-search-prototype.js +1 -1
  203. package/dist/context/sl/semantic-layer.service.js +1 -1
  204. package/dist/context/sl/source-files.d.ts +5 -0
  205. package/dist/context/sl/source-files.js +17 -11
  206. package/dist/context/sl/tools/connection-id-schema.js +1 -1
  207. package/dist/context/sql-analysis/dialect-notes.d.ts +9 -0
  208. package/dist/context/sql-analysis/dialect-notes.js +40 -0
  209. package/dist/context/sql-analysis/dialects/bigquery.md +13 -0
  210. package/dist/context/sql-analysis/dialects/clickhouse.md +9 -0
  211. package/dist/context/sql-analysis/dialects/mysql.md +9 -0
  212. package/dist/context/sql-analysis/dialects/postgres.md +10 -0
  213. package/dist/context/sql-analysis/dialects/snowflake.md +10 -0
  214. package/dist/context/sql-analysis/dialects/sqlite.md +11 -0
  215. package/dist/context/sql-analysis/dialects/tsql.md +10 -0
  216. package/dist/context/wiki/keys.js +1 -1
  217. package/dist/context/wiki/knowledge-wiki.service.d.ts +4 -4
  218. package/dist/context/wiki/knowledge-wiki.service.js +2 -1
  219. package/dist/context/wiki/local-knowledge.d.ts +13 -0
  220. package/dist/context/wiki/local-knowledge.js +50 -6
  221. package/dist/context/wiki/sqlite-knowledge-index.d.ts +2 -0
  222. package/dist/context/wiki/sqlite-knowledge-index.js +21 -5
  223. package/dist/context/wiki/tools/wiki-write.tool.d.ts +2 -0
  224. package/dist/context/wiki/tools/wiki-write.tool.js +27 -0
  225. package/dist/context/wiki/types.d.ts +6 -0
  226. package/dist/context-build-view.d.ts +3 -0
  227. package/dist/context-build-view.js +1 -0
  228. package/dist/knowledge.d.ts +2 -0
  229. package/dist/knowledge.js +12 -1
  230. package/dist/local-adapters.js +11 -0
  231. package/dist/mcp-http-server.js +15 -1
  232. package/dist/mcp-server-factory.d.ts +2 -0
  233. package/dist/mcp-server-factory.js +15 -1
  234. package/dist/mcp-stdio-server.js +10 -2
  235. package/dist/notion-page-picker.js +1 -1
  236. package/dist/prompts/memory_agent_external_ingest.md +2 -0
  237. package/dist/public-ingest.d.ts +3 -1
  238. package/dist/public-ingest.js +4 -0
  239. package/dist/scan.d.ts +3 -1
  240. package/dist/scan.js +7 -0
  241. package/dist/setup-databases.d.ts +1 -1
  242. package/dist/setup-databases.js +43 -1
  243. package/dist/setup-sources.d.ts +6 -1
  244. package/dist/setup-sources.js +208 -48
  245. package/dist/setup.d.ts +3 -0
  246. package/dist/setup.js +6 -1
  247. package/dist/skills/analytics/SKILL.md +200 -2
  248. package/dist/skills/gdrive_synthesize/SKILL.md +97 -0
  249. package/dist/skills/sigma_ingest/SKILL.md +189 -0
  250. package/dist/skills/wiki_capture/SKILL.md +24 -0
  251. package/dist/sql.js +4 -0
  252. package/dist/status-project.d.ts +4 -0
  253. package/dist/status-project.js +54 -2
  254. package/dist/telemetry/events.d.ts +2 -2
  255. package/dist/text-ingest.d.ts +4 -0
  256. package/dist/text-ingest.js +58 -29
  257. package/dist/verbatim-ingest.d.ts +46 -0
  258. package/dist/verbatim-ingest.js +193 -0
  259. package/package.json +5 -1
  260. package/dist/context/ingest/final-gate-repair.d.ts +0 -28
  261. package/dist/context/ingest/final-gate-repair.js +0 -91
@@ -27,6 +27,10 @@ const wikiWriteInputSchema = z.object({
27
27
  tags: z.array(z.string()).optional(),
28
28
  refs: z.array(z.string()).optional(),
29
29
  sl_refs: z.array(z.string()).optional(),
30
+ connections: z
31
+ .union([z.string(), z.array(z.string())])
32
+ .optional()
33
+ .describe('Connection ids this page applies to. Set [connectionId] on database-specific pages (with a connection-distinctive key); omit or leave empty for org-wide content. REPLACE semantics like tags.'),
30
34
  source: z.string().optional(),
31
35
  intent: z.string().optional(),
32
36
  tables: z.array(z.string()).optional(),
@@ -124,6 +128,28 @@ Keys must be flat file names, not directory paths. Use tags/source frontmatter f
124
128
  const resolvedTags = input.tags === undefined ? existingFm?.tags : input.tags;
125
129
  const resolvedRefs = input.refs === undefined ? existingFm?.refs : input.refs;
126
130
  const resolvedSlRefs = input.sl_refs === undefined ? existingFm?.sl_refs : input.sl_refs;
131
+ const incomingConnections = input.connections === undefined
132
+ ? undefined
133
+ : typeof input.connections === 'string'
134
+ ? [input.connections]
135
+ : input.connections;
136
+ const resolvedConnections = incomingConnections === undefined ? existingFm?.connections : incomingConnections;
137
+ // Data-loss guard: page keys are a flat global namespace, so a write whose
138
+ // incoming connection scope is disjoint from an existing same-key page would
139
+ // silently overwrite a different connection's page. Surface it instead.
140
+ const existingConnections = existingFm?.connections ?? [];
141
+ if (existing &&
142
+ incomingConnections !== undefined &&
143
+ incomingConnections.length > 0 &&
144
+ existingConnections.length > 0 &&
145
+ !incomingConnections.some((id) => existingConnections.includes(id))) {
146
+ return {
147
+ markdown: `Error: page "${input.key}" already exists scoped to a different connection ` +
148
+ `(connections: ${existingConnections.join(', ')}); writing it for ${incomingConnections.join(', ')} ` +
149
+ `would overwrite that page. Use a connection-distinctive key (e.g. "${input.key}_${incomingConnections[0]}").`,
150
+ structured: { success: false, key: input.key },
151
+ };
152
+ }
127
153
  let finalContent;
128
154
  const finalFm = {
129
155
  summary: input.summary,
@@ -132,6 +158,7 @@ Keys must be flat file names, not directory paths. Use tags/source frontmatter f
132
158
  tags: resolvedTags,
133
159
  refs: resolvedRefs,
134
160
  sl_refs: resolvedSlRefs,
161
+ connections: resolvedConnections,
135
162
  source: input.source === undefined ? existingFm?.source : input.source,
136
163
  intent: input.intent === undefined ? existingFm?.intent : input.intent,
137
164
  tables: input.tables === undefined ? existingFm?.tables : input.tables,
@@ -14,6 +14,12 @@ export interface WikiFrontmatter {
14
14
  tags?: string[];
15
15
  refs?: string[];
16
16
  sl_refs?: string[];
17
+ /**
18
+ * Connection ids this page applies to. Absent or empty ⇒ unscoped: the page
19
+ * applies to all connections. Additive metadata, orthogonal to GLOBAL/USER
20
+ * scope; it does not namespace page keys.
21
+ */
22
+ connections?: string[];
17
23
  usage_mode: 'always' | 'auto' | 'never';
18
24
  sort_order?: number;
19
25
  source?: string;
@@ -48,6 +48,9 @@ export interface ContextBuildArgs {
48
48
  scanMode?: Extract<KtxPublicIngestArgs, {
49
49
  command: 'run';
50
50
  }>['scanMode'];
51
+ stages?: Extract<KtxPublicIngestArgs, {
52
+ command: 'run';
53
+ }>['stages'];
51
54
  detectRelationships?: boolean;
52
55
  cliVersion?: string;
53
56
  runtimeInstallPolicy?: KtxManagedPythonInstallPolicy;
@@ -750,6 +750,7 @@ export async function runContextBuild(project, args, io, deps = {}) {
750
750
  ...(args.queryHistory ? { queryHistory: args.queryHistory } : {}),
751
751
  ...(args.queryHistoryWindowDays !== undefined ? { queryHistoryWindowDays: args.queryHistoryWindowDays } : {}),
752
752
  ...(args.scanMode ? { scanMode: args.scanMode } : {}),
753
+ ...(args.stages ? { stages: args.stages } : {}),
753
754
  ...(args.detectRelationships !== undefined ? { detectRelationships: args.detectRelationships } : {}),
754
755
  ...(args.cliVersion ? { cliVersion: args.cliVersion } : {}),
755
756
  ...(args.runtimeInstallPolicy ? { runtimeInstallPolicy: args.runtimeInstallPolicy } : {}),
@@ -5,6 +5,7 @@ export type KtxKnowledgeArgs = {
5
5
  command: 'list';
6
6
  projectDir: string;
7
7
  userId: string;
8
+ connectionId?: string;
8
9
  output?: string;
9
10
  json?: boolean;
10
11
  cliVersion: string;
@@ -13,6 +14,7 @@ export type KtxKnowledgeArgs = {
13
14
  projectDir: string;
14
15
  query: string;
15
16
  userId: string;
17
+ connectionId?: string;
16
18
  output?: string;
17
19
  json?: boolean;
18
20
  limit?: number;
package/dist/knowledge.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { KtxIngestEmbeddingPortAdapter } from './context/llm/embedding-port.js';
2
2
  import { loadKtxProject } from './context/project/project.js';
3
+ import { assertConfiguredConnectionId } from './context/connections/configured-connections.js';
3
4
  import { listLocalKnowledgePages, readLocalKnowledgePage, searchLocalKnowledgePages as defaultSearchLocalKnowledgePages, } from './context/wiki/local-knowledge.js';
4
5
  import { resolveProjectEmbeddingProvider, } from './embedding-resolution.js';
5
6
  import { resolveOutputMode } from './io/mode.js';
@@ -57,7 +58,13 @@ export async function runKtxKnowledge(args, io = process, deps = {}) {
57
58
  try {
58
59
  const project = await loadKtxProject({ projectDir: args.projectDir });
59
60
  if (args.command === 'list') {
60
- const pages = await listLocalKnowledgePages(project, { userId: args.userId });
61
+ const connectionId = args.connectionId === undefined
62
+ ? undefined
63
+ : assertConfiguredConnectionId(project.config.connections, args.connectionId);
64
+ const pages = await listLocalKnowledgePages(project, {
65
+ userId: args.userId,
66
+ ...(connectionId !== undefined ? { connectionId } : {}),
67
+ });
61
68
  const mode = resolveOutputMode({ explicit: args.output, json: args.json, io });
62
69
  printList({
63
70
  rows: pages,
@@ -82,6 +89,9 @@ export async function runKtxKnowledge(args, io = process, deps = {}) {
82
89
  return 0;
83
90
  }
84
91
  if (args.command === 'search') {
92
+ const connectionId = args.connectionId === undefined
93
+ ? undefined
94
+ : assertConfiguredConnectionId(project.config.connections, args.connectionId);
85
95
  const embeddingService = await wikiSearchEmbeddingService(project, deps, { cliVersion: args.cliVersion }, io);
86
96
  const search = deps.searchLocalKnowledgePages ?? defaultSearchLocalKnowledgePages;
87
97
  const results = await search(project, {
@@ -89,6 +99,7 @@ export async function runKtxKnowledge(args, io = process, deps = {}) {
89
99
  userId: args.userId,
90
100
  embeddingService,
91
101
  limit: args.limit,
102
+ ...(connectionId !== undefined ? { connectionId } : {}),
92
103
  });
93
104
  await emitTelemetryEvent({
94
105
  name: 'wiki_query_completed',
@@ -92,6 +92,17 @@ function createKtxCliLiveDatabaseIntrospection(project, options = {}) {
92
92
  return {
93
93
  async extractSchema(connectionId, options) {
94
94
  const connection = project.config.connections[connectionId];
95
+ if (String(connection?.driver ?? '').toLowerCase() === 'mongodb') {
96
+ const { createMongoDbLiveDatabaseIntrospection } = await import('./connectors/mongodb/live-database-introspection.js');
97
+ const { isKtxMongoDbConnectionConfig } = await import('./connectors/mongodb/connector.js');
98
+ if (!isKtxMongoDbConnectionConfig(connection)) {
99
+ return daemon.extractSchema(connectionId, options);
100
+ }
101
+ const mongodb = createMongoDbLiveDatabaseIntrospection({
102
+ connections: project.config.connections,
103
+ });
104
+ return mongodb.extractSchema(connectionId, options);
105
+ }
95
106
  if (isKtxPostgresConnectionConfig(connection)) {
96
107
  return postgres.extractSchema(connectionId, options);
97
108
  }
@@ -4,6 +4,7 @@ import { loadKtxProject } from './context/project/project.js';
4
4
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
5
5
  import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
6
6
  import { getKtxCliPackageInfo } from './cli-runtime.js';
7
+ import { createMcpLogger, serializeMcpError } from './context/mcp/logger.js';
7
8
  import { createKtxMcpServerFactory } from './mcp-server-factory.js';
8
9
  const DEFAULT_ALLOWED_HOSTS = ['localhost', '127.0.0.1', '::1'];
9
10
  function isLoopbackHost(host) {
@@ -121,12 +122,16 @@ export async function runKtxMcpHttpServer(options) {
121
122
  const project = options.createMcpServer === undefined
122
123
  ? await (options.loadProject ?? loadKtxProject)({ projectDir: options.projectDir })
123
124
  : undefined;
125
+ // One logger per process, shared by the tool layer (via the factory) and the
126
+ // transport lifecycle below. Falls back to a no-op sink for programmatic callers.
127
+ const logger = createMcpLogger(options.io ?? { stdout: { write() { } }, stderr: { write() { } } });
124
128
  const createMcpServer = options.createMcpServer ??
125
129
  (await createKtxMcpServerFactory({
126
130
  project: project,
127
131
  projectDir: options.projectDir,
128
132
  cliVersion: options.cliVersion ?? getKtxCliPackageInfo().version,
129
133
  io: options.io,
134
+ logger,
130
135
  }));
131
136
  const sessions = new Map();
132
137
  async function newTransport() {
@@ -135,6 +140,7 @@ export async function runKtxMcpHttpServer(options) {
135
140
  sessionIdGenerator: () => randomUUID(),
136
141
  onsessioninitialized: (sessionId) => {
137
142
  sessions.set(sessionId, transport);
143
+ logger.info({ sessionId }, 'session.open');
138
144
  },
139
145
  onsessionclosed: (sessionId) => {
140
146
  sessions.delete(sessionId);
@@ -143,14 +149,21 @@ export async function runKtxMcpHttpServer(options) {
143
149
  allowedOrigins: config.allowedOrigins,
144
150
  enableDnsRebindingProtection: true,
145
151
  });
152
+ // onclose is the universal session-end signal (clean DELETE and dropped connection both
153
+ // close the transport), so session.close is logged here rather than in onsessionclosed.
146
154
  transport.onclose = () => {
147
155
  if (transport.sessionId) {
148
156
  sessions.delete(transport.sessionId);
157
+ logger.info({ sessionId: transport.sessionId }, 'session.close');
149
158
  }
150
159
  };
160
+ transport.onerror = (error) => {
161
+ logger.error({ ...(transport.sessionId ? { sessionId: transport.sessionId } : {}), err: serializeMcpError(error) }, 'transport.error');
162
+ };
151
163
  await createMcpServer().connect(transport);
152
164
  return transport;
153
165
  }
166
+ const startedAt = performance.now();
154
167
  const server = createServer(async (req, res) => {
155
168
  const path = requestPath(req);
156
169
  const auth = isMcpRequestAuthorized({ path, headers: req.headers }, config);
@@ -160,7 +173,8 @@ export async function runKtxMcpHttpServer(options) {
160
173
  }
161
174
  if (path === '/health' && req.method === 'GET') {
162
175
  const port = listenerPort(server, config.port);
163
- writeJson(res, 200, { status: 'ok', projectDir: options.projectDir, port });
176
+ const uptimeMs = Math.round(performance.now() - startedAt);
177
+ writeJson(res, 200, { status: 'ok', projectDir: options.projectDir, port, uptimeMs });
164
178
  return;
165
179
  }
166
180
  if (path !== '/mcp' || !['POST', 'GET', 'DELETE'].includes(req.method ?? '')) {
@@ -1,3 +1,4 @@
1
+ import type { KtxMcpLogger } from './context/mcp/logger.js';
1
2
  import type { KtxLocalProject } from './context/project/project.js';
2
3
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
4
  import type { KtxCliIo } from './cli-runtime.js';
@@ -6,4 +7,5 @@ export declare function createKtxMcpServerFactory(input: {
6
7
  projectDir: string;
7
8
  cliVersion: string;
8
9
  io?: KtxCliIo;
10
+ logger?: KtxMcpLogger;
9
11
  }): Promise<() => McpServer>;
@@ -2,6 +2,7 @@ import { KtxIngestEmbeddingPortAdapter } from './context/llm/embedding-port.js';
2
2
  import { createDefaultKtxMcpServer } from './context/mcp/server.js';
3
3
  import { createLocalProjectMcpContextPorts } from './context/mcp/local-project-ports.js';
4
4
  import { createLocalProjectMemoryIngest } from './context/memory/local-memory.js';
5
+ import { assertConfiguredConnectionId } from './context/connections/configured-connections.js';
5
6
  import { resolveProjectEmbeddingProvider } from './embedding-resolution.js';
6
7
  import { createKtxCliIngestQueryExecutor } from './ingest-query-executor.js';
7
8
  import { createKtxCliScanConnector } from './local-scan-connectors.js';
@@ -47,11 +48,23 @@ export async function createKtxMcpServerFactory(input) {
47
48
  });
48
49
  let memoryIngest;
49
50
  try {
50
- memoryIngest = createLocalProjectMemoryIngest(input.project, {
51
+ const baseMemoryIngest = createLocalProjectMemoryIngest(input.project, {
51
52
  semanticLayerCompute,
52
53
  queryExecutor,
53
54
  embeddingProvider,
54
55
  });
56
+ // Validate the explicit connectionId argument here so a typo is rejected with the
57
+ // configured ids before the ingest run starts; persisted page scope is validated
58
+ // separately (warn-only) and must not fail.
59
+ memoryIngest = {
60
+ ingest: (ingestInput) => {
61
+ if (ingestInput.connectionId !== undefined) {
62
+ assertConfiguredConnectionId(input.project.config.connections, ingestInput.connectionId);
63
+ }
64
+ return baseMemoryIngest.ingest(ingestInput);
65
+ },
66
+ status: (runId) => baseMemoryIngest.status(runId),
67
+ };
55
68
  }
56
69
  catch (error) {
57
70
  io.stderr.write(`ktx MCP memory_ingest disabled: ${error instanceof Error ? error.message : String(error)}\n`);
@@ -62,6 +75,7 @@ export async function createKtxMcpServerFactory(input) {
62
75
  userContext: { userId: 'local' },
63
76
  projectDir: input.projectDir,
64
77
  io,
78
+ ...(input.logger ? { logger: input.logger } : {}),
65
79
  contextTools: {
66
80
  ...contextTools,
67
81
  ...(memoryIngest ? { memoryIngest } : {}),
@@ -2,6 +2,7 @@ import process from 'node:process';
2
2
  import { loadKtxProject } from './context/project/project.js';
3
3
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
4
  import { getKtxCliPackageInfo } from './cli-runtime.js';
5
+ import { createMcpLogger, serializeMcpError } from './context/mcp/logger.js';
5
6
  import { createKtxMcpServerFactory } from './mcp-server-factory.js';
6
7
  export async function runKtxMcpStdioServer(options) {
7
8
  const project = options.createMcpServer === undefined
@@ -11,12 +12,15 @@ export async function runKtxMcpStdioServer(options) {
11
12
  stdout: { write() { } },
12
13
  stderr: options.io?.stderr ?? process.stderr,
13
14
  };
15
+ // stdout is reserved for JSON-RPC, so the logger writes to stderr only.
16
+ const logger = createMcpLogger(protocolIo);
14
17
  const createMcpServer = options.createMcpServer ??
15
18
  (await createKtxMcpServerFactory({
16
19
  project: project,
17
20
  projectDir: options.projectDir,
18
21
  cliVersion: options.cliVersion ?? getKtxCliPackageInfo().version,
19
22
  io: protocolIo,
23
+ logger,
20
24
  }));
21
25
  const stdin = options.stdin ?? process.stdin;
22
26
  const transport = new StdioServerTransport(stdin, options.stdout);
@@ -35,13 +39,17 @@ export async function runKtxMcpStdioServer(options) {
35
39
  settle(() => reject(error instanceof Error ? error : new Error(String(error))));
36
40
  });
37
41
  };
38
- transport.onclose = () => settle(resolve);
42
+ transport.onclose = () => {
43
+ logger.info({}, 'session.close');
44
+ settle(resolve);
45
+ };
39
46
  transport.onerror = (error) => {
40
- options.io?.stderr.write(`ktx MCP stdio transport error: ${error.message}\n`);
47
+ logger.error({ err: serializeMcpError(error) }, 'transport.error');
41
48
  settle(() => reject(error));
42
49
  };
43
50
  stdin.once('end', closeTransport);
44
51
  stdin.once('close', closeTransport);
52
+ logger.info({}, 'session.open');
45
53
  createMcpServer().connect(transport).catch((error) => {
46
54
  settle(() => reject(error instanceof Error ? error : new Error(String(error))));
47
55
  });
@@ -7,7 +7,7 @@ profileMark('module:notion-page-picker');
7
7
  const NOTION_PICKER_PAGE_CAP = 5000;
8
8
  const NOTION_SCRIPTED_MODE_HINT = 'Notion picker requires a TTY. Use --no-input --notion-root-page-id <UUID> for scripted mode.';
9
9
  function assertSafeNotionPickerConnectionId(connectionId) {
10
- if (!/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(connectionId)) {
10
+ if (!/^[a-zA-Z0-9_][a-zA-Z0-9_-]*$/.test(connectionId)) {
11
11
  throw new Error(`Unsafe connection id: ${connectionId}`);
12
12
  }
13
13
  }
@@ -19,6 +19,8 @@ A single artifact typically produces multiple actions: one SL source per table/v
19
19
 
20
20
  <scope>
21
21
  All wiki writes go to the GLOBAL scope - they will be visible to every user of this ktx project. Phrase wiki pages as objective business knowledge, not personal preference. The `wiki_write` tool handles scope selection automatically for external ingest.
22
+
23
+ When a `connectionId` is shown in the prompt context, tag database-specific pages with `connections: [<that id>]` and give them connection-distinctive keys (`orders_sales_db`, not `orders`) so same-concept pages from other databases do not collide or pollute each other's searches. Leave `connections` empty for org-wide knowledge that applies across every database. See the `wiki_capture` skill's "Connection scoping" section.
22
24
  </scope>
23
25
 
24
26
  <do_not>
@@ -5,7 +5,7 @@ import type { KtxIngestArgs, KtxIngestDeps, KtxIngestProgressUpdate } from './in
5
5
  import { type KtxManagedPythonInstallPolicy, type ManagedPythonCommandRuntime } from './managed-python-command.js';
6
6
  import type { KtxRuntimeFeature } from './managed-python-runtime.js';
7
7
  import type { KtxScanArgs, KtxScanDeps } from './scan.js';
8
- import type { KtxTableRef } from './context/scan/types.js';
8
+ import type { KtxScanEnrichmentStage, KtxTableRef } from './context/scan/types.js';
9
9
  type KtxPublicIngestStepName = 'database-schema' | 'query-history' | 'source-ingest' | 'memory-update';
10
10
  type KtxPublicIngestStepStatus = 'done' | 'skipped' | 'failed' | 'not-run';
11
11
  type KtxPublicIngestInputMode = 'auto' | 'disabled';
@@ -23,6 +23,7 @@ export type KtxPublicIngestArgs = {
23
23
  scanMode?: Extract<KtxScanArgs, {
24
24
  command: 'run';
25
25
  }>['mode'];
26
+ stages?: KtxScanEnrichmentStage[];
26
27
  detectRelationships?: boolean;
27
28
  cliVersion?: string;
28
29
  runtimeInstallPolicy?: KtxManagedPythonInstallPolicy;
@@ -95,6 +96,7 @@ interface KtxPublicContextBuildArgs {
95
96
  scanMode?: Extract<KtxScanArgs, {
96
97
  command: 'run';
97
98
  }>['mode'];
99
+ stages?: KtxScanEnrichmentStage[];
98
100
  detectRelationships?: boolean;
99
101
  cliVersion?: string;
100
102
  runtimeInstallPolicy?: KtxManagedPythonInstallPolicy;
@@ -17,9 +17,11 @@ const sourceAdapterByDriver = new Map([
17
17
  ['local_metabase', 'metabase'],
18
18
  ['looker', 'looker'],
19
19
  ['notion', 'notion'],
20
+ ['gdrive', 'gdrive'],
20
21
  ['metricflow', 'metricflow'],
21
22
  ['dbt', 'dbt'],
22
23
  ['lookml', 'lookml'],
24
+ ['sigma', 'sigma'],
23
25
  ]);
24
26
  export function publicProgressMessage(message, target) {
25
27
  let current = message;
@@ -612,6 +614,7 @@ async function runIngestTargetSteps(target, args, io, deps, project) {
612
614
  mode: 'enriched',
613
615
  detectRelationships: target.detectRelationships === true,
614
616
  dryRun: false,
617
+ ...(args.stages ? { stages: args.stages } : {}),
615
618
  ...(args.cliVersion ? { cliVersion: args.cliVersion } : {}),
616
619
  ...(args.runtimeInstallPolicy ? { runtimeInstallPolicy: args.runtimeInstallPolicy } : {}),
617
620
  };
@@ -764,6 +767,7 @@ export async function runKtxPublicIngest(args, io, deps = {}) {
764
767
  ...(args.queryHistory ? { queryHistory: args.queryHistory } : {}),
765
768
  ...(args.queryHistoryWindowDays !== undefined ? { queryHistoryWindowDays: args.queryHistoryWindowDays } : {}),
766
769
  ...(args.scanMode ? { scanMode: args.scanMode } : {}),
770
+ ...(args.stages ? { stages: args.stages } : {}),
767
771
  ...(args.detectRelationships !== undefined ? { detectRelationships: args.detectRelationships } : {}),
768
772
  ...(args.cliVersion ? { cliVersion: args.cliVersion } : {}),
769
773
  ...(args.runtimeInstallPolicy ? { runtimeInstallPolicy: args.runtimeInstallPolicy } : {}),
package/dist/scan.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { KtxProgressPort, KtxScanMode } from './context/scan/types.js';
1
+ import type { KtxProgressPort, KtxScanEnrichmentStage, KtxScanMode } from './context/scan/types.js';
2
2
  import { runLocalScan } from './context/scan/local-scan.js';
3
3
  import { resolveProjectEmbeddingProvider } from './embedding-resolution.js';
4
4
  import type { KtxCliIo } from './index.js';
@@ -11,6 +11,8 @@ export interface KtxScanArgs {
11
11
  mode: KtxScanMode;
12
12
  detectRelationships: boolean;
13
13
  dryRun: boolean;
14
+ /** Enrichment stages to (re)run; omit to run all eligible stages. */
15
+ stages?: KtxScanEnrichmentStage[];
14
16
  databaseIntrospectionUrl?: string;
15
17
  cliVersion?: string;
16
18
  runtimeInstallPolicy?: KtxManagedPythonInstallPolicy;
package/dist/scan.js CHANGED
@@ -134,8 +134,14 @@ function describeWarningGroup(code, count) {
134
134
  return `${count} LLM relationship ${plural(count, 'proposal')} failed.`;
135
135
  case 'scan_enrichment_backend_not_configured':
136
136
  return 'Scan enrichment backend is not configured; AI stages were skipped.';
137
+ case 'enrichment_stage_skipped':
138
+ return `${count} requested ${plural(count, 'enrichment stage')} could not run (prerequisite missing).`;
139
+ case 'enrichment_stage_stale':
140
+ return `${count} enrichment ${plural(count, 'stage')} are stale after a selective run; re-run them to refresh.`;
137
141
  case 'credential_redacted':
138
142
  return `${count} ${plural(count, 'credential')} were redacted from scan output.`;
143
+ case 'object_introspection_failed':
144
+ return `${count} ${plural(count, 'object')} skipped during introspection (broken or inaccessible objects were excluded; the rest were ingested).`;
139
145
  default:
140
146
  return `${count} ${plural(count, 'warning')} (${code})`;
141
147
  }
@@ -272,6 +278,7 @@ export async function runKtxScan(args, io = process, deps = {}) {
272
278
  connectionId: args.connectionId,
273
279
  mode: args.mode,
274
280
  detectRelationships: args.detectRelationships,
281
+ ...(args.stages ? { stages: args.stages } : {}),
275
282
  dryRun: args.dryRun,
276
283
  trigger: 'cli',
277
284
  databaseIntrospectionUrl: args.databaseIntrospectionUrl,
@@ -9,7 +9,7 @@ import { type DatabaseScopePickResult, type PickDatabaseScopeArgs } from './data
9
9
  import type { KtxManagedPythonInstallPolicy } from './managed-python-command.js';
10
10
  import type { ManagedPythonCoreDaemonOptions } from './managed-python-http.js';
11
11
  import { type KtxSetupPromptOption } from './setup-prompts.js';
12
- export type KtxSetupDatabaseDriver = 'sqlite' | 'postgres' | 'mysql' | 'clickhouse' | 'sqlserver' | 'bigquery' | 'snowflake';
12
+ export type KtxSetupDatabaseDriver = 'sqlite' | 'postgres' | 'mysql' | 'clickhouse' | 'sqlserver' | 'bigquery' | 'snowflake' | 'mongodb';
13
13
  export interface KtxSetupDatabasesArgs {
14
14
  projectDir: string;
15
15
  inputMode: 'auto' | 'disabled';
@@ -37,6 +37,7 @@ const DRIVER_OPTIONS = [
37
37
  { value: 'mysql', label: 'MySQL' },
38
38
  { value: 'clickhouse', label: 'ClickHouse' },
39
39
  { value: 'sqlserver', label: 'SQL Server' },
40
+ { value: 'mongodb', label: 'MongoDB' },
40
41
  { value: 'sqlite', label: 'SQLite' },
41
42
  ];
42
43
  const DRIVER_LABELS = Object.fromEntries(DRIVER_OPTIONS.map((option) => [option.value, option.label]));
@@ -53,6 +54,7 @@ const DEFAULT_CONNECTION_IDS = {
53
54
  sqlserver: 'sqlserver-warehouse',
54
55
  bigquery: 'bigquery-warehouse',
55
56
  snowflake: 'snowflake-warehouse',
57
+ mongodb: 'mongodb-source',
56
58
  };
57
59
  const SUGGESTED_SCOPE_PATTERN = /^(mart|prod|analytics|core|dim|fact|gold)(_|$)/i;
58
60
  const EXCLUDED_SCOPE_PATTERN = /^(information_schema|pg_catalog|pg_toast|_airbyte_|mysql$|performance_schema$|sys$)/i;
@@ -85,6 +87,13 @@ const SCOPE_DISCOVERY_SPECS = {
85
87
  configArrayField: 'databases',
86
88
  suggest: defaultSuggest,
87
89
  },
90
+ mongodb: {
91
+ noun: 'database',
92
+ nounPlural: 'databases',
93
+ promptLabel: 'MongoDB databases',
94
+ configArrayField: 'databases',
95
+ suggest: defaultSuggest,
96
+ },
88
97
  sqlserver: {
89
98
  noun: 'schema',
90
99
  nounPlural: 'schemas',
@@ -152,7 +161,7 @@ function unique(values) {
152
161
  return [...new Set(values.filter((value) => value.trim().length > 0))];
153
162
  }
154
163
  function assertSafeDatabaseConnectionId(connectionId) {
155
- if (!/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(connectionId)) {
164
+ if (!/^[a-zA-Z0-9_][a-zA-Z0-9_-]*$/.test(connectionId)) {
156
165
  throw new Error(`Unsafe connection id: ${connectionId}`);
157
166
  }
158
167
  }
@@ -496,6 +505,31 @@ async function buildUrlConnectionConfig(input) {
496
505
  return result;
497
506
  }
498
507
  }
508
+ async function buildMongoConnectionConfig(input) {
509
+ if (input.args.inputMode === 'disabled' && !input.args.databaseUrl)
510
+ return null;
511
+ const rawUrl = input.args.databaseUrl ??
512
+ (await promptText(input.prompts, 'MongoDB connection URL\nFor example mongodb+srv://user:pass@cluster.example.net/app.', // pragma: allowlist secret
513
+ stringConfigField(input.existingConnection, 'url')));
514
+ if (rawUrl === undefined)
515
+ return 'back';
516
+ if (!rawUrl)
517
+ return null;
518
+ const url = normalizeInputReference(rawUrl);
519
+ const scope = scriptedScopeConfigForDriver('mongodb', input.args.databaseSchemas);
520
+ if (url.startsWith('env:') || url.startsWith('file:')) {
521
+ return { driver: 'mongodb', url, ...scope };
522
+ }
523
+ if (urlHasCredentials(url)) {
524
+ const ref = await writeProjectLocalSecretReference({
525
+ projectDir: input.args.projectDir,
526
+ fileName: `${input.connectionId}-url`,
527
+ value: url,
528
+ });
529
+ return { driver: 'mongodb', url: ref, ...scope };
530
+ }
531
+ return { driver: 'mongodb', url, ...scope };
532
+ }
499
533
  async function buildConnectionConfig(input) {
500
534
  const { driver, args, prompts } = input;
501
535
  if (driver === 'sqlite') {
@@ -516,6 +550,14 @@ async function buildConnectionConfig(input) {
516
550
  existingConnection: input.existingConnection,
517
551
  });
518
552
  }
553
+ if (driver === 'mongodb') {
554
+ return await buildMongoConnectionConfig({
555
+ connectionId: input.connectionId,
556
+ args,
557
+ prompts,
558
+ existingConnection: input.existingConnection,
559
+ });
560
+ }
519
561
  if (driver === 'bigquery') {
520
562
  const credentialsPath = await promptText(prompts, 'Path to service account JSON file', displayFileReference(stringConfigField(input.existingConnection, 'credentials_json')));
521
563
  if (credentialsPath === undefined)
@@ -3,7 +3,7 @@ import { type KtxProjectConnectionConfig } from './context/project/config.js';
3
3
  import type { KtxCliIo } from './cli-runtime.js';
4
4
  import { pickNotionRootPages } from './notion-page-picker.js';
5
5
  import { type KtxSetupPromptOption } from './setup-prompts.js';
6
- export type KtxSetupSourceType = 'dbt' | 'metricflow' | 'metabase' | 'looker' | 'lookml' | 'notion';
6
+ export type KtxSetupSourceType = 'dbt' | 'metricflow' | 'metabase' | 'looker' | 'lookml' | 'notion' | 'sigma' | 'gdrive';
7
7
  export interface KtxSetupSourcesArgs {
8
8
  projectDir: string;
9
9
  inputMode: 'auto' | 'disabled';
@@ -25,6 +25,9 @@ export interface KtxSetupSourcesArgs {
25
25
  metabaseDatabaseId?: number;
26
26
  notionCrawlMode?: 'all_accessible' | 'selected_roots';
27
27
  notionRootPageIds?: string[];
28
+ gdriveServiceAccountKeyRef?: string;
29
+ gdriveFolderId?: string;
30
+ gdriveRecursive?: boolean;
28
31
  runInitialSourceIngest: boolean;
29
32
  skipSources: boolean;
30
33
  }
@@ -96,6 +99,8 @@ export interface KtxSetupSourcesDeps {
96
99
  validateLooker?: (projectDir: string, connectionId: string) => Promise<SourceValidationResult>;
97
100
  validateLookml?: (connection: KtxProjectConnectionConfig) => Promise<SourceValidationResult>;
98
101
  validateNotion?: (connection: KtxProjectConnectionConfig) => Promise<SourceValidationResult>;
102
+ validateSigma?: (connection: KtxProjectConnectionConfig) => Promise<SourceValidationResult>;
103
+ validateGdrive?: (connection: KtxProjectConnectionConfig) => Promise<SourceValidationResult>;
99
104
  pickNotionRootPages?: typeof pickNotionRootPages;
100
105
  discoverMetabaseDatabases?: (args: {
101
106
  sourceUrl: string;