@wrenai/genbi 0.0.4 → 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.
- package/README.md +64 -2
- package/dist/assets/{echarts-LTFC-ysd.js → echarts-DYM4hjvk.js} +2 -2
- package/dist/assets/index-A_Wrq7Ey.css +1 -0
- package/dist/assets/{index-Bo--QMUN.js → index-DsH129tV.js} +18 -17
- package/dist/index.html +2 -2
- package/dist-server/harness/bundle/schema.d.ts +38 -0
- package/dist-server/harness/bundle/schema.js +18 -10
- package/dist-server/harness/bundle/version.js +1 -1
- package/dist-server/harness/cli-args.d.ts +10 -2
- package/dist-server/harness/cli-args.js +24 -8
- package/dist-server/harness/cli.js +75 -9
- package/dist-server/harness/compile/cache.js +4 -4
- package/dist-server/harness/compile/compose-profile.d.ts +51 -14
- package/dist-server/harness/compile/compose-profile.js +85 -19
- package/dist-server/harness/compile/context-loader.d.ts +56 -0
- package/dist-server/harness/compile/context-loader.js +237 -0
- package/dist-server/harness/compile/errors.d.ts +19 -0
- package/dist-server/harness/compile/errors.js +35 -0
- package/dist-server/harness/compile/index.d.ts +4 -3
- package/dist-server/harness/compile/index.js +4 -3
- package/dist-server/harness/compile/pipeline.d.ts +15 -7
- package/dist-server/harness/compile/pipeline.js +62 -14
- package/dist-server/harness/compile/resolve-binary.d.ts +2 -2
- package/dist-server/harness/compile/resolve-binary.js +3 -3
- package/dist-server/harness/compile/types.d.ts +29 -0
- package/dist-server/harness/compile/warble-identity.d.ts +11 -0
- package/dist-server/harness/compile/warble-identity.js +13 -0
- package/dist-server/harness/components/ai-step.d.ts +4 -0
- package/dist-server/harness/components/ai-step.js +40 -0
- package/dist-server/harness/components/broker.d.ts +60 -0
- package/dist-server/harness/components/broker.js +117 -0
- package/dist-server/harness/components/capability-card.d.ts +98 -0
- package/dist-server/harness/components/capability-card.js +169 -0
- package/dist-server/harness/components/context.d.ts +2 -0
- package/dist-server/harness/components/context.js +30 -0
- package/dist-server/harness/components/display.d.ts +6 -0
- package/dist-server/harness/components/display.js +29 -0
- package/dist-server/harness/components/egress-judge.d.ts +12 -0
- package/dist-server/harness/components/egress-judge.js +27 -0
- package/dist-server/harness/components/egress.d.ts +142 -0
- package/dist-server/harness/components/egress.js +469 -0
- package/dist-server/harness/components/in-process.d.ts +7 -0
- package/dist-server/harness/components/in-process.js +245 -0
- package/dist-server/harness/components/normalize.d.ts +35 -0
- package/dist-server/harness/components/normalize.js +245 -0
- package/dist-server/harness/components/plan.d.ts +31 -0
- package/dist-server/harness/components/plan.js +184 -0
- package/dist-server/harness/components/report.d.ts +207 -0
- package/dist-server/harness/components/report.js +309 -0
- package/dist-server/harness/components/runner.d.ts +193 -0
- package/dist-server/harness/components/runner.js +492 -0
- package/dist-server/harness/components/semantic-guards.d.ts +20 -0
- package/dist-server/harness/components/semantic-guards.js +42 -0
- package/dist-server/harness/components/terminal-json.d.ts +18 -0
- package/dist-server/harness/components/terminal-json.js +82 -0
- package/dist-server/harness/components/usage.d.ts +14 -0
- package/dist-server/harness/components/usage.js +19 -0
- package/dist-server/harness/components/wren-access.d.ts +29 -0
- package/dist-server/harness/components/wren-access.js +233 -0
- package/dist-server/harness/components/zone-dry-run.d.ts +43 -0
- package/dist-server/harness/components/zone-dry-run.js +107 -0
- package/dist-server/harness/components/zone-gate.d.ts +76 -0
- package/dist-server/harness/components/zone-gate.js +144 -0
- package/dist-server/harness/events/index.d.ts +1 -1
- package/dist-server/harness/events/types.d.ts +52 -0
- package/dist-server/harness/index.d.ts +9 -2
- package/dist-server/harness/index.js +5 -1
- package/dist-server/harness/loop/executor.d.ts +1 -0
- package/dist-server/harness/loop/executor.js +37 -15
- package/dist-server/harness/npm-package-resolve.d.ts +2 -0
- package/dist-server/harness/npm-package-resolve.js +16 -4
- package/dist-server/harness/providers/adapters/openai-compatible.d.ts +13 -0
- package/dist-server/harness/providers/adapters/openai-compatible.js +17 -0
- package/dist-server/harness/providers/adapters/openai.d.ts +7 -0
- package/dist-server/harness/providers/adapters/openai.js +6 -0
- package/dist-server/harness/providers/adapters/pi-ai.d.ts +48 -0
- package/dist-server/harness/providers/adapters/pi-ai.js +518 -0
- package/dist-server/harness/providers/binding.d.ts +45 -4
- package/dist-server/harness/providers/binding.js +44 -8
- package/dist-server/harness/providers/index.d.ts +9 -3
- package/dist-server/harness/providers/index.js +10 -3
- package/dist-server/harness/providers/zone.d.ts +96 -0
- package/dist-server/harness/providers/zone.js +112 -0
- package/dist-server/harness/render/answering-query.d.ts +29 -0
- package/dist-server/harness/render/answering-query.js +62 -0
- package/dist-server/harness/render/envelope.d.ts +6 -0
- package/dist-server/harness/render/envelope.js +10 -3
- package/dist-server/harness/route/adapter-spec.d.ts +8 -9
- package/dist-server/harness/route/adapter-spec.js +13 -14
- package/dist-server/harness/route/codex-ask-events.js +2 -1
- package/dist-server/harness/route/codex-ask.d.ts +4 -0
- package/dist-server/harness/route/codex-ask.js +69 -30
- package/dist-server/harness/route/codex-host-query.d.ts +52 -0
- package/dist-server/harness/route/codex-host-query.js +191 -0
- package/dist-server/harness/route/codex-local-manifest.d.ts +9 -1
- package/dist-server/harness/route/codex-local-manifest.js +96 -15
- package/dist-server/harness/route/codex-wren-proxy.d.ts +33 -0
- package/dist-server/harness/route/codex-wren-proxy.js +227 -0
- package/dist-server/harness/route/describe.js +45 -6
- package/dist-server/harness/route/in-process.d.ts +22 -1
- package/dist-server/harness/route/in-process.js +54 -4
- package/dist-server/harness/route/route.js +5 -2
- package/dist-server/harness/route/types.d.ts +30 -1
- package/dist-server/harness/session/run.js +30 -10
- package/dist-server/harness/setup/runner.d.ts +2 -0
- package/dist-server/harness/setup/runner.js +38 -17
- package/dist-server/harness/setup/yaml-scalar.d.ts +23 -0
- package/dist-server/harness/setup/yaml-scalar.js +62 -0
- package/dist-server/server/adopt.js +1 -17
- package/dist-server/server/app.d.ts +1 -0
- package/dist-server/server/app.js +163 -14
- package/dist-server/server/auth-choice.d.ts +13 -1
- package/dist-server/server/auth-choice.js +66 -1
- package/dist-server/server/bin.js +177 -25
- package/dist-server/server/codex-local-grounding.d.ts +18 -0
- package/dist-server/server/codex-local-grounding.js +92 -0
- package/dist-server/server/codex-native-session.d.ts +25 -0
- package/dist-server/server/codex-native-session.js +1 -0
- package/dist-server/server/codex-runtime-composition.d.ts +34 -0
- package/dist-server/server/codex-runtime-composition.js +250 -0
- package/dist-server/server/codex-structured-ask.d.ts +23 -0
- package/dist-server/server/codex-structured-ask.js +102 -0
- package/dist-server/server/conn-config.js +4 -16
- package/dist-server/server/conversation-socket.d.ts +16 -0
- package/dist-server/server/conversation-socket.js +65 -0
- package/dist-server/server/db.d.ts +46 -0
- package/dist-server/server/db.js +88 -9
- package/dist-server/server/env-detect.d.ts +6 -0
- package/dist-server/server/env-detect.js +7 -0
- package/dist-server/server/fold.d.ts +22 -4
- package/dist-server/server/fold.js +37 -5
- package/dist-server/server/harness.d.ts +2 -2
- package/dist-server/server/harness.js +33 -7
- package/dist-server/server/interactive-terminal.d.ts +10 -6
- package/dist-server/server/interactive-terminal.js +33 -8
- package/dist-server/server/managed-wren-runtime.d.ts +116 -0
- package/dist-server/server/managed-wren-runtime.js +670 -0
- package/dist-server/server/native-artifacts.d.ts +23 -7
- package/dist-server/server/native-artifacts.js +43 -12
- package/dist-server/server/native-component-context.d.ts +19 -0
- package/dist-server/server/native-component-context.js +76 -0
- package/dist-server/server/native-component-preparation.d.ts +20 -0
- package/dist-server/server/native-component-preparation.js +129 -0
- package/dist-server/server/native-component-runtime.d.ts +36 -0
- package/dist-server/server/native-component-runtime.js +92 -0
- package/dist-server/server/native-components.d.ts +84 -0
- package/dist-server/server/native-components.js +160 -0
- package/dist-server/server/native-dispatch-process.d.ts +8 -0
- package/dist-server/server/native-dispatch-process.js +65 -0
- package/dist-server/server/native-runtime-spec.d.ts +89 -0
- package/dist-server/server/native-runtime-spec.js +169 -0
- package/dist-server/server/native-sessions.d.ts +172 -19
- package/dist-server/server/native-sessions.js +839 -244
- package/dist-server/server/native-shutdown.d.ts +6 -0
- package/dist-server/server/native-shutdown.js +28 -0
- package/dist-server/server/native-wren-home.d.ts +18 -0
- package/dist-server/server/native-wren-home.js +262 -0
- package/dist-server/server/node-pty-host.d.ts +2 -1
- package/dist-server/server/node-pty-host.js +3 -2
- package/dist-server/server/profile-registry.d.ts +139 -0
- package/dist-server/server/profile-registry.js +620 -0
- package/dist-server/server/runtime-binding.d.ts +4 -1
- package/dist-server/server/runtime-binding.js +50 -2
- package/dist-server/server/runtime-host/claude-component-step.d.ts +25 -0
- package/dist-server/server/runtime-host/claude-component-step.js +186 -0
- package/dist-server/server/runtime-host/codex-app-server.d.ts +75 -0
- package/dist-server/server/runtime-host/codex-app-server.js +239 -0
- package/dist-server/server/runtime-host/codex-compatibility.d.ts +110 -0
- package/dist-server/server/runtime-host/codex-compatibility.js +162 -0
- package/dist-server/server/runtime-host/codex-component-step.d.ts +19 -0
- package/dist-server/server/runtime-host/codex-component-step.js +308 -0
- package/dist-server/server/runtime-host/codex-conversation.d.ts +109 -0
- package/dist-server/server/runtime-host/codex-conversation.js +295 -0
- package/dist-server/server/runtime-host/codex-direct-tools.d.ts +23 -0
- package/dist-server/server/runtime-host/codex-direct-tools.js +59 -0
- package/dist-server/server/runtime-host/codex-events.d.ts +647 -0
- package/dist-server/server/runtime-host/codex-events.js +66 -0
- package/dist-server/server/runtime-host/codex-policy.d.ts +16 -0
- package/dist-server/server/runtime-host/codex-policy.js +151 -0
- package/dist-server/server/runtime-host/codex-process.d.ts +8 -0
- package/dist-server/server/runtime-host/codex-process.js +96 -0
- package/dist-server/server/runtime-host/codex-rpc.d.ts +47 -0
- package/dist-server/server/runtime-host/codex-rpc.js +182 -0
- package/dist-server/server/runtime-host/codex-session.d.ts +74 -0
- package/dist-server/server/runtime-host/codex-session.js +492 -0
- package/dist-server/server/runtime-host/codex-terminal-protocol.d.ts +35 -0
- package/dist-server/server/runtime-host/codex-terminal-protocol.js +243 -0
- package/dist-server/server/runtime-host/codex-terminal.d.ts +16 -0
- package/dist-server/server/runtime-host/codex-terminal.js +120 -0
- package/dist-server/server/runtime-host/index.d.ts +5 -0
- package/dist-server/server/runtime-host/index.js +3 -0
- package/dist-server/server/runtime-host/local.d.ts +29 -0
- package/dist-server/server/runtime-host/local.js +90 -0
- package/dist-server/server/runtime-host/policy.d.ts +8 -0
- package/dist-server/server/runtime-host/policy.js +78 -0
- package/dist-server/server/runtime-host/types.d.ts +52 -0
- package/dist-server/server/runtime-host/types.js +62 -0
- package/dist-server/server/structured-query-evidence.d.ts +7 -0
- package/dist-server/server/structured-query-evidence.js +47 -0
- package/dist-server/server/structured-runtime.d.ts +52 -0
- package/dist-server/server/structured-runtime.js +130 -0
- package/dist-server/server/structured-scope.d.ts +4 -0
- package/dist-server/server/structured-scope.js +12 -0
- package/dist-server/server/turn.d.ts +6 -1
- package/dist-server/server/turn.js +82 -25
- package/dist-server/server/wire-types.d.ts +67 -3
- package/dist-server/server/wren-profiles.js +1 -1
- package/managed-wren/README.md +60 -0
- package/managed-wren/dependency-wheels.json +282 -0
- package/managed-wren/manifest.json +373 -0
- package/managed-wren/release-inputs.json +45 -0
- package/managed-wren/runtime-tree.cjs +115 -0
- package/managed-wren/source-inputs.json +40 -0
- package/package.json +15 -6
- package/profiles/genbi-default/context/binding.yml +17 -7
- package/profiles/genbi-default/context/context.json +146 -0
- package/profiles/genbi-default/ir.golden.json +39 -43
- package/profiles/genbi-default/profile.yml +31 -0
- package/profiles/genbi-enrich-context/context/binding.yml +14 -3
- package/profiles/genbi-enrich-context/context/context.json +146 -0
- package/profiles/genbi-enrich-context/ir.golden.json +4 -5
- package/profiles/genbi-monitor/context/binding.yml +13 -5
- package/profiles/genbi-monitor/context/context.json +146 -0
- package/profiles/genbi-monitor/ir.golden.json +13 -7
- package/profiles/genbi-report/context/binding.yml +19 -0
- package/profiles/genbi-report/context/context.json +223 -0
- package/profiles/genbi-report/ir.golden.json +328 -0
- package/profiles/genbi-report/profile.yml +38 -0
- package/profiles/genbi-setup/ir.golden.json +3 -1
- package/dist/assets/index-Xs4q7pNo.css +0 -1
|
@@ -1,27 +1,44 @@
|
|
|
1
|
-
import { cp, readFile, writeFile } from "node:fs/promises";
|
|
1
|
+
import { cp, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { PathTraversalError } from "../exec/index.js";
|
|
4
|
+
import { generatePreparedContext } from "./context-loader.js";
|
|
4
5
|
import { InvalidProfileShapeError } from "./errors.js";
|
|
5
6
|
/**
|
|
6
|
-
* Copies `profileSource` into `destDir
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* Copies `profileSource` into `destDir` and rebinds its context to `userProject`, producing a
|
|
8
|
+
* composed profile directory that is safe to pass straight to `warble compile`.
|
|
9
|
+
*
|
|
10
|
+
* The profile's context binding is a **prepared** binding (`kind: prepared`): Warble does not read
|
|
11
|
+
* the user's semantic layer itself, it reads a JSON *document* that WrenAI's own generator
|
|
12
|
+
* (`wren-context-loader`) produces. So rebinding is two writes, not one:
|
|
13
|
+
*
|
|
14
|
+
* 1. Run the generator over `userProject` and write its document over the profile's committed
|
|
15
|
+
* fixture document, at the path the binding's `document:` field already names.
|
|
16
|
+
* 2. Rewrite the binding's `project:` line to `userProject` (absolute).
|
|
17
|
+
*
|
|
18
|
+
* `project:` stays the layer's **identity** and never becomes the document path. That exact
|
|
19
|
+
* substitution shipped once in Warble and put the filename into every compiled prompt, telling the
|
|
20
|
+
* agent it was working on a project called `context.json`; Warble now guards against it, and this
|
|
21
|
+
* side must not hand it a binding that tries.
|
|
22
|
+
*
|
|
23
|
+
* Because the generated document is written *to the path the binding already declares*, `document:`
|
|
24
|
+
* needs no rewriting at all — the composed binding differs from the committed one only in
|
|
25
|
+
* `project:`. Note that `document:` (like `project:`) resolves relative to the **Warble project
|
|
26
|
+
* root** (the composed directory), not relative to the binding file that declares it.
|
|
9
27
|
*
|
|
10
28
|
* The binding file to rewrite is *not* hardcoded to `context/binding.yml` — it's read from the
|
|
11
29
|
* copied `profile.yml`'s own `context: project: <path>` pointer (the documented Warble mechanism:
|
|
12
30
|
* "profile mounts context via `context: project: <path-to-binding.yml>`"), so this works for any
|
|
13
|
-
* profile following that shape, not just `genbi-default`.
|
|
14
|
-
* the composed directory: a `../`-laden pointer that escapes it is a
|
|
15
|
-
* (reusing the exec module's shared traversal error rather than
|
|
16
|
-
* host file).
|
|
31
|
+
* profile following that shape, not just `genbi-default`. Both the binding path and the resolved
|
|
32
|
+
* document path are confined to the composed directory: a `../`-laden pointer that escapes it is a
|
|
33
|
+
* loud {@link PathTraversalError} (reusing the exec module's shared traversal error rather than
|
|
34
|
+
* reading/overwriting an arbitrary host file).
|
|
17
35
|
*
|
|
18
|
-
* Both `profile.yml` and the binding file are small, flat YAML where only a
|
|
19
|
-
*
|
|
20
|
-
* dependency for that.
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* revisiting.
|
|
36
|
+
* Both `profile.yml` and the binding file are small, flat YAML where only a few scalars matter here
|
|
37
|
+
* — regex extraction/rewrite is used deliberately instead of pulling in a full YAML parser
|
|
38
|
+
* dependency for that. Every lookup asserts *exactly one* match and loud-fails on zero or multiple
|
|
39
|
+
* (a duplicate top-level `project:` would otherwise leave a stale line that last-key-wins YAML
|
|
40
|
+
* parsing could silently bind to the wrong project). If a Warble profile ever grows a more
|
|
41
|
+
* elaborate `context:` block (e.g. multiple context sources), this needs revisiting.
|
|
25
42
|
*/
|
|
26
43
|
export async function composeUserProfile(options) {
|
|
27
44
|
const profileSourceAbs = path.resolve(options.profileSource);
|
|
@@ -33,21 +50,26 @@ export async function composeUserProfile(options) {
|
|
|
33
50
|
const bindingRelPath = extractContextBindingPath(profileYamlText, profileYamlPath);
|
|
34
51
|
const bindingPath = resolveWithinComposedDir(composedDir, bindingRelPath);
|
|
35
52
|
const bindingText = await readFile(bindingPath, "utf-8");
|
|
53
|
+
assertPreparedBindingKind(bindingText, bindingPath);
|
|
54
|
+
const documentRelPath = extractBindingDocumentPath(bindingText, bindingPath);
|
|
55
|
+
const documentPath = resolveWithinComposedDir(composedDir, documentRelPath);
|
|
56
|
+
await mkdir(path.dirname(documentPath), { recursive: true });
|
|
57
|
+
await generatePreparedContext(options.contextLoaderBin, userProjectAbs, documentPath);
|
|
36
58
|
const rewritten = rewriteContextBindingProject(bindingText, userProjectAbs, bindingPath);
|
|
37
59
|
await writeFile(bindingPath, rewritten, "utf-8");
|
|
38
60
|
return composedDir;
|
|
39
61
|
}
|
|
40
62
|
/**
|
|
41
|
-
* Resolves `
|
|
63
|
+
* Resolves `relPath` against `composedDir` and rejects anything that escapes it. Mirrors the
|
|
42
64
|
* containment check `harness/exec/local.ts`'s (private) `resolveWithinScope` performs, reusing its
|
|
43
65
|
* exported {@link PathTraversalError} — kept as a local check here so the fix stays within this
|
|
44
66
|
* module rather than widening the exec module's public surface.
|
|
45
67
|
*/
|
|
46
|
-
function resolveWithinComposedDir(composedDir,
|
|
47
|
-
const targetAbs = path.resolve(composedDir,
|
|
68
|
+
function resolveWithinComposedDir(composedDir, relPath) {
|
|
69
|
+
const targetAbs = path.resolve(composedDir, relPath);
|
|
48
70
|
const relative = path.relative(composedDir, targetAbs);
|
|
49
71
|
if (relative.startsWith("..") || path.isAbsolute(relative)) {
|
|
50
|
-
throw new PathTraversalError(
|
|
72
|
+
throw new PathTraversalError(relPath, composedDir);
|
|
51
73
|
}
|
|
52
74
|
return targetAbs;
|
|
53
75
|
}
|
|
@@ -71,6 +93,50 @@ export function extractContextBindingPath(profileYamlText, sourcePath) {
|
|
|
71
93
|
}
|
|
72
94
|
return unquoted;
|
|
73
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Asserts the binding declares exactly one top-level `kind: prepared`.
|
|
98
|
+
*
|
|
99
|
+
* A **missing** `kind:` is rejected rather than tolerated. Omitting it selects Warble's serde
|
|
100
|
+
* default (`wren_project`), i.e. Warble's own built-in MDL adapter — so a binding without the line
|
|
101
|
+
* would compile perfectly well while quietly ignoring the document this function's caller just
|
|
102
|
+
* generated. Since Warble emits neither `kind` nor `document` into the IR, that divergence is
|
|
103
|
+
* invisible in the compiled artifact; the only place it can be caught is here.
|
|
104
|
+
*/
|
|
105
|
+
export function assertPreparedBindingKind(bindingText, sourcePath) {
|
|
106
|
+
const matches = [...bindingText.matchAll(/^kind:[ \t]*(\S+)[ \t]*$/gm)];
|
|
107
|
+
if (matches.length === 0) {
|
|
108
|
+
throw new InvalidProfileShapeError(`"${sourcePath}" declares no top-level "kind:" — a context binding rebound to a user project must ` +
|
|
109
|
+
`declare "kind: prepared" (omitting it selects Warble's built-in "wren_project" adapter, which ` +
|
|
110
|
+
`would silently ignore the generated prepared-context document)`);
|
|
111
|
+
}
|
|
112
|
+
if (matches.length > 1) {
|
|
113
|
+
throw new InvalidProfileShapeError(`"${sourcePath}" has ${matches.length} top-level "kind:" fields — expected exactly one (ambiguous binding)`);
|
|
114
|
+
}
|
|
115
|
+
const kind = stripSurroundingQuotes(matches[0]?.[1] ?? "");
|
|
116
|
+
if (kind !== "prepared") {
|
|
117
|
+
throw new InvalidProfileShapeError(`"${sourcePath}" declares "kind: ${kind}" — a context binding rebound to a user project must declare ` +
|
|
118
|
+
`"kind: prepared"`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Extracts the single top-level `document: <path>` field naming where the prepared-context document
|
|
123
|
+
* lives, relative to the Warble project root (NOT to the binding file's own directory).
|
|
124
|
+
*/
|
|
125
|
+
export function extractBindingDocumentPath(bindingText, sourcePath) {
|
|
126
|
+
const matches = [...bindingText.matchAll(/^document:[ \t]*(\S+)[ \t]*$/gm)];
|
|
127
|
+
if (matches.length === 0) {
|
|
128
|
+
throw new InvalidProfileShapeError(`"${sourcePath}" has no top-level "document:" field — a "kind: prepared" binding must name the ` +
|
|
129
|
+
`prepared-context document it reads`);
|
|
130
|
+
}
|
|
131
|
+
if (matches.length > 1) {
|
|
132
|
+
throw new InvalidProfileShapeError(`"${sourcePath}" has ${matches.length} top-level "document:" fields — expected exactly one (ambiguous binding)`);
|
|
133
|
+
}
|
|
134
|
+
const unquoted = stripSurroundingQuotes(matches[0]?.[1] ?? "");
|
|
135
|
+
if (unquoted.length === 0) {
|
|
136
|
+
throw new InvalidProfileShapeError(`"${sourcePath}" has an empty "document:" field`);
|
|
137
|
+
}
|
|
138
|
+
return unquoted;
|
|
139
|
+
}
|
|
74
140
|
/**
|
|
75
141
|
* Replaces the single top-level `project:` line in a context-binding YAML's text, preserving
|
|
76
142
|
* surrounding comments. Asserts exactly one top-level `project:` — a second one would survive the
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export interface ResolvedContextLoader {
|
|
2
|
+
readonly bin: string;
|
|
3
|
+
readonly kind: "explicit" | "in-repo" | "package";
|
|
4
|
+
/** Package resolution is already digest-verified. Development modes use the binary hash below. */
|
|
5
|
+
readonly verifiedIdentity?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Resolves the `wren-context-loader` binary — the generator that renders a wren project as the
|
|
9
|
+
* prepared-context document a `kind: prepared` binding reads.
|
|
10
|
+
*
|
|
11
|
+
* Three deterministic tiers, then a loud failure:
|
|
12
|
+
*
|
|
13
|
+
* 1. `explicit`, else the `WREN_HARNESS_CONTEXT_LOADER_BIN` environment variable. Either must
|
|
14
|
+
* exist on disk; neither falls through to a search.
|
|
15
|
+
* 2. This repo's own build of the generator crate, found by walking up from this package looking
|
|
16
|
+
* for `core/wren-context-loader/target/{release,debug}/wren-context-loader`. `release` wins
|
|
17
|
+
* when both exist, so a stale `debug` build never shadows a deliberate release build.
|
|
18
|
+
* 3. The verified package-local binary from the exact `@wrenai/context-loader` dependency. Its
|
|
19
|
+
* install record must match package version and target, name the canonical binary, and pass a
|
|
20
|
+
* fresh SHA-256 check. Resolution never downloads at runtime.
|
|
21
|
+
*
|
|
22
|
+
* There is deliberately **no** `PATH` tier and — more importantly — **no fallback to the old
|
|
23
|
+
* `wren_project` binding**. A fallback would make the extraction unverifiable: a compiled IR is
|
|
24
|
+
* byte-identical whichever path produced it (Warble emits neither `kind` nor `document` into the
|
|
25
|
+
* IR), so a silent degrade would be undetectable from the artifact alone. Failing loudly is the
|
|
26
|
+
* only way the caller can know which path ran.
|
|
27
|
+
*
|
|
28
|
+
* Throws {@link ContextLoaderNotFoundError} with the accumulated attempts when neither tier works.
|
|
29
|
+
*/
|
|
30
|
+
export declare function resolveContextLoader(explicit?: string): ResolvedContextLoader;
|
|
31
|
+
/** Backward-compatible path-only API for callers that do not need cache provenance. */
|
|
32
|
+
export declare function resolveContextLoaderBinary(explicit?: string): string;
|
|
33
|
+
/** Stable cache identity: resolver kind plus either a verified package tuple or the dev binary's bytes. */
|
|
34
|
+
export declare function getContextLoaderIdentity(resolved: ResolvedContextLoader): string;
|
|
35
|
+
/** Validates a package-local installation record without resolving it from the host environment. */
|
|
36
|
+
export declare function readVerifiedContextLoaderPackage(packageRoot: string, target?: string): ResolvedContextLoader | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* Runs the generator over `projectDir`, writing the prepared-context document to `outPath`.
|
|
39
|
+
*
|
|
40
|
+
* An *unreadable* project is not an error here: the generator writes `parseable: false` with the
|
|
41
|
+
* assembly error attached and exits 0, because "this layer could not be assembled" is a fact about
|
|
42
|
+
* the project that Warble's `mdl_parseable` precondition exists to report. Only a genuinely
|
|
43
|
+
* unusable invocation (a path that is not a directory, an unwritable output) exits non-zero, and
|
|
44
|
+
* that surfaces as {@link ContextLoaderFailedError}.
|
|
45
|
+
*
|
|
46
|
+
* Shells with `execFile` (argv array, no shell interpolation), matching the convention `runWarble`
|
|
47
|
+
* and `harness/exec/local.ts` already use.
|
|
48
|
+
*/
|
|
49
|
+
export declare function generatePreparedContext(bin: string, projectDir: string, outPath: string, signal?: AbortSignal): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Runs the generator over `projectDir` writing both the prepared-context document (`outPath`) and
|
|
52
|
+
* the **capability catalog** (`catalogPath`): the authored, descriptive, SQL-free slice of the
|
|
53
|
+
* project that `buildCapabilityCard` renders for a planner outside the data zone. One process,
|
|
54
|
+
* one read of the project, so the two documents can never describe different states of it.
|
|
55
|
+
*/
|
|
56
|
+
export declare function generatePreparedContextAndCatalog(bin: string, projectDir: string, outPath: string, catalogPath: string, signal?: AbortSignal): Promise<void>;
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { existsSync, lstatSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { ContextLoaderFailedError, ContextLoaderNotFoundError } from "./errors.js";
|
|
7
|
+
import { resolveInstalledPackageRoot } from "../npm-package-resolve.js";
|
|
8
|
+
/** Environment override for {@link resolveContextLoaderBinary}, named like the other `WREN_HARNESS_*` binary overrides. */
|
|
9
|
+
const CONTEXT_LOADER_BIN_ENV = "WREN_HARNESS_CONTEXT_LOADER_BIN";
|
|
10
|
+
/** The generator's crate-relative build outputs, most-preferred first. */
|
|
11
|
+
const IN_REPO_BUILD_PATHS = [
|
|
12
|
+
["core", "wren-context-loader", "target", "release", "wren-context-loader"],
|
|
13
|
+
["core", "wren-context-loader", "target", "debug", "wren-context-loader"],
|
|
14
|
+
];
|
|
15
|
+
/**
|
|
16
|
+
* A generous ceiling for a step that reads a semantic layer off local disk and writes one JSON
|
|
17
|
+
* document — guards against a hang, not meant to ever fire in normal operation.
|
|
18
|
+
*/
|
|
19
|
+
const CONTEXT_LOADER_TIMEOUT_MS = 60 * 1000;
|
|
20
|
+
const CONTEXT_LOADER_PACKAGE = "@wrenai/context-loader";
|
|
21
|
+
const CANONICAL_PACKAGE_BINARY = path.join("bin", "wren-context-loader");
|
|
22
|
+
/**
|
|
23
|
+
* Resolves the `wren-context-loader` binary — the generator that renders a wren project as the
|
|
24
|
+
* prepared-context document a `kind: prepared` binding reads.
|
|
25
|
+
*
|
|
26
|
+
* Three deterministic tiers, then a loud failure:
|
|
27
|
+
*
|
|
28
|
+
* 1. `explicit`, else the `WREN_HARNESS_CONTEXT_LOADER_BIN` environment variable. Either must
|
|
29
|
+
* exist on disk; neither falls through to a search.
|
|
30
|
+
* 2. This repo's own build of the generator crate, found by walking up from this package looking
|
|
31
|
+
* for `core/wren-context-loader/target/{release,debug}/wren-context-loader`. `release` wins
|
|
32
|
+
* when both exist, so a stale `debug` build never shadows a deliberate release build.
|
|
33
|
+
* 3. The verified package-local binary from the exact `@wrenai/context-loader` dependency. Its
|
|
34
|
+
* install record must match package version and target, name the canonical binary, and pass a
|
|
35
|
+
* fresh SHA-256 check. Resolution never downloads at runtime.
|
|
36
|
+
*
|
|
37
|
+
* There is deliberately **no** `PATH` tier and — more importantly — **no fallback to the old
|
|
38
|
+
* `wren_project` binding**. A fallback would make the extraction unverifiable: a compiled IR is
|
|
39
|
+
* byte-identical whichever path produced it (Warble emits neither `kind` nor `document` into the
|
|
40
|
+
* IR), so a silent degrade would be undetectable from the artifact alone. Failing loudly is the
|
|
41
|
+
* only way the caller can know which path ran.
|
|
42
|
+
*
|
|
43
|
+
* Throws {@link ContextLoaderNotFoundError} with the accumulated attempts when neither tier works.
|
|
44
|
+
*/
|
|
45
|
+
export function resolveContextLoader(explicit) {
|
|
46
|
+
const override = explicit ?? process.env[CONTEXT_LOADER_BIN_ENV];
|
|
47
|
+
if (override !== undefined && override.length > 0) {
|
|
48
|
+
if (!existsSync(override)) {
|
|
49
|
+
const source = explicit !== undefined ? `explicit contextLoaderBin` : CONTEXT_LOADER_BIN_ENV;
|
|
50
|
+
throw new ContextLoaderNotFoundError([`${source} "${override}" does not exist`]);
|
|
51
|
+
}
|
|
52
|
+
return { bin: override, kind: "explicit" };
|
|
53
|
+
}
|
|
54
|
+
const inRepo = findInRepoBuild();
|
|
55
|
+
if (inRepo !== undefined)
|
|
56
|
+
return { bin: inRepo, kind: "in-repo" };
|
|
57
|
+
const packaged = resolveVerifiedPackageBinary();
|
|
58
|
+
if (packaged !== undefined)
|
|
59
|
+
return packaged;
|
|
60
|
+
throw new ContextLoaderNotFoundError([
|
|
61
|
+
`${CONTEXT_LOADER_BIN_ENV} is not set`,
|
|
62
|
+
`no in-repo build found (searched ancestors of this package for ` +
|
|
63
|
+
IN_REPO_BUILD_PATHS.map((segments) => `"${path.join(...segments)}"`).join(" and ") +
|
|
64
|
+
`) — ${CONTEXT_LOADER_PACKAGE} is not installed with a verified ${targetForCurrentPlatform()} binary`,
|
|
65
|
+
]);
|
|
66
|
+
}
|
|
67
|
+
/** Backward-compatible path-only API for callers that do not need cache provenance. */
|
|
68
|
+
export function resolveContextLoaderBinary(explicit) {
|
|
69
|
+
return resolveContextLoader(explicit).bin;
|
|
70
|
+
}
|
|
71
|
+
/** Stable cache identity: resolver kind plus either a verified package tuple or the dev binary's bytes. */
|
|
72
|
+
export function getContextLoaderIdentity(resolved) {
|
|
73
|
+
if (resolved.verifiedIdentity !== undefined)
|
|
74
|
+
return resolved.verifiedIdentity;
|
|
75
|
+
return `${resolved.kind}:${createHash("sha256").update(readFileSync(resolved.bin)).digest("hex")}`;
|
|
76
|
+
}
|
|
77
|
+
function resolveVerifiedPackageBinary() {
|
|
78
|
+
const packageRoot = resolveInstalledPackageRoot(CONTEXT_LOADER_PACKAGE);
|
|
79
|
+
if (packageRoot === undefined)
|
|
80
|
+
return undefined;
|
|
81
|
+
return readVerifiedContextLoaderPackage(packageRoot);
|
|
82
|
+
}
|
|
83
|
+
/** Validates a package-local installation record without resolving it from the host environment. */
|
|
84
|
+
export function readVerifiedContextLoaderPackage(packageRoot, target = targetForCurrentPlatform()) {
|
|
85
|
+
try {
|
|
86
|
+
const root = physicalPackageRoot(packageRoot);
|
|
87
|
+
if (root === undefined)
|
|
88
|
+
return undefined;
|
|
89
|
+
const packageJson = readVerifiedJson(root, "package.json");
|
|
90
|
+
const manifest = readVerifiedJson(root, "artifacts.json");
|
|
91
|
+
const state = readVerifiedJson(root, "install-state.json");
|
|
92
|
+
if (packageJson === undefined || manifest === undefined || state === undefined)
|
|
93
|
+
return undefined;
|
|
94
|
+
const artifacts = typeof manifest.artifacts === "object" && manifest.artifacts !== null ? manifest.artifacts : undefined;
|
|
95
|
+
const artifact = artifacts?.[target];
|
|
96
|
+
const bin = physicalRegularFile(root, CANONICAL_PACKAGE_BINARY);
|
|
97
|
+
if (packageJson.name !== CONTEXT_LOADER_PACKAGE ||
|
|
98
|
+
typeof packageJson.version !== "string" ||
|
|
99
|
+
manifest.schema !== 1 ||
|
|
100
|
+
manifest.package !== CONTEXT_LOADER_PACKAGE ||
|
|
101
|
+
manifest.version !== packageJson.version ||
|
|
102
|
+
!isArtifact(artifact) ||
|
|
103
|
+
state.package !== CONTEXT_LOADER_PACKAGE ||
|
|
104
|
+
state.version !== packageJson.version ||
|
|
105
|
+
state.target !== target ||
|
|
106
|
+
state.binaryPath !== CANONICAL_PACKAGE_BINARY ||
|
|
107
|
+
state.archiveSha256 !== artifact.archiveSha256 ||
|
|
108
|
+
state.binarySha256 !== artifact.binarySha256 ||
|
|
109
|
+
bin === undefined ||
|
|
110
|
+
createHash("sha256").update(readFileSync(bin)).digest("hex") !== artifact.binarySha256) {
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
return { bin, kind: "package", verifiedIdentity: `package:${CONTEXT_LOADER_PACKAGE}@${packageJson.version}:${target}:${artifact.binarySha256}` };
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return undefined;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function readVerifiedJson(root, relativePath) {
|
|
120
|
+
const file = physicalRegularFile(root, relativePath);
|
|
121
|
+
if (file === undefined)
|
|
122
|
+
return undefined;
|
|
123
|
+
try {
|
|
124
|
+
const value = JSON.parse(readFileSync(file, "utf8"));
|
|
125
|
+
return typeof value === "object" && value !== null ? value : undefined;
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function isSha256(value) {
|
|
132
|
+
return typeof value === "string" && /^[a-f0-9]{64}$/u.test(value);
|
|
133
|
+
}
|
|
134
|
+
function isArtifact(value) {
|
|
135
|
+
if (typeof value !== "object" || value === null)
|
|
136
|
+
return false;
|
|
137
|
+
const artifact = value;
|
|
138
|
+
return (typeof artifact.url === "string" &&
|
|
139
|
+
artifact.url.startsWith("https://") &&
|
|
140
|
+
isSha256(artifact.archiveSha256) &&
|
|
141
|
+
isSha256(artifact.binarySha256) &&
|
|
142
|
+
typeof artifact.binaryPath === "string" &&
|
|
143
|
+
!artifact.binaryPath.includes("..") &&
|
|
144
|
+
!path.isAbsolute(artifact.binaryPath));
|
|
145
|
+
}
|
|
146
|
+
/** Returns a package-owned physical root; package-root symlinks are never trusted. */
|
|
147
|
+
function physicalPackageRoot(packageRoot) {
|
|
148
|
+
try {
|
|
149
|
+
if (!lstatSync(packageRoot).isDirectory())
|
|
150
|
+
return undefined;
|
|
151
|
+
return realpathSync(packageRoot);
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/** Refuses final-file links and any ancestor link that resolves outside the physical package root. */
|
|
158
|
+
function physicalRegularFile(root, relativePath) {
|
|
159
|
+
const lexical = path.resolve(root, relativePath);
|
|
160
|
+
if (!lexical.startsWith(`${root}${path.sep}`))
|
|
161
|
+
return undefined;
|
|
162
|
+
try {
|
|
163
|
+
if (!lstatSync(lexical).isFile())
|
|
164
|
+
return undefined;
|
|
165
|
+
const physical = realpathSync(lexical);
|
|
166
|
+
return physical.startsWith(`${root}${path.sep}`) && statSync(physical).isFile() ? physical : undefined;
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
return undefined;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function targetForCurrentPlatform() {
|
|
173
|
+
return `${process.platform}-${process.arch}`;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Walks up from this package's own directory (`harness/compile/` in source, `dist/compile/` once
|
|
177
|
+
* built — either way two levels below the package root), returning the first existing generator
|
|
178
|
+
* build. Mirrors the ancestor walk `resolveWarbleBinary`'s sibling-checkout tier uses, so this
|
|
179
|
+
* works from the main checkout or from a git worktree nested several levels under it.
|
|
180
|
+
*/
|
|
181
|
+
function findInRepoBuild() {
|
|
182
|
+
let dir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
183
|
+
const maxDepth = 10;
|
|
184
|
+
for (let i = 0; i < maxDepth; i += 1) {
|
|
185
|
+
for (const segments of IN_REPO_BUILD_PATHS) {
|
|
186
|
+
const candidate = path.join(dir, ...segments);
|
|
187
|
+
if (existsSync(candidate))
|
|
188
|
+
return candidate;
|
|
189
|
+
}
|
|
190
|
+
const parent = path.dirname(dir);
|
|
191
|
+
if (parent === dir)
|
|
192
|
+
break; // reached filesystem root
|
|
193
|
+
dir = parent;
|
|
194
|
+
}
|
|
195
|
+
return undefined;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Runs the generator over `projectDir`, writing the prepared-context document to `outPath`.
|
|
199
|
+
*
|
|
200
|
+
* An *unreadable* project is not an error here: the generator writes `parseable: false` with the
|
|
201
|
+
* assembly error attached and exits 0, because "this layer could not be assembled" is a fact about
|
|
202
|
+
* the project that Warble's `mdl_parseable` precondition exists to report. Only a genuinely
|
|
203
|
+
* unusable invocation (a path that is not a directory, an unwritable output) exits non-zero, and
|
|
204
|
+
* that surfaces as {@link ContextLoaderFailedError}.
|
|
205
|
+
*
|
|
206
|
+
* Shells with `execFile` (argv array, no shell interpolation), matching the convention `runWarble`
|
|
207
|
+
* and `harness/exec/local.ts` already use.
|
|
208
|
+
*/
|
|
209
|
+
export function generatePreparedContext(bin, projectDir, outPath, signal) {
|
|
210
|
+
return runContextLoader(bin, [projectDir, "-o", outPath], signal);
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Runs the generator over `projectDir` writing both the prepared-context document (`outPath`) and
|
|
214
|
+
* the **capability catalog** (`catalogPath`): the authored, descriptive, SQL-free slice of the
|
|
215
|
+
* project that `buildCapabilityCard` renders for a planner outside the data zone. One process,
|
|
216
|
+
* one read of the project, so the two documents can never describe different states of it.
|
|
217
|
+
*/
|
|
218
|
+
export function generatePreparedContextAndCatalog(bin, projectDir, outPath, catalogPath, signal) {
|
|
219
|
+
return runContextLoader(bin, [projectDir, "-o", outPath, "--catalog-out", catalogPath], signal);
|
|
220
|
+
}
|
|
221
|
+
function runContextLoader(bin, args, signal) {
|
|
222
|
+
return new Promise((resolve, reject) => {
|
|
223
|
+
execFile(bin, args, { maxBuffer: 32 * 1024 * 1024, timeout: CONTEXT_LOADER_TIMEOUT_MS, ...(signal ? { signal } : {}) }, (error, stdout, stderr) => {
|
|
224
|
+
if (error) {
|
|
225
|
+
const exitCode = typeof error.code === "number" ? error.code : 1;
|
|
226
|
+
const clarifiedStderr = stderr.length > 0
|
|
227
|
+
? stderr
|
|
228
|
+
: error.killed === true
|
|
229
|
+
? `wren-context-loader timed out after ${CONTEXT_LOADER_TIMEOUT_MS}ms`
|
|
230
|
+
: stderr;
|
|
231
|
+
reject(new ContextLoaderFailedError(bin, args, exitCode, clarifiedStderr, stdout));
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
resolve();
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
}
|
|
@@ -16,6 +16,25 @@ export declare class WarbleCommandFailedError extends Error {
|
|
|
16
16
|
readonly stdout: string;
|
|
17
17
|
constructor(command: string, args: readonly string[], exitCode: number, stderr: string, stdout?: string);
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Thrown by {@link resolveContextLoaderBinary} (see `./context-loader.js`) when the
|
|
21
|
+
* `wren-context-loader` generator can be found neither via an explicit override nor as an in-repo
|
|
22
|
+
* build. Deliberately loud, and deliberately *not* recoverable by falling back to the old
|
|
23
|
+
* `wren_project` binding: Warble emits neither `kind` nor `document` into the IR, so a silent
|
|
24
|
+
* degrade to the built-in MDL adapter would be invisible in the compiled artifact.
|
|
25
|
+
*/
|
|
26
|
+
export declare class ContextLoaderNotFoundError extends Error {
|
|
27
|
+
constructor(attempts: readonly string[]);
|
|
28
|
+
}
|
|
29
|
+
/** Thrown when the `wren-context-loader` subprocess exits non-zero. */
|
|
30
|
+
export declare class ContextLoaderFailedError extends Error {
|
|
31
|
+
readonly command: string;
|
|
32
|
+
readonly args: readonly string[];
|
|
33
|
+
readonly exitCode: number;
|
|
34
|
+
readonly stderr: string;
|
|
35
|
+
readonly stdout: string;
|
|
36
|
+
constructor(command: string, args: readonly string[], exitCode: number, stderr: string, stdout?: string);
|
|
37
|
+
}
|
|
19
38
|
/** Thrown when a Warble profile directory doesn't have the expected `profile.yml` / context-binding shape. */
|
|
20
39
|
export declare class InvalidProfileShapeError extends Error {
|
|
21
40
|
constructor(message: string);
|
|
@@ -32,6 +32,41 @@ export class WarbleCommandFailedError extends Error {
|
|
|
32
32
|
this.name = "WarbleCommandFailedError";
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Thrown by {@link resolveContextLoaderBinary} (see `./context-loader.js`) when the
|
|
37
|
+
* `wren-context-loader` generator can be found neither via an explicit override nor as an in-repo
|
|
38
|
+
* build. Deliberately loud, and deliberately *not* recoverable by falling back to the old
|
|
39
|
+
* `wren_project` binding: Warble emits neither `kind` nor `document` into the IR, so a silent
|
|
40
|
+
* degrade to the built-in MDL adapter would be invisible in the compiled artifact.
|
|
41
|
+
*/
|
|
42
|
+
export class ContextLoaderNotFoundError extends Error {
|
|
43
|
+
constructor(attempts) {
|
|
44
|
+
super(`could not resolve the "wren-context-loader" binary:\n` +
|
|
45
|
+
attempts.map((attempt) => ` - ${attempt}`).join("\n") +
|
|
46
|
+
`\nfix: install the exact @wrenai/context-loader package, build it in-repo from the repository root ` +
|
|
47
|
+
`("cargo build --release --manifest-path core/wren-context-loader/Cargo.toml") ` +
|
|
48
|
+
`or point WREN_HARNESS_CONTEXT_LOADER_BIN at an existing build.`);
|
|
49
|
+
this.name = "ContextLoaderNotFoundError";
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/** Thrown when the `wren-context-loader` subprocess exits non-zero. */
|
|
53
|
+
export class ContextLoaderFailedError extends Error {
|
|
54
|
+
command;
|
|
55
|
+
args;
|
|
56
|
+
exitCode;
|
|
57
|
+
stderr;
|
|
58
|
+
stdout;
|
|
59
|
+
constructor(command, args, exitCode, stderr, stdout = "") {
|
|
60
|
+
const diagnostics = [stderr.trim(), stdout.trim()].filter((chunk) => chunk.length > 0).join("\n");
|
|
61
|
+
super(`"${command} ${args.join(" ")}" exited ${exitCode}:\n${diagnostics || "(no output)"}`);
|
|
62
|
+
this.command = command;
|
|
63
|
+
this.args = args;
|
|
64
|
+
this.exitCode = exitCode;
|
|
65
|
+
this.stderr = stderr;
|
|
66
|
+
this.stdout = stdout;
|
|
67
|
+
this.name = "ContextLoaderFailedError";
|
|
68
|
+
}
|
|
69
|
+
}
|
|
35
70
|
/** Thrown when a Warble profile directory doesn't have the expected `profile.yml` / context-binding shape. */
|
|
36
71
|
export class InvalidProfileShapeError extends Error {
|
|
37
72
|
constructor(message) {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export { createFileSystemCompileCache, createInMemoryCompileCache, resolveDefaultCacheDir } from "./cache.js";
|
|
2
|
-
export { composeUserProfile, extractContextBindingPath, rewriteContextBindingProject } from "./compose-profile.js";
|
|
3
|
-
export {
|
|
2
|
+
export { assertPreparedBindingKind, composeUserProfile, extractBindingDocumentPath, extractContextBindingPath, rewriteContextBindingProject, } from "./compose-profile.js";
|
|
3
|
+
export { generatePreparedContext, generatePreparedContextAndCatalog, resolveContextLoaderBinary } from "./context-loader.js";
|
|
4
|
+
export { ContextLoaderFailedError, ContextLoaderNotFoundError, InvalidProfileShapeError, WarbleBinaryNotFoundError, WarbleCommandFailedError, } from "./errors.js";
|
|
4
5
|
export { hashDirectory, hashFiles } from "./fingerprint.js";
|
|
5
6
|
export { compileProfile, compileRawProfile, runWarble } from "./pipeline.js";
|
|
6
7
|
export { resolveHubDir, resolveWarbleBinary } from "./resolve-binary.js";
|
|
7
8
|
export type { CompileCache, CompileCacheEntry, CompileCacheKey, CompileMode, CompileProfileOptions, CompileProfileResult, CompileRawProfileOptions, } from "./types.js";
|
|
8
|
-
export { getWarbleIdentity } from "./warble-identity.js";
|
|
9
|
+
export { getBinaryIdentity, getWarbleIdentity } from "./warble-identity.js";
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export { createFileSystemCompileCache, createInMemoryCompileCache, resolveDefaultCacheDir } from "./cache.js";
|
|
2
|
-
export { composeUserProfile, extractContextBindingPath, rewriteContextBindingProject } from "./compose-profile.js";
|
|
3
|
-
export {
|
|
2
|
+
export { assertPreparedBindingKind, composeUserProfile, extractBindingDocumentPath, extractContextBindingPath, rewriteContextBindingProject, } from "./compose-profile.js";
|
|
3
|
+
export { generatePreparedContext, generatePreparedContextAndCatalog, resolveContextLoaderBinary } from "./context-loader.js";
|
|
4
|
+
export { ContextLoaderFailedError, ContextLoaderNotFoundError, InvalidProfileShapeError, WarbleBinaryNotFoundError, WarbleCommandFailedError, } from "./errors.js";
|
|
4
5
|
export { hashDirectory, hashFiles } from "./fingerprint.js";
|
|
5
6
|
export { compileProfile, compileRawProfile, runWarble } from "./pipeline.js";
|
|
6
7
|
export { resolveHubDir, resolveWarbleBinary } from "./resolve-binary.js";
|
|
7
|
-
export { getWarbleIdentity } from "./warble-identity.js";
|
|
8
|
+
export { getBinaryIdentity, getWarbleIdentity } from "./warble-identity.js";
|
|
@@ -12,6 +12,13 @@ export declare const DEFAULT_WREN_PROVIDER_PATH: string;
|
|
|
12
12
|
* mode — additionally `warble dispatch --target vercel` for the vercel bundle this package's
|
|
13
13
|
* `runAgent()` consumes.
|
|
14
14
|
*
|
|
15
|
+
* The rebind runs WrenAI's own `wren-context-loader` generator over `userProject` and binds its
|
|
16
|
+
* output as a `kind: prepared` document, so Warble reads a projection WrenAI produced rather than
|
|
17
|
+
* introspecting the semantic layer itself. Resolving that generator loud-fails
|
|
18
|
+
* ({@link ContextLoaderNotFoundError}) — there is no fallback to Warble's built-in `wren_project`
|
|
19
|
+
* adapter, because the compiled IR is byte-identical either way and a silent degrade would be
|
|
20
|
+
* undetectable from the artifact.
|
|
21
|
+
*
|
|
15
22
|
* A cache hit (see below) never *executes* `warble`, but by default DOES need to resolve + read
|
|
16
23
|
* the binary — its content hash and the Hub root derived from its location are both cache-key
|
|
17
24
|
* inputs (see `warbleIdentity` and `hubDir` below), so a hit can't be trusted without knowing which
|
|
@@ -26,13 +33,14 @@ export declare const DEFAULT_WREN_PROVIDER_PATH: string;
|
|
|
26
33
|
* the same no-shell, structured-result `execFile` convention `harness/exec/local.ts` already uses.
|
|
27
34
|
*
|
|
28
35
|
* Results are cached on (profile content hash x user-context fingerprint x mode x resolved
|
|
29
|
-
* provider-fragment content hash x warble binary identity x
|
|
30
|
-
* so an unchanged profile/context/providers/compiler/
|
|
31
|
-
* instead of recompiling. Folding in the
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
+
* provider-fragment content hash x warble binary identity x `wren-context-loader` binary identity x
|
|
37
|
+
* resolved Hub root) — see `./cache.js` — so an unchanged profile/context/providers/compiler/
|
|
38
|
+
* generator/Hub tuple returns the previous artifact instead of recompiling. Folding in the
|
|
39
|
+
* provider-fragment hash, warble identity, generator identity and Hub root (rather than just
|
|
40
|
+
* profile+context+mode) matters: otherwise a custom `options.providers` and this package's default
|
|
41
|
+
* fragment collide on the same key, and editing a provider fragment, rebuilding `warble`, rebuilding
|
|
42
|
+
* the generator, or compiling against a different component library would keep serving a stale
|
|
43
|
+
* artifact forever, since there's no TTL/eviction.
|
|
36
44
|
*
|
|
37
45
|
* The `warble` invocations run inside a temporary scratch directory (the composed profile + raw
|
|
38
46
|
* compiler output). When the cache relocates the artifacts to a durable home outside that scratch
|