create-agdf 0.12.0 → 0.13.1

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 +116 -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 +116 -0
  57. package/lib/installers/local-marketplace.js +20 -19
  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,102 @@
1
+ import { readFileSync } from "node:fs";
2
+
3
+ export const LISTING_LIMITS = Object.freeze({
4
+ displayName: 30,
5
+ shortDescription: 30,
6
+ developerName: 80,
7
+ promptCount: 3,
8
+ promptLength: 128,
9
+ });
10
+
11
+ export function unicodeLength(value) {
12
+ return [...String(value)].length;
13
+ }
14
+
15
+ function requiredString(value, label, errors) {
16
+ if (typeof value !== "string" || value.trim() === "") errors.push(`${label} is required`);
17
+ }
18
+
19
+ function within(value, limit, label, errors) {
20
+ requiredString(value, label, errors);
21
+ if (typeof value === "string" && unicodeLength(value) > limit) {
22
+ errors.push(`${label} exceeds ${limit} Unicode code points`);
23
+ }
24
+ }
25
+
26
+ export function loadJson(path) {
27
+ return JSON.parse(readFileSync(path, "utf8"));
28
+ }
29
+
30
+ export function validatePublicPluginContract({ definition, capabilityMatrix, reviewerCases, releaseNotes }) {
31
+ const errors = [];
32
+ const contract = definition?.publicDistribution;
33
+ if (contract?.schemaVersion !== 1) errors.push("publicDistribution.schemaVersion must be 1");
34
+ if (contract?.submissionType !== "skills") errors.push("submissionType must be skills");
35
+ if (contract?.technicalId !== definition?.id) errors.push("technicalId must match canonical plugin id");
36
+ if (contract?.developerName !== definition?.developerName) errors.push("developerName must match canonical developerName");
37
+ if (contract?.category !== definition?.category) errors.push("category must match canonical category");
38
+ within(contract?.publicDisplayName, LISTING_LIMITS.displayName, "publicDisplayName", errors);
39
+ within(contract?.shortDescription, LISTING_LIMITS.shortDescription, "shortDescription", errors);
40
+ within(contract?.developerName, LISTING_LIMITS.developerName, "developerName", errors);
41
+ requiredString(contract?.fullDisplayName, "fullDisplayName", errors);
42
+ requiredString(definition?.longDescription, "longDescription", errors);
43
+ if (Object.hasOwn(contract ?? {}, "longDescription")) {
44
+ errors.push("publicDistribution.longDescription must use canonical longDescription");
45
+ }
46
+ if (contract?.fullDisplayName !== `${definition?.displayName} (${contract?.publicDisplayName})`) {
47
+ errors.push("fullDisplayName must combine canonical displayName and publicDisplayName");
48
+ }
49
+
50
+ const prompts = contract?.defaultPrompt;
51
+ if (!Array.isArray(prompts) || prompts.length !== LISTING_LIMITS.promptCount) {
52
+ errors.push(`defaultPrompt must contain exactly ${LISTING_LIMITS.promptCount} prompts`);
53
+ } else {
54
+ prompts.forEach((prompt, index) => within(prompt, LISTING_LIMITS.promptLength, `defaultPrompt[${index}]`, errors));
55
+ }
56
+ for (const [name, value] of Object.entries(contract?.urls ?? {})) {
57
+ try {
58
+ const url = new URL(value);
59
+ if (url.protocol !== "https:") errors.push(`${name} URL must use HTTPS`);
60
+ } catch {
61
+ errors.push(`${name} URL is invalid`);
62
+ }
63
+ }
64
+ for (const name of ["website", "privacy", "terms", "support"]) {
65
+ if (!contract?.urls?.[name]) errors.push(`${name} URL is required`);
66
+ }
67
+ if (contract?.publisher?.verificationState !== "unverified") {
68
+ errors.push("publisher verificationState must remain unverified without portal evidence");
69
+ }
70
+ if (!contract?.availability || !Array.isArray(contract.availability.countries) || !Array.isArray(contract.availability.regions) || !Array.isArray(contract.availability.workspaceContexts)) {
71
+ errors.push("availability decision record is incomplete");
72
+ }
73
+
74
+ const allowedStates = new Set(["common", "codex-specific", "chatgpt-specific", "advisory", "unavailable", "unverified"]);
75
+ if (capabilityMatrix?.releaseVersion !== definition?.version) errors.push("capability matrix version must match definition");
76
+ if (!Array.isArray(capabilityMatrix?.capabilities) || capabilityMatrix.capabilities.length === 0) errors.push("capability matrix is empty");
77
+ for (const capability of capabilityMatrix?.capabilities ?? []) {
78
+ if (!allowedStates.has(capability.state)) errors.push(`capability ${capability.id ?? "unknown"} has invalid state`);
79
+ requiredString(capability.evidenceClass, `capability ${capability.id} evidenceClass`, errors);
80
+ requiredString(capability.evidenceRef, `capability ${capability.id} evidenceRef`, errors);
81
+ }
82
+
83
+ if (reviewerCases?.releaseVersion !== definition?.version) errors.push("reviewer cases version must match definition");
84
+ const cases = reviewerCases?.cases ?? [];
85
+ if (cases.filter((entry) => entry.kind === "positive").length < 5) errors.push("at least five positive reviewer cases are required");
86
+ if (cases.filter((entry) => entry.kind === "negative").length < 3) errors.push("at least three negative reviewer cases are required");
87
+ for (const entry of cases) {
88
+ for (const field of ["id", "kind", "theme", "prompt", "expectedWorkflow", "expectedResult"]) requiredString(entry[field], `${entry.id ?? "case"}.${field}`, errors);
89
+ if (!Array.isArray(entry.prerequisites)) errors.push(`${entry.id}.prerequisites must be an array`);
90
+ }
91
+ for (const theme of ["missing-approval", "disproportionate-fit", "unavailable-repository-authority", "unsupported-host-capability", "unauthorized-external-action"]) {
92
+ if (!cases.some((entry) => entry.kind === "negative" && entry.theme === theme)) errors.push(`negative reviewer theme ${theme} is required`);
93
+ }
94
+ requiredString(releaseNotes, "releaseNotes", errors);
95
+ if (typeof releaseNotes === "string" && !releaseNotes.includes(definition?.version)) errors.push("release notes must contain exact version");
96
+ return errors;
97
+ }
98
+
99
+ export function assertPublicPluginContract(inputs) {
100
+ const errors = validatePublicPluginContract(inputs);
101
+ if (errors.length) throw new Error(`AGDF_PUBLIC_PLUGIN_CONTRACT_INVALID: ${errors.join("; ")}`);
102
+ }
@@ -0,0 +1,72 @@
1
+ function publicValues(definition) {
2
+ const distribution = definition.publicDistribution;
3
+ if (!distribution || distribution.schemaVersion !== 1) {
4
+ throw new Error("AGDF_PUBLIC_PLUGIN_CONTRACT_INVALID: publicDistribution schemaVersion 1 is required");
5
+ }
6
+ return distribution;
7
+ }
8
+
9
+ export function createCodexPluginManifest(definition, { publicCandidate = false } = {}) {
10
+ const distribution = publicValues(definition);
11
+ const pluginInterface = publicCandidate ? {
12
+ displayName: distribution.publicDisplayName,
13
+ shortDescription: distribution.shortDescription,
14
+ longDescription: definition.longDescription,
15
+ defaultPrompt: distribution.defaultPrompt,
16
+ } : {
17
+ displayName: definition.displayName,
18
+ shortDescription: definition.description,
19
+ longDescription: definition.longDescription,
20
+ defaultPrompt: definition.codex.defaultPrompt,
21
+ };
22
+ const manifest = {
23
+ name: definition.id,
24
+ version: definition.version,
25
+ description: definition.description,
26
+ author: definition.author,
27
+ homepage: definition.homepage,
28
+ repository: definition.repository,
29
+ license: definition.license,
30
+ keywords: definition.keywords,
31
+ skills: definition.codex.skills,
32
+ interface: {
33
+ displayName: pluginInterface.displayName,
34
+ shortDescription: pluginInterface.shortDescription,
35
+ longDescription: pluginInterface.longDescription,
36
+ developerName: distribution.developerName,
37
+ category: distribution.category,
38
+ capabilities: definition.codex.capabilities,
39
+ websiteURL: distribution.urls.website,
40
+ privacyPolicyURL: distribution.urls.privacy,
41
+ termsOfServiceURL: distribution.urls.terms,
42
+ supportURL: distribution.urls.support,
43
+ composerIcon: definition.codex.composerIcon,
44
+ logo: definition.codex.logo,
45
+ defaultPrompt: pluginInterface.defaultPrompt,
46
+ brandColor: definition.brandColor,
47
+ },
48
+ };
49
+ if (!publicCandidate) manifest.hooks = `./${definition.codex.hooks}`;
50
+ return manifest;
51
+ }
52
+
53
+ export function renderCodexPluginManifest(definition, options) {
54
+ return `${JSON.stringify(createCodexPluginManifest(definition, options), null, 2)}\n`;
55
+ }
56
+
57
+ export function createClaudePluginManifest(definition) {
58
+ return {
59
+ name: definition.id,
60
+ version: definition.version,
61
+ description: definition.longDescription,
62
+ keywords: definition.keywords,
63
+ homepage: definition.homepage,
64
+ repository: definition.repository,
65
+ license: definition.license,
66
+ author: definition.author,
67
+ };
68
+ }
69
+
70
+ export function renderClaudePluginManifest(definition) {
71
+ return `${JSON.stringify(createClaudePluginManifest(definition), null, 2)}\n`;
72
+ }
@@ -0,0 +1,33 @@
1
+ export function createReadinessReport({ definition, fileCount, inventoryDigest }) {
2
+ const contract = definition.publicDistribution;
3
+ return {
4
+ schemaVersion: 1,
5
+ releaseVersion: definition.version,
6
+ candidateState: "repository_ready",
7
+ submissionReady: false,
8
+ submissionBlockers: [
9
+ "publisher identity and Apps Management authority are unverified",
10
+ "availability selection is pending",
11
+ "public deployment and exact-host evidence are unverified",
12
+ "portal draft has not been created or reconciled",
13
+ ],
14
+ evidence: {
15
+ repository: { state: "pass", detail: "canonical contract and deterministic source checks" },
16
+ bundle: { state: "pass", detail: `${fileCount} inventoried files; inventory digest ${inventoryDigest}` },
17
+ installed_host: { state: "unverified", detail: "PPD-L02 and PPD-L03 not performed" },
18
+ portal: { state: "unverified", detail: contract.publisher.verificationState },
19
+ post_publication: { state: "unverified", detail: "not published" },
20
+ },
21
+ externalState: {
22
+ publisherIdentity: contract.publisher.verificationState,
23
+ availability: contract.availability.decisionState,
24
+ portal: "not_observed",
25
+ publication: "not_observed",
26
+ },
27
+ };
28
+ }
29
+
30
+ export function renderReadinessReport(report) {
31
+ const blockers = report.submissionBlockers.map((blocker) => `- ${blocker}`).join("\n");
32
+ return `# AGDF Public Plugin Readiness\n\n- release: \`${report.releaseVersion}\`\n- candidate_state: \`${report.candidateState}\`\n- submission_ready: \`${report.submissionReady}\`\n\n## Evidence classes\n\n| Class | State | Detail |\n|---|---|---|\n${Object.entries(report.evidence).map(([name, value]) => `| ${name} | ${value.state} | ${value.detail} |`).join("\n")}\n\n## Submission blockers\n\n${blockers}\n\nRepository and bundle evidence do not prove installation, authenticated host behavior, publisher identity, portal state, deployment or publication.\n`;
33
+ }
@@ -0,0 +1,101 @@
1
+ import { createHash } from "node:crypto";
2
+ import { lstatSync, readFileSync, readdirSync, realpathSync, statSync } from "node:fs";
3
+ import { isAbsolute, join, relative, resolve, sep } from "node:path";
4
+ import { LISTING_LIMITS, unicodeLength } from "./contract.js";
5
+
6
+ function inside(root, candidate) {
7
+ const rel = relative(root, candidate);
8
+ return rel === "" || (rel !== ".." && !rel.startsWith(`..${sep}`) && !isAbsolute(rel));
9
+ }
10
+
11
+ function hasExactCase(root, target) {
12
+ const rel = relative(root, target);
13
+ let current = root;
14
+ for (const segment of rel.split(sep)) {
15
+ if (!readdirSync(current).includes(segment)) return false;
16
+ current = join(current, segment);
17
+ }
18
+ return true;
19
+ }
20
+
21
+ export function listCandidateFiles(root) {
22
+ root = realpathSync(resolve(root));
23
+ const files = [];
24
+ function visit(directory) {
25
+ for (const name of readdirSync(directory).sort()) {
26
+ const path = join(directory, name);
27
+ const stats = lstatSync(path);
28
+ if (stats.isSymbolicLink()) throw new Error(`AGDF_PUBLIC_PLUGIN_BUNDLE_PATH_MISSING: symlink not allowed: ${relative(root, path)}`);
29
+ if (stats.isDirectory()) visit(path);
30
+ else if (stats.isFile()) files.push(relative(root, path).replaceAll("\\", "/"));
31
+ }
32
+ }
33
+ visit(root);
34
+ return files;
35
+ }
36
+
37
+ function declaredPath(root, value, label, { directory = false } = {}) {
38
+ if (typeof value !== "string" || !value.startsWith("./")) throw new Error(`AGDF_PUBLIC_PLUGIN_BUNDLE_PATH_MISSING: ${label} must start with ./`);
39
+ const target = resolve(root, value);
40
+ if (!inside(root, target)) throw new Error(`AGDF_PUBLIC_PLUGIN_BUNDLE_PATH_MISSING: ${label} escapes candidate root`);
41
+ if (!hasExactCase(root, target)) throw new Error(`AGDF_PUBLIC_PLUGIN_BUNDLE_PATH_MISSING: ${label} has case mismatch or is missing`);
42
+ const actual = realpathSync(target);
43
+ if (!inside(root, actual)) throw new Error(`AGDF_PUBLIC_PLUGIN_BUNDLE_PATH_MISSING: ${label} resolves outside candidate root`);
44
+ const stats = statSync(target);
45
+ if (directory ? !stats.isDirectory() : !stats.isFile()) throw new Error(`AGDF_PUBLIC_PLUGIN_BUNDLE_PATH_MISSING: ${label} has wrong type`);
46
+ }
47
+
48
+ function assertReferencedSkillResources(root) {
49
+ const skillsRoot = join(root, "skills");
50
+ for (const skillName of readdirSync(skillsRoot).sort()) {
51
+ const skillRoot = join(skillsRoot, skillName);
52
+ if (!statSync(skillRoot).isDirectory()) continue;
53
+ const skillPath = join(skillRoot, "SKILL.md");
54
+ if (!statSync(skillPath).isFile()) throw new Error(`AGDF_PUBLIC_PLUGIN_BUNDLE_PATH_MISSING: skills/${skillName}/SKILL.md`);
55
+ const content = readFileSync(skillPath, "utf8");
56
+ const references = [...content.matchAll(/\.\.\/\.\.\/meta\/([A-Za-z0-9._/-]+)/g)].map((match) => match[1].replace(/[`)\],.;:]+$/, ""));
57
+ for (const reference of references) {
58
+ const target = resolve(root, "meta", reference);
59
+ if (!inside(root, target) || !statSync(target).isFile()) throw new Error(`AGDF_PUBLIC_PLUGIN_BUNDLE_PATH_MISSING: skills/${skillName} references meta/${reference}`);
60
+ }
61
+ }
62
+ }
63
+
64
+ export function validateCandidate(root) {
65
+ root = realpathSync(resolve(root));
66
+ const manifestPath = join(root, ".codex-plugin", "plugin.json");
67
+ const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
68
+ if (manifest.hooks || manifest.mcp || manifest.app) throw new Error("AGDF_PUBLIC_PLUGIN_CONTRACT_INVALID: Skills-only candidate must not declare hooks, MCP or app configuration");
69
+ declaredPath(root, manifest.skills, "skills", { directory: true });
70
+ declaredPath(root, manifest.interface?.composerIcon, "composerIcon");
71
+ declaredPath(root, manifest.interface?.logo, "logo");
72
+ const definition = JSON.parse(readFileSync(join(root, "meta", "agdf-plugin.definition.json"), "utf8"));
73
+ if (definition.version !== manifest.version) throw new Error("AGDF_PUBLIC_PLUGIN_VERSION_DRIFT: manifest and definition differ");
74
+ for (const [label, source] of Object.entries(definition.publicDistribution?.submissionSources ?? {})) {
75
+ declaredPath(root, `./${source}`, `submissionSources.${label}`);
76
+ }
77
+ assertReferencedSkillResources(root);
78
+ if (unicodeLength(manifest.interface?.displayName) > LISTING_LIMITS.displayName) throw new Error("AGDF_PUBLIC_PLUGIN_LISTING_LIMIT_EXCEEDED: displayName");
79
+ if (unicodeLength(manifest.interface?.shortDescription) > LISTING_LIMITS.shortDescription) throw new Error("AGDF_PUBLIC_PLUGIN_LISTING_LIMIT_EXCEEDED: shortDescription");
80
+ if (unicodeLength(manifest.interface?.developerName) > LISTING_LIMITS.developerName) throw new Error("AGDF_PUBLIC_PLUGIN_LISTING_LIMIT_EXCEEDED: developerName");
81
+ const prompts = manifest.interface?.defaultPrompt ?? [];
82
+ if (prompts.length !== LISTING_LIMITS.promptCount || prompts.some((prompt) => unicodeLength(prompt) > LISTING_LIMITS.promptLength)) throw new Error("AGDF_PUBLIC_PLUGIN_LISTING_LIMIT_EXCEEDED: defaultPrompt");
83
+ for (const field of ["websiteURL", "privacyPolicyURL", "termsOfServiceURL", "supportURL"]) {
84
+ let url;
85
+ try { url = new URL(manifest.interface?.[field]); } catch { throw new Error(`AGDF_PUBLIC_PLUGIN_CONTRACT_INVALID: ${field}`); }
86
+ if (url.protocol !== "https:") throw new Error(`AGDF_PUBLIC_PLUGIN_CONTRACT_INVALID: ${field} must use HTTPS`);
87
+ }
88
+ const files = listCandidateFiles(root);
89
+ for (const forbidden of [".app.json", ".mcp.json", ".agdf/control/", "node_modules/", ".git/"]) {
90
+ if (files.some((file) => file === forbidden || file.startsWith(forbidden))) throw new Error(`AGDF_PUBLIC_PLUGIN_CONTRACT_INVALID: forbidden candidate content ${forbidden}`);
91
+ }
92
+ return { manifest, files };
93
+ }
94
+
95
+ export function inventory(root, { exclude = [] } = {}) {
96
+ const excluded = new Set(exclude);
97
+ return listCandidateFiles(root).filter((path) => !excluded.has(path)).map((path) => ({
98
+ path,
99
+ sha256: createHash("sha256").update(readFileSync(join(root, path))).digest("hex"),
100
+ }));
101
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-agdf",
3
- "version": "0.12.0",
3
+ "version": "0.13.1",
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": [