create-agdf 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/generated/plugins/agdf/.claude-plugin/plugin.json +2 -2
  2. package/generated/plugins/agdf/.codex-plugin/plugin.json +9 -6
  3. package/generated/plugins/agdf/meta/agdf-plugin.definition.json +41 -5
  4. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-plugin.definition.json +41 -5
  5. package/generated/plugins/agdf/runtime/create-agdf/package.json +4 -68
  6. package/generated/plugins/agdf/runtime/runtime-manifest.json +2 -2
  7. package/generated/plugins/agdf/scripts/check-runtime-integrity.mjs +27 -37
  8. package/generated/plugins/agdf/submission/openai/availability.md +16 -0
  9. package/generated/plugins/agdf/submission/openai/capability-matrix.json +49 -0
  10. package/generated/plugins/agdf/submission/openai/release-notes.md +16 -0
  11. package/generated/plugins/agdf/submission/openai/reviewer-cases.json +96 -0
  12. package/generated/submissions/openai/agdf/.codex-plugin/plugin.json +43 -0
  13. package/generated/submissions/openai/agdf/assets/agdf-icon.svg +16 -0
  14. package/generated/submissions/openai/agdf/assets/agdf-logo.svg +16 -0
  15. package/generated/submissions/openai/agdf/meta/agdf-agent-router.md +129 -0
  16. package/generated/submissions/openai/agdf/meta/agdf-constitution.md +329 -0
  17. package/generated/submissions/openai/agdf/meta/agdf-interaction-locales.json +514 -0
  18. package/generated/submissions/openai/agdf/meta/agdf-plugin.definition.json +263 -0
  19. package/generated/submissions/openai/agdf/meta/agdf-runtime-contract.md +16 -0
  20. package/generated/submissions/openai/agdf/meta/agdf-tenets.md +201 -0
  21. package/generated/submissions/openai/agdf/meta/contracts/closeout.md +29 -0
  22. package/generated/submissions/openai/agdf/meta/contracts/context-graph.md +48 -0
  23. package/generated/submissions/openai/agdf/meta/contracts/control-scaffold.md +115 -0
  24. package/generated/submissions/openai/agdf/meta/contracts/gate-transition.md +165 -0
  25. package/generated/submissions/openai/agdf/meta/contracts/interaction.md +476 -0
  26. package/generated/submissions/openai/agdf/meta/contracts/modes.md +183 -0
  27. package/generated/submissions/openai/agdf/meta/contracts/quality.md +157 -0
  28. package/generated/submissions/openai/agdf/meta/contracts/task-target-resolution.md +102 -0
  29. package/generated/submissions/openai/agdf/skills/brownfield-analysis/SKILL.md +175 -0
  30. package/generated/submissions/openai/agdf/skills/brownfield-analysis/help.md +23 -0
  31. package/generated/submissions/openai/agdf/skills/clean-implementation-review/SKILL.md +126 -0
  32. package/generated/submissions/openai/agdf/skills/clean-implementation-review/help.md +23 -0
  33. package/generated/submissions/openai/agdf/skills/code-review/SKILL.md +119 -0
  34. package/generated/submissions/openai/agdf/skills/code-review/help.md +23 -0
  35. package/generated/submissions/openai/agdf/skills/delivery-closeout/SKILL.md +118 -0
  36. package/generated/submissions/openai/agdf/skills/delivery-closeout/help.md +23 -0
  37. package/generated/submissions/openai/agdf/skills/delivery-path-search/SKILL.md +94 -0
  38. package/generated/submissions/openai/agdf/skills/delivery-path-search/help.md +23 -0
  39. package/generated/submissions/openai/agdf/skills/gate-check/SKILL.md +238 -0
  40. package/generated/submissions/openai/agdf/skills/gate-check/help.md +23 -0
  41. package/generated/submissions/openai/agdf/skills/qa-gate/SKILL.md +137 -0
  42. package/generated/submissions/openai/agdf/skills/qa-gate/help.md +23 -0
  43. package/generated/submissions/openai/agdf/skills/release-or/SKILL.md +137 -0
  44. package/generated/submissions/openai/agdf/skills/release-or/help.md +23 -0
  45. package/generated/submissions/openai/agdf/skills/task-plan-review/SKILL.md +157 -0
  46. package/generated/submissions/openai/agdf/skills/task-plan-review/help.md +23 -0
  47. package/generated/submissions/openai/agdf/skills/ux-intent-definition/SKILL.md +94 -0
  48. package/generated/submissions/openai/agdf/skills/ux-intent-definition/help.md +17 -0
  49. package/generated/submissions/openai/agdf/submission/openai/availability.md +16 -0
  50. package/generated/submissions/openai/agdf/submission/openai/capability-matrix.json +49 -0
  51. package/generated/submissions/openai/agdf/submission/openai/inventory.json +175 -0
  52. package/generated/submissions/openai/agdf/submission/openai/listing.json +38 -0
  53. package/generated/submissions/openai/agdf/submission/openai/readiness.json +40 -0
  54. package/generated/submissions/openai/agdf/submission/openai/readiness.md +24 -0
  55. package/generated/submissions/openai/agdf/submission/openai/release-notes.md +16 -0
  56. package/generated/submissions/openai/agdf/submission/openai/reviewer-cases.json +96 -0
  57. package/lib/installers/local-marketplace.js +1 -1
  58. package/lib/public-plugin/builder.js +82 -0
  59. package/lib/public-plugin/contract.js +102 -0
  60. package/lib/public-plugin/manifest.js +72 -0
  61. package/lib/public-plugin/report.js +33 -0
  62. package/lib/public-plugin/validator.js +101 -0
  63. package/package.json +4 -2
