optiprune 2.1.8 → 2.2.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,110 +1,210 @@
1
- ![Optiprune Logo](docs/public/logo.svg)
2
- ![NPM Version](https://img.shields.io/npm/v/optiprune)
3
- ![GitHub License](https://img.shields.io/github/license/DreamLongYT/optiprune)
1
+ ![OptiPrune analyzer animation](https://raw.githubusercontent.com/optiprune/core/main/animation.svg)
4
2
 
5
- # 🚀 OptiPrune
6
- ---
3
+ [![CLI npm version](https://img.shields.io/npm/v/%40optiprune%2Fcli?label=%40optiprune%2Fcli)](https://www.npmjs.com/package/@optiprune/cli)[![Core npm version](https://img.shields.io/npm/v/%40optiprune%2Fcore?label=%40optiprune%2Fcore)](https://www.npmjs.com/package/@optiprune/core)[![CLI package](https://img.shields.io/github/package-json/v/optiprune/cli?label=CLI%20package)](https://github.com/optiprune/cli)[![Core tests](https://img.shields.io/github/actions/workflow/status/optiprune/core/tests.yml?branch=main&label=core%20tests)](https://github.com/optiprune/core/actions/workflows/tests.yml)[![License](https://img.shields.io/github/license/optiprune/cli)](./LICENSE)[![Node.js](https://img.shields.io/badge/Node.js-%3E%3D21-339933?logo=node.js&logoColor=white)](https://nodejs.org/)
7
4
 
8
- ## 💎 The Vision
9
- Most dead-code analyzers just guess. They look at import graphs and hope they don't miss anything critical. This leads to **false positives**, broken builds, and developer frustration.
5
+ # OptiPrune
10
6
 
11
- **OptiPrune is different.** We use formal logic, isolated execution, and a high-performance engine to not just find dead code, but to mathematically **prove** it.
7
+ OptiPrune is a static dead-code analyzer for TypeScript and JavaScript projects. It combines parser-backed module graphs, export and member reachability, dependency and workspace inspection, dynamic-import analysis, semantic contracts, optional symbolic/concolic checks, and source-aware plugins.
12
8
 
13
- > **"Stop Guessing, Start Proving."**
9
+ The CLI package is `@optiprune/cli`. The analysis engine is available separately as the headless package `@optiprune/core`.
14
10
 
15
- ---
11
+ ## Features
16
12
 
17
- ## The 3 Pillars of Superiority
13
+ | Area | What is included |
14
+ | --- | --- |
15
+ | Project analysis | Entry discovery, module graphs, export/member reachability, dependency edges, strongly connected components, and cycle reporting. |
16
+ | TypeScript and JavaScript | `.ts`, `.tsx`, `.js`, `.jsx`, and `.vue` extensions by default, with custom extension lists available from the CLI or config. |
17
+ | Dynamic paths | Literal and pattern-based dynamic imports, unresolved-path findings, recovery information, and isolated execution checks. |
18
+ | Logic analysis | Constant conditions, contradictory guards, unreachable statements, and schema-impossible guards. |
19
+ | Dependencies | `package.json`, scripts, dependency/devDependency usage, package exports, bins, workspace packages, and lockfile-aware context. |
20
+ | Contracts and entries | Public API contracts, schema-aware protection, conventional entries, entry-file exports, test-file handling, and framework/plugin entry points. |
21
+ | Fixes | Opt-in fixes for unreachable files, unused exports and members, dependencies, development dependencies, and verified conditions. Every fix is confidence-gated and supports dry runs. |
22
+ | Output | Human-readable terminal output, JSON reports, and SARIF output for CI/code-scanning workflows. |
23
+ | Headless usage | `analyze`, `shouldFail`, cache helpers, fix helpers, reporters, and public TypeScript types from `@optiprune/core`. |
24
+ | Plugins | Source-aware adapters for frameworks, build tools, test tools, runtimes, package managers, and workspace conventions. |
18
25
 
19
- ### 1. Raw Power: The Yuku Engine (Zig)
20
- While other tools are throttled by the N-API bottleneck, OptiPrune utilizes the **Yuku Engine** written in **Zig**. It minimizes the overhead between native performance and the JavaScript runtime.
21
- * **The Result:** Up to 3x faster parsing than traditional tools, even in massive monorepos.
26
+ ## Installation
22
27
 
23
- ### 2. Deep Intelligence: SMT & Z3 Solver
24
- OptiPrune is the first analyzer to use a real **SMT Solver (Z3)**. We don't just analyze if a function is exported; we analyze if the code *inside* the function is logically reachable.
25
- * **The Result:** Detects dead logic paths (e.g., impossible `if` conditions) that are completely invisible to Knip.
28
+ Install the CLI as a development dependency:
26
29
 
27
- ### 3. Absolute Precision: WASM Sandbox Execution
28
- Dynamic imports are the final boss of static analysis. OptiPrune solves this through a **WASM-based QuickJS sandbox**. We securely execute critical code snippets to resolve paths at runtime.
29
- * **The Result:** Zero false alarms for dynamic paths. If OptiPrune says it's dead, it's dead.
30
+ ```bash
31
+ npm install --save-dev @optiprune/cli
32
+ # or
33
+ pnpm add -D @optiprune/cli
34
+ # or
35
+ yarn add -D @optiprune/cli
36
+ ```
30
37
 
31
- ---
38
+ The Core package currently requires Node.js 21 or newer.
32
39
 
33
- ## 🥊 OptiPrune vs. Knip: The Head-to-Head
40
+ ## Quick start
34
41
 
35
- | Feature | Knip | OptiPrune |
36
- | :--- | :--- | :--- |
37
- | **Engine** | Babel / OXC (Standard) | **Yuku / Zig (Hyper-Speed)** |
38
- | **Logic Analysis** | Heuristics (Guessing) | **Z3 SMT Solver (Proving)** |
39
- | **Dynamic Paths** | Pattern Matching | **WASM Sandbox Execution** |
40
- | **Interface Audit** | Ignores Members | **Deep Member-Level Analysis** |
41
- | **Framework Support** | Plugins (Core-Level) | **7-Layer Semantic Context** |
42
- | **False Positives** | High (in complex setups) | **Near-Zero (Context Aware)** |
42
+ Run an analysis from the project root:
43
43
 
44
- ---
44
+ ```bash
45
+ npx @optiprune/cli analyze
46
+ ```
45
47
 
46
- ## 🏗️ The 7-Layer Architecture
47
- OptiPrune operates in seven specialized layers to guarantee maximum accuracy:
48
+ The default command is `analyze`, so this is equivalent:
48
49
 
49
- 1. **Layer 1: Discovery** – Ultra-fast file scanning.
50
- 2. **Layer 2: Basic CFG** – Detects standard dead code after terminal statements.
51
- 3. **Layer 3: SMT Logic** – Mathematical path proofs with Z3.
52
- 4. **Layer 4: WASM Sandbox** – Dynamic path resolution via execution.
53
- 5. **Layer 6: Schema Shield** – Protection for Zod, Decorators & Contracts.
54
- 6. **Layer 6: Dependency Audit** – Scans lockfiles & package.json scripts.
55
- 7. **Layer 7: Topology Engine** – Understands NestJS DI & Event Buses.
50
+ ```bash
51
+ npx @optiprune/cli
52
+ ```
56
53
 
57
- ---
54
+ Select a machine-readable output format when integrating with tooling:
58
55
 
59
- ## 📈 Benchmark Numbers (Real-World Test)
60
- *Tested on a NestJS project with 1000+ files.*
56
+ ```bash
57
+ npx @optiprune/cli analyze --json
58
+ npx @optiprune/cli analyze --sarif > optiprune.sarif
59
+ ```
61
60
 
62
- * **Knip Speed:** 1.26s (with crash risks on complex types)
63
- * **OptiPrune Speed:** **0.87s** (Stable & Precise)
64
- * **Accuracy:** OptiPrune found **15% more** real dead code (unused interface properties & logical errors) that Knip completely missed.
61
+ ## Commands
65
62
 
66
- ---
63
+ | Command | Purpose |
64
+ | --- | --- |
65
+ | `analyze [options]` | Analyze the project. This is the default command. |
66
+ | `export-cache <targetPath>` | Export the current analysis cache to a JSON file. |
67
+ | `import-cache <sourcePath>` | Import an external cache JSON file into the local project cache. |
68
+ | `optiprune --help` | Print command and option help. |
69
+ | `optiprune --version` | Print the CLI and detected Core versions. |
67
70
 
68
- ## Installation
71
+ ## Analyze flags
69
72
 
70
- Install Optiprune as a dev dependency via pnpm, npm, or yarn:
73
+ | Flag | Description | Default |
74
+ | --- | --- | --- |
75
+ | `-r, --rootDir <path>` | Root directory of the project. | Current working directory |
76
+ | `-e, --entry <patterns...>` | Entry-point patterns, globs, or file paths. | `[]` |
77
+ | `-x, --extensions <exts...>` | File extensions to analyze. | `.ts .tsx .js .jsx .vue` |
78
+ | `-i, --ignore <patterns...>` | Glob patterns to ignore. | `[]` |
79
+ | `--no-report-unused-exports` | Disable unused-export reporting. | Enabled |
80
+ | `--no-conventional-entries` | Exclude conventional entries such as `src/index.ts`. | Included |
81
+ | `--include-entry-exports` | Report unused exports declared directly in entry files. | Disabled |
82
+ | `--cycles` | Print detected dependency cycles. | Disabled |
83
+ | `--ignore-tests` | Ignore test files such as `test.ts`, `*.test.ts`, and `__tests__`. | Disabled |
84
+ | `--fail-on <confidence>` | Exit non-zero when findings meet the selected confidence level: `high`, `medium`, `low`, or `none`. | `high` |
85
+ | `--json` | Print the structured analysis report as JSON. | Disabled |
86
+ | `--sarif` | Print SARIF output. | Disabled |
87
+ | `--skip-3` | Skip the SMT constraint-analysis layer. | Disabled |
88
+ | `--skip-4` | Skip the concolic execution-proof layer. | Disabled |
89
+ | `-v, --verbose` | Print verbose output and internal graph state. | Disabled |
90
+ | `--fix <rules...>` | Select fix targets: `files`, `exports`, `dependencies`, `devDependencies`, or `conditions`. | None |
91
+ | `--confidence <level>` | Minimum fix confidence: `high`, `medium+`, or `low+`. | `high` |
92
+ | `--force` | Allow a selected fix when the source edit is otherwise considered unsafe. | Disabled |
93
+ | `--dry-run` | Log planned fixes without changing files. | Disabled |
94
+ | `--cache-from <path>` | Import a JSON cache before analysis. | None |
95
+ | `--cache-to <path>` | Export the resulting cache after analysis. | None |
96
+
97
+ `--confidence`, `--force`, and `--dry-run` require `--fix`. Unknown fix targets are rejected before analysis begins.
98
+
99
+ ## Fixes
100
+
101
+ Fixes are explicit rather than implicit. Start with a dry run, inspect the output, then omit `--dry-run` when the proposed changes are acceptable.
71
102
 
72
103
  ```bash
73
- pnpm add -D optiprune
74
- # or
75
- npm install --save-dev optiprune
76
- # or
77
- yarn add -D optiprune
104
+ npx @optiprune/cli analyze \
105
+ --fix files exports dependencies devDependencies conditions \
106
+ --confidence medium+ \
107
+ --dry-run
108
+ ```
78
109
 
79
- ---
110
+ | Target | Applies to |
111
+ | --- | --- |
112
+ | `files` | Verified unreachable files. |
113
+ | `exports` | Verified unused exports and members. |
114
+ | `dependencies` | Unused runtime dependencies. |
115
+ | `devDependencies` | Unused development dependencies. |
116
+ | `conditions` | Verified constant conditions. |
80
117
 
81
- ## Usage
118
+ `--force` changes the safety decision for the selected fix operation; it does not make an unverified finding correct. Use it only when the source edit has been reviewed.
82
119
 
83
- Run Optiprune from your project root:
120
+ ## Cache
121
+
122
+ Use cache files to reuse analysis state in local workflows or CI:
84
123
 
85
124
  ```bash
86
- npx optiprune
125
+ npx @optiprune/cli analyze \
126
+ --cache-from .optiprune/cache.json \
127
+ --cache-to .optiprune/cache.json
128
+
129
+ npx @optiprune/cli export-cache .optiprune/cache.json
130
+ npx @optiprune/cli import-cache .optiprune/cache.json
87
131
  ```
88
132
 
89
- ### CLI Options
133
+ `export-cache` and `import-cache` accept `-r, --rootDir <path>` when the cache belongs to a directory other than the current working directory.
90
134
 
91
- | Flag | Description | Default |
92
- | :--- | :--- | :--- |
93
- | `-r, --rootDir` | Project root directory | `process.cwd()` |
94
- | `-e, --entry` | Entry point patterns (glob) | `[]` |
95
- | `-i, --ignore` | Patterns to ignore | `[]` |
96
- | `--no-report-unused-exports` | Disable unused export reporting | `false` |
97
- | `--fail-on` | Fail on confidence (high/medium/low/none) | `high` |
98
- | `--json` | Output as JSON | `false` |
99
- | `--sarif` | Output as SARIF | `false` |
100
- | `--skip-3` | Skip Layer 3 (SMT Constraint Solver) | `false` |
101
- | `--skip-4` | Skip Layer 4 (Concolic Execution Proofs) | `false` |
102
-
103
- ---
104
-
105
- ## 🤝 Join the Revolution
106
- OptiPrune isn't just a tool. It's a technical statement. Help us save the world from dirty code.
107
-
108
- **GitHub:** [DreamLongYT/optiprune](https://github.com/DreamLongYT/optiprune)
109
- **Web:** [opti.drml.int.yt](https://opti.drml.int.yt)
110
- See [CONTRIBUTING.md](CONTRIBUTING.md) for local setup and development guides.
135
+ ## Configuration
136
+
137
+ OptiPrune reads configuration through the Core loader. Supported sources include:
138
+
139
+ | Source | Notes |
140
+ | --- | --- |
141
+ | `optiprune.json` | Standard JSON configuration. |
142
+ | `optiprune.jsonc` | JSON with comments and trailing commas. |
143
+ | `optiprune.config.ts` | TypeScript configuration with a default export. |
144
+ | `optiprune.config.js` | JavaScript ESM configuration with a default export. |
145
+ | `optiprune.config.mjs` | JavaScript ESM configuration with a default export. |
146
+ | `package.json#optiprune` | Package field configuration. |
147
+
148
+ See [`config.md`](./config.md) for the configuration reference and [`schema.json`](https://github.com/optiprune/core/blob/main/schema.json) for the authoritative schema.
149
+
150
+ ## Headless Core API
151
+
152
+ Use `@optiprune/core` directly when the CLI is not the right integration boundary:
153
+
154
+ ```bash
155
+ npm install @optiprune/core
156
+ ```
157
+
158
+ ```
159
+ import { analyze, shouldFail } from "@optiprune/core";
160
+
161
+ const report = await analyze({
162
+ rootDir: process.cwd(),
163
+ entry: ["src/index.ts"],
164
+ output: "json",
165
+ });
166
+
167
+ console.log(report.summary);
168
+
169
+ if (shouldFail(report, "high")) {
170
+ process.exitCode = 1;
171
+ }
172
+ ```
173
+
174
+ The Core package also exposes cache helpers, `applyFixes`, reporters, and public types:
175
+
176
+ ```
177
+ import { applyFixes, exportCache, importCache } from "@optiprune/core";
178
+ import { formatSarif, formatTerminal } from "@optiprune/core/reporters";
179
+ import type { AnalysisReport, AnalyzerOptions, Finding } from "@optiprune/core/types";
180
+ ```
181
+
182
+ An `AnalysisReport` contains summary counts, findings, entry points, module records, exports, dependency edges, and strongly connected components.
183
+
184
+ ## Plugin model
185
+
186
+ Plugins provide source-aware context for frameworks, build tools, test runners, runtimes, package managers, and workspace conventions. They can contribute entry patterns, mark files or packages as used, interpret project metadata, and participate in analysis lifecycle hooks.
187
+
188
+ Browse the [Core plugin directory](https://github.com/optiprune/core/tree/main/src/plugins) to inspect the current source-backed set and the `AnalyzerPlugin`/`PluginAdapter` contracts.
189
+
190
+ ## Development
191
+
192
+ Build the package from this repository:
193
+
194
+ ```bash
195
+ npm run build
196
+ npm test
197
+ ```
198
+
199
+ The Core repository uses Vitest for its test suite. The workflow badges above reflect the status reported by GitHub Actions rather than a hard-coded claim in this README.
200
+
201
+ ## Links
202
+
203
+ | Resource | Link |
204
+ | --- | --- |
205
+ | CLI repository | [github.com/optiprune/cli](https://github.com/optiprune/cli) |
206
+ | Core repository | [github.com/optiprune/core](https://github.com/optiprune/core) |
207
+ | CLI package | [npmjs.com/package/@optiprune/cli](https://www.npmjs.com/package/@optiprune/cli) |
208
+ | Core package | [npmjs.com/package/@optiprune/core](https://www.npmjs.com/package/@optiprune/core) |
209
+ | Documentation site | [opti.drml.int.yt](https://opti.drml.int.yt/) |
210
+ | License | [MIT](./LICENSE) |
package/config.md ADDED
@@ -0,0 +1,142 @@
1
+ # OptiPrune Configuration Guide (`config.md`)
2
+
3
+ OptiPrune uses a structured configuration file to define entry points, rule behavior, ignore patterns, and core analysis engine mechanics.
4
+
5
+ ---
6
+
7
+ ## Quick Start
8
+
9
+ Create an `optiprune.json` or `optiprune.jsonc` file in the root directory of your project:
10
+
11
+ ```
12
+ {
13
+ "$schema": "https://raw.githubusercontent.com/optiprune/core/refs/heads/main/schema.json",
14
+ "rootDir": "src",
15
+ "entry": ["src/index.ts", "src/cli.ts"],
16
+ "ignore": ["**/*.test.ts", "**/dist/**"],
17
+ "externalContracts": ["PluginAdapter", "AnalyzerPlugin"],
18
+ "failOn": "high",
19
+ "rules": {
20
+ "unused-variable": "warning",
21
+ "dead-code": "error"
22
+ }
23
+ }
24
+ ```
25
+
26
+ ---
27
+
28
+ ## How OptiPrune Loads Configuration
29
+
30
+ When OptiPrune initializes, it checks the workspace root in the following order of precedence:
31
+
32
+ optiprune.json (Highest Priority )
33
+
34
+ optiprune.jsonc (Allows comments //, /* */, and trailing commas)
35
+
36
+ package.json (Falls back to reading an "optiprune" key)
37
+
38
+ ---
39
+
40
+ ## Configuration Reference
41
+
42
+ **1. File & Workspace Discovery**rootDir (string, default: ".")
43
+
44
+ Specifies the base directory for source files relative to the project workspace root.
45
+
46
+ entry (string[], default: [])
47
+
48
+ Defines root entry files. Any code reachable from these files (and their dependency trees) is marked as used and protected from unused-code reports.
49
+
50
+ extensions (string[], default: [".ts", ".tsx", ".js", ".jsx"])
51
+
52
+ File extensions that OptiPrune will parse and analyze.
53
+
54
+ ignore (string[], default: [])
55
+
56
+ Glob patterns or directory paths to skip entirely during analysis (e.g., test fixtures, output directories).
57
+
58
+ **2. Export & Contract Safeguards**externalContracts (string[], default: [])
59
+
60
+ List of public API symbol or interface names. Marks these exports as globally used across all execution layers, preventing OptiPrune from flagging them as dead code when building public libraries or plugins.
61
+
62
+ reportUnusedExports (boolean, default: true)
63
+
64
+ When set to true, OptiPrune reports exported functions, types, or variables that have no internal or external references.
65
+
66
+ includeConventionalEntries (boolean, default: true)
67
+
68
+ Automatically treats framework conventions (e.g., index.ts, main.ts, App.tsx) as entry points without needing manual listing in entry.
69
+
70
+ **3. CLI & Execution Controls**failOn ("high" | "medium" | "low" | "info" | "none", default: "high")
71
+
72
+ Determines the minimum issue severity level required to exit the process with a non-zero exit code in CI/CD pipelines.
73
+
74
+ verbose (boolean, default: false)
75
+
76
+ Prints step-by-step diagnostic information to stdout.
77
+
78
+ json (boolean, default: false)
79
+
80
+ Formats output directly as raw JSON for external tool ingestion.
81
+
82
+ **4. Automated Fixes (fix)**
83
+
84
+ Configures the automatic removal of dead code. Can be a boolean or an object for granular control.
85
+
86
+ ```
87
+ {
88
+ "fix": {
89
+ "confidence": "medium+",
90
+ "rules": ["exports", "files", "dependencies"],
91
+ "dryRun": false
92
+ }
93
+ }
94
+ ```
95
+
96
+ - **confidence**: Minimum confidence to apply a fix (`high`, `medium+`, `low+`, `all`).
97
+
98
+ - **rules**: Specific rules or categories (`exports`, `files`, `dependencies`) to fix.
99
+
100
+ - **dryRun**: If true, logs what would be fixed without modifying files.
101
+
102
+ **5. Rule Overrides (rules)**Fine-tune or disable specific inspection rules:
103
+
104
+ ```json
105
+ "rules": {
106
+ "rule-name": "error" | "warning" | "off"
107
+ }
108
+ ```
109
+
110
+ - `"error"`: Causes finding to trigger build errors or exit failures.
111
+
112
+ - `"warning"`: Emits warnings without halting execution (unless configured by failOn).
113
+
114
+ - `"off"`: Disables rule checking entirely.
115
+
116
+ **6. Engine & Solver Tuning (layers)**Configure isolated runtimes, SMT solvers, and symbolic execution passes:
117
+
118
+ | Option | Type | Default | Purpose |
119
+ | --- | --- | --- | --- |
120
+ | smtTimeoutMs | number | 10000 | SMT solver execution cap (in milliseconds) per proof path. |
121
+ | isolateMemoryLimitMb | number | 128 | Memory ceiling (in MB) allocated to V8 worker isolates. |
122
+ | enableConcolicProof | boolean | false | Enables concolic analysis to prove dead execution paths. |
123
+ | skip3 | boolean | false | Bypasses Analysis Layer 3. |
124
+ | skip4 | boolean | false | Bypasses Analysis Layer 4. |
125
+
126
+ ---
127
+
128
+ ## Alternative: package.json Configuration
129
+
130
+ If you do not want an additional configuration file in your root folder, add an "optiprune" field inside package.json:
131
+
132
+ ```json
133
+ {
134
+ "name": "my-library",
135
+ "version": "1.0.0",
136
+ "optiprune": {
137
+ "entry": ["src/index.ts"],
138
+ "externalContracts": ["MyPublicApi"],
139
+ "failOn": "medium"
140
+ }
141
+ }
142
+ ```
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,184 @@
1
+ #!/usr/bin/env node
2
+ import path from "pathe";
3
+ import fs from "node:fs";
4
+ import { fileURLToPath } from "node:url";
5
+ import { Command } from "commander";
6
+ const program = new Command();
7
+ const FIX_TARGETS = new Set(["files", "exports", "dependencies", "devDependencies", "conditions"]);
8
+ // Using @ts-ignore for core imports as CI environments sometimes struggle
9
+ // with subpath exports resolution in strict NodeNext mode.
10
+ // @ts-ignore
11
+ import { analyze, shouldFail, exportCache, importCache } from "@optiprune/core";
12
+ // @ts-ignore
13
+ import { formatTerminal, formatSarif } from "@optiprune/core/reporters";
14
+ /** ANSI colour helpers */
15
+ const bold = (s) => `\x1b[1m${s}\x1b[0m`;
16
+ const yellow = (s) => `\x1b[33m${s}\x1b[0m`;
17
+ const red = (s) => `\x1b[31m${s}\x1b[0m`;
18
+ const dim = (s) => `\x1b[2m${s}\x1b[0m`;
19
+ // Helper to find the CLI package version
20
+ function getCliVersion() {
21
+ try {
22
+ const currentDir = path.dirname(fileURLToPath(import.meta.url));
23
+ let dir = currentDir;
24
+ while (dir !== path.dirname(dir)) {
25
+ const pkgPath = path.join(dir, "package.json");
26
+ if (fs.existsSync(pkgPath)) {
27
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
28
+ if (pkg.version)
29
+ return pkg.version;
30
+ }
31
+ dir = path.dirname(dir);
32
+ }
33
+ }
34
+ catch (e) { }
35
+ return "unknown";
36
+ }
37
+ // Helper to find the core version safely
38
+ function getCoreVersion(rootDir) {
39
+ try {
40
+ // 1. Try local node_modules in the current working directory
41
+ const localCore = path.join(rootDir, "node_modules/@optiprune/core/package.json");
42
+ if (fs.existsSync(localCore)) {
43
+ const content = fs.readFileSync(localCore, "utf-8");
44
+ const pkg = JSON.parse(content);
45
+ if (pkg.version)
46
+ return pkg.version;
47
+ }
48
+ // 2. Try resolving relative to this CLI file if bundled together
49
+ const cliDir = path.dirname(fileURLToPath(import.meta.url));
50
+ const siblingCore = path.join(cliDir, "../core/package.json");
51
+ if (fs.existsSync(siblingCore)) {
52
+ const content = fs.readFileSync(siblingCore, "utf-8");
53
+ const pkg = JSON.parse(content);
54
+ if (pkg.version)
55
+ return pkg.version;
56
+ }
57
+ }
58
+ catch (e) { }
59
+ return "1.11.45";
60
+ }
61
+ const cliVersion = getCliVersion();
62
+ const coreVersion = getCoreVersion(process.cwd());
63
+ program
64
+ .name("optiprune")
65
+ .description("Finds dead code in TypeScript/JavaScript projects.")
66
+ .version(`CLI: ${cliVersion}, Core: ${coreVersion}`, "-V, --version", "output the version number");
67
+ program
68
+ .command("analyze", { isDefault: true })
69
+ .description("Perform full analysis of the project")
70
+ .option("-r, --rootDir <path>", "Root directory of the project", process.cwd())
71
+ .option("-e, --entry <patterns...>", "Entry point patterns (glob or file paths)", [])
72
+ .option("-x, --extensions <exts...>", "File extensions to analyze", [".ts", ".tsx", ".js", ".jsx", ".vue"])
73
+ .option("-i, --ignore <patterns...>", "Ignore patterns (glob)", [])
74
+ .option("--no-report-unused-exports", "Do not report unused exports")
75
+ .option("--no-conventional-entries", "Do not include conventional entry points (e.g., src/index.ts)")
76
+ .option("--include-entry-exports", "Report unused exports declared directly in entry files")
77
+ .option("--cycles", "Print detected dependency cycles")
78
+ .option("--ignore-tests", "Ignore test files such as test.ts, *.test.ts, and __tests__ files")
79
+ .option("--fail-on <confidence>", "Fail on findings with confidence level (high, medium, low, none)", "high")
80
+ .option("--json", "Output results as JSON")
81
+ .option("--sarif", "Output results in SARIF format")
82
+ .option("--skip-3", "Skip Layer 3 (SMT Constraint Solver)")
83
+ .option("--skip-4", "Skip Layer 4 (Concolic Execution Proofs)")
84
+ .option("-v, --verbose", "Show verbose output and internal graph state")
85
+ .option("--fix <rules...>", "Fix selected targets: files, exports, dependencies, devDependencies")
86
+ .option("--confidence <level>", "Minimum confidence to fix (high, medium+, low+)", "high")
87
+ .option("--force", "Allow fixes when the source edit is otherwise considered unsafe")
88
+ .option("--dry-run", "Log what would be fixed without changing files")
89
+ .option("--cache-from <path>", "Path to a JSON file to import cache from before analysis")
90
+ .option("--cache-to <path>", "Path to export the resulting cache to after analysis")
91
+ .action(async (options, command) => {
92
+ try {
93
+ const isCliOverride = (name) => command.getOptionValueSource(name) === "cli";
94
+ let fixOption = undefined;
95
+ const hasFixFlags = isCliOverride("fix") || isCliOverride("confidence") || isCliOverride("force") || isCliOverride("dryRun");
96
+ if (hasFixFlags) {
97
+ if (!isCliOverride("fix")) {
98
+ throw new Error("--confidence, --force, and --dry-run require --fix <target...>");
99
+ }
100
+ const invalidTargets = options.fix.filter((target) => !FIX_TARGETS.has(target));
101
+ if (invalidTargets.length > 0) {
102
+ throw new Error(`Unknown --fix target(s): ${invalidTargets.join(", ")}. Choose files, exports, dependencies, devDependencies, or conditions.`);
103
+ }
104
+ fixOption = {
105
+ confidence: options.confidence,
106
+ rules: options.fix,
107
+ force: !!options.force,
108
+ dryRun: !!options.dryRun,
109
+ };
110
+ }
111
+ const analyzerOptions = {
112
+ ...(isCliOverride("rootDir") && { rootDir: options.rootDir }),
113
+ ...(isCliOverride("entry") && { entry: options.entry }),
114
+ ...(isCliOverride("extensions") && { extensions: options.extensions }),
115
+ ...(isCliOverride("ignore") && { ignore: options.ignore }),
116
+ ...(isCliOverride("reportUnusedExports") && {
117
+ reportUnusedExports: options.reportUnusedExports,
118
+ }),
119
+ ...(isCliOverride("conventionalEntries") && {
120
+ includeConventionalEntries: options.conventionalEntries,
121
+ }),
122
+ ...(isCliOverride("includeEntryExports") && { includeEntryExports: options.includeEntryExports }),
123
+ ...(isCliOverride("cycles") && { cycles: options.cycles }),
124
+ ...(isCliOverride("ignoreTests") && { ignoreTests: options.ignoreTests }),
125
+ ...(isCliOverride("failOn") && { failOn: options.failOn }),
126
+ ...(isCliOverride("json") && { json: options.json }),
127
+ ...(isCliOverride("skip3") && { skip3: options.skip3 }),
128
+ ...(isCliOverride("skip4") && { skip4: options.skip4 }),
129
+ ...(isCliOverride("verbose") && { verbose: options.verbose }),
130
+ ...(fixOption !== undefined && { fix: fixOption }),
131
+ ...(isCliOverride("cacheFrom") && { cacheFrom: options.cacheFrom }),
132
+ ...(isCliOverride("cacheTo") && { cacheTo: options.cacheTo }),
133
+ };
134
+ const report = await analyze(analyzerOptions);
135
+ if (options.sarif) {
136
+ console.log(formatSarif(report));
137
+ }
138
+ else if (options.json) {
139
+ console.log(JSON.stringify(report, (k, v) => typeof v === 'bigint' ? v.toString() : v, 2));
140
+ }
141
+ else {
142
+ const terminal = formatTerminal(report, { showCycles: !!options.cycles });
143
+ console.log(terminal);
144
+ }
145
+ if (shouldFail(report, options.failOn))
146
+ process.exit(1);
147
+ }
148
+ catch (error) {
149
+ console.error("An unexpected error occurred during analysis:", error);
150
+ process.exit(1);
151
+ }
152
+ });
153
+ program
154
+ .command("export-cache <targetPath>")
155
+ .description("Export the current analysis cache to a JSON file")
156
+ .option("-r, --rootDir <path>", "Root directory of the project", process.cwd())
157
+ .action(async (targetPath, options) => {
158
+ try {
159
+ const rootDir = options.rootDir ?? process.cwd();
160
+ await exportCache(rootDir, targetPath);
161
+ console.log(`${yellow("✔")} Cache exported to ${bold(targetPath)}`);
162
+ }
163
+ catch (error) {
164
+ console.error("Failed to export cache:", error);
165
+ process.exit(1);
166
+ }
167
+ });
168
+ program
169
+ .command("import-cache <sourcePath>")
170
+ .description("Import an external cache JSON file into the local directory")
171
+ .option("-r, --rootDir <path>", "Root directory of the project", process.cwd())
172
+ .action(async (sourcePath, options) => {
173
+ try {
174
+ const rootDir = options.rootDir ?? process.cwd();
175
+ await importCache(rootDir, sourcePath);
176
+ console.log(`${yellow("✔")} Cache imported from ${bold(sourcePath)}`);
177
+ }
178
+ catch (error) {
179
+ console.error("Failed to import cache:", error);
180
+ process.exit(1);
181
+ }
182
+ });
183
+ program.parse(process.argv);
184
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,IAAI,MAAM,OAAO,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAC9B,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,iBAAiB,EAAE,YAAY,CAAC,CAAC,CAAC;AAEnG,2EAA2E;AAC3E,2DAA2D;AAC3D,aAAa;AACb,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAChF,aAAa;AACb,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAIxE,0BAA0B;AAC1B,MAAM,IAAI,GAAK,CAAC,CAAS,EAAE,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC;AACnD,MAAM,MAAM,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC;AACpD,MAAM,GAAG,GAAM,CAAC,CAAS,EAAE,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC;AACpD,MAAM,GAAG,GAAM,CAAC,CAAS,EAAE,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC;AAEnD,yCAAyC;AACzC,SAAS,aAAa;IACpB,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAChE,IAAI,GAAG,GAAG,UAAU,CAAC;QACrB,OAAO,GAAG,KAAK,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YACjC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;YAC/C,IAAI,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;gBAC1D,IAAI,GAAG,CAAC,OAAO;oBAAE,OAAO,GAAG,CAAC,OAAO,CAAC;YACtC,CAAC;YACD,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC,CAAA,CAAC;IACd,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,yCAAyC;AACzC,SAAS,cAAc,CAAC,OAAe;IACrC,IAAI,CAAC;QACH,6DAA6D;QAC7D,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,2CAA2C,CAAC,CAAC;QAClF,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC7B,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YACpD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAChC,IAAI,GAAG,CAAC,OAAO;gBAAE,OAAO,GAAG,CAAC,OAAO,CAAC;QACtC,CAAC;QAED,iEAAiE;QACjE,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAC5D,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;QAC9D,IAAI,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC/B,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;YACtD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAChC,IAAI,GAAG,CAAC,OAAO;gBAAE,OAAO,GAAG,CAAC,OAAO,CAAC;QACtC,CAAC;IACH,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC,CAAA,CAAC;IACd,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;AACnC,MAAM,WAAW,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;AAElD,OAAO;KACJ,IAAI,CAAC,WAAW,CAAC;KACjB,WAAW,CAAC,oDAAoD,CAAC;KACjE,OAAO,CACN,QAAQ,UAAU,WAAW,WAAW,EAAE,EAC1C,eAAe,EACf,2BAA2B,CAC5B,CAAC;AAEJ,OAAO;KACJ,OAAO,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;KACvC,WAAW,CAAC,sCAAsC,CAAC;KACnD,MAAM,CAAC,sBAAsB,EAAE,+BAA+B,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC;KAC9E,MAAM,CAAC,2BAA2B,EAAE,2CAA2C,EAAE,EAAE,CAAC;KACpF,MAAM,CAAC,4BAA4B,EAAE,4BAA4B,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;KAC1G,MAAM,CAAC,4BAA4B,EAAE,wBAAwB,EAAE,EAAE,CAAC;KAClE,MAAM,CAAC,4BAA4B,EAAE,8BAA8B,CAAC;KACpE,MAAM,CAAC,2BAA2B,EAAE,+DAA+D,CAAC;KACpG,MAAM,CAAC,yBAAyB,EAAE,wDAAwD,CAAC;KAC3F,MAAM,CAAC,UAAU,EAAE,kCAAkC,CAAC;KACtD,MAAM,CAAC,gBAAgB,EAAE,mEAAmE,CAAC;KAC7F,MAAM,CAAC,wBAAwB,EAAE,kEAAkE,EAAE,MAAM,CAAC;KAC5G,MAAM,CAAC,QAAQ,EAAE,wBAAwB,CAAC;KAC1C,MAAM,CAAC,SAAS,EAAE,gCAAgC,CAAC;KACnD,MAAM,CAAC,UAAU,EAAE,sCAAsC,CAAC;KAC1D,MAAM,CAAC,UAAU,EAAE,0CAA0C,CAAC;KAC9D,MAAM,CAAC,eAAe,EAAE,8CAA8C,CAAC;KACvE,MAAM,CAAC,kBAAkB,EAAE,qEAAqE,CAAC;KACjG,MAAM,CAAC,sBAAsB,EAAE,iDAAiD,EAAE,MAAM,CAAC;KACzF,MAAM,CAAC,SAAS,EAAE,iEAAiE,CAAC;KACpF,MAAM,CAAC,WAAW,EAAE,gDAAgD,CAAC;KACrE,MAAM,CAAC,qBAAqB,EAAE,0DAA0D,CAAC;KACzF,MAAM,CAAC,mBAAmB,EAAE,sDAAsD,CAAC;KACnF,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;IACjC,IAAI,CAAC;QACH,MAAM,aAAa,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,oBAAoB,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC;QAErF,IAAI,SAAS,GAAoC,SAAS,CAAC;QAC3D,MAAM,WAAW,GAAG,aAAa,CAAC,KAAK,CAAC,IAAI,aAAa,CAAC,YAAY,CAAC,IAAI,aAAa,CAAC,OAAO,CAAC,IAAI,aAAa,CAAC,QAAQ,CAAC,CAAC;QAC7H,IAAI,WAAW,EAAE,CAAC;YAChB,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC1B,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;YACpF,CAAC;YACD,MAAM,cAAc,GAAI,OAAO,CAAC,GAAgB,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;YAC9F,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC9B,MAAM,IAAI,KAAK,CAAC,4BAA4B,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,wEAAwE,CAAC,CAAC;YACjJ,CAAC;YACD,SAAS,GAAG;gBACV,UAAU,EAAE,OAAO,CAAC,UAAiB;gBACrC,KAAK,EAAE,OAAO,CAAC,GAAG;gBAClB,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK;gBACtB,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM;aACZ,CAAC;QACjB,CAAC;QAED,MAAM,eAAe,GAAG;YACtB,GAAG,CAAC,aAAa,CAAC,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;YAC7D,GAAG,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;YACvD,GAAG,CAAC,aAAa,CAAC,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC;YACtE,GAAG,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;YAC1D,GAAG,CAAC,aAAa,CAAC,qBAAqB,CAAC,IAAI;gBAC1C,mBAAmB,EAAE,OAAO,CAAC,mBAAmB;aACjD,CAAC;YACF,GAAG,CAAC,aAAa,CAAC,qBAAqB,CAAC,IAAI;gBAC1C,0BAA0B,EAAE,OAAO,CAAC,mBAAmB;aACxD,CAAC;YACF,GAAG,CAAC,aAAa,CAAC,qBAAqB,CAAC,IAAI,EAAE,mBAAmB,EAAE,OAAO,CAAC,mBAAmB,EAAE,CAAC;YACjG,GAAG,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;YAC1D,GAAG,CAAC,aAAa,CAAC,aAAa,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC;YACzE,GAAG,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;YAC1D,GAAG,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;YACpD,GAAG,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;YACvD,GAAG,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;YACvD,GAAG,CAAC,aAAa,CAAC,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;YAC7D,GAAG,CAAC,SAAS,KAAK,SAAS,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;YAClD,GAAG,CAAC,aAAa,CAAC,WAAW,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC;YACnE,GAAG,CAAC,aAAa,CAAC,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;SAC3C,CAAC;QAErB,MAAM,MAAM,GAAmB,MAAM,OAAO,CAAC,eAAe,CAAC,CAAC;QAE9D,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YAClB,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;QACnC,CAAC;aAAM,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACxB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7F,CAAC;aAAM,CAAC;YACN,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;YAC1E,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACxB,CAAC;QAED,IAAI,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,MAAa,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,+CAA+C,EAAE,KAAK,CAAC,CAAC;QACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,2BAA2B,CAAC;KACpC,WAAW,CAAC,kDAAkD,CAAC;KAC/D,MAAM,CAAC,sBAAsB,EAAE,+BAA+B,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC;KAC9E,MAAM,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE;IACpC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QACjD,MAAM,WAAW,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,sBAAsB,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IACtE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;QAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,2BAA2B,CAAC;KACpC,WAAW,CAAC,6DAA6D,CAAC;KAC1E,MAAM,CAAC,sBAAsB,EAAE,+BAA+B,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC;KAC9E,MAAM,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE;IACpC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QACjD,MAAM,WAAW,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,wBAAwB,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IACxE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;QAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
package/logo.svg ADDED
@@ -0,0 +1,22 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="width:100%;height:100%">
2
+ <defs>
3
+ <linearGradient id="opti-grad-1" x1="0%" y1="0%" x2="100%" y2="100%">
4
+ <stop offset="0%" stop-color="#6366F1"></stop>
5
+ <stop offset="50%" stop-color="#8B5CF6"></stop>
6
+ <stop offset="100%" stop-color="#D946EF"></stop>
7
+ </linearGradient>
8
+ <linearGradient id="opti-grad-2" x1="0%" y1="100%" x2="100%" y2="0%">
9
+ <stop offset="0%" stop-color="#06B6D4"></stop>
10
+ <stop offset="100%" stop-color="#3B82F6"></stop>
11
+ </linearGradient>
12
+ <filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
13
+ <feDropShadow dx="0" dy="8" stdDeviation="16" flood-color="#8B5CF6" flood-opacity="0.35"></feDropShadow>
14
+ </filter>
15
+ </defs>
16
+ <g filter="url(#glow)">
17
+ <path d="M 256 64 C 362 64, 448 150, 448 256 C 448 290, 439 322, 423 350 L 340 267 C 352 240, 345 208, 321 184 C 297 160, 265 153, 238 165 L 155 82 C 185 70, 220 64, 256 64 Z" fill="url(#opti-grad-1)"></path>
18
+ <path d="M 256 448 C 150 448, 64 362, 64 256 C 64 222, 73 190, 89 162 L 172 245 C 160 272, 167 304, 191 328 C 215 352, 247 359, 274 347 L 357 430 C 327 442, 292 448, 256 448 Z" fill="url(#opti-grad-1)"></path>
19
+ <polygon points="110,410 410,110 380,80 80,380" fill="url(#opti-grad-2)" opacity="0.9"></polygon>
20
+ </g>
21
+ <circle cx="256" cy="256" r="28" fill="#FFFFFF" opacity="0.95"></circle>
22
+ </svg>
package/package.json CHANGED
@@ -1,16 +1,18 @@
1
1
  {
2
2
  "name": "optiprune",
3
- "version": "2.1.8",
4
- "description": "Resilient static dead-code analyzer for TypeScript and JavaScript workspaces.",
3
+ "version": "2.2.22",
4
+ "description": "CLI for resilient static dead-code analyzer for TypeScript and JavaScript workspaces.",
5
5
  "type": "module",
6
- "main": "./dist/cli.js",
6
+ "bin": {
7
+ "optiprune": "./dist/cli.js"
8
+ },
7
9
  "homepage": "https://opti.drml.int.yt/",
8
10
  "repository": {
9
11
  "type": "git",
10
- "url": "git+https://github.com/DreamLongYT/optiprune.git"
12
+ "url": "git+https://github.com/optiprune/cli.git"
11
13
  },
12
14
  "bugs": {
13
- "url": "https://github.com/DreamLongYT/optiprune/issues"
15
+ "url": "https://github.com/optiprune/cli/issues"
14
16
  },
15
17
  "keywords": [
16
18
  "analysis",
@@ -46,26 +48,44 @@
46
48
  "pruning",
47
49
  "dead",
48
50
  "opti",
49
- "optimization"
51
+ "optimization",
52
+ "resilient",
53
+ "api",
54
+ "optimization",
55
+ "resilient",
56
+ "analyzer",
57
+ "code"
50
58
  ],
51
- "bin": {
52
- "optiprune": "./bin/runner.js"
53
- },
54
59
  "files": [
55
- "bin",
60
+ "dist",
56
61
  "README.md",
57
- "LICENSE"
62
+ "LICENSE",
63
+ "config.md",
64
+ "package.json",
65
+ "logo.svg"
58
66
  ],
67
+ "exports": {
68
+ ".": "./dist/cli.js",
69
+ "./package.json": "./package.json"
70
+ },
59
71
  "dependencies": {
60
- "@optiprune/cli": "^1.2.9",
72
+ "@optiprune/core": "^1.11.45",
73
+ "commander": "^15.0.0",
61
74
  "pathe": "2.0.3"
62
75
  },
63
- "engines": {
64
- "node": "^22.18.0 || >=24.11.0"
76
+ "devDependencies": {
77
+ "@types/node": "^22.20.1",
78
+ "typescript": "^5.8.3"
65
79
  },
66
- "license": "MIT",
67
- "directories": {
68
- "doc": "docs"
80
+ "optionalDependencies": {
81
+ "@yuku-codegen/wasm": "0.8.7",
82
+ "@yuku-parser/wasm": "0.8.7"
69
83
  },
84
+ "scripts": {
85
+ "build": "tsc -p tsconfig.json",
86
+ "test": "node --test tests/ignore-unknown-import.test.mjs",
87
+ "prepublishOnly": "npm run build"
88
+ },
89
+ "license": "MIT",
70
90
  "author": "DreamLongYT"
71
- }
91
+ }
package/bin/runner.js DELETED
@@ -1,26 +0,0 @@
1
- #!/usr/bin/env node
2
- import { createRequire } from "node:module";
3
- import { fileURLToPath, pathToFileURL } from "node:url";
4
- import path from "pathe";
5
-
6
- const require = createRequire(import.meta.url);
7
-
8
- let cliPath;
9
-
10
- try {
11
- // 1. Try standard package resolution
12
- const pkgPath = require.resolve("@optiprune/cli/package.json");
13
- cliPath = path.join(path.dirname(pkgPath), "dist/cli.js");
14
- } catch {
15
- // 2. Monorepo / global symlink fallback
16
- const currentDir = path.dirname(fileURLToPath(import.meta.url));
17
- cliPath = path.resolve(currentDir, "../../cli/dist/cli.js");
18
- }
19
-
20
- // Convert absolute Windows path (E:\...) into a valid file:// URL
21
- const cliUrl = pathToFileURL(cliPath).href;
22
-
23
- import(cliUrl).catch((err) => {
24
- console.error("Failed to execute @optiprune/cli:", err);
25
- process.exit(1);
26
- });