canary-test-cli 6.8.0 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/engine/analysis/cli.js +155 -45
  2. package/dist/engine/analysis/engine.js +9 -9
  3. package/dist/engine/analysis/reports.js +0 -0
  4. package/dist/engine/cli-commands.js +2 -2
  5. package/dist/engine/core/migrator.js +142 -31
  6. package/dist/engine/core/static-linter.js +2 -2
  7. package/dist/engine/core/workspace-detect.js +0 -0
  8. package/dist/engine/guardian/adjudication.js +1 -1
  9. package/dist/engine/guardian/agent-tier.js +3 -3
  10. package/dist/engine/guardian/coverage.js +15 -1397
  11. package/dist/engine/guardian/diff-coverage/formats/cobertura.js +130 -0
  12. package/dist/engine/guardian/diff-coverage/formats/coverage-json-lint.js +197 -0
  13. package/dist/engine/guardian/diff-coverage/formats/coverage-json.js +107 -0
  14. package/dist/engine/guardian/diff-coverage/formats/xml.js +151 -0
  15. package/dist/engine/guardian/diff-coverage/graph-tier.js +223 -0
  16. package/dist/engine/guardian/diff-coverage/heuristic-tier.js +150 -0
  17. package/dist/engine/guardian/diff-coverage/orchestrator.js +125 -0
  18. package/dist/engine/guardian/diff-coverage/paths.js +164 -0
  19. package/dist/engine/guardian/diff-coverage/report-tier.js +153 -0
  20. package/dist/engine/guardian/diff-coverage/type-only.js +150 -0
  21. package/dist/engine/guardian/diff-coverage/types.js +115 -0
  22. package/dist/engine/guardian/pr-check.js +22 -7
  23. package/dist/engine-checks.d.ts +15 -0
  24. package/dist/engine-checks.js +92 -1
  25. package/dist/overlay-commands.d.ts +12 -1
  26. package/dist/overlay-commands.js +28 -2
  27. package/dist/router.js +17 -5
  28. package/dist/uninstall-render.d.ts +11 -0
  29. package/dist/uninstall-render.js +60 -0
  30. package/dist/uninstall-scan.d.ts +14 -0
  31. package/dist/uninstall-scan.js +273 -0
  32. package/dist/uninstall-types.d.ts +46 -0
  33. package/dist/uninstall-types.js +91 -0
  34. package/dist/uninstall.d.ts +13 -0
  35. package/dist/uninstall.js +174 -0
  36. package/package.json +1 -1
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.render = exports.enumerate = void 0;
37
+ exports.removeAll = removeAll;
38
+ exports.run = run;
39
+ /**
40
+ * `canary uninstall` — remove what the CLI can safely remove, and print
41
+ * instructions for what it structurally cannot.
42
+ *
43
+ * The command deliberately refuses to claim more than it did. A full install
44
+ * scatters artifacts across seven locations (#523) and two of them belong to
45
+ * other owners: the CLI binary (the running process, removed by whichever
46
+ * package manager installed it) and the Claude Code plugin registration
47
+ * (`installed_plugins.json`, mutated only by `/plugin uninstall`). Reporting
48
+ * those as done would be the same false-green shape the guardian exists to
49
+ * catch, so they render as `manual` and are never passed to the removal path.
50
+ */
51
+ const fs = __importStar(require("node:fs"));
52
+ const os = __importStar(require("node:os"));
53
+ const path = __importStar(require("node:path"));
54
+ const registry = __importStar(require("./overlays-registry.js"));
55
+ const uninstall_scan_js_1 = require("./uninstall-scan.js");
56
+ const uninstall_render_js_1 = require("./uninstall-render.js");
57
+ const uninstall_types_js_1 = require("./uninstall-types.js");
58
+ var uninstall_scan_js_2 = require("./uninstall-scan.js");
59
+ Object.defineProperty(exports, "enumerate", { enumerable: true, get: function () { return uninstall_scan_js_2.enumerate; } });
60
+ var uninstall_render_js_2 = require("./uninstall-render.js");
61
+ Object.defineProperty(exports, "render", { enumerable: true, get: function () { return uninstall_render_js_2.render; } });
62
+ function removeCanaryDir(dir, keepQuarantine) {
63
+ if (!keepQuarantine) {
64
+ fs.rmSync(dir, { recursive: true, force: true });
65
+ return;
66
+ }
67
+ for (const child of fs.readdirSync(dir)) {
68
+ if (child === 'quarantine.json')
69
+ continue;
70
+ fs.rmSync(path.join(dir, child), { recursive: true, force: true });
71
+ }
72
+ }
73
+ function removeMcpEntry(file) {
74
+ const raw = fs.readFileSync(file, 'utf8');
75
+ const doc = JSON.parse(raw);
76
+ if (doc.mcpServers)
77
+ delete doc.mcpServers[uninstall_types_js_1.MCP_KEY];
78
+ // Two-space JSON matches what the ecosystem writes; the file is left in
79
+ // place even when `mcpServers` is now empty — deciding an empty config
80
+ // should not exist is the user's call.
81
+ fs.writeFileSync(file, `${JSON.stringify(doc, null, 2)}\n`);
82
+ }
83
+ /** Delete one artifact. Assumes the caller already checked `removable`. */
84
+ function removeOne(artifact, home, keepQuarantine) {
85
+ const target = artifact.path;
86
+ if (!target)
87
+ return;
88
+ if (artifact.kind === 'mcp-entry') {
89
+ removeMcpEntry(target);
90
+ return;
91
+ }
92
+ if (artifact.kind === 'project-config') {
93
+ removeCanaryDir(target, keepQuarantine);
94
+ return;
95
+ }
96
+ fs.rmSync(target, { recursive: true, force: true });
97
+ if (artifact.kind === 'overlay') {
98
+ // The clone is gone; drop its registry row too, or `overlay list` keeps
99
+ // advertising a path that no longer exists.
100
+ const name = artifact.label.replace(/^overlay /, '');
101
+ registry.write(registry.remove(registry.read(home), name).registry, home);
102
+ }
103
+ }
104
+ function removeAll(artifacts, deps = {}) {
105
+ const home = deps.homeDir ?? os.homedir();
106
+ const outcome = { removed: [], failed: [] };
107
+ // When the ledger was withheld, `.canary/` must be emptied around it rather
108
+ // than deleted wholesale — otherwise the removal silently undoes the
109
+ // protection the `blocked` disposition just promised.
110
+ const keepQuarantine = artifacts.some((a) => a.kind === 'quarantine-ledger' && a.disposition === 'blocked');
111
+ for (const a of artifacts) {
112
+ if (a.disposition !== 'removable')
113
+ continue;
114
+ try {
115
+ removeOne(a, home, keepQuarantine);
116
+ outcome.removed.push(a);
117
+ }
118
+ catch (e) {
119
+ outcome.failed.push({ artifact: a, error: e.message });
120
+ }
121
+ }
122
+ return outcome;
123
+ }
124
+ const KNOWN_FLAGS = new Set([
125
+ '--global',
126
+ '--project',
127
+ '--all',
128
+ '--apply',
129
+ '--include-generated',
130
+ ]);
131
+ function run(argv, deps = {}) {
132
+ const out = deps.out ?? process.stdout;
133
+ const err = deps.err ?? process.stderr;
134
+ for (const a of argv) {
135
+ if (!KNOWN_FLAGS.has(a)) {
136
+ err.write(`canary uninstall: unknown option "${a}".\n`);
137
+ return 1;
138
+ }
139
+ }
140
+ const scopes = [];
141
+ if (argv.includes('--global'))
142
+ scopes.push('global');
143
+ if (argv.includes('--project'))
144
+ scopes.push('project');
145
+ if (argv.includes('--all'))
146
+ scopes.push('all');
147
+ if (scopes.length === 0) {
148
+ err.write('canary uninstall: choose a scope.\n' +
149
+ ' --global overlays and orphaned Claude Code plugin caches\n' +
150
+ ' --project .canary/, generated reports, and the .mcp.json entry\n' +
151
+ ' --all both\n' +
152
+ 'Nothing is removed without --apply.\n');
153
+ return 1;
154
+ }
155
+ if (scopes.length > 1) {
156
+ err.write('canary uninstall: pass exactly one of --global/--project/--all.\n');
157
+ return 1;
158
+ }
159
+ const scope = scopes[0];
160
+ const apply = argv.includes('--apply');
161
+ const includeGenerated = argv.includes('--include-generated');
162
+ const artifacts = (0, uninstall_scan_js_1.enumerate)({ scope, includeGenerated }, deps);
163
+ let failed = [];
164
+ if (apply) {
165
+ failed = removeAll(artifacts, deps).failed;
166
+ }
167
+ // Hand the failures to the renderer so a removal that threw is never counted
168
+ // as removed — the report must not be cleaner than the outcome.
169
+ out.write(`${(0, uninstall_render_js_1.render)(artifacts, { scope, apply, failed: failed.map((f) => f.artifact) })}\n`);
170
+ for (const f of failed) {
171
+ err.write(`canary uninstall: failed to remove ${f.artifact.path}: ${f.error}\n`);
172
+ }
173
+ return failed.length > 0 ? 1 : 0;
174
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "canary-test-cli",
3
- "version": "6.8.0",
3
+ "version": "7.0.0",
4
4
  "description": "Canary — AI-powered test automation agent",
5
5
  "license": "MIT",
6
6
  "repository": {