create-agdf 0.11.4 → 0.13.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.
Files changed (111) hide show
  1. package/README.md +1 -1
  2. package/generated/.agdf/control/templates/artefacts/BROWNFIELD_REVIEW.md +25 -0
  3. package/generated/.github/skills/agdf-brownfield-analysis/SKILL.md +26 -0
  4. package/generated/.github/skills/agdf-gate-check/SKILL.md +40 -18
  5. package/generated/.github/skills/agdf-interaction-locales.json +50 -0
  6. package/generated/.github/skills/agdf-runtime-contract.md +1 -0
  7. package/generated/.github/skills/contracts/gate-transition.md +7 -3
  8. package/generated/.github/skills/contracts/interaction.md +22 -0
  9. package/generated/.github/skills/contracts/modes.md +81 -0
  10. package/generated/.github/skills/contracts/task-target-resolution.md +102 -0
  11. package/generated/.opencode/AGDF.md +2 -0
  12. package/generated/.opencode/agdf-interaction-locales.json +50 -0
  13. package/generated/.opencode/agdf-runtime-contract.md +1 -0
  14. package/generated/.opencode/contracts/gate-transition.md +7 -3
  15. package/generated/.opencode/contracts/interaction.md +22 -0
  16. package/generated/.opencode/contracts/modes.md +81 -0
  17. package/generated/.opencode/contracts/task-target-resolution.md +102 -0
  18. package/generated/.opencode/skills/agdf-brownfield-analysis/SKILL.md +26 -0
  19. package/generated/.opencode/skills/agdf-gate-check/SKILL.md +40 -18
  20. package/generated/AGENTS.md +1 -0
  21. package/generated/plugins/agdf/.claude-plugin/plugin.json +2 -2
  22. package/generated/plugins/agdf/.codex-plugin/plugin.json +9 -6
  23. package/generated/plugins/agdf/control/templates/artefacts/BROWNFIELD_REVIEW.md +25 -0
  24. package/generated/plugins/agdf/meta/agdf-agent-router.md +16 -0
  25. package/generated/plugins/agdf/meta/agdf-interaction-locales.json +50 -0
  26. package/generated/plugins/agdf/meta/agdf-plugin.definition.json +41 -5
  27. package/generated/plugins/agdf/meta/agdf-runtime-contract.md +1 -0
  28. package/generated/plugins/agdf/meta/contracts/gate-transition.md +7 -3
  29. package/generated/plugins/agdf/meta/contracts/interaction.md +22 -0
  30. package/generated/plugins/agdf/meta/contracts/modes.md +81 -0
  31. package/generated/plugins/agdf/meta/contracts/task-target-resolution.md +102 -0
  32. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-interaction-locales.json +50 -0
  33. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-plugin.definition.json +41 -5
  34. package/generated/plugins/agdf/runtime/create-agdf/lib/control-evaluation/gate-policy.js +14 -7
  35. package/generated/plugins/agdf/runtime/create-agdf/lib/interaction-presentation.js +85 -0
  36. package/generated/plugins/agdf/runtime/create-agdf/package.json +4 -65
  37. package/generated/plugins/agdf/runtime/runtime-manifest.json +2 -2
  38. package/generated/plugins/agdf/scripts/check-runtime-integrity.mjs +146 -40
  39. package/generated/plugins/agdf/skills/brownfield-analysis/SKILL.md +26 -0
  40. package/generated/plugins/agdf/skills/gate-check/SKILL.md +40 -18
  41. package/generated/plugins/agdf/submission/openai/availability.md +16 -0
  42. package/generated/plugins/agdf/submission/openai/capability-matrix.json +49 -0
  43. package/generated/plugins/agdf/submission/openai/release-notes.md +16 -0
  44. package/generated/plugins/agdf/submission/openai/reviewer-cases.json +96 -0
  45. package/generated/submissions/openai/agdf/.codex-plugin/plugin.json +43 -0
  46. package/generated/submissions/openai/agdf/assets/agdf-icon.svg +16 -0
  47. package/generated/submissions/openai/agdf/assets/agdf-logo.svg +16 -0
  48. package/generated/submissions/openai/agdf/meta/agdf-agent-router.md +129 -0
  49. package/generated/submissions/openai/agdf/meta/agdf-constitution.md +329 -0
  50. package/generated/submissions/openai/agdf/meta/agdf-interaction-locales.json +514 -0
  51. package/generated/submissions/openai/agdf/meta/agdf-plugin.definition.json +263 -0
  52. package/generated/submissions/openai/agdf/meta/agdf-runtime-contract.md +16 -0
  53. package/generated/submissions/openai/agdf/meta/agdf-tenets.md +201 -0
  54. package/generated/submissions/openai/agdf/meta/contracts/closeout.md +29 -0
  55. package/generated/submissions/openai/agdf/meta/contracts/context-graph.md +48 -0
  56. package/generated/submissions/openai/agdf/meta/contracts/control-scaffold.md +115 -0
  57. package/generated/submissions/openai/agdf/meta/contracts/gate-transition.md +165 -0
  58. package/generated/submissions/openai/agdf/meta/contracts/interaction.md +476 -0
  59. package/generated/submissions/openai/agdf/meta/contracts/modes.md +183 -0
  60. package/generated/submissions/openai/agdf/meta/contracts/quality.md +157 -0
  61. package/generated/submissions/openai/agdf/meta/contracts/task-target-resolution.md +102 -0
  62. package/generated/submissions/openai/agdf/skills/brownfield-analysis/SKILL.md +175 -0
  63. package/generated/submissions/openai/agdf/skills/brownfield-analysis/help.md +23 -0
  64. package/generated/submissions/openai/agdf/skills/clean-implementation-review/SKILL.md +126 -0
  65. package/generated/submissions/openai/agdf/skills/clean-implementation-review/help.md +23 -0
  66. package/generated/submissions/openai/agdf/skills/code-review/SKILL.md +119 -0
  67. package/generated/submissions/openai/agdf/skills/code-review/help.md +23 -0
  68. package/generated/submissions/openai/agdf/skills/delivery-closeout/SKILL.md +118 -0
  69. package/generated/submissions/openai/agdf/skills/delivery-closeout/help.md +23 -0
  70. package/generated/submissions/openai/agdf/skills/delivery-path-search/SKILL.md +94 -0
  71. package/generated/submissions/openai/agdf/skills/delivery-path-search/help.md +23 -0
  72. package/generated/submissions/openai/agdf/skills/gate-check/SKILL.md +238 -0
  73. package/generated/submissions/openai/agdf/skills/gate-check/help.md +23 -0
  74. package/generated/submissions/openai/agdf/skills/qa-gate/SKILL.md +137 -0
  75. package/generated/submissions/openai/agdf/skills/qa-gate/help.md +23 -0
  76. package/generated/submissions/openai/agdf/skills/release-or/SKILL.md +137 -0
  77. package/generated/submissions/openai/agdf/skills/release-or/help.md +23 -0
  78. package/generated/submissions/openai/agdf/skills/task-plan-review/SKILL.md +157 -0
  79. package/generated/submissions/openai/agdf/skills/task-plan-review/help.md +23 -0
  80. package/generated/submissions/openai/agdf/skills/ux-intent-definition/SKILL.md +94 -0
  81. package/generated/submissions/openai/agdf/skills/ux-intent-definition/help.md +17 -0
  82. package/generated/submissions/openai/agdf/submission/openai/availability.md +16 -0
  83. package/generated/submissions/openai/agdf/submission/openai/capability-matrix.json +49 -0
  84. package/generated/submissions/openai/agdf/submission/openai/inventory.json +175 -0
  85. package/generated/submissions/openai/agdf/submission/openai/listing.json +38 -0
  86. package/generated/submissions/openai/agdf/submission/openai/readiness.json +40 -0
  87. package/generated/submissions/openai/agdf/submission/openai/readiness.md +24 -0
  88. package/generated/submissions/openai/agdf/submission/openai/release-notes.md +16 -0
  89. package/generated/submissions/openai/agdf/submission/openai/reviewer-cases.json +96 -0
  90. package/lib/cli/application.js +13 -2
  91. package/lib/control-evaluation/gate-policy.js +14 -7
  92. package/lib/installers/local-marketplace.js +1 -1
  93. package/lib/installers/opencode.js +128 -1
  94. package/lib/interaction-presentation.js +85 -0
  95. package/lib/live-agent/read-only-structured.js +43 -0
  96. package/lib/proportionality-benchmark/blind-prompt.js +37 -0
  97. package/lib/proportionality-benchmark/contracts.js +120 -0
  98. package/lib/proportionality-benchmark/corpus-loader.js +110 -0
  99. package/lib/proportionality-benchmark/evaluator.js +250 -0
  100. package/lib/proportionality-benchmark/index.js +7 -0
  101. package/lib/proportionality-benchmark/live-recorder.js +100 -0
  102. package/lib/proportionality-benchmark/report.js +51 -0
  103. package/lib/proportionality-benchmark/source-fingerprint.js +30 -0
  104. package/lib/public-plugin/builder.js +82 -0
  105. package/lib/public-plugin/contract.js +102 -0
  106. package/lib/public-plugin/manifest.js +72 -0
  107. package/lib/public-plugin/report.js +33 -0
  108. package/lib/public-plugin/validator.js +101 -0
  109. package/lib/skill-evals/live-recorder.js +3 -26
  110. package/opencode-plugin.js +40 -1
  111. package/package.json +7 -2
