packagepurge 1.0.0 → 2.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 (40) hide show
  1. package/.agent/workflows/build.md +58 -0
  2. package/.github/workflows/release.yml +176 -0
  3. package/README.md +215 -49
  4. package/dist/cli/index.d.ts +1 -0
  5. package/dist/cli/index.js +122 -132
  6. package/dist/cli/index.js.map +1 -1
  7. package/dist/core/bindings.d.ts +11 -0
  8. package/dist/core/bindings.d.ts.map +1 -1
  9. package/dist/core/bindings.js +40 -94
  10. package/dist/core/bindings.js.map +1 -1
  11. package/dist/utils/core-utils.d.ts +31 -0
  12. package/dist/utils/core-utils.d.ts.map +1 -0
  13. package/dist/utils/core-utils.js +121 -0
  14. package/dist/utils/core-utils.js.map +1 -0
  15. package/dist/utils/formatter.d.ts +63 -0
  16. package/dist/utils/formatter.d.ts.map +1 -0
  17. package/dist/utils/formatter.js +295 -0
  18. package/dist/utils/formatter.js.map +1 -0
  19. package/package.json +3 -3
  20. package/core/src/arc_lfu.rs +0 -91
  21. package/core/src/cache.rs +0 -205
  22. package/core/src/lockfiles.rs +0 -112
  23. package/core/src/main.rs +0 -125
  24. package/core/src/ml.rs +0 -188
  25. package/core/src/optimization.rs +0 -314
  26. package/core/src/safety.rs +0 -103
  27. package/core/src/scanner.rs +0 -136
  28. package/core/src/symlink.rs +0 -223
  29. package/core/src/types.rs +0 -87
  30. package/core/src/usage_tracker.rs +0 -107
  31. package/src/cli/index.ts +0 -212
  32. package/src/core/bindings.ts +0 -157
  33. package/src/managers/base-manager.ts +0 -117
  34. package/src/managers/index.ts +0 -32
  35. package/src/managers/npm-manager.ts +0 -96
  36. package/src/managers/pnpm-manager.ts +0 -107
  37. package/src/managers/yarn-manager.ts +0 -112
  38. package/src/types/index.ts +0 -97
  39. package/src/utils/logger.ts +0 -50
  40. package/tsconfig.json +0 -22
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Check if running on Windows
3
+ */
4
+ export declare function isWindows(): boolean;
5
+ /**
6
+ * Check if a file exists at the given path
7
+ */
8
+ export declare function fileExists(p: string): boolean;
9
+ /**
10
+ * Resolve an executable from PATH environment variable
11
+ */
12
+ export declare function resolveFromPATH(name: string): string | null;
13
+ /**
14
+ * Get the path to the packagepurge-core binary
15
+ * Search order:
16
+ * 1. PACKAGEPURGE_CORE environment variable
17
+ * 2. Local release build (core/target/release)
18
+ * 3. Local debug build (core/target/debug)
19
+ * 4. PATH
20
+ */
21
+ export declare function coreBinary(): string;
22
+ export interface CoreResult {
23
+ stdout: string;
24
+ stderr: string;
25
+ code: number;
26
+ }
27
+ /**
28
+ * Run the packagepurge-core binary with the given arguments
29
+ */
30
+ export declare function runCore(args: string[]): Promise<CoreResult>;
31
+ //# sourceMappingURL=core-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core-utils.d.ts","sourceRoot":"","sources":["../../src/utils/core-utils.ts"],"names":[],"mappings":"AAOA;;GAEG;AACH,wBAAgB,SAAS,IAAI,OAAO,CAEnC;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAM7C;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAU3D;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAiBnC;AAED,MAAM,WAAW,UAAU;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAW3D"}
@@ -0,0 +1,121 @@
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.isWindows = isWindows;
37
+ exports.fileExists = fileExists;
38
+ exports.resolveFromPATH = resolveFromPATH;
39
+ exports.coreBinary = coreBinary;
40
+ exports.runCore = runCore;
41
+ /**
42
+ * Core utilities for PackagePurge - shared between CLI and bindings
43
+ */
44
+ const child_process_1 = require("child_process");
45
+ const path = __importStar(require("path"));
46
+ const fs = __importStar(require("fs"));
47
+ /**
48
+ * Check if running on Windows
49
+ */
50
+ function isWindows() {
51
+ return process.platform === 'win32';
52
+ }
53
+ /**
54
+ * Check if a file exists at the given path
55
+ */
56
+ function fileExists(p) {
57
+ try {
58
+ return fs.existsSync(p);
59
+ }
60
+ catch {
61
+ return false;
62
+ }
63
+ }
64
+ /**
65
+ * Resolve an executable from PATH environment variable
66
+ */
67
+ function resolveFromPATH(name) {
68
+ const exts = isWindows() ? ['.exe', '.cmd', ''] : [''];
69
+ const parts = (process.env.PATH || '').split(path.delimiter);
70
+ for (const dir of parts) {
71
+ for (const ext of exts) {
72
+ const candidate = path.join(dir, name + ext);
73
+ if (fileExists(candidate))
74
+ return candidate;
75
+ }
76
+ }
77
+ return null;
78
+ }
79
+ /**
80
+ * Get the path to the packagepurge-core binary
81
+ * Search order:
82
+ * 1. PACKAGEPURGE_CORE environment variable
83
+ * 2. Local release build (core/target/release)
84
+ * 3. Local debug build (core/target/debug)
85
+ * 4. PATH
86
+ */
87
+ function coreBinary() {
88
+ // 1) Env override
89
+ const envPath = process.env.PACKAGEPURGE_CORE;
90
+ if (envPath && fileExists(envPath))
91
+ return envPath;
92
+ // 2) Local release/debug
93
+ const exe = isWindows() ? 'packagepurge_core.exe' : 'packagepurge-core';
94
+ const rel = path.join(process.cwd(), 'core', 'target', 'release', exe);
95
+ if (fileExists(rel))
96
+ return rel;
97
+ const dbg = path.join(process.cwd(), 'core', 'target', 'debug', exe);
98
+ if (fileExists(dbg))
99
+ return dbg;
100
+ // 3) PATH
101
+ const fromPath = resolveFromPATH(isWindows() ? 'packagepurge_core' : 'packagepurge-core');
102
+ if (fromPath)
103
+ return fromPath;
104
+ throw new Error('packagepurge-core binary not found. Build with "npm run build:core" or set PACKAGEPURGE_CORE.');
105
+ }
106
+ /**
107
+ * Run the packagepurge-core binary with the given arguments
108
+ */
109
+ function runCore(args) {
110
+ return new Promise((resolve, reject) => {
111
+ const bin = coreBinary();
112
+ const child = (0, child_process_1.spawn)(bin, args, { stdio: ['ignore', 'pipe', 'pipe'], env: process.env });
113
+ let out = '';
114
+ let err = '';
115
+ child.stdout.on('data', (d) => out += d.toString());
116
+ child.stderr.on('data', (d) => err += d.toString());
117
+ child.on('error', reject);
118
+ child.on('close', (code) => resolve({ stdout: out, stderr: err, code: code ?? 1 }));
119
+ });
120
+ }
121
+ //# sourceMappingURL=core-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core-utils.js","sourceRoot":"","sources":["../../src/utils/core-utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ export type OutputFormat = 'table' | 'json' | 'yaml';
2
+ /**
3
+ * Format bytes into a human-readable string
4
+ */
5
+ export declare function formatBytes(bytes: number): string;
6
+ /**
7
+ * Truncate a path to fit within maxLen characters
8
+ */
9
+ export declare function truncatePath(pathStr: string, maxLen: number): string;
10
+ export interface PlanItem {
11
+ target_path: string;
12
+ estimated_size_bytes: number;
13
+ reason: string;
14
+ }
15
+ export interface DryRunReport {
16
+ items: PlanItem[];
17
+ total_estimated_bytes: number;
18
+ }
19
+ export interface ScanOutput {
20
+ packages: Array<{
21
+ name: string;
22
+ version: string;
23
+ path: string;
24
+ size_bytes: number;
25
+ }>;
26
+ projects: Array<{
27
+ path: string;
28
+ manager?: string;
29
+ }>;
30
+ }
31
+ /**
32
+ * Format scan output as a human-readable table
33
+ */
34
+ export declare function formatScanAsTable(data: ScanOutput): void;
35
+ /**
36
+ * Format cleanup plan as a human-readable table
37
+ */
38
+ export declare function formatPlanAsTable(data: DryRunReport): void;
39
+ /**
40
+ * Format quarantine result
41
+ */
42
+ export declare function formatQuarantineResult(data: any[]): void;
43
+ /**
44
+ * Format rollback result
45
+ */
46
+ export declare function formatRollbackResult(data: any): void;
47
+ /**
48
+ * Format symlink result
49
+ */
50
+ export declare function formatSymlinkResult(data: any): void;
51
+ /**
52
+ * Format data as JSON
53
+ */
54
+ export declare function formatAsJSON(data: any, pretty?: boolean): string;
55
+ /**
56
+ * Format data as YAML
57
+ */
58
+ export declare function formatAsYAML(data: any): string;
59
+ /**
60
+ * Output data in the specified format
61
+ */
62
+ export declare function output(data: string | object, format: OutputFormat, type?: 'scan' | 'analyze' | 'optimize' | 'quarantine' | 'rollback' | 'symlink'): void;
63
+ //# sourceMappingURL=formatter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../../src/utils/formatter.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAErD;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMjD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAMpE;AAwED,MAAM,WAAW,QAAQ;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IACzB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,qBAAqB,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,UAAU;IACvB,QAAQ,EAAE,KAAK,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;IACH,QAAQ,EAAE,KAAK,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;CACN;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAoCxD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CA2C1D;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAgBxD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,GAAG,GAAG,IAAI,CAQpD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,GAAG,GAAG,IAAI,CASnD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,GAAG,EAAE,MAAM,GAAE,OAAc,GAAG,MAAM,CAEtE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM,CAQ9C;AAED;;GAEG;AACH,wBAAgB,MAAM,CAClB,IAAI,EAAE,MAAM,GAAG,MAAM,EACrB,MAAM,EAAE,YAAY,EACpB,IAAI,GAAE,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,YAAY,GAAG,UAAU,GAAG,SAAqB,GAC1F,IAAI,CAgDN"}
@@ -0,0 +1,295 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.formatBytes = formatBytes;
7
+ exports.truncatePath = truncatePath;
8
+ exports.formatScanAsTable = formatScanAsTable;
9
+ exports.formatPlanAsTable = formatPlanAsTable;
10
+ exports.formatQuarantineResult = formatQuarantineResult;
11
+ exports.formatRollbackResult = formatRollbackResult;
12
+ exports.formatSymlinkResult = formatSymlinkResult;
13
+ exports.formatAsJSON = formatAsJSON;
14
+ exports.formatAsYAML = formatAsYAML;
15
+ exports.output = output;
16
+ /**
17
+ * Output formatting utilities for PackagePurge CLI
18
+ * Provides human-readable, JSON, and YAML output formats
19
+ */
20
+ const chalk_1 = __importDefault(require("chalk"));
21
+ const yaml_1 = __importDefault(require("yaml"));
22
+ /**
23
+ * Format bytes into a human-readable string
24
+ */
25
+ function formatBytes(bytes) {
26
+ if (bytes === 0)
27
+ return '0 B';
28
+ const k = 1024;
29
+ const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
30
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
31
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
32
+ }
33
+ /**
34
+ * Truncate a path to fit within maxLen characters
35
+ */
36
+ function truncatePath(pathStr, maxLen) {
37
+ if (pathStr.length <= maxLen)
38
+ return pathStr;
39
+ const ellipsis = '...';
40
+ const start = Math.floor((maxLen - ellipsis.length) / 3);
41
+ const end = maxLen - ellipsis.length - start;
42
+ return pathStr.slice(0, start) + ellipsis + pathStr.slice(-end);
43
+ }
44
+ /**
45
+ * Get color for a cleanup reason
46
+ */
47
+ function getReasonColor(reason) {
48
+ switch (reason.toLowerCase()) {
49
+ case 'orphaned':
50
+ return chalk_1.default.yellow;
51
+ case 'old':
52
+ return chalk_1.default.gray;
53
+ case 'duplicate':
54
+ case 'duplicate_symlink_candidate':
55
+ return chalk_1.default.blue;
56
+ case 'ml_predicted_unused':
57
+ return chalk_1.default.magenta;
58
+ case 'size_pressure':
59
+ return chalk_1.default.red;
60
+ default:
61
+ return chalk_1.default.white;
62
+ }
63
+ }
64
+ /**
65
+ * Get human-readable reason text
66
+ */
67
+ function formatReason(reason) {
68
+ switch (reason.toLowerCase()) {
69
+ case 'orphaned':
70
+ return 'Orphaned';
71
+ case 'old':
72
+ return 'Outdated';
73
+ case 'duplicate':
74
+ return 'Duplicate';
75
+ case 'duplicate_symlink_candidate':
76
+ return 'Symlink Candidate';
77
+ case 'ml_predicted_unused':
78
+ return 'ML: Unused';
79
+ case 'size_pressure':
80
+ return 'Size Pressure';
81
+ default:
82
+ return reason;
83
+ }
84
+ }
85
+ /**
86
+ * Extract package name and version from a path
87
+ */
88
+ function extractPackageInfo(targetPath) {
89
+ // Try to extract from path like /path/to/node_modules/package-name or /path/to/cache/package@version
90
+ const parts = targetPath.split(/[\/\\]/);
91
+ const last = parts[parts.length - 1] || 'unknown';
92
+ // Check for @scope/package format
93
+ const nodeModulesIdx = parts.findIndex(p => p === 'node_modules');
94
+ if (nodeModulesIdx !== -1 && nodeModulesIdx < parts.length - 1) {
95
+ const pkgName = parts[nodeModulesIdx + 1];
96
+ if (pkgName.startsWith('@') && nodeModulesIdx < parts.length - 2) {
97
+ return { name: `${pkgName}/${parts[nodeModulesIdx + 2]}`, version: '-' };
98
+ }
99
+ return { name: pkgName, version: '-' };
100
+ }
101
+ // Try to parse name@version format
102
+ const atIdx = last.lastIndexOf('@');
103
+ if (atIdx > 0) {
104
+ return { name: last.slice(0, atIdx), version: last.slice(atIdx + 1) };
105
+ }
106
+ return { name: last, version: '-' };
107
+ }
108
+ /**
109
+ * Format scan output as a human-readable table
110
+ */
111
+ function formatScanAsTable(data) {
112
+ console.log(chalk_1.default.bold.cyan('\n📦 Packages Found\n'));
113
+ // Simple table without external dependency
114
+ const header = `${'Package'.padEnd(30)} ${'Version'.padEnd(12)} ${'Size'.padEnd(10)} Path`;
115
+ console.log(chalk_1.default.bold(header));
116
+ console.log('─'.repeat(100));
117
+ const sortedPackages = [...(data.packages || [])].sort((a, b) => b.size_bytes - a.size_bytes);
118
+ const displayLimit = 50;
119
+ const packagesToShow = sortedPackages.slice(0, displayLimit);
120
+ for (const pkg of packagesToShow) {
121
+ const name = (pkg.name || 'unknown').slice(0, 28).padEnd(30);
122
+ const version = (pkg.version || '-').slice(0, 10).padEnd(12);
123
+ const size = formatBytes(pkg.size_bytes).padEnd(10);
124
+ const path = truncatePath(pkg.path, 45);
125
+ console.log(`${chalk_1.default.green(name)} ${chalk_1.default.cyan(version)} ${chalk_1.default.yellow(size)} ${chalk_1.default.gray(path)}`);
126
+ }
127
+ if (sortedPackages.length > displayLimit) {
128
+ console.log(chalk_1.default.gray(`\n... and ${sortedPackages.length - displayLimit} more packages`));
129
+ }
130
+ const totalSize = data.packages?.reduce((sum, p) => sum + p.size_bytes, 0) || 0;
131
+ console.log(chalk_1.default.bold(`\n📊 Total: ${data.packages?.length || 0} packages, ${formatBytes(totalSize)}`));
132
+ if (data.projects?.length) {
133
+ console.log(chalk_1.default.bold.cyan(`\n📁 Projects Found: ${data.projects.length}`));
134
+ for (const proj of data.projects.slice(0, 10)) {
135
+ console.log(` ${chalk_1.default.gray('•')} ${proj.path}`);
136
+ }
137
+ if (data.projects.length > 10) {
138
+ console.log(chalk_1.default.gray(` ... and ${data.projects.length - 10} more projects`));
139
+ }
140
+ }
141
+ }
142
+ /**
143
+ * Format cleanup plan as a human-readable table
144
+ */
145
+ function formatPlanAsTable(data) {
146
+ console.log(chalk_1.default.bold.cyan('\n🧹 Cleanup Plan\n'));
147
+ if (!data.items?.length) {
148
+ console.log(chalk_1.default.green('✓ No packages identified for cleanup!'));
149
+ return;
150
+ }
151
+ // Group by reason
152
+ const byReason = new Map();
153
+ for (const item of data.items) {
154
+ const items = byReason.get(item.reason) || [];
155
+ items.push(item);
156
+ byReason.set(item.reason, items);
157
+ }
158
+ // Display by category
159
+ for (const [reason, items] of byReason) {
160
+ const colorFn = getReasonColor(reason);
161
+ const reasonText = formatReason(reason);
162
+ const categorySize = items.reduce((sum, i) => sum + i.estimated_size_bytes, 0);
163
+ console.log(colorFn.bold(`\n${reasonText} (${items.length} packages, ${formatBytes(categorySize)})`));
164
+ console.log('─'.repeat(80));
165
+ const sorted = [...items].sort((a, b) => b.estimated_size_bytes - a.estimated_size_bytes);
166
+ const toShow = sorted.slice(0, 10);
167
+ for (const item of toShow) {
168
+ const { name } = extractPackageInfo(item.target_path);
169
+ const size = formatBytes(item.estimated_size_bytes).padEnd(10);
170
+ console.log(` ${colorFn('•')} ${name.padEnd(35)} ${chalk_1.default.yellow(size)} ${chalk_1.default.gray(truncatePath(item.target_path, 30))}`);
171
+ }
172
+ if (items.length > 10) {
173
+ console.log(chalk_1.default.gray(` ... and ${items.length - 10} more`));
174
+ }
175
+ }
176
+ // Summary
177
+ console.log(chalk_1.default.bold.green(`\n📊 Summary`));
178
+ console.log(` ${chalk_1.default.bold('Total packages:')} ${data.items.length}`);
179
+ console.log(` ${chalk_1.default.bold('Estimated savings:')} ${chalk_1.default.yellow.bold(formatBytes(data.total_estimated_bytes))}`);
180
+ }
181
+ /**
182
+ * Format quarantine result
183
+ */
184
+ function formatQuarantineResult(data) {
185
+ console.log(chalk_1.default.bold.cyan('\n🗄️ Quarantine Results\n'));
186
+ if (!data?.length) {
187
+ console.log(chalk_1.default.yellow('No items were quarantined.'));
188
+ return;
189
+ }
190
+ for (const rec of data) {
191
+ console.log(chalk_1.default.green('✓') + ` Quarantined: ${chalk_1.default.cyan(rec.original_path || rec.id)}`);
192
+ console.log(` ${chalk_1.default.gray('ID:')} ${rec.id}`);
193
+ console.log(` ${chalk_1.default.gray('Size:')} ${formatBytes(rec.size_bytes || 0)}`);
194
+ }
195
+ const totalSize = data.reduce((sum, r) => sum + (r.size_bytes || 0), 0);
196
+ console.log(chalk_1.default.bold.green(`\n✓ ${data.length} items quarantined, ${formatBytes(totalSize)} recoverable space`));
197
+ }
198
+ /**
199
+ * Format rollback result
200
+ */
201
+ function formatRollbackResult(data) {
202
+ console.log(chalk_1.default.bold.cyan('\n↩️ Rollback Result\n'));
203
+ if (data.status === 'ok') {
204
+ console.log(chalk_1.default.green('✓') + ` Successfully rolled back: ${chalk_1.default.cyan(data.id)}`);
205
+ }
206
+ else {
207
+ console.log(chalk_1.default.red('✗') + ` Rollback failed`);
208
+ }
209
+ }
210
+ /**
211
+ * Format symlink result
212
+ */
213
+ function formatSymlinkResult(data) {
214
+ console.log(chalk_1.default.bold.cyan('\n🔗 Symlink Results\n'));
215
+ if (data.status === 'ok') {
216
+ console.log(chalk_1.default.green('✓') + ` Successfully symlinked ${chalk_1.default.bold(data.symlinked_count)} packages`);
217
+ }
218
+ else {
219
+ console.log(chalk_1.default.yellow('ℹ') + ` Symlink operation completed`);
220
+ console.log(JSON.stringify(data, null, 2));
221
+ }
222
+ }
223
+ /**
224
+ * Format data as JSON
225
+ */
226
+ function formatAsJSON(data, pretty = true) {
227
+ return pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
228
+ }
229
+ /**
230
+ * Format data as YAML
231
+ */
232
+ function formatAsYAML(data) {
233
+ try {
234
+ return yaml_1.default.stringify(data);
235
+ }
236
+ catch (e) {
237
+ // Fallback to JSON if YAML conversion fails
238
+ console.error(chalk_1.default.yellow('Warning: YAML conversion failed, falling back to JSON'));
239
+ return JSON.stringify(data, null, 2);
240
+ }
241
+ }
242
+ /**
243
+ * Output data in the specified format
244
+ */
245
+ function output(data, format, type = 'analyze') {
246
+ // Parse JSON string if needed
247
+ let parsed;
248
+ if (typeof data === 'string') {
249
+ try {
250
+ parsed = JSON.parse(data);
251
+ }
252
+ catch {
253
+ // If not valid JSON, just print as-is for json/yaml, or show error for table
254
+ if (format === 'table') {
255
+ console.log(data);
256
+ return;
257
+ }
258
+ parsed = data;
259
+ }
260
+ }
261
+ else {
262
+ parsed = data;
263
+ }
264
+ switch (format) {
265
+ case 'table':
266
+ switch (type) {
267
+ case 'scan':
268
+ formatScanAsTable(parsed);
269
+ break;
270
+ case 'analyze':
271
+ case 'optimize':
272
+ formatPlanAsTable(parsed);
273
+ break;
274
+ case 'quarantine':
275
+ formatQuarantineResult(parsed);
276
+ break;
277
+ case 'rollback':
278
+ formatRollbackResult(parsed);
279
+ break;
280
+ case 'symlink':
281
+ formatSymlinkResult(parsed);
282
+ break;
283
+ default:
284
+ console.log(formatAsJSON(parsed));
285
+ }
286
+ break;
287
+ case 'yaml':
288
+ console.log(formatAsYAML(parsed));
289
+ break;
290
+ case 'json':
291
+ default:
292
+ console.log(formatAsJSON(parsed));
293
+ }
294
+ }
295
+ //# sourceMappingURL=formatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatter.js","sourceRoot":"","sources":["../../src/utils/formatter.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "packagepurge",
3
- "version": "1.0.0",
3
+ "version": "2.0.0",
4
4
  "description": "Intelligent package manager cache cleanup service with project-aware optimization",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "bin": {
8
+ "purge": "dist/cli/index.js",
8
9
  "packagepurge": "dist/cli/index.js"
9
10
  },
