depfresh 0.10.1 → 0.11.1

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
@@ -18,7 +18,7 @@ Spiritual successor to [taze](https://github.com/antfu/taze) by Anthony Fu -- a
18
18
  - **Per-package modes** -- `packageMode` lets you set exact, glob, or regex patterns per dependency.
19
19
  - **Write safely** -- `--write` updates files. `--verify-command` tests each dep individually and reverts failures.
20
20
  - **Post-write hooks** -- `--execute`, `--install`, `--update`. Chain commands after writing.
21
- - **Global packages** -- `--global` checks npm, pnpm, and bun globals.
21
+ - **Global packages** -- `--global` checks one detected manager, `--global-all` scans npm + pnpm + bun with deduped package names.
22
22
  - **Private registries** -- full `.npmrc` support. Scoped registries, auth tokens, env vars. Fixed from day one.
23
23
  - **JSON output** -- structured envelope for scripts and AI agents. No ANSI noise.
24
24
  - **CI mode** -- `--fail-on-outdated` exits with code 1. Plug it into your pipeline.
@@ -29,13 +29,15 @@ Spiritual successor to [taze](https://github.com/antfu/taze) by Anthony Fu -- a
29
29
  - **Sorting** -- 6 strategies: by diff severity, publish time, or name.
30
30
  - **CRLF preservation** -- Windows line endings survive the write. You're welcome.
31
31
  - **Nested workspace detection** -- auto-skips monorepos inside monorepos.
32
- - **Programmatic API** -- 9 exported functions, 7 lifecycle callbacks, full type safety.
32
+ - **Programmatic API** -- lifecycle callbacks + addon system for custom workflows.
33
33
 
34
34
  ## Why
35
35
 
36
36
  Because `npm outdated` gives you a table and then abandons you. Because Renovate requires a PhD in YAML. Because your AI coding assistant should be able to update your deps without you holding its hand.
37
37
 
38
- depfresh checks every `package.json` in your project, tells you what's outdated, and optionally writes the updates. Monorepos, workspace catalogs, private registries - it handles all of it without a config file.
38
+ depfresh checks every package manifest (`package.json`, `package.yaml`) in your project, tells you what's outdated, and optionally writes the updates. Monorepos, workspace catalogs, private registries - it handles all of it without a config file.
39
+
40
+ If both `package.yaml` and `package.json` exist in the same directory, depfresh uses `package.yaml` and skips the sibling `package.json` to avoid duplicate package entries.
39
41
 
40
42
  ## Install
41
43
 
@@ -85,6 +87,16 @@ depfresh -w --verify-command "pnpm test"
85
87
 
86
88
  # CI: fail if anything is outdated
87
89
  depfresh --fail-on-outdated
90
+
91
+ # Skip specific directories from recursive scan
92
+ depfresh --ignore-paths "apps/legacy/**,examples/**"
93
+
94
+ # Bypass cache for one run (same behavior)
95
+ depfresh --refresh-cache
96
+ depfresh --no-cache
97
+
98
+ # Check globals across npm + pnpm + bun (deduped names)
99
+ depfresh --global-all
88
100
  ```
89
101
 
90
102
  ## CLI Flags
@@ -93,14 +105,18 @@ The top flags to get you started. Full reference with all 27+ flags: **[docs/cli
93
105
 
94
106
  | Flag | Alias | Default | Description |
95
107
  |------|-------|---------|-------------|
96
- | `--recursive` | `-r` | `true` | Recursively search for package.json files |
108
+ | `--recursive` | `-r` | `true` | Recursively search for package manifests (`package.json`, `package.yaml`) |
97
109
  | `--write` | `-w` | `false` | Write updated versions to package files |
98
110
  | `--interactive` | `-I` | `false` | Select which deps to update |
99
111
  | `--mode` | `-m` | `default` | Range mode: `default` `major` `minor` `patch` `latest` `newest` `next` |
100
112
  | `--include` | `-n` | -- | Only include packages matching regex (comma-separated) |
101
113
  | `--exclude` | `-x` | -- | Exclude packages matching regex (comma-separated) |
102
- | `--force` | `-f` | `false` | Force update even if version is satisfied |
103
- | `--global` | `-g` | `false` | Check global packages |
114
+ | `--ignore-paths` | -- | -- | Extra ignore globs (comma-separated), merged with default ignored paths |
115
+ | `--force` | `-f` | `false` | Force update even if version is satisfied (does not bypass cache) |
116
+ | `--refresh-cache` | -- | `false` | Bypass cache reads and fetch fresh metadata for this run |
117
+ | `--no-cache` | -- | `false` | Alias for `--refresh-cache` |
118
+ | `--global` | `-g` | `false` | Check global packages for one detected package manager |
119
+ | `--global-all` | -- | `false` | Check global packages across npm, pnpm, and bun with deduped package names |
104
120
  | `--output` | `-o` | `table` | Output format: `table` `json` |
105
121
  | `--execute` | `-e` | -- | Run command after writing (e.g. `"pnpm test"`) |
106
122
  | `--verify-command` | `-V` | -- | Run command per dep, revert on failure |
@@ -126,6 +142,22 @@ export default defineConfig({
126
142
  })
127
143
  ```
128
144
 
145
+ Addon example (programmatic API):
146
+
147
+ ```typescript
148
+ import { check, resolveConfig, type depfreshAddon } from 'depfresh'
149
+
150
+ const addon: depfreshAddon = {
151
+ name: 'audit-log',
152
+ afterPackageWrite(_ctx, pkg, changes) {
153
+ console.log(`updated ${pkg.name}: ${changes.length} changes`)
154
+ },
155
+ }
156
+
157
+ const options = await resolveConfig({ write: true, addons: [addon] })
158
+ await check(options)
159
+ ```
160
+
129
161
  Full options reference: **[docs/configuration/](docs/configuration/)**
130
162
 
131
163
  ## JSON Output
@@ -244,7 +276,7 @@ const options = await resolveConfig({
244
276
  const exitCode = await check(options)
245
277
  ```
246
278
 
247
- 9 exported functions, 7 lifecycle callbacks, 16+ types. Full API reference: **[docs/api/](docs/api/)**
279
+ Programmatic API with lifecycle callbacks, addon plugins, and full typed exports. Full reference: **[docs/api/](docs/api/)**
248
280
 
249
281
  ## Monorepo Support
250
282
 
@@ -253,11 +285,11 @@ depfresh auto-detects workspace structures. No config needed.
253
285
  | Package Manager | Workspaces | Catalogs |
254
286
  |----------------|------------|----------|
255
287
  | pnpm | `pnpm-workspace.yaml` | `catalog:` protocol |
256
- | Bun | `workspaces` in `package.json` | `workspaces.catalog` |
257
- | Yarn | `workspaces` in `package.json` | `.yarnrc.yml` catalogs |
258
- | npm | `workspaces` in `package.json` | -- |
288
+ | Bun | `workspaces` in `package.json` or `package.yaml` | `workspaces.catalog` |
289
+ | Yarn | `workspaces` in `package.json` or `package.yaml` | `.yarnrc.yml` catalogs |
290
+ | npm | `workspaces` in `package.json` or `package.yaml` | -- |
259
291
 
260
- Workspace catalogs are resolved and updated in-place. Your `pnpm-workspace.yaml` catalog entries get depfreshaded alongside your `package.json` deps. No manual sync needed.
292
+ Workspace catalogs are resolved and updated in-place. Your `pnpm-workspace.yaml` catalog entries get depfreshaded alongside your manifest deps (`package.json` / `package.yaml`). No manual sync needed.
261
293
 
262
294
  ## Private Registries
263
295
 
@@ -271,22 +303,59 @@ depfresh reads `.npmrc` from your project and home directory. Scoped registries,
271
303
 
272
304
  This was broken in taze for 4+ years. I fixed it on day one. You're welcome.
273
305
 
274
- ## What I Fixed from taze
275
-
276
- Not to throw shade at taze -- it served the community well for years. But some things needed fixing, and "PR welcome" only goes so far when the PRs sit open for months.
277
-
278
- | Problem | taze | depfresh |
279
- |---------|------|------|
280
- | `.npmrc` / private registries | Ignored | Full support |
281
- | Network retry | None | Exponential backoff |
282
- | Write clobber (bun catalogs) | Data loss | Single-writer architecture |
283
- | Version resolution ordering | Assumed sorted arrays | Explicit semver comparison |
284
- | Interactive mode | Flickery | @clack/prompts |
285
- | JSON output | None | Structured envelope |
286
- | Dep type filtering | None | `--deps-only` / `--dev-only` |
287
- | Config merging | deepmerge (CJS) | defu (ESM) |
288
- | npm config loading | @npmcli/config (heavy, hacky) | Direct ini parsing |
289
- | Cache | JSON file (race conditions) | SQLite with WAL mode |
306
+ ## depfresh vs taze
307
+
308
+ Verified against taze v19.9.2 (commit `31c6fe8`, 2026-01-20). Not marketing. Real code inspection, runtime test runs, CLI smoke checks on actual repos.
309
+
310
+ ### Feature parity (both have it)
311
+
312
+ | Feature | taze | depfresh | Notes |
313
+ |---------|------|----------|-------|
314
+ | 7 range modes | yes | yes | |
315
+ | Include/exclude filters | yes | yes | depfresh adds glob patterns alongside regex |
316
+ | Interactive TUI | yes | yes | Both have vim keys + per-version selection |
317
+ | `--cwd` | yes | yes | |
318
+ | `--fail-on-outdated` | yes | yes | |
319
+ | `package.yaml` support | yes | yes | |
320
+ | Addon/plugin API | yes | yes | |
321
+ | pnpm catalogs | yes | yes | |
322
+ | Yarn catalogs | yes | yes | |
323
+ | CRLF preservation | yes | yes | |
324
+ | CJK width handling | yes | yes | |
325
+
326
+ ### Where depfresh is ahead
327
+
328
+ | Feature | taze | depfresh |
329
+ |---------|------|----------|
330
+ | JSON output envelope | no ([#201](https://github.com/antfu-collective/taze/issues/201) open) | Structured envelope with schema version |
331
+ | Machine-readable CLI contract | no | `--help-json` with workflows, flag relationships, schema |
332
+ | `--deps-only` / `--dev-only` | no ([#101](https://github.com/antfu-collective/taze/issues/101) open) | yes |
333
+ | `packageMode` precedence | buggy ([#91](https://github.com/antfu-collective/taze/issues/91) open) | Deterministic |
334
+ | Global package breadth | npm + pnpm | npm + pnpm + bun (`--global-all`) |
335
+ | Bun catalog writes | Bug history, data loss risk | Single-writer architecture, tested |
336
+ | `.npmrc` / private registries | Ignored for years | Full support from day one |
337
+ | `.npmrc` transport (proxy/TLS/CA) | Parsed, not applied | Applied via `undici` transport adapter |
338
+ | Network retry | None | Exponential backoff, non-transient errors fail fast |
339
+ | Cache | JSON file (race conditions) | SQLite WAL mode, memory fallback |
340
+ | Verify + rollback | no | `--verify-command` tests each dep, reverts failures |
341
+ | Typed error hierarchy | Limited | Structured subclasses with `.code` and `.cause` |
342
+ | Structured JSON errors | no | JSON error envelope with `error.code`, `error.retryable` |
343
+ | Explicit cache bypass | no | `--refresh-cache` / `--no-cache` |
344
+
345
+ ### Where taze is ahead
346
+
347
+ | Area | Why |
348
+ |------|-----|
349
+ | Ecosystem adoption | 4,061 stars, years of trust, larger user base |
350
+ | npm config edge cases | `@npmcli/config` may cover obscure auth patterns we haven't hit yet |
351
+
352
+ ### Numbers
353
+
354
+ | Metric | taze v19.9.2 | depfresh v0.11.0 |
355
+ |--------|-------------:|------------------:|
356
+ | Test files | 13 | 77 |
357
+ | Passing tests | 55 | 598 |
358
+ | CLI flags | 24 | 36 |
290
359
 
291
360
  ## Documentation
292
361
 
@@ -294,7 +363,7 @@ The full docs, for people who read manuals before assembling furniture.
294
363
 
295
364
  - **[CLI Reference](docs/cli/)** -- all 27+ flags, modes, sorting, filtering, hooks, interactive, CI, workspaces
296
365
  - **[Configuration](docs/configuration/)** -- config files, every option, packageMode, depFields, private registries, cache
297
- - **[Programmatic API](docs/api/)** -- exported functions, lifecycle callbacks, types, workflow examples
366
+ - **[Programmatic API](docs/api/)** -- exported functions, lifecycle callbacks, addon plugins, types, workflow examples
298
367
  - **[Output Formats](docs/output-formats/)** -- table, JSON, exit codes, AI agent integration
299
368
  - **[Agent Workflows](docs/agents/README.md)** -- copy-paste quickstarts for Codex, Claude Code, and Gemini CLI
300
369
  - **[Integrations](docs/integrations/README.md)** -- GitHub Actions and thin MCP wrapper guidance
@@ -6,7 +6,7 @@ import 'node:fs/promises';
6
6
  import 'node:url';
7
7
  import 'defu';
8
8
  import 'pathe';
9
- import '../shared/depfresh.FmznAfq4.mjs';
9
+ import '../shared/depfresh.CHHNqHXD.mjs';
10
10
  import '../shared/depfresh.Dxgqypc6.mjs';
11
11
  import 'ansis';
12
12
 
@@ -50,7 +50,7 @@ const FLAG_RELATIONSHIPS = {
50
50
  };
51
51
  const JSON_OUTPUT_SCHEMA = {
52
52
  "packages[]": "Array of scanned packages with their updates",
53
- "packages[].name": "Package name from package.json",
53
+ "packages[].name": "Package name from package manifest",
54
54
  "packages[].updates[]": "Array of dependencies with available updates",
55
55
  "packages[].updates[].name": "Dependency name",
56
56
  "packages[].updates[].current": "Current version range",
@@ -2,7 +2,7 @@ import { readFile, access } from 'node:fs/promises';
2
2
  import { pathToFileURL } from 'node:url';
3
3
  import { defu } from 'defu';
4
4
  import { join } from 'pathe';
5
- import { C as ConfigError } from '../shared/depfresh.FmznAfq4.mjs';
5
+ import { C as ConfigError } from '../shared/depfresh.CHHNqHXD.mjs';
6
6
  import { c as createLogger } from '../shared/depfresh.Dxgqypc6.mjs';
7
7
 
8
8
  const DEFAULT_OPTIONS = {
@@ -18,10 +18,12 @@ const DEFAULT_OPTIONS = {
18
18
  timeout: 1e4,
19
19
  retries: 2,
20
20
  cacheTTL: 30 * 60 * 1e3,
21
+ refreshCache: false,
21
22
  output: "table",
22
23
  loglevel: "info",
23
24
  peer: false,
24
25
  global: false,
26
+ globalAll: false,
25
27
  ignorePaths: ["**/node_modules/**", "**/dist/**", "**/coverage/**", "**/.git/**"],
26
28
  ignoreOtherWorkspaces: true,
27
29
  all: false,
@@ -1,5 +1,5 @@
1
- import { c as check } from '../shared/depfresh.BkxecpDK.mjs';
2
- export { d as detectPackageManager } from '../shared/depfresh.BkxecpDK.mjs';
1
+ import { c as check } from '../shared/depfresh.C-me_t4a.mjs';
2
+ export { d as detectPackageManager } from '../shared/depfresh.C-me_t4a.mjs';
3
3
  import 'ansis';
4
4
  import '../shared/depfresh.Dxgqypc6.mjs';
5
5
  import 'node:fs';
@@ -9,13 +9,15 @@ import 'ini';
9
9
  import 'pathe';
10
10
  import './json-output.mjs';
11
11
  import 'node:child_process';
12
- import '../shared/depfresh.FmznAfq4.mjs';
12
+ import '../shared/depfresh.CHHNqHXD.mjs';
13
13
  import 'detect-indent';
14
14
  import 'semver';
15
15
  import 'pnpm-workspace-yaml';
16
16
  import 'yaml';
17
17
  import 'p-limit';
18
+ import 'undici';
18
19
  import 'better-sqlite3';
20
+ import 'node:crypto';
19
21
  import 'tinyglobby';
20
22
 
21
23
 
@@ -1,6 +1,6 @@
1
1
  import * as readline from 'node:readline';
2
2
  import * as semver from 'semver';
3
- import { g as getVersionPrefix, f as applyVersionPrefix, h as getDiff, t as timeDifference, s as stripAnsi, i as truncate, j as padEnd, b as colorizeVersionDiff, a as arrow, e as colorDiff } from '../shared/depfresh.BkxecpDK.mjs';
3
+ import { g as getVersionPrefix, f as applyVersionPrefix, h as getDiff, t as timeDifference, s as stripAnsi, i as truncate, j as padEnd, b as colorizeVersionDiff, a as arrow, e as colorDiff } from '../shared/depfresh.C-me_t4a.mjs';
4
4
  import c from 'ansis';
5
5
  import '../shared/depfresh.Dxgqypc6.mjs';
6
6
  import 'node:fs';
@@ -10,12 +10,14 @@ import 'ini';
10
10
  import 'pathe';
11
11
  import './json-output.mjs';
12
12
  import 'node:child_process';
13
- import '../shared/depfresh.FmznAfq4.mjs';
13
+ import '../shared/depfresh.CHHNqHXD.mjs';
14
14
  import 'detect-indent';
15
15
  import 'pnpm-workspace-yaml';
16
16
  import 'yaml';
17
17
  import 'p-limit';
18
+ import 'undici';
18
19
  import 'better-sqlite3';
20
+ import 'node:crypto';
19
21
  import 'tinyglobby';
20
22
 
21
23
  const MAX_VERSIONS = 20;
@@ -1,8 +1,73 @@
1
1
  import './config.mjs';
2
- import '../shared/depfresh.FmznAfq4.mjs';
2
+ import '../shared/depfresh.CHHNqHXD.mjs';
3
3
  import { execSync } from 'node:child_process';
4
4
  import { c as createLogger } from '../shared/depfresh.Dxgqypc6.mjs';
5
- import '../shared/depfresh.BkxecpDK.mjs';
5
+ import '../shared/depfresh.C-me_t4a.mjs';
6
+
7
+ function addonVSCode(pkg, changes) {
8
+ const vscodeChange = changes.find((c) => c.name === "@types/vscode");
9
+ if (!vscodeChange) return;
10
+ const raw = pkg.raw;
11
+ if (raw.engines && typeof raw.engines === "object") {
12
+ const engines = raw.engines;
13
+ if (engines.vscode) {
14
+ engines.vscode = `^${vscodeChange.targetVersion}`;
15
+ }
16
+ }
17
+ }
18
+ function createVSCodeAddon() {
19
+ return {
20
+ name: "vscode-engine-sync",
21
+ beforePackageWrite(_ctx, pkg, changes) {
22
+ addonVSCode(pkg, changes);
23
+ return true;
24
+ }
25
+ };
26
+ }
27
+
28
+ const GLOBAL_ALL_PACKAGE_MANAGERS = ["npm", "pnpm", "bun"];
29
+ function isPackageManagerName(value) {
30
+ return value === "npm" || value === "pnpm" || value === "bun" || value === "yarn";
31
+ }
32
+ function dedupeGlobalPackageRecords(records) {
33
+ const byName = /* @__PURE__ */ new Map();
34
+ for (const record of records) {
35
+ const existing = byName.get(record.name);
36
+ if (!existing) {
37
+ byName.set(record.name, {
38
+ version: record.version,
39
+ managers: /* @__PURE__ */ new Set([record.manager])
40
+ });
41
+ continue;
42
+ }
43
+ existing.managers.add(record.manager);
44
+ }
45
+ const sortedEntries = [...byName.entries()].sort(([a], [b]) => a.localeCompare(b));
46
+ const packages = sortedEntries.map(([name, value]) => ({
47
+ name,
48
+ version: value.version
49
+ }));
50
+ const managersByDependency = Object.fromEntries(
51
+ sortedEntries.map(([name, value]) => [name, [...value.managers]])
52
+ );
53
+ return { packages, managersByDependency };
54
+ }
55
+ function getGlobalWriteTargets(pkg, depName) {
56
+ const raw = pkg.raw;
57
+ const mappedTargets = raw.managersByDependency?.[depName];
58
+ if (mappedTargets && mappedTargets.length > 0) {
59
+ return [...new Set(mappedTargets)];
60
+ }
61
+ if (!pkg.filepath.startsWith("global:")) {
62
+ return [];
63
+ }
64
+ const suffix = pkg.filepath.slice("global:".length);
65
+ if (!suffix) {
66
+ return [];
67
+ }
68
+ const parsedTargets = suffix.split("+").map((name) => name.trim()).filter((name) => name.length > 0 && isPackageManagerName(name));
69
+ return [...new Set(parsedTargets)];
70
+ }
6
71
 
7
72
  function detectGlobalPackageManager(pm) {
8
73
  if (pm && (pm === "npm" || pm === "pnpm" || pm === "bun")) {
@@ -110,6 +175,39 @@ function loadGlobalPackages(pm) {
110
175
  }
111
176
  ];
112
177
  }
178
+ function loadGlobalPackagesAll() {
179
+ const records = GLOBAL_ALL_PACKAGE_MANAGERS.flatMap(
180
+ (manager) => listGlobalPackages(manager).map((pkg) => ({
181
+ manager,
182
+ name: pkg.name,
183
+ version: pkg.version
184
+ }))
185
+ );
186
+ if (records.length === 0) {
187
+ return [];
188
+ }
189
+ const deduped = dedupeGlobalPackageRecords(records);
190
+ const deps = deduped.packages.map((pkg) => ({
191
+ name: pkg.name,
192
+ currentVersion: pkg.version,
193
+ source: "dependencies",
194
+ update: true,
195
+ parents: []
196
+ }));
197
+ return [
198
+ {
199
+ name: "Global packages",
200
+ type: "global",
201
+ filepath: `global:${GLOBAL_ALL_PACKAGE_MANAGERS.join("+")}`,
202
+ deps,
203
+ resolved: [],
204
+ raw: {
205
+ managersByDependency: deduped.managersByDependency
206
+ },
207
+ indent: " "
208
+ }
209
+ ];
210
+ }
113
211
  function writeGlobalPackage(pm, name, version) {
114
212
  const logger = createLogger("info");
115
213
  switch (pm) {
@@ -131,8 +229,10 @@ function writeGlobalPackage(pm, name, version) {
131
229
  const global = {
132
230
  __proto__: null,
133
231
  detectGlobalPackageManager: detectGlobalPackageManager,
232
+ getGlobalWriteTargets: getGlobalWriteTargets,
134
233
  listGlobalPackages: listGlobalPackages,
135
234
  loadGlobalPackages: loadGlobalPackages,
235
+ loadGlobalPackagesAll: loadGlobalPackagesAll,
136
236
  parseBunGlobalList: parseBunGlobalList,
137
237
  parseNpmGlobalList: parseNpmGlobalList,
138
238
  parsePnpmGlobalList: parsePnpmGlobalList,
@@ -143,4 +243,4 @@ function defineConfig(options) {
143
243
  return options;
144
244
  }
145
245
 
146
- export { defineConfig as d, global as g, loadGlobalPackages as l, writeGlobalPackage as w };
246
+ export { addonVSCode as a, loadGlobalPackagesAll as b, createVSCodeAddon as c, defineConfig as d, global as g, loadGlobalPackages as l, writeGlobalPackage as w };
@@ -1,6 +1,6 @@
1
1
  import * as p from '@clack/prompts';
2
2
  import c from 'ansis';
3
- import { a as arrow, b as colorizeVersionDiff, e as colorDiff } from '../shared/depfresh.BkxecpDK.mjs';
3
+ import { a as arrow, b as colorizeVersionDiff, e as colorDiff } from '../shared/depfresh.C-me_t4a.mjs';
4
4
  import '../shared/depfresh.Dxgqypc6.mjs';
5
5
  import 'node:fs';
6
6
  import 'node:os';
@@ -9,13 +9,15 @@ import 'ini';
9
9
  import 'pathe';
10
10
  import './json-output.mjs';
11
11
  import 'node:child_process';
12
- import '../shared/depfresh.FmznAfq4.mjs';
12
+ import '../shared/depfresh.CHHNqHXD.mjs';
13
13
  import 'detect-indent';
14
14
  import 'semver';
15
15
  import 'pnpm-workspace-yaml';
16
16
  import 'yaml';
17
17
  import 'p-limit';
18
+ import 'undici';
18
19
  import 'better-sqlite3';
20
+ import 'node:crypto';
19
21
  import 'tinyglobby';
20
22
 
21
23
  const DIFF_GROUP_ORDER = ["major", "minor", "patch"];
@@ -1,6 +1,14 @@
1
- import { C as ConfigError } from '../shared/depfresh.FmznAfq4.mjs';
1
+ import { C as ConfigError } from '../shared/depfresh.CHHNqHXD.mjs';
2
2
  import { a as VALID_SORT_OPTIONS, V as VALID_LOG_LEVELS, b as VALID_OUTPUTS, c as VALID_MODES } from '../shared/depfresh.CFLB6fqi.mjs';
3
3
 
4
+ function parseCommaSeparatedArg(value) {
5
+ if (typeof value !== "string") {
6
+ return void 0;
7
+ }
8
+ const items = value.split(",").map((item) => item.trim()).filter((item) => item.length > 0);
9
+ return items.length > 0 ? items : void 0;
10
+ }
11
+
4
12
  function validateEnum(value, flagName, validValues) {
5
13
  if (typeof value !== "string" || !validValues.includes(value)) {
6
14
  throw new ConfigError(
@@ -11,6 +19,7 @@ function validateEnum(value, flagName, validValues) {
11
19
  }
12
20
  async function normalizeArgs(args) {
13
21
  const { resolveConfig } = await import('./config.mjs').then(function (n) { return n.c; });
22
+ const globalAll = args["global-all"];
14
23
  const depFields = {};
15
24
  if (args["deps-only"]) {
16
25
  depFields.devDependencies = false;
@@ -27,8 +36,10 @@ async function normalizeArgs(args) {
27
36
  const output = validateEnum(args.output, "--output", VALID_OUTPUTS);
28
37
  const sort = validateEnum(args.sort, "--sort", VALID_SORT_OPTIONS);
29
38
  const loglevel = validateEnum(args.loglevel, "--loglevel", VALID_LOG_LEVELS);
30
- const include = typeof args.include === "string" ? args.include.split(",").map((s) => s.trim()) : void 0;
31
- const exclude = typeof args.exclude === "string" ? args.exclude.split(",").map((s) => s.trim()) : void 0;
39
+ const include = parseCommaSeparatedArg(args.include);
40
+ const exclude = parseCommaSeparatedArg(args.exclude);
41
+ const ignorePaths = parseCommaSeparatedArg(args["ignore-paths"]);
42
+ const refreshCache = Boolean(args["refresh-cache"] || args["no-cache"]);
32
43
  return resolveConfig({
33
44
  cwd: args.cwd || process.cwd(),
34
45
  recursive: args.recursive,
@@ -37,8 +48,11 @@ async function normalizeArgs(args) {
37
48
  mode,
38
49
  include,
39
50
  exclude,
51
+ ignorePaths,
40
52
  force: args.force,
41
- global: args.global,
53
+ refreshCache,
54
+ global: args.global || globalAll,
55
+ globalAll,
42
56
  peer: args.peer,
43
57
  includeLocked: args["include-locked"],
44
58
  output,
package/dist/cli.mjs CHANGED
@@ -1,7 +1,24 @@
1
1
  #!/usr/bin/env node
2
2
  import { defineCommand, runMain } from 'citty';
3
3
 
4
- const version = "0.10.1";
4
+ const version = "0.11.1";
5
+
6
+ const migrationParityArgs = {
7
+ "ignore-paths": {
8
+ type: "string",
9
+ description: "Additional ignore glob patterns (comma-separated)"
10
+ },
11
+ "refresh-cache": {
12
+ type: "boolean",
13
+ description: "Bypass cache reads and fetch fresh registry metadata",
14
+ default: false
15
+ },
16
+ "no-cache": {
17
+ type: "boolean",
18
+ description: "Alias for --refresh-cache (cache bypass for this run)",
19
+ default: false
20
+ }
21
+ };
5
22
 
6
23
  const args = {
7
24
  mode_arg: {
@@ -17,7 +34,7 @@ const args = {
17
34
  recursive: {
18
35
  type: "boolean",
19
36
  alias: "r",
20
- description: "Recursively search for package.json in subdirectories",
37
+ description: "Recursively search for package manifests (package.json, package.yaml) in subdirectories",
21
38
  default: true
22
39
  },
23
40
  write: {
@@ -57,7 +74,12 @@ const args = {
57
74
  global: {
58
75
  type: "boolean",
59
76
  alias: "g",
60
- description: "Check global packages",
77
+ description: "Check global packages for one detected package manager",
78
+ default: false
79
+ },
80
+ "global-all": {
81
+ type: "boolean",
82
+ description: "Check global packages across npm, pnpm, and bun with deduped names",
61
83
  default: false
62
84
  },
63
85
  peer: {
@@ -186,7 +208,8 @@ const args = {
186
208
  type: "boolean",
187
209
  description: "Skip packages that belong to nested/separate workspaces",
188
210
  default: true
189
- }
211
+ },
212
+ ...migrationParityArgs
190
213
  };
191
214
 
192
215
  function normalizeCliRawArgs(rawArgs) {
@@ -205,6 +228,11 @@ const main = defineCommand({
205
228
  args,
206
229
  async run({ args: args2 }) {
207
230
  try {
231
+ if (args2.mode_arg === "help") {
232
+ const { showUsage } = await import('citty');
233
+ await showUsage(main);
234
+ process.exit(0);
235
+ }
208
236
  if (args2["help-json"]) {
209
237
  const { outputCliCapabilities } = await import('./chunks/capabilities.mjs');
210
238
  outputCliCapabilities();
package/dist/index.d.mts CHANGED
@@ -107,10 +107,12 @@ interface depfreshOptions {
107
107
  timeout: number;
108
108
  retries: number;
109
109
  cacheTTL: number;
110
+ refreshCache?: boolean;
110
111
  output: OutputFormat;
111
112
  loglevel: 'silent' | 'info' | 'debug';
112
113
  peer: boolean;
113
114
  global: boolean;
115
+ globalAll?: boolean;
114
116
  ignorePaths: string[];
115
117
  ignoreOtherWorkspaces: boolean;
116
118
  all: boolean;
@@ -126,6 +128,7 @@ interface depfreshOptions {
126
128
  update: boolean;
127
129
  execute?: string;
128
130
  verifyCommand?: string;
131
+ addons?: depfreshAddon[];
129
132
  beforePackageStart?: (pkg: PackageMeta) => void | Promise<void>;
130
133
  onDependencyResolved?: (pkg: PackageMeta, dep: ResolvedDepChange) => void | Promise<void>;
131
134
  beforePackageWrite?: (pkg: PackageMeta) => boolean | Promise<boolean>;
@@ -136,6 +139,30 @@ interface depfreshOptions {
136
139
  }
137
140
  declare const DEFAULT_OPTIONS: Partial<depfreshOptions>;
138
141
 
142
+ type AddonHookName = 'setup' | 'afterPackagesLoaded' | 'beforePackageStart' | 'onDependencyResolved' | 'beforePackageWrite' | 'afterPackageWrite' | 'afterPackageEnd' | 'afterPackagesEnd';
143
+ interface AddonContext {
144
+ readonly options: depfreshOptions;
145
+ readonly runId: string;
146
+ readonly startedAt: Date;
147
+ }
148
+ interface depfreshAddon {
149
+ name: string;
150
+ setup?: (ctx: AddonContext) => void | Promise<void>;
151
+ afterPackagesLoaded?: (ctx: AddonContext, pkgs: PackageMeta[]) => void | Promise<void>;
152
+ beforePackageStart?: (ctx: AddonContext, pkg: PackageMeta) => void | Promise<void>;
153
+ onDependencyResolved?: (ctx: AddonContext, pkg: PackageMeta, dep: ResolvedDepChange) => void | Promise<void>;
154
+ beforePackageWrite?: (ctx: AddonContext, pkg: PackageMeta, changes: ResolvedDepChange[]) => boolean | Promise<boolean>;
155
+ afterPackageWrite?: (ctx: AddonContext, pkg: PackageMeta, changes: ResolvedDepChange[]) => void | Promise<void>;
156
+ afterPackageEnd?: (ctx: AddonContext, pkg: PackageMeta) => void | Promise<void>;
157
+ afterPackagesEnd?: (ctx: AddonContext, pkgs: PackageMeta[]) => void | Promise<void>;
158
+ }
159
+
160
+ /**
161
+ * Syncs engines.vscode with @types/vscode version in settings.json
162
+ */
163
+ declare function addonVSCode(pkg: PackageMeta, changes: ResolvedDepChange[]): void;
164
+ declare function createVSCodeAddon(): depfreshAddon;
165
+
139
166
  declare function check(options: depfreshOptions): Promise<number>;
140
167
 
141
168
  declare function resolveConfig(overrides?: Partial<depfreshOptions>): Promise<depfreshOptions>;
@@ -169,10 +196,16 @@ declare class WriteError extends depfreshError {
169
196
  declare class ResolveError extends depfreshError {
170
197
  constructor(message: string, options?: depfreshErrorOptions);
171
198
  }
199
+ declare class AddonError extends depfreshError {
200
+ readonly addon: string;
201
+ readonly hook: string;
202
+ constructor(message: string, addon: string, hook: string, options?: depfreshErrorOptions);
203
+ }
172
204
 
173
205
  declare function parseDependencies(raw: Record<string, unknown>, options: depfreshOptions): RawDep[];
174
206
 
175
207
  declare function loadGlobalPackages(pm?: string): PackageMeta[];
208
+ declare function loadGlobalPackagesAll(): PackageMeta[];
176
209
  declare function writeGlobalPackage(pm: PackageManagerName, name: string, version: string): void;
177
210
 
178
211
  declare function loadPackages(options: depfreshOptions): Promise<PackageMeta[]>;
@@ -200,5 +233,5 @@ declare function writePackage(pkg: PackageMeta, changes: ResolvedDepChange[], lo
200
233
 
201
234
  declare function defineConfig(options: Partial<depfreshOptions>): Partial<depfreshOptions>;
202
235
 
203
- export { CacheError, ConfigError, DEFAULT_OPTIONS, RegistryError, ResolveError, WriteError, check, defineConfig, depfreshError, loadGlobalPackages, loadPackages, parseDependencies, resolveConfig, resolvePackage, writeGlobalPackage, writePackage };
204
- export type { CatalogSource, DepFieldType, DiffType, NpmrcConfig, OutputFormat, PackageData, PackageManagerField, PackageManagerName, PackageMeta, PackageType, ProvenanceLevel, RangeMode, RawDep, RegistryConfig, ResolvedDepChange, SortOption, UpdateScore, depfreshOptions };
236
+ export { AddonError, CacheError, ConfigError, DEFAULT_OPTIONS, RegistryError, ResolveError, WriteError, addonVSCode, check, createVSCodeAddon, defineConfig, depfreshError, loadGlobalPackages, loadGlobalPackagesAll, loadPackages, parseDependencies, resolveConfig, resolvePackage, writeGlobalPackage, writePackage };
237
+ export type { AddonContext, AddonHookName, CatalogSource, DepFieldType, DiffType, NpmrcConfig, OutputFormat, PackageData, PackageManagerField, PackageManagerName, PackageMeta, PackageType, ProvenanceLevel, RangeMode, RawDep, RegistryConfig, ResolvedDepChange, SortOption, UpdateScore, depfreshAddon, depfreshOptions };