@kaelio/ktx 0.5.0 → 0.6.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 (872) hide show
  1. package/assets/python/{kaelio_ktx-0.5.0-py3-none-any.whl → kaelio_ktx-0.6.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/mcp/context-tools.js +11 -48
  70. package/dist/context/mcp/local-project-ports.js +0 -3
  71. package/dist/context/project/config.d.ts +0 -8
  72. package/dist/context/project/driver-schemas.d.ts +0 -4
  73. package/dist/context/project/driver-schemas.js +0 -2
  74. package/dist/context/scan/constraint-discovery.d.ts +19 -0
  75. package/dist/context/scan/constraint-discovery.js +23 -0
  76. package/dist/context/scan/enabled-tables.d.ts +4 -5
  77. package/dist/context/scan/enabled-tables.js +4 -18
  78. package/dist/context/scan/entity-details.js +14 -44
  79. package/dist/context/scan/local-enrichment.js +13 -1
  80. package/dist/context/scan/local-scan.js +5 -4
  81. package/dist/context/scan/local-structural-artifacts.js +51 -0
  82. package/dist/context/scan/relationship-benchmarks.js +9 -6
  83. package/dist/context/scan/relationship-composite-candidates.d.ts +3 -2
  84. package/dist/context/scan/relationship-composite-candidates.js +21 -33
  85. package/dist/context/scan/relationship-discovery.d.ts +3 -2
  86. package/dist/context/scan/relationship-discovery.js +4 -4
  87. package/dist/context/scan/relationship-profiling.d.ts +2 -3
  88. package/dist/context/scan/relationship-profiling.js +25 -94
  89. package/dist/context/scan/relationship-validation.d.ts +3 -2
  90. package/dist/context/scan/relationship-validation.js +12 -22
  91. package/dist/context/scan/table-ref.d.ts +1 -2
  92. package/dist/context/scan/table-ref.js +3 -4
  93. package/dist/context/scan/types.d.ts +6 -2
  94. package/dist/context/scan/warehouse-catalog.js +31 -48
  95. package/dist/context/sl/local-query.js +0 -3
  96. package/dist/context/sl/local-sl.js +0 -13
  97. package/dist/context/sl/semantic-layer.service.js +1 -4
  98. package/dist/context/tools/context-candidate-write.tool.d.ts +2 -2
  99. package/dist/context-build-view.js +1 -1
  100. package/dist/database-tree-picker.js +14 -7
  101. package/dist/error-message.d.ts +1 -0
  102. package/dist/error-message.js +29 -0
  103. package/dist/ingest-depth.js +0 -1
  104. package/dist/ingest.js +2 -2
  105. package/dist/llm/embedding-health.js +2 -2
  106. package/dist/local-scan-connectors.js +13 -56
  107. package/dist/managed-local-embeddings.js +2 -1
  108. package/dist/managed-python-daemon.d.ts +5 -0
  109. package/dist/managed-python-daemon.js +29 -9
  110. package/dist/managed-python-http.js +2 -1
  111. package/dist/public-ingest.js +1 -6
  112. package/dist/runtime-requirements.js +2 -2
  113. package/dist/setup-agents.d.ts +1 -1
  114. package/dist/setup-agents.js +16 -74
  115. package/dist/setup-context.js +2 -1
  116. package/dist/setup-databases.d.ts +3 -13
  117. package/dist/setup-databases.js +141 -313
  118. package/dist/setup-embeddings.js +10 -2
  119. package/dist/setup-runtime.js +2 -1
  120. package/dist/setup-sources.js +2 -1
  121. package/dist/setup.js +10 -4
  122. package/dist/skills/historic_sql_patterns/SKILL.md +1 -3
  123. package/dist/skills/historic_sql_table_digest/SKILL.md +0 -1
  124. package/dist/skills/sl/SKILL.md +2 -2
  125. package/dist/sql.js +0 -4
  126. package/dist/status-project.d.ts +3 -18
  127. package/dist/status-project.js +42 -216
  128. package/dist/telemetry/events.d.ts +1 -1
  129. package/dist/telemetry/index.js +8 -3
  130. package/dist/tree-picker-state.d.ts +2 -2
  131. package/dist/tree-picker-state.js +29 -13
  132. package/dist/tree-picker-tui.d.ts +3 -1
  133. package/dist/tree-picker-tui.js +20 -32
  134. package/package.json +6 -6
  135. package/dist/admin-reindex.test.d.ts +0 -1
  136. package/dist/admin-reindex.test.js +0 -119
  137. package/dist/admin.test.d.ts +0 -1
  138. package/dist/admin.test.js +0 -201
  139. package/dist/cli-program-telemetry.test.d.ts +0 -1
  140. package/dist/cli-program-telemetry.test.js +0 -89
  141. package/dist/cli-program.test.d.ts +0 -1
  142. package/dist/cli-program.test.js +0 -71
  143. package/dist/command-tree.test.d.ts +0 -1
  144. package/dist/command-tree.test.js +0 -126
  145. package/dist/commands/mcp-commands.test.d.ts +0 -1
  146. package/dist/commands/mcp-commands.test.js +0 -111
  147. package/dist/commands/sql-commands.test.d.ts +0 -1
  148. package/dist/commands/sql-commands.test.js +0 -68
  149. package/dist/connection.test.d.ts +0 -1
  150. package/dist/connection.test.js +0 -426
  151. package/dist/connectors/bigquery/connector.test.d.ts +0 -1
  152. package/dist/connectors/bigquery/connector.test.js +0 -363
  153. package/dist/connectors/bigquery/dialect.test.d.ts +0 -1
  154. package/dist/connectors/bigquery/dialect.test.js +0 -36
  155. package/dist/connectors/clickhouse/connector.test.d.ts +0 -1
  156. package/dist/connectors/clickhouse/connector.test.js +0 -342
  157. package/dist/connectors/clickhouse/dialect.test.d.ts +0 -1
  158. package/dist/connectors/clickhouse/dialect.test.js +0 -36
  159. package/dist/connectors/mysql/connector.test.d.ts +0 -1
  160. package/dist/connectors/mysql/connector.test.js +0 -365
  161. package/dist/connectors/mysql/dialect.test.d.ts +0 -1
  162. package/dist/connectors/mysql/dialect.test.js +0 -36
  163. package/dist/connectors/postgres/connector.test.d.ts +0 -1
  164. package/dist/connectors/postgres/connector.test.js +0 -391
  165. package/dist/connectors/postgres/dialect.test.d.ts +0 -1
  166. package/dist/connectors/postgres/dialect.test.js +0 -37
  167. package/dist/connectors/postgres/historic-sql-query-client.test.d.ts +0 -1
  168. package/dist/connectors/postgres/historic-sql-query-client.test.js +0 -45
  169. package/dist/connectors/snowflake/connector.test.d.ts +0 -1
  170. package/dist/connectors/snowflake/connector.test.js +0 -462
  171. package/dist/connectors/snowflake/dialect.test.d.ts +0 -1
  172. package/dist/connectors/snowflake/dialect.test.js +0 -34
  173. package/dist/connectors/snowflake/identifiers.test.d.ts +0 -1
  174. package/dist/connectors/snowflake/identifiers.test.js +0 -12
  175. package/dist/connectors/snowflake/sdk-logger.test.d.ts +0 -1
  176. package/dist/connectors/snowflake/sdk-logger.test.js +0 -47
  177. package/dist/connectors/sqlite/connector.test.d.ts +0 -1
  178. package/dist/connectors/sqlite/connector.test.js +0 -207
  179. package/dist/connectors/sqlite/dialect.test.d.ts +0 -1
  180. package/dist/connectors/sqlite/dialect.test.js +0 -23
  181. package/dist/connectors/sqlserver/connector.test.d.ts +0 -1
  182. package/dist/connectors/sqlserver/connector.test.js +0 -313
  183. package/dist/connectors/sqlserver/dialect.test.d.ts +0 -1
  184. package/dist/connectors/sqlserver/dialect.test.js +0 -36
  185. package/dist/context/connections/bigquery-identifiers.test.d.ts +0 -1
  186. package/dist/context/connections/bigquery-identifiers.test.js +0 -13
  187. package/dist/context/connections/dialects.test.d.ts +0 -1
  188. package/dist/context/connections/dialects.test.js +0 -24
  189. package/dist/context/connections/local-query-executor.test.d.ts +0 -1
  190. package/dist/context/connections/local-query-executor.test.js +0 -48
  191. package/dist/context/connections/local-warehouse-descriptor.test.d.ts +0 -1
  192. package/dist/context/connections/local-warehouse-descriptor.test.js +0 -53
  193. package/dist/context/connections/notion-config.test.d.ts +0 -1
  194. package/dist/context/connections/notion-config.test.js +0 -121
  195. package/dist/context/connections/postgres-query-executor.test.d.ts +0 -1
  196. package/dist/context/connections/postgres-query-executor.test.js +0 -91
  197. package/dist/context/connections/read-only-sql.test.d.ts +0 -1
  198. package/dist/context/connections/read-only-sql.test.js +0 -20
  199. package/dist/context/connections/sqlite-query-executor.test.d.ts +0 -1
  200. package/dist/context/connections/sqlite-query-executor.test.js +0 -113
  201. package/dist/context/core/config-reference.test.d.ts +0 -1
  202. package/dist/context/core/config-reference.test.js +0 -27
  203. package/dist/context/core/git.service.assert-worktree-clean.test.d.ts +0 -1
  204. package/dist/context/core/git.service.assert-worktree-clean.test.js +0 -62
  205. package/dist/context/core/git.service.delete-directories.test.d.ts +0 -1
  206. package/dist/context/core/git.service.delete-directories.test.js +0 -61
  207. package/dist/context/core/git.service.patch.test.d.ts +0 -1
  208. package/dist/context/core/git.service.patch.test.js +0 -40
  209. package/dist/context/core/git.service.reset-hard.test.d.ts +0 -1
  210. package/dist/context/core/git.service.reset-hard.test.js +0 -47
  211. package/dist/context/core/git.service.test.d.ts +0 -1
  212. package/dist/context/core/git.service.test.js +0 -357
  213. package/dist/context/core/session-worktree.service.test.d.ts +0 -1
  214. package/dist/context/core/session-worktree.service.test.js +0 -97
  215. package/dist/context/daemon/semantic-layer-compute.test.d.ts +0 -1
  216. package/dist/context/daemon/semantic-layer-compute.test.js +0 -305
  217. package/dist/context/index-sync/reindex.test.d.ts +0 -1
  218. package/dist/context/index-sync/reindex.test.js +0 -139
  219. package/dist/context/ingest/action-identity.test.d.ts +0 -1
  220. package/dist/context/ingest/action-identity.test.js +0 -19
  221. package/dist/context/ingest/adapters/dbt/chunk.test.d.ts +0 -1
  222. package/dist/context/ingest/adapters/dbt/chunk.test.js +0 -30
  223. package/dist/context/ingest/adapters/dbt/dbt.adapter.test.d.ts +0 -1
  224. package/dist/context/ingest/adapters/dbt/dbt.adapter.test.js +0 -43
  225. package/dist/context/ingest/adapters/dbt/fetch.test.d.ts +0 -1
  226. package/dist/context/ingest/adapters/dbt/fetch.test.js +0 -30
  227. package/dist/context/ingest/adapters/dbt/parse.test.d.ts +0 -1
  228. package/dist/context/ingest/adapters/dbt/parse.test.js +0 -7
  229. package/dist/context/ingest/adapters/dbt-descriptions/parse-schema.test.d.ts +0 -1
  230. package/dist/context/ingest/adapters/dbt-descriptions/parse-schema.test.js +0 -195
  231. package/dist/context/ingest/adapters/historic-sql/bigquery-query-history-reader.test.d.ts +0 -1
  232. package/dist/context/ingest/adapters/historic-sql/bigquery-query-history-reader.test.js +0 -121
  233. package/dist/context/ingest/adapters/historic-sql/buckets.test.d.ts +0 -1
  234. package/dist/context/ingest/adapters/historic-sql/buckets.test.js +0 -49
  235. package/dist/context/ingest/adapters/historic-sql/chunk-unified.test.d.ts +0 -1
  236. package/dist/context/ingest/adapters/historic-sql/chunk-unified.test.js +0 -160
  237. package/dist/context/ingest/adapters/historic-sql/detect.test.d.ts +0 -1
  238. package/dist/context/ingest/adapters/historic-sql/detect.test.js +0 -48
  239. package/dist/context/ingest/adapters/historic-sql/evidence-tool.test.d.ts +0 -1
  240. package/dist/context/ingest/adapters/historic-sql/evidence-tool.test.js +0 -67
  241. package/dist/context/ingest/adapters/historic-sql/evidence.test.d.ts +0 -1
  242. package/dist/context/ingest/adapters/historic-sql/evidence.test.js +0 -43
  243. package/dist/context/ingest/adapters/historic-sql/historic-sql.adapter.test.d.ts +0 -1
  244. package/dist/context/ingest/adapters/historic-sql/historic-sql.adapter.test.js +0 -98
  245. package/dist/context/ingest/adapters/historic-sql/local-ingest-acceptance.test.d.ts +0 -1
  246. package/dist/context/ingest/adapters/historic-sql/local-ingest-acceptance.test.js +0 -235
  247. package/dist/context/ingest/adapters/historic-sql/pattern-inputs.test.d.ts +0 -1
  248. package/dist/context/ingest/adapters/historic-sql/pattern-inputs.test.js +0 -68
  249. package/dist/context/ingest/adapters/historic-sql/postgres-pgss-reader.test.d.ts +0 -1
  250. package/dist/context/ingest/adapters/historic-sql/postgres-pgss-reader.test.js +0 -205
  251. package/dist/context/ingest/adapters/historic-sql/projection.test.d.ts +0 -1
  252. package/dist/context/ingest/adapters/historic-sql/projection.test.js +0 -392
  253. package/dist/context/ingest/adapters/historic-sql/redaction.test.d.ts +0 -1
  254. package/dist/context/ingest/adapters/historic-sql/redaction.test.js +0 -22
  255. package/dist/context/ingest/adapters/historic-sql/skill-schemas.test.d.ts +0 -1
  256. package/dist/context/ingest/adapters/historic-sql/skill-schemas.test.js +0 -62
  257. package/dist/context/ingest/adapters/historic-sql/snowflake-query-history-reader.test.d.ts +0 -1
  258. package/dist/context/ingest/adapters/historic-sql/snowflake-query-history-reader.test.js +0 -117
  259. package/dist/context/ingest/adapters/historic-sql/stage-unified.test.d.ts +0 -1
  260. package/dist/context/ingest/adapters/historic-sql/stage-unified.test.js +0 -405
  261. package/dist/context/ingest/adapters/historic-sql/types.test.d.ts +0 -1
  262. package/dist/context/ingest/adapters/historic-sql/types.test.js +0 -87
  263. package/dist/context/ingest/adapters/live-database/chunk.test.d.ts +0 -1
  264. package/dist/context/ingest/adapters/live-database/chunk.test.js +0 -95
  265. package/dist/context/ingest/adapters/live-database/daemon-introspection.test.d.ts +0 -1
  266. package/dist/context/ingest/adapters/live-database/daemon-introspection.test.js +0 -241
  267. package/dist/context/ingest/adapters/live-database/live-database.adapter.test.d.ts +0 -1
  268. package/dist/context/ingest/adapters/live-database/live-database.adapter.test.js +0 -105
  269. package/dist/context/ingest/adapters/live-database/manifest.test.d.ts +0 -1
  270. package/dist/context/ingest/adapters/live-database/manifest.test.js +0 -291
  271. package/dist/context/ingest/adapters/live-database/stage.test.d.ts +0 -1
  272. package/dist/context/ingest/adapters/live-database/stage.test.js +0 -133
  273. package/dist/context/ingest/adapters/looker/chunk.test.d.ts +0 -1
  274. package/dist/context/ingest/adapters/looker/chunk.test.js +0 -142
  275. package/dist/context/ingest/adapters/looker/client-boundary.test.d.ts +0 -1
  276. package/dist/context/ingest/adapters/looker/client-boundary.test.js +0 -12
  277. package/dist/context/ingest/adapters/looker/client.test.d.ts +0 -1
  278. package/dist/context/ingest/adapters/looker/client.test.js +0 -407
  279. package/dist/context/ingest/adapters/looker/daemon-table-identifier-parser.test.d.ts +0 -1
  280. package/dist/context/ingest/adapters/looker/daemon-table-identifier-parser.test.js +0 -40
  281. package/dist/context/ingest/adapters/looker/detect.test.d.ts +0 -1
  282. package/dist/context/ingest/adapters/looker/detect.test.js +0 -39
  283. package/dist/context/ingest/adapters/looker/evidence-documents.test.d.ts +0 -1
  284. package/dist/context/ingest/adapters/looker/evidence-documents.test.js +0 -178
  285. package/dist/context/ingest/adapters/looker/factory.test.d.ts +0 -1
  286. package/dist/context/ingest/adapters/looker/factory.test.js +0 -55
  287. package/dist/context/ingest/adapters/looker/fetch-report.test.d.ts +0 -1
  288. package/dist/context/ingest/adapters/looker/fetch-report.test.js +0 -71
  289. package/dist/context/ingest/adapters/looker/fetch.test.d.ts +0 -1
  290. package/dist/context/ingest/adapters/looker/fetch.test.js +0 -592
  291. package/dist/context/ingest/adapters/looker/local-runtime-store.test.d.ts +0 -1
  292. package/dist/context/ingest/adapters/looker/local-runtime-store.test.js +0 -106
  293. package/dist/context/ingest/adapters/looker/looker.adapter.test.d.ts +0 -1
  294. package/dist/context/ingest/adapters/looker/looker.adapter.test.js +0 -99
  295. package/dist/context/ingest/adapters/looker/mapping.test.d.ts +0 -1
  296. package/dist/context/ingest/adapters/looker/mapping.test.js +0 -334
  297. package/dist/context/ingest/adapters/looker/reconcile.test.d.ts +0 -1
  298. package/dist/context/ingest/adapters/looker/reconcile.test.js +0 -12
  299. package/dist/context/ingest/adapters/looker/scope.test.d.ts +0 -1
  300. package/dist/context/ingest/adapters/looker/scope.test.js +0 -84
  301. package/dist/context/ingest/adapters/looker/target-connections.test.d.ts +0 -1
  302. package/dist/context/ingest/adapters/looker/target-connections.test.js +0 -71
  303. package/dist/context/ingest/adapters/looker/tools/looker-query-to-sl.tool.test.d.ts +0 -1
  304. package/dist/context/ingest/adapters/looker/tools/looker-query-to-sl.tool.test.js +0 -211
  305. package/dist/context/ingest/adapters/looker/types.test.d.ts +0 -1
  306. package/dist/context/ingest/adapters/looker/types.test.js +0 -261
  307. package/dist/context/ingest/adapters/lookml/chunk.test.d.ts +0 -1
  308. package/dist/context/ingest/adapters/lookml/chunk.test.js +0 -213
  309. package/dist/context/ingest/adapters/lookml/detect.test.d.ts +0 -1
  310. package/dist/context/ingest/adapters/lookml/detect.test.js +0 -37
  311. package/dist/context/ingest/adapters/lookml/fetch-report.test.d.ts +0 -1
  312. package/dist/context/ingest/adapters/lookml/fetch-report.test.js +0 -82
  313. package/dist/context/ingest/adapters/lookml/fetch.test.d.ts +0 -1
  314. package/dist/context/ingest/adapters/lookml/fetch.test.js +0 -121
  315. package/dist/context/ingest/adapters/lookml/graph.test.d.ts +0 -1
  316. package/dist/context/ingest/adapters/lookml/graph.test.js +0 -105
  317. package/dist/context/ingest/adapters/lookml/lookml.adapter.test.d.ts +0 -1
  318. package/dist/context/ingest/adapters/lookml/lookml.adapter.test.js +0 -49
  319. package/dist/context/ingest/adapters/lookml/parse.test.d.ts +0 -1
  320. package/dist/context/ingest/adapters/lookml/parse.test.js +0 -118
  321. package/dist/context/ingest/adapters/lookml/pull-config.test.d.ts +0 -1
  322. package/dist/context/ingest/adapters/lookml/pull-config.test.js +0 -128
  323. package/dist/context/ingest/adapters/metabase/card-references.test.d.ts +0 -1
  324. package/dist/context/ingest/adapters/metabase/card-references.test.js +0 -36
  325. package/dist/context/ingest/adapters/metabase/chunk.test.d.ts +0 -1
  326. package/dist/context/ingest/adapters/metabase/chunk.test.js +0 -299
  327. package/dist/context/ingest/adapters/metabase/client-boundary.test.d.ts +0 -1
  328. package/dist/context/ingest/adapters/metabase/client-boundary.test.js +0 -38
  329. package/dist/context/ingest/adapters/metabase/client-port.test.d.ts +0 -1
  330. package/dist/context/ingest/adapters/metabase/client-port.test.js +0 -86
  331. package/dist/context/ingest/adapters/metabase/client.test.d.ts +0 -1
  332. package/dist/context/ingest/adapters/metabase/client.test.js +0 -377
  333. package/dist/context/ingest/adapters/metabase/detect.test.d.ts +0 -1
  334. package/dist/context/ingest/adapters/metabase/detect.test.js +0 -42
  335. package/dist/context/ingest/adapters/metabase/fanout-planner.test.d.ts +0 -1
  336. package/dist/context/ingest/adapters/metabase/fanout-planner.test.js +0 -44
  337. package/dist/context/ingest/adapters/metabase/fetch-scope.test.d.ts +0 -1
  338. package/dist/context/ingest/adapters/metabase/fetch-scope.test.js +0 -124
  339. package/dist/context/ingest/adapters/metabase/fetch.test.d.ts +0 -1
  340. package/dist/context/ingest/adapters/metabase/fetch.test.js +0 -557
  341. package/dist/context/ingest/adapters/metabase/local-metabase.adapter.test.d.ts +0 -1
  342. package/dist/context/ingest/adapters/metabase/local-metabase.adapter.test.js +0 -56
  343. package/dist/context/ingest/adapters/metabase/local-source-state-store.test.d.ts +0 -1
  344. package/dist/context/ingest/adapters/metabase/local-source-state-store.test.js +0 -99
  345. package/dist/context/ingest/adapters/metabase/mapping.test.d.ts +0 -1
  346. package/dist/context/ingest/adapters/metabase/mapping.test.js +0 -215
  347. package/dist/context/ingest/adapters/metabase/metabase.adapter.test.d.ts +0 -1
  348. package/dist/context/ingest/adapters/metabase/metabase.adapter.test.js +0 -129
  349. package/dist/context/ingest/adapters/metabase/serialize-card.test.d.ts +0 -1
  350. package/dist/context/ingest/adapters/metabase/serialize-card.test.js +0 -205
  351. package/dist/context/ingest/adapters/metabase/types.test.d.ts +0 -1
  352. package/dist/context/ingest/adapters/metabase/types.test.js +0 -75
  353. package/dist/context/ingest/adapters/metricflow/chunk.test.d.ts +0 -1
  354. package/dist/context/ingest/adapters/metricflow/chunk.test.js +0 -114
  355. package/dist/context/ingest/adapters/metricflow/deep-parse.test.d.ts +0 -1
  356. package/dist/context/ingest/adapters/metricflow/deep-parse.test.js +0 -1139
  357. package/dist/context/ingest/adapters/metricflow/detect.test.d.ts +0 -1
  358. package/dist/context/ingest/adapters/metricflow/detect.test.js +0 -43
  359. package/dist/context/ingest/adapters/metricflow/fetch.test.d.ts +0 -1
  360. package/dist/context/ingest/adapters/metricflow/fetch.test.js +0 -97
  361. package/dist/context/ingest/adapters/metricflow/graph.test.d.ts +0 -1
  362. package/dist/context/ingest/adapters/metricflow/graph.test.js +0 -245
  363. package/dist/context/ingest/adapters/metricflow/import-semantic-models.test.d.ts +0 -1
  364. package/dist/context/ingest/adapters/metricflow/import-semantic-models.test.js +0 -318
  365. package/dist/context/ingest/adapters/metricflow/metricflow.adapter.test.d.ts +0 -1
  366. package/dist/context/ingest/adapters/metricflow/metricflow.adapter.test.js +0 -212
  367. package/dist/context/ingest/adapters/metricflow/parse.test.d.ts +0 -1
  368. package/dist/context/ingest/adapters/metricflow/parse.test.js +0 -171
  369. package/dist/context/ingest/adapters/metricflow/pull-config.test.d.ts +0 -1
  370. package/dist/context/ingest/adapters/metricflow/pull-config.test.js +0 -57
  371. package/dist/context/ingest/adapters/metricflow/semantic-models.test.d.ts +0 -1
  372. package/dist/context/ingest/adapters/metricflow/semantic-models.test.js +0 -204
  373. package/dist/context/ingest/adapters/notion/cluster.test.d.ts +0 -1
  374. package/dist/context/ingest/adapters/notion/cluster.test.js +0 -123
  375. package/dist/context/ingest/adapters/notion/fetch.test.d.ts +0 -1
  376. package/dist/context/ingest/adapters/notion/fetch.test.js +0 -358
  377. package/dist/context/ingest/adapters/notion/local-state-store.test.d.ts +0 -1
  378. package/dist/context/ingest/adapters/notion/local-state-store.test.js +0 -29
  379. package/dist/context/ingest/adapters/notion/normalize.test.d.ts +0 -1
  380. package/dist/context/ingest/adapters/notion/normalize.test.js +0 -64
  381. package/dist/context/ingest/adapters/notion/notion-client.test.d.ts +0 -1
  382. package/dist/context/ingest/adapters/notion/notion-client.test.js +0 -49
  383. package/dist/context/ingest/adapters/notion/notion.adapter.test.d.ts +0 -1
  384. package/dist/context/ingest/adapters/notion/notion.adapter.test.js +0 -315
  385. package/dist/context/ingest/artifact-gates.test.d.ts +0 -1
  386. package/dist/context/ingest/artifact-gates.test.js +0 -167
  387. package/dist/context/ingest/canonical-pins.test.d.ts +0 -1
  388. package/dist/context/ingest/canonical-pins.test.js +0 -66
  389. package/dist/context/ingest/clustering/kmeans.test.d.ts +0 -1
  390. package/dist/context/ingest/clustering/kmeans.test.js +0 -61
  391. package/dist/context/ingest/context-candidates/candidate-dedup.service.test.d.ts +0 -1
  392. package/dist/context/ingest/context-candidates/candidate-dedup.service.test.js +0 -216
  393. package/dist/context/ingest/context-candidates/context-candidate-carryforward.service.test.d.ts +0 -1
  394. package/dist/context/ingest/context-candidates/context-candidate-carryforward.service.test.js +0 -161
  395. package/dist/context/ingest/context-candidates/curator-pagination.service.test.d.ts +0 -1
  396. package/dist/context/ingest/context-candidates/curator-pagination.service.test.js +0 -168
  397. package/dist/context/ingest/context-candidates/embedding-text.test.d.ts +0 -1
  398. package/dist/context/ingest/context-candidates/embedding-text.test.js +0 -10
  399. package/dist/context/ingest/context-candidates/store.test.d.ts +0 -1
  400. package/dist/context/ingest/context-candidates/store.test.js +0 -67
  401. package/dist/context/ingest/context-evidence/context-evidence-index.service.test.d.ts +0 -1
  402. package/dist/context/ingest/context-evidence/context-evidence-index.service.test.js +0 -374
  403. package/dist/context/ingest/context-evidence/sqlite-context-evidence-store.test.d.ts +0 -1
  404. package/dist/context/ingest/context-evidence/sqlite-context-evidence-store.test.js +0 -416
  405. package/dist/context/ingest/context-evidence/store.test.d.ts +0 -1
  406. package/dist/context/ingest/context-evidence/store.test.js +0 -55
  407. package/dist/context/ingest/dbt-shared/project-vars.test.d.ts +0 -1
  408. package/dist/context/ingest/dbt-shared/project-vars.test.js +0 -90
  409. package/dist/context/ingest/dbt-shared/schema-files.test.d.ts +0 -1
  410. package/dist/context/ingest/dbt-shared/schema-files.test.js +0 -35
  411. package/dist/context/ingest/diff-set.service.test.d.ts +0 -1
  412. package/dist/context/ingest/diff-set.service.test.js +0 -132
  413. package/dist/context/ingest/final-gate-repair.test.d.ts +0 -1
  414. package/dist/context/ingest/final-gate-repair.test.js +0 -109
  415. package/dist/context/ingest/finalization-scope.test.d.ts +0 -1
  416. package/dist/context/ingest/finalization-scope.test.js +0 -114
  417. package/dist/context/ingest/ingest-bundle.runner.isolated-diff.test.d.ts +0 -1
  418. package/dist/context/ingest/ingest-bundle.runner.isolated-diff.test.js +0 -1928
  419. package/dist/context/ingest/ingest-bundle.runner.test.d.ts +0 -1
  420. package/dist/context/ingest/ingest-bundle.runner.test.js +0 -1899
  421. package/dist/context/ingest/ingest-prompts.test.d.ts +0 -1
  422. package/dist/context/ingest/ingest-prompts.test.js +0 -32
  423. package/dist/context/ingest/ingest-runtime-assets.test.d.ts +0 -1
  424. package/dist/context/ingest/ingest-runtime-assets.test.js +0 -89
  425. package/dist/context/ingest/ingest-trace.test.d.ts +0 -1
  426. package/dist/context/ingest/ingest-trace.test.js +0 -76
  427. package/dist/context/ingest/isolated-diff/git-patch.test.d.ts +0 -1
  428. package/dist/context/ingest/isolated-diff/git-patch.test.js +0 -76
  429. package/dist/context/ingest/isolated-diff/patch-integrator.test.d.ts +0 -1
  430. package/dist/context/ingest/isolated-diff/patch-integrator.test.js +0 -369
  431. package/dist/context/ingest/isolated-diff/textual-conflict-resolver.test.d.ts +0 -1
  432. package/dist/context/ingest/isolated-diff/textual-conflict-resolver.test.js +0 -101
  433. package/dist/context/ingest/isolated-diff/work-unit-executor.test.d.ts +0 -1
  434. package/dist/context/ingest/isolated-diff/work-unit-executor.test.js +0 -137
  435. package/dist/context/ingest/local-adapters.test.d.ts +0 -1
  436. package/dist/context/ingest/local-adapters.test.js +0 -612
  437. package/dist/context/ingest/local-bundle-ingest.test.d.ts +0 -1
  438. package/dist/context/ingest/local-bundle-ingest.test.js +0 -794
  439. package/dist/context/ingest/local-bundle-runtime.test.d.ts +0 -1
  440. package/dist/context/ingest/local-bundle-runtime.test.js +0 -240
  441. package/dist/context/ingest/local-embedding-provider.integration.test.d.ts +0 -1
  442. package/dist/context/ingest/local-embedding-provider.integration.test.js +0 -139
  443. package/dist/context/ingest/local-mapping-reconcile.test.d.ts +0 -1
  444. package/dist/context/ingest/local-mapping-reconcile.test.js +0 -61
  445. package/dist/context/ingest/local-metabase-ingest.test.d.ts +0 -1
  446. package/dist/context/ingest/local-metabase-ingest.test.js +0 -227
  447. package/dist/context/ingest/local-stage-ingest.test.d.ts +0 -1
  448. package/dist/context/ingest/local-stage-ingest.test.js +0 -581
  449. package/dist/context/ingest/memory-flow/acceptance-fixtures.d.ts +0 -6
  450. package/dist/context/ingest/memory-flow/acceptance-fixtures.js +0 -155
  451. package/dist/context/ingest/memory-flow/acceptance.test.d.ts +0 -1
  452. package/dist/context/ingest/memory-flow/acceptance.test.js +0 -43
  453. package/dist/context/ingest/memory-flow/events.test.d.ts +0 -1
  454. package/dist/context/ingest/memory-flow/events.test.js +0 -319
  455. package/dist/context/ingest/memory-flow/interaction.test.d.ts +0 -1
  456. package/dist/context/ingest/memory-flow/interaction.test.js +0 -264
  457. package/dist/context/ingest/memory-flow/interactive-render.test.d.ts +0 -1
  458. package/dist/context/ingest/memory-flow/interactive-render.test.js +0 -160
  459. package/dist/context/ingest/memory-flow/live-buffer.test.d.ts +0 -1
  460. package/dist/context/ingest/memory-flow/live-buffer.test.js +0 -77
  461. package/dist/context/ingest/memory-flow/render.test.d.ts +0 -1
  462. package/dist/context/ingest/memory-flow/render.test.js +0 -105
  463. package/dist/context/ingest/memory-flow/schema.test.d.ts +0 -1
  464. package/dist/context/ingest/memory-flow/schema.test.js +0 -147
  465. package/dist/context/ingest/memory-flow/summary.test.d.ts +0 -1
  466. package/dist/context/ingest/memory-flow/summary.test.js +0 -130
  467. package/dist/context/ingest/memory-flow/view-model.test.d.ts +0 -1
  468. package/dist/context/ingest/memory-flow/view-model.test.js +0 -397
  469. package/dist/context/ingest/memory-flow/visuals.test.d.ts +0 -1
  470. package/dist/context/ingest/memory-flow/visuals.test.js +0 -49
  471. package/dist/context/ingest/page-triage/page-triage.service.test.d.ts +0 -1
  472. package/dist/context/ingest/page-triage/page-triage.service.test.js +0 -311
  473. package/dist/context/ingest/raw-sources-paths.test.d.ts +0 -1
  474. package/dist/context/ingest/raw-sources-paths.test.js +0 -18
  475. package/dist/context/ingest/repo-fetch.test.d.ts +0 -1
  476. package/dist/context/ingest/repo-fetch.test.js +0 -168
  477. package/dist/context/ingest/report-snapshot.test.d.ts +0 -1
  478. package/dist/context/ingest/report-snapshot.test.js +0 -329
  479. package/dist/context/ingest/semantic-layer-target-policy.test.d.ts +0 -1
  480. package/dist/context/ingest/semantic-layer-target-policy.test.js +0 -25
  481. package/dist/context/ingest/source-adapter-registry.test.d.ts +0 -1
  482. package/dist/context/ingest/source-adapter-registry.test.js +0 -35
  483. package/dist/context/ingest/sqlite-bundle-ingest-store.test.d.ts +0 -1
  484. package/dist/context/ingest/sqlite-bundle-ingest-store.test.js +0 -517
  485. package/dist/context/ingest/sqlite-local-ingest-store.test.d.ts +0 -1
  486. package/dist/context/ingest/sqlite-local-ingest-store.test.js +0 -143
  487. package/dist/context/ingest/stages/build-reconcile-context.context-candidates.test.d.ts +0 -1
  488. package/dist/context/ingest/stages/build-reconcile-context.context-candidates.test.js +0 -102
  489. package/dist/context/ingest/stages/build-reconcile-context.test.d.ts +0 -1
  490. package/dist/context/ingest/stages/build-reconcile-context.test.js +0 -141
  491. package/dist/context/ingest/stages/build-wu-context.test.d.ts +0 -1
  492. package/dist/context/ingest/stages/build-wu-context.test.js +0 -196
  493. package/dist/context/ingest/stages/stage-1-stage-raw-files.test.d.ts +0 -1
  494. package/dist/context/ingest/stages/stage-1-stage-raw-files.test.js +0 -54
  495. package/dist/context/ingest/stages/stage-3-work-units.test.d.ts +0 -1
  496. package/dist/context/ingest/stages/stage-3-work-units.test.js +0 -175
  497. package/dist/context/ingest/stages/stage-4-reconciliation.test.d.ts +0 -1
  498. package/dist/context/ingest/stages/stage-4-reconciliation.test.js +0 -144
  499. package/dist/context/ingest/stages/validate-wu-sources.test.d.ts +0 -1
  500. package/dist/context/ingest/stages/validate-wu-sources.test.js +0 -27
  501. package/dist/context/ingest/tools/emit-reconciliation-records.tool.test.d.ts +0 -1
  502. package/dist/context/ingest/tools/emit-reconciliation-records.tool.test.js +0 -237
  503. package/dist/context/ingest/tools/eviction-list.tool.test.d.ts +0 -1
  504. package/dist/context/ingest/tools/eviction-list.tool.test.js +0 -44
  505. package/dist/context/ingest/tools/read-raw-file.tool.test.d.ts +0 -1
  506. package/dist/context/ingest/tools/read-raw-file.tool.test.js +0 -45
  507. package/dist/context/ingest/tools/read-raw-span.tool.test.d.ts +0 -1
  508. package/dist/context/ingest/tools/read-raw-span.tool.test.js +0 -34
  509. package/dist/context/ingest/tools/stage-diff.tool.test.d.ts +0 -1
  510. package/dist/context/ingest/tools/stage-diff.tool.test.js +0 -112
  511. package/dist/context/ingest/tools/stage-list.tool.test.d.ts +0 -1
  512. package/dist/context/ingest/tools/stage-list.tool.test.js +0 -58
  513. package/dist/context/ingest/tools/tool-transcript-summary.test.d.ts +0 -1
  514. package/dist/context/ingest/tools/tool-transcript-summary.test.js +0 -141
  515. package/dist/context/ingest/tools/warehouse-verification/discover-data.tool.test.d.ts +0 -1
  516. package/dist/context/ingest/tools/warehouse-verification/discover-data.tool.test.js +0 -107
  517. package/dist/context/ingest/tools/warehouse-verification/entity-details.tool.test.d.ts +0 -1
  518. package/dist/context/ingest/tools/warehouse-verification/entity-details.tool.test.js +0 -146
  519. package/dist/context/ingest/tools/warehouse-verification/sql-execution.tool.test.d.ts +0 -1
  520. package/dist/context/ingest/tools/warehouse-verification/sql-execution.tool.test.js +0 -50
  521. package/dist/context/ingest/wiki-body-refs.test.d.ts +0 -1
  522. package/dist/context/ingest/wiki-body-refs.test.js +0 -138
  523. package/dist/context/ingest/wiki-sl-ref-repair.test.d.ts +0 -1
  524. package/dist/context/ingest/wiki-sl-ref-repair.test.js +0 -81
  525. package/dist/context/llm/ai-sdk-runtime.test.d.ts +0 -1
  526. package/dist/context/llm/ai-sdk-runtime.test.js +0 -308
  527. package/dist/context/llm/claude-code-env.test.d.ts +0 -1
  528. package/dist/context/llm/claude-code-env.test.js +0 -17
  529. package/dist/context/llm/claude-code-models.test.d.ts +0 -1
  530. package/dist/context/llm/claude-code-models.test.js +0 -15
  531. package/dist/context/llm/claude-code-runtime.test.d.ts +0 -1
  532. package/dist/context/llm/claude-code-runtime.test.js +0 -434
  533. package/dist/context/llm/debug-request-recorder.test.d.ts +0 -1
  534. package/dist/context/llm/debug-request-recorder.test.js +0 -112
  535. package/dist/context/llm/embedding-port.test.d.ts +0 -1
  536. package/dist/context/llm/embedding-port.test.js +0 -34
  537. package/dist/context/llm/local-config.test.d.ts +0 -1
  538. package/dist/context/llm/local-config.test.js +0 -164
  539. package/dist/context/llm/runtime-local-config.test.d.ts +0 -1
  540. package/dist/context/llm/runtime-local-config.test.js +0 -17
  541. package/dist/context/llm/runtime-tools.test.d.ts +0 -1
  542. package/dist/context/llm/runtime-tools.test.js +0 -36
  543. package/dist/context/mcp/local-project-ports.test.d.ts +0 -1
  544. package/dist/context/mcp/local-project-ports.test.js +0 -689
  545. package/dist/context/mcp/server.test.d.ts +0 -1
  546. package/dist/context/mcp/server.test.js +0 -902
  547. package/dist/context/memory/local-memory.test.d.ts +0 -1
  548. package/dist/context/memory/local-memory.test.js +0 -173
  549. package/dist/context/memory/memory-agent.service.ingest.test.d.ts +0 -1
  550. package/dist/context/memory/memory-agent.service.ingest.test.js +0 -355
  551. package/dist/context/memory/memory-agent.service.test.d.ts +0 -1
  552. package/dist/context/memory/memory-agent.service.test.js +0 -413
  553. package/dist/context/memory/memory-runs.test.d.ts +0 -1
  554. package/dist/context/memory/memory-runs.test.js +0 -158
  555. package/dist/context/memory/memory-runtime-assets.test.d.ts +0 -1
  556. package/dist/context/memory/memory-runtime-assets.test.js +0 -162
  557. package/dist/context/project/config.test.d.ts +0 -1
  558. package/dist/context/project/config.test.js +0 -467
  559. package/dist/context/project/driver-schemas.test.d.ts +0 -1
  560. package/dist/context/project/driver-schemas.test.js +0 -125
  561. package/dist/context/project/local-git-file-store.test.d.ts +0 -1
  562. package/dist/context/project/local-git-file-store.test.js +0 -71
  563. package/dist/context/project/mappings-yaml-schema.test.d.ts +0 -1
  564. package/dist/context/project/mappings-yaml-schema.test.js +0 -79
  565. package/dist/context/project/project.test.d.ts +0 -1
  566. package/dist/context/project/project.test.js +0 -55
  567. package/dist/context/project/setup-config.test.d.ts +0 -1
  568. package/dist/context/project/setup-config.test.js +0 -38
  569. package/dist/context/prompts/prompt.service.test.d.ts +0 -1
  570. package/dist/context/prompts/prompt.service.test.js +0 -43
  571. package/dist/context/scan/credentials.test.d.ts +0 -1
  572. package/dist/context/scan/credentials.test.js +0 -162
  573. package/dist/context/scan/data-dictionary.test.d.ts +0 -1
  574. package/dist/context/scan/data-dictionary.test.js +0 -92
  575. package/dist/context/scan/description-generation.test.d.ts +0 -1
  576. package/dist/context/scan/description-generation.test.js +0 -693
  577. package/dist/context/scan/embedding-text.test.d.ts +0 -1
  578. package/dist/context/scan/embedding-text.test.js +0 -36
  579. package/dist/context/scan/enrichment-state.test.d.ts +0 -1
  580. package/dist/context/scan/enrichment-state.test.js +0 -147
  581. package/dist/context/scan/enrichment-summary.test.d.ts +0 -1
  582. package/dist/context/scan/enrichment-summary.test.js +0 -34
  583. package/dist/context/scan/enrichment-types.test.d.ts +0 -1
  584. package/dist/context/scan/enrichment-types.test.js +0 -141
  585. package/dist/context/scan/entity-details.test.d.ts +0 -1
  586. package/dist/context/scan/entity-details.test.js +0 -234
  587. package/dist/context/scan/local-enrichment-artifacts.test.d.ts +0 -1
  588. package/dist/context/scan/local-enrichment-artifacts.test.js +0 -771
  589. package/dist/context/scan/local-enrichment.test.d.ts +0 -1
  590. package/dist/context/scan/local-enrichment.test.js +0 -765
  591. package/dist/context/scan/local-scan.test.d.ts +0 -1
  592. package/dist/context/scan/local-scan.test.js +0 -1663
  593. package/dist/context/scan/local-structural-artifacts.test.d.ts +0 -1
  594. package/dist/context/scan/local-structural-artifacts.test.js +0 -144
  595. package/dist/context/scan/relationship-benchmark-report.test.d.ts +0 -1
  596. package/dist/context/scan/relationship-benchmark-report.test.js +0 -389
  597. package/dist/context/scan/relationship-benchmarks.test.d.ts +0 -1
  598. package/dist/context/scan/relationship-benchmarks.test.js +0 -1072
  599. package/dist/context/scan/relationship-budget.test.d.ts +0 -1
  600. package/dist/context/scan/relationship-budget.test.js +0 -71
  601. package/dist/context/scan/relationship-candidates.test.d.ts +0 -1
  602. package/dist/context/scan/relationship-candidates.test.js +0 -747
  603. package/dist/context/scan/relationship-composite-candidates.test.d.ts +0 -1
  604. package/dist/context/scan/relationship-composite-candidates.test.js +0 -69
  605. package/dist/context/scan/relationship-diagnostics.test.d.ts +0 -1
  606. package/dist/context/scan/relationship-diagnostics.test.js +0 -333
  607. package/dist/context/scan/relationship-discovery.test.d.ts +0 -1
  608. package/dist/context/scan/relationship-discovery.test.js +0 -618
  609. package/dist/context/scan/relationship-formal-metadata.test.d.ts +0 -1
  610. package/dist/context/scan/relationship-formal-metadata.test.js +0 -125
  611. package/dist/context/scan/relationship-graph-resolver.test.d.ts +0 -1
  612. package/dist/context/scan/relationship-graph-resolver.test.js +0 -604
  613. package/dist/context/scan/relationship-llm-proposal.test.d.ts +0 -1
  614. package/dist/context/scan/relationship-llm-proposal.test.js +0 -197
  615. package/dist/context/scan/relationship-locality.test.d.ts +0 -1
  616. package/dist/context/scan/relationship-locality.test.js +0 -128
  617. package/dist/context/scan/relationship-name-similarity.test.d.ts +0 -1
  618. package/dist/context/scan/relationship-name-similarity.test.js +0 -68
  619. package/dist/context/scan/relationship-profiling.test.d.ts +0 -1
  620. package/dist/context/scan/relationship-profiling.test.js +0 -392
  621. package/dist/context/scan/relationship-scoring.test.d.ts +0 -1
  622. package/dist/context/scan/relationship-scoring.test.js +0 -86
  623. package/dist/context/scan/relationship-validation.test.d.ts +0 -1
  624. package/dist/context/scan/relationship-validation.test.js +0 -455
  625. package/dist/context/scan/table-ref.test.d.ts +0 -1
  626. package/dist/context/scan/table-ref.test.js +0 -53
  627. package/dist/context/scan/type-normalization.test.d.ts +0 -1
  628. package/dist/context/scan/type-normalization.test.js +0 -21
  629. package/dist/context/scan/types.test.d.ts +0 -1
  630. package/dist/context/scan/types.test.js +0 -206
  631. package/dist/context/scan/warehouse-catalog.test.d.ts +0 -1
  632. package/dist/context/scan/warehouse-catalog.test.js +0 -158
  633. package/dist/context/search/backend-conformance.test-utils.d.ts +0 -39
  634. package/dist/context/search/backend-conformance.test-utils.js +0 -88
  635. package/dist/context/search/backend-conformance.test-utils.test.d.ts +0 -1
  636. package/dist/context/search/backend-conformance.test-utils.test.js +0 -408
  637. package/dist/context/search/discover.test.d.ts +0 -1
  638. package/dist/context/search/discover.test.js +0 -197
  639. package/dist/context/search/hybrid-search-core.test.d.ts +0 -1
  640. package/dist/context/search/hybrid-search-core.test.js +0 -113
  641. package/dist/context/search/pglite-owner-process.test.d.ts +0 -1
  642. package/dist/context/search/pglite-owner-process.test.js +0 -273
  643. package/dist/context/search/pglite-runtime-boundary.test.d.ts +0 -1
  644. package/dist/context/search/pglite-runtime-boundary.test.js +0 -40
  645. package/dist/context/search/pglite-spike.test.d.ts +0 -1
  646. package/dist/context/search/pglite-spike.test.js +0 -249
  647. package/dist/context/search/query.test.d.ts +0 -1
  648. package/dist/context/search/query.test.js +0 -23
  649. package/dist/context/search/rrf.test.d.ts +0 -1
  650. package/dist/context/search/rrf.test.js +0 -47
  651. package/dist/context/skills/skills-registry.service.test.d.ts +0 -1
  652. package/dist/context/skills/skills-registry.service.test.js +0 -161
  653. package/dist/context/sl/dictionary-search.test.d.ts +0 -1
  654. package/dist/context/sl/dictionary-search.test.js +0 -204
  655. package/dist/context/sl/local-query.test.d.ts +0 -1
  656. package/dist/context/sl/local-query.test.js +0 -283
  657. package/dist/context/sl/local-sl.test.d.ts +0 -1
  658. package/dist/context/sl/local-sl.test.js +0 -334
  659. package/dist/context/sl/pglite-sl-search-prototype.test.d.ts +0 -1
  660. package/dist/context/sl/pglite-sl-search-prototype.test.js +0 -240
  661. package/dist/context/sl/schemas.contract.test.d.ts +0 -1
  662. package/dist/context/sl/schemas.contract.test.js +0 -62
  663. package/dist/context/sl/semantic-layer.service.test.d.ts +0 -1
  664. package/dist/context/sl/semantic-layer.service.test.js +0 -1107
  665. package/dist/context/sl/sl-dictionary-profile.test.d.ts +0 -1
  666. package/dist/context/sl/sl-dictionary-profile.test.js +0 -88
  667. package/dist/context/sl/sl-search.service.test.d.ts +0 -1
  668. package/dist/context/sl/sl-search.service.test.js +0 -256
  669. package/dist/context/sl/sqlite-sl-sources-index.test.d.ts +0 -1
  670. package/dist/context/sl/sqlite-sl-sources-index.test.js +0 -175
  671. package/dist/context/sl/tools/connection-id-schema.test.d.ts +0 -1
  672. package/dist/context/sl/tools/connection-id-schema.test.js +0 -14
  673. package/dist/context/sl/tools/sl-discover.tool.test.d.ts +0 -1
  674. package/dist/context/sl/tools/sl-discover.tool.test.js +0 -72
  675. package/dist/context/sl/tools/sl-edit-source.tool.test.d.ts +0 -1
  676. package/dist/context/sl/tools/sl-edit-source.tool.test.js +0 -184
  677. package/dist/context/sl/tools/sl-read-source.tool.session.test.d.ts +0 -1
  678. package/dist/context/sl/tools/sl-read-source.tool.session.test.js +0 -55
  679. package/dist/context/sl/tools/sl-rollback.tool.test.d.ts +0 -1
  680. package/dist/context/sl/tools/sl-rollback.tool.test.js +0 -57
  681. package/dist/context/sl/tools/sl-validate.tool.test.d.ts +0 -1
  682. package/dist/context/sl/tools/sl-validate.tool.test.js +0 -54
  683. package/dist/context/sl/tools/sl-warehouse-validation.test.d.ts +0 -1
  684. package/dist/context/sl/tools/sl-warehouse-validation.test.js +0 -136
  685. package/dist/context/sl/tools/sl-write-source.tool.test.d.ts +0 -1
  686. package/dist/context/sl/tools/sl-write-source.tool.test.js +0 -307
  687. package/dist/context/sql-analysis/http-sql-analysis-port.test.d.ts +0 -1
  688. package/dist/context/sql-analysis/http-sql-analysis-port.test.js +0 -147
  689. package/dist/context/test/make-local-git-repo.d.ts +0 -10
  690. package/dist/context/test/make-local-git-repo.js +0 -34
  691. package/dist/context/tools/context-evidence-tools.test.d.ts +0 -1
  692. package/dist/context/tools/context-evidence-tools.test.js +0 -486
  693. package/dist/context/tools/touched-sl-sources.test.d.ts +0 -1
  694. package/dist/context/tools/touched-sl-sources.test.js +0 -31
  695. package/dist/context/wiki/knowledge-wiki.service.test.d.ts +0 -1
  696. package/dist/context/wiki/knowledge-wiki.service.test.js +0 -205
  697. package/dist/context/wiki/local-knowledge.test.d.ts +0 -1
  698. package/dist/context/wiki/local-knowledge.test.js +0 -270
  699. package/dist/context/wiki/sqlite-knowledge-index.test.d.ts +0 -1
  700. package/dist/context/wiki/sqlite-knowledge-index.test.js +0 -129
  701. package/dist/context/wiki/tools/wiki-list-tags.tool.test.d.ts +0 -1
  702. package/dist/context/wiki/tools/wiki-list-tags.tool.test.js +0 -35
  703. package/dist/context/wiki/tools/wiki-read.tool.test.d.ts +0 -1
  704. package/dist/context/wiki/tools/wiki-read.tool.test.js +0 -66
  705. package/dist/context/wiki/tools/wiki-remove.tool.test.d.ts +0 -1
  706. package/dist/context/wiki/tools/wiki-remove.tool.test.js +0 -95
  707. package/dist/context/wiki/tools/wiki-search.tool.test.d.ts +0 -1
  708. package/dist/context/wiki/tools/wiki-search.tool.test.js +0 -35
  709. package/dist/context/wiki/tools/wiki-write.tool.test.d.ts +0 -1
  710. package/dist/context/wiki/tools/wiki-write.tool.test.js +0 -264
  711. package/dist/context/wiki/wiki-ref-validation.test.d.ts +0 -1
  712. package/dist/context/wiki/wiki-ref-validation.test.js +0 -64
  713. package/dist/context-build-view.test.d.ts +0 -1
  714. package/dist/context-build-view.test.js +0 -942
  715. package/dist/database-tree-picker.test.d.ts +0 -1
  716. package/dist/database-tree-picker.test.js +0 -188
  717. package/dist/demo-assets.test.d.ts +0 -1
  718. package/dist/demo-assets.test.js +0 -121
  719. package/dist/demo-metrics.test.d.ts +0 -1
  720. package/dist/demo-metrics.test.js +0 -108
  721. package/dist/doctor.test.d.ts +0 -1
  722. package/dist/doctor.test.js +0 -596
  723. package/dist/embedding-resolution.test.d.ts +0 -1
  724. package/dist/embedding-resolution.test.js +0 -132
  725. package/dist/example-smoke.test.d.ts +0 -1
  726. package/dist/example-smoke.test.js +0 -83
  727. package/dist/index.test.d.ts +0 -1
  728. package/dist/index.test.js +0 -1300
  729. package/dist/ingest-query-executor.test.d.ts +0 -1
  730. package/dist/ingest-query-executor.test.js +0 -71
  731. package/dist/ingest-report-file.test.d.ts +0 -1
  732. package/dist/ingest-report-file.test.js +0 -63
  733. package/dist/ingest-viz.test.d.ts +0 -1
  734. package/dist/ingest-viz.test.js +0 -691
  735. package/dist/ingest.test-utils.d.ts +0 -126
  736. package/dist/ingest.test-utils.js +0 -629
  737. package/dist/ingest.test.d.ts +0 -1
  738. package/dist/ingest.test.js +0 -1568
  739. package/dist/io/logger.test.d.ts +0 -1
  740. package/dist/io/logger.test.js +0 -55
  741. package/dist/io/mode.test.d.ts +0 -1
  742. package/dist/io/mode.test.js +0 -48
  743. package/dist/io/print-list.test.d.ts +0 -1
  744. package/dist/io/print-list.test.js +0 -277
  745. package/dist/knowledge.test.d.ts +0 -1
  746. package/dist/knowledge.test.js +0 -198
  747. package/dist/llm/embedding-health.test.d.ts +0 -1
  748. package/dist/llm/embedding-health.test.js +0 -72
  749. package/dist/llm/embedding-provider.test.d.ts +0 -1
  750. package/dist/llm/embedding-provider.test.js +0 -84
  751. package/dist/llm/message-builder.test.d.ts +0 -1
  752. package/dist/llm/message-builder.test.js +0 -127
  753. package/dist/llm/model-health.test.d.ts +0 -1
  754. package/dist/llm/model-health.test.js +0 -55
  755. package/dist/llm/model-provider.test.d.ts +0 -1
  756. package/dist/llm/model-provider.test.js +0 -246
  757. package/dist/llm/repair.test.d.ts +0 -1
  758. package/dist/llm/repair.test.js +0 -78
  759. package/dist/local-adapters.test.d.ts +0 -1
  760. package/dist/local-adapters.test.js +0 -166
  761. package/dist/local-scan-connectors.test.d.ts +0 -1
  762. package/dist/local-scan-connectors.test.js +0 -92
  763. package/dist/managed-local-embeddings.test.d.ts +0 -1
  764. package/dist/managed-local-embeddings.test.js +0 -229
  765. package/dist/managed-mcp-daemon.test.d.ts +0 -1
  766. package/dist/managed-mcp-daemon.test.js +0 -187
  767. package/dist/managed-python-command.test.d.ts +0 -1
  768. package/dist/managed-python-command.test.js +0 -262
  769. package/dist/managed-python-daemon.test.d.ts +0 -1
  770. package/dist/managed-python-daemon.test.js +0 -360
  771. package/dist/managed-python-http.test.d.ts +0 -1
  772. package/dist/managed-python-http.test.js +0 -177
  773. package/dist/managed-python-runtime.test.d.ts +0 -1
  774. package/dist/managed-python-runtime.test.js +0 -426
  775. package/dist/mcp-http-server.test.d.ts +0 -1
  776. package/dist/mcp-http-server.test.js +0 -209
  777. package/dist/mcp-server-factory.test.d.ts +0 -1
  778. package/dist/mcp-server-factory.test.js +0 -142
  779. package/dist/memory-flow-interactive.test.d.ts +0 -1
  780. package/dist/memory-flow-interactive.test.js +0 -109
  781. package/dist/memory-flow-tui.test.d.ts +0 -1
  782. package/dist/memory-flow-tui.test.js +0 -247
  783. package/dist/next-steps.test.d.ts +0 -1
  784. package/dist/next-steps.test.js +0 -77
  785. package/dist/notion-page-picker.test.d.ts +0 -1
  786. package/dist/notion-page-picker.test.js +0 -244
  787. package/dist/print-command-tree.test.d.ts +0 -1
  788. package/dist/print-command-tree.test.js +0 -37
  789. package/dist/project-dir.test.d.ts +0 -1
  790. package/dist/project-dir.test.js +0 -124
  791. package/dist/project-resolver.test.d.ts +0 -1
  792. package/dist/project-resolver.test.js +0 -49
  793. package/dist/prompt-navigation.test.d.ts +0 -1
  794. package/dist/prompt-navigation.test.js +0 -33
  795. package/dist/proxy-env.test.d.ts +0 -1
  796. package/dist/proxy-env.test.js +0 -17
  797. package/dist/public-ingest-copy.test.d.ts +0 -1
  798. package/dist/public-ingest-copy.test.js +0 -24
  799. package/dist/public-ingest.test.d.ts +0 -1
  800. package/dist/public-ingest.test.js +0 -891
  801. package/dist/runtime-requirements.test.d.ts +0 -1
  802. package/dist/runtime-requirements.test.js +0 -73
  803. package/dist/runtime.test.d.ts +0 -1
  804. package/dist/runtime.test.js +0 -381
  805. package/dist/scan.test.d.ts +0 -1
  806. package/dist/scan.test.js +0 -1123
  807. package/dist/setup-agents.test.d.ts +0 -1
  808. package/dist/setup-agents.test.js +0 -1028
  809. package/dist/setup-context.test.d.ts +0 -1
  810. package/dist/setup-context.test.js +0 -491
  811. package/dist/setup-databases.test.d.ts +0 -1
  812. package/dist/setup-databases.test.js +0 -2101
  813. package/dist/setup-demo-tour.test.d.ts +0 -1
  814. package/dist/setup-demo-tour.test.js +0 -221
  815. package/dist/setup-embeddings.test.d.ts +0 -1
  816. package/dist/setup-embeddings.test.js +0 -436
  817. package/dist/setup-interrupt.test.d.ts +0 -1
  818. package/dist/setup-interrupt.test.js +0 -77
  819. package/dist/setup-models.test.d.ts +0 -1
  820. package/dist/setup-models.test.js +0 -885
  821. package/dist/setup-project.test.d.ts +0 -1
  822. package/dist/setup-project.test.js +0 -209
  823. package/dist/setup-prompts.test.d.ts +0 -1
  824. package/dist/setup-prompts.test.js +0 -208
  825. package/dist/setup-ready-menu.test.d.ts +0 -1
  826. package/dist/setup-ready-menu.test.js +0 -44
  827. package/dist/setup-runtime.test.d.ts +0 -1
  828. package/dist/setup-runtime.test.js +0 -111
  829. package/dist/setup-secrets.test.d.ts +0 -1
  830. package/dist/setup-secrets.test.js +0 -30
  831. package/dist/setup-sources-notion.test.d.ts +0 -1
  832. package/dist/setup-sources-notion.test.js +0 -109
  833. package/dist/setup-sources.test.d.ts +0 -1
  834. package/dist/setup-sources.test.js +0 -1303
  835. package/dist/setup.test.d.ts +0 -1
  836. package/dist/setup.test.js +0 -1825
  837. package/dist/sl.test.d.ts +0 -1
  838. package/dist/sl.test.js +0 -567
  839. package/dist/source-mapping.test.d.ts +0 -1
  840. package/dist/source-mapping.test.js +0 -65
  841. package/dist/sql.test.d.ts +0 -1
  842. package/dist/sql.test.js +0 -253
  843. package/dist/standalone-smoke.test.d.ts +0 -1
  844. package/dist/standalone-smoke.test.js +0 -250
  845. package/dist/status-project.test.d.ts +0 -1
  846. package/dist/status-project.test.js +0 -502
  847. package/dist/telemetry/command-hook.test.d.ts +0 -1
  848. package/dist/telemetry/command-hook.test.js +0 -31
  849. package/dist/telemetry/demo-detect.test.d.ts +0 -1
  850. package/dist/telemetry/demo-detect.test.js +0 -22
  851. package/dist/telemetry/emitter.test.d.ts +0 -1
  852. package/dist/telemetry/emitter.test.js +0 -103
  853. package/dist/telemetry/events.snapshot.test.d.ts +0 -1
  854. package/dist/telemetry/events.snapshot.test.js +0 -135
  855. package/dist/telemetry/events.test.d.ts +0 -1
  856. package/dist/telemetry/events.test.js +0 -136
  857. package/dist/telemetry/identity.test.d.ts +0 -1
  858. package/dist/telemetry/identity.test.js +0 -148
  859. package/dist/telemetry/project-snapshot.test.d.ts +0 -1
  860. package/dist/telemetry/project-snapshot.test.js +0 -71
  861. package/dist/telemetry/schema-writer.test.d.ts +0 -1
  862. package/dist/telemetry/schema-writer.test.js +0 -23
  863. package/dist/telemetry/scrubber.test.d.ts +0 -1
  864. package/dist/telemetry/scrubber.test.js +0 -21
  865. package/dist/text-ingest.test.d.ts +0 -1
  866. package/dist/text-ingest.test.js +0 -247
  867. package/dist/tree-picker-state.test.d.ts +0 -1
  868. package/dist/tree-picker-state.test.js +0 -303
  869. package/dist/tree-picker-tui.test.d.ts +0 -1
  870. package/dist/tree-picker-tui.test.js +0 -248
  871. package/dist/viz-fallback.test.d.ts +0 -1
  872. 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
- });