@wrenai/genbi 0.0.1

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 (286) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +141 -0
  3. package/bin/genbi.mjs +31 -0
  4. package/dist/assets/echarts-LTFC-ysd.js +40 -0
  5. package/dist/assets/index-Bo--QMUN.js +441 -0
  6. package/dist/assets/index-Xs4q7pNo.css +1 -0
  7. package/dist/index.html +14 -0
  8. package/dist/wrenai_logo.png +0 -0
  9. package/dist/wrenai_logo_white.png +0 -0
  10. package/dist-server/harness/auth/detect.d.ts +18 -0
  11. package/dist-server/harness/auth/detect.js +37 -0
  12. package/dist-server/harness/auth/index.d.ts +4 -0
  13. package/dist-server/harness/auth/index.js +2 -0
  14. package/dist-server/harness/auth/probe.d.ts +18 -0
  15. package/dist-server/harness/auth/probe.js +52 -0
  16. package/dist-server/harness/auth/types.d.ts +42 -0
  17. package/dist-server/harness/auth/types.js +9 -0
  18. package/dist-server/harness/bundle/loader.d.ts +32 -0
  19. package/dist-server/harness/bundle/loader.js +43 -0
  20. package/dist-server/harness/bundle/schema.d.ts +199 -0
  21. package/dist-server/harness/bundle/schema.js +127 -0
  22. package/dist-server/harness/bundle/version.d.ts +10 -0
  23. package/dist-server/harness/bundle/version.js +43 -0
  24. package/dist-server/harness/capability/gate.d.ts +6 -0
  25. package/dist-server/harness/capability/gate.js +29 -0
  26. package/dist-server/harness/capability/registry.d.ts +6 -0
  27. package/dist-server/harness/capability/registry.js +17 -0
  28. package/dist-server/harness/cli-args.d.ts +123 -0
  29. package/dist-server/harness/cli-args.js +247 -0
  30. package/dist-server/harness/cli.d.ts +2 -0
  31. package/dist-server/harness/cli.js +151 -0
  32. package/dist-server/harness/compile/cache.d.ts +23 -0
  33. package/dist-server/harness/compile/cache.js +109 -0
  34. package/dist-server/harness/compile/compose-profile.d.ts +34 -0
  35. package/dist-server/harness/compile/compose-profile.js +95 -0
  36. package/dist-server/harness/compile/errors.d.ts +22 -0
  37. package/dist-server/harness/compile/errors.js +41 -0
  38. package/dist-server/harness/compile/fingerprint.d.ts +22 -0
  39. package/dist-server/harness/compile/fingerprint.js +84 -0
  40. package/dist-server/harness/compile/index.d.ts +8 -0
  41. package/dist-server/harness/compile/index.js +7 -0
  42. package/dist-server/harness/compile/pipeline.d.ts +66 -0
  43. package/dist-server/harness/compile/pipeline.js +176 -0
  44. package/dist-server/harness/compile/resolve-binary.d.ts +55 -0
  45. package/dist-server/harness/compile/resolve-binary.js +133 -0
  46. package/dist-server/harness/compile/types.d.ts +107 -0
  47. package/dist-server/harness/compile/types.js +1 -0
  48. package/dist-server/harness/compile/warble-identity.d.ts +12 -0
  49. package/dist-server/harness/compile/warble-identity.js +33 -0
  50. package/dist-server/harness/compliance/gate.d.ts +35 -0
  51. package/dist-server/harness/compliance/gate.js +48 -0
  52. package/dist-server/harness/compliance/index.d.ts +2 -0
  53. package/dist-server/harness/compliance/index.js +1 -0
  54. package/dist-server/harness/compliance/types.d.ts +16 -0
  55. package/dist-server/harness/compliance/types.js +1 -0
  56. package/dist-server/harness/events/emitter.d.ts +34 -0
  57. package/dist-server/harness/events/emitter.js +25 -0
  58. package/dist-server/harness/events/index.d.ts +4 -0
  59. package/dist-server/harness/events/index.js +2 -0
  60. package/dist-server/harness/events/sse.d.ts +20 -0
  61. package/dist-server/harness/events/sse.js +48 -0
  62. package/dist-server/harness/events/types.d.ts +131 -0
  63. package/dist-server/harness/events/types.js +1 -0
  64. package/dist-server/harness/exec/errors.d.ts +16 -0
  65. package/dist-server/harness/exec/errors.js +29 -0
  66. package/dist-server/harness/exec/index.d.ts +5 -0
  67. package/dist-server/harness/exec/index.js +2 -0
  68. package/dist-server/harness/exec/local.d.ts +32 -0
  69. package/dist-server/harness/exec/local.js +134 -0
  70. package/dist-server/harness/exec/policy.d.ts +12 -0
  71. package/dist-server/harness/exec/policy.js +1 -0
  72. package/dist-server/harness/exec/types.d.ts +63 -0
  73. package/dist-server/harness/exec/types.js +1 -0
  74. package/dist-server/harness/guardrails/index.d.ts +2 -0
  75. package/dist-server/harness/guardrails/index.js +1 -0
  76. package/dist-server/harness/guardrails/policy.d.ts +45 -0
  77. package/dist-server/harness/guardrails/policy.js +57 -0
  78. package/dist-server/harness/index.d.ts +37 -0
  79. package/dist-server/harness/index.js +19 -0
  80. package/dist-server/harness/loop/errors.d.ts +53 -0
  81. package/dist-server/harness/loop/errors.js +72 -0
  82. package/dist-server/harness/loop/executor.d.ts +123 -0
  83. package/dist-server/harness/loop/executor.js +380 -0
  84. package/dist-server/harness/loop/guard.d.ts +16 -0
  85. package/dist-server/harness/loop/guard.js +1 -0
  86. package/dist-server/harness/loop/index.d.ts +5 -0
  87. package/dist-server/harness/loop/index.js +3 -0
  88. package/dist-server/harness/native-producer/index.d.ts +109 -0
  89. package/dist-server/harness/native-producer/index.js +302 -0
  90. package/dist-server/harness/npm-package-resolve.d.ts +28 -0
  91. package/dist-server/harness/npm-package-resolve.js +47 -0
  92. package/dist-server/harness/providers/adapters/anthropic.d.ts +7 -0
  93. package/dist-server/harness/providers/adapters/anthropic.js +6 -0
  94. package/dist-server/harness/providers/adapters/mock.d.ts +4 -0
  95. package/dist-server/harness/providers/adapters/mock.js +5 -0
  96. package/dist-server/harness/providers/adapters/openai-compatible.d.ts +10 -0
  97. package/dist-server/harness/providers/adapters/openai-compatible.js +10 -0
  98. package/dist-server/harness/providers/binding.d.ts +23 -0
  99. package/dist-server/harness/providers/binding.js +13 -0
  100. package/dist-server/harness/providers/errors.d.ts +6 -0
  101. package/dist-server/harness/providers/errors.js +12 -0
  102. package/dist-server/harness/providers/index.d.ts +18 -0
  103. package/dist-server/harness/providers/index.js +22 -0
  104. package/dist-server/harness/providers/registry.d.ts +16 -0
  105. package/dist-server/harness/providers/registry.js +24 -0
  106. package/dist-server/harness/render/envelope.d.ts +145 -0
  107. package/dist-server/harness/render/envelope.js +428 -0
  108. package/dist-server/harness/render/errors.d.ts +33 -0
  109. package/dist-server/harness/render/errors.js +46 -0
  110. package/dist-server/harness/render/index.d.ts +5 -0
  111. package/dist-server/harness/render/index.js +3 -0
  112. package/dist-server/harness/render/validate.d.ts +13 -0
  113. package/dist-server/harness/render/validate.js +88 -0
  114. package/dist-server/harness/route/adapter-spec.d.ts +40 -0
  115. package/dist-server/harness/route/adapter-spec.js +61 -0
  116. package/dist-server/harness/route/agent-sdk-cli.d.ts +30 -0
  117. package/dist-server/harness/route/agent-sdk-cli.js +86 -0
  118. package/dist-server/harness/route/agent-sdk-manifest.d.ts +31 -0
  119. package/dist-server/harness/route/agent-sdk-manifest.js +56 -0
  120. package/dist-server/harness/route/artifact-content.d.ts +53 -0
  121. package/dist-server/harness/route/artifact-content.js +83 -0
  122. package/dist-server/harness/route/chat-event-mapper.d.ts +95 -0
  123. package/dist-server/harness/route/chat-event-mapper.js +164 -0
  124. package/dist-server/harness/route/codex-ask-events.d.ts +25 -0
  125. package/dist-server/harness/route/codex-ask-events.js +395 -0
  126. package/dist-server/harness/route/codex-ask.d.ts +15 -0
  127. package/dist-server/harness/route/codex-ask.js +242 -0
  128. package/dist-server/harness/route/codex-local-cli.d.ts +20 -0
  129. package/dist-server/harness/route/codex-local-cli.js +78 -0
  130. package/dist-server/harness/route/codex-local-manifest.d.ts +22 -0
  131. package/dist-server/harness/route/codex-local-manifest.js +180 -0
  132. package/dist-server/harness/route/describe.d.ts +54 -0
  133. package/dist-server/harness/route/describe.js +84 -0
  134. package/dist-server/harness/route/dispatched.d.ts +138 -0
  135. package/dist-server/harness/route/dispatched.js +339 -0
  136. package/dist-server/harness/route/in-process.d.ts +43 -0
  137. package/dist-server/harness/route/in-process.js +106 -0
  138. package/dist-server/harness/route/index.d.ts +19 -0
  139. package/dist-server/harness/route/index.js +12 -0
  140. package/dist-server/harness/route/profile-source.d.ts +37 -0
  141. package/dist-server/harness/route/profile-source.js +76 -0
  142. package/dist-server/harness/route/route.d.ts +33 -0
  143. package/dist-server/harness/route/route.js +114 -0
  144. package/dist-server/harness/route/tier-binding.d.ts +36 -0
  145. package/dist-server/harness/route/tier-binding.js +63 -0
  146. package/dist-server/harness/route/types.d.ts +286 -0
  147. package/dist-server/harness/route/types.js +1 -0
  148. package/dist-server/harness/session/errors.d.ts +4 -0
  149. package/dist-server/harness/session/errors.js +7 -0
  150. package/dist-server/harness/session/gate.d.ts +11 -0
  151. package/dist-server/harness/session/gate.js +13 -0
  152. package/dist-server/harness/session/index.d.ts +5 -0
  153. package/dist-server/harness/session/index.js +3 -0
  154. package/dist-server/harness/session/run.d.ts +60 -0
  155. package/dist-server/harness/session/run.js +333 -0
  156. package/dist-server/harness/session/types.d.ts +29 -0
  157. package/dist-server/harness/session/types.js +1 -0
  158. package/dist-server/harness/setup/codex-events.d.ts +12 -0
  159. package/dist-server/harness/setup/codex-events.js +108 -0
  160. package/dist-server/harness/setup/runner.d.ts +497 -0
  161. package/dist-server/harness/setup/runner.js +1314 -0
  162. package/dist-server/harness/tools/errors.d.ts +107 -0
  163. package/dist-server/harness/tools/errors.js +141 -0
  164. package/dist-server/harness/tools/index.d.ts +13 -0
  165. package/dist-server/harness/tools/index.js +8 -0
  166. package/dist-server/harness/tools/mcp.d.ts +26 -0
  167. package/dist-server/harness/tools/mcp.js +15 -0
  168. package/dist-server/harness/tools/native.d.ts +179 -0
  169. package/dist-server/harness/tools/native.js +322 -0
  170. package/dist-server/harness/tools/parse.d.ts +14 -0
  171. package/dist-server/harness/tools/parse.js +18 -0
  172. package/dist-server/harness/tools/resolve-wren-binary.d.ts +12 -0
  173. package/dist-server/harness/tools/resolve-wren-binary.js +21 -0
  174. package/dist-server/harness/tools/resolve.d.ts +51 -0
  175. package/dist-server/harness/tools/resolve.js +79 -0
  176. package/dist-server/harness/tools/setup-native.d.ts +84 -0
  177. package/dist-server/harness/tools/setup-native.js +353 -0
  178. package/dist-server/harness/tools/wiring.d.ts +10 -0
  179. package/dist-server/harness/tools/wiring.js +16 -0
  180. package/dist-server/providers/setup.provider.yaml +31 -0
  181. package/dist-server/providers/wren.provider.yaml +33 -0
  182. package/dist-server/server/adopt.d.ts +87 -0
  183. package/dist-server/server/adopt.js +263 -0
  184. package/dist-server/server/app.d.ts +6 -0
  185. package/dist-server/server/app.js +2521 -0
  186. package/dist-server/server/auth-choice.d.ts +16 -0
  187. package/dist-server/server/auth-choice.js +36 -0
  188. package/dist-server/server/bin.d.ts +2 -0
  189. package/dist-server/server/bin.js +601 -0
  190. package/dist-server/server/bootstrap-project-binding.d.ts +31 -0
  191. package/dist-server/server/bootstrap-project-binding.js +71 -0
  192. package/dist-server/server/clarify.d.ts +10 -0
  193. package/dist-server/server/clarify.js +17 -0
  194. package/dist-server/server/codex-setup-mcp.d.ts +2 -0
  195. package/dist-server/server/codex-setup-mcp.js +147 -0
  196. package/dist-server/server/compose.d.ts +89 -0
  197. package/dist-server/server/compose.js +271 -0
  198. package/dist-server/server/conn-config.d.ts +30 -0
  199. package/dist-server/server/conn-config.js +253 -0
  200. package/dist-server/server/context-files.d.ts +12 -0
  201. package/dist-server/server/context-files.js +117 -0
  202. package/dist-server/server/context-map.d.ts +30 -0
  203. package/dist-server/server/context-map.js +95 -0
  204. package/dist-server/server/context-source.d.ts +68 -0
  205. package/dist-server/server/context-source.js +85 -0
  206. package/dist-server/server/db.d.ts +862 -0
  207. package/dist-server/server/db.js +1839 -0
  208. package/dist-server/server/enrichment-runner.d.ts +184 -0
  209. package/dist-server/server/enrichment-runner.js +213 -0
  210. package/dist-server/server/enrichment-verify.d.ts +73 -0
  211. package/dist-server/server/enrichment-verify.js +290 -0
  212. package/dist-server/server/enrichment.d.ts +232 -0
  213. package/dist-server/server/enrichment.js +199 -0
  214. package/dist-server/server/env-detect.d.ts +8 -0
  215. package/dist-server/server/env-detect.js +17 -0
  216. package/dist-server/server/env-field-hints.d.ts +46 -0
  217. package/dist-server/server/env-field-hints.js +48 -0
  218. package/dist-server/server/fold.d.ts +133 -0
  219. package/dist-server/server/fold.js +407 -0
  220. package/dist-server/server/harness-profile-sources.d.ts +3 -0
  221. package/dist-server/server/harness-profile-sources.js +24 -0
  222. package/dist-server/server/harness.d.ts +19 -0
  223. package/dist-server/server/harness.js +439 -0
  224. package/dist-server/server/impact.d.ts +18 -0
  225. package/dist-server/server/impact.js +85 -0
  226. package/dist-server/server/interactive-terminal.d.ts +175 -0
  227. package/dist-server/server/interactive-terminal.js +336 -0
  228. package/dist-server/server/native-artifacts.d.ts +1004 -0
  229. package/dist-server/server/native-artifacts.js +564 -0
  230. package/dist-server/server/native-dispatch-registry.d.ts +42 -0
  231. package/dist-server/server/native-dispatch-registry.js +45 -0
  232. package/dist-server/server/native-producer-fence.d.ts +14 -0
  233. package/dist-server/server/native-producer-fence.js +48 -0
  234. package/dist-server/server/native-session-resume.d.ts +6 -0
  235. package/dist-server/server/native-session-resume.js +103 -0
  236. package/dist-server/server/native-session-workspace.d.ts +40 -0
  237. package/dist-server/server/native-session-workspace.js +175 -0
  238. package/dist-server/server/native-sessions.d.ts +374 -0
  239. package/dist-server/server/native-sessions.js +1517 -0
  240. package/dist-server/server/native-wren-runtime.d.ts +20 -0
  241. package/dist-server/server/native-wren-runtime.js +259 -0
  242. package/dist-server/server/node-pty-host.d.ts +31 -0
  243. package/dist-server/server/node-pty-host.js +100 -0
  244. package/dist-server/server/route-intent.d.ts +40 -0
  245. package/dist-server/server/route-intent.js +23 -0
  246. package/dist-server/server/runtime-binding.d.ts +52 -0
  247. package/dist-server/server/runtime-binding.js +258 -0
  248. package/dist-server/server/source-catalog.d.ts +84 -0
  249. package/dist-server/server/source-catalog.js +221 -0
  250. package/dist-server/server/source-driver.d.ts +35 -0
  251. package/dist-server/server/source-driver.js +124 -0
  252. package/dist-server/server/spa.d.ts +2 -0
  253. package/dist-server/server/spa.js +51 -0
  254. package/dist-server/server/subscription-model-catalog.d.ts +27 -0
  255. package/dist-server/server/subscription-model-catalog.js +203 -0
  256. package/dist-server/server/turn.d.ts +249 -0
  257. package/dist-server/server/turn.js +1074 -0
  258. package/dist-server/server/wire-types.d.ts +799 -0
  259. package/dist-server/server/wire-types.js +1 -0
  260. package/dist-server/server/wren-home.d.ts +19 -0
  261. package/dist-server/server/wren-home.js +33 -0
  262. package/dist-server/server/wren-profiles.d.ts +43 -0
  263. package/dist-server/server/wren-profiles.js +123 -0
  264. package/package.json +93 -0
  265. package/profiles/genbi-default/context/binding.yml +9 -0
  266. package/profiles/genbi-default/ir.golden.json +506 -0
  267. package/profiles/genbi-default/profile.yml +16 -0
  268. package/profiles/genbi-enrich-context/components/apply_enrichment/component.yml +42 -0
  269. package/profiles/genbi-enrich-context/components/draft_enrichment/component.yml +30 -0
  270. package/profiles/genbi-enrich-context/components/draft_enrichment/steps/draft.md +34 -0
  271. package/profiles/genbi-enrich-context/components/inspect_context/component.yml +32 -0
  272. package/profiles/genbi-enrich-context/components/inspect_context/steps/inspect.md +13 -0
  273. package/profiles/genbi-enrich-context/context/binding.yml +4 -0
  274. package/profiles/genbi-enrich-context/ir.golden.json +302 -0
  275. package/profiles/genbi-enrich-context/profile.yml +15 -0
  276. package/profiles/genbi-monitor/context/binding.yml +7 -0
  277. package/profiles/genbi-monitor/ir.golden.json +188 -0
  278. package/profiles/genbi-monitor/profile.yml +27 -0
  279. package/profiles/genbi-setup/components/build_context/component.yml +44 -0
  280. package/profiles/genbi-setup/components/build_context/steps/build.md +14 -0
  281. package/profiles/genbi-setup/components/connect_source/component.yml +51 -0
  282. package/profiles/genbi-setup/components/connect_source/steps/connect.md +23 -0
  283. package/profiles/genbi-setup/context/binding.yml +8 -0
  284. package/profiles/genbi-setup/ir.golden.json +140 -0
  285. package/profiles/genbi-setup/profile.yml +18 -0
  286. package/profiles/genbi-setup/raw/schema.json +5 -0
