Skip to content
Back to skills

Scripts Audit

ASecurity

Audit package.json scripts for naming, composition, lifecycle hooks, consistency, and performance.

  • 2 stars
  • 0 votes
  • 0 copies
  • 4 views
  • Added September 23, 2026
ai-agentstypescriptgoshellbashreactnodegitfrontendsecurityperformance

Works with

  • claude code
  • cli

Security analysis

A93/100
  • highPerforms destructive filesystem operations

Pro scans all 2 files and shows the line behind each finding

Scanned September 23, 2026

npx -y skills add edloidas/skills --skill scripts-audit --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Scripts Audit?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Scripts Audit
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/edloidas-scripts-audit/badge)](https://www.skillsdirectory.com/skills/edloidas-scripts-audit)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: scripts-audit
description: >
  Audit package.json scripts for naming, composition, lifecycle hooks, consistency, and
  performance.
when_to_use: >
  When auditing or designing npm, pnpm, or Bun scripts, standardizing script conventions, or
  checking whether a package's public script interface fits its role. Also on "audit scripts",
  "check package.json scripts", or "clean up my build scripts".
license: MIT
compatibility: Claude Code, Codex, OpenCode, Pi
allowed-tools: Bash(jq:*) Read Glob Grep
---

# Scripts Audit

## Purpose

Audit a package's `package.json` scripts against the role the package actually plays: naming,
composition, lifecycle hooks, consistency, and performance. Vite Plus conventions are preferred for
app-style repos. **Reports only — it reads the manifest and writes a report; no file in the repo is
touched, so the working tree is byte-identical afterwards.**

## When to Use This Skill

Use when the user asks to:
- "Audit my npm scripts"
- "Standardize package.json script names"
- "Decide whether this should be `dev` or `start`"
- "Review build, check, or release scripts"
- "Make root workspace scripts consistent with package scripts"

Trigger phrases: "scripts audit", "package.json scripts", "npm scripts", "pnpm scripts", "bun scripts", "script naming", "script conventions"

## Scope

This is still a **scripts** skill, not a full `package.json` audit.

Read adjacent manifest fields only when they change what "good scripts" means:
- `private`
- `packageManager`
- `workspaces`
- `type`
- `bin`
- `exports`
- `files`
- `engines`

Do **not** drift into dependency hygiene, `exports`, `peerDependencies`, publish metadata, or security scanning unless the user explicitly asks for that broader audit.

## Vite Plus First

If a repo uses `vite-plus`, aliases `vite` to `@voidzero-dev/vite-plus-core`, or invokes `vp` in scripts, treat Vite Plus as the primary app workflow.

Prefer VP-native guidance:
- `build`: `vp run clean && tsgo && vp build`
- `check`: `vp check && vp run typecheck`
- `test`: `vp test --run`
- `test:ci`: `vp test --run --coverage`
- `prepare`: `vp config`

Do not recommend ESLint-specific patterns in this skill. If the repo exposes Biome explicitly, it is fine to mention `biome` scripts as optional non-VP companion scripts, but VP remains the primary app workflow.

## Non-VP Patterns

Non-VP patterns are still worth mentioning when the repo actually uses them:
- Plain `pnpm` script composition is the normal baseline for monorepo roots, publishable libraries, and release flows.
- `biome` scripts are a valid non-VP quality layer, especially in libraries, CLIs, and repos with explicit lint or format commands.
- Lifecycle hooks in non-VP repos follow Step 7.

When VP is detected, do not try to "improve" the repo by replacing VP-native app flows with separate non-VP app scripts unless the user explicitly asks for that direction.

## Workflow

Done means: the Step 9 report, or `Scripts Audit: clean`, is printed.

### Step 1: Load Minimal Manifest Context

Read `scripts` plus only the manifest fields that affect script expectations:

```bash
jq '{
  name,
  private,
  packageManager,
  type,
  workspaces,
  bin,
  exports,
  files,
  engines,
  scripts
}' package.json
```

Only inspect `dependencies` or `devDependencies` when they explain a script choice, for example:
- `vite-plus`, `vite` aliased to `@voidzero-dev/vite-plus-core`, `tsgo`, `react` -> Vite Plus app expectations
- `storybook`, `next` -> non-VP app expectations
- `typescript` -> `typecheck`
- `biome`, `prettier`, `husky` -> non-VP quality/setup expectations
- `vitest`, `jest`, `bun:test` -> test naming expectations when the repo is not VP-driven

Extract and categorize scripts by purpose:
- Runtime: `dev`, `start`, `preview`
- Quality: `typecheck`, `lint`, `lint:*`, `format`, `format:*`, `check`, `check:*`
- Build: `build`, `build:*`, `clean`
- Test: `test`, `test:*`, `coverage`
- Release: `prepack`, `prepublishOnly`, `release:*`

### Step 2: Classify Package Role

Use minimal manifest signals to decide what a sensible script surface looks like.

| Role | Typical signals | Script expectations |
|------|------------------|---------------------|
| App | `private: true`, frontend/dev tooling, `vite-plus`, `vp`, `tsgo`, `dev` or `build` | Prefer VP-native `build`, `check`, `test`, `test:ci`, `prepare`; `dev` is recommended, `preview` is optional |
| Monorepo root | `workspaces`, `pnpm --filter`, `turbo`, `nx` | Root scripts should mostly delegate and mirror leaf package names |
| Publishable library | `exports`, `files`, `bin`, not private | `build`, `typecheck`, `lint`, `format:check`, `test`, `prepublishOnly`, optional `size` or `release:dry` |
| Service / bot / CLI | `start` script, runtime entrypoint, maybe private | `start`, `check`, `test`; `build` is optional if runtime executes source directly |

If the package is ambiguous, say so and audit against the closest role instead of inventing missing requirements.

Close detection with one line: `Role: monorepo root · pnpm 9 · 14 scripts · VP not detected`.

### Step 3: Check Whether the Public Script Interface Fits the Role

Do not demand the same scripts from every package. These are pattern families, not one universal
template: audit against the family the Step 2 role selected, and ignore the others.

#### App (Vite Plus)

```json
{
  "dev": "vp dev",
  "build": "vp run clean && tsgo && vp build",
  "clean": "rm -rf dist coverage reports",
  "typecheck": "tsgo --noEmit",
  "check": "vp check && vp run typecheck",
  "test": "vp test --run",
  "test:ci": "vp test --run --coverage",
  "prepare": "vp config"
}
```

Separate `lint`, `lint:fix`, `format`, and `format:check` scripts are optional in a VP-driven repo. Keep them only when they expose distinct Biome behavior the team actually uses:

```json
{
  "lint": "biome check .",
  "lint:fix": "biome check --write .",
  "format": "biome format --write .",
  "format:check": "biome format ."
}
```

#### Monorepo root (pnpm)

```json
{
  "build": "pnpm --filter @edloidas/example run build",
  "check": "pnpm --filter @edloidas/example run check",
  "test": "pnpm --filter @edloidas/example run test",
  "test:ci": "pnpm --filter @edloidas/example run test:ci",
  "dev": "pnpm --filter @edloidas/example exec vp dev",
  "prepare": "pnpm --filter @edloidas/example run prepare"
}
```

Prefer delegation over re-implementing leaf commands in the root package.

#### Publishable library (non-VP)

```json
{
  "clean": "rm -rf dist coverage",
  "typecheck": "tsc --noEmit",
  "lint": "biome lint .",
  "lint:fix": "biome lint --write .",
  "format": "biome format --write .",
  "format:check": "biome format .",
  "check": "pnpm typecheck && pnpm lint && pnpm format:check",
  "check:fix": "pnpm typecheck && pnpm lint:fix && pnpm format",
  "build": "pnpm clean && pnpm build:*",
  "test": "vitest run",
  "test:watch": "vitest",
  "test:ci": "vitest run --coverage",
  "validate": "pnpm check && pnpm build && pnpm test:ci",
  "release:dry": "pnpm publish --dry-run --no-git-checks",
  "prepublishOnly": "pnpm validate"
}
```

#### Service / bot / CLI (non-VP)

```json
{
  "start": "bun src/index.ts",
  "typecheck": "tsc --noEmit",
  "lint": "biome lint .",
  "lint:fix": "biome lint --write .",
  "format": "biome format --write .",
  "format:check": "biome format .",
  "check": "bun run typecheck && bun run lint && bun run format:check",
  "check:fix": "bun run typecheck && bun run lint:fix && bun run format",
  "test": "bun test",
  "test:watch": "bun test --watch",
  "validate": "bun run check && bun run test"
}
```

`build` is optional here if the runtime already executes the source directly.

### Step 4: Check Naming Conventions

Prefer a small stable vocabulary of public script names:

| Script | Meaning |
|--------|---------|
| `dev` | Interactive local development server |
| `start` | Runtime entrypoint for an app, service, or CLI |
| `build` | Production or distributable build |
| `clean` | Remove generated artifacts |
| `typecheck` | Static type checking only |
| `lint` | Non-mutating lint pass |
| `lint:fix` | Lint pass with writes |
| `format` | Formatter with writes |
| `format:check` | Formatter verification only |
| `test` | Default test run |
| `test:watch` | Interactive watch mode |
| `test:ci` | Deterministic CI-oriented test run |
| `coverage` | Coverage-focused test run |
| `check` | Fast preflight quality gate |
| `check:fix` | Mutating version of the quality gate |
| `preview` | Preview built output |
| `validate` | Slower release gate |
| `release:dry` | Dry-run publish or release path |

Naming rules:
- Prefer one canonical name per concern. Flag synonyms such as `serve` plus `dev`, or `verify` plus `check`, unless they are clearly different tasks.
- Prefer `action:target:variant`, for example `build:ui:css` or `typecheck:node`.
- `:fix` means mutating, `:check` means verification-only, `:watch` means interactive, `:ci` means deterministic strict mode, and `:dry` means no side effects.
- Root scripts should keep the same public names as leaf scripts when delegating.
- Use `dev` for long-running local development workflows. Use `start` for the runtime entrypoint of a service, bot, or CLI.
- In VP repos, `check` is the primary quality command. Separate `lint` or `format` scripts are optional, not mandatory.
- In non-VP repos, explicit `lint`, `format`, and `format:check` scripts are normal and worth keeping clear.

### Step 5: Check Composition

Leaf scripts should do one job well. Composite scripts should compose those leaf scripts instead of duplicating raw command strings everywhere.

Good composition:

```json
{
  "clean": "rm -rf dist coverage reports",
  "typecheck": "tsgo --noEmit",
  "build": "vp run clean && tsgo && vp build",
  "check": "vp check && vp run typecheck",
  "test": "vp test --run",
  "test:ci": "vp test --run --coverage",
  "prepare": "vp config"
}
```

Guidelines:
- `check` should be the fast, repeatable preflight gate.
- `check:fix` should touch the same surfaces as `check`, but with writes enabled where appropriate.
- `validate` should be the slower gate, usually `check && build && test` or `check && build && test:ci`.
- `prepublishOnly` should usually call `validate` or `release:dry` rather than inventing a separate release path.
- Prefer calling scripts from composite scripts. Avoid copying the same raw command string into multiple places.

Move script logic into `scripts/` files when the command becomes hard to review:
- shell conditionals or loops
- multiple `node -e` or `bun -e` snippets
- cross-platform branching
- long inline smoke tests or packaging logic

### Step 6: Check Consistency and Performance

Look for consistency across related variants:

#### Vite Plus mode pairing

```jsonc
// Good
"check": "vp check && vp run typecheck",
"test": "vp test --run",
"test:ci": "vp test --run --coverage"
```

If a VP repo exposes `test:ci`, it should usually add something CI-specific such as coverage or stricter reporting rather than duplicating `test`.

#### Biome pairing

```jsonc
"lint": "biome check .",
"lint:fix": "biome check --write .",
"format": "biome format --write .",
"format:check": "biome format ."
```

If the repo keeps Biome scripts, related variants should usually target the same scope unless the difference is intentional and documented.

#### Runtime consistency

Within one package, prefer one script runner style unless there is a real reason to mix:
- `pnpm run ...`
- `bun run ...`
- `npm run ...`

If the scripts depend on package-manager-specific features such as `pnpm --filter`, `pnpm /^build:.*/`, or Bun-only runtime behavior, call out missing or stale `packageManager` metadata because it affects script usability and reproducibility.

#### Parallelization

When sub-builds are independent, consider runner-native fan-out:

```jsonc
// Sequential
"build": "pnpm build:lib && pnpm build:css"

// Better when independent
"build:ui": "pnpm --color /^build:ui:.*$/"
```

Parallelize only when it preserves readable output and does not break dependency order.

### Step 7: Check Lifecycle Hook Usage

Use package lifecycle hooks for real lifecycle boundaries:

```json
{
  "prepare": "vp config",
  "prepack": "pnpm build",
  "prepublishOnly": "pnpm validate"
}
```

Guidelines:
- In VP repos, `prepare: "vp config"` is a strong default.
- In non-VP repos, `prepare: "husky"` is a valid setup hook when the project manages git hooks explicitly.
- `prepare` is for local setup such as VP configuration or git hooks, not for hidden build work.
- `prepack` is for ensuring distributable artifacts exist before packing.
- `prepublishOnly` is for the final release gate.
- Avoid `postinstall` build steps unless the package truly requires them.

### Step 8: Flag Anti-Patterns

Call out these issues explicitly:
- Placeholder success scripts such as `test: "exit 0"` or `prepack: "echo Packaging..."`.
- Platform-specific helpers hidden behind generic names, for example `analyze: "open dist/stats.html"`. If kept, prefer a more explicit name such as `analyze:open`.
- Root workspace scripts that embed leaf-package implementation instead of delegating.
- Missing paired scripts where the workflow expects them, such as `format` without `format:check`, or `lint` without `lint:fix` when Biome is exposed explicitly.
- VP app repos that skip `prepare: "vp config"` and require manual local setup.
- Duplicate aliases that do the same thing without adding clarity.
- Very long inline script strings that should live in `scripts/`.

### Step 9: Generate Report

One section per issue class, in the order below. Drop any section with no findings rather than
writing "none".

```markdown
## Scripts Audit Report

`@edloidas/example-root` · monorepo root · pnpm 9 · 14 scripts · VP not detected

### Package Role
- Monorepo root delegating to `@edloidas/example`

### Naming Issues
- `serve` duplicates `dev` without a clearer contract
- `lint:check` should be `lint`

### Composition Issues
- `prepublishOnly` duplicates `check && build && test`; reuse `validate`
- Root `build` re-implements leaf build steps instead of delegating

### Lifecycle Issues
- `prepare` runs a build; move that work to `build` or `prepack`

### Performance / Consistency Issues
- `lint` and `lint:fix` target different file sets
- `test:ci` duplicates `test` instead of adding coverage or stricter CI behavior

### Recommendations
1. Standardize on `build`, `check`, `test`, `test:ci`, and `prepare` as the public VP surface, with `dev` when the repo exposes it.
2. Rename scripts to follow `action:target:variant`.
3. Introduce `validate` and let `prepublishOnly` call it.
4. Move long inline smoke-test logic into `scripts/`.
```

With nothing to report, the whole report is the header line plus one sentence:

```markdown
## Scripts Audit: clean

`@edloidas/example` · publishable library · pnpm 9 · 11 scripts · VP not detected
The script surface matches the library role; no naming, composition, lifecycle, or consistency issues.
```

Then stop. Do not edit `package.json`, do not offer to apply the recommendations, and do not audit
dependencies, `exports`, or publish metadata on the way past — that is the Scope boundary above.

Files in this skill

  • SKILL.md14.9 KB
  • agents/openai.yaml436 B

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.