@rebasepro/cli 0.23.0 → 0.24.1-canary.g19596ef

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.
Files changed (186) hide show
  1. package/README.md +19 -3
  2. package/bin/rebase.js +4 -1
  3. package/dist/agent-setup-B31F00DC.js +324 -0
  4. package/dist/agent-setup-B31F00DC.js.map +1 -0
  5. package/dist/api-keys-Bl1I9q7M.js +525 -0
  6. package/dist/api-keys-Bl1I9q7M.js.map +1 -0
  7. package/dist/apps-CNgQJjg5.js +340 -0
  8. package/dist/apps-CNgQJjg5.js.map +1 -0
  9. package/dist/args-BnmsEXvu.js +109 -0
  10. package/dist/args-BnmsEXvu.js.map +1 -0
  11. package/dist/atlas-dev-database-D_LP_Woq.js +62 -0
  12. package/dist/atlas-dev-database-D_LP_Woq.js.map +1 -0
  13. package/dist/auth-aySHEF45.js +414 -0
  14. package/dist/auth-aySHEF45.js.map +1 -0
  15. package/dist/branch-pointer-DvSHBjjz.js +2 -0
  16. package/dist/build-DIHWIqO4.js +336 -0
  17. package/dist/build-DIHWIqO4.js.map +1 -0
  18. package/dist/bundle-CqURVN-K.js +1621 -0
  19. package/dist/bundle-CqURVN-K.js.map +1 -0
  20. package/dist/bundle.d.ts +12 -3
  21. package/dist/cli.d.ts +23 -2
  22. package/dist/cloud-DjByQlkW.js +9667 -0
  23. package/dist/cloud-DjByQlkW.js.map +1 -0
  24. package/dist/collection-drift-BKj_BoMq.js +106 -0
  25. package/dist/collection-drift-BKj_BoMq.js.map +1 -0
  26. package/dist/commands/__test_support__/parser-specs.d.ts +13 -0
  27. package/dist/commands/agent-setup.d.ts +116 -0
  28. package/dist/commands/api-keys.d.ts +86 -23
  29. package/dist/commands/apps.d.ts +17 -0
  30. package/dist/commands/auth.d.ts +7 -0
  31. package/dist/commands/build.d.ts +5 -1
  32. package/dist/commands/cloud/auth.d.ts +4 -3
  33. package/dist/commands/cloud/bundle-deploy.d.ts +45 -0
  34. package/dist/commands/cloud/context.d.ts +44 -5
  35. package/dist/commands/cloud/cron.d.ts +53 -0
  36. package/dist/commands/cloud/debug.d.ts +134 -0
  37. package/dist/commands/cloud/index.d.ts +89 -12
  38. package/dist/commands/cloud/token-capabilities.d.ts +76 -0
  39. package/dist/commands/cloud/tokens.d.ts +23 -0
  40. package/dist/commands/console.d.ts +12 -0
  41. package/dist/commands/db.d.ts +79 -25
  42. package/dist/commands/dev.d.ts +181 -13
  43. package/dist/commands/doctor.d.ts +5 -0
  44. package/dist/commands/generate_sdk.d.ts +29 -2
  45. package/dist/commands/init.d.ts +115 -14
  46. package/dist/commands/schema.d.ts +6 -0
  47. package/dist/commands/skills.d.ts +126 -7
  48. package/dist/commands/start.d.ts +44 -0
  49. package/dist/commands/storage.d.ts +46 -0
  50. package/dist/commands/upgrade.d.ts +1 -0
  51. package/dist/consent-ClRHmcxf.js +76 -0
  52. package/dist/consent-ClRHmcxf.js.map +1 -0
  53. package/dist/console-D6SJf8k_.js +102 -0
  54. package/dist/console-D6SJf8k_.js.map +1 -0
  55. package/dist/context-BqhRydBg.js +1234 -0
  56. package/dist/context-BqhRydBg.js.map +1 -0
  57. package/dist/{daemon-entry-LTFKtpHy.js → daemon-entry-Da-D3rmH.js} +3 -4
  58. package/dist/daemon-entry-Da-D3rmH.js.map +1 -0
  59. package/dist/daemon-pzsQwDHa.js +2 -0
  60. package/dist/db-B7RuNuaQ.js +1312 -0
  61. package/dist/db-B7RuNuaQ.js.map +1 -0
  62. package/dist/derive-Dl0z2OWi.js +484 -0
  63. package/dist/derive-Dl0z2OWi.js.map +1 -0
  64. package/dist/dev-CYr_WXan.js +1599 -0
  65. package/dist/dev-CYr_WXan.js.map +1 -0
  66. package/dist/dev-db/atlas-dev-database.d.ts +32 -0
  67. package/dist/dev-db/daemon-entry.d.ts +13 -0
  68. package/dist/dev-db/daemon.d.ts +10 -0
  69. package/dist/dev-db/last-dev-database.d.ts +41 -0
  70. package/dist/dev-db/prepare.d.ts +29 -3
  71. package/dist/dev-db/pull.d.ts +90 -5
  72. package/dist/dev-db/resolve.d.ts +26 -2
  73. package/dist/dev-preflight-B-LYyBf1.js +2 -0
  74. package/dist/dev-server-DG8Tt-uf.js +96 -0
  75. package/dist/dev-server-DG8Tt-uf.js.map +1 -0
  76. package/dist/doctor-BP8cZ-7F.js +771 -0
  77. package/dist/doctor-BP8cZ-7F.js.map +1 -0
  78. package/dist/eject-DizdoecV.js +335 -0
  79. package/dist/eject-DizdoecV.js.map +1 -0
  80. package/dist/fold-static-BC9CYicw.js +201 -0
  81. package/dist/fold-static-BC9CYicw.js.map +1 -0
  82. package/dist/fold-static.d.ts +26 -3
  83. package/dist/function-portability-BIvlvR9q.js +265 -0
  84. package/dist/function-portability-BIvlvR9q.js.map +1 -0
  85. package/dist/generate_sdk-BPqdJc3Q.js +489 -0
  86. package/dist/generate_sdk-BPqdJc3Q.js.map +1 -0
  87. package/dist/index.es.js +199 -22095
  88. package/dist/index.es.js.map +1 -1
  89. package/dist/init-Utstvh2Q.js +1149 -0
  90. package/dist/init-Utstvh2Q.js.map +1 -0
  91. package/dist/last-dev-database-B58g89uA.js +2 -0
  92. package/dist/manifest-DRp0UVTj.js +880 -0
  93. package/dist/manifest-DRp0UVTj.js.map +1 -0
  94. package/dist/manifest.d.ts +56 -4
  95. package/dist/normalize-imports-X0Tgze9y.js +107 -0
  96. package/dist/normalize-imports-X0Tgze9y.js.map +1 -0
  97. package/dist/package-manager-DSEOwTqM.js +193 -0
  98. package/dist/package-manager-DSEOwTqM.js.map +1 -0
  99. package/dist/path-flags-BFgG9V6y.js +91 -0
  100. package/dist/path-flags-BFgG9V6y.js.map +1 -0
  101. package/dist/precompress.d.ts +17 -0
  102. package/dist/prepare-CDN6lSpz.js +1236 -0
  103. package/dist/prepare-CDN6lSpz.js.map +1 -0
  104. package/dist/{project-3WCbrrfW.js → project-Wp2zoyeN.js} +34 -184
  105. package/dist/project-Wp2zoyeN.js.map +1 -0
  106. package/dist/pull-CrGYMEsy.js +458 -0
  107. package/dist/pull-CrGYMEsy.js.map +1 -0
  108. package/dist/resolve-B2O-wKKk.js +2 -0
  109. package/dist/resources-FD7AfZx8.js +183 -0
  110. package/dist/resources-FD7AfZx8.js.map +1 -0
  111. package/dist/schema-DMdr431S.js +125 -0
  112. package/dist/schema-DMdr431S.js.map +1 -0
  113. package/dist/skills-DTFibT1m.js +642 -0
  114. package/dist/skills-DTFibT1m.js.map +1 -0
  115. package/dist/start-DEa-hOBh.js +267 -0
  116. package/dist/start-DEa-hOBh.js.map +1 -0
  117. package/dist/{state-C59Elrnt.js → state-Do7ZJYkF.js} +49 -4
  118. package/dist/state-Do7ZJYkF.js.map +1 -0
  119. package/dist/status-DxnJTekv.js +352 -0
  120. package/dist/status-DxnJTekv.js.map +1 -0
  121. package/dist/storage-DyVq-f_F.js +303 -0
  122. package/dist/storage-DyVq-f_F.js.map +1 -0
  123. package/dist/telemetry/identity.d.ts +10 -1
  124. package/dist/telemetry-C8Uq8phb.js +129 -0
  125. package/dist/telemetry-C8Uq8phb.js.map +1 -0
  126. package/dist/telemetry-EMFRVRQi.js +351 -0
  127. package/dist/telemetry-EMFRVRQi.js.map +1 -0
  128. package/dist/unknown-command-DNwDcX3w.js +98 -0
  129. package/dist/unknown-command-DNwDcX3w.js.map +1 -0
  130. package/dist/upgrade-CtZtRkTE.js +1332 -0
  131. package/dist/upgrade-CtZtRkTE.js.map +1 -0
  132. package/dist/upgrade.d.ts +38 -5
  133. package/dist/utils/dev-preflight.d.ts +47 -5
  134. package/dist/utils/dev-server.d.ts +30 -0
  135. package/dist/utils/path-flags.d.ts +31 -0
  136. package/dist/utils/project.d.ts +16 -0
  137. package/dist/utils/temp-archive.d.ts +9 -0
  138. package/dist/version-Buyyo1ut.js +58 -0
  139. package/dist/version-Buyyo1ut.js.map +1 -0
  140. package/package.json +7 -7
  141. package/templates/eject/Dockerfile +4 -2
  142. package/templates/eject/backend/src/env.ts +1 -1
  143. package/templates/eject/backend/src/index.ts +42 -4
  144. package/templates/eject/docker-compose.custom.yml +8 -4
  145. package/templates/generated-schemas/blank.ts +40 -0
  146. package/templates/generated-schemas/blog.ts +127 -0
  147. package/templates/generated-schemas/ecommerce.ts +93 -0
  148. package/templates/overlays/baas/ai-instructions.md +1 -1
  149. package/templates/overlays/baas/config/package.json +1 -0
  150. package/templates/overlays/baas/config/storage.ts +5 -3
  151. package/templates/overlays/baas/package.json +1 -0
  152. package/templates/template/.cursorrules +1 -1
  153. package/templates/template/.env.example +20 -10
  154. package/templates/template/.github/copilot-instructions.md +1 -1
  155. package/templates/template/.mcp.json +2 -2
  156. package/templates/template/.windsurfrules +1 -1
  157. package/templates/template/AGENTS.md +1 -1
  158. package/templates/template/CLAUDE.md +1 -1
  159. package/templates/template/README.md +21 -15
  160. package/templates/template/ai-instructions.md +5 -4
  161. package/templates/template/backend/functions/hello.ts +8 -0
  162. package/templates/template/backend/package.json +1 -1
  163. package/templates/template/config/resources.ts +7 -6
  164. package/templates/template/config/storage.ts +5 -3
  165. package/templates/template/docker-compose.yml +15 -9
  166. package/templates/template/frontend/vite.config.ts +13 -3
  167. package/templates/template/gitignore +6 -1
  168. package/templates/template/package.json +5 -3
  169. package/templates/template/scripts/example.ts +6 -4
  170. package/templates/template/tsconfig.json +25 -0
  171. package/dist/branch-pointer-dBiClJ0p.js +0 -111
  172. package/dist/branch-pointer-dBiClJ0p.js.map +0 -1
  173. package/dist/constraints-DKGbNfUW.js +0 -48
  174. package/dist/constraints-DKGbNfUW.js.map +0 -1
  175. package/dist/daemon-DR9Tk0La.js +0 -355
  176. package/dist/daemon-DR9Tk0La.js.map +0 -1
  177. package/dist/daemon-entry-LTFKtpHy.js.map +0 -1
  178. package/dist/dev-preflight-CNLl4rdo.js +0 -367
  179. package/dist/dev-preflight-CNLl4rdo.js.map +0 -1
  180. package/dist/project-3WCbrrfW.js.map +0 -1
  181. package/dist/pull-Dywm5FWP.js +0 -232
  182. package/dist/pull-Dywm5FWP.js.map +0 -1
  183. package/dist/resolve-BAeRUBhg.js +0 -74
  184. package/dist/resolve-BAeRUBhg.js.map +0 -1
  185. package/dist/state-C59Elrnt.js.map +0 -1
  186. package/templates/template/backend/src/schema.generated.ts +0 -13
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upgrade-CtZtRkTE.js","names":[],"sources":["../src/upgrade.ts","../src/commands/upgrade.ts"],"sourcesContent":["/**\n * Moving a project's `@rebasepro/*` pins to one release.\n *\n * Every `@rebasepro/*` package ships at one version, and a project declares them\n * in several `package.json` files — the root, `backend/`, `frontend/`,\n * `config/`, and whatever else the repository holds. Bumping them by hand means\n * finding every one, keeping each range's `^` or `~`, and noticing the override\n * that quietly wins over all of them. `rebase upgrade` is that job, done the same\n * way every time; the control plane runs it too, when it rebuilds a managed\n * project on a newer release.\n *\n * Everything here is file work — git is asked only which files are the\n * project's — so it can be tested against a temporary directory: which files\n * are read, which specs move, the rewrite itself, and what overrides say. The\n * command in `commands/upgrade.ts` adds the registry lookup, the install and the\n * printing.\n *\n * ## The rewrite is textual\n *\n * A `package.json` is authored. Parsing it and writing `JSON.stringify` back\n * reformats the file, reorders nothing but reindents everything, and drops a\n * trailing newline or a two-space indent somebody chose — a one-line version\n * bump that arrives as a whole-file diff. So the file is scanned for the exact\n * byte range of each value, only those bytes are replaced, and the result is\n * parsed again and compared against what was intended. A file whose rewrite\n * does not parse back to exactly the intended values is not written.\n */\nimport fs from \"fs\";\nimport path from \"path\";\nimport { execFileSync } from \"child_process\";\nimport { isDeepStrictEqual } from \"util\";\nimport { getPMCommands } from \"./utils/package-manager\";\n\n/** The dependency blocks a pin is moved in. `peerDependencies` is not one. */\nexport const PIN_FIELDS = [\"dependencies\", \"devDependencies\", \"optionalDependencies\"] as const;\nexport type PinField = typeof PIN_FIELDS[number];\n\n/** Every framework package lives under this scope. */\nexport const FRAMEWORK_SCOPE = \"@rebasepro/\";\n\n/** The package whose published versions stand for the release as a whole. */\nexport const RELEASE_PACKAGE = \"@rebasepro/cli\";\n\n/** `MAJOR.MINOR.PATCH`, with an optional prerelease and build, and nothing else. */\nconst SEMVER =\n /^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$/;\n\n/** Whether `value` is one exact version — `0.21.0`, `0.21.1-canary.g8c5a265`. */\nexport function isExactVersion(value: string): boolean {\n return SEMVER.test(value);\n}\n\n/** An error that carries the `--json` envelope's code and a remedy. */\nexport class UpgradeError extends Error {\n constructor(message: string, readonly code: string, readonly hint?: string) {\n super(message);\n this.name = \"UpgradeError\";\n }\n}\n\n/* ─── which specs move ─────────────────────────────────────────────────────── */\n\nexport type SpecClass =\n /** A plain version, optionally `^` or `~`: moved, keeping the prefix. */\n | { kind: \"movable\"; prefix: \"\" | \"^\" | \"~\"; version: string }\n /** A path on this machine. As a pin it is left alone; as an override it wins over every pin. */\n | { kind: \"local\"; protocol: \"link:\" | \"file:\" | \"portal:\" }\n /** A pnpm `catalog:` reference: the version is in pnpm-workspace.yaml's catalog, and moves there. */\n | { kind: \"catalog\"; catalog: string }\n /** Anything else, with the reason it is left alone. */\n | { kind: \"other\"; reason: string };\n\n/**\n * What a dependency spec is, as far as moving it goes.\n *\n * Only a plain version is moved, because only a plain version has an obvious\n * answer: `^0.19.1` becomes `^0.21.0`. A `>=` floor, a `||` union or a partial\n * `^0.19` could each be rewritten several ways, and a tag or a workspace link\n * already means something other than \"this release\" — so each is reported with\n * its reason and left as written.\n */\nexport function classifySpec(spec: string): SpecClass {\n const movable = /^([\\^~]?)(.+)$/.exec(spec);\n if (movable && isExactVersion(movable[2])) {\n return { kind: \"movable\", prefix: movable[1] as \"\" | \"^\" | \"~\", version: movable[2] };\n }\n for (const protocol of [\"link:\", \"file:\", \"portal:\"] as const) {\n if (spec.startsWith(protocol)) return { kind: \"local\", protocol };\n }\n const catalog = /^catalog:(.*)$/.exec(spec.trim());\n if (catalog) return { kind: \"catalog\", catalog: catalog[1].trim() || \"default\" };\n return { kind: \"other\", reason: otherReason(spec) };\n}\n\n/** Why a spec that does not move is left alone, as the report says it. */\nfunction leftAloneReason(cls: Exclude<SpecClass, { kind: \"movable\" }>): string {\n if (cls.kind === \"local\") {\n return `a local ${cls.protocol} path, which points at a checkout on this machine rather than a release`;\n }\n if (cls.kind === \"catalog\") return \"a catalog: reference inside a catalog, which pnpm does not resolve\";\n return cls.reason;\n}\n\nfunction otherReason(spec: string): string {\n const trimmed = spec.trim();\n if (trimmed.startsWith(\"workspace:\")) return \"a workspace: link, resolved inside this repository rather than from the registry\";\n if (trimmed.startsWith(\"npm:\")) return \"an npm: alias; move the aliased version by hand\";\n if (/^(git\\+|git:|github:|gitlab:|bitbucket:|git@)/.test(trimmed) || /^https?:\\/\\//.test(trimmed)) {\n return \"a git or URL dependency, not a registry version\";\n }\n if (trimmed === \"\" || trimmed === \"*\" || /^[xX]$/.test(trimmed)) return \"a wildcard, which already takes whatever the registry has\";\n if (trimmed.includes(\"||\")) return \"a union of ranges, with no single version to move\";\n if (/^[<>=]/.test(trimmed) || /\\s-\\s/.test(trimmed)) return \"a comparator range, with no single version to move\";\n if (/^[\\^~]?v?\\d/.test(trimmed)) return \"not a plain MAJOR.MINOR.PATCH version\";\n return \"a dist-tag, not a version\";\n}\n\n/**\n * The `@rebasepro/*` package an override key targets, or null.\n *\n * pnpm and npm key an override by name, optionally narrowed: `@rebasepro/x@<1`,\n * `parent>@rebasepro/x`; yarn's `resolutions` by a path, `**\\/@rebasepro/x`. The\n * target is the last segment either way.\n */\nexport function overrideTarget(key: string): string | null {\n const match = /(?:^|[/>])(@rebasepro\\/[^/@>\\s]+)(?:@[^/>]*)?$/.exec(key);\n return match ? match[1] : null;\n}\n\n/* ─── finding the files ────────────────────────────────────────────────────── */\n\nexport interface ProjectFiles {\n /** Absolute paths, in a stable order. */\n packageJsons: string[];\n workspaceYamls: string[];\n}\n\n/**\n * Directories the walk never enters: installed packages, build output (`dist`,\n * `dist-bundle`, `dist-bundle-admin`, …) and anything hidden (`.git`,\n * `.rebase`, an editor's worktrees). None of them hold a manifest anybody\n * authored for this project, and `dist-bundle/package.json` in particular is a\n * generated copy that `rebase build` rewrites anyway. They are skipped whether\n * or not git ignores them.\n */\nfunction skipDirectory(name: string): boolean {\n return name === \"node_modules\" || name.startsWith(\"dist\") || name.startsWith(\".\");\n}\n\n/** `git -C <cwd> …`, returning stdout. Throws when git is missing or refuses. */\nexport type GitRunner = (cwd: string, args: string[]) => string;\n\nconst runGit: GitRunner = (cwd, args) => execFileSync(\"git\", [\"-C\", cwd, ...args], {\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n // `ls-files` on a large monorepo is megabytes; the default 1 MiB buffer\n // would kill it and silently fall back to the walk.\n maxBuffer: 256 * 1024 * 1024\n});\n\n/**\n * The files git counts as part of the project — tracked, or untracked and not\n * ignored — relative to `projectRoot`, POSIX. Null when git has no say: no git,\n * no repository, or a repository that lists nothing under the project root.\n *\n * Listing nothing means the repository ignores the project as a whole: a copy\n * of it under a gitignored scratch directory, say. Running the upgrade in that\n * copy is asking for the copy to move, and the repository's rules would leave\n * nothing in it to move. Asked with `git ls-files` rather than\n * `git check-ignore`, which answers differently across git versions for a\n * directory and for a negated pattern.\n */\nfunction gitProjectFiles(projectRoot: string, git: GitRunner): Set<string> | null {\n let listed: string;\n try {\n listed = git(projectRoot, [\"ls-files\", \"-z\", \"--cached\", \"--others\", \"--exclude-standard\"]);\n } catch {\n return null;\n }\n const files = new Set(listed.split(\"\\0\").filter(Boolean));\n return files.size > 0 ? files : null;\n}\n\n/**\n * Every `package.json` and `pnpm-workspace.yaml` under the project root that\n * belongs to the project.\n *\n * In a git repository that means what git lists: a gitignored build context,\n * scratch copy or vendored package is not the project's, and rewriting it\n * would change files nobody committed. The walk enters only directories that\n * hold a listed file, so an ignored tree is not read at all. Outside a\n * repository every directory is walked. {@link skipDirectory} applies either\n * way.\n */\nexport function discoverProjectFiles(projectRoot: string, git: GitRunner = runGit): ProjectFiles {\n const found: ProjectFiles = { packageJsons: [], workspaceYamls: [] };\n const listed = gitProjectFiles(projectRoot, git);\n /** Every directory a listed file sits in, at any depth. */\n const listedDirectories = new Set<string>();\n for (const file of listed ?? []) {\n for (let dir = path.posix.dirname(file); dir !== \".\" && !listedDirectories.has(dir); dir = path.posix.dirname(dir)) {\n listedDirectories.add(dir);\n }\n }\n\n const walk = (dir: string, relativeDir: string): void => {\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch {\n return;\n }\n entries.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));\n for (const entry of entries) {\n const full = path.join(dir, entry.name);\n const relative = relativeDir ? `${relativeDir}/${entry.name}` : entry.name;\n // `isDirectory()` is false for a symlink, so a linked workspace\n // package is not walked twice and a cycle cannot form.\n if (entry.isDirectory()) {\n if (!skipDirectory(entry.name) && (!listed || listedDirectories.has(relative))) walk(full, relative);\n } else if (entry.isFile() && (!listed || listed.has(relative))) {\n if (entry.name === \"package.json\") found.packageJsons.push(full);\n else if (entry.name === \"pnpm-workspace.yaml\") found.workspaceYamls.push(full);\n }\n }\n };\n walk(projectRoot, \"\");\n return found;\n}\n\n/* ─── the result ───────────────────────────────────────────────────────────── */\n\n/** Where a catalog pin sits: `catalog`, or `catalogs.<name>` for a named one. */\nexport type CatalogField = \"catalog\" | `catalogs.${string}`;\n\nexport interface ChangedPin {\n /** Relative to the project root, POSIX separators. */\n file: string;\n name: string;\n field: PinField | CatalogField;\n from: string;\n to: string;\n}\n\nexport interface SkippedSpec {\n file: string;\n name: string;\n /** A dependency block, or the override block the entry sits in. */\n field: string;\n spec: string;\n reason: string;\n}\n\nexport type OverrideAction = \"bumped\" | \"kept-local\" | \"removed-local\";\n\nexport interface OverrideFinding {\n file: string;\n /** The override key as written — `@rebasepro/types`, or a narrowed one. */\n name: string;\n spec: string;\n action: OverrideAction;\n /** The new value, for a bumped override. */\n to?: string;\n}\n\nexport interface UnreadableFile {\n file: string;\n reason: string;\n}\n\nexport interface UpgradePlan {\n target: string;\n changed: ChangedPin[];\n skipped: SkippedSpec[];\n overrides: OverrideFinding[];\n unreadable: UnreadableFile[];\n /** The files whose content changes, with the new content. */\n writes: Array<{ file: string; absolute: string; content: string }>;\n /** Pins, overrides and catalog entries that were already on the target. */\n unchanged: number;\n}\n\n/**\n * The `catalog:` references a plan met, and the catalog entries it found.\n *\n * A reference names no version, so it is not a pin to move: the catalog entry\n * it resolves to is. But the catalog may not be anywhere this looked — a\n * project inside a larger workspace keeps it above the project root — and a\n * reference to an entry nobody moved must be reported, not passed over.\n */\ninterface CatalogLedger {\n refs: Array<{ file: string; name: string; field: string; spec: string; catalog: string; pkg: string }>;\n /** `catalogKey(catalog, package)` for every framework entry of every catalog read. */\n defined: Set<string>;\n}\n\nfunction catalogKey(catalog: string, pkg: string): string {\n return `${catalog}\\u0000${pkg}`;\n}\n\nexport interface PlanOptions {\n /** Remove `link:`/`file:` overrides of framework packages instead of reporting them. */\n dropLocalOverrides?: boolean;\n}\n\n/** Project-relative, POSIX. What every file path in the output looks like. */\nfunction relativeTo(projectRoot: string, absolute: string): string {\n return path.relative(projectRoot, absolute).split(path.sep).join(\"/\");\n}\n\n/**\n * Work out every change the upgrade makes, without writing anything.\n *\n * `--dry-run` prints this; a real run writes `writes` and nothing else.\n */\nexport function planUpgrade(projectRoot: string, target: string, options: PlanOptions = {}): UpgradePlan {\n if (!isExactVersion(target)) {\n throw new UpgradeError(`\"${target}\" is not an exact version.`, \"target_invalid\");\n }\n const plan: UpgradePlan = { target, changed: [], skipped: [], overrides: [], unreadable: [], writes: [], unchanged: 0 };\n const ledger: CatalogLedger = { refs: [], defined: new Set() };\n const files = discoverProjectFiles(projectRoot);\n\n for (const absolute of files.packageJsons) {\n const file = relativeTo(projectRoot, absolute);\n const original = fs.readFileSync(absolute, \"utf8\");\n const content = planPackageJson(file, original, target, options, plan, ledger);\n if (content !== null && content !== original) plan.writes.push({ file, absolute, content });\n }\n\n for (const absolute of files.workspaceYamls) {\n const file = relativeTo(projectRoot, absolute);\n const original = fs.readFileSync(absolute, \"utf8\");\n const content = planWorkspaceYaml(file, original, target, options, plan, ledger);\n if (content !== original) plan.writes.push({ file, absolute, content });\n }\n\n for (const ref of ledger.refs) {\n if (ledger.defined.has(catalogKey(ref.catalog, ref.pkg))) continue;\n plan.skipped.push({\n file: ref.file,\n name: ref.name,\n field: ref.field,\n spec: ref.spec,\n reason: `a pnpm catalog: reference, and no catalog under this project defines it — move the version where the \"${ref.catalog}\" catalog is declared`\n });\n }\n\n return plan;\n}\n\n/** Write what the plan changes. Nothing else on disk is touched. */\nexport function applyUpgradePlan(plan: UpgradePlan): void {\n for (const write of plan.writes) fs.writeFileSync(write.absolute, write.content, \"utf8\");\n}\n\n/* ─── package.json ─────────────────────────────────────────────────────────── */\n\n/** Override blocks in a `package.json`, as paths from the root object. */\nconst JSON_OVERRIDE_BLOCKS: ReadonlyArray<readonly string[]> = [[\"pnpm\", \"overrides\"], [\"overrides\"], [\"resolutions\"]];\n\nfunction planPackageJson(\n file: string,\n original: string,\n target: string,\n options: PlanOptions,\n plan: UpgradePlan,\n ledger: CatalogLedger\n): string | null {\n const bom = original.startsWith(\"\") ? \"\" : \"\";\n const text = original.slice(bom.length);\n\n let parsed: unknown;\n let tree: JsonNode;\n try {\n parsed = JSON.parse(text);\n tree = scanJson(text);\n } catch (err) {\n plan.unreadable.push({ file, reason: `not valid JSON: ${err instanceof Error ? err.message : String(err)}` });\n return null;\n }\n if (!isRecord(parsed) || tree.kind !== \"object\") {\n plan.unreadable.push({ file, reason: \"not a JSON object\" });\n return null;\n }\n\n const expected = structuredClone(parsed);\n const edits: TextEdit[] = [];\n /** Override members to remove, as [block path, key]. */\n const removals: Array<[readonly string[], string]> = [];\n\n for (const field of PIN_FIELDS) {\n const block = memberValue(tree, [field]);\n if (block?.kind !== \"object\") continue;\n for (const member of block.members) {\n if (!member.key.startsWith(FRAMEWORK_SCOPE)) continue;\n if (member.value.kind !== \"string\") {\n plan.skipped.push({ file, name: member.key, field, spec: text.slice(member.value.start, member.value.end), reason: \"not a string\" });\n continue;\n }\n const spec = member.value.value;\n const cls = classifySpec(spec);\n if (cls.kind === \"movable\") {\n const to = `${cls.prefix}${target}`;\n if (to === spec) {\n plan.unchanged++;\n continue;\n }\n edits.push({ start: member.value.start, end: member.value.end, replacement: JSON.stringify(to) });\n setPath(expected, [field, member.key], to);\n plan.changed.push({ file, name: member.key, field, from: spec, to });\n } else if (cls.kind === \"catalog\") {\n ledger.refs.push({ file, name: member.key, field, spec, catalog: cls.catalog, pkg: member.key });\n } else {\n plan.skipped.push({ file, name: member.key, field, spec, reason: leftAloneReason(cls) });\n }\n }\n }\n\n for (const blockPath of JSON_OVERRIDE_BLOCKS) {\n const block = memberValue(tree, blockPath);\n if (block?.kind !== \"object\") continue;\n const field = blockPath.join(\".\");\n for (const member of block.members) {\n if (!overrideTarget(member.key)) continue;\n if (member.value.kind !== \"string\") {\n plan.skipped.push({\n file,\n name: member.key,\n field,\n spec: text.slice(member.value.start, member.value.end),\n reason: \"a nested override, which has no single version to move; edit it by hand\"\n });\n continue;\n }\n const spec = member.value.value;\n const cls = classifySpec(spec);\n const pkg = overrideTarget(member.key);\n if (cls.kind === \"movable\") {\n const to = `${cls.prefix}${target}`;\n if (to === spec) {\n plan.unchanged++;\n continue;\n }\n edits.push({ start: member.value.start, end: member.value.end, replacement: JSON.stringify(to) });\n setPath(expected, [...blockPath, member.key], to);\n plan.overrides.push({ file, name: member.key, spec, action: \"bumped\", to });\n } else if (cls.kind === \"catalog\" && pkg) {\n ledger.refs.push({ file, name: member.key, field, spec, catalog: cls.catalog, pkg });\n } else if (cls.kind === \"local\") {\n if (options.dropLocalOverrides) {\n removals.push([blockPath, member.key]);\n deletePath(expected, [...blockPath, member.key]);\n plan.overrides.push({ file, name: member.key, spec, action: \"removed-local\" });\n } else {\n plan.overrides.push({ file, name: member.key, spec, action: \"kept-local\" });\n }\n } else {\n plan.skipped.push({ file, name: member.key, field, spec, reason: leftAloneReason(cls) });\n }\n }\n }\n\n if (edits.length === 0 && removals.length === 0) return original;\n\n let next = applyEdits(text, edits);\n for (const [blockPath, key] of removals) {\n next = removeJsonMember(next, blockPath, key);\n }\n // An override block that only held local links is removed with them, and\n // `pnpm` with it when nothing else was in it — an empty `{}` left behind is\n // a line of diff that says nothing.\n for (const blockPath of JSON_OVERRIDE_BLOCKS) {\n if (!removals.some(([removedFrom]) => removedFrom === blockPath)) continue;\n for (let depth = blockPath.length; depth > 0; depth--) {\n const containerPath = blockPath.slice(0, depth);\n const node = memberValue(scanJson(next), containerPath);\n if (node?.kind !== \"object\" || node.members.length > 0) break;\n next = removeJsonMember(next, containerPath.slice(0, -1), containerPath[containerPath.length - 1]);\n deletePath(expected, containerPath);\n }\n }\n\n // The rewrite is only kept if it says exactly what was meant — every value\n // that was supposed to change, and nothing else.\n let reparsed: unknown;\n try {\n reparsed = JSON.parse(next);\n } catch {\n reparsed = undefined;\n }\n if (!isDeepStrictEqual(reparsed, expected)) {\n throw new UpgradeError(\n `Could not rewrite ${file} without disturbing it; nothing was written.`,\n \"rewrite_failed\",\n \"Move its @rebasepro versions by hand, then run `rebase upgrade` again.\"\n );\n }\n return bom + next;\n}\n\n/* ─── a JSON scanner that keeps byte offsets ───────────────────────────────── */\n\ninterface JsonMember {\n key: string;\n keyStart: number;\n value: JsonNode;\n}\n\ntype JsonNode =\n | { kind: \"object\"; start: number; end: number; members: JsonMember[] }\n | { kind: \"array\"; start: number; end: number }\n | { kind: \"string\"; start: number; end: number; value: string }\n | { kind: \"scalar\"; start: number; end: number };\n\n/**\n * The structure of a JSON document, with where each value starts and ends.\n *\n * `JSON.parse` answers what a file says; this answers where it says it, which is\n * what a rewrite that leaves every other byte alone needs. Throws on anything\n * that is not JSON — callers have already parsed the same text, so that never\n * happens in practice.\n */\nfunction scanJson(text: string): JsonNode {\n let i = 0;\n const WHITESPACE = \" \\t\\n\\r\";\n const skipWhitespace = (): void => {\n while (i < text.length && WHITESPACE.includes(text[i])) i++;\n };\n const unexpected = (): never => {\n throw new Error(`unexpected ${i < text.length ? `\"${text[i]}\"` : \"end of input\"} at offset ${i}`);\n };\n const readString = (): { kind: \"string\"; start: number; end: number; value: string } => {\n const start = i;\n if (text[i] !== \"\\\"\") unexpected();\n i++;\n while (i < text.length && text[i] !== \"\\\"\") i += text[i] === \"\\\\\" ? 2 : 1;\n if (i >= text.length) unexpected();\n i++;\n return { kind: \"string\", start, end: i, value: JSON.parse(text.slice(start, i)) as string };\n };\n const readValue = (): JsonNode => {\n skipWhitespace();\n const start = i;\n if (text[i] === \"{\") {\n i++;\n const members: JsonMember[] = [];\n skipWhitespace();\n if (text[i] === \"}\") {\n i++;\n return { kind: \"object\", start, end: i, members };\n }\n for (;;) {\n skipWhitespace();\n const key = readString();\n skipWhitespace();\n if (text[i] !== \":\") unexpected();\n i++;\n members.push({ key: key.value, keyStart: key.start, value: readValue() });\n skipWhitespace();\n if (text[i] === \",\") {\n i++;\n continue;\n }\n if (text[i] === \"}\") {\n i++;\n return { kind: \"object\", start, end: i, members };\n }\n unexpected();\n }\n }\n if (text[i] === \"[\") {\n i++;\n skipWhitespace();\n if (text[i] === \"]\") {\n i++;\n return { kind: \"array\", start, end: i };\n }\n for (;;) {\n readValue();\n skipWhitespace();\n if (text[i] === \",\") {\n i++;\n continue;\n }\n if (text[i] === \"]\") {\n i++;\n return { kind: \"array\", start, end: i };\n }\n unexpected();\n }\n }\n if (text[i] === \"\\\"\") return readString();\n while (i < text.length && !\",:{}[]\\\"\".includes(text[i]) && !WHITESPACE.includes(text[i])) i++;\n if (i === start) unexpected();\n return { kind: \"scalar\", start, end: i };\n };\n const root = readValue();\n skipWhitespace();\n if (i !== text.length) unexpected();\n return root;\n}\n\n/** The value at a path of object keys, or undefined. The last duplicate wins, as in `JSON.parse`. */\nfunction memberValue(root: JsonNode, keys: readonly string[]): JsonNode | undefined {\n let node: JsonNode | undefined = root;\n for (const key of keys) {\n if (node?.kind !== \"object\") return undefined;\n const members: JsonMember[] = node.members.filter(m => m.key === key);\n node = members[members.length - 1]?.value;\n }\n return node;\n}\n\ninterface TextEdit {\n start: number;\n end: number;\n replacement: string;\n}\n\n/** Apply non-overlapping edits, last first so the earlier offsets stay valid. */\nfunction applyEdits(text: string, edits: TextEdit[]): string {\n let out = text;\n for (const edit of [...edits].sort((a, b) => b.start - a.start)) {\n out = out.slice(0, edit.start) + edit.replacement + out.slice(edit.end);\n }\n return out;\n}\n\n/**\n * Remove one member from the object at `objectPath`, taking its comma with it.\n *\n * Rescans rather than trusting offsets from before an earlier edit. A middle or\n * first member takes everything up to the next key, so the next member inherits\n * its indentation; the last takes the comma and whitespace after the previous\n * value, so the closing brace keeps its line; an only member leaves `{}`.\n */\nfunction removeJsonMember(text: string, objectPath: readonly string[], key: string): string {\n const container = memberValue(scanJson(text), objectPath);\n if (container?.kind !== \"object\") return text;\n const index = container.members.findIndex(m => m.key === key);\n if (index === -1) return text;\n const members = container.members;\n const member = members[index];\n if (members.length === 1) {\n return text.slice(0, container.start + 1) + text.slice(container.end - 1);\n }\n if (index < members.length - 1) {\n return text.slice(0, member.keyStart) + text.slice(members[index + 1].keyStart);\n }\n return text.slice(0, members[index - 1].value.end) + text.slice(member.value.end);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction setPath(root: Record<string, unknown>, keys: string[], value: unknown): void {\n let node: Record<string, unknown> = root;\n for (const key of keys.slice(0, -1)) {\n const next = node[key];\n if (!isRecord(next)) return;\n node = next;\n }\n node[keys[keys.length - 1]] = value;\n}\n\nfunction deletePath(root: Record<string, unknown>, keys: readonly string[]): void {\n let node: Record<string, unknown> = root;\n for (const key of keys.slice(0, -1)) {\n const next = node[key];\n if (!isRecord(next)) return;\n node = next;\n }\n delete node[keys[keys.length - 1]];\n}\n\n/* ─── pnpm-workspace.yaml ──────────────────────────────────────────────────── */\n\ninterface YamlOverride {\n /** Index into the file's lines. */\n line: number;\n key: string;\n value: string;\n /** Where the value's text sits within the line, quotes excluded. */\n valueStart: number;\n valueEnd: number;\n}\n\ninterface YamlOverridesBlock {\n /** The block's key line — `overrides:`, `catalog:`. */\n keyLine: number;\n /** The block's lines, `keyLine` excluded: indented, blank or comment-only. */\n lines: number[];\n entries: YamlOverride[];\n /** Lines in the block that are neither an entry, nor blank, nor a comment. */\n otherContent: number;\n}\n\n/** Lines, each without its `\\r`, and whether the file used them. */\nfunction splitLines(text: string): string[] {\n return text.split(\"\\n\").map(line => (line.endsWith(\"\\r\") ? line.slice(0, -1) : line));\n}\n\n/**\n * A YAML scalar at the start of `rest`: its text, and where that text sits.\n *\n * Double- and single-quoted and plain scalars, which is every shape an override\n * value is written in. A double-quoted one with an escape in it is refused\n * rather than decoded: no version or path needs one, and getting the decoding\n * wrong would rewrite a value this does not understand.\n */\nfunction readYamlScalar(rest: string): { value: string; start: number; end: number } | null {\n if (rest.startsWith(\"\\\"\")) {\n const close = rest.indexOf(\"\\\"\", 1);\n if (close === -1 || rest.slice(1, close).includes(\"\\\\\")) return null;\n if (!/^\\s*(#.*)?$/.test(rest.slice(close + 1))) return null;\n return { value: rest.slice(1, close), start: 1, end: close };\n }\n if (rest.startsWith(\"'\")) {\n const close = rest.indexOf(\"'\", 1);\n if (close === -1 || rest[close + 1] === \"'\") return null;\n if (!/^\\s*(#.*)?$/.test(rest.slice(close + 1))) return null;\n return { value: rest.slice(1, close), start: 1, end: close };\n }\n const comment = rest.search(/\\s#/);\n const plain = (comment === -1 ? rest : rest.slice(0, comment)).trimEnd();\n if (plain === \"\" || /^[[{&*!|>%@`]/.test(plain)) return null;\n return { value: plain, start: 0, end: plain.length };\n}\n\n/**\n * A top-level block mapping of a `pnpm-workspace.yaml` — `overrides:`,\n * `catalog:` — read line by line.\n *\n * Deliberately narrow. The file is YAML, and the CLI carries no YAML parser; the\n * shape pnpm documents and every project writes is a block mapping of one\n * scalar per line, which a line reader handles exactly. Anything else in the\n * block is counted rather than guessed at, and an inline `overrides: { … }` is\n * reported as not handled.\n */\nfunction readYamlBlock(lines: string[], key: \"overrides\" | \"catalog\"): YamlOverridesBlock | null {\n const keyLine = lines.findIndex(line => new RegExp(`^${key}:\\\\s*(#.*)?$`).test(line));\n if (keyLine === -1) return null;\n\n const block: YamlOverridesBlock = { keyLine, lines: [], entries: [], otherContent: 0 };\n for (let index = keyLine + 1; index < lines.length; index++) {\n const line = lines[index];\n if (line.trim() !== \"\" && !/^\\s/.test(line) && !line.startsWith(\"#\")) break;\n block.lines.push(index);\n if (line.trim() === \"\" || /^\\s*#/.test(line)) continue;\n\n const entry = readYamlEntry(line, index);\n if (entry) block.entries.push(entry);\n else block.otherContent++;\n }\n return block;\n}\n\n/** One `key: scalar` line of a block mapping, or null when it is anything else. */\nfunction readYamlEntry(line: string, index: number): YamlOverride | null {\n const entry = /^(\\s+)(\"[^\"]*\"|'[^']*'|[^\\s\"'#][^:#]*?)\\s*:(\\s+|$)/.exec(line);\n const valueOffset = entry ? entry[0].length : -1;\n const scalar = entry ? readYamlScalar(line.slice(valueOffset)) : null;\n if (!entry || !scalar) return null;\n const rawKey = entry[2];\n return {\n line: index,\n key: /^[\"']/.test(rawKey) ? rawKey.slice(1, -1) : rawKey,\n value: scalar.value,\n valueStart: valueOffset + scalar.start,\n valueEnd: valueOffset + scalar.end\n };\n}\n\n/** One pnpm catalog: `catalog:` is the one named \"default\". */\ninterface YamlCatalog {\n name: string;\n field: CatalogField;\n entries: YamlOverride[];\n}\n\n/**\n * Every catalog a `pnpm-workspace.yaml` declares: the top-level `catalog:`\n * block, and each named block under `catalogs:`.\n *\n * `catalogs:` is one level deeper — a header line per catalog, its entries\n * indented under it — and is read with the same one-scalar-per-line rule.\n */\nfunction readYamlCatalogs(lines: string[]): YamlCatalog[] {\n const catalogs: YamlCatalog[] = [];\n const single = readYamlBlock(lines, \"catalog\");\n if (single) catalogs.push({ name: \"default\", field: \"catalog\", entries: single.entries });\n\n const keyLine = lines.findIndex(line => /^catalogs:\\s*(#.*)?$/.test(line));\n if (keyLine === -1) return catalogs;\n\n let current: YamlCatalog | null = null;\n let headerIndent = -1;\n for (let index = keyLine + 1; index < lines.length; index++) {\n const line = lines[index];\n if (line.trim() !== \"\" && !/^\\s/.test(line) && !line.startsWith(\"#\")) break;\n if (line.trim() === \"\" || /^\\s*#/.test(line)) continue;\n\n const indent = line.length - line.trimStart().length;\n const header = /^\\s+(\"[^\"]*\"|'[^']*'|[^\\s\"'#][^:#]*?)\\s*:\\s*(#.*)?$/.exec(line);\n if (header && (headerIndent === -1 || indent === headerIndent)) {\n headerIndent = indent;\n const name = /^[\"']/.test(header[1]) ? header[1].slice(1, -1) : header[1];\n current = { name, field: `catalogs.${name}`, entries: [] };\n catalogs.push(current);\n continue;\n }\n if (!current || indent <= headerIndent) continue;\n const entry = readYamlEntry(line, index);\n if (entry) current.entries.push(entry);\n }\n return catalogs;\n}\n\n/** A `pnpm-workspace.yaml`, with its overrides and then its catalogs moved. */\nfunction planWorkspaceYaml(\n file: string,\n original: string,\n target: string,\n options: PlanOptions,\n plan: UpgradePlan,\n ledger: CatalogLedger\n): string {\n const overridden = planYamlOverrides(file, original, target, options, plan, ledger);\n return planYamlCatalogs(file, overridden, target, plan, ledger);\n}\n\n/**\n * Move the framework entries of every catalog. Entries are rewritten in place\n * — a catalog loses no line — and the result is read back and held to what was\n * meant, like every other rewrite here.\n */\nfunction planYamlCatalogs(\n file: string,\n original: string,\n target: string,\n plan: UpgradePlan,\n ledger: CatalogLedger\n): string {\n const lines = splitLines(original);\n const catalogs = readYamlCatalogs(lines);\n\n for (const key of [\"catalog\", \"catalogs\"]) {\n const inline = lines.find(line => new RegExp(`^${key}:\\\\s*[^\\\\s#]`).test(line));\n if (inline && inline.includes(FRAMEWORK_SCOPE)) {\n plan.skipped.push({\n file,\n name: key,\n field: key,\n spec: inline.slice(key.length + 1).trim(),\n reason: `an inline ${key} map, which this does not rewrite; write it as a block, or edit it by hand`\n });\n }\n }\n if (catalogs.length === 0) return original;\n\n const next = [...lines];\n const expected: Array<[string, string, string]> = [];\n for (const catalog of catalogs) {\n for (const entry of catalog.entries) {\n const meant: [string, string, string] = [catalog.field, entry.key, entry.value];\n expected.push(meant);\n if (!entry.key.startsWith(FRAMEWORK_SCOPE)) continue;\n ledger.defined.add(catalogKey(catalog.name, entry.key));\n\n const cls = classifySpec(entry.value);\n if (cls.kind !== \"movable\") {\n plan.skipped.push({ file, name: entry.key, field: catalog.field, spec: entry.value, reason: leftAloneReason(cls) });\n continue;\n }\n const to = `${cls.prefix}${target}`;\n if (to === entry.value) {\n plan.unchanged++;\n continue;\n }\n meant[2] = to;\n const line = next[entry.line];\n next[entry.line] = line.slice(0, entry.valueStart) + to + line.slice(entry.valueEnd);\n plan.changed.push({ file, name: entry.key, field: catalog.field, from: entry.value, to });\n }\n }\n\n const content = next.join(original.includes(\"\\r\\n\") ? \"\\r\\n\" : \"\\n\");\n const after = readYamlCatalogs(splitLines(content))\n .flatMap(catalog => catalog.entries.map(e => [catalog.field, e.key, e.value]));\n if (!isDeepStrictEqual(after, expected)) {\n throw new UpgradeError(\n `Could not rewrite ${file} without disturbing it; nothing was written.`,\n \"rewrite_failed\",\n \"Move its @rebasepro catalog entries by hand, then run `rebase upgrade` again.\"\n );\n }\n return content;\n}\n\nfunction planYamlOverrides(\n file: string,\n original: string,\n target: string,\n options: PlanOptions,\n plan: UpgradePlan,\n ledger: CatalogLedger\n): string {\n const lines = splitLines(original);\n const crlf = original.includes(\"\\r\\n\");\n const block = readYamlBlock(lines, \"overrides\");\n\n if (!block) {\n const inline = lines.find(line => /^overrides:\\s*[^\\s#]/.test(line));\n if (inline && inline.includes(FRAMEWORK_SCOPE)) {\n plan.skipped.push({\n file,\n name: \"overrides\",\n field: \"overrides\",\n spec: inline.slice(\"overrides:\".length).trim(),\n reason: \"an inline overrides map, which this does not rewrite; write it as a block, or edit it by hand\"\n });\n }\n return original;\n }\n\n const next = [...lines];\n const removed = new Set<number>();\n const expected = new Map<string, string>();\n\n for (const entry of block.entries) {\n if (!overrideTarget(entry.key)) {\n expected.set(entry.key, entry.value);\n continue;\n }\n const cls = classifySpec(entry.value);\n const pkg = overrideTarget(entry.key);\n if (cls.kind === \"movable\") {\n const to = `${cls.prefix}${target}`;\n expected.set(entry.key, to);\n if (to === entry.value) {\n plan.unchanged++;\n continue;\n }\n const line = lines[entry.line];\n next[entry.line] = line.slice(0, entry.valueStart) + to + line.slice(entry.valueEnd);\n plan.overrides.push({ file, name: entry.key, spec: entry.value, action: \"bumped\", to });\n } else if (cls.kind === \"catalog\" && pkg) {\n expected.set(entry.key, entry.value);\n ledger.refs.push({ file, name: entry.key, field: \"overrides\", spec: entry.value, catalog: cls.catalog, pkg });\n } else if (cls.kind === \"local\") {\n if (options.dropLocalOverrides) {\n removed.add(entry.line);\n plan.overrides.push({ file, name: entry.key, spec: entry.value, action: \"removed-local\" });\n } else {\n expected.set(entry.key, entry.value);\n plan.overrides.push({ file, name: entry.key, spec: entry.value, action: \"kept-local\" });\n }\n } else {\n expected.set(entry.key, entry.value);\n plan.skipped.push({ file, name: entry.key, field: \"overrides\", spec: entry.value, reason: leftAloneReason(cls) });\n }\n }\n\n // A block the removals emptied goes too, key line included: `overrides:`\n // with nothing under it is `overrides: null`, which pnpm reads as a value.\n const survivors = block.entries.filter(entry => !removed.has(entry.line)).length + block.otherContent;\n if (removed.size > 0 && survivors === 0) removed.add(block.keyLine);\n\n const kept = next.filter((_, index) => !removed.has(index));\n const content = kept.join(crlf ? \"\\r\\n\" : \"\\n\");\n\n // Read back with the same reader, and hold it to what was meant: the same\n // entries, in the same order, with only the intended values changed, and\n // every line outside the block untouched.\n const after = readYamlBlock(splitLines(content), \"overrides\");\n const afterEntries = after ? after.entries.map(e => [e.key, e.value]) : [];\n if (!isDeepStrictEqual(afterEntries, [...expected.entries()])) {\n throw new UpgradeError(\n `Could not rewrite ${file} without disturbing it; nothing was written.`,\n \"rewrite_failed\",\n \"Move its @rebasepro overrides by hand, then run `rebase upgrade` again.\"\n );\n }\n return content;\n}\n\n/* ─── the install ──────────────────────────────────────────────────────────── */\n\nexport type Installer = \"pnpm\" | \"npm\" | \"yarn\" | \"bun\";\n\n/** Lockfiles, in the order they are looked for in each directory. */\nconst LOCKFILES: ReadonlyArray<[string, Installer]> = [\n [\"pnpm-lock.yaml\", \"pnpm\"],\n [\"package-lock.json\", \"npm\"],\n [\"yarn.lock\", \"yarn\"],\n [\"bun.lockb\", \"bun\"],\n [\"bun.lock\", \"bun\"]\n];\n\n/**\n * The package manager this project installs with, from what is on disk.\n *\n * A lockfile is the project's own statement, so it wins. The search starts at\n * the project root and walks up, because a project inside a workspace has its\n * lockfile at the workspace root; it stops at the repository's root, so a stray\n * lockfile in a home directory is never read as this project's choice. With no\n * lockfile anywhere, a `pnpm-workspace.yaml` still says pnpm; otherwise npm,\n * the one every Node install has.\n */\nexport function detectInstaller(projectRoot: string): Installer {\n let dir = path.resolve(projectRoot);\n let workspaceYaml = false;\n for (;;) {\n for (const [lockfile, installer] of LOCKFILES) {\n if (fs.existsSync(path.join(dir, lockfile))) return installer;\n }\n if (fs.existsSync(path.join(dir, \"pnpm-workspace.yaml\"))) workspaceYaml = true;\n const parent = path.dirname(dir);\n if (parent === dir || fs.existsSync(path.join(dir, \".git\"))) break;\n dir = parent;\n }\n return workspaceYaml ? \"pnpm\" : \"npm\";\n}\n\n/**\n * The install command for each package manager — pnpm's and npm's from the\n * helpers every other command uses, yarn's and bun's spelled the same way.\n */\nexport function installCommand(installer: Installer): [string, string[]] {\n const [bin, ...args] = installer === \"pnpm\" || installer === \"npm\"\n ? getPMCommands(installer).install\n : [installer, \"install\"];\n return [bin, args];\n}\n\n/* ─── the target ───────────────────────────────────────────────────────────── */\n\n/**\n * The exact version `--to` names.\n *\n * An exact version is used as written, with no network call: the control plane\n * passes one when it rebuilds a project, and that rebuild must not depend on a\n * registry lookup succeeding for anything but the install itself. Anything\n * else is a dist-tag, asked of the registry through `npmView` — which runs npm\n * in the project, so its `.npmrc` and the user's registry config apply.\n */\nexport async function resolveTarget(\n requested: string,\n npmView: (spec: string) => Promise<string>\n): Promise<string> {\n const trimmed = requested.trim();\n const bare = trimmed.replace(/^v(?=\\d)/, \"\");\n if (isExactVersion(bare)) return bare;\n\n if (!/^[A-Za-z][\\w.-]*$/.test(trimmed)) {\n throw new UpgradeError(\n `\"${requested}\" is neither an exact version nor a dist-tag.`,\n \"target_invalid\",\n \"Pass an exact version such as 0.21.0, or a dist-tag such as latest or canary.\"\n );\n }\n\n let answer: string;\n try {\n answer = (await npmView(`${RELEASE_PACKAGE}@${trimmed}`)).trim();\n } catch (err) {\n const detail = err instanceof Error ? firstLine(err.message) : String(err);\n throw new UpgradeError(\n `Could not resolve \"${trimmed}\" on the npm registry${detail ? `: ${detail}` : \".\"}`,\n \"target_unresolved\",\n \"Check the tag and your registry access, or pass an exact version with --to.\"\n );\n }\n if (!isExactVersion(answer)) {\n throw new UpgradeError(\n `The registry has no single version for ${RELEASE_PACKAGE}@${trimmed}` +\n `${answer ? ` (it answered \"${firstLine(answer)}\")` : \"\"}.`,\n \"target_unresolved\",\n \"Check the tag, or pass an exact version with --to.\"\n );\n }\n return answer;\n}\n\nfunction firstLine(text: string): string {\n return text.split(\"\\n\").map(line => line.trim()).filter(Boolean)[0] ?? \"\";\n}\n\n/**\n * Whether moving from `from` to `to` goes backwards — the note the summary\n * prints, and what `rebase upgrade` refuses without `--allow-downgrade`.\n *\n * Prerelease identifiers compare as SemVer orders them: a release outranks its\n * own prereleases, numbers compare as numbers, and the channel (`alpha` <\n * `beta` < `rc`) compares as text. One case SemVer orders and this does not:\n * two builds on one channel told apart by a non-numeric identifier. A canary\n * is `0.24.1-canary.g<git hash>`, and hashes sort in no order at all — so\n * `canary.gcb918fc` → `canary.g8c5a265` is neither forwards nor backwards as\n * far as the version can say, and the `canary` tag, which points at the newest\n * build, is the only thing that knows.\n */\nexport function isDowngrade(from: string, to: string): boolean {\n const a = SEMVER.exec(from.replace(/^[\\^~]/, \"\"));\n const b = SEMVER.exec(to.replace(/^[\\^~]/, \"\"));\n if (!a || !b) return false;\n for (let i = 1; i <= 3; i++) {\n const diff = Number(a[i]) - Number(b[i]);\n if (diff !== 0) return diff > 0;\n }\n const preA = a[4];\n const preB = b[4];\n if (preA === preB) return false;\n if (preA === undefined) return true;\n if (preB === undefined) return false;\n const partsA = preA.split(\".\");\n const partsB = preB.split(\".\");\n for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {\n const x = partsA[i];\n const y = partsB[i];\n if (x === undefined) return false;\n if (y === undefined) return true;\n if (x === y) continue;\n const nx = /^\\d+$/.test(x) ? Number(x) : NaN;\n const ny = /^\\d+$/.test(y) ? Number(y) : NaN;\n if (!Number.isNaN(nx) && !Number.isNaN(ny)) return nx > ny;\n if (!Number.isNaN(nx)) return false;\n if (!Number.isNaN(ny)) return true;\n // Past the channel, two words are a build id, not an order.\n if (i > 0) return false;\n return x > y;\n }\n return false;\n}\n\n/**\n * The prerelease channel a project's pins are on — `canary` for\n * `0.24.1-canary.gcb918fc` — or null when none is on a prerelease, or they are\n * on more than one channel.\n *\n * The channel is the prerelease's first identifier, which is also the dist-tag\n * it is published under. `rebase upgrade` with no `--to` stays on it rather than\n * defaulting to `latest`, which for a canary project is usually older than the\n * build it already has.\n */\nexport function prereleaseChannel(versions: readonly string[]): string | null {\n const channels = new Set<string>();\n for (const version of versions) {\n const prerelease = SEMVER.exec(version.replace(/^[\\^~]/, \"\"))?.[4];\n const channel = prerelease?.split(\".\")[0];\n if (channel && /^[A-Za-z][0-9A-Za-z-]*$/.test(channel)) channels.add(channel);\n }\n return channels.size === 1 ? [...channels][0] : null;\n}\n\n/** The pins a plan moves to an older release. */\nexport function downgradedPins(plan: UpgradePlan): ChangedPin[] {\n return plan.changed.filter(pin => isDowngrade(pin.from, pin.to));\n}\n","/**\n * CLI command: rebase upgrade [--to <version|tag>]\n *\n * Moves every `@rebasepro/*` package the project pins to one release, then\n * installs. The file work — which specs move, the rewrite, what overrides say —\n * is `../upgrade.ts`; this adds the registry lookup for a tag, the install, and\n * the two ways of saying what happened.\n */\nimport chalk from \"chalk\";\nimport { execa } from \"execa\";\nimport { parseCommandArgs, wantsHelp } from \"../utils/args\";\nimport { failAsJson, requireProjectRoot, type JsonFailureIssue } from \"../utils/project\";\nimport { loadManifest, ManifestError } from \"../manifest\";\nimport {\n applyUpgradePlan,\n detectInstaller,\n downgradedPins,\n installCommand,\n isDowngrade,\n isExactVersion,\n planUpgrade,\n prereleaseChannel,\n resolveTarget,\n UpgradeError,\n type ChangedPin,\n type OverrideFinding,\n type SkippedSpec,\n type UnreadableFile,\n type UpgradePlan\n} from \"../upgrade\";\n\n/** Every flag `rebase upgrade` accepts. Its help page and the docs verifier read this. */\nexport const UPGRADE_FLAGS = {\n \"--to\": String,\n \"--allow-downgrade\": Boolean,\n \"--drop-local-overrides\": Boolean,\n \"--no-install\": Boolean,\n \"--dry-run\": Boolean,\n \"--json\": Boolean\n} as const;\n\nfunction printHelp(): void {\n console.log(`\n${chalk.bold(\"rebase upgrade\")} — move every @rebasepro package this project pins to one release\n\n${chalk.bold(\"Usage\")}\n rebase upgrade [--to <version|tag>] [options]\n\n${chalk.bold(\"Options\")}\n --to <version|tag> The release: an exact version (0.21.0) or a dist-tag\n (latest, canary). Default: latest — or, for a project\n on a prerelease, its channel (canary), unless latest\n is newer\n --allow-downgrade Let a dist-tag move pins to an older release. Without\n it that is refused; an exact --to version is taken\n as asked\n --drop-local-overrides Remove link: and file: overrides of @rebasepro packages,\n which win over every pin\n --no-install Rewrite the package.json files, but do not install\n --dry-run Print what would change, and write nothing\n --json One JSON document on stdout\n -h, --help Show this help\n\n${chalk.bold(\"What it changes\")}\n Every @rebasepro/* entry in dependencies, devDependencies and optionalDependencies,\n in every package.json under the project that git does not ignore (node_modules,\n dist* and hidden directories excepted, in a repository or not). ^ and ~ are kept.\n peerDependencies are left alone, and so are workspace:, link:, file:, git and tag\n specs, which are listed with the reason.\n Overrides in pnpm-workspace.yaml and package.json are bumped the same way, and so\n are the entries of pnpm-workspace.yaml's catalog: and catalogs: blocks, which is\n where a catalog: pin's version lives.\n\n${chalk.bold(\"Examples\")}\n rebase upgrade Move to the newest release on this project's channel\n rebase upgrade --to latest --allow-downgrade Move a canary project back to stable\n rebase upgrade --to canary --dry-run See what the canary would change\n rebase upgrade --to 0.21.0 --no-install --json\n`.trim());\n}\n\n/** What the command reports, human or `--json`. */\nexport interface UpgradeResult {\n target: string;\n changed: ChangedPin[];\n skipped: SkippedSpec[];\n overrides: OverrideFinding[];\n unreadable: UnreadableFile[];\n installed: boolean;\n dryRun: boolean;\n}\n\n/**\n * The two things this command does outside the project's files: ask the\n * registry what a tag points at, and install. Injectable, so a test runs the\n * whole command without either.\n */\nexport interface UpgradeIo {\n npmView: (spec: string, cwd: string) => Promise<string>;\n /** `quietStdout`: route the installer's stdout to stderr, so `--json` keeps stdout to itself. */\n install: (command: [string, string[]], cwd: string, quietStdout: boolean) => Promise<void>;\n}\n\nconst defaultIo: UpgradeIo = {\n // Run in the project, so its `.npmrc` — a private registry, a scope\n // mapping — answers the question rather than whatever the CLI was run from.\n npmView: async (spec, cwd) => {\n try {\n return (await execa(\"npm\", [\"view\", spec, \"version\"], { cwd })).stdout;\n } catch (err) {\n throw new Error(npmFailure(err));\n }\n },\n install: async ([bin, args], cwd, quietStdout) => {\n await execa(bin, args, { cwd, stdio: quietStdout ? [\"ignore\", 2, \"inherit\"] : \"inherit\" });\n }\n};\n\n/**\n * The one line of a failed `npm view` worth printing.\n *\n * execa's own message is the command line that failed, which says nothing the\n * reader does not know. npm's stderr says why — `404 No match found for version\n * nosuchtag` — under an `npm error code E404` line that says less.\n */\nexport function npmFailure(err: unknown): string {\n const stderr = typeof err === \"object\" && err !== null && \"stderr\" in err && typeof err.stderr === \"string\"\n ? err.stderr\n : \"\";\n const reason = stderr\n .split(\"\\n\")\n .map(line => line.replace(/^npm (?:error|ERR!)\\s*/, \"\").trim())\n .find(line => line !== \"\" && !/^code\\s/.test(line) && !/^\\d{3}$/.test(line));\n return reason ?? (err instanceof Error ? err.message : String(err));\n}\n\n/**\n * The one release every moved pin came from, or `null` when they disagreed.\n * A range's `^`/`~` is not part of it: `upgrade --to` keeps each pin's operator.\n */\nfunction previousRelease(plan: UpgradePlan): string | null {\n const versions = new Set(plan.changed.map(pin => pin.from.replace(/^[\\^~]/, \"\")));\n if (versions.size !== 1) return null;\n const [version] = versions;\n return /^\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?$/.test(version) ? version : null;\n}\n\nexport async function upgradeCommand(rawArgs: string[], io: UpgradeIo = defaultIo): Promise<void> {\n if (wantsHelp(rawArgs)) {\n printHelp();\n return;\n }\n\n const { flags } = parseCommandArgs({\n spec: UPGRADE_FLAGS,\n rawArgs,\n commandWords: 1,\n command: \"upgrade\",\n maxPositionals: 0\n });\n const json = flags[\"--json\"] === true;\n const dryRun = flags[\"--dry-run\"] === true;\n\n const projectRoot = requireProjectRoot();\n\n /** Every refusal, in whichever of the two languages was asked for. */\n const refuse = (message: string, code: string, hint?: string, issues?: JsonFailureIssue[]): never => {\n if (json) failAsJson(message, code, hint, issues);\n console.error(chalk.red(`✗ ${message}`));\n for (const issue of issues ?? []) console.error(` ${chalk.gray(issue.path ?? \"\")} ${issue.message}`);\n if (hint) console.error(chalk.gray(` ${hint}`));\n process.exit(1);\n };\n\n // A project whose rebase.json does not load cannot be built on any release,\n // so moving its pins would only move the failure. Said first, and in the\n // same envelope `rebase status` uses.\n try {\n loadManifest(projectRoot);\n } catch (err) {\n if (err instanceof ManifestError) {\n refuse(err.message, \"manifest_invalid\", \"Fix rebase.json, then run this again.\",\n err.issues.map(issue => ({ path: issue.path, message: issue.message })));\n }\n throw err;\n }\n\n const requested = flags[\"--to\"];\n let plan: UpgradePlan;\n let channel: string | null = null;\n try {\n const npmView = (spec: string) => io.npmView(spec, projectRoot);\n const planFor = (target: string) =>\n planUpgrade(projectRoot, target, { dropLocalOverrides: flags[\"--drop-local-overrides\"] === true });\n plan = planFor(await resolveTarget(requested ?? \"latest\", npmView));\n channel = prereleaseChannel(plan.changed.map(pin => pin.from));\n // A project on a prerelease stays on its channel by default: for a\n // canary scaffold `latest` is usually the release *before* it. The\n // channel wins only when it is ahead, so a stable release that has\n // overtaken the channel is still where \"upgrade\" goes.\n if (requested === undefined && channel) {\n const onChannel = await resolveTarget(channel, npmView).catch(() => null);\n if (onChannel && isDowngrade(onChannel, plan.target)) {\n if (!json) {\n console.log(chalk.gray(` This project is on the ${channel} channel, so this stays on it: ${channel} is ${onChannel}.`));\n console.log(chalk.gray(` \\`rebase upgrade --to latest\\` is the stable release, ${plan.target}.`));\n }\n plan = planFor(onChannel);\n }\n }\n } catch (err) {\n if (err instanceof UpgradeError) refuse(err.message, err.code, err.hint);\n throw err;\n }\n\n // Going backwards is never a side effect. A dist-tag — `latest` above all,\n // the default — that names an older release than the project is on is\n // refused unless asked for; an exact `--to` version already is asking.\n const backwards = downgradedPins(plan);\n const exactRequest = requested !== undefined && isExactVersion(requested.trim().replace(/^v(?=\\d)/, \"\"));\n if (backwards.length > 0 && !exactRequest && flags[\"--allow-downgrade\"] !== true && !dryRun) {\n const tag = requested?.trim() ?? \"latest\";\n const current = [...new Set(backwards.map(pin => pin.from.replace(/^[\\^~]/, \"\")))].join(\", \");\n refuse(\n `\\`${tag}\\` is ${plan.target}, older than this project's ${current}: ` +\n `upgrading to it would move ${backwards.length} pin${backwards.length === 1 ? \"\" : \"s\"} backwards. Nothing was changed.`,\n \"downgrade_refused\",\n channel\n ? `Stay on the ${channel} channel with \\`rebase upgrade --to ${channel}\\`, or pass --allow-downgrade to move to ${plan.target}.`\n : `Pass --allow-downgrade to move to ${plan.target} anyway, or --to <version> for an exact release.`\n );\n }\n\n if (!dryRun) applyUpgradePlan(plan);\n const wrote = !dryRun && plan.writes.length > 0;\n const install = wrote && flags[\"--no-install\"] !== true;\n const installer = detectInstaller(projectRoot);\n const [bin, args] = installCommand(installer);\n const installLine = [bin, ...args].join(\" \");\n\n if (!json) {\n printSummary(plan, dryRun);\n if (backwards.length > 0) {\n const pins = `${backwards.length} pin${backwards.length === 1 ? \"\" : \"s\"}`;\n console.log(chalk.yellow(exactRequest || flags[\"--allow-downgrade\"] === true\n ? ` ⚠ ${plan.target} is an older release than ${pins} here ${dryRun ? \"are\" : \"were\"} on: this is a downgrade.`\n : ` ⚠ ${plan.target} is an older release than ${pins} here are on. A real run refuses it without --allow-downgrade.`));\n console.log(\"\");\n }\n }\n\n let installed = false;\n if (install) {\n if (!json) console.log(chalk.gray(` Installing with ${installer}...\\n`));\n try {\n await io.install([bin, args], projectRoot, json);\n installed = true;\n } catch {\n // The undo is a command this one already knows, when every pin it\n // moved came from one release: a mistyped `--to` (0.99.0 for\n // 0.29.0) is the commonest way here, and \"revert with git\" is no\n // answer in a project `rebase init --yes` never made a repository.\n const previous = previousRelease(plan);\n refuse(\n `\\`${installLine}\\` failed.`,\n \"install_failed\",\n `The package.json edits were kept. Fix what the install reported and run \\`${installLine}\\` again, ` +\n (previous\n ? `or put every pin back with \\`rebase upgrade --to ${previous}\\`.`\n : \"or revert the edits with git.\")\n );\n }\n }\n\n const result: UpgradeResult = {\n target: plan.target,\n changed: plan.changed,\n skipped: plan.skipped,\n overrides: plan.overrides,\n unreadable: plan.unreadable,\n installed,\n dryRun\n };\n\n if (json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n printOutcome(plan, { dryRun, wrote, installed, installLine });\n}\n\n/** Changes grouped by file, then what was left alone and why, then overrides. */\nfunction printSummary(plan: UpgradePlan, dryRun: boolean): void {\n console.log(\"\");\n console.log(`${chalk.bold(\"Rebase\")} — ${dryRun ? \"what upgrading\" : \"upgrading\"} @rebasepro packages to ${chalk.cyan(plan.target)}${dryRun ? \" would change\" : \"\"}`);\n\n const byFile = new Map<string, ChangedPin[]>();\n for (const pin of plan.changed) byFile.set(pin.file, [...(byFile.get(pin.file) ?? []), pin]);\n const nameWidth = Math.max(0, ...plan.changed.map(pin => pin.name.length));\n for (const [file, pins] of byFile) {\n console.log(\"\");\n console.log(` ${chalk.bold(file)}`);\n for (const pin of pins) {\n const field = pin.field === \"dependencies\" ? \"\" : chalk.gray(` ${pin.field}`);\n const older = isDowngrade(pin.from, pin.to) ? chalk.yellow(\" (older)\") : \"\";\n console.log(` ${pin.name.padEnd(nameWidth)} ${chalk.gray(pin.from)} → ${chalk.green(pin.to)}${field}${older}`);\n }\n }\n\n if (plan.skipped.length > 0) {\n console.log(\"\");\n console.log(` ${chalk.bold(\"Left alone\")}`);\n for (const skip of plan.skipped) {\n console.log(` ${skip.name} ${chalk.gray(skip.spec)} ${chalk.gray(`(${skip.file}, ${skip.field})`)}`);\n console.log(chalk.gray(` ${skip.reason}`));\n }\n }\n\n if (plan.overrides.length > 0) {\n console.log(\"\");\n console.log(` ${chalk.bold(\"Overrides\")}`);\n for (const override of plan.overrides) {\n const where = chalk.gray(`(${override.file})`);\n if (override.action === \"bumped\") {\n console.log(` ${override.name} ${chalk.gray(override.spec)} → ${chalk.green(override.to ?? \"\")} ${where}`);\n } else if (override.action === \"removed-local\") {\n console.log(` ${override.name} ${chalk.gray(override.spec)} ${where} ${chalk.green(dryRun ? \"would be removed\" : \"removed\")}`);\n } else {\n console.log(` ${chalk.yellow(\"⚠\")} ${override.name} → ${override.spec} ${where}`);\n console.log(chalk.yellow(\" local override — wins over every pin, the upgrade will not reach these packages\"));\n }\n }\n if (plan.overrides.some(o => o.action === \"kept-local\")) {\n console.log(chalk.gray(\" Run again with --drop-local-overrides to remove them.\"));\n }\n }\n\n if (plan.unreadable.length > 0) {\n console.log(\"\");\n console.log(` ${chalk.bold(\"Not read\")}`);\n for (const entry of plan.unreadable) {\n console.log(` ${entry.file} ${chalk.gray(entry.reason)}`);\n }\n }\n console.log(\"\");\n}\n\nfunction printOutcome(\n plan: UpgradePlan,\n outcome: { dryRun: boolean; wrote: boolean; installed: boolean; installLine: string }\n): void {\n const moved = plan.changed.length + plan.overrides.filter(o => o.action !== \"kept-local\").length;\n // What the project is not moved off by this command: every pin it left\n // alone, and every local override that wins over the pins it did move.\n const leftAlone = plan.skipped.length + plan.overrides.filter(o => o.action === \"kept-local\").length;\n const entries = (n: number): string => `${n} entr${n === 1 ? \"y\" : \"ies\"}`;\n\n // Nothing moved is only \"already on\" the target when nothing was left\n // alone either. A project whose every pin was skipped — a dist-tag, a\n // `workspace:` link, a catalog it could not find — is on whatever those\n // resolve to, and saying otherwise is the one sentence it must not print.\n if (moved === 0 && leftAlone > 0) {\n if (plan.unchanged > 0) {\n console.log(chalk.green(\n `✓ Every pin this can move is already on ${plan.target}; ${entries(leftAlone)} ${leftAlone === 1 ? \"was\" : \"were\"} left alone, above.`));\n } else if (outcome.dryRun) {\n console.log(chalk.yellow(\n ` Nothing to move to ${plan.target}: ${entries(leftAlone)} ${leftAlone === 1 ? \"is\" : \"are\"} left alone, above.`));\n } else {\n console.log(chalk.yellow(\n `⚠ Nothing moved to ${plan.target}: ${entries(leftAlone)} ${leftAlone === 1 ? \"was\" : \"were\"} left alone, above.`));\n }\n console.log(\"\");\n return;\n }\n\n if (outcome.dryRun) {\n console.log(chalk.gray(moved === 0\n ? ` Nothing to change: this project is already on ${plan.target}.`\n : \" Dry run — nothing was written. Run it without --dry-run to apply.\"));\n console.log(\"\");\n return;\n }\n\n if (!outcome.wrote) {\n console.log(chalk.green(`✓ This project is already on ${plan.target}.`));\n console.log(\"\");\n return;\n }\n\n const files = plan.writes.length;\n console.log(chalk.green(\n `✓ Moved ${moved} entr${moved === 1 ? \"y\" : \"ies\"} in ${files} file${files === 1 ? \"\" : \"s\"} to ${plan.target}` +\n `${outcome.installed ? \" and installed\" : \"\"}.`\n ));\n if (!outcome.installed) {\n console.log(chalk.gray(` Install with \\`${outcome.installLine}\\`, then run \\`rebase build\\`, then \\`rebase cloud deploy\\`.`));\n } else {\n console.log(chalk.gray(\" Run `rebase build`, then `rebase cloud deploy`.\"));\n }\n console.log(\"\");\n}\n"],"mappings":"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"}
package/dist/upgrade.d.ts CHANGED
@@ -58,8 +58,20 @@ export interface ProjectFiles {
58
58
  packageJsons: string[];
59
59
  workspaceYamls: string[];
60
60
  }
