@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,407 @@
1
+ import { BUILD_DASHBOARD_TOOL_NAME, extractEnvelopeFromText, WREN_QUERY_TOOL_NAME } from "../harness/index.js";
2
+ /**
3
+ * Canned remediation text for a refusal. `RefusalAgentEvent`/`RefusalResult`
4
+ * carry no remediation hint from the agent runtime — the UI's `fix` field is
5
+ * synthesized here as a fixed, hand-written string.
6
+ */
7
+ export const REFUSAL_FIX_HINT = "Ask a workspace admin to grant access, or rephrase the question to use an aggregate that does not expose restricted values.";
8
+ /** Floor path: one work-log snapshot from a resolved run's final `StepTrace`. */
9
+ export function foldTrace(trace) {
10
+ return trace.steps.map((step) => ({
11
+ id: step.id,
12
+ label: step.tool,
13
+ state: step.outcome === "success" ? "done" : "error",
14
+ kind: "tool",
15
+ // Carry the TraceStep's input/detail straight onto the ToolStep
16
+ // so the UI can expand a step (e.g. a SQL-repair retry's errored `query`
17
+ // step) to see what it ran and why it failed.
18
+ ...(step.input !== undefined ? { input: step.input } : {}),
19
+ ...(step.detail !== undefined ? { detail: step.detail } : {}),
20
+ }));
21
+ }
22
+ /** Extracts the floor `StepTrace` from a route() result, if the backend produced one (in-process only). */
23
+ export function extractTrace(result) {
24
+ return result.backend === "agent" ? result.trace : undefined;
25
+ }
26
+ /**
27
+ * Maps a resolved route() result to the UI's terminal answer/refusal event
28
+ * (id assigned by the caller).
29
+ *
30
+ * Dispatched (`backend: "agent-sdk"`) has no structured `RenderEnvelope` of its
31
+ * own — `runDispatchedDefault` only returns the dispatcher's final stdout text
32
+ * (`finalText`) — but the dispatched agent still emits its final structured
33
+ * answer as a (possibly fenced) JSON envelope inside that text (this was the
34
+ * root cause of the bug this handles: that envelope was previously dropped
35
+ * on the floor and the raw text always went out as `form: "text"`,
36
+ * `verified: false`). `extractEnvelopeFromText` recovers it — including
37
+ * `answer_query`'s flat `{columns, rows}` tool-contract shape, normalized
38
+ * into a `table` block — and `verified` is whatever the recovered envelope
39
+ * actually carries, never hardcoded. Only when no envelope can be recovered
40
+ * at all does the raw text fall back to `form: "text"`.
41
+ *
42
+ * That `form: "text"` fallback is the one case where "verified: false" is
43
+ * ambiguous between two very different situations: a pure conversational
44
+ * reply (no data claim at all — the UI should hide the badge) and a data
45
+ * task that ran but whose result the model chose not to render as an
46
+ * envelope (the UI should still show "Unverified" — that's meaningful).
47
+ * `worklog` (the turn's already-folded `ToolStep[]`, live or floor) is
48
+ * inspected for a data-access tool call to disambiguate the two; schema
49
+ * introspection and artifact-saving tool calls don't count as a data claim.
50
+ */
51
+ export function toAnswerOrRefusalEvent(id, result, worklog = []) {
52
+ if (result.backend === "agent-sdk" || result.backend === "codex-local") {
53
+ const envelope = extractEnvelopeFromText(result.finalText);
54
+ if (envelope !== undefined) {
55
+ return { id, kind: "answer", answer: { form: "rich", envelope } };
56
+ }
57
+ return {
58
+ id,
59
+ kind: "answer",
60
+ answer: { form: "text", text: result.finalText, verified: false, dataAnswer: attemptedDataAccess(worklog) },
61
+ };
62
+ }
63
+ if (result.kind === "answer") {
64
+ return { id, kind: "answer", answer: { form: "rich", envelope: result.envelope } };
65
+ }
66
+ return { id, kind: "refusal", reason: result.reason, fix: REFUSAL_FIX_HINT };
67
+ }
68
+ /** In-process's native in-process tool names that constitute an actual data claim — schema browsing / artifact saving don't count. */
69
+ const DATA_ACCESS_TOOL_NAMES = new Set([
70
+ WREN_QUERY_TOOL_NAME,
71
+ BUILD_DASHBOARD_TOOL_NAME,
72
+ "wren.run_sql",
73
+ ]);
74
+ /**
75
+ * Dispatched never produces those native tool names — the dispatched agent's `answer_query`/
76
+ * `generate_dashboard` components are only granted the SDK's built-in `Bash` tool and run all
77
+ * data access through the `wren` CLI's read-path, always shaped `wren -q -o json -s '<SQL>'` (see
78
+ * the warble hub components' `generate_sql.md`/`repair_sql.md`/`compose_layout.md` steps). Schema
79
+ * introspection (`wren context show`, `wren cube list`, `wren cube describe <cube>`) is also a
80
+ * bare `wren` Bash call but never carries the `-q`/`-s` flags, so it's excluded here.
81
+ */
82
+ const WREN_QUERY_FLAG = /(?:^|\s)-q(?:\s|$)/;
83
+ const WREN_SQL_FLAG = /(?:^|\s)-s(?:\s|$)/;
84
+ function isWrenQueryCommand(command) {
85
+ return /^\s*wren\b/.test(command) && WREN_QUERY_FLAG.test(command) && WREN_SQL_FLAG.test(command);
86
+ }
87
+ /** The Bash tool's input carries the shell command under `command` (confirmed by warble's own `canUseTool` guardrail). */
88
+ function bashCommandOf(step) {
89
+ const input = step.input;
90
+ if (typeof input !== "object" || input === null)
91
+ return undefined;
92
+ const command = input["command"];
93
+ return typeof command === "string" ? command : undefined;
94
+ }
95
+ /**
96
+ * Whether the turn's work log shows a real data-access attempt, success or failure alike — either
97
+ * a in-process native query/dashboard tool call, or a dispatched `Bash` call that actually ran a query
98
+ * through the `wren` CLI (as opposed to schema introspection, which doesn't count as a data claim).
99
+ */
100
+ function attemptedDataAccess(worklog) {
101
+ return worklog.some((step) => {
102
+ if (step.kind !== "tool")
103
+ return false;
104
+ if (DATA_ACCESS_TOOL_NAMES.has(step.label))
105
+ return true;
106
+ if (step.label !== "Bash")
107
+ return false;
108
+ const command = bashCommandOf(step);
109
+ return command !== undefined && isWrenQueryCommand(command);
110
+ });
111
+ }
112
+ /** Maps a `RunFinishEvent`'s companion `ArtifactAgentEvent` straight through — no BFF-side transformation needed. */
113
+ export function toArtifactEvent(id, name, artifactKind, location, artifactId) {
114
+ return { id, kind: "artifact", name, artifactKind, location, artifactId };
115
+ }
116
+ // ---------------------------------------------------------------------------
117
+ // Deterministic control-flow DECISIONS as display-only work-log
118
+ // entries. These do NOT come from the agent runtime and never affect the
119
+ // deterministic gate/result — they only make the BFF's own routing/clarify/
120
+ // verify-gate choices visible in the session. Stable ids let re-emitted live
121
+ // frames dedupe them by id like any other step.
122
+ // ---------------------------------------------------------------------------
123
+ export const DECISION_ROUTE_ID = "decision-route";
124
+ export const DECISION_CLARIFY_ID = "decision-clarify";
125
+ export const DECISION_GATE_ID = "decision-gate";
126
+ /** The intent-routing decision — always prepended to a turn's work log. */
127
+ export function routeDecisionStep(agentId, reason) {
128
+ return { id: DECISION_ROUTE_ID, kind: "decision", label: "Route", state: "done", detail: `→ ${agentId}: ${reason}` };
129
+ }
130
+ /** The clarify decision — only present when the turn short-circuits to a clarify prompt. */
131
+ export function clarifyDecisionStep(detail) {
132
+ return { id: DECISION_CLARIFY_ID, kind: "decision", label: "Clarify", state: "done", detail };
133
+ }
134
+ /**
135
+ * The trailing verify-gate verdict, derived from the resolved `route()` result:
136
+ * - a verified ANSWER (`envelope.verified === true`) -> a "done" verdict;
137
+ * - a REFUSAL -> an "error" verdict carrying the refusal reason;
138
+ * - a non-verified answer (or dispatched, which has no envelope/verify signal)
139
+ * -> `undefined`, so no gate entry is appended.
140
+ */
141
+ export function gateDecisionStep(result) {
142
+ if (result.backend === "agent-sdk" || result.backend === "codex-local")
143
+ return undefined;
144
+ if (result.kind === "refusal") {
145
+ return { id: DECISION_GATE_ID, kind: "decision", label: "Verify gate", state: "error", detail: result.reason };
146
+ }
147
+ if (result.envelope.verified === true) {
148
+ return { id: DECISION_GATE_ID, kind: "decision", label: "Verify gate", state: "done", detail: "verified — grounded in a successful data-access" };
149
+ }
150
+ return undefined;
151
+ }
152
+ /**
153
+ * A failure verdict for a turn whose execution THREW (the error path) — appended
154
+ * to the partial work log so a failed turn's persisted trace ends with why it
155
+ * failed. Detail is the bounded error message.
156
+ */
157
+ export function gateFailureStep(errorMessage) {
158
+ return { id: DECISION_GATE_ID, kind: "decision", label: "Verify gate", state: "error", detail: truncate(errorMessage, SUMMARY_MAX_LENGTH) };
159
+ }
160
+ /**
161
+ * A BFF-owned setup-contract rejection. This deliberately reuses the
162
+ * established `ToolStep.kind: "decision"` wire shape, so the frontend can
163
+ * render recovery evidence without an SSE schema addition.
164
+ */
165
+ export function hostContractRecoveryStep(detail) {
166
+ return {
167
+ id: "decision-host-contract-recovery",
168
+ kind: "decision",
169
+ label: "Host contract",
170
+ state: "error",
171
+ detail: truncate(detail, SUMMARY_MAX_LENGTH),
172
+ };
173
+ }
174
+ const SETUP_INTERNAL_DIAGNOSTIC = /["']?(?:resume[_-]?session(?:[_-]?id)?|sdk[_-]?session(?:[_-]?id)?|session[_-]?id|anchor|runner(?:[_-]?path)?|dispatcher|provider(?:[_-]?name)?)["']?\s*[:=]\s*(?:"[^"]*"|'[^']*'|[^\s,;}\]]+)/gi;
175
+ const SETUP_PROVIDER_NAME = /\b(?:openai|anthropic|gemini|claude|codex)\b/gi;
176
+ const SETUP_URL = /\b[a-z][a-z0-9+.-]*:\/\/[^\s"'`<>()\[\]{}]+/gi;
177
+ const SETUP_ABSOLUTE_PATH = /(^|[\s"'`=:(\[,])(?:(?:~|\/)\/?|[A-Za-z]:\\)[^\s"'`;,)}\]]*/g;
178
+ // JSON is frequently echoed after one or more serialization passes. Limit
179
+ // escaped-quote depth so hostile traces cannot trigger unbounded regex work.
180
+ const SETUP_ESCAPED_CREDENTIAL = /\b([a-z0-9_.-]*(?:password|pass|secret|token|api[-_]?key|credential)[a-z0-9_.-]*)(?:\\{1,4})?["']?\s*(?::|=)\s*(?:\[REDACTED(?:_URL|_PATH)?\]|(?:\\{1,4})?["']?[^\s,;)}\]]+)/gi;
181
+ const SETUP_ANSI = /\u001b(?:\][\s\S]*?(?:\u0007|\u001b\\)|[PX^_][\s\S]*?\u001b\\|\[[0-?]*[ -/]*[@-~]|[@-_])/g;
182
+ const SETUP_C1_ANSI = /\u009b[0-?]*[ -/]*[@-~]/g;
183
+ const SETUP_CONTROL = /[\u0000-\u001f\u007f-\u009f]/g;
184
+ const SETUP_FIELD_MAX_LENGTH = 160;
185
+ const SETUP_INSPECTION_MAX_LENGTH = 512;
186
+ function escapeRegExp(value) {
187
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
188
+ }
189
+ /** Removes terminal escapes and other controls before any setup text crosses a public boundary. */
190
+ function stripSetupControls(text) {
191
+ return text.replace(SETUP_ANSI, "").replace(SETUP_C1_ANSI, "").replace(SETUP_CONTROL, " ");
192
+ }
193
+ /** Redacts URLs, credentials, and arbitrary local absolute paths from setup text. */
194
+ export function redactSetupText(text) {
195
+ return stripSetupControls(text)
196
+ // A URL can contain credentials, local paths, query strings, or opaque
197
+ // provider identifiers. Preserve none of it in a setup work log.
198
+ .replace(SETUP_URL, "[REDACTED_URL]")
199
+ .replace(/((?:--user|-u)\s+)(?:\[REDACTED(?:_URL|_PATH)?\]|'[^']*'|\"[^\"]*\"|\S+)/gi, "$1[REDACTED]")
200
+ .replace(SETUP_ESCAPED_CREDENTIAL, "$1=[REDACTED]")
201
+ .replace(/\b([a-z0-9_.-]*(?:password|pass|secret|token|api[-_]?key|credential)[a-z0-9_.-]*["']?)\s*(?:=|:)\s*(?:\[REDACTED(?:_URL|_PATH)?\]|'[^']*'|\"[^\"]*\"|[^\s,;)}\]]+)/gi, "$1=[REDACTED]")
202
+ .replace(/\b((?:proxy-)?authorization\s*:\s*(?:bearer|basic)\s+)(?:\[REDACTED(?:_URL|_PATH)?\]|'[^']*'|\"[^\"]*\"|[^\s,;]+)/gi, "$1[REDACTED]")
203
+ .replace(/\b((?:x[-_])?api[-_]?key\s*:\s*)(?:\[REDACTED(?:_URL|_PATH)?\]|'[^']*'|\"[^\"]*\"|[^\s,;]+)/gi, "$1[REDACTED]")
204
+ .replace(/(--?(?:password|pass|secret|token|api[-_]?key|credential)(?:=|\s+))(?:\[REDACTED(?:_URL|_PATH)?\]|'[^']*'|\"[^\"]*\"|\S+)/gi, "$1[REDACTED]")
205
+ .replace(/(^|\s)((?:export\s+)?(?:[A-Z][A-Z0-9_]*(?:PASSWORD|PASS|SECRET|TOKEN|API_KEY|CREDENTIAL)[A-Z0-9_]*|PASSWORD|PASS|SECRET|TOKEN|API_KEY|CREDENTIAL))\s+(?:\[REDACTED(?:_URL|_PATH)?\]|'[^']*'|\"[^\"]*\"|\S+)/gim, "$1$2=[REDACTED]")
206
+ .replace(/((?:--user|-u)\s+)(?:'[^']*'|\"[^\"]*\"|\S+)/gi, "$1[REDACTED]")
207
+ .replace(SETUP_ABSOLUTE_PATH, "$1[REDACTED_PATH]");
208
+ }
209
+ /** Strict public setup diagnostic redaction shared by SSE, SQLite, and recovery. */
210
+ export function redactPublicSetupText(text, internalValues = []) {
211
+ let publicText = redactSetupText(text)
212
+ .replace(SETUP_INTERNAL_DIAGNOSTIC, "internal setup detail [REDACTED]")
213
+ .replace(SETUP_PROVIDER_NAME, "[REDACTED]");
214
+ for (const value of internalValues) {
215
+ if (value.length > 0)
216
+ publicText = publicText.replace(new RegExp(escapeRegExp(value), "gi"), "[REDACTED]");
217
+ }
218
+ return publicText;
219
+ }
220
+ /** Truncates by Unicode code point, never leaving a dangling UTF-16 surrogate. */
221
+ function truncateCodePoints(text, max) {
222
+ const codePoints = Array.from(text);
223
+ return codePoints.length > max ? `${codePoints.slice(0, Math.max(0, max - 1)).join("")}…` : text;
224
+ }
225
+ /** Strict formatter for every runtime-controlled Setup work-log string field. */
226
+ function formatSetupField(value, internalValues, max = SETUP_FIELD_MAX_LENGTH) {
227
+ return truncateCodePoints(redactPublicSetupText(value, internalValues), max);
228
+ }
229
+ function boundedInspectionText(value, internalValues) {
230
+ return formatSetupField(value, internalValues, SETUP_INSPECTION_MAX_LENGTH);
231
+ }
232
+ function setupActionSummary(input, internalValues) {
233
+ if (typeof input !== "object" || input === null || Array.isArray(input))
234
+ return undefined;
235
+ const action = input.command ?? input.action;
236
+ return typeof action === "string" && action.length > 0 ? boundedInspectionText(action, internalValues) : undefined;
237
+ }
238
+ function setupDuration(value) {
239
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 && value <= 86_400_000 ? value : undefined;
240
+ }
241
+ function setupInspection(row, state, internalValues) {
242
+ const prior = typeof row.inspection === "object" && row.inspection !== null && !Array.isArray(row.inspection)
243
+ ? row.inspection
244
+ : {};
245
+ const action = setupActionSummary(row.input, internalValues)
246
+ ?? (typeof prior.action === "string" ? boundedInspectionText(prior.action, internalValues) : undefined);
247
+ const detail = typeof row.detail === "string"
248
+ ? boundedInspectionText(row.detail, internalValues)
249
+ : state === "error"
250
+ ? typeof prior.error === "string" ? boundedInspectionText(prior.error, internalValues) : undefined
251
+ : typeof prior.output === "string" ? boundedInspectionText(prior.output, internalValues) : undefined;
252
+ const durationMs = setupDuration(row.durationMs) ?? setupDuration(prior.durationMs);
253
+ const inspection = {
254
+ ...(action !== undefined ? { action } : {}),
255
+ ...(detail !== undefined && state === "error" ? { error: detail } : {}),
256
+ ...(detail !== undefined && state !== "error" ? { output: detail } : {}),
257
+ ...(durationMs !== undefined ? { durationMs } : {}),
258
+ };
259
+ return Object.keys(inspection).length > 0 ? inspection : undefined;
260
+ }
261
+ /**
262
+ * Explicit, strict public worklog allowlist shared by all Setup boundaries.
263
+ * Raw agent `input` and `detail` never cross this boundary: the BFF derives a
264
+ * bounded inspection projection instead, so reload/recovery cannot revive a
265
+ * broader historical trace.
266
+ */
267
+ export function sanitizePublicSetupWorklog(value, internalValues = []) {
268
+ if (!Array.isArray(value))
269
+ return [];
270
+ const states = new Set(["running", "done", "error"]);
271
+ const kinds = new Set(["tool", "subagent", "step", "decision"]);
272
+ return value.flatMap((entry) => {
273
+ if (typeof entry !== "object" || entry === null)
274
+ return [];
275
+ const row = entry;
276
+ if (typeof row.id !== "string" || typeof row.label !== "string" || !states.has(row.state) || !kinds.has(row.kind))
277
+ return [];
278
+ const inspection = setupInspection(row, row.state, internalValues);
279
+ return [{
280
+ id: formatSetupField(row.id, internalValues),
281
+ label: formatSetupField(row.label, internalValues),
282
+ state: row.state,
283
+ kind: row.kind,
284
+ ...(typeof row.parent === "string" ? { parent: formatSetupField(row.parent, internalValues) } : {}),
285
+ ...(typeof row.depth === "number" && Number.isSafeInteger(row.depth) && row.depth >= 0 && row.depth <= 16 ? { depth: row.depth } : {}),
286
+ ...(inspection !== undefined ? { inspection } : {}),
287
+ }];
288
+ });
289
+ }
290
+ /**
291
+ * Live-frame variant of `sanitizePublicSetupWorklog`, for a subscription-mode
292
+ * setup turn's in-flight progress stream (see `server/turn.ts`'s
293
+ * `executeSetupTurn`). The end-of-turn snapshot can redact by KNOWN VALUE —
294
+ * `sanitizePublicSetupWorklog(..., knownInternalValues)` — once an attempt has
295
+ * actually returned its session anchor. A live frame can't: the anchor a
296
+ * rotating subscription attempt will settle on isn't known until it resolves
297
+ * or throws, so falling back to by-SHAPE redaction (this module's
298
+ * `SETUP_INTERNAL_DIAGNOSTIC`/`SETUP_PROVIDER_NAME`
299
+ * patterns) is the only option that can run before then.
300
+ *
301
+ * That fallback is a genuine, accepted weakening: a pattern only catches an
302
+ * anchor that looks the way these patterns anticipate, not any anchor shape a
303
+ * future provider might introduce. To bound that risk, this also drops raw
304
+ * `input`/`detail` and the derived `inspection` outright rather than merely
305
+ * redacting them — a step's raw tool input or diagnostic text is exactly where
306
+ * an unanticipated anchor shape would hide, and a field never sent cannot
307
+ * leak. `WorkLog.tsx` only needs `label`/`state`/`kind`/`parent`/`depth` to
308
+ * render progress; a step becomes expandable with its safe inspection
309
+ * projection once the end-of-turn snapshot replaces this live one.
310
+ */
311
+ export function sanitizeLiveSetupWorklog(worklog) {
312
+ return sanitizePublicSetupWorklog(worklog).map(({ input, detail, inspection, ...rest }) => rest);
313
+ }
314
+ const SUMMARY_MAX_LENGTH = 240;
315
+ function truncate(text, max) {
316
+ return text.length > max ? `${text.slice(0, max - 1)}…` : text;
317
+ }
318
+ /** Short text used for `turns.answer_summary` — feeds `server/compose.ts`'s D3 context composition. Never the full envelope. */
319
+ export function summarizeResult(result) {
320
+ if (result.backend === "agent-sdk" || result.backend === "codex-local") {
321
+ return truncate(result.finalText, SUMMARY_MAX_LENGTH);
322
+ }
323
+ if (result.kind === "answer") {
324
+ const summary = result.envelope.summary;
325
+ return truncate(typeof summary === "string" && summary.length > 0 ? summary : JSON.stringify(result.envelope.blocks), SUMMARY_MAX_LENGTH);
326
+ }
327
+ return truncate(`Refused: ${result.reason}`, SUMMARY_MAX_LENGTH);
328
+ }
329
+ /**
330
+ * Live path accumulator: call `ingest` for each `AgentEvent` as it arrives
331
+ * from `onEvent`; each call returns a fresh immutable snapshot of the
332
+ * work log so far, or `undefined` for event kinds that don't affect it
333
+ * (`run.start`, `token`, `answer`, `refusal`, `artifact`, `run.finish`,
334
+ * `error` — those are terminal/non-worklog events handled elsewhere).
335
+ */
336
+ export class LiveWorkLog {
337
+ order = [];
338
+ steps = new Map();
339
+ ingest(event) {
340
+ switch (event.kind) {
341
+ case "step.start":
342
+ // In-process has no sub-agent/Task mechanism (see this module's
343
+ // doc comment) — its bundle-declared LLM steps are plain steps, kind
344
+ // "step", not "subagent" (that kind stays reserved for a real nested
345
+ // sub-agent turn, which only dispatched could ever produce).
346
+ this.upsert(event.stepId, event.name, "running", "step", event.parent, event.depth);
347
+ return this.snapshot();
348
+ case "step.finish":
349
+ // Detail is the step's own reasoning/output — the text it
350
+ // produced (on success) or the best available error description —
351
+ // already bounded at the emission site (`harness/loop/executor.ts`).
352
+ this.setState(event.stepId, event.status === "ok" ? "done" : "error", event.detail);
353
+ return this.snapshot();
354
+ case "tool.call":
355
+ // Capture the tool call's input at start time — `tool.result`
356
+ // carries no input of its own, only a `summary`/`error`.
357
+ this.upsert(event.callId, event.tool, "running", "tool", event.parent, event.depth, event.input);
358
+ return this.snapshot();
359
+ case "tool.result": {
360
+ if (event.input !== undefined)
361
+ this.setInput(event.callId, event.input);
362
+ // Detail is the success summary, or the error message on
363
+ // failure — both already bounded/compact at the emission site
364
+ // (`summarizeToolOutput` / `describeError` in `harness/loop/executor.ts`).
365
+ const detail = event.status === "success" ? event.summary : event.error;
366
+ this.setState(event.callId, event.status === "success" ? "done" : "error", detail);
367
+ return this.snapshot();
368
+ }
369
+ default:
370
+ return undefined;
371
+ }
372
+ }
373
+ snapshot() {
374
+ return this.order.map((id) => {
375
+ const step = this.steps.get(id);
376
+ if (!step)
377
+ throw new Error(`LiveWorkLog: missing step for id "${id}"`);
378
+ return step;
379
+ });
380
+ }
381
+ upsert(id, label, state, kind, parent, depth, input) {
382
+ if (!this.steps.has(id))
383
+ this.order.push(id);
384
+ const step = {
385
+ id,
386
+ label,
387
+ state,
388
+ kind,
389
+ ...(parent !== undefined ? { parent } : {}),
390
+ ...(depth !== undefined ? { depth } : {}),
391
+ ...(input !== undefined ? { input } : {}),
392
+ };
393
+ this.steps.set(id, step);
394
+ }
395
+ setState(id, state, detail) {
396
+ const existing = this.steps.get(id);
397
+ if (!existing)
398
+ return; // event for a step we never saw start — ignore rather than fabricate
399
+ this.steps.set(id, { ...existing, state, ...(detail !== undefined ? { detail } : {}) });
400
+ }
401
+ setInput(id, input) {
402
+ const existing = this.steps.get(id);
403
+ if (!existing)
404
+ return;
405
+ this.steps.set(id, { ...existing, input });
406
+ }
407
+ }
@@ -0,0 +1,3 @@
1
+ import type { NativePurpose } from "./native-dispatch-registry.js";
2
+ export type HarnessProfileSources = Readonly<Record<NativePurpose, string>>;
3
+ export declare function createHarnessProfileSources(analysisProfileSource: string): HarnessProfileSources;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The profile source behind each read-only Harness purpose is BFF-owned boot
3
+ * configuration. Callers can choose a closed purpose, never a filesystem path
4
+ * or another profile source.
5
+ */
6
+ import path from "node:path";
7
+ import { assertHarnessPurposeProfile, NATIVE_DISPATCH_REGISTRY } from "./native-dispatch-registry.js";
8
+ export function createHarnessProfileSources(analysisProfileSource) {
9
+ const analysis = path.resolve(analysisProfileSource);
10
+ // `WREN_HARNESS_PROFILE` may configure only the canonical analysis source.
11
+ // This is an early boot guard; the compiled bundle is checked again before
12
+ // it can become a read-only Harness response.
13
+ assertHarnessPurposeProfile("analysis", path.basename(analysis));
14
+ const profileRoot = path.dirname(analysis);
15
+ const sources = {
16
+ analysis,
17
+ setup: path.join(profileRoot, NATIVE_DISPATCH_REGISTRY.setup.profile),
18
+ context_enrichment: path.join(profileRoot, NATIVE_DISPATCH_REGISTRY.context_enrichment.profile),
19
+ };
20
+ for (const purpose of Object.keys(sources)) {
21
+ assertHarnessPurposeProfile(purpose, path.basename(sources[purpose]));
22
+ }
23
+ return sources;
24
+ }
@@ -0,0 +1,19 @@
1
+ import type { Bundle, RouteOptions } from "../harness/index.js";
2
+ import type { Store } from "./db.js";
3
+ import type { NativePurpose } from "./native-dispatch-registry.js";
4
+ import type { NativeSessionReadiness } from "./native-sessions.js";
5
+ import type { HarnessDto } from "./wire-types.js";
6
+ type BaseRouteOptions = Omit<RouteOptions, "question" | "onEvent">;
7
+ export interface HarnessSetupReadiness {
8
+ readonly available: boolean;
9
+ readonly reason?: string;
10
+ }
11
+ /** Exported bundle-derived source used by runtime configuration validation. */
12
+ export declare function collectBundleTierNames(bundle: Bundle): string[];
13
+ /**
14
+ * Keep the compiled bundle's declared profile tied to the BFF-selected
15
+ * purpose before exposing it through the read-only Harness DTO.
16
+ */
17
+ export declare function assertHarnessBundlePurpose(bundle: Bundle, purpose: NativePurpose): void;
18
+ export declare function buildHarnessDto(bundle: Bundle, store: Store, baseRouteOptions: BaseRouteOptions, purpose?: NativePurpose, nativeReadiness?: NativeSessionReadiness, setupReadiness?: HarnessSetupReadiness): HarnessDto;
19
+ export {};