slash-do 2.5.0 → 2.7.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.
@@ -1,13 +1,13 @@
1
1
  ---
2
2
  description: Audit third-party dependencies and remove unnecessary ones by writing replacement code
3
- argument-hint: "[--interactive] [--scan-only] [--no-merge] [specific packages to evaluate]"
3
+ argument-hint: "[--interactive] [--scan-only] [--no-merge] [--heavy] [specific packages to evaluate]"
4
4
  ---
5
5
 
6
6
  # Depfree — Dependency Freedom Audit
7
7
 
8
8
  Audit all third-party dependencies, classify them as acceptable (large, widely-audited) or suspect (small, replaceable), analyze actual usage of suspect dependencies, and replace them with owned code where feasible.
9
9
 
10
- Every small library is an attack surface. Supply chain compromises are real and common. Large, widely-audited libraries (express, react, d3, three.js, next, vue, fastify, lodash-es, etc.) are acceptable. But for smaller libraries or libraries where only one helper function is used, we should write the code ourselves.
10
+ Every small library is an attack surface. Supply chain compromises are real and common. In default mode, large, widely-audited libraries (express, react, d3, three.js, next, vue, fastify, lodash-es, etc.) are acceptable. But for smaller libraries or libraries where only one helper function is used, we should write the code ourselves. In heavy mode, the acceptability bar is much higher — see the Heavy Mode section below.
11
11
 
12
12
  **Default mode: fully autonomous.** Uses Balanced model profile, proceeds through all phases without prompting.
13
13
 
@@ -17,8 +17,11 @@ Parse `$ARGUMENTS` for:
17
17
  - **`--interactive`**: pause at each decision point for user approval
18
18
  - **`--scan-only`**: run Phase 0 + 1 + 2 only (audit and plan), skip remediation
19
19
  - **`--no-merge`**: run through PR creation, skip merge
20
+ - **`--heavy`**: aggressive mode — only keep foundational frameworks and language runtimes; replace everything else that is feasibly replaceable (see Heavy Mode below)
20
21
  - **Specific packages**: limit audit scope to named packages (e.g., "chalk dotenv")
21
22
 
23
+ Set `HEAVY_MODE` to `true` if `--heavy` was passed, `false` otherwise.
24
+
22
25
  ## Configuration
23
26
 
24
27
  ### Default Mode (autonomous)
@@ -48,6 +51,18 @@ Record the selection as `MODEL_PROFILE` and derive:
48
51
 
49
52
  When the resolved model is `opus`, **omit** the `model` parameter on the Agent call so the agent inherits the session's Opus version.
50
53
 
54
+ ## Heavy Mode (`--heavy`)
55
+
56
+ Heavy mode shifts the philosophy from "remove obvious attack surface" to "own everything we feasibly can." The only dependencies that survive are foundational frameworks, core platform tooling, and language-level runtimes — the kind maintained by large teams with dedicated security processes. Everything else is a candidate for replacement.
57
+
58
+ Key behavioral changes when `HEAVY_MODE` is `true`:
59
+
60
+ 1. **Tier 1 is narrowed** to only foundational frameworks and language runtimes (see Phase 1b overrides below). Libraries like lodash, chalk, dotenv, commander, yargs, uuid, axios, etc. are NOT Tier 1 in heavy mode — they move to Tier 2 or 3.
61
+ 2. **EVALUATE recommendations become REMOVE** — the bias flips from "when in doubt, keep" to "when in doubt, replace."
62
+ 3. **Complexity ceiling rises** — replacements up to 300 lines are acceptable (vs the default where agents bail at ~2x estimate). Only truly infeasible replacements (deep domain expertise, crypto primitives, protocol parsers) are skipped.
63
+ 4. **Maintenance status is irrelevant** — even well-maintained small libraries are candidates. The question is "can we own this code?" not "is this library risky?"
64
+ 5. **DevDependencies get equal priority** — build tools and test utilities are audited with the same aggression as production dependencies (overriding the default Phase 1a deprioritization of devDependencies).
65
+
51
66
  ## Compaction Guidance
52
67
 
53
68
  When compacting during this workflow, always preserve:
@@ -57,6 +72,7 @@ When compacting during this workflow, always preserve:
57
72
  - All PR numbers and URLs created so far
58
73
  - `BUILD_CMD`, `TEST_CMD`, `PROJECT_TYPE`, `WORKTREE_DIR`, `REPO_DIR` values
59
74
  - `VCS_HOST`, `CLI_TOOL`, `DEFAULT_BRANCH`, `CURRENT_BRANCH`