61
- /** Every `package.json` and `pnpm-workspace.yaml` under the project root. */
62
- export declare function discoverProjectFiles(projectRoot: string): ProjectFiles;
61
+ /** `git -C <cwd> …`, returning stdout. Throws when git is missing or refuses. */
62
+ export type GitRunner = (cwd: string, args: string[]) => string;
63
+ /**
64
+ * Every `package.json` and `pnpm-workspace.yaml` under the project root that
65
+ * belongs to the project.
66
+ *
67
+ * In a git repository that means what git lists: a gitignored build context,
68
+ * scratch copy or vendored package is not the project's, and rewriting it
69
+ * would change files nobody committed. The walk enters only directories that
70
+ * hold a listed file, so an ignored tree is not read at all. Outside a
71
+ * repository every directory is walked. {@link skipDirectory} applies either
72
+ * way.
73
+ */
74
+ export declare function discoverProjectFiles(projectRoot: string, git?: GitRunner): ProjectFiles;
63
75
  /** Where a catalog pin sits: `catalog`, or `catalogs.<name>` for a named one. */
64
76
  export type CatalogField = "catalog" | `catalogs.${string}`;
65
77
  export interface ChangedPin {
@@ -147,8 +159,29 @@ export declare function installCommand(installer: Installer): [string, string[]]
147
159
  */
148
160
  export declare function resolveTarget(requested: string, npmView: (spec: string) => Promise<string>): Promise<string>;
149
161
  /**
150
- * Whether moving from `from` to `to` goes backwards, for the one-word note the
151
- * summary prints. Prerelease identifiers compare as SemVer orders them: a
152
- * release outranks its own prereleases.
162
+ * Whether moving from `from` to `to` goes backwards — the note the summary
163
+ * prints, and what `rebase upgrade` refuses without `--allow-downgrade`.
164
+ *
165
+ * Prerelease identifiers compare as SemVer orders them: a release outranks its
166
+ * own prereleases, numbers compare as numbers, and the channel (`alpha` <
167
+ * `beta` < `rc`) compares as text. One case SemVer orders and this does not:
168
+ * two builds on one channel told apart by a non-numeric identifier. A canary
169
+ * is `0.24.1-canary.g<git hash>`, and hashes sort in no order at all — so
170
+ * `canary.gcb918fc` → `canary.g8c5a265` is neither forwards nor backwards as
171
+ * far as the version can say, and the `canary` tag, which points at the newest
172
+ * build, is the only thing that knows.
153
173
  */
154
174
  export declare function isDowngrade(from: string, to: string): boolean;
175
+ /**
176
+ * The prerelease channel a project's pins are on — `canary` for
177
+ * `0.24.1-canary.gcb918fc` — or null when none is on a prerelease, or they are
178
+ * on more than one channel.
179
+ *
180
+ * The channel is the prerelease's first identifier, which is also the dist-tag
181
+ * it is published under. `rebase upgrade` with no `--to` stays on it rather than
182
+ * defaulting to `latest`, which for a canary project is usually older than the
183
+ * build it already has.
184
+ */
185
+ export declare function prereleaseChannel(versions: readonly string[]): string | null;
186
+ /** The pins a plan moves to an older release. */
187
+ export declare function downgradedPins(plan: UpgradePlan): ChangedPin[];
@@ -82,17 +82,57 @@ export declare function composeDatabaseUrl(yamlText: string, env?: Record<string
82
82
  * where getting it wrong meant starting a container nobody asked for.
83
83
  */
84
84
  export declare function composeHostPort(yamlText: string): number | null;
85
- /** Is something accepting connections there right now? */
85
+ /**
86
+ * Is something accepting connections there right now?
87
+ *
88
+ * A reset counts as yes: a refused connection means nothing listens, a reset
89
+ * means something accepted it and dropped it — Docker's port proxy, while the
90
+ * Postgres behind it is still starting. On macOS that reset arrives after
91
+ * `connect`; on Linux it can arrive instead of it, and read as "not listening"
92
+ * the port wait spun for its whole minute before readiness was ever asked.
93
+ */
86
94
  export declare function probeTcp(host: string, port: number, timeoutMs?: number): Promise<boolean>;
87
95
  /**
88
96
  * Poll until the port answers, or give up.
89
97
  *
90
- * Postgres publishes its port before it is ready to accept queries, so the
91
- * caller still has to tolerate a first connection that is refused at the
92
- * protocol level. This only answers "has the container got as far as listening",
93
- * which is the part that takes the seconds.
98
+ * This only answers "has the container got as far as listening". It is not
99
+ * readiness: Docker's port proxy accepts on the host port while Postgres inside
100
+ * the container is still running initdb, and resets every connection it cannot
101
+ * forward. {@link waitForQueryable} is the check that a query will work.
94
102
  */
95
103
  export declare function waitForPort(host: string, port: number, timeoutMs?: number, intervalMs?: number): Promise<boolean>;
104
+ /** Whether a database answered a query, and if not, the last reason it gave. */
105
+ export type QueryReadiness = {
106
+ ready: true;
107
+ } | {
108
+ ready: false;
109
+ error: string;
110
+ };
111
+ /**
112
+ * Poll until `SELECT 1` succeeds on this connection string, or the bound runs out.
113
+ *
114
+ * The readiness that matters to everything after it. A fresh compose volume
115
+ * answers the TCP probe seconds before it answers a query — the official image
116
+ * runs initdb on a socket-only server, then restarts on TCP — and the schema
117
+ * push that ran in that gap failed on `read ECONNRESET`, three runs out of
118
+ * three. Every error is retried: a reset, "the database system is starting up"
119
+ * and a refused connection all mean "not yet", and the bound is what turns
120
+ * "not yet" into an answer.
121
+ */
122
+ export declare function waitForQueryable(databaseUrl: string, options?: {
123
+ timeoutMs?: number;
124
+ intervalMs?: number;
125
+ }): Promise<QueryReadiness>;
126
+ /**
127
+ * What a failed schema push printed, as lines to show.
128
+ *
129
+ * `rebase dev` runs the push with its output captured, so a successful start
130
+ * stays quiet. On a failure that captured output is the diagnosis, and it was
131
+ * being dropped: the warning said "fix the error above" over nothing at all.
132
+ * The child's stdout and stderr are what is shown — not execa's own message,
133
+ * which leads with the command line, and that carries the database password.
134
+ */
135
+ export declare function pushFailureOutput(error: unknown): string[];
96
136
  export interface EnsureDevDatabaseOptions {
97
137
  projectRoot: string;
98
138
  /** The DSN from the project's env file, if it has one. */
@@ -110,6 +150,8 @@ export interface EnsureDevDatabaseOptions {
110
150
  * untestable while the only way in was a real `docker compose up`.
111
151
  */
112
152
  startDatabase?: (projectRoot: string) => Promise<void>;
153
+ /** How long a started database has to answer `SELECT 1`. Defaults to 60s. */
154
+ readyTimeoutMs?: number;
113
155
  log?: (message: string) => void;
114
156
  }
115
157
  /**
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The port `rebase dev` derives from the project root path.
3
+ * Range: 3001–3999 (avoids privileged ports and common services).
4
+ * Two different project directories will almost always get different ports.
5
+ */
6
+ export declare function getProjectPort(projectRoot: string): number;
7
+ /**
8
+ * The URL `rebase dev` serves this project on, and how that is known:
9
+ *
10
+ * - `running` — the URL a running dev wrote to `.rebase-dev-url`;
11
+ * - `recorded` — the port the last run left in `.rebase/state.json` or
12
+ * `.rebase-dev-port` (both outlive a dev that did not shut down cleanly);
13
+ * - `derived` — nothing is recorded, so the port it derives for this path.
14
+ *
15
+ * Asked only to describe where dev is; a `PORT` in the shell would move the
16
+ * next run, and is not something a stopped dev left behind.
17
+ */
18
+ export declare function devServerUrl(projectRoot: string): {
19
+ url: string;
20
+ source: "running" | "recorded" | "derived";
21
+ };
22
+ /**
23
+ * What to say when nothing answered at `baseUrl`.
24
+ *
25
+ * The first line is the question it always asked. The second is added when
26
+ * `rebase dev` serves this project somewhere else, because then `baseUrl` is
27
+ * almost always `.env`'s `PORT`, and a reader who just stopped `rebase dev`
28
+ * reads the number as the one it was using.
29
+ */
30
+ export declare function serverUnreachableHint(baseUrl: string, projectRoot?: string | null): string[];
@@ -0,0 +1,31 @@
1
+ /** The rule, as every help page and error states it. */
2
+ export declare const COLLECTIONS_PATH_RULE = "relative paths are resolved from where you run the command";
3
+ /** The `--collections` line of a help page. */
4
+ export declare const COLLECTIONS_FLAG_HELP = "Collections directory (default: config/collections); relative paths are resolved from where you run the command";
5
+ /**
6
+ * What a refusal over a missing `--collections` path spared, by what the command
7
+ * would have done with it. Only a schema writer drops tables; a console or a
8
+ * doctor run over nothing does something else wrong, and says so.
9
+ */
10
+ declare const MISSING_COLLECTIONS_CONSEQUENCE: {
11
+ readonly schema: readonly ["Nothing was generated and nothing was applied — a schema generated from a", "directory that is not there is an empty one, and applying it would drop", "every table it does not describe."];
12
+ readonly console: readonly ["Nothing was started — a console over a directory that is not there would", "load none of this project's collections."];
13
+ readonly doctor: readonly ["Nothing was checked — a directory that is not there has no collections, so", "every collection check would pass over it."];
14
+ };
15
+ /** What a command does with its `--collections` path. */
16
+ export type CollectionsPathUse = keyof typeof MISSING_COLLECTIONS_CONSEQUENCE;
17
+ /**
18
+ * The refusal for a `--collections` path that does not exist, or `null`.
19
+ *
20
+ * Checked by the CLI, in the reader's terms, before the driver is spawned: the
21
+ * driver's own check runs in `backend/` and can only describe the path it was
22
+ * handed. A generator pointed at a directory that is not there writes an empty
23
+ * schema, and a push of an empty schema drops every table — so nothing runs.
24
+ *
25
+ * Scripts written for the old rule (`--collections ../config/collections`,
26
+ * run from the root) land here, and the message says exactly what to change.
27
+ */
28
+ export declare function missingCollectionsPath(args: readonly string[], cwd: string, backendDir: string, use?: CollectionsPathUse): string[] | null;
29
+ /** Print {@link missingCollectionsPath}'s refusal and exit 1, or return. */
30
+ export declare function refuseMissingCollectionsPath(args: readonly string[], cwd: string, backendDir: string, use?: CollectionsPathUse): void;
31
+ export {};
@@ -63,6 +63,22 @@ export declare function resolveLocalBin(projectRoot: string, binName: string): s
63
63
  * Resolve the tsx binary. Checks backend node_modules first, then root.
64
64
  */
65
65
  export declare function resolveTsx(projectRoot: string): string | null;
66
+ /**
67
+ * tsx's loader, as the URL `node --import` takes, or null when none resolves.
68
+ *
69
+ * For running a TypeScript entry in one Node process. The `tsx` binary is a
70
+ * relay — pnpm's `.bin/tsx` shell shim, then tsx's CLI in one Node, which
71
+ * spawns a second Node with this same loader to run the script — so spawning
72
+ * through it costs a shell and a Node start (~50–100 ms) on every hop, and
73
+ * `rebase dev` pays a hop on every start and every collection save.
74
+ *
75
+ * Resolved the way Node resolves the package, from the project first — the
76
+ * backend, where a scaffold declares tsx, then the root and everything above it
77
+ * — so the tsx used is the one {@link resolveTsx} would have found; then from
78
+ * this package, as the repository's own tests resolve `tsx/cli`. A URL rather
79
+ * than a path: a Windows path is not a valid `--import` specifier.
80
+ */
81
+ export declare function resolveTsxLoader(projectRoot: string): string | null;
66
82
  /**
67
83
  * Validate that a resolved tsx binary actually has an intact installation.
68
84
  *
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Run `work` with a path for `<prefix>.tar.gz` inside a fresh temporary
3
+ * directory, and remove that directory however the run ends.
4
+ *
5
+ * "However" includes `process.exit`: a `fail()` inside `work` ends the process
6
+ * on the spot, and no `finally` runs after that, so the directory is removed on
7
+ * the process's `exit` event as well.
8
+ */
9
+ export declare function withTempArchive<T>(prefix: string, work: (archivePath: string) => Promise<T>): Promise<T>;
@@ -0,0 +1,58 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { fileURLToPath } from "url";
4
+ //#region src/utils/version.ts
5
+ /**
6
+ * This CLI's own version, and the User-Agent built from it.
7
+ *
8
+ * Four call sites used to answer "what version am I?" and each answered it
9
+ * differently. `cli.ts` walked one directory up from `__dirname`. `init.ts`
10
+ * walked up looking for a folder literally named `cli`. `bundle.ts` had
11
+ * `resolveCliVersion`, which walked up at most five levels for a manifest whose
12
+ * `name` matched — the only one of the three that was actually correct, and the
13
+ * one the other two did not know existed. Every HTTP request to the control
14
+ * plane answered it not at all, which is the expensive gap: a control plane
15
+ * cannot refuse a CLI that is too old for its wire format if no request ever
16
+ * says which CLI is calling.
17
+ *
18
+ * One answer now, and it is `bundle.ts`'s: walk up for the manifest that names
19
+ * this package, rather than counting directories or matching a folder name.
20
+ * `dist/` is one level down in a published install and two in a source
21
+ * checkout, and a folder called `cli` is not guaranteed to be ours. Two
22
+ * differences from that original — `fileURLToPath` instead of `new
23
+ * URL().pathname`, which is what makes it survive a path containing a space,
24
+ * and no five-level ceiling.
25
+ */
26
+ function readVersion() {
27
+ let dir = path.dirname(fileURLToPath(import.meta.url));
28
+ const root = path.parse(dir).root;
29
+ while (dir && dir !== root) {
30
+ const manifest = path.join(dir, "package.json");
31
+ if (fs.existsSync(manifest)) try {
32
+ const pkg = JSON.parse(fs.readFileSync(manifest, "utf-8"));
33
+ if (pkg.name === "@rebasepro/cli" && typeof pkg.version === "string") return pkg.version;
34
+ } catch {}
35
+ dir = path.dirname(dir);
36
+ }
37
+ return "unknown";
38
+ }
39
+ var cached;
40
+ /** The CLI's version, or `"unknown"` when it cannot be read. Memoized. */
41
+ function cliVersion() {
42
+ if (cached === void 0) cached = readVersion();
43
+ return cached;
44
+ }
45
+ /**
46
+ * `rebase-cli/0.17.3` — sent on every control-plane request.
47
+ *
48
+ * The control plane needs it to answer `CLI_TOO_OLD` with a minimum version
49
+ * instead of failing somewhere further in with a shape error. A client that
50
+ * does not identify itself can only ever be refused generically.
51
+ */
52
+ function cliUserAgent() {
53
+ return `rebase-cli/${cliVersion()}`;
54
+ }
55
+ //#endregion
56
+ export { cliVersion as n, cliUserAgent as t };
57
+
58
+ //# sourceMappingURL=version-Buyyo1ut.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version-Buyyo1ut.js","names":[],"sources":["../src/utils/version.ts"],"sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\n\n/**\n * This CLI's own version, and the User-Agent built from it.\n *\n * Four call sites used to answer \"what version am I?\" and each answered it\n * differently. `cli.ts` walked one directory up from `__dirname`. `init.ts`\n * walked up looking for a folder literally named `cli`. `bundle.ts` had\n * `resolveCliVersion`, which walked up at most five levels for a manifest whose\n * `name` matched — the only one of the three that was actually correct, and the\n * one the other two did not know existed. Every HTTP request to the control\n * plane answered it not at all, which is the expensive gap: a control plane\n * cannot refuse a CLI that is too old for its wire format if no request ever\n * says which CLI is calling.\n *\n * One answer now, and it is `bundle.ts`'s: walk up for the manifest that names\n * this package, rather than counting directories or matching a folder name.\n * `dist/` is one level down in a published install and two in a source\n * checkout, and a folder called `cli` is not guaranteed to be ours. Two\n * differences from that original — `fileURLToPath` instead of `new\n * URL().pathname`, which is what makes it survive a path containing a space,\n * and no five-level ceiling.\n */\nfunction readVersion(): string {\n let dir = path.dirname(fileURLToPath(import.meta.url));\n const root = path.parse(dir).root;\n while (dir && dir !== root) {\n const manifest = path.join(dir, \"package.json\");\n if (fs.existsSync(manifest)) {\n try {\n const pkg = JSON.parse(fs.readFileSync(manifest, \"utf-8\"));\n if (pkg.name === \"@rebasepro/cli\" && typeof pkg.version === \"string\") return pkg.version;\n } catch {\n // A malformed manifest on the way up is not ours to complain\n // about; keep walking.\n }\n }\n dir = path.dirname(dir);\n }\n return \"unknown\";\n}\n\nlet cached: string | undefined;\n\n/** The CLI's version, or `\"unknown\"` when it cannot be read. Memoized. */\nexport function cliVersion(): string {\n if (cached === undefined) cached = readVersion();\n return cached;\n}\n\n/**\n * `rebase-cli/0.17.3` — sent on every control-plane request.\n *\n * The control plane needs it to answer `CLI_TOO_OLD` with a minimum version\n * instead of failing somewhere further in with a shape error. A client that\n * does not identify itself can only ever be refused generically.\n */\nexport function cliUserAgent(): string {\n return `rebase-cli/${cliVersion()}`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,SAAS,cAAsB;CAC3B,IAAI,MAAM,KAAK,QAAQ,cAAc,OAAO,KAAK,GAAG,CAAC;CACrD,MAAM,OAAO,KAAK,MAAM,GAAG,CAAC,CAAC;CAC7B,OAAO,OAAO,QAAQ,MAAM;EACxB,MAAM,WAAW,KAAK,KAAK,KAAK,cAAc;EAC9C,IAAI,GAAG,WAAW,QAAQ,GACtB,IAAI;GACA,MAAM,MAAM,KAAK,MAAM,GAAG,aAAa,UAAU,OAAO,CAAC;GACzD,IAAI,IAAI,SAAS,oBAAoB,OAAO,IAAI,YAAY,UAAU,OAAO,IAAI;EACrF,QAAQ,CAGR;EAEJ,MAAM,KAAK,QAAQ,GAAG;CAC1B;CACA,OAAO;AACX;AAEA,IAAI;;AAGJ,SAAgB,aAAqB;CACjC,IAAI,WAAW,KAAA,GAAW,SAAS,YAAY;CAC/C,OAAO;AACX;;;;;;;;AASA,SAAgB,eAAuB;CACnC,OAAO,cAAc,WAAW;AACpC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rebasepro/cli",
3
- "version": "0.23.0",
3
+ "version": "0.24.1-canary.g19596ef",
4
4
  "description": "Developer tools for Rebase projects",
5
5
  "keywords": [
6
6
  "cli",
@@ -43,12 +43,12 @@
43
43
  "inquirer": "14.0.2",
44
44
  "jiti": "^2.7.0",
45
45
  "pg": "^8.22.0",
46
- "@rebasepro/agent-skills": "0.23.0",
47
- "@rebasepro/client": "0.23.0",
48
- "@rebasepro/codegen": "0.23.0",
49
- "@rebasepro/server": "0.23.0",
50
- "@rebasepro/types": "0.23.0",
51
- "@rebasepro/server-postgres": "0.23.0"
46
+ "@rebasepro/agent-skills": "0.24.1-canary.g19596ef",
47
+ "@rebasepro/client": "0.24.1-canary.g19596ef",
48
+ "@rebasepro/server": "0.24.1-canary.g19596ef",
49
+ "@rebasepro/server-postgres": "0.24.1-canary.g19596ef",
50
+ "@rebasepro/codegen": "0.24.1-canary.g19596ef",
51
+ "@rebasepro/types": "0.24.1-canary.g19596ef"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@types/node": "^26.1.2",
@@ -93,8 +93,10 @@ COPY --from=builder /app/config ./config
93
93
  COPY --from=builder /app/frontend/dist ./frontend/dist
94
94
  # {{/frontend}}
95
95
 
96
- # Create uploads directory
97
- RUN mkdir -p /app/backend/uploads && chown -R rebase:rebase /app
96
+ # The storage root docker-compose.custom.yml mounts its volume over. An empty
97
+ # named volume takes the owner of the directory it is mounted on, so without
98
+ # this it is root's and every upload fails EACCES for the `rebase` user.
99
+ RUN mkdir -p /storage && chown -R rebase:rebase /app /storage
98
100
 
99
101
  USER rebase
100
102
 
@@ -45,7 +45,7 @@ function findEnvFile(startDir: string): string | undefined {
45
45
  // the real process environment flow through.
46
46
  const envPath = process.env.DOTENV_CONFIG_PATH || findEnvFile(__dirname);
47
47
  if (envPath && fs.existsSync(envPath)) {
48
- dotenv.config({ path: envPath });
48
+ dotenv.config({ path: envPath, quiet: true });
49
49
  }
50
50
 
51
51
  export const env = loadEnv({