create-agdf 0.11.3 → 0.11.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +5 -4
  2. package/generated/.agdf/control/templates/MASTER_BACKLOG.md +1 -1
  3. package/generated/.github/skills/contracts/control-scaffold.md +2 -0
  4. package/generated/.opencode/contracts/control-scaffold.md +2 -0
  5. package/generated/plugins/agdf/.claude-plugin/plugin.json +1 -1
  6. package/generated/plugins/agdf/.codex-plugin/plugin.json +1 -1
  7. package/generated/plugins/agdf/control/templates/MASTER_BACKLOG.md +1 -1
  8. package/generated/plugins/agdf/meta/agdf-plugin.definition.json +2 -1
  9. package/generated/plugins/agdf/meta/contracts/control-scaffold.md +2 -0
  10. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-plugin.definition.json +2 -1
  11. package/generated/plugins/agdf/runtime/create-agdf/lib/cli/command-registry.js +2 -2
  12. package/generated/plugins/agdf/runtime/create-agdf/lib/cli/delivery-path-search-command.js +78 -14
  13. package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/shared.js +1 -0
  14. package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/claude.js +2 -11
  15. package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/codex.js +2 -11
  16. package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/opencode.js +234 -0
  17. package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/prompt.js +13 -0
  18. package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/search-engine.js +1 -0
  19. package/generated/plugins/agdf/runtime/create-agdf/lib/delivery-path-search/surfaces/capabilities.js +15 -2
  20. package/generated/plugins/agdf/runtime/create-agdf/package.json +3 -2
  21. package/generated/plugins/agdf/runtime/runtime-manifest.json +2 -2
  22. package/lib/cli/application.js +17 -2
  23. package/lib/cli/command-registry.js +2 -2
  24. package/lib/cli/delivery-path-search-command.js +78 -14
  25. package/lib/control-evaluation/shared.js +1 -0
  26. package/lib/delivery-path-search/evaluators/claude.js +2 -11
  27. package/lib/delivery-path-search/evaluators/codex.js +2 -11
  28. package/lib/delivery-path-search/evaluators/opencode.js +234 -0
  29. package/lib/delivery-path-search/evaluators/prompt.js +13 -0
  30. package/lib/delivery-path-search/search-engine.js +1 -0
  31. package/lib/delivery-path-search/surfaces/capabilities.js +15 -2
  32. package/lib/installers/opencode.js +214 -10
  33. package/lib/lifecycle/operations.js +4 -0
  34. package/opencode-plugin.js +19 -2
  35. package/package.json +3 -2
@@ -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";
@@ -131,6 +132,7 @@ function globalOpenCodeConfigPaths(configDir) {
131
132
  skills: join(configDir, "skills"),
132
133
  localValidator: join(configDir, "agdf", "bin", "agdf-local.js"),
133
134
  localValidatorPackage: join(configDir, "agdf", "package.json"),
135
+ evaluatorAgent: join(configDir, "agents", `${pluginDefinition.opencode.evaluatorAgentName}.md`),
134
136
  };
135
137
  }
136
138
 