@@ -0,0 +1,30 @@
1
+ export interface ConnConfig {
2
+ readonly datasource?: string;
3
+ readonly fields: Readonly<Record<string, string>>;
4
+ }
5
+ export interface ConnectionDetail {
6
+ readonly type: string;
7
+ readonly location: string;
8
+ }
9
+ export declare function loadConnConfig(projectDir: string): ConnConfig | undefined;
10
+ export interface ProjectManifest {
11
+ /** `wren_project.yml`'s `data_source:` — always present on a real wren project; this is the connection panel's `type`. */
12
+ readonly dataSource?: string;
13
+ /** `wren_project.yml`'s `profile:` pin, if the project has bound one — the key into `~/.wren/profiles.yml`'s `profiles:` map. */
14
+ readonly profile?: string;
15
+ }
16
+ /** Reads `<projectDir>/wren_project.yml`'s persistent `data_source:`/`profile:` scalars. Unlike `conn.yml`, this file always exists on a bound wren project. Returns `undefined` only when the manifest itself is missing/unreadable — never throws. */
17
+ export declare function loadProjectManifest(projectDir: string): ProjectManifest | undefined;
18
+ /**
19
+ * Resolves the `(datasource, fields)` pair `describeConnection` needs, per
20
+ * the precedence documented in this module's doc comment: `conn.yml` first
21
+ * if it happens to exist and declares a `datasource:`, otherwise
22
+ * `wren_project.yml`'s `data_source:` for `type` plus its pinned `profile:`
23
+ * (looked up in `~/.wren/profiles.yml`) for the location `fields`. A project
24
+ * with no pin still reports its real `data_source`, with empty fields (→
25
+ * `describeConnection` renders an honest "—" location) — it never
26
+ * substitutes the profiles store's global `active:` profile.
27
+ */
28
+ export declare function resolveConnectionSource(projectDir: string): ConnConfig;
29
+ /** Maps a resolved `(datasource, fields)` pair to the connection panel's `type`/`location` — never fabricates a label and never surfaces a secret field. */
30
+ export declare function describeConnection(datasource: string | undefined, fields: Readonly<Record<string, string>>): ConnectionDetail;
@@ -0,0 +1,253 @@
1
+ /**
2
+ * Resolves the REAL datasource + connection fields behind the Harness page's
3
+ * connection panel — see `buildConnection` in `server/harness.ts` — and
4
+ * describes them into a safe, non-secret display shape.
5
+ *
6
+ * `<project>/conn.yml` is NOT a persistent part of a wren project: the wren
7
+ * CLI's onboarding wizard writes a *temporary* scratch file inside the
8
+ * project directory (under a name deliberately not `conn.yml`, e.g.
9
+ * `conn.profile.yml`) and feeds it to `wren profile add --from-file`, then
10
+ * deletes it once the profile is created — so it never leaves a `conn.yml`
11
+ * in the project directory itself. So `loadConnConfig` below only ever finds
12
+ * something to read on hand-authored fixtures (or a project laid out that
13
+ * way on purpose) — never on a project the CLI actually onboarded. The two
14
+ * files that ARE always there:
15
+ * - `<project>/wren_project.yml` — its `data_source:` field is the real,
16
+ * always-present datasource, and its `profile:` field (if set) pins which
17
+ * stored profile the project actually connects through.
18
+ * - `~/.wren/profiles.yml` (or `$WREN_HOME/profiles.yml`) — the pinned
19
+ * profile's own field map (duckdb `url`, DB `host`/`port`/`database`, …),
20
+ * read via `server/wren-profiles.ts`'s shared parser.
21
+ * `resolveConnectionSource` is the entry point every caller should use: it
22
+ * prefers `conn.yml` when one happens to exist (kept only so a fixture/hand
23
+ * laid out project isn't silently ignored), and otherwise resolves through
24
+ * the manifest + profiles store above — WITHOUT ever falling back to the
25
+ * profiles store's global `active:` profile when the project has no pin of
26
+ * its own, since a project must never display a connection it isn't bound
27
+ * to.
28
+ *
29
+ * `conn.yml`, when present, is a flat `key: value` file (no nesting) — e.g.
30
+ * ```
31
+ * datasource: duckdb
32
+ * url: ${DUCKDB_URL}
33
+ * format: ${DUCKDB_FORMAT}
34
+ * ```
35
+ * so a small line-based parser is enough here; pulling in a full YAML
36
+ * library for one flat file would be overkill. `wren_project.yml` only ever
37
+ * needs two scalar fields read out of it, so it gets the same small-parser
38
+ * treatment (mirrors `server/adopt.ts`'s own `readYamlScalarField`).
39
+ *
40
+ * SECURITY: `describeConnection` only ever reads from a fixed ALLOWLIST of
41
+ * non-secret field names (host/port/database/project id/…) when building the
42
+ * displayed location string. It never touches or forwards arbitrary
43
+ * `conn.yml`/`.env`/profile keys, so a field named
44
+ * `password`/`user`/`token`/`credentials`/`private_key` etc. can never reach
45
+ * the DTO even if present in the parsed config — there is no denylist to
46
+ * keep in sync as new datasources are added.
47
+ */
48
+ import { existsSync, readFileSync } from "node:fs";
49
+ import path from "node:path";
50
+ import { loadProfileStore } from "./wren-profiles.js";
51
+ function stripQuotes(value) {
52
+ if (value.length >= 2) {
53
+ const first = value[0];
54
+ const last = value[value.length - 1];
55
+ if ((first === '"' && last === '"') || (first === "'" && last === "'"))
56
+ return value.slice(1, -1);
57
+ }
58
+ return value;
59
+ }
60
+ /** Parses a flat `key: value` YAML file — one mapping per line, no nested structures. */
61
+ function parseFlatYaml(text) {
62
+ const result = {};
63
+ for (const rawLine of text.split(/\r?\n/)) {
64
+ const line = rawLine.trim();
65
+ if (!line || line.startsWith("#"))
66
+ continue;
67
+ const idx = line.indexOf(":");
68
+ if (idx === -1)
69
+ continue;
70
+ const key = line.slice(0, idx).trim();
71
+ if (!key)
72
+ continue;
73
+ result[key] = stripQuotes(line.slice(idx + 1).trim());
74
+ }
75
+ return result;
76
+ }
77
+ /** Parses a `.env` file — `KEY=value` per line, optional `export ` prefix, `#` comments. */
78
+ function parseDotEnv(text) {
79
+ const result = {};
80
+ for (const rawLine of text.split(/\r?\n/)) {
81
+ const line = rawLine.trim();
82
+ if (!line || line.startsWith("#"))
83
+ continue;
84
+ const withoutExport = line.startsWith("export ") ? line.slice("export ".length) : line;
85
+ const idx = withoutExport.indexOf("=");
86
+ if (idx === -1)
87
+ continue;
88
+ const key = withoutExport.slice(0, idx).trim();
89
+ if (!key)
90
+ continue;
91
+ result[key] = stripQuotes(withoutExport.slice(idx + 1).trim());
92
+ }
93
+ return result;
94
+ }
95
+ const TEMPLATE_RE = /\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g;
96
+ /** Resolves `${VAR}` references via `lookup`; returns `undefined` (rather than a literal, broken `${VAR}`) if any reference can't be resolved. */
97
+ function resolveTemplate(value, lookup) {
98
+ let unresolved = false;
99
+ const resolved = value.replace(TEMPLATE_RE, (_match, name) => {
100
+ const resolvedValue = lookup(name);
101
+ if (resolvedValue === undefined) {
102
+ unresolved = true;
103
+ return "";
104
+ }
105
+ return resolvedValue;
106
+ });
107
+ return unresolved ? undefined : resolved;
108
+ }
109
+ /**
110
+ * Reads `<projectDir>/conn.yml`, resolving any `${VAR}` values against
111
+ * `<projectDir>/.env` (a real environment variable of the same name, if set,
112
+ * wins over the project's `.env` — mirroring the wren CLI's own dotenv
113
+ * loading, so a shell-exported override still applies). Returns `undefined`
114
+ * when there's no `conn.yml` to read (unbound project, or a project laid out
115
+ * without one) rather than throwing — callers fall back to an honest "—".
116
+ */
117
+ /**
118
+ * Resolves `${VAR}` references against a real environment variable, else the
119
+ * project's own `.env`. Shared by both connection sources: a stored profile
120
+ * holds the same `${VAR}` references `conn.yml` does — that is how wren keeps
121
+ * credentials out of `~/.wren/profiles.yml` — so a display that skipped this
122
+ * step showed the reference instead of the value.
123
+ */
124
+ function envLookup(projectDir) {
125
+ const dotenvPath = path.join(projectDir, ".env");
126
+ let dotenv = {};
127
+ if (existsSync(dotenvPath)) {
128
+ try {
129
+ dotenv = parseDotEnv(readFileSync(dotenvPath, "utf-8"));
130
+ }
131
+ catch {
132
+ dotenv = {};
133
+ }
134
+ }
135
+ return (name) => process.env[name] ?? dotenv[name];
136
+ }
137
+ export function loadConnConfig(projectDir) {
138
+ const connPath = path.join(projectDir, "conn.yml");
139
+ if (!existsSync(connPath))
140
+ return undefined;
141
+ let raw;
142
+ try {
143
+ raw = parseFlatYaml(readFileSync(connPath, "utf-8"));
144
+ }
145
+ catch {
146
+ return undefined;
147
+ }
148
+ const lookup = envLookup(projectDir);
149
+ const fields = {};
150
+ for (const [key, value] of Object.entries(raw)) {
151
+ if (key === "datasource")
152
+ continue;
153
+ const resolved = resolveTemplate(value, lookup);
154
+ if (resolved !== undefined)
155
+ fields[key] = resolved;
156
+ }
157
+ return raw.datasource !== undefined ? { datasource: raw.datasource, fields } : { fields };
158
+ }
159
+ /**
160
+ * Matches a `wren_project.yml` top-level `field: value` scalar line — a
161
+ * second small instance of `server/adopt.ts`'s own `readYamlScalarField`
162
+ * rather than an import from it: this module only ever needs the same two
163
+ * fields (`data_source`, `profile`), and adopt.ts's function isn't exported
164
+ * for reuse, so a four-line regex duplicated here is cheaper than adding a
165
+ * cross-module export just for it.
166
+ */
167
+ function readManifestScalar(content, field) {
168
+ const re = new RegExp(`^${field}:\\s*(.+?)\\s*$`, "m");
169
+ const match = re.exec(content);
170
+ return match ? stripQuotes(match[1].trim()) : undefined;
171
+ }
172
+ /** Reads `<projectDir>/wren_project.yml`'s persistent `data_source:`/`profile:` scalars. Unlike `conn.yml`, this file always exists on a bound wren project. Returns `undefined` only when the manifest itself is missing/unreadable — never throws. */
173
+ export function loadProjectManifest(projectDir) {
174
+ const manifestPath = path.join(projectDir, "wren_project.yml");
175
+ if (!existsSync(manifestPath))
176
+ return undefined;
177
+ try {
178
+ const content = readFileSync(manifestPath, "utf-8");
179
+ const dataSource = readManifestScalar(content, "data_source");
180
+ const profile = readManifestScalar(content, "profile");
181
+ return { ...(dataSource !== undefined ? { dataSource } : {}), ...(profile !== undefined ? { profile } : {}) };
182
+ }
183
+ catch {
184
+ return undefined;
185
+ }
186
+ }
187
+ /**
188
+ * Resolves the `(datasource, fields)` pair `describeConnection` needs, per
189
+ * the precedence documented in this module's doc comment: `conn.yml` first
190
+ * if it happens to exist and declares a `datasource:`, otherwise
191
+ * `wren_project.yml`'s `data_source:` for `type` plus its pinned `profile:`
192
+ * (looked up in `~/.wren/profiles.yml`) for the location `fields`. A project
193
+ * with no pin still reports its real `data_source`, with empty fields (→
194
+ * `describeConnection` renders an honest "—" location) — it never
195
+ * substitutes the profiles store's global `active:` profile.
196
+ */
197
+ export function resolveConnectionSource(projectDir) {
198
+ const connConfig = loadConnConfig(projectDir);
199
+ if (connConfig?.datasource !== undefined)
200
+ return connConfig;
201
+ const manifest = loadProjectManifest(projectDir);
202
+ if (!manifest?.dataSource)
203
+ return { fields: {} };
204
+ if (!manifest.profile)
205
+ return { datasource: manifest.dataSource, fields: {} };
206
+ const profileFields = loadProfileStore().profiles.get(manifest.profile);
207
+ if (!profileFields)
208
+ return { datasource: manifest.dataSource, fields: {} };
209
+ // A stored profile's values are `${VAR}` references into the project's
210
+ // `.env` — that is how wren keeps credentials out of `~/.wren/profiles.yml`.
211
+ // They need the same resolution `conn.yml` already gets; without it the
212
+ // connection panel rendered the literal `${BIGQUERY_PROJECT_ID}`.
213
+ const lookup = envLookup(projectDir);
214
+ const fields = {};
215
+ for (const [key, value] of profileFields) {
216
+ if (key === "datasource")
217
+ continue; // the manifest's data_source is authoritative for `type`; profiles.yml's own field is redundant and excluded from `fields`.
218
+ const resolved = resolveTemplate(value, lookup);
219
+ // An unresolved reference is dropped rather than shown: the panel's job is
220
+ // to say where this project connects, and `${SOMETHING}` answers that no
221
+ // better than showing nothing.
222
+ if (resolved !== undefined)
223
+ fields[key] = resolved;
224
+ }
225
+ return { datasource: manifest.dataSource, fields };
226
+ }
227
+ /** Filesystem-backed datasources — `url` IS the connection location (a local path, or a bucket/object URL with no embedded credentials in these connection info shapes). */
228
+ const FILE_DATASOURCES = new Set(["duckdb", "local_file", "gcs_file", "minio_file", "s3_file"]);
229
+ /**
230
+ * ALLOWLIST of non-secret field names used to build the displayed location
231
+ * string for DB-type datasources, in display order. Deliberately excludes
232
+ * every credential-shaped field (password, user, credentials, token,
233
+ * private_key, access_key/secret_key, client_id/client_secret, dsn, kwargs,
234
+ * …) — those are simply never read here, regardless of datasource.
235
+ */
236
+ const LOCATION_FIELD_ORDER = ["database", "project_id", "dataset_id", "account", "schema", "warehouse", "region_name", "schema_name"];
237
+ /** Maps a resolved `(datasource, fields)` pair to the connection panel's `type`/`location` — never fabricates a label and never surfaces a secret field. */
238
+ export function describeConnection(datasource, fields) {
239
+ if (!datasource)
240
+ return { type: "—", location: "—" };
241
+ if (FILE_DATASOURCES.has(datasource)) {
242
+ return { type: datasource, location: fields.url ?? "—" };
243
+ }
244
+ const segments = [];
245
+ if (fields.host)
246
+ segments.push(fields.port ? `${fields.host}:${fields.port}` : fields.host);
247
+ for (const key of LOCATION_FIELD_ORDER) {
248
+ const value = fields[key];
249
+ if (value)
250
+ segments.push(value);
251
+ }
252
+ return { type: datasource, location: segments.length > 0 ? segments.join("/") : "—" };
253
+ }
@@ -0,0 +1,12 @@
1
+ import type { WrenContextShow } from "./context-source.js";
2
+ import type { ContextFileNode, KnowledgeStatus } from "./wire-types.js";
3
+ /**
4
+ * `instructionsPresent` from the real presence of at least one authored
5
+ * `knowledge/rules/*.md` file (as opposed to the placeholder-only
6
+ * subdirectories, e.g. `caveats/`/`glossary/`). `verifiedPairCount` is always
7
+ * 0 — there is no live Q-SQL verified-pair source over a real project yet
8
+ * (see `server/impact.ts`'s doc comment).
9
+ */
10
+ export declare function computeKnowledgeStatus(projectDir: string): KnowledgeStatus;
11
+ /** Builds the whole `GET /api/context/files` tree — one top-level group per entity kind, skipping any group that ends up with no readable files rather than emitting an empty section. */
12
+ export declare function buildContextFileTree(projectDir: string, contextShow: WrenContextShow): ContextFileNode[];
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Builds the Context page's file tree by reading the
3
+ * REAL bound project directory (model/cube/knowledge files, relationships.yml,
4
+ * wren_project.yml) rather than a seeded fixture. Each leaf's `content` is the
5
+ * actual file text on disk, so `FileViewer.tsx` renders real project source.
6
+ *
7
+ * Model/relationship/cube NAMES come from an already-loaded
8
+ * `WrenContextShow` (see `server/context-source.ts`) rather than re-parsing
9
+ * YAML here — `wren context show` is the authoritative parse of that data;
10
+ * this module only needs it to know which per-entity files exist and how to
11
+ * label them, then reads each file's raw bytes straight from disk.
12
+ */
13
+ import { existsSync, readdirSync, readFileSync } from "node:fs";
14
+ import path from "node:path";
15
+ function readFileSafe(filePath) {
16
+ try {
17
+ return readFileSync(filePath, "utf-8");
18
+ }
19
+ catch {
20
+ return undefined;
21
+ }
22
+ }
23
+ function buildModelNodes(projectDir, contextShow) {
24
+ return contextShow.models.flatMap((model) => {
25
+ const relPath = path.join("models", model.name, "metadata.yml");
26
+ const content = readFileSafe(path.join(projectDir, relPath));
27
+ if (content === undefined)
28
+ return [];
29
+ return [{ key: `file-model-${model.name}`, title: `${model.name}/metadata.yml`, kind: "model", path: relPath, entityKey: model.name, content }];
30
+ });
31
+ }
32
+ /** `relationships.yml` is a single file holding every relationship — one leaf per relationship, all sharing that same real file text, distinguished by `entityKey`. */
33
+ function buildRelationshipNodes(projectDir, contextShow) {
34
+ const relPath = "relationships.yml";
35
+ const content = readFileSafe(path.join(projectDir, relPath));
36
+ if (content === undefined)
37
+ return [];
38
+ return contextShow.relationships.map((rel) => ({
39
+ key: `file-relationship-${rel.name}`,
40
+ title: rel.name,
41
+ kind: "relationship",
42
+ path: relPath,
43
+ entityKey: rel.name,
44
+ content,
45
+ }));
46
+ }
47
+ function buildCubeNodes(projectDir, contextShow) {
48
+ return contextShow.cubes.flatMap((cube) => {
49
+ const relPath = path.join("cubes", cube.name, "metadata.yml");
50
+ const content = readFileSafe(path.join(projectDir, relPath));
51
+ if (content === undefined)
52
+ return [];
53
+ return [{ key: `file-cube-${cube.name}`, title: `${cube.name}/metadata.yml`, kind: "cube", path: relPath, entityKey: cube.name, content }];
54
+ });
55
+ }
56
+ /** `knowledge/rules/*.md` are the only knowledge files with real authored content today (`caveats/`, `glossary/`, `metrics/`, `sql/` are placeholders) — plus `knowledge/knowledge.yml` when present. */
57
+ function buildKnowledgeNodes(projectDir) {
58
+ const rulesDir = path.join(projectDir, "knowledge", "rules");
59
+ const nodes = [];
60
+ if (existsSync(rulesDir)) {
61
+ const entries = readdirSync(rulesDir)
62
+ .filter((name) => name.endsWith(".md"))
63
+ .sort();
64
+ for (const name of entries) {
65
+ const content = readFileSafe(path.join(rulesDir, name));
66
+ if (content === undefined)
67
+ continue;
68
+ const relPath = path.join("knowledge", "rules", name);
69
+ const entityKey = name.replace(/\.md$/, "");
70
+ nodes.push({ key: `file-knowledge-rule-${entityKey}`, title: name, kind: "knowledge", path: relPath, entityKey, content });
71
+ }
72
+ }
73
+ const knowledgeYamlPath = path.join(projectDir, "knowledge", "knowledge.yml");
74
+ const knowledgeYamlContent = readFileSafe(knowledgeYamlPath);
75
+ if (knowledgeYamlContent !== undefined) {
76
+ nodes.push({ key: "file-knowledge-config", title: "knowledge.yml", kind: "knowledge", path: path.join("knowledge", "knowledge.yml"), entityKey: "knowledge-config", content: knowledgeYamlContent });
77
+ }
78
+ return nodes;
79
+ }
80
+ function buildProjectNode(projectDir) {
81
+ const content = readFileSafe(path.join(projectDir, "wren_project.yml"));
82
+ if (content === undefined)
83
+ return [];
84
+ return [{ key: "file-wren-project", title: "wren_project.yml", path: "wren_project.yml", content }];
85
+ }
86
+ /**
87
+ * `instructionsPresent` from the real presence of at least one authored
88
+ * `knowledge/rules/*.md` file (as opposed to the placeholder-only
89
+ * subdirectories, e.g. `caveats/`/`glossary/`). `verifiedPairCount` is always
90
+ * 0 — there is no live Q-SQL verified-pair source over a real project yet
91
+ * (see `server/impact.ts`'s doc comment).
92
+ */
93
+ export function computeKnowledgeStatus(projectDir) {
94
+ const rulesDir = path.join(projectDir, "knowledge", "rules");
95
+ const instructionsPresent = existsSync(rulesDir) && readdirSync(rulesDir).some((name) => name.endsWith(".md"));
96
+ return { instructionsPresent, verifiedPairCount: 0 };
97
+ }
98
+ /** Builds the whole `GET /api/context/files` tree — one top-level group per entity kind, skipping any group that ends up with no readable files rather than emitting an empty section. */
99
+ export function buildContextFileTree(projectDir, contextShow) {
100
+ const groups = [];
101
+ const models = buildModelNodes(projectDir, contextShow);
102
+ if (models.length > 0)
103
+ groups.push({ key: "models", title: "Models", children: models });
104
+ const relationships = buildRelationshipNodes(projectDir, contextShow);
105
+ if (relationships.length > 0)
106
+ groups.push({ key: "relationships", title: "Relationships", children: relationships });
107
+ const cubes = buildCubeNodes(projectDir, contextShow);
108
+ if (cubes.length > 0)
109
+ groups.push({ key: "cubes", title: "Cubes", children: cubes });
110
+ const knowledge = buildKnowledgeNodes(projectDir);
111
+ if (knowledge.length > 0)
112
+ groups.push({ key: "knowledge", title: "Knowledge", children: knowledge });
113
+ const project = buildProjectNode(projectDir);
114
+ if (project.length > 0)
115
+ groups.push({ key: "project", title: "Project", children: project });
116
+ return groups;
117
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Pure remap from `wren context show`'s output
3
+ * (`server/context-source.ts`) to the frozen UI wire contract
4
+ * (`server/wire-types.ts`). No I/O here; `server/app.ts`'s context routes are
5
+ * the only caller.
6
+ *
7
+ * `wren context show` carries no `key: pk/fk` on columns, no additivity flag
8
+ * on measures, and no ER layout positions — those are inferred/omitted
9
+ * heuristics, not authoritative facts from the semantic layer. Keep the
10
+ * inference simple and readable rather than over-fitting to one project's
11
+ * naming.
12
+ */
13
+ import type { WrenContextCube, WrenContextModel, WrenContextRelationship, WrenContextShow } from "./context-source.js";
14
+ import type { ContextOverview, KnowledgeStatus, MeasureAdditivity, SemanticMeasure, SemanticModel, SemanticRelationship } from "./wire-types.js";
15
+ /** Maps `models[]` to `SemanticModel[]`, omitting `position` (no ER layout in `wren context show` — the UI's `ErDiagram` must lay itself out when position is absent). */
16
+ export declare function mapModelsToWire(models: readonly WrenContextModel[], relationships: readonly WrenContextRelationship[]): SemanticModel[];
17
+ /** Maps `relationships[]` (unordered `models:[a,b]` pair) to `SemanticRelationship[]` (`fromModel`/`toModel`). The wire type has no slot for the raw `condition` predicate — it's only consumed internally for fk inference above. */
18
+ export declare function mapRelationshipsToWire(relationships: readonly WrenContextRelationship[]): SemanticRelationship[];
19
+ /**
20
+ * `SUM`/`COUNT` aggregates are additive (safely re-summable across any
21
+ * dimension) — UNLESS the expression is itself a ratio of two such
22
+ * aggregates (e.g. `"SUM(revenue) / SUM(cost)"`), which is never additive
23
+ * regardless of what its parts are made of. `AVG` and anything else default
24
+ * to non-additive — the safer assumption when additivity can't be confirmed
25
+ * from the expression text alone.
26
+ */
27
+ export declare function inferAdditivity(expression: string): MeasureAdditivity;
28
+ /** Maps `cubes[]` to `SemanticMeasure[]` — one entry per measure (a cube can declare several), keyed `"<cube>.<measure>"` so measures with the same name in different cubes don't collide. */
29
+ export declare function mapCubesToMeasures(cubes: readonly WrenContextCube[]): SemanticMeasure[];
30
+ export declare function mapContextShowToOverview(contextShow: WrenContextShow, projectName: string, projectPath: string, knowledge: KnowledgeStatus): ContextOverview;
@@ -0,0 +1,95 @@
1
+ const JOIN_TYPE_MAP = {
2
+ ONE_TO_ONE: "one-to-one",
3
+ ONE_TO_MANY: "one-to-many",
4
+ MANY_TO_ONE: "many-to-one",
5
+ MANY_TO_MANY: "many-to-many",
6
+ };
7
+ /** `wren`'s `joinType` is an upper-snake enum (`"MANY_TO_ONE"`, ...) — falls back to `"one-to-many"` for anything unrecognized rather than throwing, since this is display-only. */
8
+ function mapJoinType(joinType) {
9
+ return JOIN_TYPE_MAP[joinType] ?? "one-to-many";
10
+ }
11
+ /**
12
+ * A column is inferred `pk` when it matches the model's declared
13
+ * `primaryKey`, or `fk` when some relationship's `condition` string
14
+ * references `<model.name>.<column.name>` on either side of the join
15
+ * predicate (e.g. `"orders.customer_id = customers.id"` marks
16
+ * `orders.customer_id` as an fk). Both are heuristics over plain-text data —
17
+ * not something `wren context show` asserts directly.
18
+ */
19
+ function escapeRegExp(value) {
20
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
21
+ }
22
+ function inferColumnKey(modelName, columnName, primaryKey, relationships) {
23
+ if (primaryKey !== undefined && columnName === primaryKey)
24
+ return "pk";
25
+ // Match `<model>.<column>` as a whole identifier reference, not a loose
26
+ // substring: the boundaries stop a model whose name is a suffix of another
27
+ // (e.g. `old_customer.id` must NOT satisfy a lookup for `customer.id`) or a
28
+ // column that is a prefix of another (`id` vs `identifier`) from matching.
29
+ const ref = new RegExp(`(?<![A-Za-z0-9_])${escapeRegExp(modelName)}\\.${escapeRegExp(columnName)}(?![A-Za-z0-9_])`);
30
+ if (relationships.some((rel) => ref.test(rel.condition)))
31
+ return "fk";
32
+ return undefined;
33
+ }
34
+ /** Maps `models[]` to `SemanticModel[]`, omitting `position` (no ER layout in `wren context show` — the UI's `ErDiagram` must lay itself out when position is absent). */
35
+ export function mapModelsToWire(models, relationships) {
36
+ return models.map((model) => {
37
+ const columns = model.columns.map((col) => {
38
+ const key = inferColumnKey(model.name, col.name, model.primaryKey, relationships);
39
+ return key !== undefined ? { name: col.name, type: col.type, key } : { name: col.name, type: col.type };
40
+ });
41
+ return { key: model.name, name: model.name, columns };
42
+ });
43
+ }
44
+ /** Maps `relationships[]` (unordered `models:[a,b]` pair) to `SemanticRelationship[]` (`fromModel`/`toModel`). The wire type has no slot for the raw `condition` predicate — it's only consumed internally for fk inference above. */
45
+ export function mapRelationshipsToWire(relationships) {
46
+ return relationships.map((rel) => ({
47
+ key: rel.name,
48
+ name: rel.name,
49
+ fromModel: rel.models[0],
50
+ toModel: rel.models[1],
51
+ type: mapJoinType(rel.joinType),
52
+ }));
53
+ }
54
+ /**
55
+ * `SUM`/`COUNT` aggregates are additive (safely re-summable across any
56
+ * dimension) — UNLESS the expression is itself a ratio of two such
57
+ * aggregates (e.g. `"SUM(revenue) / SUM(cost)"`), which is never additive
58
+ * regardless of what its parts are made of. `AVG` and anything else default
59
+ * to non-additive — the safer assumption when additivity can't be confirmed
60
+ * from the expression text alone.
61
+ */
62
+ export function inferAdditivity(expression) {
63
+ const trimmedUpper = expression.trim().toUpperCase();
64
+ if (trimmedUpper.includes("/"))
65
+ return "non-additive";
66
+ if (/^(SUM|COUNT)\s*\(/.test(trimmedUpper))
67
+ return "additive";
68
+ return "non-additive";
69
+ }
70
+ /** Maps `cubes[]` to `SemanticMeasure[]` — one entry per measure (a cube can declare several), keyed `"<cube>.<measure>"` so measures with the same name in different cubes don't collide. */
71
+ export function mapCubesToMeasures(cubes) {
72
+ const measures = [];
73
+ for (const cube of cubes) {
74
+ for (const measure of cube.measures) {
75
+ measures.push({
76
+ key: `${cube.name}.${measure.name}`,
77
+ name: measure.name,
78
+ baseModel: cube.baseObject,
79
+ expression: measure.expression,
80
+ additivity: inferAdditivity(measure.expression),
81
+ });
82
+ }
83
+ }
84
+ return measures;
85
+ }
86
+ export function mapContextShowToOverview(contextShow, projectName, projectPath, knowledge) {
87
+ return {
88
+ models: mapModelsToWire(contextShow.models, contextShow.relationships),
89
+ relationships: mapRelationshipsToWire(contextShow.relationships),
90
+ measures: mapCubesToMeasures(contextShow.cubes),
91
+ knowledge,
92
+ projectName,
93
+ projectPath,
94
+ };
95
+ }
@@ -0,0 +1,68 @@
1
+ export interface WrenContextColumn {
2
+ readonly name: string;
3
+ readonly type: string;
4
+ readonly properties?: {
5
+ readonly description?: string;
6
+ };
7
+ }
8
+ export interface WrenContextModel {
9
+ readonly name: string;
10
+ readonly properties?: {
11
+ readonly description?: string;
12
+ };
13
+ readonly tableReference?: unknown;
14
+ readonly primaryKey?: string;
15
+ readonly columns: readonly WrenContextColumn[];
16
+ }
17
+ /** `models` is an unordered pair — `condition` is the raw join predicate, e.g. `"orders.customer_id = customers.id"`. */
18
+ export interface WrenContextRelationship {
19
+ readonly name: string;
20
+ readonly models: readonly [string, string];
21
+ readonly joinType: string;
22
+ readonly condition: string;
23
+ }
24
+ export interface WrenContextMeasure {
25
+ readonly name: string;
26
+ readonly expression: string;
27
+ readonly type?: string;
28
+ }
29
+ export interface WrenContextCube {
30
+ readonly name: string;
31
+ readonly baseObject: string;
32
+ readonly measures: readonly WrenContextMeasure[];
33
+ readonly dimensions?: readonly unknown[];
34
+ readonly timeDimensions?: readonly unknown[];
35
+ readonly properties?: Record<string, unknown>;
36
+ }
37
+ /** The full `wren context show -o json` document — a single JSON object, NOT JSONL (unlike `wren -o json` query output). */
38
+ export interface WrenContextShow {
39
+ readonly catalog?: string;
40
+ readonly schema?: string;
41
+ readonly models: readonly WrenContextModel[];
42
+ readonly relationships: readonly WrenContextRelationship[];
43
+ readonly views?: readonly unknown[];
44
+ readonly cubes: readonly WrenContextCube[];
45
+ readonly dataSource?: string;
46
+ readonly layoutVersion?: number;
47
+ }
48
+ export declare class WrenBinaryNotFoundError extends Error {
49
+ constructor(detail: string);
50
+ }
51
+ /** Covers both "project not built yet" (missing `target/mdl.json`, checked up front) and a non-zero/unparseable `wren context show` run. */
52
+ export declare class WrenContextShowError extends Error {
53
+ constructor(detail: string);
54
+ }
55
+ /** Evicts one cached project (or every entry, when called with no argument) — call after a context-changing operation (e.g. a setup "build context" turn). */
56
+ export declare function invalidateContextShowCache(projectDir?: string): void;
57
+ /**
58
+ * Runs `wren context show -o json` in `projectDir` and parses the single
59
+ * resulting JSON object. Throws {@link WrenBinaryNotFoundError} when `wren`
60
+ * isn't on PATH, or {@link WrenContextShowError} when the project hasn't
61
+ * been built (`target/mdl.json` missing — checked up front so the error names
62
+ * the real cause instead of a generic non-zero exit), the process exits
63
+ * non-zero, or stdout isn't valid JSON. Never auto-builds and never falls
64
+ * back to fabricated data.
65
+ */
66
+ export declare function loadContextShow(projectDir: string, options?: {
67
+ readonly useCache?: boolean;
68
+ }): Promise<WrenContextShow>;