@kb-labs/quality-entry 2.93.0 → 2.96.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/cli/commands/build-order.d.ts +5 -12
- package/dist/cli/commands/build-order.js +45 -97
- package/dist/cli/commands/build-order.js.map +1 -1
- package/dist/cli/commands/check-layers.d.ts +9 -0
- package/dist/cli/commands/check-layers.js +48 -0
- package/dist/cli/commands/check-layers.js.map +1 -0
- package/dist/cli/commands/context.d.ts +9 -0
- package/dist/cli/commands/context.js +94 -0
- package/dist/cli/commands/context.js.map +1 -0
- package/dist/cli/commands/coupling.d.ts +9 -0
- package/dist/cli/commands/coupling.js +35 -0
- package/dist/cli/commands/coupling.js.map +1 -0
- package/dist/cli/commands/dead-code.d.ts +4 -5
- package/dist/cli/commands/dead-code.js +41 -197
- package/dist/cli/commands/dead-code.js.map +1 -1
- package/dist/cli/commands/fix-deps.d.ts +2 -5
- package/dist/cli/commands/fix-deps.js +74 -83
- package/dist/cli/commands/fix-deps.js.map +1 -1
- package/dist/cli/commands/flags.d.ts +115 -1
- package/dist/cli/commands/flags.js +46 -1
- package/dist/cli/commands/flags.js.map +1 -1
- package/dist/cli/commands/gate.d.ts +9 -0
- package/dist/cli/commands/gate.js +59 -0
- package/dist/cli/commands/gate.js.map +1 -0
- package/dist/cli/commands/health.d.ts +4 -5
- package/dist/cli/commands/health.js +42 -191
- package/dist/cli/commands/health.js.map +1 -1
- package/dist/cli/commands/history.d.ts +9 -0
- package/dist/cli/commands/history.js +55 -0
- package/dist/cli/commands/history.js.map +1 -0
- package/dist/cli/commands/index.d.ts +6 -2
- package/dist/cli/commands/index.js +411 -828
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/snapshot.d.ts +9 -0
- package/dist/cli/commands/snapshot.js +91 -0
- package/dist/cli/commands/snapshot.js.map +1 -0
- package/dist/cli/commands/stats.d.ts +4 -5
- package/dist/cli/commands/stats.js +17 -265
- package/dist/cli/commands/stats.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +198 -306
- package/dist/index.js.map +1 -1
- package/dist/manifest.d.ts +95 -82
- package/dist/manifest.js +198 -306
- package/dist/manifest.js.map +1 -1
- package/dist/rest/handlers/build-order-handler.d.ts +5 -13
- package/dist/rest/handlers/build-order-handler.js +14 -17
- package/dist/rest/handlers/build-order-handler.js.map +1 -1
- package/dist/rest/handlers/builds-handler.js +10 -6
- package/dist/rest/handlers/builds-handler.js.map +1 -1
- package/dist/rest/handlers/coupling-handler.d.ts +8 -0
- package/dist/rest/handlers/coupling-handler.js +28 -0
- package/dist/rest/handlers/coupling-handler.js.map +1 -0
- package/dist/rest/handlers/cycles-handler.js +16 -12
- package/dist/rest/handlers/cycles-handler.js.map +1 -1
- package/dist/rest/handlers/dependencies-handler.js +12 -8
- package/dist/rest/handlers/dependencies-handler.js.map +1 -1
- package/dist/rest/handlers/graph-handler.js +77 -73
- package/dist/rest/handlers/graph-handler.js.map +1 -1
- package/dist/rest/handlers/health-handler.d.ts +4 -11
- package/dist/rest/handlers/health-handler.js +35 -9
- package/dist/rest/handlers/health-handler.js.map +1 -1
- package/dist/rest/handlers/history-handler.d.ts +7 -0
- package/dist/rest/handlers/history-handler.js +21 -0
- package/dist/rest/handlers/history-handler.js.map +1 -0
- package/dist/rest/handlers/knip-handler.d.ts +8 -0
- package/dist/rest/handlers/knip-handler.js +31 -0
- package/dist/rest/handlers/knip-handler.js.map +1 -0
- package/dist/rest/handlers/layers-handler.d.ts +8 -0
- package/dist/rest/handlers/layers-handler.js +28 -0
- package/dist/rest/handlers/layers-handler.js.map +1 -0
- package/dist/rest/handlers/snapshot-handler.d.ts +7 -0
- package/dist/rest/handlers/snapshot-handler.js +67 -0
- package/dist/rest/handlers/snapshot-handler.js.map +1 -0
- package/dist/rest/handlers/stale-handler.js +13 -9
- package/dist/rest/handlers/stale-handler.js.map +1 -1
- package/dist/rest/handlers/stats-handler.d.ts +4 -9
- package/dist/rest/handlers/stats-handler.js +22 -18
- package/dist/rest/handlers/stats-handler.js.map +1 -1
- package/dist/rest/handlers/tests-handler.js +12 -8
- package/dist/rest/handlers/tests-handler.js.map +1 -1
- package/dist/rest/handlers/types-handler.js +10 -6
- package/dist/rest/handlers/types-handler.js.map +1 -1
- package/dist/widgets/117.js +24 -1
- package/dist/widgets/117.js.map +1 -1
- package/dist/widgets/370.js +1 -1
- package/dist/widgets/370.js.map +1 -1
- package/dist/widgets/62.js +97 -0
- package/dist/widgets/62.js.map +1 -0
- package/dist/widgets/__federation_expose_QualityOverview.js +1 -1
- package/dist/widgets/__federation_expose_QualityOverview.js.map +1 -1
- package/dist/widgets/mf-manifest.json +27 -27
- package/dist/widgets/mf-stats.json +27 -27
- package/dist/widgets/remoteEntry.js +2 -2
- package/dist/widgets/remoteEntry.js.map +1 -1
- package/package.json +9 -8
- package/dist/widgets/418.js +0 -39
- package/dist/widgets/418.js.map +0 -1
|
@@ -1,216 +1,60 @@
|
|
|
1
|
-
import { defineCommand } from '@kb-labs/sdk';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { defineCommand, useConfig } from '@kb-labs/sdk';
|
|
2
|
+
import { runKnip } from '@kb-labs/quality-core';
|
|
3
|
+
import { defaultQualityConfig } from '@kb-labs/quality-contracts';
|
|
4
4
|
|
|
5
5
|
// src/cli/commands/dead-code.ts
|
|
6
6
|
var dead_code_default = defineCommand({
|
|
7
7
|
id: "quality:dead-code",
|
|
8
|
-
description: "Detect
|
|
8
|
+
description: "Detect unused files, exports, and deps via knip",
|
|
9
9
|
handler: {
|
|
10
10
|
async execute(ctx, input) {
|
|
11
|
-
const {
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
outputBackupList(backups, ui);
|
|
19
|
-
}
|
|
20
|
-
return { exitCode: 0, result: backups };
|
|
11
|
+
const { flags } = input;
|
|
12
|
+
const config = await useConfig();
|
|
13
|
+
const cwd = ctx.cwd ?? process.cwd();
|
|
14
|
+
const cfg = config ?? defaultQualityConfig;
|
|
15
|
+
if (!cfg.knip.enabled) {
|
|
16
|
+
ctx.ui?.success?.("knip is disabled in config (knip.enabled = false)");
|
|
17
|
+
return { exitCode: 0 };
|
|
21
18
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
ui?.json?.(result2);
|
|
27
|
-
} else {
|
|
28
|
-
ui?.success?.(`Restored ${result2.restoredFiles} file(s) from backup ${flags.restore}`, {});
|
|
29
|
-
if (result2.restoredExports > 0) {
|
|
30
|
-
ui?.info?.(`Note: ${result2.restoredExports} package.json export(s) were cleaned. You may need to rebuild.`);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
return { exitCode: 0 };
|
|
34
|
-
} catch (err) {
|
|
35
|
-
if (flags.json) {
|
|
36
|
-
ui?.json?.({ error: err instanceof Error ? err.message : String(err) });
|
|
37
|
-
} else {
|
|
38
|
-
ui?.error?.(err instanceof Error ? err.message : String(err));
|
|
39
|
-
}
|
|
40
|
-
return { exitCode: 1 };
|
|
41
|
-
}
|
|
19
|
+
const report = await runKnip({ shell: ctx.api.shell, rootDir: cwd });
|
|
20
|
+
if (flags.json) {
|
|
21
|
+
ctx.ui?.json?.(report);
|
|
22
|
+
return { exitCode: report.totalIssues > 0 ? 1 : 0 };
|
|
42
23
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (cached) {
|
|
47
|
-
outputDeadCodeReport({ ...cached, cached: true }, flags, ui);
|
|
48
|
-
return { exitCode: cached.summary.totalDead > 0 ? 1 : 0, result: cached };
|
|
49
|
-
}
|
|
24
|
+
if (report.totalIssues === 0) {
|
|
25
|
+
ctx.ui?.success?.("No dead code detected");
|
|
26
|
+
return { exitCode: 0 };
|
|
50
27
|
}
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
await platform.analytics.track("quality:dead-code", {
|
|
57
|
-
totalPackages: result.summary.totalPackages,
|
|
58
|
-
totalFiles: result.summary.totalFiles,
|
|
59
|
-
totalDead: result.summary.totalDead,
|
|
60
|
-
totalDeadBytes: result.summary.totalDeadBytes,
|
|
61
|
-
duration: result.duration,
|
|
62
|
-
autoRemove: !!flags["auto-remove"],
|
|
63
|
-
dryRun: !!flags["dry-run"]
|
|
64
|
-
});
|
|
65
|
-
if (flags["auto-remove"]) {
|
|
66
|
-
if (result.summary.totalDead === 0) {
|
|
67
|
-
if (flags.json) {
|
|
68
|
-
ui?.json?.({ message: "No dead files found", ...result });
|
|
69
|
-
} else {
|
|
70
|
-
ui?.success?.("No dead files found. Nothing to remove.", {});
|
|
71
|
-
}
|
|
72
|
-
return { exitCode: 0, result };
|
|
73
|
-
}
|
|
74
|
-
const removalResult = await removeDeadFiles(ctx.cwd, result, {
|
|
75
|
-
dryRun: flags["dry-run"]
|
|
28
|
+
const sections = [];
|
|
29
|
+
if (report.unusedFiles.length > 0) {
|
|
30
|
+
sections.push({
|
|
31
|
+
header: `Unused files (${report.unusedFiles.length})`,
|
|
32
|
+
items: report.unusedFiles
|
|
76
33
|
});
|
|
77
|
-
if (flags.json) {
|
|
78
|
-
ui?.json?.(removalResult);
|
|
79
|
-
} else {
|
|
80
|
-
outputRemovalReport(removalResult, flags, ui);
|
|
81
|
-
}
|
|
82
|
-
return { exitCode: 0, result: removalResult };
|
|
83
34
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
function outputDeadCodeReport(result, flags, ui) {
|
|
93
|
-
if (flags.json) {
|
|
94
|
-
ui?.json?.(result);
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
const sections = [];
|
|
98
|
-
const packagesWithDead = result.packages.filter((p) => p.deadFiles.length > 0);
|
|
99
|
-
if (packagesWithDead.length > 0) {
|
|
100
|
-
const items = [];
|
|
101
|
-
for (const pkg of packagesWithDead) {
|
|
102
|
-
items.push(`${pkg.packageName} (${pkg.deadFiles.length} dead file${pkg.deadFiles.length === 1 ? "" : "s"})`);
|
|
103
|
-
for (const dead of pkg.deadFiles.slice(0, 5)) {
|
|
104
|
-
const sizeKb = (dead.sizeBytes / 1024).toFixed(1);
|
|
105
|
-
items.push(` ${dead.relativePath} (${sizeKb} KB)`);
|
|
35
|
+
if (report.unusedExports.length > 0) {
|
|
36
|
+
sections.push({
|
|
37
|
+
header: `Unused exports (${report.unusedExports.length})`,
|
|
38
|
+
items: report.unusedExports.map((e) => `${e.file} ${e.symbol}`)
|
|
39
|
+
});
|
|
106
40
|
}
|
|
107
|
-
if (
|
|
108
|
-
|
|
41
|
+
if (report.unusedDependencies.length > 0) {
|
|
42
|
+
sections.push({
|
|
43
|
+
header: `Unused dependencies (${report.unusedDependencies.length})`,
|
|
44
|
+
items: report.unusedDependencies.map((d) => `${d.package} in ${d.workspace}`)
|
|
45
|
+
});
|
|
109
46
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
if (pkg.entryPoints.length > 0) {
|
|
116
|
-
const items = pkg.entryPoints.slice(0, 10).map((ep) => ` ${ep}`);
|
|
117
|
-
if (pkg.entryPoints.length > 10) {
|
|
118
|
-
items.push(` ... and ${pkg.entryPoints.length - 10} more`);
|
|
119
|
-
}
|
|
120
|
-
sections.push({ header: `Entry Points: ${pkg.packageName}`, items });
|
|
47
|
+
if (report.unlistedDependencies.length > 0) {
|
|
48
|
+
sections.push({
|
|
49
|
+
header: `Unlisted dependencies (${report.unlistedDependencies.length})`,
|
|
50
|
+
items: report.unlistedDependencies.map((d) => `${d.package} in ${d.workspace}`)
|
|
51
|
+
});
|
|
121
52
|
}
|
|
53
|
+
ctx.ui?.error?.(`${report.totalIssues} dead code issue(s) found`, { sections });
|
|
54
|
+
return { exitCode: 1 };
|
|
122
55
|
}
|
|
123
56
|
}
|
|
124
|
-
|
|
125
|
-
if (allWarnings.length > 0) {
|
|
126
|
-
sections.push({
|
|
127
|
-
header: "Warnings",
|
|
128
|
-
items: allWarnings.slice(0, 10)
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
const totalDeadKb = (result.summary.totalDeadBytes / 1024).toFixed(1);
|
|
132
|
-
const summaryItems = [
|
|
133
|
-
`Packages scanned: ${result.summary.totalPackages}`,
|
|
134
|
-
`Total source files: ${result.summary.totalFiles}`,
|
|
135
|
-
`Alive files: ${result.summary.totalAlive}`,
|
|
136
|
-
`Dead files: ${result.summary.totalDead}`,
|
|
137
|
-
result.summary.totalDead > 0 ? `Dead code size: ${totalDeadKb} KB` : null,
|
|
138
|
-
result.summary.emptyDirectories.length > 0 ? `Empty directories: ${result.summary.emptyDirectories.length}` : null,
|
|
139
|
-
`Duration: ${(result.duration / 1e3).toFixed(1)}s`,
|
|
140
|
-
result.cached ? "(cached \u2014 use --refresh to rescan)" : null
|
|
141
|
-
].filter(Boolean);
|
|
142
|
-
sections.push({ header: "Summary", items: summaryItems });
|
|
143
|
-
if (result.summary.totalDead > 0) {
|
|
144
|
-
sections.push({
|
|
145
|
-
header: "Next Steps",
|
|
146
|
-
items: [
|
|
147
|
-
"Run with --auto-remove --dry-run to preview removal",
|
|
148
|
-
"Run with --auto-remove to remove and create backup",
|
|
149
|
-
"Run with --verbose to see entry points"
|
|
150
|
-
]
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
const title = result.summary.totalDead === 0 ? "No dead files found" : `${result.summary.totalDead} dead file(s) found`;
|
|
154
|
-
ui?.success?.("Dead code analysis completed", { title, sections });
|
|
155
|
-
}
|
|
156
|
-
function outputRemovalReport(result, flags, ui) {
|
|
157
|
-
const isDryRun = flags["dry-run"];
|
|
158
|
-
const prefix = isDryRun ? "[DRY RUN] Would" : "Successfully";
|
|
159
|
-
const sections = [];
|
|
160
|
-
const items = [
|
|
161
|
-
`${prefix} remove ${result.filesRemoved} file(s)`,
|
|
162
|
-
`${prefix} free ${(result.bytesRemoved / 1024).toFixed(1)} KB`
|
|
163
|
-
];
|
|
164
|
-
if (result.emptyDirsRemoved > 0) {
|
|
165
|
-
items.push(`${prefix} remove ${result.emptyDirsRemoved} empty director${result.emptyDirsRemoved === 1 ? "y" : "ies"}`);
|
|
166
|
-
}
|
|
167
|
-
if (result.exportsCleanedUp > 0) {
|
|
168
|
-
items.push(`${prefix} clean ${result.exportsCleanedUp} package.json export(s)`);
|
|
169
|
-
}
|
|
170
|
-
sections.push({ header: isDryRun ? "Preview" : "Removal Complete", items });
|
|
171
|
-
if (!isDryRun) {
|
|
172
|
-
sections.push({
|
|
173
|
-
header: "Backup",
|
|
174
|
-
items: [
|
|
175
|
-
`Backup ID: ${result.backupId}`,
|
|
176
|
-
`To restore: pnpm kb quality:dead-code --restore ${result.backupId}`
|
|
177
|
-
]
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
const fileItems = [];
|
|
181
|
-
for (const file of result.manifest.removedFiles.slice(0, 10)) {
|
|
182
|
-
const sizeKb = (file.sizeBytes / 1024).toFixed(1);
|
|
183
|
-
fileItems.push(`${file.backupPath} (${sizeKb} KB)`);
|
|
184
|
-
}
|
|
185
|
-
if (result.manifest.removedFiles.length > 10) {
|
|
186
|
-
fileItems.push(`... and ${result.manifest.removedFiles.length - 10} more`);
|
|
187
|
-
}
|
|
188
|
-
sections.push({ header: "Files", items: fileItems });
|
|
189
|
-
const title = isDryRun ? `[DRY RUN] Would remove ${result.filesRemoved} file(s)` : `Removed ${result.filesRemoved} file(s)`;
|
|
190
|
-
ui?.success?.(title, { title, sections });
|
|
191
|
-
}
|
|
192
|
-
function outputBackupList(backups, ui) {
|
|
193
|
-
if (backups.length === 0) {
|
|
194
|
-
ui?.info?.("No backups found.");
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
const sections = [];
|
|
198
|
-
for (const backup of backups) {
|
|
199
|
-
const date = new Date(backup.createdAt).toLocaleString();
|
|
200
|
-
const items = [
|
|
201
|
-
`Date: ${date}`,
|
|
202
|
-
`Git: ${backup.gitBranch} @ ${backup.gitSha.slice(0, 8)}`,
|
|
203
|
-
`Files: ${backup.totalFilesRemoved}`,
|
|
204
|
-
`Size: ${(backup.totalBytesRemoved / 1024).toFixed(1)} KB`,
|
|
205
|
-
`Restore: pnpm kb quality:dead-code --restore ${backup.id}`
|
|
206
|
-
];
|
|
207
|
-
sections.push({ header: `Backup: ${backup.id}`, items });
|
|
208
|
-
}
|
|
209
|
-
ui?.success?.(`${backups.length} backup(s) found`, {
|
|
210
|
-
title: "Dead Code Backups",
|
|
211
|
-
sections
|
|
212
|
-
});
|
|
213
|
-
}
|
|
57
|
+
});
|
|
214
58
|
|
|
215
59
|
export { dead_code_default as default };
|
|
216
60
|
//# sourceMappingURL=dead-code.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/cli/commands/dead-code.ts"],"names":["result"],"mappings":"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","file":"dead-code.js","sourcesContent":["/**\n * quality:dead-code - Detect and optionally remove dead source files\n *\n * Uses reachability analysis: builds import graph, walks from entry points,\n * files not reachable are dead. Zero false positives by design.\n */\n\nimport { defineCommand, type PluginContextV3 } from '@kb-labs/sdk';\nimport type { UIFacade } from '@kb-labs/sdk';\nimport type { DeadCodeResult, DeadCodeRemovalResult, DeadCodeBackupManifest } from '@kb-labs/quality-contracts';\nimport { CACHE_KEYS } from '@kb-labs/quality-contracts';\nimport {\n scanDeadFiles,\n removeDeadFiles,\n restoreFromBackup,\n listBackups,\n} from '@kb-labs/quality-core/dead-code';\nimport type { DeadCodeFlags } from './flags.js';\n\ntype DeadCodeInput = DeadCodeFlags & { argv?: string[] };\n\ntype DeadCodeCommandResult = {\n exitCode: number;\n result?: DeadCodeResult | DeadCodeRemovalResult | DeadCodeBackupManifest[];\n meta?: Record<string, unknown>;\n};\n\nexport default defineCommand({\n id: 'quality:dead-code',\n description: 'Detect and optionally remove dead (unreachable) source files',\n\n handler: {\n async execute(\n ctx: PluginContextV3,\n input: DeadCodeInput,\n ): Promise<DeadCodeCommandResult> {\n const { ui, platform } = ctx;\n // V3: Flags may come wrapped in input.flags or passed directly\n const flags = ('flags' in input && typeof (input as { flags?: unknown }).flags === 'object' && (input as { flags?: unknown }).flags !== null)\n ? (input as { flags: DeadCodeInput }).flags\n : input;\n\n // --- Sub-operations ---\n\n // List backups\n if (flags['list-backups']) {\n const backups = listBackups(ctx.cwd);\n if (flags.json) {\n ui?.json?.(backups);\n } else {\n outputBackupList(backups, ui);\n }\n return { exitCode: 0, result: backups };\n }\n\n // Restore from backup\n if (flags.restore) {\n try {\n const result = await restoreFromBackup(ctx.cwd, flags.restore);\n if (flags.json) {\n ui?.json?.(result);\n } else {\n ui?.success?.(`Restored ${result.restoredFiles} file(s) from backup ${flags.restore}`, {});\n if (result.restoredExports > 0) {\n ui?.info?.(`Note: ${result.restoredExports} package.json export(s) were cleaned. You may need to rebuild.`);\n }\n }\n return { exitCode: 0 };\n } catch (err: unknown) {\n if (flags.json) {\n ui?.json?.({ error: err instanceof Error ? err.message : String(err) });\n } else {\n ui?.error?.(err instanceof Error ? err.message : String(err));\n }\n return { exitCode: 1 };\n }\n }\n\n // --- Main scan flow ---\n\n // Check cache\n const cacheKey = `${CACHE_KEYS.DEAD_CODE}:${flags.package || 'all'}`;\n if (!flags.refresh && !flags['auto-remove']) {\n const cached = await platform.cache.get<DeadCodeResult>(cacheKey);\n if (cached) {\n outputDeadCodeReport({ ...cached, cached: true }, flags, ui);\n return { exitCode: cached.summary.totalDead > 0 ? 1 : 0, result: cached };\n }\n }\n\n // Run scan\n const result = await scanDeadFiles(ctx.cwd, {\n packageFilter: flags.package,\n verbose: flags.verbose,\n });\n\n // Cache results for 5 minutes\n await platform.cache.set(cacheKey, result, 5 * 60 * 1000);\n\n // Track analytics\n await platform.analytics.track('quality:dead-code', {\n totalPackages: result.summary.totalPackages,\n totalFiles: result.summary.totalFiles,\n totalDead: result.summary.totalDead,\n totalDeadBytes: result.summary.totalDeadBytes,\n duration: result.duration,\n autoRemove: !!flags['auto-remove'],\n dryRun: !!flags['dry-run'],\n });\n\n // Auto-remove flow\n if (flags['auto-remove']) {\n if (result.summary.totalDead === 0) {\n if (flags.json) {\n ui?.json?.({ message: 'No dead files found', ...result });\n } else {\n ui?.success?.('No dead files found. Nothing to remove.', {});\n }\n return { exitCode: 0, result };\n }\n\n const removalResult = await removeDeadFiles(ctx.cwd, result, {\n dryRun: flags['dry-run'],\n });\n\n if (flags.json) {\n ui?.json?.(removalResult);\n } else {\n outputRemovalReport(removalResult, flags, ui);\n }\n\n return { exitCode: 0, result: removalResult };\n }\n\n // Output scan results\n outputDeadCodeReport({ ...result, cached: false }, flags, ui);\n\n return {\n exitCode: result.summary.totalDead > 0 ? 1 : 0,\n result,\n };\n },\n },\n});\n\n// --- Output helpers ---\n\nfunction outputDeadCodeReport(\n result: DeadCodeResult & { cached?: boolean },\n flags: DeadCodeFlags,\n ui: UIFacade | undefined,\n): void {\n if (flags.json) {\n ui?.json?.(result);\n return;\n }\n\n const sections: Array<{ header: string; items: string[] }> = [];\n\n // Per-package results (only packages with dead files)\n const packagesWithDead = result.packages.filter(p => p.deadFiles.length > 0);\n\n if (packagesWithDead.length > 0) {\n const items: string[] = [];\n for (const pkg of packagesWithDead) {\n items.push(`${pkg.packageName} (${pkg.deadFiles.length} dead file${pkg.deadFiles.length === 1 ? '' : 's'})`);\n for (const dead of pkg.deadFiles.slice(0, 5)) {\n const sizeKb = (dead.sizeBytes / 1024).toFixed(1);\n items.push(` ${dead.relativePath} (${sizeKb} KB)`);\n }\n if (pkg.deadFiles.length > 5) {\n items.push(` ... and ${pkg.deadFiles.length - 5} more`);\n }\n }\n sections.push({ header: 'Dead Files', items });\n }\n\n // Verbose: show entry points\n if (flags.verbose) {\n for (const pkg of result.packages) {\n if (pkg.entryPoints.length > 0) {\n const items = pkg.entryPoints.slice(0, 10).map(ep => ` ${ep}`);\n if (pkg.entryPoints.length > 10) {\n items.push(` ... and ${pkg.entryPoints.length - 10} more`);\n }\n sections.push({ header: `Entry Points: ${pkg.packageName}`, items });\n }\n }\n }\n\n // Warnings\n const allWarnings = result.packages.flatMap(p => p.warnings);\n if (allWarnings.length > 0) {\n sections.push({\n header: 'Warnings',\n items: allWarnings.slice(0, 10),\n });\n }\n\n // Summary\n const totalDeadKb = (result.summary.totalDeadBytes / 1024).toFixed(1);\n const summaryItems = [\n `Packages scanned: ${result.summary.totalPackages}`,\n `Total source files: ${result.summary.totalFiles}`,\n `Alive files: ${result.summary.totalAlive}`,\n `Dead files: ${result.summary.totalDead}`,\n result.summary.totalDead > 0 ? `Dead code size: ${totalDeadKb} KB` : null,\n result.summary.emptyDirectories.length > 0\n ? `Empty directories: ${result.summary.emptyDirectories.length}`\n : null,\n `Duration: ${(result.duration / 1000).toFixed(1)}s`,\n result.cached ? '(cached — use --refresh to rescan)' : null,\n ].filter(Boolean) as string[];\n sections.push({ header: 'Summary', items: summaryItems });\n\n // Recommendations\n if (result.summary.totalDead > 0) {\n sections.push({\n header: 'Next Steps',\n items: [\n 'Run with --auto-remove --dry-run to preview removal',\n 'Run with --auto-remove to remove and create backup',\n 'Run with --verbose to see entry points',\n ],\n });\n }\n\n const title =\n result.summary.totalDead === 0\n ? 'No dead files found'\n : `${result.summary.totalDead} dead file(s) found`;\n\n ui?.success?.('Dead code analysis completed', { title, sections });\n}\n\nfunction outputRemovalReport(\n result: DeadCodeRemovalResult,\n flags: DeadCodeFlags,\n ui: UIFacade | undefined,\n): void {\n const isDryRun = flags['dry-run'];\n const prefix = isDryRun ? '[DRY RUN] Would' : 'Successfully';\n\n const sections: Array<{ header: string; items: string[] }> = [];\n\n const items = [\n `${prefix} remove ${result.filesRemoved} file(s)`,\n `${prefix} free ${(result.bytesRemoved / 1024).toFixed(1)} KB`,\n ];\n\n if (result.emptyDirsRemoved > 0) {\n items.push(`${prefix} remove ${result.emptyDirsRemoved} empty director${result.emptyDirsRemoved === 1 ? 'y' : 'ies'}`);\n }\n if (result.exportsCleanedUp > 0) {\n items.push(`${prefix} clean ${result.exportsCleanedUp} package.json export(s)`);\n }\n\n sections.push({ header: isDryRun ? 'Preview' : 'Removal Complete', items });\n\n if (!isDryRun) {\n sections.push({\n header: 'Backup',\n items: [\n `Backup ID: ${result.backupId}`,\n `To restore: pnpm kb quality:dead-code --restore ${result.backupId}`,\n ],\n });\n }\n\n // Show removed files\n const fileItems: string[] = [];\n for (const file of result.manifest.removedFiles.slice(0, 10)) {\n const sizeKb = (file.sizeBytes / 1024).toFixed(1);\n fileItems.push(`${file.backupPath} (${sizeKb} KB)`);\n }\n if (result.manifest.removedFiles.length > 10) {\n fileItems.push(`... and ${result.manifest.removedFiles.length - 10} more`);\n }\n sections.push({ header: 'Files', items: fileItems });\n\n const title = isDryRun\n ? `[DRY RUN] Would remove ${result.filesRemoved} file(s)`\n : `Removed ${result.filesRemoved} file(s)`;\n\n ui?.success?.(title, { title, sections });\n}\n\nfunction outputBackupList(\n backups: DeadCodeBackupManifest[],\n ui: UIFacade | undefined,\n): void {\n if (backups.length === 0) {\n ui?.info?.('No backups found.');\n return;\n }\n\n const sections: Array<{ header: string; items: string[] }> = [];\n\n for (const backup of backups) {\n const date = new Date(backup.createdAt).toLocaleString();\n const items = [\n `Date: ${date}`,\n `Git: ${backup.gitBranch} @ ${backup.gitSha.slice(0, 8)}`,\n `Files: ${backup.totalFilesRemoved}`,\n `Size: ${(backup.totalBytesRemoved / 1024).toFixed(1)} KB`,\n `Restore: pnpm kb quality:dead-code --restore ${backup.id}`,\n ];\n sections.push({ header: `Backup: ${backup.id}`, items });\n }\n\n ui?.success?.(`${backups.length} backup(s) found`, {\n title: 'Dead Code Backups',\n sections,\n });\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/cli/commands/dead-code.ts"],"names":[],"mappings":"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","file":"dead-code.js","sourcesContent":["import {\n defineCommand,\n useConfig,\n type CLIInput,\n type PluginContextV3,\n} from '@kb-labs/sdk';\nimport { runKnip } from '@kb-labs/quality-core';\nimport { defaultQualityConfig, type QualityPluginConfig } from '@kb-labs/quality-contracts';\nimport type { DeadCodeFlags } from './flags.js';\n\nexport default defineCommand<unknown, CLIInput<DeadCodeFlags>, { exitCode: number }>({\n id: 'quality:dead-code',\n description: 'Detect unused files, exports, and deps via knip',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<DeadCodeFlags>): Promise<{ exitCode: number }> {\n const { flags } = input;\n const config = await useConfig<QualityPluginConfig>();\n const cwd = ctx.cwd ?? process.cwd();\n const cfg = config ?? defaultQualityConfig;\n\n if (!cfg.knip.enabled) {\n ctx.ui?.success?.('knip is disabled in config (knip.enabled = false)');\n return { exitCode: 0 };\n }\n\n const report = await runKnip({ shell: ctx.api.shell, rootDir: cwd });\n\n if (flags.json) {\n ctx.ui?.json?.(report);\n return { exitCode: report.totalIssues > 0 ? 1 : 0 };\n }\n\n if (report.totalIssues === 0) {\n ctx.ui?.success?.('No dead code detected');\n return { exitCode: 0 };\n }\n\n const sections: Array<{ header: string; items: string[] }> = [];\n\n if (report.unusedFiles.length > 0) {\n sections.push({\n header: `Unused files (${report.unusedFiles.length})`,\n items: report.unusedFiles,\n });\n }\n\n if (report.unusedExports.length > 0) {\n sections.push({\n header: `Unused exports (${report.unusedExports.length})`,\n items: report.unusedExports.map(e => `${e.file} ${e.symbol}`),\n });\n }\n\n if (report.unusedDependencies.length > 0) {\n sections.push({\n header: `Unused dependencies (${report.unusedDependencies.length})`,\n items: report.unusedDependencies.map(d => `${d.package} in ${d.workspace}`),\n });\n }\n\n if (report.unlistedDependencies.length > 0) {\n sections.push({\n header: `Unlisted dependencies (${report.unlistedDependencies.length})`,\n items: report.unlistedDependencies.map(d => `${d.package} in ${d.workspace}`),\n });\n }\n\n ctx.ui?.error?.(`${report.totalIssues} dead code issue(s) found`, { sections });\n return { exitCode: 1 };\n },\n },\n});\n"]}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import * as _kb_labs_shared_command_kit from '@kb-labs/shared-command-kit';
|
|
2
|
+
import { CLIInput } from '@kb-labs/sdk';
|
|
2
3
|
import { FixDepsFlags } from './flags.js';
|
|
3
4
|
|
|
4
|
-
type FixDepsInput = FixDepsFlags & {
|
|
5
|
-
argv?: string[];
|
|
6
|
-
};
|
|
7
5
|
interface FixResult {
|
|
8
6
|
packagesScanned: number;
|
|
9
7
|
removedDeps: Array<{
|
|
@@ -21,8 +19,7 @@ interface FixResult {
|
|
|
21
19
|
to: string;
|
|
22
20
|
packages: string[];
|
|
23
21
|
}>;
|
|
24
|
-
dryRun: boolean;
|
|
25
22
|
}
|
|
26
|
-
declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown,
|
|
23
|
+
declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, CLIInput<FixDepsFlags>, FixResult>;
|
|
27
24
|
|
|
28
25
|
export { _default as default };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineCommand, useLoader } from '@kb-labs/sdk';
|
|
1
|
+
import { defineCommand, validationError, useLoader } from '@kb-labs/sdk';
|
|
2
2
|
import fs from 'fs';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
|
|
@@ -7,10 +7,39 @@ var fix_deps_default = defineCommand({
|
|
|
7
7
|
id: "quality:fix-deps",
|
|
8
8
|
description: "Auto-fix dependency issues",
|
|
9
9
|
handler: {
|
|
10
|
+
async intent(_ctx, input) {
|
|
11
|
+
const flags = input.flags;
|
|
12
|
+
const removeUnused = flags["remove-unused"] || flags.all;
|
|
13
|
+
const addMissing = flags["add-missing"] || flags.all;
|
|
14
|
+
const alignVersions = flags["align-versions"] || flags.all;
|
|
15
|
+
const packages = findPackages(_ctx.cwd);
|
|
16
|
+
const preview = await runAnalysis(packages, { removeUnused, addMissing, alignVersions, dryRun: true });
|
|
17
|
+
const operations = [
|
|
18
|
+
...preview.alignedDeps.map((a) => ({
|
|
19
|
+
type: "update",
|
|
20
|
+
resource: "dependency",
|
|
21
|
+
details: { dep: a.dep, from: a.from, to: a.to, packages: a.packages }
|
|
22
|
+
})),
|
|
23
|
+
...preview.addedDeps.map((a) => ({
|
|
24
|
+
type: "create",
|
|
25
|
+
resource: "dependency",
|
|
26
|
+
details: { package: a.package, dep: a.dep, version: a.version }
|
|
27
|
+
})),
|
|
28
|
+
...preview.removedDeps.map((r) => ({
|
|
29
|
+
type: "delete",
|
|
30
|
+
resource: "dependency",
|
|
31
|
+
details: { package: r.package, dep: r.dep }
|
|
32
|
+
}))
|
|
33
|
+
];
|
|
34
|
+
const total = operations.length;
|
|
35
|
+
return {
|
|
36
|
+
summary: total > 0 ? `Fix ${total} dependency issue(s) across ${preview.packagesScanned} packages` : `No dependency issues found in ${preview.packagesScanned} packages`,
|
|
37
|
+
operations
|
|
38
|
+
};
|
|
39
|
+
},
|
|
10
40
|
async execute(ctx, input) {
|
|
11
41
|
const { ui, platform } = ctx;
|
|
12
|
-
const flags =
|
|
13
|
-
const dryRun = flags["dry-run"] ?? false;
|
|
42
|
+
const flags = input.flags;
|
|
14
43
|
const removeUnused = flags["remove-unused"] || flags.all;
|
|
15
44
|
const addMissing = flags["add-missing"] || flags.all;
|
|
16
45
|
const alignVersions = flags["align-versions"] || flags.all;
|
|
@@ -21,52 +50,45 @@ var fix_deps_default = defineCommand({
|
|
|
21
50
|
return { exitCode: 0 };
|
|
22
51
|
}
|
|
23
52
|
if (!removeUnused && !addMissing && !alignVersions) {
|
|
24
|
-
|
|
53
|
+
validationError(ctx, "No fix options specified", "Use --remove-unused, --add-missing, --align-versions, or --all", flags.json);
|
|
25
54
|
return { exitCode: 1 };
|
|
26
55
|
}
|
|
27
56
|
const loader = useLoader("Scanning packages...");
|
|
28
57
|
loader.start();
|
|
29
|
-
const result = {
|
|
30
|
-
packagesScanned: 0,
|
|
31
|
-
removedDeps: [],
|
|
32
|
-
addedDeps: [],
|
|
33
|
-
alignedDeps: [],
|
|
34
|
-
dryRun
|
|
35
|
-
};
|
|
36
58
|
const packages = findPackages(ctx.cwd);
|
|
37
|
-
result.packagesScanned = packages.length;
|
|
38
59
|
loader.update({ text: `Scanned ${packages.length} packages` });
|
|
39
|
-
|
|
40
|
-
loader.update({ text: "Analyzing duplicate dependencies..." });
|
|
41
|
-
const aligned = await alignDuplicateVersions(packages, dryRun);
|
|
42
|
-
result.alignedDeps = aligned;
|
|
43
|
-
}
|
|
44
|
-
if (addMissing) {
|
|
45
|
-
loader.update({ text: "Checking for missing workspace dependencies..." });
|
|
46
|
-
const added = await addMissingWorkspaceDeps(packages, dryRun);
|
|
47
|
-
result.addedDeps = added;
|
|
48
|
-
}
|
|
49
|
-
if (removeUnused) {
|
|
50
|
-
loader.update({ text: "Checking for unused dependencies..." });
|
|
51
|
-
const removed = await removeUnusedDeps(packages, dryRun);
|
|
52
|
-
result.removedDeps = removed;
|
|
53
|
-
}
|
|
60
|
+
const result = await runAnalysis(packages, { removeUnused, addMissing, alignVersions, dryRun: false });
|
|
54
61
|
loader.succeed("Dependency analysis completed");
|
|
55
62
|
await platform.analytics.track("quality:fix-deps", {
|
|
56
|
-
dryRun,
|
|
63
|
+
dryRun: false,
|
|
57
64
|
packagesScanned: result.packagesScanned,
|
|
58
65
|
removedCount: result.removedDeps.length,
|
|
59
66
|
addedCount: result.addedDeps.length,
|
|
60
67
|
alignedCount: result.alignedDeps.length
|
|
61
68
|
});
|
|
62
|
-
outputResults(result, flags, ui);
|
|
63
|
-
return {
|
|
64
|
-
exitCode: 0,
|
|
65
|
-
result
|
|
66
|
-
};
|
|
69
|
+
outputResults({ ...result, dryRun: false }, flags, ui);
|
|
70
|
+
return { exitCode: 0, result };
|
|
67
71
|
}
|
|
68
72
|
}
|
|
69
73
|
});
|
|
74
|
+
async function runAnalysis(packages, opts) {
|
|
75
|
+
const result = {
|
|
76
|
+
packagesScanned: packages.length,
|
|
77
|
+
removedDeps: [],
|
|
78
|
+
addedDeps: [],
|
|
79
|
+
alignedDeps: []
|
|
80
|
+
};
|
|
81
|
+
if (opts.alignVersions) {
|
|
82
|
+
result.alignedDeps = await alignDuplicateVersions(packages, opts.dryRun);
|
|
83
|
+
}
|
|
84
|
+
if (opts.addMissing) {
|
|
85
|
+
result.addedDeps = await addMissingWorkspaceDeps(packages, opts.dryRun);
|
|
86
|
+
}
|
|
87
|
+
if (opts.removeUnused) {
|
|
88
|
+
result.removedDeps = await removeUnusedDeps(packages, opts.dryRun);
|
|
89
|
+
}
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
70
92
|
function findPackages(rootDir) {
|
|
71
93
|
const packages = [];
|
|
72
94
|
if (!fs.existsSync(rootDir)) {
|
|
@@ -161,12 +183,7 @@ async function alignDuplicateVersions(packages, dryRun) {
|
|
|
161
183
|
continue;
|
|
162
184
|
}
|
|
163
185
|
for (const { version, packages: pkgNames } of versionCounts.slice(1)) {
|
|
164
|
-
aligned.push({
|
|
165
|
-
dep,
|
|
166
|
-
from: version,
|
|
167
|
-
to: targetVersion,
|
|
168
|
-
packages: pkgNames
|
|
169
|
-
});
|
|
186
|
+
aligned.push({ dep, from: version, to: targetVersion, packages: pkgNames });
|
|
170
187
|
if (!dryRun) {
|
|
171
188
|
for (const pkgName of pkgNames) {
|
|
172
189
|
const pkg = packages.find((p) => p.name === pkgName);
|
|
@@ -207,11 +224,7 @@ async function addMissingWorkspaceDeps(packages, dryRun) {
|
|
|
207
224
|
};
|
|
208
225
|
for (const imp of imports) {
|
|
209
226
|
if (imp.startsWith("@kb-labs/") && workspacePackages.has(imp) && !currentDeps[imp]) {
|
|
210
|
-
added.push({
|
|
211
|
-
package: pkg.name,
|
|
212
|
-
dep: imp,
|
|
213
|
-
version: "workspace:*"
|
|
214
|
-
});
|
|
227
|
+
added.push({ package: pkg.name, dep: imp, version: "workspace:*" });
|
|
215
228
|
if (!dryRun) {
|
|
216
229
|
if (!pkg.json.dependencies) {
|
|
217
230
|
pkg.json.dependencies = {};
|
|
@@ -242,10 +255,7 @@ async function removeUnusedDeps(packages, dryRun) {
|
|
|
242
255
|
continue;
|
|
243
256
|
}
|
|
244
257
|
if (!imports.has(dep)) {
|
|
245
|
-
removed.push({
|
|
246
|
-
package: pkg.name,
|
|
247
|
-
dep
|
|
248
|
-
});
|
|
258
|
+
removed.push({ package: pkg.name, dep });
|
|
249
259
|
if (!dryRun) {
|
|
250
260
|
delete pkg.json.dependencies?.[dep];
|
|
251
261
|
delete pkg.json.devDependencies?.[dep];
|
|
@@ -321,7 +331,7 @@ function outputStats(stats, flags, ui) {
|
|
|
321
331
|
});
|
|
322
332
|
}
|
|
323
333
|
ui?.success?.("Dependency statistics", {
|
|
324
|
-
title: "
|
|
334
|
+
title: "Dependency Statistics",
|
|
325
335
|
sections
|
|
326
336
|
});
|
|
327
337
|
}
|
|
@@ -331,55 +341,36 @@ function outputResults(result, flags, ui) {
|
|
|
331
341
|
return;
|
|
332
342
|
}
|
|
333
343
|
const sections = [];
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
`
|
|
337
|
-
|
|
338
|
-
sections.push({ header: "Summary", items: summaryItems });
|
|
344
|
+
sections.push({
|
|
345
|
+
header: "Summary",
|
|
346
|
+
items: [`Packages Scanned: ${result.packagesScanned}`]
|
|
347
|
+
});
|
|
339
348
|
if (result.alignedDeps.length > 0) {
|
|
340
|
-
const
|
|
341
|
-
(a) => `${a.dep}: ${a.from} \u2192 ${a.to} (${a.packages.length} packages)`
|
|
342
|
-
);
|
|
343
|
-
sections.push({ header: "Aligned Versions", items: alignedItems.slice(0, 10) });
|
|
349
|
+
const items = result.alignedDeps.slice(0, 10).map((a) => `${a.dep}: ${a.from} \u2192 ${a.to} (${a.packages.length} packages)`);
|
|
344
350
|
if (result.alignedDeps.length > 10) {
|
|
345
|
-
|
|
346
|
-
if (lastSection) {
|
|
347
|
-
lastSection.items.push(`... and ${result.alignedDeps.length - 10} more`);
|
|
348
|
-
}
|
|
351
|
+
items.push(`... and ${result.alignedDeps.length - 10} more`);
|
|
349
352
|
}
|
|
353
|
+
sections.push({ header: "Aligned Versions", items });
|
|
350
354
|
}
|
|
351
355
|
if (result.addedDeps.length > 0) {
|
|
352
|
-
const
|
|
353
|
-
sections.push({ header: "Added Dependencies", items: addedItems.slice(0, 10) });
|
|
356
|
+
const items = result.addedDeps.slice(0, 10).map((a) => `${a.package}: +${a.dep}`);
|
|
354
357
|
if (result.addedDeps.length > 10) {
|
|
355
|
-
|
|
356
|
-
if (lastSection) {
|
|
357
|
-
lastSection.items.push(`... and ${result.addedDeps.length - 10} more`);
|
|
358
|
-
}
|
|
358
|
+
items.push(`... and ${result.addedDeps.length - 10} more`);
|
|
359
359
|
}
|
|
360
|
+
sections.push({ header: "Added Dependencies", items });
|
|
360
361
|
}
|
|
361
362
|
if (result.removedDeps.length > 0) {
|
|
362
|
-
const
|
|
363
|
-
sections.push({ header: "Removed Dependencies", items: removedItems.slice(0, 10) });
|
|
363
|
+
const items = result.removedDeps.slice(0, 10).map((r) => `${r.package}: -${r.dep}`);
|
|
364
364
|
if (result.removedDeps.length > 10) {
|
|
365
|
-
|
|
366
|
-
if (lastSection) {
|
|
367
|
-
lastSection.items.push(`... and ${result.removedDeps.length - 10} more`);
|
|
368
|
-
}
|
|
365
|
+
items.push(`... and ${result.removedDeps.length - 10} more`);
|
|
369
366
|
}
|
|
367
|
+
sections.push({ header: "Removed Dependencies", items });
|
|
370
368
|
}
|
|
371
369
|
if (result.alignedDeps.length === 0 && result.addedDeps.length === 0 && result.removedDeps.length === 0) {
|
|
372
|
-
sections.push({ header: "Result", items: ["
|
|
373
|
-
}
|
|
374
|
-
if (result.dryRun && (result.alignedDeps.length > 0 || result.addedDeps.length > 0 || result.removedDeps.length > 0)) {
|
|
375
|
-
sections.push({
|
|
376
|
-
header: "Next Steps",
|
|
377
|
-
items: ["Remove --dry-run flag to apply changes", "Run `pnpm install` after applying changes"]
|
|
378
|
-
});
|
|
370
|
+
sections.push({ header: "Result", items: ["No issues found!"] });
|
|
379
371
|
}
|
|
380
|
-
const title = result.dryRun ? "\u{1F50D} Dependency Fix Preview" : "\u2705 Dependency Fix Complete";
|
|
381
372
|
ui?.success?.("Dependency fix completed", {
|
|
382
|
-
title,
|
|
373
|
+
title: "Dependency Fix Complete",
|
|
383
374
|
sections
|
|
384
375
|
});
|
|
385
376
|
}
|