create-agdf 0.13.4 → 0.13.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +7 -1
  2. package/generated/plugins/agdf/.claude-plugin/plugin.json +1 -1
  3. package/generated/plugins/agdf/.codex-plugin/plugin.json +2 -3
  4. package/generated/plugins/agdf/hooks/session-start.sh +31 -0
  5. package/generated/plugins/agdf/meta/agdf-plugin.definition.json +30 -9
  6. package/generated/plugins/agdf/runtime/agdf-local.js +8 -1
  7. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-plugin.definition.json +30 -9
  8. package/generated/plugins/agdf/runtime/create-agdf/lib/runtime/local-validator.js +116 -31
  9. package/generated/plugins/agdf/runtime/create-agdf/lib/runtime/plugin-provenance.js +206 -0
  10. package/generated/plugins/agdf/runtime/create-agdf/package.json +1 -1
  11. package/generated/plugins/agdf/runtime/runtime-manifest.json +2 -2
  12. package/generated/plugins/agdf/scripts/check-runtime-integrity.mjs +64 -19
  13. package/generated/plugins/agdf/submission/openai/availability.md +1 -1
  14. package/generated/plugins/agdf/submission/openai/capability-matrix.json +1 -1
  15. package/generated/plugins/agdf/submission/openai/release-notes.md +1 -1
  16. package/generated/plugins/agdf/submission/openai/reviewer-cases.json +1 -1
  17. package/generated/submissions/openai/agdf/.codex-plugin/plugin.json +1 -1
  18. package/generated/submissions/openai/agdf/meta/agdf-plugin.definition.json +30 -9
  19. package/generated/submissions/openai/agdf/submission/openai/availability.md +1 -1
  20. package/generated/submissions/openai/agdf/submission/openai/capability-matrix.json +1 -1
  21. package/generated/submissions/openai/agdf/submission/openai/inventory.json +9 -9
  22. package/generated/submissions/openai/agdf/submission/openai/listing.json +1 -1
  23. package/generated/submissions/openai/agdf/submission/openai/readiness.json +2 -2
  24. package/generated/submissions/openai/agdf/submission/openai/readiness.md +2 -2
  25. package/generated/submissions/openai/agdf/submission/openai/release-notes.md +1 -1
  26. package/generated/submissions/openai/agdf/submission/openai/reviewer-cases.json +1 -1
  27. package/lib/cli/application.js +4 -3
  28. package/lib/fs-swap.js +26 -0
  29. package/lib/installers/local-development.js +202 -0
  30. package/lib/installers/local-marketplace.js +181 -36
  31. package/lib/installers/opencode.js +17 -2
  32. package/lib/installers/plugin-installers.js +86 -22
  33. package/lib/lifecycle/operations.js +9 -5
  34. package/lib/lifecycle/status.js +10 -2
  35. package/lib/public-plugin/builder.js +5 -4
  36. package/lib/runtime/local-validator.js +116 -31
  37. package/lib/runtime/plugin-provenance.js +206 -0
  38. package/package.json +6 -2
package/README.md CHANGED
@@ -126,7 +126,9 @@ it does not localize the CLI lifecycle card.
126
126
  The `codex` and `claude` commands install from the complete plugin built into the released
127
127
  `create-agdf` package. They atomically stage it under an AGDF-owned user-data marketplace, register
128
128
  that stable local path through the host CLI and verify the exposed version. Source `plugin/` therefore
129
- contains no generated runtime bytes, and routine installed validation does not depend on the GitHub
129
+ contains no generated runtime bytes and the source checkout exposes no installable root marketplace.
130
+ The staged plugin contains one installation-provenance marker and the shared exact-version runtime;
131
+ routine installed validation does not depend on the GitHub
130
132
  checkout, npm cache, PATH or registry. Rerunning either command performs the explicit update and
131
133
  migrates only the exact known legacy AGDF GitHub marketplace; foreign same-name registrations fail
132
134
  closed and failed host operations restore the prior owned stage.
@@ -137,6 +139,10 @@ Use the `codex-repo` target when AGDF should be available only inside one reposi
137
139
 
138
140
  After `npm create agdf@latest -- codex-repo`, restart Codex in that repository, open `/plugins`, select `This repository` and install `agdf`.
139
141
 
