create-agdf 0.13.8 → 0.14.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.
- package/README.md +7 -9
- package/generated/plugins/agdf/.claude-plugin/plugin.json +1 -1
- package/generated/plugins/agdf/.codex-plugin/plugin.json +2 -4
- package/generated/plugins/agdf/hooks/copilot-hooks.json +15 -0
- package/generated/plugins/agdf/meta/agdf-plugin.definition.json +21 -2
- package/generated/plugins/agdf/plugin.json +22 -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 +21 -2
- package/generated/plugins/agdf/runtime/create-agdf/lib/cli/command-registry.js +6 -7
- 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 +31 -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/submissions/openai/agdf/.codex-plugin/plugin.json +1 -2
- package/generated/submissions/openai/agdf/meta/agdf-plugin.definition.json +21 -2
- package/generated/submissions/openai/agdf/submission/openai/availability.md +1 -1
- package/generated/submissions/openai/agdf/submission/openai/capability-matrix.json +1 -1
- package/generated/submissions/openai/agdf/submission/openai/inventory.json +9 -9
- package/generated/submissions/openai/agdf/submission/openai/listing.json +1 -1
- package/generated/submissions/openai/agdf/submission/openai/readiness.json +2 -2
- package/generated/submissions/openai/agdf/submission/openai/readiness.md +2 -2
- package/generated/submissions/openai/agdf/submission/openai/release-notes.md +1 -1
- package/generated/submissions/openai/agdf/submission/openai/reviewer-cases.json +1 -1
- package/lib/cli/application.js +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/plugin-installers.js +147 -4
- 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/manifest.js +34 -2
- package/lib/public-plugin/validator.js +1 -1
- package/lib/release/version-coherence.js +1 -0
- 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 +5 -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/AGENTS.md +0 -113
- /package/generated/{.github/skills → plugins/agdf/copilot-skills}/agdf-brownfield-analysis/SKILL.md +0 -0
- /package/generated/{.github/skills → plugins/agdf/copilot-skills}/agdf-clean-implementation-review/SKILL.md +0 -0
- /package/generated/{.github/skills → plugins/agdf/copilot-skills}/agdf-code-review/SKILL.md +0 -0
- /package/generated/{.github/skills → plugins/agdf/copilot-skills}/agdf-delivery-closeout/SKILL.md +0 -0
- /package/generated/{.github/skills → plugins/agdf/copilot-skills}/agdf-delivery-path-search/SKILL.md +0 -0
- /package/generated/{.github/skills → plugins/agdf/copilot-skills}/agdf-gate-check/SKILL.md +0 -0
- /package/generated/{.github/skills → plugins/agdf/copilot-skills}/agdf-interaction-locales.json +0 -0
- /package/generated/{.github/skills → plugins/agdf/copilot-skills}/agdf-qa-gate/SKILL.md +0 -0
- /package/generated/{.github/skills → plugins/agdf/copilot-skills}/agdf-release-or/SKILL.md +0 -0
- /package/generated/{.github/skills → plugins/agdf/copilot-skills}/agdf-runtime-contract.md +0 -0
- /package/generated/{.github/skills → plugins/agdf/copilot-skills}/agdf-task-plan-review/SKILL.md +0 -0
- /package/generated/{.github/skills → plugins/agdf/copilot-skills}/agdf-ux-intent-definition/SKILL.md +0 -0
- /package/generated/{.github/skills → plugins/agdf/copilot-skills}/contracts/closeout.md +0 -0
- /package/generated/{.github/skills → plugins/agdf/copilot-skills}/contracts/context-graph.md +0 -0
- /package/generated/{.github/skills → plugins/agdf/copilot-skills}/contracts/control-scaffold.md +0 -0
- /package/generated/{.github/skills → plugins/agdf/copilot-skills}/contracts/gate-transition.md +0 -0
- /package/generated/{.github/skills → plugins/agdf/copilot-skills}/contracts/interaction.md +0 -0
- /package/generated/{.github/skills → plugins/agdf/copilot-skills}/contracts/modes.md +0 -0
- /package/generated/{.github/skills → plugins/agdf/copilot-skills}/contracts/quality.md +0 -0
- /package/generated/{.github/skills → plugins/agdf/copilot-skills}/contracts/task-target-resolution.md +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"releaseVersion": "0.
|
|
4
|
-
"digest": "
|
|
3
|
+
"releaseVersion": "0.14.1",
|
|
4
|
+
"digest": "915aec01d7b4ba084bef25b8e772c70e27c31c89c5be111f549e793ec00395ad",
|
|
5
5
|
"files": [
|
|
6
6
|
{
|
|
7
7
|
"path": ".codex-plugin/plugin.json",
|
|
8
|
-
"sha256": "
|
|
8
|
+
"sha256": "235325cbcc2fff4e90d875df1e1fccb35c92e7c36cac2ded442983171376d7f8"
|
|
9
9
|
},
|
|
10
10
|
{
|
|
11
11
|
"path": "assets/agdf-icon.svg",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
},
|
|
30
30
|
{
|
|
31
31
|
"path": "meta/agdf-plugin.definition.json",
|
|
32
|
-
"sha256": "
|
|
32
|
+
"sha256": "6408fc6148f7c9579d5584924155402b98c2ffe68bd21c6048fb5b3169de671a"
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
35
|
"path": "meta/agdf-runtime-contract.md",
|
|
@@ -157,23 +157,23 @@
|
|
|
157
157
|
},
|
|
158
158
|
{
|
|
159
159
|
"path": "submission/openai/availability.md",
|
|
160
|
-
"sha256": "
|
|
160
|
+
"sha256": "fffc251c0d221ca99e0ac26d7a999efa5f5d6b369f006af515840c2540696956"
|
|
161
161
|
},
|
|
162
162
|
{
|
|
163
163
|
"path": "submission/openai/capability-matrix.json",
|
|
164
|
-
"sha256": "
|
|
164
|
+
"sha256": "98c4efb49f8ec4adc253ba82617539b6a7cd60951cdc1fb0201537c64cb45f56"
|
|
165
165
|
},
|
|
166
166
|
{
|
|
167
167
|
"path": "submission/openai/listing.json",
|
|
168
|
-
"sha256": "
|
|
168
|
+
"sha256": "61caa4b27640afcaf1741af96f5693fb1c70db5d9544bd7131a01d93d573441c"
|
|
169
169
|
},
|
|
170
170
|
{
|
|
171
171
|
"path": "submission/openai/release-notes.md",
|
|
172
|
-
"sha256": "
|
|
172
|
+
"sha256": "f05001114ea205666b6333ceaae2f0bd1df8d0c5ad462ec7dd922029640954f3"
|
|
173
173
|
},
|
|
174
174
|
{
|
|
175
175
|
"path": "submission/openai/reviewer-cases.json",
|
|
176
|
-
"sha256": "
|
|
176
|
+
"sha256": "f0a37d259eab3f2432ceb4a1f3d602f812f9b45bd063503679fa094de344046c"
|
|
177
177
|
}
|
|
178
178
|
]
|
|
179
179
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"releaseVersion": "0.
|
|
3
|
+
"releaseVersion": "0.14.1",
|
|
4
4
|
"candidateState": "repository_ready",
|
|
5
5
|
"submissionReady": false,
|
|
6
6
|
"submissionBlockers": [
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
},
|
|
17
17
|
"bundle": {
|
|
18
18
|
"state": "pass",
|
|
19
|
-
"detail": "43 inventoried files; inventory digest
|
|
19
|
+
"detail": "43 inventoried files; inventory digest 915aec01d7b4ba084bef25b8e772c70e27c31c89c5be111f549e793ec00395ad"
|
|
20
20
|
},
|
|
21
21
|
"installed_host": {
|
|
22
22
|
"state": "unverified",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# AGDF Public Plugin Readiness
|
|
2
2
|
|
|
3
|
-
- release: `0.
|
|
3
|
+
- release: `0.14.1`
|
|
4
4
|
- candidate_state: `repository_ready`
|
|
5
5
|
- submission_ready: `false`
|
|
6
6
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
| Class | State | Detail |
|
|
10
10
|
|---|---|---|
|
|
11
11
|
| repository | pass | canonical contract and deterministic source checks |
|
|
12
|
-
| bundle | pass | 43 inventoried files; inventory digest
|
|
12
|
+
| bundle | pass | 43 inventoried files; inventory digest 915aec01d7b4ba084bef25b8e772c70e27c31c89c5be111f549e793ec00395ad |
|
|
13
13
|
| installed_host | unverified | PPD-L02 and PPD-L03 not performed |
|
|
14
14
|
| portal | unverified | unverified |
|
|
15
15
|
| post_publication | unverified | not published |
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# AGDF 0.
|
|
1
|
+
# AGDF 0.14.1 — Initial OpenAI Public Plugin Candidate
|
|
2
2
|
|
|
3
3
|
This candidate packages the canonical AGDF workflow skills for public discovery in ChatGPT and
|
|
4
4
|
Codex. It helps users assess delivery fit, preserve explicit human approvals, inspect existing-system
|
package/lib/cli/application.js
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
} from "../installers/opencode.js";
|
|
18
18
|
import {
|
|
19
19
|
installClaudeGlobalPlugin,
|
|
20
|
+
installCopilotGlobalPlugin,
|
|
20
21
|
installCodexGlobalPlugin,
|
|
21
22
|
} from "../installers/plugin-installers.js";
|
|
22
23
|
import {
|
|
@@ -30,7 +31,7 @@ import { printGeneralStatus, printLifecycleResult } from "../lifecycle/presentat
|
|
|
30
31
|
import { createLifecycleResult, globalInstallRestartAction, lifecycleFailure } from "../lifecycle/result.js";
|
|
31
32
|
import { prepareInstallConsent, persistInstallConsent, retainCurrentInstallConsent, runtimeCheckStatus, setRuntimeChecksManual } from "../runtime-check-consent/service.js";
|
|
32
33
|
import { evaluateGeneralStatus } from "../lifecycle/status.js";
|
|
33
|
-
import {
|
|
34
|
+
import { generatedFilesForTarget } from "../scaffold/plan.js";
|
|
34
35
|
import { printNextSteps } from "../scaffold/presentation.js";
|
|
35
36
|
import { assertGeneratedWritePlan, writeGeneratedFile } from "../scaffold/write.js";
|
|
36
37
|
import { renderUsage, resolveCommand, validateCommandOptions } from "./command-registry.js";
|
|
@@ -38,19 +39,19 @@ import { CliUsageError, parseArgs } from "./parse-args.js";
|
|
|
38
39
|
import { pluginDefinition } from "./runtime-context.js";
|
|
39
40
|
import { createValidationHandlers } from "./validation-handlers.js";
|
|
40
41
|
|
|
41
|
-
function createHandlers({ io, env, exec, prepare, openCodePackageSource, askRuntimeCheckDecision, interactive }) {
|
|
42
|
+
function createHandlers({ io, env, exec, packagedCopilotExec, prepare, openCodePackageSource, copilotSettingsPath, askRuntimeCheckDecision, interactive }) {
|
|
42
43
|
const installerAdapters = {
|
|
43
44
|
...(exec ? { exec } : {}),
|
|
45
|
+
...(packagedCopilotExec ? { packagedCopilotExec } : {}),
|
|
44
46
|
...(prepare ? { prepare } : {}),
|
|
47
|
+
...(copilotSettingsPath ? { copilotSettingsPath } : {}),
|
|
45
48
|
...(env.AGDF_DATA_DIR ? { dataRoot: env.AGDF_DATA_DIR } : {}),
|
|
46
49
|
};
|
|
47
50
|
const scaffoldHandler = (options) => runScaffold(options, io);
|
|
48
51
|
return new Map([
|
|
49
52
|
...createValidationHandlers(io),
|
|
50
53
|
["codex-repo", scaffoldHandler],
|
|
51
|
-
["copilot", scaffoldHandler],
|
|
52
54
|
["opencode-repo", scaffoldHandler],
|
|
53
|
-
["both", scaffoldHandler],
|
|
54
55
|
["init", scaffoldHandler],
|
|
55
56
|
["config", scaffoldHandler],
|
|
56
57
|
["run-create", (options) => {
|
|
@@ -141,6 +142,56 @@ function createHandlers({ io, env, exec, prepare, openCodePackageSource, askRunt
|
|
|
141
142
|
return 1;
|
|
142
143
|
}
|
|
143
144
|
}],
|
|
145
|
+
["copilot", async (options) => {
|
|
146
|
+
const surface = "copilot";
|
|
147
|
+
try {
|
|
148
|
+
const consent = await installConsentDecision(surface, options, { io, askRuntimeCheckDecision, interactive, dataRoot: installerAdapters.dataRoot });
|
|
149
|
+
if (consent.decision === "cancel") return printCancelledConsent(surface, options, io);
|
|
150
|
+
printInstallProgress(surface, options, io, interactive);
|
|
151
|
+
const installed = installCopilotGlobalPlugin({
|
|
152
|
+
...installerAdapters,
|
|
153
|
+
});
|
|
154
|
+
const finalizedConsent = finalizeInstallConsent(consent, { surface, installed, dataRoot: installerAdapters.dataRoot });
|
|
155
|
+
if (installed.declarativeConfigured) {
|
|
156
|
+
printLifecycleResult(createLifecycleResult({
|
|
157
|
+
operation: "install", result: "partial", surface, scope: "global",
|
|
158
|
+
version: { expected: installed.expectedVersion, installed: null, status: "unknown" },
|
|
159
|
+
verification: { status: "configured_pending_restart", evidence: installed.evidence },
|
|
160
|
+
installation: { status: "configured_pending_restart" },
|
|
161
|
+
activation: { status: "pending_restart" },
|
|
162
|
+
runtime_checks: finalizedConsent.state,
|
|
163
|
+
restart: { required: true, reason: "host_reload" },
|
|
164
|
+
next_action: { kind: "restart", text: "Restart GitHub Copilot. Then verify AGDF in Plugins and the agdf- skills in a fresh session." },
|
|
165
|
+
}), { json: options.json, compact: !options.verbose, io });
|
|
166
|
+
return 0;
|
|
167
|
+
}
|
|
168
|
+
if (installed.manualHandoff) {
|
|
169
|
+
printLifecycleResult(createLifecycleResult({
|
|
170
|
+
operation: "install", result: "partial", surface, scope: "global",
|
|
171
|
+
version: { expected: installed.expectedVersion, installed: null, status: "unknown" },
|
|
172
|
+
verification: { status: "unavailable", evidence: installed.evidence },
|
|
173
|
+
installation: { status: "not_verified" },
|
|
174
|
+
activation: { status: "not_verified" },
|
|
175
|
+
runtime_checks: finalizedConsent.state,
|
|
176
|
+
restart: { required: false, reason: "none" },
|
|
177
|
+
next_action: { kind: "manual_install", text: `In GitHub Copilot, run /plugins install ${installed.pluginRoot}. Then run /restart and verify /plugins list and /skills list.` },
|
|
178
|
+
failure: { phase: "executable", message: "Copilot CLI was not available; no plugin installation was performed." },
|
|
179
|
+
}), { json: options.json, compact: !options.verbose, io });
|
|
180
|
+
return 1;
|
|
181
|
+
}
|
|
182
|
+
printLifecycleResult(installResult(installed, {
|
|
183
|
+
restartRequired: true,
|
|
184
|
+
nextAction: installNextAction(surface, finalizedConsent.state, globalInstallRestartAction(surface).text),
|
|
185
|
+
runtimeChecks: finalizedConsent.state,
|
|
186
|
+
consentFailure: finalizedConsent.failure,
|
|
187
|
+
}), { json: options.json, compact: !options.verbose, io });
|
|
188
|
+
printVerboseHostOutput(installed, options, io);
|
|
189
|
+
return installed.verificationStatus === "healthy" ? 0 : 1;
|
|
190
|
+
} catch (error) {
|
|
191
|
+
printInstallFailure(surface, error, options, io, "copilot");
|
|
192
|
+
return 1;
|
|
193
|
+
}
|
|
194
|
+
}],
|
|
144
195
|
["opencode", async (options) => {
|
|
145
196
|
const configDir = options.dirExplicit ? options.dir : defaultOpenCodeConfigDir();
|
|
146
197
|
try {
|
|
@@ -230,6 +281,9 @@ function installNextAction(surface, runtimeChecks, fallback) {
|
|
|
230
281
|
if (surface === "codex" && runtimeChecks.requested === "enabled" && runtimeChecks.effective === "decision_required") {
|
|
231
282
|
return "Restart Codex, then approve the AGDF session hook when Codex asks.";
|
|
232
283
|
}
|
|
284
|
+
if (surface === "copilot" && runtimeChecks.requested === "enabled" && runtimeChecks.effective === "decision_required") {
|
|
285
|
+
return "Restart GitHub Copilot, then review the AGDF session hook when Copilot asks.";
|
|
286
|
+
}
|
|
233
287
|
return fallback;
|
|
234
288
|
}
|
|
235
289
|
|
|
@@ -313,6 +367,7 @@ function printInstallConsentDisclosure(disclosure, retained, io) {
|
|
|
313
367
|
|
|
314
368
|
function installSurfaceLabel(surface) {
|
|
315
369
|
if (surface === "claude") return "Claude Code";
|
|
370
|
+
if (surface === "copilot") return "GitHub Copilot";
|
|
316
371
|
if (surface === "opencode") return "OpenCode";
|
|
317
372
|
return "Codex";
|
|
318
373
|
}
|
|
@@ -356,7 +411,7 @@ function printVerboseHostOutput(installed, options, io) {
|
|
|
356
411
|
for (const output of installed.nativeOutput) io.log(output);
|
|
357
412
|
}
|
|
358
413
|
|
|
359
|
-
function printInstallFailure(surface, error, options, io) {
|
|
414
|
+
function printInstallFailure(surface, error, options, io, command = surface) {
|
|
360
415
|
const report = lifecycleFailure({
|
|
361
416
|
operation: "install",
|
|
362
417
|
surface,
|
|
@@ -364,7 +419,7 @@ function printInstallFailure(surface, error, options, io) {
|
|
|
364
419
|
phase: error.phase || "plugin_operation",
|
|
365
420
|
message: error.message,
|
|
366
421
|
evidence: [error.evidence ?? {}],
|
|
367
|
-
nextAction: `Resolve the ${error.phase || "plugin operation"} failure and rerun npx --yes @agdf/cli@latest ${
|
|
422
|
+
nextAction: `Resolve the ${error.phase || "plugin operation"} failure and rerun npx --yes @agdf/cli@latest ${command}.`,
|
|
368
423
|
});
|
|
369
424
|
if (options.json) printLifecycleResult(report, { json: true, io });
|
|
370
425
|
else {
|
|
@@ -445,7 +500,6 @@ function runUninstall(options, { io, env, exec }) {
|
|
|
445
500
|
|
|
446
501
|
function runScaffold(options, io) {
|
|
447
502
|
const files = generatedFilesForTarget(options.target, options.dir, options.force, options.language);
|
|
448
|
-
const wroteAgentsFragment = files.some((file) => file.path === agdfFragmentPath);
|
|
449
503
|
let removedOpenCodeAgents = [];
|
|
450
504
|
|
|
451
505
|
try {
|
|
@@ -460,7 +514,7 @@ function runScaffold(options, io) {
|
|
|
460
514
|
return 1;
|
|
461
515
|
}
|
|
462
516
|
|
|
463
|
-
printNextSteps(options.target, options.dir, files,
|
|
517
|
+
printNextSteps(options.target, options.dir, files, removedOpenCodeAgents, { verbose: options.verbose, json: options.json, io });
|
|
464
518
|
return 0;
|
|
465
519
|
}
|
|
466
520
|
|
|
@@ -500,8 +554,10 @@ export async function runCli(argv = process.argv.slice(2), adapters = {}) {
|
|
|
500
554
|
io,
|
|
501
555
|
env,
|
|
502
556
|
exec: adapters.exec,
|
|
557
|
+
packagedCopilotExec: adapters.packagedCopilotExec,
|
|
503
558
|
prepare: adapters.prepare,
|
|
504
559
|
openCodePackageSource: adapters.openCodePackageSource,
|
|
560
|
+
copilotSettingsPath: adapters.copilotSettingsPath,
|
|
505
561
|
askRuntimeCheckDecision: adapters.askRuntimeCheckDecision ?? defaultAskRuntimeCheckDecision,
|
|
506
562
|
interactive: adapters.interactive ?? (Boolean(process.stdin.isTTY) && Boolean(process.stdout.isTTY)),
|
|
507
563
|
}).get(command.handler);
|
|
@@ -13,15 +13,14 @@ export const commandRegistry = Object.freeze([
|
|
|
13
13
|
command("codex", { preferred: [""], scaffold: [""] }),
|
|
14
14
|
command("codex-repo", { preferred: [""], scaffold: [""] }),
|
|
15
15
|
command("claude", { preferred: [""], scaffold: [""] }),
|
|
16
|
-
command("copilot", { preferred: [""]
|
|
16
|
+
command("copilot", { preferred: [""] }),
|
|
17
17
|
command("opencode", { preferred: [""], scaffold: [""] }),
|
|
18
18
|
command("opencode-status", { preferred: [""], scaffold: [""] }),
|
|
19
19
|
command("status", { preferred: [" [--surface <surface>] [--run <run_id>] [--json]"] }),
|
|
20
|
-
command("runtime-checks", { preferred: [" <status|enable|manual> --surface <codex|claude|opencode> [--json]"] }),
|
|
20
|
+
command("runtime-checks", { preferred: [" <status|enable|manual> --surface <codex|claude|copilot|opencode> [--json]"] }),
|
|
21
21
|
command("disable", { preferred: [" --surface <surface> [--scope repository] [--dir <path>]"] }),
|
|
22
22
|
command("uninstall", { preferred: [" --surface <surface> --scope global [--confirm]"] }),
|
|
23
23
|
command("opencode-repo", { preferred: [""], scaffold: [""] }),
|
|
24
|
-
command("both", { scaffold: [""] }),
|
|
25
24
|
command("init", { preferred: [""], scaffold: [""] }),
|
|
26
25
|
command("config", { scaffold: [" --language de"] }),
|
|
27
26
|
command("doctor", { local: [""], scaffold: [""], legacy: [" --json"] }),
|
|
@@ -66,11 +65,11 @@ export function validateCommandOptions(options) {
|
|
|
66
65
|
throw new Error("uninstall requires explicit --scope global");
|
|
67
66
|
}
|
|
68
67
|
if (options.confirm && options.target !== "uninstall") throw new Error("--confirm is supported only by uninstall");
|
|
69
|
-
if (options.runtimeChecksDecision && !["codex", "claude", "opencode"].includes(options.target)) {
|
|
70
|
-
throw new Error("--runtime-checks is supported only by codex, claude and opencode installation commands");
|
|
68
|
+
if (options.runtimeChecksDecision && !["codex", "claude", "copilot", "opencode"].includes(options.target)) {
|
|
69
|
+
throw new Error("--runtime-checks is supported only by codex, claude, copilot and opencode installation commands");
|
|
71
70
|
}
|
|
72
|
-
if (options.target === "runtime-checks" && !["codex", "claude", "opencode"].includes(options.surface)) {
|
|
73
|
-
throw new Error("runtime-checks requires --surface codex, claude or opencode");
|
|
71
|
+
if (options.target === "runtime-checks" && !["codex", "claude", "copilot", "opencode"].includes(options.surface)) {
|
|
72
|
+
throw new Error("runtime-checks requires --surface codex, claude, copilot or opencode");
|
|
74
73
|
}
|
|
75
74
|
if (options.approvalEnvelope && options.target !== "gate-check") throw new Error("--approval-envelope is supported only by gate-check");
|
|
76
75
|
if (options.approvalEnvelope && (options.json || options.statusCard || options.allActive)) {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
function skillNames(values, field) {
|
|
2
|
+
if (!Array.isArray(values) || values.some((value) => typeof value !== "string" || !value.trim())) {
|
|
3
|
+
throw new Error(`AGDF_COPILOT_PRECEDENCE_INVALID: ${field}`);
|
|
4
|
+
}
|
|
5
|
+
const normalized = values.map((value) => value.trim());
|
|
6
|
+
if (new Set(normalized).size !== normalized.length) throw new Error(`AGDF_COPILOT_PRECEDENCE_DUPLICATE: ${field}`);
|
|
7
|
+
return new Set(normalized);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function diagnoseCopilotSkillPrecedence({ declaredPluginSkills, projectSkills = [], personalSkills = [] } = {}) {
|
|
11
|
+
const plugin = skillNames(declaredPluginSkills, "declaredPluginSkills");
|
|
12
|
+
const project = skillNames(projectSkills, "projectSkills");
|
|
13
|
+
const personal = skillNames(personalSkills, "personalSkills");
|
|
14
|
+
const skills = [...plugin].sort().map((name) => {
|
|
15
|
+
const projectMatch = project.has(name);
|
|
16
|
+
const personalMatch = personal.has(name);
|
|
17
|
+
return Object.freeze({
|
|
18
|
+
name,
|
|
19
|
+
effective_source: projectMatch ? "project" : personalMatch ? "personal" : "plugin",
|
|
20
|
+
plugin_loaded: !projectMatch && !personalMatch,
|
|
21
|
+
collisions: Object.freeze([
|
|
22
|
+
...(projectMatch ? ["project"] : []),
|
|
23
|
+
...(personalMatch ? ["personal"] : []),
|
|
24
|
+
]),
|
|
25
|
+
mutation: "none",
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
return Object.freeze({
|
|
29
|
+
schema_version: 1,
|
|
30
|
+
precedence: Object.freeze(["project", "personal", "plugin"]),
|
|
31
|
+
skills: Object.freeze(skills),
|
|
32
|
+
destructive_override: false,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { chmodSync, existsSync, lstatSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
import { renameSyncWithRetry } from "../fs-swap.js";
|
|
6
|
+
|
|
7
|
+
export function defaultCopilotSettingsPath({ env = process.env, home = homedir() } = {}) {
|
|
8
|
+
return join(resolve(env.COPILOT_HOME || join(home, ".copilot")), "settings.json");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function readCopilotSettings(path = defaultCopilotSettingsPath()) {
|
|
12
|
+
if (!existsSync(path)) return { exists: false, settings: {} };
|
|
13
|
+
const stats = lstatSync(path);
|
|
14
|
+
if (!stats.isFile() || stats.isSymbolicLink()) throw new Error("AGDF_COPILOT_SETTINGS_UNOWNED_PATH");
|
|
15
|
+
try {
|
|
16
|
+
const settings = JSON.parse(readFileSync(path, "utf8"));
|
|
17
|
+
if (!settings || typeof settings !== "object" || Array.isArray(settings)) throw new Error("not an object");
|
|
18
|
+
if (settings.enabledPlugins !== undefined
|
|
19
|
+
&& (!settings.enabledPlugins || typeof settings.enabledPlugins !== "object" || Array.isArray(settings.enabledPlugins))) {
|
|
20
|
+
throw new Error("enabledPlugins must be an object");
|
|
21
|
+
}
|
|
22
|
+
return { exists: true, settings };
|
|
23
|
+
} catch (error) {
|
|
24
|
+
throw new Error(`AGDF_COPILOT_SETTINGS_INVALID: ${error.message}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function atomicSettingsWrite(path, settings) {
|
|
29
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
30
|
+
const temp = `${path}.agdf-tmp-${process.pid}`;
|
|
31
|
+
const backup = `${path}.agdf-backup-${process.pid}`;
|
|
32
|
+
const hadPrevious = existsSync(path);
|
|
33
|
+
const mode = hadPrevious ? lstatSync(path).mode & 0o777 : 0o600;
|
|
34
|
+
writeFileSync(temp, `${JSON.stringify(settings, null, 2)}\n`, { encoding: "utf8", flag: "wx", mode });
|
|
35
|
+
if (process.platform !== "win32") chmodSync(temp, mode);
|
|
36
|
+
try {
|
|
37
|
+
if (hadPrevious && process.platform === "win32") renameSyncWithRetry(path, backup);
|
|
38
|
+
renameSyncWithRetry(temp, path);
|
|
39
|
+
if (hadPrevious && process.platform === "win32") rmSync(backup, { force: true });
|
|
40
|
+
} catch (error) {
|
|
41
|
+
try { rmSync(temp, { force: true }); } catch {}
|
|
42
|
+
if (hadPrevious && process.platform === "win32" && existsSync(backup) && !existsSync(path)) renameSyncWithRetry(backup, path);
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function configureCopilotDeclarativePlugin({ path = defaultCopilotSettingsPath(), pluginRoot }) {
|
|
48
|
+
if (typeof pluginRoot !== "string" || !pluginRoot.trim() || !isAbsolute(pluginRoot)) {
|
|
49
|
+
throw new Error("AGDF_COPILOT_PLUGIN_SPEC_INVALID");
|
|
50
|
+
}
|
|
51
|
+
const spec = resolve(pluginRoot);
|
|
52
|
+
if (!existsSync(spec) || !lstatSync(spec).isDirectory() || lstatSync(spec).isSymbolicLink()) {
|
|
53
|
+
throw new Error("AGDF_COPILOT_PLUGIN_SPEC_UNAVAILABLE");
|
|
54
|
+
}
|
|
55
|
+
const before = readCopilotSettings(path);
|
|
56
|
+
const next = structuredClone(before.settings);
|
|
57
|
+
next.enabledPlugins = { ...(next.enabledPlugins ?? {}), [spec]: true };
|
|
58
|
+
atomicSettingsWrite(path, next);
|
|
59
|
+
const verified = readCopilotSettings(path);
|
|
60
|
+
if (verified.settings.enabledPlugins?.[spec] !== true) throw new Error("AGDF_COPILOT_SETTINGS_VERIFICATION_FAILED");
|
|
61
|
+
return {
|
|
62
|
+
status: "configured_pending_restart",
|
|
63
|
+
reason: "host_activation_unverified",
|
|
64
|
+
path,
|
|
65
|
+
spec,
|
|
66
|
+
rollback() {
|
|
67
|
+
if (before.exists) atomicSettingsWrite(path, before.settings);
|
|
68
|
+
else rmSync(path, { force: true });
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function revokeCopilotDeclarativePlugin({ path = defaultCopilotSettingsPath(), pluginRoot }) {
|
|
74
|
+
const before = readCopilotSettings(path);
|
|
75
|
+
if (!before.exists) return { status: "not_configured", path };
|
|
76
|
+
const spec = resolve(pluginRoot);
|
|
77
|
+
const next = structuredClone(before.settings);
|
|
78
|
+
if (next.enabledPlugins && Object.hasOwn(next.enabledPlugins, spec)) {
|
|
79
|
+
delete next.enabledPlugins[spec];
|
|
80
|
+
if (Object.keys(next.enabledPlugins).length === 0) delete next.enabledPlugins;
|
|
81
|
+
atomicSettingsWrite(path, next);
|
|
82
|
+
}
|
|
83
|
+
return { status: "removed", path, spec };
|
|
84
|
+
}
|
|
@@ -1,7 +1,13 @@
|
|
|
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";
|
|
6
|
+
import { digestNormalizedPluginSource } from "../runtime/plugin-provenance.js";
|
|
3
7
|
import { CODEX_REGISTRATION_REVISION, classifyMarketplaceList, inspectLocalMarketplaceProjection, isCodexLocalInstallVersion, prepareLocalMarketplace } from "./local-marketplace.js";
|
|
4
8
|
|
|
9
|
+
export const COPILOT_CLI_NPM_PACKAGE = "@github/copilot@1.0.80";
|
|
10
|
+
|
|
5
11
|
export function installCodexGlobalPlugin({ exec = execFileSync, prepare = prepareLocalMarketplace, dataRoot } = {}) {
|
|
6
12
|
const expectedVersion = pluginDefinition.version;
|
|
7
13
|
const nativeOutput = [];
|
|
@@ -93,6 +99,142 @@ export function installClaudeGlobalPlugin({ exec = execFileSync, prepare = prepa
|
|
|
93
99
|
}
|
|
94
100
|
}
|
|
95
101
|
|
|
102
|
+
export function installCopilotGlobalPlugin({ exec = execFileSync, packagedCopilotExec = execFileSync, prepare = prepareLocalMarketplace, 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 marketplaceAdded = false;
|
|
143
|
+
let directRemoved = false;
|
|
144
|
+
try {
|
|
145
|
+
const nativeOutput = [];
|
|
146
|
+
const marketplaceOutput = runPluginPhase(activeExec, "copilot", ["plugin", "marketplace", "list"], "marketplace", captureOptions());
|
|
147
|
+
const marketplace = classifyCopilotMarketplaceList(marketplaceOutput, transaction?.root ?? resolve(effectivePluginRoot, "..", ".."));
|
|
148
|
+
if (marketplace.state === "conflict") {
|
|
149
|
+
throw lifecycleAdapterError("marketplace", `Refusing to replace non-AGDF Copilot marketplace registration agdf (${marketplace.source || "unknown source"}).`);
|
|
150
|
+
}
|
|
151
|
+
if (marketplace.state === "absent") {
|
|
152
|
+
nativeOutput.push(runPluginPhase(activeExec, "copilot", ["plugin", "marketplace", "add", transaction?.root ?? resolve(effectivePluginRoot, "..", "..")], "marketplace", captureOptions()));
|
|
153
|
+
marketplaceAdded = true;
|
|
154
|
+
}
|
|
155
|
+
if (directInstalled) {
|
|
156
|
+
nativeOutput.push(runPluginPhase(activeExec, "copilot", ["plugin", "uninstall", "agdf"], "plugin_operation", captureOptions()));
|
|
157
|
+
directRemoved = true;
|
|
158
|
+
}
|
|
159
|
+
nativeOutput.push(runPluginPhase(activeExec, "copilot", ["plugin", "install", "agdf@agdf"], "plugin_operation", captureOptions()));
|
|
160
|
+
const after = runPluginPhase(activeExec, "copilot", ["plugin", "list"], "verification", captureOptions());
|
|
161
|
+
const installed = pluginListHasPlugin(after, "agdf@agdf");
|
|
162
|
+
const installedVersion = installed ? pluginVersionFromList(after, "agdf@agdf") : "";
|
|
163
|
+
if (!installed) throw lifecycleAdapterError("verification", "AGDF was not present in copilot plugin list after installation.");
|
|
164
|
+
if (installedVersion && installedVersion !== expectedVersion) {
|
|
165
|
+
throw lifecycleAdapterError("version", versionMismatchMessage("GitHub Copilot", "agdf", expectedVersion, installedVersion, "npx --yes @agdf/cli@latest copilot"));
|
|
166
|
+
}
|
|
167
|
+
transaction?.commit();
|
|
168
|
+
return {
|
|
169
|
+
surface: "copilot", operation: directInstalled || marketplaceInstalled ? "update" : "install", expectedVersion,
|
|
170
|
+
installedVersion: installedVersion || null, verificationStatus: installedVersion ? "healthy" : "degraded",
|
|
171
|
+
manualHandoff: false,
|
|
172
|
+
evidence: [...bootstrapEvidence, "durable_local_plugin_stage", "copilot plugin marketplace list", ...(marketplaceAdded ? ["copilot plugin marketplace add"] : ["marketplace:owned_local_current"]), ...(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"])],
|
|
173
|
+
pluginRoot: effectivePluginRoot, runtimeDigest: runtimeManifest.digest, sourceDigest, nativeOutput: nativeOutput.filter(Boolean).map(String),
|
|
174
|
+
};
|
|
175
|
+
} catch (error) {
|
|
176
|
+
transaction?.rollback();
|
|
177
|
+
if (directRemoved) {
|
|
178
|
+
try {
|
|
179
|
+
activeExec("copilot", ["plugin", "install", effectivePluginRoot], captureOptions());
|
|
180
|
+
} catch (recoveryError) {
|
|
181
|
+
error.evidence = { ...(error.evidence ?? {}), direct_install_recovery: commandErrorText(recoveryError) };
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (marketplaceAdded) {
|
|
185
|
+
try {
|
|
186
|
+
activeExec("copilot", ["plugin", "marketplace", "remove", "agdf"], captureOptions());
|
|
187
|
+
} catch (recoveryError) {
|
|
188
|
+
error.evidence = { ...(error.evidence ?? {}), marketplace_recovery: commandErrorText(recoveryError) };
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
throw error;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export function classifyCopilotMarketplaceList(output, expectedRoot) {
|
|
196
|
+
const line = String(output || "").split(/\r?\n/).find((entry) => /^\s*[◆•]?\s*agdf\s+\(/.test(entry));
|
|
197
|
+
if (!line) return { state: "absent", source: "" };
|
|
198
|
+
const local = line.match(/\(Local:\s*(.+)\)\s*$/);
|
|
199
|
+
if (!local) return { state: "conflict", source: line.trim() };
|
|
200
|
+
return resolve(local[1]) === resolve(expectedRoot)
|
|
201
|
+
? { state: "owned_local_current", source: local[1] }
|
|
202
|
+
: { state: "conflict", source: local[1] };
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export function copilotNpmInvocation({ env = process.env, platform = process.platform, execPath = process.execPath } = {}) {
|
|
206
|
+
const args = ["exec", "--yes", `--package=${COPILOT_CLI_NPM_PACKAGE}`, "--", "copilot"];
|
|
207
|
+
if (env.npm_execpath) return { executable: execPath, args: [env.npm_execpath, ...args] };
|
|
208
|
+
return { executable: platform === "win32" ? "npm.cmd" : "npm", args };
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export function setCopilotPluginEnabled({ enabled, exec = execFileSync } = {}) {
|
|
212
|
+
if (typeof enabled !== "boolean") throw lifecycleAdapterError("plugin_operation", "Copilot plugin enabled state must be boolean.");
|
|
213
|
+
const operation = enabled ? "enable" : "disable";
|
|
214
|
+
try {
|
|
215
|
+
const nativeOutput = runPluginPhase(exec, "copilot", ["plugin", operation, "agdf"], "plugin_operation", captureOptions());
|
|
216
|
+
const listOutput = runPluginPhase(exec, "copilot", ["plugin", "list"], "verification", captureOptions());
|
|
217
|
+
if (!pluginListHasPlugin(listOutput, "agdf") && !pluginListHasPlugin(listOutput, "agdf@agdf")) {
|
|
218
|
+
throw lifecycleAdapterError("verification", "AGDF was not present in copilot plugin list after the state change.");
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
surface: "copilot",
|
|
222
|
+
requestedState: enabled ? "enabled" : "disabled",
|
|
223
|
+
status: "command_accepted_host_state_unverified",
|
|
224
|
+
evidence: [`copilot plugin ${operation} agdf`, "copilot plugin list", "fresh_session_required"],
|
|
225
|
+
nativeOutput: String(nativeOutput || ""),
|
|
226
|
+
};
|
|
227
|
+
} catch (error) {
|
|
228
|
+
if (/\bmanaged\b/i.test(commandErrorText(error))) {
|
|
229
|
+
return {
|
|
230
|
+
surface: "copilot", requestedState: enabled ? "enabled" : "disabled", status: "managed",
|
|
231
|
+
evidence: ["managed_policy_precedence", commandErrorText(error)], nativeOutput: "",
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
throw error;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
96
238
|
function migrateMarketplace({ surface, exec, output, root, nativeOutput, migration, refreshOwnedLocal = false }) {
|
|
97
239
|
const classification = classifyMarketplaceList(surface, output, root);
|
|
98
240
|
Object.assign(migration, classification);
|
|
@@ -176,10 +318,10 @@ function captureOptions() {
|
|
|
176
318
|
}
|
|
177
319
|
|
|
178
320
|
export function inspectPluginSurface(surface, exec = execFileSync, options = {}) {
|
|
179
|
-
const executable = surface === "claude" ? "claude" : "codex";
|
|
180
|
-
const pluginId = "agdf@agdf";
|
|
321
|
+
const executable = surface === "claude" ? "claude" : surface === "copilot" ? "copilot" : "codex";
|
|
181
322
|
try {
|
|
182
323
|
const output = exec(executable, ["plugin", "list"], { encoding: "utf8", stdio: "pipe" });
|
|
324
|
+
const pluginId = surface === "copilot" && !pluginListHasPlugin(output, "agdf@agdf") ? "agdf" : "agdf@agdf";
|
|
183
325
|
const installed = pluginListHasPlugin(output, pluginId);
|
|
184
326
|
const version = installed ? pluginVersionFromList(output, pluginId) : "";
|
|
185
327
|
let localDevelopmentVersion = false;
|
|
@@ -227,12 +369,13 @@ function commandErrorText(error) {
|
|
|
227
369
|
}
|
|
228
370
|
|
|
229
371
|
export function pluginListHasPlugin(output, pluginId) {
|
|
372
|
+
const escapedPluginId = pluginId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
230
373
|
return output
|
|
231
374
|
.split(/\r?\n/)
|
|
232
|
-
.some((line) =>
|
|
375
|
+
.some((line) => new RegExp(`(^|\\s)${escapedPluginId}(\\s|$)`).test(line));
|
|
233
376
|
}
|
|
234
377
|
|
|
235
|
-
const VERSION_PATTERN = "(\\d+\\.\\d+\\.\\d+(?:[-+][0-9A-Za-z.-]+)?)";
|
|
378
|
+
const VERSION_PATTERN = "v?(\\d+\\.\\d+\\.\\d+(?:[-+][0-9A-Za-z.-]+)?)";
|
|
236
379
|
|
|
237
380
|
export function pluginVersionFromList(output, pluginId) {
|
|
238
381
|
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");
|
package/lib/lifecycle/result.js
CHANGED
|
@@ -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
|
|