Skip to content

refactor: move the TypeScript packages into languages/typescript - #1000

Draft
auxesis wants to merge 9 commits into
mainfrom
refactor/typescript-to-languages
Draft

auxesis wants to merge 9 commits into
mainfrom
refactor/typescript-to-languages

Conversation

@auxesis

@auxesis auxesis commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

This PR moves every npm package except EQL from packages/ to languages/typescript/packages/, and moves examples/ to languages/typescript/examples/. It changes folders and the paths that name them, and renames no package. The move leaves only EQL in packages/, so PR B can put the Rust crates there.

This is PR A of 6 in the stack crates import. The import moves six Rust crates, their bindings and the Go module here from the private cipherstash/cipherstash-suite repository, with their git history. The stack crates import plan in Linear lists every step, and Linear issue CIP-4274 tracks the work.

PR A is the first of the six, so its base is main, and each later PR is built on the one before it. All six stay drafts until the freeze on Friday 2 October 2026, Pacific time. The freeze is the window in which they merge in order: #1000, #1001, #1003, #1002, #1009, then #1010. The steps for that day are in §9.1 of the plan.

Spot-check commits 1 and 2, and read commits 3 to 9 line by line

Scripts produced commits 1 and 2, and both are very large. Check their shape rather than reading every line:

  • Commit 1 only moves files. git show --stat -M 71099940 reports 1,017 files changed, with 0 insertions and 0 deletions.
  • Commit 2 rewrites old paths to new ones in 177 files. It then runs Biome, the formatter and linter, which rewraps some lines that grew longer. Open a few files and confirm that each change is a path or a rewrapped line.
  • In pnpm-lock.yaml, commit 2 changes paths only. pnpm also re-sorts the lockfile's list of workspace folders, so the EQL block moves position, but no version changes.

Commits 3 to 9 are written by hand. They fix what the scripts cannot, so they need a full review.

The scripts are in stack-migration/pr-a/ on the migration machine, not in this repository. If main moves before the merge, redo.sh there rebuilds this PR on the newer main. It re-runs the scripts for commits 1 and 2, then replays commits 3 to 9 on top.