142
+ `codex-repo` is a generated runtime-complete repository projection. It is distinct from this
143
+ runtime-free source checkout and is validated before lifecycle status treats `agdf@agdf-repo` as
144
+ active.
145
+
140
146
  Use the `opencode` target to install the AGDF npm plugin as a user-wide OpenCode hook:
141
147
 
142
148
  ```bash
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agdf",
3
- "version": "0.13.4",
3
+ "version": "0.13.6",
4
4
  "description": "AI Governance & Delivery Framework (AGDF) is a governance framework for agentic work. Its first implementation provides a control layer for governed AI-assisted software delivery. It combines workflow skills, explicit gates, control templates and machine-readable repository checks to keep work aligned with approved scope and make evidence a prerequisite for consequential gate transitions. Supported workflows include brownfield analysis, task-plan review, QA decisions, durable run state and auditable delivery closeout. AGDF is an independent open-source project, not a security sandbox, compliance certification or autonomous release system.",
5
5
  "keywords": [
6
6
  "agentic",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agdf",
3
- "version": "0.13.4",
3
+ "version": "0.13.6",
4
4
  "description": "Control layer for governed AI-assisted delivery.",
5
5
  "author": {
6
6
  "name": "Arndt Gold",
@@ -34,9 +34,8 @@
34
34
  "composerIcon": "./assets/agdf-icon.svg",
35
35
  "logo": "./assets/agdf-logo.svg",
36
36
  "defaultPrompt": [
37
- "Assess whether AGDF is proportionate for this repository and request before proposing any implementation. Explain AGDF's purpose and practical benefits, weigh governance overhead against the project's delivery risk, and recommend the lightest suitable path — or explicitly advise against AGDF where it would add more process than value.",
37
+ "Assess whether AGDF fits this request and recommend the lightest safe path before proposing implementation.",
38
38
  "Start this request under AGDF governance.",
39
- "Create durable AGDF control state for this repository.",
40
39
  "Close this delivery run with an auditable AGDF report."
41
40
  ],
42
41
  "brandColor": "#14B8A6"
@@ -3,11 +3,40 @@
3
3
  # Activates a compact AGDF runtime reminder for the agent session.
4
4
 
5
5
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6
+ PLUGIN_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
6
7
  META_DIR="$(cd "${SCRIPT_DIR}/../meta" && pwd)"
7
8
  ROUTER="${META_DIR}/agdf-agent-router.md"
8
9
  CONSTITUTION="${META_DIR}/agdf-constitution.md"
9
10
  RUNTIME_CONTRACT="${META_DIR}/agdf-runtime-contract.md"
10
11
  CONFIG_PATH="${PWD}/.agdf/control/config.json"
12
+ LOCAL_RUNTIME="${PLUGIN_DIR}/runtime/agdf-local.js"
13
+
14
+ RUNTIME_HINT="AGDF runtime: profile=source-development evidence=source_checkout machine_validation=unavailable provenance=not_applicable."
15
+ if [[ -f "${PLUGIN_DIR}/.agdf-installation.json" && ! -f "${LOCAL_RUNTIME}" ]]; then
16
+ RUNTIME_HINT="AGDF runtime: profile=runtime-plugin evidence=installed_plugin_root machine_validation=unavailable provenance=unverified. Use the supported AGDF install/update command, then restart the host and retry in a fresh session."
17
+ fi
18
+ if [[ -f "${LOCAL_RUNTIME}" ]]; then
19
+ RUNTIME_HINT="AGDF runtime: profile=runtime-plugin evidence=unverified machine_validation=unavailable provenance=unverified. Retry the surface-local runtime probe or use the supported AGDF install/update command."
20
+ RUNTIME_JSON="$(AGDF_SURFACE="${AGDF_SURFACE:-plugin}" node "${LOCAL_RUNTIME}" --resolve-only --json 2>/dev/null || true)"
21
+ RUNTIME_RENDERED="$(RUNTIME_JSON="${RUNTIME_JSON}" node <<'NODE' 2>/dev/null || true
22
+ try {
23
+ const value = JSON.parse(process.env.RUNTIME_JSON || "{}");
24
+ const profile = value.distribution_profile || "runtime-plugin";
25
+ const evidence = value.evidence_plane || "unverified";
26
+ const version = value.plugin_version || value.observed_version || value.expected_version || "unknown";
27
+ const provenance = value.provenance_status || "unverified";
28
+ const validation = value.machine_validation || "unavailable";
29
+ const root = value.plugin_root || "unavailable";
30
+ console.log(`AGDF runtime: profile=${profile} evidence=${evidence} version=${version} provenance=${provenance} machine_validation=${validation} root=${root}.`);
31
+ } catch {
32
+ console.log("AGDF runtime: profile=runtime-plugin evidence=unverified machine_validation=unavailable provenance=invalid. Retry the surface-local runtime probe or use the supported AGDF install/update command.");
33
+ }
34
+ NODE
35
+ )"
36
+ if [[ -n "${RUNTIME_RENDERED}" ]]; then
37
+ RUNTIME_HINT="${RUNTIME_RENDERED}"
38
+ fi
39
+ fi
11
40
 
12
41
  CONFIG_HINT="Project config: .agdf/control/config.json not found. Use npx --yes @agdf/cli@latest config --language de|en to persist the project language."
13
42
  if [[ -f "${CONFIG_PATH}" ]]; then
@@ -33,6 +62,8 @@ fi
33
62
  cat <<EOF
34
63
  AGDF active.
35
64
 
65
+ ${RUNTIME_HINT}
66
+
36
67
  Use the installed AGDF skills as workflow controls.
37
68
  For a new build, change, extension, refactor, CLI, app, fix with product semantics, unclear approval, or unclear next step, use gate-check before implementation or later-gate artefacts.
38
69
  ${CONFIG_HINT}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "id": "agdf",
4
- "version": "0.13.4",
4
+ "version": "0.13.6",
5
5
  "displayName": "AI Governance & Delivery Framework",
6
6
  "developerName": "Arndt Gold",
7
7
  "description": "Control layer for governed AI-assisted delivery.",
@@ -33,9 +33,8 @@
33
33
  "Write"
34
34
  ],
35
35
  "defaultPrompt": [
36
- "Assess whether AGDF is proportionate for this repository and request before proposing any implementation. Explain AGDF's purpose and practical benefits, weigh governance overhead against the project's delivery risk, and recommend the lightest suitable path — or explicitly advise against AGDF where it would add more process than value.",
36
+ "Assess whether AGDF fits this request and recommend the lightest safe path before proposing implementation.",
37
37
  "Start this request under AGDF governance.",
38
- "Create durable AGDF control state for this repository.",
39
38
  "Close this delivery run with an auditable AGDF report."
40
39
  ],
41
40
  "hooks": "hooks/hooks.json"
@@ -44,9 +43,8 @@
44
43
  "skillPrefix": "",
45
44
  "agentRouter": "meta/agdf-agent-router.md",
46
45
  "defaultPrompt": [
47
- "Assess whether AGDF is proportionate for this repository and request before proposing any implementation. Explain AGDF's purpose and practical benefits, weigh governance overhead against the project's delivery risk, and recommend the lightest suitable path — or explicitly advise against AGDF where it would add more process than value.",
46
+ "Assess whether AGDF fits this request and recommend the lightest safe path before proposing implementation.",
48
47
  "Start this request under AGDF governance.",
49
- "Create durable AGDF control state for this repository.",
50
48
  "Close this delivery run with an auditable AGDF report."
51
49
  ]
52
50
  },
@@ -254,10 +252,33 @@
254
252
  "boundary": "supports Quality Readiness; no final QA decision"
255
253
  }
256
254
  ],
257
- "marketplaces": {
258
- "repository": {
259
- "name": "agdf-repo",
260
- "displayName": "This repository"
255
+ "distributionProfiles": {
256
+ "schemaVersion": 1,
257
+ "marketplaceIdentities": {
258
+ "durable": "agdf",
259
+ "generatedRepository": "agdf-repo"
260
+ },
261
+ "profiles": {
262
+ "source-development": {
263
+ "runtime": "absent",
264
+ "installable": false,
265
+ "machineValidation": "unavailable"
266
+ },
267
+ "runtime-plugin": {
268
+ "runtime": "required",
269
+ "installable": true,
270
+ "machineValidation": "local_exact_version_digest"
271
+ },
272
+ "opencode-config-local": {
273
+ "runtime": "config_local_package",
274
+ "installable": true,
275
+ "machineValidation": "local_exact_version"
276
+ },
277
+ "portable-skills": {
278
+ "runtime": "absent",
279
+ "installable": true,
280
+ "machineValidation": "unavailable_or_external_required"
281
+ }
261
282
  }
262
283
  }
263
284
  }
@@ -7,5 +7,12 @@ import { fileURLToPath } from "node:url";
7
7
  import { runLocalValidator } from "./create-agdf/lib/runtime/local-validator.js";
8
8
 
9
9
  const runtimeRoot = fileURLToPath(new URL(".", import.meta.url));
10
+ const pluginRoot = fileURLToPath(new URL("../", import.meta.url));
10
11
  const manifest = JSON.parse(readFileSync(new URL("./runtime-manifest.json", import.meta.url), "utf8"));
11
- process.exitCode = runLocalValidator({ runtimeRoot, expectedVersion: manifest.version, surface: process.env.AGDF_SURFACE || "plugin" }, process.argv.slice(2));
12
+ process.exitCode = runLocalValidator({
13
+ runtimeRoot,
14
+ pluginRoot,
15
+ expectedPluginRoot: process.env.CLAUDE_PLUGIN_ROOT || undefined,
16
+ expectedVersion: manifest.version,
17
+ surface: process.env.AGDF_SURFACE || "plugin",
18
+ }, process.argv.slice(2));
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "id": "agdf",
4
- "version": "0.13.4",
4
+ "version": "0.13.6",
5
5
  "displayName": "AI Governance & Delivery Framework",
6
6
  "developerName": "Arndt Gold",
7
7
  "description": "Control layer for governed AI-assisted delivery.",
@@ -33,9 +33,8 @@
33
33
  "Write"
34
34
  ],
35
35
  "defaultPrompt": [
36
- "Assess whether AGDF is proportionate for this repository and request before proposing any implementation. Explain AGDF's purpose and practical benefits, weigh governance overhead against the project's delivery risk, and recommend the lightest suitable path — or explicitly advise against AGDF where it would add more process than value.",
36
+ "Assess whether AGDF fits this request and recommend the lightest safe path before proposing implementation.",
37
37
  "Start this request under AGDF governance.",
38
- "Create durable AGDF control state for this repository.",
39
38
  "Close this delivery run with an auditable AGDF report."
40
39
  ],
41
40
  "hooks": "hooks/hooks.json"
@@ -44,9 +43,8 @@
44
43
  "skillPrefix": "",
45
44
  "agentRouter": "meta/agdf-agent-router.md",
46
45
  "defaultPrompt": [
47
- "Assess whether AGDF is proportionate for this repository and request before proposing any implementation. Explain AGDF's purpose and practical benefits, weigh governance overhead against the project's delivery risk, and recommend the lightest suitable path — or explicitly advise against AGDF where it would add more process than value.",
46
+ "Assess whether AGDF fits this request and recommend the lightest safe path before proposing implementation.",
48
47
  "Start this request under AGDF governance.",
49
- "Create durable AGDF control state for this repository.",
50
48
  "Close this delivery run with an auditable AGDF report."
51
49
  ]
52
50
  },
@@ -254,10 +252,33 @@
254
252
  "boundary": "supports Quality Readiness; no final QA decision"
255
253
  }
256
254
  ],
257
- "marketplaces": {
258
- "repository": {
259
- "name": "agdf-repo",
260
- "displayName": "This repository"
255
+ "distributionProfiles": {
256
+ "schemaVersion": 1,
257
+ "marketplaceIdentities": {
258
+ "durable": "agdf",
259
+ "generatedRepository": "agdf-repo"
260
+ },
261
+ "profiles": {
262
+ "source-development": {
263
+ "runtime": "absent",
264
+ "installable": false,
265
+ "machineValidation": "unavailable"
266
+ },
267
+ "runtime-plugin": {
268
+ "runtime": "required",
269
+ "installable": true,
270
+ "machineValidation": "local_exact_version_digest"
271
+ },
272
+ "opencode-config-local": {
273
+ "runtime": "config_local_package",
274
+ "installable": true,
275
+ "machineValidation": "local_exact_version"
276
+ },
277
+ "portable-skills": {
278
+ "runtime": "absent",
279
+ "installable": true,
280
+ "machineValidation": "unavailable_or_external_required"
281
+ }
261
282
  }
262
283
  }
263
284
  }
@@ -1,8 +1,14 @@
1
- import { createHash } from "node:crypto";
2
1
  import { spawnSync } from "node:child_process";
3
- import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
2
+ import { existsSync, readFileSync, realpathSync } from "node:fs";
4
3
  import { isAbsolute, join, relative, resolve, sep } from "node:path";
5
4
  import process from "node:process";
5
+ import {
6
+ INSTALLATION_PROVENANCE_FILE,
7
+ digestDirectory,
8
+ inspectGeneratedRepositoryMarketplace,
9
+ inspectInstallationProvenance,
10
+ validateDistributionProfiles,
11
+ } from "./plugin-provenance.js";
6
12
 
7
13
  function readJson(path) {
8
14
  try {
@@ -12,27 +18,12 @@ function readJson(path) {
12
18
  }
13
19
  }
14
20
 
15
- export function digestDirectory(root) {
16
- const files = [];
17
- function visit(directory) {
18
- for (const name of readdirSync(directory).sort()) {
19
- const path = join(directory, name);
20
- const stats = statSync(path);
21
- if (stats.isDirectory()) visit(path);
22
- else if (stats.isFile()) files.push(path);
23
- }
24
- }
25
- visit(root);
26
- const hash = createHash("sha256");
27
- for (const path of files) {
28
- hash.update(relative(root, path).replaceAll("\\", "/"));
29
- hash.update("\0");
30
- hash.update(readFileSync(path));
31
- hash.update("\0");
32
- }
33
- return hash.digest("hex");
21
+ function canonicalPath(path) {
22
+ try { return realpathSync(path); } catch { return resolve(path); }
34
23
  }
35
24
 
25
+ export { digestDirectory };
26
+
36
27
  function envelope(machineValidation, options, evidence = {}) {
37
28
  return {
38
29
  schema_version: "1",
@@ -42,6 +33,14 @@ function envelope(machineValidation, options, evidence = {}) {
42
33
  observed_version: evidence.observedVersion ?? null,
43
34
  source: evidence.source ?? null,
44
35
  registry_access: false,
36
+ distribution_profile: evidence.distributionProfile ?? null,
37
+ evidence_plane: evidence.evidencePlane ?? null,
38
+ canonical_version: evidence.canonicalVersion ?? options.expectedVersion ?? null,
39
+ plugin_version: evidence.pluginVersion ?? null,
40
+ runtime_digest: evidence.runtimeDigest ?? null,
41
+ source_digest: evidence.sourceDigest ?? null,
42
+ plugin_root: evidence.pluginRoot ?? null,
43
+ provenance_status: evidence.provenanceStatus ?? null,
45
44
  ...(evidence.reason ? { reason: evidence.reason } : {}),
46
45
  };
47
46
  }
@@ -51,17 +50,17 @@ export function resolveLocalValidator(options) {
51
50
  const packageManifest = readJson(join(options.ownedPackageRoot, "package.json"));
52
51
  const observedVersion = packageManifest?.version ?? null;
53
52
  if (!packageManifest) {
54
- return { envelope: envelope("unavailable", options, { source: "config_local_package", reason: "package_missing" }) };
53
+ return { envelope: envelope("unavailable", options, { source: "config_local_package", evidencePlane: "opencode_config_local", distributionProfile: "opencode-config-local", reason: "package_missing" }) };
55
54
  }
56
55
  if (observedVersion !== options.expectedVersion) {
57
- return { envelope: envelope("version_mismatch", options, { observedVersion, source: "config_local_package" }) };
56
+ return { envelope: envelope("version_mismatch", options, { observedVersion, source: "config_local_package", evidencePlane: "opencode_config_local", distributionProfile: "opencode-config-local" }) };
58
57
  }
59
58
  const entrypoint = join(options.ownedPackageRoot, "bin", "create-agdf.js");
60
59
  if (!existsSync(entrypoint)) {
61
- return { envelope: envelope("unavailable", options, { observedVersion, source: "config_local_package", reason: "entrypoint_missing" }) };
60
+ return { envelope: envelope("unavailable", options, { observedVersion, source: "config_local_package", evidencePlane: "opencode_config_local", distributionProfile: "opencode-config-local", reason: "entrypoint_missing" }) };
62
61
  }
63
62
  return {
64
- envelope: envelope("owned_version_matched", options, { observedVersion, source: "config_local_package" }),
63
+ envelope: envelope("owned_version_matched", options, { observedVersion, source: "config_local_package", evidencePlane: "opencode_config_local", distributionProfile: "opencode-config-local", provenanceStatus: "matched" }),
65
64
  executable: process.execPath,
66
65
  prefixArgs: [entrypoint],
67
66
  };
@@ -73,30 +72,116 @@ export function resolveLocalValidator(options) {
73
72
  return { envelope: envelope("version_mismatch", options, { source: "plugin_bundle", reason: "manifest_invalid" }) };
74
73
  }
75
74
  if (manifest) {
75
+ const pluginRoot = canonicalPath(options.pluginRoot ?? join(options.runtimeRoot, ".."));
76
+ if (options.expectedPluginRoot && canonicalPath(options.expectedPluginRoot) !== pluginRoot) {
77
+ return { envelope: envelope("version_mismatch", options, { source: "plugin_bundle", pluginRoot, evidencePlane: "loaded_session", distributionProfile: "runtime-plugin", provenanceStatus: "mismatch", reason: "plugin_root_mismatch" }) };
78
+ }
79
+ const definition = readJson(join(pluginRoot, "meta", "agdf-plugin.definition.json"));
80
+ const profile = validateDistributionProfiles(definition);
81
+ if (profile.status !== "matched") {
82
+ return { envelope: envelope("version_mismatch", options, { source: "plugin_bundle", pluginRoot, distributionProfile: "runtime-plugin", provenanceStatus: "invalid", reason: "profile_invalid" }) };
83
+ }
84
+ const codexManifest = readJson(join(pluginRoot, ".codex-plugin", "plugin.json"));
85
+ const claudeManifest = readJson(join(pluginRoot, ".claude-plugin", "plugin.json"));
86
+ const pluginVersion = codexManifest?.version ?? null;
87
+ if (!codexManifest || !claudeManifest || claudeManifest.version !== definition.version) {
88
+ return { envelope: envelope("version_mismatch", options, { source: "plugin_bundle", pluginRoot, pluginVersion, canonicalVersion: definition.version, distributionProfile: "runtime-plugin", provenanceStatus: "invalid", reason: "manifest_invalid" }) };
89
+ }
76
90
  const packageRoot = join(options.runtimeRoot, "create-agdf");
77
91
  if (!existsSync(packageRoot)) {
78
- return { envelope: envelope("unavailable", options, { source: "plugin_bundle", reason: "package_missing" }) };
92
+ return { envelope: envelope("unavailable", options, { source: "plugin_bundle", pluginRoot, pluginVersion, distributionProfile: "runtime-plugin", reason: "runtime_missing" }) };
79
93
  }
80
94
  const packageManifest = readJson(join(packageRoot, "package.json"));
81
95
  const observedVersion = packageManifest?.version ?? manifest.version ?? null;
82
96
  if (observedVersion !== options.expectedVersion || manifest.version !== options.expectedVersion) {
83
- return { envelope: envelope("version_mismatch", options, { observedVersion, source: "plugin_bundle" }) };
97
+ return { envelope: envelope("version_mismatch", options, { observedVersion, source: "plugin_bundle", pluginRoot, pluginVersion, canonicalVersion: definition.version, distributionProfile: "runtime-plugin" }) };
84
98
  }
85
99
  let observedDigest = null;
86
100
  try { observedDigest = digestDirectory(packageRoot); } catch {}
87
101
  if (!observedDigest || manifest.digest !== observedDigest) {
88
- return { envelope: envelope("version_mismatch", options, { observedVersion, source: "plugin_bundle", reason: "digest_mismatch" }) };
102
+ return { envelope: envelope("version_mismatch", options, { observedVersion, source: "plugin_bundle", pluginRoot, pluginVersion, canonicalVersion: definition.version, runtimeDigest: observedDigest, distributionProfile: "runtime-plugin", reason: "runtime_digest_mismatch" }) };
89
103
  }
90
104
  const entrypoint = resolve(options.runtimeRoot, manifest.entrypoint ?? "");
91
105
  const entrypointRelative = relative(options.runtimeRoot, entrypoint);
92
106
  if (!manifest.entrypoint || entrypointRelative === ".." || entrypointRelative.startsWith(`..${sep}`) || isAbsolute(entrypointRelative)) {
93
- return { envelope: envelope("version_mismatch", options, { observedVersion, source: "plugin_bundle", reason: "invalid_entrypoint" }) };
107
+ return { envelope: envelope("version_mismatch", options, { observedVersion, source: "plugin_bundle", pluginRoot, pluginVersion, canonicalVersion: definition.version, runtimeDigest: observedDigest, distributionProfile: "runtime-plugin", reason: "invalid_entrypoint" }) };
94
108
  }
95
109
  if (!existsSync(entrypoint)) {
96
- return { envelope: envelope("unavailable", options, { observedVersion, source: "plugin_bundle", reason: "entrypoint_missing" }) };
110
+ return { envelope: envelope("unavailable", options, { observedVersion, source: "plugin_bundle", pluginRoot, pluginVersion, canonicalVersion: definition.version, runtimeDigest: observedDigest, distributionProfile: "runtime-plugin", reason: "entrypoint_missing" }) };
111
+ }
112
+ const installed = existsSync(join(pluginRoot, INSTALLATION_PROVENANCE_FILE));
113
+ let provenanceStatus = "not_applicable";
114
+ let sourceDigest = null;
115
+ let evidencePlane = "loaded_session";
116
+ if (installed) {
117
+ const provenance = inspectInstallationProvenance(pluginRoot, {
118
+ definition,
119
+ runtimeManifest: manifest,
120
+ pluginVersion,
121
+ });
122
+ provenanceStatus = provenance.status;
123
+ sourceDigest = provenance.marker?.source_digest ?? null;
124
+ if (provenance.status !== "matched") {
125
+ return { envelope: envelope("version_mismatch", options, {
126
+ observedVersion,
127
+ source: "plugin_bundle",
128
+ pluginRoot,
129
+ pluginVersion,
130
+ canonicalVersion: definition.version,
131
+ runtimeDigest: observedDigest,
132
+ sourceDigest,
133
+ distributionProfile: "runtime-plugin",
134
+ evidencePlane: "loaded_session",
135
+ provenanceStatus,
136
+ reason: provenance.reason,
137
+ }) };
138
+ }
139
+ } else if (existsSync(join(pluginRoot, ".agdf-local-install.json"))) {
140
+ return { envelope: envelope("unavailable", options, {
141
+ observedVersion,
142
+ source: "plugin_bundle",
143
+ pluginRoot,
144
+ pluginVersion,
145
+ canonicalVersion: definition.version,
146
+ runtimeDigest: observedDigest,
147
+ distributionProfile: "runtime-plugin",
148
+ evidencePlane: "loaded_session",
149
+ provenanceStatus: "missing",
150
+ reason: "installation_provenance_missing",
151
+ }) };
152
+ } else {
153
+ const generatedRepository = inspectGeneratedRepositoryMarketplace(resolve(pluginRoot, "..", ".."));
154
+ if (pluginVersion !== definition.version
155
+ || generatedRepository.status !== "matched"
156
+ || canonicalPath(generatedRepository.pluginRoot) !== pluginRoot) {
157
+ return { envelope: envelope("unavailable", options, {
158
+ observedVersion,
159
+ source: "plugin_bundle",
160
+ pluginRoot,
161
+ pluginVersion,
162
+ canonicalVersion: definition.version,
163
+ runtimeDigest: observedDigest,
164
+ distributionProfile: "runtime-plugin",
165
+ evidencePlane: "installed_plugin_root",
166
+ provenanceStatus: "missing",
167
+ reason: "installation_provenance_missing",
168
+ }) };
169
+ }
170
+ evidencePlane = "generated_bundle";
97
171
  }
98
172
  return {
99
- envelope: envelope("owned_version_matched", options, { observedVersion, source: "plugin_bundle" }),
173
+ envelope: envelope("owned_version_matched", options, {
174
+ observedVersion,
175
+ source: "plugin_bundle",
176
+ pluginRoot,
177
+ pluginVersion,
178
+ canonicalVersion: definition.version,
179
+ runtimeDigest: observedDigest,
180
+ sourceDigest,
181
+ distributionProfile: "runtime-plugin",
182
+ evidencePlane,
183
+ provenanceStatus,
184
+ }),
100
185
  executable: process.execPath,
101
186
  prefixArgs: [entrypoint],
102
187
  };