# Update Package Locks

> Use when refreshing package-lock.json files in ng-mocks, resolving lockfile conflicts in an existing dependency PR, or ensuring a lockfile PR is conflict-free after creation.

- Skill: `help-me-mom/update-package-locks` (Agent Skill)
- Install (CLI): `npx skillmds@latest add help-me-mom/update-package-locks`
- Raw SKILL.md: https://api.skillmd.com/api/skills/help-me-mom/update-package-locks/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: help-me-mom (https://skillmd.com/u/help-me-mom)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/help-me-mom/update-package-locks

---


# Update Package Locks

Use this skill for a fresh lockfile refresh or to regenerate a lockfile while resolving an existing dependency PR conflict, without permanently changing the repo's normal install flow.

This workflow is intentionally narrow. Follow the sequence exactly. Do not manually add tests, lint, rebases, or unrelated cleanup unless the user explicitly asks for them. All execution must follow `AGENTS.md`'s Docker-only rule.

## Task List

Create a plain Markdown checklist that any AI agent can follow:

```md
- [ ] Identify whether this is a fresh refresh or an existing dependency PR conflict
- [ ] Create an isolated worktree from `upstream/main` or the existing PR branch
- [ ] For a PR conflict, merge `upstream/main` and keep the dependency PR's lockfile side as the regeneration base
- [ ] Temporarily change the relevant `compose.yml` service command line(s) from `npm install` to `npm update`
- [ ] Run the update wrapper pass, serializing cold browser installs before batches of 2-4
- [ ] Restore `compose.yml` back to `npm install`
- [ ] Run the install wrapper pass with wrapper targets in batches of 2-4
- [ ] Commit the refreshed lockfiles with only the dependency or merge changes already in scope
- [ ] Push a fresh branch and create a PR, or push the existing PR branch
- [ ] Check the remote PR mergeability after every push
- [ ] If conflicts exist, merge current `upstream/main`, preserve both sides' intended changes, regenerate affected lockfiles, push, and recheck
- [ ] Summarize the two wrapper passes and any npm warnings
```

## Workflow

1. Work in an isolated worktree:
   - For a fresh refresh, fetch the current base and create a new branch from `upstream/main`.
   - For an existing dependency PR conflict, fetch that PR branch into an isolated worktree, merge `upstream/main` without rewriting history, and keep the dependency PR's lockfile side as the regeneration base.
2. In that new worktree, inspect `compose.yml`.
3. Temporarily change only the affected `compose.yml` service command line(s) from `npm install` to `npm update`.
4. For a repo-wide refresh, derive the current wrapper targets from `compose.sh` and `compose.yml`, then run them in batches of 2-4 concurrent commands. Serialize targets that may download the same uncached browser build, as described below. If the user explicitly named one target, run only that target.
5. Restore the same service command line(s) back to `npm install`.
6. Run the same target set again in batches of 2-4 so the resulting lockfiles match the normal CI install flow.
7. Commit the refreshed `package-lock.json` files with only the dependency or merge changes already in scope, plus `.agents/skills/update-package-locks/SKILL.md` if this skill was intentionally edited.
8. For a fresh refresh, push the branch to a writable remote and create a PR against `upstream/main`. For an existing dependency PR, push back to that PR branch.
9. After creating the PR or pushing its branch, query the hosting provider for the PR's current mergeability. If the result is indeterminate, wait and query again. Do not treat pending or failed CI checks as merge conflicts.
10. If the provider reports conflicts:
    - Fetch current `upstream/main` and merge it into the PR branch in the same isolated worktree without rebasing or rewriting history.
    - Inspect every conflicted file. Resolve non-lockfile conflicts semantically so both sides' intended changes remain; never choose an entire side without checking what it would discard.
    - When merging `upstream/main` into the PR branch, keep the PR side of each conflicted `package-lock.json` only as the regeneration base, then run the update and install wrapper passes for every affected target against the combined manifests. Never hand-merge lockfile conflict blocks.
    - Verify there are no unmerged paths, restore every affected `compose.yml` command to `npm install`, commit with normal hooks, push, and query remote mergeability again.
    - Repeat the check if the base advances. Finish only when the provider returns a definitive conflict-free state.

Do not use the current active worktree. A fresh refresh needs a new branch; an existing dependency PR conflict stays on its PR branch in an isolated worktree. Do not manually run `sh test.sh`, root tests, lint, or TypeScript checks as part of this workflow unless the user explicitly asks for them. Never use local runtimes or ad-hoc dependency commands.

For a repo-wide refresh, the affected command lines are all service command entries in `compose.yml` that currently read `- install`. Change only those entries to `- update`, run the wrapper, then change those same entries back to `- install`. Do not edit `package.json`, shell scripts, or lockfiles by hand.

For repo-wide refreshes, derive targets from the current `compose.sh` and `compose.yml`; do not hardcode target names or rely on bare `sh compose.sh`. Run each target once per pass in batches of 2-4, with a unique `COMPOSE_PROJECT_NAME` per concurrent command. Clean each batch with `docker compose down -v` before starting the next one.

