Skip to content

deps: report script and refresh skill for recurring dependency updates - #1440

Merged
Stvad merged 11 commits into
masterfrom
claude/dependencies-audit-upgrade-d7e81a
Oct 25, 2026
Merged

Stvad merged 11 commits into
masterfrom
claude/dependencies-audit-upgrade-d7e81a

Conversation

@Stvad

@Stvad Stvad commented Oct 24, 2026 •

Copy link
Copy Markdown
Owner

The groundwork for a recurring dependency refresh, which a scheduled cloud routine will run every two weeks. The routine itself is configured outside the repo and only opens PRs; it never merges.

What's here

node scripts/deps-report.mjs [--cwd <dir>] prints a markdown report of what a refresh can take today under the project's minimumReleaseAge cooldown.

  • Inventory: the lockfile, via pnpm ls -r --depth 0 --json --lockfile-only.
    • It needs no install and applies no policy.
    • pnpm outdated is unusable here because it already applies the cooldown, so a package whose only newer releases are inside it would vanish.
  • Eligibility: computed from each package's registry document. Only published, non-deprecated versions count: an explicit pin would otherwise override pnpm's own avoidance of deprecated releases.
  • Sections:
    • same-major updates, with one pnpm --filter <project> up name@version … command per project, so a package on different majors in different projects never drags one across. The pnpm up -r refresh comes last. Named versions keep each pin style and move exact pins;
    • eligible next majors;
    • what the cooldown still holds, with the date each clears;
    • packages to check by hand;
    • the pinned pnpm;
    • GitHub Actions refs behind their latest major, with each release's date.
  • Failure handling: a failed pnpm ls, or a project with no minimumReleaseAge, makes the report refuse rather than read as "nothing to update" or "everything is eligible". An unreadable GitHub release names its cause.
  • Tests: the pure parts have 19 unit tests: cooldown classification, the per-project commands, the inventory boundary, and uses: parsing.
  • Run against master on 2026-10-24, it lists:

.claude/skills/deps-refresh/SKILL.md is the playbook from the manual audit (#1436):

  • the same-major refresh;
  • override floors, followed by a plain pnpm install so the frozen install passes;
  • scaffold pins;
  • React, which is an ordinary dependency since build: serve React same-origin instead of from esm.sh #1444. If a bump changes React's exports, src/vendor/vendorEntries.test.ts fails, and the step points at the facades to update.
  • removal of unused dependencies;
  • when to take a major, and the majors to always hold: anything that can change stored data or how stored extensions compile (PowerSync, better-sqlite3, @babel/standalone, crypto, Supabase);
  • Actions, taken only when released at least 7 days ago and exercised by a PR-triggered workflow; the pnpm pins, root and standalone extension together;
  • a baseline gate run that stops on an already-red master, one flake rule, and putting back any bump that breaks verification instead of editing tests;
  • verification, and the PR shape.

agent-extensions/social-media-publisher/pnpm-workspace.yaml gets the root's 7-day minimumReleaseAge and its verifyDepsBeforeRun: warn. That extension installs standalone and inherits neither. Without the second setting, its check silently ran a non-frozen install that rewrote its lockfile.

@types/better-sqlite3 7.6.13 → 9.6.0. The report flagged it after PowerSync 2 moved better-sqlite3 to 13. The two index.d.ts files are byte-identical; only the declared minimum TypeScript changes. This is version hygiene with no API change.

Verification

  • pnpm run check passes on the branch merged with current master (pnpm 12, Babel 8, PowerSync 2, same-origin React): 840 test files, 12,326 tests.
  • An /areview round found two latent majors in the report, both now fixed with tests: cross-project major drag, and deprecated versions as targets. It also found instruction gaps for an unattended run, now closed in the skill.
  • Tests came first for each fix. Every guard clause in the inventory boundary and the bump command was deleted with pnpm mutate, and a named test failed each time.
  • The report was run under pnpm 10 and pnpm 12, against the repo and the standalone extension, with and without a GitHub token.

🤖 Generated with Claude Code

…dates

`node scripts/deps-report.mjs [--cwd <dir>]` prints, as markdown, what a
refresh can take today under the project's `minimumReleaseAge`:
- the newest eligible version within each package's major, with the exact
  `pnpm up` commands;
- the newest eligible next major;
- what the cooldown still holds, with the date it clears;
- the pinned pnpm, version-pinned esm.sh URL imports, and GitHub Actions
  refs behind their latest major.

`pnpm outdated` reports the registry's `latest` tag, which ignores the
cooldown, so eligibility comes from publish times. The pure parts
(classification, the `--latest` command, workflow `uses:` and esm.sh
parsing) are unit-tested.

The deps-refresh skill is the playbook from the last manual audit: the
same-major refresh, override floors, scaffold pins, unused-dependency
removal, which majors to take or always hold (anything that can change
stored data or how stored extensions compile), Actions, verification and
the PR shape. It is written so a scheduled cloud run can follow it.

The social-media-publisher extension installs standalone and did not
inherit the root cooldown. It now sets the same 7 days.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-25T07:33:22.396583Z 54fa555 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0d65798f79

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/deps-report.mjs Resolved
Comment thread scripts/deps-report.mjs Resolved
Comment thread scripts/deps-report.mjs Resolved
Review fixes:
- The bump command now names every same-major target as
  `pnpm up -r name@version`. Before, an exact pin whose next major was
  also eligible (e.g. `cmdk: "1.1.1"` with 1.1.2 and 2.0.0 out) got no
  command, and a bare `pnpm up -r` can't move an exact pin.
  `name@version` keeps each specifier's pin style (checked: exact stays
  exact, `^` stays `^`). The pinned pnpm row is left out of the
  command; the report prints the packageManager edit separately.
