@kaelio/ktx 0.5.0 → 0.7.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 (875) hide show
  1. package/assets/python/{kaelio_ktx-0.5.0-py3-none-any.whl → kaelio_ktx-0.7.0-py3-none-any.whl} +0 -0
  2. package/assets/python/manifest.json +4 -4
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/clack.d.ts +8 -0
  5. package/dist/clack.js +14 -0
  6. package/dist/connection.js +2 -9
  7. package/dist/connectors/bigquery/connector.d.ts +6 -1
  8. package/dist/connectors/bigquery/connector.js +38 -9
  9. package/dist/connectors/bigquery/dialect.d.ts +11 -9
  10. package/dist/connectors/bigquery/dialect.js +25 -45
  11. package/dist/connectors/clickhouse/connector.d.ts +5 -0
  12. package/dist/connectors/clickhouse/connector.js +36 -3
  13. package/dist/connectors/clickhouse/dialect.d.ts +11 -12
  14. package/dist/connectors/clickhouse/dialect.js +25 -100
  15. package/dist/connectors/mysql/connector.d.ts +7 -1
  16. package/dist/connectors/mysql/connector.js +67 -9
  17. package/dist/connectors/mysql/dialect.d.ts +11 -9
  18. package/dist/connectors/mysql/dialect.js +25 -43
  19. package/dist/connectors/postgres/connector.d.ts +6 -0
  20. package/dist/connectors/postgres/connector.js +67 -12
  21. package/dist/connectors/postgres/dialect.d.ts +11 -9
  22. package/dist/connectors/postgres/dialect.js +26 -35
  23. package/dist/connectors/snowflake/connector.d.ts +8 -3
  24. package/dist/connectors/snowflake/connector.js +39 -20
  25. package/dist/connectors/snowflake/dialect.d.ts +11 -9
  26. package/dist/connectors/snowflake/dialect.js +25 -24
  27. package/dist/connectors/sqlite/connector.d.ts +3 -1
  28. package/dist/connectors/sqlite/connector.js +23 -3
  29. package/dist/connectors/sqlite/dialect.d.ts +11 -9
  30. package/dist/connectors/sqlite/dialect.js +25 -29
  31. package/dist/connectors/sqlserver/connector.d.ts +6 -0
  32. package/dist/connectors/sqlserver/connector.js +56 -9
  33. package/dist/connectors/sqlserver/dialect.d.ts +11 -10
  34. package/dist/connectors/sqlserver/dialect.js +24 -40
  35. package/dist/context/connections/connection-type.d.ts +1 -1
  36. package/dist/context/connections/dialect-helpers.d.ts +9 -0
  37. package/dist/context/connections/dialect-helpers.js +67 -0
  38. package/dist/context/connections/dialects.d.ts +23 -5
  39. package/dist/context/connections/dialects.js +18 -56
  40. package/dist/context/connections/drivers.d.ts +23 -0
  41. package/dist/context/connections/drivers.js +171 -0
  42. package/dist/context/connections/local-query-executor.js +25 -7
  43. package/dist/context/connections/local-warehouse-descriptor.js +0 -2
  44. package/dist/context/connections/postgres-query-executor.js +1 -1
  45. package/dist/context/connections/sqlite-query-executor.js +1 -1
  46. package/dist/context/ingest/adapters/historic-sql/chunk-unified.js +1 -1
  47. package/dist/context/ingest/adapters/historic-sql/connection-dialect.js +11 -7
  48. package/dist/context/ingest/adapters/historic-sql/evidence-tool.d.ts +1 -1
  49. package/dist/context/ingest/adapters/historic-sql/evidence-tool.js +8 -5
  50. package/dist/context/ingest/adapters/historic-sql/evidence.d.ts +4 -4
  51. package/dist/context/ingest/adapters/historic-sql/evidence.js +2 -2
  52. package/dist/context/ingest/adapters/historic-sql/projection.js +5 -2
  53. package/dist/context/ingest/adapters/live-database/daemon-introspection.js +1 -1
  54. package/dist/context/ingest/adapters/live-database/stage.d.ts +2 -0
  55. package/dist/context/ingest/adapters/live-database/stage.js +9 -0
  56. package/dist/context/ingest/adapters/looker/mapping.d.ts +0 -3
  57. package/dist/context/ingest/adapters/looker/mapping.js +0 -3
  58. package/dist/context/ingest/adapters/looker/types.d.ts +1 -1
  59. package/dist/context/ingest/historic-sql-probes/bigquery-runner.d.ts +34 -0
  60. package/dist/context/ingest/historic-sql-probes/bigquery-runner.js +99 -0
  61. package/dist/context/ingest/historic-sql-probes/postgres-runner.d.ts +26 -0
  62. package/dist/context/ingest/historic-sql-probes/postgres-runner.js +76 -0
  63. package/dist/context/ingest/historic-sql-probes/snowflake-runner.d.ts +29 -0
  64. package/dist/context/ingest/historic-sql-probes/snowflake-runner.js +62 -0
  65. package/dist/context/ingest/historic-sql-probes.d.ts +46 -0
  66. package/dist/context/ingest/historic-sql-probes.js +62 -0
  67. package/dist/context/ingest/local-adapters.js +0 -1
  68. package/dist/context/ingest/local-ingest.js +1 -1
  69. package/dist/context/llm/claude-code-runtime.js +16 -1
  70. package/dist/context/mcp/context-tools.js +11 -48
  71. package/dist/context/mcp/local-project-ports.js +0 -3
  72. package/dist/context/project/config.d.ts +0 -8
  73. package/dist/context/project/driver-schemas.d.ts +0 -4
  74. package/dist/context/project/driver-schemas.js +0 -2
  75. package/dist/context/scan/constraint-discovery.d.ts +19 -0
  76. package/dist/context/scan/constraint-discovery.js +23 -0
  77. package/dist/context/scan/enabled-tables.d.ts +4 -5
  78. package/dist/context/scan/enabled-tables.js +4 -18
  79. package/dist/context/scan/entity-details.js +14 -44
  80. package/dist/context/scan/local-enrichment.js +13 -1
  81. package/dist/context/scan/local-scan.js +5 -4
  82. package/dist/context/scan/local-structural-artifacts.js +51 -0
  83. package/dist/context/scan/relationship-benchmarks.js +9 -6
  84. package/dist/context/scan/relationship-composite-candidates.d.ts +3 -2
  85. package/dist/context/scan/relationship-composite-candidates.js +21 -33
  86. package/dist/context/scan/relationship-discovery.d.ts +3 -2
  87. package/dist/context/scan/relationship-discovery.js +4 -4
  88. package/dist/context/scan/relationship-profiling.d.ts +2 -3
  89. package/dist/context/scan/relationship-profiling.js +25 -94
  90. package/dist/context/scan/relationship-validation.d.ts +3 -2
  91. package/dist/context/scan/relationship-validation.js +12 -22
  92. package/dist/context/scan/table-ref.d.ts +1 -2
  93. package/dist/context/scan/table-ref.js +3 -4
  94. package/dist/context/scan/types.d.ts +6 -2
  95. package/dist/context/scan/warehouse-catalog.js +31 -48
  96. package/dist/context/sl/local-query.js +0 -3
  97. package/dist/context/sl/local-sl.js +0 -13
  98. package/dist/context/sl/semantic-layer.service.js +1 -4
  99. package/dist/context/tools/context-candidate-write.tool.d.ts +2 -2
  100. package/dist/context-build-view.js +1 -1
  101. package/dist/database-tree-picker.js +14 -7
  102. package/dist/error-message.d.ts +1 -0
  103. package/dist/error-message.js +29 -0
  104. package/dist/ingest-depth.js +0 -1
  105. package/dist/ingest.js +2 -2
  106. package/dist/llm/embedding-health.js +2 -2
  107. package/dist/local-scan-connectors.js +13 -56
  108. package/dist/managed-local-embeddings.js +2 -1
  109. package/dist/managed-python-daemon.d.ts +5 -0
  110. package/dist/managed-python-daemon.js +29 -9
  111. package/dist/managed-python-http.js +2 -1
  112. package/dist/public-ingest.js +1 -6
  113. package/dist/runtime-requirements.js +2 -2
  114. package/dist/setup-agents.d.ts +1 -1
  115. package/dist/setup-agents.js +16 -74
  116. package/dist/setup-context.js +2 -1
  117. package/dist/setup-databases.d.ts +3 -13
  118. package/dist/setup-databases.js +141 -313
  119. package/dist/setup-embeddings.js +10 -2
  120. package/dist/setup-project.d.ts +0 -8
  121. package/dist/setup-project.js +3 -27
  122. package/dist/setup-runtime.js +2 -1
  123. package/dist/setup-sources.js +2 -1
  124. package/dist/setup.js +11 -18
  125. package/dist/skills/historic_sql_patterns/SKILL.md +1 -3
  126. package/dist/skills/historic_sql_table_digest/SKILL.md +0 -1
  127. package/dist/skills/sl/SKILL.md +2 -2
  128. package/dist/sql.js +0 -4
  129. package/dist/status-project.d.ts +3 -18
  130. package/dist/status-project.js +42 -216
  131. package/dist/telemetry/events.d.ts +1 -1
  132. package/dist/telemetry/index.js +8 -3
  133. package/dist/tree-picker-state.d.ts +2 -2
  134. package/dist/tree-picker-state.js +29 -13
  135. package/dist/tree-picker-tui.d.ts +3 -1
  136. package/dist/tree-picker-tui.js +20 -32
  137. package/package.json +6 -6
  138. package/dist/admin-reindex.test.d.ts +0 -1
  139. package/dist/admin-reindex.test.js +0 -119
  140. package/dist/admin.test.d.ts +0 -1
  141. package/dist/admin.test.js +0 -201
  142. package/dist/cli-program-telemetry.test.d.ts +0 -1
  143. package/dist/cli-program-telemetry.test.js +0 -89
  144. package/dist/cli-program.test.d.ts +0 -1
  145. package/dist/cli-program.test.js +0 -71
  146. package/dist/command-tree.test.d.ts +0 -1
  147. package/dist/command-tree.test.js +0 -126
  148. package/dist/commands/mcp-commands.test.d.ts +0 -1
  149. package/dist/commands/mcp-commands.test.js +0 -111
  150. package/dist/commands/sql-commands.test.d.ts +0 -1
  151. package/dist/commands/sql-commands.test.js +0 -68
  152. package/dist/connection.test.d.ts +0 -1
  153. package/dist/connection.test.js +0 -426
  154. package/dist/connectors/bigquery/connector.test.d.ts +0 -1
  155. package/dist/connectors/bigquery/connector.test.js +0 -363
  156. package/dist/connectors/bigquery/dialect.test.d.ts +0 -1
  157. package/dist/connectors/bigquery/dialect.test.js +0 -36
  158. package/dist/connectors/clickhouse/connector.test.d.ts +0 -1
  159. package/dist/connectors/clickhouse/connector.test.js +0 -342
  160. package/dist/connectors/clickhouse/dialect.test.d.ts +0 -1
  161. package/dist/connectors/clickhouse/dialect.test.js +0 -36
  162. package/dist/connectors/mysql/connector.test.d.ts +0 -1
  163. package/dist/connectors/mysql/connector.test.js +0 -365
  164. package/dist/connectors/mysql/dialect.test.d.ts +0 -1
  165. package/dist/connectors/mysql/dialect.test.js +0 -36
  166. package/dist/connectors/postgres/connector.test.d.ts +0 -1
  167. package/dist/connectors/postgres/connector.test.js +0 -391
  168. package/dist/connectors/postgres/dialect.test.d.ts +0 -1
  169. package/dist/connectors/postgres/dialect.test.js +0 -37
  170. package/dist/connectors/postgres/historic-sql-query-client.test.d.ts +0 -1
  171. package/dist/connectors/postgres/historic-sql-query-client.test.js +0 -45
  172. package/dist/connectors/snowflake/connector.test.d.ts +0 -1
  173. package/dist/connectors/snowflake/connector.test.js +0 -462
  174. package/dist/connectors/snowflake/dialect.test.d.ts +0 -1
  175. package/dist/connectors/snowflake/dialect.test.js +0 -34
  176. package/dist/connectors/snowflake/identifiers.test.d.ts +0 -1
  177. package/dist/connectors/snowflake/identifiers.test.js +0 -12
  178. package/dist/connectors/snowflake/sdk-logger.test.d.ts +0 -1
  179. package/dist/connectors/snowflake/sdk-logger.test.js +0 -47
  180. package/dist/connectors/sqlite/connector.test.d.ts +0 -1
  181. package/dist/connectors/sqlite/connector.test.js +0 -207
  182. package/dist/connectors/sqlite/dialect.test.d.ts +0 -1
  183. package/dist/connectors/sqlite/dialect.test.js +0 -23
  184. package/dist/connectors/sqlserver/connector.test.d.ts +0 -1
  185. package/dist/connectors/sqlserver/connector.test.js +0 -313
  186. package/dist/connectors/sqlserver/dialect.test.d.ts +0 -1
  187. package/dist/connectors/sqlserver/dialect.test.js +0 -36
  188. package/dist/context/connections/bigquery-identifiers.test.d.ts +0 -1
  189. package/dist/context/connections/bigquery-identifiers.test.js +0 -13
  190. package/dist/context/connections/dialects.test.d.ts +0 -1
  191. package/dist/context/connections/dialects.test.js +0 -24
  192. package/dist/context/connections/local-query-executor.test.d.ts +0 -1
  193. package/dist/context/connections/local-query-executor.test.js +0 -48
  194. package/dist/context/connections/local-warehouse-descriptor.test.d.ts +0 -1
  195. package/dist/context/connections/local-warehouse-descriptor.test.js +0 -53
  196. package/dist/context/connections/notion-config.test.d.ts +0 -1
  197. package/dist/context/connections/notion-config.test.js +0 -121
  198. package/dist/context/connections/postgres-query-executor.test.d.ts +0 -1
  199. package/dist/context/connections/postgres-query-executor.test.js +0 -91
  200. package/dist/context/connections/read-only-sql.test.d.ts +0 -1
  201. package/dist/context/connections/read-only-sql.test.js +0 -20
  202. package/dist/context/connections/sqlite-query-executor.test.d.ts +0 -1
  203. package/dist/context/connections/sqlite-query-executor.test.js +0 -113
  204. package/dist/context/core/config-reference.test.d.ts +0 -1
  205. package/dist/context/core/config-reference.test.js +0 -27
  206. package/dist/context/core/git.service.assert-worktree-clean.test.d.ts +0 -1
  207. package/dist/context/core/git.service.assert-worktree-clean.test.js +0 -62
  208. package/dist/context/core/git.service.delete-directories.test.d.ts +0 -1
  209. package/dist/context/core/git.service.delete-directories.test.js +0 -61
  210. package/dist/context/core/git.service.patch.test.d.ts +0 -1
  211. package/dist/context/core/git.service.patch.test.js +0 -40
  212. package/dist/context/core/git.service.reset-hard.test.d.ts +0 -1
  213. package/dist/context/core/git.service.reset-hard.test.js +0 -47
  214. package/dist/context/core/git.service.test.d.ts +0 -1
  215. package/dist/context/core/git.service.test.js +0 -357
  216. package/dist/context/core/session-worktree.service.test.d.ts +0 -1
  217. package/dist/context/core/session-worktree.service.test.js +0 -97
  218. package/dist/context/daemon/semantic-layer-compute.test.d.ts +0 -1
  219. package/dist/context/daemon/semantic-layer-compute.test.js +0 -305
  220. package/dist/context/index-sync/reindex.test.d.ts +0 -1
  221. package/dist/context/index-sync/reindex.test.js +0 -139
  222. package/dist/context/ingest/action-identity.test.d.ts +0 -1
  223. package/dist/context/ingest/action-identity.test.js +0 -19
  224. package/dist/context/ingest/adapters/dbt/chunk.test.d.ts +0 -1
  225. package/dist/context/ingest/adapters/dbt/chunk.test.js +0 -30
  226. package/dist/context/ingest/adapters/dbt/dbt.adapter.test.d.ts +0 -1
  227. package/dist/context/ingest/adapters/dbt/dbt.adapter.test.js +0 -43
  228. package/dist/context/ingest/adapters/dbt/fetch.test.d.ts +0 -1
  229. package/dist/context/ingest/adapters/dbt/fetch.test.js +0 -30
  230. package/dist/context/ingest/adapters/dbt/parse.test.d.ts +0 -1
  231. package/dist/context/ingest/adapters/dbt/parse.test.js +0 -7
  232. package/dist/context/ingest/adapters/dbt-descriptions/parse-schema.test.d.ts +0 -1
  233. package/dist/context/ingest/adapters/dbt-descriptions/parse-schema.test.js +0 -195
  234. package/dist/context/ingest/adapters/historic-sql/bigquery-query-history-reader.test.d.ts +0 -1
  235. package/dist/context/ingest/adapters/historic-sql/bigquery-query-history-reader.test.js +0 -121
  236. package/dist/context/ingest/adapters/historic-sql/buckets.test.d.ts +0 -1
  237. package/dist/context/ingest/adapters/historic-sql/buckets.test.js +0 -49
  238. package/dist/context/ingest/adapters/historic-sql/chunk-unified.test.d.ts +0 -1
  239. package/dist/context/ingest/adapters/historic-sql/chunk-unified.test.js +0 -160
  240. package/dist/context/ingest/adapters/historic-sql/detect.test.d.ts +0 -1
  241. package/dist/context/ingest/adapters/historic-sql/detect.test.js +0 -48
  242. package/dist/context/ingest/adapters/historic-sql/evidence-tool.test.d.ts +0 -1
  243. package/dist/context/ingest/adapters/historic-sql/evidence-tool.test.js +0 -67
  244. package/dist/context/ingest/adapters/historic-sql/evidence.test.d.ts +0 -1
  245. package/dist/context/ingest/adapters/historic-sql/evidence.test.js +0 -43
  246. package/dist/context/ingest/adapters/historic-sql/historic-sql.adapter.test.d.ts +0 -1
  247. package/dist/context/ingest/adapters/historic-sql/historic-sql.adapter.test.js +0 -98
  248. package/dist/context/ingest/adapters/historic-sql/local-ingest-acceptance.test.d.ts +0 -1
  249. package/dist/context/ingest/adapters/historic-sql/local-ingest-acceptance.test.js +0 -235
  250. package/dist/context/ingest/adapters/historic-sql/pattern-inputs.test.d.ts +0 -1
  251. package/dist/context/ingest/adapters/historic-sql/pattern-inputs.test.js +0 -68
  252. package/dist/context/ingest/adapters/historic-sql/postgres-pgss-reader.test.d.ts +0 -1
  253. package/dist/context/ingest/adapters/historic-sql/postgres-pgss-reader.test.js +0 -205
  254. package/dist/context/ingest/adapters/historic-sql/projection.test.d.ts +0 -1
  255. package/dist/context/ingest/adapters/historic-sql/projection.test.js +0 -392
  256. package/dist/context/ingest/adapters/historic-sql/redaction.test.d.ts +0 -1
  257. package/dist/context/ingest/adapters/historic-sql/redaction.test.js +0 -22
  258. package/dist/context/ingest/adapters/historic-sql/skill-schemas.test.d.ts +0 -1
  259. package/dist/context/ingest/adapters/historic-sql/skill-schemas.test.js +0 -62
  260. package/dist/context/ingest/adapters/historic-sql/snowflake-query-history-reader.test.d.ts +0 -1
  261. package/dist/context/ingest/adapters/historic-sql/snowflake-query-history-reader.test.js +0 -117
  262. package/dist/context/ingest/adapters/historic-sql/stage-unified.test.d.ts +0 -1
  263. package/dist/context/ingest/adapters/historic-sql/stage-unified.test.js +0 -405
  264. package/dist/context/ingest/adapters/historic-sql/types.test.d.ts +0 -1
  265. package/dist/context/ingest/adapters/historic-sql/types.test.js +0 -87
  266. package/dist/context/ingest/adapters/live-database/chunk.test.d.ts +0 -1
  267. package/dist/context/ingest/adapters/live-database/chunk.test.js +0 -95
  268. package/dist/context/ingest/adapters/live-database/daemon-introspection.test.d.ts +0 -1
  269. package/dist/context/ingest/adapters/live-database/daemon-introspection.test.js +0 -241
  270. package/dist/context/ingest/adapters/live-database/live-database.adapter.test.d.ts +0 -1
  271. package/dist/context/ingest/adapters/live-database/live-database.adapter.test.js +0 -105
  272. package/dist/context/ingest/adapters/live-database/manifest.test.d.ts +0 -1
  273. package/dist/context/ingest/adapters/live-database/manifest.test.js +0 -291
  274. package/dist/context/ingest/adapters/live-database/stage.test.d.ts +0 -1
  275. package/dist/context/ingest/adapters/live-database/stage.test.js +0 -133
  276. package/dist/context/ingest/adapters/looker/chunk.test.d.ts +0 -1
  277. package/dist/context/ingest/adapters/looker/chunk.test.js +0 -142
  278. package/dist/context/ingest/adapters/looker/client-boundary.test.d.ts +0 -1
  279. package/dist/context/ingest/adapters/looker/client-boundary.test.js +0 -12
  280. package/dist/context/ingest/adapters/looker/client.test.d.ts +0 -1
  281. package/dist/context/ingest/adapters/looker/client.test.js +0 -407
  282. package/dist/context/ingest/adapters/looker/daemon-table-identifier-parser.test.d.ts +0 -1
  283. package/dist/context/ingest/adapters/looker/daemon-table-identifier-parser.test.js +0 -40
  284. package/dist/context/ingest/adapters/looker/detect.test.d.ts +0 -1
  285. package/dist/context/ingest/adapters/looker/detect.test.js +0 -39
  286. package/dist/context/ingest/adapters/looker/evidence-documents.test.d.ts +0 -1
  287. package/dist/context/ingest/adapters/looker/evidence-documents.test.js +0 -178
  288. package/dist/context/ingest/adapters/looker/factory.test.d.ts +0 -1
  289. package/dist/context/ingest/adapters/looker/factory.test.js +0 -55
  290. package/dist/context/ingest/adapters/looker/fetch-report.test.d.ts +0 -1
  291. package/dist/context/ingest/adapters/looker/fetch-report.test.js +0 -71
  292. package/dist/context/ingest/adapters/looker/fetch.test.d.ts +0 -1
  293. package/dist/context/ingest/adapters/looker/fetch.test.js +0 -592
  294. package/dist/context/ingest/adapters/looker/local-runtime-store.test.d.ts +0 -1
  295. package/dist/context/ingest/adapters/looker/local-runtime-store.test.js +0 -106
  296. package/dist/context/ingest/adapters/looker/looker.adapter.test.d.ts +0 -1
  297. package/dist/context/ingest/adapters/looker/looker.adapter.test.js +0 -99
  298. package/dist/context/ingest/adapters/looker/mapping.test.d.ts +0 -1
  299. package/dist/context/ingest/adapters/looker/mapping.test.js +0 -334
  300. package/dist/context/ingest/adapters/looker/reconcile.test.d.ts +0 -1
  301. package/dist/context/ingest/adapters/looker/reconcile.test.js +0 -12
  302. package/dist/context/ingest/adapters/looker/scope.test.d.ts +0 -1
  303. package/dist/context/ingest/adapters/looker/scope.test.js +0 -84
  304. package/dist/context/ingest/adapters/looker/target-connections.test.d.ts +0 -1
  305. package/dist/context/ingest/adapters/looker/target-connections.test.js +0 -71
  306. package/dist/context/ingest/adapters/looker/tools/looker-query-to-sl.tool.test.d.ts +0 -1
  307. package/dist/context/ingest/adapters/looker/tools/looker-query-to-sl.tool.test.js +0 -211
  308. package/dist/context/ingest/adapters/looker/types.test.d.ts +0 -1
  309. package/dist/context/ingest/adapters/looker/types.test.js +0 -261
  310. package/dist/context/ingest/adapters/lookml/chunk.test.d.ts +0 -1
  311. package/dist/context/ingest/adapters/lookml/chunk.test.js +0 -213
  312. package/dist/context/ingest/adapters/lookml/detect.test.d.ts +0 -1
  313. package/dist/context/ingest/adapters/lookml/detect.test.js +0 -37
  314. package/dist/context/ingest/adapters/lookml/fetch-report.test.d.ts +0 -1
  315. package/dist/context/ingest/adapters/lookml/fetch-report.test.js +0 -82
  316. package/dist/context/ingest/adapters/lookml/fetch.test.d.ts +0 -1
  317. package/dist/context/ingest/adapters/lookml/fetch.test.js +0 -121
  318. package/dist/context/ingest/adapters/lookml/graph.test.d.ts +0 -1
  319. package/dist/context/ingest/adapters/lookml/graph.test.js +0 -105
  320. package/dist/context/ingest/adapters/lookml/lookml.adapter.test.d.ts +0 -1
  321. package/dist/context/ingest/adapters/lookml/lookml.adapter.test.js +0 -49
  322. package/dist/context/ingest/adapters/lookml/parse.test.d.ts +0 -1
  323. package/dist/context/ingest/adapters/lookml/parse.test.js +0 -118
  324. package/dist/context/ingest/adapters/lookml/pull-config.test.d.ts +0 -1
  325. package/dist/context/ingest/adapters/lookml/pull-config.test.js +0 -128
  326. package/dist/context/ingest/adapters/metabase/card-references.test.d.ts +0 -1
  327. package/dist/context/ingest/adapters/metabase/card-references.test.js +0 -36
  328. package/dist/context/ingest/adapters/metabase/chunk.test.d.ts +0 -1
  329. package/dist/context/ingest/adapters/metabase/chunk.test.js +0 -299
  330. package/dist/context/ingest/adapters/metabase/client-boundary.test.d.ts +0 -1
  331. package/dist/context/ingest/adapters/metabase/client-boundary.test.js +0 -38
  332. package/dist/context/ingest/adapters/metabase/client-port.test.d.ts +0 -1
  333. package/dist/context/ingest/adapters/metabase/client-port.test.js +0 -86
  334. package/dist/context/ingest/adapters/metabase/client.test.d.ts +0 -1
  335. package/dist/context/ingest/adapters/metabase/client.test.js +0 -377
  336. package/dist/context/ingest/adapters/metabase/detect.test.d.ts +0 -1
  337. package/dist/context/ingest/adapters/metabase/detect.test.js +0 -42
  338. package/dist/context/ingest/adapters/metabase/fanout-planner.test.d.ts +0 -1
  339. package/dist/context/ingest/adapters/metabase/fanout-planner.test.js +0 -44
  340. package/dist/context/ingest/adapters/metabase/fetch-scope.test.d.ts +0 -1
  341. package/dist/context/ingest/adapters/metabase/fetch-scope.test.js +0 -124
  342. package/dist/context/ingest/adapters/metabase/fetch.test.d.ts +0 -1
  343. package/dist/context/ingest/adapters/metabase/fetch.test.js +0 -557
  344. package/dist/context/ingest/adapters/metabase/local-metabase.adapter.test.d.ts +0 -1
  345. package/dist/context/ingest/adapters/metabase/local-metabase.adapter.test.js +0 -56
  346. package/dist/context/ingest/adapters/metabase/local-source-state-store.test.d.ts +0 -1
  347. package/dist/context/ingest/adapters/metabase/local-source-state-store.test.js +0 -99
  348. package/dist/context/ingest/adapters/metabase/mapping.test.d.ts +0 -1
  349. package/dist/context/ingest/adapters/metabase/mapping.test.js +0 -215
  350. package/dist/context/ingest/adapters/metabase/metabase.adapter.test.d.ts +0 -1
  351. package/dist/context/ingest/adapters/metabase/metabase.adapter.test.js +0 -129
  352. package/dist/context/ingest/adapters/metabase/serialize-card.test.d.ts +0 -1
  353. package/dist/context/ingest/adapters/metabase/serialize-card.test.js +0 -205
  354. package/dist/context/ingest/adapters/metabase/types.test.d.ts +0 -1
  355. package/dist/context/ingest/adapters/metabase/types.test.js +0 -75
  356. package/dist/context/ingest/adapters/metricflow/chunk.test.d.ts +0 -1
  357. package/dist/context/ingest/adapters/metricflow/chunk.test.js +0 -114
  358. package/dist/context/ingest/adapters/metricflow/deep-parse.test.d.ts +0 -1
  359. package/dist/context/ingest/adapters/metricflow/deep-parse.test.js +0 -1139
  360. package/dist/context/ingest/adapters/metricflow/detect.test.d.ts +0 -1
  361. package/dist/context/ingest/adapters/metricflow/detect.test.js +0 -43
  362. package/dist/context/ingest/adapters/metricflow/fetch.test.d.ts +0 -1
  363. package/dist/context/ingest/adapters/metricflow/fetch.test.js +0 -97
  364. package/dist/context/ingest/adapters/metricflow/graph.test.d.ts +0 -1
  365. package/dist/context/ingest/adapters/metricflow/graph.test.js +0 -245
  366. package/dist/context/ingest/adapters/metricflow/import-semantic-models.test.d.ts +0 -1
  367. package/dist/context/ingest/adapters/metricflow/import-semantic-models.test.js +0 -318
  368. package/dist/context/ingest/adapters/metricflow/metricflow.adapter.test.d.ts +0 -1
  369. package/dist/context/ingest/adapters/metricflow/metricflow.adapter.test.js +0 -212
  370. package/dist/context/ingest/adapters/metricflow/parse.test.d.ts +0 -1
  371. package/dist/context/ingest/adapters/metricflow/parse.test.js +0 -171
  372. package/dist/context/ingest/adapters/metricflow/pull-config.test.d.ts +0 -1
  373. package/dist/context/ingest/adapters/metricflow/pull-config.test.js +0 -57
  374. package/dist/context/ingest/adapters/metricflow/semantic-models.test.d.ts +0 -1
  375. package/dist/context/ingest/adapters/metricflow/semantic-models.test.js +0 -204
  376. package/dist/context/ingest/adapters/notion/cluster.test.d.ts +0 -1
  377. package/dist/context/ingest/adapters/notion/cluster.test.js +0 -123
  378. package/dist/context/ingest/adapters/notion/fetch.test.d.ts +0 -1
  379. package/dist/context/ingest/adapters/notion/fetch.test.js +0 -358
  380. package/dist/context/ingest/adapters/notion/local-state-store.test.d.ts +0 -1
  381. package/dist/context/ingest/adapters/notion/local-state-store.test.js +0 -29
  382. package/dist/context/ingest/adapters/notion/normalize.test.d.ts +0 -1
  383. package/dist/context/ingest/adapters/notion/normalize.test.js +0 -64
  384. package/dist/context/ingest/adapters/notion/notion-client.test.d.ts +0 -1
  385. package/dist/context/ingest/adapters/notion/notion-client.test.js +0 -49
  386. package/dist/context/ingest/adapters/notion/notion.adapter.test.d.ts +0 -1
  387. package/dist/context/ingest/adapters/notion/notion.adapter.test.js +0 -315
  388. package/dist/context/ingest/artifact-gates.test.d.ts +0 -1
  389. package/dist/context/ingest/artifact-gates.test.js +0 -167
  390. package/dist/context/ingest/canonical-pins.test.d.ts +0 -1
  391. package/dist/context/ingest/canonical-pins.test.js +0 -66
  392. package/dist/context/ingest/clustering/kmeans.test.d.ts +0 -1
  393. package/dist/context/ingest/clustering/kmeans.test.js +0 -61
  394. package/dist/context/ingest/context-candidates/candidate-dedup.service.test.d.ts +0 -1
  395. package/dist/context/ingest/context-candidates/candidate-dedup.service.test.js +0 -216
  396. package/dist/context/ingest/context-candidates/context-candidate-carryforward.service.test.d.ts +0 -1
  397. package/dist/context/ingest/context-candidates/context-candidate-carryforward.service.test.js +0 -161
  398. package/dist/context/ingest/context-candidates/curator-pagination.service.test.d.ts +0 -1
  399. package/dist/context/ingest/context-candidates/curator-pagination.service.test.js +0 -168
  400. package/dist/context/ingest/context-candidates/embedding-text.test.d.ts +0 -1
  401. package/dist/context/ingest/context-candidates/embedding-text.test.js +0 -10
  402. package/dist/context/ingest/context-candidates/store.test.d.ts +0 -1
  403. package/dist/context/ingest/context-candidates/store.test.js +0 -67
  404. package/dist/context/ingest/context-evidence/context-evidence-index.service.test.d.ts +0 -1
  405. package/dist/context/ingest/context-evidence/context-evidence-index.service.test.js +0 -374
  406. package/dist/context/ingest/context-evidence/sqlite-context-evidence-store.test.d.ts +0 -1
  407. package/dist/context/ingest/context-evidence/sqlite-context-evidence-store.test.js +0 -416
  408. package/dist/context/ingest/context-evidence/store.test.d.ts +0 -1
  409. package/dist/context/ingest/context-evidence/store.test.js +0 -55
  410. package/dist/context/ingest/dbt-shared/project-vars.test.d.ts +0 -1
  411. package/dist/context/ingest/dbt-shared/project-vars.test.js +0 -90
  412. package/dist/context/ingest/dbt-shared/schema-files.test.d.ts +0 -1
  413. package/dist/context/ingest/dbt-shared/schema-files.test.js +0 -35
  414. package/dist/context/ingest/diff-set.service.test.d.ts +0 -1
  415. package/dist/context/ingest/diff-set.service.test.js +0 -132
  416. package/dist/context/ingest/final-gate-repair.test.d.ts +0 -1
  417. package/dist/context/ingest/final-gate-repair.test.js +0 -109
  418. package/dist/context/ingest/finalization-scope.test.d.ts +0 -1
  419. package/dist/context/ingest/finalization-scope.test.js +0 -114
  420. package/dist/context/ingest/ingest-bundle.runner.isolated-diff.test.d.ts +0 -1
  421. package/dist/context/ingest/ingest-bundle.runner.isolated-diff.test.js +0 -1928
  422. package/dist/context/ingest/ingest-bundle.runner.test.d.ts +0 -1
  423. package/dist/context/ingest/ingest-bundle.runner.test.js +0 -1899
  424. package/dist/context/ingest/ingest-prompts.test.d.ts +0 -1
  425. package/dist/context/ingest/ingest-prompts.test.js +0 -32
  426. package/dist/context/ingest/ingest-runtime-assets.test.d.ts +0 -1
  427. package/dist/context/ingest/ingest-runtime-assets.test.js +0 -89
  428. package/dist/context/ingest/ingest-trace.test.d.ts +0 -1
  429. package/dist/context/ingest/ingest-trace.test.js +0 -76
  430. package/dist/context/ingest/isolated-diff/git-patch.test.d.ts +0 -1
  431. package/dist/context/ingest/isolated-diff/git-patch.test.js +0 -76
  432. package/dist/context/ingest/isolated-diff/patch-integrator.test.d.ts +0 -1
  433. package/dist/context/ingest/isolated-diff/patch-integrator.test.js +0 -369
  434. package/dist/context/ingest/isolated-diff/textual-conflict-resolver.test.d.ts +0 -1
  435. package/dist/context/ingest/isolated-diff/textual-conflict-resolver.test.js +0 -101
  436. package/dist/context/ingest/isolated-diff/work-unit-executor.test.d.ts +0 -1
  437. package/dist/context/ingest/isolated-diff/work-unit-executor.test.js +0 -137
  438. package/dist/context/ingest/local-adapters.test.d.ts +0 -1
  439. package/dist/context/ingest/local-adapters.test.js +0 -612
  440. package/dist/context/ingest/local-bundle-ingest.test.d.ts +0 -1
  441. package/dist/context/ingest/local-bundle-ingest.test.js +0 -794
  442. package/dist/context/ingest/local-bundle-runtime.test.d.ts +0 -1
  443. package/dist/context/ingest/local-bundle-runtime.test.js +0 -240
  444. package/dist/context/ingest/local-embedding-provider.integration.test.d.ts +0 -1
  445. package/dist/context/ingest/local-embedding-provider.integration.test.js +0 -139
  446. package/dist/context/ingest/local-mapping-reconcile.test.d.ts +0 -1
  447. package/dist/context/ingest/local-mapping-reconcile.test.js +0 -61
  448. package/dist/context/ingest/local-metabase-ingest.test.d.ts +0 -1
  449. package/dist/context/ingest/local-metabase-ingest.test.js +0 -227
  450. package/dist/context/ingest/local-stage-ingest.test.d.ts +0 -1
  451. package/dist/context/ingest/local-stage-ingest.test.js +0 -581
  452. package/dist/context/ingest/memory-flow/acceptance-fixtures.d.ts +0 -6
  453. package/dist/context/ingest/memory-flow/acceptance-fixtures.js +0 -155
  454. package/dist/context/ingest/memory-flow/acceptance.test.d.ts +0 -1
  455. package/dist/context/ingest/memory-flow/acceptance.test.js +0 -43
  456. package/dist/context/ingest/memory-flow/events.test.d.ts +0 -1
  457. package/dist/context/ingest/memory-flow/events.test.js +0 -319
  458. package/dist/context/ingest/memory-flow/interaction.test.d.ts +0 -1
  459. package/dist/context/ingest/memory-flow/interaction.test.js +0 -264
  460. package/dist/context/ingest/memory-flow/interactive-render.test.d.ts +0 -1
  461. package/dist/context/ingest/memory-flow/interactive-render.test.js +0 -160
  462. package/dist/context/ingest/memory-flow/live-buffer.test.d.ts +0 -1
  463. package/dist/context/ingest/memory-flow/live-buffer.test.js +0 -77
  464. package/dist/context/ingest/memory-flow/render.test.d.ts +0 -1
  465. package/dist/context/ingest/memory-flow/render.test.js +0 -105
  466. package/dist/context/ingest/memory-flow/schema.test.d.ts +0 -1
  467. package/dist/context/ingest/memory-flow/schema.test.js +0 -147
  468. package/dist/context/ingest/memory-flow/summary.test.d.ts +0 -1
  469. package/dist/context/ingest/memory-flow/summary.test.js +0 -130
  470. package/dist/context/ingest/memory-flow/view-model.test.d.ts +0 -1
  471. package/dist/context/ingest/memory-flow/view-model.test.js +0 -397
  472. package/dist/context/ingest/memory-flow/visuals.test.d.ts +0 -1
  473. package/dist/context/ingest/memory-flow/visuals.test.js +0 -49
  474. package/dist/context/ingest/page-triage/page-triage.service.test.d.ts +0 -1
  475. package/dist/context/ingest/page-triage/page-triage.service.test.js +0 -311
  476. package/dist/context/ingest/raw-sources-paths.test.d.ts +0 -1
  477. package/dist/context/ingest/raw-sources-paths.test.js +0 -18
  478. package/dist/context/ingest/repo-fetch.test.d.ts +0 -1
  479. package/dist/context/ingest/repo-fetch.test.js +0 -168
  480. package/dist/context/ingest/report-snapshot.test.d.ts +0 -1
  481. package/dist/context/ingest/report-snapshot.test.js +0 -329
  482. package/dist/context/ingest/semantic-layer-target-policy.test.d.ts +0 -1
  483. package/dist/context/ingest/semantic-layer-target-policy.test.js +0 -25
  484. package/dist/context/ingest/source-adapter-registry.test.d.ts +0 -1
  485. package/dist/context/ingest/source-adapter-registry.test.js +0 -35
  486. package/dist/context/ingest/sqlite-bundle-ingest-store.test.d.ts +0 -1
  487. package/dist/context/ingest/sqlite-bundle-ingest-store.test.js +0 -517
  488. package/dist/context/ingest/sqlite-local-ingest-store.test.d.ts +0 -1
  489. package/dist/context/ingest/sqlite-local-ingest-store.test.js +0 -143
  490. package/dist/context/ingest/stages/build-reconcile-context.context-candidates.test.d.ts +0 -1
  491. package/dist/context/ingest/stages/build-reconcile-context.context-candidates.test.js +0 -102
  492. package/dist/context/ingest/stages/build-reconcile-context.test.d.ts +0 -1
  493. package/dist/context/ingest/stages/build-reconcile-context.test.js +0 -141
  494. package/dist/context/ingest/stages/build-wu-context.test.d.ts +0 -1
  495. package/dist/context/ingest/stages/build-wu-context.test.js +0 -196
  496. package/dist/context/ingest/stages/stage-1-stage-raw-files.test.d.ts +0 -1
  497. package/dist/context/ingest/stages/stage-1-stage-raw-files.test.js +0 -54
  498. package/dist/context/ingest/stages/stage-3-work-units.test.d.ts +0 -1
  499. package/dist/context/ingest/stages/stage-3-work-units.test.js +0 -175
  500. package/dist/context/ingest/stages/stage-4-reconciliation.test.d.ts +0 -1
  501. package/dist/context/ingest/stages/stage-4-reconciliation.test.js +0 -144
  502. package/dist/context/ingest/stages/validate-wu-sources.test.d.ts +0 -1
  503. package/dist/context/ingest/stages/validate-wu-sources.test.js +0 -27
  504. package/dist/context/ingest/tools/emit-reconciliation-records.tool.test.d.ts +0 -1
  505. package/dist/context/ingest/tools/emit-reconciliation-records.tool.test.js +0 -237
  506. package/dist/context/ingest/tools/eviction-list.tool.test.d.ts +0 -1
  507. package/dist/context/ingest/tools/eviction-list.tool.test.js +0 -44
  508. package/dist/context/ingest/tools/read-raw-file.tool.test.d.ts +0 -1
  509. package/dist/context/ingest/tools/read-raw-file.tool.test.js +0 -45
  510. package/dist/context/ingest/tools/read-raw-span.tool.test.d.ts +0 -1
  511. package/dist/context/ingest/tools/read-raw-span.tool.test.js +0 -34
  512. package/dist/context/ingest/tools/stage-diff.tool.test.d.ts +0 -1
  513. package/dist/context/ingest/tools/stage-diff.tool.test.js +0 -112
  514. package/dist/context/ingest/tools/stage-list.tool.test.d.ts +0 -1
  515. package/dist/context/ingest/tools/stage-list.tool.test.js +0 -58
  516. package/dist/context/ingest/tools/tool-transcript-summary.test.d.ts +0 -1
  517. package/dist/context/ingest/tools/tool-transcript-summary.test.js +0 -141
  518. package/dist/context/ingest/tools/warehouse-verification/discover-data.tool.test.d.ts +0 -1
  519. package/dist/context/ingest/tools/warehouse-verification/discover-data.tool.test.js +0 -107
  520. package/dist/context/ingest/tools/warehouse-verification/entity-details.tool.test.d.ts +0 -1
  521. package/dist/context/ingest/tools/warehouse-verification/entity-details.tool.test.js +0 -146
  522. package/dist/context/ingest/tools/warehouse-verification/sql-execution.tool.test.d.ts +0 -1
  523. package/dist/context/ingest/tools/warehouse-verification/sql-execution.tool.test.js +0 -50
  524. package/dist/context/ingest/wiki-body-refs.test.d.ts +0 -1
  525. package/dist/context/ingest/wiki-body-refs.test.js +0 -138
  526. package/dist/context/ingest/wiki-sl-ref-repair.test.d.ts +0 -1
  527. package/dist/context/ingest/wiki-sl-ref-repair.test.js +0 -81
  528. package/dist/context/llm/ai-sdk-runtime.test.d.ts +0 -1
  529. package/dist/context/llm/ai-sdk-runtime.test.js +0 -308
  530. package/dist/context/llm/claude-code-env.test.d.ts +0 -1
  531. package/dist/context/llm/claude-code-env.test.js +0 -17
  532. package/dist/context/llm/claude-code-models.test.d.ts +0 -1
  533. package/dist/context/llm/claude-code-models.test.js +0 -15
  534. package/dist/context/llm/claude-code-runtime.test.d.ts +0 -1
  535. package/dist/context/llm/claude-code-runtime.test.js +0 -434
  536. package/dist/context/llm/debug-request-recorder.test.d.ts +0 -1
  537. package/dist/context/llm/debug-request-recorder.test.js +0 -112
  538. package/dist/context/llm/embedding-port.test.d.ts +0 -1
  539. package/dist/context/llm/embedding-port.test.js +0 -34
  540. package/dist/context/llm/local-config.test.d.ts +0 -1
  541. package/dist/context/llm/local-config.test.js +0 -164
  542. package/dist/context/llm/runtime-local-config.test.d.ts +0 -1
  543. package/dist/context/llm/runtime-local-config.test.js +0 -17
  544. package/dist/context/llm/runtime-tools.test.d.ts +0 -1
  545. package/dist/context/llm/runtime-tools.test.js +0 -36
  546. package/dist/context/mcp/local-project-ports.test.d.ts +0 -1
  547. package/dist/context/mcp/local-project-ports.test.js +0 -689
  548. package/dist/context/mcp/server.test.d.ts +0 -1
  549. package/dist/context/mcp/server.test.js +0 -902
  550. package/dist/context/memory/local-memory.test.d.ts +0 -1
  551. package/dist/context/memory/local-memory.test.js +0 -173
  552. package/dist/context/memory/memory-agent.service.ingest.test.d.ts +0 -1
  553. package/dist/context/memory/memory-agent.service.ingest.test.js +0 -355
  554. package/dist/context/memory/memory-agent.service.test.d.ts +0 -1
  555. package/dist/context/memory/memory-agent.service.test.js +0 -413
  556. package/dist/context/memory/memory-runs.test.d.ts +0 -1
  557. package/dist/context/memory/memory-runs.test.js +0 -158
  558. package/dist/context/memory/memory-runtime-assets.test.d.ts +0 -1
  559. package/dist/context/memory/memory-runtime-assets.test.js +0 -162
  560. package/dist/context/project/config.test.d.ts +0 -1
  561. package/dist/context/project/config.test.js +0 -467
  562. package/dist/context/project/driver-schemas.test.d.ts +0 -1
  563. package/dist/context/project/driver-schemas.test.js +0 -125
  564. package/dist/context/project/local-git-file-store.test.d.ts +0 -1
  565. package/dist/context/project/local-git-file-store.test.js +0 -71
  566. package/dist/context/project/mappings-yaml-schema.test.d.ts +0 -1
  567. package/dist/context/project/mappings-yaml-schema.test.js +0 -79
  568. package/dist/context/project/project.test.d.ts +0 -1
  569. package/dist/context/project/project.test.js +0 -55
  570. package/dist/context/project/setup-config.test.d.ts +0 -1
  571. package/dist/context/project/setup-config.test.js +0 -38
  572. package/dist/context/prompts/prompt.service.test.d.ts +0 -1
  573. package/dist/context/prompts/prompt.service.test.js +0 -43
  574. package/dist/context/scan/credentials.test.d.ts +0 -1
  575. package/dist/context/scan/credentials.test.js +0 -162
  576. package/dist/context/scan/data-dictionary.test.d.ts +0 -1
  577. package/dist/context/scan/data-dictionary.test.js +0 -92
  578. package/dist/context/scan/description-generation.test.d.ts +0 -1
  579. package/dist/context/scan/description-generation.test.js +0 -693
  580. package/dist/context/scan/embedding-text.test.d.ts +0 -1
  581. package/dist/context/scan/embedding-text.test.js +0 -36
  582. package/dist/context/scan/enrichment-state.test.d.ts +0 -1
  583. package/dist/context/scan/enrichment-state.test.js +0 -147
  584. package/dist/context/scan/enrichment-summary.test.d.ts +0 -1
  585. package/dist/context/scan/enrichment-summary.test.js +0 -34
  586. package/dist/context/scan/enrichment-types.test.d.ts +0 -1
  587. package/dist/context/scan/enrichment-types.test.js +0 -141
  588. package/dist/context/scan/entity-details.test.d.ts +0 -1
  589. package/dist/context/scan/entity-details.test.js +0 -234
  590. package/dist/context/scan/local-enrichment-artifacts.test.d.ts +0 -1
  591. package/dist/context/scan/local-enrichment-artifacts.test.js +0 -771
  592. package/dist/context/scan/local-enrichment.test.d.ts +0 -1
  593. package/dist/context/scan/local-enrichment.test.js +0 -765
  594. package/dist/context/scan/local-scan.test.d.ts +0 -1
  595. package/dist/context/scan/local-scan.test.js +0 -1663
  596. package/dist/context/scan/local-structural-artifacts.test.d.ts +0 -1
  597. package/dist/context/scan/local-structural-artifacts.test.js +0 -144
  598. package/dist/context/scan/relationship-benchmark-report.test.d.ts +0 -1
  599. package/dist/context/scan/relationship-benchmark-report.test.js +0 -389
  600. package/dist/context/scan/relationship-benchmarks.test.d.ts +0 -1
  601. package/dist/context/scan/relationship-benchmarks.test.js +0 -1072
  602. package/dist/context/scan/relationship-budget.test.d.ts +0 -1
  603. package/dist/context/scan/relationship-budget.test.js +0 -71
  604. package/dist/context/scan/relationship-candidates.test.d.ts +0 -1
  605. package/dist/context/scan/relationship-candidates.test.js +0 -747
  606. package/dist/context/scan/relationship-composite-candidates.test.d.ts +0 -1
  607. package/dist/context/scan/relationship-composite-candidates.test.js +0 -69
  608. package/dist/context/scan/relationship-diagnostics.test.d.ts +0 -1
  609. package/dist/context/scan/relationship-diagnostics.test.js +0 -333
  610. package/dist/context/scan/relationship-discovery.test.d.ts +0 -1
  611. package/dist/context/scan/relationship-discovery.test.js +0 -618
  612. package/dist/context/scan/relationship-formal-metadata.test.d.ts +0 -1
  613. package/dist/context/scan/relationship-formal-metadata.test.js +0 -125
  614. package/dist/context/scan/relationship-graph-resolver.test.d.ts +0 -1
  615. package/dist/context/scan/relationship-graph-resolver.test.js +0 -604
  616. package/dist/context/scan/relationship-llm-proposal.test.d.ts +0 -1
  617. package/dist/context/scan/relationship-llm-proposal.test.js +0 -197
  618. package/dist/context/scan/relationship-locality.test.d.ts +0 -1
  619. package/dist/context/scan/relationship-locality.test.js +0 -128
  620. package/dist/context/scan/relationship-name-similarity.test.d.ts +0 -1
  621. package/dist/context/scan/relationship-name-similarity.test.js +0 -68
  622. package/dist/context/scan/relationship-profiling.test.d.ts +0 -1
  623. package/dist/context/scan/relationship-profiling.test.js +0 -392
  624. package/dist/context/scan/relationship-scoring.test.d.ts +0 -1
  625. package/dist/context/scan/relationship-scoring.test.js +0 -86
  626. package/dist/context/scan/relationship-validation.test.d.ts +0 -1
  627. package/dist/context/scan/relationship-validation.test.js +0 -455
  628. package/dist/context/scan/table-ref.test.d.ts +0 -1
  629. package/dist/context/scan/table-ref.test.js +0 -53
  630. package/dist/context/scan/type-normalization.test.d.ts +0 -1
  631. package/dist/context/scan/type-normalization.test.js +0 -21
  632. package/dist/context/scan/types.test.d.ts +0 -1
  633. package/dist/context/scan/types.test.js +0 -206
  634. package/dist/context/scan/warehouse-catalog.test.d.ts +0 -1
  635. package/dist/context/scan/warehouse-catalog.test.js +0 -158
  636. package/dist/context/search/backend-conformance.test-utils.d.ts +0 -39
  637. package/dist/context/search/backend-conformance.test-utils.js +0 -88
  638. package/dist/context/search/backend-conformance.test-utils.test.d.ts +0 -1
  639. package/dist/context/search/backend-conformance.test-utils.test.js +0 -408
  640. package/dist/context/search/discover.test.d.ts +0 -1
  641. package/dist/context/search/discover.test.js +0 -197
  642. package/dist/context/search/hybrid-search-core.test.d.ts +0 -1
  643. package/dist/context/search/hybrid-search-core.test.js +0 -113
  644. package/dist/context/search/pglite-owner-process.test.d.ts +0 -1
  645. package/dist/context/search/pglite-owner-process.test.js +0 -273
  646. package/dist/context/search/pglite-runtime-boundary.test.d.ts +0 -1
  647. package/dist/context/search/pglite-runtime-boundary.test.js +0 -40
  648. package/dist/context/search/pglite-spike.test.d.ts +0 -1
  649. package/dist/context/search/pglite-spike.test.js +0 -249
  650. package/dist/context/search/query.test.d.ts +0 -1
  651. package/dist/context/search/query.test.js +0 -23
  652. package/dist/context/search/rrf.test.d.ts +0 -1
  653. package/dist/context/search/rrf.test.js +0 -47
  654. package/dist/context/skills/skills-registry.service.test.d.ts +0 -1
  655. package/dist/context/skills/skills-registry.service.test.js +0 -161
  656. package/dist/context/sl/dictionary-search.test.d.ts +0 -1
  657. package/dist/context/sl/dictionary-search.test.js +0 -204
  658. package/dist/context/sl/local-query.test.d.ts +0 -1
  659. package/dist/context/sl/local-query.test.js +0 -283
  660. package/dist/context/sl/local-sl.test.d.ts +0 -1
  661. package/dist/context/sl/local-sl.test.js +0 -334
  662. package/dist/context/sl/pglite-sl-search-prototype.test.d.ts +0 -1
  663. package/dist/context/sl/pglite-sl-search-prototype.test.js +0 -240
  664. package/dist/context/sl/schemas.contract.test.d.ts +0 -1
  665. package/dist/context/sl/schemas.contract.test.js +0 -62
  666. package/dist/context/sl/semantic-layer.service.test.d.ts +0 -1
  667. package/dist/context/sl/semantic-layer.service.test.js +0 -1107
  668. package/dist/context/sl/sl-dictionary-profile.test.d.ts +0 -1
  669. package/dist/context/sl/sl-dictionary-profile.test.js +0 -88
  670. package/dist/context/sl/sl-search.service.test.d.ts +0 -1
  671. package/dist/context/sl/sl-search.service.test.js +0 -256
  672. package/dist/context/sl/sqlite-sl-sources-index.test.d.ts +0 -1
  673. package/dist/context/sl/sqlite-sl-sources-index.test.js +0 -175
  674. package/dist/context/sl/tools/connection-id-schema.test.d.ts +0 -1
  675. package/dist/context/sl/tools/connection-id-schema.test.js +0 -14
  676. package/dist/context/sl/tools/sl-discover.tool.test.d.ts +0 -1
  677. package/dist/context/sl/tools/sl-discover.tool.test.js +0 -72
  678. package/dist/context/sl/tools/sl-edit-source.tool.test.d.ts +0 -1
  679. package/dist/context/sl/tools/sl-edit-source.tool.test.js +0 -184
  680. package/dist/context/sl/tools/sl-read-source.tool.session.test.d.ts +0 -1
  681. package/dist/context/sl/tools/sl-read-source.tool.session.test.js +0 -55
  682. package/dist/context/sl/tools/sl-rollback.tool.test.d.ts +0 -1
  683. package/dist/context/sl/tools/sl-rollback.tool.test.js +0 -57
  684. package/dist/context/sl/tools/sl-validate.tool.test.d.ts +0 -1
  685. package/dist/context/sl/tools/sl-validate.tool.test.js +0 -54
  686. package/dist/context/sl/tools/sl-warehouse-validation.test.d.ts +0 -1
  687. package/dist/context/sl/tools/sl-warehouse-validation.test.js +0 -136
  688. package/dist/context/sl/tools/sl-write-source.tool.test.d.ts +0 -1
  689. package/dist/context/sl/tools/sl-write-source.tool.test.js +0 -307
  690. package/dist/context/sql-analysis/http-sql-analysis-port.test.d.ts +0 -1
  691. package/dist/context/sql-analysis/http-sql-analysis-port.test.js +0 -147
  692. package/dist/context/test/make-local-git-repo.d.ts +0 -10
  693. package/dist/context/test/make-local-git-repo.js +0 -34
  694. package/dist/context/tools/context-evidence-tools.test.d.ts +0 -1
  695. package/dist/context/tools/context-evidence-tools.test.js +0 -486
  696. package/dist/context/tools/touched-sl-sources.test.d.ts +0 -1
  697. package/dist/context/tools/touched-sl-sources.test.js +0 -31
  698. package/dist/context/wiki/knowledge-wiki.service.test.d.ts +0 -1
  699. package/dist/context/wiki/knowledge-wiki.service.test.js +0 -205
  700. package/dist/context/wiki/local-knowledge.test.d.ts +0 -1
  701. package/dist/context/wiki/local-knowledge.test.js +0 -270
  702. package/dist/context/wiki/sqlite-knowledge-index.test.d.ts +0 -1
  703. package/dist/context/wiki/sqlite-knowledge-index.test.js +0 -129
  704. package/dist/context/wiki/tools/wiki-list-tags.tool.test.d.ts +0 -1
  705. package/dist/context/wiki/tools/wiki-list-tags.tool.test.js +0 -35
  706. package/dist/context/wiki/tools/wiki-read.tool.test.d.ts +0 -1
  707. package/dist/context/wiki/tools/wiki-read.tool.test.js +0 -66
  708. package/dist/context/wiki/tools/wiki-remove.tool.test.d.ts +0 -1
  709. package/dist/context/wiki/tools/wiki-remove.tool.test.js +0 -95
  710. package/dist/context/wiki/tools/wiki-search.tool.test.d.ts +0 -1
  711. package/dist/context/wiki/tools/wiki-search.tool.test.js +0 -35
  712. package/dist/context/wiki/tools/wiki-write.tool.test.d.ts +0 -1
  713. package/dist/context/wiki/tools/wiki-write.tool.test.js +0 -264
  714. package/dist/context/wiki/wiki-ref-validation.test.d.ts +0 -1
  715. package/dist/context/wiki/wiki-ref-validation.test.js +0 -64
  716. package/dist/context-build-view.test.d.ts +0 -1
  717. package/dist/context-build-view.test.js +0 -942
  718. package/dist/database-tree-picker.test.d.ts +0 -1
  719. package/dist/database-tree-picker.test.js +0 -188
  720. package/dist/demo-assets.test.d.ts +0 -1
  721. package/dist/demo-assets.test.js +0 -121
  722. package/dist/demo-metrics.test.d.ts +0 -1
  723. package/dist/demo-metrics.test.js +0 -108
  724. package/dist/doctor.test.d.ts +0 -1
  725. package/dist/doctor.test.js +0 -596
  726. package/dist/embedding-resolution.test.d.ts +0 -1
  727. package/dist/embedding-resolution.test.js +0 -132
  728. package/dist/example-smoke.test.d.ts +0 -1
  729. package/dist/example-smoke.test.js +0 -83
  730. package/dist/index.test.d.ts +0 -1
  731. package/dist/index.test.js +0 -1300
  732. package/dist/ingest-query-executor.test.d.ts +0 -1
  733. package/dist/ingest-query-executor.test.js +0 -71
  734. package/dist/ingest-report-file.test.d.ts +0 -1
  735. package/dist/ingest-report-file.test.js +0 -63
  736. package/dist/ingest-viz.test.d.ts +0 -1
  737. package/dist/ingest-viz.test.js +0 -691
  738. package/dist/ingest.test-utils.d.ts +0 -126
  739. package/dist/ingest.test-utils.js +0 -629
  740. package/dist/ingest.test.d.ts +0 -1
  741. package/dist/ingest.test.js +0 -1568
  742. package/dist/io/logger.test.d.ts +0 -1
  743. package/dist/io/logger.test.js +0 -55
  744. package/dist/io/mode.test.d.ts +0 -1
  745. package/dist/io/mode.test.js +0 -48
  746. package/dist/io/print-list.test.d.ts +0 -1
  747. package/dist/io/print-list.test.js +0 -277
  748. package/dist/knowledge.test.d.ts +0 -1
  749. package/dist/knowledge.test.js +0 -198
  750. package/dist/llm/embedding-health.test.d.ts +0 -1
  751. package/dist/llm/embedding-health.test.js +0 -72
  752. package/dist/llm/embedding-provider.test.d.ts +0 -1
  753. package/dist/llm/embedding-provider.test.js +0 -84
  754. package/dist/llm/message-builder.test.d.ts +0 -1
  755. package/dist/llm/message-builder.test.js +0 -127
  756. package/dist/llm/model-health.test.d.ts +0 -1
  757. package/dist/llm/model-health.test.js +0 -55
  758. package/dist/llm/model-provider.test.d.ts +0 -1
  759. package/dist/llm/model-provider.test.js +0 -246
  760. package/dist/llm/repair.test.d.ts +0 -1
  761. package/dist/llm/repair.test.js +0 -78
  762. package/dist/local-adapters.test.d.ts +0 -1
  763. package/dist/local-adapters.test.js +0 -166
  764. package/dist/local-scan-connectors.test.d.ts +0 -1
  765. package/dist/local-scan-connectors.test.js +0 -92
  766. package/dist/managed-local-embeddings.test.d.ts +0 -1
  767. package/dist/managed-local-embeddings.test.js +0 -229
  768. package/dist/managed-mcp-daemon.test.d.ts +0 -1
  769. package/dist/managed-mcp-daemon.test.js +0 -187
  770. package/dist/managed-python-command.test.d.ts +0 -1
  771. package/dist/managed-python-command.test.js +0 -262
  772. package/dist/managed-python-daemon.test.d.ts +0 -1
  773. package/dist/managed-python-daemon.test.js +0 -360
  774. package/dist/managed-python-http.test.d.ts +0 -1
  775. package/dist/managed-python-http.test.js +0 -177
  776. package/dist/managed-python-runtime.test.d.ts +0 -1
  777. package/dist/managed-python-runtime.test.js +0 -426
  778. package/dist/mcp-http-server.test.d.ts +0 -1
  779. package/dist/mcp-http-server.test.js +0 -209
  780. package/dist/mcp-server-factory.test.d.ts +0 -1
  781. package/dist/mcp-server-factory.test.js +0 -142
  782. package/dist/memory-flow-interactive.test.d.ts +0 -1
  783. package/dist/memory-flow-interactive.test.js +0 -109
  784. package/dist/memory-flow-tui.test.d.ts +0 -1
  785. package/dist/memory-flow-tui.test.js +0 -247
  786. package/dist/next-steps.test.d.ts +0 -1
  787. package/dist/next-steps.test.js +0 -77
  788. package/dist/notion-page-picker.test.d.ts +0 -1
  789. package/dist/notion-page-picker.test.js +0 -244
  790. package/dist/print-command-tree.test.d.ts +0 -1
  791. package/dist/print-command-tree.test.js +0 -37
  792. package/dist/project-dir.test.d.ts +0 -1
  793. package/dist/project-dir.test.js +0 -124
  794. package/dist/project-resolver.test.d.ts +0 -1
  795. package/dist/project-resolver.test.js +0 -49
  796. package/dist/prompt-navigation.test.d.ts +0 -1
  797. package/dist/prompt-navigation.test.js +0 -33
  798. package/dist/proxy-env.test.d.ts +0 -1
  799. package/dist/proxy-env.test.js +0 -17
  800. package/dist/public-ingest-copy.test.d.ts +0 -1
  801. package/dist/public-ingest-copy.test.js +0 -24
  802. package/dist/public-ingest.test.d.ts +0 -1
  803. package/dist/public-ingest.test.js +0 -891
  804. package/dist/runtime-requirements.test.d.ts +0 -1
  805. package/dist/runtime-requirements.test.js +0 -73
  806. package/dist/runtime.test.d.ts +0 -1
  807. package/dist/runtime.test.js +0 -381
  808. package/dist/scan.test.d.ts +0 -1
  809. package/dist/scan.test.js +0 -1123
  810. package/dist/setup-agents.test.d.ts +0 -1
  811. package/dist/setup-agents.test.js +0 -1028
  812. package/dist/setup-context.test.d.ts +0 -1
  813. package/dist/setup-context.test.js +0 -491
  814. package/dist/setup-databases.test.d.ts +0 -1
  815. package/dist/setup-databases.test.js +0 -2101
  816. package/dist/setup-demo-tour.test.d.ts +0 -1
  817. package/dist/setup-demo-tour.test.js +0 -221
  818. package/dist/setup-embeddings.test.d.ts +0 -1
  819. package/dist/setup-embeddings.test.js +0 -436
  820. package/dist/setup-interrupt.test.d.ts +0 -1
  821. package/dist/setup-interrupt.test.js +0 -77
  822. package/dist/setup-models.test.d.ts +0 -1
  823. package/dist/setup-models.test.js +0 -885
  824. package/dist/setup-project.test.d.ts +0 -1
  825. package/dist/setup-project.test.js +0 -209
  826. package/dist/setup-prompts.test.d.ts +0 -1
  827. package/dist/setup-prompts.test.js +0 -208
  828. package/dist/setup-ready-menu.test.d.ts +0 -1
  829. package/dist/setup-ready-menu.test.js +0 -44
  830. package/dist/setup-runtime.test.d.ts +0 -1
  831. package/dist/setup-runtime.test.js +0 -111
  832. package/dist/setup-secrets.test.d.ts +0 -1
  833. package/dist/setup-secrets.test.js +0 -30
  834. package/dist/setup-sources-notion.test.d.ts +0 -1
  835. package/dist/setup-sources-notion.test.js +0 -109
  836. package/dist/setup-sources.test.d.ts +0 -1
  837. package/dist/setup-sources.test.js +0 -1303
  838. package/dist/setup.test.d.ts +0 -1
  839. package/dist/setup.test.js +0 -1825
  840. package/dist/sl.test.d.ts +0 -1
  841. package/dist/sl.test.js +0 -567
  842. package/dist/source-mapping.test.d.ts +0 -1
  843. package/dist/source-mapping.test.js +0 -65
  844. package/dist/sql.test.d.ts +0 -1
  845. package/dist/sql.test.js +0 -253
  846. package/dist/standalone-smoke.test.d.ts +0 -1
  847. package/dist/standalone-smoke.test.js +0 -250
  848. package/dist/status-project.test.d.ts +0 -1
  849. package/dist/status-project.test.js +0 -502
  850. package/dist/telemetry/command-hook.test.d.ts +0 -1
  851. package/dist/telemetry/command-hook.test.js +0 -31
  852. package/dist/telemetry/demo-detect.test.d.ts +0 -1
  853. package/dist/telemetry/demo-detect.test.js +0 -22
  854. package/dist/telemetry/emitter.test.d.ts +0 -1
  855. package/dist/telemetry/emitter.test.js +0 -103
  856. package/dist/telemetry/events.snapshot.test.d.ts +0 -1
  857. package/dist/telemetry/events.snapshot.test.js +0 -135
  858. package/dist/telemetry/events.test.d.ts +0 -1
  859. package/dist/telemetry/events.test.js +0 -136
  860. package/dist/telemetry/identity.test.d.ts +0 -1
  861. package/dist/telemetry/identity.test.js +0 -148
  862. package/dist/telemetry/project-snapshot.test.d.ts +0 -1
  863. package/dist/telemetry/project-snapshot.test.js +0 -71
  864. package/dist/telemetry/schema-writer.test.d.ts +0 -1
  865. package/dist/telemetry/schema-writer.test.js +0 -23
  866. package/dist/telemetry/scrubber.test.d.ts +0 -1
  867. package/dist/telemetry/scrubber.test.js +0 -21
  868. package/dist/text-ingest.test.d.ts +0 -1
  869. package/dist/text-ingest.test.js +0 -247
  870. package/dist/tree-picker-state.test.d.ts +0 -1
  871. package/dist/tree-picker-state.test.js +0 -303
  872. package/dist/tree-picker-tui.test.d.ts +0 -1
  873. package/dist/tree-picker-tui.test.js +0 -248
  874. package/dist/viz-fallback.test.d.ts +0 -1
  875. package/dist/viz-fallback.test.js +0 -77
