@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,322 @@
1
+ import { tool } from "ai";
2
+ import { z } from "zod";
3
+ import { UnknownNativeToolError, WrenBinaryNotFoundError, WrenIntrospectExecutionError, WrenQueryExecutionError, } from "./errors.js";
4
+ export function createNativeToolRegistry() {
5
+ const factories = new Map();
6
+ return {
7
+ register(name, factory) {
8
+ factories.set(name, factory);
9
+ },
10
+ has(name) {
11
+ return factories.has(name);
12
+ },
13
+ create(name) {
14
+ const factory = factories.get(name);
15
+ if (!factory) {
16
+ throw new UnknownNativeToolError(name);
17
+ }
18
+ return factory();
19
+ },
20
+ };
21
+ }
22
+ export const WRITE_ARTIFACT_TOOL_NAME = "write_artifact";
23
+ /**
24
+ * `write_artifact`: routes the write through the injected `ExecutionEnv`,
25
+ * confined to `policy.artifactWriteScope`. The policy is the
26
+ * `deriveEnforcement`-computed `EnforcementPolicy` for the owning
27
+ * agent — a locked `scoped_write` guardrail is what grants
28
+ * `artifactWriteScope` in the first place, so an agent with no such
29
+ * guardrail gets a policy with no scope and every call fails closed with
30
+ * `WriteScopeNotGrantedError` (thrown by the `ExecutionEnv`, not here).
31
+ * This coexists with a locked `read_only_execution` guardrail by design:
32
+ * `readOnly` gates *data-access* execution (`exec`/non-allowlisted
33
+ * `fetch`), never the scoped artifact write.
34
+ */
35
+ export function createWriteArtifactTool(env, policy) {
36
+ return tool({
37
+ description: "Write an artifact to the agent's scoped workspace.",
38
+ inputSchema: z.object({
39
+ path: z.string(),
40
+ content: z.string(),
41
+ }),
42
+ execute: async (input) => {
43
+ await env.writeFile(input.path, input.content, policy);
44
+ return {
45
+ written: true,
46
+ path: input.path,
47
+ bytes: input.content.length,
48
+ };
49
+ },
50
+ });
51
+ }
52
+ /** A native-tool registry pre-populated with the built-in `write_artifact` and `build_dashboard` tools, bound to `env`/`policy`. */
53
+ export function createDefaultNativeToolRegistry(env, policy) {
54
+ const registry = createNativeToolRegistry();
55
+ registry.register(WRITE_ARTIFACT_TOOL_NAME, () => createWriteArtifactTool(env, policy));
56
+ registry.register(BUILD_DASHBOARD_TOOL_NAME, () => createBuildDashboardTool());
57
+ return registry;
58
+ }
59
+ export const BUILD_DASHBOARD_TOOL_NAME = "build_dashboard";
60
+ /**
61
+ * A dashboard row, as the model may hand it in: either a column-keyed object
62
+ * (the shape `generate_dashboard`'s `chart`/`table` render blocks require),
63
+ * or a positional array aligned to that panel's known key order (`columns`
64
+ * for a table, `[x, ...series]` for a chart). Accepting both keeps the
65
+ * schema forgiving of how a model naturally emits rows it just queried,
66
+ * while `normalizeDashboardRow` below deterministically reshapes either
67
+ * form into the object shape the output contract needs.
68
+ */
69
+ const dashboardRowSchema = z.union([z.record(z.string(), z.unknown()), z.array(z.unknown())]);
70
+ const kpiCardInputSchema = z.object({
71
+ label: z.string(),
72
+ value: z.union([z.number(), z.string()]),
73
+ unit: z.string().optional(),
74
+ delta: z.number().optional(),
75
+ });
76
+ const chartInputSchema = z.object({
77
+ chart_type: z.enum(["bar", "line", "pie", "area", "scatter"]),
78
+ x: z.string(),
79
+ series: z.array(z.string()),
80
+ rows: z.array(dashboardRowSchema),
81
+ });
82
+ const tableInputSchema = z.object({
83
+ columns: z.array(z.string()),
84
+ rows: z.array(dashboardRowSchema),
85
+ });
86
+ const definitionInputSchema = z.object({
87
+ sql: z.string(),
88
+ source_tables: z.array(z.string()).optional(),
89
+ filters: z.array(z.string()).optional(),
90
+ });
91
+ export const buildDashboardInputSchema = z.object({
92
+ kpi_cards: z.array(kpiCardInputSchema).optional(),
93
+ chart: chartInputSchema.optional(),
94
+ table: tableInputSchema.optional(),
95
+ definition: definitionInputSchema.optional(),
96
+ summary: z.string().optional(),
97
+ });
98
+ /** Reshapes a row into a plain object: passes an already-object row through; zips a positional array row against `keys`. */
99
+ function normalizeDashboardRow(row, keys) {
100
+ if (!Array.isArray(row))
101
+ return row;
102
+ return Object.fromEntries(keys.map((key, index) => [key, row[index]]));
103
+ }
104
+ /**
105
+ * Deterministically assembles the typed panels the model composed
106
+ * (`kpi_cards`/`chart`/`table`/`definition`) into `generate_dashboard`'s
107
+ * `{blocks}` render contract — one `kpi_card` block per KPI, then `chart`,
108
+ * then `table`, then `definition` (this is the "sensible dashboard order":
109
+ * headline numbers first, then the visual trend/breakdown, then the
110
+ * supporting detail, then the query provenance), each only when the
111
+ * corresponding panel is present in `input`. No LLM call, no I/O — pure
112
+ * reshaping of model-supplied, schema-validated structure, which is what
113
+ * makes this safe to trust as `verified: true` (see `WrenQueryResult`'s own
114
+ * reasoning for why a real, non-erroring data-access result earns
115
+ * `verified`): every panel here was composed by the model from its own
116
+ * queried results, not fabricated by this function.
117
+ */
118
+ export function assembleDashboardBlocks(input) {
119
+ const blocks = [];
120
+ for (const kpi of input.kpi_cards ?? []) {
121
+ blocks.push({
122
+ type: "kpi_card",
123
+ label: kpi.label,
124
+ value: kpi.value,
125
+ ...(kpi.unit !== undefined ? { unit: kpi.unit } : {}),
126
+ ...(kpi.delta !== undefined ? { delta: kpi.delta } : {}),
127
+ });
128
+ }
129
+ if (input.chart) {
130
+ const keys = [input.chart.x, ...input.chart.series];
131
+ blocks.push({
132
+ type: "chart",
133
+ chart_type: input.chart.chart_type,
134
+ x: input.chart.x,
135
+ series: input.chart.series,
136
+ rows: input.chart.rows.map((row) => normalizeDashboardRow(row, keys)),
137
+ });
138
+ }
139
+ if (input.table) {
140
+ const { columns } = input.table;
141
+ blocks.push({
142
+ type: "table",
143
+ columns,
144
+ rows: input.table.rows.map((row) => normalizeDashboardRow(row, columns)),
145
+ });
146
+ }
147
+ if (input.definition) {
148
+ blocks.push({
149
+ type: "definition",
150
+ sql: input.definition.sql,
151
+ source_tables: input.definition.source_tables ?? [],
152
+ filters: input.definition.filters ?? [],
153
+ });
154
+ }
155
+ return {
156
+ blocks,
157
+ ...(input.summary !== undefined ? { summary: input.summary } : {}),
158
+ verified: true,
159
+ };
160
+ }
161
+ /**
162
+ * `build_dashboard` (native realization): a schema-enforced, purely
163
+ * deterministic assembly tool. The zod `inputSchema` is what makes the model
164
+ * reliably supply *structured* panels (typed kpi/chart/table/definition
165
+ * shapes) instead of prose it would otherwise have to be trusted to format
166
+ * correctly; `execute` then just reshapes that already-validated input into
167
+ * the render contract — no LLM call, no I/O, so it can never itself fail
168
+ * non-deterministically the way a render-LLM synthesis step can.
169
+ */
170
+ export function createBuildDashboardTool() {
171
+ return tool({
172
+ description: "Assemble queried dashboard panels (KPI cards, a chart, a table, and/or the query definition) " +
173
+ "into the final dashboard's render blocks, in dashboard order.",
174
+ inputSchema: buildDashboardInputSchema,
175
+ execute: async (input) => assembleDashboardBlocks(input),
176
+ });
177
+ }
178
+ export const WREN_QUERY_TOOL_NAME = "query";
179
+ /**
180
+ * Clamps the model-volunteered `requestedLimit` to the guardrail-derived
181
+ * `policyLimit` (`EnforcementPolicy.rowLimit`), always preferring the
182
+ * smaller. When the model volunteers nothing, the policy limit itself
183
+ * becomes the applied `-l` — a locked-in cap, not just a ceiling on a value
184
+ * the model chose not to supply. When there is no policy limit at all (an
185
+ * agent whose guardrails carry no `row_limit` threshold), the model's
186
+ * requested limit (if any) passes through unclamped.
187
+ */
188
+ function clampRowLimit(policyLimit, requestedLimit) {
189
+ if (policyLimit === undefined)
190
+ return requestedLimit;
191
+ if (requestedLimit === undefined)
192
+ return policyLimit;
193
+ return Math.min(policyLimit, requestedLimit);
194
+ }
195
+ /**
196
+ * `query` (native realization): runs a read-only SQL query through the real
197
+ * `wren` CLI — `wren -q -o json [-l <limit>] -s '<sql>'` — executed via the
198
+ * injected `ExecutionEnv` with `cwd: projectDir`, exactly like
199
+ * `write_artifact` routes through `env.writeFile` instead of touching the
200
+ * filesystem directly. Declared `mode: "read"` so a locked
201
+ * `read_only_execution` guardrail (which `answer_query` always carries)
202
+ * never blocks it — only `mode: "write"` commands are rejected by a
203
+ * read-only policy (see `ExecutionEnv.exec`'s doc comment).
204
+ *
205
+ * `policy.rowLimit` (guardrail-enforcement fix): clamps `input.limit` via
206
+ * `clampRowLimit`, so a locked `row_limit` guardrail actually bounds `-l`
207
+ * instead of being derived and then ignored. `policy.statementTimeoutSec`
208
+ * becomes `ExecCommand.timeoutMs` on the `wren` invocation, so a locked
209
+ * `statement_timeout` guardrail actually kills a runaway query instead of
210
+ * letting it run unbounded.
211
+ *
212
+ * `wren -o json` prints one JSON object per result row (JSONL, not a JSON
213
+ * array) — this parses that into `{ columns, rows }`, where `columns` are
214
+ * the first row's keys (an empty result set yields `columns: []`).
215
+ */
216
+ export function createWrenQueryTool(options) {
217
+ const { env, policy, projectDir } = options;
218
+ return tool({
219
+ description: "Run a read-only SQL query against the wren semantic layer via the native `wren` CLI.",
220
+ inputSchema: z.object({
221
+ sql: z.string(),
222
+ limit: z.number().int().positive().optional(),
223
+ }),
224
+ execute: async (input) => {
225
+ const limit = clampRowLimit(policy.rowLimit, input.limit);
226
+ const args = ["-q", "-o", "json", ...(limit !== undefined ? ["-l", String(limit)] : []), "-s", input.sql];
227
+ const timeoutMs = policy.statementTimeoutSec !== undefined ? policy.statementTimeoutSec * 1000 : undefined;
228
+ const result = await env.exec({ mode: "read", command: "wren", args, cwd: projectDir, ...(timeoutMs !== undefined ? { timeoutMs } : {}) }, policy);
229
+ // A mid-run disappearance of the `wren` binary (e.g.
230
+ // uninstalled/moved after `resolveWrenBinary`'s preflight passed)
231
+ // surfaces here as `ExecResult.notFound`, not just a nonzero
232
+ // `exitCode` — checked first so it throws the specific
233
+ // `WrenBinaryNotFoundError` instead of the generic
234
+ // `WrenQueryExecutionError`, which the repair-fold loop treats as a
235
+ // retryable tool error even though retrying can never help.
236
+ if (result.notFound) {
237
+ throw new WrenBinaryNotFoundError(`"wren" was not found while running this query (spawn ENOENT)`);
238
+ }
239
+ if (result.exitCode !== 0) {
240
+ throw new WrenQueryExecutionError(input.sql, result.exitCode, result.stderr);
241
+ }
242
+ return parseWrenJsonl(result.stdout);
243
+ },
244
+ });
245
+ }
246
+ function parseWrenJsonl(stdout) {
247
+ const rows = stdout
248
+ .split("\n")
249
+ .map((line) => line.trim())
250
+ .filter((line) => line.length > 0)
251
+ .map((line) => JSON.parse(line));
252
+ const columns = rows.length > 0 ? Object.keys(rows[0]) : [];
253
+ return { columns, rows };
254
+ }
255
+ export const SEMANTIC_INTROSPECT_TOOL_NAME = "semantic_introspect";
256
+ /**
257
+ * `semantic_introspect` (native realization): introspects the bound
258
+ * semantic layer via the real `wren` CLI — `wren context show -o json` —
259
+ * executed via the injected `ExecutionEnv` with `cwd: projectDir`, the same
260
+ * shape as {@link createWrenQueryTool}. Declared `mode: "read"` for the same
261
+ * reason `query` is: `explore_model` always carries a locked
262
+ * `read_only_execution` guardrail, and this must never be blocked by it.
263
+ *
264
+ * Unlike `query`, `wren context show -o json` prints a SINGLE JSON object
265
+ * (not JSONL), so this parses with a plain `JSON.parse` rather than
266
+ * `parseWrenJsonl`, and takes no per-call input (introspection covers the
267
+ * whole project, not one statement) — `inputSchema` is deliberately empty.
268
+ *
269
+ * NOTE: `wren cube list` enrichment (cubes/metrics, "if available" per the
270
+ * component's step prompt) is intentionally deferred — it prints plain,
271
+ * non-JSON text (e.g. "No cubes defined.") rather than structured output,
272
+ * which would need its own ad hoc parser for a v1 that's optional per the
273
+ * step prompt anyway.
274
+ */
275
+ export function createWrenSemanticIntrospectTool(options) {
276
+ const { env, policy, projectDir } = options;
277
+ return tool({
278
+ description: "Introspect the wren semantic layer's models, columns, relationships, and metrics via the native `wren` CLI.",
279
+ inputSchema: z.object({}),
280
+ execute: async () => {
281
+ const timeoutMs = policy.statementTimeoutSec !== undefined ? policy.statementTimeoutSec * 1000 : undefined;
282
+ const result = await env.exec({
283
+ mode: "read",
284
+ command: "wren",
285
+ args: ["context", "show", "-o", "json"],
286
+ cwd: projectDir,
287
+ ...(timeoutMs !== undefined ? { timeoutMs } : {}),
288
+ }, policy);
289
+ // Same reasoning as `query`: a mid-run disappearance of the
290
+ // `wren` binary surfaces as `notFound`, checked first so it throws the
291
+ // specific `WrenBinaryNotFoundError` rather than the generic
292
+ // `WrenIntrospectExecutionError`.
293
+ if (result.notFound) {
294
+ throw new WrenBinaryNotFoundError(`"wren" was not found while introspecting the semantic layer (spawn ENOENT)`);
295
+ }
296
+ if (result.exitCode !== 0) {
297
+ throw new WrenIntrospectExecutionError(`exit code ${result.exitCode}\n${result.stderr}`);
298
+ }
299
+ try {
300
+ return JSON.parse(result.stdout);
301
+ }
302
+ catch (error) {
303
+ throw new WrenIntrospectExecutionError(`could not parse "wren context show -o json" output as JSON: ${error instanceof Error ? error.message : String(error)}`);
304
+ }
305
+ },
306
+ });
307
+ }
308
+ /**
309
+ * A native-tool registry carrying both the built-in `write_artifact` tool
310
+ * (bound to `options.env`/`options.policy`, same as
311
+ * `createDefaultNativeToolRegistry`) and the real `query` tool wired to
312
+ * `options.projectDir`. Pass this as `RunAgentContext.nativeTools` to
313
+ * resolve an `answer_query` agent whose `query` tool declares
314
+ * `source: "native"` to a real `wren` CLI invocation instead of an MCP
315
+ * server.
316
+ */
317
+ export function createWrenNativeToolRegistry(options) {
318
+ const registry = createDefaultNativeToolRegistry(options.env, options.policy);
319
+ registry.register(WREN_QUERY_TOOL_NAME, () => createWrenQueryTool(options));
320
+ registry.register(SEMANTIC_INTROSPECT_TOOL_NAME, () => createWrenSemanticIntrospectTool(options));
321
+ return registry;
322
+ }
@@ -0,0 +1,14 @@
1
+ /** A tool declaration's `source` field, parsed into its harness-meaningful shape. */
2
+ export type ParsedToolSource = {
3
+ readonly kind: "native";
4
+ } | {
5
+ readonly kind: "mcp";
6
+ readonly server: string;
7
+ readonly toolName: string;
8
+ };
9
+ /**
10
+ * Parses an `agent.tools[].source` string. Two shapes are recognized:
11
+ * `"native"` and `"mcp:<server>/<name>"` (e.g. `"mcp:wren/query"`). Anything
12
+ * else is a load-time error — bundle producers only ever emit these two.
13
+ */
14
+ export declare function parseToolSource(source: string): ParsedToolSource;
@@ -0,0 +1,18 @@
1
+ import { UnsupportedToolSourceError } from "./errors.js";
2
+ const MCP_SOURCE_PATTERN = /^mcp:([^/]+)\/(.+)$/;
3
+ /**
4
+ * Parses an `agent.tools[].source` string. Two shapes are recognized:
5
+ * `"native"` and `"mcp:<server>/<name>"` (e.g. `"mcp:wren/query"`). Anything
6
+ * else is a load-time error — bundle producers only ever emit these two.
7
+ */
8
+ export function parseToolSource(source) {
9
+ if (source === "native") {
10
+ return { kind: "native" };
11
+ }
12
+ const match = MCP_SOURCE_PATTERN.exec(source);
13
+ if (match) {
14
+ const [, server, toolName] = match;
15
+ return { kind: "mcp", server: server, toolName: toolName };
16
+ }
17
+ throw new UnsupportedToolSourceError(source);
18
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Preflights that a `wren` binary is resolvable on `PATH` (`wren --version`
3
+ * exits 0) — mirrors `resolveWarbleBinary`'s PATH tier
4
+ * (`../compile/resolve-binary.js`) for the `warble` binary. `wren` is a
5
+ * separately-installed CLI, not a sibling repo this package sits beside, so
6
+ * there is no explicit-override or sibling-repo-build tier here — just the
7
+ * one PATH check. Throws {@link WrenBinaryNotFoundError} (loud-fail) so a
8
+ * missing `wren` fails clearly before a native-tool run even starts, instead
9
+ * of surfacing later as an opaque exec failure once the tool loop is already
10
+ * mid-run (see `ExecResult.notFound` for the mid-run counterpart).
11
+ */
12
+ export declare function resolveWrenBinary(): Promise<void>;
@@ -0,0 +1,21 @@
1
+ import { execFile } from "node:child_process";
2
+ import { WrenBinaryNotFoundError } from "./errors.js";
3
+ /**
4
+ * Preflights that a `wren` binary is resolvable on `PATH` (`wren --version`
5
+ * exits 0) — mirrors `resolveWarbleBinary`'s PATH tier
6
+ * (`../compile/resolve-binary.js`) for the `warble` binary. `wren` is a
7
+ * separately-installed CLI, not a sibling repo this package sits beside, so
8
+ * there is no explicit-override or sibling-repo-build tier here — just the
9
+ * one PATH check. Throws {@link WrenBinaryNotFoundError} (loud-fail) so a
10
+ * missing `wren` fails clearly before a native-tool run even starts, instead
11
+ * of surfacing later as an opaque exec failure once the tool loop is already
12
+ * mid-run (see `ExecResult.notFound` for the mid-run counterpart).
13
+ */
14
+ export async function resolveWrenBinary() {
15
+ const onPath = await new Promise((resolve) => {
16
+ execFile("wren", ["--version"], (error) => resolve(!error));
17
+ });
18
+ if (!onPath) {
19
+ throw new WrenBinaryNotFoundError(`not found on PATH (tried running "wren --version")`);
20
+ }
21
+ }
@@ -0,0 +1,51 @@
1
+ import type { ToolSet } from "ai";
2
+ import type { Agent } from "../bundle/schema.js";
3
+ import { type ExecutionEnv, type ExecutionPolicy } from "../exec/index.js";
4
+ import { type McpServerConfigMap } from "./mcp.js";
5
+ import { type NativeToolRegistry } from "./native.js";
6
+ export interface ResolveToolsContext {
7
+ /**
8
+ * Defaults to a registry built from `executionEnv`/`enforcementPolicy`
9
+ * (built-in `write_artifact` tool only). Supplying this bypasses both of
10
+ * those fields entirely.
11
+ */
12
+ readonly nativeTools?: NativeToolRegistry;
13
+ /** Runtime-injected MCP server connection config, keyed by server id. Defaults to `{}`. */
14
+ readonly mcpServers?: McpServerConfigMap;
15
+ /** Backend native tools execute side effects through. Defaults to `createLocalExecutionEnv()`. */
16
+ readonly executionEnv?: ExecutionEnv;
17
+ /**
18
+ * The guardrail-derived policy passed to every native-tool call. Defaults
19
+ * to `{ readOnly: false }` (no scope, no allowlist) — the secure-by-default
20
+ * fallback: without a real `deriveEnforcement(agent)` result threaded in
21
+ * (as `runAgent` does), `write_artifact` rejects every call.
22
+ */
23
+ readonly enforcementPolicy?: ExecutionPolicy;
24
+ }
25
+ export interface ResolvedTools {
26
+ /** The AI SDK tool set the loop executor consumes as `ExecuteAgentContext.tools`. */
27
+ readonly tools: ToolSet;
28
+ /** Shuts down every MCP client this resolution opened. Always safe to call once. */
29
+ close(): Promise<void>;
30
+ }
31
+ /**
32
+ * Turns `agent.tools[]` into an AI SDK `ToolSet`, connecting whatever MCP
33
+ * servers the agent's tools declare and discovering their tools. This is
34
+ * the tool-level "second door" (mirroring the capability gate):
35
+ * every declared tool is resolved and validated *before* the loop executor
36
+ * ever runs a step, so a misconfigured or drifted tool fails loud at
37
+ * session start rather than surfacing as an opaque tool-call error mid-run.
38
+ *
39
+ * Fail-fast is two passes:
40
+ * 1. Before connecting anything: unknown `native` names
41
+ * ({@link UnknownNativeToolError}) and MCP server ids with no entry in
42
+ * `mcpServers` ({@link McpServerNotConfiguredError}).
43
+ * 2. After connecting + discovering each referenced server's tools: any
44
+ * declared `mcp:<server>/<name>` whose server doesn't actually expose
45
+ * `<name>` ({@link McpToolNotExposedError}).
46
+ *
47
+ * On any failure (including a later tool in the list) every MCP client this
48
+ * call opened is closed before the error propagates — resolution never
49
+ * leaks a connected client.
50
+ */
51
+ export declare function resolveTools(agent: Agent, ctx?: ResolveToolsContext): Promise<ResolvedTools>;
@@ -0,0 +1,79 @@
1
+ import { createLocalExecutionEnv } from "../exec/index.js";
2
+ import { McpServerNotConfiguredError, McpToolNotExposedError, UnknownNativeToolError } from "./errors.js";
3
+ import { connectMcpServer } from "./mcp.js";
4
+ import { createDefaultNativeToolRegistry } from "./native.js";
5
+ import { parseToolSource } from "./parse.js";
6
+ /**
7
+ * Turns `agent.tools[]` into an AI SDK `ToolSet`, connecting whatever MCP
8
+ * servers the agent's tools declare and discovering their tools. This is
9
+ * the tool-level "second door" (mirroring the capability gate):
10
+ * every declared tool is resolved and validated *before* the loop executor
11
+ * ever runs a step, so a misconfigured or drifted tool fails loud at
12
+ * session start rather than surfacing as an opaque tool-call error mid-run.
13
+ *
14
+ * Fail-fast is two passes:
15
+ * 1. Before connecting anything: unknown `native` names
16
+ * ({@link UnknownNativeToolError}) and MCP server ids with no entry in
17
+ * `mcpServers` ({@link McpServerNotConfiguredError}).
18
+ * 2. After connecting + discovering each referenced server's tools: any
19
+ * declared `mcp:<server>/<name>` whose server doesn't actually expose
20
+ * `<name>` ({@link McpToolNotExposedError}).
21
+ *
22
+ * On any failure (including a later tool in the list) every MCP client this
23
+ * call opened is closed before the error propagates — resolution never
24
+ * leaks a connected client.
25
+ */
26
+ export async function resolveTools(agent, ctx = {}) {
27
+ const executionEnv = ctx.executionEnv ?? createLocalExecutionEnv();
28
+ const enforcementPolicy = ctx.enforcementPolicy ?? { readOnly: false };
29
+ const nativeTools = ctx.nativeTools ?? createDefaultNativeToolRegistry(executionEnv, enforcementPolicy);
30
+ const mcpServers = ctx.mcpServers ?? {};
31
+ const specs = agent.tools.map((toolSpec) => ({
32
+ toolSpec,
33
+ source: parseToolSource(toolSpec.source),
34
+ }));
35
+ const serverIds = new Set();
36
+ for (const { toolSpec, source } of specs) {
37
+ if (source.kind === "native") {
38
+ if (!nativeTools.has(toolSpec.name)) {
39
+ throw new UnknownNativeToolError(toolSpec.name);
40
+ }
41
+ }
42
+ else if (!mcpServers[source.server]) {
43
+ throw new McpServerNotConfiguredError(source.server);
44
+ }
45
+ else {
46
+ serverIds.add(source.server);
47
+ }
48
+ }
49
+ const clients = new Map();
50
+ const discoveredByServer = new Map();
51
+ async function closeAll() {
52
+ await Promise.all([...clients.values()].map((client) => client.close().catch(() => undefined)));
53
+ }
54
+ try {
55
+ for (const serverId of serverIds) {
56
+ const client = await connectMcpServer(mcpServers[serverId]);
57
+ clients.set(serverId, client);
58
+ discoveredByServer.set(serverId, (await client.tools()));
59
+ }
60
+ const tools = {};
61
+ for (const { toolSpec, source } of specs) {
62
+ if (source.kind === "native") {
63
+ tools[toolSpec.name] = nativeTools.create(toolSpec.name);
64
+ continue;
65
+ }
66
+ const serverTools = discoveredByServer.get(source.server);
67
+ const discoveredTool = serverTools[source.toolName];
68
+ if (!discoveredTool) {
69
+ throw new McpToolNotExposedError(source.server, source.toolName);
70
+ }
71
+ tools[toolSpec.name] = discoveredTool;
72
+ }
73
+ return { tools, close: closeAll };
74
+ }
75
+ catch (error) {
76
+ await closeAll();
77
+ throw error;
78
+ }
79
+ }
@@ -0,0 +1,84 @@
1
+ import { type Tool } from "ai";
2
+ import { z } from "zod";
3
+ import type { ExecutionEnv, ExecutionPolicy } from "../exec/index.js";
4
+ export declare const SETUP_EXECUTION_TOOL_NAME = "setup_execution";
5
+ export interface SetupExecutionToolOptions {
6
+ /** Backend the tool's side effects route through — never a direct child_process/fs call. */
7
+ readonly env: ExecutionEnv;
8
+ readonly policy: ExecutionPolicy;
9
+ /**
10
+ * The setup workspace root — the default (and outer bound) for the `exec`
11
+ * action's subprocess `cwd`, and the `write` action's scope boundary.
12
+ * Always caller-supplied and fixed as the ceiling; the `exec` action MAY
13
+ * narrow its own cwd via an optional per-call `cwd` field (see
14
+ * `resolveExecCwd`), but that value is contained by the same two-phase
15
+ * check as the write path and can never resolve outside this root — a
16
+ * command/path can narrow its own working directory within the root, but
17
+ * never broaden either its cwd or its write scope beyond it.
18
+ */
19
+ readonly workspaceRoot: string;
20
+ }
21
+ /**
22
+ * A single flat top-level object, NOT a `z.discriminatedUnion` — a
23
+ * discriminated union serializes (via `z.toJSONSchema`) to a schema whose
24
+ * TOP level is `{"oneOf": [...]}` with no top-level `"type": "object"`, which
25
+ * both OpenAI's function-calling API and Anthropic's `input_schema` reject
26
+ * outright (confirmed against a real OpenAI `gpt-4.1` call; see
27
+ * `test/native-tool-schema-shape.test.ts` for the offline, no-API-key-spent
28
+ * regression coverage). `command`/`path`/`content` are therefore all
29
+ * optional here — the per-action required-field combination a discriminated
30
+ * union would enforce at the schema level is instead checked in
31
+ * `createSetupExecutionTool`'s `execute`, before any side effect.
32
+ *
33
+ * Flattening the schema drops the model-facing pairing a discriminated union
34
+ * used to encode for free (`exec` needs `command`; `write` needs `path` +
35
+ * `content`) — nothing about the field TYPES says which action requires
36
+ * which field. Since in-process has no turn budget (unlike dispatched's fixed
37
+ * `--max-turns` cap on setup), an under-described schema makes that pairing
38
+ * discoverable only by the model guessing wrong and reading a thrown
39
+ * `SetupExecutionInputError` back — unbounded trial-and-error on the user's
40
+ * own API spend. The `.describe()` calls below and the tool `description` in
41
+ * `createSetupExecutionTool` spell the pairing out explicitly so the model
42
+ * can satisfy it on the first call; the `execute`-time checks remain as the
43
+ * enforced (not just described) guarantee.
44
+ */
45
+ export declare const setupExecutionInputSchema: z.ZodObject<{
46
+ action: z.ZodEnum<{
47
+ exec: "exec";
48
+ write: "write";
49
+ }>;
50
+ command: z.ZodOptional<z.ZodString>;
51
+ cwd: z.ZodOptional<z.ZodString>;
52
+ path: z.ZodOptional<z.ZodString>;
53
+ content: z.ZodOptional<z.ZodString>;
54
+ }, z.core.$strip>;
55
+ export type SetupExecutionInput = z.infer<typeof setupExecutionInputSchema>;
56
+ export type SetupExecutionResult = {
57
+ exitCode: number;
58
+ stdout: string;
59
+ stderr: string;
60
+ notFound?: boolean;
61
+ timedOut?: boolean;
62
+ maxBufferExceeded?: boolean;
63
+ } | {
64
+ written: true;
65
+ path: string;
66
+ bytes: number;
67
+ };
68
+ /**
69
+ * Builds the combined `setup_execution` tool: `action: "exec"` runs a shell
70
+ * command via `/bin/sh -c`, cwd defaulting to `workspaceRoot` but narrowable
71
+ * per-call via the optional `cwd` field (see {@link resolveExecCwd} — always
72
+ * contained within `workspaceRoot`, never able to escape it), broadened
73
+ * beyond a single fixed binary the way the dispatcher-side `setup_execution`
74
+ * guardrail broadens Bash — but still subject to the same denylist, checked
75
+ * first, never relaxed. `action: "write"` writes a file relative to the same
76
+ * optional cwd (workspaceRoot by default), scoped to `workspaceRoot` by the
77
+ * two-phase containment check above, then delegates the actual write to
78
+ * `env.writeFile` (which applies its OWN, nominal-only
79
+ * `policy.artifactWriteScope` check — this tool's pre-flight check is
80
+ * additional, not a replacement, since `env.writeFile` has no realpath
81
+ * re-check of its own; see `harness/exec/local.ts`).
82
+ */
83
+ export declare function executeSetupExecution(input: SetupExecutionInput, options: SetupExecutionToolOptions): Promise<SetupExecutionResult>;
84
+ export declare function createSetupExecutionTool(options: SetupExecutionToolOptions): Tool;