10
11
  "scripts": {
@@ -60,5 +61,4 @@
60
61
  "engines": {
61
62
  "node": ">=16.0.0"
62
63
  }
63
- }
64
-
64
+ }
@@ -1,91 +0,0 @@
1
- #![allow(dead_code)]
2
- use std::collections::{HashMap, VecDeque};
3
-
4
- // SLRU: probationary and protected segments, each LRU-like (front=MRU, back=LRU)
5
- pub struct SlruPolicy {
6
- probationary: VecDeque<String>,
7
- protected: VecDeque<String>,
8
- cap_probationary: usize,
9
- cap_protected: usize,
10
- in_probationary: HashMap<String, bool>,
11
- in_protected: HashMap<String, bool>,
12
- }
13
-
14
- impl SlruPolicy {
15
- pub fn new(capacity: usize) -> Self {
16
- let cap_protected = (capacity as f32 * 0.8) as usize;
17
- let cap_probationary = capacity.saturating_sub(cap_protected);
18
- Self {
19
- probationary: VecDeque::new(),
20
- protected: VecDeque::new(),
21
- cap_probationary,
22
- cap_protected,
23
- in_probationary: HashMap::new(),
24
- in_protected: HashMap::new(),
25
- }
26
- }
27
-
28
- pub fn record_hit(&mut self, key: &str) {
29
- let k = key.to_string();
30
- if self.in_protected.remove(&k).is_some() {
31
- self.protected.retain(|x| x != &k);
32
- self.protected.push_front(k.clone());
33
- self.in_protected.insert(k, true);
34
- return;
35
- }
36
- if self.in_probationary.remove(&k).is_some() {
37
- // promote to protected
38
- self.probationary.retain(|x| x != &k);
39
- self.protected.push_front(k.clone());
40
- self.in_protected.insert(k.clone(), true);
41
- // enforce protected capacity
42
- while self.protected.len() > self.cap_protected {
43
- if let Some(v) = self.protected.pop_back() { self.in_protected.remove(&v); }
44
- }
45
- return;
46
- }
47
- // new entry goes to probationary
48
- self.probationary.push_front(k.clone());
49
- self.in_probationary.insert(k.clone(), true);
50
- while self.probationary.len() > self.cap_probationary {
51
- if let Some(v) = self.probationary.pop_back() { self.in_probationary.remove(&v); }
52
- }
53
- }
54
-
55
- pub fn select_victim(&mut self) -> Option<String> {
56
- if let Some(v) = self.probationary.pop_back() { self.in_probationary.remove(&v); return Some(v); }
57
- if let Some(v) = self.protected.pop_back() { self.in_protected.remove(&v); return Some(v); }
58
- None
59
- }
60
- }
61
-
62
- // Simple LFU: key->freq, and buckets freq->VecDeque keys. Evicts from lowest freq, oldest within bucket
63
- pub struct SimpleLfu {
64
- freq: HashMap<String, usize>,
65
- buckets: HashMap<usize, VecDeque<String>>,
66
- }
67
-
68
- impl SimpleLfu {
69
- pub fn new() -> Self { Self { freq: HashMap::new(), buckets: HashMap::new() } }
70
-
71
- pub fn increment(&mut self, key: &str) {
72
- let k = key.to_string();
73
- let f = *self.freq.get(&k).unwrap_or(&0);
74
- if let Some(q) = self.buckets.get_mut(&f) { q.retain(|x| x != &k); }
75
- let nf = f + 1;
76
- self.freq.insert(k.clone(), nf);
77
- self.buckets.entry(nf).or_default().push_front(k);
78
- }
79
-
80
- pub fn victim(&mut self) -> Option<String> {
81
- if self.freq.is_empty() { return None; }
82
- let minf = *self.freq.values().min().unwrap_or(&0);
83
- if let Some(q) = self.buckets.get_mut(&minf) {
84
- if let Some(k) = q.pop_back() {
85
- self.freq.remove(&k);
86
- return Some(k);
87
- }
88
- }
89
- None
90
- }
91
- }