The browser volume is external and shared across these namespaces. Before placing targets that use the same
browser build in a parallel batch, complete one target's wrapper run to populate that build. If cache state
or the build selected by an update is uncertain, run those targets sequentially. Apply this rule in both
passes and coordinate with other worktrees. Batch cleanup retains the external browser volume; do not
remove it while another worktree may be using it. See `CONTRIBUTING.md` for cache revision mappings.

If a wrapper target fails, including Docker address-pool or Puppeteer cache errors, report the command, error, and remaining work to the user and discuss the solution before cleanup, retries, or other recovery steps. Do not switch to local runtimes or create a workaround.

If several worktrees or agent sessions are active, use a unique compose namespace for every wrapper command:

```bash
COMPOSE_PROJECT_NAME=ngmocks_<unique> sh compose.sh <target>
```

## Commands

```bash
# Start from upstream/main in a new worktree.
git fetch upstream main
git worktree add -b codex/<lockfile-branch> ../<lockfile-worktree> upstream/main

# Resolve an existing dependency PR without rewriting its history.
git fetch upstream main <pr-branch>
git worktree add ../<pr-worktree> <pr-branch>
git merge --no-edit upstream/main
git checkout --ours path/to/package-lock.json # PR side when merging main into the PR branch

# Repo-wide lockfile refresh.
# Edit compose.yml to npm update, run current wrapper targets in batches of 2-4, then restore npm install and repeat the same batches.

# Specific target lockfile refresh, only when the user named a target.
# First edit that target's compose.yml service command to npm update.
COMPOSE_PROJECT_NAME=ngmocks_<unique> sh compose.sh <target>
# Then restore that target's compose.yml service command to npm install.
COMPOSE_PROJECT_NAME=ngmocks_<unique> sh compose.sh <target>

# Commit and publish after the wrapper sequence succeeds.
git add package-lock.json docs/package-lock.json tests-e2e/package-lock.json e2e/*/package-lock.json
git add .agents/skills/update-package-locks/SKILL.md # only if intentionally edited
git commit -m "chore: refresh package lockfiles"
git remote -v
git push -u origin codex/<lockfile-branch>
# Create a PR against upstream/main after the push succeeds.

# If the remote PR reports conflicts, merge current main without rewriting history.
git fetch upstream main
git merge --no-edit upstream/main
git diff --name-only --diff-filter=U
git checkout --ours path/to/package-lock.json # PR side is only the regeneration base
# Resolve non-lockfile conflicts semantically, rerun both wrapper passes for affected targets,
# restore compose.yml to npm install, and then finish the merge.
git diff --check
git commit --no-edit
git push
# Query the remote PR mergeability again; repeat if the base advanced and conflicts remain.
```

## Validation

- The required validation for this skill is a successful wrapper-based update pass followed by a successful wrapper-based install pass.
- For a single target, run `sh compose.sh <target>` once while the service command is temporarily `npm update`, then run `sh compose.sh <target>` again after restoring `npm install`.
- For a repo-wide lock refresh, run every relevant wrapper target once with all relevant service commands temporarily set to `npm update`, then run every same target again after restoring all service commands to `npm install`.
- Repo-wide target runs may be concurrent in batches of 2-4 after shared browser builds are populated; serialize uncertain or cold installs of the same build. A batch is successful only when every target command exits successfully.
- After the final push, the hosting provider must report a definitive conflict-free PR state. A local clean merge is not sufficient, and CI status is a separate signal.
- Do not run `sh test.sh`, `npm test`, lint, or TypeScript checks as part of this skill's default validation.

## Guardrails

- Always use an isolated worktree: a new branch from current `upstream/main` for fresh work, or the existing PR branch for conflict resolution.
- Never delete lockfiles.
- Never hand-merge lockfile conflict blocks or rewrite dependency PR history.
- Never discard either side of a non-lockfile conflict without inspecting and preserving its intended behavior.
- Never leave `compose.yml` in an `npm update` state after finishing.
- Use only the documented wrapper flow and repo images. Never use local runtimes or custom install, build, test, or
  check scripts, including inside Docker.
- If multiple worktrees, agent sessions, or concurrent wrapper targets are active, set a unique `COMPOSE_PROJECT_NAME` for each wrapper command.
- Clean up temporary compose projects with `docker compose down -v` after successful batches. Discuss failed setup
  runs with the user before recovery steps.
- When committing or pushing, let the repository's normal git hooks run. Do not bypass hooks unless the user explicitly asks.
- Do not manually invoke extra validation beyond this skill. If a hook requires local runtime execution or fails,
  report it and discuss the solution; do not bypass it or use local tooling to make it pass.
- Push to a configured writable remote; never assume `upstream` accepts contributor branches.
- Never declare the PR conflict-free from local Git state alone; query its remote mergeability after the final push.

