@wrenai/genbi 0.0.3 → 0.0.5

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 (230) hide show
  1. package/README.md +65 -3
  2. package/dist/assets/{echarts-LTFC-ysd.js → echarts-DYM4hjvk.js} +2 -2
  3. package/dist/assets/index-A_Wrq7Ey.css +1 -0
  4. package/dist/assets/{index-Bo--QMUN.js → index-DsH129tV.js} +18 -17
  5. package/dist/index.html +2 -2
  6. package/dist-server/harness/bundle/schema.d.ts +38 -0
  7. package/dist-server/harness/bundle/schema.js +18 -10
  8. package/dist-server/harness/bundle/version.js +1 -1
  9. package/dist-server/harness/cli-args.d.ts +10 -2
  10. package/dist-server/harness/cli-args.js +24 -8
  11. package/dist-server/harness/cli.js +75 -9
  12. package/dist-server/harness/compile/cache.js +4 -4
  13. package/dist-server/harness/compile/compose-profile.d.ts +51 -14
  14. package/dist-server/harness/compile/compose-profile.js +85 -19
  15. package/dist-server/harness/compile/context-loader.d.ts +56 -0
  16. package/dist-server/harness/compile/context-loader.js +237 -0
  17. package/dist-server/harness/compile/errors.d.ts +19 -0
  18. package/dist-server/harness/compile/errors.js +35 -0
  19. package/dist-server/harness/compile/index.d.ts +4 -3
  20. package/dist-server/harness/compile/index.js +4 -3
  21. package/dist-server/harness/compile/pipeline.d.ts +15 -7
  22. package/dist-server/harness/compile/pipeline.js +62 -14
  23. package/dist-server/harness/compile/resolve-binary.d.ts +2 -2
  24. package/dist-server/harness/compile/resolve-binary.js +13 -3
  25. package/dist-server/harness/compile/types.d.ts +29 -0
  26. package/dist-server/harness/compile/warble-identity.d.ts +11 -0
  27. package/dist-server/harness/compile/warble-identity.js +13 -0
  28. package/dist-server/harness/components/ai-step.d.ts +4 -0
  29. package/dist-server/harness/components/ai-step.js +40 -0
  30. package/dist-server/harness/components/broker.d.ts +60 -0
  31. package/dist-server/harness/components/broker.js +117 -0
  32. package/dist-server/harness/components/capability-card.d.ts +98 -0
  33. package/dist-server/harness/components/capability-card.js +169 -0
  34. package/dist-server/harness/components/context.d.ts +2 -0
  35. package/dist-server/harness/components/context.js +30 -0
  36. package/dist-server/harness/components/display.d.ts +6 -0
  37. package/dist-server/harness/components/display.js +29 -0
  38. package/dist-server/harness/components/egress-judge.d.ts +12 -0
  39. package/dist-server/harness/components/egress-judge.js +27 -0
  40. package/dist-server/harness/components/egress.d.ts +142 -0
  41. package/dist-server/harness/components/egress.js +469 -0
  42. package/dist-server/harness/components/in-process.d.ts +7 -0
  43. package/dist-server/harness/components/in-process.js +245 -0
  44. package/dist-server/harness/components/normalize.d.ts +35 -0
  45. package/dist-server/harness/components/normalize.js +245 -0
  46. package/dist-server/harness/components/plan.d.ts +31 -0
  47. package/dist-server/harness/components/plan.js +184 -0
  48. package/dist-server/harness/components/report.d.ts +207 -0
  49. package/dist-server/harness/components/report.js +309 -0
  50. package/dist-server/harness/components/runner.d.ts +193 -0
  51. package/dist-server/harness/components/runner.js +492 -0
  52. package/dist-server/harness/components/semantic-guards.d.ts +20 -0
  53. package/dist-server/harness/components/semantic-guards.js +42 -0
  54. package/dist-server/harness/components/terminal-json.d.ts +18 -0
  55. package/dist-server/harness/components/terminal-json.js +82 -0
  56. package/dist-server/harness/components/usage.d.ts +14 -0
  57. package/dist-server/harness/components/usage.js +19 -0
  58. package/dist-server/harness/components/wren-access.d.ts +29 -0
  59. package/dist-server/harness/components/wren-access.js +233 -0
  60. package/dist-server/harness/components/zone-dry-run.d.ts +43 -0
  61. package/dist-server/harness/components/zone-dry-run.js +107 -0
  62. package/dist-server/harness/components/zone-gate.d.ts +76 -0
  63. package/dist-server/harness/components/zone-gate.js +144 -0
  64. package/dist-server/harness/events/index.d.ts +1 -1
  65. package/dist-server/harness/events/types.d.ts +52 -0
  66. package/dist-server/harness/index.d.ts +9 -2
  67. package/dist-server/harness/index.js +5 -1
  68. package/dist-server/harness/loop/executor.d.ts +1 -0
  69. package/dist-server/harness/loop/executor.js +37 -15
  70. package/dist-server/harness/npm-package-resolve.d.ts +2 -0
  71. package/dist-server/harness/npm-package-resolve.js +16 -4
  72. package/dist-server/harness/providers/adapters/openai-compatible.d.ts +13 -0
  73. package/dist-server/harness/providers/adapters/openai-compatible.js +17 -0
  74. package/dist-server/harness/providers/adapters/openai.d.ts +7 -0
  75. package/dist-server/harness/providers/adapters/openai.js +6 -0
  76. package/dist-server/harness/providers/adapters/pi-ai.d.ts +48 -0
  77. package/dist-server/harness/providers/adapters/pi-ai.js +518 -0
  78. package/dist-server/harness/providers/binding.d.ts +45 -4
  79. package/dist-server/harness/providers/binding.js +44 -8
  80. package/dist-server/harness/providers/index.d.ts +9 -3
  81. package/dist-server/harness/providers/index.js +10 -3
  82. package/dist-server/harness/providers/zone.d.ts +96 -0
  83. package/dist-server/harness/providers/zone.js +112 -0
  84. package/dist-server/harness/render/answering-query.d.ts +29 -0
  85. package/dist-server/harness/render/answering-query.js +62 -0
  86. package/dist-server/harness/render/envelope.d.ts +6 -0
  87. package/dist-server/harness/render/envelope.js +10 -3
  88. package/dist-server/harness/route/adapter-spec.d.ts +8 -9
  89. package/dist-server/harness/route/adapter-spec.js +13 -14
  90. package/dist-server/harness/route/codex-ask-events.js +2 -1
  91. package/dist-server/harness/route/codex-ask.d.ts +4 -0
  92. package/dist-server/harness/route/codex-ask.js +69 -30
  93. package/dist-server/harness/route/codex-host-query.d.ts +52 -0
  94. package/dist-server/harness/route/codex-host-query.js +191 -0
  95. package/dist-server/harness/route/codex-local-manifest.d.ts +9 -1
  96. package/dist-server/harness/route/codex-local-manifest.js +96 -15
  97. package/dist-server/harness/route/codex-wren-proxy.d.ts +33 -0
  98. package/dist-server/harness/route/codex-wren-proxy.js +227 -0
  99. package/dist-server/harness/route/describe.js +45 -6
  100. package/dist-server/harness/route/in-process.d.ts +22 -1
  101. package/dist-server/harness/route/in-process.js +54 -4
  102. package/dist-server/harness/route/route.js +5 -2
  103. package/dist-server/harness/route/types.d.ts +30 -1
  104. package/dist-server/harness/session/run.js +30 -10
  105. package/dist-server/harness/setup/runner.d.ts +2 -0
  106. package/dist-server/harness/setup/runner.js +38 -17
  107. package/dist-server/harness/setup/yaml-scalar.d.ts +23 -0
  108. package/dist-server/harness/setup/yaml-scalar.js +62 -0
  109. package/dist-server/server/adopt.js +1 -17
  110. package/dist-server/server/app.d.ts +1 -0
  111. package/dist-server/server/app.js +163 -14
  112. package/dist-server/server/auth-choice.d.ts +13 -1
  113. package/dist-server/server/auth-choice.js +66 -1
  114. package/dist-server/server/bin.js +197 -26
  115. package/dist-server/server/codex-local-grounding.d.ts +18 -0
  116. package/dist-server/server/codex-local-grounding.js +92 -0
  117. package/dist-server/server/codex-native-session.d.ts +25 -0
  118. package/dist-server/server/codex-native-session.js +1 -0
  119. package/dist-server/server/codex-runtime-composition.d.ts +34 -0
  120. package/dist-server/server/codex-runtime-composition.js +250 -0
  121. package/dist-server/server/codex-structured-ask.d.ts +23 -0
  122. package/dist-server/server/codex-structured-ask.js +102 -0
  123. package/dist-server/server/conn-config.js +4 -16
  124. package/dist-server/server/conversation-socket.d.ts +16 -0
  125. package/dist-server/server/conversation-socket.js +65 -0
  126. package/dist-server/server/db.d.ts +46 -0
  127. package/dist-server/server/db.js +88 -9
  128. package/dist-server/server/env-detect.d.ts +6 -0
  129. package/dist-server/server/env-detect.js +7 -0
  130. package/dist-server/server/fold.d.ts +22 -4
  131. package/dist-server/server/fold.js +37 -5
  132. package/dist-server/server/harness.d.ts +2 -2
  133. package/dist-server/server/harness.js +33 -7
  134. package/dist-server/server/interactive-terminal.d.ts +10 -6
  135. package/dist-server/server/interactive-terminal.js +33 -8
  136. package/dist-server/server/managed-wren-runtime.d.ts +116 -0
  137. package/dist-server/server/managed-wren-runtime.js +670 -0
  138. package/dist-server/server/native-artifacts.d.ts +23 -7
  139. package/dist-server/server/native-artifacts.js +43 -12
  140. package/dist-server/server/native-component-context.d.ts +19 -0
  141. package/dist-server/server/native-component-context.js +76 -0
  142. package/dist-server/server/native-component-preparation.d.ts +20 -0
  143. package/dist-server/server/native-component-preparation.js +129 -0
  144. package/dist-server/server/native-component-runtime.d.ts +36 -0
  145. package/dist-server/server/native-component-runtime.js +92 -0
  146. package/dist-server/server/native-components.d.ts +84 -0
  147. package/dist-server/server/native-components.js +160 -0
  148. package/dist-server/server/native-dispatch-process.d.ts +8 -0
  149. package/dist-server/server/native-dispatch-process.js +65 -0
  150. package/dist-server/server/native-runtime-spec.d.ts +89 -0
  151. package/dist-server/server/native-runtime-spec.js +169 -0
  152. package/dist-server/server/native-sessions.d.ts +172 -19
  153. package/dist-server/server/native-sessions.js +870 -251
  154. package/dist-server/server/native-shutdown.d.ts +6 -0
  155. package/dist-server/server/native-shutdown.js +28 -0
  156. package/dist-server/server/native-wren-home.d.ts +18 -0
  157. package/dist-server/server/native-wren-home.js +262 -0
  158. package/dist-server/server/node-pty-host.d.ts +2 -1
  159. package/dist-server/server/node-pty-host.js +3 -2
  160. package/dist-server/server/profile-registry.d.ts +139 -0
  161. package/dist-server/server/profile-registry.js +620 -0
  162. package/dist-server/server/runtime-binding.d.ts +4 -1
  163. package/dist-server/server/runtime-binding.js +50 -2
  164. package/dist-server/server/runtime-host/claude-component-step.d.ts +25 -0
  165. package/dist-server/server/runtime-host/claude-component-step.js +186 -0
  166. package/dist-server/server/runtime-host/codex-app-server.d.ts +75 -0
  167. package/dist-server/server/runtime-host/codex-app-server.js +239 -0
  168. package/dist-server/server/runtime-host/codex-compatibility.d.ts +110 -0
  169. package/dist-server/server/runtime-host/codex-compatibility.js +162 -0
  170. package/dist-server/server/runtime-host/codex-component-step.d.ts +19 -0
  171. package/dist-server/server/runtime-host/codex-component-step.js +308 -0
  172. package/dist-server/server/runtime-host/codex-conversation.d.ts +109 -0
  173. package/dist-server/server/runtime-host/codex-conversation.js +295 -0
  174. package/dist-server/server/runtime-host/codex-direct-tools.d.ts +23 -0
  175. package/dist-server/server/runtime-host/codex-direct-tools.js +59 -0
  176. package/dist-server/server/runtime-host/codex-events.d.ts +647 -0
  177. package/dist-server/server/runtime-host/codex-events.js +66 -0
  178. package/dist-server/server/runtime-host/codex-policy.d.ts +16 -0
  179. package/dist-server/server/runtime-host/codex-policy.js +151 -0
  180. package/dist-server/server/runtime-host/codex-process.d.ts +8 -0
  181. package/dist-server/server/runtime-host/codex-process.js +96 -0
  182. package/dist-server/server/runtime-host/codex-rpc.d.ts +47 -0
  183. package/dist-server/server/runtime-host/codex-rpc.js +182 -0
  184. package/dist-server/server/runtime-host/codex-session.d.ts +74 -0
  185. package/dist-server/server/runtime-host/codex-session.js +492 -0
  186. package/dist-server/server/runtime-host/codex-terminal-protocol.d.ts +35 -0
  187. package/dist-server/server/runtime-host/codex-terminal-protocol.js +243 -0
  188. package/dist-server/server/runtime-host/codex-terminal.d.ts +16 -0
  189. package/dist-server/server/runtime-host/codex-terminal.js +120 -0
  190. package/dist-server/server/runtime-host/index.d.ts +5 -0
  191. package/dist-server/server/runtime-host/index.js +3 -0
  192. package/dist-server/server/runtime-host/local.d.ts +29 -0
  193. package/dist-server/server/runtime-host/local.js +90 -0
  194. package/dist-server/server/runtime-host/policy.d.ts +8 -0
  195. package/dist-server/server/runtime-host/policy.js +78 -0
  196. package/dist-server/server/runtime-host/types.d.ts +52 -0
  197. package/dist-server/server/runtime-host/types.js +62 -0
  198. package/dist-server/server/structured-query-evidence.d.ts +7 -0
  199. package/dist-server/server/structured-query-evidence.js +47 -0
  200. package/dist-server/server/structured-runtime.d.ts +52 -0
  201. package/dist-server/server/structured-runtime.js +130 -0
  202. package/dist-server/server/structured-scope.d.ts +4 -0
  203. package/dist-server/server/structured-scope.js +12 -0
  204. package/dist-server/server/turn.d.ts +6 -1
  205. package/dist-server/server/turn.js +82 -25
  206. package/dist-server/server/wire-types.d.ts +67 -3
  207. package/dist-server/server/wren-profiles.js +1 -1
  208. package/managed-wren/README.md +60 -0
  209. package/managed-wren/dependency-wheels.json +282 -0
  210. package/managed-wren/manifest.json +373 -0
  211. package/managed-wren/release-inputs.json +45 -0
  212. package/managed-wren/runtime-tree.cjs +115 -0
  213. package/managed-wren/source-inputs.json +40 -0
  214. package/package.json +15 -6
  215. package/profiles/genbi-default/context/binding.yml +17 -7
  216. package/profiles/genbi-default/context/context.json +146 -0
  217. package/profiles/genbi-default/ir.golden.json +39 -43
  218. package/profiles/genbi-default/profile.yml +31 -0
  219. package/profiles/genbi-enrich-context/context/binding.yml +14 -3
  220. package/profiles/genbi-enrich-context/context/context.json +146 -0
  221. package/profiles/genbi-enrich-context/ir.golden.json +4 -5
  222. package/profiles/genbi-monitor/context/binding.yml +13 -5
  223. package/profiles/genbi-monitor/context/context.json +146 -0
  224. package/profiles/genbi-monitor/ir.golden.json +13 -7
  225. package/profiles/genbi-report/context/binding.yml +19 -0
  226. package/profiles/genbi-report/context/context.json +223 -0
  227. package/profiles/genbi-report/ir.golden.json +328 -0
  228. package/profiles/genbi-report/profile.yml +38 -0
  229. package/profiles/genbi-setup/ir.golden.json +3 -1
  230. package/dist/assets/index-Xs4q7pNo.css +0 -1
