create-agdf 0.13.8 → 0.14.2
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 +14 -10
- package/generated/plugins/agdf/.claude-plugin/plugin.json +1 -1
- package/generated/plugins/agdf/.codex-plugin/plugin.json +2 -4
- package/generated/plugins/agdf/meta/agdf-plugin.definition.json +26 -2
- package/generated/plugins/agdf/meta/copilot-payload-baseline.json +7 -0
- package/generated/plugins/agdf/runtime/agdf-local.js +1 -1
- package/generated/plugins/agdf/runtime/agdf-session-check.js +10 -5
- package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-plugin.definition.json +26 -2
- package/generated/plugins/agdf/runtime/create-agdf/lib/cli/command-registry.js +6 -7
- package/generated/plugins/agdf/runtime/create-agdf/lib/runtime/local-validator.js +29 -17
- package/generated/plugins/agdf/runtime/create-agdf/lib/runtime/plugin-provenance.js +50 -1
- package/generated/plugins/agdf/runtime/create-agdf/lib/runtime-check-consent/contract.js +3 -1
- 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 +32 -3
- 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/plugins/copilot/agdf/.agdf-payload-inventory.json +771 -0
- package/generated/plugins/copilot/agdf/LICENSE +201 -0
- package/generated/plugins/copilot/agdf/hooks/copilot-hooks.json +15 -0
- package/generated/{AGENTS.md → plugins/copilot/agdf/meta/agdf-agent-router.md} +49 -33
- package/generated/plugins/copilot/agdf/meta/agdf-constitution.md +329 -0
- package/generated/plugins/copilot/agdf/meta/agdf-plugin.definition.json +331 -0
- package/generated/plugins/copilot/agdf/meta/agdf-runtime-contract.md +16 -0
- package/generated/plugins/copilot/agdf/plugin.json +22 -0
- package/generated/plugins/copilot/agdf/runtime/agdf-local.js +18 -0
- package/generated/plugins/copilot/agdf/runtime/agdf-session-check.js +97 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/NOTICE +10 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/bin/agdf-validator.js +11 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-interaction-locales.json +512 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-plugin.definition.json +331 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/command-registry.js +144 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/delivery-path-search-command.js +139 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/parse-args.js +173 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/runtime-context.js +83 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/validation-handlers.js +46 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/delivery-map.js +301 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/doctor.js +272 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/gate-check.js +455 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/gate-policy.js +305 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/parent-reconciliation.js +284 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/required-files.js +9 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/run-state.js +217 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/shared.js +345 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/verified-change.js +156 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-state/aggregate.js +18 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-state/gate-approval-validator.js +49 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-state/index.js +7 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-state/legacy-migration.js +95 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-state/run-state-parser.js +265 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-state/run-state-repository.js +68 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-state/run-state-resolver.js +45 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-state/run-state-writer.js +97 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/candidate-policy.js +99 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/contracts.js +237 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/claude.js +35 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/codex.js +44 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/opencode.js +234 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/prompt.js +13 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/protocol.js +13 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/generators/claude.js +40 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/generators/codex.js +38 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/generators/protocol.js +12 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/persistence.js +39 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/scoring.js +21 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/search-engine.js +155 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/state-adapter.js +161 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/surfaces/capabilities.js +27 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/transports/read-only-guard.js +43 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/interaction-presentation.js +842 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/runtime/local-validator.js +239 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/runtime/plugin-provenance.js +255 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/runtime/validator-application.js +40 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/runtime-check-consent/contract.js +73 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/package.json +6 -0
- package/generated/plugins/copilot/agdf/runtime/runtime-manifest.json +8 -0
- package/generated/submissions/openai/agdf/.codex-plugin/plugin.json +1 -2
- package/generated/submissions/openai/agdf/meta/agdf-plugin.definition.json +26 -2
- package/generated/submissions/openai/agdf/meta/copilot-payload-baseline.json +7 -0
- 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 +13 -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 +64 -8
- package/lib/cli/command-registry.js +6 -7
- package/lib/installers/copilot-precedence.js +34 -0
- package/lib/installers/copilot-settings.js +84 -0
- package/lib/installers/local-marketplace.js +112 -30
- package/lib/installers/plugin-installers.js +184 -5
- package/lib/lifecycle/operations.js +3 -0
- package/lib/lifecycle/result.js +1 -0
- package/lib/lifecycle/status.js +3 -3
- package/lib/public-plugin/copilot-profile.js +126 -0
- package/lib/public-plugin/manifest.js +34 -2
- package/lib/public-plugin/validator.js +1 -1
- package/lib/release/version-coherence.js +4 -0
- package/lib/runtime/local-validator.js +29 -17
- package/lib/runtime/plugin-provenance.js +50 -1
- package/lib/runtime-check-consent/contract.js +3 -1
- package/lib/runtime-check-consent/coordinator.js +1 -0
- package/lib/runtime-check-consent/service.js +1 -1
- package/lib/runtime-check-consent/state.js +3 -3
- package/lib/scaffold/plan.js +3 -89
- package/lib/scaffold/presentation.js +3 -22
- package/package.json +6 -3
- package/generated/.github/copilot-instructions.md +0 -16
- package/generated/.github/instructions/agdf-governance.instructions.md +0 -14
- package/generated/.github/skills/README.md +0 -20
- /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/agdf-brownfield-analysis/SKILL.md +0 -0
- /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/agdf-clean-implementation-review/SKILL.md +0 -0
- /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/agdf-code-review/SKILL.md +0 -0
- /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/agdf-delivery-closeout/SKILL.md +0 -0
- /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/agdf-delivery-path-search/SKILL.md +0 -0
- /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/agdf-gate-check/SKILL.md +0 -0
- /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/agdf-interaction-locales.json +0 -0
- /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/agdf-qa-gate/SKILL.md +0 -0
- /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/agdf-release-or/SKILL.md +0 -0
- /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/agdf-runtime-contract.md +0 -0
- /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/agdf-task-plan-review/SKILL.md +0 -0
- /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/agdf-ux-intent-definition/SKILL.md +0 -0
- /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/contracts/closeout.md +0 -0
- /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/contracts/context-graph.md +0 -0
- /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/contracts/control-scaffold.md +0 -0
- /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/contracts/gate-transition.md +0 -0
- /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/contracts/interaction.md +0 -0
- /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/contracts/modes.md +0 -0
- /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/contracts/quality.md +0 -0
- /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/contracts/task-target-resolution.md +0 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { existsSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { join, relative } from "node:path";
|
|
4
|
+
|
|
5
|
+
export const COPILOT_PROFILE_ID = "copilot-runtime-plugin";
|
|
6
|
+
export const COPILOT_INVENTORY_FILE = ".agdf-payload-inventory.json";
|
|
7
|
+
|
|
8
|
+
function sha256(content) {
|
|
9
|
+
return createHash("sha256").update(content).digest("hex");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function filesUnder(root) {
|
|
13
|
+
const files = [];
|
|
14
|
+
function visit(directory) {
|
|
15
|
+
for (const name of readdirSync(directory).sort()) {
|
|
16
|
+
const path = join(directory, name);
|
|
17
|
+
const stats = statSync(path);
|
|
18
|
+
if (stats.isDirectory()) visit(path);
|
|
19
|
+
else if (stats.isFile()) files.push(path);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
visit(root);
|
|
23
|
+
return files;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function payloadInventoryDigest(inventory) {
|
|
27
|
+
return sha256(`${JSON.stringify(inventory, null, 2)}\n`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function buildCopilotPayloadInventory({ profileRoot, mappings, version, baseline }) {
|
|
31
|
+
const files = filesUnder(profileRoot)
|
|
32
|
+
.map((path) => ({ path, relativePath: relative(profileRoot, path).replaceAll("\\", "/") }))
|
|
33
|
+
.filter(({ relativePath }) => relativePath !== COPILOT_INVENTORY_FILE);
|
|
34
|
+
const byDestination = new Map(mappings.map((entry) => [entry.destination, entry]));
|
|
35
|
+
const unmapped = files.filter(({ relativePath }) => !byDestination.has(relativePath));
|
|
36
|
+
if (unmapped.length) throw new Error(`AGDF_COPILOT_PAYLOAD_UNMAPPED: ${unmapped.map(({ relativePath }) => relativePath).join(", ")}`);
|
|
37
|
+
const missing = mappings.filter(({ destination }) => !files.some(({ relativePath }) => relativePath === destination));
|
|
38
|
+
if (missing.length) throw new Error(`AGDF_COPILOT_PAYLOAD_MISSING: ${missing.map(({ destination }) => destination).join(", ")}`);
|
|
39
|
+
if (new Set(mappings.map(({ destination }) => destination)).size !== mappings.length) {
|
|
40
|
+
throw new Error("AGDF_COPILOT_PAYLOAD_DUPLICATE_DESTINATION");
|
|
41
|
+
}
|
|
42
|
+
const entries = files.map(({ path, relativePath }) => {
|
|
43
|
+
const mapping = byDestination.get(relativePath);
|
|
44
|
+
const content = readFileSync(path);
|
|
45
|
+
return {
|
|
46
|
+
destination: relativePath,
|
|
47
|
+
component: mapping.component,
|
|
48
|
+
owner: mapping.owner,
|
|
49
|
+
rule: mapping.rule,
|
|
50
|
+
requirement: mapping.requirement,
|
|
51
|
+
...(mapping.source ? { source: mapping.source } : {}),
|
|
52
|
+
...(mapping.sourceDigest ? { source_digest: mapping.sourceDigest } : {}),
|
|
53
|
+
digest: sha256(content),
|
|
54
|
+
bytes: content.byteLength,
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
const totalBytes = entries.reduce((sum, entry) => sum + entry.bytes, 0);
|
|
58
|
+
const inventory = {
|
|
59
|
+
schema_version: 1,
|
|
60
|
+
profile_id: COPILOT_PROFILE_ID,
|
|
61
|
+
version,
|
|
62
|
+
baseline,
|
|
63
|
+
stats: { files: entries.length, bytes: totalBytes },
|
|
64
|
+
entries,
|
|
65
|
+
};
|
|
66
|
+
writeFileSync(join(profileRoot, COPILOT_INVENTORY_FILE), `${JSON.stringify(inventory, null, 2)}\n`, "utf8");
|
|
67
|
+
return inventory;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function validateCopilotPayload({ profileRoot, repoRoot, expectedVersion, expectedSkills, baseline }) {
|
|
71
|
+
const inventoryPath = join(profileRoot, COPILOT_INVENTORY_FILE);
|
|
72
|
+
if (!existsSync(inventoryPath)) throw new Error("AGDF_COPILOT_PAYLOAD_INVENTORY_MISSING");
|
|
73
|
+
let inventory;
|
|
74
|
+
try { inventory = JSON.parse(readFileSync(inventoryPath, "utf8")); } catch {
|
|
75
|
+
throw new Error("AGDF_COPILOT_PAYLOAD_INVENTORY_INVALID");
|
|
76
|
+
}
|
|
77
|
+
if (inventory.schema_version !== 1 || inventory.profile_id !== COPILOT_PROFILE_ID || inventory.version !== expectedVersion) {
|
|
78
|
+
throw new Error("AGDF_COPILOT_PAYLOAD_INVENTORY_INVALID");
|
|
79
|
+
}
|
|
80
|
+
const actualFiles = filesUnder(profileRoot)
|
|
81
|
+
.map((path) => relative(profileRoot, path).replaceAll("\\", "/"))
|
|
82
|
+
.filter((path) => path !== COPILOT_INVENTORY_FILE);
|
|
83
|
+
const entries = Array.isArray(inventory.entries) ? inventory.entries : [];
|
|
84
|
+
if (new Set(entries.map(({ destination }) => destination)).size !== entries.length) {
|
|
85
|
+
throw new Error("AGDF_COPILOT_PAYLOAD_DUPLICATE_DESTINATION");
|
|
86
|
+
}
|
|
87
|
+
const mapped = new Set(entries.map(({ destination }) => destination));
|
|
88
|
+
const unmapped = actualFiles.filter((path) => !mapped.has(path));
|
|
89
|
+
if (unmapped.length) throw new Error(`AGDF_COPILOT_PAYLOAD_UNMAPPED: ${unmapped.join(", ")}`);
|
|
90
|
+
const missing = entries.filter(({ destination }) => !actualFiles.includes(destination));
|
|
91
|
+
if (missing.length) throw new Error(`AGDF_COPILOT_PAYLOAD_MISSING: ${missing.map(({ destination }) => destination).join(", ")}`);
|
|
92
|
+
for (const entry of entries) {
|
|
93
|
+
const content = readFileSync(join(profileRoot, entry.destination));
|
|
94
|
+
if (sha256(content) !== entry.digest || content.byteLength !== entry.bytes) {
|
|
95
|
+
throw new Error(`AGDF_COPILOT_PAYLOAD_DIGEST_MISMATCH: ${entry.destination}`);
|
|
96
|
+
}
|
|
97
|
+
if (repoRoot && entry.source) {
|
|
98
|
+
const source = readFileSync(join(repoRoot, entry.source));
|
|
99
|
+
if (sha256(source) !== entry.source_digest) {
|
|
100
|
+
throw new Error(`AGDF_COPILOT_PAYLOAD_STALE_SOURCE: ${entry.destination}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const excluded = actualFiles.filter((path) => path === "skills" || path.startsWith("skills/")
|
|
105
|
+
|| path.startsWith(".codex-plugin/") || path.startsWith(".claude-plugin/")
|
|
106
|
+
|| path === "hooks/hooks.json" || path === "hooks/session-start.sh"
|
|
107
|
+
|| path.startsWith("submission/"));
|
|
108
|
+
if (excluded.length) throw new Error(`AGDF_COPILOT_PAYLOAD_EXCLUDED_SURFACE: ${excluded.join(", ")}`);
|
|
109
|
+
const skillFiles = actualFiles.filter((path) => /^copilot-skills\/agdf-[^/]+\/SKILL\.md$/.test(path));
|
|
110
|
+
const expectedSkillFiles = expectedSkills.map((slug) => `copilot-skills/agdf-${slug}/SKILL.md`).sort();
|
|
111
|
+
if (JSON.stringify(skillFiles.sort()) !== JSON.stringify(expectedSkillFiles)) {
|
|
112
|
+
throw new Error("AGDF_COPILOT_PAYLOAD_SKILL_SET_MISMATCH");
|
|
113
|
+
}
|
|
114
|
+
const stats = {
|
|
115
|
+
files: entries.length,
|
|
116
|
+
bytes: entries.reduce((sum, entry) => sum + entry.bytes, 0),
|
|
117
|
+
};
|
|
118
|
+
if (stats.files > baseline.max_files || stats.bytes > baseline.max_bytes) {
|
|
119
|
+
throw new Error(`AGDF_COPILOT_PAYLOAD_GROWTH: observed ${stats.files} files/${stats.bytes} bytes; baseline ${baseline.max_files}/${baseline.max_bytes}`);
|
|
120
|
+
}
|
|
121
|
+
if (inventory.stats?.files !== stats.files || inventory.stats?.bytes !== stats.bytes
|
|
122
|
+
|| inventory.baseline?.max_files !== baseline.max_files || inventory.baseline?.max_bytes !== baseline.max_bytes) {
|
|
123
|
+
throw new Error("AGDF_COPILOT_PAYLOAD_BASELINE_MISMATCH");
|
|
124
|
+
}
|
|
125
|
+
return { inventory, inventoryDigest: payloadInventoryDigest(inventory), stats };
|
|
126
|
+
}
|
|
@@ -39,14 +39,12 @@ export function createCodexPluginManifest(definition, { publicCandidate = false
|
|
|
39
39
|
websiteURL: distribution.urls.website,
|
|
40
40
|
privacyPolicyURL: distribution.urls.privacy,
|
|
41
41
|
termsOfServiceURL: distribution.urls.terms,
|
|
42
|
-
supportURL: distribution.urls.support,
|
|
43
42
|
composerIcon: definition.codex.composerIcon,
|
|
44
43
|
logo: definition.codex.logo,
|
|
45
44
|
defaultPrompt: pluginInterface.defaultPrompt,
|
|
46
45
|
brandColor: definition.brandColor,
|
|
47
46
|
},
|
|
48
47
|
};
|
|
49
|
-
if (!publicCandidate) manifest.hooks = `./${definition.codex.hooks}`;
|
|
50
48
|
return manifest;
|
|
51
49
|
}
|
|
52
50
|
|
|
@@ -70,3 +68,37 @@ export function createClaudePluginManifest(definition) {
|
|
|
70
68
|
export function renderClaudePluginManifest(definition) {
|
|
71
69
|
return `${JSON.stringify(createClaudePluginManifest(definition), null, 2)}\n`;
|
|
72
70
|
}
|
|
71
|
+
|
|
72
|
+
function requireCopilotPath(value, field) {
|
|
73
|
+
if (typeof value !== "string" || !value || value.startsWith("/") || value.includes("..") || value.includes("\\")) {
|
|
74
|
+
throw new Error(`AGDF_COPILOT_PLUGIN_CONTRACT_INVALID: ${field} must be a relative POSIX path`);
|
|
75
|
+
}
|
|
76
|
+
return value;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function createCopilotPluginManifest(definition) {
|
|
80
|
+
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(definition.id ?? "") || definition.id.length > 64) {
|
|
81
|
+
throw new Error("AGDF_COPILOT_PLUGIN_CONTRACT_INVALID: kebab-case name is required");
|
|
82
|
+
}
|
|
83
|
+
if (!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(definition.version ?? "")) {
|
|
84
|
+
throw new Error("AGDF_COPILOT_PLUGIN_CONTRACT_INVALID: semantic version is required");
|
|
85
|
+
}
|
|
86
|
+
const copilot = definition.copilot ?? {};
|
|
87
|
+
return {
|
|
88
|
+
name: definition.id,
|
|
89
|
+
version: definition.version,
|
|
90
|
+
description: definition.description,
|
|
91
|
+
author: definition.author,
|
|
92
|
+
homepage: definition.homepage,
|
|
93
|
+
repository: definition.repository,
|
|
94
|
+
license: definition.license,
|
|
95
|
+
keywords: definition.keywords,
|
|
96
|
+
category: definition.category,
|
|
97
|
+
skills: requireCopilotPath(copilot.skills, "skills"),
|
|
98
|
+
hooks: requireCopilotPath(copilot.hooks, "hooks"),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function renderCopilotPluginManifest(definition) {
|
|
103
|
+
return `${JSON.stringify(createCopilotPluginManifest(definition), null, 2)}\n`;
|
|
104
|
+
}
|
|
@@ -80,7 +80,7 @@ export function validateCandidate(root) {
|
|
|
80
80
|
if (unicodeLength(manifest.interface?.developerName) > LISTING_LIMITS.developerName) throw new Error("AGDF_PUBLIC_PLUGIN_LISTING_LIMIT_EXCEEDED: developerName");
|
|
81
81
|
const prompts = manifest.interface?.defaultPrompt ?? [];
|
|
82
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"
|
|
83
|
+
for (const field of ["websiteURL", "privacyPolicyURL", "termsOfServiceURL"]) {
|
|
84
84
|
let url;
|
|
85
85
|
try { url = new URL(manifest.interface?.[field]); } catch { throw new Error(`AGDF_PUBLIC_PLUGIN_CONTRACT_INVALID: ${field}`); }
|
|
86
86
|
if (url.protocol !== "https:") throw new Error(`AGDF_PUBLIC_PLUGIN_CONTRACT_INVALID: ${field} must use HTTPS`);
|
|
@@ -34,6 +34,10 @@ const VERSION_SURFACES = [
|
|
|
34
34
|
jsonVersion("create-agdf/generated/plugins/agdf/.claude-plugin/plugin.json"),
|
|
35
35
|
jsonVersion("create-agdf/generated/plugins/agdf/runtime/runtime-manifest.json"),
|
|
36
36
|
jsonVersion("create-agdf/generated/plugins/agdf/runtime/create-agdf/package.json"),
|
|
37
|
+
jsonVersion("create-agdf/generated/plugins/copilot/agdf/meta/agdf-plugin.definition.json"),
|
|
38
|
+
jsonVersion("create-agdf/generated/plugins/copilot/agdf/plugin.json"),
|
|
39
|
+
jsonVersion("create-agdf/generated/plugins/copilot/agdf/runtime/runtime-manifest.json"),
|
|
40
|
+
jsonVersion("create-agdf/generated/plugins/copilot/agdf/runtime/create-agdf/package.json"),
|
|
37
41
|
jsonVersion("create-agdf/generated/submissions/openai/agdf/meta/agdf-plugin.definition.json"),
|
|
38
42
|
jsonVersion("create-agdf/generated/submissions/openai/agdf/.codex-plugin/plugin.json"),
|
|
39
43
|
jsonVersion("create-agdf/generated/submissions/openai/agdf/submission/openai/capability-matrix.json", (value) => value.releaseVersion),
|
|
@@ -5,6 +5,7 @@ import process from "node:process";
|
|
|
5
5
|
import {
|
|
6
6
|
INSTALLATION_PROVENANCE_FILE,
|
|
7
7
|
digestDirectory,
|
|
8
|
+
inspectCopilotPayloadInventory,
|
|
8
9
|
inspectGeneratedRepositoryMarketplace,
|
|
9
10
|
inspectInstallationProvenance,
|
|
10
11
|
validateDistributionProfiles,
|
|
@@ -83,41 +84,52 @@ export function resolveLocalValidator(options) {
|
|
|
83
84
|
}
|
|
84
85
|
const codexManifest = readJson(join(pluginRoot, ".codex-plugin", "plugin.json"));
|
|
85
86
|
const claudeManifest = readJson(join(pluginRoot, ".claude-plugin", "plugin.json"));
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
const copilotManifest = readJson(join(pluginRoot, "plugin.json"));
|
|
88
|
+
const copilotProfile = Boolean(copilotManifest && !codexManifest && !claudeManifest);
|
|
89
|
+
const distributionProfile = copilotProfile ? "copilot-runtime-plugin" : "runtime-plugin";
|
|
90
|
+
const pluginVersion = copilotProfile ? copilotManifest?.version ?? null : codexManifest?.version ?? null;
|
|
91
|
+
if (copilotProfile
|
|
92
|
+
? copilotManifest.version !== definition.version
|
|
93
|
+
: (!codexManifest || !claudeManifest || claudeManifest.version !== definition.version)) {
|
|
94
|
+
return { envelope: envelope("version_mismatch", options, { source: "plugin_bundle", pluginRoot, pluginVersion, canonicalVersion: definition.version, distributionProfile, provenanceStatus: "invalid", reason: "manifest_invalid" }) };
|
|
95
|
+
}
|
|
96
|
+
const copilotInventory = copilotProfile ? inspectCopilotPayloadInventory(pluginRoot, definition.version) : null;
|
|
97
|
+
if (copilotProfile && copilotInventory.status !== "matched") {
|
|
98
|
+
return { envelope: envelope("version_mismatch", options, { source: "plugin_bundle", pluginRoot, pluginVersion, canonicalVersion: definition.version, distributionProfile, provenanceStatus: "invalid", reason: copilotInventory.reason }) };
|
|
89
99
|
}
|
|
90
100
|
const packageRoot = join(options.runtimeRoot, "create-agdf");
|
|
91
101
|
if (!existsSync(packageRoot)) {
|
|
92
|
-
return { envelope: envelope("unavailable", options, { source: "plugin_bundle", pluginRoot, pluginVersion, distributionProfile
|
|
102
|
+
return { envelope: envelope("unavailable", options, { source: "plugin_bundle", pluginRoot, pluginVersion, distributionProfile, reason: "runtime_missing" }) };
|
|
93
103
|
}
|
|
94
104
|
const packageManifest = readJson(join(packageRoot, "package.json"));
|
|
95
105
|
const observedVersion = packageManifest?.version ?? manifest.version ?? null;
|
|
96
106
|
if (observedVersion !== options.expectedVersion || manifest.version !== options.expectedVersion) {
|
|
97
|
-
return { envelope: envelope("version_mismatch", options, { observedVersion, source: "plugin_bundle", pluginRoot, pluginVersion, canonicalVersion: definition.version, distributionProfile
|
|
107
|
+
return { envelope: envelope("version_mismatch", options, { observedVersion, source: "plugin_bundle", pluginRoot, pluginVersion, canonicalVersion: definition.version, distributionProfile }) };
|
|
98
108
|
}
|
|
99
109
|
let observedDigest = null;
|
|
100
110
|
try { observedDigest = digestDirectory(packageRoot); } catch {}
|
|
101
111
|
if (!observedDigest || manifest.digest !== observedDigest) {
|
|
102
|
-
return { envelope: envelope("version_mismatch", options, { observedVersion, source: "plugin_bundle", pluginRoot, pluginVersion, canonicalVersion: definition.version, runtimeDigest: observedDigest, distributionProfile
|
|
112
|
+
return { envelope: envelope("version_mismatch", options, { observedVersion, source: "plugin_bundle", pluginRoot, pluginVersion, canonicalVersion: definition.version, runtimeDigest: observedDigest, distributionProfile, reason: "runtime_digest_mismatch" }) };
|
|
103
113
|
}
|
|
104
114
|
const entrypoint = resolve(options.runtimeRoot, manifest.entrypoint ?? "");
|
|
105
115
|
const entrypointRelative = relative(options.runtimeRoot, entrypoint);
|
|
106
116
|
if (!manifest.entrypoint || entrypointRelative === ".." || entrypointRelative.startsWith(`..${sep}`) || isAbsolute(entrypointRelative)) {
|
|
107
|
-
return { envelope: envelope("version_mismatch", options, { observedVersion, source: "plugin_bundle", pluginRoot, pluginVersion, canonicalVersion: definition.version, runtimeDigest: observedDigest, distributionProfile
|
|
117
|
+
return { envelope: envelope("version_mismatch", options, { observedVersion, source: "plugin_bundle", pluginRoot, pluginVersion, canonicalVersion: definition.version, runtimeDigest: observedDigest, distributionProfile, reason: "invalid_entrypoint" }) };
|
|
108
118
|
}
|
|
109
119
|
if (!existsSync(entrypoint)) {
|
|
110
|
-
return { envelope: envelope("unavailable", options, { observedVersion, source: "plugin_bundle", pluginRoot, pluginVersion, canonicalVersion: definition.version, runtimeDigest: observedDigest, distributionProfile
|
|
120
|
+
return { envelope: envelope("unavailable", options, { observedVersion, source: "plugin_bundle", pluginRoot, pluginVersion, canonicalVersion: definition.version, runtimeDigest: observedDigest, distributionProfile, reason: "entrypoint_missing" }) };
|
|
111
121
|
}
|
|
112
122
|
const installed = existsSync(join(pluginRoot, INSTALLATION_PROVENANCE_FILE));
|
|
113
123
|
let provenanceStatus = "not_applicable";
|
|
114
124
|
let sourceDigest = null;
|
|
115
|
-
let evidencePlane = "loaded_session";
|
|
125
|
+
let evidencePlane = options.expectedPluginRoot ? "loaded_session" : "installed_plugin_root";
|
|
116
126
|
if (installed) {
|
|
117
127
|
const provenance = inspectInstallationProvenance(pluginRoot, {
|
|
118
128
|
definition,
|
|
119
129
|
runtimeManifest: manifest,
|
|
120
130
|
pluginVersion,
|
|
131
|
+
profileId: distributionProfile,
|
|
132
|
+
inventoryDigest: copilotInventory?.inventoryDigest ?? null,
|
|
121
133
|
});
|
|
122
134
|
provenanceStatus = provenance.status;
|
|
123
135
|
sourceDigest = provenance.marker?.source_digest ?? null;
|
|
@@ -130,8 +142,8 @@ export function resolveLocalValidator(options) {
|
|
|
130
142
|
canonicalVersion: definition.version,
|
|
131
143
|
runtimeDigest: observedDigest,
|
|
132
144
|
sourceDigest,
|
|
133
|
-
distributionProfile
|
|
134
|
-
evidencePlane
|
|
145
|
+
distributionProfile,
|
|
146
|
+
evidencePlane,
|
|
135
147
|
provenanceStatus,
|
|
136
148
|
reason: provenance.reason,
|
|
137
149
|
}) };
|
|
@@ -144,16 +156,16 @@ export function resolveLocalValidator(options) {
|
|
|
144
156
|
pluginVersion,
|
|
145
157
|
canonicalVersion: definition.version,
|
|
146
158
|
runtimeDigest: observedDigest,
|
|
147
|
-
distributionProfile
|
|
159
|
+
distributionProfile,
|
|
148
160
|
evidencePlane: "loaded_session",
|
|
149
161
|
provenanceStatus: "missing",
|
|
150
162
|
reason: "installation_provenance_missing",
|
|
151
163
|
}) };
|
|
152
164
|
} else {
|
|
153
|
-
const generatedRepository = inspectGeneratedRepositoryMarketplace(resolve(pluginRoot, "..", ".."));
|
|
165
|
+
const generatedRepository = copilotProfile ? null : inspectGeneratedRepositoryMarketplace(resolve(pluginRoot, "..", ".."));
|
|
154
166
|
if (pluginVersion !== definition.version
|
|
155
|
-
|| generatedRepository.status !== "matched"
|
|
156
|
-
|
|
167
|
+
|| (!copilotProfile && (generatedRepository.status !== "matched"
|
|
168
|
+
|| canonicalPath(generatedRepository.pluginRoot) !== pluginRoot))) {
|
|
157
169
|
return { envelope: envelope("unavailable", options, {
|
|
158
170
|
observedVersion,
|
|
159
171
|
source: "plugin_bundle",
|
|
@@ -161,7 +173,7 @@ export function resolveLocalValidator(options) {
|
|
|
161
173
|
pluginVersion,
|
|
162
174
|
canonicalVersion: definition.version,
|
|
163
175
|
runtimeDigest: observedDigest,
|
|
164
|
-
distributionProfile
|
|
176
|
+
distributionProfile,
|
|
165
177
|
evidencePlane: "installed_plugin_root",
|
|
166
178
|
provenanceStatus: "missing",
|
|
167
179
|
reason: "installation_provenance_missing",
|
|
@@ -178,7 +190,7 @@ export function resolveLocalValidator(options) {
|
|
|
178
190
|
canonicalVersion: definition.version,
|
|
179
191
|
runtimeDigest: observedDigest,
|
|
180
192
|
sourceDigest,
|
|
181
|
-
distributionProfile
|
|
193
|
+
distributionProfile,
|
|
182
194
|
evidencePlane,
|
|
183
195
|
provenanceStatus,
|
|
184
196
|
}),
|
|
@@ -4,10 +4,12 @@ import { isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
|
4
4
|
|
|
5
5
|
export const INSTALLATION_PROVENANCE_FILE = ".agdf-installation.json";
|
|
6
6
|
export const LEGACY_LOCAL_INSTALL_FILE = ".agdf-local-install.json";
|
|
7
|
+
export const COPILOT_PAYLOAD_INVENTORY_FILE = ".agdf-payload-inventory.json";
|
|
7
8
|
|
|
8
9
|
const EXPECTED_PROFILES = Object.freeze({
|
|
9
10
|
"source-development": Object.freeze({ runtime: "absent", installable: false, machineValidation: "unavailable" }),
|
|
10
11
|
"runtime-plugin": Object.freeze({ runtime: "required", installable: true, machineValidation: "local_exact_version_digest" }),
|
|
12
|
+
"copilot-runtime-plugin": Object.freeze({ runtime: "required", installable: true, machineValidation: "local_exact_version_digest_inventory" }),
|
|
11
13
|
"opencode-config-local": Object.freeze({ runtime: "config_local_package", installable: true, machineValidation: "local_exact_version" }),
|
|
12
14
|
"portable-skills": Object.freeze({ runtime: "absent", installable: true, machineValidation: "unavailable_or_external_required" }),
|
|
13
15
|
});
|
|
@@ -41,6 +43,50 @@ export function digestDirectory(root) {
|
|
|
41
43
|
return hash.digest("hex");
|
|
42
44
|
}
|
|
43
45
|
|
|
46
|
+
export function digestFile(path) {
|
|
47
|
+
return createHash("sha256").update(readFileSync(path)).digest("hex");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function inspectCopilotPayloadInventory(pluginRoot, expectedVersion) {
|
|
51
|
+
const inventoryPath = join(pluginRoot, COPILOT_PAYLOAD_INVENTORY_FILE);
|
|
52
|
+
const inventory = readJson(inventoryPath);
|
|
53
|
+
if (!inventory || inventory.schema_version !== 1 || inventory.profile_id !== "copilot-runtime-plugin"
|
|
54
|
+
|| inventory.version !== expectedVersion || !Array.isArray(inventory.entries)) {
|
|
55
|
+
return { status: "invalid", reason: "copilot_payload_inventory_invalid" };
|
|
56
|
+
}
|
|
57
|
+
const destinations = inventory.entries.map((entry) => entry.destination);
|
|
58
|
+
if (new Set(destinations).size !== destinations.length) {
|
|
59
|
+
return { status: "invalid", reason: "copilot_payload_inventory_duplicate" };
|
|
60
|
+
}
|
|
61
|
+
const actual = [];
|
|
62
|
+
function visit(directory) {
|
|
63
|
+
for (const name of readdirSync(directory).sort()) {
|
|
64
|
+
const path = join(directory, name);
|
|
65
|
+
const stats = statSync(path);
|
|
66
|
+
if (stats.isDirectory()) visit(path);
|
|
67
|
+
else if (stats.isFile()) {
|
|
68
|
+
const normalized = relative(pluginRoot, path).replaceAll("\\", "/");
|
|
69
|
+
if (![COPILOT_PAYLOAD_INVENTORY_FILE, INSTALLATION_PROVENANCE_FILE, LEGACY_LOCAL_INSTALL_FILE].includes(normalized)) actual.push(normalized);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
try { visit(pluginRoot); } catch { return { status: "invalid", reason: "copilot_payload_incomplete" }; }
|
|
74
|
+
if (JSON.stringify(actual.sort()) !== JSON.stringify([...destinations].sort())) {
|
|
75
|
+
return { status: "invalid", reason: "copilot_payload_inventory_mismatch" };
|
|
76
|
+
}
|
|
77
|
+
for (const entry of inventory.entries) {
|
|
78
|
+
const path = join(pluginRoot, entry.destination);
|
|
79
|
+
if (!existsSync(path) || digestFile(path) !== entry.digest || statSync(path).size !== entry.bytes) {
|
|
80
|
+
return { status: "invalid", reason: "copilot_payload_digest_mismatch", entry: entry.destination };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const excluded = actual.some((path) => path.startsWith("skills/") || path.startsWith(".codex-plugin/")
|
|
84
|
+
|| path.startsWith(".claude-plugin/") || path.startsWith("submission/")
|
|
85
|
+
|| path === "hooks/hooks.json" || path === "hooks/session-start.sh");
|
|
86
|
+
if (excluded) return { status: "invalid", reason: "copilot_payload_excluded_surface" };
|
|
87
|
+
return { status: "matched", inventory, inventoryDigest: digestFile(inventoryPath) };
|
|
88
|
+
}
|
|
89
|
+
|
|
44
90
|
export function digestNormalizedPluginSource(root, canonicalVersion) {
|
|
45
91
|
const files = [];
|
|
46
92
|
function visit(directory) {
|
|
@@ -148,6 +194,8 @@ export function inspectInstallationProvenance(pluginRoot, {
|
|
|
148
194
|
runtimeManifest,
|
|
149
195
|
pluginVersion,
|
|
150
196
|
allowLegacy = false,
|
|
197
|
+
profileId = "runtime-plugin",
|
|
198
|
+
inventoryDigest = null,
|
|
151
199
|
} = {}) {
|
|
152
200
|
const markerPath = join(pluginRoot, INSTALLATION_PROVENANCE_FILE);
|
|
153
201
|
const legacyPath = join(pluginRoot, LEGACY_LOCAL_INSTALL_FILE);
|
|
@@ -181,11 +229,12 @@ export function inspectInstallationProvenance(pluginRoot, {
|
|
|
181
229
|
if (!marker
|
|
182
230
|
|| marker.schema_version !== 1
|
|
183
231
|
|| marker.owner !== "create-agdf"
|
|
184
|
-
|| marker.profile_id !==
|
|
232
|
+
|| marker.profile_id !== profileId
|
|
185
233
|
|| marker.marketplace_id !== profile.contract.marketplaceIdentities.durable
|
|
186
234
|
|| marker.canonical_version !== definition.version
|
|
187
235
|
|| marker.codex_install_version !== pluginVersion
|
|
188
236
|
|| marker.runtime_digest !== runtimeManifest?.digest
|
|
237
|
+
|| (profileId === "copilot-runtime-plugin" && marker.inventory_digest !== inventoryDigest)
|
|
189
238
|
|| !/^[a-f0-9]{64}$/.test(marker.source_digest ?? "")) {
|
|
190
239
|
return { status: "invalid", reason: "installation_provenance_invalid", marker };
|
|
191
240
|
}
|
|
@@ -32,6 +32,7 @@ export function validateRuntimeCheckCapability(capability) {
|
|
|
32
32
|
}
|
|
33
33
|
const surfaces = capability.surfaces ?? {};
|
|
34
34
|
if (surfaces.codex !== "native-hook-review" || surfaces.claude !== "exact-command-rule"
|
|
35
|
+
|| surfaces.copilot !== "plugin-hook-review"
|
|
35
36
|
|| surfaces.opencode !== "plugin-internal"
|
|
36
37
|
|| surfaces["portable-skills"] !== "manual-external-required") {
|
|
37
38
|
throw new Error("AGDF_RUNTIME_CHECK_CAPABILITY_INVALID: surface contract");
|
|
@@ -41,7 +42,7 @@ export function validateRuntimeCheckCapability(capability) {
|
|
|
41
42
|
|
|
42
43
|
export function runtimeCheckCapabilityIdentity({ capability, surface, runtimeDigest, sourceDigest, command }) {
|
|
43
44
|
validateRuntimeCheckCapability(capability);
|
|
44
|
-
if (!["codex", "claude", "opencode"].includes(surface)) throw new Error("AGDF_RUNTIME_CHECK_SURFACE_INVALID");
|
|
45
|
+
if (!["codex", "claude", "copilot", "opencode"].includes(surface)) throw new Error("AGDF_RUNTIME_CHECK_SURFACE_INVALID");
|
|
45
46
|
for (const [name, value] of Object.entries({ runtimeDigest, sourceDigest })) {
|
|
46
47
|
if (typeof value !== "string" || !/^[a-f0-9]{64}$/.test(value)) throw new Error(`AGDF_RUNTIME_CHECK_IDENTITY_INVALID: ${name}`);
|
|
47
48
|
}
|
|
@@ -59,6 +60,7 @@ export function runtimeCheckCapabilityIdentity({ capability, surface, runtimeDig
|
|
|
59
60
|
|
|
60
61
|
export function fixedRuntimeCheckCommand(surface, pluginRoot, platform = process.platform) {
|
|
61
62
|
if (surface === "opencode") return "plugin:agdf:automatic-runtime-checks";
|
|
63
|
+
if (surface === "copilot") return 'node "${PLUGIN_ROOT}/runtime/agdf-session-check.js"';
|
|
62
64
|
if (surface === "codex" || surface === "claude") {
|
|
63
65
|
return platform === "win32"
|
|
64
66
|
? "node \"$([Environment]::GetEnvironmentVariable('PLUGIN_ROOT') + [Environment]::GetEnvironmentVariable('CLAUDE_PLUGIN_ROOT'))\\runtime\\agdf-session-check.js\""
|
|
@@ -18,6 +18,7 @@ export function resolveRuntimeCheckDecision({ explicitValue, interactive = false
|
|
|
18
18
|
export function consentDisclosure(surface) {
|
|
19
19
|
const permissionOwner = surface === "codex" ? "Codex native hook trust"
|
|
20
20
|
: surface === "claude" ? "Claude Code user permission settings"
|
|
21
|
+
: surface === "copilot" ? "GitHub Copilot plugin hook review"
|
|
21
22
|
: "OpenCode plugin and explicit permission configuration";
|
|
22
23
|
return Object.freeze({
|
|
23
24
|
surface,
|
|
@@ -35,7 +35,7 @@ function prospectiveRuntimeCheckIdentity(surface, platform = process.platform) {
|
|
|
35
35
|
command: fixedRuntimeCheckCommand(surface, installed.root, platform),
|
|
36
36
|
});
|
|
37
37
|
}
|
|
38
|
-
if (!["codex", "claude"].includes(surface)) return null;
|
|
38
|
+
if (!["codex", "claude", "copilot"].includes(surface)) return null;
|
|
39
39
|
const pluginRoot = join(generatedRoot, "plugins", "agdf");
|
|
40
40
|
let runtimeManifest;
|
|
41
41
|
try { runtimeManifest = JSON.parse(readFileSync(join(pluginRoot, "runtime", "runtime-manifest.json"), "utf8")); } catch { return null; }
|
|
@@ -4,12 +4,12 @@ import { dirname, join, resolve } from "node:path";
|
|
|
4
4
|
import { renameSyncWithRetry } from "../fs-swap.js";
|
|
5
5
|
|
|
6
6
|
export function runtimeCheckReceiptPath(dataRoot, surface) {
|
|
7
|
-
if (!["codex", "claude", "opencode"].includes(surface)) throw new Error("AGDF_RUNTIME_CHECK_RECEIPT_SURFACE_INVALID");
|
|
7
|
+
if (!["codex", "claude", "copilot", "opencode"].includes(surface)) throw new Error("AGDF_RUNTIME_CHECK_RECEIPT_SURFACE_INVALID");
|
|
8
8
|
return join(resolve(dataRoot), "runtime-checks", `${surface}.json`);
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export function createRuntimeCheckReceipt({ surface, decision, capabilityIdentity, command }) {
|
|
12
|
-
if (!["codex", "claude", "opencode"].includes(surface)) throw new Error("AGDF_RUNTIME_CHECK_RECEIPT_SURFACE_INVALID");
|
|
12
|
+
if (!["codex", "claude", "copilot", "opencode"].includes(surface)) throw new Error("AGDF_RUNTIME_CHECK_RECEIPT_SURFACE_INVALID");
|
|
13
13
|
if (!["enable", "manual"].includes(decision)) throw new Error("AGDF_RUNTIME_CHECK_RECEIPT_DECISION_INVALID");
|
|
14
14
|
if (!/^[a-f0-9]{64}$/.test(capabilityIdentity)) throw new Error("AGDF_RUNTIME_CHECK_RECEIPT_IDENTITY_INVALID");
|
|
15
15
|
return Object.freeze({
|
|
@@ -26,7 +26,7 @@ export function createRuntimeCheckReceipt({ surface, decision, capabilityIdentit
|
|
|
26
26
|
export function validateRuntimeCheckReceipt(receipt) {
|
|
27
27
|
if (receipt?.schema_version !== 1 || receipt.owner !== "create-agdf"
|
|
28
28
|
|| receipt.capability_id !== "automatic-runtime-checks") return { status: "receipt_unowned", receipt: null };
|
|
29
|
-
if (!["codex", "claude", "opencode"].includes(receipt.surface)
|
|
29
|
+
if (!["codex", "claude", "copilot", "opencode"].includes(receipt.surface)
|
|
30
30
|
|| !["enabled", "manual"].includes(receipt.requested_state)
|
|
31
31
|
|| !/^[a-f0-9]{64}$/.test(receipt.capability_identity)
|
|
32
32
|
|| typeof receipt.command !== "string" || !receipt.command.trim()) {
|
package/lib/scaffold/plan.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { generatedRoot, languageConfigContent, pluginDefinition } from "../cli/runtime-context.js";
|
|
4
4
|
export { doctorRequiredFiles } from "../control-evaluation/required-files.js";
|
|
5
5
|
|
|
6
|
-
export const agdfFragmentPath = "AGENTS.agdf.md";
|
|
7
6
|
const codexSkillNames = pluginDefinition.skillSet.map((skill) => `${pluginDefinition.codex.skillPrefix}${skill.slug}`);
|
|
8
|
-
const copilotSkillNames = pluginDefinition.skillSet.map((skill) => `${pluginDefinition.copilot.skillPrefix}${skill.slug}`);
|
|
9
7
|
const globalOpenCodeSkillNames = pluginDefinition.skillSet.map((skill) => `${pluginDefinition.opencode.globalSkillPrefix}${skill.slug}`);
|
|
10
8
|
const contractModules = [
|
|
11
9
|
"gate-transition.md",
|
|
@@ -96,63 +94,11 @@ const artefactTemplateFiles = [
|
|
|
96
94
|
join(".agdf", "control", "templates", "artefacts", "QA_REPORT.md"),
|
|
97
95
|
join(".agdf", "control", "templates", "artefacts", "OR.md"),
|
|
98
96
|
];
|
|
99
|
-
const copilotInstructionFiles = [
|
|
100
|
-
join(".github", "copilot-instructions.md"),
|
|
101
|
-
join(".github", "instructions", "agdf-governance.instructions.md"),
|
|
102
|
-
];
|
|
103
|
-
const copilotSkillFiles = [
|
|
104
|
-
join(".github", "skills", "README.md"),
|
|
105
|
-
join(".github", "skills", pluginDefinition.copilot.runtimeContractFileName),
|
|
106
|
-
...contractModules.map((moduleName) => join(".github", "skills", "contracts", moduleName)),
|
|
107
|
-
...copilotSkillNames.map((skillName) => join(".github", "skills", skillName, "SKILL.md")),
|
|
108
|
-
];
|
|
109
97
|
|
|
110
98
|
function loadAsset(relativePath) {
|
|
111
99
|
return readFileSync(join(generatedRoot, relativePath), "utf8");
|
|
112
100
|
}
|
|
113
101
|
|
|
114
|
-
function isAgdfOwnedAgentsFile(content) {
|
|
115
|
-
return content.includes("## Surface Convention")
|
|
116
|
-
&& content.includes("GitHub Copilot repository skills do not have a plugin namespace")
|
|
117
|
-
&& content.includes("AGDF is agent-native first and CLI-verifiable by design");
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function addCopilotAgentsFile(files, targetDir, force) {
|
|
121
|
-
const agentsPath = join(targetDir, "AGENTS.md");
|
|
122
|
-
if (!existsSync(agentsPath) || force) {
|
|
123
|
-
files.push({
|
|
124
|
-
path: "AGENTS.md",
|
|
125
|
-
content: loadAsset("AGENTS.md"),
|
|
126
|
-
});
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
const existingAgents = readFileSync(agentsPath, "utf8");
|
|
131
|
-
if (isAgdfOwnedAgentsFile(existingAgents)) {
|
|
132
|
-
files.push({
|
|
133
|
-
path: "AGENTS.md",
|
|
134
|
-
content: loadAsset("AGENTS.md"),
|
|
135
|
-
allowOverwrite: true,
|
|
136
|
-
action: "refreshed",
|
|
137
|
-
});
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
files.push({
|
|
142
|
-
path: agdfFragmentPath,
|
|
143
|
-
content: loadAsset("AGENTS.md"),
|
|
144
|
-
allowOverwrite: true,
|
|
145
|
-
action: "refreshed",
|
|
146
|
-
preserved: "AGENTS.md",
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function shouldWriteLanguageConfig(target, targetDir, force) {
|
|
151
|
-
if (force) return true;
|
|
152
|
-
if ((target === "copilot" || target === "both") && existsSync(join(targetDir, ".agdf", "control", "config.json"))) return false;
|
|
153
|
-
return true;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
102
|
function addLanguageConfig(files, languagePreference) {
|
|
157
103
|
files.push({
|
|
158
104
|
path: join(".agdf", "control", "config.json"),
|
|
@@ -196,8 +142,8 @@ export function generatedFilesForTarget(target, targetDir, force, languagePrefer
|
|
|
196
142
|
return files;
|
|
197
143
|
}
|
|
198
144
|
|
|
199
|
-
if (target === "codex-repo"
|
|
200
|
-
|
|
145
|
+
if (target === "codex-repo") {
|
|
146
|
+
addLanguageConfig(files, languagePreference);
|
|
201
147
|
for (const codexPath of codexPluginFiles) {
|
|
202
148
|
files.push({
|
|
203
149
|
path: codexPath,
|
|
@@ -206,38 +152,6 @@ export function generatedFilesForTarget(target, targetDir, force, languagePrefer
|
|
|
206
152
|
}
|
|
207
153
|
}
|
|
208
154
|
|
|
209
|
-
if (target === "copilot" || target === "both") {
|
|
210
|
-
if (target !== "both" && shouldWriteLanguageConfig(target, targetDir, force)) addLanguageConfig(files, languagePreference);
|
|
211
|
-
addCopilotAgentsFile(files, targetDir, force);
|
|
212
|
-
|
|
213
|
-
for (const controlPath of controlFiles) {
|
|
214
|
-
files.push({
|
|
215
|
-
path: controlPath,
|
|
216
|
-
content: loadAsset(controlPath),
|
|
217
|
-
allowOverwrite: true,
|
|
218
|
-
action: "refreshed",
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
for (const instructionPath of copilotInstructionFiles) {
|
|
223
|
-
files.push({
|
|
224
|
-
path: instructionPath,
|
|
225
|
-
content: loadAsset(instructionPath),
|
|
226
|
-
allowOverwrite: true,
|
|
227
|
-
action: "refreshed",
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
for (const skillPath of copilotSkillFiles) {
|
|
232
|
-
files.push({
|
|
233
|
-
path: skillPath,
|
|
234
|
-
content: loadAsset(skillPath),
|
|
235
|
-
allowOverwrite: true,
|
|
236
|
-
action: "refreshed",
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
155
|
if (target === "opencode-repo") {
|
|
242
156
|
addLanguageConfig(files, languagePreference);
|
|
243
157
|
for (const controlPath of controlFiles) {
|