diff --git a/current-errors.txt b/current-errors.txt new file mode 100644 index 0000000..333ed54 --- /dev/null +++ b/current-errors.txt @@ -0,0 +1,493 @@ +src/tools/advanced-caching/cache-analytics.ts(1,598): error TS6133: 'CacheEngine' is declared but its value is never read. +src/tools/advanced-caching/cache-benchmark.ts(408,16): error TS2554: Expected 4 arguments, but got 3. +src/tools/advanced-caching/cache-compression.ts(217,11): error TS6196: 'DeltaState' is declared but never used. +src/tools/advanced-caching/cache-compression.ts(486,51): error TS2322: Type 'string' is not assignable to type 'Uint8Array'. +src/tools/advanced-caching/cache-compression.ts(1023,7): error TS2322: Type 'string' is not assignable to type 'Buffer'. +src/tools/advanced-caching/cache-compression.ts(1044,9): error TS2322: Type 'string' is not assignable to type 'Buffer'. +src/tools/advanced-caching/cache-compression.ts(1284,7): error TS2322: Type 'string' is not assignable to type 'Buffer'. +src/tools/advanced-caching/cache-compression.ts(1304,9): error TS2322: Type 'string' is not assignable to type 'Buffer'. +src/tools/advanced-caching/cache-invalidation.ts(1,545): error TS6133: 'createHash' is declared but its value is never read. +src/tools/advanced-caching/cache-optimizer.ts(1,430): error TS6133: 'CacheEngine' is declared but its value is never read. +src/tools/advanced-caching/cache-partition.ts(228,30): error TS2339: Property 'generateKey' does not exist on type 'typeof CacheEngine'. +src/tools/advanced-caching/cache-partition.ts(237,37): error TS2345: Argument of type 'string | null' is not assignable to parameter of type 'string'. +src/tools/advanced-caching/cache-partition.ts(1469,11): error TS6133: '_coAccessPatterns' is declared but its value is never read. +src/tools/advanced-caching/cache-replication.ts(1,509): error TS6133: 'createHash' is declared but its value is never read. +src/tools/advanced-caching/cache-warmup.ts(1,648): error TS6133: 'CacheEngine' is declared but its value is never read. +src/tools/advanced-caching/predictive-cache.ts(1,868): error TS6133: 'CacheEngine' is declared but its value is never read. +src/tools/advanced-caching/predictive-cache.ts(2,1): error TS6192: All imports in import declaration are unused. +src/tools/advanced-caching/smart-cache.ts(1,677): error TS6133: 'CacheEngine' is declared but its value is never read. +src/tools/api-database/index.ts(49,3): error TS2305: Module '"./smart-rest"' has no exported member 'SmartREST'. +src/tools/api-database/index.ts(50,3): error TS2305: Module '"./smart-rest"' has no exported member 'getSmartRest'. +src/tools/api-database/index.ts(51,3): error TS2305: Module '"./smart-rest"' has no exported member 'runSmartREST'. +src/tools/api-database/index.ts(52,3): error TS2305: Module '"./smart-rest"' has no exported member 'SMART_REST_TOOL_DEFINITION'. +src/tools/api-database/index.ts(53,8): error TS2305: Module '"./smart-rest"' has no exported member 'SmartRESTOptions'. +src/tools/api-database/index.ts(54,8): error TS2305: Module '"./smart-rest"' has no exported member 'SmartRESTResult'. +src/tools/api-database/index.ts(55,8): error TS2305: Module '"./smart-rest"' has no exported member 'EndpointInfo'. +src/tools/api-database/index.ts(56,8): error TS2305: Module '"./smart-rest"' has no exported member 'ResourceGroup'. +src/tools/api-database/index.ts(57,8): error TS2305: Module '"./smart-rest"' has no exported member 'HealthIssue'. +src/tools/api-database/index.ts(58,8): error TS2305: Module '"./smart-rest"' has no exported member 'RateLimit'. +src/tools/api-database/smart-api-fetch.ts(669,33): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/api-database/smart-cache-api.ts(246,40): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Buffer'. +src/tools/api-database/smart-cache-api.ts(384,48): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Buffer'. +src/tools/api-database/smart-cache-api.ts(407,46): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Buffer'. +src/tools/api-database/smart-cache-api.ts(427,46): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Buffer'. +src/tools/api-database/smart-cache-api.ts(445,46): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Buffer'. +src/tools/api-database/smart-cache-api.ts(498,42): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Buffer'. +src/tools/api-database/smart-cache-api.ts(882,5): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/api-database/smart-database.ts(1,641): error TS6133: 'createHash' is declared but its value is never read. +src/tools/api-database/smart-database.ts(2,1): error TS6133: 'CacheEngine' is declared but its value is never read. +src/tools/api-database/smart-database.ts(3,1): error TS6133: 'TokenCounter' is declared but its value is never read. +src/tools/api-database/smart-database.ts(4,1): error TS6133: 'MetricsCollector' is declared but its value is never read. +src/tools/api-database/smart-database.ts(5,1): error TS6133: 'CacheEngineClass' is declared but its value is never read. +src/tools/api-database/smart-graphql.ts(755,33): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/api-database/smart-migration.ts(26,10): error TS2724: '"../../core/token-counter"' has no exported member named 'globalTokenCounter'. Did you mean 'TokenCounter'? +src/tools/api-database/smart-migration.ts(520,18): error TS2554: Expected 4 arguments, but got 3. +src/tools/api-database/smart-migration.ts(895,5): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/api-database/smart-orm.ts(185,11): error TS6133: 'relationships' is declared but its value is never read. +src/tools/api-database/smart-orm.ts(803,24): error TS2339: Property 'generateKey' does not exist on type 'typeof CacheEngine'. +src/tools/api-database/smart-orm.ts(827,22): error TS2554: Expected 4 arguments, but got 3. +src/tools/api-database/smart-orm.ts(856,5): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/api-database/smart-rest.ts(1,311): error TS6133: 'createHash' is declared but its value is never read. +src/tools/api-database/smart-schema.ts(25,10): error TS2724: '"../../core/token-counter"' has no exported member named 'globalTokenCounter'. Did you mean 'TokenCounter'? +src/tools/api-database/smart-schema.ts(1166,5): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/api-database/smart-sql.ts(528,13): error TS6133: 'compact' is declared but its value is never read. +src/tools/api-database/smart-sql.ts(543,13): error TS6133: 'compact' is declared but its value is never read. +src/tools/api-database/smart-sql.ts(557,13): error TS6133: 'compact' is declared but its value is never read. +src/tools/api-database/smart-sql.ts(571,13): error TS6133: 'compact' is declared but its value is never read. +src/tools/api-database/smart-sql.ts(581,13): error TS6133: 'compact' is declared but its value is never read. +src/tools/api-database/smart-sql.ts(616,24): error TS2339: Property 'generateKey' does not exist on type 'typeof CacheEngine'. +src/tools/api-database/smart-sql.ts(669,7): error TS2554: Expected 4 arguments, but got 5. +src/tools/api-database/smart-sql.ts(694,33): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/api-database/smart-sql.ts(697,22): error TS2554: Expected 0 arguments, but got 1. +src/tools/api-database/smart-websocket.ts(712,33): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/build-systems/smart-build.ts(119,11): error TS6133: '_tokenCounter' is declared but its value is never read. +src/tools/build-systems/smart-build.ts(119,26): error TS2304: Cannot find name '_tokenCounter'. +src/tools/build-systems/smart-build.ts(120,11): error TS6133: '_metrics' is declared but its value is never read. +src/tools/build-systems/smart-build.ts(126,20): error TS2749: '_tokenCounter' refers to a value, but is being used as a type here. Did you mean 'typeof _tokenCounter'? +src/tools/build-systems/smart-build.ts(586,18): error TS2749: '_tokenCounter' refers to a value, but is being used as a type here. Did you mean 'typeof _tokenCounter'? +src/tools/build-systems/smart-build.ts(600,33): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/build-systems/smart-build.ts(601,9): error TS7022: '_tokenCounter' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer. +src/tools/build-systems/smart-build.ts(601,29): error TS2448: Block-scoped variable '_tokenCounter' used before its declaration. +src/tools/build-systems/smart-docker.ts(729,33): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/build-systems/smart-install.ts(596,33): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/build-systems/smart-lint.ts(152,11): error TS6133: '_tokenCounter' is declared but its value is never read. +src/tools/build-systems/smart-lint.ts(152,26): error TS2304: Cannot find name '_tokenCounter'. +src/tools/build-systems/smart-lint.ts(153,11): error TS6133: '_metrics' is declared but its value is never read. +src/tools/build-systems/smart-lint.ts(160,20): error TS2749: '_tokenCounter' refers to a value, but is being used as a type here. Did you mean 'typeof _tokenCounter'? +src/tools/build-systems/smart-lint.ts(363,11): error TS6133: '_markAsIgnored' is declared but its value is never read. +src/tools/build-systems/smart-lint.ts(596,18): error TS2749: '_tokenCounter' refers to a value, but is being used as a type here. Did you mean 'typeof _tokenCounter'? +src/tools/build-systems/smart-lint.ts(610,33): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/build-systems/smart-lint.ts(611,9): error TS7022: '_tokenCounter' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer. +src/tools/build-systems/smart-lint.ts(611,29): error TS2448: Block-scoped variable '_tokenCounter' used before its declaration. +src/tools/build-systems/smart-logs.ts(875,33): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/build-systems/smart-network.ts(21,7): error TS6133: '_dnsResolve' is declared but its value is never read. +src/tools/build-systems/smart-network.ts(183,11): error TS6133: 'projectRoot' is declared but its value is never read. +src/tools/build-systems/smart-network.ts(829,33): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/build-systems/smart-processes.ts(148,11): error TS6133: 'tokenCounter' is declared but its value is never read. +src/tools/build-systems/smart-processes.ts(149,11): error TS6133: 'metrics' is declared but its value is never read. +src/tools/build-systems/smart-processes.ts(152,11): error TS6133: '_projectRoot' is declared but its value is never read. +src/tools/build-systems/smart-system-metrics.ts(171,11): error TS6133: 'projectRoot' is declared but its value is never read. +src/tools/build-systems/smart-test.ts(135,11): error TS6133: 'tokenCounter' is declared but its value is never read. +src/tools/build-systems/smart-test.ts(136,11): error TS6133: 'metrics' is declared but its value is never read. +src/tools/build-systems/smart-typecheck.ts(112,11): error TS6133: '_tokenCounter' is declared but its value is never read. +src/tools/build-systems/smart-typecheck.ts(112,26): error TS2304: Cannot find name '_tokenCounter'. +src/tools/build-systems/smart-typecheck.ts(113,11): error TS6133: '_metrics' is declared but its value is never read. +src/tools/build-systems/smart-typecheck.ts(119,20): error TS2749: '_tokenCounter' refers to a value, but is being used as a type here. Did you mean 'typeof _tokenCounter'? +src/tools/build-systems/smart-typecheck.ts(639,18): error TS2749: '_tokenCounter' refers to a value, but is being used as a type here. Did you mean 'typeof _tokenCounter'? +src/tools/build-systems/smart-typecheck.ts(655,9): error TS7022: '_tokenCounter' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer. +src/tools/build-systems/smart-typecheck.ts(655,29): error TS2448: Block-scoped variable '_tokenCounter' used before its declaration. +src/tools/code-analysis/smart-ambiance.ts(1,506): error TS6192: All imports in import declaration are unused. +src/tools/code-analysis/smart-ambiance.ts(7,1): error TS6192: All imports in import declaration are unused. +src/tools/code-analysis/smart-ambiance.ts(8,1): error TS6192: All imports in import declaration are unused. +src/tools/code-analysis/smart-ambiance.ts(9,1): error TS6192: All imports in import declaration are unused. +src/tools/code-analysis/smart-ambiance.ts(10,1): error TS6192: All imports in import declaration are unused. +src/tools/code-analysis/smart-ambiance.ts(11,1): error TS6133: 'ts' is declared but its value is never read. +src/tools/code-analysis/smart-ast-grep.ts(161,9): error TS6133: '_cachedResult' is declared but its value is never read. +src/tools/code-analysis/smart-ast-grep.ts(605,24): error TS2339: Property 'generateKey' does not exist on type 'typeof CacheEngine'. +src/tools/code-analysis/smart-ast-grep.ts(619,24): error TS2339: Property 'generateKey' does not exist on type 'typeof CacheEngine'. +src/tools/code-analysis/smart-complexity.ts(746,30): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/code-analysis/smart-dependencies.ts(770,42): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/code-analysis/smart-dependencies.ts(782,9): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/code-analysis/smart-dependencies.ts(784,27): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/code-analysis/smart-dependencies.ts(841,42): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/code-analysis/smart-dependencies.ts(853,9): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/code-analysis/smart-dependencies.ts(855,27): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/code-analysis/smart-dependencies.ts(964,42): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/code-analysis/smart-dependencies.ts(976,9): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/code-analysis/smart-dependencies.ts(978,27): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/code-analysis/smart-dependencies.ts(1014,42): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/code-analysis/smart-dependencies.ts(1026,9): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/code-analysis/smart-dependencies.ts(1028,27): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/code-analysis/smart-dependencies.ts(1164,7): error TS2554: Expected 4 arguments, but got 5. +src/tools/code-analysis/smart-exports.ts(254,11): error TS6133: '_reductionPercentage' is declared but its value is never read. +src/tools/code-analysis/smart-exports.ts(254,36): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/code-analysis/smart-exports.ts(254,53): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/code-analysis/smart-exports.ts(254,72): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/code-analysis/smart-exports.ts(257,40): error TS2345: Argument of type 'TokenCountResult' is not assignable to parameter of type 'number'. +src/tools/code-analysis/smart-exports.ts(265,7): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/code-analysis/smart-exports.ts(266,7): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/code-analysis/smart-exports.ts(267,20): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/code-analysis/smart-exports.ts(267,37): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/code-analysis/smart-exports.ts(449,11): error TS6133: '_fileDir' is declared but its value is never read. +src/tools/code-analysis/smart-exports.ts(825,33): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/code-analysis/smart-exports.ts(826,41): error TS2554: Expected 0 arguments, but got 1. +src/tools/code-analysis/smart-imports.ts(272,11): error TS6133: '_reductionPercentage' is declared but its value is never read. +src/tools/code-analysis/smart-imports.ts(272,36): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/code-analysis/smart-imports.ts(272,53): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/code-analysis/smart-imports.ts(272,72): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/code-analysis/smart-imports.ts(275,40): error TS2345: Argument of type 'TokenCountResult' is not assignable to parameter of type 'number'. +src/tools/code-analysis/smart-imports.ts(283,7): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/code-analysis/smart-imports.ts(284,7): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/code-analysis/smart-imports.ts(285,20): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/code-analysis/smart-imports.ts(285,37): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/code-analysis/smart-imports.ts(923,33): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/code-analysis/smart-imports.ts(924,41): error TS2554: Expected 0 arguments, but got 1. +src/tools/code-analysis/smart-refactor.ts(17,54): error TS6133: 'SymbolInfo' is declared but its value is never read. +src/tools/code-analysis/smart-refactor.ts(18,60): error TS6133: 'ComplexityMetrics' is declared but its value is never read. +src/tools/code-analysis/smart-refactor.ts(162,11): error TS6133: '_symbolsResult' is declared but its value is never read. +src/tools/code-analysis/smart-refactor.ts(234,5): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/code-analysis/smart-refactor.ts(235,5): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/code-analysis/smart-refactor.ts(373,17): error TS6133: 'hash' is declared but its value is never read. +src/tools/code-analysis/smart-refactor.ts(648,33): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/code-analysis/smart-refactor.ts(649,41): error TS2554: Expected 0 arguments, but got 1. +src/tools/code-analysis/smart-security.ts(554,11): error TS6133: 'tokenCounter' is declared but its value is never read. +src/tools/code-analysis/smart-security.ts(1291,33): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/code-analysis/smart-symbols.ts(119,11): error TS6133: 'tokenCounter' is declared but its value is never read. +src/tools/code-analysis/smart-symbols.ts(711,30): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/code-analysis/smart-typescript.ts(158,11): error TS6133: 'tokenCounter' is declared but its value is never read. +src/tools/code-analysis/smart-typescript.ts(915,33): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/code-analysis/smart-typescript.ts(916,41): error TS2554: Expected 0 arguments, but got 1. +src/tools/configuration/smart-config-read.ts(142,7): error TS6133: 'includeMetadata' is declared but its value is never read. +src/tools/configuration/smart-config-read.ts(176,7): error TS2322: Type 'string | null' is not assignable to type 'Buffer | null'. +src/tools/configuration/smart-config-read.ts(177,7): error TS2322: Type 'string | null' is not assignable to type 'Buffer | null'. +src/tools/configuration/smart-config-read.ts(210,11): error TS2345: Argument of type 'Buffer' is not assignable to parameter of type 'string'. +src/tools/configuration/smart-config-read.ts(210,22): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Buffer'. +src/tools/configuration/smart-config-read.ts(261,37): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/configuration/smart-config-read.ts(261,54): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/configuration/smart-config-read.ts(271,13): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/configuration/smart-config-read.ts(272,15): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/configuration/smart-config-read.ts(292,9): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/configuration/smart-config-read.ts(293,9): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/configuration/smart-config-read.ts(301,35): error TS2554: Expected 0 arguments, but got 1. +src/tools/configuration/smart-config-read.ts(301,44): error TS2339: Property 'compressed' does not exist on type 'string'. +src/tools/configuration/smart-config-read.ts(313,37): error TS2554: Expected 0 arguments, but got 1. +src/tools/configuration/smart-config-read.ts(313,46): error TS2339: Property 'compressed' does not exist on type 'string'. +src/tools/configuration/smart-config-read.ts(324,30): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/configuration/smart-config-read.ts(324,44): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/configuration/smart-config-read.ts(333,7): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/configuration/smart-config-read.ts(334,7): error TS2322: Type 'number | TokenCountResult' is not assignable to type 'number | undefined'. +src/tools/configuration/smart-config-read.ts(357,9): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/configuration/smart-config-read.ts(358,9): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/configuration/smart-config-read.ts(770,33): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/configuration/smart-env.ts(1,338): error TS6133: 'fs' is declared but its value is never read. +src/tools/configuration/smart-env.ts(2,1): error TS6133: 'path' is declared but its value is never read. +src/tools/configuration/smart-package-json.ts(835,11): error TS6133: '_size' is declared but its value is never read. +src/tools/configuration/smart-package-json.ts(843,7): error TS2554: Expected 4 arguments, but got 5. +src/tools/configuration/smart-package-json.ts(853,37): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/configuration/smart-package-json.ts(854,12): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/configuration/smart-package-json.ts(1108,33): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/configuration/smart-tsconfig.ts(130,36): error TS2339: Property 'generateFileHash' does not exist on type 'typeof CacheEngine'. +src/tools/configuration/smart-tsconfig.ts(131,40): error TS2339: Property 'createHash' does not exist on type 'Crypto'. +src/tools/configuration/smart-tsconfig.ts(170,20): error TS2339: Property 'invalidateByFileHash' does not exist on type 'CacheEngine'. +src/tools/configuration/smart-tsconfig.ts(199,25): error TS2554: Expected 0 arguments, but got 1. +src/tools/configuration/smart-tsconfig.ts(199,34): error TS2339: Property 'from' does not exist on type 'string'. +src/tools/configuration/smart-tsconfig.ts(548,37): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/configuration/smart-tsconfig.ts(548,54): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/configuration/smart-tsconfig.ts(550,7): error TS2365: Operator '>' cannot be applied to types 'TokenCountResult' and 'number'. +src/tools/configuration/smart-tsconfig.ts(550,43): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/configuration/smart-tsconfig.ts(553,7): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/configuration/smart-tsconfig.ts(554,7): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/configuration/smart-tsconfig.ts(614,33): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/configuration/smart-workflow.ts(1,464): error TS6192: All imports in import declaration are unused. +src/tools/configuration/smart-workflow.ts(7,1): error TS6192: All imports in import declaration are unused. +src/tools/configuration/smart-workflow.ts(8,1): error TS6133: 'parseYAML' is declared but its value is never read. +src/tools/configuration/smart-workflow.ts(9,1): error TS6192: All imports in import declaration are unused. +src/tools/dashboard-monitoring/alert-manager.ts(362,79): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Encoding'. +src/tools/dashboard-monitoring/alert-manager.ts(380,30): error TS2554: Expected 0 arguments, but got 1. +src/tools/dashboard-monitoring/alert-manager.ts(430,79): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Encoding'. +src/tools/dashboard-monitoring/alert-manager.ts(448,30): error TS2554: Expected 0 arguments, but got 1. +src/tools/dashboard-monitoring/alert-manager.ts(492,79): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Encoding'. +src/tools/dashboard-monitoring/alert-manager.ts(524,85): error TS2345: Argument of type '"all"' is not assignable to parameter of type 'Encoding'. +src/tools/dashboard-monitoring/alert-manager.ts(573,27): error TS2554: Expected 0 arguments, but got 1. +src/tools/dashboard-monitoring/alert-manager.ts(685,81): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Encoding'. +src/tools/dashboard-monitoring/alert-manager.ts(736,27): error TS2554: Expected 0 arguments, but got 1. +src/tools/dashboard-monitoring/alert-manager.ts(766,82): error TS2345: Argument of type '"all"' is not assignable to parameter of type 'Encoding'. +src/tools/dashboard-monitoring/alert-manager.ts(871,22): error TS2554: Expected 4 arguments, but got 3. +src/tools/dashboard-monitoring/alert-manager.ts(871,56): error TS2554: Expected 0 arguments, but got 1. +src/tools/dashboard-monitoring/alert-manager.ts(940,81): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Encoding'. +src/tools/dashboard-monitoring/alert-manager.ts(942,22): error TS2554: Expected 4 arguments, but got 3. +src/tools/dashboard-monitoring/alert-manager.ts(942,56): error TS2554: Expected 0 arguments, but got 1. +src/tools/dashboard-monitoring/alert-manager.ts(1075,25): error TS2339: Property 'estimateFromBytes' does not exist on type 'TokenCounter'. +src/tools/dashboard-monitoring/alert-manager.ts(1133,85): error TS2345: Argument of type '"alerts"' is not assignable to parameter of type 'Encoding'. +src/tools/dashboard-monitoring/alert-manager.ts(1135,50): error TS2554: Expected 0 arguments, but got 1. +src/tools/dashboard-monitoring/alert-manager.ts(1139,85): error TS2345: Argument of type '"events"' is not assignable to parameter of type 'Encoding'. +src/tools/dashboard-monitoring/alert-manager.ts(1141,50): error TS2554: Expected 0 arguments, but got 1. +src/tools/dashboard-monitoring/alert-manager.ts(1145,85): error TS2345: Argument of type '"channels"' is not assignable to parameter of type 'Encoding'. +src/tools/dashboard-monitoring/alert-manager.ts(1153,85): error TS2345: Argument of type '"silences"' is not assignable to parameter of type 'Encoding'. +src/tools/dashboard-monitoring/alert-manager.ts(1162,86): error TS2345: Argument of type '"alerts"' is not assignable to parameter of type 'Encoding'. +src/tools/dashboard-monitoring/alert-manager.ts(1174,86): error TS2345: Argument of type '"events"' is not assignable to parameter of type 'Encoding'. +src/tools/dashboard-monitoring/alert-manager.ts(1185,88): error TS2345: Argument of type '"channels"' is not assignable to parameter of type 'Encoding'. +src/tools/dashboard-monitoring/alert-manager.ts(1200,88): error TS2345: Argument of type '"silences"' is not assignable to parameter of type 'Encoding'. +src/tools/dashboard-monitoring/custom-widget.ts(228,43): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Buffer'. +src/tools/dashboard-monitoring/custom-widget.ts(303,31): error TS2554: Expected 0 arguments, but got 1. +src/tools/dashboard-monitoring/custom-widget.ts(303,40): error TS2339: Property 'compressed' does not exist on type 'string'. +src/tools/dashboard-monitoring/data-visualizer.ts(437,25): error TS2322: Type 'string' is not assignable to type 'Buffer'. +src/tools/dashboard-monitoring/data-visualizer.ts(465,9): error TS2322: Type 'string' is not assignable to type 'Buffer'. +src/tools/dashboard-monitoring/data-visualizer.ts(564,7): error TS2345: Argument of type 'Buffer' is not assignable to parameter of type 'string'. +src/tools/dashboard-monitoring/data-visualizer.ts(623,7): error TS2345: Argument of type 'Buffer' is not assignable to parameter of type 'string'. +src/tools/dashboard-monitoring/data-visualizer.ts(691,7): error TS2345: Argument of type 'Buffer' is not assignable to parameter of type 'string'. +src/tools/dashboard-monitoring/data-visualizer.ts(754,7): error TS2345: Argument of type 'Buffer' is not assignable to parameter of type 'string'. +src/tools/dashboard-monitoring/data-visualizer.ts(827,7): error TS2345: Argument of type 'Buffer' is not assignable to parameter of type 'string'. +src/tools/dashboard-monitoring/health-monitor.ts(1057,7): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Record'. +src/tools/dashboard-monitoring/health-monitor.ts(1092,23): error TS2554: Expected 0 arguments, but got 1. +src/tools/dashboard-monitoring/health-monitor.ts(1092,32): error TS2339: Property 'from' does not exist on type 'string'. +src/tools/dashboard-monitoring/health-monitor.ts(1120,7): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Record'. +src/tools/dashboard-monitoring/health-monitor.ts(1160,23): error TS2554: Expected 0 arguments, but got 1. +src/tools/dashboard-monitoring/health-monitor.ts(1160,32): error TS2339: Property 'from' does not exist on type 'string'. +src/tools/dashboard-monitoring/health-monitor.ts(1198,79): error TS2345: Argument of type '"graph"' is not assignable to parameter of type 'Encoding'. +src/tools/dashboard-monitoring/health-monitor.ts(1203,23): error TS2554: Expected 0 arguments, but got 1. +src/tools/dashboard-monitoring/health-monitor.ts(1203,32): error TS2339: Property 'from' does not exist on type 'string'. +src/tools/dashboard-monitoring/health-monitor.ts(1235,7): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Record'. +src/tools/dashboard-monitoring/health-monitor.ts(1266,23): error TS2554: Expected 0 arguments, but got 1. +src/tools/dashboard-monitoring/health-monitor.ts(1266,32): error TS2339: Property 'from' does not exist on type 'string'. +src/tools/dashboard-monitoring/log-dashboard.ts(1,540): error TS6133: 'CacheEngine' is declared but its value is never read. +src/tools/dashboard-monitoring/metric-collector.ts(1,848): error TS6133: 'CacheEngine' is declared but its value is never read. +src/tools/dashboard-monitoring/monitoring-integration.ts(1,730): error TS6133: 'CacheEngine' is declared but its value is never read. +src/tools/dashboard-monitoring/performance-tracker.ts(1,641): error TS6133: 'CacheEngine' is declared but its value is never read. +src/tools/dashboard-monitoring/report-generator.ts(1,724): error TS6192: All imports in import declaration are unused. +src/tools/dashboard-monitoring/report-generator.ts(6,1): error TS6192: All imports in import declaration are unused. +src/tools/dashboard-monitoring/smart-dashboard.ts(1,790): error TS6133: 'CacheEngine' is declared but its value is never read. +src/tools/file-operations/smart-branch.ts(228,26): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-branch.ts(231,26): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-branch.ts(234,26): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-branch.ts(237,44): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-branch.ts(238,32): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-branch.ts(250,11): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/file-operations/smart-branch.ts(265,11): error TS2345: Argument of type 'TokenCountResult' is not assignable to parameter of type 'number'. +src/tools/file-operations/smart-branch.ts(276,9): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/file-operations/smart-branch.ts(593,33): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/file-operations/smart-edit.ts(143,24): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-edit.ts(157,26): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-edit.ts(159,13): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/file-operations/smart-edit.ts(160,36): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-edit.ts(177,29): error TS2365: Operator '+' cannot be applied to types 'import("C:/Users/yolan/source/repos/token-optimizer-mcp/src/core/token-counter").TokenCountResult' and 'import("C:/Users/yolan/source/repos/token-optimizer-mcp/src/core/token-counter").TokenCountResult'. +src/tools/file-operations/smart-edit.ts(177,87): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-edit.ts(182,11): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/file-operations/smart-edit.ts(200,13): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/file-operations/smart-edit.ts(201,13): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/file-operations/smart-edit.ts(202,31): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-edit.ts(202,44): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-edit.ts(225,29): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-edit.ts(225,46): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-edit.ts(226,79): error TS2554: Expected 4 arguments, but got 5. +src/tools/file-operations/smart-edit.ts(231,27): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-edit.ts(231,44): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-edit.ts(236,9): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/file-operations/smart-edit.ts(254,11): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/file-operations/smart-edit.ts(255,11): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/file-operations/smart-edit.ts(256,29): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-edit.ts(256,42): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-edit.ts(471,33): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/file-operations/smart-edit.ts(472,41): error TS2554: Expected 0 arguments, but got 1. +src/tools/file-operations/smart-glob.ts(258,9): error TS2322: Type 'number' is not assignable to type 'TokenCountResult'. +src/tools/file-operations/smart-glob.ts(258,26): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-glob.ts(261,9): error TS2322: Type 'number' is not assignable to type 'TokenCountResult'. +src/tools/file-operations/smart-glob.ts(261,26): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-glob.ts(264,27): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-glob.ts(264,44): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-glob.ts(265,32): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-glob.ts(265,47): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-glob.ts(276,11): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/file-operations/smart-glob.ts(277,11): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/file-operations/smart-glob.ts(292,11): error TS2554: Expected 4 arguments, but got 5. +src/tools/file-operations/smart-glob.ts(303,9): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/file-operations/smart-glob.ts(429,33): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/file-operations/smart-glob.ts(430,41): error TS2554: Expected 0 arguments, but got 1. +src/tools/file-operations/smart-grep.ts(274,9): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/file-operations/smart-grep.ts(278,9): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/file-operations/smart-grep.ts(282,9): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/file-operations/smart-grep.ts(330,11): error TS2554: Expected 4 arguments, but got 5. +src/tools/file-operations/smart-grep.ts(480,33): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/file-operations/smart-grep.ts(481,41): error TS2554: Expected 0 arguments, but got 1. +src/tools/file-operations/smart-log.ts(568,33): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/file-operations/smart-merge.ts(772,33): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/file-operations/smart-read.ts(125,7): error TS2322: Type 'string | null' is not assignable to type 'Buffer | null'. +src/tools/file-operations/smart-read.ts(190,30): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-read.ts(245,29): error TS2554: Expected 0 arguments, but got 1. +src/tools/file-operations/smart-read.ts(245,38): error TS2339: Property 'compressed' does not exist on type 'string'. +src/tools/file-operations/smart-read.ts(377,33): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/file-operations/smart-status.ts(641,33): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/file-operations/smart-write.ts(135,32): error TS2365: Operator '<=' cannot be applied to types 'TokenCountResult' and 'number'. +src/tools/file-operations/smart-write.ts(137,13): error TS2365: Operator '<=' cannot be applied to types 'TokenCountResult' and 'number'. +src/tools/file-operations/smart-write.ts(138,37): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-write.ts(139,38): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-write.ts(141,41): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-write.ts(166,13): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/file-operations/smart-write.ts(167,46): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-write.ts(233,55): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-write.ts(233,67): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-write.ts(239,78): error TS2554: Expected 4 arguments, but got 5. +src/tools/file-operations/smart-write.ts(247,9): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/file-operations/smart-write.ts(265,11): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/file-operations/smart-write.ts(266,11): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/file-operations/smart-write.ts(267,29): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-write.ts(267,42): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/file-operations/smart-write.ts(527,33): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/file-operations/smart-write.ts(528,41): error TS2554: Expected 0 arguments, but got 1. +src/tools/intelligence/anomaly-explainer.ts(1,478): error TS6133: 'CacheEngine' is declared but its value is never read. +src/tools/intelligence/anomaly-explainer.ts(2,1): error TS6192: All imports in import declaration are unused. +src/tools/intelligence/auto-remediation.ts(1,610): error TS6133: 'CacheEngine' is declared but its value is never read. +src/tools/intelligence/auto-remediation.ts(2,1): error TS6192: All imports in import declaration are unused. +src/tools/intelligence/intelligent-assistant.ts(1,270): error TS6133: 'CacheEngine' is declared but its value is never read. +src/tools/intelligence/intelligent-assistant.ts(2,1): error TS6133: 'nlp' is declared but its value is never read. +src/tools/intelligence/knowledge-graph.ts(999,21): error TS2304: Cannot find name 'createHash'. +src/tools/intelligence/knowledge-graph.ts(1004,11): error TS6133: 'getDefaultTTL' is declared but its value is never read. +src/tools/intelligence/natural-language-query.ts(1,391): error TS6133: 'CacheEngine' is declared but its value is never read. +src/tools/intelligence/pattern-recognition.ts(1,711): error TS6133: 'CacheEngine' is declared but its value is never read. +src/tools/intelligence/pattern-recognition.ts(2,1): error TS6192: All imports in import declaration are unused. +src/tools/intelligence/predictive-analytics.ts(1,711): error TS6133: 'CacheEngine' is declared but its value is never read. +src/tools/intelligence/recommendation-engine.ts(1,387): error TS6133: 'CacheEngine' is declared but its value is never read. +src/tools/intelligence/recommendation-engine.ts(2,1): error TS6133: 'stats' is declared but its value is never read. +src/tools/intelligence/sentiment-analysis.ts(493,13): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/intelligence/sentiment-analysis.ts(494,13): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/intelligence/sentiment-analysis.ts(516,20): error TS2554: Expected 4 arguments, but got 2. +src/tools/intelligence/sentiment-analysis.ts(518,27): error TS2554: Expected 0 arguments, but got 1. +src/tools/intelligence/sentiment-analysis.ts(518,36): error TS2339: Property 'from' does not exist on type 'string'. +src/tools/intelligence/sentiment-analysis.ts(533,9): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/intelligence/sentiment-analysis.ts(546,11): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/intelligence/smart-summarization.ts(1,939): error TS6133: 'CacheEngine' is declared but its value is never read. +src/tools/output-formatting/smart-diff.ts(1,497): error TS6192: All imports in import declaration are unused. +src/tools/output-formatting/smart-diff.ts(7,3): error TS6133: 'diffLines' is declared but its value is never read. +src/tools/output-formatting/smart-diff.ts(8,3): error TS6133: 'diffWords' is declared but its value is never read. +src/tools/output-formatting/smart-diff.ts(9,3): error TS6133: 'diffChars' is declared but its value is never read. +src/tools/output-formatting/smart-diff.ts(10,3): error TS6133: 'createTwoFilesPatch' is declared but its value is never read. +src/tools/output-formatting/smart-diff.ts(12,3): error TS6133: 'parsePatch' is declared but its value is never read. +src/tools/output-formatting/smart-diff.ts(14,1): error TS6192: All imports in import declaration are unused. +src/tools/output-formatting/smart-diff.ts(15,1): error TS6192: All imports in import declaration are unused. +src/tools/output-formatting/smart-export.ts(1,437): error TS6192: All imports in import declaration are unused. +src/tools/output-formatting/smart-export.ts(7,1): error TS6192: All imports in import declaration are unused. +src/tools/output-formatting/smart-export.ts(9,7): error TS6133: 'unparseCsv' is declared but its value is never read. +src/tools/output-formatting/smart-export.ts(10,1): error TS6192: All imports in import declaration are unused. +src/tools/output-formatting/smart-format.ts(2,3): error TS2724: '"fs"' has no exported member named '_createReadStream'. Did you mean 'createReadStream'? +src/tools/output-formatting/smart-format.ts(4,1): error TS6192: All imports in import declaration are unused. +src/tools/output-formatting/smart-format.ts(5,1): error TS6192: All imports in import declaration are unused. +src/tools/output-formatting/smart-format.ts(6,1): error TS6192: All imports in import declaration are unused. +src/tools/output-formatting/smart-format.ts(8,7): error TS6198: All destructured elements are unused. +src/tools/output-formatting/smart-format.ts(9,1): error TS6192: All imports in import declaration are unused. +src/tools/output-formatting/smart-format.ts(10,1): error TS6192: All imports in import declaration are unused. +src/tools/output-formatting/smart-log.ts(1,567): error TS6192: All imports in import declaration are unused. +src/tools/output-formatting/smart-log.ts(9,1): error TS6192: All imports in import declaration are unused. +src/tools/output-formatting/smart-log.ts(10,1): error TS6192: All imports in import declaration are unused. +src/tools/output-formatting/smart-log.ts(11,1): error TS6192: All imports in import declaration are unused. +src/tools/output-formatting/smart-pretty.ts(405,11): error TS6133: 'grammarCache' is declared but its value is never read. +src/tools/output-formatting/smart-pretty.ts(510,7): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Record'. +src/tools/output-formatting/smart-pretty.ts(517,41): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Buffer'. +src/tools/output-formatting/smart-pretty.ts(608,29): error TS2554: Expected 0 arguments, but got 1. +src/tools/output-formatting/smart-pretty.ts(608,38): error TS2339: Property 'compressed' does not exist on type 'string'. +src/tools/output-formatting/smart-pretty.ts(792,7): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Record'. +src/tools/output-formatting/smart-pretty.ts(799,41): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Buffer'. +src/tools/output-formatting/smart-pretty.ts(867,29): error TS2554: Expected 0 arguments, but got 1. +src/tools/output-formatting/smart-pretty.ts(867,38): error TS2339: Property 'compressed' does not exist on type 'string'. +src/tools/output-formatting/smart-pretty.ts(1326,3): error TS6133: 'projectRoot' is declared but its value is never read. +src/tools/output-formatting/smart-pretty.ts(1338,33): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/output-formatting/smart-report.ts(2,3): error TS2724: '"fs"' has no exported member named '_readFileSync'. Did you mean 'readFileSync'? +src/tools/output-formatting/smart-report.ts(3,3): error TS6133: 'writeFileSync' is declared but its value is never read. +src/tools/output-formatting/smart-report.ts(4,3): error TS6133: 'existsSync' is declared but its value is never read. +src/tools/output-formatting/smart-report.ts(5,3): error TS6133: 'mkdirSync' is declared but its value is never read. +src/tools/output-formatting/smart-report.ts(7,1): error TS6192: All imports in import declaration are unused. +src/tools/output-formatting/smart-report.ts(8,1): error TS6192: All imports in import declaration are unused. +src/tools/output-formatting/smart-stream.ts(1,559): error TS6192: All imports in import declaration are unused. +src/tools/output-formatting/smart-stream.ts(10,1): error TS6192: All imports in import declaration are unused. +src/tools/output-formatting/smart-stream.ts(17,1): error TS6192: All imports in import declaration are unused. +src/tools/output-formatting/smart-stream.ts(18,1): error TS6192: All imports in import declaration are unused. +src/tools/output-formatting/smart-stream.ts(19,7): error TS6133: '_pipelineAsync' is declared but its value is never read. +src/tools/system-operations/smart-archive.ts(1,465): error TS6133: 'CacheEngine' is declared but its value is never read. +src/tools/system-operations/smart-archive.ts(2,1): error TS6133: 'tarStream' is declared but its value is never read. +src/tools/system-operations/smart-archive.ts(2,33): error TS7016: Could not find a declaration file for module 'tar-stream'. 'C:/Users/yolan/source/repos/token-optimizer-mcp/node_modules/tar-stream/index.js' implicitly has an 'any' type. +src/tools/system-operations/smart-archive.ts(3,1): error TS6133: 'tar' is declared but its value is never read. +src/tools/system-operations/smart-archive.ts(3,22): error TS7016: Could not find a declaration file for module 'tar-stream'. 'C:/Users/yolan/source/repos/token-optimizer-mcp/node_modules/tar-stream/index.js' implicitly has an 'any' type. +src/tools/system-operations/smart-archive.ts(4,1): error TS6133: 'zlib' is declared but its value is never read. +src/tools/system-operations/smart-archive.ts(6,1): error TS6133: 'path' is declared but its value is never read. +src/tools/system-operations/smart-archive.ts(9,7): error TS6133: '_pipelineAsync' is declared but its value is never read. +src/tools/system-operations/smart-archive.ts(10,7): error TS6133: '_stat' is declared but its value is never read. +src/tools/system-operations/smart-archive.ts(10,28): error TS2551: Property '_stat' does not exist on type 'typeof import("fs")'. Did you mean 'stat'? +src/tools/system-operations/smart-archive.ts(11,7): error TS6133: '_readdir' is declared but its value is never read. +src/tools/system-operations/smart-archive.ts(11,31): error TS2551: Property '_readdir' does not exist on type 'typeof import("fs")'. Did you mean 'readdir'? +src/tools/system-operations/smart-archive.ts(12,7): error TS6133: '_mkdir' is declared but its value is never read. +src/tools/system-operations/smart-archive.ts(12,29): error TS2551: Property '_mkdir' does not exist on type 'typeof import("fs")'. Did you mean 'mkdir'? +src/tools/system-operations/smart-cleanup.ts(1,471): error TS6133: 'CacheEngine' is declared but its value is never read. +src/tools/system-operations/smart-cleanup.ts(3,1): error TS6133: 'path' is declared but its value is never read. +src/tools/system-operations/smart-cleanup.ts(5,7): error TS6133: '_stat' is declared but its value is never read. +src/tools/system-operations/smart-cleanup.ts(5,28): error TS2551: Property '_stat' does not exist on type 'typeof import("fs")'. Did you mean 'stat'? +src/tools/system-operations/smart-cleanup.ts(6,7): error TS6133: '_readdir' is declared but its value is never read. +src/tools/system-operations/smart-cleanup.ts(6,31): error TS2551: Property '_readdir' does not exist on type 'typeof import("fs")'. Did you mean 'readdir'? +src/tools/system-operations/smart-cleanup.ts(7,7): error TS6133: '_unlink' is declared but its value is never read. +src/tools/system-operations/smart-cleanup.ts(7,30): error TS2551: Property '_unlink' does not exist on type 'typeof import("fs")'. Did you mean 'unlink'? +src/tools/system-operations/smart-cleanup.ts(8,7): error TS6133: '_rmdir' is declared but its value is never read. +src/tools/system-operations/smart-cleanup.ts(8,29): error TS2551: Property '_rmdir' does not exist on type 'typeof import("fs")'. Did you mean 'rmdir'? +src/tools/system-operations/smart-cleanup.ts(9,7): error TS6133: '_mkdir' is declared but its value is never read. +src/tools/system-operations/smart-cleanup.ts(9,29): error TS2551: Property '_mkdir' does not exist on type 'typeof import("fs")'. Did you mean 'mkdir'? +src/tools/system-operations/smart-cleanup.ts(10,7): error TS6133: '_rename' is declared but its value is never read. +src/tools/system-operations/smart-cleanup.ts(10,30): error TS2551: Property '_rename' does not exist on type 'typeof import("fs")'. Did you mean 'rename'? +src/tools/system-operations/smart-cleanup.ts(11,7): error TS6133: '_access' is declared but its value is never read. +src/tools/system-operations/smart-cleanup.ts(11,30): error TS2551: Property '_access' does not exist on type 'typeof import("fs")'. Did you mean 'access'? +src/tools/system-operations/smart-cron.ts(288,28): error TS2345: Argument of type 'SchedulerType' is not assignable to parameter of type 'Encoding'. +src/tools/system-operations/smart-cron.ts(325,66): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. +src/tools/system-operations/smart-cron.ts(570,28): error TS2345: Argument of type 'SchedulerType' is not assignable to parameter of type 'Encoding'. +src/tools/system-operations/smart-cron.ts(715,28): error TS2345: Argument of type 'SchedulerType' is not assignable to parameter of type 'Encoding'. +src/tools/system-operations/smart-cron.ts(844,28): error TS2345: Argument of type 'SchedulerType' is not assignable to parameter of type 'Encoding'. +src/tools/system-operations/smart-cron.ts(919,79): error TS2345: Argument of type '`undefined:${string}` | `auto:${string}` | `cron:${string}` | `windows-task:${string}`' is not assignable to parameter of type 'Encoding'. +src/tools/system-operations/smart-cron.ts(955,66): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. +src/tools/system-operations/smart-cron.ts(1076,7): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Record'. +src/tools/system-operations/smart-cron.ts(1132,67): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. +src/tools/system-operations/smart-cron.ts(1403,30): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/system-operations/smart-metrics.ts(1,618): error TS6133: 'CacheEngine' is declared but its value is never read. +src/tools/system-operations/smart-metrics.ts(2,1): error TS6133: 'si' is declared but its value is never read. +src/tools/system-operations/smart-network.ts(1,494): error TS6133: 'CacheEngine' is declared but its value is never read. +src/tools/system-operations/smart-network.ts(5,1): error TS6133: 'net' is declared but its value is never read. +src/tools/system-operations/smart-network.ts(6,1): error TS6133: 'crypto' is declared but its value is never read. +src/tools/system-operations/smart-network.ts(7,7): error TS6133: '_execAsync' is declared but its value is never read. +src/tools/system-operations/smart-network.ts(8,7): error TS6133: '_dnsLookup' is declared but its value is never read. +src/tools/system-operations/smart-network.ts(9,7): error TS6133: '_dnsReverse' is declared but its value is never read. +src/tools/system-operations/smart-network.ts(10,7): error TS6133: '_dnsResolve' is declared but its value is never read. +src/tools/system-operations/smart-network.ts(11,7): error TS6133: '_dnsResolve4' is declared but its value is never read. +src/tools/system-operations/smart-network.ts(12,7): error TS6133: '_dnsResolve6' is declared but its value is never read. +src/tools/system-operations/smart-process.ts(159,11): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/system-operations/smart-process.ts(201,9): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/system-operations/smart-process.ts(249,9): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/system-operations/smart-process.ts(258,34): error TS2339: Property 'generateKey' does not exist on type 'typeof CacheEngine'. +src/tools/system-operations/smart-process.ts(267,32): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/system-operations/smart-process.ts(274,13): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/system-operations/smart-process.ts(275,43): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/system-operations/smart-process.ts(290,38): error TS2345: Argument of type 'Buffer' is not assignable to parameter of type 'string'. +src/tools/system-operations/smart-process.ts(298,9): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/system-operations/smart-process.ts(346,9): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/system-operations/smart-process.ts(355,34): error TS2339: Property 'generateKey' does not exist on type 'typeof CacheEngine'. +src/tools/system-operations/smart-process.ts(364,32): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/system-operations/smart-process.ts(371,13): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/system-operations/smart-process.ts(372,43): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. +src/tools/system-operations/smart-process.ts(387,38): error TS2345: Argument of type 'Buffer' is not assignable to parameter of type 'string'. +src/tools/system-operations/smart-process.ts(395,9): error TS2322: Type 'TokenCountResult' is not assignable to type 'number'. +src/tools/system-operations/smart-process.ts(555,11): error TS6133: '_stdout' is declared but its value is never read. +src/tools/system-operations/smart-process.ts(555,13): error TS2339: Property '_stdout' does not exist on type '{ stdout: string; stderr: string; }'. +src/tools/system-operations/smart-process.ts(591,50): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/system-operations/smart-process.ts(592,65): error TS2554: Expected 0 arguments, but got 1. +src/tools/system-operations/smart-service.ts(248,81): error TS2345: Argument of type '`undefined:${string}` | `docker:${string}` | `systemd:${string}` | `windows:${string}`' is not assignable to parameter of type 'Encoding'. +src/tools/system-operations/smart-service.ts(476,83): error TS2345: Argument of type '`docker:${string}` | `systemd:${string}` | `windows:${string}`' is not assignable to parameter of type 'Encoding'. +src/tools/system-operations/smart-service.ts(526,83): error TS2345: Argument of type '`docker:${string}` | `systemd:${string}` | `windows:${string}`' is not assignable to parameter of type 'Encoding'. +src/tools/system-operations/smart-service.ts(579,83): error TS2345: Argument of type '`docker:${string}` | `systemd:${string}` | `windows:${string}`' is not assignable to parameter of type 'Encoding'. +src/tools/system-operations/smart-service.ts(789,79): error TS2345: Argument of type '`undefined:${string}` | `docker:${string}` | `systemd:${string}` | `windows:${string}`' is not assignable to parameter of type 'Encoding'. +src/tools/system-operations/smart-service.ts(934,30): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/tools/system-operations/smart-user.ts(264,77): error TS2345: Argument of type '"include-system:undefined" | "include-system:false" | "include-system:true"' is not assignable to parameter of type 'Encoding'. +src/tools/system-operations/smart-user.ts(318,78): error TS2345: Argument of type '"include-system:undefined" | "include-system:false" | "include-system:true"' is not assignable to parameter of type 'Encoding'. +src/tools/system-operations/smart-user.ts(378,76): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Encoding'. +src/tools/system-operations/smart-user.ts(436,77): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Encoding'. +src/tools/system-operations/smart-user.ts(495,78): error TS2345: Argument of type '`${string}:${string}`' is not assignable to parameter of type 'Encoding'. +src/tools/system-operations/smart-user.ts(527,67): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. +src/tools/system-operations/smart-user.ts(551,70): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Encoding'. +src/tools/system-operations/smart-user.ts(583,67): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. +src/tools/system-operations/smart-user.ts(604,77): error TS2345: Argument of type 'string' is not assignable to parameter of type 'Encoding'. +src/tools/system-operations/smart-user.ts(636,67): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. +src/tools/system-operations/smart-user.ts(658,81): error TS2345: Argument of type '"full"' is not assignable to parameter of type 'Encoding'. +src/tools/system-operations/smart-user.ts(690,67): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. +src/tools/system-operations/smart-user.ts(1486,30): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. diff --git a/error-breakdown.txt b/error-breakdown.txt new file mode 100644 index 0000000..7faf65b --- /dev/null +++ b/error-breakdown.txt @@ -0,0 +1,76 @@ + 107 Argument + 67 The + 59 Type + 43 Expected + 36 All + 34 Property + 23 'CacheEngine' + 12 '_tokenCounter' + 10 Module + 5 'tokenCounter' + 5 'compact' + 4 Operator + 4 'createHash' + 4 Cannot + 3 'projectRoot' + 3 'path' + 3 Block-scoped + 3 '_metrics' + 2 'metrics' + 2 Could + 2 '_stat' + 2 '_reductionPercentage' + 2 '_readdir' + 2 '_pipelineAsync' + 2 '_mkdir' + 2 '_dnsResolve' + 2 '"fs"' + 2 '"../../core/token-counter"' + 1 'zlib' + 1 'writeFileSync' + 1 'unparseCsv' + 1 'ts' + 1 'TokenCounter' + 1 'tarStream' + 1 'tar' + 1 'SymbolInfo' + 1 'stats' + 1 'si' + 1 'relationships' + 1 'parseYAML' + 1 'parsePatch' + 1 'nlp' + 1 'net' + 1 'mkdirSync' + 1 'MetricsCollector' + 1 'includeMetadata' + 1 'hash' + 1 'grammarCache' + 1 'getDefaultTTL' + 1 'fs' + 1 'existsSync' + 1 'diffWords' + 1 'diffLines' + 1 'diffChars' + 1 'DeltaState' + 1 'crypto' + 1 'createTwoFilesPatch' + 1 'ComplexityMetrics' + 1 'CacheEngineClass' + 1 '_unlink' + 1 '_symbolsResult' + 1 '_stdout' + 1 '_size' + 1 '_rmdir' + 1 '_rename' + 1 '_projectRoot' + 1 '_markAsIgnored' + 1 '_fileDir' + 1 '_execAsync' + 1 '_dnsReverse' + 1 '_dnsResolve6' + 1 '_dnsResolve4' + 1 '_dnsLookup' + 1 '_coAccessPatterns' + 1 '_cachedResult' + 1 '_access' diff --git a/fix-cache-set-syntax.cjs b/fix-cache-set-syntax.cjs index a18c382..5ad38ac 100644 --- a/fix-cache-set-syntax.cjs +++ b/fix-cache-set-syntax.cjs @@ -1,171 +1,77 @@ -#!/usr/bin/env node -/** - * Fix malformed cache.set() calls created by previous regex script - * - * The previous fix-migrated-tools.cjs created syntax errors like: - * cache.set(key, value, BAD SYNTAX) - * - * This needs to be: - * cache.set(key, value, originalSize, compressedSize) - * - * Strategy: - * 1. Find all cache.set() calls with malformed syntax - * 2. Extract actual values for originalSize and compressedSize - * 3. Reconstruct proper call - */ - const fs = require('fs'); const path = require('path'); +const { execSync } = require('child_process'); -// Find all TypeScript files in src/tools -function findToolFiles(dir, files = []) { - const entries = fs.readdirSync(dir, { withFileTypes: true }); - - for (const entry of entries) { - const fullPath = path.join(dir, entry.name); - if (entry.isDirectory()) { - findToolFiles(fullPath, files); - } else if (entry.isFile() && entry.name.endsWith('.ts')) { - files.push(fullPath); - } - } +console.log('Getting list of syntax errors from build...'); - return files; -} - -/** - * Fix cache.set() syntax errors - * - * Patterns to fix: - * 1. cache.set calls with malformed parameter comments - * 2. cache.set calls with wrong parameters - */ -function fixCacheSetSyntax(content, filePath) { - let fixed = content; - let changesMade = false; - - // Pattern 1: Remove malformed syntax with duration label and fix parameters - // Example: cache.set with bad comment syntax - const pattern1 = /this\.cache\.set\(\s*([^,]+),\s*([^,]+),\s*(?:duration:\s*)?([^\/,]+)\s*\/\*\s*originalSize\s*\*\/\s*,\s*([^)]+)\s*\/\*\s*compressedSize\s*\*\/\s*\)/g; - - fixed = fixed.replace(pattern1, (match, key, value, param3, param4) => { - changesMade = true; - - // Extract actual variable names from param3 and param4 - const originalSize = param3.trim(); - const compressedSize = param4.trim(); - - console.log(` Fixing: ${match.substring(0, 80)}...`); - console.log(` Key: ${key.trim()}`); - console.log(` Value: ${value.trim()}`); - console.log(` OriginalSize: ${originalSize}`); - console.log(` CompressedSize: ${compressedSize}`); - - return `this.cache.set(${key}, ${value}, ${originalSize}, ${compressedSize})`; +let buildOutput; +try { + buildOutput = execSync('npm run build 2>&1', { + cwd: __dirname, + encoding: 'utf-8', + maxBuffer: 10 * 1024 * 1024 }); +} catch (error) { + buildOutput = error.stdout || error.output.join(''); +} - // Pattern 2: Fix any remaining malformed cache.set() with comments in wrong places - // Example: cache.set with label syntax - const pattern2 = /this\.cache\.set\(\s*([^,]+),\s*([^,]+),\s*([^:;,]+):\s*([^)]+)\s*\)/g; - - fixed = fixed.replace(pattern2, (match, key, value, label, rest) => { - changesMade = true; - console.log(` Fixing labeled parameter: ${match.substring(0, 80)}...`); - - // This pattern indicates broken syntax - we need context to fix it properly - // For now, mark it for manual review - return `this.cache.set(${key}, ${value}, 0, 0) /* FIXME: Manual review needed */`; - }); +const lines = buildOutput.split('\n'); +const errorFiles = new Set(); - // Pattern 3: Fix cache.set() calls with only 2 parameters (missing originalSize and compressedSize) - const pattern3 = /this\.cache\.set\(\s*([^,]+),\s*([^,)]+)\s*\);/g; - - // Only fix if the match doesn't have 4 parameters already - fixed = fixed.replace(pattern3, (match, key, value) => { - // Check if this is actually a 2-parameter call or if it's just a formatting issue - const fullMatch = match.trim(); - if (!fullMatch.includes('/*') && fullMatch.split(',').length === 2) { - changesMade = true; - console.log(` Adding missing parameters to: ${match.substring(0, 60)}...`); - return `this.cache.set(${key}, ${value}, 0, 0) /* FIXME: Add originalSize and compressedSize */`; - } - return match; - }); +lines.forEach(line => { + const cleanLine = line.replace(/\r/g, ''); + const syntaxMatch = cleanLine.match(/^(.+\.ts)\(\d+,\d+\): error TS1(005|109|134|128):/); + if (syntaxMatch) { + errorFiles.add(syntaxMatch[1]); + } +}); - return { fixed, changesMade }; -} +console.log(`Found ${errorFiles.size} files with syntax errors`); -/** - * Analyze file to understand cache.set() context - */ -function analyzeFileContext(content, filePath) { - const lines = content.split('\n'); - const cacheSetLines = []; - - lines.forEach((line, index) => { - if (line.includes('cache.set')) { - cacheSetLines.push({ - line: index + 1, - content: line.trim(), - context: lines.slice(Math.max(0, index - 3), Math.min(lines.length, index + 3)) - }); - } - }); +let filesModified = 0; - return cacheSetLines; -} +for (const relativeFilePath of errorFiles) { + const filePath = path.join(__dirname, relativeFilePath); -// Main processing -function processFile(filePath) { - const relativePath = path.relative(process.cwd(), filePath); + if (!fs.existsSync(filePath)) { + console.log(`Skipping ${relativeFilePath} - file not found`); + continue; + } let content = fs.readFileSync(filePath, 'utf-8'); - const original = content; + const originalContent = content; - // Analyze context first - const cacheSetCalls = analyzeFileContext(content, filePath); + // Fix: JSON.stringify(data), "utf-8"), -> JSON.stringify(data), + content = content.replace(/JSON\.stringify\(([^)]+)\),\s*"utf-8"\),/g, 'JSON.stringify($1),'); - if (cacheSetCalls.length > 0) { - console.log(`\n${relativePath} - ${cacheSetCalls.length} cache.set() calls found`); + // Fix: variable), "utf-8"), -> variable, + content = content.replace(/([a-zA-Z_$][a-zA-Z0-9_$]*)\),\s*"utf-8"\),/g, '$1,'); - // Apply fixes - const { fixed, changesMade } = fixCacheSetSyntax(content, filePath); + // Fix: JSON.stringify(data)), -> JSON.stringify(data), + content = content.replace(/JSON\.stringify\(([^)]+)\)\),/g, 'JSON.stringify($1),'); - // Only write if changes were made - if (changesMade && fixed !== original) { - fs.writeFileSync(filePath, fixed, 'utf-8'); - console.log(` ✓ Fixed and saved`); - return true; - } else if (cacheSetCalls.length > 0) { - console.log(` - No auto-fix applied (may need manual review)`); - } - } - - return false; -} + // Fix: variable)), -> variable, + content = content.replace(/([a-zA-Z_$][a-zA-Z0-9_$]*)\)\),/g, '$1,'); -// Run -const toolsDir = path.join(__dirname, 'src', 'tools'); + // Fix: JSON.stringify(data), 'utf-8'); -> JSON.stringify(data); + content = content.replace(/JSON\.stringify\(([^)]+)\),\s*['"]utf-8['"]?\);/g, 'JSON.stringify($1);'); -if (!fs.existsSync(toolsDir)) { - console.error(`Error: ${toolsDir} not found`); - process.exit(1); -} + // Fix: variable), 'utf-8'); -> variable; + content = content.replace(/([a-zA-Z_$][a-zA-Z0-9_$]*)\),\s*['"]utf-8['"]?\);/g, '$1);'); -const files = findToolFiles(toolsDir); + // Fix: JSON.stringify(data)); -> JSON.stringify(data); + content = content.replace(/JSON\.stringify\(([^)]+)\)\);/g, 'JSON.stringify($1);'); -console.log(`Analyzing ${files.length} tool files for cache.set() syntax errors...\n`); + // Fix: variable)); -> variable; + content = content.replace(/\b([a-zA-Z_$][a-zA-Z0-9_$]*)\)\);/g, '$1);'); -let fixedCount = 0; -for (const file of files) { - try { - if (processFile(file)) { - fixedCount++; - } - } catch (error) { - console.error(` ✗ Error processing ${file}: ${error.message}`); + if (content !== originalContent) { + fs.writeFileSync(filePath, content, 'utf-8'); + filesModified++; + console.log(`✓ ${relativeFilePath}: Fixed syntax errors`); } } -console.log(`\n✓ Fixed cache.set() syntax in ${fixedCount} files out of ${files.length}`); -console.log(`\nNext: Run 'npm run build' to verify TypeScript compilation`); +console.log(`\n✅ Summary:`); +console.log(` Files modified: ${filesModified}`); +console.log(`\nRun 'npm run build' to verify all syntax errors are fixed.`); diff --git a/gemini-agent-plan.md b/gemini-agent-plan.md new file mode 100644 index 0000000..ed6f6ee --- /dev/null +++ b/gemini-agent-plan.md @@ -0,0 +1,123 @@ +Loaded cached credentials. +File C:\Users\yolan\.cache/vscode-ripgrep/ripgrep-v13.0.0-10-x86_64-pc-windows-msvc.zip has been cached +Of course. Based on the error breakdown and your requirements, here is a detailed execution plan for a team of specialized AI agents to systematically eliminate all 493 TypeScript errors. + +This plan prioritizes foundational errors, enables maximum parallelism for independent tasks, and leaves cleanup tasks for the end to prevent rework. + +### Pre-Execution Setup + +1. **Create a dedicated branch:** Before starting, create a new git branch to isolate these fixes. + ```bash + git checkout -b feature/typescript-error-fix + ``` +2. **Initial Verification:** Confirm the starting error count. + * **Command:** `npx tsc --noEmit > initial-errors.txt` + * **Expected:** The file should contain exactly 493 errors. + +--- + +### Agent Team Roster & Execution Plan + +The team consists of 6 agents, organized into three phases. + +| Phase | Agent Name | Goal | Order | +| :--- | :--- | :--- | :--- | +| **1** | **The Architect** | Fix foundational project and type resolution errors. | Sequential | +| **2** | **The Type Guardian** | Resolve core type mismatch and assignment errors. | Parallel | +| **2** | **The Signature Specialist** | Correct all function call signature mismatches. | Parallel | +| **2** | **The Operator** | Fix all invalid arithmetic and logical operations. | Parallel | +| **2** | **The Property Master** | Resolve incorrect property access on objects. | Parallel | +| **3** | **The Janitor** | Clean up all unused code and remaining minor errors. | Sequential | + +--- + +### **Phase 1: Foundational Fixes (Sequential)** + +This phase must be completed first, as these errors can affect the entire compilation and the accuracy of other error reports. + +#### **Agent 1: The Architect** +* **Goal:** Fix 21 foundational errors. + * `TS2304`: 4 (Cannot find name) + * `TS7016`: 2 (Could not find declaration file for module) + * `TS6196`: 1 (Composite project requires rootDir) + * `TS2551`: 10 (Property does not exist, did you mean...) + * `TS2724`: 4 (No exported member, did you mean...) +* **Execution Order:** Sequential (Must complete before Phase 2). +* **Verification:** + * **Command:** `npx tsc --noEmit` + * **Success Criteria:** The total error count is reduced by exactly 21. +* **Expected Error Count:** 493 - 21 = **472 errors** +* **Rollback Strategy:** If the goal is not met, run `git reset --hard HEAD` to revert the agent's changes and analyze the remaining errors for a new approach. + +--- + +### **Phase 2: Core Logic & Type Safety (Parallel)** + +These agents can work simultaneously in separate branches, which can then be merged sequentially. + +#### **Agent 2: The Type Guardian** +* **Goal:** Fix 166 core type-mismatch errors. + * `TS2345`: 107 (Argument of type 'X' is not assignable to parameter of type 'Y') + * `TS2322`: 59 (Type 'X' is not assignable to type 'Y') +* **Execution Order:** Parallel. +* **Verification:** + * **Command:** `npx tsc --noEmit` + * **Success Criteria:** The total error count is reduced by exactly 166 from the post-Phase 1 total. +* **Expected Error Count:** 472 - 166 = **306 errors** +* **Rollback Strategy:** `git reset --hard HEAD`. These errors are complex; failure may require breaking the goal into smaller, file-specific tasks. + +#### **Agent 3: The Signature Specialist** +* **Goal:** Fix 43 function argument count errors. + * `TS2554`: 43 (Expected X arguments, but got Y) +* **Execution Order:** Parallel. +* **Verification:** + * **Command:** `npx tsc --noEmit` + * **Success Criteria:** The total error count is reduced by exactly 43. +* **Expected Error Count:** 306 - 43 = **263 errors** +* **Rollback Strategy:** `git reset --hard HEAD`. + +#### **Agent 4: The Operator** +* **Goal:** Fix 71 invalid operation errors. + * `TS2362`: 36 (Operand of an arithmetic operation must be type 'number'...) + * `TS2363`: 31 (The left-hand side of a 'for...in' statement must be of type 'string' or 'any') + * `TS2365`: 4 (Operator 'X' cannot be applied to types 'Y' and 'Z') +* **Execution Order:** Parallel. +* **Verification:** + * **Command:** `npx tsc --noEmit` + * **Success Criteria:** The total error count is reduced by exactly 71. +* **Expected Error Count:** 263 - 71 = **192 errors** +* **Rollback Strategy:** `git reset --hard HEAD`. + +#### **Agent 5: The Property Master** +* **Goal:** Fix 24 property access errors. + * `TS2339`: 24 (Property 'X' does not exist on type 'Y') +* **Execution Order:** Parallel. +* **Verification:** + * **Command:** `npx tsc --noEmit` + * **Success Criteria:** The total error count is reduced by exactly 24. +* **Expected Error Count:** 192 - 24 = **168 errors** +* **Rollback Strategy:** `git reset --hard HEAD`. + +--- + +### **Phase 3: Final Cleanup (Sequential)** + +This final agent runs after all other fixes are merged. It handles cleanup, which could have been affected by the previous fixes (e.g., a variable is no longer unused). + +#### **Agent 6: The Janitor** +* **Goal:** Fix the remaining 168 errors. + * `TS6133`: 110 (unused variables) + * `TS6192`: 35 (all imports in declaration unused) + * `TS2305`: 10 (module has no exported member - *Note: These may have been introduced by other fixes*) + * `TS2749`: 6 (refers to a value but is being used as a type) + * `TS7022`: 3 (implicitly has type 'any') + * `TS2448`: 3 (block-scoped variable used before declaration) + * `TS6198`: 1 (all imports unused, could use type-only import) +* **Execution Order:** Sequential (Must run last). +* **Verification:** + * **Command:** `npx tsc --noEmit` + * **Success Criteria:** The command executes without any output. +* **Expected Error Count:** 168 - 168 = **0 errors** +* **Rollback Strategy:** `git reset --hard HEAD`. If this agent fails, it's likely due to cascading changes. The remaining errors should be analyzed manually and potentially assigned to a new, highly specialized agent. + +This structured plan provides a clear path to a zero-error state while maximizing efficiency through parallel work. diff --git a/gemini-prompt.txt b/gemini-prompt.txt new file mode 100644 index 0000000..10395d0 --- /dev/null +++ b/gemini-prompt.txt @@ -0,0 +1,46 @@ +You are an expert TypeScript error resolution planner. I have 493 TypeScript compilation errors that need to be fixed systematically using a team of AI agents. + +ERROR BREAKDOWN: +- TS6133: 110 (unused variables - declared but never read) +- TS2345: 107 (type argument mismatches) +- TS2322: 59 (type assignment mismatches) +- TS2554: 43 (function argument count wrong) +- TS2362: 36 (arithmetic operand must be number) +- TS6192: 35 (all imports in declaration unused) +- TS2363: 31 (left operand must be unique symbol) +- TS2339: 24 (property does not exist on type) +- TS2551: 10 (property does not exist, did you mean...) +- TS2305: 10 (module has no exported member) +- TS2749: 6 (refers to value but used as type) +- TS2724: 4 (has no exported member, did you mean...) +- TS2365: 4 (operator cannot be applied to types) +- TS2304: 4 (cannot find name) +- TS7022: 3 (implicitly has type any) +- TS2448: 3 (block-scoped variable used before declaration) +- TS7016: 2 (could not find declaration file for module) +- TS6198: 1 (all imports unused, could use type-only import) +- TS6196: 1 (composite project requires rootDir) + +TOTAL: 493 errors + +REQUIREMENTS: +1. Create a team of 5-7 expert AI agents +2. Each agent must have a SPECIFIC goal: "Fix X errors of type Y" +3. Agents should work on independent error types to enable parallel execution +4. Each agent MUST meet or surpass their goal (not just partial progress) +5. Provide verification criteria for each agent +6. Account for dependencies (e.g., fixing unused imports might reveal other errors) + +PREVIOUS ATTEMPTS: +- Successfully removed 168 unused imports (reduced TS6133/TS6192 by ~50%) +- Fixed all TS2305 export errors in index files +- Fixed import paths and function signatures +- Created automated scripts for pattern-based fixes + +Create a detailed execution plan with: +1. Agent team roster (5-7 agents) +2. Each agent's specific goal (X errors of type Y) +3. Order of execution (sequential vs parallel) +4. Verification command for each agent +5. Expected error count after each agent completes +6. Rollback strategy if agent fails to meet goal diff --git a/package-lock.json b/package-lock.json index 05f60fb..676449b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "devDependencies": { "@types/better-sqlite3": "^7.6.13", "@types/node": "^24.7.2", + "@types/tar-stream": "^3.1.4", "typescript": "^5.9.3" } }, @@ -63,6 +64,16 @@ "undici-types": "~7.14.0" } }, + "node_modules/@types/tar-stream": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/tar-stream/-/tar-stream-3.1.4.tgz", + "integrity": "sha512-921gW0+g29mCJX0fRvqeHzBlE/XclDaAG0Ousy1LCghsOhvaKacDeRGEVzQP9IPfKn8Vysy7FEXAIxycpc/CMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/accepts": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", diff --git a/package.json b/package.json index 400d0b7..5345ba1 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "devDependencies": { "@types/better-sqlite3": "^7.6.13", "@types/node": "^24.7.2", + "@types/tar-stream": "^3.1.4", "typescript": "^5.9.3" }, "dependencies": { diff --git a/src/tools/advanced-caching/cache-benchmark.ts b/src/tools/advanced-caching/cache-benchmark.ts index 323410d..71d576c 100644 --- a/src/tools/advanced-caching/cache-benchmark.ts +++ b/src/tools/advanced-caching/cache-benchmark.ts @@ -405,15 +405,13 @@ class BenchmarkExecutor { ): Promise { const startTime = process.hrtime.bigint(); const value = this.generateValue(workload.valueSize); - this.cache.set(key, value.toString("utf-8"), 0); + const valueStr = value.toString("utf-8"); + this.cache.set(key, valueStr, valueStr.length, valueStr.length); const endTime = process.hrtime.bigint(); const latency = Number(endTime - startTime) / 1_000_000; // Convert to ms - this.latencies.push( - latency /* originalSize */, - config.ttl || 3600 /* compressedSize */, - ); + this.latencies.push(latency); this.operations.push({ type: "write", timestamp: Date.now(), latency }); } diff --git a/src/tools/advanced-caching/cache-compression.ts b/src/tools/advanced-caching/cache-compression.ts index 94d9abf..ee285e7 100644 --- a/src/tools/advanced-caching/cache-compression.ts +++ b/src/tools/advanced-caching/cache-compression.ts @@ -211,15 +211,6 @@ export interface CacheCompressionResult { }; } -/** - * Delta compression state for time-series data - */ -interface DeltaState { - baseline: any; - timestamp: number; - version: number; -} - /** * Cache Compression Tool - Advanced compression strategies */ @@ -479,7 +470,7 @@ export class CacheCompressionTool { timestamp: Date.now(), }; - const metadataBuffer = JSON.stringify(metadata)); + const metadataBuffer = JSON.stringify(metadata); const metadataLength = Buffer.allocUnsafe(4); metadataLength.writeUInt32LE(metadataBuffer.length, 0); @@ -1020,7 +1011,7 @@ export class CacheCompressionTool { // Replace repeated strings with dictionary references const compressed = this.compressWithDictionary(obj, dict); - return JSON.stringify(compressed)); + return Buffer.from(JSON.stringify(compressed), 'utf-8'); } catch { // Not JSON, just use gzip return Buffer.from(str); @@ -1041,7 +1032,7 @@ export class CacheCompressionTool { compressed.data, dict, ); - return JSON.stringify(decompressed)); + return Buffer.from(JSON.stringify(decompressed), 'utf-8'); } return data; @@ -1281,7 +1272,7 @@ export class CacheCompressionTool { } else if (typeof data === "string") { return Buffer.from(data, "utf-8"); } else { - return JSON.stringify(data), "utf-8"); + return Buffer.from(JSON.stringify(data), "utf-8"); } } @@ -1301,7 +1292,7 @@ export class CacheCompressionTool { active: i % 2 === 0, })), }; - return JSON.stringify(obj)); + return Buffer.from(JSON.stringify(obj), "utf-8"); } case "text": { diff --git a/src/tools/advanced-caching/cache-partition.ts b/src/tools/advanced-caching/cache-partition.ts index a76b4e3..92d7be8 100644 --- a/src/tools/advanced-caching/cache-partition.ts +++ b/src/tools/advanced-caching/cache-partition.ts @@ -225,13 +225,10 @@ export class CachePartitionTool extends EventEmitter { // Generate cache key for cacheable operations let cacheKey: string | null = null; if (useCache && this.isCacheableOperation(operation)) { - cacheKey = CacheEngine.generateKey( - "cache-partition", - JSON.stringify({ - operation, - ...this.getCacheKeyParams(options), - }), - ); + cacheKey = `cache-partition:${JSON.stringify({ + operation, + ...this.getCacheKeyParams(options), + })}`; // Check cache const cached = this.cache.get(cacheKey); @@ -291,7 +288,7 @@ export class CachePartitionTool extends EventEmitter { if (cacheKey && useCache) { this.cache.set( cacheKey, - JSON.stringify(data), "utf-8"), + JSON.stringify(data), cacheTTL, tokensUsed, ); diff --git a/src/tools/api-database/smart-api-fetch.ts b/src/tools/api-database/smart-api-fetch.ts index 6093b6d..86eb71e 100644 --- a/src/tools/api-database/smart-api-fetch.ts +++ b/src/tools/api-database/smart-api-fetch.ts @@ -1,4 +1,4 @@ -/** +/** * Smart API Fetch Tool - 83% Token Reduction * * HTTP client with intelligent features: @@ -427,7 +427,7 @@ export class SmartApiFetch { } try { - const result = JSON.parse(cached) as SmartApiFetchResult; + const result = JSON.parse(cached.toString('utf-8')) as SmartApiFetchResult; // Check if cache is still valid const age = (Date.now() - result.timestamp) / 1000; diff --git a/src/tools/api-database/smart-database.ts b/src/tools/api-database/smart-database.ts index b279870..d8a1764 100644 --- a/src/tools/api-database/smart-database.ts +++ b/src/tools/api-database/smart-database.ts @@ -1,4 +1,22 @@ -/** * Smart Database - Database Query Optimizer with 83% Token Reduction * * Features: * - Query execution with intelligent result caching * - Query plan analysis (EXPLAIN) * - Index usage detection and recommendations * - Query optimization suggestions * - Slow query detection and bottleneck analysis * - Connection pooling information * - Query performance tracking * * Token Reduction Strategy: * - Cached queries: Row count only (95% reduction) * - EXPLAIN analysis: Plan summary (85% reduction) * - Query execution: Top 10 rows (80% reduction) * - Analysis only: Query info + suggestions (90% reduction) * - Average: 83% reduction */ import { createHash } from "crypto"; +/** + * Smart Database - Database Query Optimizer with 83% Token Reduction + * + * Features: + * - Query execution with intelligent result caching + * - Query plan analysis (EXPLAIN) + * - Index usage detection and recommendations + * - Query optimization suggestions + * - Slow query detection and bottleneck analysis + * - Connection pooling information + * - Query performance tracking + * + * Token Reduction Strategy: + * - Cached queries: Row count only (95% reduction) + * - EXPLAIN analysis: Plan summary (85% reduction) + * - Query execution: Top 10 rows (80% reduction) + * - Analysis only: Query info + suggestions (90% reduction) + * - Average: 83% reduction + */ import { createHash } from "crypto"; import type { CacheEngine } from "../../core/cache-engine"; import type { TokenCounter } from "../../core/token-counter"; import type { MetricsCollector } from "../../core/metrics"; diff --git a/src/tools/api-database/smart-graphql.ts b/src/tools/api-database/smart-graphql.ts index 725c8de..e53a2ce 100644 --- a/src/tools/api-database/smart-graphql.ts +++ b/src/tools/api-database/smart-graphql.ts @@ -484,7 +484,7 @@ export class SmartGraphQL { // Check for deeply nested queries if (parsed.selections.length > 0) { const maxDepth = Math.max( - ...parsed.selections.map((s) => this.getSelectionDepth(s)), + ...parsed.selections.map((s) => this.getSelectionDepth(s)) ); if (maxDepth > 4) { reductions.push({ @@ -587,7 +587,7 @@ export class SmartGraphQL { // Cache for 1 hour await this.cache.set( cacheKey, - Buffer.from(JSON.stringify(schemaInfo), "utf-8"), + JSON.stringify(schemaInfo), 0, 3600, ); @@ -723,7 +723,7 @@ export class SmartGraphQL { await this.cache.set( key, - JSON.stringify(cacheData)), + JSON.stringify(cacheData), tokensSaved, ttl, ); diff --git a/src/tools/api-database/smart-migration.ts b/src/tools/api-database/smart-migration.ts index 4bc0fab..8559420 100644 --- a/src/tools/api-database/smart-migration.ts +++ b/src/tools/api-database/smart-migration.ts @@ -23,8 +23,8 @@ import type { CacheEngine } from "../../core/cache-engine"; import type { TokenCounter } from "../../core/token-counter"; import type { MetricsCollector } from "../../core/metrics"; import { CacheEngine as CacheEngineClass } from "../../core/cache-engine"; -import { globalTokenCounter } from "../../core/token-counter"; -import { globalMetricsCollector } from "../../core/metrics"; +import { TokenCounter } from "../../core/token-counter"; +import { MetricsCollector } from "../../core/metrics"; // ============================================================================ // Type Definitions @@ -517,16 +517,18 @@ CREATE TABLE IF NOT EXISTS example ( const tokensSaved = this.tokenCounter.count(fullOutput).tokens; // Cache for specified TTL (default: 1 hour) + const cacheStr = JSON.stringify(cacheData); this.cache.set( key, - JSON.stringify(cacheData)), // Convert to milliseconds + cacheStr, tokensSaved, + cacheStr.length, ); } catch (error) { // Caching failure should not break the operation console.error( - "Failed to cache migration result:" /* originalSize */, - (ttl || 3600) * 1000 /* compressedSize */, + "Failed to cache migration result:", + error ); } } @@ -895,10 +897,12 @@ export async function runSmartMigration( 100, join(homedir(), ".hypercontext", "cache"), ); + const tokenCounter = new TokenCounter(); + const metrics = new MetricsCollector(); const migration = getSmartMigration( cache, - globalTokenCounter, - globalMetricsCollector, + tokenCounter, + metrics, ); const result = await migration.run(options); diff --git a/src/tools/api-database/smart-orm.ts b/src/tools/api-database/smart-orm.ts index 2d62930..56f6597 100644 --- a/src/tools/api-database/smart-orm.ts +++ b/src/tools/api-database/smart-orm.ts @@ -800,7 +800,7 @@ export class SmartORM { suggestEagerLoading: options.suggestEagerLoading, analyzeRelationships: options.analyzeRelationships, }; - return CacheEngine.generateKey("smart_orm", JSON.stringify(keyData)); + return `smart_orm:${JSON.stringify(keyData)}`; } private async getCachedResult(key: string, ttl: number): Promise { @@ -824,7 +824,8 @@ export class SmartORM { _ttl?: number, ): Promise { const cacheData = { ...result, timestamp: Date.now() }; - await this.cache.set(key, JSON.stringify(cacheData)), 3600); + const cacheStr = JSON.stringify(cacheData); + await this.cache.set(key, cacheStr, cacheStr.length, cacheStr.length); } } diff --git a/src/tools/api-database/smart-schema.ts b/src/tools/api-database/smart-schema.ts index 293ebb6..8ae8428 100644 --- a/src/tools/api-database/smart-schema.ts +++ b/src/tools/api-database/smart-schema.ts @@ -22,8 +22,8 @@ import type { CacheEngine } from "../../core/cache-engine"; import type { TokenCounter } from "../../core/token-counter"; import type { MetricsCollector } from "../../core/metrics"; import { CacheEngine as CacheEngineClass } from "../../core/cache-engine"; -import { globalTokenCounter } from "../../core/token-counter"; -import { globalMetricsCollector } from "../../core/metrics"; +import { TokenCounter } from "../../core/token-counter"; +import { MetricsCollector } from "../../core/metrics"; import { generateCacheKey } from "../shared/hash-utils"; // ============================================================================ @@ -1166,10 +1166,12 @@ export async function runSmartSchema( 100, join(homedir(), ".hypercontext", "cache"), ); + const tokenCounter = new TokenCounter(); + const metrics = new MetricsCollector(); const schema = getSmartSchema( cacheInstance, - globalTokenCounter, - globalMetricsCollector, + tokenCounter, + metrics, ); const result = await schema.run(options); diff --git a/src/tools/api-database/smart-sql.ts b/src/tools/api-database/smart-sql.ts index a14f61f..99ebba5 100644 --- a/src/tools/api-database/smart-sql.ts +++ b/src/tools/api-database/smart-sql.ts @@ -613,7 +613,7 @@ export class SmartSql { .digest("hex") .substring(0, 16); - return CacheEngine.generateKey("smart_sql", hash); + return `smart_sql:${hash}`; } private async getCachedResult( @@ -658,15 +658,15 @@ export class SmartSql { timestamp: Date.now(), }; - const tokensSavedResult = this.tokenCounter.count(JSON.stringify(cacheData)); + const cacheStr = JSON.stringify(cacheData); + const tokensSavedResult = this.tokenCounter.count(cacheStr); const tokensSaved = tokensSavedResult.tokens; await this.cache.set( key, - JSON.stringify(cacheData)), - ttl, - tokensSaved, - "", + cacheStr, + cacheStr.length, + cacheStr.length, ); } } @@ -694,7 +694,7 @@ export async function runSmartSql(options: SmartSqlOptions): Promise { const cache = new CacheEngine(100, join(homedir(), ".hypercontext", "cache")); const sql = getSmartSql( cache, - new TokenCounter("gpt-4"), + new TokenCounter(), new MetricsCollector(), ); diff --git a/src/tools/build-systems/smart-build.ts b/src/tools/build-systems/smart-build.ts index c69cf86..075f6a4 100644 --- a/src/tools/build-systems/smart-build.ts +++ b/src/tools/build-systems/smart-build.ts @@ -10,6 +10,7 @@ import { spawn } from "child_process"; import { CacheEngine } from "../../core/cache-engine"; +import { TokenCounter } from "../../core/token-counter"; import { MetricsCollector } from "../../core/metrics"; import { createHash } from "crypto"; import { readFileSync, existsSync, readdirSync, statSync } from "fs"; @@ -116,20 +117,20 @@ interface SmartBuildOutput { export class SmartBuild { private cache: CacheEngine; - private _tokenCounter: _tokenCounter; - private _metrics: MetricsCollector; + private tokenCounter: TokenCounter; + private metrics: MetricsCollector; private cacheNamespace = "smart_build"; private projectRoot: string; constructor( cache: CacheEngine, - _tokenCounter: _tokenCounter, - _metrics: MetricsCollector, + tokenCounter: TokenCounter, + metrics: MetricsCollector, projectRoot?: string, ) { this.cache = cache; - this._tokenCounter = _tokenCounter; - this._metrics = _metrics; + this.tokenCounter = tokenCounter; + this.metrics = metrics; this.projectRoot = projectRoot || process.cwd(); } @@ -583,11 +584,11 @@ export class SmartBuild { */ export function getSmartBuildTool( cache: CacheEngine, - _tokenCounter: _tokenCounter, - _metrics: MetricsCollector, + tokenCounter: TokenCounter, + metrics: MetricsCollector, projectRoot?: string, ): SmartBuild { - return new SmartBuild(cache, _tokenCounter, _metrics, projectRoot); + return new SmartBuild(cache, tokenCounter, metrics, projectRoot); } /** @@ -598,13 +599,13 @@ export async function runSmartBuild( ): Promise { // Create standalone resources for CLI usage const cache = new CacheEngine(100, join(homedir(), ".hypercontext", "cache")); - const _tokenCounter = new _tokenCounter(); - const _metrics = new MetricsCollector(); + const tokenCounter = new TokenCounter(); + const metrics = new MetricsCollector(); const smartBuild = new SmartBuild( cache, - _tokenCounter, - _metrics, + tokenCounter, + metrics, options.projectRoot, ); try { diff --git a/src/tools/build-systems/smart-docker.ts b/src/tools/build-systems/smart-docker.ts index 7732201..0bcc0b0 100644 --- a/src/tools/build-systems/smart-docker.ts +++ b/src/tools/build-systems/smart-docker.ts @@ -584,7 +584,7 @@ export class SmartDocker { const cacheData = { ...result, cachedAt: Date.now() }; this.cache.set( this.cacheNamespace + ":" + key, - JSON.stringify(cacheData)), + JSON.stringify(cacheData), ttl, 0, ); diff --git a/src/tools/build-systems/smart-lint.ts b/src/tools/build-systems/smart-lint.ts index 8d2fe9d..d2d2adf 100644 --- a/src/tools/build-systems/smart-lint.ts +++ b/src/tools/build-systems/smart-lint.ts @@ -10,6 +10,7 @@ import { spawn } from "child_process"; import { CacheEngine } from "../../core/cache-engine"; +import { TokenCounter } from "../../core/token-counter"; import { MetricsCollector } from "../../core/metrics"; import { createHash } from "crypto"; import { readFileSync, existsSync } from "fs"; @@ -149,21 +150,21 @@ interface SmartLintOutput { export class SmartLint { private cache: CacheEngine; - private _tokenCounter: _tokenCounter; - private _metrics: MetricsCollector; + private tokenCounter: TokenCounter; + private metrics: MetricsCollector; private cacheNamespace = "smart_lint"; private projectRoot: string; private ignoredIssuesKey = "ignored_issues"; constructor( cache: CacheEngine, - _tokenCounter: _tokenCounter, - _metrics: MetricsCollector, + tokenCounter: TokenCounter, + metrics: MetricsCollector, projectRoot?: string, ) { this.cache = cache; - this._tokenCounter = _tokenCounter; - this._metrics = _metrics; + this.tokenCounter = tokenCounter; + this.metrics = metrics; this.projectRoot = projectRoot || process.cwd(); } @@ -593,11 +594,11 @@ export class SmartLint { */ export function getSmartLintTool( cache: CacheEngine, - _tokenCounter: _tokenCounter, - _metrics: MetricsCollector, + tokenCounter: TokenCounter, + metrics: MetricsCollector, projectRoot?: string, ): SmartLint { - return new SmartLint(cache, _tokenCounter, _metrics, projectRoot); + return new SmartLint(cache, tokenCounter, metrics, projectRoot); } /** @@ -608,12 +609,12 @@ export async function runSmartLint( ): Promise { const cacheDir = join(homedir(), ".hypercontext", "cache"); const cache = new CacheEngine(100, cacheDir); - const _tokenCounter = new _tokenCounter(); - const _metrics = new MetricsCollector(); + const tokenCounter = new TokenCounter(); + const metrics = new MetricsCollector(); const smartLint = new SmartLint( cache, - _tokenCounter, - _metrics, + tokenCounter, + metrics, options.projectRoot, ); try { diff --git a/src/tools/build-systems/smart-logs.ts b/src/tools/build-systems/smart-logs.ts index a49aac7..da06842 100644 --- a/src/tools/build-systems/smart-logs.ts +++ b/src/tools/build-systems/smart-logs.ts @@ -695,7 +695,7 @@ export class SmartLogs { const cacheData = { ...result, cachedAt: Date.now() }; this.cache.set( this.cacheNamespace + ":" + key, - JSON.stringify(cacheData)), + JSON.stringify(cacheData), 3600, 0, ); diff --git a/src/tools/build-systems/smart-network.ts b/src/tools/build-systems/smart-network.ts index 517cbe0..dfdc0e2 100644 --- a/src/tools/build-systems/smart-network.ts +++ b/src/tools/build-systems/smart-network.ts @@ -671,7 +671,7 @@ export class SmartNetwork { const cacheData = { ...result, cachedAt: Date.now() }; this.cache.set( this.cacheNamespace + ":" + key, - JSON.stringify(cacheData)), + JSON.stringify(cacheData), 3600, 0, ); diff --git a/src/tools/build-systems/smart-typecheck.ts b/src/tools/build-systems/smart-typecheck.ts index 092c615..a21b56d 100644 --- a/src/tools/build-systems/smart-typecheck.ts +++ b/src/tools/build-systems/smart-typecheck.ts @@ -11,6 +11,7 @@ import { spawn } from "child_process"; import { CacheEngine } from "../../core/cache-engine"; import { MetricsCollector } from "../../core/metrics"; +import { TokenCounter } from "../../core/token-counter"; import { createHash } from "crypto"; import { readFileSync, existsSync } from "fs"; import { join } from "path"; @@ -109,19 +110,19 @@ interface SmartTypeCheckOutput { export class SmartTypeCheck { private cache: CacheEngine; - private _tokenCounter: _tokenCounter; + private tokenCounter: TokenCounter; private _metrics: MetricsCollector; private cacheNamespace = "smart_typecheck"; private projectRoot: string; constructor( cache: CacheEngine, - _tokenCounter: _tokenCounter, + tokenCounter: TokenCounter, _metrics: MetricsCollector, projectRoot?: string, ) { this.cache = cache; - this._tokenCounter = _tokenCounter; + this.tokenCounter = tokenCounter; this._metrics = _metrics; this.projectRoot = projectRoot || process.cwd(); } @@ -636,10 +637,10 @@ export class SmartTypeCheck { */ export function getSmartTypeCheckTool( cache: CacheEngine, - _tokenCounter: _tokenCounter, + tokenCounter: TokenCounter, _metrics: MetricsCollector, ): SmartTypeCheck { - return new SmartTypeCheck(cache, _tokenCounter, _metrics); + return new SmartTypeCheck(cache, tokenCounter, _metrics); } /** @@ -652,12 +653,12 @@ export async function runSmartTypeCheck( const cache = new CacheEngine( join(homedir(), ".token-optimizer-cache", "cache.db"), ); - const _tokenCounter = new _tokenCounter(); - const _metrics = new MetricsCollector(); + const tokenCounter = new TokenCounter(); + const metrics = new MetricsCollector(); const smartTypeCheck = new SmartTypeCheck( cache, - _tokenCounter, - _metrics, + tokenCounter, + metrics, options.projectRoot, ); try { diff --git a/src/tools/code-analysis/smart-ast-grep.ts b/src/tools/code-analysis/smart-ast-grep.ts index 0ba1f16..c125276 100644 --- a/src/tools/code-analysis/smart-ast-grep.ts +++ b/src/tools/code-analysis/smart-ast-grep.ts @@ -602,7 +602,7 @@ export class SmartAstGrepTool { * Generate cache key for AST index */ private generateIndexKey(projectPath: string, language: string): string { - return CacheEngine.generateKey('ast-index', `${projectPath}:${language}:${SmartAstGrepTool.INDEX_VERSION}`); + return `ast-index:${projectPath}:${language}:${SmartAstGrepTool.INDEX_VERSION}`; } /** @@ -616,7 +616,7 @@ export class SmartAstGrepTool { filePattern: options.filePattern, contextLines: options.contextLines, }); - return CacheEngine.generateKey('ast-pattern', keyContent); + return `ast-pattern:${keyContent}`; } /** @@ -685,7 +685,7 @@ export class SmartAstGrepTool { lastUpdated: index.lastUpdated, }; - const data = JSON.stringify(serializable), 'utf-8'); + const data = JSON.stringify(serializable); const tokensSaved = this.estimateTokensSaved(index); this.cache.set(key, data, ttl, tokensSaved); @@ -699,7 +699,7 @@ export class SmartAstGrepTool { */ private cachePatternResult(key: string, result: SmartAstGrepResult, ttl: number): void { try { - const data = JSON.stringify(result), 'utf-8'); + const data = JSON.stringify(result); this.cache.set(key, data, ttl, result.metadata.tokensSaved); } catch (error) { console.warn('Failed to cache pattern result:', error); diff --git a/src/tools/code-analysis/smart-dependencies.ts b/src/tools/code-analysis/smart-dependencies.ts index 71bd9c6..7ca7448 100644 --- a/src/tools/code-analysis/smart-dependencies.ts +++ b/src/tools/code-analysis/smart-dependencies.ts @@ -765,7 +765,7 @@ export class SmartDependenciesTool { // Calculate tokens const resultData = { circular }; - const resultTokens = this.tokenCounter.count(JSON.stringify(resultData)); + const resultTokens = this.tokenCounter.count(JSON.stringify(resultData)).tokens; const originalTokens = this.estimateFullFileTokens(Array.from(graph.keys())); const tokensSaved = originalTokens - resultTokens; @@ -836,7 +836,7 @@ export class SmartDependenciesTool { // Calculate tokens const resultData = { unused }; - const resultTokens = this.tokenCounter.count(JSON.stringify(resultData)); + const resultTokens = this.tokenCounter.count(JSON.stringify(resultData)).tokens; const originalTokens = this.estimateFullFileTokens(Array.from(graph.keys())); const tokensSaved = originalTokens - resultTokens; @@ -959,7 +959,7 @@ export class SmartDependenciesTool { // Calculate tokens const resultData = { impact }; - const resultTokens = this.tokenCounter.count(JSON.stringify(resultData)); + const resultTokens = this.tokenCounter.count(JSON.stringify(resultData)).tokens; const originalTokens = this.estimateFullFileTokens([opts.targetFile, ...directDependents, ...indirectDependents]); const tokensSaved = originalTokens - resultTokens; @@ -1009,7 +1009,7 @@ export class SmartDependenciesTool { ? this.compactGraphRepresentation(filteredGraph) : Array.from(filteredGraph.entries()); - const resultTokens = this.tokenCounter.count(JSON.stringify(graphData)); + const resultTokens = this.tokenCounter.count(JSON.stringify(graphData)).tokens; const originalTokens = this.estimateFullFileTokens(Array.from(graph.keys())); const tokensSaved = originalTokens - resultTokens; @@ -1160,8 +1160,7 @@ export class SmartDependenciesTool { cacheKey, serialized as any, ttlSeconds, - tokensSaved, - '' // No specific file hash for full graph + tokensSaved ); } diff --git a/src/tools/code-analysis/smart-exports.ts b/src/tools/code-analysis/smart-exports.ts index 8664921..177bf4f 100644 --- a/src/tools/code-analysis/smart-exports.ts +++ b/src/tools/code-analysis/smart-exports.ts @@ -249,8 +249,8 @@ export class SmartExportsTool { // Calculate token metrics const fullOutput = JSON.stringify(result, null, 2); const compactOutput = this.compactResult(result); - const originalTokens = this.tokenCounter.count(fullOutput); - const compactedTokens = this.tokenCounter.count(compactOutput); + const originalTokens = this.tokenCounter.count(fullOutput).tokens; + const compactedTokens = this.tokenCounter.count(compactOutput).tokens; const _reductionPercentage = ((originalTokens - compactedTokens) / originalTokens) * 100; // Cache result @@ -768,7 +768,7 @@ export class SmartExportsTool { originalTokens, compactedTokens }; - const buffer = JSON.stringify(toCache), 'utf-8'); + const buffer = JSON.stringify(toCache); const tokensSaved = originalTokens && compactedTokens ? originalTokens - compactedTokens : 0; this.cache.set(cacheKey, buffer, 300, tokensSaved); } @@ -823,7 +823,7 @@ export async function runSmartExports( options: SmartExportsOptions ): Promise { const cache = new CacheEngine(100, join(homedir(), '.hypercontext', 'cache')); - const tokenCounter = new TokenCounter('gpt-4'); + const tokenCounter = new TokenCounter(); const metrics = new MetricsCollector(); const tool = getSmartExportsTool(cache, tokenCounter, metrics, options.projectRoot); return tool.run(options); diff --git a/src/tools/code-analysis/smart-imports.ts b/src/tools/code-analysis/smart-imports.ts index 7165c51..4bed34f 100644 --- a/src/tools/code-analysis/smart-imports.ts +++ b/src/tools/code-analysis/smart-imports.ts @@ -267,8 +267,8 @@ export class SmartImportsTool { // Calculate token metrics const fullOutput = JSON.stringify(result, null, 2); const compactOutput = this.compactResult(result); - const originalTokens = this.tokenCounter.count(fullOutput); - const compactedTokens = this.tokenCounter.count(compactOutput); + const originalTokens = this.tokenCounter.count(fullOutput).tokens; + const compactedTokens = this.tokenCounter.count(compactOutput).tokens; const _reductionPercentage = ((originalTokens - compactedTokens) / originalTokens) * 100; // Cache result @@ -863,7 +863,7 @@ export class SmartImportsTool { originalTokens, compactedTokens }; - const buffer = JSON.stringify(toCache), 'utf-8'); + const buffer = JSON.stringify(toCache); const tokensSaved = originalTokens && compactedTokens ? originalTokens - compactedTokens : 0; this.cache.set(cacheKey, buffer, 300, tokensSaved); } @@ -921,7 +921,7 @@ export async function runSmartImports( options: SmartImportsOptions ): Promise { const cache = new CacheEngine(100, join(homedir(), '.hypercontext', 'cache')); - const tokenCounter = new TokenCounter('gpt-4'); + const tokenCounter = new TokenCounter(); const metrics = new MetricsCollector(); const tool = getSmartImportsTool(cache, tokenCounter, metrics, options.projectRoot); return tool.run(options); diff --git a/src/tools/code-analysis/smart-refactor.ts b/src/tools/code-analysis/smart-refactor.ts index 71a4e7b..78472b8 100644 --- a/src/tools/code-analysis/smart-refactor.ts +++ b/src/tools/code-analysis/smart-refactor.ts @@ -627,7 +627,7 @@ export class SmartRefactorTool { private cacheResult(key: string, output: SmartRefactorResult): void { const toCache = { ...output, cachedAt: Date.now() }; - const buffer = JSON.stringify(toCache), 'utf-8'); + const buffer = JSON.stringify(toCache); const tokensSaved = output.metrics.originalTokens - output.metrics.compactedTokens; this.cache.set(key, buffer, 300, tokensSaved); } @@ -646,7 +646,7 @@ export function getSmartRefactorTool( // Standalone function for CLI usage export async function runSmartRefactor(options: SmartRefactorOptions): Promise { const cache = new CacheEngine(100, join(homedir(), '.hypercontext', 'cache')); - const tokenCounter = new TokenCounter('gpt-4'); + const tokenCounter = new TokenCounter(); const metrics = new MetricsCollector(); const tool = getSmartRefactorTool(cache, tokenCounter, metrics, options.projectRoot); return tool.run(options); diff --git a/src/tools/code-analysis/smart-typescript.ts b/src/tools/code-analysis/smart-typescript.ts index 7fbc1c1..6e48537 100644 --- a/src/tools/code-analysis/smart-typescript.ts +++ b/src/tools/code-analysis/smart-typescript.ts @@ -841,7 +841,7 @@ export class SmartTypeScript { cachedAt: Date.now() }; - const buffer = JSON.stringify(toCache), 'utf-8'); + const buffer = JSON.stringify(toCache); const tokensSaved = output.metrics.originalTokens - output.metrics.compactedTokens; this.cache.set(key, buffer, 300, tokensSaved); // 5 minute TTL @@ -913,7 +913,7 @@ export function getSmartTypeScriptTool( */ export async function runSmartTypescript(options: SmartTypeScriptOptions = {}): Promise { const cache = new CacheEngine(100, join(homedir(), '.hypercontext', 'cache')); - const tokenCounter = new TokenCounter('gpt-4'); + const tokenCounter = new TokenCounter(); const metrics = new MetricsCollector(); const smartTS = new SmartTypeScript(cache, tokenCounter, metrics, options.projectRoot); try { diff --git a/src/tools/configuration/smart-config-read.ts b/src/tools/configuration/smart-config-read.ts index 3cb1c6a..d42b844 100644 --- a/src/tools/configuration/smart-config-read.ts +++ b/src/tools/configuration/smart-config-read.ts @@ -190,7 +190,7 @@ export class SmartConfigReadTool { // Calculate original tokens const originalTokens = this.tokenCounter.count( JSON.stringify(parsedConfig, null, 2), - ); + ).tokens; let finalOutput: Record = parsedConfig; let isDiff = false; @@ -207,7 +207,7 @@ export class SmartConfigReadTool { // Check schema cache if (cachedSchema) { const cachedSchemaObj = JSON.parse( - decompress(cachedSchema.toString("utf-8"), "gzip"), + decompress(cachedSchema.toString(), "gzip"), ) as ConfigSchema; // Compare schemas to detect structural changes @@ -243,7 +243,7 @@ export class SmartConfigReadTool { try { const decompressed = decompress(cachedData, "gzip"); const cachedConfig = JSON.parse( - decompressed.toString("utf-8"), + decompressed.toString(), ) as Record; // Calculate diff @@ -257,7 +257,7 @@ export class SmartConfigReadTool { const diffTokens = this.tokenCounter.count( JSON.stringify(finalOutput, null, 2), - ); + ).tokens; tokensSaved = Math.max(0, originalTokens - diffTokens); } else { // No changes - return minimal response @@ -269,7 +269,7 @@ export class SmartConfigReadTool { tokensSaved = Math.max( 0, originalTokens - - this.tokenCounter.count(JSON.stringify(finalOutput)), + this.tokenCounter.count(JSON.stringify(finalOutput)).tokens, ); } } catch (error) { @@ -290,7 +290,7 @@ export class SmartConfigReadTool { tokensSaved = originalTokens - - this.tokenCounter.count(JSON.stringify(finalOutput, null, 2)); + this.tokenCounter.count(JSON.stringify(finalOutput, null, 2)).tokens; } // Cache the parsed config and schema @@ -298,7 +298,7 @@ export class SmartConfigReadTool { const configCompressed = compress(JSON.stringify(parsedConfig), "gzip"); this.cache.set( configCacheKey, - configCompressed.toString("utf-8").compressed, + configCompressed.toString(), tokensSaved, ttl, ); @@ -310,7 +310,7 @@ export class SmartConfigReadTool { ); this.cache.set( schemaCacheKey, - schemaCompressed.toString("utf-8").compressed, + schemaCompressed.toString(), 0, ttl, ); @@ -320,7 +320,7 @@ export class SmartConfigReadTool { // Calculate final metrics const finalTokens = this.tokenCounter.count( JSON.stringify(finalOutput, null, 2), - ); + ).tokens; const compressionRatio = finalTokens / originalTokens; // Record metrics diff --git a/src/tools/configuration/smart-package-json.ts b/src/tools/configuration/smart-package-json.ts index d48c081..f8ce3a0 100644 --- a/src/tools/configuration/smart-package-json.ts +++ b/src/tools/configuration/smart-package-json.ts @@ -837,10 +837,9 @@ export class SmartPackageJson { this.cache.set( this.cacheNamespace + ':' + key, - JSON.stringify(cacheData)), + JSON.stringify(cacheData), 86400, // 24 hour TTL - tokensSaved, - fileHash + tokensSaved ); } @@ -849,7 +848,7 @@ export class SmartPackageJson { */ private estimateTokensSaved(result: ParsedPackageJson): number { const fullOutput = JSON.stringify(result); - const originalTokens = this.tokenCounter.count(fullOutput); + const originalTokens = this.tokenCounter.count(fullOutput).tokens; const compactTokens = Math.ceil(originalTokens * 0.05); // 95% reduction return originalTokens - compactTokens; } diff --git a/src/tools/configuration/smart-tsconfig.ts b/src/tools/configuration/smart-tsconfig.ts index 4051b84..8155bdf 100644 --- a/src/tools/configuration/smart-tsconfig.ts +++ b/src/tools/configuration/smart-tsconfig.ts @@ -16,6 +16,7 @@ import { homedir } from "os"; import { CacheEngine } from "../../core/cache-engine"; import { globalMetricsCollector } from "../../core/metrics"; import { TokenCounter } from "../../core/token-counter"; +import { hashContent, generateCacheKey } from "../shared/hash-utils"; // ==================== Type Definitions ==================== @@ -127,8 +128,8 @@ class SmartTsConfig { try { // Generate cache key based on file content and path const configContent = await readFile(configPath, "utf-8"); - const fileHash = CacheEngine.generateFileHash(configPath, configContent); - const cacheKey = `cache-${crypto.createHash("md5").update("tsconfig", configPath).digest("hex")}`; + const fileHash = hashContent(configContent); + const cacheKey = generateCacheKey("tsconfig", { path: configPath, hash: fileHash }); // Check cache first const cached = this.cache.get(cacheKey); @@ -166,8 +167,8 @@ class SmartTsConfig { return output; } - // Cache invalid, invalidate it - this.cache.invalidateByFileHash(fileHash); + // Cache invalid, delete it + this.cache.delete(cacheKey); } // Resolve the config with extends chain @@ -196,7 +197,7 @@ class SmartTsConfig { const maxAge = options.maxCacheAge ?? 7 * 24 * 60 * 60; // 7 days default this.cache.set( cacheKey, - Buffer.toString("utf-8").from(JSON.stringify(toCache)), + Buffer.from(JSON.stringify(toCache)).toString("utf-8"), 0, maxAge, ); @@ -541,10 +542,10 @@ class SmartTsConfig { // Calculate token metrics const originalTokens = this.tokenCounter.count( JSON.stringify(originalOutput), - ); + ).tokens; const compactTokens = this.tokenCounter.count( JSON.stringify(compactOutput), - ); + ).tokens; const savedTokens = Math.max(0, originalTokens - compactTokens); const savingsPercent = originalTokens > 0 ? (savedTokens / originalTokens) * 100 : 0; diff --git a/src/tools/dashboard-monitoring/alert-manager.ts b/src/tools/dashboard-monitoring/alert-manager.ts index 21be7be..fb75aae 100644 --- a/src/tools/dashboard-monitoring/alert-manager.ts +++ b/src/tools/dashboard-monitoring/alert-manager.ts @@ -361,7 +361,7 @@ export class AlertManager { // Cache alert metadata (92% reduction, 6-hour TTL) const cacheKey = `cache-${createHash("md5").update("alert-manager:alert", alertId).digest("hex")}`; const alertMetadata = this.compressAlertMetadata(alert); - const cachedData = JSON.stringify(alertMetadata)); + const cachedData = JSON.stringify(alertMetadata); const tokensUsed = this.tokenCounter.count(JSON.stringify(alert)).tokens; const tokensSaved = @@ -372,12 +372,12 @@ export class AlertManager { cacheKey, cachedData, tokensUsed, - this.tokenCounter.count(JSON.stringify(alertMetadata.toString("utf-8"))) + this.tokenCounter.count(JSON.stringify(alertMetadata.toString())) .tokens, ); // Persist to storage - await this.persistAlerts(options.cacheTTL || 21600); + await this.persistAlerts(); return { success: true, @@ -429,7 +429,7 @@ export class AlertManager { // Update cache const cacheKey = `cache-${createHash("md5").update("alert-manager:alert", alertId).digest("hex")}`; const alertMetadata = this.compressAlertMetadata(alert); - const cachedData = JSON.stringify(alertMetadata)); + const cachedData = JSON.stringify(alertMetadata); const tokensUsed = this.tokenCounter.count(JSON.stringify(alert)).tokens; const tokensSaved = @@ -440,12 +440,12 @@ export class AlertManager { cacheKey, cachedData, tokensUsed, - this.tokenCounter.count(JSON.stringify(alertMetadata.toString("utf-8"))) + this.tokenCounter.count(JSON.stringify(alertMetadata.toString())) .tokens, ); // Persist to storage - await this.persistAlerts(options.cacheTTL || 21600); + await this.persistAlerts(); return { success: true, @@ -530,7 +530,7 @@ export class AlertManager { const cachedAlerts = JSON.parse(cached); const tokensSaved = this.tokenCounter.count( - JSON.stringify(Array.from(this.alerts.values().tokens)), + JSON.stringify(Array.from(this.alerts.values())) ).tokens - this.tokenCounter.count(JSON.stringify(cachedAlerts)).tokens; @@ -567,10 +567,10 @@ export class AlertManager { const tokensSaved = fullTokens - compressedTokens; // Cache compressed list (92% reduction, 6-hour TTL) - const cachedData = JSON.stringify(compressedAlerts)); + const cachedData = JSON.stringify(compressedAlerts); await this.cache.set( cacheKey, - cachedData.toString("utf-8"), + cachedData.toString(), tokensSaved, options.cacheTTL || 21600, ); @@ -730,10 +730,10 @@ export class AlertManager { const tokensSaved = fullTokens - aggregatedTokens; // Cache aggregated history (88% reduction, 5-minute TTL) - const cachedData = JSON.stringify(aggregatedHistory)); + const cachedData = JSON.stringify(aggregatedHistory); await this.cache.set( cacheKey, - cachedData.toString("utf-8"), + cachedData.toString(), tokensSaved, options.cacheTTL || 300, ); @@ -867,8 +867,8 @@ export class AlertManager { const tokensSaved = fullTokens - compressedTokens; // Cache channel configuration (95% reduction, 24-hour TTL) - const cachedData = JSON.stringify(compressedChannels)); - await this.cache.set(cacheKey, cachedData.toString("utf-8"), tokensSaved); + const cachedData = JSON.stringify(compressedChannels); + await this.cache.set(cacheKey, cachedData, cachedData.length, cachedData.length); // Persist channels await this.persistChannels(); @@ -938,8 +938,8 @@ export class AlertManager { // Cache silence state (90% reduction, based on duration) const cacheKey = `cache-${createHash("md5").update("alert-manager:silence", silenceId).digest("hex")}`; - const cachedData = JSON.stringify(compressedSilence)); - await this.cache.set(cacheKey, cachedData.toString("utf-8"), tokensSaved); + const cachedData = JSON.stringify(compressedSilence); + await this.cache.set(cacheKey, cachedData, cachedData.length, cachedData.length); // Persist changes await this.persistSilences(); @@ -1070,10 +1070,9 @@ export class AlertManager { // Estimate that aggregation saves 88% compared to full event list const estimatedFullSize = aggregatedHistory.totalEvents * 100; // rough estimate const actualSize = JSON.stringify(aggregatedHistory).length; - return Math.max( - 0, - this.tokenCounter.estimateFromBytes(estimatedFullSize - actualSize), - ); + const bytesSaved = estimatedFullSize - actualSize; + // Convert bytes to estimated tokens (rough estimate: ~4 characters per token) + return Math.max(0, Math.ceil(bytesSaved / 4)); } private async sendNotifications( @@ -1131,14 +1130,14 @@ export class AlertManager { // In production, persist to database // For now, use cache as simple persistence const cacheKey = `cache-${createHash("md5").update("alert-manager:persistence", "alerts").digest("hex")}`; - const data = JSON.stringify(Array.from(this.alerts.entries()))); - await this.cache.set(cacheKey, data.toString("utf-8"), 0, 86400 * 365); // 1 year TTL + const data = JSON.stringify(Array.from(this.alerts.entries())); + await this.cache.set(cacheKey, data.toString(), 0, 86400 * 365); // 1 year TTL } private async persistEvents(): Promise { const cacheKey = `cache-${createHash("md5").update("alert-manager:persistence", "events").digest("hex")}`; - const data = JSON.stringify(this.alertEvents)); - await this.cache.set(cacheKey, data.toString("utf-8"), 0, 86400 * 30); // 30 days TTL + const data = JSON.stringify(this.alertEvents); + await this.cache.set(cacheKey, data.toString(), 0, 86400 * 30); // 30 days TTL } private async persistChannels(): Promise { @@ -1146,7 +1145,7 @@ export class AlertManager { const data = Buffer.from( JSON.stringify(Array.from(this.notificationChannels.entries())), ); - await this.cache.set(cacheKey, data.toString("utf-8"), 0, 86400 * 365); // 1 year TTL + await this.cache.set(cacheKey, data.toString(), 0, 86400 * 365); // 1 year TTL } private async persistSilences(): Promise { @@ -1154,7 +1153,7 @@ export class AlertManager { const data = Buffer.from( JSON.stringify(Array.from(this.silenceRules.entries())), ); - await this.cache.set(cacheKey, data.toString("utf-8"), 0, 86400 * 30); // 30 days TTL + await this.cache.set(cacheKey, data.toString(), 0, 86400 * 30); // 30 days TTL } private loadPersistedData(): void { diff --git a/src/tools/dashboard-monitoring/custom-widget.ts b/src/tools/dashboard-monitoring/custom-widget.ts index 4cae700..3fbe980 100644 --- a/src/tools/dashboard-monitoring/custom-widget.ts +++ b/src/tools/dashboard-monitoring/custom-widget.ts @@ -227,7 +227,7 @@ export class CustomWidget { if (cached) { const decompressed = decompress(cached, "gzip"); const cachedResult = JSON.parse( - decompressed.toString("utf-8"), + decompressed.toString(), ) as CustomWidgetResult; const tokensSaved = this.tokenCounter.count( @@ -300,7 +300,7 @@ export class CustomWidget { const ttl = this.getCacheTTL(options); this.cache.set( cacheKey, - compressed.toString("utf-8").compressed, + compressed.toString(), tokensUsed, ttl, ); diff --git a/src/tools/dashboard-monitoring/data-visualizer.ts b/src/tools/dashboard-monitoring/data-visualizer.ts index 938109a..ecd733c 100644 --- a/src/tools/dashboard-monitoring/data-visualizer.ts +++ b/src/tools/dashboard-monitoring/data-visualizer.ts @@ -329,7 +329,7 @@ export class DataVisualizer { // Cache the result const tokensUsed = this.tokenCounter.count(JSON.stringify(chart)).tokens; - const cacheData = JSON.stringify(chart)); + const cacheData = JSON.stringify(chart); this.cache.set( cacheKey, cacheData, @@ -462,7 +462,7 @@ export class DataVisualizer { exported = await this.exportToHTML(chart, options); break; case "json": - exported = JSON.stringify(chart, null, 2)); + exported = JSON.stringify(chart, null, 2); break; default: throw new Error(`Unsupported export format: ${format}`); diff --git a/src/tools/dashboard-monitoring/health-monitor.ts b/src/tools/dashboard-monitoring/health-monitor.ts index 9b246fd..0fab40b 100644 --- a/src/tools/dashboard-monitoring/health-monitor.ts +++ b/src/tools/dashboard-monitoring/health-monitor.ts @@ -1089,7 +1089,7 @@ export class HealthMonitor { const ttl = options.cacheTTL || 30; // 30 seconds this.cache.set( cacheKey, - Buffer.toString("utf-8").from(JSON.stringify(status)), + Buffer.from(JSON.stringify(status)).toString("utf-8"), tokensUsed, ttl, ); @@ -1157,7 +1157,7 @@ export class HealthMonitor { const ttl = options.cacheTTL || 60; // 1 minute this.cache.set( cacheKey, - Buffer.toString("utf-8").from(JSON.stringify(aggregatedHistory)), + Buffer.from(JSON.stringify(aggregatedHistory)).toString("utf-8"), tokensUsed, ttl, ); @@ -1200,7 +1200,7 @@ export class HealthMonitor { const ttl = options.cacheTTL || 600; // 10 minutes this.cache.set( cacheKey, - Buffer.toString("utf-8").from(JSON.stringify(graph)), + Buffer.from(JSON.stringify(graph)).toString("utf-8"), tokensUsed, ttl, ); @@ -1263,7 +1263,7 @@ export class HealthMonitor { const ttl = options.cacheTTL || 600; // 10 minutes this.cache.set( cacheKey, - Buffer.toString("utf-8").from(JSON.stringify(impact)), + Buffer.from(JSON.stringify(impact)).toString("utf-8"), tokensUsed, ttl, ); diff --git a/src/tools/file-operations/smart-edit.ts b/src/tools/file-operations/smart-edit.ts index 3d08306..cb63ed6 100644 --- a/src/tools/file-operations/smart-edit.ts +++ b/src/tools/file-operations/smart-edit.ts @@ -118,7 +118,7 @@ export class SmartEditTool { // Read original content const originalContent = readFileSync(filePath, opts.encoding); const originalLines = originalContent.split('\n'); - const originalTokens = this.tokenCounter.count(originalContent); + const originalTokens = this.tokenCounter.count(originalContent).tokens; // Normalize operations to array const ops = Array.isArray(operations) ? operations : [operations]; @@ -168,13 +168,13 @@ export class SmartEditTool { // Calculate diff const diff = this.calculateDiff(originalContent, editedContent, filePath, opts.contextLines); const diffTokens = opts.returnDiff - ? this.tokenCounter.count(diff.unifiedDiff) - : this.tokenCounter.count(editedContent); + ? this.tokenCounter.count(diff.unifiedDiff).tokens + : this.tokenCounter.count(editedContent).tokens; // If dry run, return preview without applying if (opts.dryRun) { const duration = Date.now() - startTime; - const tokensSaved = originalTokens + this.tokenCounter.count(editedContent) - diffTokens; + const tokensSaved = originalTokens + this.tokenCounter.count(editedContent).tokens - diffTokens; this.metrics.record({ operation: 'smart_edit', @@ -223,7 +223,7 @@ export class SmartEditTool { const fileHash = hashContent(editedContent); const cacheKey = generateCacheKey('file-edit', { path: filePath }); const tokensSaved = originalTokens - diffTokens; - this.cache.set(cacheKey, editedContent as any, opts.ttl, tokensSaved, fileHash); + this.cache.set(cacheKey, editedContent as any, opts.ttl, tokensSaved); } // Record metrics @@ -469,7 +469,7 @@ export async function runSmartEdit( options: SmartEditOptions = {} ): Promise { const cache = new CacheEngine(100, join(homedir(), '.hypercontext', 'cache')); - const tokenCounter = new TokenCounter('gpt-4'); + const tokenCounter = new TokenCounter(); const metrics = new MetricsCollector(); const tool = getSmartEditTool(cache, tokenCounter, metrics); diff --git a/src/tools/file-operations/smart-glob.ts b/src/tools/file-operations/smart-glob.ts index 2e19bc2..ee1902a 100644 --- a/src/tools/file-operations/smart-glob.ts +++ b/src/tools/file-operations/smart-glob.ts @@ -288,8 +288,7 @@ export class SmartGlobTool { cacheKey, JSON.stringify(result) as any, opts.ttl, - tokensSaved, - hashContent(pattern) + tokensSaved ); } @@ -427,7 +426,7 @@ export async function runSmartGlob( options: SmartGlobOptions = {} ): Promise { const cache = new CacheEngine(100, join(homedir(), '.hypercontext', 'cache')); - const tokenCounter = new TokenCounter('gpt-4'); + const tokenCounter = new TokenCounter(); const metrics = new MetricsCollector(); const tool = getSmartGlobTool(cache, tokenCounter, metrics); diff --git a/src/tools/file-operations/smart-grep.ts b/src/tools/file-operations/smart-grep.ts index c5947fc..72d639e 100644 --- a/src/tools/file-operations/smart-grep.ts +++ b/src/tools/file-operations/smart-grep.ts @@ -326,8 +326,7 @@ export class SmartGrepTool { cacheKey, JSON.stringify(result) as any, opts.ttl, - tokensSaved, - hashContent(pattern) + tokensSaved ); } @@ -478,7 +477,7 @@ export async function runSmartGrep( options: SmartGrepOptions = {} ): Promise { const cache = new CacheEngine(100, join(homedir(), '.hypercontext', 'cache')); - const tokenCounter = new TokenCounter('gpt-4'); + const tokenCounter = new TokenCounter(); const metrics = new MetricsCollector(); const tool = getSmartGrepTool(cache, tokenCounter, metrics); diff --git a/src/tools/file-operations/smart-read.ts b/src/tools/file-operations/smart-read.ts index 14546dc..e308974 100644 --- a/src/tools/file-operations/smart-read.ts +++ b/src/tools/file-operations/smart-read.ts @@ -149,10 +149,10 @@ export class SmartReadTool { const cachedContent = decompressed; // Check if content has meaningful changes - if (hasMeaningfulChanges(cachedContent.toString("utf-8"), rawContent)) { + if (hasMeaningfulChanges(cachedContent.toString(), rawContent)) { // Generate diff const diff = generateDiff( - cachedContent.toString("utf-8"), + cachedContent.toString(), rawContent, { contextLines: 3, @@ -187,7 +187,7 @@ export class SmartReadTool { isDiff = true; tokensSaved = Math.max( 0, - originalTokens - this.tokenCounter.count(finalContent), + originalTokens - this.tokenCounter.count(finalContent).tokens, ); } } catch (error) { @@ -242,7 +242,7 @@ export class SmartReadTool { const compressed = compress(rawContent, "gzip"); this.cache.set( cacheKey, - compressed.toString("utf-8").compressed, + compressed.toString(), tokensSaved, ttl, ); diff --git a/src/tools/file-operations/smart-write.ts b/src/tools/file-operations/smart-write.ts index 54f186f..d64b450 100644 --- a/src/tools/file-operations/smart-write.ts +++ b/src/tools/file-operations/smart-write.ts @@ -126,7 +126,7 @@ export class SmartWriteTool { // Step 1: Verify before write (skip if identical) if (opts.verifyBeforeWrite && fileExists && originalContent === content) { const duration = Date.now() - startTime; - const originalTokens = this.tokenCounter.count(originalContent); + const originalTokens = this.tokenCounter.count(originalContent).tokens; // Smart threshold: scale overhead based on content size // For very small files (1-5 tokens), use 0 overhead to ensure we show savings @@ -213,9 +213,9 @@ export class SmartWriteTool { // Step 6: Calculate changes and token savings const originalTokens = originalContent - ? this.tokenCounter.count(originalContent) + ? this.tokenCounter.count(originalContent).tokens : 0; - const newTokens = this.tokenCounter.count(finalContent); + const newTokens = this.tokenCounter.count(finalContent).tokens; // Only generate diff if there's original content AND options require it const shouldGenerateDiff = (opts.trackChanges || opts.returnDiff) && originalContent; @@ -225,7 +225,7 @@ export class SmartWriteTool { // Token reduction: return only diff instead of full content (only if we have a meaningful diff) const diffTokens = (diff && opts.returnDiff && originalContent) - ? this.tokenCounter.count(diff.unifiedDiff) + ? this.tokenCounter.count(diff.unifiedDiff).tokens : newTokens; // Only claim token savings if diff is actually smaller than full content @@ -236,7 +236,7 @@ export class SmartWriteTool { if (opts.updateCache) { const fileHash = hashContent(finalContent); const cacheKey = generateCacheKey('file-write', { path: filePath }); - this.cache.set(cacheKey, finalContent as any, opts.ttl, tokensSaved, fileHash); + this.cache.set(cacheKey, finalContent as any, opts.ttl, tokensSaved); } // Step 8: Record metrics @@ -525,7 +525,7 @@ export async function runSmartWrite( options: SmartWriteOptions = {} ): Promise { const cache = new CacheEngine(100, join(homedir(), '.hypercontext', 'cache')); - const tokenCounter = new TokenCounter('gpt-4'); + const tokenCounter = new TokenCounter(); const metrics = new MetricsCollector(); const tool = getSmartWriteTool(cache, tokenCounter, metrics); diff --git a/src/tools/intelligence/sentiment-analysis.ts b/src/tools/intelligence/sentiment-analysis.ts index 914fcd3..63bb3b6 100644 --- a/src/tools/intelligence/sentiment-analysis.ts +++ b/src/tools/intelligence/sentiment-analysis.ts @@ -513,13 +513,12 @@ export class SentimentAnalysisTool { const ttl = this.getCacheTTL(options); if (options.useCache !== false) { + const resultStr = JSON.stringify(result); this.cache.set( cacheKey, - Buffer.toString("utf-8").from( - JSON.stringify(result), - ttl /* originalSize */, - "utf-8", - ) /* compressedSize */, + resultStr, + tokensUsed, + tokensUsed ); } diff --git a/src/tools/output-formatting/smart-format.ts b/src/tools/output-formatting/smart-format.ts index f0a4a50..0a11fcc 100644 --- a/src/tools/output-formatting/smart-format.ts +++ b/src/tools/output-formatting/smart-format.ts @@ -1,5 +1,5 @@ /** * SmartFormat - Intelligent Format Conversion Tool * * Track 2C - Tool #9: Format conversion with 86%+ token reduction * * Capabilities: * - JSON ↔ YAML ↔ TOML ↔ XML ↔ CSV ↔ INI conversions * - Schema validation during conversion * - Preserve comments where possible * - Pretty printing with custom styles * - Batch conversion support * * Token Reduction Strategy: * - Cache conversion schemas (93% reduction) * - Incremental format diffs (86% reduction) * - Compressed results (88% reduction) */ import { - _createReadStream, + createReadStream, } from "fs"; import { parse as parseYAML, stringify as stringifyYAML } from "yaml"; import { parse as parseTOML, stringify as stringifyTOML } from "@iarna/toml"; diff --git a/src/tools/output-formatting/smart-pretty.ts b/src/tools/output-formatting/smart-pretty.ts index 63743a5..d28a0eb 100644 --- a/src/tools/output-formatting/smart-pretty.ts +++ b/src/tools/output-formatting/smart-pretty.ts @@ -516,7 +516,7 @@ export class SmartPretty { if (cached) { const decompressed = decompress(cached, "gzip"); const cachedResult = JSON.parse( - decompressed.toString("utf-8"), + decompressed.toString(), ) as HighlightResult; const tokensUsed = this.tokenCounter.count(cachedResult.code).tokens; @@ -605,7 +605,7 @@ export class SmartPretty { const resultTokens = this.tokenCounter.count(highlightedCode).tokens; this.cache.set( cacheKey, - compressed.toString("utf-8").compressed, + compressed.toString(), resultTokens, options.ttl || 3600, ); @@ -798,7 +798,7 @@ export class SmartPretty { if (cached) { const decompressed = decompress(cached, "gzip"); const cachedResult = JSON.parse( - decompressed.toString("utf-8"), + decompressed.toString(), ) as FormatResult; const tokensUsed = this.tokenCounter.count(cachedResult.code).tokens; @@ -864,7 +864,7 @@ export class SmartPretty { const resultTokens = this.tokenCounter.count(formattedCode).tokens; this.cache.set( cacheKey, - compressed.toString("utf-8").compressed, + compressed.toString(), resultTokens, options.ttl || 3600, ); diff --git a/src/tools/output-formatting/smart-report.ts b/src/tools/output-formatting/smart-report.ts index 9ac9f73..af517f3 100644 --- a/src/tools/output-formatting/smart-report.ts +++ b/src/tools/output-formatting/smart-report.ts @@ -1,5 +1,5 @@ /** * SmartReport - Intelligent Report Generation Tool * * Track 2C - Tool #12: Report generation with 84%+ token reduction * * Capabilities: * - Markdown report generation with templates * - HTML report generation with custom styling * - PDF generation via headless browser simulation * - Chart and graph embedding (ASCII/Unicode for text, data URLs for HTML) * - Custom template caching and reuse * - Multi-section reports with TOC * * Token Reduction Strategy: * - Cache report templates (92% reduction) * - Incremental data updates (84% reduction) * - Compressed render output (86% reduction) */ import { - _readFileSync, + readFileSync, writeFileSync, existsSync, mkdirSync, diff --git a/src/tools/system-operations/smart-archive.ts b/src/tools/system-operations/smart-archive.ts index d505a0d..d368688 100644 --- a/src/tools/system-operations/smart-archive.ts +++ b/src/tools/system-operations/smart-archive.ts @@ -7,6 +7,6 @@ import * as path from "path"; import { promisify } from "util"; import { pipeline } from "stream"; const _pipelineAsync = promisify(pipeline); -const _stat = promisify(fs._stat); -const _readdir = promisify(fs._readdir); -const _mkdir = promisify(fs._mkdir); // ===========================// Types & Interfaces// ===========================export type ArchiveFormat = 'tar' | 'tar.gz' | 'tar.bz2' | 'zip';export type CompressionLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;export type ArchiveOperation = 'create' | 'extract' | 'list' | 'verify' | 'incremental-backup';export interface SmartArchiveOptions { operation: ArchiveOperation; format?: ArchiveFormat; source?: string | string[]; destination?: string; compressionLevel?: CompressionLevel; includePatterns?: string[]; excludePatterns?: string[]; preservePermissions?: boolean; followSymlinks?: boolean; baseDir?: string; useCache?: boolean; ttl?: number; verifyIntegrity?: boolean; incrementalBase?: string;}export interface ArchiveEntry { name: string; size: number; type: 'file' | 'directory' | 'symlink'; mode?: number; mtime?: Date; checksum?: string; compressed?: boolean;}export interface ArchiveMetadata { format: ArchiveFormat; path: string; totalSize: number; compressedSize?: number; compressionRatio?: number; entryCount: number; entries: ArchiveEntry[]; created: Date; checksum: string;}export interface IncrementalBackupInfo { baseArchive: string; newFiles: string[]; modifiedFiles: string[]; deletedFiles: string[]; totalChanges: number; timestamp: Date;}export interface ArchiveVerificationResult { valid: boolean; checksumMatch: boolean; entriesValid: number; entriesCorrupted: number; errors: string[]; warnings: string[];}export interface SmartArchiveResult { success: boolean; operation: ArchiveOperation; data: { metadata?: ArchiveMetadata; entries?: ArchiveEntry[]; extractedPath?: string; verification?: ArchiveVerificationResult; incrementalInfo?: IncrementalBackupInfo; bytesProcessed?: number; error?: string; }; metadata: { tokensUsed: number; tokensSaved: number; cacheHit: boolean; executionTime: number; };}// ===========================// SmartArchive Class// ===========================export class SmartArchive { constructor( private cache: CacheEngine, private tokenCounter: TokenCounter, private metricsCollector: MetricsCollector ) {} /** * Main entry point for archive operations */ async run(options: SmartArchiveOptions): Promise { const startTime = Date.now(); const operation = options.operation; let result: SmartArchiveResult; try { switch (operation) { case 'create': result = await this.createArchive(options); break; case 'extract': result = await this.extractArchive(options); break; case 'list': result = await this.listArchive(options); break; case 'verify': result = await this.verifyArchive(options); break; case 'incremental-backup': result = await this.incrementalBackup(options); break; default: throw new Error(`Unknown operation: ${operation}`); } // Record metrics this.metricsCollector.record({ operation: `smart-archive:${operation}`, duration: Date.now() - startTime, success: result.success, cacheHit: result.metadata.cacheHit, metadata: { format: options.format, source: options.source } }); return result; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); const errorResult: SmartArchiveResult = { success: false, operation, data: { error: errorMessage }, metadata: { tokensUsed: this.tokenCounter.count(errorMessage).tokens, tokensSaved: 0, cacheHit: false, executionTime: Date.now() - startTime } }; this.metricsCollector.record({ operation: `smart-archive:${operation}`, duration: Date.now() - startTime, success: false, cacheHit: false, metadata: { error: errorMessage, format: options.format } }); return errorResult; } } /** * Create an archive with smart compression selection */ private async createArchive(options: SmartArchiveOptions): Promise { if (!options.source) { throw new Error('Source is required for create operation'); } if (!options.destination) { throw new Error('Destination is required for create operation'); } const sources = Array.isArray(options.source) ? options.source : [options.source]; const format = options.format || this.detectOptimalFormat(sources); const compressionLevel = options.compressionLevel ?? 6; // Collect files to archive const filesToArchive = await this.collectFiles(sources, options); // Check cache for incremental archiving const cacheKey = `cache-${createHash("md5").update('archive-metadata', options.destination).digest("hex")}`; const useCache = options.useCache !== false; let _previousMetadata: ArchiveMetadata | null = null; if (useCache) { const cached = await this.cache.get(cacheKey); if (cached) { previousMetadata = JSON.parse(cached); } } // Create the archive const bytesProcessed = await this.createArchiveFile( filesToArchive, options.destination, format, compressionLevel, options ); // Generate metadata const metadata = await this.generateArchiveMetadata( options.destination, format, filesToArchive ); // Cache the metadata if (useCache) { const metadataStr = JSON.stringify(metadata); await this.cache.set( cacheKey, Buffer.from(metadataStr, 'utf-8'), options.ttl || 3600, this.tokenCounter.count(metadataStr) ); } const dataStr = JSON.stringify({ metadata, bytesProcessed }); const tokensUsed = this.tokenCounter.count(dataStr).tokens; return { success: true, operation: 'create', data: { metadata, bytesProcessed }, metadata: { tokensUsed, tokensSaved: 0, cacheHit: false, executionTime: 0 } }; } /** * Extract an archive with progress tracking */ private async extractArchive(options: SmartArchiveOptions): Promise { if (!options.source || Array.isArray(options.source)) { throw new Error('Source must be a single archive path for extract operation'); } if (!options.destination) { throw new Error('Destination directory is required for extract operation'); } const archivePath = options.source; const format = options.format || this.detectFormatFromPath(archivePath); // Ensure destination directory exists await _mkdir(options.destination, { recursive: true }); let bytesProcessed = 0; const entries: ArchiveEntry[] = []; if (format === 'zip') { await this.extractZip(archivePath, options.destination, entries); bytesProcessed = (await stat(archivePath)).size; } else { await this.extractTar(archivePath, options.destination, format, entries); bytesProcessed = (await stat(archivePath)).size; } const dataStr = JSON.stringify({ extractedPath: options.destination, entries, bytesProcessed }); const tokensUsed = this.tokenCounter.count(dataStr).tokens; return { success: true, operation: 'extract', data: { extractedPath: options.destination, entries, bytesProcessed }, metadata: { tokensUsed, tokensSaved: 0, cacheHit: false, executionTime: 0 } }; } /** * List archive contents with smart caching */ private async listArchive(options: SmartArchiveOptions): Promise { if (!options.source || Array.isArray(options.source)) { throw new Error('Source must be a single archive path for list operation'); } const archivePath = options.source; const format = options.format || this.detectFormatFromPath(archivePath); // Check cache const cacheKey = `cache-${createHash("md5").update('archive-list', archivePath).digest("hex")}`; const useCache = options.useCache !== false; if (useCache) { const cached = await this.cache.get(cacheKey); if (cached) { const dataStr = cached; const tokensUsed = this.tokenCounter.count(dataStr).tokens; const baselineTokens = tokensUsed * 6; // Estimate 6x baseline for archive listings return { success: true, operation: 'list', data: JSON.parse(dataStr), metadata: { tokensUsed, tokensSaved: baselineTokens - tokensUsed, cacheHit: true, executionTime: 0 } }; } } // List entries const entries: ArchiveEntry[] = []; if (format === 'zip') { await this.listZipEntries(archivePath, entries); } else { await this.listTarEntries(archivePath, format, entries); } const metadata = await this.generateArchiveMetadata(archivePath, format, entries); const dataStr = JSON.stringify({ metadata, entries }); const tokensUsed = this.tokenCounter.count(dataStr).tokens; // Cache the result if (useCache) { await this.cache.set(cacheKey, dataStr, options.ttl || 1800, 'utf-8'); } return { success: true, operation: 'list', data: { metadata, entries }, metadata: { tokensUsed, tokensSaved: 0, cacheHit: false, executionTime: 0 } }; } /** * Verify archive integrity with caching */ private async verifyArchive(options: SmartArchiveOptions): Promise { if (!options.source || Array.isArray(options.source)) { throw new Error('Source must be a single archive path for verify operation'); } const archivePath = options.source; const format = options.format || this.detectFormatFromPath(archivePath); // Check cache const cacheKey = `cache-${createHash("md5").update('archive-verify', archivePath).digest("hex")}`; const useCache = options.useCache !== false; if (useCache) { const cached = await this.cache.get(cacheKey); if (cached) { const dataStr = cached; const tokensUsed = this.tokenCounter.count(dataStr).tokens; const baselineTokens = tokensUsed * 7; // Estimate 7x baseline for verification return { success: true, operation: 'verify', data: JSON.parse(dataStr), metadata: { tokensUsed, tokensSaved: baselineTokens - tokensUsed, cacheHit: true, executionTime: 0 } }; } } // Perform verification const verification = await this.performVerification(archivePath, format); const dataStr = JSON.stringify({ verification }); const tokensUsed = this.tokenCounter.count(dataStr).tokens; // Cache the result (shorter TTL for verification results) if (useCache) { await this.cache.set(cacheKey, dataStr, options.ttl || 300, 'utf-8'); } return { success: true, operation: 'verify', data: { verification }, metadata: { tokensUsed, tokensSaved: 0, cacheHit: false, executionTime: 0 } }; } /** * Create incremental backup based on base archive */ private async incrementalBackup(options: SmartArchiveOptions): Promise { if (!options.source) { throw new Error('Source is required for incremental backup operation'); } if (!options.destination) { throw new Error('Destination is required for incremental backup operation'); } if (!options.incrementalBase) { throw new Error('Incremental base archive is required'); } const sources = Array.isArray(options.source) ? options.source : [options.source]; const format = options.format || 'tar.gz'; // Get base archive metadata const baseMetadata = await this.getArchiveMetadata(options.incrementalBase); const baseFileMap = new Map(baseMetadata.entries.map(e => [e.name, e])); // Collect current files const currentFiles = await this.collectFiles(sources, options); // Determine changes const incrementalInfo: IncrementalBackupInfo = { baseArchive: options.incrementalBase, newFiles: [], modifiedFiles: [], deletedFiles: [], totalChanges: 0, timestamp: new Date() }; const filesToBackup: ArchiveEntry[] = []; for (const file of currentFiles) { const baseEntry = baseFileMap.get(file.name); if (!baseEntry) { // New file incrementalInfo.newFiles.push(file.name); filesToBackup.push(file); } else if ( file.mtime && baseEntry.mtime && file.mtime.getTime() > baseEntry.mtime.getTime() ) { // Modified file incrementalInfo.modifiedFiles.push(file.name); filesToBackup.push(file); } baseFileMap.delete(file.name); } // Remaining files in baseFileMap are deleted incrementalInfo.deletedFiles = Array.from(baseFileMap.keys()); incrementalInfo.totalChanges = incrementalInfo.newFiles.length + incrementalInfo.modifiedFiles.length + incrementalInfo.deletedFiles.length; // Create incremental archive only if there are changes let bytesProcessed = 0; if (filesToBackup.length > 0) { bytesProcessed = await this.createArchiveFile( filesToBackup, options.destination, format, options.compressionLevel ?? 6, options ); } const dataStr = JSON.stringify({ incrementalInfo, bytesProcessed }); const tokensUsed = this.tokenCounter.count(dataStr).tokens; return { success: true, operation: 'incremental-backup', data: { incrementalInfo, bytesProcessed }, metadata: { tokensUsed, tokensSaved: 0, cacheHit: false, executionTime: 0 } }; } /** * Detect optimal archive format based on file types */ private detectOptimalFormat(_sources: string[]): ArchiveFormat { // For now, default to tar.gz which provides good compression for most files // Could be enhanced with content-type detection return 'tar.gz'; } /** * Detect archive format from file extension */ private detectFormatFromPath(archivePath: string): ArchiveFormat { const ext = path.extname(archivePath).toLowerCase(); if (archivePath.endsWith('.tar.gz') || archivePath.endsWith('.tgz')) { return 'tar.gz'; } else if (archivePath.endsWith('.tar.bz2') || archivePath.endsWith('.tbz2')) { return 'tar.bz2'; } else if (ext === '.tar') { return 'tar'; } else if (ext === '.zip') { return 'zip'; } throw new Error(`Unable to detect archive format from path: ${archivePath}`); } /** * Collect files to archive based on patterns */ private async collectFiles( sources: string[], options: SmartArchiveOptions ): Promise { const entries: ArchiveEntry[] = []; for (const source of sources) { await this.collectFilesRecursive( source, options.baseDir || path.dirname(source), entries, options ); } return entries; } /** * Recursively collect files */ private async collectFilesRecursive( filePath: string, baseDir: string, entries: ArchiveEntry[], options: SmartArchiveOptions ): Promise { const stats = await stat(filePath); const relativePath = path.relative(baseDir, filePath); // Check exclude patterns if (options.excludePatterns && this.matchesPatterns(relativePath, options.excludePatterns)) { return; } // Check include patterns (if specified, only include matching files) if ( options.includePatterns && options.includePatterns.length > 0 && !this.matchesPatterns(relativePath, options.includePatterns) ) { return; } if (stats.isDirectory()) { const files = await readdir(filePath); for (const file of files) { await this.collectFilesRecursive( path.join(filePath, file), baseDir, entries, options ); } } else if (stats.isFile()) { entries.push({ name: relativePath, size: stats.size, type: 'file', mode: stats.mode, mtime: stats.mtime }); } else if (stats.isSymbolicLink() && options.followSymlinks) { const realPath = await fs.promises.realpath(filePath); await this.collectFilesRecursive(realPath, baseDir, entries, options); } } /** * Check if path matches any of the patterns */ private matchesPatterns(filePath: string, patterns: string[]): boolean { const normalizedPath = filePath.replace(/\\/g, '/'); for (const pattern of patterns) { const normalizedPattern = pattern.replace(/\\/g, '/'); const regex = new RegExp( '^' + normalizedPattern.replace(/\*/g, '.*').replace(/\?/g, '.') + '$' ); if (regex.test(normalizedPath)) { return true; } } return false; } /** * Create archive file */ private async createArchiveFile( files: ArchiveEntry[], destination: string, format: ArchiveFormat, compressionLevel: CompressionLevel, options: SmartArchiveOptions ): Promise { if (format === 'zip') { return await this.createZipArchive(files, destination, compressionLevel, options); } else { return await this.createTarArchive(files, destination, format, compressionLevel, options); } } /** * Create ZIP archive */ private async createZipArchive( files: ArchiveEntry[], destination: string, compressionLevel: CompressionLevel, options: SmartArchiveOptions ): Promise { return new Promise((resolve, reject) => { const output = fs.createWriteStream(destination); const archive = archiver('zip', { zlib: { level: compressionLevel } }); let _bytesProcessed = 0; output.on('close', () => { resolve(archive.pointer()); }); archive.on('error', reject); archive.pipe(output); const baseDir = options.baseDir || process.cwd(); for (const file of files) { const fullPath = path.join(baseDir, file.name); if (file.type === 'file') { archive.file(fullPath, { name: file.name, mode: file.mode, date: file.mtime }); } } archive.finalize(); }); } /** * Create TAR archive */ private async createTarArchive( files: ArchiveEntry[], destination: string, format: ArchiveFormat, compressionLevel: CompressionLevel, options: SmartArchiveOptions ): Promise { const pack = tar.pack(); const baseDir = options.baseDir || process.cwd(); // Queue all files for (const file of files) { const fullPath = path.join(baseDir, file.name); if (file.type === 'file') { const content = await fs.promises.readFile(fullPath); pack.entry( { name: file.name, size: file.size, mode: file.mode, mtime: file.mtime }, content ); } } pack.finalize(); const output = fs.createWriteStream(destination); if (format === 'tar.gz') { const gzip = zlib.createGzip({ level: compressionLevel }); await pipelineAsync(pack, gzip, output); } else if (format === 'tar.bz2') { const bzip2 = zlib.createBrotliCompress({ params: { [zlib.constants.BROTLI_PARAM_QUALITY]: compressionLevel } }); await pipelineAsync(pack, bzip2, output); } else { await pipelineAsync(pack, output); } const stats = await stat(destination); return stats.size; } /** * Extract ZIP archive */ private async extractZip( archivePath: string, destination: string, entries: ArchiveEntry[] ): Promise { await new Promise((resolve, reject) => { fs.createReadStream(archivePath) .pipe(unzipper.Parse()) .on('entry', async (entry: any) => { const entryPath = path.join(destination, entry.path); entries.push({ name: entry.path, size: entry.vars.uncompressedSize, type: entry.type === 'Directory' ? 'directory' : 'file', mtime: entry.vars.lastModifiedTime }); if (entry.type === 'Directory') { await _mkdir(entryPath, { recursive: true }); entry.autodrain(); } else { await _mkdir(path.dirname(entryPath), { recursive: true }); entry.pipe(fs.createWriteStream(entryPath)); } }) .on('close', resolve) .on('error', reject); }); } /** * Extract TAR archive */ private async extractTar( archivePath: string, destination: string, format: ArchiveFormat, entries: ArchiveEntry[] ): Promise { const extract = tar.extract(); extract.on('entry', async (header: tarStream.Headers, stream: NodeJS.ReadableStream, next: () => void) => { const entryPath = path.join(destination, header.name); entries.push({ name: header.name, size: header.size || 0, type: header.type === 'directory' ? 'directory' : 'file', mode: header.mode, mtime: header.mtime }); if (header.type === 'directory') { await _mkdir(entryPath, { recursive: true }); stream.resume(); next(); } else { await _mkdir(path.dirname(entryPath), { recursive: true }); const writeStream = fs.createWriteStream(entryPath); stream.pipe(writeStream); stream.on('end', next); } }); const input = fs.createReadStream(archivePath); if (format === 'tar.gz') { const gunzip = zlib.createGunzip(); await pipelineAsync(input, gunzip, extract); } else if (format === 'tar.bz2') { const bunzip2 = zlib.createBrotliDecompress(); await pipelineAsync(input, bunzip2, extract); } else { await pipelineAsync(input, extract); } } /** * List ZIP entries */ private async listZipEntries(archivePath: string, entries: ArchiveEntry[]): Promise { await new Promise((resolve, reject) => { fs.createReadStream(archivePath) .pipe(unzipper.Parse()) .on('entry', (entry: any) => { entries.push({ name: entry.path, size: entry.vars.uncompressedSize, type: entry.type === 'Directory' ? 'directory' : 'file', mtime: entry.vars.lastModifiedTime, compressed: true }); entry.autodrain(); }) .on('close', resolve) .on('error', reject); }); } /** * List TAR entries */ private async listTarEntries( archivePath: string, format: ArchiveFormat, entries: ArchiveEntry[] ): Promise { const extract = tar.extract(); extract.on('entry', (header: tarStream.Headers, stream: NodeJS.ReadableStream, next: () => void) => { entries.push({ name: header.name, size: header.size || 0, type: header.type === 'directory' ? 'directory' : 'file', mode: header.mode, mtime: header.mtime, compressed: format !== 'tar' }); stream.on('end', next); stream.resume(); }); const input = fs.createReadStream(archivePath); if (format === 'tar.gz') { const gunzip = zlib.createGunzip(); await pipelineAsync(input, gunzip, extract); } else if (format === 'tar.bz2') { const bunzip2 = zlib.createBrotliDecompress(); await pipelineAsync(input, bunzip2, extract); } else { await pipelineAsync(input, extract); } } /** * Generate archive metadata */ private async generateArchiveMetadata( archivePath: string, format: ArchiveFormat, entries: ArchiveEntry[] ): Promise { const stats = await stat(archivePath); const checksum = await this.calculateFileChecksum(archivePath); const totalSize = entries.reduce((sum, e) => sum + e.size, 0); const compressionRatio = totalSize > 0 ? stats.size / totalSize : 0; return { format, path: archivePath, totalSize, compressedSize: stats.size, compressionRatio, entryCount: entries.length, entries, created: stats.mtime, checksum }; } /** * Get archive metadata from cache or by listing */ private async getArchiveMetadata(archivePath: string): Promise { const cacheKey = `cache-${createHash("md5").update('archive-metadata', archivePath).digest("hex")}`; const cached = await this.cache.get(cacheKey); if (cached) { return JSON.parse(cached); } // Generate metadata const format = this.detectFormatFromPath(archivePath); const entries: ArchiveEntry[] = []; if (format === 'zip') { await this.listZipEntries(archivePath, entries); } else { await this.listTarEntries(archivePath, format, entries); } return await this.generateArchiveMetadata(archivePath, format, entries); } /** * Perform integrity verification */ private async performVerification( archivePath: string, format: ArchiveFormat ): Promise { const result: ArchiveVerificationResult = { valid: true, checksumMatch: true, entriesValid: 0, entriesCorrupted: 0, errors: [], warnings: [] }; try { // List entries to verify archive structure const entries: ArchiveEntry[] = []; if (format === 'zip') { await this.listZipEntries(archivePath, entries); } else { await this.listTarEntries(archivePath, format, entries); } result.entriesValid = entries.length; // Verify file exists and is readable const stats = await stat(archivePath); if (stats.size === 0) { result.valid = false; result.errors.push('Archive file is empty'); } // Calculate and verify checksum if metadata exists const cacheKey = `cache-${createHash("md5").update('archive-metadata', archivePath).digest("hex")}`; const cached = await this.cache.get(cacheKey); if (cached) { const metadata: ArchiveMetadata = JSON.parse(cached); const currentChecksum = await this.calculateFileChecksum(archivePath); if (metadata.checksum !== currentChecksum) { result.checksumMatch = false; result.warnings.push('Archive checksum does not match stored metadata'); } } } catch (error) { result.valid = false; result.errors.push(error instanceof Error ? error.message : String(error)); } return result; } /** * Calculate file checksum (SHA-256) */ private async calculateFileChecksum(filePath: string): Promise { return new Promise((resolve, reject) => { const hash = createHash('sha256'); const stream = fs.createReadStream(filePath); stream.on('data', (chunk) => hash.update(chunk)); stream.on('end', () => resolve(hash.digest('hex'))); stream.on('error', reject); }); }}// ===========================// Factory Function// ===========================export function getSmartArchive( cache: CacheEngine, tokenCounter: TokenCounter, metricsCollector: MetricsCollector): SmartArchive { return new SmartArchive(cache, tokenCounter, metricsCollector);}// ===========================// Standalone Runner Function (CLI)// ===========================export async function runSmartArchive( options: SmartArchiveOptions, cache?: CacheEngine, tokenCounter?: TokenCounter, metricsCollector?: MetricsCollector): Promise { const { homedir } = await import('os'); const { join } = await import('path'); const cacheInstance = cache || new CacheEngine(100, join(homedir(), '.hypercontext', 'cache')); const tokenCounterInstance = tokenCounter || new TokenCounter(); const metricsInstance = metricsCollector || new MetricsCollector(); const tool = getSmartArchive(cacheInstance, tokenCounterInstance, metricsInstance); return await tool.run(options);}// ===========================// MCP Tool Definition// ===========================export const SMART_ARCHIVE_TOOL_DEFINITION = { name: 'smart_archive', description: 'Intelligent archive operations with smart caching (84%+ token reduction). Create, extract, list, and verify TAR/ZIP/GZ archives with incremental backup support and integrity verification.', inputSchema: { type: 'object' as const, properties: { operation: { type: 'string' as const, enum: ['create', 'extract', 'list', 'verify', 'incremental-backup'], description: 'Archive operation to perform' }, format: { type: 'string' as const, enum: ['tar', 'tar.gz', 'tar.bz2', 'zip'], description: 'Archive format (auto-detected if not specified)' }, source: { type: ['string', 'array'] as const, description: 'Source file(s) or directory for create/incremental-backup, archive path for extract/list/verify', items: { type: 'string' as const } }, destination: { type: 'string' as const, description: 'Destination archive path for create, or extraction directory for extract' }, compressionLevel: { type: 'number' as const, description: 'Compression level 0-9 (default: 6)', minimum: 0, maximum: 9, default: 6 }, includePatterns: { type: 'array' as const, items: { type: 'string' as const }, description: 'Patterns to include (e.g., ["*.js", "src/**"])' }, excludePatterns: { type: 'array' as const, items: { type: 'string' as const }, description: 'Patterns to exclude (e.g., ["node_modules/**", "*.log"])' }, preservePermissions: { type: 'boolean' as const, description: 'Preserve file permissions (default: true)', default: true }, followSymlinks: { type: 'boolean' as const, description: 'Follow symbolic links (default: false)', default: false }, baseDir: { type: 'string' as const, description: 'Base directory for relative paths' }, useCache: { type: 'boolean' as const, description: 'Use cached metadata when available (default: true)', default: true }, ttl: { type: 'number' as const, description: 'Cache TTL in seconds (default: 3600 for metadata, 1800 for listings)' }, verifyIntegrity: { type: 'boolean' as const, description: 'Verify archive integrity after creation (default: false)', default: false }, incrementalBase: { type: 'string' as const, description: 'Base archive path for incremental-backup operation' } }, required: ['operation'] }}; +const _stat = promisify(fs.stat); +const _readdir = promisify(fs.readdir); +const _mkdir = promisify(fs.mkdir); // ===========================// Types & Interfaces// ===========================export type ArchiveFormat = 'tar' | 'tar.gz' | 'tar.bz2' | 'zip';export type CompressionLevel = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;export type ArchiveOperation = 'create' | 'extract' | 'list' | 'verify' | 'incremental-backup';export interface SmartArchiveOptions { operation: ArchiveOperation; format?: ArchiveFormat; source?: string | string[]; destination?: string; compressionLevel?: CompressionLevel; includePatterns?: string[]; excludePatterns?: string[]; preservePermissions?: boolean; followSymlinks?: boolean; baseDir?: string; useCache?: boolean; ttl?: number; verifyIntegrity?: boolean; incrementalBase?: string;}export interface ArchiveEntry { name: string; size: number; type: 'file' | 'directory' | 'symlink'; mode?: number; mtime?: Date; checksum?: string; compressed?: boolean;}export interface ArchiveMetadata { format: ArchiveFormat; path: string; totalSize: number; compressedSize?: number; compressionRatio?: number; entryCount: number; entries: ArchiveEntry[]; created: Date; checksum: string;}export interface IncrementalBackupInfo { baseArchive: string; newFiles: string[]; modifiedFiles: string[]; deletedFiles: string[]; totalChanges: number; timestamp: Date;}export interface ArchiveVerificationResult { valid: boolean; checksumMatch: boolean; entriesValid: number; entriesCorrupted: number; errors: string[]; warnings: string[];}export interface SmartArchiveResult { success: boolean; operation: ArchiveOperation; data: { metadata?: ArchiveMetadata; entries?: ArchiveEntry[]; extractedPath?: string; verification?: ArchiveVerificationResult; incrementalInfo?: IncrementalBackupInfo; bytesProcessed?: number; error?: string; }; metadata: { tokensUsed: number; tokensSaved: number; cacheHit: boolean; executionTime: number; };}// ===========================// SmartArchive Class// ===========================export class SmartArchive { constructor( private cache: CacheEngine, private tokenCounter: TokenCounter, private metricsCollector: MetricsCollector ) {} /** * Main entry point for archive operations */ async run(options: SmartArchiveOptions): Promise { const startTime = Date.now(); const operation = options.operation; let result: SmartArchiveResult; try { switch (operation) { case 'create': result = await this.createArchive(options); break; case 'extract': result = await this.extractArchive(options); break; case 'list': result = await this.listArchive(options); break; case 'verify': result = await this.verifyArchive(options); break; case 'incremental-backup': result = await this.incrementalBackup(options); break; default: throw new Error(`Unknown operation: ${operation}`); } // Record metrics this.metricsCollector.record({ operation: `smart-archive:${operation}`, duration: Date.now() - startTime, success: result.success, cacheHit: result.metadata.cacheHit, metadata: { format: options.format, source: options.source } }); return result; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); const errorResult: SmartArchiveResult = { success: false, operation, data: { error: errorMessage }, metadata: { tokensUsed: this.tokenCounter.count(errorMessage).tokens, tokensSaved: 0, cacheHit: false, executionTime: Date.now() - startTime } }; this.metricsCollector.record({ operation: `smart-archive:${operation}`, duration: Date.now() - startTime, success: false, cacheHit: false, metadata: { error: errorMessage, format: options.format } }); return errorResult; } } /** * Create an archive with smart compression selection */ private async createArchive(options: SmartArchiveOptions): Promise { if (!options.source) { throw new Error('Source is required for create operation'); } if (!options.destination) { throw new Error('Destination is required for create operation'); } const sources = Array.isArray(options.source) ? options.source : [options.source]; const format = options.format || this.detectOptimalFormat(sources); const compressionLevel = options.compressionLevel ?? 6; // Collect files to archive const filesToArchive = await this.collectFiles(sources, options); // Check cache for incremental archiving const cacheKey = `cache-${createHash("md5").update('archive-metadata', options.destination).digest("hex")}`; const useCache = options.useCache !== false; let _previousMetadata: ArchiveMetadata | null = null; if (useCache) { const cached = await this.cache.get(cacheKey); if (cached) { previousMetadata = JSON.parse(cached); } } // Create the archive const bytesProcessed = await this.createArchiveFile( filesToArchive, options.destination, format, compressionLevel, options ); // Generate metadata const metadata = await this.generateArchiveMetadata( options.destination, format, filesToArchive ); // Cache the metadata if (useCache) { const metadataStr = JSON.stringify(metadata); await this.cache.set( cacheKey, Buffer.from(metadataStr, 'utf-8'), options.ttl || 3600, this.tokenCounter.count(metadataStr) ); } const dataStr = JSON.stringify({ metadata, bytesProcessed }); const tokensUsed = this.tokenCounter.count(dataStr).tokens; return { success: true, operation: 'create', data: { metadata, bytesProcessed }, metadata: { tokensUsed, tokensSaved: 0, cacheHit: false, executionTime: 0 } }; } /** * Extract an archive with progress tracking */ private async extractArchive(options: SmartArchiveOptions): Promise { if (!options.source || Array.isArray(options.source)) { throw new Error('Source must be a single archive path for extract operation'); } if (!options.destination) { throw new Error('Destination directory is required for extract operation'); } const archivePath = options.source; const format = options.format || this.detectFormatFromPath(archivePath); // Ensure destination directory exists await _mkdir(options.destination, { recursive: true }); let bytesProcessed = 0; const entries: ArchiveEntry[] = []; if (format === 'zip') { await this.extractZip(archivePath, options.destination, entries); bytesProcessed = (await stat(archivePath)).size; } else { await this.extractTar(archivePath, options.destination, format, entries); bytesProcessed = (await stat(archivePath)).size; } const dataStr = JSON.stringify({ extractedPath: options.destination, entries, bytesProcessed }); const tokensUsed = this.tokenCounter.count(dataStr).tokens; return { success: true, operation: 'extract', data: { extractedPath: options.destination, entries, bytesProcessed }, metadata: { tokensUsed, tokensSaved: 0, cacheHit: false, executionTime: 0 } }; } /** * List archive contents with smart caching */ private async listArchive(options: SmartArchiveOptions): Promise { if (!options.source || Array.isArray(options.source)) { throw new Error('Source must be a single archive path for list operation'); } const archivePath = options.source; const format = options.format || this.detectFormatFromPath(archivePath); // Check cache const cacheKey = `cache-${createHash("md5").update('archive-list', archivePath).digest("hex")}`; const useCache = options.useCache !== false; if (useCache) { const cached = await this.cache.get(cacheKey); if (cached) { const dataStr = cached; const tokensUsed = this.tokenCounter.count(dataStr).tokens; const baselineTokens = tokensUsed * 6; // Estimate 6x baseline for archive listings return { success: true, operation: 'list', data: JSON.parse(dataStr), metadata: { tokensUsed, tokensSaved: baselineTokens - tokensUsed, cacheHit: true, executionTime: 0 } }; } } // List entries const entries: ArchiveEntry[] = []; if (format === 'zip') { await this.listZipEntries(archivePath, entries); } else { await this.listTarEntries(archivePath, format, entries); } const metadata = await this.generateArchiveMetadata(archivePath, format, entries); const dataStr = JSON.stringify({ metadata, entries }); const tokensUsed = this.tokenCounter.count(dataStr).tokens; // Cache the result if (useCache) { await this.cache.set(cacheKey, dataStr, options.ttl || 1800, 'utf-8'); } return { success: true, operation: 'list', data: { metadata, entries }, metadata: { tokensUsed, tokensSaved: 0, cacheHit: false, executionTime: 0 } }; } /** * Verify archive integrity with caching */ private async verifyArchive(options: SmartArchiveOptions): Promise { if (!options.source || Array.isArray(options.source)) { throw new Error('Source must be a single archive path for verify operation'); } const archivePath = options.source; const format = options.format || this.detectFormatFromPath(archivePath); // Check cache const cacheKey = `cache-${createHash("md5").update('archive-verify', archivePath).digest("hex")}`; const useCache = options.useCache !== false; if (useCache) { const cached = await this.cache.get(cacheKey); if (cached) { const dataStr = cached; const tokensUsed = this.tokenCounter.count(dataStr).tokens; const baselineTokens = tokensUsed * 7; // Estimate 7x baseline for verification return { success: true, operation: 'verify', data: JSON.parse(dataStr), metadata: { tokensUsed, tokensSaved: baselineTokens - tokensUsed, cacheHit: true, executionTime: 0 } }; } } // Perform verification const verification = await this.performVerification(archivePath, format); const dataStr = JSON.stringify({ verification }); const tokensUsed = this.tokenCounter.count(dataStr).tokens; // Cache the result (shorter TTL for verification results) if (useCache) { await this.cache.set(cacheKey, dataStr, options.ttl || 300, 'utf-8'); } return { success: true, operation: 'verify', data: { verification }, metadata: { tokensUsed, tokensSaved: 0, cacheHit: false, executionTime: 0 } }; } /** * Create incremental backup based on base archive */ private async incrementalBackup(options: SmartArchiveOptions): Promise { if (!options.source) { throw new Error('Source is required for incremental backup operation'); } if (!options.destination) { throw new Error('Destination is required for incremental backup operation'); } if (!options.incrementalBase) { throw new Error('Incremental base archive is required'); } const sources = Array.isArray(options.source) ? options.source : [options.source]; const format = options.format || 'tar.gz'; // Get base archive metadata const baseMetadata = await this.getArchiveMetadata(options.incrementalBase); const baseFileMap = new Map(baseMetadata.entries.map(e => [e.name, e])); // Collect current files const currentFiles = await this.collectFiles(sources, options); // Determine changes const incrementalInfo: IncrementalBackupInfo = { baseArchive: options.incrementalBase, newFiles: [], modifiedFiles: [], deletedFiles: [], totalChanges: 0, timestamp: new Date() }; const filesToBackup: ArchiveEntry[] = []; for (const file of currentFiles) { const baseEntry = baseFileMap.get(file.name); if (!baseEntry) { // New file incrementalInfo.newFiles.push(file.name); filesToBackup.push(file); } else if ( file.mtime && baseEntry.mtime && file.mtime.getTime() > baseEntry.mtime.getTime() ) { // Modified file incrementalInfo.modifiedFiles.push(file.name); filesToBackup.push(file); } baseFileMap.delete(file.name); } // Remaining files in baseFileMap are deleted incrementalInfo.deletedFiles = Array.from(baseFileMap.keys()); incrementalInfo.totalChanges = incrementalInfo.newFiles.length + incrementalInfo.modifiedFiles.length + incrementalInfo.deletedFiles.length; // Create incremental archive only if there are changes let bytesProcessed = 0; if (filesToBackup.length > 0) { bytesProcessed = await this.createArchiveFile( filesToBackup, options.destination, format, options.compressionLevel ?? 6, options ); } const dataStr = JSON.stringify({ incrementalInfo, bytesProcessed }); const tokensUsed = this.tokenCounter.count(dataStr).tokens; return { success: true, operation: 'incremental-backup', data: { incrementalInfo, bytesProcessed }, metadata: { tokensUsed, tokensSaved: 0, cacheHit: false, executionTime: 0 } }; } /** * Detect optimal archive format based on file types */ private detectOptimalFormat(_sources: string[]): ArchiveFormat { // For now, default to tar.gz which provides good compression for most files // Could be enhanced with content-type detection return 'tar.gz'; } /** * Detect archive format from file extension */ private detectFormatFromPath(archivePath: string): ArchiveFormat { const ext = path.extname(archivePath).toLowerCase(); if (archivePath.endsWith('.tar.gz') || archivePath.endsWith('.tgz')) { return 'tar.gz'; } else if (archivePath.endsWith('.tar.bz2') || archivePath.endsWith('.tbz2')) { return 'tar.bz2'; } else if (ext === '.tar') { return 'tar'; } else if (ext === '.zip') { return 'zip'; } throw new Error(`Unable to detect archive format from path: ${archivePath}`); } /** * Collect files to archive based on patterns */ private async collectFiles( sources: string[], options: SmartArchiveOptions ): Promise { const entries: ArchiveEntry[] = []; for (const source of sources) { await this.collectFilesRecursive( source, options.baseDir || path.dirname(source), entries, options ); } return entries; } /** * Recursively collect files */ private async collectFilesRecursive( filePath: string, baseDir: string, entries: ArchiveEntry[], options: SmartArchiveOptions ): Promise { const stats = await stat(filePath); const relativePath = path.relative(baseDir, filePath); // Check exclude patterns if (options.excludePatterns && this.matchesPatterns(relativePath, options.excludePatterns)) { return; } // Check include patterns (if specified, only include matching files) if ( options.includePatterns && options.includePatterns.length > 0 && !this.matchesPatterns(relativePath, options.includePatterns) ) { return; } if (stats.isDirectory()) { const files = await readdir(filePath); for (const file of files) { await this.collectFilesRecursive( path.join(filePath, file), baseDir, entries, options ); } } else if (stats.isFile()) { entries.push({ name: relativePath, size: stats.size, type: 'file', mode: stats.mode, mtime: stats.mtime }); } else if (stats.isSymbolicLink() && options.followSymlinks) { const realPath = await fs.promises.realpath(filePath); await this.collectFilesRecursive(realPath, baseDir, entries, options); } } /** * Check if path matches any of the patterns */ private matchesPatterns(filePath: string, patterns: string[]): boolean { const normalizedPath = filePath.replace(/\\/g, '/'); for (const pattern of patterns) { const normalizedPattern = pattern.replace(/\\/g, '/'); const regex = new RegExp( '^' + normalizedPattern.replace(/\*/g, '.*').replace(/\?/g, '.') + '$' ); if (regex.test(normalizedPath)) { return true; } } return false; } /** * Create archive file */ private async createArchiveFile( files: ArchiveEntry[], destination: string, format: ArchiveFormat, compressionLevel: CompressionLevel, options: SmartArchiveOptions ): Promise { if (format === 'zip') { return await this.createZipArchive(files, destination, compressionLevel, options); } else { return await this.createTarArchive(files, destination, format, compressionLevel, options); } } /** * Create ZIP archive */ private async createZipArchive( files: ArchiveEntry[], destination: string, compressionLevel: CompressionLevel, options: SmartArchiveOptions ): Promise { return new Promise((resolve, reject) => { const output = fs.createWriteStream(destination); const archive = archiver('zip', { zlib: { level: compressionLevel } }); let _bytesProcessed = 0; output.on('close', () => { resolve(archive.pointer()); }); archive.on('error', reject); archive.pipe(output); const baseDir = options.baseDir || process.cwd(); for (const file of files) { const fullPath = path.join(baseDir, file.name); if (file.type === 'file') { archive.file(fullPath, { name: file.name, mode: file.mode, date: file.mtime }); } } archive.finalize(); }); } /** * Create TAR archive */ private async createTarArchive( files: ArchiveEntry[], destination: string, format: ArchiveFormat, compressionLevel: CompressionLevel, options: SmartArchiveOptions ): Promise { const pack = tar.pack(); const baseDir = options.baseDir || process.cwd(); // Queue all files for (const file of files) { const fullPath = path.join(baseDir, file.name); if (file.type === 'file') { const content = await fs.promises.readFile(fullPath); pack.entry( { name: file.name, size: file.size, mode: file.mode, mtime: file.mtime }, content ); } } pack.finalize(); const output = fs.createWriteStream(destination); if (format === 'tar.gz') { const gzip = zlib.createGzip({ level: compressionLevel }); await pipelineAsync(pack, gzip, output); } else if (format === 'tar.bz2') { const bzip2 = zlib.createBrotliCompress({ params: { [zlib.constants.BROTLI_PARAM_QUALITY]: compressionLevel } }); await pipelineAsync(pack, bzip2, output); } else { await pipelineAsync(pack, output); } const stats = await stat(destination); return stats.size; } /** * Extract ZIP archive */ private async extractZip( archivePath: string, destination: string, entries: ArchiveEntry[] ): Promise { await new Promise((resolve, reject) => { fs.createReadStream(archivePath) .pipe(unzipper.Parse()) .on('entry', async (entry: any) => { const entryPath = path.join(destination, entry.path); entries.push({ name: entry.path, size: entry.vars.uncompressedSize, type: entry.type === 'Directory' ? 'directory' : 'file', mtime: entry.vars.lastModifiedTime }); if (entry.type === 'Directory') { await _mkdir(entryPath, { recursive: true }); entry.autodrain(); } else { await _mkdir(path.dirname(entryPath), { recursive: true }); entry.pipe(fs.createWriteStream(entryPath)); } }) .on('close', resolve) .on('error', reject); }); } /** * Extract TAR archive */ private async extractTar( archivePath: string, destination: string, format: ArchiveFormat, entries: ArchiveEntry[] ): Promise { const extract = tar.extract(); extract.on('entry', async (header: tarStream.Headers, stream: NodeJS.ReadableStream, next: () => void) => { const entryPath = path.join(destination, header.name); entries.push({ name: header.name, size: header.size || 0, type: header.type === 'directory' ? 'directory' : 'file', mode: header.mode, mtime: header.mtime }); if (header.type === 'directory') { await _mkdir(entryPath, { recursive: true }); stream.resume(); next(); } else { await _mkdir(path.dirname(entryPath), { recursive: true }); const writeStream = fs.createWriteStream(entryPath); stream.pipe(writeStream); stream.on('end', next); } }); const input = fs.createReadStream(archivePath); if (format === 'tar.gz') { const gunzip = zlib.createGunzip(); await pipelineAsync(input, gunzip, extract); } else if (format === 'tar.bz2') { const bunzip2 = zlib.createBrotliDecompress(); await pipelineAsync(input, bunzip2, extract); } else { await pipelineAsync(input, extract); } } /** * List ZIP entries */ private async listZipEntries(archivePath: string, entries: ArchiveEntry[]): Promise { await new Promise((resolve, reject) => { fs.createReadStream(archivePath) .pipe(unzipper.Parse()) .on('entry', (entry: any) => { entries.push({ name: entry.path, size: entry.vars.uncompressedSize, type: entry.type === 'Directory' ? 'directory' : 'file', mtime: entry.vars.lastModifiedTime, compressed: true }); entry.autodrain(); }) .on('close', resolve) .on('error', reject); }); } /** * List TAR entries */ private async listTarEntries( archivePath: string, format: ArchiveFormat, entries: ArchiveEntry[] ): Promise { const extract = tar.extract(); extract.on('entry', (header: tarStream.Headers, stream: NodeJS.ReadableStream, next: () => void) => { entries.push({ name: header.name, size: header.size || 0, type: header.type === 'directory' ? 'directory' : 'file', mode: header.mode, mtime: header.mtime, compressed: format !== 'tar' }); stream.on('end', next); stream.resume(); }); const input = fs.createReadStream(archivePath); if (format === 'tar.gz') { const gunzip = zlib.createGunzip(); await pipelineAsync(input, gunzip, extract); } else if (format === 'tar.bz2') { const bunzip2 = zlib.createBrotliDecompress(); await pipelineAsync(input, bunzip2, extract); } else { await pipelineAsync(input, extract); } } /** * Generate archive metadata */ private async generateArchiveMetadata( archivePath: string, format: ArchiveFormat, entries: ArchiveEntry[] ): Promise { const stats = await stat(archivePath); const checksum = await this.calculateFileChecksum(archivePath); const totalSize = entries.reduce((sum, e) => sum + e.size, 0); const compressionRatio = totalSize > 0 ? stats.size / totalSize : 0; return { format, path: archivePath, totalSize, compressedSize: stats.size, compressionRatio, entryCount: entries.length, entries, created: stats.mtime, checksum }; } /** * Get archive metadata from cache or by listing */ private async getArchiveMetadata(archivePath: string): Promise { const cacheKey = `cache-${createHash("md5").update('archive-metadata', archivePath).digest("hex")}`; const cached = await this.cache.get(cacheKey); if (cached) { return JSON.parse(cached); } // Generate metadata const format = this.detectFormatFromPath(archivePath); const entries: ArchiveEntry[] = []; if (format === 'zip') { await this.listZipEntries(archivePath, entries); } else { await this.listTarEntries(archivePath, format, entries); } return await this.generateArchiveMetadata(archivePath, format, entries); } /** * Perform integrity verification */ private async performVerification( archivePath: string, format: ArchiveFormat ): Promise { const result: ArchiveVerificationResult = { valid: true, checksumMatch: true, entriesValid: 0, entriesCorrupted: 0, errors: [], warnings: [] }; try { // List entries to verify archive structure const entries: ArchiveEntry[] = []; if (format === 'zip') { await this.listZipEntries(archivePath, entries); } else { await this.listTarEntries(archivePath, format, entries); } result.entriesValid = entries.length; // Verify file exists and is readable const stats = await stat(archivePath); if (stats.size === 0) { result.valid = false; result.errors.push('Archive file is empty'); } // Calculate and verify checksum if metadata exists const cacheKey = `cache-${createHash("md5").update('archive-metadata', archivePath).digest("hex")}`; const cached = await this.cache.get(cacheKey); if (cached) { const metadata: ArchiveMetadata = JSON.parse(cached); const currentChecksum = await this.calculateFileChecksum(archivePath); if (metadata.checksum !== currentChecksum) { result.checksumMatch = false; result.warnings.push('Archive checksum does not match stored metadata'); } } } catch (error) { result.valid = false; result.errors.push(error instanceof Error ? error.message : String(error)); } return result; } /** * Calculate file checksum (SHA-256) */ private async calculateFileChecksum(filePath: string): Promise { return new Promise((resolve, reject) => { const hash = createHash('sha256'); const stream = fs.createReadStream(filePath); stream.on('data', (chunk) => hash.update(chunk)); stream.on('end', () => resolve(hash.digest('hex'))); stream.on('error', reject); }); }}// ===========================// Factory Function// ===========================export function getSmartArchive( cache: CacheEngine, tokenCounter: TokenCounter, metricsCollector: MetricsCollector): SmartArchive { return new SmartArchive(cache, tokenCounter, metricsCollector);}// ===========================// Standalone Runner Function (CLI)// ===========================export async function runSmartArchive( options: SmartArchiveOptions, cache?: CacheEngine, tokenCounter?: TokenCounter, metricsCollector?: MetricsCollector): Promise { const { homedir } = await import('os'); const { join } = await import('path'); const cacheInstance = cache || new CacheEngine(100, join(homedir(), '.hypercontext', 'cache')); const tokenCounterInstance = tokenCounter || new TokenCounter(); const metricsInstance = metricsCollector || new MetricsCollector(); const tool = getSmartArchive(cacheInstance, tokenCounterInstance, metricsInstance); return await tool.run(options);}// ===========================// MCP Tool Definition// ===========================export const SMART_ARCHIVE_TOOL_DEFINITION = { name: 'smart_archive', description: 'Intelligent archive operations with smart caching (84%+ token reduction). Create, extract, list, and verify TAR/ZIP/GZ archives with incremental backup support and integrity verification.', inputSchema: { type: 'object' as const, properties: { operation: { type: 'string' as const, enum: ['create', 'extract', 'list', 'verify', 'incremental-backup'], description: 'Archive operation to perform' }, format: { type: 'string' as const, enum: ['tar', 'tar.gz', 'tar.bz2', 'zip'], description: 'Archive format (auto-detected if not specified)' }, source: { type: ['string', 'array'] as const, description: 'Source file(s) or directory for create/incremental-backup, archive path for extract/list/verify', items: { type: 'string' as const } }, destination: { type: 'string' as const, description: 'Destination archive path for create, or extraction directory for extract' }, compressionLevel: { type: 'number' as const, description: 'Compression level 0-9 (default: 6)', minimum: 0, maximum: 9, default: 6 }, includePatterns: { type: 'array' as const, items: { type: 'string' as const }, description: 'Patterns to include (e.g., ["*.js", "src/**"])' }, excludePatterns: { type: 'array' as const, items: { type: 'string' as const }, description: 'Patterns to exclude (e.g., ["node_modules/**", "*.log"])' }, preservePermissions: { type: 'boolean' as const, description: 'Preserve file permissions (default: true)', default: true }, followSymlinks: { type: 'boolean' as const, description: 'Follow symbolic links (default: false)', default: false }, baseDir: { type: 'string' as const, description: 'Base directory for relative paths' }, useCache: { type: 'boolean' as const, description: 'Use cached metadata when available (default: true)', default: true }, ttl: { type: 'number' as const, description: 'Cache TTL in seconds (default: 3600 for metadata, 1800 for listings)' }, verifyIntegrity: { type: 'boolean' as const, description: 'Verify archive integrity after creation (default: false)', default: false }, incrementalBase: { type: 'string' as const, description: 'Base archive path for incremental-backup operation' } }, required: ['operation'] }}; diff --git a/src/tools/system-operations/smart-cleanup.ts b/src/tools/system-operations/smart-cleanup.ts index 4b4da12..a1bf30d 100644 --- a/src/tools/system-operations/smart-cleanup.ts +++ b/src/tools/system-operations/smart-cleanup.ts @@ -2,10 +2,10 @@ import * as fs from "fs"; import * as path from "path"; import { promisify } from "util"; -const _stat = promisify(fs._stat); -const _readdir = promisify(fs._readdir); -const _unlink = promisify(fs._unlink); -const _rmdir = promisify(fs._rmdir); -const _mkdir = promisify(fs._mkdir); -const _rename = promisify(fs._rename); -const _access = promisify(fs._access); // ===========================// Types & Interfaces// ===========================export type CleanupOperation = 'analyze' | 'preview' | 'execute' | 'rollback' | 'estimate-savings';export interface SmartCleanupOptions { operation: CleanupOperation; paths?: string[]; patterns?: string[]; olderThanDays?: number; minSizeBytes?: number; maxSizeBytes?: number; dryRun?: boolean; useCache?: boolean; ttl?: number; backupBeforeDelete?: boolean; backupPath?: string; categories?: CleanupCategory[]; excludePatterns?: string[]; recursive?: boolean;}export type CleanupCategory = | 'temp-files' | 'cache-dirs' | 'old-logs' | 'build-artifacts' | 'node-modules' | 'package-lock' | 'coverage-reports' | 'dist-folders' | 'test-output' | 'backups' | 'thumbnails' | 'crash-dumps' | 'all';export interface FileCandidate { path: string; size: number; created: number; modified: number; accessed: number; category: CleanupCategory; reason: string; safeToDelete: boolean; estimatedTokens: number;}export interface CleanupAnalysis { totalFiles: number; totalSize: number; totalSizeHuman: string; candidateCount: number; candidateSize: number; candidateSizeHuman: string; byCategory: Record; largestFiles: FileCandidate[]; oldestFiles: FileCandidate[]; riskAssessment: { low: number; medium: number; high: number; };}export interface CleanupPreview { willDelete: FileCandidate[]; totalFilesToDelete: number; totalSpaceToRecover: number; totalSpaceToRecoverHuman: string; estimatedDuration: number; backupRequired: boolean; backupSize: number; warnings: string[];}export interface CleanupExecution { deletedFiles: string[]; deletedCount: number; freedSpace: number; freedSpaceHuman: string; duration: number; errors: Array<{ path: string; error: string; }>; backupLocation?: string; rollbackAvailable: boolean;}export interface CleanupRollback { restoredFiles: string[]; restoredCount: number; errors: Array<{ path: string; error: string; }>; success: boolean;}export interface DiskSpaceEstimate { currentUsed: number; currentFree: number; potentialRecovery: number; afterCleanup: { used: number; free: number; percentFree: number; }; recommendations: string[];}export interface SmartCleanupResult { success: boolean; operation: CleanupOperation; data: { analysis?: CleanupAnalysis; preview?: CleanupPreview; execution?: CleanupExecution; rollback?: CleanupRollback; estimate?: DiskSpaceEstimate; error?: string; }; metadata: { tokensUsed: number; tokensSaved: number; cacheHit: boolean; executionTime: number; };}// ===========================// Pattern Definitions// ===========================const CLEANUP_PATTERNS: Record = { 'temp-files': [ '**/*.tmp', '**/*.temp', '**/tmp/**', '**/temp/**', '**/.tmp/**', '**/~*', '**/*.bak', '**/*.swp', '**/*.swo', '**/.DS_Store', '**/Thumbs.db' ], 'cache-dirs': [ '**/.cache/**', '**/cache/**', '**/.jest-cache/**', '**/.eslintcache', '**/.stylelintcache', '**/.parcel-cache/**', '**/.turbo/**', '**/.next/cache/**' ], 'old-logs': [ '**/*.log', '**/*.log.*', '**/logs/**/*.log', '**/log/**/*.log', '**/*.log.gz', '**/*.log.zip' ], 'build-artifacts': [ '**/dist/**', '**/build/**', '**/out/**', '**/*.o', '**/*.obj', '**/*.exe', '**/*.dll', '**/*.so', '**/*.dylib' ], 'node-modules': [ '**/node_modules/**' ], 'package-lock': [ '**/package-lock.json', '**/yarn.lock', '**/pnpm-lock.yaml' ], 'coverage-reports': [ '**/coverage/**', '**/.nyc_output/**', '**/htmlcov/**' ], 'dist-folders': [ '**/dist/**', '**/build/**', '**/.next/**', '**/.nuxt/**', '**/.output/**' ], 'test-output': [ '**/test-results/**', '**/__snapshots__/**/*.snap', '**/playwright-report/**', '**/.playwright/**' ], 'backups': [ '**/*.backup', '**/*.bak', '**/*~', '**/*.old' ], 'thumbnails': [ '**/.thumbnails/**', '**/thumbs.db', '**/.DS_Store' ], 'crash-dumps': [ '**/*.dmp', '**/*.mdmp', '**/core', '**/core.*' ], 'all': []};// ===========================// SmartCleanup Class// ===========================export class SmartCleanup { private backupDir: string; private activeCleanupsMap: Map = new Map(); constructor( private cache: CacheEngine, private tokenCounter: TokenCounter, private metricsCollector: MetricsCollector ) { this.backupDir = path.join(process.cwd(), '.cleanup-backups'); } /** * Main entry point for cleanup operations */ async run(options: SmartCleanupOptions): Promise { const startTime = Date.now(); const operation = options.operation; let result: SmartCleanupResult; try { switch (operation) { case 'analyze': result = await this.analyze(options); break; case 'preview': result = await this.preview(options); break; case 'execute': result = await this.execute(options); break; case 'rollback': result = await this.rollback(options); break; case 'estimate-savings': result = await this.estimateSavings(options); break; default: throw new Error(`Unknown operation: ${operation}`); } // Record metrics this.metricsCollector.record({ operation: `smart-cleanup:${operation}`, duration: Date.now() - startTime, success: result.success, cacheHit: result.metadata.cacheHit, metadata: { paths: options.paths, categories: options.categories } }); return result; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); const errorResult: SmartCleanupResult = { success: false, operation, data: { error: errorMessage }, metadata: { tokensUsed: this.tokenCounter.count(errorMessage).tokens, tokensSaved: 0, cacheHit: false, executionTime: Date.now() - startTime } }; this.metricsCollector.record({ operation: `smart-cleanup:${operation}`, duration: Date.now() - startTime, success: false, cacheHit: false, metadata: { error: errorMessage, paths: options.paths } }); return errorResult; } } /** * Analyze filesystem for cleanup candidates */ private async analyze(options: SmartCleanupOptions): Promise { const paths = options.paths || [process.cwd()]; const cacheKey = generateCacheKey('cleanup-analysis', { paths, patterns: options.patterns, categories: options.categories, olderThanDays: options.olderThanDays }); const useCache = options.useCache !== false; // Check cache if (useCache) { const cached = await this.cache.get(cacheKey); if (cached) { const dataStr = cached; const tokensUsed = this.tokenCounter.count(dataStr).tokens; const baselineTokens = tokensUsed * 10; // Baseline without caching (filesystem scans are expensive) return { success: true, operation: 'analyze', data: JSON.parse(dataStr), metadata: { tokensUsed, tokensSaved: baselineTokens - tokensUsed, cacheHit: true, executionTime: 0 } }; } } // Perform analysis const categories = options.categories || ['all']; const candidates: FileCandidate[] = []; let totalFiles = 0; let totalSize = 0; for (const basePath of paths) { const pathCandidates = await this.scanPath(basePath, { categories, patterns: options.patterns, olderThanDays: options.olderThanDays, minSizeBytes: options.minSizeBytes, maxSizeBytes: options.maxSizeBytes, excludePatterns: options.excludePatterns, recursive: options.recursive !== false }); candidates.push(...pathCandidates.candidates); totalFiles += pathCandidates.totalFiles; totalSize += pathCandidates.totalSize; } // Build analysis const analysis = this.buildAnalysis(candidates, totalFiles, totalSize); const dataStr = JSON.stringify({ analysis }); const tokensUsed = this.tokenCounter.count(dataStr).tokens; // Cache the result (filesystem scans can be cached longer) if (useCache) { await this.cache.set(cacheKey, dataStr, options.ttl || 1800, 'utf-8'); } return { success: true, operation: 'analyze', data: { analysis }, metadata: { tokensUsed, tokensSaved: 0, cacheHit: false, executionTime: 0 } }; } /** * Preview cleanup operation */ private async preview(options: SmartCleanupOptions): Promise { // First, get analysis const analysisResult = await this.analyze(options); if (!analysisResult.success || !analysisResult.data.analysis) { return { success: false, operation: 'preview', data: { error: 'Failed to analyze files for preview' }, metadata: { tokensUsed: 100, tokensSaved: 0, cacheHit: false, executionTime: 0 } }; } const analysis = analysisResult.data.analysis; // Build preview const preview = this.buildPreview(analysis, options); // Compressed preview using incremental reporting const compressedPreview = this.compressPreview(preview); const dataStr = JSON.stringify({ preview: compressedPreview }); const tokensUsed = this.tokenCounter.count(dataStr).tokens; // Calculate baseline (full preview without compression) const fullPreviewStr = JSON.stringify({ preview }); const baselineTokens = this.tokenCounter.count(fullPreviewStr).tokens; return { success: true, operation: 'preview', data: { preview }, metadata: { tokensUsed, tokensSaved: baselineTokens - tokensUsed, cacheHit: false, executionTime: 0 } }; } /** * Execute cleanup operation */ private async execute(options: SmartCleanupOptions): Promise { if (options.dryRun) { return this.preview(options); } // Get preview first const previewResult = await this.preview(options); if (!previewResult.success || !previewResult.data.preview) { return { success: false, operation: 'execute', data: { error: 'Failed to generate preview for execution' }, metadata: { tokensUsed: 100, tokensSaved: 0, cacheHit: false, executionTime: 0 } }; } const preview = previewResult.data.preview; const startTime = Date.now(); // Create backup if requested let backupLocation: string | undefined; if (options.backupBeforeDelete !== false) { backupLocation = await this.createBackup(preview.willDelete, options.backupPath); } // Execute deletion const deletedFiles: string[] = []; const errors: Array<{ path: string; error: string }> = []; let freedSpace = 0; for (const candidate of preview.willDelete) { try { const stats = await stat(candidate.path); await unlink(candidate.path); deletedFiles.push(candidate.path); freedSpace += stats.size; } catch (error) { errors.push({ path: candidate.path, error: error instanceof Error ? error.message : String(error) }); } } const execution: CleanupExecution = { deletedFiles, deletedCount: deletedFiles.length, freedSpace, freedSpaceHuman: this.formatBytes(freedSpace), duration: Date.now() - startTime, errors, backupLocation, rollbackAvailable: !!backupLocation }; // Store execution info for potential rollback if (backupLocation) { this.activeCleanupsMap.set(backupLocation, preview.willDelete); } // Compressed execution report const compressedExecution = this.compressExecution(execution); const dataStr = JSON.stringify({ execution: compressedExecution }); const tokensUsed = this.tokenCounter.count(dataStr).tokens; // Calculate baseline const fullExecutionStr = JSON.stringify({ execution }); const baselineTokens = this.tokenCounter.count(fullExecutionStr).tokens; return { success: true, operation: 'execute', data: { execution }, metadata: { tokensUsed, tokensSaved: baselineTokens - tokensUsed, cacheHit: false, executionTime: Date.now() - startTime } }; } /** * Rollback cleanup operation */ private async rollback(options: SmartCleanupOptions): Promise { const backupLocation = options.backupPath; if (!backupLocation) { throw new Error('Backup location is required for rollback operation'); } const candidates = this.activeCleanupsMap.get(backupLocation); if (!candidates) { throw new Error('No active cleanup found for the specified backup location'); } const restoredFiles: string[] = []; const errors: Array<{ path: string; error: string }> = []; // Restore files from backup for (const candidate of candidates) { try { const backupPath = this.getBackupPath(candidate.path, backupLocation); const originalPath = candidate.path; // Ensure directory exists await mkdir(path.dirname(originalPath), { recursive: true }); // Restore file await rename(backupPath, originalPath); restoredFiles.push(originalPath); } catch (error) { errors.push({ path: candidate.path, error: error instanceof Error ? error.message : String(error) }); } } const rollback: CleanupRollback = { restoredFiles, restoredCount: restoredFiles.length, errors, success: errors.length === 0 }; // Remove from active cleanups this.activeCleanupsMap.delete(backupLocation); const dataStr = JSON.stringify({ rollback }); const tokensUsed = this.tokenCounter.count(dataStr).tokens; return { success: true, operation: 'rollback', data: { rollback }, metadata: { tokensUsed, tokensSaved: 0, cacheHit: false, executionTime: 0 } }; } /** * Estimate disk space savings */ private async estimateSavings(options: SmartCleanupOptions): Promise { // Get analysis const analysisResult = await this.analyze(options); if (!analysisResult.success || !analysisResult.data.analysis) { return { success: false, operation: 'estimate-savings', data: { error: 'Failed to analyze files for estimation' }, metadata: { tokensUsed: 100, tokensSaved: 0, cacheHit: false, executionTime: 0 } }; } const analysis = analysisResult.data.analysis; // Get disk space info (if paths provided) const _paths = options._paths || [process.cwd()]; let currentUsed = 0; let currentFree = 0; // This is a simplified estimation - in production, use system calls try { // Platform-specific disk space check would go here // For now, use analysis data currentUsed = analysis.totalSize; currentFree = 0; // Would get from system } catch (error) { // Fallback to analysis-only estimation } const potentialRecovery = analysis.candidateSize; const estimate: DiskSpaceEstimate = { currentUsed, currentFree, potentialRecovery, afterCleanup: { used: currentUsed - potentialRecovery, free: currentFree + potentialRecovery, percentFree: currentUsed > 0 ? ((currentFree + potentialRecovery) / (currentUsed + currentFree)) * 100 : 0 }, recommendations: this.generateRecommendations(analysis) }; const dataStr = JSON.stringify({ estimate }); const tokensUsed = this.tokenCounter.count(dataStr).tokens; return { success: true, operation: 'estimate-savings', data: { estimate }, metadata: { tokensUsed, tokensSaved: 0, cacheHit: false, executionTime: 0 } }; } /** * Scan a path for cleanup candidates */ private async scanPath( basePath: string, options: { categories: CleanupCategory[]; patterns?: string[]; olderThanDays?: number; minSizeBytes?: number; maxSizeBytes?: number; excludePatterns?: string[]; recursive: boolean; } ): Promise<{ candidates: FileCandidate[]; totalFiles: number; totalSize: number }> { const candidates: FileCandidate[] = []; let totalFiles = 0; let totalSize = 0; const scan = async (dirPath: string, depth: number = 0): Promise => { try { const entries = await readdir(dirPath, { withFileTypes: true }); for (const entry of entries) { const fullPath = path.join(dirPath, entry.name); // Check exclusions if (this.matchesPatterns(fullPath, options.excludePatterns || [])) { continue; } if (entry.isDirectory()) { if (options.recursive && depth < 10) { // Limit recursion depth await scan(fullPath, depth + 1); } } else if (entry.isFile()) { totalFiles++; try { const stats = await stat(fullPath); totalSize += stats.size; // Check if file matches cleanup criteria const candidate = await this.evaluateFile(fullPath, stats, options); if (candidate) { candidates.push(candidate); } } catch (error) { // Skip files we can't access } } } } catch (error) { // Skip directories we can't access } }; await scan(basePath); return { candidates, totalFiles, totalSize }; } /** * Evaluate if a file should be cleaned up */ private async evaluateFile( filePath: string, stats: fs.Stats, options: { categories: CleanupCategory[]; patterns?: string[]; olderThanDays?: number; minSizeBytes?: number; maxSizeBytes?: number; } ): Promise { // Check size constraints if (options.minSizeBytes && stats.size < options.minSizeBytes) { return null; } if (options.maxSizeBytes && stats.size > options.maxSizeBytes) { return null; } // Check age constraint if (options.olderThanDays) { const ageMs = Date.now() - stats.mtime.getTime(); const ageDays = ageMs / (1000 * 60 * 60 * 24); if (ageDays < options.olderThanDays) { return null; } } // Check if file matches any cleanup category const category = this.categorizeFile(filePath, options.categories, options.patterns); if (!category) { return null; } // Assess safety const safeToDelete = this.isSafeToDelete(filePath, category); const reason = this.getCleanupReason(filePath, category, stats); return { path: filePath, size: stats.size, created: stats.birthtime.getTime(), modified: stats.mtime.getTime(), accessed: stats.atime.getTime(), category, reason, safeToDelete, estimatedTokens: Math.ceil(stats.size / 4) // Rough token estimate }; } /** * Categorize a file for cleanup */ private categorizeFile( filePath: string, categories: CleanupCategory[], customPatterns?: string[] ): CleanupCategory | null { // Check custom patterns first if (customPatterns && customPatterns.length > 0) { if (this.matchesPatterns(filePath, customPatterns)) { return 'all'; } } // Check each category for (const category of categories) { if (category === 'all') { // 'all' means check all patterns for (const [cat, patterns] of Object.entries(CLEANUP_PATTERNS)) { if (cat !== 'all' && this.matchesPatterns(filePath, patterns)) { return cat as CleanupCategory; } } } else { const patterns = CLEANUP_PATTERNS[category]; if (this.matchesPatterns(filePath, patterns)) { return category; } } } return null; } /** * Check if path matches any pattern */ private matchesPatterns(filePath: string, patterns: string[]): boolean { const normalizedPath = filePath.replace(/\\/g, '/'); for (const pattern of patterns) { const normalizedPattern = pattern.replace(/\\/g, '/'); // Simple glob matching (for basic patterns) if (normalizedPattern.includes('**')) { const regex = new RegExp( normalizedPattern .replace(/\*\*/g, '.*') .replace(/\*/g, '[^/]*') .replace(/\?/g, '.') ); if (regex.test(normalizedPath)) { return true; } } else if (normalizedPattern.includes('*')) { const regex = new RegExp( normalizedPattern .replace(/\*/g, '[^/]*') .replace(/\?/g, '.') ); if (regex.test(normalizedPath)) { return true; } } else { if (normalizedPath.includes(normalizedPattern)) { return true; } } } return false; } /** * Check if file is safe to delete */ private isSafeToDelete(filePath: string, category: CleanupCategory): boolean { const normalizedPath = filePath.replace(/\\/g, '/').toLowerCase(); // Never delete these const neverDelete = [ '.git', '.env', 'package.json', 'tsconfig.json', 'webpack.config', 'vite.config', 'next.config' ]; for (const pattern of neverDelete) { if (normalizedPath.includes(pattern)) { return false; } } // Category-specific safety checks switch (category) { case 'node-modules': case 'package-lock': return false; // These should be regenerated, but user should confirm case 'temp-files': case 'cache-dirs': case 'old-logs': return true; case 'build-artifacts': case 'dist-folders': case 'coverage-reports': case 'test-output': return true; // Can be regenerated default: return true; } } /** * Get reason for cleanup */ private getCleanupReason(_filePath: string, category: CleanupCategory, stats: fs.Stats): string { const ageMs = Date.now() - stats.mtime.getTime(); const ageDays = Math.floor(ageMs / (1000 * 60 * 60 * 24)); const sizeStr = this.formatBytes(stats.size); switch (category) { case 'temp-files': return `Temporary file (${sizeStr}, ${ageDays} days old)`; case 'cache-dirs': return `Cache directory (${sizeStr}, can be regenerated)`; case 'old-logs': return `Old log file (${sizeStr}, ${ageDays} days old)`; case 'build-artifacts': return `Build artifact (${sizeStr}, can be rebuilt)`; case 'node-modules': return `Node modules (${sizeStr}, can be reinstalled)`; case 'coverage-reports': return `Coverage report (${sizeStr}, can be regenerated)`; case 'dist-folders': return `Distribution folder (${sizeStr}, can be rebuilt)`; case 'test-output': return `Test output (${sizeStr}, can be regenerated)`; default: return `Cleanup candidate (${sizeStr})`; } } /** * Build analysis from candidates */ private buildAnalysis( candidates: FileCandidate[], totalFiles: number, totalSize: number ): CleanupAnalysis { const byCategory: Record = {} as any; // Initialize categories for (const category of Object.keys(CLEANUP_PATTERNS) as CleanupCategory[]) { byCategory[category] = { count: 0, size: 0, sizeHuman: '0 B' }; } // Group by category for (const candidate of candidates) { const cat = byCategory[candidate.category]; cat.count++; cat.size += candidate.size; cat.sizeHuman = this.formatBytes(cat.size); } // Sort for top files const sortedBySize = [...candidates].sort((a, b) => b.size - a.size); const sortedByAge = [...candidates].sort((a, b) => a.modified - b.modified); // Risk assessment const riskAssessment = { low: candidates.filter(c => c.safeToDelete).length, medium: candidates.filter(c => !c.safeToDelete && c.category !== 'node-modules').length, high: candidates.filter(c => !c.safeToDelete && c.category === 'node-modules').length }; const candidateSize = candidates.reduce((sum, c) => sum + c.size, 0); return { totalFiles, totalSize, totalSizeHuman: this.formatBytes(totalSize), candidateCount: candidates.length, candidateSize, candidateSizeHuman: this.formatBytes(candidateSize), byCategory, largestFiles: sortedBySize.slice(0, 10), oldestFiles: sortedByAge.slice(0, 10), riskAssessment }; } /** * Build preview from analysis */ private buildPreview(analysis: CleanupAnalysis, options: SmartCleanupOptions): CleanupPreview { const willDelete = [ ...analysis.largestFiles.filter(f => f.safeToDelete), ...analysis.oldestFiles.filter(f => f.safeToDelete) ]; // Remove duplicates const uniqueDelete = Array.from(new Map(willDelete.map(f => [f.path, f])).values()); const totalSpaceToRecover = uniqueDelete.reduce((sum, f) => sum + f.size, 0); const estimatedDuration = uniqueDelete.length * 10; // ~10ms per file const warnings: string[] = []; if (analysis.riskAssessment.high > 0) { warnings.push(`${analysis.riskAssessment.high} high-risk files detected (e.g., node_modules)`); } if (totalSpaceToRecover > 10 * 1024 * 1024 * 1024) { // > 10GB warnings.push('Large cleanup operation (>10GB) - consider backing up first'); } return { willDelete: uniqueDelete, totalFilesToDelete: uniqueDelete.length, totalSpaceToRecover, totalSpaceToRecoverHuman: this.formatBytes(totalSpaceToRecover), estimatedDuration, backupRequired: options.backupBeforeDelete !== false, backupSize: totalSpaceToRecover, warnings }; } /** * Compress preview for token reduction */ private compressPreview(preview: CleanupPreview): any { return { files: preview.totalFilesToDelete, space: preview.totalSpaceToRecoverHuman, duration: `~${Math.ceil(preview.estimatedDuration / 1000)}s`, backup: preview.backupRequired, warnings: preview.warnings.length > 0 ? preview.warnings : undefined, // Only include top 5 files instead of all top5: preview.willDelete.slice(0, 5).map(f => ({ p: f.path.split('/').pop(), s: this.formatBytes(f.size), c: f.category })) }; } /** * Compress execution for token reduction */ private compressExecution(execution: CleanupExecution): any { return { deleted: execution.deletedCount, freed: execution.freedSpaceHuman, duration: `${Math.ceil(execution.duration / 1000)}s`, errors: execution.errors.length, rollback: execution.rollbackAvailable, // Only include first 3 errors errorSample: execution.errors.slice(0, 3).map(e => e.path.split('/').pop()) }; } /** * Create backup before deletion */ private async createBackup(files: FileCandidate[], customBackupPath?: string): Promise { const timestamp = Date.now(); const backupLocation = customBackupPath || path.join(this.backupDir, `cleanup-${timestamp}`); await mkdir(backupLocation, { recursive: true }); for (const file of files) { const backupPath = this.getBackupPath(file.path, backupLocation); try { // Ensure backup directory exists await mkdir(path.dirname(backupPath), { recursive: true }); // Copy file to backup (using rename for efficiency, but could use copyFile for safety) await fs.promises.copyFile(file.path, backupPath); } catch (error) { // Skip files that can't be backed up } } return backupLocation; } /** * Get backup path for a file */ private getBackupPath(originalPath: string, backupLocation: string): string { const hash = createHash('md5').update(originalPath).digest('hex').substring(0, 8); const basename = path.basename(originalPath); return path.join(backupLocation, `${hash}-${basename}`); } /** * Generate recommendations */ private generateRecommendations(analysis: CleanupAnalysis): string[] { const recommendations: string[] = []; // Check node_modules if (analysis.byCategory['node-modules']?.size > 1024 * 1024 * 1024) { // > 1GB recommendations.push('Large node_modules detected - consider using pnpm or yarn PnP'); } // Check cache dirs if (analysis.byCategory['cache-dirs']?.size > 500 * 1024 * 1024) { // > 500MB recommendations.push('Large cache directories - configure cache size limits'); } // Check logs if (analysis.byCategory['old-logs']?.size > 100 * 1024 * 1024) { // > 100MB recommendations.push('Large log files - implement log rotation'); } // Check build artifacts if (analysis.byCategory['build-artifacts']?.count > 100) { recommendations.push('Many build artifacts - consider automated cleanup in CI/CD'); } return recommendations; } /** * Format bytes to human readable */ private formatBytes(bytes: number): string { if (bytes === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB', 'TB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`; }}// ===========================// Factory Function// ===========================export function getSmartCleanup( cache: CacheEngine, tokenCounter: TokenCounter, metricsCollector: MetricsCollector): SmartCleanup { return new SmartCleanup(cache, tokenCounter, metricsCollector);}// ===========================// Standalone Runner Function (CLI)// ===========================export async function runSmartCleanup( options: SmartCleanupOptions, cache?: CacheEngine, tokenCounter?: TokenCounter, metricsCollector?: MetricsCollector): Promise { const { homedir } = await import('os'); const { join } = await import('path'); const cacheInstance = cache || new CacheEngine(100, join(homedir(), '.hypercontext', 'cache')); const tokenCounterInstance = tokenCounter || new TokenCounter(); const metricsInstance = metricsCollector || new MetricsCollector(); const tool = getSmartCleanup(cacheInstance, tokenCounterInstance, metricsInstance); return await tool.run(options);}// ===========================// MCP Tool Definition// ===========================export const SMART_CLEANUP_TOOL_DEFINITION = { name: 'smart_cleanup', description: 'Intelligent system cleanup with smart caching (87%+ token reduction). Analyze, preview, and execute safe file cleanup operations with automatic backup and rollback support. Includes temp files, cache dirs, old logs, and build artifacts detection.', inputSchema: { type: 'object' as const, properties: { operation: { type: 'string' as const, enum: ['analyze', 'preview', 'execute', 'rollback', 'estimate-savings'], description: 'Cleanup operation to perform' }, paths: { type: 'array' as const, items: { type: 'string' as const }, description: 'Paths to analyze for cleanup (default: current directory)' }, patterns: { type: 'array' as const, items: { type: 'string' as const }, description: 'Custom glob patterns for file matching' }, categories: { type: 'array' as const, items: { type: 'string' as const, enum: [ 'temp-files', 'cache-dirs', 'old-logs', 'build-artifacts', 'node-modules', 'package-lock', 'coverage-reports', 'dist-folders', 'test-output', 'backups', 'thumbnails', 'crash-dumps', 'all' ] }, description: 'Cleanup categories to target (default: all)' }, olderThanDays: { type: 'number' as const, description: 'Only clean files older than this many days' }, minSizeBytes: { type: 'number' as const, description: 'Minimum file size in bytes' }, maxSizeBytes: { type: 'number' as const, description: 'Maximum file size in bytes' }, excludePatterns: { type: 'array' as const, items: { type: 'string' as const }, description: 'Patterns to exclude from cleanup' }, recursive: { type: 'boolean' as const, description: 'Scan directories recursively (default: true)', default: true }, dryRun: { type: 'boolean' as const, description: 'Preview changes without executing (default: false)', default: false }, backupBeforeDelete: { type: 'boolean' as const, description: 'Create backup before deletion for rollback (default: true)', default: true }, backupPath: { type: 'string' as const, description: 'Custom backup location (for execute and rollback operations)' }, useCache: { type: 'boolean' as const, description: 'Use cached results when available (default: true)', default: true }, ttl: { type: 'number' as const, description: 'Cache TTL in seconds (default: 1800 for analysis)' } }, required: ['operation'] }}; +const stat = promisify(fs.stat); +const readdir = promisify(fs.readdir); +const unlink = promisify(fs.unlink); +const rmdir = promisify(fs.rmdir); +const mkdir = promisify(fs.mkdir); +const rename = promisify(fs.rename); +const access = promisify(fs.access); // ===========================// Types & Interfaces// ===========================export type CleanupOperation = 'analyze' | 'preview' | 'execute' | 'rollback' | 'estimate-savings';export interface SmartCleanupOptions { operation: CleanupOperation; paths?: string[]; patterns?: string[]; olderThanDays?: number; minSizeBytes?: number; maxSizeBytes?: number; dryRun?: boolean; useCache?: boolean; ttl?: number; backupBeforeDelete?: boolean; backupPath?: string; categories?: CleanupCategory[]; excludePatterns?: string[]; recursive?: boolean;}export type CleanupCategory = | 'temp-files' | 'cache-dirs' | 'old-logs' | 'build-artifacts' | 'node-modules' | 'package-lock' | 'coverage-reports' | 'dist-folders' | 'test-output' | 'backups' | 'thumbnails' | 'crash-dumps' | 'all';export interface FileCandidate { path: string; size: number; created: number; modified: number; accessed: number; category: CleanupCategory; reason: string; safeToDelete: boolean; estimatedTokens: number;}export interface CleanupAnalysis { totalFiles: number; totalSize: number; totalSizeHuman: string; candidateCount: number; candidateSize: number; candidateSizeHuman: string; byCategory: Record; largestFiles: FileCandidate[]; oldestFiles: FileCandidate[]; riskAssessment: { low: number; medium: number; high: number; };}export interface CleanupPreview { willDelete: FileCandidate[]; totalFilesToDelete: number; totalSpaceToRecover: number; totalSpaceToRecoverHuman: string; estimatedDuration: number; backupRequired: boolean; backupSize: number; warnings: string[];}export interface CleanupExecution { deletedFiles: string[]; deletedCount: number; freedSpace: number; freedSpaceHuman: string; duration: number; errors: Array<{ path: string; error: string; }>; backupLocation?: string; rollbackAvailable: boolean;}export interface CleanupRollback { restoredFiles: string[]; restoredCount: number; errors: Array<{ path: string; error: string; }>; success: boolean;}export interface DiskSpaceEstimate { currentUsed: number; currentFree: number; potentialRecovery: number; afterCleanup: { used: number; free: number; percentFree: number; }; recommendations: string[];}export interface SmartCleanupResult { success: boolean; operation: CleanupOperation; data: { analysis?: CleanupAnalysis; preview?: CleanupPreview; execution?: CleanupExecution; rollback?: CleanupRollback; estimate?: DiskSpaceEstimate; error?: string; }; metadata: { tokensUsed: number; tokensSaved: number; cacheHit: boolean; executionTime: number; };}// ===========================// Pattern Definitions// ===========================const CLEANUP_PATTERNS: Record = { 'temp-files': [ '**/*.tmp', '**/*.temp', '**/tmp/**', '**/temp/**', '**/.tmp/**', '**/~*', '**/*.bak', '**/*.swp', '**/*.swo', '**/.DS_Store', '**/Thumbs.db' ], 'cache-dirs': [ '**/.cache/**', '**/cache/**', '**/.jest-cache/**', '**/.eslintcache', '**/.stylelintcache', '**/.parcel-cache/**', '**/.turbo/**', '**/.next/cache/**' ], 'old-logs': [ '**/*.log', '**/*.log.*', '**/logs/**/*.log', '**/log/**/*.log', '**/*.log.gz', '**/*.log.zip' ], 'build-artifacts': [ '**/dist/**', '**/build/**', '**/out/**', '**/*.o', '**/*.obj', '**/*.exe', '**/*.dll', '**/*.so', '**/*.dylib' ], 'node-modules': [ '**/node_modules/**' ], 'package-lock': [ '**/package-lock.json', '**/yarn.lock', '**/pnpm-lock.yaml' ], 'coverage-reports': [ '**/coverage/**', '**/.nyc_output/**', '**/htmlcov/**' ], 'dist-folders': [ '**/dist/**', '**/build/**', '**/.next/**', '**/.nuxt/**', '**/.output/**' ], 'test-output': [ '**/test-results/**', '**/__snapshots__/**/*.snap', '**/playwright-report/**', '**/.playwright/**' ], 'backups': [ '**/*.backup', '**/*.bak', '**/*~', '**/*.old' ], 'thumbnails': [ '**/.thumbnails/**', '**/thumbs.db', '**/.DS_Store' ], 'crash-dumps': [ '**/*.dmp', '**/*.mdmp', '**/core', '**/core.*' ], 'all': []};// ===========================// SmartCleanup Class// ===========================export class SmartCleanup { private backupDir: string; private activeCleanupsMap: Map = new Map(); constructor( private cache: CacheEngine, private tokenCounter: TokenCounter, private metricsCollector: MetricsCollector ) { this.backupDir = path.join(process.cwd(), '.cleanup-backups'); } /** * Main entry point for cleanup operations */ async run(options: SmartCleanupOptions): Promise { const startTime = Date.now(); const operation = options.operation; let result: SmartCleanupResult; try { switch (operation) { case 'analyze': result = await this.analyze(options); break; case 'preview': result = await this.preview(options); break; case 'execute': result = await this.execute(options); break; case 'rollback': result = await this.rollback(options); break; case 'estimate-savings': result = await this.estimateSavings(options); break; default: throw new Error(`Unknown operation: ${operation}`); } // Record metrics this.metricsCollector.record({ operation: `smart-cleanup:${operation}`, duration: Date.now() - startTime, success: result.success, cacheHit: result.metadata.cacheHit, metadata: { paths: options.paths, categories: options.categories } }); return result; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); const errorResult: SmartCleanupResult = { success: false, operation, data: { error: errorMessage }, metadata: { tokensUsed: this.tokenCounter.count(errorMessage).tokens, tokensSaved: 0, cacheHit: false, executionTime: Date.now() - startTime } }; this.metricsCollector.record({ operation: `smart-cleanup:${operation}`, duration: Date.now() - startTime, success: false, cacheHit: false, metadata: { error: errorMessage, paths: options.paths } }); return errorResult; } } /** * Analyze filesystem for cleanup candidates */ private async analyze(options: SmartCleanupOptions): Promise { const paths = options.paths || [process.cwd()]; const cacheKey = generateCacheKey('cleanup-analysis', { paths, patterns: options.patterns, categories: options.categories, olderThanDays: options.olderThanDays }); const useCache = options.useCache !== false; // Check cache if (useCache) { const cached = await this.cache.get(cacheKey); if (cached) { const dataStr = cached; const tokensUsed = this.tokenCounter.count(dataStr).tokens; const baselineTokens = tokensUsed * 10; // Baseline without caching (filesystem scans are expensive) return { success: true, operation: 'analyze', data: JSON.parse(dataStr), metadata: { tokensUsed, tokensSaved: baselineTokens - tokensUsed, cacheHit: true, executionTime: 0 } }; } } // Perform analysis const categories = options.categories || ['all']; const candidates: FileCandidate[] = []; let totalFiles = 0; let totalSize = 0; for (const basePath of paths) { const pathCandidates = await this.scanPath(basePath, { categories, patterns: options.patterns, olderThanDays: options.olderThanDays, minSizeBytes: options.minSizeBytes, maxSizeBytes: options.maxSizeBytes, excludePatterns: options.excludePatterns, recursive: options.recursive !== false }); candidates.push(...pathCandidates.candidates); totalFiles += pathCandidates.totalFiles; totalSize += pathCandidates.totalSize; } // Build analysis const analysis = this.buildAnalysis(candidates, totalFiles, totalSize); const dataStr = JSON.stringify({ analysis }); const tokensUsed = this.tokenCounter.count(dataStr).tokens; // Cache the result (filesystem scans can be cached longer) if (useCache) { await this.cache.set(cacheKey, dataStr, options.ttl || 1800, 'utf-8'); } return { success: true, operation: 'analyze', data: { analysis }, metadata: { tokensUsed, tokensSaved: 0, cacheHit: false, executionTime: 0 } }; } /** * Preview cleanup operation */ private async preview(options: SmartCleanupOptions): Promise { // First, get analysis const analysisResult = await this.analyze(options); if (!analysisResult.success || !analysisResult.data.analysis) { return { success: false, operation: 'preview', data: { error: 'Failed to analyze files for preview' }, metadata: { tokensUsed: 100, tokensSaved: 0, cacheHit: false, executionTime: 0 } }; } const analysis = analysisResult.data.analysis; // Build preview const preview = this.buildPreview(analysis, options); // Compressed preview using incremental reporting const compressedPreview = this.compressPreview(preview); const dataStr = JSON.stringify({ preview: compressedPreview }); const tokensUsed = this.tokenCounter.count(dataStr).tokens; // Calculate baseline (full preview without compression) const fullPreviewStr = JSON.stringify({ preview }); const baselineTokens = this.tokenCounter.count(fullPreviewStr).tokens; return { success: true, operation: 'preview', data: { preview }, metadata: { tokensUsed, tokensSaved: baselineTokens - tokensUsed, cacheHit: false, executionTime: 0 } }; } /** * Execute cleanup operation */ private async execute(options: SmartCleanupOptions): Promise { if (options.dryRun) { return this.preview(options); } // Get preview first const previewResult = await this.preview(options); if (!previewResult.success || !previewResult.data.preview) { return { success: false, operation: 'execute', data: { error: 'Failed to generate preview for execution' }, metadata: { tokensUsed: 100, tokensSaved: 0, cacheHit: false, executionTime: 0 } }; } const preview = previewResult.data.preview; const startTime = Date.now(); // Create backup if requested let backupLocation: string | undefined; if (options.backupBeforeDelete !== false) { backupLocation = await this.createBackup(preview.willDelete, options.backupPath); } // Execute deletion const deletedFiles: string[] = []; const errors: Array<{ path: string; error: string }> = []; let freedSpace = 0; for (const candidate of preview.willDelete) { try { const stats = await stat(candidate.path); await unlink(candidate.path); deletedFiles.push(candidate.path); freedSpace += stats.size; } catch (error) { errors.push({ path: candidate.path, error: error instanceof Error ? error.message : String(error) }); } } const execution: CleanupExecution = { deletedFiles, deletedCount: deletedFiles.length, freedSpace, freedSpaceHuman: this.formatBytes(freedSpace), duration: Date.now() - startTime, errors, backupLocation, rollbackAvailable: !!backupLocation }; // Store execution info for potential rollback if (backupLocation) { this.activeCleanupsMap.set(backupLocation, preview.willDelete); } // Compressed execution report const compressedExecution = this.compressExecution(execution); const dataStr = JSON.stringify({ execution: compressedExecution }); const tokensUsed = this.tokenCounter.count(dataStr).tokens; // Calculate baseline const fullExecutionStr = JSON.stringify({ execution }); const baselineTokens = this.tokenCounter.count(fullExecutionStr).tokens; return { success: true, operation: 'execute', data: { execution }, metadata: { tokensUsed, tokensSaved: baselineTokens - tokensUsed, cacheHit: false, executionTime: Date.now() - startTime } }; } /** * Rollback cleanup operation */ private async rollback(options: SmartCleanupOptions): Promise { const backupLocation = options.backupPath; if (!backupLocation) { throw new Error('Backup location is required for rollback operation'); } const candidates = this.activeCleanupsMap.get(backupLocation); if (!candidates) { throw new Error('No active cleanup found for the specified backup location'); } const restoredFiles: string[] = []; const errors: Array<{ path: string; error: string }> = []; // Restore files from backup for (const candidate of candidates) { try { const backupPath = this.getBackupPath(candidate.path, backupLocation); const originalPath = candidate.path; // Ensure directory exists await mkdir(path.dirname(originalPath), { recursive: true }); // Restore file await rename(backupPath, originalPath); restoredFiles.push(originalPath); } catch (error) { errors.push({ path: candidate.path, error: error instanceof Error ? error.message : String(error) }); } } const rollback: CleanupRollback = { restoredFiles, restoredCount: restoredFiles.length, errors, success: errors.length === 0 }; // Remove from active cleanups this.activeCleanupsMap.delete(backupLocation); const dataStr = JSON.stringify({ rollback }); const tokensUsed = this.tokenCounter.count(dataStr).tokens; return { success: true, operation: 'rollback', data: { rollback }, metadata: { tokensUsed, tokensSaved: 0, cacheHit: false, executionTime: 0 } }; } /** * Estimate disk space savings */ private async estimateSavings(options: SmartCleanupOptions): Promise { // Get analysis const analysisResult = await this.analyze(options); if (!analysisResult.success || !analysisResult.data.analysis) { return { success: false, operation: 'estimate-savings', data: { error: 'Failed to analyze files for estimation' }, metadata: { tokensUsed: 100, tokensSaved: 0, cacheHit: false, executionTime: 0 } }; } const analysis = analysisResult.data.analysis; // Get disk space info (if paths provided) const _paths = options._paths || [process.cwd()]; let currentUsed = 0; let currentFree = 0; // This is a simplified estimation - in production, use system calls try { // Platform-specific disk space check would go here // For now, use analysis data currentUsed = analysis.totalSize; currentFree = 0; // Would get from system } catch (error) { // Fallback to analysis-only estimation } const potentialRecovery = analysis.candidateSize; const estimate: DiskSpaceEstimate = { currentUsed, currentFree, potentialRecovery, afterCleanup: { used: currentUsed - potentialRecovery, free: currentFree + potentialRecovery, percentFree: currentUsed > 0 ? ((currentFree + potentialRecovery) / (currentUsed + currentFree)) * 100 : 0 }, recommendations: this.generateRecommendations(analysis) }; const dataStr = JSON.stringify({ estimate }); const tokensUsed = this.tokenCounter.count(dataStr).tokens; return { success: true, operation: 'estimate-savings', data: { estimate }, metadata: { tokensUsed, tokensSaved: 0, cacheHit: false, executionTime: 0 } }; } /** * Scan a path for cleanup candidates */ private async scanPath( basePath: string, options: { categories: CleanupCategory[]; patterns?: string[]; olderThanDays?: number; minSizeBytes?: number; maxSizeBytes?: number; excludePatterns?: string[]; recursive: boolean; } ): Promise<{ candidates: FileCandidate[]; totalFiles: number; totalSize: number }> { const candidates: FileCandidate[] = []; let totalFiles = 0; let totalSize = 0; const scan = async (dirPath: string, depth: number = 0): Promise => { try { const entries = await readdir(dirPath, { withFileTypes: true }); for (const entry of entries) { const fullPath = path.join(dirPath, entry.name); // Check exclusions if (this.matchesPatterns(fullPath, options.excludePatterns || [])) { continue; } if (entry.isDirectory()) { if (options.recursive && depth < 10) { // Limit recursion depth await scan(fullPath, depth + 1); } } else if (entry.isFile()) { totalFiles++; try { const stats = await stat(fullPath); totalSize += stats.size; // Check if file matches cleanup criteria const candidate = await this.evaluateFile(fullPath, stats, options); if (candidate) { candidates.push(candidate); } } catch (error) { // Skip files we can't access } } } } catch (error) { // Skip directories we can't access } }; await scan(basePath); return { candidates, totalFiles, totalSize }; } /** * Evaluate if a file should be cleaned up */ private async evaluateFile( filePath: string, stats: fs.Stats, options: { categories: CleanupCategory[]; patterns?: string[]; olderThanDays?: number; minSizeBytes?: number; maxSizeBytes?: number; } ): Promise { // Check size constraints if (options.minSizeBytes && stats.size < options.minSizeBytes) { return null; } if (options.maxSizeBytes && stats.size > options.maxSizeBytes) { return null; } // Check age constraint if (options.olderThanDays) { const ageMs = Date.now() - stats.mtime.getTime(); const ageDays = ageMs / (1000 * 60 * 60 * 24); if (ageDays < options.olderThanDays) { return null; } } // Check if file matches any cleanup category const category = this.categorizeFile(filePath, options.categories, options.patterns); if (!category) { return null; } // Assess safety const safeToDelete = this.isSafeToDelete(filePath, category); const reason = this.getCleanupReason(filePath, category, stats); return { path: filePath, size: stats.size, created: stats.birthtime.getTime(), modified: stats.mtime.getTime(), accessed: stats.atime.getTime(), category, reason, safeToDelete, estimatedTokens: Math.ceil(stats.size / 4) // Rough token estimate }; } /** * Categorize a file for cleanup */ private categorizeFile( filePath: string, categories: CleanupCategory[], customPatterns?: string[] ): CleanupCategory | null { // Check custom patterns first if (customPatterns && customPatterns.length > 0) { if (this.matchesPatterns(filePath, customPatterns)) { return 'all'; } } // Check each category for (const category of categories) { if (category === 'all') { // 'all' means check all patterns for (const [cat, patterns] of Object.entries(CLEANUP_PATTERNS)) { if (cat !== 'all' && this.matchesPatterns(filePath, patterns)) { return cat as CleanupCategory; } } } else { const patterns = CLEANUP_PATTERNS[category]; if (this.matchesPatterns(filePath, patterns)) { return category; } } } return null; } /** * Check if path matches any pattern */ private matchesPatterns(filePath: string, patterns: string[]): boolean { const normalizedPath = filePath.replace(/\\/g, '/'); for (const pattern of patterns) { const normalizedPattern = pattern.replace(/\\/g, '/'); // Simple glob matching (for basic patterns) if (normalizedPattern.includes('**')) { const regex = new RegExp( normalizedPattern .replace(/\*\*/g, '.*') .replace(/\*/g, '[^/]*') .replace(/\?/g, '.') ); if (regex.test(normalizedPath)) { return true; } } else if (normalizedPattern.includes('*')) { const regex = new RegExp( normalizedPattern .replace(/\*/g, '[^/]*') .replace(/\?/g, '.') ); if (regex.test(normalizedPath)) { return true; } } else { if (normalizedPath.includes(normalizedPattern)) { return true; } } } return false; } /** * Check if file is safe to delete */ private isSafeToDelete(filePath: string, category: CleanupCategory): boolean { const normalizedPath = filePath.replace(/\\/g, '/').toLowerCase(); // Never delete these const neverDelete = [ '.git', '.env', 'package.json', 'tsconfig.json', 'webpack.config', 'vite.config', 'next.config' ]; for (const pattern of neverDelete) { if (normalizedPath.includes(pattern)) { return false; } } // Category-specific safety checks switch (category) { case 'node-modules': case 'package-lock': return false; // These should be regenerated, but user should confirm case 'temp-files': case 'cache-dirs': case 'old-logs': return true; case 'build-artifacts': case 'dist-folders': case 'coverage-reports': case 'test-output': return true; // Can be regenerated default: return true; } } /** * Get reason for cleanup */ private getCleanupReason(_filePath: string, category: CleanupCategory, stats: fs.Stats): string { const ageMs = Date.now() - stats.mtime.getTime(); const ageDays = Math.floor(ageMs / (1000 * 60 * 60 * 24)); const sizeStr = this.formatBytes(stats.size); switch (category) { case 'temp-files': return `Temporary file (${sizeStr}, ${ageDays} days old)`; case 'cache-dirs': return `Cache directory (${sizeStr}, can be regenerated)`; case 'old-logs': return `Old log file (${sizeStr}, ${ageDays} days old)`; case 'build-artifacts': return `Build artifact (${sizeStr}, can be rebuilt)`; case 'node-modules': return `Node modules (${sizeStr}, can be reinstalled)`; case 'coverage-reports': return `Coverage report (${sizeStr}, can be regenerated)`; case 'dist-folders': return `Distribution folder (${sizeStr}, can be rebuilt)`; case 'test-output': return `Test output (${sizeStr}, can be regenerated)`; default: return `Cleanup candidate (${sizeStr})`; } } /** * Build analysis from candidates */ private buildAnalysis( candidates: FileCandidate[], totalFiles: number, totalSize: number ): CleanupAnalysis { const byCategory: Record = {} as any; // Initialize categories for (const category of Object.keys(CLEANUP_PATTERNS) as CleanupCategory[]) { byCategory[category] = { count: 0, size: 0, sizeHuman: '0 B' }; } // Group by category for (const candidate of candidates) { const cat = byCategory[candidate.category]; cat.count++; cat.size += candidate.size; cat.sizeHuman = this.formatBytes(cat.size); } // Sort for top files const sortedBySize = [...candidates].sort((a, b) => b.size - a.size); const sortedByAge = [...candidates].sort((a, b) => a.modified - b.modified); // Risk assessment const riskAssessment = { low: candidates.filter(c => c.safeToDelete).length, medium: candidates.filter(c => !c.safeToDelete && c.category !== 'node-modules').length, high: candidates.filter(c => !c.safeToDelete && c.category === 'node-modules').length }; const candidateSize = candidates.reduce((sum, c) => sum + c.size, 0); return { totalFiles, totalSize, totalSizeHuman: this.formatBytes(totalSize), candidateCount: candidates.length, candidateSize, candidateSizeHuman: this.formatBytes(candidateSize), byCategory, largestFiles: sortedBySize.slice(0, 10), oldestFiles: sortedByAge.slice(0, 10), riskAssessment }; } /** * Build preview from analysis */ private buildPreview(analysis: CleanupAnalysis, options: SmartCleanupOptions): CleanupPreview { const willDelete = [ ...analysis.largestFiles.filter(f => f.safeToDelete), ...analysis.oldestFiles.filter(f => f.safeToDelete) ]; // Remove duplicates const uniqueDelete = Array.from(new Map(willDelete.map(f => [f.path, f])).values()); const totalSpaceToRecover = uniqueDelete.reduce((sum, f) => sum + f.size, 0); const estimatedDuration = uniqueDelete.length * 10; // ~10ms per file const warnings: string[] = []; if (analysis.riskAssessment.high > 0) { warnings.push(`${analysis.riskAssessment.high} high-risk files detected (e.g., node_modules)`); } if (totalSpaceToRecover > 10 * 1024 * 1024 * 1024) { // > 10GB warnings.push('Large cleanup operation (>10GB) - consider backing up first'); } return { willDelete: uniqueDelete, totalFilesToDelete: uniqueDelete.length, totalSpaceToRecover, totalSpaceToRecoverHuman: this.formatBytes(totalSpaceToRecover), estimatedDuration, backupRequired: options.backupBeforeDelete !== false, backupSize: totalSpaceToRecover, warnings }; } /** * Compress preview for token reduction */ private compressPreview(preview: CleanupPreview): any { return { files: preview.totalFilesToDelete, space: preview.totalSpaceToRecoverHuman, duration: `~${Math.ceil(preview.estimatedDuration / 1000)}s`, backup: preview.backupRequired, warnings: preview.warnings.length > 0 ? preview.warnings : undefined, // Only include top 5 files instead of all top5: preview.willDelete.slice(0, 5).map(f => ({ p: f.path.split('/').pop(), s: this.formatBytes(f.size), c: f.category })) }; } /** * Compress execution for token reduction */ private compressExecution(execution: CleanupExecution): any { return { deleted: execution.deletedCount, freed: execution.freedSpaceHuman, duration: `${Math.ceil(execution.duration / 1000)}s`, errors: execution.errors.length, rollback: execution.rollbackAvailable, // Only include first 3 errors errorSample: execution.errors.slice(0, 3).map(e => e.path.split('/').pop()) }; } /** * Create backup before deletion */ private async createBackup(files: FileCandidate[], customBackupPath?: string): Promise { const timestamp = Date.now(); const backupLocation = customBackupPath || path.join(this.backupDir, `cleanup-${timestamp}`); await mkdir(backupLocation, { recursive: true }); for (const file of files) { const backupPath = this.getBackupPath(file.path, backupLocation); try { // Ensure backup directory exists await mkdir(path.dirname(backupPath), { recursive: true }); // Copy file to backup (using rename for efficiency, but could use copyFile for safety) await fs.promises.copyFile(file.path, backupPath); } catch (error) { // Skip files that can't be backed up } } return backupLocation; } /** * Get backup path for a file */ private getBackupPath(originalPath: string, backupLocation: string): string { const hash = createHash('md5').update(originalPath).digest('hex').substring(0, 8); const basename = path.basename(originalPath); return path.join(backupLocation, `${hash}-${basename}`); } /** * Generate recommendations */ private generateRecommendations(analysis: CleanupAnalysis): string[] { const recommendations: string[] = []; // Check node_modules if (analysis.byCategory['node-modules']?.size > 1024 * 1024 * 1024) { // > 1GB recommendations.push('Large node_modules detected - consider using pnpm or yarn PnP'); } // Check cache dirs if (analysis.byCategory['cache-dirs']?.size > 500 * 1024 * 1024) { // > 500MB recommendations.push('Large cache directories - configure cache size limits'); } // Check logs if (analysis.byCategory['old-logs']?.size > 100 * 1024 * 1024) { // > 100MB recommendations.push('Large log files - implement log rotation'); } // Check build artifacts if (analysis.byCategory['build-artifacts']?.count > 100) { recommendations.push('Many build artifacts - consider automated cleanup in CI/CD'); } return recommendations; } /** * Format bytes to human readable */ private formatBytes(bytes: number): string { if (bytes === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB', 'TB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`; }}// ===========================// Factory Function// ===========================export function getSmartCleanup( cache: CacheEngine, tokenCounter: TokenCounter, metricsCollector: MetricsCollector): SmartCleanup { return new SmartCleanup(cache, tokenCounter, metricsCollector);}// ===========================// Standalone Runner Function (CLI)// ===========================export async function runSmartCleanup( options: SmartCleanupOptions, cache?: CacheEngine, tokenCounter?: TokenCounter, metricsCollector?: MetricsCollector): Promise { const { homedir } = await import('os'); const { join } = await import('path'); const cacheInstance = cache || new CacheEngine(100, join(homedir(), '.hypercontext', 'cache')); const tokenCounterInstance = tokenCounter || new TokenCounter(); const metricsInstance = metricsCollector || new MetricsCollector(); const tool = getSmartCleanup(cacheInstance, tokenCounterInstance, metricsInstance); return await tool.run(options);}// ===========================// MCP Tool Definition// ===========================export const SMART_CLEANUP_TOOL_DEFINITION = { name: 'smart_cleanup', description: 'Intelligent system cleanup with smart caching (87%+ token reduction). Analyze, preview, and execute safe file cleanup operations with automatic backup and rollback support. Includes temp files, cache dirs, old logs, and build artifacts detection.', inputSchema: { type: 'object' as const, properties: { operation: { type: 'string' as const, enum: ['analyze', 'preview', 'execute', 'rollback', 'estimate-savings'], description: 'Cleanup operation to perform' }, paths: { type: 'array' as const, items: { type: 'string' as const }, description: 'Paths to analyze for cleanup (default: current directory)' }, patterns: { type: 'array' as const, items: { type: 'string' as const }, description: 'Custom glob patterns for file matching' }, categories: { type: 'array' as const, items: { type: 'string' as const, enum: [ 'temp-files', 'cache-dirs', 'old-logs', 'build-artifacts', 'node-modules', 'package-lock', 'coverage-reports', 'dist-folders', 'test-output', 'backups', 'thumbnails', 'crash-dumps', 'all' ] }, description: 'Cleanup categories to target (default: all)' }, olderThanDays: { type: 'number' as const, description: 'Only clean files older than this many days' }, minSizeBytes: { type: 'number' as const, description: 'Minimum file size in bytes' }, maxSizeBytes: { type: 'number' as const, description: 'Maximum file size in bytes' }, excludePatterns: { type: 'array' as const, items: { type: 'string' as const }, description: 'Patterns to exclude from cleanup' }, recursive: { type: 'boolean' as const, description: 'Scan directories recursively (default: true)', default: true }, dryRun: { type: 'boolean' as const, description: 'Preview changes without executing (default: false)', default: false }, backupBeforeDelete: { type: 'boolean' as const, description: 'Create backup before deletion for rollback (default: true)', default: true }, backupPath: { type: 'string' as const, description: 'Custom backup location (for execute and rollback operations)' }, useCache: { type: 'boolean' as const, description: 'Use cached results when available (default: true)', default: true }, ttl: { type: 'number' as const, description: 'Cache TTL in seconds (default: 1800 for analysis)' } }, required: ['operation'] }}; diff --git a/src/tools/system-operations/smart-process.ts b/src/tools/system-operations/smart-process.ts index 12d8934..bef3b81 100644 --- a/src/tools/system-operations/smart-process.ts +++ b/src/tools/system-operations/smart-process.ts @@ -156,7 +156,7 @@ export class SmartProcess { operation, data: { error: errorMessage }, metadata: { - tokensUsed: this.tokenCounter.count(errorMessage), + tokensUsed: this.tokenCounter.count(errorMessage).tokens, tokensSaved: 0, cacheHit: false, executionTime: Date.now() - startTime @@ -191,7 +191,7 @@ export class SmartProcess { }; const dataStr = JSON.stringify(processInfo); - const tokensUsed = this.tokenCounter.count(dataStr); + const tokensUsed = this.tokenCounter.count(dataStr).tokens; return { success: true, @@ -239,7 +239,7 @@ export class SmartProcess { const result = { pid, stopped: true }; const dataStr = JSON.stringify(result); - const tokensUsed = this.tokenCounter.count(dataStr); + const tokensUsed = this.tokenCounter.count(dataStr).tokens; return { success: true, @@ -255,7 +255,7 @@ export class SmartProcess { } private async getProcessStatus(options: SmartProcessOptions): Promise { - const cacheKey = CacheEngine.generateKey('process-status', `${options.pid || options.name}`); + const cacheKey = `process-status:${options.pid || options.name}`; const useCache = options.useCache !== false; // Check cache @@ -352,7 +352,7 @@ export class SmartProcess { } private async getProcessTree(options: SmartProcessOptions): Promise { - const cacheKey = CacheEngine.generateKey('process-tree', `${options.pid || 'all'}`); + const cacheKey = `process-tree:${options.pid || 'all'}`; const useCache = options.useCache !== false; // Check cache @@ -552,7 +552,7 @@ export class SmartProcess { private async buildProcessTreeUnix(rootPid?: number): Promise { // Use pstree on Unix const pid = rootPid || process.pid; - const { _stdout } = await execAsync(`pstree -p ${pid}`); + const { stdout } = await execAsync(`pstree -p ${pid}`); // Parse pstree output (simplified) return { @@ -589,7 +589,7 @@ export async function runSmartProcess( const { join } = await import('path'); const cacheInstance = cache || new CacheEngine(100, join(homedir(), '.hypercontext', 'cache')); - const tokenCounterInstance = tokenCounter || new TokenCounter('gpt-4'); + const tokenCounterInstance = tokenCounter || new TokenCounter(); const metricsInstance = metricsCollector || new MetricsCollector(); const tool = getSmartProcess(cacheInstance, tokenCounterInstance, metricsInstance);