package/dist/index.html CHANGED
@@ -5,8 +5,8 @@
5
5
  <link rel="icon" type="image/png" href="/wrenai_logo.png" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>GenBI</title>
8
- <script type="module" crossorigin src="/assets/index-Bo--QMUN.js"></script>
9
- <link rel="stylesheet" crossorigin href="/assets/index-Xs4q7pNo.css">
8
+ <script type="module" crossorigin src="/assets/index-DsH129tV.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/index-A_Wrq7Ey.css">
10
10
  </head>
11
11
  <body>
12
12
  <div id="root"></div>
@@ -49,11 +49,18 @@ declare const capabilitySchema: z.ZodObject<{
49
49
  declare const outputSchemaSchema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
50
50
  declare const agentSchema: z.ZodUnion<readonly [z.ZodObject<{
51
51
  id: z.ZodString;
52
+ entrypoint: z.ZodOptional<z.ZodBoolean>;
53
+ dependencies: z.ZodOptional<z.ZodArray<z.ZodObject<{
54
+ step: z.ZodString;
55
+ alias: z.ZodString;
56
+ component: z.ZodString;
57
+ }, z.core.$strict>>>;
52
58
  verb: z.ZodString;
53
59
  component_type: z.ZodString;
54
60
  realization_kind: z.ZodString;
55
61
  trigger: z.ZodString;
56
62
  outcome: z.ZodString;
63
+ brief: z.ZodOptional<z.ZodString>;
57
64
  steps: z.ZodArray<z.ZodObject<{
58
65
  name: z.ZodString;
59
66
  tier: z.ZodString;
@@ -92,6 +99,18 @@ declare const agentSchema: z.ZodUnion<readonly [z.ZodObject<{
92
99
  }, z.core.$strip>>;
93
100
  }, z.core.$strict>, z.ZodObject<{
94
101
  id: z.ZodString;
102
+ entrypoint: z.ZodOptional<z.ZodBoolean>;
103
+ dependencies: z.ZodOptional<z.ZodArray<z.ZodObject<{
104
+ step: z.ZodString;
105
+ alias: z.ZodString;
106
+ component: z.ZodString;
107
+ }, z.core.$strict>>>;
108
+ capability_inspection: z.ZodOptional<z.ZodArray<z.ZodObject<{
109
+ capability: z.ZodString;
110
+ outcome: z.ZodString;
111
+ provided_by: z.ZodString;
112
+ criticality: z.ZodString;
113
+ }, z.core.$strip>>>;
95
114
  verb: z.ZodString;
96
115
  component_type: z.ZodString;
97
116
  realization_kind: z.ZodString;
@@ -118,11 +137,18 @@ export declare const bundleSchema: z.ZodObject<{
118
137
  target: z.ZodString;
119
138
  agents: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
120
139
  id: z.ZodString;
140
+ entrypoint: z.ZodOptional<z.ZodBoolean>;
141
+ dependencies: z.ZodOptional<z.ZodArray<z.ZodObject<{
142
+ step: z.ZodString;
143
+ alias: z.ZodString;
144
+ component: z.ZodString;
145
+ }, z.core.$strict>>>;
121
146
  verb: z.ZodString;
122
147
  component_type: z.ZodString;
123
148
  realization_kind: z.ZodString;
124
149
  trigger: z.ZodString;
125
150
  outcome: z.ZodString;
151
+ brief: z.ZodOptional<z.ZodString>;
126
152
  steps: z.ZodArray<z.ZodObject<{
127
153
  name: z.ZodString;
128
154
  tier: z.ZodString;
@@ -161,6 +187,18 @@ export declare const bundleSchema: z.ZodObject<{
161
187
  }, z.core.$strip>>;
162
188
  }, z.core.$strict>, z.ZodObject<{
163
189
  id: z.ZodString;
190
+ entrypoint: z.ZodOptional<z.ZodBoolean>;
191
+ dependencies: z.ZodOptional<z.ZodArray<z.ZodObject<{
192
+ step: z.ZodString;
193
+ alias: z.ZodString;
194
+ component: z.ZodString;
195
+ }, z.core.$strict>>>;
196
+ capability_inspection: z.ZodOptional<z.ZodArray<z.ZodObject<{
197
+ capability: z.ZodString;
198
+ outcome: z.ZodString;
199
+ provided_by: z.ZodString;
200
+ criticality: z.ZodString;
201
+ }, z.core.$strip>>>;
164
202
  verb: z.ZodString;
165
203
  component_type: z.ZodString;
166
204
  realization_kind: z.ZodString;
@@ -33,6 +33,7 @@ const capabilitySchema = z.object({
33
33
  provided_by: z.string(),
34
34
  criticality: z.string(),
35
35
  });
36
+ const dependencySchema = z.object({ step: z.string(), alias: z.string(), component: z.string() }).strict();
36
37
  // output_schema is a nested JSON Schema document. The harness stores it as-is
37
38
  // and does not interpret it until a later milestone validates output against it.
38
39
  const outputSchemaSchema = z.record(z.string(), z.unknown());
@@ -40,31 +41,38 @@ const outputSchemaSchema = z.record(z.string(), z.unknown());
40
41
  // silently discard an `availability` marker: doing so would turn a redacted
41
42
  // unavailable declaration into an executable-looking component downstream.
42
43
  //
43
- // Strictness has a cost worth naming, because it has already been paid once.
44
- // IR 0.5 added an optional component-level `brief`, and no key for it is
45
- // declared below. Warble omits the field entirely while no profile sets one, so
46
- // nothing fails today — but the first time a profile author writes `brief:` on a
47
- // component, the next dispatch emits that key, `loadBundle` rejects the bundle,
48
- // and `GET /api/harness` starts returning 500 for a reason that has nothing to
49
- // do with the annotation someone just added. That is a deliberate deferral, not
50
- // an oversight: adding a key for a field nothing populates would be guessing at
51
- // its shape. Declare it here when a profile first needs it.
44
+ // IR 0.5 added an optional component-level `brief`: free-form framing text a
45
+ // profile author writes on a mounted component, shared across every one of
46
+ // its steps (Warble's `docs/spec/authoring.md`, "brief — authored framing
47
+ // shared across every step"). It is declared only on the available variant
48
+ // below — an unavailable component (see `unavailableAgentSchema`) has no
49
+ // executable steps for it to frame, so there is nothing for it to reach.
52
50
  const availableAgentSchema = z.object({
53
51
  id: z.string(),
52
+ entrypoint: z.boolean().optional(),
53
+ dependencies: z.array(dependencySchema).optional(),
54
54
  verb: z.string(),
55
55
  component_type: z.string(),
56
56
  realization_kind: z.string(),
57
57
  trigger: z.string(),
58
58
  outcome: z.string(),
59
+ brief: z.string().optional(),
59
60
  steps: z.array(stepSchema),
60
61
  guardrails: z.record(z.string(), guardrailSchema),
61
62
  tools: z.array(toolSchema),
62
63
  output_schema: outputSchemaSchema,
63
64
  capabilities: z.array(capabilitySchema),
64
65
  }).strict();
65
- /** Read-only manifest variant for a declared component this target cannot execute. */
66
+ /**
67
+ * Read-only manifest variant for a declared component this target cannot
68
+ * execute. Carries no `brief`: this branch has no executable steps and no
69
+ * rendering path for framing text to reach.
70
+ */
66
71
  const unavailableAgentSchema = z.object({
67
72
  id: z.string(),
73
+ entrypoint: z.boolean().optional(),
74
+ dependencies: z.array(dependencySchema).optional(),
75
+ capability_inspection: z.array(capabilitySchema).optional(),
68
76
  verb: z.string(),
69
77
  component_type: z.string(),
70
78
  realization_kind: z.string(),
@@ -6,7 +6,7 @@ export class BundleCompatError extends Error {
6
6
  }
7
7
  }
8
8
  export const HARNESS_SUPPORT = {
9
- irVersion: "0.6",
9
+ irVersion: "0.9",
10
10
  bundleVersions: ["0.1"],
11
11
  };
12
12
  function parseVersion(version) {
@@ -1,6 +1,7 @@
1
1
  import type { AuthChoice, LoginProbe } from "./auth/index.js";
2
2
  import type { Deployment } from "./compliance/index.js";
3
3
  import type { AdapterSpec } from "./providers/index.js";
4
+ import { type Zone } from "./providers/index.js";
4
5
  import type { RouteResult } from "./route/types.js";
5
6
  /**
6
7
  * Parsed CLI flags after normalization. Kept separate from `node:util`'s
@@ -25,6 +26,10 @@ export interface CliFlags {
25
26
  readonly tierAdapters?: readonly string[];
26
27
  /** Hybrid mode, dispatched: `--models-config <path>`, forwarded verbatim to `warble-agent-sdk chat`. */
27
28
  readonly modelsConfig?: string;
29
+ /** Hybrid privacy split, in-process: `--tier-binding <path>`, a JSON tier binding document (tiers + disclosure_policy + roles). */
30
+ readonly tierBindingFile?: string;
31
+ /** In-process: `--zone-dry-run` prints the zone audit of the composed plan and exits without running a model. */
32
+ readonly zoneDryRun?: boolean;
28
33
  /** Dispatched only: `--chat-timeout-ms <n>`, overrides `spawnChat`'s default 10-minute hang guard. See `DispatchedOptions.chatTimeoutMs`. */
29
34
  readonly chatTimeoutMs?: number;
30
35
  }
@@ -91,13 +96,16 @@ export declare const EXIT_REFUSAL = 2;
91
96
  export declare function determineExitCode(result: RouteResult): number;
92
97
  /** api-key config from `--api-key`/`--model`; `undefined` when neither is set (so the adapter's own env lookup applies). */
93
98
  export declare function buildApiKeyConfig(flags: CliFlags): Record<string, unknown> | undefined;
94
- /** gateway config from `--endpoint`/`--model`/`--api-key`; `undefined` when none are set (so `deriveAdapterSpec` loud-fails). */
99
+ /** gateway (pi-ai) config from `--provider`/`--model`/`--endpoint`/`--api-key`; `undefined` when none are set (so `deriveAdapterSpec` loud-fails). */
95
100
  export declare function buildGatewayConfig(flags: CliFlags): Record<string, unknown> | undefined;
96
101
  /** One parsed `--tier-adapter` entry, before it's turned into an `AdapterSpec`. */
97
102
  interface ParsedTierAdapterFlag {
103
+ /** A bare tier name or a mount-qualified `<mount>/<tier>` key. */
98
104
  readonly tier: string;
99
105
  readonly mode: string;
100
- readonly fields: Pick<CliFlags, "adapter" | "apiKey" | "model" | "endpoint">;
106
+ readonly fields: Pick<CliFlags, "adapter" | "apiKey" | "model" | "endpoint" | "provider">;
107
+ /** The deployment zone declared for this tier, when the entry carries `zone=`. */
108
+ readonly zone?: Zone;
101
109
  }
102
110
  /**
103
111
  * Parses one hybrid-mode `--tier-adapter <tier>=<mode>[:<field>=<value>,...]`
@@ -1,4 +1,5 @@
1
1
  import { detectAndPick } from "./auth/index.js";
2
+ import { ZONES } from "./providers/index.js";
2
3
  import { deriveAdapterSpec } from "./route/adapter-spec.js";
3
4
  /** Thrown for user-facing CLI misuse (bad/missing flags), surfaced as a top-level `error:` line. */
4
5
  export class CliUsageError extends Error {
@@ -166,11 +167,13 @@ export function buildApiKeyConfig(flags) {
166
167
  config["model"] = flags.model;
167
168
  return Object.keys(config).length > 0 ? config : undefined;
168
169
  }
169
- /** gateway config from `--endpoint`/`--model`/`--api-key`; `undefined` when none are set (so `deriveAdapterSpec` loud-fails). */
170
+ /** gateway (pi-ai) config from `--provider`/`--model`/`--endpoint`/`--api-key`; `undefined` when none are set (so `deriveAdapterSpec` loud-fails). */
170
171
  export function buildGatewayConfig(flags) {
171
172
  const config = {};
173
+ if (flags.provider !== undefined)
174
+ config["provider"] = flags.provider;
172
175
  if (flags.endpoint !== undefined)
173
- config["baseURL"] = flags.endpoint;
176
+ config["baseUrl"] = flags.endpoint;
174
177
  if (flags.model !== undefined)
175
178
  config["model"] = flags.model;
176
179
  if (flags.apiKey !== undefined)
@@ -178,7 +181,7 @@ export function buildGatewayConfig(flags) {
178
181
  return Object.keys(config).length > 0 ? config : undefined;
179
182
  }
180
183
  const TIER_ADAPTER_ALLOWED_MODES = new Set(["api-key", "local", "gateway"]);
181
- const TIER_ADAPTER_ALLOWED_FIELDS = new Set(["adapter", "apiKey", "model", "endpoint"]);
184
+ const TIER_ADAPTER_ALLOWED_FIELDS = new Set(["adapter", "apiKey", "model", "endpoint", "provider", "zone"]);
182
185
  /**
183
186
  * Parses one hybrid-mode `--tier-adapter <tier>=<mode>[:<field>=<value>,...]`
184
187
  * entry — e.g. `cheap=local:endpoint=http://localhost:11434/v1,model=llama3.1`
@@ -201,7 +204,11 @@ export function parseTierAdapterFlag(raw) {
201
204
  throw new CliUsageError(`--tier-adapter "${raw}": mode must be one of api-key|local|gateway (a hybrid tier has no ` +
202
205
  `subscription adapter of its own), got "${mode}"`);
203
206
  }
207
+ if (tier.startsWith("/") || tier.endsWith("/") || tier.split("/").length > 2) {
208
+ throw new CliUsageError(`--tier-adapter "${raw}": tier must be "<tier>" or "<mount>/<tier>", got "${tier}"`);
209
+ }
204
210
  const fields = {};
211
+ let zone;
205
212
  if (fieldsRaw.length > 0) {
206
213
  for (const pair of fieldsRaw.split(",")) {
207
214
  const pairEq = pair.indexOf("=");
@@ -210,12 +217,20 @@ export function parseTierAdapterFlag(raw) {
210
217
  }
211
218
  const key = pair.slice(0, pairEq);
212
219
  if (!TIER_ADAPTER_ALLOWED_FIELDS.has(key)) {
213
- throw new CliUsageError(`--tier-adapter "${raw}": unknown field "${key}" (allowed: adapter, apiKey, model, endpoint)`);
220
+ throw new CliUsageError(`--tier-adapter "${raw}": unknown field "${key}" (allowed: adapter, apiKey, model, endpoint, provider, zone)`);
221
+ }
222
+ const value = pair.slice(pairEq + 1);
223
+ if (key === "zone") {
224
+ if (!ZONES.includes(value)) {
225
+ throw new CliUsageError(`--tier-adapter "${raw}": zone must be one of ${ZONES.join("|")}, got "${value}"`);
226
+ }
227
+ zone = value;
228
+ continue;
214
229
  }
215
- fields[key] = pair.slice(pairEq + 1);
230
+ fields[key] = value;
216
231
  }
217
232
  }
218
- return { tier, mode, fields };
233
+ return { tier, mode, fields, ...(zone !== undefined ? { zone } : {}) };
219
234
  }
220
235
  /**
221
236
  * Builds the hybrid-mode per-tier `AdapterSpec` map from every `--tier-adapter`
@@ -231,13 +246,14 @@ export function parseTierAdapterFlag(raw) {
231
246
  export function buildTierBindingFromFlags(raw) {
232
247
  const tiers = {};
233
248
  for (const entry of raw) {
234
- const { tier, mode, fields } = parseTierAdapterFlag(entry);
249
+ const { tier, mode, fields, zone } = parseTierAdapterFlag(entry);
235
250
  if (tier in tiers) {
236
251
  throw new CliUsageError(`--tier-adapter names tier "${tier}" more than once`);
237
252
  }
238
253
  try {
239
254
  const authChoice = buildExplicitAuthChoice(mode, fields); // `mode` was already restricted to api-key|local|gateway above, so this is never "subscription".
240
- tiers[tier] = deriveAdapterSpec(authChoice, fields.model !== undefined ? { model: fields.model } : {});
255
+ const spec = deriveAdapterSpec(authChoice, fields.model !== undefined ? { model: fields.model } : {});
256
+ tiers[tier] = zone !== undefined ? { ...spec, zone } : spec;
241
257
  }
242
258
  catch (error) {
243
259
  throw new CliUsageError(`--tier-adapter "${entry}": ${error instanceof Error ? error.message : String(error)}`);
@@ -1,20 +1,32 @@
1
1
  #!/usr/bin/env node
2
2
  import { parseArgs } from "node:util";
3
3
  import { createDefaultLoginProbe } from "./auth/index.js";
4
- import { buildTierBindingFromFlags, determineExitCode, parseChatTimeoutMs, resolveAuthChoice, resolveDeployment, validateRequiredInputs, } from "./cli-args.js";
4
+ import { buildTierBindingFromFlags, CliUsageError, determineExitCode, parseChatTimeoutMs, resolveAuthChoice, resolveDeployment, validateRequiredInputs, } from "./cli-args.js";
5
5
  import { enforceCompliance } from "./compliance/index.js";
6
- import { resolveDefaultProfileSource, route } from "./route/index.js";
6
+ import { mkdtemp, readFile, rm } from "node:fs/promises";
7
+ import os from "node:os";
8
+ import path from "node:path";
9
+ import { generatePreparedContextAndCatalog, resolveContextLoader } from "./compile/context-loader.js";
10
+ import { buildCapabilityCard } from "./components/capability-card.js";
11
+ import { executionPlanFor } from "./components/display.js";
12
+ import { defaultEntry } from "./components/in-process.js";
13
+ import { describeZoneDryRun, formatZoneDryRun } from "./components/zone-dry-run.js";
14
+ import { readTierBindingFile } from "./providers/index.js";
15
+ import { describeBundle, resolveDefaultProfileSource, route } from "./route/index.js";
7
16
  const USAGE = `Usage: wren-harness <question> --project <dir> [options]
8
17
 
9
18
  Options:
10
19
  --project <dir> User's wren project directory (required)
11
20
  --profile <dir> Warble profile source directory (default: this package's profiles/genbi-default)
12
21
  --mode <mode> subscription | api-key | local | gateway (default: see policy below)
13
- --provider <name> subscription mode: claude | codex (default: claude)
14
- --adapter <name> api-key mode: provider registry adapter id (e.g. anthropic)
15
- --api-key <key> api-key mode: API key (omit to rely on the adapter's own env var lookup)
16
- --model <name> api-key/local mode: model name
17
- --endpoint <url> local/gateway mode: endpoint URL
22
+ --provider <name> subscription mode: claude | codex (default: claude);
23
+ gateway mode: pi-ai provider id (e.g. openrouter, amazon-bedrock)
24
+ --adapter <name> api-key mode: provider registry adapter id (e.g. openai, anthropic)
25
+ --api-key <key> api-key mode: API key (omit to rely on the adapter's own env var lookup);
26
+ gateway mode: key sent to the pi-ai provider (never read from its env vars)
27
+ --model <name> api-key/local/gateway mode: model name
28
+ --endpoint <url> local mode: endpoint URL; gateway mode: optional custom
29
+ OpenAI-compatible base URL for the --provider name
18
30
  --warble-bin <path> Explicit warble binary (default: the installed @warble/cli, then PATH)
19
31
  --agent-sdk-bin <path> Explicit warble-agent-sdk CLI (subscription mode only)
20
32
  --out <dir> subscription mode: run output directory
@@ -32,6 +44,17 @@ Options:
32
44
  per-tier YAML config, forwarded verbatim as --models-config <path> to
33
45
  "warble-agent-sdk chat". Known limitation: warble's render stage still
34
46
  wall-hits on non-"render: none" components under a non-Anthropic tier.
47
+ --tier-binding <path> Hybrid privacy split, in-process only: a JSON tier binding document
48
+ {"tiers": {"<tier>"|"<mount>/<tier>": {"adapter","config","zone"}},
49
+ "disclosure_policy": {...}, "roles": {"judge": "<key>", "render": "<key>"}}.
50
+ Keys may be mount-qualified so a caller and callee sharing a tier name bind
51
+ different models. Mutually exclusive with --tier-adapter. A zone on any entry
52
+ (or a disclosure_policy / roles block) arms the zone gate, which rejects a
53
+ public or unset zone on any callee or data-bearing step before any model runs.
54
+ --zone-dry-run In-process only: compile the profile, print every step's component, tier,
55
+ binding key, zone, adapter, model, endpoint host and thinking setting plus
56
+ every alias call edge, run the zone gate and exit (0 ok, 1 gate violation).
57
+ Starts no model, opens no network connection and needs no credentials.
35
58
  --chat-timeout-ms <n> dispatched only (subscription): overrides the default 10-minute hang guard
36
59
  on a "warble-agent-sdk chat" invocation. Raise this for a legitimately
37
60
  slower cold-start turn (e.g. right after onboarding a project) rather
@@ -74,6 +97,8 @@ async function main() {
74
97
  deployment: { type: "string" },
75
98
  "tier-adapter": { type: "string", multiple: true },
76
99
  "models-config": { type: "string" },
100
+ "tier-binding": { type: "string" },
101
+ "zone-dry-run": { type: "boolean" },
77
102
  "chat-timeout-ms": { type: "string" },
78
103
  help: { type: "boolean" },
79
104
  },
@@ -103,6 +128,8 @@ async function main() {
103
128
  ...(values.deployment !== undefined ? { deployment: values.deployment } : {}),
104
129
  ...(values["tier-adapter"] !== undefined ? { tierAdapters: values["tier-adapter"] } : {}),
105
130
  ...(values["models-config"] !== undefined ? { modelsConfig: values["models-config"] } : {}),
131
+ ...(values["tier-binding"] !== undefined ? { tierBindingFile: values["tier-binding"] } : {}),
132
+ ...(values["zone-dry-run"] === true ? { zoneDryRun: true } : {}),
106
133
  ...(chatTimeoutMs !== undefined ? { chatTimeoutMs } : {}),
107
134
  };
108
135
  const question = positionals.join(" ");
@@ -123,7 +150,46 @@ async function main() {
123
150
  // Error, caught like any other error below) if the wrong one is supplied
124
151
  // for the resolved authChoice.mode, so no separate CLI-level guard is
125
152
  // duplicated here.
126
- const tierBinding = flags.tierAdapters !== undefined ? buildTierBindingFromFlags(flags.tierAdapters) : undefined;
153
+ if (flags.tierAdapters !== undefined && flags.tierBindingFile !== undefined) {
154
+ throw new CliUsageError("--tier-adapter and --tier-binding are mutually exclusive; declare the binding in one place");
155
+ }
156
+ const fileBinding = flags.tierBindingFile !== undefined ? await readTierBindingFile(flags.tierBindingFile) : undefined;
157
+ const tierBinding = fileBinding?.tiers ?? (flags.tierAdapters !== undefined ? buildTierBindingFromFlags(flags.tierAdapters) : undefined);
158
+ const zoneOptions = {
159
+ ...(tierBinding !== undefined ? { tierBinding } : {}),
160
+ ...(fileBinding?.disclosurePolicy !== undefined ? { disclosurePolicy: fileBinding.disclosurePolicy } : {}),
161
+ ...(fileBinding?.roles !== undefined ? { zoneRoles: fileBinding.roles } : {}),
162
+ };
163
+ if (flags.zoneDryRun === true) {
164
+ if (authChoice.mode === "subscription") {
165
+ throw new CliUsageError("--zone-dry-run audits the in-process composed runtime; it does not apply to subscription mode");
166
+ }
167
+ const bundle = await describeBundle({ authChoice, profileSource, userProject: project,
168
+ ...(flags.warbleBin !== undefined ? { warbleBin: flags.warbleBin } : {}) });
169
+ if (bundle.vercel_bundle_version !== "0.2") {
170
+ throw new CliUsageError("--zone-dry-run needs a composed (vercel bundle 0.2) profile; this profile compiled to the legacy agent format");
171
+ }
172
+ const plan = executionPlanFor(bundle);
173
+ if (!plan)
174
+ throw new Error("Composed display has no trusted execution plan");
175
+ const binding = { tiers: tierBinding ?? {}, ...(fileBinding?.disclosurePolicy !== undefined ? { disclosurePolicy: fileBinding.disclosurePolicy } : {}),
176
+ ...(fileBinding?.roles !== undefined ? { roles: fileBinding.roles } : {}) };
177
+ // The card public-zone steps would receive: generated by code from the bound project, no model involved.
178
+ const scratch = await mkdtemp(path.join(os.tmpdir(), "genbi-zone-dry-run-"));
179
+ let card;
180
+ try {
181
+ const catalogPath = path.join(scratch, "catalog.json");
182
+ await generatePreparedContextAndCatalog(resolveContextLoader().bin, path.resolve(project), path.join(scratch, "context.json"), catalogPath);
183
+ card = buildCapabilityCard(JSON.parse(await readFile(catalogPath, "utf8")), binding.disclosurePolicy ? { disclosure: binding.disclosurePolicy } : {});
184
+ }
185
+ finally {
186
+ await rm(scratch, { recursive: true, force: true });
187
+ }
188
+ const dryRun = describeZoneDryRun(plan, defaultEntry(plan), binding, { card: { digest: card.digest, bytes: card.bytes, truncated: card.truncated } });
189
+ process.stdout.write(formatZoneDryRun(dryRun));
190
+ process.exitCode = dryRun.exitCode;
191
+ return;
192
+ }
127
193
  const result = await route({
128
194
  authChoice,
129
195
  profileSource,
@@ -134,7 +200,7 @@ async function main() {
134
200
  ...(flags.warbleBin !== undefined ? { warbleBin: flags.warbleBin } : {}),
135
201
  ...(flags.agentSdkBin !== undefined ? { agentSdkBin: flags.agentSdkBin } : {}),
136
202
  ...(flags.out !== undefined ? { outDir: flags.out } : {}),
137
- ...(tierBinding !== undefined ? { tierBinding } : {}),
203
+ ...zoneOptions,
138
204
  ...(flags.modelsConfig !== undefined ? { modelsConfig: flags.modelsConfig } : {}),
139
205
  ...(flags.chatTimeoutMs !== undefined ? { chatTimeoutMs: flags.chatTimeoutMs } : {}),
140
206
  });
@@ -5,13 +5,13 @@ import os from "node:os";
5
5
  import path from "node:path";
6
6
  /**
7
7
  * Deterministic on-disk slot name for a cache key — order-independent, one directory per (profile,
8
- * context, mode, provider-fragment-hash, warble-identity, hub-dir). An absent `hubDir` (no
9
- * `--hub-dir` passed, so warble's compiled-in default applied) hashes as the empty string, which is
10
- * a distinct value from any real root rather than an alias for one.
8
+ * context, mode, provider-fragment-hash, warble-identity, context-loader-identity, hub-dir). An
9
+ * absent `hubDir` (no `--hub-dir` passed, so warble's compiled-in default applied) hashes as the
10
+ * empty string, which is a distinct value from any real root rather than an alias for one.
11
11
  */
12
12
  function keyDigest(key) {
13
13
  return createHash("sha256")
14
- .update(`${key.profileHash}:${key.contextFingerprint}:${key.mode}:${key.providerFragmentHash}:${key.warbleIdentity}:${key.hubDir ?? ""}`)
14
+ .update(`${key.profileHash}:${key.contextFingerprint}:${key.mode}:${key.providerFragmentHash}:${key.warbleIdentity}:${key.contextLoaderIdentity}:${key.hubDir ?? ""}`)
15
15
  .digest("hex");
16
16
  }
17
17
  /**
@@ -1,31 +1,68 @@
1
1
  /**
2
- * Copies `profileSource` into `destDir`, then rewrites its context binding's `project:` field to
3
- * point at `userProject` (absolute path) instead of the profile's own fixture binding. Returns the
4
- * composed profile's directory (safe to pass straight to `warble compile`).
2
+ * Copies `profileSource` into `destDir` and rebinds its context to `userProject`, producing a
3
+ * composed profile directory that is safe to pass straight to `warble compile`.
4
+ *
5
+ * The profile's context binding is a **prepared** binding (`kind: prepared`): Warble does not read
6
+ * the user's semantic layer itself, it reads a JSON *document* that WrenAI's own generator
7
+ * (`wren-context-loader`) produces. So rebinding is two writes, not one:
8
+ *
9
+ * 1. Run the generator over `userProject` and write its document over the profile's committed
10
+ * fixture document, at the path the binding's `document:` field already names.
11
+ * 2. Rewrite the binding's `project:` line to `userProject` (absolute).
12
+ *
13
+ * `project:` stays the layer's **identity** and never becomes the document path. That exact
14
+ * substitution shipped once in Warble and put the filename into every compiled prompt, telling the
15
+ * agent it was working on a project called `context.json`; Warble now guards against it, and this
16
+ * side must not hand it a binding that tries.
17
+ *
18
+ * Because the generated document is written *to the path the binding already declares*, `document:`
19
+ * needs no rewriting at all — the composed binding differs from the committed one only in
20
+ * `project:`. Note that `document:` (like `project:`) resolves relative to the **Warble project
21
+ * root** (the composed directory), not relative to the binding file that declares it.
5
22
  *
6
23
  * The binding file to rewrite is *not* hardcoded to `context/binding.yml` — it's read from the
7
24
  * copied `profile.yml`'s own `context: project: <path>` pointer (the documented Warble mechanism:
8
25
  * "profile mounts context via `context: project: <path-to-binding.yml>`"), so this works for any
9
- * profile following that shape, not just `genbi-default`. The resolved binding path is confined to
10
- * the composed directory: a `../`-laden pointer that escapes it is a loud {@link PathTraversalError}
11
- * (reusing the exec module's shared traversal error rather than reading/overwriting an arbitrary
12
- * host file).
26
+ * profile following that shape, not just `genbi-default`. Both the binding path and the resolved
27
+ * document path are confined to the composed directory: a `../`-laden pointer that escapes it is a
28
+ * loud {@link PathTraversalError} (reusing the exec module's shared traversal error rather than
29
+ * reading/overwriting an arbitrary host file).
13
30
  *
14
- * Both `profile.yml` and the binding file are small, flat YAML where only a single scalar matters
15
- * here — regex extraction/rewrite is used deliberately instead of pulling in a full YAML parser
16
- * dependency for that. Both the pointer lookup and the `project:` rewrite assert *exactly one*
17
- * match and loud-fail on zero or multiple (a duplicate top-level `project:` would otherwise leave a
18
- * stale line that last-key-wins YAML parsing could silently bind to the wrong project). If a Warble
19
- * profile ever grows a more elaborate `context:` block (e.g. multiple context sources), this needs
20
- * revisiting.
31
+ * Both `profile.yml` and the binding file are small, flat YAML where only a few scalars matter here
32
+ * — regex extraction/rewrite is used deliberately instead of pulling in a full YAML parser
33
+ * dependency for that. Every lookup asserts *exactly one* match and loud-fails on zero or multiple
34
+ * (a duplicate top-level `project:` would otherwise leave a stale line that last-key-wins YAML
35
+ * parsing could silently bind to the wrong project). If a Warble profile ever grows a more
36
+ * elaborate `context:` block (e.g. multiple context sources), this needs revisiting.
21
37
  */
22
38
  export declare function composeUserProfile(options: {
23
39
  readonly profileSource: string;
24
40
  readonly userProject: string;
25
41
  readonly destDir: string;
42
+ /**
43
+ * The resolved `wren-context-loader` binary (see `resolveContextLoaderBinary`). Required, not
44
+ * optional-with-a-default: there is no fallback path that skips the generator, and making the
45
+ * caller supply it keeps that structural rather than a comment.
46
+ */
47
+ readonly contextLoaderBin: string;
26
48
  }): Promise<string>;
27
49
  /** Extracts the single `context: project: <path>` pointer from a profile.yml's text. */
28
50
  export declare function extractContextBindingPath(profileYamlText: string, sourcePath: string): string;
51
+ /**
52
+ * Asserts the binding declares exactly one top-level `kind: prepared`.
53
+ *
54
+ * A **missing** `kind:` is rejected rather than tolerated. Omitting it selects Warble's serde
55
+ * default (`wren_project`), i.e. Warble's own built-in MDL adapter — so a binding without the line
56
+ * would compile perfectly well while quietly ignoring the document this function's caller just
57
+ * generated. Since Warble emits neither `kind` nor `document` into the IR, that divergence is
58
+ * invisible in the compiled artifact; the only place it can be caught is here.
59
+ */
60
+ export declare function assertPreparedBindingKind(bindingText: string, sourcePath: string): void;
61
+ /**
62
+ * Extracts the single top-level `document: <path>` field naming where the prepared-context document
63
+ * lives, relative to the Warble project root (NOT to the binding file's own directory).
64
+ */
65
+ export declare function extractBindingDocumentPath(bindingText: string, sourcePath: string): string;
29
66
  /**
30
67
  * Replaces the single top-level `project:` line in a context-binding YAML's text, preserving
31
68
  * surrounding comments. Asserts exactly one top-level `project:` — a second one would survive the