@@ -1,1303 +0,0 @@
1
- import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
2
- import { tmpdir } from 'node:os';
3
- import { join } from 'node:path';
4
- import { initKtxProject } from './context/project/project.js';
5
- import { parseKtxProjectConfig, serializeKtxProjectConfig } from './context/project/config.js';
6
- import { readKtxSetupState } from './context/project/setup-config.js';
7
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
8
- import { runKtxSetupSourcesStep, } from './setup-sources.js';
9
- function makeIo() {
10
- let stdout = '';
11
- let stderr = '';
12
- return {
13
- io: {
14
- stdout: {
15
- isTTY: true,
16
- write: (chunk) => {
17
- stdout += chunk;
18
- },
19
- },
20
- stderr: {
21
- write: (chunk) => {
22
- stderr += chunk;
23
- },
24
- },
25
- },
26
- stdout: () => stdout,
27
- stderr: () => stderr,
28
- };
29
- }
30
- function prompts(values) {
31
- const multiselectValues = [...(values.multiselect ?? [])];
32
- const selectValues = [...(values.select ?? [])];
33
- const textValues = [...(values.text ?? [])];
34
- const passwordValues = [...(values.password ?? [])];
35
- return {
36
- multiselect: vi.fn(async () => multiselectValues.shift() ?? []),
37
- select: vi.fn(async () => selectValues.shift() ?? 'skip'),
38
- autocomplete: vi.fn(async () => selectValues.shift() ?? 'skip'),
39
- text: vi.fn(async () => (textValues.length > 0 ? textValues.shift() : '')),
40
- password: vi.fn(async () => (passwordValues.length > 0 ? passwordValues.shift() : undefined)),
41
- cancel: vi.fn(),
42
- log: vi.fn(),
43
- };
44
- }
45
- function connectionNamePrompt(label) {
46
- return `Name this ${label} connection\nKTX will use this short name in commands and config. You can rename it now.`;
47
- }
48
- function textInputPrompt(message) {
49
- const normalized = message.replace(/\n+$/, '');
50
- if (!normalized.includes('\n')) {
51
- return `${normalized}\n│ Press Escape to go back.\n│`;
52
- }
53
- const [title, ...bodyLines] = normalized.split('\n');
54
- return `${title}\n│\n│ ${bodyLines.join('\n│ ')}\n│ Press Escape to go back.\n│`;
55
- }
56
- describe('setup sources step', () => {
57
- let tempDir;
58
- let projectDir;
59
- beforeEach(async () => {
60
- tempDir = await mkdtemp(join(tmpdir(), 'ktx-setup-sources-'));
61
- projectDir = join(tempDir, 'project');
62
- await initKtxProject({ projectDir });
63
- });
64
- afterEach(async () => {
65
- vi.unstubAllEnvs();
66
- await rm(tempDir, { recursive: true, force: true });
67
- });
68
- async function readConfig() {
69
- return parseKtxProjectConfig(await readFile(join(projectDir, 'ktx.yaml'), 'utf-8'));
70
- }
71
- async function addPrimarySource() {
72
- const config = await readConfig();
73
- await writeFile(join(projectDir, 'ktx.yaml'), serializeKtxProjectConfig({
74
- ...config,
75
- connections: {
76
- ...config.connections,
77
- warehouse: { driver: 'postgres', url: 'env:DATABASE_URL' },
78
- },
79
- setup: {
80
- ...config.setup,
81
- database_connection_ids: ['warehouse'],
82
- },
83
- }), 'utf-8');
84
- }
85
- async function addConnection(connectionId, connection) {
86
- const config = await readConfig();
87
- await writeFile(join(projectDir, 'ktx.yaml'), serializeKtxProjectConfig({
88
- ...config,
89
- connections: {
90
- ...config.connections,
91
- [connectionId]: connection,
92
- },
93
- }), 'utf-8');
94
- }
95
- it('marks optional sources complete when skipped', async () => {
96
- const io = makeIo();
97
- await expect(runKtxSetupSourcesStep({ projectDir, inputMode: 'disabled', runInitialSourceIngest: false, skipSources: true }, io.io)).resolves.toEqual({
98
- status: 'skipped',
99
- projectDir,
100
- });
101
- expect((await readKtxSetupState(projectDir)).completed_steps).toContain('sources');
102
- expect(io.stdout()).toContain('Context source setup skipped.');
103
- });
104
- it('writes a dbt local source connection after validation succeeds', async () => {
105
- await addPrimarySource();
106
- const validateDbt = vi.fn(async () => ({ ok: true, detail: 'project=analytics schemas=2' }));
107
- const runInitialIngest = vi.fn(async () => 0);
108
- const io = makeIo();
109
- await expect(runKtxSetupSourcesStep({
110
- projectDir,
111
- inputMode: 'disabled',
112
- source: 'dbt',
113
- sourceConnectionId: 'analytics_dbt',
114
- sourcePath: '/repo/dbt',
115
- sourceProjectName: 'analytics',
116
- runInitialSourceIngest: true,
117
- skipSources: false,
118
- }, io.io, { validateDbt, runInitialIngest })).resolves.toEqual({ status: 'ready', projectDir, connectionIds: ['analytics_dbt'] });
119
- const config = await readConfig();
120
- expect(config.connections.analytics_dbt).toMatchObject({
121
- driver: 'dbt',
122
- source_dir: '/repo/dbt',
123
- project_name: 'analytics',
124
- });
125
- expect((await readKtxSetupState(projectDir)).completed_steps).toContain('sources');
126
- expect(runInitialIngest).toHaveBeenCalledWith(projectDir, 'analytics_dbt', io.io, { inputMode: 'disabled' });
127
- });
128
- it('emits debug telemetry when setup writes a source connection', async () => {
129
- vi.stubEnv('KTX_TELEMETRY_DEBUG', '1');
130
- vi.stubEnv('CI', '');
131
- await addPrimarySource();
132
- const io = makeIo();
133
- const result = await runKtxSetupSourcesStep({
134
- projectDir,
135
- inputMode: 'disabled',
136
- source: 'dbt',
137
- sourceConnectionId: 'analytics_dbt',
138
- sourcePath: '/repo/dbt',
139
- sourceProjectName: 'analytics',
140
- runInitialSourceIngest: false,
141
- skipSources: false,
142
- }, io.io, { validateDbt: vi.fn(async () => ({ ok: true, detail: 'project=analytics schemas=2' })) });
143
- expect(result.status).toBe('ready');
144
- expect(io.stderr()).toContain('"event":"connection_added"');
145
- expect(io.stderr()).toContain('"driver":"dbt"');
146
- expect(io.stderr()).toContain('"isDemoConnection":false');
147
- expect(io.stderr()).not.toContain(projectDir);
148
- });
149
- it('writes Metabase config and validates mapping through existing mapping path', async () => {
150
- await addPrimarySource();
151
- const validateMetabase = vi.fn(async () => ({ ok: true, detail: 'user=admin@example.com' }));
152
- const runMapping = vi.fn(async (_projectDir, _connectionId, commandIo) => {
153
- commandIo.stdout.write('Mapping validated — 1 mapping configured\n');
154
- return 0;
155
- });
156
- const io = makeIo();
157
- await expect(runKtxSetupSourcesStep({
158
- projectDir,
159
- inputMode: 'disabled',
160
- source: 'metabase',
161
- sourceConnectionId: 'prod_metabase',
162
- sourceUrl: 'https://metabase.example.com',
163
- sourceApiKeyRef: 'env:METABASE_API_KEY', // pragma: allowlist secret
164
- sourceWarehouseConnectionId: 'warehouse',
165
- metabaseDatabaseId: 1,
166
- runInitialSourceIngest: false,
167
- skipSources: false,
168
- }, io.io, { validateMetabase, runMapping })).resolves.toEqual({ status: 'ready', projectDir, connectionIds: ['prod_metabase'] });
169
- expect((await readConfig()).connections.prod_metabase).toMatchObject({
170
- driver: 'metabase',
171
- api_url: 'https://metabase.example.com',
172
- api_key_ref: 'env:METABASE_API_KEY', // pragma: allowlist secret
173
- mappings: {
174
- databaseMappings: { '1': 'warehouse' },
175
- syncEnabled: { '1': true },
176
- syncMode: 'ALL',
177
- },
178
- });
179
- expect(runMapping).toHaveBeenCalledWith(projectDir, 'prod_metabase', expect.objectContaining({
180
- stdout: expect.objectContaining({ write: expect.any(Function) }),
181
- stderr: expect.objectContaining({ write: expect.any(Function) }),
182
- }));
183
- expect(io.stdout()).toContain('│ Mapping validated — 1 mapping configured');
184
- expect(io.stdout()).not.toMatch(/^Mapping validated — 1 mapping configured$/m);
185
- });
186
- it('writes Notion config with the full default knowledge create budget', async () => {
187
- await addPrimarySource();
188
- const validateNotion = vi.fn(async () => ({ ok: true, detail: 'roots=1' }));
189
- await expect(runKtxSetupSourcesStep({
190
- projectDir,
191
- inputMode: 'disabled',
192
- source: 'notion',
193
- sourceConnectionId: 'notion-main',
194
- sourceApiKeyRef: 'env:NOTION_TOKEN', // pragma: allowlist secret
195
- notionCrawlMode: 'selected_roots',
196
- notionRootPageIds: ['page-1'],
197
- runInitialSourceIngest: false,
198
- skipSources: false,
199
- }, makeIo().io, { validateNotion })).resolves.toEqual({ status: 'ready', projectDir, connectionIds: ['notion-main'] });
200
- expect((await readConfig()).connections['notion-main']).toMatchObject({
201
- driver: 'notion',
202
- auth_token_ref: 'env:NOTION_TOKEN',
203
- root_page_ids: ['page-1'],
204
- max_knowledge_creates_per_run: 25,
205
- max_knowledge_updates_per_run: 20,
206
- });
207
- expect((await readConfig()).connections['notion-main']?.last_successful_cursor).toBeUndefined();
208
- });
209
- it('accepts former ingest subcommand names as interactive source connection ids', async () => {
210
- await addPrimarySource();
211
- const io = makeIo();
212
- const validateNotion = vi.fn(async () => ({ ok: true, detail: 'workspace=ok' }));
213
- const result = await runKtxSetupSourcesStep({
214
- projectDir,
215
- inputMode: 'auto',
216
- runInitialSourceIngest: false,
217
- skipSources: false,
218
- }, io.io, {
219
- prompts: prompts({
220
- multiselect: [['notion']],
221
- text: ['status', 'env:NOTION_TOKEN'],
222
- select: ['env', 'all_accessible'],
223
- }),
224
- validateNotion,
225
- });
226
- expect(result.status).toBe('ready');
227
- const config = await readConfig();
228
- expect(config.connections.status).toMatchObject({
229
- driver: 'notion',
230
- auth_token_ref: 'env:NOTION_TOKEN',
231
- });
232
- });
233
- it('uses selected Notion roots when root page ids are provided even if crawl mode says all accessible', async () => {
234
- await addPrimarySource();
235
- const validateNotion = vi.fn(async () => ({ ok: true, detail: 'roots=1' }));
236
- await expect(runKtxSetupSourcesStep({
237
- projectDir,
238
- inputMode: 'disabled',
239
- source: 'notion',
240
- sourceConnectionId: 'notion-main',
241
- sourceApiKeyRef: 'env:NOTION_TOKEN', // pragma: allowlist secret
242
- notionCrawlMode: 'all_accessible',
243
- notionRootPageIds: ['page-1'],
244
- runInitialSourceIngest: false,
245
- skipSources: false,
246
- }, makeIo().io, { validateNotion })).resolves.toEqual({ status: 'ready', projectDir, connectionIds: ['notion-main'] });
247
- expect((await readConfig()).connections['notion-main']).toMatchObject({
248
- driver: 'notion',
249
- root_page_ids: ['page-1'],
250
- crawl_mode: 'selected_roots',
251
- });
252
- });
253
- it('uses the rich Notion picker for interactive selected root setup', async () => {
254
- await addPrimarySource();
255
- const validateNotion = vi.fn(async () => ({ ok: true, detail: 'roots=1' }));
256
- const pickNotionRootPages = vi.fn(async (input) => {
257
- expect(input.connectionId).toBe('notion-main');
258
- expect(input.connection).toMatchObject({
259
- driver: 'notion',
260
- auth_token_ref: 'env:NOTION_TOKEN',
261
- crawl_mode: 'selected_roots',
262
- root_page_ids: [],
263
- });
264
- return { kind: 'selected', rootPageIds: ['11111111-2222-3333-4444-555555555555'] };
265
- });
266
- const testPrompts = prompts({
267
- multiselect: [['notion']],
268
- select: ['env', 'selected_roots', 'done'],
269
- text: ['notion-main'],
270
- });
271
- await expect(runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: false, skipSources: false }, makeIo().io, { prompts: testPrompts, validateNotion, pickNotionRootPages })).resolves.toEqual({ status: 'ready', projectDir, connectionIds: ['notion-main'] });
272
- expect(pickNotionRootPages).toHaveBeenCalledOnce();
273
- expect(testPrompts.select).toHaveBeenCalledWith({
274
- message: 'Which Notion pages should KTX ingest?',
275
- options: [
276
- { value: 'selected_roots', label: 'Specific pages and their subpages (choose them in a picker)' },
277
- { value: 'all_accessible', label: 'All pages the integration can access' },
278
- { value: 'back', label: 'Back' },
279
- ],
280
- });
281
- expect((await readConfig()).connections['notion-main']).toMatchObject({
282
- driver: 'notion',
283
- auth_token_ref: 'env:NOTION_TOKEN',
284
- crawl_mode: 'selected_roots',
285
- root_page_ids: ['11111111-2222-3333-4444-555555555555'],
286
- });
287
- });
288
- it('backs out of the Notion picker without writing selected_roots when the picker quits', async () => {
289
- await addPrimarySource();
290
- const validateNotion = vi.fn(async () => ({ ok: true, detail: 'roots=0' }));
291
- const pickNotionRootPages = vi.fn(async () => ({ kind: 'back' }));
292
- const testPrompts = prompts({
293
- multiselect: [['notion']],
294
- select: ['env', 'selected_roots', 'all_accessible', 'done'],
295
- text: ['notion-main'],
296
- });
297
- await expect(runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: false, skipSources: false }, makeIo().io, { prompts: testPrompts, validateNotion, pickNotionRootPages })).resolves.toEqual({ status: 'ready', projectDir, connectionIds: ['notion-main'] });
298
- expect(pickNotionRootPages).toHaveBeenCalledOnce();
299
- expect((await readConfig()).connections['notion-main']).toMatchObject({
300
- driver: 'notion',
301
- crawl_mode: 'all_accessible',
302
- });
303
- expect((await readConfig()).connections['notion-main']?.root_page_ids).toBeUndefined();
304
- });
305
- it('surfaces Notion picker failures and returns to the page-mode step', async () => {
306
- await addPrimarySource();
307
- const validateNotion = vi.fn(async () => ({ ok: true, detail: 'roots=0' }));
308
- const pickNotionRootPages = vi.fn(async () => ({
309
- kind: 'unavailable',
310
- message: 'Notion picker requires a TTY',
311
- }));
312
- const testPrompts = prompts({
313
- multiselect: [['notion']],
314
- select: ['env', 'selected_roots', 'all_accessible', 'done'],
315
- text: ['notion-main'],
316
- });
317
- const io = makeIo();
318
- await expect(runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: false, skipSources: false }, io.io, { prompts: testPrompts, validateNotion, pickNotionRootPages })).resolves.toEqual({ status: 'ready', projectDir, connectionIds: ['notion-main'] });
319
- expect(io.stderr()).toContain('Notion picker requires a TTY');
320
- expect((await readConfig()).connections['notion-main']).toMatchObject({
321
- driver: 'notion',
322
- crawl_mode: 'all_accessible',
323
- });
324
- });
325
- it('defaults interactive Metabase and Looker source setup to the only warehouse connection', async () => {
326
- await addPrimarySource();
327
- const cases = [
328
- {
329
- source: 'metabase',
330
- text: ['metabase-main', 'https://metabase.example.com'],
331
- deps: {
332
- discoverMetabaseDatabases: vi.fn(async () => [
333
- { id: 1, name: 'Analytics', engine: 'postgres', host: 'db.example.com', dbName: 'analytics' },
334
- ]),
335
- validateMetabase: vi.fn(async () => ({ ok: true, detail: 'mapping validated' })),
336
- runMapping: vi.fn(async () => 0),
337
- },
338
- expectedConnection: {
339
- driver: 'metabase',
340
- mappings: { databaseMappings: { '1': 'warehouse' } },
341
- },
342
- },
343
- {
344
- source: 'looker',
345
- text: ['looker-main', 'https://looker.example.com', 'client-id', ''],
346
- deps: {
347
- validateLooker: vi.fn(async () => ({ ok: true, detail: 'mapping refreshed' })),
348
- runMapping: vi.fn(async () => 0),
349
- },
350
- expectedConnection: {
351
- driver: 'looker',
352
- mappings: { connectionMappings: { warehouse: 'warehouse' } },
353
- },
354
- },
355
- ];
356
- for (const testCase of cases) {
357
- const testPrompts = prompts({
358
- multiselect: [[testCase.source]],
359
- select: ['env', 'done'],
360
- text: testCase.text,
361
- });
362
- await expect(runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: false, skipSources: false }, makeIo().io, {
363
- prompts: testPrompts,
364
- ...testCase.deps,
365
- })).resolves.toEqual({ status: 'ready', projectDir, connectionIds: [`${testCase.source}-main`] });
366
- expect(vi.mocked(testPrompts.text).mock.calls.some(([options]) => options.message.includes('Mapped warehouse'))).toBe(false);
367
- if (testCase.source === 'metabase') {
368
- expect(vi.mocked(testPrompts.text).mock.calls.some(([options]) => options.message.includes('Metabase database id'))).toBe(false);
369
- }
370
- expect((await readConfig()).connections[`${testCase.source}-main`]).toMatchObject(testCase.expectedConnection);
371
- }
372
- });
373
- it('prompts for the mapped warehouse when interactive Metabase and Looker source setup has multiple choices', async () => {
374
- await addPrimarySource();
375
- await addConnection('analytics_warehouse', {
376
- driver: 'snowflake',
377
- account: 'acme',
378
- database: 'analytics',
379
- });
380
- const cases = [
381
- {
382
- source: 'metabase',
383
- text: ['metabase-main', 'https://metabase.example.com'],
384
- deps: {
385
- discoverMetabaseDatabases: vi.fn(async () => [
386
- { id: 1, name: 'Finance', engine: 'postgres', host: 'db.example.com', dbName: 'finance' },
387
- { id: 2, name: 'Analytics', engine: 'postgres', host: 'db.example.com', dbName: 'analytics' },
388
- ]),
389
- validateMetabase: vi.fn(async () => ({ ok: true, detail: 'mapping validated' })),
390
- runMapping: vi.fn(async () => 0),
391
- },
392
- expectedConnection: {
393
- driver: 'metabase',
394
- mappings: { databaseMappings: { '2': 'analytics_warehouse' } },
395
- },
396
- },
397
- {
398
- source: 'looker',
399
- text: ['looker-main', 'https://looker.example.com', 'client-id', 'analytics'],
400
- deps: {
401
- validateLooker: vi.fn(async () => ({ ok: true, detail: 'mapping refreshed' })),
402
- runMapping: vi.fn(async () => 0),
403
- },
404
- expectedConnection: {
405
- driver: 'looker',
406
- mappings: { connectionMappings: { analytics: 'analytics_warehouse' } },
407
- },
408
- },
409
- ];
410
- for (const testCase of cases) {
411
- const testPrompts = prompts({
412
- multiselect: [[testCase.source]],
413
- select: testCase.source === 'metabase' ? ['env', 'analytics_warehouse', '2', 'done'] : ['env', 'analytics_warehouse', 'done'],
414
- text: testCase.text,
415
- });
416
- await expect(runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: false, skipSources: false }, makeIo().io, {
417
- prompts: testPrompts,
418
- ...testCase.deps,
419
- })).resolves.toEqual({ status: 'ready', projectDir, connectionIds: [`${testCase.source}-main`] });
420
- expect(testPrompts.select).toHaveBeenCalledWith({
421
- message: 'Mapped warehouse connection',
422
- options: [
423
- { value: 'analytics_warehouse', label: 'analytics_warehouse (SNOWFLAKE)' },
424
- { value: 'warehouse', label: 'warehouse (POSTGRESQL)' },
425
- { value: 'back', label: 'Back' },
426
- ],
427
- });
428
- if (testCase.source === 'metabase') {
429
- expect(testPrompts.autocomplete).toHaveBeenCalledWith({
430
- message: 'Metabase database',
431
- placeholder: 'Type to search databases',
432
- options: [
433
- { value: '1', label: '1: Finance (postgres)' },
434
- { value: '2', label: '2: Analytics (postgres)' },
435
- { value: 'back', label: 'Back' },
436
- ],
437
- });
438
- expect(vi.mocked(testPrompts.text).mock.calls.some(([options]) => options.message.includes('Metabase database id'))).toBe(false);
439
- }
440
- expect((await readConfig()).connections[`${testCase.source}-main`]).toMatchObject(testCase.expectedConnection);
441
- }
442
- });
443
- it('lets visible Metabase mapping surface refresh and validation failures', async () => {
444
- await addPrimarySource();
445
- const runMapping = vi.fn(async (_projectDir, _connectionId, io) => {
446
- io.stderr.write('1: Metabase database does not match KTX connection database\n');
447
- return 1;
448
- });
449
- const io = makeIo();
450
- const testPrompts = prompts({
451
- multiselect: [['metabase']],
452
- select: ['env'],
453
- text: ['metabase-main', 'https://metabase.example.com'],
454
- });
455
- const result = await runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: false, skipSources: false }, io.io, {
456
- prompts: testPrompts,
457
- discoverMetabaseDatabases: vi.fn(async () => [
458
- { id: 1, name: 'Analytics', engine: 'postgres', host: 'db.example.com', dbName: 'analytics' },
459
- ]),
460
- runMapping,
461
- });
462
- expect(result.status).not.toBe('failed');
463
- expect(runMapping).toHaveBeenCalledWith(projectDir, 'metabase-main', expect.objectContaining({
464
- stdout: expect.objectContaining({ write: expect.any(Function) }),
465
- stderr: expect.objectContaining({ write: expect.any(Function) }),
466
- }));
467
- expect(io.stderr()).toContain('1: Metabase database does not match KTX connection database');
468
- expect(io.stderr()).not.toContain('Metabase mapping validation failed');
469
- expect(testPrompts.log).toHaveBeenCalledWith('Edit the connection or pick a different source to continue.');
470
- });
471
- it('does not mark sources complete when validation fails', async () => {
472
- await addPrimarySource();
473
- const io = makeIo();
474
- await expect(runKtxSetupSourcesStep({
475
- projectDir,
476
- inputMode: 'disabled',
477
- source: 'lookml',
478
- sourceConnectionId: 'looker_repo',
479
- sourceGitUrl: 'https://github.com/acme/lookml.git',
480
- runInitialSourceIngest: false,
481
- skipSources: false,
482
- }, io.io, { validateLookml: vi.fn(async () => ({ ok: false, message: 'No LookML files found' })) })).resolves.toEqual({ status: 'failed', projectDir });
483
- expect((await readKtxSetupState(projectDir)).completed_steps).not.toContain('sources');
484
- expect(io.stderr()).toContain('No LookML files found');
485
- });
486
- it('can go back from the interactive source checklist', async () => {
487
- await addPrimarySource();
488
- const io = makeIo();
489
- const testPrompts = prompts({ multiselect: [['back']] });
490
- await expect(runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: false, skipSources: false }, io.io, {
491
- prompts: testPrompts,
492
- })).resolves.toEqual({ status: 'back', projectDir });
493
- expect(testPrompts.multiselect).toHaveBeenCalledWith(expect.objectContaining({
494
- message: 'Which context sources should KTX ingest?\nUse Up/Down to move, Space to select or unselect, Enter to confirm, Escape to go back, or Ctrl+C to exit.',
495
- }));
496
- const options = vi.mocked(testPrompts.multiselect).mock.calls[0]?.[0].options ?? [];
497
- expect(options).toContainEqual({ value: 'notion', label: 'Notion' });
498
- });
499
- it('shows already configured context sources in the interactive checklist', async () => {
500
- await addPrimarySource();
501
- await addConnection('notion-main', {
502
- driver: 'notion',
503
- auth_token_ref: 'env:NOTION_TOKEN',
504
- crawl_mode: 'all_accessible',
505
- });
506
- const io = makeIo();
507
- const testPrompts = prompts({ multiselect: [['back']] });
508
- await expect(runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: false, skipSources: false }, io.io, { prompts: testPrompts })).resolves.toEqual({ status: 'back', projectDir });
509
- expect(testPrompts.multiselect).toHaveBeenCalledWith(expect.objectContaining({
510
- initialValues: ['notion'],
511
- options: expect.arrayContaining([{ value: 'notion', label: 'Notion', hint: 'configured: notion-main' }]),
512
- }));
513
- });
514
- it('uses a source-specific editable connection name for new interactive connections', async () => {
515
- await addPrimarySource();
516
- const validateDbt = vi.fn(async () => ({ ok: true, detail: 'project=analytics schemas=2' }));
517
- const io = makeIo();
518
- const testPrompts = prompts({
519
- multiselect: [['dbt']],
520
- select: ['path'],
521
- text: ['dbt-main', '/repo/dbt', '', ''],
522
- });
523
- await expect(runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: false, skipSources: false }, io.io, {
524
- prompts: testPrompts,
525
- validateDbt,
526
- })).resolves.toEqual({ status: 'ready', projectDir, connectionIds: ['dbt-main'] });
527
- expect(testPrompts.text).toHaveBeenNthCalledWith(1, {
528
- message: textInputPrompt(connectionNamePrompt('dbt')),
529
- placeholder: 'dbt-main',
530
- initialValue: 'dbt-main',
531
- });
532
- expect((await readConfig()).connections['dbt-main']).toMatchObject({
533
- driver: 'dbt',
534
- source_dir: '/repo/dbt',
535
- });
536
- });
537
- it('skips token prompt for public repos when git connection test succeeds', async () => {
538
- await addPrimarySource();
539
- const validateDbt = vi.fn(async () => ({ ok: true, detail: 'project=analytics schemas=2' }));
540
- const testGitRepo = vi.fn(async () => ({ ok: true }));
541
- const io = makeIo();
542
- const testPrompts = prompts({
543
- multiselect: [['dbt']],
544
- select: ['git'],
545
- text: ['dbt-main', 'https://github.com/acme-org/ktx-dbt-demo', 'main', ''],
546
- });
547
- await expect(runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: false, skipSources: false }, io.io, {
548
- prompts: testPrompts,
549
- validateDbt,
550
- testGitRepo,
551
- })).resolves.toEqual({ status: 'ready', projectDir, connectionIds: ['dbt-main'] });
552
- expect(testGitRepo).toHaveBeenCalledWith({ repoUrl: 'https://github.com/acme-org/ktx-dbt-demo' });
553
- expect(testPrompts.log).toHaveBeenCalledWith('Repository connected.');
554
- expect(testPrompts.text).toHaveBeenNthCalledWith(4, {
555
- message: textInputPrompt([
556
- 'Folder containing dbt_project.yml (optional)',
557
- 'Press Enter when dbt_project.yml is at the repo root.',
558
- 'For monorepos, enter a relative path like analytics/dbt.',
559
- ].join('\n')),
560
- placeholder: 'optional',
561
- });
562
- expect(testPrompts.text).toHaveBeenCalledTimes(4);
563
- });
564
- it('prompts for token when git connection test fails', async () => {
565
- await addPrimarySource();
566
- const validateDbt = vi.fn(async () => ({ ok: true, detail: 'project=analytics schemas=2' }));
567
- const testGitRepo = vi.fn(async () => ({ ok: false, error: 'authentication required' }));
568
- const io = makeIo();
569
- const testPrompts = prompts({
570
- multiselect: [['dbt']],
571
- select: ['git', 'env'],
572
- text: ['dbt-main', 'https://github.com/acme-org/private-repo', 'main', ''],
573
- });
574
- await expect(runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: false, skipSources: false }, io.io, {
575
- prompts: testPrompts,
576
- validateDbt,
577
- testGitRepo,
578
- })).resolves.toEqual({ status: 'ready', projectDir, connectionIds: ['dbt-main'] });
579
- expect(testGitRepo).toHaveBeenCalledWith({ repoUrl: 'https://github.com/acme-org/private-repo' });
580
- expect(testPrompts.select).toHaveBeenCalledWith({
581
- message: 'This repo requires authentication.',
582
- options: [
583
- { value: 'env', label: 'Use GITHUB_TOKEN from the environment' },
584
- { value: 'paste', label: 'Paste a token and save it as a local secret file' },
585
- { value: 'skip', label: 'Skip — try without authentication' },
586
- { value: 'back', label: 'Back' },
587
- ],
588
- });
589
- expect(testPrompts.text).toHaveBeenCalledTimes(4);
590
- });
591
- it('re-prompts when a pasted token fails authentication and accepts the second token', async () => {
592
- await addPrimarySource();
593
- const validateDbt = vi.fn(async () => ({ ok: true, detail: 'project=analytics schemas=2' }));
594
- const testGitRepo = vi
595
- .fn()
596
- .mockResolvedValueOnce({ ok: false, error: 'authentication required' })
597
- .mockResolvedValueOnce({ ok: false, error: 'Invalid username or token.' })
598
- .mockResolvedValue({ ok: true });
599
- const io = makeIo();
600
- const testPrompts = prompts({
601
- multiselect: [['dbt']],
602
- select: ['git', 'paste', 'paste'],
603
- text: ['dbt-main', 'https://github.com/acme-org/private-repo', 'main', ''],
604
- password: ['bad-token', 'good-token'],
605
- });
606
- await expect(runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: false, skipSources: false }, io.io, {
607
- prompts: testPrompts,
608
- validateDbt,
609
- testGitRepo,
610
- })).resolves.toEqual({ status: 'ready', projectDir, connectionIds: ['dbt-main'] });
611
- expect(testGitRepo).toHaveBeenNthCalledWith(1, { repoUrl: 'https://github.com/acme-org/private-repo' });
612
- expect(testGitRepo).toHaveBeenNthCalledWith(2, {
613
- repoUrl: 'https://github.com/acme-org/private-repo',
614
- authToken: 'bad-token',
615
- });
616
- expect(testGitRepo).toHaveBeenNthCalledWith(3, {
617
- repoUrl: 'https://github.com/acme-org/private-repo',
618
- authToken: 'good-token',
619
- });
620
- expect(testPrompts.password).toHaveBeenCalledTimes(2);
621
- expect(testPrompts.log).toHaveBeenCalledWith('Authentication failed: Invalid username or token.');
622
- expect(testPrompts.log).toHaveBeenCalledWith('Saved to .ktx/secrets/dbt-main-auth-token');
623
- expect((await readConfig()).connections['dbt-main']).toMatchObject({
624
- driver: 'dbt',
625
- repo_url: 'https://github.com/acme-org/private-repo',
626
- auth_token_ref: expect.stringMatching(/^file:.*\.ktx\/secrets\/dbt-main-auth-token$/),
627
- });
628
- });
629
- it('does not exit interactive setup when validation fails for an existing connection', async () => {
630
- await addPrimarySource();
631
- await addConnection('dbt-main', {
632
- driver: 'dbt',
633
- repo_url: 'https://github.com/acme/private-repo',
634
- auth_token_ref: 'env:GITHUB_TOKEN',
635
- });
636
- const validateDbt = vi.fn(async () => ({
637
- ok: false,
638
- message: 'Failed to clone https://github.com/acme/private-repo: Authentication failed',
639
- }));
640
- const testPrompts = prompts({
641
- multiselect: [['dbt']],
642
- select: ['existing:dbt-main'],
643
- });
644
- const io = makeIo();
645
- const result = await runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: false, skipSources: false }, io.io, { prompts: testPrompts, validateDbt });
646
- expect(result.status).not.toBe('failed');
647
- expect(io.stderr()).toContain('Failed to clone https://github.com/acme/private-repo: Authentication failed');
648
- expect(testPrompts.log).toHaveBeenCalledWith('Edit the connection or pick a different source to continue.');
649
- });
650
- it('adds a dbt source connection and enables its adapter', async () => {
651
- await addPrimarySource();
652
- const validateDbt = vi.fn(async () => ({ ok: true, detail: 'project=analytics schemas=2' }));
653
- await expect(runKtxSetupSourcesStep({
654
- projectDir,
655
- inputMode: 'disabled',
656
- source: 'dbt',
657
- sourceConnectionId: 'dbt-main',
658
- sourcePath: '/repo/dbt',
659
- runInitialSourceIngest: false,
660
- skipSources: false,
661
- }, makeIo().io, { validateDbt })).resolves.toEqual({ status: 'ready', projectDir, connectionIds: ['dbt-main'] });
662
- const configText = await readFile(join(projectDir, 'ktx.yaml'), 'utf-8');
663
- expect(configText).not.toContain('live-database');
664
- expect(configText).not.toContain('historic-sql');
665
- expect((await readConfig()).ingest.adapters).toEqual(['dbt']);
666
- });
667
- it('lets interactive setup retry or continue after initial source ingest fails', async () => {
668
- await addPrimarySource();
669
- const validateDbt = vi.fn(async () => ({ ok: true, detail: 'project=analytics schemas=2' }));
670
- const runInitialIngest = vi.fn(async () => 1);
671
- const io = makeIo();
672
- const testPrompts = prompts({
673
- multiselect: [['dbt']],
674
- select: ['path', 'continue', 'done'],
675
- text: ['dbt-main', '/repo/dbt', '', ''],
676
- });
677
- await expect(runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: true, skipSources: false }, io.io, {
678
- prompts: testPrompts,
679
- validateDbt,
680
- runInitialIngest,
681
- })).resolves.toEqual({ status: 'ready', projectDir, connectionIds: ['dbt-main'] });
682
- expect(runInitialIngest).toHaveBeenCalledTimes(1);
683
- expect((await readConfig()).connections['dbt-main']).toMatchObject({ driver: 'dbt', source_dir: '/repo/dbt' });
684
- expect(io.stdout()).toContain('Context source saved without a completed context build for dbt-main.');
685
- expect(io.stdout()).toContain('Run later: ktx ingest dbt-main');
686
- expect(io.stdout()).not.toContain('ktx ingest run --connection-id');
687
- expect(io.stdout()).not.toContain('--adapter');
688
- });
689
- it('retries initial source ingest from the failure menu', async () => {
690
- await addPrimarySource();
691
- const validateDbt = vi.fn(async () => ({ ok: true, detail: 'project=analytics schemas=2' }));
692
- const runInitialIngest = vi.fn(async () => (runInitialIngest.mock.calls.length === 1 ? 1 : 0));
693
- const testPrompts = prompts({
694
- multiselect: [['dbt']],
695
- select: ['path', 'retry'],
696
- text: ['dbt-main', '/repo/dbt', '', ''],
697
- });
698
- await expect(runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: true, skipSources: false }, makeIo().io, {
699
- prompts: testPrompts,
700
- validateDbt,
701
- runInitialIngest,
702
- })).resolves.toEqual({ status: 'ready', projectDir, connectionIds: ['dbt-main'] });
703
- expect(runInitialIngest).toHaveBeenCalledTimes(2);
704
- });
705
- it('offers existing context source connections before prompting for new details', async () => {
706
- await addPrimarySource();
707
- await addConnection('dbt-main', {
708
- driver: 'dbt',
709
- source_dir: '/repo/existing-dbt',
710
- project_name: 'analytics',
711
- });
712
- const validateDbt = vi.fn(async () => ({ ok: true, detail: 'project=analytics schemas=2' }));
713
- const testPrompts = prompts({
714
- multiselect: [['dbt']],
715
- select: ['existing:dbt-main'],
716
- text: [undefined],
717
- });
718
- await expect(runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: false, skipSources: false }, makeIo().io, {
719
- prompts: testPrompts,
720
- validateDbt,
721
- })).resolves.toEqual({ status: 'ready', projectDir, connectionIds: ['dbt-main'] });
722
- expect(testPrompts.select).toHaveBeenCalledWith({
723
- message: 'Configure dbt',
724
- options: [
725
- { value: 'existing:dbt-main', label: 'Use existing dbt connection: dbt-main' },
726
- { value: 'edit:dbt-main', label: 'Edit existing dbt connection: dbt-main' },
727
- { value: 'new', label: 'Add new dbt connection' },
728
- { value: 'back', label: 'Back' },
729
- ],
730
- });
731
- expect(testPrompts.text).not.toHaveBeenCalled();
732
- expect(validateDbt).toHaveBeenCalledWith({
733
- driver: 'dbt',
734
- source_dir: '/repo/existing-dbt',
735
- project_name: 'analytics',
736
- });
737
- expect((await readConfig()).connections['dbt-main']).toMatchObject({
738
- driver: 'dbt',
739
- source_dir: '/repo/existing-dbt',
740
- });
741
- });
742
- it('offers existing connections for every context source type', async () => {
743
- await addPrimarySource();
744
- const cases = [
745
- {
746
- source: 'dbt',
747
- connectionId: 'dbt-main',
748
- connection: { driver: 'dbt', source_dir: '/repo/dbt', project_name: 'analytics' },
749
- deps: { validateDbt: vi.fn(async () => ({ ok: true, detail: 'project=analytics schemas=2' })) },
750
- expectedLabel: 'dbt',
751
- },
752
- {
753
- source: 'metricflow',
754
- connectionId: 'metricflow-main',
755
- connection: { driver: 'metricflow', metricflow: { repoUrl: 'file:///repo/metricflow' } },
756
- deps: { validateMetricflow: vi.fn(async () => ({ ok: true, detail: 'metrics=1' })) },
757
- expectedLabel: 'MetricFlow',
758
- },
759
- {
760
- source: 'metabase',
761
- connectionId: 'metabase-main',
762
- connection: {
763
- driver: 'metabase',
764
- api_url: 'https://metabase.example.com',
765
- api_key_ref: 'env:METABASE_API_KEY', // pragma: allowlist secret
766
- mappings: {
767
- databaseMappings: { '1': 'warehouse' },
768
- syncEnabled: { '1': true },
769
- syncMode: 'ALL',
770
- selections: { collections: [], items: [] },
771
- defaultTagNames: [],
772
- },
773
- },
774
- deps: {
775
- validateMetabase: vi.fn(async () => ({ ok: true, detail: 'mapping validated' })),
776
- runMapping: vi.fn(async () => 0),
777
- },
778
- expectedLabel: 'Metabase',
779
- },
780
- {
781
- source: 'looker',
782
- connectionId: 'looker-main',
783
- connection: {
784
- driver: 'looker',
785
- base_url: 'https://looker.example.com',
786
- client_id: 'client-id',
787
- client_secret_ref: 'env:LOOKER_CLIENT_SECRET', // pragma: allowlist secret
788
- mappings: { connectionMappings: { warehouse: 'warehouse' } },
789
- },
790
- deps: {
791
- validateLooker: vi.fn(async () => ({ ok: true, detail: 'mapping refreshed' })),
792
- runMapping: vi.fn(async () => 0),
793
- },
794
- expectedLabel: 'Looker',
795
- },
796
- {
797
- source: 'lookml',
798
- connectionId: 'lookml-main',
799
- connection: {
800
- driver: 'lookml',
801
- repoUrl: 'file:///repo/lookml',
802
- mappings: { expectedLookerConnectionName: null },
803
- },
804
- deps: { validateLookml: vi.fn(async () => ({ ok: true, detail: 'lookmlFiles=1' })) },
805
- expectedLabel: 'LookML',
806
- },
807
- {
808
- source: 'notion',
809
- connectionId: 'notion-main',
810
- connection: {
811
- driver: 'notion',
812
- auth_token_ref: 'env:NOTION_TOKEN',
813
- crawl_mode: 'all_accessible',
814
- root_page_ids: [],
815
- root_database_ids: [],
816
- root_data_source_ids: [],
817
- },
818
- deps: { validateNotion: vi.fn(async () => ({ ok: true, detail: 'roots=0' })) },
819
- expectedLabel: 'Notion',
820
- },
821
- ];
822
- for (const testCase of cases) {
823
- await addConnection(testCase.connectionId, testCase.connection);
824
- const testPrompts = prompts({
825
- multiselect: [[testCase.source]],
826
- select: [`existing:${testCase.connectionId}`],
827
- text: [undefined],
828
- });
829
- await expect(runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: false, skipSources: false }, makeIo().io, {
830
- prompts: testPrompts,
831
- ...testCase.deps,
832
- })).resolves.toEqual({ status: 'ready', projectDir, connectionIds: [testCase.connectionId] });
833
- expect(testPrompts.select).toHaveBeenCalledWith({
834
- message: `Configure ${testCase.expectedLabel}`,
835
- options: [
836
- {
837
- value: `existing:${testCase.connectionId}`,
838
- label: `Use existing ${testCase.expectedLabel} connection: ${testCase.connectionId}`,
839
- },
840
- {
841
- value: `edit:${testCase.connectionId}`,
842
- label: `Edit existing ${testCase.expectedLabel} connection: ${testCase.connectionId}`,
843
- },
844
- { value: 'new', label: `Add new ${testCase.expectedLabel} connection` },
845
- { value: 'back', label: 'Back' },
846
- ],
847
- });
848
- expect(testPrompts.text).not.toHaveBeenCalled();
849
- }
850
- });
851
- it('edits an existing Notion source and reopens the page picker with stored pages selected', async () => {
852
- await addPrimarySource();
853
- await addConnection('notion-main', {
854
- driver: 'notion',
855
- auth_token_ref: 'env:NOTION_TOKEN',
856
- crawl_mode: 'selected_roots',
857
- root_page_ids: ['old-page'],
858
- root_database_ids: [],
859
- root_data_source_ids: [],
860
- });
861
- const validateNotion = vi.fn(async () => ({ ok: true, detail: 'roots=1' }));
862
- const pickNotionRootPages = vi.fn(async () => ({ kind: 'selected', rootPageIds: ['new-page'] }));
863
- const testPrompts = prompts({
864
- multiselect: [['notion']],
865
- select: ['edit:notion-main', 'keep', 'selected_roots', 'done'],
866
- });
867
- await expect(runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: false, skipSources: false }, makeIo().io, {
868
- prompts: testPrompts,
869
- validateNotion,
870
- pickNotionRootPages,
871
- })).resolves.toEqual({ status: 'ready', projectDir, connectionIds: ['notion-main'] });
872
- expect(testPrompts.select).toHaveBeenCalledWith({
873
- message: 'How should KTX find your Notion integration token?',
874
- options: [
875
- { value: 'keep', label: 'Keep existing credential' },
876
- { value: 'env', label: 'Use NOTION_TOKEN from the environment' },
877
- { value: 'paste', label: 'Paste a key and save it as a local secret file' },
878
- { value: 'back', label: 'Back' },
879
- ],
880
- });
881
- expect(pickNotionRootPages).toHaveBeenCalledWith({
882
- connectionId: 'notion-main',
883
- connection: expect.objectContaining({
884
- driver: 'notion',
885
- auth_token_ref: 'env:NOTION_TOKEN',
886
- crawl_mode: 'selected_roots',
887
- root_page_ids: ['old-page'],
888
- }),
889
- }, expect.anything());
890
- expect((await readConfig()).connections['notion-main']).toMatchObject({
891
- driver: 'notion',
892
- auth_token_ref: 'env:NOTION_TOKEN',
893
- crawl_mode: 'selected_roots',
894
- root_page_ids: ['new-page'],
895
- });
896
- });
897
- it('edits an existing Metabase source with the current URL and credential as defaults', async () => {
898
- await addPrimarySource();
899
- await addConnection('metabase-main', {
900
- driver: 'metabase',
901
- api_url: 'https://metabase-old.example.com',
902
- api_key_ref: 'env:METABASE_API_KEY', // pragma: allowlist secret
903
- mappings: {
904
- databaseMappings: { '1': 'warehouse' },
905
- syncEnabled: { '1': true },
906
- syncMode: 'ALL',
907
- selections: { collections: [], items: [] },
908
- defaultTagNames: [],
909
- },
910
- });
911
- const testPrompts = prompts({
912
- multiselect: [['metabase']],
913
- select: ['edit:metabase-main', 'keep', 'done'],
914
- text: ['https://metabase-new.example.com'],
915
- });
916
- const discoverMetabaseDatabases = vi.fn(async () => [
917
- { id: 2, name: 'Analytics', engine: 'postgres', host: 'db.example.com', dbName: 'analytics' },
918
- ]);
919
- await expect(runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: false, skipSources: false }, makeIo().io, {
920
- prompts: testPrompts,
921
- discoverMetabaseDatabases,
922
- validateMetabase: vi.fn(async () => ({ ok: true, detail: 'mapping validated' })),
923
- runMapping: vi.fn(async () => 0),
924
- })).resolves.toEqual({ status: 'ready', projectDir, connectionIds: ['metabase-main'] });
925
- expect(testPrompts.text).toHaveBeenCalledWith({
926
- message: textInputPrompt('Metabase URL'),
927
- initialValue: 'https://metabase-old.example.com',
928
- });
929
- expect(testPrompts.select).toHaveBeenCalledWith({
930
- message: 'How should KTX find your Metabase API key?',
931
- options: [
932
- { value: 'keep', label: 'Keep existing credential' },
933
- { value: 'env', label: 'Use METABASE_API_KEY from the environment' },
934
- { value: 'paste', label: 'Paste a key and save it as a local secret file' },
935
- { value: 'back', label: 'Back' },
936
- ],
937
- });
938
- expect(discoverMetabaseDatabases).toHaveBeenCalledWith({
939
- sourceUrl: 'https://metabase-new.example.com',
940
- sourceApiKeyRef: 'env:METABASE_API_KEY', // pragma: allowlist secret
941
- sourceConnectionId: 'metabase-main',
942
- });
943
- expect((await readConfig()).connections['metabase-main']).toMatchObject({
944
- driver: 'metabase',
945
- api_url: 'https://metabase-new.example.com',
946
- api_key_ref: 'env:METABASE_API_KEY', // pragma: allowlist secret
947
- mappings: {
948
- databaseMappings: { '2': 'warehouse' },
949
- syncEnabled: { '2': true },
950
- syncMode: 'ALL',
951
- },
952
- });
953
- });
954
- it('rolls back an edited context source when validation fails', async () => {
955
- await addPrimarySource();
956
- await addConnection('dbt-main', {
957
- driver: 'dbt',
958
- source_dir: '/repo/existing-dbt',
959
- project_name: 'analytics',
960
- });
961
- const validateDbt = vi.fn(async () => ({ ok: false, message: 'dbt project not found' }));
962
- const testPrompts = prompts({
963
- multiselect: [['dbt']],
964
- select: ['edit:dbt-main', 'path'],
965
- text: ['/repo/new-dbt', ''],
966
- });
967
- const io = makeIo();
968
- const result = await runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: false, skipSources: false }, io.io, {
969
- prompts: testPrompts,
970
- validateDbt,
971
- });
972
- expect(result.status).not.toBe('failed');
973
- expect(validateDbt).toHaveBeenCalledWith(expect.objectContaining({
974
- driver: 'dbt',
975
- source_dir: '/repo/new-dbt',
976
- }));
977
- expect(io.stderr()).toContain('dbt project not found');
978
- expect(testPrompts.log).toHaveBeenCalledWith('Edit the connection or pick a different source to continue.');
979
- const config = await readConfig();
980
- expect(config.connections['dbt-main']).toMatchObject({
981
- driver: 'dbt',
982
- source_dir: '/repo/existing-dbt',
983
- project_name: 'analytics',
984
- });
985
- expect(config.ingest.adapters).not.toContain('dbt');
986
- });
987
- it('lets git-backed context source edits keep the existing repo credential', async () => {
988
- await addPrimarySource();
989
- await addConnection('metricflow-main', {
990
- driver: 'metricflow',
991
- metricflow: {
992
- repoUrl: 'https://github.com/acme/private-metricflow',
993
- branch: 'main',
994
- path: 'metrics',
995
- auth_token_ref: 'env:METRICFLOW_REPO_TOKEN', // pragma: allowlist secret
996
- },
997
- });
998
- const testGitRepo = vi.fn(async () => ({ ok: false, error: 'authentication required' }));
999
- const testPrompts = prompts({
1000
- multiselect: [['metricflow']],
1001
- select: ['edit:metricflow-main', 'git', 'keep', 'done'],
1002
- text: ['https://github.com/acme/private-metricflow', 'main', 'metrics'],
1003
- });
1004
- await expect(runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: false, skipSources: false }, makeIo().io, {
1005
- prompts: testPrompts,
1006
- testGitRepo,
1007
- validateMetricflow: vi.fn(async () => ({ ok: true, detail: 'metrics=1' })),
1008
- })).resolves.toEqual({ status: 'ready', projectDir, connectionIds: ['metricflow-main'] });
1009
- expect(testPrompts.select).toHaveBeenCalledWith({
1010
- message: 'This MetricFlow repo requires authentication.',
1011
- options: [
1012
- { value: 'keep', label: 'Keep existing credential' },
1013
- { value: 'env', label: 'Use GITHUB_TOKEN from the environment' },
1014
- { value: 'paste', label: 'Paste a token and save it as a local secret file' },
1015
- { value: 'skip', label: 'Skip — try without authentication' },
1016
- { value: 'back', label: 'Back' },
1017
- ],
1018
- });
1019
- expect((await readConfig()).connections['metricflow-main']).toMatchObject({
1020
- driver: 'metricflow',
1021
- metricflow: {
1022
- repoUrl: 'https://github.com/acme/private-metricflow',
1023
- branch: 'main',
1024
- path: 'metrics',
1025
- auth_token_ref: 'env:METRICFLOW_REPO_TOKEN',
1026
- },
1027
- });
1028
- });
1029
- it('edits an existing context source from the configured-source follow-up menu', async () => {
1030
- await addPrimarySource();
1031
- await addConnection('dbt-main', {
1032
- driver: 'dbt',
1033
- source_dir: '/repo/existing-dbt',
1034
- project_name: 'analytics',
1035
- });
1036
- const validateDbt = vi.fn(async () => ({ ok: true, detail: 'project=analytics schemas=2' }));
1037
- const testPrompts = prompts({
1038
- multiselect: [['dbt']],
1039
- select: ['existing:dbt-main', 'edit', 'dbt-main', 'path', 'done'],
1040
- text: ['/repo/edited-dbt', ''],
1041
- });
1042
- await expect(runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: false, skipSources: false }, makeIo().io, {
1043
- prompts: testPrompts,
1044
- validateDbt,
1045
- })).resolves.toEqual({ status: 'ready', projectDir, connectionIds: ['dbt-main'] });
1046
- expect(testPrompts.select).toHaveBeenCalledWith({
1047
- message: '1 context source configured (dbt-main). Add another?',
1048
- options: [
1049
- { value: 'done', label: 'Done — continue to context build' },
1050
- { value: 'edit', label: 'Edit an existing context source' },
1051
- { value: 'add', label: 'Add another context source' },
1052
- ],
1053
- });
1054
- expect(testPrompts.select).toHaveBeenCalledWith({
1055
- message: 'Context source to edit',
1056
- options: [
1057
- { value: 'dbt-main', label: 'dbt-main (dbt)' },
1058
- { value: 'back', label: 'Back' },
1059
- ],
1060
- });
1061
- expect(testPrompts.text).toHaveBeenCalledWith({
1062
- message: textInputPrompt('dbt local path'),
1063
- initialValue: '/repo/existing-dbt',
1064
- });
1065
- expect(validateDbt).toHaveBeenLastCalledWith(expect.objectContaining({
1066
- driver: 'dbt',
1067
- source_dir: '/repo/edited-dbt',
1068
- }));
1069
- expect((await readConfig()).connections['dbt-main']).toMatchObject({
1070
- driver: 'dbt',
1071
- source_dir: '/repo/edited-dbt',
1072
- project_name: 'analytics',
1073
- });
1074
- });
1075
- it('backs out of editing an existing context source to the source connection menu', async () => {
1076
- await addPrimarySource();
1077
- await addConnection('dbt-main', {
1078
- driver: 'dbt',
1079
- source_dir: '/repo/existing-dbt',
1080
- project_name: 'analytics',
1081
- });
1082
- const validateDbt = vi.fn(async () => ({ ok: true, detail: 'project=analytics schemas=2' }));
1083
- const testPrompts = prompts({
1084
- multiselect: [['dbt']],
1085
- select: ['edit:dbt-main', 'back', 'existing:dbt-main'],
1086
- });
1087
- await expect(runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: false, skipSources: false }, makeIo().io, {
1088
- prompts: testPrompts,
1089
- validateDbt,
1090
- })).resolves.toEqual({ status: 'ready', projectDir, connectionIds: ['dbt-main'] });
1091
- expect(vi
1092
- .mocked(testPrompts.select)
1093
- .mock.calls.map(([options]) => options.message)
1094
- .filter((message) => message === 'Configure dbt')).toHaveLength(2);
1095
- expect(validateDbt).toHaveBeenCalledWith({
1096
- driver: 'dbt',
1097
- source_dir: '/repo/existing-dbt',
1098
- project_name: 'analytics',
1099
- });
1100
- expect((await readConfig()).connections['dbt-main']).toMatchObject({
1101
- driver: 'dbt',
1102
- source_dir: '/repo/existing-dbt',
1103
- project_name: 'analytics',
1104
- });
1105
- });
1106
- it('lets Escape from dbt git URL return to source location selection', async () => {
1107
- await addPrimarySource();
1108
- const validateDbt = vi.fn(async () => ({ ok: true, detail: 'project=analytics schemas=2' }));
1109
- const testPrompts = prompts({
1110
- multiselect: [['dbt']],
1111
- select: ['git', 'path'],
1112
- text: ['dbt-main', undefined, '/repo/dbt', '', ''],
1113
- });
1114
- await expect(runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: false, skipSources: false }, makeIo().io, {
1115
- prompts: testPrompts,
1116
- validateDbt,
1117
- })).resolves.toEqual({ status: 'ready', projectDir, connectionIds: ['dbt-main'] });
1118
- const selectMessages = vi.mocked(testPrompts.select).mock.calls.map(([options]) => options.message);
1119
- expect(selectMessages[0]).toBe('dbt source location');
1120
- expect(selectMessages[1]).toBe('dbt source location');
1121
- expect(selectMessages.at(-1)).toContain('Add another?');
1122
- expect((await readConfig()).connections['dbt-main']).toMatchObject({
1123
- driver: 'dbt',
1124
- source_dir: '/repo/dbt',
1125
- });
1126
- });
1127
- it('lets Escape from source connection name return to context source selection', async () => {
1128
- await addPrimarySource();
1129
- const validateDbt = vi.fn(async () => ({ ok: true, detail: 'project=analytics schemas=2' }));
1130
- const testPrompts = prompts({
1131
- multiselect: [['dbt'], ['back']],
1132
- text: [undefined],
1133
- });
1134
- await expect(runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: false, skipSources: false }, makeIo().io, {
1135
- prompts: testPrompts,
1136
- validateDbt,
1137
- })).resolves.toEqual({ status: 'back', projectDir });
1138
- expect(testPrompts.multiselect).toHaveBeenCalledTimes(2);
1139
- expect(validateDbt).not.toHaveBeenCalled();
1140
- });
1141
- it('backs up one prompt inside every interactive context source connection', async () => {
1142
- await addPrimarySource();
1143
- const cases = [
1144
- {
1145
- source: 'dbt',
1146
- select: ['git', 'path'],
1147
- text: ['dbt-main', undefined, '/repo/dbt', '', ''],
1148
- deps: { validateDbt: vi.fn(async () => ({ ok: true, detail: 'project=analytics schemas=2' })) },
1149
- repeatedSelectMessage: 'dbt source location',
1150
- },
1151
- {
1152
- source: 'metricflow',
1153
- select: ['git', 'path'],
1154
- text: ['metricflow-main', undefined, '/repo/metricflow', ''],
1155
- deps: { validateMetricflow: vi.fn(async () => ({ ok: true, detail: 'metrics=1' })) },
1156
- repeatedSelectMessage: 'metricflow source location',
1157
- },
1158
- {
1159
- source: 'lookml',
1160
- select: ['git', 'path'],
1161
- text: ['lookml-main', undefined, '/repo/lookml', ''],
1162
- deps: { validateLookml: vi.fn(async () => ({ ok: true, detail: 'lookmlFiles=1' })) },
1163
- repeatedSelectMessage: 'lookml source location',
1164
- },
1165
- {
1166
- source: 'metabase',
1167
- select: ['back', 'env'],
1168
- text: [
1169
- 'metabase-main',
1170
- 'https://old-metabase.example.com',
1171
- 'https://metabase.example.com',
1172
- '1',
1173
- ],
1174
- deps: {
1175
- validateMetabase: vi.fn(async () => ({ ok: true, detail: 'mapping validated' })),
1176
- runMapping: vi.fn(async () => 0),
1177
- },
1178
- repeatedTextMessage: textInputPrompt('Metabase URL'),
1179
- },
1180
- {
1181
- source: 'looker',
1182
- select: ['env'],
1183
- text: [
1184
- 'looker-main',
1185
- 'https://old-looker.example.com',
1186
- undefined,
1187
- 'https://looker.example.com',
1188
- 'client-id',
1189
- '',
1190
- ],
1191
- deps: {
1192
- validateLooker: vi.fn(async () => ({ ok: true, detail: 'mapping refreshed' })),
1193
- runMapping: vi.fn(async () => 0),
1194
- },
1195
- repeatedTextMessage: textInputPrompt('Looker base URL'),
1196
- },
1197
- {
1198
- source: 'notion',
1199
- select: ['env', 'back', 'env', 'all_accessible'],
1200
- text: ['notion-main'],
1201
- deps: { validateNotion: vi.fn(async () => ({ ok: true, detail: 'roots=0' })) },
1202
- repeatedSelectMessage: 'How should KTX find your Notion integration token?',
1203
- },
1204
- ];
1205
- for (const testCase of cases) {
1206
- const testPrompts = prompts({
1207
- multiselect: [[testCase.source]],
1208
- select: testCase.select,
1209
- text: testCase.text,
1210
- });
1211
- await expect(runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: false, skipSources: false }, makeIo().io, {
1212
- prompts: testPrompts,
1213
- ...testCase.deps,
1214
- })).resolves.toEqual({ status: 'ready', projectDir, connectionIds: [`${testCase.source}-main`] });
1215
- if (testCase.repeatedSelectMessage) {
1216
- expect(vi
1217
- .mocked(testPrompts.select)
1218
- .mock.calls.map(([options]) => options.message)
1219
- .filter((message) => message === testCase.repeatedSelectMessage)).toHaveLength(2);
1220
- }
1221
- if (testCase.repeatedTextMessage) {
1222
- expect(vi
1223
- .mocked(testPrompts.text)
1224
- .mock.calls.map(([options]) => options.message)
1225
- .filter((message) => message === testCase.repeatedTextMessage)).toHaveLength(2);
1226
- }
1227
- }
1228
- });
1229
- it('does not offer context sources until a database exists', async () => {
1230
- const io = makeIo();
1231
- const testPrompts = prompts({ multiselect: [['notion']] });
1232
- await expect(runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: false, skipSources: false }, io.io, { prompts: testPrompts })).resolves.toEqual({ status: 'skipped', projectDir });
1233
- expect(testPrompts.multiselect).not.toHaveBeenCalled();
1234
- expect(io.stdout()).toContain('Connect a database before adding context sources.');
1235
- expect(await readFile(join(projectDir, 'ktx.yaml'), 'utf-8')).not.toContain('completed_steps:');
1236
- });
1237
- it('auto-detects dbt_project.yml at the root of a local path', async () => {
1238
- await addPrimarySource();
1239
- const dbtDir = join(tempDir, 'dbt-repo');
1240
- await mkdir(dbtDir, { recursive: true });
1241
- await writeFile(join(dbtDir, 'dbt_project.yml'), 'name: analytics\n');
1242
- const validateDbt = vi.fn(async () => ({ ok: true, detail: 'project=analytics schemas=2' }));
1243
- const io = makeIo();
1244
- const testPrompts = prompts({
1245
- multiselect: [['dbt']],
1246
- select: ['path'],
1247
- text: ['dbt-main', dbtDir],
1248
- });
1249
- await expect(runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: false, skipSources: false }, io.io, { prompts: testPrompts, validateDbt })).resolves.toEqual({ status: 'ready', projectDir, connectionIds: ['dbt-main'] });
1250
- expect(testPrompts.text).toHaveBeenCalledTimes(2);
1251
- const config = await readConfig();
1252
- expect(config.connections['dbt-main']).toMatchObject({ driver: 'dbt', source_dir: dbtDir });
1253
- expect(config.connections['dbt-main']).not.toHaveProperty('path');
1254
- });
1255
- it('auto-detects dbt_project.yml in a subdirectory of a local path', async () => {
1256
- await addPrimarySource();
1257
- const dbtDir = join(tempDir, 'monorepo');
1258
- await mkdir(join(dbtDir, 'analytics', 'dbt'), { recursive: true });
1259
- await writeFile(join(dbtDir, 'analytics', 'dbt', 'dbt_project.yml'), 'name: analytics\n');
1260
- const validateDbt = vi.fn(async () => ({ ok: true, detail: 'project=analytics schemas=2' }));
1261
- const io = makeIo();
1262
- const testPrompts = prompts({
1263
- multiselect: [['dbt']],
1264
- select: ['path'],
1265
- text: ['dbt-main', dbtDir],
1266
- });
1267
- await expect(runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: false, skipSources: false }, io.io, { prompts: testPrompts, validateDbt })).resolves.toEqual({ status: 'ready', projectDir, connectionIds: ['dbt-main'] });
1268
- expect(testPrompts.text).toHaveBeenCalledTimes(2);
1269
- expect(testPrompts.log).toHaveBeenCalledWith('Found dbt_project.yml in analytics/dbt/');
1270
- const config = await readConfig();
1271
- expect(config.connections['dbt-main']).toMatchObject({
1272
- driver: 'dbt',
1273
- source_dir: dbtDir,
1274
- path: 'analytics/dbt',
1275
- });
1276
- });
1277
- it('shows a picker when multiple dbt projects are found in a local path', async () => {
1278
- await addPrimarySource();
1279
- const dbtDir = join(tempDir, 'multi-dbt');
1280
- await mkdir(join(dbtDir, 'analytics'), { recursive: true });
1281
- await mkdir(join(dbtDir, 'staging'), { recursive: true });
1282
- await writeFile(join(dbtDir, 'analytics', 'dbt_project.yml'), 'name: analytics\n');
1283
- await writeFile(join(dbtDir, 'staging', 'dbt_project.yml'), 'name: staging\n');
1284
- const validateDbt = vi.fn(async () => ({ ok: true, detail: 'project=analytics schemas=2' }));
1285
- const io = makeIo();
1286
- const testPrompts = prompts({
1287
- multiselect: [['dbt']],
1288
- select: ['path', 'staging'],
1289
- text: ['dbt-main', dbtDir],
1290
- });
1291
- await expect(runKtxSetupSourcesStep({ projectDir, inputMode: 'auto', runInitialSourceIngest: false, skipSources: false }, io.io, { prompts: testPrompts, validateDbt })).resolves.toEqual({ status: 'ready', projectDir, connectionIds: ['dbt-main'] });
1292
- expect(testPrompts.select).toHaveBeenCalledWith(expect.objectContaining({
1293
- message: 'Multiple dbt projects found — which one should KTX use?',
1294
- }));
1295
- expect(testPrompts.text).toHaveBeenCalledTimes(2);
1296
- const config = await readConfig();
1297
- expect(config.connections['dbt-main']).toMatchObject({
1298
- driver: 'dbt',
1299
- source_dir: dbtDir,
1300
- path: 'staging',
1301
- });
1302
- });
1303
- });