@rebasepro/cli 0.25.0-canary.ge06257e → 0.25.1

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 (142) hide show
  1. package/bin/rebase.js +9 -5
  2. package/dist/{agent-setup-C83DXnlx.js → agent-setup-BYb2Tbdz.js} +2 -2
  3. package/dist/{agent-setup-C83DXnlx.js.map → agent-setup-BYb2Tbdz.js.map} +1 -1
  4. package/dist/{api-keys-Bc4FJKYp.js → api-keys-CSMbsmAn.js} +28 -22
  5. package/dist/api-keys-CSMbsmAn.js.map +1 -0
  6. package/dist/{apps-wG-ZTryA.js → apps-iBXNZhVN.js} +6 -7
  7. package/dist/{apps-wG-ZTryA.js.map → apps-iBXNZhVN.js.map} +1 -1
  8. package/dist/{atlas-dev-database-DeK3Sa4h.js → atlas-dev-database-BusbHP6n.js} +4 -4
  9. package/dist/{atlas-dev-database-DeK3Sa4h.js.map → atlas-dev-database-BusbHP6n.js.map} +1 -1
  10. package/dist/{auth-BL7bNQVu.js → auth-DRsTWPky.js} +77 -11
  11. package/dist/auth-DRsTWPky.js.map +1 -0
  12. package/dist/{branch-pointer-DTQNLFtb.js → branch-pointer-Bn_FjNld.js} +1 -1
  13. package/dist/{build-h_7Re-67.js → build-et7Rccxi.js} +6 -7
  14. package/dist/{build-h_7Re-67.js.map → build-et7Rccxi.js.map} +1 -1
  15. package/dist/{bundle-CqURVN-K.js → bundle-DlqkDYSe.js} +6 -21
  16. package/dist/bundle-DlqkDYSe.js.map +1 -0
  17. package/dist/{cloud-DVV_5GPG.js → cloud-B-ZIjHrA.js} +10 -11
  18. package/dist/{cloud-DVV_5GPG.js.map → cloud-B-ZIjHrA.js.map} +1 -1
  19. package/dist/commands/api-keys.d.ts +4 -1
  20. package/dist/commands/auth.d.ts +3 -2
  21. package/dist/commands/dev.d.ts +12 -0
  22. package/dist/commands/generate_sdk.d.ts +4 -2
  23. package/dist/commands/init.d.ts +20 -0
  24. package/dist/commands/start.d.ts +10 -0
  25. package/dist/commands/upgrade.d.ts +12 -0
  26. package/dist/connection-banner-DbLJzWf4.js +128 -0
  27. package/dist/connection-banner-DbLJzWf4.js.map +1 -0
  28. package/dist/{consent-ClRHmcxf.js → consent-BaB-eQKG.js} +2 -2
  29. package/dist/{consent-ClRHmcxf.js.map → consent-BaB-eQKG.js.map} +1 -1
  30. package/dist/{console-Dw3HLdUs.js → console-BlD9kjFW.js} +4 -4
  31. package/dist/{console-Dw3HLdUs.js.map → console-BlD9kjFW.js.map} +1 -1
  32. package/dist/{context-BM-oOMNX.js → context-DHiiiJ5C.js} +3 -4
  33. package/dist/context-DHiiiJ5C.js.map +1 -0
  34. package/dist/{daemon-CknkDjd6.js → daemon-DDMRbz4T.js} +160 -5
  35. package/dist/daemon-DDMRbz4T.js.map +1 -0
  36. package/dist/{daemon-entry-C6pxdily.js → daemon-entry-zOC1revO.js} +204 -5
  37. package/dist/daemon-entry-zOC1revO.js.map +1 -0
  38. package/dist/{db-Dkn9XhT-.js → db-9P6MnmdC.js} +237 -86
  39. package/dist/db-9P6MnmdC.js.map +1 -0
  40. package/dist/{derive-Dl0z2OWi.js → derive-MTdClnkc.js} +29 -14
  41. package/dist/{derive-Dl0z2OWi.js.map → derive-MTdClnkc.js.map} +1 -1
  42. package/dist/{dev-DAcZR4Pp.js → dev-BDN_OKXA.js} +183 -23
  43. package/dist/dev-BDN_OKXA.js.map +1 -0
  44. package/dist/dev-db/connection-banner.d.ts +47 -0
  45. package/dist/dev-db/daemon.d.ts +41 -0
  46. package/dist/dev-db/notification-proxy.d.ts +82 -1
  47. package/dist/dev-db/pull.d.ts +33 -5
  48. package/dist/dev-db/state.d.ts +9 -0
  49. package/dist/{dev-preflight-CorMg7Ub.js → dev-preflight-FT9GbJVj.js} +73 -4
  50. package/dist/dev-preflight-FT9GbJVj.js.map +1 -0
  51. package/dist/{dev-server-B1UYifZJ.js → dev-server-CIZwAfZa.js} +14 -3
  52. package/dist/dev-server-CIZwAfZa.js.map +1 -0
  53. package/dist/{doctor-Ds_lzc9p.js → doctor-D8YXz7df.js} +6 -6
  54. package/dist/doctor-D8YXz7df.js.map +1 -0
  55. package/dist/{eject-CJHkfnat.js → eject-izG2KjMo.js} +3 -4
  56. package/dist/{eject-CJHkfnat.js.map → eject-izG2KjMo.js.map} +1 -1
  57. package/dist/{fold-static-BC9CYicw.js → fold-static-CybSay_W.js} +3 -3
  58. package/dist/{fold-static-BC9CYicw.js.map → fold-static-CybSay_W.js.map} +1 -1
  59. package/dist/{generate_sdk-kfkZmG-d.js → generate_sdk-B4R65oUV.js} +22 -12
  60. package/dist/generate_sdk-B4R65oUV.js.map +1 -0
  61. package/dist/index.es.js +36 -37
  62. package/dist/index.es.js.map +1 -1
  63. package/dist/{init-CjoJoThg.js → init-DYaeppEN.js} +52 -63
  64. package/dist/init-DYaeppEN.js.map +1 -0
  65. package/dist/invoked-command-CG_rIa_o.js +55 -0
  66. package/dist/invoked-command-CG_rIa_o.js.map +1 -0
  67. package/dist/last-dev-database-B_75fxZC.js +2 -0
  68. package/dist/{manifest-DRp0UVTj.js → manifest-nvPdLlJY.js} +2 -2
  69. package/dist/{manifest-DRp0UVTj.js.map → manifest-nvPdLlJY.js.map} +1 -1
  70. package/dist/{normalize-imports-BHxL2d05.js → normalize-imports-BYw8ad87.js} +3 -3
  71. package/dist/{normalize-imports-BHxL2d05.js.map → normalize-imports-BYw8ad87.js.map} +1 -1
  72. package/dist/precompress.d.ts +0 -7
  73. package/dist/{prepare-C1iaiTC4.js → prepare-1rVNd2PF.js} +7 -6
  74. package/dist/prepare-1rVNd2PF.js.map +1 -0
  75. package/dist/project-g4K6kV1t.js +701 -0
  76. package/dist/project-g4K6kV1t.js.map +1 -0
  77. package/dist/{pull-COpNJFzY.js → pull-DDMpsZ5r.js} +143 -63
  78. package/dist/pull-DDMpsZ5r.js.map +1 -0
  79. package/dist/refusal-ReeeGP8a.js +26 -0
  80. package/dist/refusal-ReeeGP8a.js.map +1 -0
  81. package/dist/resolve-BQUAC3Wi.js +2 -0
  82. package/dist/resources/derive.d.ts +9 -0
  83. package/dist/{resources-CLm6g0br.js → resources-CovP8AZ-.js} +4 -5
  84. package/dist/{resources-CLm6g0br.js.map → resources-CovP8AZ-.js.map} +1 -1
  85. package/dist/{schema-BKdh6UoE.js → schema-nuxvvc50.js} +5 -6
  86. package/dist/{schema-BKdh6UoE.js.map → schema-nuxvvc50.js.map} +1 -1
  87. package/dist/{skills-DEhYiPeO.js → skills-DeUIsZcT.js} +3 -4
  88. package/dist/{skills-DEhYiPeO.js.map → skills-DeUIsZcT.js.map} +1 -1
  89. package/dist/{start-BsPJedPQ.js → start-RzZqDroW.js} +20 -7
  90. package/dist/start-RzZqDroW.js.map +1 -0
  91. package/dist/{state-CCB-FAQ9.js → state-CYdBvnwA.js} +3 -2
  92. package/dist/state-CYdBvnwA.js.map +1 -0
  93. package/dist/{status-D_B3tlDy.js → status-D9Zm88NZ.js} +11 -12
  94. package/dist/{status-D_B3tlDy.js.map → status-D9Zm88NZ.js.map} +1 -1
  95. package/dist/{storage-CtB8polS.js → storage-BB3umRfw.js} +3 -4
  96. package/dist/{storage-CtB8polS.js.map → storage-BB3umRfw.js.map} +1 -1
  97. package/dist/{telemetry-EMFRVRQi.js → telemetry-HfU5uAh1.js} +2 -2
  98. package/dist/{telemetry-EMFRVRQi.js.map → telemetry-HfU5uAh1.js.map} +1 -1
  99. package/dist/{telemetry-BYmPU-Ji.js → telemetry-TseNLk6X.js} +4 -4
  100. package/dist/{telemetry-BYmPU-Ji.js.map → telemetry-TseNLk6X.js.map} +1 -1
  101. package/dist/{upgrade-DbuKX9lv.js → upgrade-apiPKKE_.js} +29 -6
  102. package/dist/{upgrade-DbuKX9lv.js.map → upgrade-apiPKKE_.js.map} +1 -1
  103. package/dist/utils/args.d.ts +45 -3
  104. package/dist/utils/boot-retry.d.ts +41 -0
  105. package/dist/utils/dev-preflight.d.ts +34 -1
  106. package/dist/utils/dev-server.d.ts +11 -0
  107. package/dist/utils/project.d.ts +5 -1
  108. package/dist/utils/redact.d.ts +10 -0
  109. package/dist/utils/refusal.d.ts +18 -0
  110. package/dist/utils/unknown-command.d.ts +4 -0
  111. package/package.json +7 -7
  112. package/templates/overlays/baas/README.md +2 -1
  113. package/templates/resource-graphs/blank.json +25 -0
  114. package/templates/resource-graphs/blog.json +28 -0
  115. package/templates/resource-graphs/ecommerce.json +28 -0
  116. package/templates/resource-graphs/headless.json +22 -0
  117. package/templates/template/.env.example +11 -4
  118. package/templates/template/frontend/src/App.tsx +10 -9
  119. package/templates/template/frontend/vite.config.ts +7 -73
  120. package/dist/api-keys-Bc4FJKYp.js.map +0 -1
  121. package/dist/args-CcBphFdj.js +0 -237
  122. package/dist/args-CcBphFdj.js.map +0 -1
  123. package/dist/auth-BL7bNQVu.js.map +0 -1
  124. package/dist/bundle-CqURVN-K.js.map +0 -1
  125. package/dist/context-BM-oOMNX.js.map +0 -1
  126. package/dist/daemon-CknkDjd6.js.map +0 -1
  127. package/dist/daemon-entry-C6pxdily.js.map +0 -1
  128. package/dist/db-Dkn9XhT-.js.map +0 -1
  129. package/dist/dev-DAcZR4Pp.js.map +0 -1
  130. package/dist/dev-preflight-CorMg7Ub.js.map +0 -1
  131. package/dist/dev-server-B1UYifZJ.js.map +0 -1
  132. package/dist/doctor-Ds_lzc9p.js.map +0 -1
  133. package/dist/generate_sdk-kfkZmG-d.js.map +0 -1
  134. package/dist/init-CjoJoThg.js.map +0 -1
  135. package/dist/last-dev-database-BEBPfAMY.js +0 -2
  136. package/dist/prepare-C1iaiTC4.js.map +0 -1
  137. package/dist/project-Wp2zoyeN.js +0 -349
  138. package/dist/project-Wp2zoyeN.js.map +0 -1
  139. package/dist/pull-COpNJFzY.js.map +0 -1
  140. package/dist/resolve-b_p9bmdH.js +0 -2
  141. package/dist/start-BsPJedPQ.js.map +0 -1
  142. package/dist/state-CCB-FAQ9.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"prepare-C1iaiTC4.js","names":[],"sources":["../src/dev-db/branch-pointer.ts","../src/dev-db/last-dev-database.ts","../src/dev-db/resolve.ts","../src/dev-db/prepare.ts"],"sourcesContent":["/**\n * Which database branch this checkout is working on.\n *\n * `rebase db branch create` made a full copy of the database in about a second\n * and then stopped one step short of being a feature: there was no `switch`, no\n * `--branch` on `rebase dev`, and nothing wrote the branch anywhere a command\n * would read it. The only way to *use* a branch was to hand-edit\n * `DATABASE_URL`, and the documentation claimed otherwise — \"the CLI updates\n * your local development configuration\" — which it did not; the `.env` was\n * byte-identical afterwards.\n *\n * This is that missing step, and the shape of it is chosen to avoid three\n * things:\n *\n * 1. **It does not touch `.env`.** That file holds secrets, comments and the\n * developer's own ordering, and a command that rewrites it in place will\n * eventually lose something that was not its business. The branch is\n * recorded beside the other per-checkout state in `.rebase/`, which is\n * already gitignored — a branch is a fact about one machine, never about\n * the project.\n *\n * 2. **It stores a name, not a connection string.** The credentials stay in\n * exactly one place; the URL is derived by swapping the database name on\n * the base one at resolution time. A stored URL would be a second copy of\n * the password, and would go stale the moment `.env` changed.\n *\n * 3. **It does not outrank an explicit instruction.** `--database-url` and a\n * `DATABASE_URL` in the shell are more immediate and more specific than a\n * switch made yesterday, so they still win. The pointer sits directly above\n * the project's `.env`: it is a deliberate, persistent choice, and `.env` is\n * the project default it is meant to override. Anything less and `switch`\n * would silently do nothing on every project that sets `DATABASE_URL` —\n * which is every project not using the managed database.\n */\n\nimport fs from \"fs\";\nimport path from \"path\";\n\n/** Where the pointer lives, next to the rest of the per-checkout state. */\nexport function branchPointerPath(projectRoot: string): string {\n return path.join(projectRoot, \".rebase\", \"branch.json\");\n}\n\nexport interface ActiveBranch {\n /** The name the developer typed. */\n name: string;\n /** The PostgreSQL database that name refers to. */\n database: string;\n}\n\n/**\n * The prefix `BranchService` puts on every branch database.\n *\n * Duplicated from the driver rather than imported because the CLI must answer\n * \"which database\" without loading a database driver — `rebase dev` reads this\n * before it knows which plugin the project uses. It is covered by a test that\n * fails if the driver's prefix moves.\n */\nexport const BRANCH_DB_PREFIX = \"rb_\";\n\nexport function branchDatabaseName(name: string): string {\n return `${BRANCH_DB_PREFIX}${name}`;\n}\n\n/** Read the active branch, or null when the checkout is on the main database. */\nexport function readActiveBranch(projectRoot: string): ActiveBranch | null {\n try {\n const raw = fs.readFileSync(branchPointerPath(projectRoot), \"utf-8\");\n const parsed = JSON.parse(raw) as Partial<ActiveBranch>;\n if (typeof parsed.name !== \"string\" || typeof parsed.database !== \"string\") return null;\n if (!parsed.name || !parsed.database) return null;\n\n return { name: parsed.name, database: parsed.database };\n } catch {\n // Absent is the common case and is not an error. A corrupt file is\n // treated the same way: the answer is \"no branch\", which is the state\n // the developer can always get back to with `branch switch --off`.\n return null;\n }\n}\n\nexport function writeActiveBranch(projectRoot: string, branch: ActiveBranch): void {\n const file = branchPointerPath(projectRoot);\n fs.mkdirSync(path.dirname(file), { recursive: true });\n fs.writeFileSync(file, `${JSON.stringify(branch, null, 2)}\\n`, \"utf-8\");\n}\n\n/** Return to the main database. Absent is success — this is idempotent. */\nexport function clearActiveBranch(projectRoot: string): void {\n fs.rmSync(branchPointerPath(projectRoot), { force: true });\n}\n\n/**\n * The base connection string with its database swapped for the branch's.\n *\n * Everything else is carried across untouched — credentials, host, port, and\n * the query string, which is load-bearing here: `?sslmode=disable` is what a\n * local Docker Postgres needs, and dropping it turns a switch into a TLS error\n * that says nothing about branches.\n *\n * Returns null for a connection string that cannot be parsed, so the caller can\n * say so plainly rather than emitting a mangled URL that fails later.\n */\nexport function branchUrl(baseUrl: string, database: string): string | null {\n try {\n const url = new URL(baseUrl);\n // `pathname` keeps its leading slash; a URL with no database at all\n // still gets one, which is what connecting to a named branch means.\n url.pathname = `/${database}`;\n\n return url.toString();\n } catch {\n return null;\n }\n}\n\n/** The database name in a connection string, for reporting what you are on. */\nexport function databaseNameOf(connectionString: string): string | null {\n try {\n const name = new URL(connectionString).pathname.replace(/^\\//, \"\");\n\n return name || null;\n } catch {\n return null;\n }\n}\n","/**\n * Which database the last `rebase dev` ran on, when nothing else records it.\n *\n * `rebase dev --docker` is a choice made on one command line, and every other\n * command resolved without it: while dev served the project from its compose\n * database, `rebase db url` printed a managed PGlite URL — and started that\n * daemon to print it — and `db push`, `console` and the rest would have used\n * the same empty database. Nothing said the two disagreed.\n *\n * So `rebase dev` records its choice here, and the other commands follow it\n * (`resolve.ts`, rule 5). Only Docker is recorded. Every other database is\n * already somewhere each command reads — `--database-url` aside, which is a\n * choice for one command line — or is the default, so the record holds\n * `docker` exactly when the last `rebase dev` ran on it, and any other start\n * of `rebase dev` removes it. That is also the way back: `rebase dev` without\n * `--docker`.\n *\n * Beside the branch pointer in `.rebase/`, which is gitignored: which database\n * this checkout last ran on is a fact about one machine, never the project.\n */\n\nimport fs from \"fs\";\nimport path from \"path\";\n\nimport type { DevDatabase } from \"./resolve\";\n\nexport function lastDevDatabasePath(projectRoot: string): string {\n return path.join(projectRoot, \".rebase\", \"dev-database.json\");\n}\n\n/** Whether the last `rebase dev` ran on the compose database. */\nexport function readLastDevDocker(projectRoot: string): boolean {\n try {\n const parsed: unknown = JSON.parse(fs.readFileSync(lastDevDatabasePath(projectRoot), \"utf8\"));\n return typeof parsed === \"object\" && parsed !== null && \"kind\" in parsed && parsed.kind === \"docker\";\n } catch {\n // Absent is the common case; unreadable has the same answer.\n return false;\n }\n}\n\n/** What this `rebase dev` was asked for, beside what it runs on. */\nexport interface LastDevRun {\n /** `--docker` was on this command line. */\n dockerFlag?: boolean;\n}\n\n/**\n * Record what this `rebase dev` runs on, and say what the last one ran on.\n *\n * A run that asked for Docker and was outranked by a connection string leaves\n * the record as it was. It is not on Docker, so it records nothing; but it is\n * not a run without `--docker` either, which is what forgets the record. The\n * reader was told to comment the `.env` line out to reach Docker, and once\n * they have, the other commands follow Docker as they did before.\n *\n * Best effort: a checkout whose `.rebase/` cannot be written still runs, and\n * the other commands then resolve as they did before this existed.\n */\nexport function recordLastDevDatabase(\n projectRoot: string,\n kind: DevDatabase[\"kind\"],\n run: LastDevRun = {}\n): { previous: \"docker\" | null } {\n const previous = readLastDevDocker(projectRoot) ? \"docker\" : null;\n if (run.dockerFlag && kind !== \"docker\") return { previous };\n const file = lastDevDatabasePath(projectRoot);\n try {\n if (kind === \"docker\") {\n fs.mkdirSync(path.dirname(file), { recursive: true });\n fs.writeFileSync(file, `${JSON.stringify({ kind: \"docker\", recordedAt: new Date().toISOString() }, null, 2)}\\n`);\n } else {\n fs.rmSync(file, { force: true });\n }\n } catch {\n // See above: not worth failing a dev start over.\n }\n\n return { previous };\n}\n\n/**\n * What `rebase dev` says when it leaves the Docker database the last run used.\n *\n * Said rather than left to be noticed: the data a developer was working with\n * is in the container, and the managed database this run is on is a different,\n * possibly empty, one. Not said to a run that asked for Docker: the line that\n * says `--docker` was ignored, and what outranked it, is the one that applies.\n */\nexport function lastDevDatabaseNotice(previous: \"docker\" | null, kind: DevDatabase[\"kind\"], run: LastDevRun = {}): string | null {\n if (previous !== \"docker\" || kind === \"docker\" || run.dockerFlag) return null;\n\n return \"The last `rebase dev` ran on Postgres in Docker; this one does not. \"\n + \"Pass --docker to stay on it — the other commands now follow this run.\";\n}\n","/**\n * Which database a command should talk to, decided in one place.\n *\n * Before this existed every command that needed Postgres read `DATABASE_URL`\n * for itself, which was fine while there was exactly one answer. Introducing a\n * managed database makes the question real: a project may have no\n * `DATABASE_URL` at all and still expect `rebase db push` to work, and a\n * project that *does* set one must never be quietly redirected somewhere else.\n *\n * So the rule is ordered and boring, and the order is the promise:\n *\n * 1. `--database-url <url>` — said on this command line, wins over everything\n * 2. `DATABASE_URL` in the shell environment\n * 3. the database branch this checkout is switched to\n * 4. `DATABASE_URL` in the project's `.env`\n * 5. `--docker`, or the last `rebase dev` having run with it\n * 6. the managed PGlite database\n *\n * An explicit connection string always wins. That is the whole point of the\n * override: someone pointing Rebase at their own Postgres — a colleague's\n * staging box, a Neon branch, a container they manage — must get exactly that,\n * with no cleverness in between. The managed database is what fills the vacuum\n * when nobody has said anything, and it is the only case where the CLI picks.\n *\n * The second half of (5) is `rebase dev --docker` remembered, so that `rebase\n * db url`, `db push` and the rest reach the database a dev server is on rather\n * than start an empty PGlite beside it (`last-dev-database.ts`). It is exactly\n * as strong as the flag it stands in for, and no stronger.\n *\n * The branch at (3) is the one addition that is not an explicit connection\n * string, and it sits where it does deliberately. It has to outrank `.env` or\n * `rebase db branch switch` would silently do nothing on every project that\n * sets `DATABASE_URL` — which is every project not on the managed database.\n * It must not outrank (1) or (2), because a flag on this command line and a\n * variable in this shell are more immediate than a switch made yesterday.\n *\n * {@link resolveDevDatabase} is pure: inputs in, decision out, no filesystem\n * and no process. Reading `.env`, reading the branch pointer and starting a\n * daemon happen elsewhere, so the ordering above can be tested without any of\n * them.\n */\n\n/** Where the answer came from. Carried so diagnostics can name it. */\nexport type DevDatabaseSource =\n /** `--database-url` on the command line. */\n | \"flag\"\n /** `DATABASE_URL` in the shell environment. */\n | \"environment\"\n /** `DATABASE_URL` in the project's `.env`. */\n | \"env-file\"\n /** The branch this checkout is switched to, over the base connection. */\n | \"branch\"\n /** `--docker`. */\n | \"docker\"\n /** `--docker`, on the last `rebase dev` rather than this command line. */\n | \"last-dev\"\n /** Nobody said anything, so the managed database fills in. */\n | \"managed\";\n\nexport type DevDatabase =\n | {\n kind: \"external\";\n /** The connection string, exactly as given. Never rewritten. */\n url: string;\n source: Extract<DevDatabaseSource, \"flag\" | \"environment\" | \"env-file\" | \"branch\">;\n /** The branch name, when this checkout is switched to one. */\n branch?: string;\n }\n | {\n kind: \"docker\";\n source: Extract<DevDatabaseSource, \"docker\" | \"last-dev\">;\n /**\n * The compose `db` service's connection string, derived by the caller.\n *\n * Null when the project has no compose file to derive one from, which\n * is a `--docker` that cannot be honoured rather than a fallback: the\n * caller says so instead of guessing at `localhost:5432`.\n */\n url: string | null;\n }\n | {\n kind: \"managed\";\n source: \"managed\";\n };\n\nexport interface ResolveDevDatabaseInput {\n /** `--database-url <url>`, if given. */\n flagUrl?: string | null;\n /** `--docker`, if given. */\n flagDocker?: boolean;\n /**\n * Whether the last `rebase dev` ran with `--docker`. Followed only while\n * the compose file still names a database, since there is none to go back\n * to otherwise.\n */\n lastDevDocker?: boolean;\n /** The shell environment. Only `DATABASE_URL` is read. */\n env?: Record<string, string | undefined>;\n /** Parsed `.env` from the project root. Only `DATABASE_URL` is read. */\n envFile?: Record<string, string> | null;\n /**\n * The compose `db` service's connection string, when the project has one.\n *\n * Passed in rather than read here so this function stays pure. Only\n * consulted for the Docker case; an explicit `DATABASE_URL` still wins.\n */\n composeUrl?: string | null;\n /**\n * The branch this checkout is switched to, already resolved to a URL.\n *\n * Resolved by the caller rather than here so this stays pure: deriving it\n * needs the base connection string, which needs the `.env` this function is\n * handed rather than reads.\n */\n branch?: { name: string; url: string } | null;\n}\n\n/**\n * A value that is present but empty is treated as absent.\n *\n * `DATABASE_URL=` in a `.env` is what a developer writes when they mean \"not\n * this one\" — honouring it literally would hand an empty connection string to\n * libpq and produce an error about a missing host, which explains nothing.\n */\nfunction present(value: string | undefined | null): string | null {\n if (typeof value !== \"string\") return null;\n const trimmed = value.trim();\n\n return trimmed.length > 0 ? trimmed : null;\n}\n\nexport function resolveDevDatabase(input: ResolveDevDatabaseInput = {}): DevDatabase {\n const flagUrl = present(input.flagUrl);\n if (flagUrl) return { kind: \"external\", url: flagUrl, source: \"flag\" };\n\n const fromEnvironment = present(input.env?.DATABASE_URL);\n if (fromEnvironment) return { kind: \"external\", url: fromEnvironment, source: \"environment\" };\n\n // Above `.env`, below anything said explicitly — see the ordering note at\n // the top of this file.\n const fromBranch = present(input.branch?.url);\n if (fromBranch && input.branch) {\n return { kind: \"external\", url: fromBranch, source: \"branch\", branch: input.branch.name };\n }\n\n const fromEnvFile = present(input.envFile?.DATABASE_URL);\n if (fromEnvFile) return { kind: \"external\", url: fromEnvFile, source: \"env-file\" };\n\n // Only consulted once every explicit connection string is exhausted: asking\n // for Docker is a choice about *how to get* a database, not which one, so a\n // DATABASE_URL that already names one outranks it.\n if (input.flagDocker) {\n return { kind: \"docker\", source: \"docker\", url: present(input.composeUrl) };\n }\n const composeUrl = present(input.composeUrl);\n if (input.lastDevDocker && composeUrl) {\n return { kind: \"docker\", source: \"last-dev\", url: composeUrl };\n }\n\n return { kind: \"managed\", source: \"managed\" };\n}\n\n/**\n * The line to print when `--docker` was typed and a connection string outranked\n * it, or null when it was not typed or was what this command used.\n *\n * The order stays as documented: asking for Docker says how to get a database,\n * and a `DATABASE_URL` that already names one wins. But a flag on this command\n * line that changes nothing without a word reads as a flag that worked. Only the\n * typed flag is reported — the last `rebase dev --docker` standing in for it is\n * a default, and losing to `.env` is what a default does.\n */\nexport function outrankedDockerFlagNotice(database: DevDatabase, flagDocker: boolean | undefined): string | null {\n if (!flagDocker || database.kind !== \"external\") return null;\n const ignored = \"--docker is ignored:\";\n switch (database.source) {\n case \"flag\":\n return `${ignored} --database-url outranks it.`;\n case \"environment\":\n return `${ignored} DATABASE_URL in the environment outranks it. Unset it to use Postgres in Docker.`;\n case \"branch\":\n return `${ignored} branch \"${database.branch}\" (rebase db branch switch) outranks it. ` +\n \"`rebase db branch switch --off` returns to the database in .env.\";\n case \"env-file\":\n return `${ignored} DATABASE_URL in .env outranks it. Comment that line out to use Postgres in Docker.`;\n }\n}\n\n/** One line for the startup banner, naming both the database and why. */\nexport function describeDevDatabase(database: DevDatabase): string {\n switch (database.kind) {\n case \"external\":\n switch (database.source) {\n case \"flag\":\n return \"your database (--database-url)\";\n case \"environment\":\n return \"your database (DATABASE_URL in the environment)\";\n case \"env-file\":\n return \"your database (DATABASE_URL in .env)\";\n case \"branch\":\n return `branch \"${database.branch}\" (rebase db branch switch)`;\n }\n break;\n case \"docker\":\n return database.source === \"last-dev\"\n ? \"Postgres in Docker (as the last `rebase dev --docker`)\"\n : \"Postgres in Docker\";\n case \"managed\":\n return \"the managed development database (PGlite)\";\n }\n\n // Unreachable while the union is exhaustive; kept so a future variant fails\n // loudly in review rather than printing \"undefined\" to a user.\n throw new Error(`Unhandled dev database: ${JSON.stringify(database)}`);\n}\n","/**\n * The one place a command asks \"which database, and how do I reach it?\".\n *\n * Every command that touches Postgres — `dev`, and the whole `db` namespace\n * through the driver plugin — goes through {@link prepareDatabaseEnv}. It\n * resolves the ordering in `resolve.ts`, starts the managed database if that is\n * what the ordering chose, and hands back the environment additions the child\n * process needs.\n *\n * Two things it deliberately does *not* do:\n *\n * - **It never overwrites an existing `DATABASE_URL`.** When the developer has\n * named a database, the returned environment is empty and the child inherits\n * exactly what it would have inherited before this feature existed. A\n * migration must never be redirected away from the database its author meant.\n *\n * - **It never starts anything for a command that is not going to connect.**\n * `--help` and argument errors are handled by the caller before this is\n * reached, because booting a Postgres to print usage would be absurd.\n */\n\nimport fs from \"fs\";\nimport path from \"path\";\n\nimport { composeDatabaseUrl } from \"../utils/dev-preflight\";\nimport { findProjectRoot, readEnvFile } from \"../utils/project\";\nimport { resourceEnvSuffix } from \"@rebasepro/types\";\nimport { branchUrl, databaseNameOf, readActiveBranch } from \"./branch-pointer\";\nimport { readLastDevDocker } from \"./last-dev-database\";\nimport { MANAGED_LIMITATIONS, MANAGED_POOL_MAX } from \"./constraints\";\nimport { ensureManagedDatabase } from \"./daemon\";\nimport { type DevDatabase, describeDevDatabase, outrankedDockerFlagNotice, resolveDevDatabase } from \"./resolve\";\n\nexport interface PrepareOptions {\n /** `--database-url <url>`. */\n flagUrl?: string | null;\n /** `--docker`. */\n flagDocker?: boolean;\n /**\n * Follow the database the last `rebase dev` ran on (`last-dev-database.ts`).\n * On by default; `rebase dev` itself turns it off, because its own flags are\n * the choice being recorded.\n */\n followLastDev?: boolean;\n /** Suppress the \"starting…\" progress line. */\n quiet?: boolean;\n /** Where human-facing lines go. Defaults to stdout via the caller. */\n onProgress?: (message: string) => void;\n /**\n * Keys of the additional databases the project declares —\n * `database(\"analytics\")` → `analytics`. On the managed path each gets\n * its own PGlite instance and a `DATABASE_URL__<KEY>` in the child's\n * environment, unless the developer set that variable themselves. On an\n * external database nothing is added: whoever chose the database binds\n * the rest of them.\n */\n additionalKeys?: readonly string[];\n}\n\nexport interface PreparedDatabase {\n /** What the resolver chose, for the banner and for tests. */\n database: DevDatabase;\n /**\n * Variables to add to a child process's environment.\n *\n * Empty for an external database: the child already has what it needs, and\n * adding to it could only do harm.\n */\n env: Record<string, string>;\n /** One line naming the database, suitable for a startup banner. */\n description: string;\n /** Absolute path of the managed data directory, when there is one. */\n dataDir?: string;\n /** True when this call started the managed database rather than finding it. */\n startedDaemon?: boolean;\n /** The additional managed databases, by declared key, when any were asked for. */\n additional?: Record<string, string>;\n}\n\n/**\n * The branch this checkout is switched to, over the `DATABASE_URL` in `.env`.\n *\n * Derived rather than stored: the pointer holds a name, and the credentials\n * stay in the one place the developer wrote them. The base here is the\n * project's `.env` — a switch is a statement about *this project's* database,\n * so a `DATABASE_URL` that happens to be in the shell is not the thing being\n * branched, and it outranks the branch anyway.\n *\n * Returns null when there is no branch, and also when `.env` names no base to\n * swap the database name on. That is not the end of it: a project on Postgres\n * in Docker has no `DATABASE_URL` either, and its branch is applied over the\n * compose URL once the order has picked Docker — see\n * {@link resolveProjectDatabaseAndBranch}.\n *\n * Exported for its tests. Asserting this through {@link prepareDatabaseEnv}\n * would start a real PGlite daemon to check a decision made before any daemon\n * is involved.\n */\nexport function resolveActiveBranch(\n projectRoot: string,\n envFile: Record<string, string>\n): { name: string; url: string } | null {\n const active = readActiveBranch(projectRoot);\n if (!active) return null;\n\n const base = envFile.DATABASE_URL?.trim();\n if (!base) return null;\n\n const url = branchUrl(base, active.database);\n\n return url ? { name: active.name, url } : null;\n}\n\n/**\n * The compose `db` service's connection string for this project, or null.\n *\n * Read here rather than in `resolve.ts` so the ordering there stays pure, and\n * exported for the commands that feed the resolver themselves (`rebase status`,\n * `db branch switch`). The preflight that starts the container takes the URL\n * from {@link resolveProjectDatabase}, so it starts one only when the order\n * picks Docker.\n */\nexport function resolveComposeUrl(projectRoot: string, envFile: Record<string, string>): string | null {\n const composePath = path.join(projectRoot, \"docker-compose.yml\");\n if (!fs.existsSync(composePath)) return null;\n try {\n return composeDatabaseUrl(fs.readFileSync(composePath, \"utf8\"), envFile);\n } catch {\n return null;\n }\n}\n\n/**\n * Which database a project is on, decided without starting anything.\n *\n * `resolveDevDatabase` is pure, so the answer is available to help text and to\n * a driver child alike — and neither should pay for a daemon to learn it. The\n * driver cannot work it out for itself: on the managed path `DATABASE_URL` is a\n * perfectly ordinary connection string to a Postgres on loopback, so a child\n * handed only that has no way to know that `rebase db generate` will be refused.\n *\n * Null when there is no project here, which is legal — `rebase db --help` is\n * answered outside one — and when anything at all goes wrong reading the\n * project, because help text must not fail to print over an unreadable `.env`.\n */\nexport function devDatabaseKind(projectRoot?: string | null): DevDatabase[\"kind\"] | null {\n try {\n const root = projectRoot ?? findProjectRoot();\n if (!root) return null;\n\n return resolveProjectDatabase(root).kind;\n } catch {\n return null;\n }\n}\n\n/**\n * The database this command resolves to in this project, decided without\n * starting anything: the ordering in `resolve.ts`, fed from the project's\n * `.env`, its branch pointer, its compose file and the last `rebase dev`.\n *\n * The one place those four are read for a resolution, so a command that asks\n * \"which database\" and a command that then connects to it cannot disagree.\n */\nexport function resolveProjectDatabase(\n projectRoot: string,\n options: Pick<PrepareOptions, \"flagUrl\" | \"flagDocker\" | \"followLastDev\"> = {}\n): DevDatabase {\n return resolveProjectDatabaseAndBranch(projectRoot, options).database;\n}\n\n/** The branch a resolution landed on. */\nexport interface ResolvedBranch {\n /** The name the developer switched to. */\n name: string;\n /** The PostgreSQL database that name refers to. */\n database: string;\n /**\n * The database the branch was taken from, where the branch registry lives:\n * the one the switch swapped the name on.\n */\n parent: string | null;\n}\n\nexport interface ProjectDatabase {\n database: DevDatabase;\n /** Set when the resolved database is this checkout's branch rather than the main one. */\n branch: ResolvedBranch | null;\n /**\n * The branch this checkout is switched to, when the database resolved to\n * is the managed one — which serves exactly one database, so the switch\n * cannot be honoured and the main database is used instead. Null otherwise.\n */\n ignoredBranch: string | null;\n}\n\n/**\n * {@link resolveProjectDatabase}, and which branch the answer is.\n *\n * The switch applies to whichever base the order picks, not to `.env` alone. A\n * project on Postgres in Docker — `rebase dev --docker`, remembered, with the\n * scaffold's `DATABASE_URL` left commented out, which is the setup the docs\n * point to for branching — resolved its branch to nothing, and every command\n * went on using the main database while `switch` said they had moved. So the\n * branch is applied over the compose URL whenever the order picks Docker, by a\n * typed `--docker` or the remembered one, and the answer stays Docker: that is\n * what has the container started and what `rebase dev` records.\n *\n * What outranks a switch still does. `--database-url` and a `DATABASE_URL` in\n * the shell name a database outright, and the managed database cannot hold a\n * branch at all — that last one is reported as `ignoredBranch`, so the caller\n * can say so instead of quietly using main.\n *\n * `env` is the shell environment to judge against, `process.env` by default;\n * `rebase status` passes `{}`, because it asks what *this project* is on.\n */\nexport function resolveProjectDatabaseAndBranch(\n projectRoot: string,\n options: Pick<PrepareOptions, \"flagUrl\" | \"flagDocker\" | \"followLastDev\"> & {\n env?: Record<string, string | undefined>;\n } = {}\n): ProjectDatabase {\n const envFile = readEnvFile(projectRoot);\n const active = readActiveBranch(projectRoot);\n\n const database = resolveDevDatabase({\n flagUrl: options.flagUrl,\n flagDocker: options.flagDocker,\n lastDevDocker: options.followLastDev !== false && readLastDevDocker(projectRoot),\n env: options.env ?? process.env,\n envFile,\n branch: resolveActiveBranch(projectRoot, envFile),\n composeUrl: resolveComposeUrl(projectRoot, envFile)\n });\n\n if (!active) return { database, branch: null, ignoredBranch: null };\n\n if (database.kind === \"external\" && database.source === \"branch\") {\n const parent = databaseNameOf(envFile.DATABASE_URL?.trim() ?? \"\");\n return { database, branch: { ...active, parent }, ignoredBranch: null };\n }\n\n if (database.kind === \"docker\" && database.url) {\n const url = branchUrl(database.url, active.database);\n if (url) {\n return {\n database: { ...database, url },\n branch: { ...active, parent: databaseNameOf(database.url) },\n ignoredBranch: null\n };\n }\n }\n\n return { database, branch: null, ignoredBranch: database.kind === \"managed\" ? active.name : null };\n}\n\n/**\n * The variable a driver child reads {@link devDatabaseKind} from.\n *\n * One name, exported, because three commands build that child's environment and\n * a fourth reads it in another package.\n */\nexport const DEV_DATABASE_KIND_ENV = \"REBASE_DEV_DATABASE_KIND\";\n\n/**\n * The variable that tells a server started on a branch which database it was\n * branched from.\n *\n * The branch registry lives in that database, and a branch database holds\n * only a snapshot of it taken when it was copied — so a server on a branch\n * keeps its branches, and copies new ones from, the database named here. A\n * branch URL does not say which that is; only this checkout's `.env` does.\n */\nexport const BRANCH_PARENT_DATABASE_ENV = \"REBASE_BRANCH_PARENT_DATABASE\";\n\n/**\n * Resolve, start if needed, and describe the database for this command.\n *\n * `projectRoot` is where the managed database's data lives, so two projects on\n * one machine get two databases without either being told about the other.\n */\nexport async function prepareDatabaseEnv(\n projectRoot: string,\n options: PrepareOptions = {}\n): Promise<PreparedDatabase> {\n const envFile = readEnvFile(projectRoot);\n const { database, branch, ignoredBranch } = resolveProjectDatabaseAndBranch(projectRoot, options);\n\n // A branch on Docker is still Docker to the resolver, so its own line does\n // not name the branch; this does, because that is the database in use.\n const description = database.kind === \"docker\" && branch\n ? `branch \"${branch.name}\" (rebase db branch switch) on ${describeDevDatabase(database)}`\n : describeDevDatabase(database);\n // Where a branch lives, for the server: the registry is kept in the\n // database the branch was taken from, and a branch URL does not say which.\n const parentEnv: Record<string, string> = branch?.parent ? { [BRANCH_PARENT_DATABASE_ENV]: branch.parent } : {};\n\n // Said even on a quiet command: `rebase db url --docker` is quiet, and its\n // progress goes to stderr, which is where a flag it did not follow belongs.\n const outranked = outrankedDockerFlagNotice(database, options.flagDocker);\n if (outranked) options.onProgress?.(outranked);\n\n if (ignoredBranch) {\n options.onProgress?.(\n `Branch \"${ignoredBranch}\" is switched to, but this uses the managed database, which has no branches, `\n + \"so the main database is used. `--docker` (or DATABASE_URL in .env) reaches the branch; \"\n + \"`rebase db branch switch --off` clears the switch.\"\n );\n }\n\n if (database.kind === \"external\" && (database.source === \"branch\" || database.source === \"flag\")) {\n // The two external cases that MUST be exported. `environment` and\n // `env-file` are already somewhere the child will look — the shell it\n // inherits, or `.env` via DOTENV_CONFIG_PATH — but a branch URL is\n // derived here and exists nowhere else, and `--database-url` lives only\n // in this process's argv. Without this the pointer resolves correctly\n // and then changes nothing: `rebase db backup` on a switched checkout\n // still reported `Database: leadgen`, and `rebase dev --database-url …`\n // announced the database and then died on `DATABASE_URL: is required`.\n //\n // Safe to set: `dotenv` does not overwrite a variable that is already\n // in the environment, so the child's own `.env` load cannot undo it.\n // On a branch, the database it was branched from too.\n return { database, env: { DATABASE_URL: database.url, ...parentEnv }, description };\n }\n\n if (database.kind === \"docker\") {\n // Docker is the one case where nothing has named a connection string:\n // `.env` leaves DATABASE_URL commented out, so without this the child\n // booted with no database at all and failed on the message a project\n // that configured nothing gets — while the container it had just been\n // asked for was never started either.\n if (!database.url) {\n throw new Error(\n \"--docker needs a docker-compose.yml with a db service in this project, \" +\n \"and this one has none that names POSTGRES_USER, POSTGRES_DB and a published port. \" +\n \"Set DATABASE_URL in .env to point at the database you mean instead.\"\n );\n }\n // Said every time it decides, because nothing on this command line\n // asked for Docker: the reader should not have to remember that an\n // earlier `rebase dev` did.\n if (database.source === \"last-dev\") {\n options.onProgress?.(\n `Using ${branch ? `branch \"${branch.name}\" (${branch.database}) of ` : \"\"}Postgres in Docker, `\n + \"as the last `rebase dev --docker` did. `rebase dev` without --docker goes back to the managed database.\"\n );\n }\n return { database, env: { DATABASE_URL: database.url, ...parentEnv }, description };\n }\n\n if (database.kind !== \"managed\") {\n // `environment` or `env-file`: the connection string is already in a\n // place the child reads for itself, so this adds nothing to it.\n return { database, env: {}, description };\n }\n\n // Only the keys nobody bound by hand. A developer who set\n // DATABASE_URL__ANALYTICS to a warehouse of their own has said which\n // database that is, and the managed one fills a vacuum, never a choice.\n const unbound = (options.additionalKeys ?? []).filter((key) => {\n const name = `DATABASE_URL${resourceEnvSuffix(key)}`;\n return !process.env[name] && !envFile[name];\n });\n\n const managed = await ensureManagedDatabase(projectRoot, {\n quiet: options.quiet,\n onProgress: options.onProgress,\n additionalKeys: unbound\n });\n\n const additionalEnv: Record<string, string> = {};\n for (const [key, url] of Object.entries(managed.additional)) {\n additionalEnv[`DATABASE_URL${resourceEnvSuffix(key)}`] = url;\n }\n\n return {\n database,\n description,\n dataDir: managed.dataDir,\n startedDaemon: managed.started,\n additional: managed.additional,\n env: {\n DATABASE_URL: managed.url,\n // PGlite is one session behind a multiplexer: two pooled clients in\n // overlapping transactions deadlock there. This is the ceiling that\n // turns that into ordinary queueing — see `constraints.ts`.\n REBASE_DB_POOL_MAX: String(MANAGED_POOL_MAX),\n ...additionalEnv\n }\n };\n}\n\n/**\n * The lines to print about a managed database, in the order to print them.\n *\n * Returned rather than printed so the caller decides where they go — `dev` has\n * a banner, `db push` has a single line above its own output — and so a test can\n * assert on them without capturing a stream.\n */\nexport function managedNotices(prepared: PreparedDatabase): string[] {\n if (prepared.database.kind !== \"managed\") return [];\n\n const lines = [`Using ${prepared.description}.`];\n if (prepared.dataDir) lines.push(`Data: ${prepared.dataDir}`);\n for (const key of Object.keys(prepared.additional ?? {})) {\n lines.push(`Also serving database \"${key}\" as DATABASE_URL${resourceEnvSuffix(key)}`);\n }\n\n // Stated every time rather than discovered. A developer who does not know\n // requests are serialized here will read a concurrency difference as a bug\n // in their own code.\n for (const limitation of MANAGED_LIMITATIONS) {\n lines.push(`${limitation.summary} ${limitation.remedy}`);\n }\n lines.push(\"To use your own Postgres instead, set DATABASE_URL in .env.\");\n\n return lines;\n}\n"],"mappings":"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"}
