create-agdf 0.11.3 → 0.12.0
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 +5 -4
- package/generated/.agdf/control/templates/MASTER_BACKLOG.md +1 -1
- package/generated/.agdf/control/templates/artefacts/BROWNFIELD_REVIEW.md +25 -0
- package/generated/.github/skills/agdf-brownfield-analysis/SKILL.md +26 -0
- package/generated/.github/skills/agdf-gate-check/SKILL.md +40 -18
- package/generated/.github/skills/agdf-interaction-locales.json +50 -0
- package/generated/.github/skills/agdf-runtime-contract.md +1 -0
- package/generated/.github/skills/contracts/control-scaffold.md +2 -0
- package/generated/.github/skills/contracts/gate-transition.md +7 -3
- package/generated/.github/skills/contracts/interaction.md +22 -0
- package/generated/.github/skills/contracts/modes.md +81 -0
- package/generated/.github/skills/contracts/task-target-resolution.md +102 -0
- package/generated/.opencode/AGDF.md +2 -0
- package/generated/.opencode/agdf-interaction-locales.json +50 -0
- package/generated/.opencode/agdf-runtime-contract.md +1 -0
- package/generated/.opencode/contracts/control-scaffold.md +2 -0
- package/generated/.opencode/contracts/gate-transition.md +7 -3
- package/generated/.opencode/contracts/interaction.md +22 -0
- package/generated/.opencode/contracts/modes.md +81 -0
- package/generated/.opencode/contracts/task-target-resolution.md +102 -0
- package/generated/.opencode/skills/agdf-brownfield-analysis/SKILL.md +26 -0
- package/generated/.opencode/skills/agdf-gate-check/SKILL.md +40 -18
- package/generated/AGENTS.md +1 -0
- package/generated/plugins/agdf/.claude-plugin/plugin.json +1 -1
- package/generated/plugins/agdf/.codex-plugin/plugin.json +1 -1
- package/generated/plugins/agdf/control/templates/MASTER_BACKLOG.md +1 -1
- package/generated/plugins/agdf/control/templates/artefacts/BROWNFIELD_REVIEW.md +25 -0
- package/generated/plugins/agdf/meta/agdf-agent-router.md +16 -0
- package/generated/plugins/agdf/meta/agdf-interaction-locales.json +50 -0
- package/generated/plugins/agdf/meta/agdf-plugin.definition.json +2 -1
- package/generated/plugins/agdf/meta/agdf-runtime-contract.md +1 -0
- package/generated/plugins/agdf/meta/contracts/control-scaffold.md +2 -0
- package/generated/plugins/agdf/meta/contracts/gate-transition.md +7 -3
- package/generated/plugins/agdf/meta/contracts/interaction.md +22 -0
- package/generated/plugins/agdf/meta/contracts/modes.md +81 -0
- package/generated/plugins/agdf/meta/contracts/task-target-resolution.md +102 -0
- package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-interaction-locales.json +50 -0
- package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-plugin.definition.json +2 -1
- package/generated/plugins/agdf/runtime/create-agdf/lib/cli/command-registry.js +2 -2
- package/generated/plugins/agdf/runtime/create-agdf/lib/cli/delivery-path-search-command.js +78 -14
- package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/gate-policy.js +14 -7
- package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/shared.js +1 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/claude.js +2 -11
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/codex.js +2 -11
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/opencode.js +234 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/prompt.js +13 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/search-engine.js +1 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/surfaces/capabilities.js +15 -2
- package/generated/plugins/agdf/runtime/create-agdf/lib/interaction-presentation.js +85 -0
- package/generated/plugins/agdf/runtime/create-agdf/package.json +6 -2
- package/generated/plugins/agdf/runtime/runtime-manifest.json +2 -2
- package/generated/plugins/agdf/scripts/check-runtime-integrity.mjs +119 -3
- package/generated/plugins/agdf/skills/brownfield-analysis/SKILL.md +26 -0
- package/generated/plugins/agdf/skills/gate-check/SKILL.md +40 -18
- package/lib/cli/application.js +29 -3
- package/lib/cli/command-registry.js +2 -2
- package/lib/cli/delivery-path-search-command.js +78 -14
- package/lib/control-evaluation/gate-policy.js +14 -7
- package/lib/control-evaluation/shared.js +1 -0
- package/lib/delivery-path-search/evaluators/claude.js +2 -11
- package/lib/delivery-path-search/evaluators/codex.js +2 -11
- package/lib/delivery-path-search/evaluators/opencode.js +234 -0
- package/lib/delivery-path-search/evaluators/prompt.js +13 -0
- package/lib/delivery-path-search/search-engine.js +1 -0
- package/lib/delivery-path-search/surfaces/capabilities.js +15 -2
- package/lib/installers/opencode.js +341 -10
- package/lib/interaction-presentation.js +85 -0
- package/lib/lifecycle/operations.js +4 -0
- package/lib/live-agent/read-only-structured.js +43 -0
- package/lib/proportionality-benchmark/blind-prompt.js +37 -0
- package/lib/proportionality-benchmark/contracts.js +120 -0
- package/lib/proportionality-benchmark/corpus-loader.js +110 -0
- package/lib/proportionality-benchmark/evaluator.js +250 -0
- package/lib/proportionality-benchmark/index.js +7 -0
- package/lib/proportionality-benchmark/live-recorder.js +100 -0
- package/lib/proportionality-benchmark/report.js +51 -0
- package/lib/proportionality-benchmark/source-fingerprint.js +30 -0
- package/lib/skill-evals/live-recorder.js +3 -26
- package/opencode-plugin.js +59 -3
- package/package.json +6 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { validateEnforcement } from "../contracts.js";
|
|
2
2
|
|
|
3
|
-
export function enforcementForSurface(surface, evidence = []) {
|
|
3
|
+
export function enforcementForSurface(surface, evidence = [], context = {}) {
|
|
4
4
|
const defaults = {
|
|
5
5
|
codex: { level: "tool_enforced", evidence: ["codex exec --sandbox read-only --ephemeral"] },
|
|
6
6
|
claude: { level: "tool_enforced", evidence: ["claude -p --disallowedTools Edit,Write,Bash"] },
|
|
@@ -9,6 +9,19 @@ export function enforcementForSurface(surface, evidence = []) {
|
|
|
9
9
|
generic: { level: "instruction_only", evidence: [] },
|
|
10
10
|
};
|
|
11
11
|
const selected = structuredClone(defaults[surface] ?? defaults.generic);
|
|
12
|
-
if (
|
|
12
|
+
if (surface === "opencode") {
|
|
13
|
+
const preflight = context.preflight;
|
|
14
|
+
if (preflight?.surface === "opencode"
|
|
15
|
+
&& preflight.status === "passed"
|
|
16
|
+
&& typeof preflight.invocation_id === "string"
|
|
17
|
+
&& preflight.invocation_id
|
|
18
|
+
&& Array.isArray(preflight.evidence)
|
|
19
|
+
&& preflight.evidence === evidence) {
|
|
20
|
+
selected.level = "tool_enforced";
|
|
21
|
+
selected.evidence = [...evidence];
|
|
22
|
+
}
|
|
23
|
+
} else if (evidence.length) {
|
|
24
|
+
selected.evidence = evidence;
|
|
25
|
+
}
|
|
13
26
|
return validateEnforcement(selected);
|
|
14
27
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { execFileSync } from "node:child_process";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
|
-
import { dirname, join } from "node:path";
|
|
4
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
5
5
|
import process from "node:process";
|
|
6
6
|
import { generatedRoot, pluginDefinition } from "../cli/runtime-context.js";
|
|
7
7
|
import { evaluateOpenCodeRepositoryActivation } from "./opencode-activation.js";
|
|
@@ -14,6 +14,7 @@ const globalOpenCodeSkillOwnershipMarker = "<!-- AGDF-GLOBAL-SKILL: ";
|
|
|
14
14
|
const globalOpenCodeInstructionsOwnershipMarker = "<!-- AGDF-GLOBAL-INSTRUCTIONS -->";
|
|
15
15
|
const globalOpenCodeRuntimeContractOwnershipMarker = "<!-- AGDF-GLOBAL-RUNTIME-CONTRACT -->";
|
|
16
16
|
const globalOpenCodeValidatorOwnershipMarker = "// AGDF-GLOBAL-LOCAL-VALIDATOR";
|
|
17
|
+
const globalOpenCodeAgentOwnershipMarker = `<!-- AGDF-GLOBAL-AGENT: ${pluginDefinition.opencode.evaluatorAgentName} -->`;
|
|
17
18
|
const globalOpenCodeValidatorPackageOwner = "create-agdf";
|
|
18
19
|
const testNpmCliPath = process.env.NODE_ENV === "test" ? process.env.AGDF_TEST_NPM_CLI_PATH || "" : "";
|
|
19
20
|
const npmCommand = testNpmCliPath ? process.execPath : process.platform === "win32" ? process.execPath : "npm";
|
|
@@ -115,11 +116,13 @@ export function installOpenCodeGlobalPlugin(configDir) {
|
|
|
115
116
|
throw openCodeLifecycleError("configuration", `Failed to write OpenCode config ${configPath}: ${error.message}`, { configPath });
|
|
116
117
|
}
|
|
117
118
|
const installedPackage = resolveOpenCodePackage(configDir);
|
|
119
|
+
const sdkAlignment = alignOpenCodePluginSdk(configDir);
|
|
118
120
|
|
|
119
121
|
return {
|
|
120
122
|
configPath,
|
|
121
123
|
added: !alreadyInstalled,
|
|
122
124
|
transition: openCodePackageTransition(previousPackage, installedPackage),
|
|
125
|
+
sdk_alignment: sdkAlignment,
|
|
123
126
|
};
|
|
124
127
|
}
|
|
125
128
|
|
|
@@ -131,6 +134,7 @@ function globalOpenCodeConfigPaths(configDir) {
|
|
|
131
134
|
skills: join(configDir, "skills"),
|
|
132
135
|
localValidator: join(configDir, "agdf", "bin", "agdf-local.js"),
|
|
133
136
|
localValidatorPackage: join(configDir, "agdf", "package.json"),
|
|
137
|
+
evaluatorAgent: join(configDir, "agents", `${pluginDefinition.opencode.evaluatorAgentName}.md`),
|
|
134
138
|
};
|
|
135
139
|
}
|
|
136
140
|
|
|
@@ -179,6 +183,7 @@ function assertGlobalOpenCodeSurfaceWritable(configDir) {
|
|
|
179
183
|
assertGlobalOpenCodeFileWritable(paths.instructions, globalOpenCodeInstructionsOwnershipMarker, "first-line");
|
|
180
184
|
assertGlobalOpenCodeFileWritable(paths.runtimeContract, globalOpenCodeRuntimeContractOwnershipMarker, "first-line");
|
|
181
185
|
assertGlobalOpenCodeFileWritable(paths.localValidator, globalOpenCodeValidatorOwnershipMarker, "first-line");
|
|
186
|
+
assertGlobalOpenCodeFileWritable(paths.evaluatorAgent, globalOpenCodeAgentOwnershipMarker, "after-frontmatter");
|
|
182
187
|
assertGlobalOpenCodeValidatorPackageWritable(paths.localValidatorPackage);
|
|
183
188
|
for (const moduleName of contractModules) {
|
|
184
189
|
assertGlobalOpenCodeFileWritable(
|
|
@@ -212,6 +217,10 @@ function globalOpenCodeBoundary() {
|
|
|
212
217
|
"Before applying AGDF gates, later artefacts or implementation guidance, inspect the current repository for valid `.agdf/control/config.json` durable control.",
|
|
213
218
|
"If durable control is missing or invalid, stop and direct the user to `npx --yes @agdf/cli@latest opencode-repo` in this repository.",
|
|
214
219
|
"When durable control is valid, use the global `agdf-global-*` skill surface; existing local OpenCode assets remain a compatibility path.",
|
|
220
|
+
"Only exact `Approval: <GateName>` values can advance AGDF gates; host permissions and plugin hooks never grant delivery authority.",
|
|
221
|
+
"Resolve and use the installed version-matched `agdf/bin/agdf-local.js` validator for deterministic checks.",
|
|
222
|
+
"If activation, approval, evidence or validator ownership is missing or unclear, stop before later artefacts or implementation.",
|
|
223
|
+
"Use `opencode-status --json` to inspect installed hook declarations, version divergence and evaluator availability without treating SDK declarations as live hook execution proof.",
|
|
215
224
|
"",
|
|
216
225
|
].join("\n");
|
|
217
226
|
}
|
|
@@ -255,10 +264,27 @@ export function installOpenCodeGlobalSurface(configDir) {
|
|
|
255
264
|
].join("\n");
|
|
256
265
|
const globalRuntimeContract = `${globalOpenCodeRuntimeContractOwnershipMarker}\n${generatedRuntimeContract}`;
|
|
257
266
|
const localValidator = `${globalOpenCodeValidatorOwnershipMarker}\nimport process from "node:process";\nimport { fileURLToPath } from "node:url";\nimport { runLocalValidator } from "../../node_modules/create-agdf/lib/runtime/local-validator.js";\n\nconst ownedPackageRoot = fileURLToPath(new URL("../../node_modules/create-agdf", import.meta.url));\nprocess.exitCode = runLocalValidator({ ownedPackageRoot, expectedVersion: ${JSON.stringify(pluginDefinition.version)}, surface: "opencode" }, process.argv.slice(2));\n`;
|
|
267
|
+
const evaluatorAgent = [
|
|
268
|
+
"---",
|
|
269
|
+
"description: Evaluate one AGDF Delivery Path Search candidate without tools or side effects.",
|
|
270
|
+
"mode: primary",
|
|
271
|
+
"permission:",
|
|
272
|
+
' "*": deny',
|
|
273
|
+
"---",
|
|
274
|
+
globalOpenCodeAgentOwnershipMarker,
|
|
275
|
+
"",
|
|
276
|
+
"# AGDF Delivery Path Search evaluator",
|
|
277
|
+
"",
|
|
278
|
+
"Evaluate only the bounded candidate supplied in the user message.",
|
|
279
|
+
"Do not call tools, inspect files, delegate work or modify state.",
|
|
280
|
+
"Return only the requested JSON object; AGDF validates it independently.",
|
|
281
|
+
"",
|
|
282
|
+
].join("\n");
|
|
258
283
|
|
|
259
284
|
writeOwnedGlobalOpenCodeFile(paths.instructions, globalInstructions, globalOpenCodeInstructionsOwnershipMarker, "first-line");
|
|
260
285
|
writeOwnedGlobalOpenCodeFile(paths.runtimeContract, globalRuntimeContract, globalOpenCodeRuntimeContractOwnershipMarker, "first-line");
|
|
261
286
|
writeOwnedGlobalOpenCodeFile(paths.localValidator, localValidator, globalOpenCodeValidatorOwnershipMarker, "first-line");
|
|
287
|
+
writeOwnedGlobalOpenCodeFile(paths.evaluatorAgent, evaluatorAgent, globalOpenCodeAgentOwnershipMarker, "after-frontmatter");
|
|
262
288
|
mkdirSync(dirname(paths.localValidatorPackage), { recursive: true });
|
|
263
289
|
writeFileSync(paths.localValidatorPackage, `${JSON.stringify({
|
|
264
290
|
name: "agdf-opencode-validator-runtime",
|
|
@@ -296,6 +322,7 @@ export function installOpenCodeGlobalSurface(configDir) {
|
|
|
296
322
|
skills: paths.skills,
|
|
297
323
|
localValidator: paths.localValidator,
|
|
298
324
|
localValidatorPackage: paths.localValidatorPackage,
|
|
325
|
+
evaluatorAgent: paths.evaluatorAgent,
|
|
299
326
|
};
|
|
300
327
|
}
|
|
301
328
|
|
|
@@ -308,24 +335,64 @@ function readOpenCodeConfig(configPath) {
|
|
|
308
335
|
}
|
|
309
336
|
}
|
|
310
337
|
|
|
311
|
-
function
|
|
312
|
-
const
|
|
338
|
+
export function resolveOpenCodeInstalledPackage(configDir, packageName, dependencies = {}) {
|
|
339
|
+
const run = dependencies.execFileSync ?? execFileSync;
|
|
313
340
|
try {
|
|
314
|
-
const
|
|
341
|
+
const probe = [
|
|
342
|
+
'const fs = require("node:fs");',
|
|
343
|
+
'const path = require("node:path");',
|
|
344
|
+
`const packageName = ${JSON.stringify(packageName)};`,
|
|
345
|
+
'let resolvedPath = "";',
|
|
346
|
+
'try { resolvedPath = require.resolve(packageName); } catch {}',
|
|
347
|
+
'let manifestPath = "";',
|
|
348
|
+
'for (const root of require.resolve.paths(packageName) || []) {',
|
|
349
|
+
' const candidate = path.join(root, packageName, "package.json");',
|
|
350
|
+
' if (fs.existsSync(candidate)) { manifestPath = candidate; break; }',
|
|
351
|
+
'}',
|
|
352
|
+
'if (!manifestPath) throw new Error(`installed package manifest not found: ${packageName}`);',
|
|
353
|
+
'process.stdout.write(JSON.stringify({ resolvedPath, manifestPath }));',
|
|
354
|
+
].join("\n");
|
|
355
|
+
const rawResolution = run(process.execPath, ["-e", probe], {
|
|
315
356
|
cwd: configDir,
|
|
316
357
|
encoding: "utf8",
|
|
317
358
|
stdio: "pipe",
|
|
318
359
|
});
|
|
319
|
-
let
|
|
360
|
+
let resolvedPath = rawResolution;
|
|
361
|
+
let probedManifestPath = "";
|
|
320
362
|
try {
|
|
321
|
-
const
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
363
|
+
const parsed = JSON.parse(rawResolution);
|
|
364
|
+
resolvedPath = parsed.resolvedPath || parsed.manifestPath;
|
|
365
|
+
probedManifestPath = parsed.manifestPath;
|
|
366
|
+
} catch {}
|
|
367
|
+
let current = probedManifestPath ? dirname(probedManifestPath) : dirname(resolvedPath);
|
|
368
|
+
let manifestPath = "";
|
|
369
|
+
let packageRoot = "";
|
|
370
|
+
let manifest = null;
|
|
371
|
+
for (let depth = 0; depth < 20; depth += 1) {
|
|
372
|
+
const candidate = join(current, "package.json");
|
|
373
|
+
if (existsSync(candidate)) {
|
|
374
|
+
try {
|
|
375
|
+
const value = JSON.parse(readFileSync(candidate, "utf8"));
|
|
376
|
+
if (value?.name === packageName) {
|
|
377
|
+
manifestPath = candidate;
|
|
378
|
+
packageRoot = current;
|
|
379
|
+
manifest = value;
|
|
380
|
+
break;
|
|
381
|
+
}
|
|
382
|
+
} catch {}
|
|
383
|
+
}
|
|
384
|
+
const parent = dirname(current);
|
|
385
|
+
if (parent === current) break;
|
|
386
|
+
current = parent;
|
|
325
387
|
}
|
|
388
|
+
if (!manifest) throw new Error(`resolved ${packageName} entry has no matching package manifest`);
|
|
389
|
+
const installedVersion = typeof manifest.version === "string" && manifest.version.trim() ? manifest.version.trim() : "";
|
|
326
390
|
return {
|
|
327
391
|
loadable: true,
|
|
328
392
|
path: resolvedPath,
|
|
393
|
+
manifest_path: manifestPath,
|
|
394
|
+
package_root: packageRoot,
|
|
395
|
+
manifest,
|
|
329
396
|
installed_version: installedVersion,
|
|
330
397
|
error: "",
|
|
331
398
|
};
|
|
@@ -333,12 +400,252 @@ function resolveOpenCodePackage(configDir) {
|
|
|
333
400
|
return {
|
|
334
401
|
loadable: false,
|
|
335
402
|
path: "",
|
|
403
|
+
manifest_path: "",
|
|
404
|
+
package_root: "",
|
|
405
|
+
manifest: null,
|
|
336
406
|
installed_version: "",
|
|
337
407
|
error: (error.stderr || error.message || "package not resolvable").toString().trim(),
|
|
338
408
|
};
|
|
339
409
|
}
|
|
340
410
|
}
|
|
341
411
|
|
|
412
|
+
function resolveOpenCodePackage(configDir) {
|
|
413
|
+
return resolveOpenCodeInstalledPackage(configDir, pluginDefinition.opencode.npmPackage);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
const requiredExperimentalHooks = [
|
|
417
|
+
"experimental.chat.system.transform",
|
|
418
|
+
"experimental.session.compacting",
|
|
419
|
+
];
|
|
420
|
+
|
|
421
|
+
function packageLocalPath(packageRoot, candidate) {
|
|
422
|
+
if (!packageRoot || !candidate) return "";
|
|
423
|
+
const path = resolve(packageRoot, candidate);
|
|
424
|
+
const relation = relative(packageRoot, path);
|
|
425
|
+
return relation === "" || (relation !== ".." && !relation.startsWith(`..${sep}`) && !isAbsolute(relation)) ? path : "";
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function openCodeHostProbe(dependencies = {}) {
|
|
429
|
+
const executable = dependencies.openCodeBin ?? process.env.AGDF_OPENCODE_BIN ?? "opencode";
|
|
430
|
+
const run = dependencies.execFileSync ?? execFileSync;
|
|
431
|
+
try {
|
|
432
|
+
return {
|
|
433
|
+
name: "opencode",
|
|
434
|
+
executable,
|
|
435
|
+
inspectable: true,
|
|
436
|
+
installed_version: run(executable, ["--version"], {
|
|
437
|
+
encoding: "utf8",
|
|
438
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
439
|
+
timeout: 5000,
|
|
440
|
+
}).trim(),
|
|
441
|
+
error: "",
|
|
442
|
+
};
|
|
443
|
+
} catch (error) {
|
|
444
|
+
return {
|
|
445
|
+
name: "opencode",
|
|
446
|
+
executable,
|
|
447
|
+
inspectable: false,
|
|
448
|
+
installed_version: "",
|
|
449
|
+
error: (error.stderr || error.message || "host version unavailable").toString().trim(),
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function openCodeSdkProbe(configDir, dependencies = {}) {
|
|
455
|
+
const sdk = resolveOpenCodeInstalledPackage(configDir, "@opencode-ai/plugin", dependencies);
|
|
456
|
+
let declarationPath = "";
|
|
457
|
+
let declaration = "";
|
|
458
|
+
if (sdk.loadable) {
|
|
459
|
+
const declaredEntry = sdk.manifest?.types || sdk.manifest?.typings || "dist/index.d.ts";
|
|
460
|
+
declarationPath = packageLocalPath(sdk.package_root, declaredEntry);
|
|
461
|
+
if (declarationPath && existsSync(declarationPath)) {
|
|
462
|
+
try {
|
|
463
|
+
declaration = readFileSync(declarationPath, "utf8");
|
|
464
|
+
} catch (error) {
|
|
465
|
+
sdk.error = error.message;
|
|
466
|
+
}
|
|
467
|
+
} else {
|
|
468
|
+
sdk.error = `SDK declaration not found: ${declaredEntry}`;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
const hooks = requiredExperimentalHooks.map((name) => ({
|
|
472
|
+
name,
|
|
473
|
+
state: !declaration
|
|
474
|
+
? "uninspectable"
|
|
475
|
+
: declaration.includes(`"${name}"`)
|
|
476
|
+
? "declared_supported"
|
|
477
|
+
: "declared_missing",
|
|
478
|
+
}));
|
|
479
|
+
const states = hooks.map((hook) => hook.state);
|
|
480
|
+
const aggregate = states.every((state) => state === "declared_supported")
|
|
481
|
+
? "declared_supported"
|
|
482
|
+
: states.some((state) => state === "uninspectable")
|
|
483
|
+
? "uninspectable"
|
|
484
|
+
: "degraded";
|
|
485
|
+
return {
|
|
486
|
+
package: {
|
|
487
|
+
name: "@opencode-ai/plugin",
|
|
488
|
+
loadable: sdk.loadable,
|
|
489
|
+
resolved_path: sdk.path,
|
|
490
|
+
manifest_path: sdk.manifest_path,
|
|
491
|
+
declaration_path: declarationPath,
|
|
492
|
+
installed_version: sdk.installed_version || null,
|
|
493
|
+
error: sdk.error,
|
|
494
|
+
},
|
|
495
|
+
hooks: {
|
|
496
|
+
evidence_level: "sdk_declaration",
|
|
497
|
+
aggregate,
|
|
498
|
+
hooks,
|
|
499
|
+
live_invocation_observed: false,
|
|
500
|
+
},
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
export function evaluateOpenCodeHostSdk(configDir, dependencies = {}) {
|
|
505
|
+
const host = openCodeHostProbe(dependencies);
|
|
506
|
+
const sdk = openCodeSdkProbe(configDir, dependencies);
|
|
507
|
+
return {
|
|
508
|
+
host,
|
|
509
|
+
plugin_sdk: sdk.package,
|
|
510
|
+
experimental_hooks: sdk.hooks,
|
|
511
|
+
host_sdk_version: {
|
|
512
|
+
status: !host.installed_version || !sdk.package.installed_version
|
|
513
|
+
? "unknown"
|
|
514
|
+
: host.installed_version === sdk.package.installed_version
|
|
515
|
+
? "matching"
|
|
516
|
+
: "divergent",
|
|
517
|
+
host_version: host.installed_version || null,
|
|
518
|
+
sdk_version: sdk.package.installed_version || null,
|
|
519
|
+
policy: "warn_only",
|
|
520
|
+
},
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
const exactOpenCodeVersionPattern = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
|
|
525
|
+
|
|
526
|
+
function openCodeSdkAlignmentResult(status, initial, overrides = {}) {
|
|
527
|
+
return {
|
|
528
|
+
status,
|
|
529
|
+
attempted: false,
|
|
530
|
+
host_version: initial.host.installed_version || null,
|
|
531
|
+
previous_version: initial.plugin_sdk.installed_version || null,
|
|
532
|
+
target_version: null,
|
|
533
|
+
installed_version: initial.plugin_sdk.installed_version || null,
|
|
534
|
+
error: "",
|
|
535
|
+
...overrides,
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
function openCodeRegistryVersion(raw) {
|
|
540
|
+
const value = String(raw ?? "").trim();
|
|
541
|
+
if (!value) return "";
|
|
542
|
+
try {
|
|
543
|
+
const parsed = JSON.parse(value);
|
|
544
|
+
return typeof parsed === "string" ? parsed.trim() : "";
|
|
545
|
+
} catch {
|
|
546
|
+
return value;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
function openCodeSdkUnavailable(error) {
|
|
551
|
+
return /(?:ETARGET|E404|404 Not Found|No matching version)/i.test(
|
|
552
|
+
(error?.stderr || error?.message || "").toString(),
|
|
553
|
+
);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
export function alignOpenCodePluginSdk(configDir, dependencies = {}) {
|
|
557
|
+
const initial = evaluateOpenCodeHostSdk(configDir, dependencies);
|
|
558
|
+
const hostVersion = initial.host.installed_version || "";
|
|
559
|
+
const sdkVersion = initial.plugin_sdk.installed_version || "";
|
|
560
|
+
if (!initial.host.inspectable || !initial.plugin_sdk.loadable || !exactOpenCodeVersionPattern.test(hostVersion)) {
|
|
561
|
+
return openCodeSdkAlignmentResult("not_attempted", initial, {
|
|
562
|
+
target_version: exactOpenCodeVersionPattern.test(hostVersion) ? hostVersion : null,
|
|
563
|
+
error: !initial.host.inspectable
|
|
564
|
+
? initial.host.error || "OpenCode host version is not inspectable."
|
|
565
|
+
: !initial.plugin_sdk.loadable
|
|
566
|
+
? initial.plugin_sdk.error || "OpenCode plugin SDK is not inspectable."
|
|
567
|
+
: `OpenCode host version is not an exact semantic version: ${hostVersion || "unknown"}`,
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
if (sdkVersion === hostVersion) {
|
|
571
|
+
return openCodeSdkAlignmentResult("already_matching", initial, {
|
|
572
|
+
target_version: hostVersion,
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
const run = dependencies.execFileSync ?? execFileSync;
|
|
577
|
+
const packageSpecifier = `@opencode-ai/plugin@${hostVersion}`;
|
|
578
|
+
const registryInvocation = openCodeNpmInvocation(["view", packageSpecifier, "version", "--json"]);
|
|
579
|
+
try {
|
|
580
|
+
const availableVersion = openCodeRegistryVersion(run(registryInvocation.executable, registryInvocation.args, {
|
|
581
|
+
cwd: configDir,
|
|
582
|
+
encoding: "utf8",
|
|
583
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
584
|
+
timeout: 15000,
|
|
585
|
+
}));
|
|
586
|
+
if (availableVersion !== hostVersion) {
|
|
587
|
+
return openCodeSdkAlignmentResult("unavailable", initial, {
|
|
588
|
+
target_version: hostVersion,
|
|
589
|
+
error: `Exact plugin SDK version is unavailable: ${packageSpecifier}`,
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
} catch (error) {
|
|
593
|
+
return openCodeSdkAlignmentResult(openCodeSdkUnavailable(error) ? "unavailable" : "failed", initial, {
|
|
594
|
+
target_version: hostVersion,
|
|
595
|
+
error: (error.stderr || error.message || "plugin SDK registry lookup failed").toString().trim(),
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
const installInvocation = openCodeNpmInvocation([
|
|
600
|
+
"install",
|
|
601
|
+
"--silent",
|
|
602
|
+
"--ignore-scripts",
|
|
603
|
+
"--no-audit",
|
|
604
|
+
"--no-fund",
|
|
605
|
+
"--save-prod",
|
|
606
|
+
"--save-exact",
|
|
607
|
+
packageSpecifier,
|
|
608
|
+
]);
|
|
609
|
+
let installError = null;
|
|
610
|
+
try {
|
|
611
|
+
run(installInvocation.executable, installInvocation.args, {
|
|
612
|
+
cwd: configDir,
|
|
613
|
+
encoding: "utf8",
|
|
614
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
615
|
+
timeout: 60000,
|
|
616
|
+
});
|
|
617
|
+
} catch (error) {
|
|
618
|
+
installError = error;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
const observed = evaluateOpenCodeHostSdk(configDir, dependencies);
|
|
622
|
+
const verified = observed.plugin_sdk.installed_version === hostVersion
|
|
623
|
+
&& observed.experimental_hooks.aggregate === "declared_supported";
|
|
624
|
+
if (installError) {
|
|
625
|
+
return openCodeSdkAlignmentResult("failed", initial, {
|
|
626
|
+
attempted: true,
|
|
627
|
+
target_version: hostVersion,
|
|
628
|
+
installed_version: observed.plugin_sdk.installed_version || null,
|
|
629
|
+
error: (installError.stderr || installError.message || "plugin SDK installation failed").toString().trim(),
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
if (!verified) {
|
|
633
|
+
return openCodeSdkAlignmentResult("verification_failed", initial, {
|
|
634
|
+
attempted: true,
|
|
635
|
+
target_version: hostVersion,
|
|
636
|
+
installed_version: observed.plugin_sdk.installed_version || null,
|
|
637
|
+
error: observed.plugin_sdk.installed_version !== hostVersion
|
|
638
|
+
? `Observed plugin SDK ${observed.plugin_sdk.installed_version || "unknown"} after targeting ${hostVersion}.`
|
|
639
|
+
: `Plugin SDK ${hostVersion} does not declare all required experimental hooks.`,
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
return openCodeSdkAlignmentResult("aligned", initial, {
|
|
643
|
+
attempted: true,
|
|
644
|
+
target_version: hostVersion,
|
|
645
|
+
installed_version: observed.plugin_sdk.installed_version,
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
|
|
342
649
|
function openCodePackageVersionStatus(packageState) {
|
|
343
650
|
if (!packageState.loadable) return "unloadable";
|
|
344
651
|
if (!packageState.installed_version) return "unknown";
|
|
@@ -393,18 +700,24 @@ function evaluateGlobalOpenCodeSurface(configDir) {
|
|
|
393
700
|
present: existsSync(paths.localValidator),
|
|
394
701
|
...validatorResolution.envelope,
|
|
395
702
|
},
|
|
703
|
+
evaluator_agent: {
|
|
704
|
+
name: pluginDefinition.opencode.evaluatorAgentName,
|
|
705
|
+
path: paths.evaluatorAgent,
|
|
706
|
+
present: existsSync(paths.evaluatorAgent),
|
|
707
|
+
},
|
|
396
708
|
present: existsSync(paths.skills),
|
|
397
709
|
complete: existsSync(paths.instructions)
|
|
398
710
|
&& existsSync(paths.runtimeContract)
|
|
399
711
|
&& contractCount === contractModules.length
|
|
400
712
|
&& skillCount === openCodeSkillNames.length
|
|
401
713
|
&& existsSync(paths.localValidator)
|
|
714
|
+
&& existsSync(paths.evaluatorAgent)
|
|
402
715
|
&& globalOpenCodeValidatorPackageIsValid(paths.localValidatorPackage)
|
|
403
716
|
&& validatorResolution.envelope.machine_validation === "owned_version_matched",
|
|
404
717
|
};
|
|
405
718
|
}
|
|
406
719
|
|
|
407
|
-
export function evaluateOpenCodeStatus(targetDir, configDir = defaultOpenCodeConfigDir(), transition = null) {
|
|
720
|
+
export function evaluateOpenCodeStatus(targetDir, configDir = defaultOpenCodeConfigDir(), transition = null, dependencies = {}) {
|
|
408
721
|
const configPath = join(configDir, "opencode.json");
|
|
409
722
|
const configState = readOpenCodeConfig(configPath);
|
|
410
723
|
const plugins = Array.isArray(configState.config.plugin) ? configState.config.plugin : [];
|
|
@@ -412,6 +725,7 @@ export function evaluateOpenCodeStatus(targetDir, configDir = defaultOpenCodeCon
|
|
|
412
725
|
const packageState = resolveOpenCodePackage(configDir);
|
|
413
726
|
const packageVersionStatus = openCodePackageVersionStatus(packageState);
|
|
414
727
|
const globalNativeSurface = evaluateGlobalOpenCodeSurface(configDir);
|
|
728
|
+
const hostSdk = evaluateOpenCodeHostSdk(configDir, dependencies);
|
|
415
729
|
const sessionSignals = {
|
|
416
730
|
active: process.env.AGDF_PLUGIN_ACTIVE === "1",
|
|
417
731
|
version: process.env.AGDF_PLUGIN_VERSION || "",
|
|
@@ -434,6 +748,11 @@ export function evaluateOpenCodeStatus(targetDir, configDir = defaultOpenCodeCon
|
|
|
434
748
|
`Global OpenCode native surface is incomplete (${globalNativeSurface.skill_count}/${globalNativeSurface.expected_skill_count} skills; ${globalNativeSurface.contract_count}/${globalNativeSurface.expected_contract_count} contract modules).`,
|
|
435
749
|
);
|
|
436
750
|
}
|
|
751
|
+
if (hostSdk.experimental_hooks.aggregate === "uninspectable") findings.push("Installed OpenCode plugin SDK hook declarations could not be inspected.");
|
|
752
|
+
if (hostSdk.experimental_hooks.aggregate === "degraded") findings.push("Installed OpenCode plugin SDK is missing one or more required experimental hook declarations.");
|
|
753
|
+
if (hostSdk.host_sdk_version.status === "divergent") {
|
|
754
|
+
findings.push(`OpenCode host ${hostSdk.host_sdk_version.host_version} and plugin SDK ${hostSdk.host_sdk_version.sdk_version} diverge; policy is warning-only.`);
|
|
755
|
+
}
|
|
437
756
|
if (!sessionSignals.active) findings.push("No active AGDF OpenCode session signal is visible in this process.");
|
|
438
757
|
if (!repositoryActivation.active) {
|
|
439
758
|
findings.push(repositoryActivation.state === "invalid_control"
|
|
@@ -460,6 +779,7 @@ export function evaluateOpenCodeStatus(targetDir, configDir = defaultOpenCodeCon
|
|
|
460
779
|
...(transition ? { transition } : {}),
|
|
461
780
|
error: packageState.error,
|
|
462
781
|
},
|
|
782
|
+
...hostSdk,
|
|
463
783
|
global_native_surface: globalNativeSurface,
|
|
464
784
|
session: sessionSignals,
|
|
465
785
|
repository_activation: repositoryActivation.state,
|
|
@@ -482,6 +802,12 @@ export function evaluateOpenCodeStatus(targetDir, configDir = defaultOpenCodeCon
|
|
|
482
802
|
? "Run npx --yes @agdf/cli@latest opencode to install or repair the OpenCode package version."
|
|
483
803
|
: !globalNativeSurface.complete
|
|
484
804
|
? "Run npx --yes @agdf/cli@latest opencode to install or repair the global native OpenCode skill surface."
|
|
805
|
+
: hostSdk.experimental_hooks.aggregate === "uninspectable"
|
|
806
|
+
? "Repair the installed OpenCode plugin SDK so its declarations can be inspected; do not assume dynamic hook support."
|
|
807
|
+
: hostSdk.experimental_hooks.aggregate === "degraded"
|
|
808
|
+
? "Use static AGDF instructions and review OpenCode compatibility before relying on dynamic hook injection."
|
|
809
|
+
: hostSdk.host_sdk_version.status === "divergent"
|
|
810
|
+
? "Run npx --yes @agdf/cli@latest opencode to align the plugin SDK to the exact OpenCode host version; status itself remains read-only."
|
|
485
811
|
: repositoryActivation.state === "invalid_control"
|
|
486
812
|
? "Repair .agdf/control/config.json so it contains valid artifact_language, chat_language and runtime_language values."
|
|
487
813
|
: repositoryActivation.active
|
|
@@ -505,6 +831,11 @@ export function printOpenCodeStatus(report, json, io = console) {
|
|
|
505
831
|
io.log(`Package version: ${report.package.installed_version || "unknown"}`);
|
|
506
832
|
io.log(`Expected version: ${report.package.expected_version}`);
|
|
507
833
|
io.log(`Version status: ${report.package.version_status}`);
|
|
834
|
+
io.log(`OpenCode host version: ${report.host.installed_version || "unknown"}`);
|
|
835
|
+
io.log(`Plugin SDK version: ${report.plugin_sdk.installed_version || "unknown"}`);
|
|
836
|
+
io.log(`Host/SDK version: ${report.host_sdk_version.status} (${report.host_sdk_version.policy})`);
|
|
837
|
+
io.log(`Experimental hook declarations: ${report.experimental_hooks.aggregate} (${report.experimental_hooks.evidence_level}; live invocation not observed)`);
|
|
838
|
+
for (const hook of report.experimental_hooks.hooks) io.log(`- ${hook.name}: ${hook.state}`);
|
|
508
839
|
if (report.package.transition?.status === "updated") {
|
|
509
840
|
io.log(`Version transition: ${report.package.transition.previous_version} -> ${report.package.transition.installed_version}`);
|
|
510
841
|
} else if (report.package.transition?.status === "installed") {
|
|
@@ -349,6 +349,91 @@ export function renderOperationalStatusCard(statusCard, {
|
|
|
349
349
|
});
|
|
350
350
|
}
|
|
351
351
|
|
|
352
|
+
export function renderTaskTargetOrientation(resolution, {
|
|
353
|
+
registry,
|
|
354
|
+
requestedLocale,
|
|
355
|
+
} = {}) {
|
|
356
|
+
if (!plainObject(resolution)) return null;
|
|
357
|
+
|
|
358
|
+
const resolutionState = String(resolution.resolution_state ?? "").trim();
|
|
359
|
+
const reasonCode = String(resolution.reason_code ?? "").trim();
|
|
360
|
+
const primaryTarget = String(resolution.primary_target ?? "").trim();
|
|
361
|
+
const governanceTarget = String(resolution.governance_target ?? "").trim();
|
|
362
|
+
const workingDirectory = String(resolution.working_directory ?? "").trim();
|
|
363
|
+
const nextAction = String(resolution.next_action ?? "").trim();
|
|
364
|
+
if (typeof resolution.target_changed !== "boolean") return null;
|
|
365
|
+
const targetChanged = resolution.target_changed === true;
|
|
366
|
+
const evidenceSources = Array.isArray(resolution.evidence_sources)
|
|
367
|
+
? resolution.evidence_sources.map((item) => String(item ?? "").trim()).filter(Boolean)
|
|
368
|
+
: null;
|
|
369
|
+
|
|
370
|
+
const resolvedReasons = new Set(["explicit_target", "continued_target"]);
|
|
371
|
+
const unresolvedReasons = new Set([
|
|
372
|
+
"multiple_plausible_targets",
|
|
373
|
+
"target_content_mismatch",
|
|
374
|
+
"target_unavailable",
|
|
375
|
+
"no_reliable_target",
|
|
376
|
+
]);
|
|
377
|
+
|
|
378
|
+
if (!["resolved", "unresolved"].includes(resolutionState)) return null;
|
|
379
|
+
if (!workingDirectory || evidenceSources === null) return null;
|
|
380
|
+
if (resolutionState === "resolved") {
|
|
381
|
+
if (!resolvedReasons.has(reasonCode) || !primaryTarget || nextAction) return null;
|
|
382
|
+
} else if (!unresolvedReasons.has(reasonCode) || primaryTarget || governanceTarget || !nextAction || targetChanged) {
|
|
383
|
+
return null;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
let locale;
|
|
387
|
+
try {
|
|
388
|
+
locale = resolvePresentationLocale(registry, requestedLocale);
|
|
389
|
+
} catch {
|
|
390
|
+
return null;
|
|
391
|
+
}
|
|
392
|
+
if (!locale) return null;
|
|
393
|
+
|
|
394
|
+
const pack = localePack(registry, locale);
|
|
395
|
+
const labels = pack?.taskTargetResolution;
|
|
396
|
+
if (!plainObject(labels) || !plainObject(labels.reasonCodes)) return null;
|
|
397
|
+
const reason = labels.reasonCodes[reasonCode];
|
|
398
|
+
if (!reason) return null;
|
|
399
|
+
|
|
400
|
+
const rows = resolutionState === "resolved"
|
|
401
|
+
? [
|
|
402
|
+
[labels.state, labels.resolved],
|
|
403
|
+
[labels.primaryTarget, primaryTarget],
|
|
404
|
+
[labels.governanceTarget, governanceTarget || labels.none],
|
|
405
|
+
[labels.evidenceSources, evidenceSources.join("; ") || labels.none],
|
|
406
|
+
[labels.workingDirectory, workingDirectory],
|
|
407
|
+
[labels.reason, reason],
|
|
408
|
+
...(targetChanged ? [[labels.targetChanged, labels.yes]] : []),
|
|
409
|
+
]
|
|
410
|
+
: [
|
|
411
|
+
[labels.state, labels.unresolved],
|
|
412
|
+
[labels.reason, reason],
|
|
413
|
+
[labels.evidenceSources, evidenceSources.join("; ") || labels.none],
|
|
414
|
+
[labels.workingDirectory, workingDirectory],
|
|
415
|
+
[labels.nextAction, nextAction],
|
|
416
|
+
];
|
|
417
|
+
|
|
418
|
+
const markdown = [
|
|
419
|
+
`## ${labels.title}`,
|
|
420
|
+
"",
|
|
421
|
+
`| ${labels.field} | ${labels.value} |`,
|
|
422
|
+
"|---|---|",
|
|
423
|
+
...rows.map(([label, value]) => `| ${markdownCell(label)} | ${markdownCell(value)} |`),
|
|
424
|
+
].join("\n");
|
|
425
|
+
|
|
426
|
+
return Object.freeze({
|
|
427
|
+
schema_version: "1",
|
|
428
|
+
semantic_block: "task_target_orientation",
|
|
429
|
+
presentation_language: locale,
|
|
430
|
+
resolution_state: resolutionState,
|
|
431
|
+
reason_code: reasonCode,
|
|
432
|
+
markdown,
|
|
433
|
+
authorizes: false,
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
|
|
352
437
|
export function renderScopeClassificationCard(classification, {
|
|
353
438
|
registry,
|
|
354
439
|
requestedLocale,
|
|
@@ -131,6 +131,10 @@ function openCodeOwnedGlobalFiles(configDir) {
|
|
|
131
131
|
const files = [
|
|
132
132
|
{ path: join(configDir, pluginDefinition.opencode.instructionsFileName), owned: firstLine("<!-- AGDF-GLOBAL-INSTRUCTIONS -->") },
|
|
133
133
|
{ path: join(configDir, pluginDefinition.opencode.runtimeContractFileName), owned: firstLine("<!-- AGDF-GLOBAL-RUNTIME-CONTRACT -->") },
|
|
134
|
+
{
|
|
135
|
+
path: join(configDir, "agents", `${pluginDefinition.opencode.evaluatorAgentName}.md`),
|
|
136
|
+
owned: afterFrontmatter(`<!-- AGDF-GLOBAL-AGENT: ${pluginDefinition.opencode.evaluatorAgentName} -->`),
|
|
137
|
+
},
|
|
134
138
|
];
|
|
135
139
|
for (const moduleName of ["gate-transition.md", "interaction.md", "modes.md", "quality.md", "context-graph.md", "control-scaffold.md", "closeout.md"]) {
|
|
136
140
|
files.push({ path: join(configDir, "contracts", moduleName), owned: firstLine("<!-- AGDF-GLOBAL-RUNTIME-CONTRACT -->") });
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { guardedExecFileSync } from "../delivery-path-search/transports/read-only-guard.js";
|
|
5
|
+
|
|
6
|
+
export function executeStructuredAgent({ surface, cwd, prompt, model, outputSchema, timeoutMs = 120000 }) {
|
|
7
|
+
if (surface === "codex") {
|
|
8
|
+
const temp = mkdtempSync(join(tmpdir(), "agdf-live-codex-"));
|
|
9
|
+
try {
|
|
10
|
+
const schemaPath = join(temp, "schema.json");
|
|
11
|
+
const outputPath = join(temp, "output.json");
|
|
12
|
+
writeFileSync(schemaPath, `${JSON.stringify(outputSchema, null, 2)}\n`, "utf8");
|
|
13
|
+
const args = [
|
|
14
|
+
"exec", "--sandbox", "read-only", "--ephemeral", "--ignore-user-config",
|
|
15
|
+
"--skip-git-repo-check", "--output-schema", schemaPath,
|
|
16
|
+
"--output-last-message", outputPath, "--color", "never",
|
|
17
|
+
];
|
|
18
|
+
if (model) args.push("--model", model);
|
|
19
|
+
args.push(prompt);
|
|
20
|
+
guardedExecFileSync("codex", args, {
|
|
21
|
+
cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: timeoutMs,
|
|
22
|
+
});
|
|
23
|
+
return readFileSync(outputPath, "utf8");
|
|
24
|
+
} finally {
|
|
25
|
+
rmSync(temp, { recursive: true, force: true });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (surface === "claude") {
|
|
29
|
+
const args = [
|
|
30
|
+
"-p", "--disallowedTools", "Edit,Write,Bash", "--output-format", "json",
|
|
31
|
+
"--json-schema", JSON.stringify(outputSchema),
|
|
32
|
+
];
|
|
33
|
+
if (model) args.push("--model", model);
|
|
34
|
+
args.push(prompt);
|
|
35
|
+
const raw = guardedExecFileSync("claude", args, {
|
|
36
|
+
cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: timeoutMs,
|
|
37
|
+
});
|
|
38
|
+
const envelope = JSON.parse(raw);
|
|
39
|
+
if (envelope.is_error) throw new Error(`claude live adapter failed: ${envelope.result ?? "unknown error"}`);
|
|
40
|
+
return envelope.result;
|
|
41
|
+
}
|
|
42
|
+
throw new Error(`unsupported live surface: ${surface}`);
|
|
43
|
+
}
|