@@ -0,0 +1,33 @@
1
+ export function createReadinessReport({ definition, fileCount, inventoryDigest }) {
2
+ const contract = definition.publicDistribution;
3
+ return {
4
+ schemaVersion: 1,
5
+ releaseVersion: definition.version,
6
+ candidateState: "repository_ready",
7
+ submissionReady: false,
8
+ submissionBlockers: [
9
+ "publisher identity and Apps Management authority are unverified",
10
+ "availability selection is pending",
11
+ "public deployment and exact-host evidence are unverified",
12
+ "portal draft has not been created or reconciled",
13
+ ],
14
+ evidence: {
15
+ repository: { state: "pass", detail: "canonical contract and deterministic source checks" },
16
+ bundle: { state: "pass", detail: `${fileCount} inventoried files; inventory digest ${inventoryDigest}` },
17
+ installed_host: { state: "unverified", detail: "PPD-L02 and PPD-L03 not performed" },
18
+ portal: { state: "unverified", detail: contract.publisher.verificationState },
19
+ post_publication: { state: "unverified", detail: "not published" },
20
+ },
21
+ externalState: {
22
+ publisherIdentity: contract.publisher.verificationState,
23
+ availability: contract.availability.decisionState,
24
+ portal: "not_observed",
25
+ publication: "not_observed",
26
+ },
27
+ };
28
+ }
29
+
30
+ export function renderReadinessReport(report) {
31
+ const blockers = report.submissionBlockers.map((blocker) => `- ${blocker}`).join("\n");
32
+ return `# AGDF Public Plugin Readiness\n\n- release: \`${report.releaseVersion}\`\n- candidate_state: \`${report.candidateState}\`\n- submission_ready: \`${report.submissionReady}\`\n\n## Evidence classes\n\n| Class | State | Detail |\n|---|---|---|\n${Object.entries(report.evidence).map(([name, value]) => `| ${name} | ${value.state} | ${value.detail} |`).join("\n")}\n\n## Submission blockers\n\n${blockers}\n\nRepository and bundle evidence do not prove installation, authenticated host behavior, publisher identity, portal state, deployment or publication.\n`;
33
+ }
@@ -0,0 +1,101 @@
1
+ import { createHash } from "node:crypto";
2
+ import { lstatSync, readFileSync, readdirSync, realpathSync, statSync } from "node:fs";
3
+ import { isAbsolute, join, relative, resolve, sep } from "node:path";
4
+ import { LISTING_LIMITS, unicodeLength } from "./contract.js";
5
+
6
+ function inside(root, candidate) {
7
+ const rel = relative(root, candidate);
8
+ return rel === "" || (rel !== ".." && !rel.startsWith(`..${sep}`) && !isAbsolute(rel));
9
+ }
10
+
11
+ function hasExactCase(root, target) {
12
+ const rel = relative(root, target);
13
+ let current = root;
14
+ for (const segment of rel.split(sep)) {
15
+ if (!readdirSync(current).includes(segment)) return false;
16
+ current = join(current, segment);
17
+ }
18
+ return true;
19
+ }
20
+
21
+ export function listCandidateFiles(root) {
22
+ root = realpathSync(resolve(root));
23
+ const files = [];
24
+ function visit(directory) {
25
+ for (const name of readdirSync(directory).sort()) {
26
+ const path = join(directory, name);
27
+ const stats = lstatSync(path);
28
+ if (stats.isSymbolicLink()) throw new Error(`AGDF_PUBLIC_PLUGIN_BUNDLE_PATH_MISSING: symlink not allowed: ${relative(root, path)}`);
29
+ if (stats.isDirectory()) visit(path);
30
+ else if (stats.isFile()) files.push(relative(root, path).replaceAll("\\", "/"));
31
+ }
32
+ }
33
+ visit(root);
34
+ return files;
35
+ }
36
+
37
+ function declaredPath(root, value, label, { directory = false } = {}) {
38
+ if (typeof value !== "string" || !value.startsWith("./")) throw new Error(`AGDF_PUBLIC_PLUGIN_BUNDLE_PATH_MISSING: ${label} must start with ./`);
39
+ const target = resolve(root, value);
40
+ if (!inside(root, target)) throw new Error(`AGDF_PUBLIC_PLUGIN_BUNDLE_PATH_MISSING: ${label} escapes candidate root`);
41
+ if (!hasExactCase(root, target)) throw new Error(`AGDF_PUBLIC_PLUGIN_BUNDLE_PATH_MISSING: ${label} has case mismatch or is missing`);
42
+ const actual = realpathSync(target);
43
+ if (!inside(root, actual)) throw new Error(`AGDF_PUBLIC_PLUGIN_BUNDLE_PATH_MISSING: ${label} resolves outside candidate root`);
44
+ const stats = statSync(target);
45
+ if (directory ? !stats.isDirectory() : !stats.isFile()) throw new Error(`AGDF_PUBLIC_PLUGIN_BUNDLE_PATH_MISSING: ${label} has wrong type`);
46
+ }
47
+
48
+ function assertReferencedSkillResources(root) {
49
+ const skillsRoot = join(root, "skills");
50
+ for (const skillName of readdirSync(skillsRoot).sort()) {
51
+ const skillRoot = join(skillsRoot, skillName);
52
+ if (!statSync(skillRoot).isDirectory()) continue;
53
+ const skillPath = join(skillRoot, "SKILL.md");
54
+ if (!statSync(skillPath).isFile()) throw new Error(`AGDF_PUBLIC_PLUGIN_BUNDLE_PATH_MISSING: skills/${skillName}/SKILL.md`);
55
+ const content = readFileSync(skillPath, "utf8");
56
+ const references = [...content.matchAll(/\.\.\/\.\.\/meta\/([A-Za-z0-9._/-]+)/g)].map((match) => match[1].replace(/[`)\],.;:]+$/, ""));
57
+ for (const reference of references) {
58
+ const target = resolve(root, "meta", reference);
59
+ if (!inside(root, target) || !statSync(target).isFile()) throw new Error(`AGDF_PUBLIC_PLUGIN_BUNDLE_PATH_MISSING: skills/${skillName} references meta/${reference}`);
60
+ }
61
+ }
62
+ }
63
+
64
+ export function validateCandidate(root) {
65
+ root = realpathSync(resolve(root));
66
+ const manifestPath = join(root, ".codex-plugin", "plugin.json");
67
+ const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
68
+ if (manifest.hooks || manifest.mcp || manifest.app) throw new Error("AGDF_PUBLIC_PLUGIN_CONTRACT_INVALID: Skills-only candidate must not declare hooks, MCP or app configuration");
69
+ declaredPath(root, manifest.skills, "skills", { directory: true });
70
+ declaredPath(root, manifest.interface?.composerIcon, "composerIcon");
71
+ declaredPath(root, manifest.interface?.logo, "logo");
72
+ const definition = JSON.parse(readFileSync(join(root, "meta", "agdf-plugin.definition.json"), "utf8"));
73
+ if (definition.version !== manifest.version) throw new Error("AGDF_PUBLIC_PLUGIN_VERSION_DRIFT: manifest and definition differ");
74
+ for (const [label, source] of Object.entries(definition.publicDistribution?.submissionSources ?? {})) {
75
+ declaredPath(root, `./${source}`, `submissionSources.${label}`);
76
+ }
77
+ assertReferencedSkillResources(root);
78
+ if (unicodeLength(manifest.interface?.displayName) > LISTING_LIMITS.displayName) throw new Error("AGDF_PUBLIC_PLUGIN_LISTING_LIMIT_EXCEEDED: displayName");
79
+ if (unicodeLength(manifest.interface?.shortDescription) > LISTING_LIMITS.shortDescription) throw new Error("AGDF_PUBLIC_PLUGIN_LISTING_LIMIT_EXCEEDED: shortDescription");
80
+ if (unicodeLength(manifest.interface?.developerName) > LISTING_LIMITS.developerName) throw new Error("AGDF_PUBLIC_PLUGIN_LISTING_LIMIT_EXCEEDED: developerName");
81
+ const prompts = manifest.interface?.defaultPrompt ?? [];
82
+ if (prompts.length !== LISTING_LIMITS.promptCount || prompts.some((prompt) => unicodeLength(prompt) > LISTING_LIMITS.promptLength)) throw new Error("AGDF_PUBLIC_PLUGIN_LISTING_LIMIT_EXCEEDED: defaultPrompt");
83
+ for (const field of ["websiteURL", "privacyPolicyURL", "termsOfServiceURL", "supportURL"]) {
84
+ let url;
85
+ try { url = new URL(manifest.interface?.[field]); } catch { throw new Error(`AGDF_PUBLIC_PLUGIN_CONTRACT_INVALID: ${field}`); }
86
+ if (url.protocol !== "https:") throw new Error(`AGDF_PUBLIC_PLUGIN_CONTRACT_INVALID: ${field} must use HTTPS`);
87
+ }
88
+ const files = listCandidateFiles(root);
89
+ for (const forbidden of [".app.json", ".mcp.json", ".agdf/control/", "node_modules/", ".git/"]) {
90
+ if (files.some((file) => file === forbidden || file.startsWith(forbidden))) throw new Error(`AGDF_PUBLIC_PLUGIN_CONTRACT_INVALID: forbidden candidate content ${forbidden}`);
91
+ }
92
+ return { manifest, files };
93
+ }
94
+
95
+ export function inventory(root, { exclude = [] } = {}) {
96
+ const excluded = new Set(exclude);
97
+ return listCandidateFiles(root).filter((path) => !excluded.has(path)).map((path) => ({
98
+ path,
99
+ sha256: createHash("sha256").update(readFileSync(join(root, path))).digest("hex"),
100
+ }));
101
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-agdf",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "Bootstrap AGDF repository-local plugin files, Copilot/OpenCode instructions, skills, control files and machine-readable checks.",
5
5
  "type": "module",
6
6
  "files": [
@@ -21,6 +21,8 @@
21
21
  },
22
22
  "scripts": {
23
23
  "sync-package-assets": "node ./scripts/sync-package-assets.js",
24
+ "build:public-plugin": "node ./scripts/build-public-plugin.js",
25
+ "test:public-plugin": "node ./scripts/public-plugin-test.js",
24
26
  "test:delivery-path-search": "node ./scripts/delivery-path-search-test.js",
25
27
  "test:delivery-path-search-unit": "node ./scripts/delivery-path-search-unit-test.js",
26
28
  "test:delivery-path-search-generator": "node ./scripts/delivery-path-search-generator-test.js",
@@ -44,7 +46,7 @@
44
46
  "test:proportionality": "node ./scripts/proportionality-benchmark-test.js",
45
47
  "test:release-bootstrap": "node ./scripts/release-bootstrap-smoke-test.js",
46
48
  "test:routing": "npm run sync-package-assets && node ./scripts/test-routing.js",
47
- "smoke-test": "npm run sync-package-assets && npm run test:cli-modularization && npm run test:local-validator && npm run test:local-marketplace && npm run test:package-build && npm run test:package-contents && npm run test:lifecycle && npm run test:control-state && npm run test:interaction-presentation && npm run test:verified-change && npm run test:runtime-integrity-layout && npm run test:runtime-integrity-negative && npm run test:skill-evals && npm run eval:skills && npm run test:proportionality && npm run test:delivery-path-search && npm run test:delivery-path-search-unit && npm run test:delivery-path-search-generator && npm run test:opencode-hardening && node ./scripts/smoke-test.js && node ./scripts/test-routing.js",
49
+ "smoke-test": "npm run sync-package-assets && npm run test:public-plugin && npm run test:cli-modularization && npm run test:local-validator && npm run test:local-marketplace && npm run test:package-build && npm run test:package-contents && npm run test:lifecycle && npm run test:control-state && npm run test:interaction-presentation && npm run test:verified-change && npm run test:runtime-integrity-layout && npm run test:runtime-integrity-negative && npm run test:skill-evals && npm run eval:skills && npm run test:proportionality && npm run test:delivery-path-search && npm run test:delivery-path-search-unit && npm run test:delivery-path-search-generator && npm run test:opencode-hardening && node ./scripts/smoke-test.js && node ./scripts/test-routing.js",
48
50
  "prepack": "npm run sync-package-assets"
49
51
  },
50
52
  "keywords": [