@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,242 @@
1
+ import { spawn } from "node:child_process";
2
+ import { accessSync, constants as fsConstants } from "node:fs";
3
+ import { createInterface } from "node:readline";
4
+ import path from "node:path";
5
+ import { enforceCompliance } from "../compliance/index.js";
6
+ import { compileProfile } from "../compile/pipeline.js";
7
+ import { createAgentEventEmitter } from "../events/index.js";
8
+ import { CodexAskEventMapper } from "./codex-ask-events.js";
9
+ import { resolveCodexLocalCli } from "./codex-local-cli.js";
10
+ import { CODEX_ASK_COMPONENTS, } from "./codex-local-manifest.js";
11
+ const CODEX_BILLING_ENV_KEYS = new Set([
12
+ "OPENAI_API_KEY",
13
+ "CODEX_API_KEY",
14
+ "AZURE_OPENAI_API_KEY",
15
+ "OPENAI_ORGANIZATION",
16
+ "OPENAI_ORG_ID",
17
+ "OPENAI_PROJECT",
18
+ "OPENAI_PROJECT_ID",
19
+ ]);
20
+ const DEFAULT_CODEX_ASK_TIMEOUT_MS = 10 * 60 * 1000;
21
+ export function buildCodexAskArgs(cli, options) {
22
+ if (!options.question.trim())
23
+ throw new Error("Codex Ask question must not be empty");
24
+ return [
25
+ ...cli.prefixArgs,
26
+ "dispatch",
27
+ options.irPath,
28
+ options.question,
29
+ "--component",
30
+ options.component ?? "answer_query",
31
+ "--project",
32
+ options.userProject,
33
+ "--codex-home",
34
+ options.codexHome,
35
+ "--orchestrator-model",
36
+ options.models.orchestrator,
37
+ "--cheap-model",
38
+ options.models.cheap,
39
+ "--strong-model",
40
+ options.models.strong,
41
+ "--server",
42
+ "wren",
43
+ "--server-command",
44
+ options.mcpServer.command,
45
+ ...options.mcpServer.prefixArgs.flatMap((arg) => arg.startsWith("-") ? [`--server-arg=${arg}`] : ["--server-arg", arg]),
46
+ "--server-arg",
47
+ "serve",
48
+ "--server-arg",
49
+ "mcp",
50
+ "--server-arg=--project",
51
+ "--server-arg",
52
+ options.userProject,
53
+ "--server-arg=--quiet",
54
+ "--inspect-tool",
55
+ "get_context",
56
+ "--query-tool",
57
+ "run_sql",
58
+ "--timeout",
59
+ String(options.timeoutMs),
60
+ ...(options.codexBin ? ["--codex-bin", options.codexBin] : []),
61
+ "--stream-json",
62
+ ];
63
+ }
64
+ export async function runCodexAskDefault(options) {
65
+ enforceCompliance(options.authChoice, { deployment: options.deployment ?? "personal" });
66
+ if (options.authChoice.provider !== "codex") {
67
+ throw new Error("Codex Ask runner requires a Codex subscription auth choice");
68
+ }
69
+ const agentId = options.agentId ?? "answer_query";
70
+ if (!CODEX_ASK_COMPONENTS.includes(agentId)) {
71
+ throw new Error(`codex:local Ask does not support the "${agentId}" component`);
72
+ }
73
+ const component = agentId;
74
+ const models = resolveModels(options.codexModels);
75
+ const codexHome = options.codexHome?.trim();
76
+ if (!codexHome || !path.isAbsolute(codexHome)) {
77
+ throw new Error("Codex Ask requires an absolute WREN_HARNESS_CODEX_HOME for its dedicated authenticated session home");
78
+ }
79
+ if (options.signal?.aborted)
80
+ throw new Error("warble-codex-local Ask was cancelled before start");
81
+ const emitter = createAgentEventEmitter(options.onEvent);
82
+ emitter.emit({ kind: "run.start", mode: "B", agentId: component });
83
+ try {
84
+ const irPath = options.irPath ?? (await compileProfile({
85
+ profileSource: options.profileSource,
86
+ userProject: options.userProject,
87
+ mode: "native",
88
+ ...(options.warbleBin !== undefined ? { warbleBin: options.warbleBin } : {}),
89
+ ...(options.workDir !== undefined ? { workDir: options.workDir } : {}),
90
+ })).irPath;
91
+ if (options.signal?.aborted)
92
+ throw new Error("warble-codex-local Ask was cancelled during preparation");
93
+ const cli = options.codexLocalCli ?? (await resolveCodexLocalCli(options.codexLocalBin));
94
+ if (options.signal?.aborted)
95
+ throw new Error("warble-codex-local Ask was cancelled during preparation");
96
+ const mcpServer = options.mcpServer ?? { command: resolveExecutableOnPath("wren"), prefixArgs: [] };
97
+ if (options.signal?.aborted)
98
+ throw new Error("warble-codex-local Ask was cancelled during preparation");
99
+ const timeoutMs = options.timeoutMs ?? DEFAULT_CODEX_ASK_TIMEOUT_MS;
100
+ const args = buildCodexAskArgs(cli, {
101
+ irPath,
102
+ question: options.question,
103
+ userProject: options.userProject,
104
+ codexHome,
105
+ models,
106
+ mcpServer,
107
+ timeoutMs,
108
+ component,
109
+ ...(options.codexBin !== undefined ? { codexBin: options.codexBin } : {}),
110
+ });
111
+ const mapper = new CodexAskEventMapper(models, component);
112
+ const finalText = await spawnCodexAsk(cli.command, args, mapper, emitter.emit, options.processTimeoutMs ?? timeoutMs + 5_000, options.signal);
113
+ emitter.emit({ kind: "run.finish", status: "answer" });
114
+ return { finalText };
115
+ }
116
+ catch (error) {
117
+ const message = error instanceof Error ? error.message : String(error);
118
+ emitter.emit({ kind: "error", message });
119
+ emitter.emit({ kind: "run.finish", status: "error" });
120
+ throw error;
121
+ }
122
+ }
123
+ function resolveModels(value) {
124
+ const models = typeof value === "function" ? value() : value;
125
+ if (!models || !models.orchestrator.trim() || !models.cheap.trim() || !models.strong.trim()) {
126
+ throw new Error("Codex Ask requires orchestrator, cheap, and strong model bindings");
127
+ }
128
+ return models;
129
+ }
130
+ function resolveExecutableOnPath(name) {
131
+ for (const directory of (process.env.PATH ?? "").split(path.delimiter)) {
132
+ if (!directory)
133
+ continue;
134
+ const candidate = path.join(directory, name);
135
+ try {
136
+ accessSync(candidate, fsConstants.X_OK);
137
+ return candidate;
138
+ }
139
+ catch {
140
+ // Keep searching.
141
+ }
142
+ }
143
+ throw new Error(`could not find the "${name}" executable on PATH`);
144
+ }
145
+ function sanitizedCodexEnvironment() {
146
+ return Object.fromEntries(Object.entries(process.env).filter(([key, value]) => value !== undefined && !CODEX_BILLING_ENV_KEYS.has(key.toUpperCase())));
147
+ }
148
+ function spawnCodexAsk(command, args, mapper, emit, timeoutMs, signal) {
149
+ return new Promise((resolve, reject) => {
150
+ if (signal?.aborted) {
151
+ reject(new Error("warble-codex-local Ask was cancelled before spawn"));
152
+ return;
153
+ }
154
+ const child = spawn(command, [...args], {
155
+ env: sanitizedCodexEnvironment(),
156
+ stdio: ["ignore", "pipe", "pipe"],
157
+ detached: process.platform !== "win32",
158
+ });
159
+ let stderr = "";
160
+ let settled = false;
161
+ let stopReason;
162
+ let killTimer;
163
+ const terminate = (childSignal) => {
164
+ if (child.pid !== undefined && process.platform !== "win32") {
165
+ try {
166
+ process.kill(-child.pid, childSignal);
167
+ return;
168
+ }
169
+ catch {
170
+ // Fall through to the direct child.
171
+ }
172
+ }
173
+ child.kill(childSignal);
174
+ };
175
+ const stop = (reason) => {
176
+ if (settled || stopReason !== undefined)
177
+ return;
178
+ stopReason = reason;
179
+ terminate("SIGTERM");
180
+ killTimer = setTimeout(() => terminate("SIGKILL"), 1_000);
181
+ };
182
+ const timer = setTimeout(() => stop("timeout"), timeoutMs);
183
+ const cancel = () => stop("cancelled");
184
+ signal?.addEventListener("abort", cancel, { once: true });
185
+ const lines = createInterface({ input: child.stdout, crlfDelay: Infinity });
186
+ lines.on("line", (line) => {
187
+ if (settled || !line.trim())
188
+ return;
189
+ try {
190
+ for (const event of mapper.nextLine(line))
191
+ emit(event);
192
+ }
193
+ catch (error) {
194
+ settled = true;
195
+ clearTimeout(timer);
196
+ signal?.removeEventListener("abort", cancel);
197
+ terminate("SIGTERM");
198
+ killTimer = setTimeout(() => terminate("SIGKILL"), 1_000);
199
+ reject(error);
200
+ }
201
+ });
202
+ child.stderr.on("data", (chunk) => {
203
+ if (stderr.length < 8_192)
204
+ stderr += chunk.toString("utf8");
205
+ });
206
+ child.on("error", (error) => {
207
+ if (settled)
208
+ return;
209
+ settled = true;
210
+ clearTimeout(timer);
211
+ if (killTimer)
212
+ clearTimeout(killTimer);
213
+ signal?.removeEventListener("abort", cancel);
214
+ reject(new Error(`warble-codex-local Ask failed to start: ${error.message}`));
215
+ });
216
+ child.on("close", (code, childSignal) => {
217
+ clearTimeout(timer);
218
+ signal?.removeEventListener("abort", cancel);
219
+ lines.close();
220
+ if (settled)
221
+ return;
222
+ settled = true;
223
+ if (stopReason === "timeout") {
224
+ reject(new Error(`warble-codex-local Ask timed out after ${timeoutMs}ms`));
225
+ }
226
+ else if (stopReason === "cancelled") {
227
+ reject(new Error("warble-codex-local Ask was cancelled"));
228
+ }
229
+ else if (code !== 0) {
230
+ reject(new Error(`warble-codex-local Ask exited with ${code ?? childSignal ?? "unknown"}: ${stderr.trim()}`));
231
+ }
232
+ else {
233
+ try {
234
+ resolve(mapper.result());
235
+ }
236
+ catch (error) {
237
+ reject(error);
238
+ }
239
+ }
240
+ });
241
+ });
242
+ }
@@ -0,0 +1,20 @@
1
+ import type { ResolvedCli } from "./agent-sdk-cli.js";
2
+ export declare class CodexLocalCliNotFoundError extends Error {
3
+ constructor(attempts: readonly string[]);
4
+ }
5
+ /**
6
+ * Resolves the warble `codex-local` dispatcher CLI in four tiers, mirroring
7
+ * `resolveAgentSdkCli`/`resolveWarbleBinary`:
8
+ *
9
+ * 1. `explicit` — trusted as-is, no existence check.
10
+ * 2. The pinned `@warble/codex-local` npm package this workspace depends on, run via
11
+ * `node <dist/cli.js>`.
12
+ * 3. `PATH` — a `warble-codex-local` executable found by walking `PATH` directly (this resolver's
13
+ * existing convention, unlike `resolveAgentSdkCli`'s `--help` probe).
14
+ * 4. A sibling `warble` repo's dev-mode invocation, gated behind the explicit
15
+ * `WREN_HARNESS_ALLOW_WARBLE_SIBLING_CHECKOUT=1` opt-in — must not silently win over the pinned
16
+ * package now that tier 2 exists.
17
+ *
18
+ * Throws {@link CodexLocalCliNotFoundError} (loud-fail) if none of the four work.
19
+ */
20
+ export declare function resolveCodexLocalCli(explicit?: string): Promise<ResolvedCli>;
@@ -0,0 +1,78 @@
1
+ import { accessSync, constants as fsConstants, existsSync } from "node:fs";
2
+ import { delimiter, dirname, join, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { isWarbleSiblingCheckoutDevModeEnabled, resolveInstalledPackageBin } from "../npm-package-resolve.js";
5
+ export class CodexLocalCliNotFoundError extends Error {
6
+ constructor(attempts) {
7
+ super(`could not resolve the warble-codex-local CLI:\n${attempts.map((attempt) => ` - ${attempt}`).join("\n")}`);
8
+ this.name = "CodexLocalCliNotFoundError";
9
+ }
10
+ }
11
+ /**
12
+ * Resolves the warble `codex-local` dispatcher CLI in four tiers, mirroring
13
+ * `resolveAgentSdkCli`/`resolveWarbleBinary`:
14
+ *
15
+ * 1. `explicit` — trusted as-is, no existence check.
16
+ * 2. The pinned `@warble/codex-local` npm package this workspace depends on, run via
17
+ * `node <dist/cli.js>`.
18
+ * 3. `PATH` — a `warble-codex-local` executable found by walking `PATH` directly (this resolver's
19
+ * existing convention, unlike `resolveAgentSdkCli`'s `--help` probe).
20
+ * 4. A sibling `warble` repo's dev-mode invocation, gated behind the explicit
21
+ * `WREN_HARNESS_ALLOW_WARBLE_SIBLING_CHECKOUT=1` opt-in — must not silently win over the pinned
22
+ * package now that tier 2 exists.
23
+ *
24
+ * Throws {@link CodexLocalCliNotFoundError} (loud-fail) if none of the four work.
25
+ */
26
+ export async function resolveCodexLocalCli(explicit) {
27
+ if (explicit !== undefined)
28
+ return { command: explicit, prefixArgs: [] };
29
+ const attempts = [];
30
+ const packageBin = resolveInstalledPackageBin("@warble/codex-local", "warble-codex-local");
31
+ if (packageBin !== undefined)
32
+ return { command: process.execPath, prefixArgs: [packageBin] };
33
+ attempts.push(`"@warble/codex-local" is not installed (or declares no "warble-codex-local" bin) in this workspace`);
34
+ const fromPath = resolveOnPath("warble-codex-local");
35
+ if (fromPath !== undefined)
36
+ return { command: fromPath, prefixArgs: [] };
37
+ attempts.push('not found on PATH as "warble-codex-local"');
38
+ if (isWarbleSiblingCheckoutDevModeEnabled()) {
39
+ const sibling = findSiblingDevInvocation();
40
+ if (sibling !== undefined)
41
+ return sibling;
42
+ attempts.push('no sibling "warble/dispatcher/codex-local" package with a tsx dev entry was found');
43
+ }
44
+ else {
45
+ attempts.push(`sibling "warble" checkout dev mode is disabled (set WREN_HARNESS_ALLOW_WARBLE_SIBLING_CHECKOUT=1 to enable it)`);
46
+ }
47
+ throw new CodexLocalCliNotFoundError(attempts);
48
+ }
49
+ function resolveOnPath(binaryName) {
50
+ for (const dir of (process.env.PATH ?? "").split(delimiter)) {
51
+ if (!dir)
52
+ continue;
53
+ const candidate = join(dir, binaryName);
54
+ try {
55
+ accessSync(candidate, fsConstants.X_OK);
56
+ return candidate;
57
+ }
58
+ catch {
59
+ // Keep searching.
60
+ }
61
+ }
62
+ return undefined;
63
+ }
64
+ function findSiblingDevInvocation() {
65
+ let dir = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..");
66
+ for (let i = 0; i < 10; i += 1) {
67
+ const parent = dirname(dir);
68
+ const pkgDir = join(parent, "warble", "dispatcher", "codex-local");
69
+ const tsx = join(pkgDir, "node_modules", ".bin", "tsx");
70
+ const entry = join(pkgDir, "src", "cli.ts");
71
+ if (existsSync(tsx) && existsSync(entry))
72
+ return { command: tsx, prefixArgs: [entry] };
73
+ if (parent === dir)
74
+ break;
75
+ dir = parent;
76
+ }
77
+ return undefined;
78
+ }
@@ -0,0 +1,22 @@
1
+ import type { Bundle } from "../bundle/schema.js";
2
+ import type { ResolvedCli } from "./agent-sdk-cli.js";
3
+ export interface CodexManifestModels {
4
+ readonly orchestrator: string;
5
+ readonly cheap: string;
6
+ readonly strong: string;
7
+ }
8
+ export declare const CODEX_ASK_COMPONENTS: readonly ["answer_query", "generate_dashboard"];
9
+ export type CodexAskComponent = (typeof CODEX_ASK_COMPONENTS)[number];
10
+ export declare const CODEX_ENRICH_COMPONENTS: readonly ["inspect_context", "draft_enrichment"];
11
+ export type CodexManifestPurpose = "analysis" | "setup" | "context_enrichment";
12
+ export declare function buildCodexAskManifestArgs(cli: ResolvedCli, irPath: string, models: CodexManifestModels, component?: CodexAskComponent): readonly string[];
13
+ export declare function buildCodexBootstrapManifestArgs(cli: ResolvedCli, irPath: string): readonly string[];
14
+ export declare function buildCodexEnrichmentManifestArgs(cli: ResolvedCli, irPath: string, models: CodexManifestModels, component: (typeof CODEX_ENRICH_COMPONENTS)[number]): readonly string[];
15
+ export declare function describeCodexAskManifest(cli: ResolvedCli, irPath: string, models: CodexManifestModels): Promise<Bundle>;
16
+ /**
17
+ * Setup is a raw/bootstrap profile, not an Ask profile. Its dispatcher has a
18
+ * dedicated whole-profile `manifest` command that neither needs nor accepts a
19
+ * bound Wren project, so never route it through the Ask-only component list.
20
+ */
21
+ export declare function describeCodexBootstrapManifest(cli: ResolvedCli, irPath: string): Promise<Bundle>;
22
+ export declare function describeCodexEnrichmentManifest(cli: ResolvedCli, irPath: string, models: CodexManifestModels): Promise<Bundle>;
@@ -0,0 +1,180 @@
1
+ import { execFile } from "node:child_process";
2
+ import { readFile } from "node:fs/promises";
3
+ import { loadBundle } from "../bundle/loader.js";
4
+ export const CODEX_ASK_COMPONENTS = ["answer_query", "generate_dashboard"];
5
+ export const CODEX_ENRICH_COMPONENTS = ["inspect_context", "draft_enrichment"];
6
+ export function buildCodexAskManifestArgs(cli, irPath, models, component = "answer_query") {
7
+ return [
8
+ ...cli.prefixArgs,
9
+ "manifest",
10
+ irPath,
11
+ "--component",
12
+ component,
13
+ "--orchestrator-model",
14
+ models.orchestrator,
15
+ "--cheap-model",
16
+ models.cheap,
17
+ "--strong-model",
18
+ models.strong,
19
+ // Manifest preparation validates an absolute MCP command but does not
20
+ // spawn it; the runtime binds the real Wren MCP command separately.
21
+ "--server-command",
22
+ process.execPath,
23
+ "--inspect-tool",
24
+ "get_context",
25
+ "--query-tool",
26
+ "run_sql",
27
+ ];
28
+ }
29
+ export function buildCodexBootstrapManifestArgs(cli, irPath) {
30
+ return [
31
+ ...cli.prefixArgs,
32
+ "manifest",
33
+ irPath,
34
+ "--server-command",
35
+ process.execPath,
36
+ "--source-tool",
37
+ "setup_execution",
38
+ "--context-tool",
39
+ "setup_execution",
40
+ ];
41
+ }
42
+ export function buildCodexEnrichmentManifestArgs(cli, irPath, models, component) {
43
+ return [
44
+ ...cli.prefixArgs,
45
+ "manifest",
46
+ irPath,
47
+ "--component",
48
+ component,
49
+ "--model",
50
+ component === "inspect_context" ? models.cheap : models.strong,
51
+ "--server-command",
52
+ process.execPath,
53
+ "--semantic-tool",
54
+ "get_context",
55
+ "--raw-material-tool",
56
+ "get_context",
57
+ ];
58
+ }
59
+ async function describeCodexComponentManifests(cli, irPath, components, argsFor) {
60
+ const ir = JSON.parse(await readFile(irPath, "utf8"));
61
+ const bundles = await Promise.all(components.map(async (component) => {
62
+ const stdout = await execCodexManifest(cli.command, argsFor(component));
63
+ return normalizeCodexManifest(JSON.parse(stdout), ir);
64
+ }));
65
+ const primary = bundles[0];
66
+ for (const bundle of bundles.slice(1)) {
67
+ if (bundle.manifest_version !== primary.manifest_version ||
68
+ JSON.stringify(bundle.compat) !== JSON.stringify(primary.compat) ||
69
+ bundle.profile !== primary.profile ||
70
+ bundle.target !== primary.target) {
71
+ throw new Error("Codex component manifests disagree on their target identity");
72
+ }
73
+ }
74
+ return loadBundle({ ...primary, agents: bundles.flatMap((bundle) => bundle.agents) });
75
+ }
76
+ export async function describeCodexAskManifest(cli, irPath, models) {
77
+ return describeCodexComponentManifests(cli, irPath, CODEX_ASK_COMPONENTS, (component) => buildCodexAskManifestArgs(cli, irPath, models, component));
78
+ }
79
+ /**
80
+ * Setup is a raw/bootstrap profile, not an Ask profile. Its dispatcher has a
81
+ * dedicated whole-profile `manifest` command that neither needs nor accepts a
82
+ * bound Wren project, so never route it through the Ask-only component list.
83
+ */
84
+ export async function describeCodexBootstrapManifest(cli, irPath) {
85
+ const ir = JSON.parse(await readFile(irPath, "utf8"));
86
+ const stdout = await execCodexManifest(cli.command, buildCodexBootstrapManifestArgs(cli, irPath));
87
+ return normalizeCodexManifest(JSON.parse(stdout), ir);
88
+ }
89
+ export async function describeCodexEnrichmentManifest(cli, irPath, models) {
90
+ return describeCodexComponentManifests(cli, irPath, CODEX_ENRICH_COMPONENTS, (component) => buildCodexEnrichmentManifestArgs(cli, irPath, models, component));
91
+ }
92
+ function execCodexManifest(command, args) {
93
+ return new Promise((resolve, reject) => {
94
+ execFile(command, [...args], { maxBuffer: 32 * 1024 * 1024, timeout: 120_000 }, (error, stdout, stderr) => {
95
+ if (error) {
96
+ reject(new Error(`warble-codex-local manifest failed: ${stderr || error.message}`));
97
+ return;
98
+ }
99
+ resolve(stdout);
100
+ });
101
+ });
102
+ }
103
+ function records(value) {
104
+ return Array.isArray(value)
105
+ ? value.filter((entry) => typeof entry === "object" && entry !== null)
106
+ : [];
107
+ }
108
+ function normalizeCodexManifest(manifest, ir) {
109
+ const irComponents = records(ir["components"]);
110
+ const agents = records(manifest["agents"]).map((agent) => {
111
+ const id = String(agent["id"] ?? "");
112
+ const component = irComponents.find((candidate) => candidate["id"] === id);
113
+ if (!component)
114
+ throw new Error(`Codex manifest component "${id}" is absent from compiled IR`);
115
+ const irSteps = records(component["llm_calls"]);
116
+ const irGuards = records(component["guardrails"]);
117
+ const renderBlocks = records(component["effect"]?.["render_blocks"]);
118
+ const manifestGuards = (agent["guardrails"] ?? {});
119
+ return {
120
+ id,
121
+ verb: String(agent["verb"] ?? component["verb"] ?? id),
122
+ component_type: String(agent["component_type"] ?? component["type"] ?? "analytical"),
123
+ realization_kind: String(agent["realization_kind"] ?? component["realization_kind"] ?? "skill"),
124
+ trigger: String(agent["trigger"] ?? component["trigger"]?.["kind"] ?? "one_shot"),
125
+ outcome: String(agent["outcome"] ?? component["effect"]?.["outcome"] ?? "none"),
126
+ steps: records(agent["steps"]).map((step) => {
127
+ const name = String(step["name"] ?? "");
128
+ const source = irSteps.find((candidate) => candidate["name"] === name) ?? {};
129
+ const when = source["when"];
130
+ return {
131
+ name,
132
+ tier: String(step["tier"] ?? source["tier"] ?? "strong"),
133
+ consumes: Array.isArray(step["consumes"]) ? step["consumes"].map(String) : [],
134
+ produces: String(step["produces"] ?? source["produces"] ?? "result"),
135
+ prompt: String(source["prompt"] ?? ""),
136
+ realization: when
137
+ ? { kind: "repair_fold", fold_into: String(when["target"] ?? ""), max_attempts: 1 }
138
+ : { kind: "independent" },
139
+ ...(when ? { when: { guard: String(when["guard"] ?? ""), target: String(when["target"] ?? "") } } : {}),
140
+ };
141
+ }),
142
+ guardrails: Object.fromEntries(irGuards.map((guard) => {
143
+ const name = String(guard["name"] ?? "");
144
+ const described = manifestGuards[name] ?? {};
145
+ return [
146
+ name,
147
+ {
148
+ enforcement: String(described["enforcement"] ?? "codex-local"),
149
+ locked: Boolean(guard["locked"]),
150
+ ...(typeof guard["threshold"] === "number" ? { threshold: guard["threshold"] } : {}),
151
+ ...(typeof guard["scope"] === "string" ? { scope: guard["scope"] } : {}),
152
+ },
153
+ ];
154
+ })),
155
+ tools: records(agent["tools"]).map((tool) => ({ name: String(tool["name"] ?? ""), source: String(tool["source"] ?? "") })),
156
+ output_schema: {
157
+ properties: {
158
+ blocks: {
159
+ items: {
160
+ anyOf: renderBlocks.map((block) => ({ properties: { type: { const: String(block["type"] ?? "") } } })),
161
+ },
162
+ },
163
+ },
164
+ },
165
+ capabilities: records(agent["capabilities"]).map((capability) => ({
166
+ capability: String(capability["capability"] ?? ""),
167
+ outcome: String(capability["outcome"] ?? "native"),
168
+ provided_by: typeof capability["via"] === "string" ? capability["via"] : "codex-local",
169
+ criticality: "required",
170
+ })),
171
+ };
172
+ });
173
+ return loadBundle({
174
+ manifest_version: manifest["manifest_version"],
175
+ compat: manifest["compat"],
176
+ profile: manifest["profile"],
177
+ target: manifest["target"],
178
+ agents,
179
+ });
180
+ }
@@ -0,0 +1,54 @@
1
+ import type { AuthChoice } from "../auth/index.js";
2
+ import type { Bundle } from "../bundle/schema.js";
3
+ import { type CodexManifestModels, type CodexManifestPurpose } from "./codex-local-manifest.js";
4
+ /**
5
+ * The subset of `RouteOptions`/`InProcessOptions` needed to describe how a
6
+ * profile is CURRENTLY realized. `authChoice` is required (not optional)
7
+ * because it's the discriminator `describeBundle` branches on — see below —
8
+ * unlike `question`/`onEvent`/model-routing options, which don't affect what
9
+ * gets described.
10
+ */
11
+ interface DescribeBundleBaseOptions {
12
+ readonly authChoice: AuthChoice;
13
+ readonly profileSource: string;
14
+ readonly warbleBin?: string;
15
+ readonly agentSdkBin?: string;
16
+ readonly codexLocalBin?: string;
17
+ readonly codexModels?: CodexManifestModels;
18
+ readonly workDir?: string;
19
+ /** Selects the executable component family shown by the purpose-scoped Harness. */
20
+ readonly codexManifestPurpose?: CodexManifestPurpose;
21
+ }
22
+ /** A profile whose context must be rebound to the currently bound project. */
23
+ export interface BoundDescribeBundleOptions extends DescribeBundleBaseOptions {
24
+ /** Omitted by legacy bound callers; bootstrap must always be explicit. */
25
+ readonly context?: "bound_project";
26
+ readonly userProject: string;
27
+ }
28
+ /** A profile that owns its authored raw/bootstrap context and has no user project. */
29
+ export interface BootstrapDescribeBundleOptions extends DescribeBundleBaseOptions {
30
+ readonly context: "bootstrap";
31
+ }
32
+ export type DescribeBundleOptions = BoundDescribeBundleOptions | BootstrapDescribeBundleOptions;
33
+ /**
34
+ * Describes whichever back-end will ACTUALLY run a turn for
35
+ * `options.authChoice` — the invariant this maintains is: Harness-shown
36
+ * target == `runtimeDispatcher`'s prediction (`server/harness.ts`)
37
+ * == what `route()` really dispatches to. The IR itself stays target-neutral
38
+ * either way; only the DISPLAY artifact this function loads differs:
39
+ *
40
+ * - `authChoice.mode === "subscription"` (dispatched): compiles IR only
41
+ * (`mode: "native"`, reusing `compileProfile`'s cache) — no vercel bundle
42
+ * is produced on this path at all — then sources the display from the
43
+ * claude-agent-sdk dispatcher's OWN `manifest` subcommand, which reads
44
+ * that same IR and emits a structurally-identical-to-the-vercel-bundle
45
+ * JSON (`target: "claude-agent-sdk:local"`) to stdout. This is genuinely
46
+ * what dispatched runs — `runDispatchedDefault` (`./dispatched.js`) shells this same
47
+ * dispatcher's `chat` subcommand against the same IR.
48
+ * - every other `authChoice.mode` (in-process: api-key/local/gateway): compiles
49
+ * to a vercel bundle (`mode: "agnostic"`, `warble dispatch --target
50
+ * vercel`) — unchanged pre-existing behavior; `runInProcessDefault`
51
+ * (`./in-process.js`) calls this too rather than keeping its own copy.
52
+ */
53
+ export declare function describeBundle(options: DescribeBundleOptions): Promise<Bundle>;
54
+ export {};