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.
Files changed (134) hide show
  1. package/README.md +14 -10
  2. package/generated/plugins/agdf/.claude-plugin/plugin.json +1 -1
  3. package/generated/plugins/agdf/.codex-plugin/plugin.json +2 -4
  4. package/generated/plugins/agdf/meta/agdf-plugin.definition.json +26 -2
  5. package/generated/plugins/agdf/meta/copilot-payload-baseline.json +7 -0
  6. package/generated/plugins/agdf/runtime/agdf-local.js +1 -1
  7. package/generated/plugins/agdf/runtime/agdf-session-check.js +10 -5
  8. package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-plugin.definition.json +26 -2
  9. package/generated/plugins/agdf/runtime/create-agdf/lib/cli/command-registry.js +6 -7
  10. package/generated/plugins/agdf/runtime/create-agdf/lib/runtime/local-validator.js +29 -17
  11. package/generated/plugins/agdf/runtime/create-agdf/lib/runtime/plugin-provenance.js +50 -1
  12. package/generated/plugins/agdf/runtime/create-agdf/lib/runtime-check-consent/contract.js +3 -1
  13. package/generated/plugins/agdf/runtime/create-agdf/package.json +1 -1
  14. package/generated/plugins/agdf/runtime/runtime-manifest.json +2 -2
  15. package/generated/plugins/agdf/scripts/check-runtime-integrity.mjs +32 -3
  16. package/generated/plugins/agdf/submission/openai/availability.md +1 -1
  17. package/generated/plugins/agdf/submission/openai/capability-matrix.json +1 -1
  18. package/generated/plugins/agdf/submission/openai/release-notes.md +1 -1
  19. package/generated/plugins/agdf/submission/openai/reviewer-cases.json +1 -1
  20. package/generated/plugins/copilot/agdf/.agdf-payload-inventory.json +771 -0
  21. package/generated/plugins/copilot/agdf/LICENSE +201 -0
  22. package/generated/plugins/copilot/agdf/hooks/copilot-hooks.json +15 -0
  23. package/generated/{AGENTS.md → plugins/copilot/agdf/meta/agdf-agent-router.md} +49 -33
  24. package/generated/plugins/copilot/agdf/meta/agdf-constitution.md +329 -0
  25. package/generated/plugins/copilot/agdf/meta/agdf-plugin.definition.json +331 -0
  26. package/generated/plugins/copilot/agdf/meta/agdf-runtime-contract.md +16 -0
  27. package/generated/plugins/copilot/agdf/plugin.json +22 -0
  28. package/generated/plugins/copilot/agdf/runtime/agdf-local.js +18 -0
  29. package/generated/plugins/copilot/agdf/runtime/agdf-session-check.js +97 -0
  30. package/generated/plugins/copilot/agdf/runtime/create-agdf/NOTICE +10 -0
  31. package/generated/plugins/copilot/agdf/runtime/create-agdf/bin/agdf-validator.js +11 -0
  32. package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-interaction-locales.json +512 -0
  33. package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-plugin.definition.json +331 -0
  34. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/command-registry.js +144 -0
  35. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/delivery-path-search-command.js +139 -0
  36. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/parse-args.js +173 -0
  37. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/runtime-context.js +83 -0
  38. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/validation-handlers.js +46 -0
  39. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/delivery-map.js +301 -0
  40. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/doctor.js +272 -0
  41. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/gate-check.js +455 -0
  42. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/gate-policy.js +305 -0
  43. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/parent-reconciliation.js +284 -0
  44. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/required-files.js +9 -0
  45. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/run-state.js +217 -0
  46. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/shared.js +345 -0
  47. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-evaluation/verified-change.js +156 -0
  48. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-state/aggregate.js +18 -0
  49. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-state/gate-approval-validator.js +49 -0
  50. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-state/index.js +7 -0
  51. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-state/legacy-migration.js +95 -0
  52. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-state/run-state-parser.js +265 -0
  53. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-state/run-state-repository.js +68 -0
  54. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-state/run-state-resolver.js +45 -0
  55. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/control-state/run-state-writer.js +97 -0
  56. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/candidate-policy.js +99 -0
  57. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/contracts.js +237 -0
  58. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/claude.js +35 -0
  59. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/codex.js +44 -0
  60. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/opencode.js +234 -0
  61. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/prompt.js +13 -0
  62. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/evaluators/protocol.js +13 -0
  63. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/generators/claude.js +40 -0
  64. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/generators/codex.js +38 -0
  65. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/generators/protocol.js +12 -0
  66. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/persistence.js +39 -0
  67. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/scoring.js +21 -0
  68. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/search-engine.js +155 -0
  69. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/state-adapter.js +161 -0
  70. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/surfaces/capabilities.js +27 -0
  71. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/delivery-path-search/transports/read-only-guard.js +43 -0
  72. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/interaction-presentation.js +842 -0
  73. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/runtime/local-validator.js +239 -0
  74. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/runtime/plugin-provenance.js +255 -0
  75. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/runtime/validator-application.js +40 -0
  76. package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/runtime-check-consent/contract.js +73 -0
  77. package/generated/plugins/copilot/agdf/runtime/create-agdf/package.json +6 -0
  78. package/generated/plugins/copilot/agdf/runtime/runtime-manifest.json +8 -0
  79. package/generated/submissions/openai/agdf/.codex-plugin/plugin.json +1 -2
  80. package/generated/submissions/openai/agdf/meta/agdf-plugin.definition.json +26 -2
  81. package/generated/submissions/openai/agdf/meta/copilot-payload-baseline.json +7 -0
  82. package/generated/submissions/openai/agdf/submission/openai/availability.md +1 -1
  83. package/generated/submissions/openai/agdf/submission/openai/capability-matrix.json +1 -1
  84. package/generated/submissions/openai/agdf/submission/openai/inventory.json +13 -9
  85. package/generated/submissions/openai/agdf/submission/openai/listing.json +1 -1
  86. package/generated/submissions/openai/agdf/submission/openai/readiness.json +2 -2
  87. package/generated/submissions/openai/agdf/submission/openai/readiness.md +2 -2
  88. package/generated/submissions/openai/agdf/submission/openai/release-notes.md +1 -1
  89. package/generated/submissions/openai/agdf/submission/openai/reviewer-cases.json +1 -1
  90. package/lib/cli/application.js +64 -8
  91. package/lib/cli/command-registry.js +6 -7
  92. package/lib/installers/copilot-precedence.js +34 -0
  93. package/lib/installers/copilot-settings.js +84 -0
  94. package/lib/installers/local-marketplace.js +112 -30
  95. package/lib/installers/plugin-installers.js +184 -5
  96. package/lib/lifecycle/operations.js +3 -0
  97. package/lib/lifecycle/result.js +1 -0
  98. package/lib/lifecycle/status.js +3 -3
  99. package/lib/public-plugin/copilot-profile.js +126 -0
  100. package/lib/public-plugin/manifest.js +34 -2
  101. package/lib/public-plugin/validator.js +1 -1
  102. package/lib/release/version-coherence.js +4 -0
  103. package/lib/runtime/local-validator.js +29 -17
  104. package/lib/runtime/plugin-provenance.js +50 -1
  105. package/lib/runtime-check-consent/contract.js +3 -1
  106. package/lib/runtime-check-consent/coordinator.js +1 -0
  107. package/lib/runtime-check-consent/service.js +1 -1
  108. package/lib/runtime-check-consent/state.js +3 -3
  109. package/lib/scaffold/plan.js +3 -89
  110. package/lib/scaffold/presentation.js +3 -22
  111. package/package.json +6 -3
  112. package/generated/.github/copilot-instructions.md +0 -16
  113. package/generated/.github/instructions/agdf-governance.instructions.md +0 -14
  114. package/generated/.github/skills/README.md +0 -20
  115. /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/agdf-brownfield-analysis/SKILL.md +0 -0
  116. /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/agdf-clean-implementation-review/SKILL.md +0 -0
  117. /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/agdf-code-review/SKILL.md +0 -0
  118. /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/agdf-delivery-closeout/SKILL.md +0 -0
  119. /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/agdf-delivery-path-search/SKILL.md +0 -0
  120. /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/agdf-gate-check/SKILL.md +0 -0
  121. /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/agdf-interaction-locales.json +0 -0
  122. /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/agdf-qa-gate/SKILL.md +0 -0
  123. /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/agdf-release-or/SKILL.md +0 -0
  124. /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/agdf-runtime-contract.md +0 -0
  125. /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/agdf-task-plan-review/SKILL.md +0 -0
  126. /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/agdf-ux-intent-definition/SKILL.md +0 -0
  127. /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/contracts/closeout.md +0 -0
  128. /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/contracts/context-graph.md +0 -0
  129. /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/contracts/control-scaffold.md +0 -0
  130. /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/contracts/gate-transition.md +0 -0
  131. /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/contracts/interaction.md +0 -0
  132. /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/contracts/modes.md +0 -0
  133. /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/contracts/quality.md +0 -0
  134. /package/generated/{.github/skills → plugins/copilot/agdf/copilot-skills}/contracts/task-target-resolution.md +0 -0