75
+ - `HEAVY_MODE` flag
60
76
 
61
77
 
62
78
  ## Phase 0: Discovery & Setup
@@ -126,6 +142,8 @@ For each dependency, classify it into one of three tiers:
126
142
 
127
143
  **Tier 1 — ACCEPTABLE (keep without question):**
128
144
  Large, widely-audited, foundational libraries. Examples by ecosystem:
145
+
146
+ **Default mode:**
129
147
  - **Node.js**: react, next, vue, express, fastify, hono, typescript, eslint, prettier, webpack, vite, jest, vitest, mocha, d3, three, prisma, drizzle, @types/*, tailwindcss, postcss
130
148
  - **Rust**: tokio, serde, clap, reqwest, hyper, tracing, sqlx, axum, actix-web
131
149
  - **Python**: django, flask, fastapi, sqlalchemy, pandas, numpy, scipy, pytest, requests, httpx, pydantic
@@ -133,8 +151,21 @@ Large, widely-audited, foundational libraries. Examples by ecosystem:
133
151
  - **Ruby**: rails, rspec, sidekiq, puma, devise
134
152
  - Any dependency with >10M weekly downloads (npm) or equivalent popularity metric for the ecosystem
135
153
 
154
+ **Heavy mode (`HEAVY_MODE=true`) — Tier 1 is restricted to foundational frameworks, core platform tooling, and runtimes:**
155
+ - **Node.js**: react, next, vue, express, fastify, typescript, webpack, vite, tailwindcss, postcss, prisma, drizzle
156
+ - **Rust**: tokio, serde, hyper, sqlx, axum, actix-web
157
+ - **Python**: django, flask, fastapi, sqlalchemy, pandas, numpy, scipy, pydantic
158
+ - **Go**: standard library only
159
+ - **Ruby**: rails, puma
160
+ - Download count is NOT a factor — popularity does not exempt a library from replacement
161
+ - Libraries that are wrappers, utilities, CLIs, or single-purpose tools are Tier 2 or 3 regardless of popularity
162
+ - Linting/formatting tools (eslint, prettier) in heavy mode: remain Tier 1 when required by CI or organization-wide standards (do not attempt replacement); otherwise treat as Tier 2 (audit usage, but do not rewrite their behavior)
163
+ - Examples of libraries that DROP from Tier 1 in heavy mode: lodash, chalk, commander, yargs, dotenv, uuid, axios, node-fetch, glob, minimatch, semver, debug, winston, morgan, cors, helmet, body-parser, cookie-parser, compression, color, ora, inquirer, boxen, marked, highlight.js, moment, dayjs, date-fns, underscore, ramda, rxjs (if only basic operators used), jest (if vitest is also present — deduplicate), mocha, d3 (unless the visualization requires it), three (unless 3D rendering is core), rspec, sidekiq, devise, requests, httpx, pytest, clap, reqwest, tracing
164
+
136
165
  **Tier 2 — SUSPECT (audit usage):**
137
- Smaller libraries that may be doing something we can write ourselves. Indicators:
166
+ Smaller libraries that may be doing something we can write ourselves.
167
+
168
+ **Default mode indicators:**
138
169
  - <1M weekly downloads (npm) or equivalent
139
170
  - Single-purpose utility (does one thing)
140
171
  - We only use 1-2 functions from it
@@ -142,8 +173,19 @@ Smaller libraries that may be doing something we can write ourselves. Indicators
142
173
  - Libraries that replicate functionality available in newer language/runtime versions
143
174
  - Abandoned or unmaintained (no commits in 12+ months, open security issues)
144
175
 
176
+ **Heavy mode additional indicators** (these move libraries INTO Tier 2 that would otherwise be Tier 1):
177
+ - Any library maintained by an individual or small team (not a major org/foundation)
178
+ - Any library where we use <50% of its API surface
179
+ - Utility collections where we use a handful of functions (lodash, ramda, underscore)
180
+ - HTTP clients when the runtime has built-in fetch (axios, node-fetch, got, superagent)
181
+ - Logging libraries (winston, pino, morgan, debug) — evaluate if a thin wrapper over console suffices
182
+ - CLI argument parsers (commander, yargs, minimist) — evaluate if process.argv parsing is feasible
183
+ - Test runners if multiple are present — deduplicate to one
184
+
145
185
  **Tier 3 — REMOVABLE (strong candidate for replacement):**
146
186
  Libraries where the cost of owning the code is clearly lower than the supply chain risk:
187
+
188
+ **Default mode:**
147
189
  - We use a single function that's <50 lines to implement
148
190
  - The library wraps a built-in API with minimal added value
149
191
  - The library is unmaintained with known vulnerabilities
@@ -154,6 +196,23 @@ Libraries where the cost of owning the code is clearly lower than the supply cha
154
196
  - `dotenv` when the runtime supports `--env-file` natively
155
197
  - `is-odd`, `is-number`, `left-pad` tier micro-packages
156
198
 
199
+ **Heavy mode — Tier 3 expands significantly:**
200
+ All of the above, PLUS:
201
+ - Any library where the replacement is <=300 lines of owned code (up from ~50 in default)
202
+ - Utility libraries where we use any subset of functions, even if heavily used (write an owned utils module)
203
+ - HTTP client wrappers — replace with native `fetch` + a thin owned wrapper
204
+ - Color/terminal libraries regardless of how many functions we use (chalk, colors, kleur, ansi-colors) — write an ANSI utility
205
+ - Argument parsers for CLIs with <20 flags — write a simple parser
206
+ - Environment loaders (dotenv, envalid, env-var) — use runtime flags or write a loader
207
+ - Date libraries if we use <10 functions (moment, dayjs, date-fns) — write owned date helpers
208
+ - Glob/path matching (glob, minimatch, micromatch) if usage is simple — use native `fs.glob` (Node 22+) or write a matcher
209
+ - String utilities (camelcase, slugify, pluralize, humanize) — write the specific transformations used
210
+ - Validation libraries where we use <30% of their schemas (joi, yup, zod) — write focused validators
211
+ - Retry/backoff libraries (p-retry, async-retry) — write a retry function
212
+ - Deep equality/diff (deep-equal, fast-deep-equal, deep-diff) — write what's needed for actual use cases
213
+ - Event emitter libraries (eventemitter3, mitt) — use native EventEmitter or EventTarget
214
+ - Markdown parsers if only rendering basic markdown — consider native or minimal owned parser
215
+
157
216
  Record the full classification as `DEPENDENCY_MAP`.
158
217
 
159
218
  ### 1c: Usage Analysis (Tier 2 & 3 only)
@@ -171,6 +230,7 @@ Each agent should:
171
230
  - **Infeasible** (300+ lines or requires deep domain expertise): keep the dependency
172
231
  5. Check if the package has known vulnerabilities: `npm audit`, `cargo audit`, `pip-audit`, etc.
173
232
  6. Check last publish date and maintenance status
233
+ 7. Check for **consolidation opportunities**: does this package overlap in purpose with another dependency in the project? (e.g., two state managers, two HTTP clients, two date libraries, two test runners). If so, flag which kept dependency could absorb this one's usage
174
234
 
175
235
  Report format:
176
236
  ```
@@ -181,17 +241,40 @@ Report format:
181
241
  - Replacement complexity: {Trivial|Moderate|Complex|Infeasible}
182
242
  - Maintenance: {last publish date, open issues, known CVEs}
183
243
  - Recommendation: **REMOVE** / **KEEP** / **EVALUATE**
244
+ - Consolidation target: {kept dependency that covers the same purpose, if any — e.g., "redux" for zustand, "dayjs" for moment}
184
245
  - Replacement sketch: {brief description of how to replace, if REMOVE}
185
246
  ```
186
247
 
187
248
  Wait for all agents to complete before proceeding.
188
249
 
250
+ ### 1d: Transitive Dependency Check
251
+
252
+ Before planning replacements, check whether any REMOVE candidate is also a transitive dependency of a package we are keeping. Removing a direct dependency that remains in the lock file as a transitive dep of a kept package provides zero supply chain benefit — the code is still downloaded, installed, and executable.
253
+
254
+ For each REMOVE candidate:
255
+
256
+ 1. Check if it appears as a transitive dependency of any Tier 1 or kept Tier 2 package:
257
+ - **Node.js (npm)**: `npm ls {package}` — check the output for dependents *other than the project root*. Since REMOVE candidates are direct dependencies, they always appear at the top level; the signal is whether a kept dependency *also* depends on them (shown as a nested entry under that kept package's tree)
258
+ - **Node.js (yarn)**: `yarn why {package}` — check if any kept dependency requires it
259
+ - **Node.js (pnpm)**: `pnpm why {package}` — same check
260
+ - **Rust**: `cargo tree -i {package}` — check if a kept crate depends on it
261
+ - **Python**: use a reverse dependency tree, e.g. `pipdeptree -r -p {package}` or `uv pip tree --invert | grep {package}`, and check whether any kept package depends on it (record the full chain)
262
+ - **Go**: `go mod graph | grep {package}` — check if a kept module requires it
263
+ - **Ruby**: `bundle why {gem}` — shows the dependency chain explaining why the gem is in the bundle; check if any kept gem appears in the chain
264
+ 2. If the package IS a transitive dependency of a kept package, determine the **removal motivation**:
265
+ - **Supply chain only** — the package was flagged purely for attack surface reduction (e.g., small/unmaintained utility). Downgrade to **KEEP (transitive)** because removing the direct entry doesn't remove the code from the lock file or the runtime.
266
+ - **Consolidation** — the package overlaps in purpose with another kept dependency and removal unifies the codebase around one solution (e.g., zustand→redux, moment→dayjs, lodash→native utils). Keep the **REMOVE** recommendation — the value is in eliminating redundant usage from *our* code, not in shrinking the lock file. Record the consolidation target (e.g., "consolidate state management into redux").
267
+ - Record the dependency chain in either case, root-to-leaf (e.g., `@react-three/fiber → tunnel-rat → zustand`)
268
+ 3. Exception: if the direct dependency pulls a **different major version** than the transitive one, removal still eliminates that version from the dependency tree. In this case, keep the REMOVE recommendation but note the version difference.
269
+
270
+ Update `DEPENDENCY_MAP` with transitive check results before proceeding to Phase 2.
271
+
189
272
 
190
273
  ## Phase 2: Replacement Plan
191
274
 
192
275
  1. Read the existing `PLAN.md` (create if it doesn't exist)
193
- 2. Filter to only REMOVE recommendations from Phase 1c
194
- 3. For EVALUATE recommendations: **Default mode** — treat as KEEP (conservative). **Interactive mode** — present to user via `AskUserQuestion` for each
276
+ 2. Filter to only REMOVE recommendations from Phase 1c/1d (exclude any downgraded to KEEP (transitive) in Phase 1d)
277
+ 3. For EVALUATE recommendations: **Default mode** — treat as KEEP (conservative). **Heavy mode** — treat as REMOVE (aggressive). **Interactive mode** — present to user via `AskUserQuestion` for each. If both `--interactive` and `--heavy` are set, still prompt for each EVALUATE item (interactive takes precedence), but present REMOVE as the default suggestion
195
278
  4. Group removable dependencies by replacement strategy:
196
279
  - **Native replacement**: built-in API replaces the library (e.g., `crypto.randomUUID()`)
197
280
  - **Inline replacement**: write a small utility function (e.g., ANSI color wrapper)
@@ -210,6 +293,16 @@ Estimated replacement code: ~{lines} lines across {files} new/modified files.
210
293
  |---------|------|---------------|------------|-------------|------------|------|
211
294
  | ... | ... | ... | ... | ... | ... | ... |
212
295
 
296
+ ### Dependencies to Remove — Consolidation (transitive dep of kept package, but redundant with another kept dep)
297
+ | Package | Tier | Consolidation Target | Transitive Via |
298
+ |---------|------|---------------------|----------------|
299
+ | ... | ... | ... | ... |
300
+
301
+ ### Dependencies Kept — Transitive (would remain in lock file, no consolidation value)
302
+ | Package | Tier | Kept Via (dependency chain) |
303
+ |---------|------|-----------------------------|
304
+ | ... | ... | ... |
305
+
213
306
  ### Dependencies Kept (with rationale)
214
307
  | Package | Tier | Reason Kept |
215
308
  |---------|------|-------------|
@@ -296,7 +389,7 @@ Steps:
296
389
  - Do NOT introduce new dependencies to replace old ones
297
390
  - Do NOT use `git add -A` or `git add .` — stage specific files only
298
391
  - Keep replacement code minimal
299
- - If replacement is more complex than estimated (>2x the estimated lines), report back and skip — do not force a bad replacement
392
+ - If replacement is more complex than estimated (>2x the estimated lines), report back and skip — do not force a bad replacement. In `HEAVY_MODE`, the ceiling is 300 lines per replacement — only skip if replacement requires deep domain expertise (crypto primitives, binary protocol parsers, codec implementations) or exceeds 300 lines
300
393
  - Place shared utility replacements in a sensible location (e.g., `src/utils/`, `lib/`, `internal/`) following existing project conventions
301
394
  - Commit each replacement independently: `refactor: replace {package} with owned {utility/code}`
302
395
  </guardrails>
@@ -396,10 +489,15 @@ Create the PR:
396
489
 
397
490
  **GitHub:**
398
491
  ```bash
399
- gh pr create --head depfree/{DATE} --base {DEFAULT_BRANCH} \
400
- --title "refactor: remove {N} unnecessary dependencies" \
401
- --body "$(cat <<'EOF'
402
- ## Depfree Audit — Dependency Removal
492
+ HEAVY_SUFFIX=""
493
+ HEAVY_HEADING=""
494
+ if [ "$HEAVY_MODE" = "true" ]; then
495
+ HEAVY_SUFFIX=" (heavy mode)"
496
+ HEAVY_HEADING=" (Heavy Mode)"
497
+ fi
498
+
499
+ PR_TITLE="refactor: remove {N} unnecessary dependencies${HEAVY_SUFFIX}"
500
+ PR_BODY="## Depfree Audit — Dependency Removal${HEAVY_HEADING}
403
501
 
404
502
  ### Summary
405
503
  Removed {N} unnecessary third-party dependencies and replaced with owned code.
@@ -420,9 +518,11 @@ Estimated supply chain attack surface reduction: {N} packages ({transitive count
420
518
  - [ ] Build passes
421
519
  - [ ] All tests pass
422
520
  - [ ] No phantom references to removed packages
423
- - [ ] Lock file updated
424
- EOF
425
- )"
521
+ - [ ] Lock file updated"
522
+
523
+ gh pr create --head depfree/{DATE} --base {DEFAULT_BRANCH} \
524
+ --title "$PR_TITLE" \
525
+ --body "$PR_BODY"
426
526
  ```
427
527
 
428
528
  **GitLab:**
@@ -522,8 +622,10 @@ Transitive deps eliminated: ~{count} (estimated)
522
622
 
523
623
  - This command complements `/do:better` — run `depfree` for dependency hygiene, `better` for code quality
524
624
  - All remediation happens in an isolated worktree — the user's working directory is never modified
525
- - The threshold for "acceptable" libraries is deliberately generous — the goal is to remove obvious attack surface, not to rewrite everything
625
+ - **Default mode**: the threshold for "acceptable" libraries is deliberately generous — the goal is to remove obvious attack surface, not to rewrite everything
626
+ - **Heavy mode**: the threshold narrows to foundational frameworks only — the goal is to own as much code as feasibly possible, eliminating supply chain risk from individual maintainers and small projects
526
627
  - Replacement code should be minimal and focused — don't over-engineer utilities that replace single-purpose packages
527
- - When in doubt, keep the dependency. A maintained library is better than a buggy reimplementation
528
- - devDependencies are lower priority since they don't ship to production, but unmaintained build tools still pose supply chain risk
628
+ - **Default mode**: when in doubt, keep the dependency. A maintained library is better than a buggy reimplementation
629
+ - **Heavy mode**: when in doubt, replace it. Write owned code unless the replacement requires crypto primitives, binary protocol parsing, or deep domain expertise that would be unsafe to reimplement
630
+ - **Default mode**: devDependencies are lower priority since they don't ship to production. **Heavy mode**: devDependencies are audited on par with production deps — unmaintained build tools still pose supply chain risk
529
631
  - For monorepos, audit the root manifest and each workspace package manifest
@@ -14,7 +14,7 @@ List all available `/do:*` commands with their descriptions.
14
14
  |---|---|
15
15
  | `/do:better` | Unified DevSecOps audit, remediation, per-category PRs, CI verification, and Copilot review loop |
16
16
  | `/do:better-swift` | SwiftUI-optimized DevSecOps audit with multi-platform coverage (iOS, macOS, watchOS, tvOS, visionOS) |
17
- | `/do:depfree` | Audit third-party dependencies and remove unnecessary ones by writing replacement code |
17
+ | `/do:depfree` | Audit third-party dependencies and remove unnecessary ones by writing replacement code. Use `--heavy` for aggressive mode that targets all non-foundational libraries for replacement where feasible |
18
18
  | `/do:fpr` | Commit, push to fork, and open a PR against the upstream repo |
19
19
  | `/do:goals` | Scan codebase to infer project goals, clarify with user, and generate GOALS.md |
20
20
  | `/do:help` | List all available slashdo commands |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slash-do",
3
- "version": "2.5.0",
3
+ "version": "2.7.0",
4
4
  "description": "Curated slash commands for AI coding assistants — Claude Code, OpenCode, Gemini CLI, and Codex",
5
5
  "author": "Adam Eivy <adam@eivy.com>",
6
6
  "license": "MIT",