pruneguard 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +247 -115
- package/bin/pruneguard +0 -0
- package/dist/bin.mjs +5 -1
- package/dist/index.d.mts +177 -4
- package/dist/index.mjs +64 -5
- package/dist/{runtime-BxlGT_W-.mjs → runtime-BSHQsTbN.mjs} +71 -9
- package/package.json +11 -9
- package/report_schema.json +96 -0
- package/review_report_schema.json +278 -0
- package/safe_delete_report_schema.json +131 -0
package/README.md
CHANGED
|
@@ -1,37 +1,31 @@
|
|
|
1
1
|
# pruneguard
|
|
2
2
|
|
|
3
|
-
**One graph. Every answer.** Find unused exports, dead files, phantom dependencies, import cycles, and boundary violations across your entire JS/TS monorepo
|
|
3
|
+
**One graph. Every answer.** Find unused exports, dead files, phantom dependencies, import cycles, and boundary violations across your entire JS/TS monorepo -- in a single, fast Rust-powered pass.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/pruneguard)
|
|
6
6
|
[](https://github.com/ferc/pruneguard/blob/main/LICENSE)
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## Install
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
```sh
|
|
13
|
+
npm install -D pruneguard # or: npx pruneguard scan
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The package automatically installs the correct platform-specific native binary. No Rust toolchain, no compilation, no native addons -- just `npm install` and go.
|
|
13
17
|
|
|
14
|
-
|
|
18
|
+
**Supported platforms:** macOS (ARM64, x64), Linux (x64/ARM64, glibc and musl), Windows (x64, ARM64). Requires Node.js >= 18.
|
|
15
19
|
|
|
16
|
-
###
|
|
20
|
+
### How it works
|
|
17
21
|
|
|
18
|
-
|
|
19
|
-
- **Monorepo-first** — understands pnpm/npm/yarn/bun workspaces, cross-package imports, and `exports` maps out of the box
|
|
20
|
-
- **8 built-in analyzers** — unused exports, unused files, unused packages, unused dependencies, cycles, boundary violations, ownership, and impact analysis
|
|
21
|
-
- **Framework-aware** — auto-detects Next.js, Vite, Vitest, Jest, and Storybook entrypoints so you don't over-report
|
|
22
|
-
- **Trust model** — every finding carries a confidence level; partial-scope scans are clearly marked as advisory
|
|
23
|
-
- **Explainability** — `impact` and `explain` commands let you trace proof chains before acting
|
|
24
|
-
- **CI-ready** — SARIF output, deterministic mode, `--changed-since` for incremental PR checks, exit codes for gating
|
|
25
|
-
- **Migrate easily** — built-in config converters for knip and dependency-cruiser
|
|
22
|
+
pruneguard ships a compiled Rust binary for each platform. The JS API and CLI both spawn this binary. Locally the daemon keeps the graph warm for instant queries. In CI every invocation is a fresh one-shot run.
|
|
26
23
|
|
|
27
24
|
---
|
|
28
25
|
|
|
29
26
|
## Quick start
|
|
30
27
|
|
|
31
28
|
```sh
|
|
32
|
-
# Install
|
|
33
|
-
npm install -D pruneguard # or: npx pruneguard scan
|
|
34
|
-
|
|
35
29
|
# Scan your repo
|
|
36
30
|
pruneguard scan
|
|
37
31
|
|
|
@@ -53,28 +47,34 @@ pruneguard init
|
|
|
53
47
|
pruneguard [OPTIONS] <COMMAND>
|
|
54
48
|
|
|
55
49
|
Commands:
|
|
56
|
-
scan [PATHS...]
|
|
57
|
-
impact <TARGET>
|
|
58
|
-
explain <QUERY>
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
50
|
+
scan [PATHS...] Analyze the repo (default command)
|
|
51
|
+
impact <TARGET> Compute blast radius for a file or export
|
|
52
|
+
explain <QUERY> Show proof chain for a finding, file, or export
|
|
53
|
+
review Branch review gate (blocking vs advisory findings)
|
|
54
|
+
safe-delete <TARGETS...> Evaluate targets for safe deletion
|
|
55
|
+
fix-plan <TARGETS...> Generate structured remediation plan
|
|
56
|
+
suggest-rules Auto-suggest governance rules from graph analysis
|
|
57
|
+
init Generate a default pruneguard.json
|
|
58
|
+
print-config Display the resolved configuration
|
|
59
|
+
debug resolve Debug module resolution
|
|
60
|
+
debug entrypoints List detected entrypoints
|
|
61
|
+
debug runtime Print runtime diagnostics
|
|
62
|
+
daemon start|stop|status Manage the background daemon
|
|
63
|
+
migrate knip Convert knip config to pruneguard
|
|
64
|
+
migrate depcruise Convert dependency-cruiser config to pruneguard
|
|
66
65
|
|
|
67
66
|
Options:
|
|
68
67
|
-c, --config <FILE> Config file path [default: pruneguard.json]
|
|
69
68
|
--format <FORMAT> Output format: text, json, sarif, dot
|
|
70
69
|
--profile <PROFILE> Analysis profile: production, development, all
|
|
71
|
-
--changed-since <REF> Only
|
|
70
|
+
--changed-since <REF> Only report findings for changed files
|
|
72
71
|
--focus <GLOB> Filter findings to matching files
|
|
73
72
|
--severity <SEVERITY> Minimum severity: error, warn, info
|
|
74
73
|
--no-cache Disable incremental cache
|
|
75
74
|
--no-baseline Disable baseline suppression
|
|
76
75
|
--require-full-scope Fail if scan is partial-scope
|
|
77
76
|
--max-findings <N> Cap the number of reported findings
|
|
77
|
+
--daemon <MODE> Daemon mode: auto, off, required
|
|
78
78
|
-V, --version Print version
|
|
79
79
|
-h, --help Print help
|
|
80
80
|
```
|
|
@@ -83,24 +83,155 @@ Options:
|
|
|
83
83
|
|
|
84
84
|
```sh
|
|
85
85
|
# Full scan with JSON output for CI
|
|
86
|
-
pruneguard
|
|
86
|
+
pruneguard --format json scan
|
|
87
87
|
|
|
88
|
-
# PR check
|
|
88
|
+
# PR check -- only findings from changed files
|
|
89
89
|
pruneguard --changed-since origin/main scan
|
|
90
90
|
|
|
91
91
|
# Deterministic CI (no cache, no baseline)
|
|
92
92
|
pruneguard --no-baseline --no-cache scan
|
|
93
93
|
|
|
94
|
+
# Branch review gate
|
|
95
|
+
pruneguard --changed-since origin/main review
|
|
96
|
+
|
|
97
|
+
# Safe-delete check before cleanup
|
|
98
|
+
pruneguard safe-delete src/old.ts src/legacy/widget.ts
|
|
99
|
+
|
|
94
100
|
# Focus on a specific area without narrowing analysis scope
|
|
95
101
|
pruneguard --focus "packages/core/**" scan
|
|
96
102
|
|
|
97
103
|
# SARIF for GitHub Code Scanning
|
|
98
|
-
pruneguard
|
|
104
|
+
pruneguard --format sarif scan > results.sarif
|
|
99
105
|
|
|
100
106
|
# Visualize the module graph
|
|
101
|
-
pruneguard
|
|
107
|
+
pruneguard --format dot scan | dot -Tsvg -o graph.svg
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Programmatic API
|
|
113
|
+
|
|
114
|
+
All functions spawn the native binary and return typed results.
|
|
115
|
+
|
|
116
|
+
```js
|
|
117
|
+
import {
|
|
118
|
+
scan,
|
|
119
|
+
review,
|
|
120
|
+
safeDelete,
|
|
121
|
+
fixPlan,
|
|
122
|
+
impact,
|
|
123
|
+
explain,
|
|
124
|
+
suggestRules,
|
|
125
|
+
run,
|
|
126
|
+
binaryPath,
|
|
127
|
+
loadConfig,
|
|
128
|
+
schemaPath,
|
|
129
|
+
scanDot,
|
|
130
|
+
migrateKnip,
|
|
131
|
+
migrateDepcruise,
|
|
132
|
+
} from "pruneguard";
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### scan
|
|
136
|
+
|
|
137
|
+
```js
|
|
138
|
+
const report = await scan({
|
|
139
|
+
profile: "production",
|
|
140
|
+
changedSince: "origin/main",
|
|
141
|
+
});
|
|
142
|
+
console.log(`${report.summary.totalFindings} findings`);
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### review
|
|
146
|
+
|
|
147
|
+
```js
|
|
148
|
+
const result = await review({ baseRef: "origin/main", noCache: true });
|
|
149
|
+
if (result.blockingFindings.length > 0) {
|
|
150
|
+
console.error("Blocking findings exist");
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### safeDelete
|
|
156
|
+
|
|
157
|
+
```js
|
|
158
|
+
const result = await safeDelete({ targets: ["src/old.ts"] });
|
|
159
|
+
console.log("Safe:", result.safe.map(e => e.target));
|
|
160
|
+
console.log("Blocked:", result.blocked.map(e => e.target));
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### fixPlan
|
|
164
|
+
|
|
165
|
+
```js
|
|
166
|
+
const plan = await fixPlan({ targets: ["src/old.ts"] });
|
|
167
|
+
for (const action of plan.actions) {
|
|
168
|
+
console.log(`${action.kind}: ${action.targets.join(", ")}`);
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### impact
|
|
173
|
+
|
|
174
|
+
```js
|
|
175
|
+
const blast = await impact({ target: "src/utils/helpers.ts" });
|
|
176
|
+
console.log(`Affects ${blast.affectedEntrypoints.length} entrypoints`);
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### explain
|
|
180
|
+
|
|
181
|
+
```js
|
|
182
|
+
const proof = await explain({ query: "src/old.ts#deprecatedFn" });
|
|
183
|
+
console.log(proof.proofs);
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### run
|
|
187
|
+
|
|
188
|
+
```js
|
|
189
|
+
const result = await run(["--format", "json", "--daemon", "off", "scan"]);
|
|
190
|
+
console.log(result.exitCode, result.durationMs);
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### binaryPath
|
|
194
|
+
|
|
195
|
+
```js
|
|
196
|
+
console.log(binaryPath());
|
|
197
|
+
// => /path/to/node_modules/@pruneguard/cli-darwin-arm64/bin/pruneguard
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Other functions
|
|
201
|
+
|
|
202
|
+
```js
|
|
203
|
+
const config = await loadConfig();
|
|
204
|
+
const schema = schemaPath();
|
|
205
|
+
const dot = await scanDot();
|
|
206
|
+
const rules = await suggestRules();
|
|
207
|
+
const knip = await migrateKnip();
|
|
208
|
+
const dc = await migrateDepcruise();
|
|
102
209
|
```
|
|
103
210
|
|
|
211
|
+
### Error handling
|
|
212
|
+
|
|
213
|
+
All functions throw `PruneguardExecutionError` with a `code` field:
|
|
214
|
+
|
|
215
|
+
| Code | Meaning |
|
|
216
|
+
|---|---|
|
|
217
|
+
| `PRUNEGUARD_BINARY_NOT_FOUND` | Native binary not found |
|
|
218
|
+
| `PRUNEGUARD_EXECUTION_FAILED` | Binary exited with unexpected code |
|
|
219
|
+
| `PRUNEGUARD_JSON_PARSE_FAILED` | Output was not valid JSON |
|
|
220
|
+
|
|
221
|
+
```js
|
|
222
|
+
import { scan, PruneguardExecutionError } from "pruneguard";
|
|
223
|
+
|
|
224
|
+
try {
|
|
225
|
+
await scan();
|
|
226
|
+
} catch (err) {
|
|
227
|
+
if (err instanceof PruneguardExecutionError) {
|
|
228
|
+
console.error(err.code, err.message);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Full TypeScript types are included via `dist/index.d.mts`.
|
|
234
|
+
|
|
104
235
|
---
|
|
105
236
|
|
|
106
237
|
## Configuration
|
|
@@ -116,47 +247,22 @@ Create `pruneguard.json` (or `.pruneguardrc.json`) in your project root. Run `pr
|
|
|
116
247
|
"packageManager": "pnpm"
|
|
117
248
|
},
|
|
118
249
|
|
|
119
|
-
"entrypoints": {
|
|
120
|
-
"auto": true,
|
|
121
|
-
"include": ["src/index.ts"],
|
|
122
|
-
"exclude": ["**/*.test.ts"]
|
|
123
|
-
},
|
|
124
|
-
|
|
125
250
|
"analysis": {
|
|
126
251
|
"unusedExports": "error",
|
|
127
252
|
"unusedFiles": "warn",
|
|
128
253
|
"unusedDependencies": "error",
|
|
129
|
-
"
|
|
130
|
-
"cycles": "warn",
|
|
131
|
-
"boundaries": "error"
|
|
254
|
+
"cycles": "warn"
|
|
132
255
|
},
|
|
133
256
|
|
|
134
257
|
"frameworks": {
|
|
135
258
|
"next": "auto",
|
|
136
259
|
"vitest": "auto",
|
|
137
260
|
"storybook": "auto"
|
|
138
|
-
},
|
|
139
|
-
|
|
140
|
-
"rules": {
|
|
141
|
-
"forbidden": [
|
|
142
|
-
{
|
|
143
|
-
"name": "no-cross-app-imports",
|
|
144
|
-
"severity": "error",
|
|
145
|
-
"comment": "Apps must not import from other apps",
|
|
146
|
-
"from": { "workspace": ["apps/*"] },
|
|
147
|
-
"to": { "workspace": ["apps/*"] }
|
|
148
|
-
}
|
|
149
|
-
]
|
|
150
|
-
},
|
|
151
|
-
|
|
152
|
-
"ownership": {
|
|
153
|
-
"importCodeowners": true,
|
|
154
|
-
"unownedSeverity": "warn"
|
|
155
261
|
}
|
|
156
262
|
}
|
|
157
263
|
```
|
|
158
264
|
|
|
159
|
-
Full schema reference is bundled at `node_modules/pruneguard/configuration_schema.json
|
|
265
|
+
Full schema reference is bundled at `node_modules/pruneguard/configuration_schema.json`.
|
|
160
266
|
|
|
161
267
|
---
|
|
162
268
|
|
|
@@ -171,65 +277,116 @@ Full schema reference is bundled at `node_modules/pruneguard/configuration_schem
|
|
|
171
277
|
| **Cycles** | `cycles` | Circular dependency chains (strongly connected components) |
|
|
172
278
|
| **Boundary violations** | `boundaries` | Custom forbidden/required import rules |
|
|
173
279
|
| **Ownership** | `ownership` | Files without a matching team in CODEOWNERS or config |
|
|
174
|
-
| **Impact** |
|
|
280
|
+
| **Impact** | -- | Reverse-reachability blast radius (via `pruneguard impact`) |
|
|
175
281
|
|
|
176
|
-
Each finding includes a **confidence level** (high / medium / low)
|
|
282
|
+
Each finding includes a **confidence level** (high / medium / low) so you always know how much to trust a result.
|
|
177
283
|
|
|
178
284
|
---
|
|
179
285
|
|
|
180
286
|
## Trust model
|
|
181
287
|
|
|
182
|
-
Pruneguard is designed for safe, incremental adoption — not surprise bulk deletions.
|
|
183
|
-
|
|
184
288
|
| Mode | Behavior | Use case |
|
|
185
289
|
|---|---|---|
|
|
186
290
|
| `pruneguard scan` | Full-repo analysis, high-confidence findings | Deletion decisions, CI gating |
|
|
187
291
|
| `--focus "glob"` | Full analysis, findings filtered to matching files | Scoping reports to a team or area |
|
|
188
292
|
| `scan <paths...>` | Partial-scope, findings marked advisory | Quick local checks |
|
|
189
|
-
| `--changed-since ref` |
|
|
293
|
+
| `--changed-since ref` | Full graph, only changed-file findings reported | PR review, fast CI |
|
|
190
294
|
| `--require-full-scope` | Fails if scan would be partial-scope | Strict CI enforcement |
|
|
191
295
|
| `--no-baseline` | No baseline suppression | Deterministic CI, benchmarks |
|
|
192
296
|
|
|
193
|
-
**Recommended deletion flow:**
|
|
194
|
-
|
|
195
|
-
1. `pruneguard scan --format json` — identify candidates
|
|
196
|
-
2. `pruneguard impact <target>` — check blast radius
|
|
197
|
-
3. `pruneguard explain <finding>` — review proof chain
|
|
198
|
-
4. Delete with confidence
|
|
199
|
-
|
|
200
297
|
---
|
|
201
298
|
|
|
202
|
-
##
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
299
|
+
## GitHub Actions
|
|
300
|
+
|
|
301
|
+
### Branch review gate
|
|
302
|
+
|
|
303
|
+
```yaml
|
|
304
|
+
name: pruneguard
|
|
305
|
+
on: [pull_request]
|
|
306
|
+
|
|
307
|
+
jobs:
|
|
308
|
+
review:
|
|
309
|
+
runs-on: ubuntu-latest
|
|
310
|
+
steps:
|
|
311
|
+
- uses: actions/checkout@v5
|
|
312
|
+
with:
|
|
313
|
+
fetch-depth: 0
|
|
314
|
+
- uses: actions/setup-node@v6
|
|
315
|
+
with:
|
|
316
|
+
node-version: 24
|
|
317
|
+
- run: npm install pruneguard
|
|
318
|
+
- name: Branch review
|
|
319
|
+
run: npx pruneguard --changed-since origin/main --format json review
|
|
320
|
+
```
|
|
206
321
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
322
|
+
### Baseline-gated CI
|
|
323
|
+
|
|
324
|
+
```yaml
|
|
325
|
+
name: pruneguard-baseline
|
|
326
|
+
on:
|
|
327
|
+
push:
|
|
328
|
+
branches: [main]
|
|
329
|
+
pull_request:
|
|
330
|
+
|
|
331
|
+
jobs:
|
|
332
|
+
scan:
|
|
333
|
+
runs-on: ubuntu-latest
|
|
334
|
+
steps:
|
|
335
|
+
- uses: actions/checkout@v5
|
|
336
|
+
with:
|
|
337
|
+
fetch-depth: 0
|
|
338
|
+
- uses: actions/setup-node@v6
|
|
339
|
+
with:
|
|
340
|
+
node-version: 24
|
|
341
|
+
- run: npm install pruneguard
|
|
342
|
+
|
|
343
|
+
- name: Save baseline
|
|
344
|
+
if: github.ref == 'refs/heads/main'
|
|
345
|
+
run: npx pruneguard --no-cache --no-baseline --format json scan > baseline.json
|
|
346
|
+
|
|
347
|
+
- uses: actions/upload-artifact@v6
|
|
348
|
+
if: github.ref == 'refs/heads/main'
|
|
349
|
+
with:
|
|
350
|
+
name: pruneguard-baseline
|
|
351
|
+
path: baseline.json
|
|
352
|
+
|
|
353
|
+
- uses: actions/download-artifact@v7
|
|
354
|
+
if: github.event_name == 'pull_request'
|
|
355
|
+
with:
|
|
356
|
+
name: pruneguard-baseline
|
|
357
|
+
continue-on-error: true
|
|
358
|
+
|
|
359
|
+
- name: Check for new findings
|
|
360
|
+
if: github.event_name == 'pull_request'
|
|
361
|
+
run: |
|
|
362
|
+
npx pruneguard --no-cache --no-baseline --format json scan > current.json
|
|
363
|
+
node -e "
|
|
364
|
+
const fs = require('fs');
|
|
365
|
+
if (!fs.existsSync('baseline.json')) { console.log('No baseline, skipping'); process.exit(0); }
|
|
366
|
+
const base = JSON.parse(fs.readFileSync('baseline.json','utf-8'));
|
|
367
|
+
const curr = JSON.parse(fs.readFileSync('current.json','utf-8'));
|
|
368
|
+
const ids = new Set(base.findings.map(f => f.id));
|
|
369
|
+
const n = curr.findings.filter(f => !ids.has(f.id));
|
|
370
|
+
if (n.length) { n.forEach(f => console.error(f.id+': '+f.message)); process.exit(1); }
|
|
371
|
+
console.log('No new findings.');
|
|
372
|
+
"
|
|
373
|
+
```
|
|
212
374
|
|
|
213
|
-
|
|
375
|
+
---
|
|
214
376
|
|
|
215
|
-
|
|
216
|
-
const blast = await impact({ target: "src/utils/helpers.ts" });
|
|
217
|
-
console.log(`Affects ${blast.affectedEntrypoints.length} entrypoints`);
|
|
377
|
+
## Migrating from other tools
|
|
218
378
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
});
|
|
379
|
+
```sh
|
|
380
|
+
pruneguard migrate knip # reads knip.json or package.json#knip
|
|
381
|
+
pruneguard migrate depcruise # reads .dependency-cruiser.* files
|
|
223
382
|
```
|
|
224
383
|
|
|
225
|
-
|
|
384
|
+
Both commands emit an equivalent `pruneguard.json` with migration notes.
|
|
226
385
|
|
|
227
386
|
---
|
|
228
387
|
|
|
229
388
|
## Framework detection
|
|
230
389
|
|
|
231
|
-
Pruneguard auto-detects popular frameworks and registers their entrypoints and file conventions, so test files, stories, and framework config files aren't flagged as unused.
|
|
232
|
-
|
|
233
390
|
| Framework | Auto-detected via | Entrypoints added |
|
|
234
391
|
|---|---|---|
|
|
235
392
|
| **Next.js** | `next` dependency, `next.config.*` | `app/page.*`, `app/layout.*`, `pages/**` |
|
|
@@ -242,31 +399,6 @@ Override with `"frameworks": { "next": "off" }` in config.
|
|
|
242
399
|
|
|
243
400
|
---
|
|
244
401
|
|
|
245
|
-
## Migrating from other tools
|
|
246
|
-
|
|
247
|
-
```sh
|
|
248
|
-
# From knip
|
|
249
|
-
pruneguard migrate knip
|
|
250
|
-
|
|
251
|
-
# From dependency-cruiser
|
|
252
|
-
pruneguard migrate depcruise
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
Both commands read your existing config and emit an equivalent `pruneguard.json` with migration notes.
|
|
256
|
-
|
|
257
|
-
---
|
|
258
|
-
|
|
259
|
-
## Output formats
|
|
260
|
-
|
|
261
|
-
| Format | Flag | Use case |
|
|
262
|
-
|---|---|---|
|
|
263
|
-
| **Text** | `--format text` | Human-readable terminal output (default) |
|
|
264
|
-
| **JSON** | `--format json` | CI pipelines, scripts, programmatic consumption |
|
|
265
|
-
| **SARIF** | `--format sarif` | GitHub Code Scanning, Azure DevOps, IDE integrations |
|
|
266
|
-
| **DOT** | `--format dot` | Graph visualization with Graphviz |
|
|
267
|
-
|
|
268
|
-
---
|
|
269
|
-
|
|
270
402
|
## Requirements
|
|
271
403
|
|
|
272
404
|
- Node.js >= 18
|
package/bin/pruneguard
CHANGED
|
File without changes
|
package/dist/bin.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { n as binaryPath, t as PruneguardExecutionError } from "./runtime-
|
|
2
|
+
import { n as binaryPath, t as PruneguardExecutionError } from "./runtime-BSHQsTbN.mjs";
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
4
|
//#region src-js/bin.ts
|
|
5
5
|
try {
|
|
@@ -9,6 +9,10 @@ try {
|
|
|
9
9
|
"SIGTERM",
|
|
10
10
|
"SIGHUP"
|
|
11
11
|
]) process.on(sig, () => child.kill(sig));
|
|
12
|
+
child.on("error", (err) => {
|
|
13
|
+
console.error(`pruneguard: failed to execute binary: ${err.message}`);
|
|
14
|
+
process.exitCode = 2;
|
|
15
|
+
});
|
|
12
16
|
child.on("close", (code, signal) => {
|
|
13
17
|
if (signal) process.kill(process.pid, signal);
|
|
14
18
|
else process.exitCode = code ?? 1;
|