@wrenai/genbi 0.0.4 → 0.0.6
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 +65 -3
- 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 +43 -45
- 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/describe.js +45 -6
- package/dist-server/harness/route/dispatched.d.ts +20 -0
- package/dist-server/harness/route/dispatched.js +122 -24
- package/dist-server/harness/route/host-query.d.ts +93 -0
- package/dist-server/harness/route/host-query.js +257 -0
- 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 +8 -2
- package/dist-server/harness/route/types.d.ts +47 -1
- package/dist-server/harness/route/wren-host-proxy.d.ts +33 -0
- package/dist-server/harness/route/wren-host-proxy.js +228 -0
- package/dist-server/harness/session/run.js +30 -10
- package/dist-server/harness/setup/runner.d.ts +17 -3
- package/dist-server/harness/setup/runner.js +272 -89
- package/dist-server/harness/setup/yaml-scalar.d.ts +23 -0
- package/dist-server/harness/setup/yaml-scalar.js +62 -0
- package/dist-server/harness/tools/setup-native.d.ts +7 -0
- package/dist-server/harness/tools/setup-native.js +7 -4
- package/dist-server/server/adopt.js +1 -17
- package/dist-server/server/app.d.ts +1 -0
- package/dist-server/server/app.js +175 -17
- 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 +185 -25
- 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 +23 -4
- package/dist-server/server/fold.js +42 -5
- package/dist-server/server/harness.d.ts +2 -2
- package/dist-server/server/harness.js +33 -7
- package/dist-server/server/host-evidence-grounding.d.ts +21 -0
- package/dist-server/server/host-evidence-grounding.js +93 -0
- 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 +112 -7
- package/dist-server/server/native-artifacts.js +194 -14
- 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 +86 -26
- 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
|
@@ -61,6 +61,7 @@ import { buildUniformTierBinding } from "../route/tier-binding.js";
|
|
|
61
61
|
import { createNativeToolRegistry, createSetupExecutionTool, SETUP_EXECUTION_TOOL_NAME } from "../tools/index.js";
|
|
62
62
|
import { withResolvedTools } from "../tools/wiring.js";
|
|
63
63
|
import { CodexSetupEventMapper } from "./codex-events.js";
|
|
64
|
+
import { readYamlScalarField } from "./yaml-scalar.js";
|
|
64
65
|
/** The warble component the setup wizard's connect step dispatches. */
|
|
65
66
|
export const CONNECT_SOURCE_AGENT_ID = "connect_source";
|
|
66
67
|
/** The Warble component the setup wizard's context step dispatches (`profiles/genbi-setup/components/build_context`). */
|
|
@@ -123,6 +124,22 @@ function resolveDispatchedUserProject(runOptions, agentId) {
|
|
|
123
124
|
}
|
|
124
125
|
return canonicalProject;
|
|
125
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* The project directory a project-bound step (`connect_resume`/`context`) runs
|
|
129
|
+
* against, as the default exec cwd of the in-process `setup_execution` tool.
|
|
130
|
+
* `undefined` for the initial `connect` step, which scaffolds the project from
|
|
131
|
+
* the workspace root, and for a missing/unsafe project name. The tool applies
|
|
132
|
+
* it only while the directory actually exists.
|
|
133
|
+
*/
|
|
134
|
+
function boundSetupProjectDir(runOptions, agentId) {
|
|
135
|
+
const stepKey = runOptions.stepKey ?? (agentId === BUILD_CONTEXT_AGENT_ID ? "context" : "connect");
|
|
136
|
+
if (stepKey === "connect")
|
|
137
|
+
return undefined;
|
|
138
|
+
const projectName = runOptions.projectName;
|
|
139
|
+
if (projectName === undefined || !SAFE_PROJECT_NAME.test(projectName))
|
|
140
|
+
return undefined;
|
|
141
|
+
return path.resolve(runOptions.workspaceRoot, projectName);
|
|
142
|
+
}
|
|
126
143
|
/**
|
|
127
144
|
* Dispatches a setup-wizard turn over dispatched, bypassing `route()` entirely
|
|
128
145
|
* (unlike the Ask turn path) so it can perform its own, setup-specific
|
|
@@ -142,6 +159,7 @@ export class DispatchedSetupRunner {
|
|
|
142
159
|
return resolveEffectiveMaxTurns(this.options.maxTurns, agentId);
|
|
143
160
|
}
|
|
144
161
|
async run(runOptions) {
|
|
162
|
+
runOptions.signal?.throwIfAborted();
|
|
145
163
|
const { authChoice } = runOptions;
|
|
146
164
|
const agentId = runOptions.agentId ?? CONNECT_SOURCE_AGENT_ID;
|
|
147
165
|
// Only build_context needs the raised turn budget — generating an MDL is
|
|
@@ -176,6 +194,7 @@ export class DispatchedSetupRunner {
|
|
|
176
194
|
...(modelsConfig !== undefined ? { modelsConfig } : {}),
|
|
177
195
|
...(maxTurns !== undefined ? { maxTurns } : {}),
|
|
178
196
|
...(runOptions.onEvent !== undefined ? { onEvent: runOptions.onEvent } : {}),
|
|
197
|
+
...(runOptions.signal !== undefined ? { signal: runOptions.signal } : {}),
|
|
179
198
|
...(runOptions.resumeSessionId !== undefined ? { resumeSessionId: runOptions.resumeSessionId } : {}),
|
|
180
199
|
});
|
|
181
200
|
return { finalText: result.finalText, ...(result.sessionId !== undefined ? { sessionId: result.sessionId } : {}) };
|
|
@@ -248,6 +267,7 @@ export class CodexSetupRunner {
|
|
|
248
267
|
this.options = options;
|
|
249
268
|
}
|
|
250
269
|
async run(runOptions) {
|
|
270
|
+
runOptions.signal?.throwIfAborted();
|
|
251
271
|
if (runOptions.authChoice.mode !== "subscription" || runOptions.authChoice.provider !== "codex") {
|
|
252
272
|
throw new Error("Codex setup runner requires a Codex subscription auth choice");
|
|
253
273
|
}
|
|
@@ -286,10 +306,9 @@ export class CodexSetupRunner {
|
|
|
286
306
|
"--server-arg=--workspace-root",
|
|
287
307
|
"--server-arg",
|
|
288
308
|
turnRoot,
|
|
289
|
-
"--
|
|
290
|
-
SETUP_EXECUTION_TOOL_NAME
|
|
291
|
-
"--
|
|
292
|
-
SETUP_EXECUTION_TOOL_NAME,
|
|
309
|
+
"--transport", "exec",
|
|
310
|
+
"--step-tool", `${agentId === CONNECT_SOURCE_AGENT_ID ? "connect" : "build"}=${SETUP_EXECUTION_TOOL_NAME}`,
|
|
311
|
+
"--require-tool", agentId === CONNECT_SOURCE_AGENT_ID ? "connect" : "build",
|
|
293
312
|
"--timeout",
|
|
294
313
|
String(timeoutMs),
|
|
295
314
|
...(this.options.codexBin ? ["--codex-bin", this.options.codexBin] : []),
|
|
@@ -299,7 +318,7 @@ export class CodexSetupRunner {
|
|
|
299
318
|
emitter.emit({ kind: "run.start", mode: "B", agentId });
|
|
300
319
|
const mapper = new CodexSetupEventMapper(tracePath);
|
|
301
320
|
try {
|
|
302
|
-
const rawFinalText = await spawnCodexSetup(cli.command, args, mapper, emitter.emit, timeoutMs + 5_000);
|
|
321
|
+
const rawFinalText = await spawnCodexSetup(cli.command, args, mapper, emitter.emit, timeoutMs + 5_000, runOptions.signal);
|
|
303
322
|
const finalText = unwrapCodexSetupEnvelope(rawFinalText, expectedProducedField);
|
|
304
323
|
emitter.emit({ kind: "run.finish", status: "answer" });
|
|
305
324
|
return { finalText };
|
|
@@ -325,8 +344,12 @@ function defaultCodexSetupMcpInvocation(tracePath) {
|
|
|
325
344
|
function sanitizedCodexSetupEnvironment() {
|
|
326
345
|
return Object.fromEntries(Object.entries(process.env).filter(([key, value]) => value !== undefined && !CODEX_BILLING_ENV_KEYS.has(key.toUpperCase())));
|
|
327
346
|
}
|
|
328
|
-
function spawnCodexSetup(command, args, mapper, emit, timeoutMs) {
|
|
347
|
+
function spawnCodexSetup(command, args, mapper, emit, timeoutMs, abortSignal) {
|
|
329
348
|
return new Promise((resolve, reject) => {
|
|
349
|
+
if (abortSignal?.aborted) {
|
|
350
|
+
reject(new Error("Codex setup cancelled"));
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
330
353
|
const child = spawn(command, [...args], {
|
|
331
354
|
env: sanitizedCodexSetupEnvironment(),
|
|
332
355
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -335,6 +358,7 @@ function spawnCodexSetup(command, args, mapper, emit, timeoutMs) {
|
|
|
335
358
|
let stderr = "";
|
|
336
359
|
let settled = false;
|
|
337
360
|
let timedOut = false;
|
|
361
|
+
let cancelled = false;
|
|
338
362
|
let killTimer;
|
|
339
363
|
const terminate = (signal) => {
|
|
340
364
|
if (child.pid !== undefined && process.platform !== "win32") {
|
|
@@ -348,7 +372,17 @@ function spawnCodexSetup(command, args, mapper, emit, timeoutMs) {
|
|
|
348
372
|
}
|
|
349
373
|
child.kill(signal);
|
|
350
374
|
};
|
|
375
|
+
const cancel = () => {
|
|
376
|
+
if (settled || cancelled || timedOut)
|
|
377
|
+
return;
|
|
378
|
+
cancelled = true;
|
|
379
|
+
terminate("SIGTERM");
|
|
380
|
+
killTimer = setTimeout(() => terminate("SIGKILL"), 1_000);
|
|
381
|
+
};
|
|
382
|
+
abortSignal?.addEventListener("abort", cancel, { once: true });
|
|
351
383
|
const timer = setTimeout(() => {
|
|
384
|
+
if (cancelled)
|
|
385
|
+
return;
|
|
352
386
|
timedOut = true;
|
|
353
387
|
terminate("SIGTERM");
|
|
354
388
|
killTimer = setTimeout(() => terminate("SIGKILL"), 1_000);
|
|
@@ -365,6 +399,7 @@ function spawnCodexSetup(command, args, mapper, emit, timeoutMs) {
|
|
|
365
399
|
catch (error) {
|
|
366
400
|
settled = true;
|
|
367
401
|
clearTimeout(timer);
|
|
402
|
+
abortSignal?.removeEventListener("abort", cancel);
|
|
368
403
|
terminate("SIGTERM");
|
|
369
404
|
killTimer = setTimeout(() => terminate("SIGKILL"), 1_000);
|
|
370
405
|
reject(error);
|
|
@@ -379,12 +414,14 @@ function spawnCodexSetup(command, args, mapper, emit, timeoutMs) {
|
|
|
379
414
|
return;
|
|
380
415
|
settled = true;
|
|
381
416
|
clearTimeout(timer);
|
|
417
|
+
abortSignal?.removeEventListener("abort", cancel);
|
|
382
418
|
if (killTimer)
|
|
383
419
|
clearTimeout(killTimer);
|
|
384
420
|
reject(new Error(`warble-codex-local failed to start: ${error.message}`));
|
|
385
421
|
});
|
|
386
422
|
child.on("close", (code, signal) => {
|
|
387
423
|
clearTimeout(timer);
|
|
424
|
+
abortSignal?.removeEventListener("abort", cancel);
|
|
388
425
|
lines.close();
|
|
389
426
|
// Do not cancel an already-scheduled process-group SIGKILL here. The
|
|
390
427
|
// direct dispatcher can exit on SIGTERM while one of its descendants
|
|
@@ -392,7 +429,10 @@ function spawnCodexSetup(command, args, mapper, emit, timeoutMs) {
|
|
|
392
429
|
if (settled)
|
|
393
430
|
return;
|
|
394
431
|
settled = true;
|
|
395
|
-
if (
|
|
432
|
+
if (cancelled) {
|
|
433
|
+
reject(new Error("Codex setup cancelled"));
|
|
434
|
+
}
|
|
435
|
+
else if (timedOut) {
|
|
396
436
|
reject(new Error(`warble-codex-local timed out after ${timeoutMs}ms`));
|
|
397
437
|
}
|
|
398
438
|
else if (code !== 0) {
|
|
@@ -483,6 +523,7 @@ export class InProcessSetupRunner {
|
|
|
483
523
|
return resolveEffectiveMaxTurns(this.options.maxTurns, agentId);
|
|
484
524
|
}
|
|
485
525
|
async run(runOptions) {
|
|
526
|
+
runOptions.signal?.throwIfAborted();
|
|
486
527
|
const { authChoice } = runOptions;
|
|
487
528
|
const agentId = runOptions.agentId ?? CONNECT_SOURCE_AGENT_ID;
|
|
488
529
|
if (authChoice.mode === "subscription") {
|
|
@@ -537,8 +578,14 @@ export class InProcessSetupRunner {
|
|
|
537
578
|
// project-root write scope on the dispatched side.
|
|
538
579
|
const policy = { readOnly: false, artifactWriteScope: "." };
|
|
539
580
|
const env = createLocalExecutionEnv({ rootDir: runOptions.workspaceRoot });
|
|
581
|
+
const boundProjectDir = boundSetupProjectDir(runOptions, agentId);
|
|
540
582
|
const nativeTools = createNativeToolRegistry();
|
|
541
|
-
nativeTools.register(SETUP_EXECUTION_TOOL_NAME, () => createSetupExecutionTool({
|
|
583
|
+
nativeTools.register(SETUP_EXECUTION_TOOL_NAME, () => createSetupExecutionTool({
|
|
584
|
+
env,
|
|
585
|
+
policy,
|
|
586
|
+
workspaceRoot: runOptions.workspaceRoot,
|
|
587
|
+
...(boundProjectDir !== undefined ? { defaultExecCwd: boundProjectDir } : {}),
|
|
588
|
+
}));
|
|
542
589
|
// Kept in lockstep with `effectiveMaxTurns()` above via the shared
|
|
543
590
|
// `resolveEffectiveMaxTurns` helper, exactly like `DispatchedSetupRunner.run()`
|
|
544
591
|
// does for its own `--max-turns` flag.
|
|
@@ -548,6 +595,7 @@ export class InProcessSetupRunner {
|
|
|
548
595
|
registry,
|
|
549
596
|
tools,
|
|
550
597
|
userInput: runOptions.prompt,
|
|
598
|
+
...(runOptions.signal ? { signal: runOptions.signal } : {}),
|
|
551
599
|
onEvent: emitter.emit,
|
|
552
600
|
...(maxSteps !== undefined ? { maxSteps } : {}),
|
|
553
601
|
}));
|
|
@@ -620,7 +668,9 @@ export class InProcessSetupRunner {
|
|
|
620
668
|
* rather than pulling in a YAML parser dependency. Matches only an unindented
|
|
621
669
|
* `field:` key (so it can't be fooled by a same-named key nested under
|
|
622
670
|
* another mapping), strips a single layer of surrounding quotes, and returns
|
|
623
|
-
* `undefined` if the file is missing/unreadable or the field isn't present.
|
|
671
|
+
* `undefined` if the file is missing/unreadable or the field isn't present. Values
|
|
672
|
+
* are read as YAML scalars (trailing comments dropped; blank or comment-only is `""`),
|
|
673
|
+
* via `./yaml-scalar.ts`.
|
|
624
674
|
*/
|
|
625
675
|
function readProjectYamlField(yamlPath, field) {
|
|
626
676
|
let content;
|
|
@@ -630,14 +680,7 @@ function readProjectYamlField(yamlPath, field) {
|
|
|
630
680
|
catch {
|
|
631
681
|
return undefined;
|
|
632
682
|
}
|
|
633
|
-
|
|
634
|
-
const match = pattern.exec(content);
|
|
635
|
-
if (!match) {
|
|
636
|
-
return undefined;
|
|
637
|
-
}
|
|
638
|
-
const raw = match[1];
|
|
639
|
-
const unquoted = /^"(.*)"$/.exec(raw) ?? /^'(.*)'$/.exec(raw);
|
|
640
|
-
return (unquoted ? unquoted[1] : raw).trim();
|
|
683
|
+
return readYamlScalarField(content, field);
|
|
641
684
|
}
|
|
642
685
|
/** Parses the small KEY=value subset of a project .env file used by Wren profiles. */
|
|
643
686
|
function parseDotEnv(text) {
|
|
@@ -809,7 +852,7 @@ export function contextLifecycleIdentityFingerprint(root, name, selectedSourceTy
|
|
|
809
852
|
const declaredSourceType = readProjectYamlField(projectYml, "data_source");
|
|
810
853
|
const normalizedSelectedSourceType = selectedSourceType.trim().toLowerCase();
|
|
811
854
|
const normalizedDeclaredSourceType = declaredSourceType?.trim().toLowerCase();
|
|
812
|
-
if (profile
|
|
855
|
+
if (!profile || normalizedDeclaredSourceType === undefined || normalizedDeclaredSourceType !== normalizedSelectedSourceType)
|
|
813
856
|
return undefined;
|
|
814
857
|
const connectionTargetDigest = effectiveConnectionTargetDigest(projectDir, normalizedSelectedSourceType);
|
|
815
858
|
if (connectionTargetDigest === undefined)
|
|
@@ -1031,6 +1074,64 @@ const SCHEMA_INTROSPECTION_COMMANDS = [
|
|
|
1031
1074
|
/\b(?:psql|mysql|sqlite3|duckdb|snowsql|clickhouse-client|trino(?:-cli)?)\b[\s\S]*(?:\s(?:-c|--command|--execute|--query)\s|\b(?:information_schema|show\s+(?:tables|columns)|describe\s+(?:table|schema)|\.tables)\b)/i,
|
|
1032
1075
|
/\bbq\s+query\b/i,
|
|
1033
1076
|
];
|
|
1077
|
+
const CD_PREFIX = /^\s*cd\s+("[^"$`\\]*"|'[^']*'|[^\s;&|<>()$`\\'"~]+)\s*&&\s*([\s\S]*)$/;
|
|
1078
|
+
const STARTS_WITH_CD = /^\s*cd(?:\s|$)/;
|
|
1079
|
+
/**
|
|
1080
|
+
* A recorded relative `cwd` resolves against the tool's own root: the workspace
|
|
1081
|
+
* for the in-process tool, the project for Codex local (whose tool root is the
|
|
1082
|
+
* project directory for project steps).
|
|
1083
|
+
*/
|
|
1084
|
+
function recordedCwdBase(entry, cwd, binding) {
|
|
1085
|
+
return path.resolve(entry.label === CODEX_SETUP_EXECUTION_TOOL_NAME ? binding.projectDir : binding.root, cwd);
|
|
1086
|
+
}
|
|
1087
|
+
function samePath(a, b) {
|
|
1088
|
+
const resolvedA = path.resolve(a);
|
|
1089
|
+
const resolvedB = path.resolve(b);
|
|
1090
|
+
if (resolvedA === resolvedB)
|
|
1091
|
+
return true;
|
|
1092
|
+
try {
|
|
1093
|
+
return realpathSync(resolvedA) === realpathSync(resolvedB);
|
|
1094
|
+
}
|
|
1095
|
+
catch {
|
|
1096
|
+
return false;
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
/**
|
|
1100
|
+
* The ONE recogniser rule shared by schema discovery and the context
|
|
1101
|
+
* lifecycle: a recorded command counts only as the bare command or as exactly
|
|
1102
|
+
* one `cd <dir> && <cmd>` whose `<dir>` is the bound project. Returns the
|
|
1103
|
+
* command to match against the per-stage patterns (the `cd` prefix stripped),
|
|
1104
|
+
* or `undefined` when the shape is not recognised (another directory, a second
|
|
1105
|
+
* `cd`, a dynamic or `~` directory, or no binding to verify against).
|
|
1106
|
+
*
|
|
1107
|
+
* `<dir>` resolves against the exec's explicit `cwd` when the entry recorded
|
|
1108
|
+
* one. Otherwise the effective cwd was not recorded, so the target is accepted
|
|
1109
|
+
* if it names the project from either candidate default (workspace root, the
|
|
1110
|
+
* pre-binding default; or the project itself, the post-binding default). The
|
|
1111
|
+
* entry already exited 0, so the `cd` really resolved to that directory.
|
|
1112
|
+
*/
|
|
1113
|
+
function projectLocalCommand(entry, command, binding) {
|
|
1114
|
+
const explicitCwd = entry.input?.cwd;
|
|
1115
|
+
const recordedCwd = typeof explicitCwd === "string" && explicitCwd.length > 0 ? explicitCwd : undefined;
|
|
1116
|
+
if (!STARTS_WITH_CD.test(command)) {
|
|
1117
|
+
if (binding === undefined || recordedCwd === undefined)
|
|
1118
|
+
return command;
|
|
1119
|
+
// A recorded cwd must itself be the project for a bare command to count.
|
|
1120
|
+
return samePath(recordedCwdBase(entry, recordedCwd, binding), binding.projectDir) ? command : undefined;
|
|
1121
|
+
}
|
|
1122
|
+
if (binding === undefined)
|
|
1123
|
+
return undefined;
|
|
1124
|
+
const match = CD_PREFIX.exec(command);
|
|
1125
|
+
if (!match)
|
|
1126
|
+
return undefined;
|
|
1127
|
+
const raw = match[1];
|
|
1128
|
+
const dir = raw.startsWith('"') || raw.startsWith("'") ? raw.slice(1, -1) : raw;
|
|
1129
|
+
const inner = match[2];
|
|
1130
|
+
if (dir.length === 0 || STARTS_WITH_CD.test(inner))
|
|
1131
|
+
return undefined;
|
|
1132
|
+
const bases = recordedCwd !== undefined ? [recordedCwdBase(entry, recordedCwd, binding)] : [binding.root, binding.projectDir];
|
|
1133
|
+
return bases.some((base) => samePath(path.resolve(base, dir), binding.projectDir)) ? inner : undefined;
|
|
1134
|
+
}
|
|
1034
1135
|
/**
|
|
1035
1136
|
* The single setup-workflow contract for recognisable schema discovery. A
|
|
1036
1137
|
* matching command is evidence only after it completed successfully (see
|
|
@@ -1039,13 +1140,18 @@ const SCHEMA_INTROSPECTION_COMMANDS = [
|
|
|
1039
1140
|
* this for both terminal acceptance and the no-introspection diagnostic,
|
|
1040
1141
|
* rather than reimplementing the allowlist elsewhere.
|
|
1041
1142
|
*/
|
|
1042
|
-
export function classifyRecordedSchemaDiscovery(worklog) {
|
|
1143
|
+
export function classifyRecordedSchemaDiscovery(worklog, binding) {
|
|
1043
1144
|
let failed;
|
|
1044
1145
|
for (const entry of worklog) {
|
|
1045
1146
|
const command = isSetupExecutionEntry(entry) ? execCommandOf(entry) : undefined;
|
|
1046
|
-
if (command === undefined
|
|
1047
|
-
|
|
1048
|
-
|
|
1147
|
+
if (command === undefined)
|
|
1148
|
+
continue;
|
|
1149
|
+
// Without a binding (legacy callers) the matching below is unchanged; with
|
|
1150
|
+
// one, a leading `cd` must satisfy the shared project-local rule.
|
|
1151
|
+
const recognised = binding === undefined ? command : projectLocalCommand(entry, command, binding);
|
|
1152
|
+
if (recognised === undefined ||
|
|
1153
|
+
!SCHEMA_DISCOVERY_EVIDENCE.test(recognised) ||
|
|
1154
|
+
!SCHEMA_INTROSPECTION_COMMANDS.some((pattern) => pattern.test(recognised))) {
|
|
1049
1155
|
continue;
|
|
1050
1156
|
}
|
|
1051
1157
|
const succeeded = execSucceeded(entry);
|
|
@@ -1066,7 +1172,7 @@ const DIRECT_CONTEXT_LIFECYCLE_COMMAND = new RegExp(String.raw `^\s*(?:(?:${SHEL
|
|
|
1066
1172
|
* context build`, each recorded as a successful setup execution. An artifact
|
|
1067
1173
|
* alone or merely naming a command in the final message is not evidence.
|
|
1068
1174
|
*/
|
|
1069
|
-
function contextLifecycleStage(command) {
|
|
1175
|
+
function contextLifecycleStage(entry, command, binding) {
|
|
1070
1176
|
// This evidence must describe the actual lifecycle invocation, rather than
|
|
1071
1177
|
// merely mention it. `setup_execution` already supplies the project cwd as
|
|
1072
1178
|
// a separate structured field; the only shell prefixes we accept here are
|
|
@@ -1075,7 +1181,12 @@ function contextLifecycleStage(command) {
|
|
|
1075
1181
|
// command cwd to the canonical project, so this is the same project-local
|
|
1076
1182
|
// lifecycle operation emitted by some Wren guidance. Arbitrary paths, other
|
|
1077
1183
|
// flags, shell sequencing, quoted text, and wrappers remain unrecognized.
|
|
1078
|
-
|
|
1184
|
+
// The one additional shape is a single `cd <project> &&` prefix, decided by
|
|
1185
|
+
// the shared `projectLocalCommand` rule (also used for schema discovery).
|
|
1186
|
+
const inner = projectLocalCommand(entry, command, binding);
|
|
1187
|
+
if (inner === undefined)
|
|
1188
|
+
return undefined;
|
|
1189
|
+
const match = DIRECT_CONTEXT_LIFECYCLE_COMMAND.exec(inner);
|
|
1079
1190
|
return match?.[1]?.toLowerCase();
|
|
1080
1191
|
}
|
|
1081
1192
|
function stageAfter(prefix) {
|
|
@@ -1090,40 +1201,55 @@ function prefixFor(stage) {
|
|
|
1090
1201
|
return "discovery";
|
|
1091
1202
|
return stage === "build" ? "validate" : "none";
|
|
1092
1203
|
}
|
|
1093
|
-
|
|
1204
|
+
const CONTEXT_LIFECYCLE_MENTION = /\bwren\s+context\s+(validate|build)\b/i;
|
|
1205
|
+
function scanRecordedContextLifecycle(worklog, prior, binding) {
|
|
1094
1206
|
let stage = stageAfter(prior);
|
|
1095
1207
|
let completed = prior === "build";
|
|
1096
1208
|
let outOfOrderObserved;
|
|
1209
|
+
// Successful commands that mention a lifecycle command but were not
|
|
1210
|
+
// recognised as one, so a failure can quote them instead of claiming the
|
|
1211
|
+
// command never ran.
|
|
1212
|
+
const unrecognisedMentions = [];
|
|
1097
1213
|
for (const entry of worklog) {
|
|
1098
1214
|
if (!isSetupExecutionEntry(entry) || execSucceeded(entry) !== true)
|
|
1099
1215
|
continue;
|
|
1100
1216
|
const command = execCommandOf(entry);
|
|
1101
1217
|
if (command === undefined)
|
|
1102
1218
|
continue;
|
|
1219
|
+
const noteUnrecognised = (candidate, text) => {
|
|
1220
|
+
if (contextLifecycleStage(candidate, text, binding) !== undefined)
|
|
1221
|
+
return;
|
|
1222
|
+
const mention = CONTEXT_LIFECYCLE_MENTION.exec(text);
|
|
1223
|
+
if (mention)
|
|
1224
|
+
unrecognisedMentions.push({ command: text, stage: mention[1].toLowerCase() });
|
|
1225
|
+
};
|
|
1103
1226
|
if (stage === "discovery") {
|
|
1104
|
-
if (classifyRecordedSchemaDiscovery([entry]).kind === "successful") {
|
|
1227
|
+
if (classifyRecordedSchemaDiscovery([entry], binding).kind === "successful") {
|
|
1105
1228
|
stage = "validate";
|
|
1106
1229
|
continue;
|
|
1107
1230
|
}
|
|
1108
|
-
if (contextLifecycleStage(command) !== undefined) {
|
|
1109
|
-
outOfOrderObserved ??= `successful
|
|
1231
|
+
if (contextLifecycleStage(entry, command, binding) !== undefined) {
|
|
1232
|
+
outOfOrderObserved ??= `successful ${quoteCommand(command)} ran before successful schema discovery`;
|
|
1110
1233
|
}
|
|
1234
|
+
noteUnrecognised(entry, command);
|
|
1111
1235
|
continue;
|
|
1112
1236
|
}
|
|
1113
|
-
const nativeStage = contextLifecycleStage(command);
|
|
1237
|
+
const nativeStage = contextLifecycleStage(entry, command, binding);
|
|
1238
|
+
if (nativeStage === undefined)
|
|
1239
|
+
noteUnrecognised(entry, command);
|
|
1114
1240
|
if (stage === "validate") {
|
|
1115
1241
|
if (nativeStage === "validate") {
|
|
1116
1242
|
stage = "build";
|
|
1117
1243
|
}
|
|
1118
1244
|
else if (nativeStage === "build") {
|
|
1119
|
-
outOfOrderObserved ??= `successful
|
|
1245
|
+
outOfOrderObserved ??= `successful ${quoteCommand(command)} ran before successful \`wren context validate\``;
|
|
1120
1246
|
}
|
|
1121
1247
|
continue;
|
|
1122
1248
|
}
|
|
1123
1249
|
if (nativeStage === "build")
|
|
1124
1250
|
completed = true;
|
|
1125
1251
|
}
|
|
1126
|
-
return { stage, completed, outOfOrderObserved };
|
|
1252
|
+
return { stage, completed, outOfOrderObserved, unrecognisedMentions };
|
|
1127
1253
|
}
|
|
1128
1254
|
/**
|
|
1129
1255
|
* Returns the greatest ordered prefix proved by the supplied successful tool
|
|
@@ -1131,26 +1257,122 @@ function scanRecordedContextLifecycle(worklog, prior) {
|
|
|
1131
1257
|
* call in the same attempt is out of order, so a corrective attempt can ask
|
|
1132
1258
|
* only for the unproven suffix.
|
|
1133
1259
|
*/
|
|
1134
|
-
export function recordedContextLifecyclePrefix(worklog, prior = "none") {
|
|
1135
|
-
const scan = scanRecordedContextLifecycle(worklog, prior);
|
|
1260
|
+
export function recordedContextLifecyclePrefix(worklog, prior = "none", binding) {
|
|
1261
|
+
const scan = scanRecordedContextLifecycle(worklog, prior, binding);
|
|
1136
1262
|
return scan.completed ? "build" : prefixFor(scan.stage);
|
|
1137
1263
|
}
|
|
1138
|
-
export function classifyRecordedContextLifecycle(worklog, prior = "none") {
|
|
1139
|
-
const { stage, completed, outOfOrderObserved } = scanRecordedContextLifecycle(worklog, prior);
|
|
1264
|
+
export function classifyRecordedContextLifecycle(worklog, prior = "none", binding) {
|
|
1265
|
+
const { stage, completed, outOfOrderObserved, unrecognisedMentions } = scanRecordedContextLifecycle(worklog, prior, binding);
|
|
1266
|
+
const wanted = stage === "validate" ? "validate" : "build";
|
|
1267
|
+
const unrecognised = (unrecognisedMentions.find((mention) => mention.stage === wanted) ?? unrecognisedMentions[0])?.command;
|
|
1140
1268
|
if (completed)
|
|
1141
1269
|
return { kind: "successful" };
|
|
1270
|
+
const withUnrecognised = unrecognised !== undefined ? { unrecognised } : {};
|
|
1142
1271
|
if (outOfOrderObserved !== undefined)
|
|
1143
|
-
return { kind: "out_of_order", observed: outOfOrderObserved };
|
|
1272
|
+
return { kind: "out_of_order", observed: outOfOrderObserved, ...withUnrecognised };
|
|
1144
1273
|
if (stage === "discovery")
|
|
1145
1274
|
return { kind: "missing_discovery" };
|
|
1146
|
-
if (stage === "validate")
|
|
1147
|
-
return { kind: "validate_missing", observed: "no successful `wren context validate` followed successful schema discovery" };
|
|
1148
|
-
|
|
1275
|
+
if (stage === "validate") {
|
|
1276
|
+
return { kind: "validate_missing", observed: "no recognised successful `wren context validate` followed successful schema discovery", ...withUnrecognised };
|
|
1277
|
+
}
|
|
1278
|
+
return { kind: "build_missing", observed: "no recognised successful `wren context build` followed successful `wren context validate`", ...withUnrecognised };
|
|
1149
1279
|
}
|
|
1150
1280
|
/** A narrow terminal-message check: only override a context error that explicitly claims a zero-table/model outcome. */
|
|
1151
1281
|
function claimsNoTablesOrModels(message) {
|
|
1152
1282
|
return /\b(?:no|zero)\s+(?:tables?|models?)\b|\b0\s+(?:tables?|models?)\b/i.test(message);
|
|
1153
1283
|
}
|
|
1284
|
+
const ENV_ASSIGNMENT_VALUE = /(^|[\s;&|(])([A-Za-z_][A-Za-z0-9_]*)=("[^"]*"|'[^']*'|[^\s;&|]*)/g;
|
|
1285
|
+
/** Masks the value of every `NAME=value` assignment (leading, after `env`, or after `&&`/`;`). */
|
|
1286
|
+
function redactEnvAssignments(command) {
|
|
1287
|
+
return command.replace(ENV_ASSIGNMENT_VALUE, "$1$2=***");
|
|
1288
|
+
}
|
|
1289
|
+
/** Quotes a command for an error message: env values redacted first, then bounded so a long script cannot flood it. */
|
|
1290
|
+
function quoteCommand(command) {
|
|
1291
|
+
const flat = redactEnvAssignments(command).replace(/\s+/g, " ").trim();
|
|
1292
|
+
return `\`${flat.length > 300 ? `${flat.slice(0, 300)}...` : flat}\``;
|
|
1293
|
+
}
|
|
1294
|
+
const UNRECOGNISED_LIFECYCLE_HINT = "It exited successfully but is not a recognised lifecycle invocation: only the bare command (optionally with environment assignments or `--path .`) or a single `cd <project directory> &&` prefix naming this step's project directory is accepted. Run it again as the bare command and set the `setup_execution` `cwd` field to the project directory instead of shell chaining.";
|
|
1295
|
+
function projectBindingOf(context) {
|
|
1296
|
+
return { root: context.root, projectDir: path.join(context.root, context.name) };
|
|
1297
|
+
}
|
|
1298
|
+
/**
|
|
1299
|
+
* The host-held evidence gate for a successful `context` step: the recorded
|
|
1300
|
+
* discovery -> validate -> build lifecycle, then the built `target/mdl.json`.
|
|
1301
|
+
* Returns the failure, or `undefined` when the evidence supports success. It
|
|
1302
|
+
* never looks at the agent's own status line.
|
|
1303
|
+
*/
|
|
1304
|
+
function verifyContextEvidence(context) {
|
|
1305
|
+
if (context.worklog !== undefined) {
|
|
1306
|
+
const lifecycle = classifyRecordedContextLifecycle(context.worklog, context.priorContextLifecycle, projectBindingOf(context));
|
|
1307
|
+
if (lifecycle.kind === "missing_discovery") {
|
|
1308
|
+
return hostContractFailure("context_schema_discovery_missing", "The agent never completed recognized schema discovery in its recorded worklog, so its model/build result cannot be accepted. This is an agent-workflow failure, not evidence that the connection or data source lacks tables.", "the recorded worklog has no successful recognized schema-discovery command", [
|
|
1309
|
+
"run a recognized schema-discovery command against the connected source and make sure it exits successfully",
|
|
1310
|
+
"build target/mdl.json only from that discovered schema, with at least one model",
|
|
1311
|
+
], "no_successful_schema_discovery");
|
|
1312
|
+
}
|
|
1313
|
+
const discovery = classifyRecordedSchemaDiscovery(context.worklog, projectBindingOf(context));
|
|
1314
|
+
if (discovery.kind === "failed") {
|
|
1315
|
+
const exitCodeSuffix = discovery.exitCode !== undefined ? ` with exit code ${discovery.exitCode}` : "";
|
|
1316
|
+
return hostContractFailure("context_schema_discovery_failed", `${quoteCommand(discovery.command)} failed${exitCodeSuffix} during schema discovery — a model/build result cannot be accepted until that command/tool failure is resolved; this is not evidence that the connection or data source lacks tables.`, discovery.exitCode !== undefined
|
|
1317
|
+
? `the recorded schema-discovery command exited with code ${discovery.exitCode}`
|
|
1318
|
+
: "the recorded schema-discovery command failed", [
|
|
1319
|
+
"resolve the schema-discovery command failure and run a recognized discovery command successfully",
|
|
1320
|
+
"build target/mdl.json only from that discovered schema, with at least one model",
|
|
1321
|
+
]);
|
|
1322
|
+
}
|
|
1323
|
+
if (lifecycle.kind === "validate_missing") {
|
|
1324
|
+
return hostContractFailure("context_validate_missing", lifecycle.unrecognised !== undefined
|
|
1325
|
+
? `The agent ran ${quoteCommand(lifecycle.unrecognised)} successfully, but it was not recognised as \`wren context validate\` after schema discovery. ${UNRECOGNISED_LIFECYCLE_HINT}`
|
|
1326
|
+
: "The agent did not successfully run `wren context validate` after recognized schema discovery, so its model/build result cannot be accepted.", lifecycle.unrecognised !== undefined
|
|
1327
|
+
? `${lifecycle.observed}; unrecognised successful command: ${quoteCommand(lifecycle.unrecognised)}`
|
|
1328
|
+
: lifecycle.observed, [
|
|
1329
|
+
"run a recognized schema-discovery command successfully",
|
|
1330
|
+
"run `wren context validate` successfully before `wren context build`",
|
|
1331
|
+
"build target/mdl.json only after validation, with at least one model",
|
|
1332
|
+
...(lifecycle.unrecognised !== undefined
|
|
1333
|
+
? ["pass the project directory through the `setup_execution` `cwd` field rather than `cd`/shell chaining"]
|
|
1334
|
+
: []),
|
|
1335
|
+
]);
|
|
1336
|
+
}
|
|
1337
|
+
if (lifecycle.kind === "build_missing") {
|
|
1338
|
+
return hostContractFailure("context_build_missing", lifecycle.unrecognised !== undefined
|
|
1339
|
+
? `The agent ran ${quoteCommand(lifecycle.unrecognised)} successfully, but it was not recognised as \`wren context build\` after \`wren context validate\`. ${UNRECOGNISED_LIFECYCLE_HINT}`
|
|
1340
|
+
: "The agent did not successfully run `wren context build` after `wren context validate`, so its claimed context success cannot be accepted.", lifecycle.unrecognised !== undefined
|
|
1341
|
+
? `${lifecycle.observed}; unrecognised successful command: ${quoteCommand(lifecycle.unrecognised)}`
|
|
1342
|
+
: lifecycle.observed, [
|
|
1343
|
+
"run a recognized schema-discovery command successfully",
|
|
1344
|
+
"run `wren context validate` successfully",
|
|
1345
|
+
"run `wren context build` successfully after validation and produce target/mdl.json with at least one model",
|
|
1346
|
+
...(lifecycle.unrecognised !== undefined
|
|
1347
|
+
? ["pass the project directory through the `setup_execution` `cwd` field rather than `cd`/shell chaining"]
|
|
1348
|
+
: []),
|
|
1349
|
+
]);
|
|
1350
|
+
}
|
|
1351
|
+
if (lifecycle.kind === "out_of_order") {
|
|
1352
|
+
return hostContractFailure("context_lifecycle_out_of_order", lifecycle.unrecognised !== undefined
|
|
1353
|
+
? `The native context lifecycle ran out of order; Setup requires successful schema discovery followed by \`wren context validate\` and then \`wren context build\`. The agent also ran ${quoteCommand(lifecycle.unrecognised)} successfully, but it was not recognised. ${UNRECOGNISED_LIFECYCLE_HINT}`
|
|
1354
|
+
: "The native context lifecycle ran out of order; Setup requires successful schema discovery followed by `wren context validate` and then `wren context build`.", lifecycle.unrecognised !== undefined
|
|
1355
|
+
? `${lifecycle.observed}; unrecognised successful command: ${quoteCommand(lifecycle.unrecognised)}`
|
|
1356
|
+
: lifecycle.observed, [
|
|
1357
|
+
"run a recognized schema-discovery command successfully",
|
|
1358
|
+
"run `wren context validate` successfully before `wren context build`",
|
|
1359
|
+
"produce target/mdl.json with at least one schema-derived model",
|
|
1360
|
+
...(lifecycle.unrecognised !== undefined
|
|
1361
|
+
? ["pass the project directory through the `setup_execution` `cwd` field rather than `cd`/shell chaining"]
|
|
1362
|
+
: []),
|
|
1363
|
+
]);
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
const mdlPath = path.join(context.root, context.name, "target", "mdl.json");
|
|
1367
|
+
if (!existsSync(mdlPath)) {
|
|
1368
|
+
return hostContractFailure("context_mdl_missing", `the setup agent reported "ok" but ${mdlPath} does not exist — treating this as a failed context build`, "target/mdl.json is missing after the claimed context build", ["target/mdl.json must exist", "target/mdl.json must contain at least one model"]);
|
|
1369
|
+
}
|
|
1370
|
+
const modelCount = countMdlModels(mdlPath);
|
|
1371
|
+
if (modelCount < 1) {
|
|
1372
|
+
return hostContractFailure("context_mdl_empty", `the setup agent reported "ok" but ${mdlPath} has ${modelCount} models — treating this as a failed context build`, `target/mdl.json has ${modelCount} models after the claimed context build`, ["target/mdl.json must contain at least one model"]);
|
|
1373
|
+
}
|
|
1374
|
+
return undefined;
|
|
1375
|
+
}
|
|
1154
1376
|
/**
|
|
1155
1377
|
* Parses the LAST `SETUP_STATUS: ok|needs_input|error` line out of a setup
|
|
1156
1378
|
* turn's finalText (the terminal contract lives in the composed
|
|
@@ -1193,6 +1415,12 @@ export function parseSetupTerminal(finalText, context) {
|
|
|
1193
1415
|
}
|
|
1194
1416
|
}
|
|
1195
1417
|
if (!matched) {
|
|
1418
|
+
// For the context step the status line is advisory: recorded execution
|
|
1419
|
+
// evidence plus the built project decide success. Anything short of that
|
|
1420
|
+
// keeps the missing-status failure (and its bounded correction turn).
|
|
1421
|
+
if (context.stepKey === "context" && context.worklog !== undefined && verifyContextEvidence(context) === undefined) {
|
|
1422
|
+
return { status: "ok", message: defaultMessageFor("ok") };
|
|
1423
|
+
}
|
|
1196
1424
|
return {
|
|
1197
1425
|
status: "error",
|
|
1198
1426
|
message: "the setup agent's final message did not contain a SETUP_STATUS line",
|
|
@@ -1201,54 +1429,9 @@ export function parseSetupTerminal(finalText, context) {
|
|
|
1201
1429
|
}
|
|
1202
1430
|
if (matched.status === "ok") {
|
|
1203
1431
|
if (context.stepKey === "context") {
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
return hostContractFailure("context_schema_discovery_missing", "The agent never completed recognized schema discovery in its recorded worklog, so its model/build result cannot be accepted. This is an agent-workflow failure, not evidence that the connection or data source lacks tables.", "the recorded worklog has no successful recognized schema-discovery command", [
|
|
1208
|
-
"run a recognized schema-discovery command against the connected source and make sure it exits successfully",
|
|
1209
|
-
"build target/mdl.json only from that discovered schema, with at least one model",
|
|
1210
|
-
], "no_successful_schema_discovery");
|
|
1211
|
-
}
|
|
1212
|
-
const discovery = classifyRecordedSchemaDiscovery(context.worklog);
|
|
1213
|
-
if (discovery.kind === "failed") {
|
|
1214
|
-
const exitCodeSuffix = discovery.exitCode !== undefined ? ` with exit code ${discovery.exitCode}` : "";
|
|
1215
|
-
return hostContractFailure("context_schema_discovery_failed", `\`${discovery.command}\` failed${exitCodeSuffix} during schema discovery — a model/build result cannot be accepted until that command/tool failure is resolved; this is not evidence that the connection or data source lacks tables.`, discovery.exitCode !== undefined
|
|
1216
|
-
? `the recorded schema-discovery command exited with code ${discovery.exitCode}`
|
|
1217
|
-
: "the recorded schema-discovery command failed", [
|
|
1218
|
-
"resolve the schema-discovery command failure and run a recognized discovery command successfully",
|
|
1219
|
-
"build target/mdl.json only from that discovered schema, with at least one model",
|
|
1220
|
-
]);
|
|
1221
|
-
}
|
|
1222
|
-
if (lifecycle.kind === "validate_missing") {
|
|
1223
|
-
return hostContractFailure("context_validate_missing", "The agent did not successfully run `wren context validate` after recognized schema discovery, so its model/build result cannot be accepted.", lifecycle.observed, [
|
|
1224
|
-
"run a recognized schema-discovery command successfully",
|
|
1225
|
-
"run `wren context validate` successfully before `wren context build`",
|
|
1226
|
-
"build target/mdl.json only after validation, with at least one model",
|
|
1227
|
-
]);
|
|
1228
|
-
}
|
|
1229
|
-
if (lifecycle.kind === "build_missing") {
|
|
1230
|
-
return hostContractFailure("context_build_missing", "The agent did not successfully run `wren context build` after `wren context validate`, so its claimed context success cannot be accepted.", lifecycle.observed, [
|
|
1231
|
-
"run a recognized schema-discovery command successfully",
|
|
1232
|
-
"run `wren context validate` successfully",
|
|
1233
|
-
"run `wren context build` successfully after validation and produce target/mdl.json with at least one model",
|
|
1234
|
-
]);
|
|
1235
|
-
}
|
|
1236
|
-
if (lifecycle.kind === "out_of_order") {
|
|
1237
|
-
return hostContractFailure("context_lifecycle_out_of_order", "The native context lifecycle ran out of order; Setup requires successful schema discovery followed by `wren context validate` and then `wren context build`.", lifecycle.observed, [
|
|
1238
|
-
"run a recognized schema-discovery command successfully",
|
|
1239
|
-
"run `wren context validate` successfully before `wren context build`",
|
|
1240
|
-
"produce target/mdl.json with at least one schema-derived model",
|
|
1241
|
-
]);
|
|
1242
|
-
}
|
|
1243
|
-
}
|
|
1244
|
-
const mdlPath = path.join(context.root, context.name, "target", "mdl.json");
|
|
1245
|
-
if (!existsSync(mdlPath)) {
|
|
1246
|
-
return hostContractFailure("context_mdl_missing", `the setup agent reported "ok" but ${mdlPath} does not exist — treating this as a failed context build`, "target/mdl.json is missing after the claimed context build", ["target/mdl.json must exist", "target/mdl.json must contain at least one model"]);
|
|
1247
|
-
}
|
|
1248
|
-
const modelCount = countMdlModels(mdlPath);
|
|
1249
|
-
if (modelCount < 1) {
|
|
1250
|
-
return hostContractFailure("context_mdl_empty", `the setup agent reported "ok" but ${mdlPath} has ${modelCount} models — treating this as a failed context build`, `target/mdl.json has ${modelCount} models after the claimed context build`, ["target/mdl.json must contain at least one model"]);
|
|
1251
|
-
}
|
|
1432
|
+
const failure = verifyContextEvidence(context);
|
|
1433
|
+
if (failure !== undefined)
|
|
1434
|
+
return failure;
|
|
1252
1435
|
}
|
|
1253
1436
|
else {
|
|
1254
1437
|
const markerName = context.stepKey === "connect_resume" ? ".wren-validated" : "wren_project.yml";
|
|
@@ -1295,14 +1478,14 @@ export function parseSetupTerminal(finalText, context) {
|
|
|
1295
1478
|
// `setup_execution` call that exited non-zero, and reframe if one is found.
|
|
1296
1479
|
const failedExec = firstFailedExec(context.worklog);
|
|
1297
1480
|
if (failedExec !== undefined) {
|
|
1298
|
-
const command = failedExec.command !== undefined ?
|
|
1481
|
+
const command = failedExec.command !== undefined ? quoteCommand(failedExec.command) : "a command";
|
|
1299
1482
|
const exitCodeSuffix = failedExec.exitCode !== undefined ? ` with exit code ${failedExec.exitCode}` : "";
|
|
1300
1483
|
return {
|
|
1301
1484
|
status: "error",
|
|
1302
1485
|
message: `${command} failed${exitCodeSuffix} during this step — a command in this step's own history failed, so this step's error framing can't be trusted until that's ruled out; this is a command/tool failure, not by itself evidence that the connection or data source lacks tables. The agent's own report was: "${matched.message}"`,
|
|
1303
1486
|
};
|
|
1304
1487
|
}
|
|
1305
|
-
if (claimsNoTablesOrModels(matched.message) && classifyRecordedSchemaDiscovery(context.worklog).kind === "none") {
|
|
1488
|
+
if (claimsNoTablesOrModels(matched.message) && classifyRecordedSchemaDiscovery(context.worklog, projectBindingOf(context)).kind === "none") {
|
|
1306
1489
|
return {
|
|
1307
1490
|
status: "error",
|
|
1308
1491
|
failureKind: "no_successful_schema_discovery",
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads a top-level `field: value` scalar from a `wren_project.yml`-shaped
|
|
3
|
+
* document and returns the YAML *value*, not the raw line remainder.
|
|
4
|
+
*
|
|
5
|
+
* `wren context init` scaffolds lines such as
|
|
6
|
+
* `data_source: # not set yet — ...`, and hand-edited projects keep trailing
|
|
7
|
+
* comments (`data_source: duckdb # change to your datasource type`). A raw
|
|
8
|
+
* remainder would hand that comment to callers as part of the value. This
|
|
9
|
+
* stays a single-purpose reader (no YAML dependency, matching the rest of
|
|
10
|
+
* `server/`); it only understands what a plain scalar line can contain:
|
|
11
|
+
*
|
|
12
|
+
* - an unquoted value ends at the first ` #` (a `#` preceded by whitespace);
|
|
13
|
+
* - a quoted value ends at its closing quote, so `"a#b"` stays `a#b` and
|
|
14
|
+
* anything after the closing quote is a comment;
|
|
15
|
+
* - a blank value, or one that is only a comment, reads as `""` (unset).
|
|
16
|
+
*
|
|
17
|
+
* Double-quoted escapes are NOT unescaped (`"a\"b"` yields `a\"b`): only plain
|
|
18
|
+
* identifiers (data source types, profile names) are ever read through here.
|
|
19
|
+
* A leading BOM is ignored.
|
|
20
|
+
*
|
|
21
|
+
* Returns `undefined` only when the field's key line is absent.
|
|
22
|
+
*/
|
|
23
|
+
export declare function readYamlScalarField(content: string, field: string): string | undefined;
|