diff --git a/.changeset/stack-upgrade-skill.md b/.changeset/stack-upgrade-skill.md new file mode 100644 index 0000000..942d39f --- /dev/null +++ b/.changeset/stack-upgrade-skill.md @@ -0,0 +1,5 @@ +--- +"@toruslabs/torus-scripts": patch +--- + +Ship the Web3Auth stack upgrade steps in the migration skill so one published skill covers both. diff --git a/.cursor/skills/migrating-to-torus-cli/reference.md b/.cursor/skills/migrating-to-torus-cli/reference.md new file mode 120000 index 0000000..6b89cd9 --- /dev/null +++ b/.cursor/skills/migrating-to-torus-cli/reference.md @@ -0,0 +1 @@ +../../../packages/torus-scripts/skills/migrating-to-torus-cli/reference.md \ No newline at end of file diff --git a/packages/torus-scripts/README.md b/packages/torus-scripts/README.md index 8964cb6..7cd5c44 100644 --- a/packages/torus-scripts/README.md +++ b/packages/torus-scripts/README.md @@ -60,7 +60,7 @@ The old `@toruslabs/eslint-config-*` packages are removed. Do not treat an Oxlin ## Upgrade from the old CLI -The package includes an agent skill at `skills/migrating-to-torus-cli/SKILL.md`. In a consumer project, read it at `node_modules/@toruslabs/torus-scripts/skills/migrating-to-torus-cli/SKILL.md`. To make it available as a project skill in Cursor, copy it to `.cursor/skills/migrating-to-torus-cli/SKILL.md` in that project, but do not commit that copy. The skill belongs to this package; a committed copy goes stale and the consumer repository then carries two versions. Keep the skill and this README from the same package version. +The package includes an agent skill at `skills/migrating-to-torus-cli/`. In a consumer project, read it at `node_modules/@toruslabs/torus-scripts/skills/migrating-to-torus-cli/SKILL.md`. To make it available as a project skill in Cursor, copy that directory to `.cursor/skills/migrating-to-torus-cli/` in that project, but do not commit that copy. The skill belongs to this package; a committed copy goes stale and the consumer repository then carries two versions. Keep the skill and this README from the same package version. The same skill plans a Web3Auth stack upgrade. `reference.md` in that directory holds the CODEOWNERS, Dependabot, and `.npmrc` lookup tables. Run `torus-scripts-upgrade ` to inspect an old project without changing files. It reports unsupported custom behavior and exits nonzero for those cases. Run `vp migrate` at the workspace root, not inside each package, and review its changes. The diagnostic does not run `vp migrate` for you. diff --git a/packages/torus-scripts/package.json b/packages/torus-scripts/package.json index 19038e1..9745b34 100644 --- a/packages/torus-scripts/package.json +++ b/packages/torus-scripts/package.json @@ -8,7 +8,8 @@ }, "files": [ "dist", - "skills/migrating-to-torus-cli/SKILL.md" + "skills/migrating-to-torus-cli/SKILL.md", + "skills/migrating-to-torus-cli/reference.md" ], "scripts": { "build": "vp pack", diff --git a/packages/torus-scripts/skills/migrating-to-torus-cli/SKILL.md b/packages/torus-scripts/skills/migrating-to-torus-cli/SKILL.md index fb825a0..92d1414 100644 --- a/packages/torus-scripts/skills/migrating-to-torus-cli/SKILL.md +++ b/packages/torus-scripts/skills/migrating-to-torus-cli/SKILL.md @@ -1,10 +1,18 @@ --- name: migrating-to-torus-cli -description: Use when moving an existing consumer project from old Torus scripts, ESLint presets, or build tools to current Torus CLI and Vite+ presets. +description: >- + Use when moving an existing consumer project from old Torus scripts, ESLint + presets, or build tools to current Torus CLI and Vite+ presets. Also use when + planning a Web3Auth stack upgrade, an EMBED tooling/dependencies/security + story, a torus-scripts 9 migration, or a forked-agent plan for that upgrade. + The epic is always EMBED-573. Ask which story ticket to follow when the + conversation does not already name it. --- # Migrate a consumer to Torus CLI +If the user asked for a Web3Auth stack upgrade, an EMBED story, or a forked-agent plan, follow Stack upgrade and use the migration sections when a step points at them. Otherwise follow Inspect, Migrate, Monorepos, and Verify. Do not run the stack upgrade steps for a plain migration. + Use `node_modules/@toruslabs/torus-scripts/README.md` in an installed consumer, or `packages/torus-scripts/README.md` in this repository, as the current source for presets, commands, and known lint gaps. A successful diagnostic does not prove that a project is ready to migrate. Do not commit this skill into the consumer repository. Read it from `node_modules`. A committed copy goes stale against the installed package version. @@ -57,3 +65,202 @@ export default defineConfig({ Run the consumer's install, build, lint/check, typecheck, and tests when available. Inspect package contents and import/require entry points if published files changed. If browser tests fail, separate missing browser executables from test failures and browser timeouts. Report each command and result, preserved behavior, manual follow-up, and any check you could not run. Never report a migration as complete if package outputs or lint coverage remain unverified. Example: A project can get “No known unsupported behavior detected” while its `package.json` entry paths still point at old bundle folders. Inspect the scripts and published paths before changing it. + +## Stack upgrade + +Plan the upgrade. The user commits. Do one step at a time when they ask to implement. + +### Tickets + +The epic is always [EMBED-573](https://consensyssoftware.atlassian.net/browse/EMBED-573). + +The story changes per repository. If this conversation does not already name the story key, ask which ticket to follow and wait. Do not guess from the open workspace or from an earlier repository. + +Fetch both issues from `consensyssoftware.atlassian.net` before planning. Use the story for the repository, source, and repository-specific acceptance checks. Use the live epic text for the shared acceptance criteria. + +Read the story's **Sequence and prerequisites** section before choosing dependency versions. That section is the list of releases this repository adopts. Classify each entry: + +- **Release-adoption gate** or **direct runtime package prerequisite**: install that package's latest published release. Look it up with `npm view version` during this run. Ignore the 3-day window (`min-release-age` and Dependabot cooldown) and install with `npm install --min-release-age=0`. A range already in `package.json` is not a reason to stay on an older major. +- **Shared tooling** (`torus-cli` / `@toruslabs/torus-scripts`): install the published `@toruslabs/torus-scripts` that contains this skill, also with `--min-release-age=0`. The epic text may still say `9.0.0`. Do not install an older release than the copy being read. +- **Anything else** in that section: follow the wording. Step 4 does not bump packages the section does not list. Step 7 raises those other direct ranges on the same major. + +A release-adoption gate with no published release blocks the dependency bump. Name the package and stop that step. A publish date inside the 3-day window does not block it. + +### Working agreement + +- Default output is a step plan for forked agents. Do not edit, commit, push, publish, or open a PR unless the user asks to do a step. +- When they ask to do a step, do that step only, then stop. The user commits and pushes. Do not commit or push. +- Step 1 creates `feat/embed--stack-upgrade` from the default branch. Stay on a branch they already created. +- Write each step so a new agent can do it without this chat: repo, org, default branch, package manager, versions, files, and the stop condition. +- Read **Notes to consider** before planning or implementing. A fork does not report its later turns back to the parent chat. + +### Version overrides + +Versions for a new major come from **Sequence and prerequisites**, not from memory of another repository. Step 7 raises every other direct range on the same major. + +`@types/node` is the exception. It follows major 26, the same major as `.nvmrc`, even when **Sequence and prerequisites** does not list it. Step 5 installs that major. Step 7 only raises it within 26. + +Keep `cooldown.default-days: 3` in `dependabot.yml` and `min-release-age=3` in `.npmrc` for later updates. The install that resolves the section's packages uses `--min-release-age=0`. + +### Plan + +Copy this checklist into the plan and fill the repo-specific blanks. + +``` +- [ ] 1. GitHub policy files +- [ ] 2. Draft pull request body +- [ ] 3. Read-only diagnostic +- [ ] 4. Runtime prerequisites +- [ ] 5. Tooling migration +- [ ] 6. CI, release PR, and security scanner +- [ ] 7. Update dependencies and audit +- [ ] 8. Package.json cleanup +- [ ] 9. Verify and finish the draft +``` + +#### 1. GitHub policy files + +Create `feat/embed--stack-upgrade` from the default branch when that branch does not already exist, and check it out. Stay on it when it already exists. + +Touch only `.github/CODEOWNERS`, `.github/PULL_REQUEST_TEMPLATE.md`, and `.github/dependabot.yml`. Leave workflows for step 6. + +CODEOWNERS follows `origin`'s org. See [reference.md](reference.md). Product owners cover directories that exist. A single package gets `src/` and `test/`. Add `packages/`, `demo/`, or `examples/` only when those directories exist. + +PR template includes Motivation and Context above Jira Link. Dependabot covers npm (or the repo's package manager) and github-actions, weekly, with a 3-day cooldown. + +Stop after the branch exists and those files are in place. Do not commit or push. + +#### 2. Draft pull request body + +Write the body from the template copied in step 1. Fill motivation, the story link, and the EMBED-573 link. Mark a breaking change when engines or published entries change. Leave testing as a checklist for step 9. + +Create that pull request as a draft with `gh pr create --draft` against the default branch. Do not commit or push. If the branch is not on the remote, stop and give the user the body. The draft waits until they push. + +#### 3. Read-only diagnostic + +Read the Inspect, Migrate, Monorepos, and Verify sections in this skill, and the README from the same package version. To load this skill in Cursor, copy the skill directory from `node_modules/@toruslabs/torus-scripts/skills/migrating-to-torus-cli/` to `.cursor/skills/migrating-to-torus-cli/`. Do not commit that copy, and do not add it to `.gitignore`. The default `.git/info/exclude` is comments only, so an untracked `.cursor/` still shows in `git status`. Append `.cursor/` to `.git/info/exclude` when `git check-ignore` does not already match that path. + +Run `torus-scripts-upgrade` on the repo root and record its exit code and findings. Also inspect `package.json` scripts and entry points, ESLint config, `tsconfig`, Babel, Prettier, and release scripts. Do not edit build files. + +#### 4. Runtime prerequisites + +Use the release-adoption gates and direct runtime package prerequisites from **Sequence and prerequisites**. Skip this step when that section lists none. + +Bump each of those packages to the latest version resolved for this run, including a release inside the 3-day window. Install with `--min-release-age=0`. Fix call sites only where the new types fail. Leave every other direct range for step 7. Leave engines, tooling, and CI for later steps. + +#### 5. Tooling migration + +Follow the Migrate and Monorepos sections in this file, then apply the epic rules below. A single package copies its file shape from [eccrypto](https://github.com/torusresearch/eccrypto), including when `origin` is MetaMask. A monorepo copies its file shape from the newest completed sibling on `origin`'s org. CODEOWNERS still follows `origin`'s org. See [reference.md](reference.md). + +Apply the epic rules that fit this repository: + +- Keep the repo's npm or Yarn choice. Upgrade Yarn Classic to stable Yarn 4.16+ with the node-modules linker. +- `engines.node` `>=24.22.0`, `engines.npm` `>=12`, `.nvmrc` `26`. +- `@types/node` uses major 26, the same major as `.nvmrc`. Set the range to the newest `26` release older than `min-release-age` (3 days). Look it up with `npm view` during the run. A range already on 25, or any older major, still moves to 26. Install with `--min-release-age=0` only when that 26 release is still inside the window. Fix call sites only where the new types fail. +- `@lavamoat/harden` at moderate level, plus the `.npmrc` in [reference.md](reference.md). +- Latest stable TypeScript, `@toruslabs/config@5`, the `@toruslabs/oxlint-config-*` preset for the project type, and `formatPreset()`. +- `@toruslabs/config@5` sets `strictNullChecks` and drops DOM libs. Add DOM libs for browser packages and fix the new type errors. +- Extend `@toruslabs/config/tsconfig.library.json` or `@toruslabs/config/tsconfig.node.json`. Do not extend a relative `node_modules` path. Typecheck that package after the change. +- Remove a direct `eslint` devDependency. The Oxlint preset loads `eslint` as a transitive peer. After `npm run lint` reports 0 errors, remove `eslint-disable` comments for rules Oxlint does not run. Leave comments for rules Oxlint does run. `.eslintcache` stays gitignored. Delete the local file. +- `libraryPreset()` needs `entry`. Pass `format: ["esm", "cjs"]` with explicit `dist/lib.esm` and `dist/lib.cjs` dirs when consumers need CommonJS. Point `types` at `dist/lib.cjs/index.d.ts` when that is where Vite+ writes declarations. +- Keep required runtime dependencies external. Compare the build with `main`, `module`, `types`, `unpkg`, and `jsdelivr`. +- Replace `torus-scripts` CLI scripts with `vp` tasks. `version-packages` runs Changesets and then updates the lockfile. `release-packages` is `changeset publish` and is not run here. +- Changesets `baseBranch` is the real default branch. `access` is `public` for published packages. +- Retarget an existing lint-staged config to `vp fmt` and `vp lint --fix`. +- Record ESLint rules the Oxlint preset does not replace. +- For Vue, install `oxlint-plugin-vize` and add a separate template-only check. Merge a Tailwind lint fragment field by field. +- Remove a `@babel/runtime` peer only after the build shows it is unused, and record that in the changeset. + +Run `vp help`, `vp help migrate`, and `vp migrate` at the workspace root, then review the diff before further edits. + +#### 6. CI, release PR, and security scanner + +Replace the old test workflows. Copy current action pins from the same reference at execution time: eccrypto for a single package, the newest completed sibling on `origin`'s org for a monorepo. + +- `validate`: pull requests and the default branch; Node `24.22.0` and `26`; install npm 12 for npm repos; `npm ci` (or Yarn equivalent); `npm exec --no -- harden check --package-manager npm`; check; `npm run build`; typecheck; tests. Then `npm pack --dry-run --json`, or `npm pack --workspaces --dry-run --json` in a monorepo. Typecheck does not run `vp pack`. `npm run pack` writes tarballs. Skip `changeset status` on `changeset-release/*` and `dependabot/*`. On npm 12, `npx --no-install` still contacts the registry, so the harden step uses `npm exec --no`. Playwright install stays a separate `npm exec` step. `harden check` defaults to moderate. +- `release-pr`: `workflow_dispatch` only, job limited to the default branch, `changesets/action` v2 pinned to a commit SHA, version script updates the lockfile. It opens or updates the release PR. It does not publish. +- `security-code-scanner`: the MetaMask reusable workflow from [torus-cli #123](https://github.com/torusresearch/torus-cli/pull/123). Resolve the current pin from that reference's `.github/workflows/security-code-scanner.yml`. `scanner-ref` matches that pin. Ignore `node_modules`, `dist`, `build`, and `coverage`. Do not add a second CodeQL workflow. Do not copy the torus-cli package test or its changeset. + +Drop `legacy-peer-deps` from `validate`, deploy, and `release-pr`. Confirm with `npm ci` on npm 12, not with `npm ls`. An optional peer mismatch is not a failed install. Add the flag only after a current install fails without it. + +Add KICS and Trivy only for backend, container, or infrastructure. Add the AWS role and Wiz sensor only when this repo already deploys. Record items that do not apply. + +#### 7. Update dependencies and audit + +Update every direct dependency, devDependency, peerDependency, and override. Move each declared range to the newest release on the same major that is older than `min-release-age` (3 days). `npm view version` ignores that window, so check the publish time. A range that already accepts the version still moves up to that release, including a peer range. `"vite": "^1.0.0"` becomes `"vite": "^1.4.0"` when `1.4.0` is that release. Refresh the lockfile with the npm major CI uses (npm 12). Update an `allowScripts` pin when the installed version changes. + +Do not cross a major unless **Sequence and prerequisites** lists that package. `@types/node` is already on major 26 from step 5. Raise it only within 26, to the newest release older than the window. Do not move a version another tool pins exactly (`vite-plus` pins `vitest` and `@vitest/browser-playwright` at `5.0.5`). Also leave a direct dependency whose next release requires that pin: `@vitest/coverage-istanbul@5.1.0` requires `vitest@5.1.0`, so it stays at `5.0.5`. Leave a release inside the 3-day window for the next Dependabot pass, except packages from **Sequence and prerequisites**, which stay on the version installed in step 4. + +Compare `npm audit` (or Yarn) with Dependabot. An in-range fix updates the lockfile only. Do not force a major with an override when that changes the API. Re-run `harden check` after each dependency update. List alerts left open and why. Leave Dependabot dismissal to the user. + +#### 8. Package.json cleanup + +Check every `package.json` entry and remove one only when this repository does not use it. Cover `dependencies`, `devDependencies`, `peerDependencies`, `optionalDependencies`, `overrides`, and `allowScripts`. Leave `engines`, `devEngines`, and `scripts` alone unless a removed package is the only reason a script exists. + +Search the repo outside `node_modules`, `dist`, and the lockfile. Then check the dependency list of each package you keep. A package another dependency already installs can still stay when this repo imports it or a script runs it. + +- Remove a direct dependency that nothing imports and no script or CI step runs. `rimraf` and `tsx` are leftovers from the old `torus-scripts` scripts. Confirm the kept packages do not depend on them. +- Remove a direct `vite` or `vitest` devDependency when `vite-plus` already depends on those exact versions. Keep `vite-plus`. Keep the `vite` and `vitest` overrides: the `vite` override points every `vite` install at `@voidzero-dev/vite-plus-core`, and the `vitest` override holds the version `vite-plus` pins. Keep `@vitest/browser-playwright` and `@vitest/coverage-istanbul` while the test config uses them, on the versions from step 7. +- Keep `@lavamoat/harden`, `@changesets/cli`, `typescript`, `@toruslabs/config`, the Oxlint preset, `@toruslabs/torus-scripts`, `playwright`, and `@types/*` packages the compiler still resolves. Keep `husky` and `lint-staged` when `prepare` and the pre-commit hook use them. +- Remove an override when a lockfile refresh without it resolves the same version, and the override is not a security floor or a tool pin. The old `esbuild` override is that case once `tsx` is gone and Vite no longer installs `esbuild`. Confirm with `npm install --package-lock-only` on npm 12. Put the override back if the resolved version changes. +- Under `allowScripts`, remove a `pkg@version` pin that is not in the lockfile. `fsevents@2.3.2` leaves with `tsx`. Keep a pin for an installed package that has an install script. `false` means the script does not run, so `fsevents@2.3.3` stays while Vite installs that version. When a removal changes the installed version of a package that still has an install script, update that pin. + +Leave `devEngines` as the reference writes it: `packageManager` `npm` `>=11.17.0` with `onFail` `error`. That check is for contributors. `engines.npm` stays `>=12`. + +Refresh the lockfile with npm 12. Run check, build, and typecheck. Do not commit. + +#### 9. Verify and finish the draft + +Clean install, check, build, typecheck, and tests on Node 24 and 26. Inspect the packed tarball and both `require` and import when the package publishes both. Run browser and service checks the story asks for. + +Do not publish. + +Finish the step 2 PR body: majors, export and types paths, scan coverage, open alerts, checks that did not run, and the GitHub setting that lets Actions open the release PR. Publish stays manual on the default branch after that PR merges. + +### Notes to consider + +These were settled on torus-ui ([PR #370](https://github.com/torusresearch/torus-ui/pull/370), EMBED-592) by two forks of the review chat. Apply the lesson to the repository in front of you. A major upgrade is allowed for a package listed in **Sequence and prerequisites**, and for `@types/node` major 26. Step 7 raises every other direct range on the same major. + +#### Forks on one branch + +- The parent chat keeps only the turns from before the fork. Look up the other forks before editing the same branch. +- Pull before you commit. Name commits that were already on the branch. A push publishes every local commit, including ones another fork made. +- The torus-ui split after the shared comments: one fork took 6, 7, 8, and 10; the other took 5, 9, and 12. Comments 1, 2, and 4 landed once. There is no comment 11. + +#### Step 5 + +- Declare every package a workspace imports. `oxfmt` and `@toruslabs/torus-scripts` in a child package are not covered by the root `package.json` or by hoisting. When adding `oxfmt`, pin the version already resolved by vite-plus. Leave unrelated lockfile `dev` flags alone. +- `oxfmt` formats SVG only when the filename passed to it ends in `.html`. The icons lint script already did that with Prettier. The files on disk stay `.svg`. Log the error in that script's `catch` before `process.exit(1)`. +- `@ts-expect-error` on `TS2590` fails typecheck with `TS2578` once the diagnostic disappears. `@ts-ignore` is acceptable there when the user will replace it with a real type later. Keep the `TS2590` explanation on the comment. +- `?? ""` changes runtime behavior. An empty string then matches a missing value. Guard with `!== undefined`. +- Type element refs as `ref`. Check them again after `await`. A check before `computePosition` does not cover the property read after it. +- The Vue template lint script must `throw result.error` when `spawnSync` fails. Ignore the temp oxlintrc it writes. +- Merge `tailwindLintPreset` into `vueLintPreset` field by field (`jsPlugins`, `rules`, `settings`). A single spread replaces `jsPlugins` and drops `oxlint-plugin-vize`. Install `oxlint-tailwindcss`. Record that those rules read JSX and `className`, and they do not read `class` inside a Vue `