@@ -179,6 +181,7 @@ function assertGlobalOpenCodeSurfaceWritable(configDir) {
179
181
  assertGlobalOpenCodeFileWritable(paths.instructions, globalOpenCodeInstructionsOwnershipMarker, "first-line");
180
182
  assertGlobalOpenCodeFileWritable(paths.runtimeContract, globalOpenCodeRuntimeContractOwnershipMarker, "first-line");
181
183
  assertGlobalOpenCodeFileWritable(paths.localValidator, globalOpenCodeValidatorOwnershipMarker, "first-line");
184
+ assertGlobalOpenCodeFileWritable(paths.evaluatorAgent, globalOpenCodeAgentOwnershipMarker, "after-frontmatter");
182
185
  assertGlobalOpenCodeValidatorPackageWritable(paths.localValidatorPackage);
183
186
  for (const moduleName of contractModules) {
184
187
  assertGlobalOpenCodeFileWritable(
@@ -212,6 +215,10 @@ function globalOpenCodeBoundary() {
212
215
  "Before applying AGDF gates, later artefacts or implementation guidance, inspect the current repository for valid `.agdf/control/config.json` durable control.",
213
216
  "If durable control is missing or invalid, stop and direct the user to `npx --yes @agdf/cli@latest opencode-repo` in this repository.",
214
217
  "When durable control is valid, use the global `agdf-global-*` skill surface; existing local OpenCode assets remain a compatibility path.",
218
+ "Only exact `Approval: <GateName>` values can advance AGDF gates; host permissions and plugin hooks never grant delivery authority.",
219
+ "Resolve and use the installed version-matched `agdf/bin/agdf-local.js` validator for deterministic checks.",
220
+ "If activation, approval, evidence or validator ownership is missing or unclear, stop before later artefacts or implementation.",
221
+ "Use `opencode-status --json` to inspect installed hook declarations, version divergence and evaluator availability without treating SDK declarations as live hook execution proof.",
215
222
  "",
216
223
  ].join("\n");
217
224
  }
@@ -255,10 +262,27 @@ export function installOpenCodeGlobalSurface(configDir) {
255
262
  ].join("\n");
256
263
  const globalRuntimeContract = `${globalOpenCodeRuntimeContractOwnershipMarker}\n${generatedRuntimeContract}`;
257
264
  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`;
265
+ const evaluatorAgent = [
266
+ "---",
267
+ "description: Evaluate one AGDF Delivery Path Search candidate without tools or side effects.",
268
+ "mode: primary",
269
+ "permission:",
270
+ ' "*": deny',
271
+ "---",
272
+ globalOpenCodeAgentOwnershipMarker,
273
+ "",
274
+ "# AGDF Delivery Path Search evaluator",
275
+ "",
276
+ "Evaluate only the bounded candidate supplied in the user message.",
277
+ "Do not call tools, inspect files, delegate work or modify state.",
278
+ "Return only the requested JSON object; AGDF validates it independently.",
279
+ "",
280
+ ].join("\n");
258
281
 
259
282
  writeOwnedGlobalOpenCodeFile(paths.instructions, globalInstructions, globalOpenCodeInstructionsOwnershipMarker, "first-line");
260
283
  writeOwnedGlobalOpenCodeFile(paths.runtimeContract, globalRuntimeContract, globalOpenCodeRuntimeContractOwnershipMarker, "first-line");
261
284
  writeOwnedGlobalOpenCodeFile(paths.localValidator, localValidator, globalOpenCodeValidatorOwnershipMarker, "first-line");
285
+ writeOwnedGlobalOpenCodeFile(paths.evaluatorAgent, evaluatorAgent, globalOpenCodeAgentOwnershipMarker, "after-frontmatter");
262
286
  mkdirSync(dirname(paths.localValidatorPackage), { recursive: true });
263
287
  writeFileSync(paths.localValidatorPackage, `${JSON.stringify({
264
288
  name: "agdf-opencode-validator-runtime",
@@ -296,6 +320,7 @@ export function installOpenCodeGlobalSurface(configDir) {
296
320
  skills: paths.skills,
297
321
  localValidator: paths.localValidator,
298
322
  localValidatorPackage: paths.localValidatorPackage,
323
+ evaluatorAgent: paths.evaluatorAgent,
299
324
  };
300
325
  }
301
326
 
@@ -308,24 +333,64 @@ function readOpenCodeConfig(configPath) {
308
333
  }
309
334
  }
310
335
 
311
- function resolveOpenCodePackage(configDir) {
312
- const packageName = pluginDefinition.opencode.npmPackage;
336
+ export function resolveOpenCodeInstalledPackage(configDir, packageName, dependencies = {}) {
337
+ const run = dependencies.execFileSync ?? execFileSync;
313
338
  try {
314
- const resolvedPath = execFileSync(process.execPath, ["-e", `process.stdout.write(require.resolve(${JSON.stringify(packageName)}))`], {
339
+ const probe = [
340
+ 'const fs = require("node:fs");',
341
+ 'const path = require("node:path");',
342
+ `const packageName = ${JSON.stringify(packageName)};`,
343
+ 'let resolvedPath = "";',
344
+ 'try { resolvedPath = require.resolve(packageName); } catch {}',
345
+ 'let manifestPath = "";',
346
+ 'for (const root of require.resolve.paths(packageName) || []) {',
347
+ ' const candidate = path.join(root, packageName, "package.json");',
348
+ ' if (fs.existsSync(candidate)) { manifestPath = candidate; break; }',
349
+ '}',
350
+ 'if (!manifestPath) throw new Error(`installed package manifest not found: ${packageName}`);',
351
+ 'process.stdout.write(JSON.stringify({ resolvedPath, manifestPath }));',
352
+ ].join("\n");
353
+ const rawResolution = run(process.execPath, ["-e", probe], {
315
354
  cwd: configDir,
316
355
  encoding: "utf8",
317
356
  stdio: "pipe",
318
357
  });
319
- let installedVersion = "";
358
+ let resolvedPath = rawResolution;
359
+ let probedManifestPath = "";
320
360
  try {
321
- const packageManifest = JSON.parse(readFileSync(join(dirname(resolvedPath), "package.json"), "utf8"));
322
- installedVersion = typeof packageManifest.version === "string" && packageManifest.version.trim() ? packageManifest.version.trim() : "";
323
- } catch {
324
- installedVersion = "";
361
+ const parsed = JSON.parse(rawResolution);
362
+ resolvedPath = parsed.resolvedPath || parsed.manifestPath;
363
+ probedManifestPath = parsed.manifestPath;
364
+ } catch {}
365
+ let current = probedManifestPath ? dirname(probedManifestPath) : dirname(resolvedPath);
366
+ let manifestPath = "";
367
+ let packageRoot = "";
368
+ let manifest = null;
369
+ for (let depth = 0; depth < 20; depth += 1) {
370
+ const candidate = join(current, "package.json");
371
+ if (existsSync(candidate)) {
372
+ try {
373
+ const value = JSON.parse(readFileSync(candidate, "utf8"));
374
+ if (value?.name === packageName) {
375
+ manifestPath = candidate;
376
+ packageRoot = current;
377
+ manifest = value;
378
+ break;
379
+ }
380
+ } catch {}
381
+ }
382
+ const parent = dirname(current);
383
+ if (parent === current) break;
384
+ current = parent;
325
385
  }
386
+ if (!manifest) throw new Error(`resolved ${packageName} entry has no matching package manifest`);
387
+ const installedVersion = typeof manifest.version === "string" && manifest.version.trim() ? manifest.version.trim() : "";
326
388
  return {
327
389
  loadable: true,
328
390
  path: resolvedPath,
391
+ manifest_path: manifestPath,
392
+ package_root: packageRoot,
393
+ manifest,
329
394
  installed_version: installedVersion,
330
395
  error: "",
331
396
  };
@@ -333,12 +398,127 @@ function resolveOpenCodePackage(configDir) {
333
398
  return {
334
399
  loadable: false,
335
400
  path: "",
401
+ manifest_path: "",
402
+ package_root: "",
403
+ manifest: null,
336
404
  installed_version: "",
337
405
  error: (error.stderr || error.message || "package not resolvable").toString().trim(),
338
406
  };
339
407
  }
340
408
  }
341
409
 
410
+ function resolveOpenCodePackage(configDir) {
411
+ return resolveOpenCodeInstalledPackage(configDir, pluginDefinition.opencode.npmPackage);
412
+ }
413
+
414
+ const requiredExperimentalHooks = [
415
+ "experimental.chat.system.transform",
416
+ "experimental.session.compacting",
417
+ ];
418
+
419
+ function packageLocalPath(packageRoot, candidate) {
420
+ if (!packageRoot || !candidate) return "";
421
+ const path = resolve(packageRoot, candidate);
422
+ const relation = relative(packageRoot, path);
423
+ return relation === "" || (relation !== ".." && !relation.startsWith(`..${sep}`) && !isAbsolute(relation)) ? path : "";
424
+ }
425
+
426
+ function openCodeHostProbe(dependencies = {}) {
427
+ const executable = dependencies.openCodeBin ?? process.env.AGDF_OPENCODE_BIN ?? "opencode";
428
+ const run = dependencies.execFileSync ?? execFileSync;
429
+ try {
430
+ return {
431
+ name: "opencode",
432
+ executable,
433
+ inspectable: true,
434
+ installed_version: run(executable, ["--version"], {
435
+ encoding: "utf8",
436
+ stdio: ["ignore", "pipe", "pipe"],
437
+ timeout: 5000,
438
+ }).trim(),
439
+ error: "",
440
+ };
441
+ } catch (error) {
442
+ return {
443
+ name: "opencode",
444
+ executable,
445
+ inspectable: false,
446
+ installed_version: "",
447
+ error: (error.stderr || error.message || "host version unavailable").toString().trim(),
448
+ };
449
+ }
450
+ }
451
+
452
+ function openCodeSdkProbe(configDir, dependencies = {}) {
453
+ const sdk = resolveOpenCodeInstalledPackage(configDir, "@opencode-ai/plugin", dependencies);
454
+ let declarationPath = "";
455
+ let declaration = "";
456
+ if (sdk.loadable) {
457
+ const declaredEntry = sdk.manifest?.types || sdk.manifest?.typings || "dist/index.d.ts";
458
+ declarationPath = packageLocalPath(sdk.package_root, declaredEntry);
459
+ if (declarationPath && existsSync(declarationPath)) {
460
+ try {
461
+ declaration = readFileSync(declarationPath, "utf8");
462
+ } catch (error) {
463
+ sdk.error = error.message;
464
+ }
465
+ } else {
466
+ sdk.error = `SDK declaration not found: ${declaredEntry}`;
467
+ }
468
+ }
469
+ const hooks = requiredExperimentalHooks.map((name) => ({
470
+ name,
471
+ state: !declaration
472
+ ? "uninspectable"
473
+ : declaration.includes(`"${name}"`)
474
+ ? "declared_supported"
475
+ : "declared_missing",
476
+ }));
477
+ const states = hooks.map((hook) => hook.state);
478
+ const aggregate = states.every((state) => state === "declared_supported")
479
+ ? "declared_supported"
480
+ : states.some((state) => state === "uninspectable")
481
+ ? "uninspectable"
482
+ : "degraded";
483
+ return {
484
+ package: {
485
+ name: "@opencode-ai/plugin",
486
+ loadable: sdk.loadable,
487
+ resolved_path: sdk.path,
488
+ manifest_path: sdk.manifest_path,
489
+ declaration_path: declarationPath,
490
+ installed_version: sdk.installed_version || null,
491
+ error: sdk.error,
492
+ },
493
+ hooks: {
494
+ evidence_level: "sdk_declaration",
495
+ aggregate,
496
+ hooks,
497
+ live_invocation_observed: false,
498
+ },
499
+ };
500
+ }
501
+
502
+ export function evaluateOpenCodeHostSdk(configDir, dependencies = {}) {
503
+ const host = openCodeHostProbe(dependencies);
504
+ const sdk = openCodeSdkProbe(configDir, dependencies);
505
+ return {
506
+ host,
507
+ plugin_sdk: sdk.package,
508
+ experimental_hooks: sdk.hooks,
509
+ host_sdk_version: {
510
+ status: !host.installed_version || !sdk.package.installed_version
511
+ ? "unknown"
512
+ : host.installed_version === sdk.package.installed_version
513
+ ? "matching"
514
+ : "divergent",
515
+ host_version: host.installed_version || null,
516
+ sdk_version: sdk.package.installed_version || null,
517
+ policy: "warn_only",
518
+ },
519
+ };
520
+ }
521
+
342
522
  function openCodePackageVersionStatus(packageState) {
343
523
  if (!packageState.loadable) return "unloadable";
344
524
  if (!packageState.installed_version) return "unknown";
@@ -393,18 +573,24 @@ function evaluateGlobalOpenCodeSurface(configDir) {
393
573
  present: existsSync(paths.localValidator),
394
574
  ...validatorResolution.envelope,
395
575
  },
576
+ evaluator_agent: {
577
+ name: pluginDefinition.opencode.evaluatorAgentName,
578
+ path: paths.evaluatorAgent,
579
+ present: existsSync(paths.evaluatorAgent),
580
+ },
396
581
  present: existsSync(paths.skills),
397
582
  complete: existsSync(paths.instructions)
398
583
  && existsSync(paths.runtimeContract)
399
584
  && contractCount === contractModules.length
400
585
  && skillCount === openCodeSkillNames.length
401
586
  && existsSync(paths.localValidator)
587
+ && existsSync(paths.evaluatorAgent)
402
588
  && globalOpenCodeValidatorPackageIsValid(paths.localValidatorPackage)
403
589
  && validatorResolution.envelope.machine_validation === "owned_version_matched",
404
590
  };
405
591
  }
406
592
 
407
- export function evaluateOpenCodeStatus(targetDir, configDir = defaultOpenCodeConfigDir(), transition = null) {
593
+ export function evaluateOpenCodeStatus(targetDir, configDir = defaultOpenCodeConfigDir(), transition = null, dependencies = {}) {
408
594
  const configPath = join(configDir, "opencode.json");
409
595
  const configState = readOpenCodeConfig(configPath);
410
596
  const plugins = Array.isArray(configState.config.plugin) ? configState.config.plugin : [];
@@ -412,6 +598,7 @@ export function evaluateOpenCodeStatus(targetDir, configDir = defaultOpenCodeCon
412
598
  const packageState = resolveOpenCodePackage(configDir);
413
599
  const packageVersionStatus = openCodePackageVersionStatus(packageState);
414
600
  const globalNativeSurface = evaluateGlobalOpenCodeSurface(configDir);
601
+ const hostSdk = evaluateOpenCodeHostSdk(configDir, dependencies);
415
602
  const sessionSignals = {
416
603
  active: process.env.AGDF_PLUGIN_ACTIVE === "1",
417
604
  version: process.env.AGDF_PLUGIN_VERSION || "",
@@ -434,6 +621,11 @@ export function evaluateOpenCodeStatus(targetDir, configDir = defaultOpenCodeCon
434
621
  `Global OpenCode native surface is incomplete (${globalNativeSurface.skill_count}/${globalNativeSurface.expected_skill_count} skills; ${globalNativeSurface.contract_count}/${globalNativeSurface.expected_contract_count} contract modules).`,
435
622
  );
436
623
  }
624
+ if (hostSdk.experimental_hooks.aggregate === "uninspectable") findings.push("Installed OpenCode plugin SDK hook declarations could not be inspected.");
625
+ if (hostSdk.experimental_hooks.aggregate === "degraded") findings.push("Installed OpenCode plugin SDK is missing one or more required experimental hook declarations.");
626
+ if (hostSdk.host_sdk_version.status === "divergent") {
627
+ findings.push(`OpenCode host ${hostSdk.host_sdk_version.host_version} and plugin SDK ${hostSdk.host_sdk_version.sdk_version} diverge; policy is warning-only.`);
628
+ }
437
629
  if (!sessionSignals.active) findings.push("No active AGDF OpenCode session signal is visible in this process.");
438
630
  if (!repositoryActivation.active) {
439
631
  findings.push(repositoryActivation.state === "invalid_control"
@@ -460,6 +652,7 @@ export function evaluateOpenCodeStatus(targetDir, configDir = defaultOpenCodeCon
460
652
  ...(transition ? { transition } : {}),
461
653
  error: packageState.error,
462
654
  },
655
+ ...hostSdk,
463
656
  global_native_surface: globalNativeSurface,
464
657
  session: sessionSignals,
465
658
  repository_activation: repositoryActivation.state,
@@ -482,6 +675,12 @@ export function evaluateOpenCodeStatus(targetDir, configDir = defaultOpenCodeCon
482
675
  ? "Run npx --yes @agdf/cli@latest opencode to install or repair the OpenCode package version."
483
676
  : !globalNativeSurface.complete
484
677
  ? "Run npx --yes @agdf/cli@latest opencode to install or repair the global native OpenCode skill surface."
678
+ : hostSdk.experimental_hooks.aggregate === "uninspectable"
679
+ ? "Repair the installed OpenCode plugin SDK so its declarations can be inspected; do not assume dynamic hook support."
680
+ : hostSdk.experimental_hooks.aggregate === "degraded"
681
+ ? "Use static AGDF instructions and review OpenCode compatibility before relying on dynamic hook injection."
682
+ : hostSdk.host_sdk_version.status === "divergent"
683
+ ? "Review OpenCode host/plugin-SDK compatibility; AGDF reports this divergence but does not align versions automatically."
485
684
  : repositoryActivation.state === "invalid_control"
486
685
  ? "Repair .agdf/control/config.json so it contains valid artifact_language, chat_language and runtime_language values."
487
686
  : repositoryActivation.active
@@ -505,6 +704,11 @@ export function printOpenCodeStatus(report, json, io = console) {
505
704
  io.log(`Package version: ${report.package.installed_version || "unknown"}`);
506
705
  io.log(`Expected version: ${report.package.expected_version}`);
507
706
  io.log(`Version status: ${report.package.version_status}`);
707
+ io.log(`OpenCode host version: ${report.host.installed_version || "unknown"}`);
708
+ io.log(`Plugin SDK version: ${report.plugin_sdk.installed_version || "unknown"}`);
709
+ io.log(`Host/SDK version: ${report.host_sdk_version.status} (${report.host_sdk_version.policy})`);
710
+ io.log(`Experimental hook declarations: ${report.experimental_hooks.aggregate} (${report.experimental_hooks.evidence_level}; live invocation not observed)`);
711
+ for (const hook of report.experimental_hooks.hooks) io.log(`- ${hook.name}: ${hook.state}`);
508
712
  if (report.package.transition?.status === "updated") {
509
713
  io.log(`Version transition: ${report.package.transition.previous_version} -> ${report.package.transition.installed_version}`);
510
714
  } else if (report.package.transition?.status === "installed") {
@@ -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 -->") });
@@ -30,6 +30,23 @@ export const AGDFPlugin = async ({ directory, client }) => {
30
30
  "Do not apply AGDF gates from the global plugin alone. Create or repair durable AGDF control state with `npx --yes @agdf/cli@latest opencode-repo` when governance should be active here.",
31
31
  ].join("\n");
32
32
 
33
+ const appendGuidance = async (output, key) => {
34
+ if (!output || !Array.isArray(output[key])) {
35
+ try {
36
+ await client.app.log({
37
+ body: {
38
+ service: "agdf",
39
+ level: "warn",
40
+ message: `AGDF OpenCode guidance degraded: ${key} output is unavailable`,
41
+ extra: { key, repositoryActivation: activation().state },
42
+ },
43
+ });
44
+ } catch {}
45
+ return;
46
+ }
47
+ output[key].push(activation().active ? activeGuidance : inactiveGuidance);
48
+ };
49
+
33
50
  return {
34
51
  event: async ({ event }) => {
35
52
  if (event?.type === "session.created") {
@@ -55,11 +72,11 @@ export const AGDFPlugin = async ({ directory, client }) => {
55
72
  },
56
73
 
57
74
  "experimental.chat.system.transform": async (_input, output) => {
58
- output.system.push(activation().active ? activeGuidance : inactiveGuidance);
75
+ await appendGuidance(output, "system");
59
76
  },
60
77
 
61
78
  "experimental.session.compacting": async (_input, output) => {
62
- output.context.push(activation().active ? activeGuidance : inactiveGuidance);
79
+ await appendGuidance(output, "context");
63
80
  },
64
81
  };
65
82
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-agdf",
3
- "version": "0.11.3",
3
+ "version": "0.11.4",
4
4
  "description": "Bootstrap AGDF repository-local plugin files, Copilot/OpenCode instructions, skills, control files and machine-readable checks.",
5
5
  "type": "module",
6
6
  "files": [
@@ -24,6 +24,7 @@
24
24
  "test:delivery-path-search": "node ./scripts/delivery-path-search-test.js",
25
25
  "test:delivery-path-search-unit": "node ./scripts/delivery-path-search-unit-test.js",
26
26
  "test:delivery-path-search-generator": "node ./scripts/delivery-path-search-generator-test.js",
27
+ "test:opencode-hardening": "node ./scripts/opencode-hardening-test.js",
27
28
  "test:cli-modularization": "node ./scripts/cli-modularization-test.js",
28
29
  "test:local-validator": "node ./scripts/local-validator-test.js",
29
30
  "test:local-marketplace": "node ./scripts/local-marketplace-test.js",
@@ -40,7 +41,7 @@
40
41
  "eval:skills:record": "node ./scripts/record-skill-evals.js",
41
42
  "test:release-bootstrap": "node ./scripts/release-bootstrap-smoke-test.js",
42
43
  "test:routing": "npm run sync-package-assets && node ./scripts/test-routing.js",
43
- "smoke-test": "npm run sync-package-assets && npm run test:cli-modularization && npm run test:local-validator && npm run test:local-marketplace && npm run test:package-build && npm run test:package-contents && npm run test:lifecycle && npm run test:control-state && npm run test:interaction-presentation && npm run test:verified-change && npm run test:runtime-integrity-layout && npm run test:runtime-integrity-negative && npm run test:skill-evals && npm run eval:skills && npm run test:delivery-path-search && npm run test:delivery-path-search-unit && npm run test:delivery-path-search-generator && node ./scripts/smoke-test.js && node ./scripts/test-routing.js",
44
+ "smoke-test": "npm run sync-package-assets && npm run test:cli-modularization && npm run test:local-validator && npm run test:local-marketplace && npm run test:package-build && npm run test:package-contents && npm run test:lifecycle && npm run test:control-state && npm run test:interaction-presentation && npm run test:verified-change && npm run test:runtime-integrity-layout && npm run test:runtime-integrity-negative && npm run test:skill-evals && npm run eval:skills && npm run test:delivery-path-search && npm run test:delivery-path-search-unit && npm run test:delivery-path-search-generator && npm run test:opencode-hardening && node ./scripts/smoke-test.js && node ./scripts/test-routing.js",
44
45
  "prepack": "npm run sync-package-assets"
45
46
  },
46
47
  "keywords": [