create-agdf 0.13.5 → 0.13.7
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 +7 -1
- package/generated/plugins/agdf/.claude-plugin/plugin.json +1 -1
- package/generated/plugins/agdf/.codex-plugin/plugin.json +2 -3
- package/generated/plugins/agdf/hooks/session-start.sh +31 -0
- package/generated/plugins/agdf/meta/agdf-plugin.definition.json +30 -9
- package/generated/plugins/agdf/runtime/agdf-local.js +8 -1
- package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-plugin.definition.json +30 -9
- package/generated/plugins/agdf/runtime/create-agdf/lib/runtime/local-validator.js +116 -31
- package/generated/plugins/agdf/runtime/create-agdf/lib/runtime/plugin-provenance.js +206 -0
- package/generated/plugins/agdf/runtime/create-agdf/package.json +1 -1
- package/generated/plugins/agdf/runtime/runtime-manifest.json +2 -2
- package/generated/plugins/agdf/scripts/check-runtime-integrity.mjs +64 -19
- package/generated/plugins/agdf/submission/openai/availability.md +1 -1
- package/generated/plugins/agdf/submission/openai/capability-matrix.json +1 -1
- package/generated/plugins/agdf/submission/openai/release-notes.md +1 -1
- package/generated/plugins/agdf/submission/openai/reviewer-cases.json +1 -1
- package/generated/submissions/openai/agdf/.codex-plugin/plugin.json +1 -1
- package/generated/submissions/openai/agdf/meta/agdf-plugin.definition.json +30 -9
- package/generated/submissions/openai/agdf/submission/openai/availability.md +1 -1
- package/generated/submissions/openai/agdf/submission/openai/capability-matrix.json +1 -1
- package/generated/submissions/openai/agdf/submission/openai/inventory.json +9 -9
- package/generated/submissions/openai/agdf/submission/openai/listing.json +1 -1
- package/generated/submissions/openai/agdf/submission/openai/readiness.json +2 -2
- package/generated/submissions/openai/agdf/submission/openai/readiness.md +2 -2
- package/generated/submissions/openai/agdf/submission/openai/release-notes.md +1 -1
- package/generated/submissions/openai/agdf/submission/openai/reviewer-cases.json +1 -1
- package/lib/cli/application.js +4 -3
- package/lib/fs-swap.js +26 -0
- package/lib/installers/local-development.js +202 -0
- package/lib/installers/local-marketplace.js +253 -46
- package/lib/installers/opencode.js +17 -2
- package/lib/installers/plugin-installers.js +88 -22
- package/lib/lifecycle/operations.js +9 -5
- package/lib/lifecycle/status.js +10 -2
- package/lib/public-plugin/builder.js +5 -4
- package/lib/runtime/local-validator.js +116 -31
- package/lib/runtime/plugin-provenance.js +206 -0
- package/package.json +6 -2
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
3
|
+
import { isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
4
|
+
|
|
5
|
+
export const INSTALLATION_PROVENANCE_FILE = ".agdf-installation.json";
|
|
6
|
+
export const LEGACY_LOCAL_INSTALL_FILE = ".agdf-local-install.json";
|
|
7
|
+
|
|
8
|
+
const EXPECTED_PROFILES = Object.freeze({
|
|
9
|
+
"source-development": Object.freeze({ runtime: "absent", installable: false, machineValidation: "unavailable" }),
|
|
10
|
+
"runtime-plugin": Object.freeze({ runtime: "required", installable: true, machineValidation: "local_exact_version_digest" }),
|
|
11
|
+
"opencode-config-local": Object.freeze({ runtime: "config_local_package", installable: true, machineValidation: "local_exact_version" }),
|
|
12
|
+
"portable-skills": Object.freeze({ runtime: "absent", installable: true, machineValidation: "unavailable_or_external_required" }),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
function readJson(path) {
|
|
16
|
+
try {
|
|
17
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
18
|
+
} catch {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function digestDirectory(root) {
|
|
24
|
+
const files = [];
|
|
25
|
+
function visit(directory) {
|
|
26
|
+
for (const name of readdirSync(directory).sort()) {
|
|
27
|
+
const path = join(directory, name);
|
|
28
|
+
const stats = statSync(path);
|
|
29
|
+
if (stats.isDirectory()) visit(path);
|
|
30
|
+
else if (stats.isFile()) files.push(path);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
visit(root);
|
|
34
|
+
const hash = createHash("sha256");
|
|
35
|
+
for (const path of files) {
|
|
36
|
+
hash.update(relative(root, path).replaceAll("\\", "/"));
|
|
37
|
+
hash.update("\0");
|
|
38
|
+
hash.update(readFileSync(path));
|
|
39
|
+
hash.update("\0");
|
|
40
|
+
}
|
|
41
|
+
return hash.digest("hex");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function digestNormalizedPluginSource(root, canonicalVersion) {
|
|
45
|
+
const files = [];
|
|
46
|
+
function visit(directory) {
|
|
47
|
+
for (const name of readdirSync(directory).sort()) {
|
|
48
|
+
const path = join(directory, name);
|
|
49
|
+
const stats = statSync(path);
|
|
50
|
+
if (stats.isDirectory()) visit(path);
|
|
51
|
+
else if (stats.isFile()) files.push(path);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
visit(root);
|
|
55
|
+
const hash = createHash("sha256");
|
|
56
|
+
for (const path of files) {
|
|
57
|
+
const normalizedPath = relative(root, path).replaceAll("\\", "/");
|
|
58
|
+
if ([INSTALLATION_PROVENANCE_FILE, LEGACY_LOCAL_INSTALL_FILE].includes(normalizedPath)) continue;
|
|
59
|
+
let content = readFileSync(path);
|
|
60
|
+
if (normalizedPath === ".codex-plugin/plugin.json") {
|
|
61
|
+
const manifest = readJson(path);
|
|
62
|
+
if (!manifest) throw new Error(`Invalid Codex plugin manifest: ${path}`);
|
|
63
|
+
content = `${JSON.stringify({ ...manifest, version: canonicalVersion }, null, 2)}\n`;
|
|
64
|
+
}
|
|
65
|
+
hash.update(normalizedPath);
|
|
66
|
+
hash.update("\0");
|
|
67
|
+
hash.update(content);
|
|
68
|
+
hash.update("\0");
|
|
69
|
+
}
|
|
70
|
+
return hash.digest("hex");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function validateDistributionProfiles(definition) {
|
|
74
|
+
const contract = definition?.distributionProfiles;
|
|
75
|
+
if (contract?.schemaVersion !== 1) return { status: "invalid", reason: "profile_invalid" };
|
|
76
|
+
if (contract.marketplaceIdentities?.durable !== "agdf"
|
|
77
|
+
|| contract.marketplaceIdentities?.generatedRepository !== "agdf-repo") {
|
|
78
|
+
return { status: "invalid", reason: "profile_invalid" };
|
|
79
|
+
}
|
|
80
|
+
for (const [profileId, expected] of Object.entries(EXPECTED_PROFILES)) {
|
|
81
|
+
const observed = contract.profiles?.[profileId];
|
|
82
|
+
if (!observed
|
|
83
|
+
|| Object.keys(observed).length !== Object.keys(expected).length
|
|
84
|
+
|| Object.keys(expected).some((key) => observed[key] !== expected[key])) {
|
|
85
|
+
return { status: "invalid", reason: "profile_invalid" };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (Object.keys(contract.profiles ?? {}).length !== Object.keys(EXPECTED_PROFILES).length) {
|
|
89
|
+
return { status: "invalid", reason: "profile_invalid" };
|
|
90
|
+
}
|
|
91
|
+
return { status: "matched", contract };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function inspectGeneratedRepositoryMarketplace(targetDir) {
|
|
95
|
+
const marketplacePath = join(targetDir, ".agents", "plugins", "marketplace.json");
|
|
96
|
+
if (!existsSync(marketplacePath)) return { status: "absent", marketplacePath };
|
|
97
|
+
const marketplace = readJson(marketplacePath);
|
|
98
|
+
const plugin = marketplace?.plugins?.length === 1 ? marketplace.plugins[0] : null;
|
|
99
|
+
const pluginPath = plugin?.source?.source === "local" ? plugin.source.path : null;
|
|
100
|
+
if (marketplace?.name !== "agdf-repo" || plugin?.name !== "agdf" || pluginPath !== "./plugins/agdf") {
|
|
101
|
+
return { status: "invalid", reason: "repository_marketplace_invalid", marketplacePath };
|
|
102
|
+
}
|
|
103
|
+
const pluginRoot = resolve(targetDir, pluginPath);
|
|
104
|
+
const rel = relative(resolve(targetDir), pluginRoot);
|
|
105
|
+
if (rel === ".." || rel.startsWith(`..${sep}`) || isAbsolute(rel)) {
|
|
106
|
+
return { status: "invalid", reason: "repository_marketplace_path_escape", marketplacePath };
|
|
107
|
+
}
|
|
108
|
+
const definition = readJson(join(pluginRoot, "meta", "agdf-plugin.definition.json"));
|
|
109
|
+
const runtimeManifest = readJson(join(pluginRoot, "runtime", "runtime-manifest.json"));
|
|
110
|
+
const codexManifest = readJson(join(pluginRoot, ".codex-plugin", "plugin.json"));
|
|
111
|
+
const claudeManifest = readJson(join(pluginRoot, ".claude-plugin", "plugin.json"));
|
|
112
|
+
const runtimeRoot = join(pluginRoot, "runtime");
|
|
113
|
+
const runtimePackageRoot = join(pluginRoot, "runtime", "create-agdf");
|
|
114
|
+
const runtimeEntrypoint = resolve(runtimeRoot, runtimeManifest?.entrypoint ?? "");
|
|
115
|
+
const runtimeEntrypointRel = relative(runtimeRoot, runtimeEntrypoint);
|
|
116
|
+
if (validateDistributionProfiles(definition).status !== "matched"
|
|
117
|
+
|| definition?.version !== runtimeManifest?.version
|
|
118
|
+
|| codexManifest?.version !== definition?.version
|
|
119
|
+
|| claudeManifest?.version !== definition?.version
|
|
120
|
+
|| !/^[a-f0-9]{64}$/.test(runtimeManifest?.digest ?? "")
|
|
121
|
+
|| !existsSync(join(runtimeRoot, "agdf-local.js"))
|
|
122
|
+
|| !runtimeManifest?.entrypoint
|
|
123
|
+
|| runtimeEntrypointRel === ".."
|
|
124
|
+
|| runtimeEntrypointRel.startsWith(`..${sep}`)
|
|
125
|
+
|| isAbsolute(runtimeEntrypointRel)
|
|
126
|
+
|| !existsSync(runtimeEntrypoint)
|
|
127
|
+
|| !existsSync(runtimePackageRoot)) {
|
|
128
|
+
return { status: "invalid", reason: "repository_runtime_incomplete", marketplacePath, pluginRoot };
|
|
129
|
+
}
|
|
130
|
+
let runtimeDigest;
|
|
131
|
+
try { runtimeDigest = digestDirectory(runtimePackageRoot); } catch {
|
|
132
|
+
return { status: "invalid", reason: "repository_runtime_incomplete", marketplacePath, pluginRoot };
|
|
133
|
+
}
|
|
134
|
+
if (runtimeDigest !== runtimeManifest.digest) {
|
|
135
|
+
return { status: "invalid", reason: "runtime_digest_mismatch", marketplacePath, pluginRoot };
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
status: "matched",
|
|
139
|
+
marketplacePath,
|
|
140
|
+
pluginRoot,
|
|
141
|
+
selector: `${plugin.name}@${marketplace.name}`,
|
|
142
|
+
runtimeDigest,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function inspectInstallationProvenance(pluginRoot, {
|
|
147
|
+
definition,
|
|
148
|
+
runtimeManifest,
|
|
149
|
+
pluginVersion,
|
|
150
|
+
allowLegacy = false,
|
|
151
|
+
} = {}) {
|
|
152
|
+
const markerPath = join(pluginRoot, INSTALLATION_PROVENANCE_FILE);
|
|
153
|
+
const legacyPath = join(pluginRoot, LEGACY_LOCAL_INSTALL_FILE);
|
|
154
|
+
if (!existsSync(markerPath)) {
|
|
155
|
+
if (allowLegacy && existsSync(legacyPath)) {
|
|
156
|
+
const marker = readJson(legacyPath);
|
|
157
|
+
if (!marker
|
|
158
|
+
|| marker.schema_version !== 1
|
|
159
|
+
|| marker.owner !== "create-agdf"
|
|
160
|
+
|| marker.kind !== "codex_local_development_projection"
|
|
161
|
+
|| marker.canonical_version !== definition.version
|
|
162
|
+
|| marker.codex_install_version !== pluginVersion
|
|
163
|
+
|| !/^[a-f0-9]{64}$/.test(marker.source_digest ?? "")) {
|
|
164
|
+
return { status: "invalid", reason: "installation_provenance_invalid", marker };
|
|
165
|
+
}
|
|
166
|
+
let observedSourceDigest;
|
|
167
|
+
try { observedSourceDigest = digestNormalizedPluginSource(pluginRoot, definition.version); } catch {
|
|
168
|
+
return { status: "invalid", reason: "source_digest_mismatch", marker };
|
|
169
|
+
}
|
|
170
|
+
return observedSourceDigest === marker.source_digest
|
|
171
|
+
? { status: "legacy", marker, observedSourceDigest, reason: "legacy_installation_provenance" }
|
|
172
|
+
: { status: "invalid", reason: "source_digest_mismatch", marker, observedSourceDigest };
|
|
173
|
+
}
|
|
174
|
+
const profile = validateDistributionProfiles(definition);
|
|
175
|
+
if (profile.status !== "matched") return profile;
|
|
176
|
+
return { status: "missing", reason: "installation_provenance_missing" };
|
|
177
|
+
}
|
|
178
|
+
const profile = validateDistributionProfiles(definition);
|
|
179
|
+
if (profile.status !== "matched") return profile;
|
|
180
|
+
const marker = readJson(markerPath);
|
|
181
|
+
if (!marker
|
|
182
|
+
|| marker.schema_version !== 1
|
|
183
|
+
|| marker.owner !== "create-agdf"
|
|
184
|
+
|| marker.profile_id !== "runtime-plugin"
|
|
185
|
+
|| marker.marketplace_id !== profile.contract.marketplaceIdentities.durable
|
|
186
|
+
|| marker.canonical_version !== definition.version
|
|
187
|
+
|| marker.codex_install_version !== pluginVersion
|
|
188
|
+
|| marker.runtime_digest !== runtimeManifest?.digest
|
|
189
|
+
|| !/^[a-f0-9]{64}$/.test(marker.source_digest ?? "")) {
|
|
190
|
+
return { status: "invalid", reason: "installation_provenance_invalid", marker };
|
|
191
|
+
}
|
|
192
|
+
let observedSourceDigest;
|
|
193
|
+
try {
|
|
194
|
+
observedSourceDigest = digestNormalizedPluginSource(pluginRoot, definition.version);
|
|
195
|
+
} catch {
|
|
196
|
+
return { status: "invalid", reason: "source_digest_mismatch", marker };
|
|
197
|
+
}
|
|
198
|
+
if (observedSourceDigest !== marker.source_digest) {
|
|
199
|
+
return { status: "invalid", reason: "source_digest_mismatch", marker, observedSourceDigest };
|
|
200
|
+
}
|
|
201
|
+
return { status: "matched", marker, observedSourceDigest };
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export const distributionProfileContract = Object.freeze({
|
|
205
|
+
expectedProfiles: EXPECTED_PROFILES,
|
|
206
|
+
});
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schema_version": "1",
|
|
3
3
|
"generated": true,
|
|
4
4
|
"source": "create-agdf/cli",
|
|
5
|
-
"version": "0.13.
|
|
5
|
+
"version": "0.13.7",
|
|
6
6
|
"entrypoint": "create-agdf/bin/agdf-validator.js",
|
|
7
|
-
"digest": "
|
|
7
|
+
"digest": "05afaf9ec478d50900a79cbdda8fcd7c61fa5627f4770ba093b19908fa6df91b"
|
|
8
8
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
1
2
|
import { readdirSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
2
3
|
import { spawnSync } from "node:child_process";
|
|
3
4
|
import { fileURLToPath } from "node:url";
|
|
4
|
-
import { dirname, join, resolve } from "node:path";
|
|
5
|
+
import { dirname, join, relative, resolve } from "node:path";
|
|
5
6
|
|
|
6
7
|
const scriptPluginRoot = resolve(fileURLToPath(new URL("..", import.meta.url)));
|
|
7
8
|
|
|
@@ -46,7 +47,6 @@ function hasPluginLayout(root) {
|
|
|
46
47
|
function hasSourceLayout(root) {
|
|
47
48
|
return hasPluginLayout(join(root, "plugin"))
|
|
48
49
|
&& [
|
|
49
|
-
".claude-plugin/marketplace.json",
|
|
50
50
|
"agdf/package.json",
|
|
51
51
|
"create-agdf/package.json",
|
|
52
52
|
"pages/package.json",
|
|
@@ -92,9 +92,12 @@ try {
|
|
|
92
92
|
console.error("- AGDF_AGENT_SKILLS_VALIDATOR_MISSING: scripts/agent-skills-conformance.mjs must be present and loadable");
|
|
93
93
|
process.exit(1);
|
|
94
94
|
}
|
|
95
|
-
const
|
|
95
|
+
const codexSourceMarketplacePath = sourceMode ? join(repoRoot, ".agents", "plugins", "marketplace.json") : null;
|
|
96
|
+
const claudeSourceMarketplacePath = sourceMode ? join(repoRoot, ".claude-plugin", "marketplace.json") : null;
|
|
96
97
|
const codexPluginPath = join(pluginRoot, ".codex-plugin", "plugin.json");
|
|
97
98
|
const claudePluginPath = join(pluginRoot, ".claude-plugin", "plugin.json");
|
|
99
|
+
const installationProvenancePath = join(pluginRoot, ".agdf-installation.json");
|
|
100
|
+
const legacyLocalInstallMarkerPath = join(pluginRoot, ".agdf-local-install.json");
|
|
98
101
|
const pluginDefinitionPath = join(pluginRoot, "meta", "agdf-plugin.definition.json");
|
|
99
102
|
const agentRouterPath = join(pluginRoot, "meta", "agdf-agent-router.md");
|
|
100
103
|
const runtimeContractPath = join(pluginRoot, "meta", "agdf-runtime-contract.md");
|
|
@@ -203,6 +206,32 @@ function readJson(path, label) {
|
|
|
203
206
|
}
|
|
204
207
|
}
|
|
205
208
|
|
|
209
|
+
function digestPluginSource(root, canonicalVersion) {
|
|
210
|
+
const files = [];
|
|
211
|
+
function visit(directory) {
|
|
212
|
+
for (const name of readdirSync(directory).sort()) {
|
|
213
|
+
const path = join(directory, name);
|
|
214
|
+
const stats = statSync(path);
|
|
215
|
+
if (stats.isDirectory()) visit(path);
|
|
216
|
+
else if (stats.isFile()) files.push(path);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
visit(root);
|
|
220
|
+
const hash = createHash("sha256");
|
|
221
|
+
for (const path of files) {
|
|
222
|
+
const normalizedPath = relative(root, path).replaceAll("\\", "/");
|
|
223
|
+
if ([".agdf-installation.json", ".agdf-local-install.json"].includes(normalizedPath)) continue;
|
|
224
|
+
const content = normalizedPath === ".codex-plugin/plugin.json"
|
|
225
|
+
? `${JSON.stringify({ ...readJson(path, "Codex plugin manifest"), version: canonicalVersion }, null, 2)}\n`
|
|
226
|
+
: readFileSync(path);
|
|
227
|
+
hash.update(normalizedPath);
|
|
228
|
+
hash.update("\0");
|
|
229
|
+
hash.update(content);
|
|
230
|
+
hash.update("\0");
|
|
231
|
+
}
|
|
232
|
+
return hash.digest("hex");
|
|
233
|
+
}
|
|
234
|
+
|
|
206
235
|
function stripAllowedGerman(content) {
|
|
207
236
|
let next = content;
|
|
208
237
|
for (const fragment of allowedGermanFragments) {
|
|
@@ -300,7 +329,8 @@ assertFile(join(controlRoot, "README.md"), "AGDF control scaffold README");
|
|
|
300
329
|
assertFile(pluginLicensePath, "plugin LICENSE");
|
|
301
330
|
|
|
302
331
|
if (sourceMode) {
|
|
303
|
-
|
|
332
|
+
if (isFile(codexSourceMarketplacePath)) failures.push("source checkout must not expose a runtime-free Codex marketplace");
|
|
333
|
+
if (isFile(claudeSourceMarketplacePath)) failures.push("source checkout must not expose a runtime-free Claude marketplace");
|
|
304
334
|
assertFile(agdfPackagePath, "agdf CLI package manifest");
|
|
305
335
|
assertFile(createAgdfPackagePath, "create-agdf package manifest");
|
|
306
336
|
assertFile(pagesPackagePath, "Pages package manifest");
|
|
@@ -328,6 +358,7 @@ for (const forbiddenRuntimeDirectory of ["installers", "lifecycle", "scaffold"])
|
|
|
328
358
|
}
|
|
329
359
|
for (const requiredRuntimeFile of sourceMode ? [] : [
|
|
330
360
|
"runtime/create-agdf/lib/runtime/validator-application.js",
|
|
361
|
+
"runtime/create-agdf/lib/runtime/plugin-provenance.js",
|
|
331
362
|
"runtime/create-agdf/lib/cli/validation-handlers.js",
|
|
332
363
|
]) assertFile(join(pluginRoot, requiredRuntimeFile), `focused surface-local runtime module ${requiredRuntimeFile}`);
|
|
333
364
|
if (!sourceMode && isFile(localRuntimeEntrypointPath)) {
|
|
@@ -401,6 +432,8 @@ for (const required of [
|
|
|
401
432
|
}
|
|
402
433
|
const codexPlugin = isFile(codexPluginPath) ? readJson(codexPluginPath, "Codex plugin manifest") : null;
|
|
403
434
|
const claudePlugin = isFile(claudePluginPath) ? readJson(claudePluginPath, "Claude plugin manifest") : null;
|
|
435
|
+
const installationProvenance = isFile(installationProvenancePath) ? readJson(installationProvenancePath, "AGDF installation provenance") : null;
|
|
436
|
+
const legacyLocalInstallMarker = isFile(legacyLocalInstallMarkerPath) ? readJson(legacyLocalInstallMarkerPath, "legacy AGDF local install marker") : null;
|
|
404
437
|
const agdfPackage = isFile(agdfPackagePath) ? readJson(agdfPackagePath, "agdf CLI package manifest") : null;
|
|
405
438
|
const createAgdfPackage = isFile(createAgdfPackagePath) ? readJson(createAgdfPackagePath, "create-agdf package manifest") : null;
|
|
406
439
|
const pagesPackage = isFile(pagesPackagePath) ? readJson(pagesPackagePath, "Pages package manifest") : null;
|
|
@@ -637,8 +670,18 @@ if (pluginDefinition) {
|
|
|
637
670
|
if (!skill?.boundary) failures.push(`canonical AGDF plugin definition skill ${skill?.slug ?? "<unknown>"} must declare boundary`);
|
|
638
671
|
}
|
|
639
672
|
}
|
|
640
|
-
|
|
641
|
-
|
|
673
|
+
const expectedProfiles = {
|
|
674
|
+
"source-development": { runtime: "absent", installable: false, machineValidation: "unavailable" },
|
|
675
|
+
"runtime-plugin": { runtime: "required", installable: true, machineValidation: "local_exact_version_digest" },
|
|
676
|
+
"opencode-config-local": { runtime: "config_local_package", installable: true, machineValidation: "local_exact_version" },
|
|
677
|
+
"portable-skills": { runtime: "absent", installable: true, machineValidation: "unavailable_or_external_required" },
|
|
678
|
+
};
|
|
679
|
+
if (pluginDefinition.distributionProfiles?.schemaVersion !== 1
|
|
680
|
+
|| pluginDefinition.distributionProfiles?.marketplaceIdentities?.durable !== "agdf"
|
|
681
|
+
|| pluginDefinition.distributionProfiles?.marketplaceIdentities?.generatedRepository !== "agdf-repo"
|
|
682
|
+
|| JSON.stringify(pluginDefinition.distributionProfiles?.profiles) !== JSON.stringify(expectedProfiles)) {
|
|
683
|
+
failures.push("canonical AGDF plugin definition distribution profiles must match the runtime integrity contract");
|
|
684
|
+
}
|
|
642
685
|
expectedSkills = (pluginDefinition.skillSet ?? [])
|
|
643
686
|
.map((skill) => `${pluginDefinition.codex?.skillPrefix ?? ""}${skill?.slug ?? ""}`)
|
|
644
687
|
.sort();
|
|
@@ -709,7 +752,21 @@ if (isFile(pagesSiteDataPath)) {
|
|
|
709
752
|
|
|
710
753
|
if (codexPlugin && pluginDefinition) {
|
|
711
754
|
if (codexPlugin.name !== pluginDefinition.id) failures.push("Codex plugin manifest name must match canonical AGDF plugin definition");
|
|
712
|
-
|
|
755
|
+
const expectedInstallVersion = installationProvenance?.codex_install_version ?? pluginDefinition.version;
|
|
756
|
+
const validInstalledProjection = !sourceMode
|
|
757
|
+
&& installationProvenance?.schema_version === 1
|
|
758
|
+
&& installationProvenance?.owner === "create-agdf"
|
|
759
|
+
&& installationProvenance?.profile_id === "runtime-plugin"
|
|
760
|
+
&& installationProvenance?.marketplace_id === "agdf"
|
|
761
|
+
&& installationProvenance?.canonical_version === pluginDefinition.version
|
|
762
|
+
&& /^[a-f0-9]{64}$/.test(installationProvenance?.source_digest ?? "")
|
|
763
|
+
&& installationProvenance?.source_digest === digestPluginSource(pluginRoot, pluginDefinition.version)
|
|
764
|
+
&& installationProvenance?.runtime_digest === localRuntimeManifest?.digest
|
|
765
|
+
&& codexPlugin.version === expectedInstallVersion;
|
|
766
|
+
if (codexPlugin.version !== pluginDefinition.version && !validInstalledProjection) failures.push("Codex plugin manifest version must match canonical AGDF plugin definition or one owned installed projection");
|
|
767
|
+
if (installationProvenance && !validInstalledProjection) failures.push("AGDF installation provenance must match plugin, runtime and normalized source digests");
|
|
768
|
+
if (sourceMode && (installationProvenance || legacyLocalInstallMarker)) failures.push("source plugin must not contain AGDF installation provenance");
|
|
769
|
+
if (!sourceMode && legacyLocalInstallMarker) failures.push("installed plugin must not retain the legacy AGDF local install marker");
|
|
713
770
|
if (codexPlugin.description !== pluginDefinition.description) failures.push("Codex plugin manifest description must match canonical AGDF plugin definition");
|
|
714
771
|
if (codexPlugin.homepage !== pluginDefinition.homepage) failures.push("Codex plugin manifest homepage must match canonical AGDF plugin definition");
|
|
715
772
|
if (codexPlugin.repository !== pluginDefinition.repository) failures.push("Codex plugin manifest repository must match canonical AGDF plugin definition");
|
|
@@ -962,18 +1019,6 @@ if (isFile(runtimeContractPath)) {
|
|
|
962
1019
|
}
|
|
963
1020
|
}
|
|
964
1021
|
|
|
965
|
-
if (sourceMode) {
|
|
966
|
-
const marketplace = isFile(marketplacePath) ? readJson(marketplacePath, "plugin marketplace") : null;
|
|
967
|
-
const agdfMarketplaceEntry = marketplace?.plugins?.find((plugin) => plugin?.name === "agdf");
|
|
968
|
-
if (!agdfMarketplaceEntry) {
|
|
969
|
-
failures.push("plugin marketplace must expose agdf");
|
|
970
|
-
} else {
|
|
971
|
-
if (agdfMarketplaceEntry.source !== "./plugin/") failures.push("plugin marketplace agdf source must point to ./plugin/");
|
|
972
|
-
if (Object.hasOwn(agdfMarketplaceEntry, "policy")) failures.push("Claude plugin marketplace agdf entry must not use unsupported policy field");
|
|
973
|
-
if (agdfMarketplaceEntry.category !== "Productivity") failures.push("plugin marketplace agdf category must be Productivity");
|
|
974
|
-
}
|
|
975
|
-
}
|
|
976
|
-
|
|
977
1022
|
const actualSkills = readdirSync(skillRoot)
|
|
978
1023
|
.filter((entry) => statSync(join(skillRoot, entry)).isDirectory())
|
|
979
1024
|
.sort();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# AGDF 0.13.
|
|
1
|
+
# AGDF 0.13.7 — Initial OpenAI Public Plugin Candidate
|
|
2
2
|
|
|
3
3
|
This candidate packages the canonical AGDF workflow skills for public discovery in ChatGPT and
|
|
4
4
|
Codex. It helps users assess delivery fit, preserve explicit human approvals, inspect existing-system
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"id": "agdf",
|
|
4
|
-
"version": "0.13.
|
|
4
|
+
"version": "0.13.7",
|
|
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
|
|
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
|
|
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
|
-
"
|
|
258
|
-
"
|
|
259
|
-
|
|
260
|
-
"
|
|
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,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"releaseVersion": "0.13.
|
|
4
|
-
"digest": "
|
|
3
|
+
"releaseVersion": "0.13.7",
|
|
4
|
+
"digest": "66e5c26d1673393afd09b24ff17306497f958414ab24f2e1e3b55fb7cd3ad18e",
|
|
5
5
|
"files": [
|
|
6
6
|
{
|
|
7
7
|
"path": ".codex-plugin/plugin.json",
|
|
8
|
-
"sha256": "
|
|
8
|
+
"sha256": "be5e69d2c1c1a1ac8e1da3b4770003b027ddbf32b7dd7eeab2519aa6316a7b32"
|
|
9
9
|
},
|
|
10
10
|
{
|
|
11
11
|
"path": "assets/agdf-icon.svg",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
},
|
|
30
30
|
{
|
|
31
31
|
"path": "meta/agdf-plugin.definition.json",
|
|
32
|
-
"sha256": "
|
|
32
|
+
"sha256": "ce61ec6a7210c34616e4eda529029629c3e3b74756921c437bc2aa51387dc56a"
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
35
|
"path": "meta/agdf-runtime-contract.md",
|
|
@@ -157,23 +157,23 @@
|
|
|
157
157
|
},
|
|
158
158
|
{
|
|
159
159
|
"path": "submission/openai/availability.md",
|
|
160
|
-
"sha256": "
|
|
160
|
+
"sha256": "940be7ccc82c41be6c2a53e58e7fac6e1d580d1c622ee8457134ddb9d502b2ba"
|
|
161
161
|
},
|
|
162
162
|
{
|
|
163
163
|
"path": "submission/openai/capability-matrix.json",
|
|
164
|
-
"sha256": "
|
|
164
|
+
"sha256": "108c87450f6c234dec7c371df21a80a31647fb158eaae9768af14095f3dbc448"
|
|
165
165
|
},
|
|
166
166
|
{
|
|
167
167
|
"path": "submission/openai/listing.json",
|
|
168
|
-
"sha256": "
|
|
168
|
+
"sha256": "daeaad9b36df9f37b07c505ef081297e67bc171b3a58bca5e2b022f3658c36f3"
|
|
169
169
|
},
|
|
170
170
|
{
|
|
171
171
|
"path": "submission/openai/release-notes.md",
|
|
172
|
-
"sha256": "
|
|
172
|
+
"sha256": "69fb2e3dfd2af90de40c07019f4dac960d950871dfdf5819be59613688286b7b"
|
|
173
173
|
},
|
|
174
174
|
{
|
|
175
175
|
"path": "submission/openai/reviewer-cases.json",
|
|
176
|
-
"sha256": "
|
|
176
|
+
"sha256": "dc3b27cd47fb390e105c386c3e842f9da0ea554d357d42a4d99a8a13655431b1"
|
|
177
177
|
}
|
|
178
178
|
]
|
|
179
179
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"releaseVersion": "0.13.
|
|
3
|
+
"releaseVersion": "0.13.7",
|
|
4
4
|
"candidateState": "repository_ready",
|
|
5
5
|
"submissionReady": false,
|
|
6
6
|
"submissionBlockers": [
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
},
|
|
17
17
|
"bundle": {
|
|
18
18
|
"state": "pass",
|
|
19
|
-
"detail": "43 inventoried files; inventory digest
|
|
19
|
+
"detail": "43 inventoried files; inventory digest 66e5c26d1673393afd09b24ff17306497f958414ab24f2e1e3b55fb7cd3ad18e"
|
|
20
20
|
},
|
|
21
21
|
"installed_host": {
|
|
22
22
|
"state": "unverified",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# AGDF Public Plugin Readiness
|
|
2
2
|
|
|
3
|
-
- release: `0.13.
|
|
3
|
+
- release: `0.13.7`
|
|
4
4
|
- candidate_state: `repository_ready`
|
|
5
5
|
- submission_ready: `false`
|
|
6
6
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
| Class | State | Detail |
|
|
10
10
|
|---|---|---|
|
|
11
11
|
| repository | pass | canonical contract and deterministic source checks |
|
|
12
|
-
| bundle | pass | 43 inventoried files; inventory digest
|
|
12
|
+
| bundle | pass | 43 inventoried files; inventory digest 66e5c26d1673393afd09b24ff17306497f958414ab24f2e1e3b55fb7cd3ad18e |
|
|
13
13
|
| installed_host | unverified | PPD-L02 and PPD-L03 not performed |
|
|
14
14
|
| portal | unverified | unverified |
|
|
15
15
|
| post_publication | unverified | not published |
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# AGDF 0.13.
|
|
1
|
+
# AGDF 0.13.7 — Initial OpenAI Public Plugin Candidate
|
|
2
2
|
|
|
3
3
|
This candidate packages the canonical AGDF workflow skills for public discovery in ChatGPT and
|
|
4
4
|
Codex. It helps users assess delivery fit, preserve explicit human approvals, inspect existing-system
|