@@ -15,6 +15,7 @@ import {
15
15
  INSTALLATION_PROVENANCE_FILE,
16
16
  LEGACY_LOCAL_INSTALL_FILE,
17
17
  digestDirectory,
18
+ inspectCopilotPayloadInventory,
18
19
  digestNormalizedPluginSource,
19
20
  inspectInstallationProvenance,
20
21
  validateDistributionProfiles,
@@ -141,20 +142,39 @@ function claudeMarketplace(definition = pluginDefinition) {
141
142
  };
142
143
  }
143
144
 
145
+ function copilotMarketplace(definition = pluginDefinition) {
146
+ return {
147
+ name: MARKETPLACE_ID,
148
+ owner: { name: definition.displayName, email: "" },
149
+ metadata: { description: definition.description, version: definition.version },
150
+ plugins: [{
151
+ name: definition.id,
152
+ description: definition.copilotDescription || definition.longDescription,
153
+ version: definition.version,
154
+ source: "./plugins/agdf",
155
+ }],
156
+ };
157
+ }
158
+
144
159
  function validateBuiltPlugin(pluginRoot, expectedVersion, expectedCodexInstallVersion = expectedVersion, sourceDigest = "", {
145
160
  requireInstallationProvenance = false,
146
161
  allowLegacyProvenanceForMigration = false,
147
162
  allowPreProvenanceShape = false,
163
+ profileId = "runtime-plugin",
148
164
  } = {}) {
149
165
  const definition = readJson(join(pluginRoot, "meta", "agdf-plugin.definition.json"), "built plugin definition");
150
166
  const runtime = readJson(join(pluginRoot, "runtime", "runtime-manifest.json"), "built runtime manifest");
151
- const codex = readJson(join(pluginRoot, ".codex-plugin", "plugin.json"), "built Codex plugin manifest");
152
- const claude = readJson(join(pluginRoot, ".claude-plugin", "plugin.json"), "built Claude plugin manifest");
167
+ const copilotProfile = profileId === "copilot-runtime-plugin";
168
+ const codex = copilotProfile ? null : readJson(join(pluginRoot, ".codex-plugin", "plugin.json"), "built Codex plugin manifest");
169
+ const claude = copilotProfile ? null : readJson(join(pluginRoot, ".claude-plugin", "plugin.json"), "built Claude plugin manifest");
170
+ const copilot = copilotProfile ? readJson(join(pluginRoot, "plugin.json"), "built Copilot plugin manifest") : null;
153
171
  for (const required of [
154
- join(pluginRoot, ".codex-plugin", "plugin.json"),
155
- join(pluginRoot, ".claude-plugin", "plugin.json"),
172
+ ...(copilotProfile ? [join(pluginRoot, "plugin.json"), join(pluginRoot, ".agdf-payload-inventory.json")] : [
173
+ join(pluginRoot, ".codex-plugin", "plugin.json"),
174
+ join(pluginRoot, ".claude-plugin", "plugin.json"),
175
+ join(pluginRoot, "scripts", "check-runtime-integrity.mjs"),
176
+ ]),
156
177
  join(pluginRoot, "runtime", "agdf-local.js"),
157
- join(pluginRoot, "scripts", "check-runtime-integrity.mjs"),
158
178
  ]) {
159
179
  if (!existsSync(required)) throw new Error(`Built plugin is incomplete: ${required}`);
160
180
  }
@@ -178,13 +198,20 @@ function validateBuiltPlugin(pluginRoot, expectedVersion, expectedCodexInstallVe
178
198
  if (profile.status !== "matched" && provenance?.status !== "legacy" && !isPreProvenanceShape) {
179
199
  throw new Error("Built plugin distribution profile contract is invalid.");
180
200
  }
181
- if (codex.version !== expectedCodexInstallVersion) {
201
+ if (!copilotProfile && codex.version !== expectedCodexInstallVersion) {
182
202
  throw new Error(`Built Codex plugin version mismatch: expected ${expectedCodexInstallVersion}, observed ${codex.version}`);
183
203
  }
184
- if (claude.version !== expectedVersion) {
204
+ if (!copilotProfile && claude.version !== expectedVersion) {
185
205
  throw new Error(`Built Claude plugin version mismatch: expected ${expectedVersion}, observed ${claude.version}`);
186
206
  }
187
- if (expectedCodexInstallVersion !== expectedVersion) {
207
+ if (copilotProfile && copilot.version !== expectedVersion) {
208
+ throw new Error(`Built Copilot plugin version mismatch: expected ${expectedVersion}, observed ${copilot.version}`);
209
+ }
210
+ const copilotInventory = copilotProfile ? inspectCopilotPayloadInventory(pluginRoot, expectedVersion) : null;
211
+ if (copilotProfile && copilotInventory.status !== "matched") {
212
+ throw new Error(`Built Copilot plugin inventory is invalid: ${copilotInventory.reason}`);
213
+ }
214
+ if (!copilotProfile && expectedCodexInstallVersion !== expectedVersion) {
188
215
  if (!isCodexLocalInstallVersion(expectedVersion, expectedCodexInstallVersion, sourceDigest)) {
189
216
  throw new Error(`Invalid AGDF Codex local install version: ${expectedCodexInstallVersion}`);
190
217
  }
@@ -199,6 +226,8 @@ function validateBuiltPlugin(pluginRoot, expectedVersion, expectedCodexInstallVe
199
226
  runtimeManifest: runtime,
200
227
  pluginVersion: expectedCodexInstallVersion,
201
228
  allowLegacy: allowLegacyProvenanceForMigration,
229
+ profileId,
230
+ inventoryDigest: copilotInventory?.inventoryDigest ?? null,
202
231
  });
203
232
  if (provenance.status !== "matched"
204
233
  && !(allowLegacyProvenanceForMigration && provenance.status === "legacy")) {
@@ -208,11 +237,15 @@ function validateBuiltPlugin(pluginRoot, expectedVersion, expectedCodexInstallVe
208
237
  return definition;
209
238
  }
210
239
 
211
- function validateMarketplaceRoot(root, definition = pluginDefinition) {
212
- const codex = readJson(join(root, ".agents", "plugins", "marketplace.json"), "Codex local marketplace manifest");
213
- const claude = readJson(join(root, ".claude-plugin", "marketplace.json"), "Claude local marketplace manifest");
240
+ function validateMarketplaceRoot(root, definition = pluginDefinition, { profileId = "runtime-plugin" } = {}) {
241
+ const copilotProfile = profileId === "copilot-runtime-plugin";
242
+ const codex = copilotProfile ? null : readJson(join(root, ".agents", "plugins", "marketplace.json"), "Codex local marketplace manifest");
243
+ const copilot = copilotProfile ? readJson(join(root, ".github", "plugin", "marketplace.json"), "Copilot local marketplace manifest") : null;
244
+ const claude = copilotProfile ? null : readJson(join(root, ".claude-plugin", "marketplace.json"), "Claude local marketplace manifest");
214
245
  const serializedCodex = JSON.stringify(codex);
215
- const codexShape = serializedCodex === JSON.stringify(codexMarketplace(definition))
246
+ const codexShape = copilotProfile
247
+ ? "current"
248
+ : serializedCodex === JSON.stringify(codexMarketplace(definition))
216
249
  ? "current"
217
250
  : serializedCodex === JSON.stringify(legacyCodexMarketplace(definition))
218
251
  ? "legacy_full_product_label"
@@ -220,15 +253,19 @@ function validateMarketplaceRoot(root, definition = pluginDefinition) {
220
253
  if (codexShape === "invalid") {
221
254
  throw new Error(`Codex local marketplace manifest is not owned by ${MARKETPLACE_ID}: ${root}`);
222
255
  }
223
- if (JSON.stringify(claude) !== JSON.stringify(claudeMarketplace(definition))) {
256
+ if (!copilotProfile && JSON.stringify(claude) !== JSON.stringify(claudeMarketplace(definition))) {
224
257
  throw new Error(`Claude local marketplace manifest is not owned by ${MARKETPLACE_ID}: ${root}`);
225
258
  }
259
+ if (copilotProfile && JSON.stringify(copilot) !== JSON.stringify(copilotMarketplace(definition))) {
260
+ throw new Error(`Copilot local marketplace manifest is not owned by ${MARKETPLACE_ID}: ${root}`);
261
+ }
226
262
  return Object.freeze({ codexShape });
227
263
  }
228
264
 
229
- function classifyExistingMarketplace(stableRoot, marker) {
265
+ function classifyExistingMarketplace(stableRoot, marker, { profileId = "runtime-plugin" } = {}) {
230
266
  const existingPluginRoot = join(stableRoot, "plugins", MARKETPLACE_ID);
231
- const existingCodexInstallVersion = marker.codex_install_version ?? marker.version;
267
+ const copilotProfile = profileId === "copilot-runtime-plugin";
268
+ const existingCodexInstallVersion = copilotProfile ? marker.version : marker.codex_install_version ?? marker.version;
232
269
  if (!isSemanticVersion(marker.version)
233
270
  || !/^[a-f0-9]{64}$/.test(marker.plugin_digest ?? "")) {
234
271
  throw new Error(`Refusing invalid AGDF marketplace ownership evidence: ${stableRoot}`);
@@ -238,7 +275,7 @@ function classifyExistingMarketplace(stableRoot, marker) {
238
275
  "built plugin definition",
239
276
  );
240
277
  const hasCurrentProvenance = existsSync(join(existingPluginRoot, INSTALLATION_PROVENANCE_FILE));
241
- const hasLegacyProvenance = existsSync(join(existingPluginRoot, LEGACY_LOCAL_INSTALL_FILE));
278
+ const hasLegacyProvenance = !copilotProfile && existsSync(join(existingPluginRoot, LEGACY_LOCAL_INSTALL_FILE));
242
279
  const preProvenanceCandidate = !hasCurrentProvenance
243
280
  && !hasLegacyProvenance
244
281
  && !Object.hasOwn(definition, "distributionProfiles");
@@ -249,9 +286,9 @@ function classifyExistingMarketplace(stableRoot, marker) {
249
286
  marker.source_digest ?? "",
250
287
  preProvenanceCandidate
251
288
  ? { allowPreProvenanceShape: true }
252
- : { requireInstallationProvenance: true, allowLegacyProvenanceForMigration: true },
289
+ : { requireInstallationProvenance: true, allowLegacyProvenanceForMigration: true, profileId },
253
290
  );
254
- const marketplace = validateMarketplaceRoot(stableRoot, existingDefinition);
291
+ const marketplace = validateMarketplaceRoot(stableRoot, existingDefinition, { profileId });
255
292
  if (digestDirectory(existingPluginRoot) !== marker.plugin_digest) {
256
293
  throw new Error(`Refusing tampered AGDF marketplace root: ${stableRoot}`);
257
294
  }
@@ -287,25 +324,30 @@ function recoverInterruptedTransaction(stableRoot, stageRoot, backupRoot, failed
287
324
 
288
325
  export function prepareLocalMarketplace({
289
326
  dataRoot = defaultAgdfDataRoot(),
290
- builtPluginRoot = join(generatedRoot, "plugins", "agdf"),
327
+ builtPluginRoot,
291
328
  expectedVersion = pluginDefinition.version,
292
329
  codexInstallVersion = expectedVersion,
293
330
  codexRegistrationRevision = null,
331
+ profileId = "runtime-plugin",
294
332
  } = {}) {
295
333
  dataRoot = resolve(dataRoot);
334
+ const copilotProfile = profileId === "copilot-runtime-plugin";
335
+ if (!builtPluginRoot) builtPluginRoot = copilotProfile
336
+ ? join(generatedRoot, "plugins", "copilot", "agdf")
337
+ : join(generatedRoot, "plugins", "agdf");
296
338
  builtPluginRoot = resolve(builtPluginRoot);
297
- const stableRoot = join(dataRoot, "marketplaces", MARKETPLACE_ID);
339
+ const stableRoot = join(dataRoot, "marketplaces", copilotProfile ? "agdf-copilot" : MARKETPLACE_ID);
298
340
  const parent = dirname(stableRoot);
299
341
  const stageRoot = `${stableRoot}.stage`;
300
342
  const backupRoot = `${stableRoot}.backup`;
301
343
  const failedRoot = `${stableRoot}.failed`;
302
344
  if (!pathInside(dataRoot, stableRoot) || dirname(stableRoot) !== parent) throw new Error(`Unsafe AGDF marketplace root: ${stableRoot}`);
303
345
  const sourceDigest = digestPluginSource(builtPluginRoot, expectedVersion);
304
- if (codexInstallVersion !== expectedVersion
346
+ if (!copilotProfile && codexInstallVersion !== expectedVersion
305
347
  && !isCodexLocalInstallVersion(expectedVersion, codexInstallVersion, sourceDigest)) {
306
348
  throw new Error(`Invalid AGDF Codex local install version: ${codexInstallVersion}`);
307
349
  }
308
- const targetDefinition = validateBuiltPlugin(builtPluginRoot, expectedVersion);
350
+ const targetDefinition = validateBuiltPlugin(builtPluginRoot, expectedVersion, expectedVersion, "", { profileId });
309
351
  mkdirSync(parent, { recursive: true });
310
352
  recoverInterruptedTransaction(stableRoot, stageRoot, backupRoot, failedRoot);
311
353
 
@@ -313,6 +355,7 @@ export function prepareLocalMarketplace({
313
355
  if (existsSync(stableRoot)) {
314
356
  try {
315
357
  existing = ownership(stableRoot);
358
+ if ((existing.profile_id ?? "runtime-plugin") !== profileId) throw new Error(`AGDF marketplace profile mismatch: ${stableRoot}`);
316
359
  } catch (error) {
317
360
  throw invalidExistingMarketplace(error);
318
361
  }
@@ -325,7 +368,7 @@ export function prepareLocalMarketplace({
325
368
  if (existing) {
326
369
  let classified;
327
370
  try {
328
- classified = classifyExistingMarketplace(stableRoot, existing);
371
+ classified = classifyExistingMarketplace(stableRoot, existing, { profileId });
329
372
  } catch (error) {
330
373
  throw invalidExistingMarketplace(error);
331
374
  }
@@ -338,6 +381,7 @@ export function prepareLocalMarketplace({
338
381
  schema_version: 1,
339
382
  owner: "create-agdf",
340
383
  marketplace_id: MARKETPLACE_ID,
384
+ profile_id: profileId,
341
385
  codex_registration_revision: targetCodexRegistrationRevision,
342
386
  version: expectedVersion,
343
387
  codex_install_version: codexInstallVersion,
@@ -348,8 +392,8 @@ export function prepareLocalMarketplace({
348
392
  });
349
393
  const stagedPluginRoot = join(stageRoot, "plugins", MARKETPLACE_ID);
350
394
  cpSync(builtPluginRoot, stagedPluginRoot, { recursive: true });
351
- validateBuiltPlugin(stagedPluginRoot, expectedVersion);
352
- if (codexInstallVersion !== expectedVersion) {
395
+ validateBuiltPlugin(stagedPluginRoot, expectedVersion, expectedVersion, "", { profileId });
396
+ if (!copilotProfile && codexInstallVersion !== expectedVersion) {
353
397
  const codexManifestPath = join(stagedPluginRoot, ".codex-plugin", "plugin.json");
354
398
  writeJson(codexManifestPath, { ...readJson(codexManifestPath, "built Codex plugin manifest"), version: codexInstallVersion });
355
399
  }
@@ -357,25 +401,31 @@ export function prepareLocalMarketplace({
357
401
  writeJson(join(stagedPluginRoot, INSTALLATION_PROVENANCE_FILE), {
358
402
  schema_version: 1,
359
403
  owner: "create-agdf",
360
- profile_id: "runtime-plugin",
404
+ profile_id: profileId,
361
405
  marketplace_id: MARKETPLACE_ID,
362
406
  canonical_version: expectedVersion,
363
407
  codex_install_version: codexInstallVersion,
364
408
  source_digest: sourceDigest,
365
409
  runtime_digest: runtimeManifest.digest,
410
+ ...(copilotProfile ? { inventory_digest: inspectCopilotPayloadInventory(stagedPluginRoot, expectedVersion).inventoryDigest } : {}),
366
411
  });
367
412
  if (existsSync(join(stagedPluginRoot, LEGACY_LOCAL_INSTALL_FILE))) {
368
413
  rmSync(join(stagedPluginRoot, LEGACY_LOCAL_INSTALL_FILE));
369
414
  }
370
- validateBuiltPlugin(stagedPluginRoot, expectedVersion, codexInstallVersion, sourceDigest, { requireInstallationProvenance: true });
371
- writeJson(join(stageRoot, ".agents", "plugins", "marketplace.json"), codexMarketplace(targetDefinition));
372
- writeJson(join(stageRoot, ".claude-plugin", "marketplace.json"), claudeMarketplace(targetDefinition));
373
- validateMarketplaceRoot(stageRoot, targetDefinition);
415
+ validateBuiltPlugin(stagedPluginRoot, expectedVersion, copilotProfile ? expectedVersion : codexInstallVersion, sourceDigest, { requireInstallationProvenance: true, profileId });
416
+ if (copilotProfile) {
417
+ writeJson(join(stageRoot, ".github", "plugin", "marketplace.json"), copilotMarketplace(targetDefinition));
418
+ } else {
419
+ writeJson(join(stageRoot, ".agents", "plugins", "marketplace.json"), codexMarketplace(targetDefinition));
420
+ writeJson(join(stageRoot, ".claude-plugin", "marketplace.json"), claudeMarketplace(targetDefinition));
421
+ }
422
+ validateMarketplaceRoot(stageRoot, targetDefinition, { profileId });
374
423
  const pluginDigest = digestDirectory(stagedPluginRoot);
375
424
  const marker = {
376
425
  schema_version: 1,
377
426
  owner: "create-agdf",
378
427
  marketplace_id: MARKETPLACE_ID,
428
+ profile_id: profileId,
379
429
  codex_registration_revision: targetCodexRegistrationRevision,
380
430
  version: expectedVersion,
381
431
  codex_install_version: codexInstallVersion,
@@ -448,6 +498,10 @@ export function prepareLocalMarketplace({
448
498
  }
449
499
  }
450
500
 
501
+ export function prepareCopilotMarketplace(options = {}) {
502
+ return prepareLocalMarketplace({ ...options, profileId: "copilot-runtime-plugin", codexInstallVersion: options.expectedVersion ?? pluginDefinition.version });
503
+ }
504
+
451
505
  export function inspectLocalMarketplaceProjection({
452
506
  dataRoot = defaultAgdfDataRoot(),
453
507
  expectedVersion = pluginDefinition.version,
@@ -478,6 +532,34 @@ export function inspectLocalMarketplaceProjection({
478
532
  });
479
533
  }
480
534
 
535
+ export function inspectOwnedSharedMarketplaceForCopilotMigration({
536
+ dataRoot = defaultAgdfDataRoot(),
537
+ expectedVersion = pluginDefinition.version,
538
+ } = {}) {
539
+ const root = join(resolve(dataRoot), "marketplaces", MARKETPLACE_ID);
540
+ if (!existsSync(root)) return null;
541
+ const marker = ownership(root);
542
+ if ((marker.profile_id ?? "runtime-plugin") !== "runtime-plugin"
543
+ || marker.version !== expectedVersion
544
+ || !/^[a-f0-9]{64}$/.test(marker.plugin_digest ?? "")) {
545
+ throw new Error(`Refusing incompatible AGDF shared marketplace migration source: ${root}`);
546
+ }
547
+ const pluginRoot = join(root, "plugins", MARKETPLACE_ID);
548
+ const definition = readJson(join(pluginRoot, "meta", "agdf-plugin.definition.json"), "shared plugin definition");
549
+ const runtime = readJson(join(pluginRoot, "runtime", "runtime-manifest.json"), "shared runtime manifest");
550
+ const codex = readJson(join(pluginRoot, ".codex-plugin", "plugin.json"), "shared Codex manifest");
551
+ const claude = readJson(join(pluginRoot, ".claude-plugin", "plugin.json"), "shared Claude manifest");
552
+ if (definition.id !== MARKETPLACE_ID
553
+ || definition.version !== expectedVersion
554
+ || runtime.version !== expectedVersion
555
+ || claude.version !== expectedVersion
556
+ || (codex.version !== expectedVersion && !isCodexLocalInstallVersion(expectedVersion, codex.version))
557
+ || digestDirectory(pluginRoot) !== marker.plugin_digest) {
558
+ throw new Error(`Refusing stale or tampered AGDF shared marketplace migration source: ${root}`);
559
+ }
560
+ return Object.freeze({ root, pluginRoot, version: marker.version, digest: marker.plugin_digest });
561
+ }
562
+
481
563
  function normalizedLegacySource(value) {
482
564
  if (typeof value !== "string") return "";
483
565
  return value.trim().toLowerCase()
@@ -1,6 +1,12 @@
1
1
  import { execFileSync } from "node:child_process";
2
+ import { readFileSync } from "node:fs";
3
+ import { join, resolve } from "node:path";
4
+ import process from "node:process";
2
5
  import { pluginDefinition } from "../cli/runtime-context.js";
3
- import { CODEX_REGISTRATION_REVISION, classifyMarketplaceList, inspectLocalMarketplaceProjection, isCodexLocalInstallVersion, prepareLocalMarketplace } from "./local-marketplace.js";
6
+ import { digestNormalizedPluginSource } from "../runtime/plugin-provenance.js";
7
+ import { CODEX_REGISTRATION_REVISION, classifyMarketplaceList, inspectLocalMarketplaceProjection, inspectOwnedSharedMarketplaceForCopilotMigration, isCodexLocalInstallVersion, prepareCopilotMarketplace, prepareLocalMarketplace } from "./local-marketplace.js";
8
+
9
+ export const COPILOT_CLI_NPM_PACKAGE = "@github/copilot@1.0.80";
4
10
 
5
11
  export function installCodexGlobalPlugin({ exec = execFileSync, prepare = prepareLocalMarketplace, dataRoot } = {}) {
6
12
  const expectedVersion = pluginDefinition.version;
@@ -93,6 +99,178 @@ export function installClaudeGlobalPlugin({ exec = execFileSync, prepare = prepa
93
99
  }
94
100
  }
95
101
 
102
+ export function installCopilotGlobalPlugin({ exec = execFileSync, packagedCopilotExec = execFileSync, prepare = prepareCopilotMarketplace, dataRoot, pluginRoot } = {}) {
103
+ const expectedVersion = pluginDefinition.version;
104
+ const transaction = pluginRoot ? null : prepare({ expectedVersion, ...(dataRoot ? { dataRoot } : {}) });
105
+ const effectivePluginRoot = pluginRoot ?? transaction?.pluginRoot;
106
+ if (!effectivePluginRoot) throw lifecycleAdapterError("package", "AGDF Copilot plugin root is required.");
107
+ let runtimeManifest;
108
+ try {
109
+ runtimeManifest = JSON.parse(readFileSync(join(effectivePluginRoot, "runtime", "runtime-manifest.json"), "utf8"));
110
+ } catch (error) {
111
+ transaction?.rollback();
112
+ throw lifecycleAdapterError("package", `AGDF Copilot runtime manifest is unavailable: ${error.message}`);
113
+ }
114
+ const sourceDigest = transaction?.sourceDigest || digestNormalizedPluginSource(effectivePluginRoot, expectedVersion);
115
+ let before = "";
116
+ let activeExec = exec;
117
+ const bootstrapEvidence = [];
118
+ try {
119
+ before = activeExec("copilot", ["plugin", "list"], captureOptions());
120
+ } catch (error) {
121
+ if (error?.code !== "ENOENT") {
122
+ transaction?.rollback();
123
+ throw lifecycleAdapterError("verification", commandErrorText(error), { executable: "copilot", args: ["plugin", "list"] });
124
+ }
125
+ const invocation = copilotNpmInvocation();
126
+ activeExec = (_executable, args, options) => packagedCopilotExec(invocation.executable, [...invocation.args, ...args], options);
127
+ try {
128
+ before = activeExec("copilot", ["plugin", "list"], captureOptions());
129
+ bootstrapEvidence.push("copilot_cli_not_found", `copilot_cli_npm_package:${COPILOT_CLI_NPM_PACKAGE}`);
130
+ } catch (bootstrapError) {
131
+ transaction?.commit();
132
+ return {
133
+ surface: "copilot", operation: "install", expectedVersion, installedVersion: null,
134
+ verificationStatus: "unavailable", manualHandoff: true,
135
+ evidence: ["copilot_cli_not_found", `copilot_cli_npm_bootstrap_failed:${commandErrorText(bootstrapError)}`, "durable_local_plugin_stage", `local_plugin_root:${effectivePluginRoot}`, `source_digest:${sourceDigest}`],
136
+ pluginRoot: effectivePluginRoot, runtimeDigest: runtimeManifest.digest, sourceDigest, nativeOutput: [],
137
+ };
138
+ }
139
+ }
140
+ const directInstalled = pluginListHasPlugin(before, "agdf");
141
+ const marketplaceInstalled = pluginListHasPlugin(before, "agdf@agdf");
142
+ let legacySharedProjection = null;
143
+ if (transaction) {
144
+ try { legacySharedProjection = inspectOwnedSharedMarketplaceForCopilotMigration({ ...(dataRoot ? { dataRoot } : {}), expectedVersion }); } catch {}
145
+ }
146
+ let marketplaceAdded = false;
147
+ let legacyMarketplaceRemoved = false;
148
+ let marketplacePluginRemoved = false;
149
+ let directRemoved = false;
150
+ try {
151
+ const nativeOutput = [];
152
+ const marketplaceOutput = runPluginPhase(activeExec, "copilot", ["plugin", "marketplace", "list"], "marketplace", captureOptions());
153
+ const marketplace = classifyCopilotMarketplaceList(
154
+ marketplaceOutput,
155
+ transaction?.root ?? resolve(effectivePluginRoot, "..", ".."),
156
+ { ownedLegacyRoots: legacySharedProjection ? [legacySharedProjection.root] : [] },
157
+ );
158
+ if (marketplace.state === "conflict") {
159
+ throw lifecycleAdapterError("marketplace", `Refusing to replace non-AGDF Copilot marketplace registration agdf (${marketplace.source || "unknown source"}).`);
160
+ }
161
+ if (marketplace.state === "owned_legacy_shared") {
162
+ if (marketplaceInstalled) {
163
+ nativeOutput.push(runPluginPhase(activeExec, "copilot", ["plugin", "uninstall", "agdf@agdf"], "plugin_operation", captureOptions()));
164
+ marketplacePluginRemoved = true;
165
+ }
166
+ nativeOutput.push(runPluginPhase(activeExec, "copilot", ["plugin", "marketplace", "remove", "agdf"], "marketplace", captureOptions()));
167
+ legacyMarketplaceRemoved = true;
168
+ }
169
+ if (["absent", "owned_legacy_shared"].includes(marketplace.state)) {
170
+ nativeOutput.push(runPluginPhase(activeExec, "copilot", ["plugin", "marketplace", "add", transaction?.root ?? resolve(effectivePluginRoot, "..", "..")], "marketplace", captureOptions()));
171
+ marketplaceAdded = true;
172
+ }
173
+ if (marketplace.state === "owned_local_current" && marketplaceInstalled) {
174
+ nativeOutput.push(runPluginPhase(activeExec, "copilot", ["plugin", "uninstall", "agdf@agdf"], "plugin_operation", captureOptions()));
175
+ marketplacePluginRemoved = true;
176
+ }
177
+ if (directInstalled) {
178
+ nativeOutput.push(runPluginPhase(activeExec, "copilot", ["plugin", "uninstall", "agdf"], "plugin_operation", captureOptions()));
179
+ directRemoved = true;
180
+ }
181
+ nativeOutput.push(runPluginPhase(activeExec, "copilot", ["plugin", "install", "agdf@agdf"], "plugin_operation", captureOptions()));
182
+ const after = runPluginPhase(activeExec, "copilot", ["plugin", "list"], "verification", captureOptions());
183
+ const installed = pluginListHasPlugin(after, "agdf@agdf");
184
+ const installedVersion = installed ? pluginVersionFromList(after, "agdf@agdf") : "";
185
+ if (!installed) throw lifecycleAdapterError("verification", "AGDF was not present in copilot plugin list after installation.");
186
+ if (installedVersion && installedVersion !== expectedVersion) {
187
+ throw lifecycleAdapterError("version", versionMismatchMessage("GitHub Copilot", "agdf", expectedVersion, installedVersion, "npx --yes @agdf/cli@latest copilot"));
188
+ }
189
+ transaction?.commit();
190
+ return {
191
+ surface: "copilot", operation: directInstalled || marketplaceInstalled ? "update" : "install", expectedVersion,
192
+ installedVersion: installedVersion || null, verificationStatus: installedVersion ? "healthy" : "degraded",
193
+ manualHandoff: false,
194
+ evidence: [...bootstrapEvidence, "durable_local_plugin_stage", "copilot plugin marketplace list", ...(marketplaceAdded ? ["copilot plugin marketplace add"] : ["marketplace:owned_local_current"]), ...(legacyMarketplaceRemoved ? ["shared_marketplace_registration_migrated"] : []), ...(directRemoved ? ["direct_install_migrated"] : []), "copilot plugin install agdf@agdf", "copilot plugin list", `local_plugin_root:${effectivePluginRoot}`, `source_digest:${sourceDigest}`, ...(installedVersion ? [] : ["host_did_not_expose_version"])],
195
+ pluginRoot: effectivePluginRoot, runtimeDigest: runtimeManifest.digest, sourceDigest, nativeOutput: nativeOutput.filter(Boolean).map(String),
196
+ };
197
+ } catch (error) {
198
+ transaction?.rollback();
199
+ if (directRemoved) {
200
+ try {
201
+ activeExec("copilot", ["plugin", "install", effectivePluginRoot], captureOptions());
202
+ } catch (recoveryError) {
203
+ error.evidence = { ...(error.evidence ?? {}), direct_install_recovery: commandErrorText(recoveryError) };
204
+ }
205
+ }
206
+ if (marketplaceAdded) {
207
+ try {
208
+ activeExec("copilot", ["plugin", "marketplace", "remove", "agdf"], captureOptions());
209
+ } catch (recoveryError) {
210
+ error.evidence = { ...(error.evidence ?? {}), marketplace_recovery: commandErrorText(recoveryError) };
211
+ }
212
+ }
213
+ if (legacyMarketplaceRemoved && legacySharedProjection) {
214
+ try {
215
+ activeExec("copilot", ["plugin", "marketplace", "add", legacySharedProjection.root], captureOptions());
216
+ if (marketplacePluginRemoved) activeExec("copilot", ["plugin", "install", "agdf@agdf"], captureOptions());
217
+ } catch (recoveryError) {
218
+ error.evidence = { ...(error.evidence ?? {}), legacy_marketplace_recovery: commandErrorText(recoveryError) };
219
+ }
220
+ } else if (marketplacePluginRemoved) {
221
+ try {
222
+ activeExec("copilot", ["plugin", "install", "agdf@agdf"], captureOptions());
223
+ } catch (recoveryError) {
224
+ error.evidence = { ...(error.evidence ?? {}), marketplace_plugin_recovery: commandErrorText(recoveryError) };
225
+ }
226
+ }
227
+ throw error;
228
+ }
229
+ }
230
+
231
+ export function classifyCopilotMarketplaceList(output, expectedRoot, { ownedLegacyRoots = [] } = {}) {
232
+ const line = String(output || "").split(/\r?\n/).find((entry) => /^\s*[◆•]?\s*agdf\s+\(/.test(entry));
233
+ if (!line) return { state: "absent", source: "" };
234
+ const local = line.match(/\(Local:\s*(.+)\)\s*$/);
235
+ if (!local) return { state: "conflict", source: line.trim() };
236
+ if (resolve(local[1]) === resolve(expectedRoot)) return { state: "owned_local_current", source: local[1] };
237
+ if (ownedLegacyRoots.some((root) => resolve(root) === resolve(local[1]))) return { state: "owned_legacy_shared", source: local[1] };
238
+ return { state: "conflict", source: local[1] };
239
+ }
240
+
241
+ export function copilotNpmInvocation({ env = process.env, platform = process.platform, execPath = process.execPath } = {}) {
242
+ const args = ["exec", "--yes", `--package=${COPILOT_CLI_NPM_PACKAGE}`, "--", "copilot"];
243
+ if (env.npm_execpath) return { executable: execPath, args: [env.npm_execpath, ...args] };
244
+ return { executable: platform === "win32" ? "npm.cmd" : "npm", args };
245
+ }
246
+
247
+ export function setCopilotPluginEnabled({ enabled, exec = execFileSync } = {}) {
248
+ if (typeof enabled !== "boolean") throw lifecycleAdapterError("plugin_operation", "Copilot plugin enabled state must be boolean.");
249
+ const operation = enabled ? "enable" : "disable";
250
+ try {
251
+ const nativeOutput = runPluginPhase(exec, "copilot", ["plugin", operation, "agdf"], "plugin_operation", captureOptions());
252
+ const listOutput = runPluginPhase(exec, "copilot", ["plugin", "list"], "verification", captureOptions());
253
+ if (!pluginListHasPlugin(listOutput, "agdf") && !pluginListHasPlugin(listOutput, "agdf@agdf")) {
254
+ throw lifecycleAdapterError("verification", "AGDF was not present in copilot plugin list after the state change.");
255
+ }
256
+ return {
257
+ surface: "copilot",
258
+ requestedState: enabled ? "enabled" : "disabled",
259
+ status: "command_accepted_host_state_unverified",
260
+ evidence: [`copilot plugin ${operation} agdf`, "copilot plugin list", "fresh_session_required"],
261
+ nativeOutput: String(nativeOutput || ""),
262
+ };
263
+ } catch (error) {
264
+ if (/\bmanaged\b/i.test(commandErrorText(error))) {
265
+ return {
266
+ surface: "copilot", requestedState: enabled ? "enabled" : "disabled", status: "managed",
267
+ evidence: ["managed_policy_precedence", commandErrorText(error)], nativeOutput: "",
268
+ };
269
+ }
270
+ throw error;
271
+ }
272
+ }
273
+
96
274
  function migrateMarketplace({ surface, exec, output, root, nativeOutput, migration, refreshOwnedLocal = false }) {
97
275
  const classification = classifyMarketplaceList(surface, output, root);
98
276
  Object.assign(migration, classification);
@@ -176,10 +354,10 @@ function captureOptions() {
176
354
  }
177
355
 
178
356
  export function inspectPluginSurface(surface, exec = execFileSync, options = {}) {
179
- const executable = surface === "claude" ? "claude" : "codex";
180
- const pluginId = "agdf@agdf";
357
+ const executable = surface === "claude" ? "claude" : surface === "copilot" ? "copilot" : "codex";
181
358
  try {
182
359
  const output = exec(executable, ["plugin", "list"], { encoding: "utf8", stdio: "pipe" });
360
+ const pluginId = surface === "copilot" && !pluginListHasPlugin(output, "agdf@agdf") ? "agdf" : "agdf@agdf";
183
361
  const installed = pluginListHasPlugin(output, pluginId);
184
362
  const version = installed ? pluginVersionFromList(output, pluginId) : "";
185
363
  let localDevelopmentVersion = false;
@@ -227,12 +405,13 @@ function commandErrorText(error) {
227
405
  }
228
406
 
229
407
  export function pluginListHasPlugin(output, pluginId) {
408
+ const escapedPluginId = pluginId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
230
409
  return output
231
410
  .split(/\r?\n/)
232
- .some((line) => line.includes(pluginId));
411
+ .some((line) => new RegExp(`(^|\\s)${escapedPluginId}(\\s|$)`).test(line));
233
412
  }
234
413
 
235
- const VERSION_PATTERN = "(\\d+\\.\\d+\\.\\d+(?:[-+][0-9A-Za-z.-]+)?)";
414
+ const VERSION_PATTERN = "v?(\\d+\\.\\d+\\.\\d+(?:[-+][0-9A-Za-z.-]+)?)";
236
415
 
237
416
  export function pluginVersionFromList(output, pluginId) {
238
417
  const escapedPluginId = pluginId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -85,6 +85,9 @@ export function planGlobalUninstall(surface, { configDir } = {}) {
85
85
  if (surface === "claude") {
86
86
  return nativeUninstallPlan(surface, "claude", ["plugin", "uninstall", "agdf@agdf", "--scope", "user"]);
87
87
  }
88
+ if (surface === "copilot") {
89
+ return nativeUninstallPlan(surface, "copilot", ["plugin", "uninstall", "agdf"]);
90
+ }
88
91
  if (surface === "opencode") {
89
92
  if (!configDir) throw new Error("OpenCode uninstall requires its explicit config directory.");
90
93
  const configPath = join(configDir, "opencode.json");
@@ -5,6 +5,7 @@ const SURFACES = new Set(["codex", "claude", "copilot", "opencode", "generic"]);
5
5
  const GLOBAL_INSTALL_RESTART_ACTIONS = Object.freeze({
6
6
  codex: "Restart Codex.",
7
7
  claude: "Restart Claude Code.",
8
+ copilot: "Restart GitHub Copilot.",
8
9
  opencode: "Restart OpenCode.",
9
10
  });
10
11
 
@@ -63,7 +63,7 @@ function inspectInstallation(surface, targetDir, options, deps, exec) {
63
63
  evidence: [report.global_config.path],
64
64
  };
65
65
  }
66
- if (["codex", "claude"].includes(surface)) return deps.inspectPluginSurface(surface, exec);
66
+ if (["codex", "claude", "copilot"].includes(surface)) return deps.inspectPluginSurface(surface, exec);
67
67
  return { status: "unknown", surface, version: null, evidence: [`unsupported_status_probe:${surface}`] };
68
68
  }
69
69
 
@@ -79,7 +79,7 @@ export function evaluateGeneralStatus(targetDir, options = {}, dependencies = {}
79
79
  if (surface) {
80
80
  installation = inspectInstallation(surface, targetDir, options, deps, dependencies.exec);
81
81
  } else {
82
- const probes = ["codex", "claude", "opencode"].map((candidate) => inspectInstallation(candidate, targetDir, options, deps, dependencies.exec));
82
+ const probes = ["codex", "claude", "copilot", "opencode"].map((candidate) => inspectInstallation(candidate, targetDir, options, deps, dependencies.exec));
83
83
  const observed = probes.filter((probe) => ["healthy", "degraded"].includes(probe.status));
84
84
  if (observed.length === 1) {
85
85
  installation = observed[0];
@@ -96,7 +96,7 @@ export function evaluateGeneralStatus(targetDir, options = {}, dependencies = {}
96
96
  }
97
97
  const repository = repositoryStatus(targetDir, surface);
98
98
  const delivery = deliveryStatus(targetDir, { runId: options.runId }, deps);
99
- const runtimeChecks = ["codex", "claude", "opencode"].includes(surface)
99
+ const runtimeChecks = ["codex", "claude", "copilot", "opencode"].includes(surface)
100
100
  ? runtimeCheckStatus(options.dataRoot, surface)
101
101
  : { requested: "unknown", effective: "unavailable", reason: "unsupported_host_capability" };
102
102
  const nextText = surface === "multiple"