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.
- package/dist/engine/analysis/cli.js +155 -45
- package/dist/engine/analysis/engine.js +9 -9
- package/dist/engine/analysis/reports.js +0 -0
- package/dist/engine/cli-commands.js +2 -2
- package/dist/engine/core/migrator.js +142 -31
- package/dist/engine/core/static-linter.js +2 -2
- package/dist/engine/core/workspace-detect.js +0 -0
- package/dist/engine/guardian/adjudication.js +1 -1
- package/dist/engine/guardian/agent-tier.js +3 -3
- package/dist/engine/guardian/coverage.js +15 -1397
- package/dist/engine/guardian/diff-coverage/formats/cobertura.js +130 -0
- package/dist/engine/guardian/diff-coverage/formats/coverage-json-lint.js +197 -0
- package/dist/engine/guardian/diff-coverage/formats/coverage-json.js +107 -0
- package/dist/engine/guardian/diff-coverage/formats/xml.js +151 -0
- package/dist/engine/guardian/diff-coverage/graph-tier.js +223 -0
- package/dist/engine/guardian/diff-coverage/heuristic-tier.js +150 -0
- package/dist/engine/guardian/diff-coverage/orchestrator.js +125 -0
- package/dist/engine/guardian/diff-coverage/paths.js +164 -0
- package/dist/engine/guardian/diff-coverage/report-tier.js +153 -0
- package/dist/engine/guardian/diff-coverage/type-only.js +150 -0
- package/dist/engine/guardian/diff-coverage/types.js +115 -0
- package/dist/engine/guardian/pr-check.js +22 -7
- package/dist/engine-checks.d.ts +15 -0
- package/dist/engine-checks.js +92 -1
- package/dist/overlay-commands.d.ts +12 -1
- package/dist/overlay-commands.js +28 -2
- package/dist/router.js +17 -5
- package/dist/uninstall-render.d.ts +11 -0
- package/dist/uninstall-render.js +60 -0
- package/dist/uninstall-scan.d.ts +14 -0
- package/dist/uninstall-scan.js +273 -0
- package/dist/uninstall-types.d.ts +46 -0
- package/dist/uninstall-types.js +91 -0
- package/dist/uninstall.d.ts +13 -0
- package/dist/uninstall.js +174 -0
- 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
|
+
}
|