- `readOutdated` owns the `pnpm outdated` boundary. A spawn error, an
  exit status other than 0/1, or exit 1 without JSON now throws, so a
  failed scan can't read as "nothing to update". Before the first
  install pnpm prints no `current`, so the locked `wanted` stands in.
- The skill installs before taking the snapshot, and describes the new
  command.

Each new clause was deleted with `pnpm mutate`, and a named test failed
each time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 65b8061288

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/deps-report.mjs Resolved
`pnpm outdated` already applies `minimumReleaseAge`. A dependency whose
only newer releases are still inside the cooldown is missing from its
output, so the report couldn't show it as held or say when it clears.
On today's lockfile that hid the CodeMirror/Lezer patches, the MCP SDK,
vite, postcss, typescript-eslint and happy-dom 21.0.4 (a security fix).

The inventory is now `pnpm ls -r --depth 0 --json --lockfile-only`:
every project's direct dependencies as locked, with no install needed
and no policy applied. `readInventory` replaces `readOutdated` and keeps
its strict boundary: a spawn error, a non-zero exit, or output that
isn't a project list throws. Workspace links are skipped. An aliased
dependency (e.g. `typescript-native` -> `npm:typescript`) is looked up
under its registry name. It is left out of the generated command, with
a bump-by-hand line instead, since `pnpm up alias@version` would
rewrite its specifier.

Each package first fetches only its small `/latest` manifest. The full
publish history is fetched only when something newer exists, so a full
run takes ~6 s.

Tests: six `readOutdated` cases are replaced by four `readInventory`
cases and one alias case. Deleting each new clause with `pnpm mutate`
failed a named test. Dependents are collected in a Set instead of an
unpinnable includes-check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8565226b90

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/deps-report.mjs Resolved
Comment thread .claude/skills/deps-refresh/SKILL.md Resolved
Stvad and others added 8 commits October 24, 2026 00:16
…ailed

Review fixes:
- The `latest` dist-tag shortcut is gone. A package whose `latest` tag
  still matches the locked version can have a newer stable release
  under another tag, and the shortcut skipped it. Every package's
  publish history is read now. A full run still takes about 4 s, and on
  today's lockfile it gives the same rows.
- The skill says to run a plain `pnpm install` after raising the
  override floors. Without it the lockfile keeps the old overrides, and
  the frozen install fails with ERR_PNPM_LOCKFILE_CONFIG_MISMATCH.

Also: an Action whose latest release can't be read now says why (its
HTTP status). On 403/429 the report suggests setting GITHUB_TOKEN,
since unauthenticated GitHub API calls are limited to 60 an hour. The
skill tells a cloud run to fall back to the GitHub MCP tools.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-audit-upgrade-d7e81a

# Conflicts:
#	agent-extensions/social-media-publisher/pnpm-workspace.yaml
#1444 replaced the esm.sh importmap with same-origin facades in
`src/vendor/`, so the "hold React while reactImportMapMode.ts exists"
step is gone. A React bump is now taken like any other. If it changes
React's exports or browser subpaths, `src/vendor/vendorEntries.test.ts`
fails, and the step points at updating the facades to the set it names.