Each commit makes one kind of change

  1. 71099940 moves 1,017 files with git mv and changes nothing inside them, so git log --follow keeps each file's history. The repository does not build at this commit, because the paths still point at the old folders.
  2. 61960da4 rewrites every path that names a moved package. It covers workflows, scripts, configs, docs, pnpm-lock.yaml and the globs in biome.json, Biome's config. It also covers repository.directory, the package.json field that tells npm which folder holds a published package.
  3. 5867232b fixes relative paths that climb out of a moved package. Each package now sits two folders deeper, so a path such as ../../skills needs two more ../. Some of these fail without an error. With the old path, the stash and @cipherstash/wizard builds succeed but ship no skills. The commit also fixes protect-ffi's path dependency on eql-bindings.
  4. 6df068d0 updates five repository checks that name a package folder as a plain string, such as 'packages'. A path rewrite cannot see a bare folder name. Two of these checks skip a missing folder silently, so after the move they passed without checking anything.
  5. ea5cf1a9 keeps EQL in the root test and dev scripts. Both now select packages in languages/typescript/packages/ and in packages/, so pnpm test still runs EQL's tests.
  6. 1b18f0fb describes the new layout in AGENTS.md, CONTRIBUTING.md, SECURITY.md and the other current docs. It fixes paths that the rewrite missed, for example a path that ends at a backtick.
  7. bafbfc72 points the end-to-end Dependabot test at the new folder. The test uses a made-up Dependabot entry for /packages/*, which now matches only EQL. Only turbo run test:e2e --filter @cipherstash/e2e runs this test.
  8. 7162d957 redraws the folder diagrams in CONTRIBUTING.md and docs/agents/domain.md. Each diagram draws a folder on its own line, so no path rewrite could match it.
  9. b3ffccd4 adds repository.directory to the @cipherstash/protect-ffi wrapper. It was the one published package without the field, so npm could not link its package page to its source folder.

History files keep the old paths on purpose

docs/plans/, docs/superpowers/, every CHANGELOG.md and every pending .changeset/*.md file keep the old paths. A changeset is a file that describes a change, and the next release copies it into a changelog. These files record what was true when someone wrote them. scripts/lint-no-dead-package-paths.mjs, the check that finds paths to missing folders, exempts them for that reason.

The checks pass locally and in CI

  • pnpm install --frozen-lockfile passes. A frozen install fails if the lockfile does not match the package manifests.
  • pnpm run code:check passes. It runs biome check.
  • pnpm test:scripts passes 937 tests. These test the repository's own scripts and checks.
  • turbo run typecheck passes in 16 of 16 packages.
  • With no credentials set, the end-to-end tests pass 48 and skip 16.
  • The stash and @cipherstash/wizard tarballs each contain all 14 skills.
  • CI: 41 checks pass and 1 is skipped.

A deliberate break makes each changed check fail

Commit 4 changes five repository checks. For each one, a deliberate break of the thing it checks now makes it fail:

  • lint-typecheck-scope: a moved package's tsconfig compiles dist/.
  • lint-no-hardcoded-runners: a bare 'npx' in stack/src.
  • lint-no-dead-package-paths: an old packages/stack path in CONTRIBUTING.md.
  • package-readmes: --eql-version in the stack README.
  • turbo-skills-inputs: the skills input removed from stash#build.

Before commit 4, lint-typecheck-scope and lint-no-hardcoded-runners passed with their breaks in place, because they checked nothing.

Links in published READMEs return 404 until this PR merges

The READMEs that npm publishes now link to tree/main/languages/typescript/... on GitHub. Those links return 404 until this PR merges, because the new folders exist on main only after it.

Merge this PR with a merge commit

Merge it with a merge commit, which keeps all 9 commits, and never with a squash or a rebase. PR B is built on these exact commits. A squash or a rebase would leave PR B based on commits that are not in main.

🤖 Generated with Claude Code

https://claude.ai/code/session_01PaY5xYydZUWhv8Nex9Sw8a

@changeset-bot

changeset-bot Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: b3ffccd

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

auxesis and others added 9 commits October 2, 2026 17:45
Pure rename, no content changes, so git log --follow keeps each file's
history. Every package under packages/ except EQL moves to
languages/typescript/packages/, and examples/ moves to
languages/typescript/examples/. packages/ is left for Rust crates and
EQL, which stays whole at packages/eql.

The tree does not build at this commit; the next commits update the
references to the old paths.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PaY5xYydZUWhv8Nex9Sw8a
Mechanical rewrite of every root-relative reference to a moved package
or to examples/: workflows, the build-ffi-binding action, Dependabot,
scripts, turbo.json, biome.json, vitest.shared.ts, .gitignore, e2e/,
skills/, the agent guides and current docs, each package's own files
(including repository.directory in every published manifest), and the
importer keys and link: paths in pnpm-lock.yaml.

The lock change is path-only. pnpm then puts the importers in its own
order, which moves the packages/eql/packages/eql block; regenerating
the lock changes no version.

Left alone because they record history: docs/plans/,
docs/superpowers/, every CHANGELOG.md and pending .changeset/*.md
files, as scripts/lint-no-dead-package-paths.mjs already requires.

This commit is generated, then formatted with biome format. Relative
paths that climb out of a moved package, bare-string package roots in
the linters, and prose follow in separate commits.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PaY5xYydZUWhv8Nex9Sw8a
Each moved package now sits two levels deeper, so every relative path
that climbs to the repository root gains two `..`. A rewrite of
`packages/` cannot see these, and several fail silently:

- cli and wizard tsup configs copy ../../../../skills. The copy is
  guarded by existsSync, so the old path built tarballs without
  skills/ and no error.
- seven vitest configs import ../../../../vitest.shared, and the cli
  scaffold tsconfig extends ../../../../tsconfig.json.
- protect-ffi's eql-bindings path dependency becomes
  ../../../../../../packages/eql/crates/eql-bindings. The comments in
  workflows, the build-ffi-binding action and scripts that quote it
  follow.
- repository-root helpers built from resolve(x, '../..') or
  join(..., '..', '..') in the cli tests, test-kit/src/install.ts,
  the stack-prisma tests and the cli's bundled-folder dev fallback.
- protect-ffi tests that read ../../.github and ../../turbo.json
  relative to process.cwd(), the package root.
- e2e/tests imports of ../../packages/cli/src/*.js, which name .ts
  files, the dist/ and node_modules/ mappings in e2e/wasm/deno.json,
  and scripts/__tests__ imports of package vitest configs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PaY5xYydZUWhv8Nex9Sw8a
A path rewrite does not touch a package root held as a bare string,
because it has no trailing slash. Two checks skip a missing root
without an error, so after the move they passed while checking
nothing:

- lint-typecheck-scope walked `packages` and `examples`, so it
  checked only EQL. With a migrate tsconfig that compiles dist/, it
  exited 0. It now walks languages/typescript/packages and
  languages/typescript/examples as well, and reports the break.
- lint-no-hardcoded-runners scanned only `packages`. With a bare
  'npx' in stack/src it exited 0. It now scans
  languages/typescript/packages and packages, and reports it.

Three failed loudly and needed the same change:

- lint-no-dead-package-paths took its live set from packages/ alone.
  It now checks each reference against the root it names, so a
  leftover root-level path to a moved package is reported dead. Its
  fixtures name the new root.
- lib/package-readmes.mjs selects README pathspecs from both roots.
  The unshipped EQL subtree root README (packages/eql/README.md) is
  no longer selected, because packages/* is no longer a workspace
  glob; the guards that use it run three fewer cases (912 to 909).
- turbo-skills-inputs reads languages/typescript/packages and matches
  the four-level cpSync('../../../../skills').

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PaY5xYydZUWhv8Nex9Sw8a
The JavaScript root stays at the repository root; only its member
paths move.

- Root test and dev filter both ./languages/typescript/packages/** and
  ./packages/**. The second filter is what runs @cipherstash/eql#test;
  a filter naming only languages/typescript drops it, as the one-level
  ./packages/* filter once did. build stays one level deep on
  ./languages/typescript/packages/*, and consumers pull EQL's build
  through ^build.
- pnpm-workspace.yaml: the comments that explained the old packages/*
  glob in terms of EQL no longer described the file after the rewrite.
- turbo.json: the comment quoting the tsup skills copy names the new
  four-level path.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PaY5xYydZUWhv8Nex9Sw8a
AGENTS.md gains a layout paragraph, and its notes on the root test
filter name both package roots, since a filter naming only
languages/typescript drops @cipherstash/eql#test. CONTRIBUTING.md,
SECURITY.md, e2e/README.md and docs/query-api-walkthrough.md name
examples/ and packages/ in prose the rewrite could not see, because
the path ends at a backtick.

Left alone on purpose: docs/plans/, docs/superpowers/, CHANGELOG.md
files and pending changesets. They record history, and
lint-no-dead-package-paths already exempts them for that reason.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PaY5xYydZUWhv8Nex9Sw8a
supply-chain.e2e.test.ts exercises the `directories` glob branch with a
synthetic `/packages/*` entry. After the move that glob matches only
packages/eql, which has no package.json, so the assertion failed.
Neither `pnpm test` nor `test:scripts` runs this suite; it fails only
under `turbo run test:e2e --filter @cipherstash/e2e`.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PaY5xYydZUWhv8Nex9Sw8a
The ASCII trees in CONTRIBUTING.md and docs/agents/domain.md draw
packages/ and examples/ as tree branches, which no path rewrite
matches. They now show languages/typescript/packages/,
languages/typescript/examples/ and EQL at packages/eql/.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PaY5xYydZUWhv8Nex9Sw8a
Every other published manifest, including the six protect-ffi platform
packages, names its folder in repository.directory. The wrapper did
not, so npm and GitHub could not link its package page to its source,
and no test could check every published manifest at once.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PaY5xYydZUWhv8Nex9Sw8a

@yujiyokoo yujiyokoo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks like all structural changes. LGTM

Reviewed with GPT-6-Luna medium

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants