uptide 0.0.1 → 0.2.0-next.20261001225052

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Uptide contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,213 @@
1
+ # Uptide
2
+
3
+ **Renovate updates the version. We update the code.**
4
+
5
+ Uptide tells you which of your call sites a dependency upgrade breaks, then migrates
6
+ them on a branch it has verified with your own compiler and tests. Today it covers
7
+ **zod 3 → 4** and **stripe**, in TypeScript repositories.
8
+
9
+ ## Quickstart (30 seconds)
10
+
11
+ No account, no config. In your repository, with dependencies installed:
12
+
13
+ ```sh
14
+ npx uptide # where zod and stripe stand: installed, latest, majors behind
15
+ npx uptide check # which of your lines the upgrade breaks
16
+ npx uptide fix --only zod # migrate on a new branch; nothing is pushed
17
+ ```
18
+
19
+ Requires Node 20 or newer. `check` reads npm, pnpm (workspaces and catalogs), yarn
20
+ classic and bun (text lockfile) repositories. `fix` supports npm (lockfile v2/v3, including workspaces), pnpm, and Yarn classic/Berry with the node-modules linker.
21
+
22
+ ## What `check` prints
23
+
24
+ Real output, zod 3.23.8 → 4.6.5 on the pnpm workspace fixture in
25
+ [`packages/cli/smoke/fixtures/pnpm`](packages/cli/smoke/fixtures/pnpm):
26
+
27
+ ```console
28
+ $ uptide check --only zod
29
+ ✔ Repository smoke-pnpm (pnpm workspace, 2 packages) (1ms)
30
+ ✔ Dependencies zod 3.23.8 (1ms)
31
+ ✔ Analysis of zod 4 breaking, 0 deprecated (2.3s)
32
+ zod 3.23.8 → 4.6.5: fetch 6ms, diff 818ms, usages 1.1s, compile 386ms, runtime 6ms
33
+
34
+ (shared across workspaces)
35
+
36
+ zod 3.23.8 → 4.6.5 (1 major behind) · catalog · packages/api, packages/shared
37
+
38
+ BREAKING 4 call sites in 2 files
39
+ ✗ string compiler rejects this usage: No overload matches this call. assisted
40
+ packages/api/src/signup.ts:4
41
+ ✗ enum overload removed or changed assisted
42
+ packages/api/src/signup.ts:5
43
+ ✗ number compiler rejects this usage: Object literal may only specify known properties, and 'invalid_type_error' does not exist in type '$ZodNumberParams'. assisted (80%)
44
+ packages/shared/src/index.ts:8
45
+ ✗ TS2769: No overload matches this call. unknown
46
+ packages/shared/src/index.ts:5
47
+ 14 low-confidence findings hidden (use --all)
48
+ ⚙ 31 unused exports removed (use --all)
49
+
50
+ Summary: 1 package needs attention · 4 breaking · 0 deprecated · 0 unaffected
51
+ 4 of 4 findings are mechanical
52
+ ```
53
+
54
+ The `✔` lines are progress on stderr; the report is on stdout. `check` diffs the public
55
+ API of the installed and the target version, finds your usages of what changed, compiles
56
+ your code against the target, and loads both versions in a sandboxed Node. Nothing in
57
+ your repository is executed.
58
+
59
+ | Flag | Meaning |
60
+ | --- | --- |
61
+ | `--only zod,stripe` | dependencies to check (the default); `--only all` checks every dependency |
62
+ | `--target zod@4.6.5` | exact target, repeatable; default is `latest` |
63
+ | `--cwd <dir>` | repository to work on |
64
+ | `--json` | the full report as JSON on stdout |
65
+ | `--ci` | plain log output: no color, no spinner (`NO_COLOR` is respected too) |
66
+
67
+ Exit codes, for scripts and CI: **0** nothing breaking, **1** breaking changes found,
68
+ **2** uptide could not answer (bad arguments, unsupported repository, no network). When
69
+ it cannot answer, it says why and prints the exact command to run next.
70
+
71
+ ## What `fix` does, and how it verifies
72
+
73
+ On the same fixture (output abridged):
74
+
75
+ ```console
76
+ $ uptide fix --only zod --no-llm
77
+ ✔ Repository smoke-pnpm (pnpm workspace, 2 packages) (29ms)
78
+ assisted fixes off (--no-llm): no code leaves this machine
79
+ ✔ Migration of zod (check, upgrade, fixes, verification) verification passed (5.3s)
80
+
81
+ ## Upgrade zod 3.23.8 → 4.6.5
82
+
83
+ Assisted fixes disabled (--no-llm).
84
+
85
+ | **Changes** | 4 sites in 2 files · 4 by rule · 0 by agent |
86
+ | **Types** | ✅ 4 errors after the bump → 0 |
87
+ ```
88
+
89
+ 1. **Starts clean.** It needs a git repository with a clean working tree, and works on a
90
+ new branch `uptide/<package>-<version>`. Nothing is pushed unless you pass `--pr --yes`.
91
+ 2. **Upgrades.** Bumps the version in every workspace that declares it (and in pnpm
92
+ catalogs), preserving `^`, `~`, or exact ranges. Installs run in a temporary git worktree with lifecycle scripts disabled. The real package manager produces the lockfile; Uptide rejects changes outside the target dependency subtree before copying it back unchanged. One commit.
93
+ 3. **Rule-based fixes.** Deterministic rewrites for the changes it has rules for, such as
94
+ zod's `required_error` / `invalid_type_error` (add `--include-deprecated` for
95
+ `z.string().email()`-style chains). One commit.
96
+ 4. **Assisted fixes (optional).** With `ANTHROPIC_API_KEY` set, sites the rules cannot
97
+ migrate go to the LLM one at a time. A patch is kept only if it removes its compiler
98
+ error and introduces none; otherwise it is reverted and the site is left for you.
99
+ `--no-llm` turns this off.
100
+ 5. **Verifies.** Type-checks with *your* TypeScript (or the bundled compiler when absent) before and after and subtracts the
101
+ errors you already had; runs the test scripts of the affected workspaces; for zod,
102
+ compares v3 and v4 behaviour of your schemas on generated inputs. The exit code is 0
103
+ only if no new type error remains and tests pass. Passing compilation does not prove
104
+ runtime equivalence, so the report in `.uptide/pr-body.md` lists what to review.
105
+
106
+ Stripe API-version changes are never rewritten by rule: they are assisted or left for
107
+ you, with the relevant changelog entries and a dashboard/webhook checklist in the report.
108
+
109
+ ## Scope
110
+
111
+ - **Dependencies:** zod 3 → 4 and stripe (14 and newer). Other dependencies can be
112
+ checked with `uptide check --only <package>`, but that generic check is frozen
113
+ ([decision](docs/decisions/0010-check-freeze.md)) and has no migrations.
114
+ - **Languages:** TypeScript, and JavaScript the compiler can see (`allowJs`).
115
+ - **Package managers:** `check` on npm, pnpm, yarn classic, bun; `fix` on npm v2/v3, pnpm, and Yarn classic/Berry (node-modules).
116
+ - **Not supported:** Yarn Plug'n'Play, bun's binary lockfile, Deno.
117
+
118
+ ## Privacy
119
+
120
+ Analysis runs locally. Your code is sent only to the LLM provider (Anthropic), only
121
+ for assisted fixes in `uptide fix`, and only with your own ANTHROPIC_API_KEY: for each
122
+ site the rules cannot migrate, the finding, the enclosing function and the compiler
123
+ error. `uptide fix --no-llm` turns assisted fixes off. No telemetry, no account.
124
+ Other network use: your npm registry for package metadata and tarballs, and GitHub
125
+ only when you pass `fix --pr` or run `pr-body`.
126
+
127
+ ## GitHub Action: Renovate / Dependabot
128
+
129
+ Use [the example workflow](examples/uptide-workflow.yml), pinning a reviewed commit of `lucasbraum/uptide`. It checks same-repository bot PRs on `pull_request`
130
+ `opened`/`synchronize`, detects zod/stripe upgrades from manifests, catalogs and lockfile
131
+ importers, and maintains one sticky findings comment. `only` selects dependencies;
132
+ `paths` selects repository-relative source directories/globs.
133
+
134
+ `fix: 'true'` plus `anthropic-api-key` enables migration. Comparison uses **PR-head
135
+ source with the base dependency graph** in a temporary worktree. Final verification
136
+ uses the actual PR-head manifests/lockfile; only source patches are transferred. A
137
+ passing migration pushes **one commit on the existing PR branch**. Manual sites,
138
+ failed tests/types, or a changed PR head prevent publication. No force-push or merge.
139
+ Current migration support is TypeScript, zod and stripe, using npm, pnpm or Yarn with node_modules. Missing workspace test
140
+ scripts are reported, not claimed as passing tests. Code context may be sent to
141
+ Anthropic only in assisted mode. Install/test children receive no API/token secrets.
142
+
143
+ Use `contents: write` and `pull-requests: write`, `persist-credentials: false`, and the
144
+ same-PR concurrency group shown in the example. Dependabot PRs normally receive a
145
+ read-only `GITHUB_TOKEN` and do not receive ordinary Actions secrets: configure the
146
+ key and an appropriately scoped write token as **Dependabot secrets**, or run in a
147
+ maintainer-controlled workflow. Do not change to `pull_request_target` to bypass
148
+ this boundary. Fork PRs are skipped. See [GitHub's Dependabot restrictions](https://docs.github.com/en/code-security/reference/supply-chain-security/troubleshoot-dependabot/dependabot-on-actions).
149
+
150
+ ```sh
151
+ pnpm eval:action # local GitHub API simulation + real check/fix/tsc/tests/git remote
152
+ ```
153
+
154
+ This creates an isolated demo repository and bare local remote under `eval-out/`,
155
+ with a zod 3 baseline, a Renovate-style bump branch, and the verified migration result.
156
+ It also proves that a final-verification failure cannot push. The generated README
157
+ contains commands to publish your throwaway repository. **No hosted GitHub run or PR
158
+ is created by this evaluation.** The real workflow requires a bot-authored PR; a
159
+ human-authored imitation is intentionally rejected.
160
+
161
+ ## PR descriptions
162
+
163
+ `fix` saves `.uptide/report.json` with the verified commit, Uptide version/commit, rule IDs, patches, agent
164
+ reasoning and run metadata. PR bodies show a computed risk, a five-row summary, changes
165
+ grouped by rule, and actionable review items.
166
+
167
+ To regenerate an existing description without another migration or any push:
168
+
169
+ ```sh
170
+ uptide pr-body --pr 82 --preview # review the complete proposal first
171
+ uptide pr-body --pr 82 # update only the description
172
+ # For a retained eval run, add --cwd /path/to/target/repo --run /path/to/report.json.
173
+ ```
174
+
175
+ The selected PR must match the stored run's branch and verified commit. Risk is Low
176
+ for verified rule-only edits, Medium for agent edits, sensitive paths or missing tests,
177
+ and High for unverified sites, behavior changes or remaining manual work. Unchecked
178
+ schema samples are called out separately; they do not imply unresolved compiler sites.
179
+
180
+ Builds embed the Uptide commit and whether its source checkout had working-tree changes.
181
+ `pnpm exec tsx scripts/reverify-run.ts <run.json> [output.json]` refreshes behavior
182
+ and type verification on the recorded commit without installing or changing source.
183
+ Diffs, file lists, verification and run details are collapsed; the Action comment and
184
+ terminal share the compact migration renderer.
185
+
186
+ ## Development
187
+
188
+ ```sh
189
+ pnpm test # offline regressions
190
+ UPTIDE_NETWORK=1 pnpm test # real package digests and Stripe tsc fixture
191
+ pnpm eval:fix ../wayapi --without-key
192
+ pnpm eval:fix ../wayapi --with-key
193
+ # Only after reviewing a successful eval, publish from another temporary worktree:
194
+ pnpm eval:fix ../wayapi --with-key --pr --yes
195
+ pnpm eval:fix /path/to/repo --only=stripe --target=stripe@22.6.2 --without-key
196
+ ```
197
+
198
+ `eval:fix` creates a temporary git worktree, copies installed dependencies (not symlinks
199
+ to the source repo), and retains the result for review. Artifacts go in `eval-out/`.
200
+ `--with-key` fails explicitly when no key is configured. `pnpm eval:stripe-fixture`
201
+ measures the checked-in Stripe consumer with real `tsc`; `pnpm build:stripe-changelog`
202
+ refreshes the versioned public changelog JSON. Migration execution never fetches it.
203
+
204
+ `uptide diff <pkg> <from> <to> [--json]` compares the full public surface of two
205
+ versions. Tarballs, surfaces and runtime probes are cached in `~/.cache/uptide/`.
206
+ Releasing is described in [docs/releasing.md](docs/releasing.md); `pnpm smoke` runs the
207
+ packed CLI against npm v3, npm workspaces v2, pnpm catalogs, Yarn classic and Yarn Berry fixtures in clean Node 20/22 containers. Run `pnpm smoke 20` and `pnpm smoke 22`. Each case verifies zod migration and a compatible Stripe SDK upgrade without an LLM; lifecycle-script traps must remain untouched. Lockfile diffs and JSON results are saved beside the temporary CLI tarball.
208
+
209
+ Yarn PnP remains unsupported. Missing package-manager binaries or mismatched pinned versions fail with an exact Corepack recovery command. Unsupported range/lockfile syntax fails explicitly rather than silently broadening the upgrade.
210
+
211
+ ## License
212
+
213
+ [MIT](LICENSE).
@@ -0,0 +1,6 @@
1
+ import { createRequire as __uptideCreateRequire } from 'node:module';
2
+ import { fileURLToPath as __uptideFileURLToPath } from 'node:url';
3
+ const require = __uptideCreateRequire(import.meta.url);
4
+ const __filename = __uptideFileURLToPath(import.meta.url);
5
+ const __dirname = __uptideFileURLToPath(new URL('.', import.meta.url));
6
+ var __create=Object.create;var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __getProtoOf=Object.getPrototypeOf,__hasOwnProp=Object.prototype.hasOwnProperty;var __require=(x=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(x,{get:(a,b)=>(typeof require<"u"?require:a)[b]}):x)(function(x){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+x+'" is not supported')});var __commonJS=(cb,mod)=>function(){return mod||(0,cb[__getOwnPropNames(cb)[0]])((mod={exports:{}}).exports,mod),mod.exports};var __copyProps=(to,from,except,desc)=>{if(from&&typeof from=="object"||typeof from=="function")for(let key of __getOwnPropNames(from))!__hasOwnProp.call(to,key)&&key!==except&&__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable});return to};var __toESM=(mod,isNodeMode,target)=>(target=mod!=null?__create(__getProtoOf(mod)):{},__copyProps(isNodeMode||!mod||!mod.__esModule?__defProp(target,"default",{value:mod,enumerable:!0}):target,mod));var __defProp2=Object.defineProperty,__export=(target,all)=>{for(var name in all)__defProp2(target,name,{get:all[name],enumerable:!0})};export{__require,__commonJS,__toESM,__export};