@@ -1,349 +0,0 @@
1
- import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { n as getPMCommands, t as detectPackageManager } from "./package-manager-DSEOwTqM.js";
3
- import chalk from "chalk";
4
- import fs from "fs";
5
- import path from "path";
6
- import { pathToFileURL } from "url";
7
- import { createRequire } from "module";
8
- import { execSync } from "child_process";
9
- import dotenv from "dotenv";
10
- //#region src/utils/project.ts
11
- /**
12
- * Project discovery utilities for the Rebase CLI.
13
- *
14
- * These helpers locate the project root, backend directory, .env file,
15
- * and local binaries — used by all CLI command modules.
16
- */
17
- var project_exports = /* @__PURE__ */ __exportAll({
18
- MANIFEST_FILENAME: () => MANIFEST_FILENAME,
19
- dependenciesNotInstalled: () => dependenciesNotInstalled,
20
- exitDependenciesNotInstalled: () => exitDependenciesNotInstalled,
21
- failAsJson: () => failAsJson,
22
- findBackendDir: () => findBackendDir,
23
- findEnvFile: () => findEnvFile,
24
- findFrontendDir: () => findFrontendDir,
25
- findProjectRoot: () => findProjectRoot,
26
- getActiveBackendPlugin: () => getActiveBackendPlugin,
27
- readEnvFile: () => readEnvFile,
28
- requireBackendDir: () => requireBackendDir,
29
- requireProjectRoot: () => requireProjectRoot,
30
- resolveLocalBin: () => resolveLocalBin,
31
- resolvePluginCliScript: () => resolvePluginCliScript,
32
- resolveTsx: () => resolveTsx,
33
- resolveTsxLoader: () => resolveTsxLoader,
34
- validateTsxInstallation: () => validateTsxInstallation,
35
- wantsJsonOutput: () => wantsJsonOutput
36
- });
37
- /** The authored project manifest. Its presence alone marks a project root. */
38
- var MANIFEST_FILENAME = "rebase.json";
39
- /**
40
- * Walk up from `startDir` to find the Rebase project root.
41
- *
42
- * A directory is the root when it holds a `rebase.json`, or when it holds a
43
- * `package.json` that either lists `backend` as a workspace or sits beside both
44
- * `backend/` and `config/`.
45
- *
46
- * `rebase.json` is checked first and needs no `package.json` beside it, because
47
- * the conventions below all describe a repository that *contains the backend*.
48
- * A repository holding only a frontend — the normal shape once a project's apps
49
- * live in separate repositories — matches none of them, so without this the
50
- * tooling could not run there at all.
51
- */
52
- function findProjectRoot(startDir = process.cwd()) {
53
- let dir = path.resolve(startDir);
54
- const root = path.parse(dir).root;
55
- while (dir !== root) {
56
- if (fs.existsSync(path.join(dir, "rebase.json"))) return dir;
57
- const pkgPath = path.join(dir, "package.json");
58
- if (fs.existsSync(pkgPath)) {
59
- try {
60
- const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
61
- if (pkg.workspaces && Array.isArray(pkg.workspaces)) {
62
- if (pkg.workspaces.some((w) => w === "backend")) return dir;
63
- }
64
- } catch {}
65
- if (fs.existsSync(path.join(dir, "backend")) && fs.existsSync(path.join(dir, "config"))) return dir;
66
- }
67
- dir = path.dirname(dir);
68
- }
69
- return null;
70
- }
71
- /**
72
- * Locate the backend directory within the project root.
73
- */
74
- function findBackendDir(projectRoot) {
75
- const backendDir = path.join(projectRoot, "backend");
76
- return fs.existsSync(backendDir) ? backendDir : null;
77
- }
78
- /**
79
- * Detect the active backend plugin (e.g. @rebasepro/server-postgres) from the backend's package.json.
80
- */
81
- function getActiveBackendPlugin(backendDir) {
82
- const pkgPath = path.join(backendDir, "package.json");
83
- if (!fs.existsSync(pkgPath)) return null;
84
- try {
85
- const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
86
- const deps = {
87
- ...pkg.dependencies,
88
- ...pkg.devDependencies
89
- };
90
- const candidates = Object.keys(deps).filter((dep) => dep.startsWith("@rebasepro/server-") && dep !== "@rebasepro/server");
91
- if (candidates.length === 0) return null;
92
- if (candidates.includes("@rebasepro/server-postgres")) return "@rebasepro/server-postgres";
93
- for (const candidate of candidates) if (resolvePluginCliScript(backendDir, candidate)) return candidate;
94
- return candidates[0];
95
- } catch {}
96
- return null;
97
- }
98
- /**
99
- * Resolve the active plugin's CLI script.
100
- */
101
- function resolvePluginCliScript(backendDir, pluginName) {
102
- const candidates = [];
103
- let dir = path.resolve(backendDir);
104
- const fsRoot = path.parse(dir).root;
105
- while (dir !== fsRoot) {
106
- candidates.push(path.join(dir, "node_modules", pluginName, "src", "cli.ts"), path.join(dir, "node_modules", pluginName, "dist", "cli.js"));
107
- dir = path.dirname(dir);
108
- }
109
- candidates.push(path.resolve(backendDir, "..", "..", "..", "packages", pluginName.replace("@rebasepro/", ""), "src", "cli.ts"), path.resolve(backendDir, "..", "..", "packages", pluginName.replace("@rebasepro/", ""), "src", "cli.ts"), path.resolve(backendDir, "..", "packages", pluginName.replace("@rebasepro/", ""), "src", "cli.ts"));
110
- for (const candidate of candidates) if (fs.existsSync(candidate)) return candidate;
111
- return null;
112
- }
113
- /**
114
- * Locate the frontend directory within the project root.
115
- */
116
- function findFrontendDir(projectRoot) {
117
- const frontendDir = path.join(projectRoot, "frontend");
118
- return fs.existsSync(frontendDir) ? frontendDir : null;
119
- }
120
- /**
121
- * Find the .env file. Checks the project root first, then backend.
122
- */
123
- function findEnvFile(projectRoot) {
124
- const candidates = [path.join(projectRoot, ".env"), path.join(projectRoot, "backend", ".env")];
125
- for (const candidate of candidates) if (fs.existsSync(candidate)) return candidate;
126
- return null;
127
- }
128
- /**
129
- * Read the project's `.env` into a plain object.
130
- *
131
- * One reader, because there were four: `dotenv` in `start`, a hand-rolled
132
- * `indexOf("=")` loop in `api-keys`, a single-key regex in `auth`, and its own
133
- * splitting in `cloud env`. `dotenv` is a declared dependency of this package,
134
- * so the other three existed for no reason and disagreed with the correct one
135
- * on the two things people actually write in a `.env`:
136
- *
137
- * - `export KEY=value`, which the hand-rolled parser keyed as
138
- * `export KEY` — so the command reported the key as unset while it was
139
- * right there in the file;
140
- * - `KEY=value # comment`, whose comment travelled into the value and then
141
- * into an `Authorization` header, coming back as a 401 with nothing
142
- * pointing at the cause.
143
- *
144
- * Returns `{}` when the project has no `.env`, so callers can treat "absent"
145
- * and "empty" alike.
146
- */
147
- function readEnvFile(projectRoot) {
148
- const envFile = findEnvFile(projectRoot);
149
- if (!envFile || !fs.existsSync(envFile)) return {};
150
- try {
151
- return dotenv.parse(fs.readFileSync(envFile, "utf-8"));
152
- } catch {
153
- return {};
154
- }
155
- }
156
- /**
157
- * Resolve a binary from the project's node_modules/.bin.
158
- * Checks backend, root, parent monorepo root, then falls back to PATH.
159
- */
160
- function resolveLocalBin(projectRoot, binName) {
161
- const candidates = [path.join(projectRoot, "backend", "node_modules", ".bin", binName), path.join(projectRoot, "node_modules", ".bin", binName)];
162
- let parent = path.dirname(projectRoot);
163
- const rootDir = path.parse(parent).root;
164
- while (parent !== rootDir) {
165
- candidates.push(path.join(parent, "node_modules", ".bin", binName));
166
- parent = path.dirname(parent);
167
- }
168
- for (const candidate of candidates) if (fs.existsSync(candidate)) return candidate;
169
- try {
170
- const globalPath = execSync(`which ${binName}`, { encoding: "utf-8" }).trim();
171
- if (globalPath && fs.existsSync(globalPath)) return globalPath;
172
- } catch {}
173
- return null;
174
- }
175
- /**
176
- * Resolve the tsx binary. Checks backend node_modules first, then root.
177
- */
178
- function resolveTsx(projectRoot) {
179
- return resolveLocalBin(projectRoot, "tsx");
180
- }
181
- /**
182
- * tsx's loader, as the URL `node --import` takes, or null when none resolves.
183
- *
184
- * For running a TypeScript entry in one Node process. The `tsx` binary is a
185
- * relay — pnpm's `.bin/tsx` shell shim, then tsx's CLI in one Node, which
186
- * spawns a second Node with this same loader to run the script — so spawning
187
- * through it costs a shell and a Node start (~50–100 ms) on every hop, and
188
- * `rebase dev` pays a hop on every start and every collection save.
189
- *
190
- * Resolved the way Node resolves the package, from the project first — the
191
- * backend, where a scaffold declares tsx, then the root and everything above it
192
- * — so the tsx used is the one {@link resolveTsx} would have found; then from
193
- * this package, as the repository's own tests resolve `tsx/cli`. A URL rather
194
- * than a path: a Windows path is not a valid `--import` specifier.
195
- */
196
- function resolveTsxLoader(projectRoot) {
197
- const bases = [
198
- path.join(projectRoot, "backend", "noop.js"),
199
- path.join(projectRoot, "noop.js"),
200
- import.meta.url
201
- ];
202
- for (const base of bases) try {
203
- return pathToFileURL(createRequire(base).resolve("tsx")).href;
204
- } catch {}
205
- return null;
206
- }
207
- /**
208
- * Validate that a resolved tsx binary actually has an intact installation.
209
- *
210
- * `resolveLocalBin` only checks whether `node_modules/.bin/tsx` (a symlink)
211
- * exists. If the pnpm content-addressable store was cleaned or a previous
212
- * install was interrupted, the symlink can exist while critical files inside
213
- * the tsx package (e.g. `dist/preflight.cjs`) are missing — causing a
214
- * confusing MODULE_NOT_FOUND error at runtime.
215
- *
216
- * This function follows the symlink, walks up to find the tsx package root
217
- * (`package.json` with `name: "tsx"`), and verifies that `dist/preflight.cjs`
218
- * is present. Returns `null` when the installation looks healthy, or an
219
- * error description string when it appears corrupted.
220
- */
221
- function validateTsxInstallation(tsxBinPath) {
222
- try {
223
- const realPath = fs.realpathSync(tsxBinPath);
224
- let dir = path.dirname(realPath);
225
- const fsRoot = path.parse(dir).root;
226
- for (let depth = 0; depth < 10 && dir !== fsRoot; depth++) {
227
- const pkgPath = path.join(dir, "package.json");
228
- if (fs.existsSync(pkgPath)) try {
229
- if (JSON.parse(fs.readFileSync(pkgPath, "utf-8")).name === "tsx") {
230
- const preflightPath = path.join(dir, "dist", "preflight.cjs");
231
- if (!fs.existsSync(preflightPath)) return `tsx package at ${dir} is missing dist/preflight.cjs`;
232
- return null;
233
- }
234
- } catch {}
235
- dir = path.dirname(dir);
236
- }
237
- return null;
238
- } catch (err) {
239
- return `tsx binary symlink is broken: ${err instanceof Error ? err.message : String(err)}`;
240
- }
241
- }
242
- /**
243
- * The one sentence a command says when the project's dependencies are missing.
244
- *
245
- * Six commands each had their own wording for the same state, and none of them
246
- * named the remedy:
247
- *
248
- * ✗ Could not find CLI entry point for @rebasepro/server-postgres.
249
- * ✗ Could not find tsx binary.
250
- * ✗ Could not find tsx binary for backend.
251
- *
252
- * All three mean "you have not installed yet" — `getActiveBackendPlugin` has
253
- * already read the driver out of `backend/package.json` by the time the first
254
- * one fires, so the package is declared and simply not on disk, and `tsx` is a
255
- * devDependency of every scaffold. But they read as *Rebase* being broken, and
256
- * they name an internal path or a binary the developer never asked for rather
257
- * than the command that fixes it. That is the whole of the failure someone sees
258
- * on a fresh clone, where `node_modules/` is the one thing a checkout does not
259
- * carry.
260
- *
261
- * So: one sentence, naming the package manager this project uses and the
262
- * directory to run it in — the working directory is usually neither.
263
- */
264
- function dependenciesNotInstalled(projectRoot) {
265
- return `Dependencies are not installed — run \`${getPMCommands(detectPackageManager(projectRoot)).install.join(" ")}\` in ${projectRoot}`;
266
- }
267
- /**
268
- * Print {@link dependenciesNotInstalled} and exit 1.
269
- *
270
- * For the five commands that report and stop. `db.ts` throws instead, because
271
- * its caller adds the `✗` and the exit itself.
272
- */
273
- function exitDependenciesNotInstalled(projectRoot) {
274
- console.error(chalk.red(`✗ ${dependenciesNotInstalled(projectRoot)}`));
275
- process.exit(1);
276
- }
277
- /**
278
- * The refusal envelope, for a caller that asked for JSON.
279
- *
280
- * Same shape as the cloud family's `fail()` — `{ error: { message, code, hint } }`
281
- * — because there is one CLI and a caller should not have to know which half of
282
- * it answered. `code` is what a caller branches on and is never absent; the
283
- * cloud family's reasoning about that applies here unchanged. `issues` carries
284
- * the per-problem detail a human reader gets as a bullet list, because a
285
- * refusal that says "2 problem(s)" and does not say which two is not
286
- * machine-readable in any useful sense.
287
- *
288
- * On **stdout**, like every other `--json` result: the contract those commands
289
- * make is that stdout holds one JSON value, and a caller that pipes stdout to a
290
- * parser must get a parseable refusal rather than an empty stream and a
291
- * human sentence it never sees. That contract used to hold for exactly one
292
- * failure of each command — the one that goes through `requireProjectRoot` —
293
- * while every other exit of the *same* command wrote human text to stderr and
294
- * left stdout empty. So `rebase status --json` was parseable outside a project
295
- * and unparseable inside a broken one, which is the case a caller actually has
296
- * to handle.
297
- *
298
- * The flag is read off `process.argv` because the failure happens inside a
299
- * helper the command calls before it has parsed anything. Coarse — a literal
300
- * `--json` as some other flag's value would count — and worth it: the failure
301
- * mode of being coarse is a JSON error where a human one was wanted, and the
302
- * failure mode of not doing it is an unparseable stream.
303
- */
304
- function failAsJson(message, code, hint, issues) {
305
- const error = {
306
- message,
307
- code
308
- };
309
- if (hint !== void 0) error.hint = hint;
310
- if (issues !== void 0) error.issues = issues;
311
- console.log(JSON.stringify({ error }, null, 2));
312
- process.exit(1);
313
- }
314
- /** Did the command line ask for machine-readable output? */
315
- function wantsJsonOutput(argv = process.argv) {
316
- return argv.includes("--json");
317
- }
318
- /**
319
- * Require the project root or exit with a helpful error.
320
- */
321
- function requireProjectRoot() {
322
- const root = findProjectRoot();
323
- if (!root) {
324
- if (wantsJsonOutput()) failAsJson("Could not find a Rebase project root.", "no_project_root", `Looked in this directory and every parent for a ${MANIFEST_FILENAME}, a package.json with a "backend" workspace, or a backend/ next to a config/.`);
325
- console.error(chalk.red("✗ Could not find a Rebase project root."));
326
- console.error(chalk.gray(` Looked in this directory and every parent for a ${MANIFEST_FILENAME},`));
327
- console.error(chalk.gray(" a package.json with a \"backend\" workspace, or a backend/ next to a config/."));
328
- console.error(chalk.gray(" Run this from inside a project, or create one with `rebase init`."));
329
- process.exit(1);
330
- }
331
- return root;
332
- }
333
- /**
334
- * Require the backend directory or exit with a helpful error.
335
- */
336
- function requireBackendDir(projectRoot) {
337
- const backendDir = findBackendDir(projectRoot);
338
- if (!backendDir) {
339
- if (wantsJsonOutput()) failAsJson("Could not find a backend/ directory.", "no_backend_dir", `Expected at: ${path.join(projectRoot, "backend")}`);
340
- console.error(chalk.red("✗ Could not find a backend/ directory."));
341
- console.error(chalk.gray(` Expected at: ${path.join(projectRoot, "backend")}`));
342
- process.exit(1);
343
- }
344
- return backendDir;
345
- }
346
- //#endregion
347
- export { resolveTsxLoader as _, findBackendDir as a, findProjectRoot as c, readEnvFile as d, requireBackendDir as f, resolveTsx as g, resolvePluginCliScript as h, failAsJson as i, getActiveBackendPlugin as l, resolveLocalBin as m, dependenciesNotInstalled as n, findEnvFile as o, requireProjectRoot as p, exitDependenciesNotInstalled as r, findFrontendDir as s, MANIFEST_FILENAME as t, project_exports as u, validateTsxInstallation as v };
348
-
349
- //# sourceMappingURL=project-Wp2zoyeN.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"project-Wp2zoyeN.js","names":[],"sources":["../src/utils/project.ts"],"sourcesContent":["/**\n * Project discovery utilities for the Rebase CLI.\n *\n * These helpers locate the project root, backend directory, .env file,\n * and local binaries — used by all CLI command modules.\n */\nimport fs from \"fs\";\nimport { createRequire } from \"module\";\nimport path from \"path\";\nimport { pathToFileURL } from \"url\";\nimport { execSync } from \"child_process\";\nimport dotenv from \"dotenv\";\nimport chalk from \"chalk\";\nimport { detectPackageManager, getPMCommands } from \"./package-manager\";\n\n/** The authored project manifest. Its presence alone marks a project root. */\nexport const MANIFEST_FILENAME = \"rebase.json\";\n\n/**\n * Walk up from `startDir` to find the Rebase project root.\n *\n * A directory is the root when it holds a `rebase.json`, or when it holds a\n * `package.json` that either lists `backend` as a workspace or sits beside both\n * `backend/` and `config/`.\n *\n * `rebase.json` is checked first and needs no `package.json` beside it, because\n * the conventions below all describe a repository that *contains the backend*.\n * A repository holding only a frontend — the normal shape once a project's apps\n * live in separate repositories — matches none of them, so without this the\n * tooling could not run there at all.\n */\nexport function findProjectRoot(startDir: string = process.cwd()): string | null {\n let dir = path.resolve(startDir);\n const root = path.parse(dir).root;\n\n while (dir !== root) {\n if (fs.existsSync(path.join(dir, MANIFEST_FILENAME))) {\n return dir;\n }\n\n const pkgPath = path.join(dir, \"package.json\");\n\n if (fs.existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\"));\n // Check for workspace-based project (monorepo root)\n if (pkg.workspaces && Array.isArray(pkg.workspaces)) {\n const hasBackend = pkg.workspaces.some((w: string) =>\n w === \"backend\"\n );\n if (hasBackend) return dir;\n }\n } catch {\n // ignore parse errors\n }\n\n // Check for sibling backend directory\n if (fs.existsSync(path.join(dir, \"backend\")) && fs.existsSync(path.join(dir, \"config\"))) {\n return dir;\n }\n }\n\n dir = path.dirname(dir);\n }\n\n return null;\n}\n\n/**\n * Locate the backend directory within the project root.\n */\nexport function findBackendDir(projectRoot: string): string | null {\n const backendDir = path.join(projectRoot, \"backend\");\n return fs.existsSync(backendDir) ? backendDir : null;\n}\n\n/**\n * Detect the active backend plugin (e.g. @rebasepro/server-postgres) from the backend's package.json.\n */\nexport function getActiveBackendPlugin(backendDir: string): string | null {\n const pkgPath = path.join(backendDir, \"package.json\");\n if (!fs.existsSync(pkgPath)) return null;\n\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\"));\n const deps = { ...pkg.dependencies,\n...pkg.devDependencies };\n\n // Collect all @rebasepro/server-* driver plugins (exclude server itself)\n const candidates = Object.keys(deps).filter(\n dep => dep.startsWith(\"@rebasepro/server-\") && dep !== \"@rebasepro/server\"\n );\n\n if (candidates.length === 0) return null;\n\n // Prefer server-postgres — it's the primary supported driver\n if (candidates.includes(\"@rebasepro/server-postgres\")) {\n return \"@rebasepro/server-postgres\";\n }\n\n // Fallback: return the first candidate that actually has a CLI entry point\n for (const candidate of candidates) {\n if (resolvePluginCliScript(backendDir, candidate)) {\n return candidate;\n }\n }\n\n // Last resort: return whatever we found\n return candidates[0];\n } catch {\n // Ignore parse errors\n }\n return null;\n}\n\n/**\n * Resolve the active plugin's CLI script.\n */\nexport function resolvePluginCliScript(backendDir: string, pluginName: string): string | null {\n const candidates: string[] = [];\n\n // Walk up from the backend dir: pnpm links the plugin into\n // backend/node_modules, while npm workspaces hoist it to the project (or an\n // enclosing monorepo) root.\n let dir = path.resolve(backendDir);\n const fsRoot = path.parse(dir).root;\n while (dir !== fsRoot) {\n candidates.push(\n path.join(dir, \"node_modules\", pluginName, \"src\", \"cli.ts\"),\n path.join(dir, \"node_modules\", pluginName, \"dist\", \"cli.js\")\n );\n dir = path.dirname(dir);\n }\n\n candidates.push(\n // For monorepo dev mode:\n path.resolve(backendDir, \"..\", \"..\", \"..\", \"packages\", pluginName.replace(\"@rebasepro/\", \"\"), \"src\", \"cli.ts\"),\n path.resolve(backendDir, \"..\", \"..\", \"packages\", pluginName.replace(\"@rebasepro/\", \"\"), \"src\", \"cli.ts\"),\n path.resolve(backendDir, \"..\", \"packages\", pluginName.replace(\"@rebasepro/\", \"\"), \"src\", \"cli.ts\")\n );\n\n for (const candidate of candidates) {\n if (fs.existsSync(candidate)) return candidate;\n }\n return null;\n}\n\n/**\n * Locate the frontend directory within the project root.\n */\nexport function findFrontendDir(projectRoot: string): string | null {\n const frontendDir = path.join(projectRoot, \"frontend\");\n return fs.existsSync(frontendDir) ? frontendDir : null;\n}\n\n/**\n * Find the .env file. Checks the project root first, then backend.\n */\nexport function findEnvFile(projectRoot: string): string | null {\n const candidates = [\n path.join(projectRoot, \".env\"),\n path.join(projectRoot, \"backend\", \".env\")\n ];\n\n for (const candidate of candidates) {\n if (fs.existsSync(candidate)) return candidate;\n }\n\n return null;\n}\n\n/**\n * Read the project's `.env` into a plain object.\n *\n * One reader, because there were four: `dotenv` in `start`, a hand-rolled\n * `indexOf(\"=\")` loop in `api-keys`, a single-key regex in `auth`, and its own\n * splitting in `cloud env`. `dotenv` is a declared dependency of this package,\n * so the other three existed for no reason and disagreed with the correct one\n * on the two things people actually write in a `.env`:\n *\n * - `export KEY=value`, which the hand-rolled parser keyed as\n * `export KEY` — so the command reported the key as unset while it was\n * right there in the file;\n * - `KEY=value # comment`, whose comment travelled into the value and then\n * into an `Authorization` header, coming back as a 401 with nothing\n * pointing at the cause.\n *\n * Returns `{}` when the project has no `.env`, so callers can treat \"absent\"\n * and \"empty\" alike.\n */\nexport function readEnvFile(projectRoot: string): Record<string, string> {\n const envFile = findEnvFile(projectRoot);\n if (!envFile || !fs.existsSync(envFile)) return {};\n try {\n return dotenv.parse(fs.readFileSync(envFile, \"utf-8\"));\n } catch {\n // An unreadable or malformed file is not worth failing a command over;\n // the caller reports the missing value it was looking for.\n return {};\n }\n}\n\n/**\n * Resolve a binary from the project's node_modules/.bin.\n * Checks backend, root, parent monorepo root, then falls back to PATH.\n */\nexport function resolveLocalBin(projectRoot: string, binName: string): string | null {\n const candidates = [\n path.join(projectRoot, \"backend\", \"node_modules\", \".bin\", binName),\n path.join(projectRoot, \"node_modules\", \".bin\", binName)\n ];\n\n // Also check parent directories (for monorepo setups where app/ is nested)\n let parent = path.dirname(projectRoot);\n const rootDir = path.parse(parent).root;\n while (parent !== rootDir) {\n candidates.push(path.join(parent, \"node_modules\", \".bin\", binName));\n parent = path.dirname(parent);\n }\n\n for (const candidate of candidates) {\n if (fs.existsSync(candidate)) return candidate;\n }\n\n // Fall back to globally installed binary via which\n try {\n const globalPath = execSync(`which ${binName}`, { encoding: \"utf-8\" }).trim();\n if (globalPath && fs.existsSync(globalPath)) return globalPath;\n } catch {\n // not found globally\n }\n\n return null;\n}\n\n/**\n * Resolve the tsx binary. Checks backend node_modules first, then root.\n */\nexport function resolveTsx(projectRoot: string): string | null {\n return resolveLocalBin(projectRoot, \"tsx\");\n}\n\n/**\n * tsx's loader, as the URL `node --import` takes, or null when none resolves.\n *\n * For running a TypeScript entry in one Node process. The `tsx` binary is a\n * relay — pnpm's `.bin/tsx` shell shim, then tsx's CLI in one Node, which\n * spawns a second Node with this same loader to run the script — so spawning\n * through it costs a shell and a Node start (~50–100 ms) on every hop, and\n * `rebase dev` pays a hop on every start and every collection save.\n *\n * Resolved the way Node resolves the package, from the project first — the\n * backend, where a scaffold declares tsx, then the root and everything above it\n * — so the tsx used is the one {@link resolveTsx} would have found; then from\n * this package, as the repository's own tests resolve `tsx/cli`. A URL rather\n * than a path: a Windows path is not a valid `--import` specifier.\n */\nexport function resolveTsxLoader(projectRoot: string): string | null {\n const bases = [\n path.join(projectRoot, \"backend\", \"noop.js\"),\n path.join(projectRoot, \"noop.js\"),\n import.meta.url\n ];\n for (const base of bases) {\n try {\n return pathToFileURL(createRequire(base).resolve(\"tsx\")).href;\n } catch {\n // Not resolvable from here; try the next base.\n }\n }\n return null;\n}\n\n/**\n * Validate that a resolved tsx binary actually has an intact installation.\n *\n * `resolveLocalBin` only checks whether `node_modules/.bin/tsx` (a symlink)\n * exists. If the pnpm content-addressable store was cleaned or a previous\n * install was interrupted, the symlink can exist while critical files inside\n * the tsx package (e.g. `dist/preflight.cjs`) are missing — causing a\n * confusing MODULE_NOT_FOUND error at runtime.\n *\n * This function follows the symlink, walks up to find the tsx package root\n * (`package.json` with `name: \"tsx\"`), and verifies that `dist/preflight.cjs`\n * is present. Returns `null` when the installation looks healthy, or an\n * error description string when it appears corrupted.\n */\nexport function validateTsxInstallation(tsxBinPath: string): string | null {\n try {\n // Follow the symlink chain to the real tsx entry script\n const realPath = fs.realpathSync(tsxBinPath);\n\n // Walk up from the real binary to locate the tsx package root\n let dir = path.dirname(realPath);\n const fsRoot = path.parse(dir).root;\n for (let depth = 0; depth < 10 && dir !== fsRoot; depth++) {\n const pkgPath = path.join(dir, \"package.json\");\n if (fs.existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\"));\n if (pkg.name === \"tsx\") {\n // Found the tsx package root — verify critical preload file\n const preflightPath = path.join(dir, \"dist\", \"preflight.cjs\");\n if (!fs.existsSync(preflightPath)) {\n return `tsx package at ${dir} is missing dist/preflight.cjs`;\n }\n return null; // Installation looks healthy\n }\n } catch {\n // Malformed package.json — keep walking\n }\n }\n dir = path.dirname(dir);\n }\n\n // Could not determine tsx root — don't block, assume valid\n return null;\n } catch (err) {\n // realpathSync throws if the symlink target is completely gone\n return `tsx binary symlink is broken: ${err instanceof Error ? err.message : String(err)}`;\n }\n}\n\n/**\n * The one sentence a command says when the project's dependencies are missing.\n *\n * Six commands each had their own wording for the same state, and none of them\n * named the remedy:\n *\n * ✗ Could not find CLI entry point for @rebasepro/server-postgres.\n * ✗ Could not find tsx binary.\n * ✗ Could not find tsx binary for backend.\n *\n * All three mean \"you have not installed yet\" — `getActiveBackendPlugin` has\n * already read the driver out of `backend/package.json` by the time the first\n * one fires, so the package is declared and simply not on disk, and `tsx` is a\n * devDependency of every scaffold. But they read as *Rebase* being broken, and\n * they name an internal path or a binary the developer never asked for rather\n * than the command that fixes it. That is the whole of the failure someone sees\n * on a fresh clone, where `node_modules/` is the one thing a checkout does not\n * carry.\n *\n * So: one sentence, naming the package manager this project uses and the\n * directory to run it in — the working directory is usually neither.\n */\nexport function dependenciesNotInstalled(projectRoot: string): string {\n const install = getPMCommands(detectPackageManager(projectRoot)).install.join(\" \");\n return `Dependencies are not installed — run \\`${install}\\` in ${projectRoot}`;\n}\n\n/**\n * Print {@link dependenciesNotInstalled} and exit 1.\n *\n * For the five commands that report and stop. `db.ts` throws instead, because\n * its caller adds the `✗` and the exit itself.\n */\nexport function exitDependenciesNotInstalled(projectRoot: string): never {\n console.error(chalk.red(`✗ ${dependenciesNotInstalled(projectRoot)}`));\n process.exit(1);\n}\n\n/** One problem inside a refusal, when the command found several. */\nexport interface JsonFailureIssue {\n /** Where it is — a config path, a manifest key, a file. */\n path?: string;\n message: string;\n}\n\n/**\n * The refusal envelope, for a caller that asked for JSON.\n *\n * Same shape as the cloud family's `fail()` — `{ error: { message, code, hint } }`\n * — because there is one CLI and a caller should not have to know which half of\n * it answered. `code` is what a caller branches on and is never absent; the\n * cloud family's reasoning about that applies here unchanged. `issues` carries\n * the per-problem detail a human reader gets as a bullet list, because a\n * refusal that says \"2 problem(s)\" and does not say which two is not\n * machine-readable in any useful sense.\n *\n * On **stdout**, like every other `--json` result: the contract those commands\n * make is that stdout holds one JSON value, and a caller that pipes stdout to a\n * parser must get a parseable refusal rather than an empty stream and a\n * human sentence it never sees. That contract used to hold for exactly one\n * failure of each command — the one that goes through `requireProjectRoot` —\n * while every other exit of the *same* command wrote human text to stderr and\n * left stdout empty. So `rebase status --json` was parseable outside a project\n * and unparseable inside a broken one, which is the case a caller actually has\n * to handle.\n *\n * The flag is read off `process.argv` because the failure happens inside a\n * helper the command calls before it has parsed anything. Coarse — a literal\n * `--json` as some other flag's value would count — and worth it: the failure\n * mode of being coarse is a JSON error where a human one was wanted, and the\n * failure mode of not doing it is an unparseable stream.\n */\nexport function failAsJson(\n message: string,\n code: string,\n hint?: string,\n issues?: JsonFailureIssue[]\n): never {\n const error: Record<string, unknown> = { message, code };\n if (hint !== undefined) error.hint = hint;\n if (issues !== undefined) error.issues = issues;\n console.log(JSON.stringify({ error }, null, 2));\n process.exit(1);\n}\n\n/** Did the command line ask for machine-readable output? */\nexport function wantsJsonOutput(argv: readonly string[] = process.argv): boolean {\n return argv.includes(\"--json\");\n}\n\n/**\n * Require the project root or exit with a helpful error.\n */\nexport function requireProjectRoot(): string {\n const root = findProjectRoot();\n if (!root) {\n if (wantsJsonOutput()) {\n // `rebase status --json` outside a project wrote four grey lines to\n // stderr and nothing at all to stdout, so the agent or CI step that\n // asked for JSON got an empty parse and no reason.\n failAsJson(\n \"Could not find a Rebase project root.\",\n \"no_project_root\",\n `Looked in this directory and every parent for a ${MANIFEST_FILENAME}, `\n + \"a package.json with a \\\"backend\\\" workspace, or a backend/ next to a config/.\"\n );\n }\n // Name what is actually looked for, in the order `findProjectRoot`\n // looks for it. The old wording (\"backend/, frontend/, and config/\")\n // described neither the manifest — which is the primary marker and the\n // only one `rebase init` writes — nor a `--headless` project, which has\n // no frontend at all and would read this as \"you are in the wrong\n // place\" while standing in the right one.\n console.error(chalk.red(\"✗ Could not find a Rebase project root.\"));\n console.error(chalk.gray(` Looked in this directory and every parent for a ${MANIFEST_FILENAME},`));\n console.error(chalk.gray(\" a package.json with a \\\"backend\\\" workspace, or a backend/ next to a config/.\"));\n console.error(chalk.gray(\" Run this from inside a project, or create one with `rebase init`.\"));\n process.exit(1);\n }\n return root;\n}\n\n/**\n * Require the backend directory or exit with a helpful error.\n */\nexport function requireBackendDir(projectRoot: string): string {\n const backendDir = findBackendDir(projectRoot);\n if (!backendDir) {\n if (wantsJsonOutput()) {\n failAsJson(\n \"Could not find a backend/ directory.\",\n \"no_backend_dir\",\n `Expected at: ${path.join(projectRoot, \"backend\")}`\n );\n }\n console.error(chalk.red(\"✗ Could not find a backend/ directory.\"));\n console.error(chalk.gray(` Expected at: ${path.join(projectRoot, \"backend\")}`));\n process.exit(1);\n }\n return backendDir;\n}\n"],"mappings":"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"}