@@ -0,0 +1,72 @@
1
+ function publicValues(definition) {
2
+ const distribution = definition.publicDistribution;
3
+ if (!distribution || distribution.schemaVersion !== 1) {
4
+ throw new Error("AGDF_PUBLIC_PLUGIN_CONTRACT_INVALID: publicDistribution schemaVersion 1 is required");
5
+ }
6
+ return distribution;
7
+ }
8
+
9
+ export function createCodexPluginManifest(definition, { publicCandidate = false } = {}) {
10
+ const distribution = publicValues(definition);
11
+ const pluginInterface = publicCandidate ? {
12
+ displayName: distribution.publicDisplayName,
13
+ shortDescription: distribution.shortDescription,
14
+ longDescription: definition.longDescription,
15
+ defaultPrompt: distribution.defaultPrompt,
16
+ } : {
17
+ displayName: definition.displayName,
18
+ shortDescription: definition.description,
19
+ longDescription: definition.longDescription,
20
+ defaultPrompt: definition.codex.defaultPrompt,
21
+ };
22
+ const manifest = {
23
+ name: definition.id,
24
+ version: definition.version,
25
+ description: definition.description,
26
+ author: definition.author,
27
+ homepage: definition.homepage,
28
+ repository: definition.repository,
29
+ license: definition.license,
30
+ keywords: definition.keywords,
31
+ skills: definition.codex.skills,
32
+ interface: {
33
+ displayName: pluginInterface.displayName,
34
+ shortDescription: pluginInterface.shortDescription,
35
+ longDescription: pluginInterface.longDescription,
36
+ developerName: distribution.developerName,
37
+ category: distribution.category,
38
+ capabilities: definition.codex.capabilities,
39
+ websiteURL: distribution.urls.website,
40
+ privacyPolicyURL: distribution.urls.privacy,
41
+ termsOfServiceURL: distribution.urls.terms,
42
+ supportURL: distribution.urls.support,
43
+ composerIcon: definition.codex.composerIcon,
44
+ logo: definition.codex.logo,
45
+ defaultPrompt: pluginInterface.defaultPrompt,
46
+ brandColor: definition.brandColor,
47
+ },
48
+ };
49
+ if (!publicCandidate) manifest.hooks = `./${definition.codex.hooks}`;
50
+ return manifest;
51
+ }
52
+
53
+ export function renderCodexPluginManifest(definition, options) {
54
+ return `${JSON.stringify(createCodexPluginManifest(definition, options), null, 2)}\n`;
55
+ }
56
+
57
+ export function createClaudePluginManifest(definition) {
58
+ return {
59
+ name: definition.id,
60
+ version: definition.version,
61
+ description: definition.longDescription,
62
+ keywords: definition.keywords,
63
+ homepage: definition.homepage,
64
+ repository: definition.repository,
65
+ license: definition.license,
66
+ author: definition.author,
67
+ };
68
+ }
69
+
70
+ export function renderClaudePluginManifest(definition) {
71
+ return `${JSON.stringify(createClaudePluginManifest(definition), null, 2)}\n`;
72
+ }
@@ -0,0 +1,33 @@
1
+ export function createReadinessReport({ definition, fileCount, inventoryDigest }) {
2
+ const contract = definition.publicDistribution;
3
+ return {
4
+ schemaVersion: 1,
5
+ releaseVersion: definition.version,
6
+ candidateState: "repository_ready",
7
+ submissionReady: false,
8
+ submissionBlockers: [
9
+ "publisher identity and Apps Management authority are unverified",
10
+ "availability selection is pending",
11
+ "public deployment and exact-host evidence are unverified",
12
+ "portal draft has not been created or reconciled",
13
+ ],
14
+ evidence: {
15
+ repository: { state: "pass", detail: "canonical contract and deterministic source checks" },
16
+ bundle: { state: "pass", detail: `${fileCount} inventoried files; inventory digest ${inventoryDigest}` },
17
+ installed_host: { state: "unverified", detail: "PPD-L02 and PPD-L03 not performed" },
18
+ portal: { state: "unverified", detail: contract.publisher.verificationState },
19
+ post_publication: { state: "unverified", detail: "not published" },
20
+ },
21
+ externalState: {
22
+ publisherIdentity: contract.publisher.verificationState,
23
+ availability: contract.availability.decisionState,
24
+ portal: "not_observed",
25
+ publication: "not_observed",
26
+ },
27
+ };
28
+ }
29
+
30
+ export function renderReadinessReport(report) {
31
+ const blockers = report.submissionBlockers.map((blocker) => `- ${blocker}`).join("\n");
32
+ return `# AGDF Public Plugin Readiness\n\n- release: \`${report.releaseVersion}\`\n- candidate_state: \`${report.candidateState}\`\n- submission_ready: \`${report.submissionReady}\`\n\n## Evidence classes\n\n| Class | State | Detail |\n|---|---|---|\n${Object.entries(report.evidence).map(([name, value]) => `| ${name} | ${value.state} | ${value.detail} |`).join("\n")}\n\n## Submission blockers\n\n${blockers}\n\nRepository and bundle evidence do not prove installation, authenticated host behavior, publisher identity, portal state, deployment or publication.\n`;
33
+ }
@@ -0,0 +1,101 @@
1
+ import { createHash } from "node:crypto";
2
+ import { lstatSync, readFileSync, readdirSync, realpathSync, statSync } from "node:fs";
3
+ import { isAbsolute, join, relative, resolve, sep } from "node:path";
4
+ import { LISTING_LIMITS, unicodeLength } from "./contract.js";
5
+
6
+ function inside(root, candidate) {
7
+ const rel = relative(root, candidate);
8
+ return rel === "" || (rel !== ".." && !rel.startsWith(`..${sep}`) && !isAbsolute(rel));
9
+ }
10
+
11
+ function hasExactCase(root, target) {
12
+ const rel = relative(root, target);
13
+ let current = root;
14
+ for (const segment of rel.split(sep)) {
15
+ if (!readdirSync(current).includes(segment)) return false;
16
+ current = join(current, segment);
17
+ }
18
+ return true;
19
+ }
20
+
21
+ export function listCandidateFiles(root) {
22
+ root = realpathSync(resolve(root));
23
+ const files = [];
24
+ function visit(directory) {
25
+ for (const name of readdirSync(directory).sort()) {
26
+ const path = join(directory, name);
27
+ const stats = lstatSync(path);
28
+ if (stats.isSymbolicLink()) throw new Error(`AGDF_PUBLIC_PLUGIN_BUNDLE_PATH_MISSING: symlink not allowed: ${relative(root, path)}`);
29
+ if (stats.isDirectory()) visit(path);
30
+ else if (stats.isFile()) files.push(relative(root, path).replaceAll("\\", "/"));
31
+ }
32
+ }
33
+ visit(root);
34
+ return files;
35
+ }
36
+
37
+ function declaredPath(root, value, label, { directory = false } = {}) {
38
+ if (typeof value !== "string" || !value.startsWith("./")) throw new Error(`AGDF_PUBLIC_PLUGIN_BUNDLE_PATH_MISSING: ${label} must start with ./`);
39
+ const target = resolve(root, value);
40
+ if (!inside(root, target)) throw new Error(`AGDF_PUBLIC_PLUGIN_BUNDLE_PATH_MISSING: ${label} escapes candidate root`);
41
+ if (!hasExactCase(root, target)) throw new Error(`AGDF_PUBLIC_PLUGIN_BUNDLE_PATH_MISSING: ${label} has case mismatch or is missing`);
42
+ const actual = realpathSync(target);
43
+ if (!inside(root, actual)) throw new Error(`AGDF_PUBLIC_PLUGIN_BUNDLE_PATH_MISSING: ${label} resolves outside candidate root`);
44
+ const stats = statSync(target);
45
+ if (directory ? !stats.isDirectory() : !stats.isFile()) throw new Error(`AGDF_PUBLIC_PLUGIN_BUNDLE_PATH_MISSING: ${label} has wrong type`);
46
+ }
47
+
48
+ function assertReferencedSkillResources(root) {
49
+ const skillsRoot = join(root, "skills");
50
+ for (const skillName of readdirSync(skillsRoot).sort()) {
51
+ const skillRoot = join(skillsRoot, skillName);
52
+ if (!statSync(skillRoot).isDirectory()) continue;
53
+ const skillPath = join(skillRoot, "SKILL.md");
54
+ if (!statSync(skillPath).isFile()) throw new Error(`AGDF_PUBLIC_PLUGIN_BUNDLE_PATH_MISSING: skills/${skillName}/SKILL.md`);
55
+ const content = readFileSync(skillPath, "utf8");
56
+ const references = [...content.matchAll(/\.\.\/\.\.\/meta\/([A-Za-z0-9._/-]+)/g)].map((match) => match[1].replace(/[`)\],.;:]+$/, ""));
57
+ for (const reference of references) {
58
+ const target = resolve(root, "meta", reference);
59
+ if (!inside(root, target) || !statSync(target).isFile()) throw new Error(`AGDF_PUBLIC_PLUGIN_BUNDLE_PATH_MISSING: skills/${skillName} references meta/${reference}`);
60
+ }
61
+ }
62
+ }
63
+
64
+ export function validateCandidate(root) {
65
+ root = realpathSync(resolve(root));
66
+ const manifestPath = join(root, ".codex-plugin", "plugin.json");
67
+ const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
68
+ if (manifest.hooks || manifest.mcp || manifest.app) throw new Error("AGDF_PUBLIC_PLUGIN_CONTRACT_INVALID: Skills-only candidate must not declare hooks, MCP or app configuration");
69
+ declaredPath(root, manifest.skills, "skills", { directory: true });
70
+ declaredPath(root, manifest.interface?.composerIcon, "composerIcon");
71
+ declaredPath(root, manifest.interface?.logo, "logo");
72
+ const definition = JSON.parse(readFileSync(join(root, "meta", "agdf-plugin.definition.json"), "utf8"));
73
+ if (definition.version !== manifest.version) throw new Error("AGDF_PUBLIC_PLUGIN_VERSION_DRIFT: manifest and definition differ");
74
+ for (const [label, source] of Object.entries(definition.publicDistribution?.submissionSources ?? {})) {
75
+ declaredPath(root, `./${source}`, `submissionSources.${label}`);
76
+ }
77
+ assertReferencedSkillResources(root);
78
+ if (unicodeLength(manifest.interface?.displayName) > LISTING_LIMITS.displayName) throw new Error("AGDF_PUBLIC_PLUGIN_LISTING_LIMIT_EXCEEDED: displayName");
79
+ if (unicodeLength(manifest.interface?.shortDescription) > LISTING_LIMITS.shortDescription) throw new Error("AGDF_PUBLIC_PLUGIN_LISTING_LIMIT_EXCEEDED: shortDescription");
80
+ if (unicodeLength(manifest.interface?.developerName) > LISTING_LIMITS.developerName) throw new Error("AGDF_PUBLIC_PLUGIN_LISTING_LIMIT_EXCEEDED: developerName");
81
+ const prompts = manifest.interface?.defaultPrompt ?? [];
82
+ if (prompts.length !== LISTING_LIMITS.promptCount || prompts.some((prompt) => unicodeLength(prompt) > LISTING_LIMITS.promptLength)) throw new Error("AGDF_PUBLIC_PLUGIN_LISTING_LIMIT_EXCEEDED: defaultPrompt");
83
+ for (const field of ["websiteURL", "privacyPolicyURL", "termsOfServiceURL", "supportURL"]) {
84
+ let url;
85
+ try { url = new URL(manifest.interface?.[field]); } catch { throw new Error(`AGDF_PUBLIC_PLUGIN_CONTRACT_INVALID: ${field}`); }
86
+ if (url.protocol !== "https:") throw new Error(`AGDF_PUBLIC_PLUGIN_CONTRACT_INVALID: ${field} must use HTTPS`);
87
+ }
88
+ const files = listCandidateFiles(root);
89
+ for (const forbidden of [".app.json", ".mcp.json", ".agdf/control/", "node_modules/", ".git/"]) {
90
+ if (files.some((file) => file === forbidden || file.startsWith(forbidden))) throw new Error(`AGDF_PUBLIC_PLUGIN_CONTRACT_INVALID: forbidden candidate content ${forbidden}`);
91
+ }
92
+ return { manifest, files };
93
+ }
94
+
95
+ export function inventory(root, { exclude = [] } = {}) {
96
+ const excluded = new Set(exclude);
97
+ return listCandidateFiles(root).filter((path) => !excluded.has(path)).map((path) => ({
98
+ path,
99
+ sha256: createHash("sha256").update(readFileSync(join(root, path))).digest("hex"),
100
+ }));
101
+ }
@@ -1,8 +1,7 @@
1
1
  import { execFileSync } from "node:child_process";
2
- import { mkdirSync, mkdtempSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
3
- import { tmpdir } from "node:os";
2
+ import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
4
3
  import { dirname, join } from "node:path";
5
- import { guardedExecFileSync } from "../delivery-path-search/transports/read-only-guard.js";
4
+ import { executeStructuredAgent } from "../live-agent/read-only-structured.js";
6
5
  import { gradeCase } from "./index.js";
7
6
  import { changedPaths, disposeFixture, materializeFixture, mutationViolations, snapshotWorkspace, workspaceEvidence } from "./workspace.js";
8
7
 
@@ -43,29 +42,7 @@ function promptFor(skillSource, routingSource, testCase, fixtureDefinition, fixt
43
42
  }
44
43
 
45
44
  function defaultExecute({ surface, cwd, prompt, model, timeoutMs = 120000 }) {
46
- if (surface === "codex") {
47
- const temp = mkdtempSync(join(tmpdir(), "agdf-live-codex-"));
48
- try {
49
- const schemaPath = join(temp, "schema.json");
50
- const outputPath = join(temp, "output.json");
51
- writeFileSync(schemaPath, `${JSON.stringify(outputSchema, null, 2)}\n`, "utf8");
52
- const args = ["exec", "--sandbox", "read-only", "--ephemeral", "--ignore-user-config", "--skip-git-repo-check", "--output-schema", schemaPath, "--output-last-message", outputPath, "--color", "never"];
53
- if (model) args.push("--model", model);
54
- args.push(prompt);
55
- guardedExecFileSync("codex", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: timeoutMs });
56
- return readFileSync(outputPath, "utf8");
57
- } finally { rmSync(temp, { recursive: true, force: true }); }
58
- }
59
- if (surface === "claude") {
60
- const args = ["-p", "--disallowedTools", "Edit,Write,Bash", "--output-format", "json", "--json-schema", JSON.stringify(outputSchema)];
61
- if (model) args.push("--model", model);
62
- args.push(prompt);
63
- const raw = guardedExecFileSync("claude", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: timeoutMs });
64
- const envelope = JSON.parse(raw);
65
- if (envelope.is_error) throw new Error(`claude live adapter failed: ${envelope.result ?? "unknown error"}`);
66
- return envelope.result;
67
- }
68
- throw new Error(`unsupported live surface: ${surface}`);
45
+ return executeStructuredAgent({ surface, cwd, prompt, model, outputSchema, timeoutMs });
69
46
  }
70
47
 
71
48
  export function persistLiveObservation(path, result) {
@@ -1,8 +1,20 @@
1
- import { readFileSync } from "node:fs";
1
+ import { existsSync, readFileSync } from "node:fs";
2
2
  import { evaluateOpenCodeRepositoryActivation } from "./lib/installers/opencode-activation.js";
3
3
 
4
4
  const packageJson = JSON.parse(readFileSync(new URL("./package.json", import.meta.url), "utf8"));
5
5
 
6
+ const readValidatorExpectedVersion = () => {
7
+ try {
8
+ const validatorPath = new URL("../../agdf/bin/agdf-local.js", import.meta.url);
9
+ if (!existsSync(validatorPath)) return null;
10
+ const content = readFileSync(validatorPath, "utf8");
11
+ const match = content.match(/expectedVersion["']?\s*[:=]\s*["']([^"']+)["']/);
12
+ return match?.[1] ?? null;
13
+ } catch {
14
+ return null;
15
+ }
16
+ };
17
+
6
18
  export const AGDFPlugin = async ({ directory, client }) => {
7
19
  const controlDir = `${directory}/.agdf/control`;
8
20
  const activation = () => evaluateOpenCodeRepositoryActivation(directory);
@@ -47,6 +59,12 @@ export const AGDFPlugin = async ({ directory, client }) => {
47
59
  output[key].push(activation().active ? activeGuidance : inactiveGuidance);
48
60
  };
49
61
 
62
+ const safeToast = async (message, variant) => {
63
+ try {
64
+ if (client?.tui?.showToast) await client.tui.showToast({ body: { message, variant } });
65
+ } catch {}
66
+ };
67
+
50
68
  return {
51
69
  event: async ({ event }) => {
52
70
  if (event?.type === "session.created") {
@@ -59,6 +77,27 @@ export const AGDFPlugin = async ({ directory, client }) => {
59
77
  extra: currentStatus,
60
78
  },
61
79
  });
80
+ if (!currentStatus.active) {
81
+ await safeToast(
82
+ "AGDF: No valid .agdf/control/config.json. Run npx --yes @agdf/cli@latest opencode-repo to activate governance.",
83
+ "warning",
84
+ );
85
+ }
86
+ const validatorVersion = readValidatorExpectedVersion();
87
+ if (validatorVersion && validatorVersion !== packageJson.version) {
88
+ await client.app.log({
89
+ body: {
90
+ service: "agdf",
91
+ level: "warn",
92
+ message: `AGDF version drift: plugin ${packageJson.version} vs validator ${validatorVersion}`,
93
+ extra: { plugin_version: packageJson.version, validator_version: validatorVersion },
94
+ },
95
+ });
96
+ await safeToast(
97
+ `AGDF version drift: plugin ${packageJson.version} vs validator ${validatorVersion}. Run npx --yes @agdf/cli@latest opencode-repo to repair.`,
98
+ "warning",
99
+ );
100
+ }
62
101
  }
63
102
  },
64
103
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-agdf",
3
- "version": "0.11.4",
3
+ "version": "0.13.0",
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": [
@@ -21,6 +21,8 @@
21
21
  },
22
22
  "scripts": {
23
23
  "sync-package-assets": "node ./scripts/sync-package-assets.js",
24
+ "build:public-plugin": "node ./scripts/build-public-plugin.js",
25
+ "test:public-plugin": "node ./scripts/public-plugin-test.js",
24
26
  "test:delivery-path-search": "node ./scripts/delivery-path-search-test.js",
25
27
  "test:delivery-path-search-unit": "node ./scripts/delivery-path-search-unit-test.js",
26
28
  "test:delivery-path-search-generator": "node ./scripts/delivery-path-search-generator-test.js",
@@ -39,9 +41,12 @@
39
41
  "test:skill-evals": "node ./scripts/skill-evals-test.js",
40
42
  "eval:skills": "node ./scripts/run-skill-evals.js",
41
43
  "eval:skills:record": "node ./scripts/record-skill-evals.js",
44
+ "eval:proportionality:record": "node ./scripts/record-proportionality-benchmark.js",
45
+ "eval:proportionality": "node ./scripts/run-proportionality-benchmark.js",
46
+ "test:proportionality": "node ./scripts/proportionality-benchmark-test.js",
42
47
  "test:release-bootstrap": "node ./scripts/release-bootstrap-smoke-test.js",
43
48
  "test:routing": "npm run sync-package-assets && 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",
49
+ "smoke-test": "npm run sync-package-assets && npm run test:public-plugin && 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:proportionality && 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",
45
50
  "prepack": "npm run sync-package-assets"
46
51
  },
47
52
  "keywords": [