create-agdf 0.9.3 → 0.9.6

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 CHANGED
@@ -21,7 +21,7 @@ Use a different target when Codex is not your agent surface:
21
21
  | Claude Code | `npx --yes @agdf/cli@latest claude` | The AGDF plugin for Claude Code. |
22
22
  | OpenCode, user-wide discovery | `npx --yes @agdf/cli@latest opencode` | The npm plugin and global native skills; repository governance remains opt-in. |
23
23
  | OpenCode, one repository | `npx --yes @agdf/cli@latest opencode-repo` | Repository instructions, native skills, permissions and control templates. |
24
- | GitHub Copilot | `npm create agdf@latest -- copilot` | Repository instructions, visible skills and control templates. |
24
+ | GitHub Copilot | `npx --yes @agdf/cli@latest copilot` | Repository instructions, visible skills and control templates. |
25
25
  | Durable control state in an existing setup | `npx --yes @agdf/cli@latest init` | Live `.agdf/control/` state when the repository explicitly needs it. |
26
26
 
27
27
  For prerequisites, all surface-specific flows and operational boundaries, use the authoritative [installation guide](../INSTALL.md). Do not run `init` merely to ask a fresh question: an agent can first clarify the request and ask for `Approval: UR` when durable control state is needed.
@@ -39,6 +39,9 @@ npx --yes @agdf/cli@latest claude
39
39
  npx --yes @agdf/cli@latest opencode
40
40
  npx --yes @agdf/cli@latest opencode-status
41
41
  npx --yes @agdf/cli@latest opencode-repo
42
+ npx --yes @agdf/cli@latest status --surface codex
43
+ npx --yes @agdf/cli@latest disable --surface codex --scope repository
44
+ npx --yes @agdf/cli@latest uninstall --surface codex --scope global
42
45
  npx --yes @agdf/cli@latest init
43
46
  npx --yes @agdf/cli@latest config --language en
44
47
  npx --yes @agdf/cli@latest doctor
@@ -62,6 +65,8 @@ npx --yes @agdf/cli@latest run-migrate [--run <run_id>]
62
65
  npx --yes @agdf/cli@latest run-render-legacy --run <run_id>
63
66
  ```
64
67
 
68
+ ### Advanced / Compatibility
69
+
65
70
  Backward-compatible scaffold usage:
66
71
 
67
72
  ```bash
@@ -87,6 +92,8 @@ Optional flags:
87
92
  - `--dir <path>` write into a specific directory
88
93
  - `--force` overwrite existing generated files
89
94
  - `--language <tag>` or `--lang <tag>` persist a BCP 47 language tag such as `de`, `en` or `fr-CA`
95
+ - `--scope <repository|global>` select an explicit lifecycle mutation scope
96
+ - `--confirm` apply a global uninstall after reviewing the default non-mutating preview
90
97
 
91
98
  If no language is provided, `create-agdf` derives the preference from the local system locale (`LC_ALL`, `LC_MESSAGES`, `LANG`, `LANGUAGE` or the Node.js runtime locale) and falls back to `en`.
92
99
 
@@ -98,6 +105,9 @@ If no language is provided, `create-agdf` derives the preference from the local
98
105
  - `copilot` writes `AGENTS.md`, Copilot custom instructions under `.github/`, visible repository skills under `.github/skills/`, and AGDF control templates under `.agdf/control/`
99
106
  - `opencode` installs the AGDF npm plugin and nine native skills as a user-wide OpenCode surface
100
107
  - `opencode-status` reports OpenCode global config, package loadability, global native-skill completeness, session signals and repository surface presence
108
+ - `status` reports installation, repository activation and delivery separately without mutating state
109
+ - `disable` writes a supported repository-local opt-out while retaining global capability and durable control state
110
+ - `uninstall` previews and, only with `--confirm`, applies a selected global removal through supported native/owned operations
101
111
  - `opencode-repo` writes `opencode.json`, `.opencode/AGDF.md`, prefixed native OpenCode skills under `.opencode/skills/`, explicit question/edit/bash/skill permissions, and AGDF control templates under `.agdf/control/`
102
112
  - `both` writes the Codex repository-local marketplace plus the Copilot-facing repository files
103
113
  - `config` writes or updates only `.agdf/control/config.json` for an already installed plugin or an existing repository
@@ -64,6 +64,11 @@ Use the Runtime Contract's Native Interaction Contract to classify every candida
64
64
 
65
65
  Prefer inspection over asking. Do not invoke a structured question for status reporting, facts available in the repository, routine read-only work or a gate that is not ready. Do not repeatedly prompt for the same non-ready gate.
66
66
 
67
+ For a fresh request classified as read-only with no required run decision, emit the locale pack's
68
+ `primary.readOnlyOrientationDescription` sentence once before the findings. This path creates no run, persists
69
+ nothing, requests no approval and reuses the existing status projection. Do not repeat the sentence
70
+ during the same request.
71
+
67
72
  For a ready `gate_approval`:
68
73
 
69
74
  1. Resolve exactly one selected run and evaluate the current gate.
@@ -109,6 +109,24 @@
109
109
  "notYetCreated": "not yet created"
110
110
  },
111
111
  "primary": {
112
+ "readOnlyOrientationDescription": "Read-only check — no new AGDF run and no approval required.",
113
+ "lifecycleResult": {
114
+ "title": "AGDF lifecycle result",
115
+ "statusTitle": "AGDF status",
116
+ "result": "Result",
117
+ "surface": "Surface",
118
+ "scope": "Installation scope",
119
+ "version": "AGDF version",
120
+ "verification": "Verification",
121
+ "restart": "Restart required",
122
+ "installation": "Installation",
123
+ "repository": "Repository",
124
+ "delivery": "Delivery",
125
+ "next": "Next action",
126
+ "yes": "yes",
127
+ "no": "no",
128
+ "unknown": "unknown"
129
+ },
112
130
  "status": {
113
131
  "open": "open",
114
132
  "blocked": "blocked",
@@ -278,6 +296,24 @@
278
296
  "notYetCreated": "noch nicht erstellt"
279
297
  },
280
298
  "primary": {
299
+ "readOnlyOrientationDescription": "Read-only Prüfung – kein neuer AGDF-Run und keine Freigabe erforderlich.",
300
+ "lifecycleResult": {
301
+ "title": "AGDF-Lifecycle-Ergebnis",
302
+ "statusTitle": "AGDF-Status",
303
+ "result": "Ergebnis",
304
+ "surface": "Oberfläche",
305
+ "scope": "Installationsscope",
306
+ "version": "AGDF-Version",
307
+ "verification": "Verifikation",
308
+ "restart": "Neustart erforderlich",
309
+ "installation": "Installation",
310
+ "repository": "Repository",
311
+ "delivery": "Delivery",
312
+ "next": "Nächste Aktion",
313
+ "yes": "ja",
314
+ "no": "nein",
315
+ "unknown": "unbekannt"
316
+ },
281
317
  "status": {
282
318
  "open": "offen",
283
319
  "blocked": "blockiert",
@@ -274,6 +274,15 @@ Surface adapter rules:
274
274
 
275
275
  Native structured questions are for real decision points. Prefer repository inspection over clarification and do not show them for status reporting, discoverable facts, routine read-only work or repeated non-ready gate prompts.
276
276
 
277
+ ### Read-only request orientation
278
+
279
+ For a newly classified read-only request that does not require a run decision, render the localized
280
+ `primary.readOnlyOrientationDescription` sentence exactly once before the findings. This is a visible
281
+ orientation, not durable state: do not create a run, write control files, request gate approval or
282
+ repeat the sentence later in the same request. Existing-run status inspection remains read-only and
283
+ uses the existing status projection; this branch must not create a second status-card or narration
284
+ owner.
285
+
277
286
  Exact textual approvals remain canonical and fully supported on every surface. If native capability availability or safety is unknown, use the textual fallback. Host permission, plan approval, native question presentation, timeout/default behavior, hook output and agent messages never carry AGDF gate authority by themselves.
278
287
 
279
288
  ### Interaction Locale Contract
@@ -367,4 +376,3 @@ Missing input, timeout, cancellation and empty input are not decline. Only
367
376
  `approve` backed by the exact revalidated `Approval: <GateName>` value may
368
377
  advance a gate. Clarification, blocked, internal-step and status-only
369
378
  interactions must not display gate-approval controls.
370
-
@@ -109,6 +109,24 @@
109
109
  "notYetCreated": "not yet created"
110
110
  },
111
111
  "primary": {
112
+ "readOnlyOrientationDescription": "Read-only check — no new AGDF run and no approval required.",
113
+ "lifecycleResult": {
114
+ "title": "AGDF lifecycle result",
115
+ "statusTitle": "AGDF status",
116
+ "result": "Result",
117
+ "surface": "Surface",
118
+ "scope": "Installation scope",
119
+ "version": "AGDF version",
120
+ "verification": "Verification",
121
+ "restart": "Restart required",
122
+ "installation": "Installation",
123
+ "repository": "Repository",
124
+ "delivery": "Delivery",
125
+ "next": "Next action",
126
+ "yes": "yes",
127
+ "no": "no",
128
+ "unknown": "unknown"
129
+ },
112
130
  "status": {
113
131
  "open": "open",
114
132
  "blocked": "blocked",
@@ -278,6 +296,24 @@
278
296
  "notYetCreated": "noch nicht erstellt"
279
297
  },
280
298
  "primary": {
299
+ "readOnlyOrientationDescription": "Read-only Prüfung – kein neuer AGDF-Run und keine Freigabe erforderlich.",
300
+ "lifecycleResult": {
301
+ "title": "AGDF-Lifecycle-Ergebnis",
302
+ "statusTitle": "AGDF-Status",
303
+ "result": "Ergebnis",
304
+ "surface": "Oberfläche",
305
+ "scope": "Installationsscope",
306
+ "version": "AGDF-Version",
307
+ "verification": "Verifikation",
308
+ "restart": "Neustart erforderlich",
309
+ "installation": "Installation",
310
+ "repository": "Repository",
311
+ "delivery": "Delivery",
312
+ "next": "Nächste Aktion",
313
+ "yes": "ja",
314
+ "no": "nein",
315
+ "unknown": "unbekannt"
316
+ },
281
317
  "status": {
282
318
  "open": "offen",
283
319
  "blocked": "blockiert",
@@ -274,6 +274,15 @@ Surface adapter rules:
274
274
 
275
275
  Native structured questions are for real decision points. Prefer repository inspection over clarification and do not show them for status reporting, discoverable facts, routine read-only work or repeated non-ready gate prompts.
276
276
 
277
+ ### Read-only request orientation
278
+
279
+ For a newly classified read-only request that does not require a run decision, render the localized
280
+ `primary.readOnlyOrientationDescription` sentence exactly once before the findings. This is a visible
281
+ orientation, not durable state: do not create a run, write control files, request gate approval or
282
+ repeat the sentence later in the same request. Existing-run status inspection remains read-only and
283
+ uses the existing status projection; this branch must not create a second status-card or narration
284
+ owner.
285
+
277
286
  Exact textual approvals remain canonical and fully supported on every surface. If native capability availability or safety is unknown, use the textual fallback. Host permission, plan approval, native question presentation, timeout/default behavior, hook output and agent messages never carry AGDF gate authority by themselves.
278
287
 
279
288
  ### Interaction Locale Contract
@@ -367,4 +376,3 @@ Missing input, timeout, cancellation and empty input are not decline. Only
367
376
  `approve` backed by the exact revalidated `Approval: <GateName>` value may
368
377
  advance a gate. Clarification, blocked, internal-step and status-only
369
378
  interactions must not display gate-approval controls.
370
-
@@ -64,6 +64,11 @@ Use the Runtime Contract's Native Interaction Contract to classify every candida
64
64
 
65
65
  Prefer inspection over asking. Do not invoke a structured question for status reporting, facts available in the repository, routine read-only work or a gate that is not ready. Do not repeatedly prompt for the same non-ready gate.
66
66
 
67
+ For a fresh request classified as read-only with no required run decision, emit the locale pack's
68
+ `primary.readOnlyOrientationDescription` sentence once before the findings. This path creates no run, persists
69
+ nothing, requests no approval and reuses the existing status projection. Do not repeat the sentence
70
+ during the same request.
71
+
67
72
  For a ready `gate_approval`:
68
73
 
69
74
  1. Resolve exactly one selected run and evaluate the current gate.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agdf",
3
- "version": "0.9.3",
3
+ "version": "0.9.6",
4
4
  "description": "Operating system for governed AI-assisted delivery.",
5
5
  "author": {
6
6
  "name": "Arndt Gold",
@@ -109,6 +109,24 @@
109
109
  "notYetCreated": "not yet created"
110
110
  },
111
111
  "primary": {
112
+ "readOnlyOrientationDescription": "Read-only check — no new AGDF run and no approval required.",
113
+ "lifecycleResult": {
114
+ "title": "AGDF lifecycle result",
115
+ "statusTitle": "AGDF status",
116
+ "result": "Result",
117
+ "surface": "Surface",
118
+ "scope": "Installation scope",
119
+ "version": "AGDF version",
120
+ "verification": "Verification",
121
+ "restart": "Restart required",
122
+ "installation": "Installation",
123
+ "repository": "Repository",
124
+ "delivery": "Delivery",
125
+ "next": "Next action",
126
+ "yes": "yes",
127
+ "no": "no",
128
+ "unknown": "unknown"
129
+ },
112
130
  "status": {
113
131
  "open": "open",
114
132
  "blocked": "blocked",
@@ -278,6 +296,24 @@
278
296
  "notYetCreated": "noch nicht erstellt"
279
297
  },
280
298
  "primary": {
299
+ "readOnlyOrientationDescription": "Read-only Prüfung – kein neuer AGDF-Run und keine Freigabe erforderlich.",
300
+ "lifecycleResult": {
301
+ "title": "AGDF-Lifecycle-Ergebnis",
302
+ "statusTitle": "AGDF-Status",
303
+ "result": "Ergebnis",
304
+ "surface": "Oberfläche",
305
+ "scope": "Installationsscope",
306
+ "version": "AGDF-Version",
307
+ "verification": "Verifikation",
308
+ "restart": "Neustart erforderlich",
309
+ "installation": "Installation",
310
+ "repository": "Repository",
311
+ "delivery": "Delivery",
312
+ "next": "Nächste Aktion",
313
+ "yes": "ja",
314
+ "no": "nein",
315
+ "unknown": "unbekannt"
316
+ },
281
317
  "status": {
282
318
  "open": "offen",
283
319
  "blocked": "blockiert",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "id": "agdf",
4
- "version": "0.9.3",
4
+ "version": "0.9.6",
5
5
  "displayName": "AI Governance & Delivery Framework",
6
6
  "developerName": "Arndt Gold",
7
7
  "description": "Operating system for governed AI-assisted delivery.",
@@ -274,6 +274,15 @@ Surface adapter rules:
274
274
 
275
275
  Native structured questions are for real decision points. Prefer repository inspection over clarification and do not show them for status reporting, discoverable facts, routine read-only work or repeated non-ready gate prompts.
276
276
 
277
+ ### Read-only request orientation
278
+
279
+ For a newly classified read-only request that does not require a run decision, render the localized
280
+ `primary.readOnlyOrientationDescription` sentence exactly once before the findings. This is a visible
281
+ orientation, not durable state: do not create a run, write control files, request gate approval or
282
+ repeat the sentence later in the same request. Existing-run status inspection remains read-only and
283
+ uses the existing status projection; this branch must not create a second status-card or narration
284
+ owner.
285
+
277
286
  Exact textual approvals remain canonical and fully supported on every surface. If native capability availability or safety is unknown, use the textual fallback. Host permission, plan approval, native question presentation, timeout/default behavior, hook output and agent messages never carry AGDF gate authority by themselves.
278
287
 
279
288
  ### Interaction Locale Contract
@@ -367,4 +376,3 @@ Missing input, timeout, cancellation and empty input are not decline. Only
367
376
  `approve` backed by the exact revalidated `Approval: <GateName>` value may
368
377
  advance a gate. Clarification, blocked, internal-step and status-only
369
378
  interactions must not display gate-approval controls.
370
-
@@ -64,6 +64,11 @@ Use the Runtime Contract's Native Interaction Contract to classify every candida
64
64
 
65
65
  Prefer inspection over asking. Do not invoke a structured question for status reporting, facts available in the repository, routine read-only work or a gate that is not ready. Do not repeatedly prompt for the same non-ready gate.
66
66
 
67
+ For a fresh request classified as read-only with no required run decision, emit the locale pack's
68
+ `primary.readOnlyOrientationDescription` sentence once before the findings. This path creates no run, persists
69
+ nothing, requests no approval and reuses the existing status projection. Do not repeat the sentence
70
+ during the same request.
71
+
67
72
  For a ready `gate_approval`:
68
73
 
69
74
  1. Resolve exactly one selected run and evaluate the current gate.
@@ -28,6 +28,16 @@ import {
28
28
  installClaudeGlobalPlugin,
29
29
  installCodexGlobalPlugin,
30
30
  } from "../installers/plugin-installers.js";
31
+ import {
32
+ applyLifecyclePlan,
33
+ planGlobalUninstall,
34
+ planRepositoryDisable,
35
+ verifyGlobalUninstall,
36
+ verifyRepositoryDisabled,
37
+ } from "../lifecycle/operations.js";
38
+ import { printGeneralStatus, printLifecycleResult } from "../lifecycle/presentation.js";
39
+ import { createLifecycleResult, lifecycleFailure } from "../lifecycle/result.js";
40
+ import { evaluateGeneralStatus } from "../lifecycle/status.js";
31
41
  import { agdfFragmentPath, generatedFilesForTarget, openCodeConfigFragmentPath } from "../scaffold/plan.js";
32
42
  import { printNextSteps } from "../scaffold/presentation.js";
33
43
  import { assertGeneratedWritePlan, removeOwnedLegacyOpenCodeAgents, writeGeneratedFile } from "../scaffold/write.js";
@@ -96,45 +106,186 @@ function createHandlers({ io, env, exec }) {
96
106
  printOpenCodeStatus(report, options.json, io);
97
107
  return report.status === "configured" ? 0 : 1;
98
108
  }],
99
- ["codex", () => {
109
+ ["status", (options) => {
110
+ const report = evaluateGeneralStatus(options.dir, {
111
+ ...options,
112
+ configDir: env.OPENCODE_CONFIG_DIR || defaultOpenCodeConfigDir(),
113
+ }, { exec });
114
+ printGeneralStatus(report, { json: options.json, locale: options.language.chat_language, io });
115
+ return report.installation.status === "healthy" ? 0 : 1;
116
+ }],
117
+ ["disable", (options) => runDisable(options, { io, exec })],
118
+ ["uninstall", (options) => runUninstall(options, { io, env, exec })],
119
+ ["codex", (options) => {
100
120
  try {
101
- installCodexGlobalPlugin(installerAdapters);
102
- io.log("AGDF Codex plugin installed globally.");
103
- io.log("Run npx --yes @agdf/cli@latest codex-repo in a repository when you want to test AGDF from repository-local plugin files.");
121
+ const installed = installCodexGlobalPlugin(installerAdapters);
122
+ printLifecycleResult(installResult(installed, {
123
+ restartRequired: true,
124
+ nextAction: "Restart Codex, then run npx --yes @agdf/cli@latest codex-repo in a repository where AGDF should be active.",
125
+ }), { json: options.json, locale: options.language.chat_language, io });
104
126
  return 0;
105
127
  } catch (error) {
106
- io.error(error.message);
128
+ printInstallFailure("codex", error, options, io);
107
129
  return 1;
108
130
  }
109
131
  }],
110
- ["claude", () => {
132
+ ["claude", (options) => {
111
133
  try {
112
- installClaudeGlobalPlugin(installerAdapters);
113
- io.log("AGDF Claude Code plugin installed globally.");
134
+ const installed = installClaudeGlobalPlugin(installerAdapters);
135
+ printLifecycleResult(installResult(installed, {
136
+ restartRequired: true,
137
+ nextAction: "Restart Claude Code, then verify the plugin in a new session.",
138
+ }), { json: options.json, locale: options.language.chat_language, io });
114
139
  return 0;
115
140
  } catch (error) {
116
- io.error(error.message);
141
+ printInstallFailure("claude", error, options, io);
117
142
  return 1;
118
143
  }
119
144
  }],
120
145
  ["opencode", (options) => {
121
146
  const configDir = options.dirExplicit ? options.dir : defaultOpenCodeConfigDir();
122
147
  try {
123
- const result = installOpenCodeGlobalPlugin(configDir);
124
- installOpenCodeGlobalSurface(configDir);
125
- io.log(`AGDF OpenCode global plugin ${result.added ? "installed" : "already present"}: ${result.configPath}`);
126
- const report = evaluateOpenCodeStatus(options.dir, configDir, result.transition);
127
- printOpenCodeStatus(report, false, io);
128
- io.log("Restart OpenCode so it loads the updated global plugin config.");
129
- return 0;
148
+ const result = runLifecyclePhase("plugin_operation", () => installOpenCodeGlobalPlugin(configDir));
149
+ runLifecyclePhase("global_surface", () => installOpenCodeGlobalSurface(configDir));
150
+ const report = runLifecyclePhase("verification", () => evaluateOpenCodeStatus(options.dir, configDir, result.transition));
151
+ const verificationHealthy = report.status === "configured"
152
+ && report.package.version_status === "current"
153
+ && report.global_native_surface.complete;
154
+ printLifecycleResult(createLifecycleResult({
155
+ operation: result.transition.status === "updated" ? "update" : "install",
156
+ result: verificationHealthy ? "success" : "partial",
157
+ surface: "opencode",
158
+ scope: "global",
159
+ version: {
160
+ expected: report.package.expected_version,
161
+ installed: report.package.installed_version,
162
+ previous: result.transition.previous_version,
163
+ status: report.package.version_status === "current" ? "verified" : "unknown",
164
+ transition: result.transition.status,
165
+ },
166
+ verification: { status: verificationHealthy ? "healthy" : "degraded", evidence: [report.global_config.path, report.global_native_surface.path] },
167
+ restart: { required: true, reason: "host_reload" },
168
+ next_action: { kind: "restart", text: "Restart OpenCode so it loads the updated global plugin config." },
169
+ }), { json: options.json, locale: options.language.chat_language, io });
170
+ return verificationHealthy ? 0 : 1;
130
171
  } catch (error) {
131
- io.error(error.message);
172
+ printInstallFailure("opencode", error, options, io);
132
173
  return 1;
133
174
  }
134
175
  }],
135
176
  ]);
136
177
  }
137
178
 
179
+ function runLifecyclePhase(phase, operation) {
180
+ try {
181
+ return operation();
182
+ } catch (error) {
183
+ if (!error.phase) error.phase = phase;
184
+ if (!error.evidence) error.evidence = {};
185
+ throw error;
186
+ }
187
+ }
188
+
189
+ function installResult(installed, { restartRequired, nextAction }) {
190
+ return createLifecycleResult({
191
+ operation: "install",
192
+ result: "success",
193
+ surface: installed.surface,
194
+ scope: "global",
195
+ version: { expected: installed.expectedVersion, installed: installed.installedVersion, status: installed.installedVersion ? "verified" : "unknown" },
196
+ verification: { status: installed.verificationStatus, evidence: installed.evidence },
197
+ restart: { required: restartRequired, reason: restartRequired ? "host_reload" : "none" },
198
+ next_action: { kind: restartRequired ? "restart" : "prompt", text: nextAction },
199
+ });
200
+ }
201
+
202
+ function printInstallFailure(surface, error, options, io) {
203
+ const report = lifecycleFailure({
204
+ operation: "install",
205
+ surface,
206
+ scope: "global",
207
+ phase: error.phase || "plugin_operation",
208
+ message: error.message,
209
+ evidence: [error.evidence ?? {}],
210
+ nextAction: `Resolve the ${error.phase || "plugin operation"} failure and rerun npx --yes @agdf/cli@latest ${surface}.`,
211
+ });
212
+ if (options.json) printLifecycleResult(report, { json: true, io });
213
+ else {
214
+ io.error(error.message);
215
+ printLifecycleResult(report, { locale: options.language.chat_language, io });
216
+ }
217
+ }
218
+
219
+ function runDisable(options, { io, exec }) {
220
+ try {
221
+ const plan = planRepositoryDisable(options.dir, options.surface);
222
+ const applied = applyLifecyclePlan(plan, exec ? { exec } : {});
223
+ const verified = applied.status === "success" ? verifyRepositoryDisabled(options.dir) : { status: "failed", evidence: [] };
224
+ const result = applied.status === "success" && verified.status !== "healthy" ? "failed" : applied.status;
225
+ const report = createLifecycleResult({
226
+ operation: "disable",
227
+ result,
228
+ surface: options.surface,
229
+ scope: "repository",
230
+ verification: { status: verified.status === "healthy" ? "healthy" : "degraded", evidence: [...applied.completed.map((item) => item.path || item.executable), ...verified.evidence] },
231
+ restart: { required: result === "success", reason: result === "success" ? "host_reload" : "none" },
232
+ next_action: result === "success"
233
+ ? { kind: "restart", text: "Restart the host in this repository; global AGDF availability and .agdf/control are retained." }
234
+ : { kind: "verify", text: "Inspect the reported repository configuration failure before retrying disable." },
235
+ changes: applied.completed,
236
+ retained: applied.retained,
237
+ failure: applied.error
238
+ ? { phase: "repository_configuration", message: applied.error.message }
239
+ : result === "failed" ? { phase: "verification", message: "Repository disable postcondition was not observed." } : null,
240
+ });
241
+ printLifecycleResult(report, { json: options.json, locale: options.language.chat_language, io });
242
+ return result === "success" ? 0 : 1;
243
+ } catch (error) {
244
+ io.error(error.message);
245
+ return 1;
246
+ }
247
+ }
248
+
249
+ function runUninstall(options, { io, env, exec }) {
250
+ try {
251
+ const configDir = env.OPENCODE_CONFIG_DIR || defaultOpenCodeConfigDir();
252
+ const plan = planGlobalUninstall(options.surface, { configDir });
253
+ if (!options.confirm) {
254
+ const preview = createLifecycleResult({
255
+ operation: "uninstall", result: "preview", surface: options.surface, scope: "global",
256
+ verification: { status: "unknown", evidence: ["non_mutating_preview"] },
257
+ restart: { required: false },
258
+ next_action: { kind: "confirm", text: `Review this preview, then rerun with --surface ${options.surface} --scope global --confirm; ownership is revalidated before apply.` },
259
+ changes: plan.mutations, retained: plan.retained,
260
+ });
261
+ printLifecycleResult(preview, { json: options.json, locale: options.language.chat_language, io });
262
+ return 0;
263
+ }
264
+ const applied = applyLifecyclePlan(plan, exec ? { exec } : {});
265
+ const verified = applied.status === "success"
266
+ ? verifyGlobalUninstall(plan, options.dir, { configDir, exec })
267
+ : { status: "failed", evidence: [] };
268
+ const result = applied.status === "success" && verified.status !== "healthy" ? "failed" : applied.status;
269
+ const report = createLifecycleResult({
270
+ operation: "uninstall", result, surface: options.surface, scope: "global",
271
+ verification: { status: verified.status === "healthy" ? "healthy" : "degraded", evidence: [...applied.completed.map((item) => item.path || item.executable), ...verified.evidence] },
272
+ restart: { required: result === "success", reason: result === "success" ? "host_reload" : "none" },
273
+ next_action: result === "success"
274
+ ? { kind: "restart", text: "Restart the host; the uninstall postcondition has already been verified." }
275
+ : { kind: "verify", text: "Inspect the reported uninstall or verification failure before retrying." },
276
+ changes: applied.completed, retained: applied.retained,
277
+ failure: applied.error
278
+ ? { phase: "plugin_operation", message: applied.error.message }
279
+ : result === "failed" ? { phase: "verification", message: "Global uninstall postcondition was not observed." } : null,
280
+ });
281
+ printLifecycleResult(report, { json: options.json, locale: options.language.chat_language, io });
282
+ return result === "success" ? 0 : 1;
283
+ } catch (error) {
284
+ io.error(error.message);
285
+ return 1;
286
+ }
287
+ }
288
+
138
289
  function runScaffold(options, io) {
139
290
  const files = generatedFilesForTarget(options.target, options.dir, options.force, options.language);
140
291
  const wroteAgentsFragment = files.some((file) => file.path === agdfFragmentPath);
@@ -13,9 +13,12 @@ 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", { scaffold: [""] }),
16
+ command("copilot", { preferred: [""], scaffold: [""] }),
17
17
  command("opencode", { preferred: [""], scaffold: [""] }),
18
18
  command("opencode-status", { preferred: [""], scaffold: [""] }),
19
+ command("status", { preferred: [" [--surface <surface>] [--run <run_id>] [--json]"] }),
20
+ command("disable", { preferred: [" --surface <surface> [--scope repository] [--dir <path>]"] }),
21
+ command("uninstall", { preferred: [" --surface <surface> --scope global [--confirm]"] }),
19
22
  command("opencode-repo", { preferred: [""], scaffold: [""] }),
20
23
  command("both", { scaffold: [""] }),
21
24
  command("init", { preferred: [""], scaffold: [""] }),
@@ -52,6 +55,16 @@ export function validateCommandOptions(options) {
52
55
  if (options.target === "run-render-legacy" && !options.runId) {
53
56
  throw new Error("run-render-legacy requires --run");
54
57
  }
58
+ if (["disable", "uninstall"].includes(options.target) && ["", "generic", undefined].includes(options.surface)) {
59
+ throw new Error(`${options.target} requires an explicit --surface`);
60
+ }
61
+ if (options.target === "disable" && options.scope && options.scope !== "repository") {
62
+ throw new Error("disable supports repository scope only");
63
+ }
64
+ if (options.target === "uninstall" && options.scope !== "global") {
65
+ throw new Error("uninstall requires explicit --scope global");
66
+ }
67
+ if (options.confirm && options.target !== "uninstall") throw new Error("--confirm is supported only by uninstall");
55
68
  return options;
56
69
  }
57
70
 
@@ -62,11 +75,13 @@ function usageLines(group, prefix) {
62
75
  }
63
76
 
64
77
  export function renderUsage() {
65
- return `create-agdf
78
+ return `AGDF CLI
66
79
 
67
- Preferred AGDF CLI:
80
+ Primary commands:
68
81
  ${usageLines("preferred", "npx --yes @agdf/cli@latest ")}
69
82
 
83
+ Advanced / Compatibility
84
+
70
85
  Scaffold-compatible npm create usage:
71
86
  ${usageLines("scaffold", "npm create agdf@latest -- ")}
72
87
 
@@ -85,6 +100,9 @@ Options:
85
100
  --all-active Evaluate every active run (doctor and delivery-map only)
86
101
  --surface <codex|claude|copilot|opencode|generic>
87
102
  Declare the active Delivery Path Search surface
103
+ --scope <repository|global>
104
+ Select the lifecycle mutation scope
105
+ --confirm Apply a previously previewed global uninstall plan
88
106
  --fixture <path>
89
107
  Use deterministic evaluator/candidate fixtures instead of a live evaluator
90
108
  --persist Persist the redacted Delivery Path Search result under the current scope
@@ -41,6 +41,8 @@ export function parseArgs(argv, dependencies = {}) {
41
41
  let generationCostUnits = 5;
42
42
  let runId;
43
43
  let allActive = false;
44
+ let scope;
45
+ let confirm = false;
44
46
 
45
47
  for (let i = 0; i < args.length; i += 1) {
46
48
  const arg = args[i];
@@ -52,6 +54,7 @@ export function parseArgs(argv, dependencies = {}) {
52
54
  if (arg === "--persist") { persist = true; continue; }
53
55
  if (arg === "--generate-candidates") { generateCandidates = true; continue; }
54
56
  if (arg === "--all-active") { allActive = true; continue; }
57
+ if (arg === "--confirm") { confirm = true; continue; }
55
58
 
56
59
  if (arg === "--run") {
57
60
  runId = requiredValue(args, i, arg);
@@ -59,13 +62,16 @@ export function parseArgs(argv, dependencies = {}) {
59
62
  continue;
60
63
  }
61
64
 
62
- if (["--surface", "--fixture", "--model", "--generator-model", "--max-generated-candidates", "--generation-timeout-ms", "--generation-cost-units"].includes(arg)) {
65
+ if (["--surface", "--scope", "--fixture", "--model", "--generator-model", "--max-generated-candidates", "--generation-timeout-ms", "--generation-cost-units"].includes(arg)) {
63
66
  const next = requiredValue(args, i, arg);
64
67
  if (arg === "--surface") {
65
68
  if (!["codex", "claude", "copilot", "opencode", "generic"].includes(next)) {
66
69
  throw new CliUsageError("Unsupported surface. Use codex, claude, copilot, opencode or generic.");
67
70
  }
68
71
  surface = next;
72
+ } else if (arg === "--scope") {
73
+ if (!["repository", "global"].includes(next)) throw new CliUsageError("Unsupported scope. Use repository or global.");
74
+ scope = next;
69
75
  } else if (arg === "--fixture") fixture = next;
70
76
  else if (arg === "--model") model = next;
71
77
  else if (arg === "--generator-model") generatorModel = next;
@@ -133,6 +139,8 @@ export function parseArgs(argv, dependencies = {}) {
133
139
  generateCandidates,
134
140
  runId,
135
141
  allActive,
142
+ scope,
143
+ confirm,
136
144
  generatorModel,
137
145
  maxGeneratedCandidates,
138
146
  generationTimeoutMs,