Also from master: @journeyapps/wa-sqlite is no longer a direct
dependency (PowerSync 2), so it leaves the hold list. The standalone
extension pins its own pnpm (#1442), so a pnpm bump updates both pins.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
better-sqlite3 is on 13 (with PowerSync 2), and the deps report flagged
its types as a major behind. 9.6.0's index.d.ts is byte-identical to
7.6.13's; only the declared minimum TypeScript moves (5.1 -> 5.6). So
this is version hygiene with no API change. Neither version types 13's
new `db.explain()` / `stmt.toString()`, and better-sqlite3 13 ships no
types of its own.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The report lists version-pinned esm.sh imports. Those are agent
extensions loading their own libraries at runtime (e.g. the Matrix
client's SDK), not app dependencies. The routine reports them, and a
bump belongs in a change to that extension.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ed versions

Review fixes:
- Bump commands are now one per project, as
  `pnpm --filter <project> up name@version …`, with the `pnpm up -r`
  refresh always printed last. `pnpm up -r pkg@x` applies x to every
  project that has pkg, so a package on different majors in different
  projects would drag one across: observed as a 7 -> 6 downgrade.
  An empty target list no longer drops the transitive refresh.
- Only published, non-deprecated versions are targets. The registry
  `time` map keeps unpublished versions, and an explicit pin overrides
  pnpm's own avoidance of deprecated releases (e.g. jest-dom 6.10.0,
  deprecated as a breaking minor). A version with no publish time is
  skipped, since its cooldown can't be judged.
- `0.0.x` versions are each their own line, as caret treats them.
- `--cwd` commands carry `-C <dir>`, and the header and commands use a
  path relative to the working directory, never an absolute one.
- A transport failure names the package (npm), or becomes a per-action
  error (GitHub), instead of killing the run with "fetch failed".
- Each Action's latest release date is shown, for the cooldown check.
- A project with no `minimumReleaseAge` makes the report refuse instead
  of treating every release as eligible.

Cleanups:
- `classifyPackage` drops `compareLines` (a newer version on another
  line is always a higher one) and computes `held` as "the newest isn't
  eligible yet".
- Removed a duplicated row filter.
- `from` is required.
- Registry documents are cached per name (the `typescript-native` alias
  shared a 16 MB fetch) and reduced to time plus deprecation.
- No release lookup for SHA-pinned Action refs.
- The test-only `as never` casts are gone.
- The esm.sh pin scan is removed: those are agent extensions' runtime
  imports, not app dependencies, so the core refresh never acts on them.

Every new clause was deleted with `pnpm mutate`, and a named test
failed each time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ion fixes

Review fixes for an unattended run:
- Baseline: run the gate on the untouched tree first, and stop if master
  is already red, so a refresh never blames its bumps for an existing
  break.
- One flake rule: on `check: FAIL` with only "failed only under load"
  verdicts, re-run once, then proceed and list them. Any "fails alone
  too" is a real break.
- A bump that breaks verification is put back and listed as held. Never
  edit tests, lint rules, tsconfig or the gate to make a bump pass.
- The cooldown can't be routed around: no flags, env vars, interactive
  approvals, `minimumReleaseAgeExclude`, or new `overrides`.
- Extension: run the commands its report prints (they carry `-C` and
  move exact pins). A bare `up` never moved its pins.
- Its `pnpm-workspace.yaml` gains `verifyDepsBeforeRun: warn`, as the
  root has. Under pnpm 12's default, its `check` silently ran a
  non-frozen install and rewrote the lockfile. Verify now also checks
  the extension's frozen install and a clean `git status`.
- Actions majors only when released at least 7 days ago and exercised
  by a PR-triggered workflow, in the last commit.
- Same-major bumps of hold-list packages get their own commit and a
  Data-path section. Overrides with no direct dependency get a rule.
  `pnpm audit`'s exit 1 is a finding. `@types/*` is tooling.

Cleanups: the React step points at vendorEntries.test.ts's own message,
and sentences that restated AGENTS.md (gate mechanics, publishing,
cloud doc) are gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Stvad
Stvad merged commit 680b537 into master Oct 25, 2026
2 checks passed
@Stvad
Stvad deleted the claude/dependencies-audit-upgrade-d7e81a branch October 25, 2026 07:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant