@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.
- package/bin/rebase.js +9 -5
- package/dist/{agent-setup-C83DXnlx.js → agent-setup-BYb2Tbdz.js} +2 -2
- package/dist/{agent-setup-C83DXnlx.js.map → agent-setup-BYb2Tbdz.js.map} +1 -1
- package/dist/{api-keys-Bc4FJKYp.js → api-keys-CSMbsmAn.js} +28 -22
- package/dist/api-keys-CSMbsmAn.js.map +1 -0
- package/dist/{apps-wG-ZTryA.js → apps-iBXNZhVN.js} +6 -7
- package/dist/{apps-wG-ZTryA.js.map → apps-iBXNZhVN.js.map} +1 -1
- package/dist/{atlas-dev-database-DeK3Sa4h.js → atlas-dev-database-BusbHP6n.js} +4 -4
- package/dist/{atlas-dev-database-DeK3Sa4h.js.map → atlas-dev-database-BusbHP6n.js.map} +1 -1
- package/dist/{auth-BL7bNQVu.js → auth-DRsTWPky.js} +77 -11
- package/dist/auth-DRsTWPky.js.map +1 -0
- package/dist/{branch-pointer-DTQNLFtb.js → branch-pointer-Bn_FjNld.js} +1 -1
- package/dist/{build-h_7Re-67.js → build-et7Rccxi.js} +6 -7
- package/dist/{build-h_7Re-67.js.map → build-et7Rccxi.js.map} +1 -1
- package/dist/{bundle-CqURVN-K.js → bundle-DlqkDYSe.js} +6 -21
- package/dist/bundle-DlqkDYSe.js.map +1 -0
- package/dist/{cloud-DVV_5GPG.js → cloud-B-ZIjHrA.js} +10 -11
- package/dist/{cloud-DVV_5GPG.js.map → cloud-B-ZIjHrA.js.map} +1 -1
- package/dist/commands/api-keys.d.ts +4 -1
- package/dist/commands/auth.d.ts +3 -2
- package/dist/commands/dev.d.ts +12 -0
- package/dist/commands/generate_sdk.d.ts +4 -2
- package/dist/commands/init.d.ts +20 -0
- package/dist/commands/start.d.ts +10 -0
- package/dist/commands/upgrade.d.ts +12 -0
- package/dist/connection-banner-DbLJzWf4.js +128 -0
- package/dist/connection-banner-DbLJzWf4.js.map +1 -0
- package/dist/{consent-ClRHmcxf.js → consent-BaB-eQKG.js} +2 -2
- package/dist/{consent-ClRHmcxf.js.map → consent-BaB-eQKG.js.map} +1 -1
- package/dist/{console-Dw3HLdUs.js → console-BlD9kjFW.js} +4 -4
- package/dist/{console-Dw3HLdUs.js.map → console-BlD9kjFW.js.map} +1 -1
- package/dist/{context-BM-oOMNX.js → context-DHiiiJ5C.js} +3 -4
- package/dist/context-DHiiiJ5C.js.map +1 -0
- package/dist/{daemon-CknkDjd6.js → daemon-DDMRbz4T.js} +160 -5
- package/dist/daemon-DDMRbz4T.js.map +1 -0
- package/dist/{daemon-entry-C6pxdily.js → daemon-entry-zOC1revO.js} +204 -5
- package/dist/daemon-entry-zOC1revO.js.map +1 -0
- package/dist/{db-Dkn9XhT-.js → db-9P6MnmdC.js} +237 -86
- package/dist/db-9P6MnmdC.js.map +1 -0
- package/dist/{derive-Dl0z2OWi.js → derive-MTdClnkc.js} +29 -14
- package/dist/{derive-Dl0z2OWi.js.map → derive-MTdClnkc.js.map} +1 -1
- package/dist/{dev-DAcZR4Pp.js → dev-BDN_OKXA.js} +183 -23
- package/dist/dev-BDN_OKXA.js.map +1 -0
- package/dist/dev-db/connection-banner.d.ts +47 -0
- package/dist/dev-db/daemon.d.ts +41 -0
- package/dist/dev-db/notification-proxy.d.ts +82 -1
- package/dist/dev-db/pull.d.ts +33 -5
- package/dist/dev-db/state.d.ts +9 -0
- package/dist/{dev-preflight-CorMg7Ub.js → dev-preflight-FT9GbJVj.js} +73 -4
- package/dist/dev-preflight-FT9GbJVj.js.map +1 -0
- package/dist/{dev-server-B1UYifZJ.js → dev-server-CIZwAfZa.js} +14 -3
- package/dist/dev-server-CIZwAfZa.js.map +1 -0
- package/dist/{doctor-Ds_lzc9p.js → doctor-D8YXz7df.js} +6 -6
- package/dist/doctor-D8YXz7df.js.map +1 -0
- package/dist/{eject-CJHkfnat.js → eject-izG2KjMo.js} +3 -4
- package/dist/{eject-CJHkfnat.js.map → eject-izG2KjMo.js.map} +1 -1
- package/dist/{fold-static-BC9CYicw.js → fold-static-CybSay_W.js} +3 -3
- package/dist/{fold-static-BC9CYicw.js.map → fold-static-CybSay_W.js.map} +1 -1
- package/dist/{generate_sdk-kfkZmG-d.js → generate_sdk-B4R65oUV.js} +22 -12
- package/dist/generate_sdk-B4R65oUV.js.map +1 -0
- package/dist/index.es.js +36 -37
- package/dist/index.es.js.map +1 -1
- package/dist/{init-CjoJoThg.js → init-DYaeppEN.js} +52 -63
- package/dist/init-DYaeppEN.js.map +1 -0
- package/dist/invoked-command-CG_rIa_o.js +55 -0
- package/dist/invoked-command-CG_rIa_o.js.map +1 -0
- package/dist/last-dev-database-B_75fxZC.js +2 -0
- package/dist/{manifest-DRp0UVTj.js → manifest-nvPdLlJY.js} +2 -2
- package/dist/{manifest-DRp0UVTj.js.map → manifest-nvPdLlJY.js.map} +1 -1
- package/dist/{normalize-imports-BHxL2d05.js → normalize-imports-BYw8ad87.js} +3 -3
- package/dist/{normalize-imports-BHxL2d05.js.map → normalize-imports-BYw8ad87.js.map} +1 -1
- package/dist/precompress.d.ts +0 -7
- package/dist/{prepare-C1iaiTC4.js → prepare-1rVNd2PF.js} +7 -6
- package/dist/prepare-1rVNd2PF.js.map +1 -0
- package/dist/project-g4K6kV1t.js +701 -0
- package/dist/project-g4K6kV1t.js.map +1 -0
- package/dist/{pull-COpNJFzY.js → pull-DDMpsZ5r.js} +143 -63
- package/dist/pull-DDMpsZ5r.js.map +1 -0
- package/dist/refusal-ReeeGP8a.js +26 -0
- package/dist/refusal-ReeeGP8a.js.map +1 -0
- package/dist/resolve-BQUAC3Wi.js +2 -0
- package/dist/resources/derive.d.ts +9 -0
- package/dist/{resources-CLm6g0br.js → resources-CovP8AZ-.js} +4 -5
- package/dist/{resources-CLm6g0br.js.map → resources-CovP8AZ-.js.map} +1 -1
- package/dist/{schema-BKdh6UoE.js → schema-nuxvvc50.js} +5 -6
- package/dist/{schema-BKdh6UoE.js.map → schema-nuxvvc50.js.map} +1 -1
- package/dist/{skills-DEhYiPeO.js → skills-DeUIsZcT.js} +3 -4
- package/dist/{skills-DEhYiPeO.js.map → skills-DeUIsZcT.js.map} +1 -1
- package/dist/{start-BsPJedPQ.js → start-RzZqDroW.js} +20 -7
- package/dist/start-RzZqDroW.js.map +1 -0
- package/dist/{state-CCB-FAQ9.js → state-CYdBvnwA.js} +3 -2
- package/dist/state-CYdBvnwA.js.map +1 -0
- package/dist/{status-D_B3tlDy.js → status-D9Zm88NZ.js} +11 -12
- package/dist/{status-D_B3tlDy.js.map → status-D9Zm88NZ.js.map} +1 -1
- package/dist/{storage-CtB8polS.js → storage-BB3umRfw.js} +3 -4
- package/dist/{storage-CtB8polS.js.map → storage-BB3umRfw.js.map} +1 -1
- package/dist/{telemetry-EMFRVRQi.js → telemetry-HfU5uAh1.js} +2 -2
- package/dist/{telemetry-EMFRVRQi.js.map → telemetry-HfU5uAh1.js.map} +1 -1
- package/dist/{telemetry-BYmPU-Ji.js → telemetry-TseNLk6X.js} +4 -4
- package/dist/{telemetry-BYmPU-Ji.js.map → telemetry-TseNLk6X.js.map} +1 -1
- package/dist/{upgrade-DbuKX9lv.js → upgrade-apiPKKE_.js} +29 -6
- package/dist/{upgrade-DbuKX9lv.js.map → upgrade-apiPKKE_.js.map} +1 -1
- package/dist/utils/args.d.ts +45 -3
- package/dist/utils/boot-retry.d.ts +41 -0
- package/dist/utils/dev-preflight.d.ts +34 -1
- package/dist/utils/dev-server.d.ts +11 -0
- package/dist/utils/project.d.ts +5 -1
- package/dist/utils/redact.d.ts +10 -0
- package/dist/utils/refusal.d.ts +18 -0
- package/dist/utils/unknown-command.d.ts +4 -0
- package/package.json +7 -7
- package/templates/overlays/baas/README.md +2 -1
- package/templates/resource-graphs/blank.json +25 -0
- package/templates/resource-graphs/blog.json +28 -0
- package/templates/resource-graphs/ecommerce.json +28 -0
- package/templates/resource-graphs/headless.json +22 -0
- package/templates/template/.env.example +11 -4
- package/templates/template/frontend/src/App.tsx +10 -9
- package/templates/template/frontend/vite.config.ts +7 -73
- package/dist/api-keys-Bc4FJKYp.js.map +0 -1
- package/dist/args-CcBphFdj.js +0 -237
- package/dist/args-CcBphFdj.js.map +0 -1
- package/dist/auth-BL7bNQVu.js.map +0 -1
- package/dist/bundle-CqURVN-K.js.map +0 -1
- package/dist/context-BM-oOMNX.js.map +0 -1
- package/dist/daemon-CknkDjd6.js.map +0 -1
- package/dist/daemon-entry-C6pxdily.js.map +0 -1
- package/dist/db-Dkn9XhT-.js.map +0 -1
- package/dist/dev-DAcZR4Pp.js.map +0 -1
- package/dist/dev-preflight-CorMg7Ub.js.map +0 -1
- package/dist/dev-server-B1UYifZJ.js.map +0 -1
- package/dist/doctor-Ds_lzc9p.js.map +0 -1
- package/dist/generate_sdk-kfkZmG-d.js.map +0 -1
- package/dist/init-CjoJoThg.js.map +0 -1
- package/dist/last-dev-database-BEBPfAMY.js +0 -2
- package/dist/prepare-C1iaiTC4.js.map +0 -1
- package/dist/project-Wp2zoyeN.js +0 -349
- package/dist/project-Wp2zoyeN.js.map +0 -1
- package/dist/pull-COpNJFzY.js.map +0 -1
- package/dist/resolve-b_p9bmdH.js +0 -2
- package/dist/start-BsPJedPQ.js.map +0 -1
- package/dist/state-CCB-FAQ9.js.map +0 -1
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { i as failAsJson, p as requireProjectRoot } from "./project-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { a as projectResourceGraph, l as writeResourceGraphFile, n as deriveOptionsFor, o as readResourceGraphFile, r as deriveResourceGraph, s as serializeResourceGraph, t as RESOURCE_GRAPH_FILENAME } from "./derive-Dl0z2OWi.js";
|
|
1
|
+
import { C as wantsHelp, b as parseCommandArgs, i as failAsJson, p as requireProjectRoot } from "./project-g4K6kV1t.js";
|
|
2
|
+
import { d as findBackendApp, o as ManifestError, p as loadManifest } from "./manifest-nvPdLlJY.js";
|
|
3
|
+
import { a as projectResourceGraph, l as writeResourceGraphFile, n as deriveOptionsFor, o as readResourceGraphFile, r as deriveResourceGraph, s as serializeResourceGraph, t as RESOURCE_GRAPH_FILENAME } from "./derive-MTdClnkc.js";
|
|
5
4
|
import chalk from "chalk";
|
|
6
5
|
import path from "path";
|
|
7
6
|
import { declaredSubscriptions } from "@rebasepro/types";
|
|
@@ -180,4 +179,4 @@ async function resourcesCommand(rawArgs) {
|
|
|
180
179
|
//#endregion
|
|
181
180
|
export { resourcesCommand };
|
|
182
181
|
|
|
183
|
-
//# sourceMappingURL=resources-
|
|
182
|
+
//# sourceMappingURL=resources-CovP8AZ-.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resources-CLm6g0br.js","names":[],"sources":["../src/commands/resources.ts"],"sourcesContent":["/**\n * CLI command: rebase resources\n *\n * Shows what a project declares, and keeps the committed graph honest.\n *\n * The graph is generated, so it can drift the moment somebody adds a bucket and\n * does not regenerate. Drift here is not cosmetic: the committed file is what a\n * host reads to decide what to provision, so a stale one means the console\n * offers a project one set of resources while the runtime asks for another.\n * `--check` is the gate that makes that impossible to land.\n */\nimport chalk from \"chalk\";\nimport path from \"path\";\nimport { failAsJson, requireProjectRoot } from \"../utils/project\";\nimport { findBackendApp, loadManifest, ManifestError } from \"../manifest\";\nimport { parseCommandArgs, wantsHelp } from \"../utils/args\";\nimport {\n RESOURCE_GRAPH_FILENAME,\n deriveOptionsFor, deriveResourceGraph,\n projectResourceGraph,\n readResourceGraphFile,\n serializeResourceGraph,\n writeResourceGraphFile,\n type ProjectedResource\n} from \"../resources/derive\";\nimport { declaredSubscriptions, type RebaseBackendAppConfig } from \"@rebasepro/types\";\n\nfunction usage(): void {\n console.log(`\n${chalk.bold(\"rebase resources\")} — what this project needs\n\n ${chalk.blue(\"rebase resources\")} List them, declared and implicit\n ${chalk.blue(\"rebase resources --write\")} Regenerate ${RESOURCE_GRAPH_FILENAME}\n ${chalk.blue(\"rebase resources --check\")} Fail if the committed graph is stale\n ${chalk.blue(\"rebase resources --json\")} The same set, machine-readable; with --check or --write,\n their result too (a failed check is an error envelope, exit 1)\n\nA resource is declared in config code — ${chalk.gray('database(\"analytics\"), bucket(\"media\"), topic(\"signups\")')} —\nand never in ${RESOURCE_GRAPH_FILENAME}, which is generated from those declarations so a host\ncan read what a project needs without building it. A backend also has a default\ndatabase and a default storage source nobody declared; both are listed here,\nmarked ${chalk.gray(\"implicit\")}, and neither is written to that file — the host supplies them.\n`);\n}\n\n/**\n * Render the projection the way somebody reads it: grouped by kind, key first.\n *\n * The projection, not the raw graph. `rebase status` has always included the\n * implicit default database and bucket and this listing did not, so the two\n * commands answered \"what does this project need\" differently on the same stock\n * scaffold. There is no \"no resources declared\" case any more: a backend has a\n * database and a storage source whether or not anyone wrote them down.\n */\nfunction print(resources: ProjectedResource[]): void {\n // Infrastructure first, then code: what needs binding is what a reader\n // is here to check.\n const order = [\"database\", \"bucket\", \"topic\", \"queue\", \"cron\", \"function\"];\n const kinds = [...new Set(resources.map(r => r.kind))]\n .sort((a, b) => (order.indexOf(a) === -1 ? 99 : order.indexOf(a)) - (order.indexOf(b) === -1 ? 99 : order.indexOf(b)));\n for (const kind of kinds) {\n console.log(`\\n ${chalk.bold(kind)}`);\n for (const r of resources.filter(x => x.kind === kind)) {\n const bits: string[] = [];\n if (kind === \"cron\") {\n bits.push(chalk.cyan(String(r.options.schedule)));\n bits.push(chalk.gray(r.options.timezone ? String(r.options.timezone) : \"local time\"));\n } else if (kind === \"function\") {\n bits.push(chalk.gray(String(r.options.file ?? \"\")));\n if (r.options.portable === false) bits.push(chalk.yellow(\"node-only\"));\n } else {\n bits.push(chalk.gray(r.engine));\n if (r.transport !== \"server\") bits.push(chalk.yellow(r.transport));\n for (const [k, v] of Object.entries(r.options)) bits.push(chalk.gray(`${k}=${String(v)}`));\n }\n // Marked, not hidden: a declared resource is recorded in\n // `rebase.resources.json` for a host to provision, and an implicit\n // one is a default the runtime supplies regardless.\n if (r.implicit) bits.push(chalk.gray(\"implicit\"));\n console.log(` ${r.key.padEnd(24)} ${bits.join(\" · \")}`);\n if (kind === \"topic\") {\n for (const sub of declaredSubscriptions(r.key)) {\n console.log(` ${chalk.gray(\"→\")} ${sub.name}`);\n }\n }\n if (r.usedBy && r.usedBy.length > 0) {\n console.log(` ${chalk.gray(\"used by\")} ${chalk.gray(r.usedBy.join(\", \"))}`);\n }\n }\n }\n console.log(\"\");\n}\n\nexport async function resourcesCommand(rawArgs: string[]): Promise<void> {\n if (wantsHelp(rawArgs)) return usage();\n\n const { flags } = parseCommandArgs({\n spec: {\n \"--write\": Boolean,\n \"--check\": Boolean,\n \"--json\": Boolean\n },\n rawArgs,\n commandWords: 1,\n command: \"resources\",\n maxPositionals: 0\n });\n\n const projectRoot = requireProjectRoot();\n\n // Every exit below has a `--json` arm, for the reason in `failAsJson`:\n // `--json` is a promise about stdout, and a promise kept on one exit of a\n // command and broken on the next is not one.\n const asJson = Boolean(flags[\"--json\"]);\n\n let backendApp: RebaseBackendAppConfig;\n try {\n const loaded = loadManifest(projectRoot);\n const backend = findBackendApp(loaded.manifest);\n if (!backend) {\n if (asJson) {\n failAsJson(\n \"This project declares no backend app, so it declares no resources.\",\n \"no_backend_app\",\n \"Add a backend app to rebase.json, or run `rebase apps init`.\"\n );\n }\n console.error(chalk.red(\"This project declares no backend app, so it declares no resources.\"));\n process.exitCode = 1;\n return;\n }\n backendApp = backend.app;\n } catch (err) {\n if (err instanceof ManifestError) {\n if (asJson) {\n failAsJson(err.message, \"manifest_invalid\", \"Fix rebase.json, then run this again.\",\n err.issues.map(issue => ({ path: issue.path, message: issue.message })));\n }\n console.error(chalk.red(err.message));\n for (const issue of err.issues) console.error(` ${chalk.gray(issue.path)} ${issue.message}`);\n process.exitCode = 1;\n return;\n }\n throw err;\n }\n\n const { graph, issues } = await deriveResourceGraph(deriveOptionsFor(projectRoot, backendApp));\n\n if (issues.length > 0) {\n if (asJson) {\n failAsJson(\n `${issues.length} problem(s) in the declared resources.`,\n \"resource_declaration_invalid\",\n \"Fix the declarations the issues name, then run this again.\",\n issues.map(issue => ({ path: issue.path, message: issue.message }))\n );\n }\n console.error(chalk.red(`\\n✗ ${issues.length} problem(s) in the declared resources:\\n`));\n for (const issue of issues) console.error(` ${chalk.bold(issue.path)} ${issue.message}`);\n console.error(\"\");\n process.exitCode = 1;\n return;\n }\n\n // The projection, so this and `rebase status --json` describe the same\n // set. `version` is kept so a reader of either can tell them apart from a\n // future shape. `--check` and `--write` add what they did to it: `--json`\n // changes how the answer is printed, never which question is answered — it\n // used to return here, so `--check --json` exited 0 on any drift and\n // `--write --json` wrote nothing.\n const projection = () => ({ version: graph.version, resources: projectResourceGraph(graph) });\n\n if (flags[\"--check\"]) {\n const committed = readResourceGraphFile(projectRoot);\n const expected = serializeResourceGraph(graph);\n // Declaring nothing and having no file is a consistent state, not a\n // stale one. The file records declarations; a project with none has\n // nothing to record, and its default database and bucket are implicit\n // by design — that is the overwhelmingly common project and it must not\n // be required to commit an empty file saying so.\n //\n // This mattered the moment the check was put in a gate: it would have\n // failed this repository's own reference app, which declares nothing,\n // and every scaffolded project until someone declared a second bucket.\n const status = committed === expected\n ? \"current\"\n : committed === null && graph.resources.length === 0 ? \"nothing-declared\" : null;\n\n if (status !== null) {\n if (asJson) {\n console.log(JSON.stringify({ ...projection(), check: { file: RESOURCE_GRAPH_FILENAME, status } }, null, 2));\n return;\n }\n console.log(status === \"current\"\n ? chalk.green(`✓ ${RESOURCE_GRAPH_FILENAME} matches the declarations.`)\n : chalk.gray(\"✓ Nothing declared, so there is nothing to record.\"));\n return;\n }\n\n const state = committed === null ? \"missing\" : \"stale\";\n if (asJson) {\n failAsJson(\n `${RESOURCE_GRAPH_FILENAME} is ${state}.`,\n `resource_graph_${state}`,\n \"Regenerate it with `rebase resources --write`, and commit it.\"\n );\n }\n console.error(chalk.red(`\\n✗ ${RESOURCE_GRAPH_FILENAME} is ${state}.\\n`));\n console.error(\n \" A host reads this file to decide what to provision, so a stale one means the\\n\" +\n \" console offers one set of resources while the runtime asks for another.\\n\"\n );\n console.error(` Regenerate it: ${chalk.blue(\"rebase resources --write\")}\\n`);\n process.exitCode = 1;\n return;\n }\n\n if (flags[\"--write\"]) {\n const { changed, file } = writeResourceGraphFile(projectRoot, graph);\n const relative = path.relative(projectRoot, file);\n if (asJson) {\n console.log(JSON.stringify({ ...projection(), written: { file: relative, changed } }, null, 2));\n return;\n }\n console.log(changed\n ? chalk.green(`✓ Wrote ${relative}`)\n : chalk.gray(`${relative} already matched the declarations.`));\n return;\n }\n\n if (asJson) {\n console.log(JSON.stringify(projection(), null, 2));\n return;\n }\n\n print(projectResourceGraph(graph));\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"resources-CovP8AZ-.js","names":[],"sources":["../src/commands/resources.ts"],"sourcesContent":["/**\n * CLI command: rebase resources\n *\n * Shows what a project declares, and keeps the committed graph honest.\n *\n * The graph is generated, so it can drift the moment somebody adds a bucket and\n * does not regenerate. Drift here is not cosmetic: the committed file is what a\n * host reads to decide what to provision, so a stale one means the console\n * offers a project one set of resources while the runtime asks for another.\n * `--check` is the gate that makes that impossible to land.\n */\nimport chalk from \"chalk\";\nimport path from \"path\";\nimport { failAsJson, requireProjectRoot } from \"../utils/project\";\nimport { findBackendApp, loadManifest, ManifestError } from \"../manifest\";\nimport { parseCommandArgs, wantsHelp } from \"../utils/args\";\nimport {\n RESOURCE_GRAPH_FILENAME,\n deriveOptionsFor, deriveResourceGraph,\n projectResourceGraph,\n readResourceGraphFile,\n serializeResourceGraph,\n writeResourceGraphFile,\n type ProjectedResource\n} from \"../resources/derive\";\nimport { declaredSubscriptions, type RebaseBackendAppConfig } from \"@rebasepro/types\";\n\nfunction usage(): void {\n console.log(`\n${chalk.bold(\"rebase resources\")} — what this project needs\n\n ${chalk.blue(\"rebase resources\")} List them, declared and implicit\n ${chalk.blue(\"rebase resources --write\")} Regenerate ${RESOURCE_GRAPH_FILENAME}\n ${chalk.blue(\"rebase resources --check\")} Fail if the committed graph is stale\n ${chalk.blue(\"rebase resources --json\")} The same set, machine-readable; with --check or --write,\n their result too (a failed check is an error envelope, exit 1)\n\nA resource is declared in config code — ${chalk.gray('database(\"analytics\"), bucket(\"media\"), topic(\"signups\")')} —\nand never in ${RESOURCE_GRAPH_FILENAME}, which is generated from those declarations so a host\ncan read what a project needs without building it. A backend also has a default\ndatabase and a default storage source nobody declared; both are listed here,\nmarked ${chalk.gray(\"implicit\")}, and neither is written to that file — the host supplies them.\n`);\n}\n\n/**\n * Render the projection the way somebody reads it: grouped by kind, key first.\n *\n * The projection, not the raw graph. `rebase status` has always included the\n * implicit default database and bucket and this listing did not, so the two\n * commands answered \"what does this project need\" differently on the same stock\n * scaffold. There is no \"no resources declared\" case any more: a backend has a\n * database and a storage source whether or not anyone wrote them down.\n */\nfunction print(resources: ProjectedResource[]): void {\n // Infrastructure first, then code: what needs binding is what a reader\n // is here to check.\n const order = [\"database\", \"bucket\", \"topic\", \"queue\", \"cron\", \"function\"];\n const kinds = [...new Set(resources.map(r => r.kind))]\n .sort((a, b) => (order.indexOf(a) === -1 ? 99 : order.indexOf(a)) - (order.indexOf(b) === -1 ? 99 : order.indexOf(b)));\n for (const kind of kinds) {\n console.log(`\\n ${chalk.bold(kind)}`);\n for (const r of resources.filter(x => x.kind === kind)) {\n const bits: string[] = [];\n if (kind === \"cron\") {\n bits.push(chalk.cyan(String(r.options.schedule)));\n bits.push(chalk.gray(r.options.timezone ? String(r.options.timezone) : \"local time\"));\n } else if (kind === \"function\") {\n bits.push(chalk.gray(String(r.options.file ?? \"\")));\n if (r.options.portable === false) bits.push(chalk.yellow(\"node-only\"));\n } else {\n bits.push(chalk.gray(r.engine));\n if (r.transport !== \"server\") bits.push(chalk.yellow(r.transport));\n for (const [k, v] of Object.entries(r.options)) bits.push(chalk.gray(`${k}=${String(v)}`));\n }\n // Marked, not hidden: a declared resource is recorded in\n // `rebase.resources.json` for a host to provision, and an implicit\n // one is a default the runtime supplies regardless.\n if (r.implicit) bits.push(chalk.gray(\"implicit\"));\n console.log(` ${r.key.padEnd(24)} ${bits.join(\" · \")}`);\n if (kind === \"topic\") {\n for (const sub of declaredSubscriptions(r.key)) {\n console.log(` ${chalk.gray(\"→\")} ${sub.name}`);\n }\n }\n if (r.usedBy && r.usedBy.length > 0) {\n console.log(` ${chalk.gray(\"used by\")} ${chalk.gray(r.usedBy.join(\", \"))}`);\n }\n }\n }\n console.log(\"\");\n}\n\nexport async function resourcesCommand(rawArgs: string[]): Promise<void> {\n if (wantsHelp(rawArgs)) return usage();\n\n const { flags } = parseCommandArgs({\n spec: {\n \"--write\": Boolean,\n \"--check\": Boolean,\n \"--json\": Boolean\n },\n rawArgs,\n commandWords: 1,\n command: \"resources\",\n maxPositionals: 0\n });\n\n const projectRoot = requireProjectRoot();\n\n // Every exit below has a `--json` arm, for the reason in `failAsJson`:\n // `--json` is a promise about stdout, and a promise kept on one exit of a\n // command and broken on the next is not one.\n const asJson = Boolean(flags[\"--json\"]);\n\n let backendApp: RebaseBackendAppConfig;\n try {\n const loaded = loadManifest(projectRoot);\n const backend = findBackendApp(loaded.manifest);\n if (!backend) {\n if (asJson) {\n failAsJson(\n \"This project declares no backend app, so it declares no resources.\",\n \"no_backend_app\",\n \"Add a backend app to rebase.json, or run `rebase apps init`.\"\n );\n }\n console.error(chalk.red(\"This project declares no backend app, so it declares no resources.\"));\n process.exitCode = 1;\n return;\n }\n backendApp = backend.app;\n } catch (err) {\n if (err instanceof ManifestError) {\n if (asJson) {\n failAsJson(err.message, \"manifest_invalid\", \"Fix rebase.json, then run this again.\",\n err.issues.map(issue => ({ path: issue.path, message: issue.message })));\n }\n console.error(chalk.red(err.message));\n for (const issue of err.issues) console.error(` ${chalk.gray(issue.path)} ${issue.message}`);\n process.exitCode = 1;\n return;\n }\n throw err;\n }\n\n const { graph, issues } = await deriveResourceGraph(deriveOptionsFor(projectRoot, backendApp));\n\n if (issues.length > 0) {\n if (asJson) {\n failAsJson(\n `${issues.length} problem(s) in the declared resources.`,\n \"resource_declaration_invalid\",\n \"Fix the declarations the issues name, then run this again.\",\n issues.map(issue => ({ path: issue.path, message: issue.message }))\n );\n }\n console.error(chalk.red(`\\n✗ ${issues.length} problem(s) in the declared resources:\\n`));\n for (const issue of issues) console.error(` ${chalk.bold(issue.path)} ${issue.message}`);\n console.error(\"\");\n process.exitCode = 1;\n return;\n }\n\n // The projection, so this and `rebase status --json` describe the same\n // set. `version` is kept so a reader of either can tell them apart from a\n // future shape. `--check` and `--write` add what they did to it: `--json`\n // changes how the answer is printed, never which question is answered — it\n // used to return here, so `--check --json` exited 0 on any drift and\n // `--write --json` wrote nothing.\n const projection = () => ({ version: graph.version, resources: projectResourceGraph(graph) });\n\n if (flags[\"--check\"]) {\n const committed = readResourceGraphFile(projectRoot);\n const expected = serializeResourceGraph(graph);\n // Declaring nothing and having no file is a consistent state, not a\n // stale one. The file records declarations; a project with none has\n // nothing to record, and its default database and bucket are implicit\n // by design — that is the overwhelmingly common project and it must not\n // be required to commit an empty file saying so.\n //\n // This mattered the moment the check was put in a gate: it would have\n // failed this repository's own reference app, which declares nothing,\n // and every scaffolded project until someone declared a second bucket.\n const status = committed === expected\n ? \"current\"\n : committed === null && graph.resources.length === 0 ? \"nothing-declared\" : null;\n\n if (status !== null) {\n if (asJson) {\n console.log(JSON.stringify({ ...projection(), check: { file: RESOURCE_GRAPH_FILENAME, status } }, null, 2));\n return;\n }\n console.log(status === \"current\"\n ? chalk.green(`✓ ${RESOURCE_GRAPH_FILENAME} matches the declarations.`)\n : chalk.gray(\"✓ Nothing declared, so there is nothing to record.\"));\n return;\n }\n\n const state = committed === null ? \"missing\" : \"stale\";\n if (asJson) {\n failAsJson(\n `${RESOURCE_GRAPH_FILENAME} is ${state}.`,\n `resource_graph_${state}`,\n \"Regenerate it with `rebase resources --write`, and commit it.\"\n );\n }\n console.error(chalk.red(`\\n✗ ${RESOURCE_GRAPH_FILENAME} is ${state}.\\n`));\n console.error(\n \" A host reads this file to decide what to provision, so a stale one means the\\n\" +\n \" console offers one set of resources while the runtime asks for another.\\n\"\n );\n console.error(` Regenerate it: ${chalk.blue(\"rebase resources --write\")}\\n`);\n process.exitCode = 1;\n return;\n }\n\n if (flags[\"--write\"]) {\n const { changed, file } = writeResourceGraphFile(projectRoot, graph);\n const relative = path.relative(projectRoot, file);\n if (asJson) {\n console.log(JSON.stringify({ ...projection(), written: { file: relative, changed } }, null, 2));\n return;\n }\n console.log(changed\n ? chalk.green(`✓ Wrote ${relative}`)\n : chalk.gray(`${relative} already matched the declarations.`));\n return;\n }\n\n if (asJson) {\n console.log(JSON.stringify(projection(), null, 2));\n return;\n }\n\n print(projectResourceGraph(graph));\n}\n"],"mappings":"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"}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { i as recordEvent } from "./telemetry-
|
|
2
|
-
import { f as requireBackendDir, h as resolvePluginCliScript, l as getActiveBackendPlugin, o as findEnvFile, p as requireProjectRoot, r as exitDependenciesNotInstalled } from "./project-
|
|
3
|
-
import { a as unknownCommand, r as wantsHelp } from "./args-CcBphFdj.js";
|
|
1
|
+
import { i as recordEvent } from "./telemetry-HfU5uAh1.js";
|
|
2
|
+
import { C as wantsHelp, T as unknownCommand, f as requireBackendDir, h as resolvePluginCliScript, l as getActiveBackendPlugin, o as findEnvFile, p as requireProjectRoot, r as exitDependenciesNotInstalled } from "./project-g4K6kV1t.js";
|
|
4
3
|
import { r as refuseMissingCollectionsPath, t as COLLECTIONS_FLAG_HELP } from "./path-flags-BFgG9V6y.js";
|
|
5
|
-
import { DEV_DATABASE_KIND_ENV, devDatabaseKind, managedNotices, prepareDatabaseEnv } from "./prepare-
|
|
6
|
-
import { absolutizeLocalPathArgs, ensureDockerDatabase, n as argsFromCommand, spawnDriverCli, t as reportSpawnFailure } from "./db-
|
|
4
|
+
import { DEV_DATABASE_KIND_ENV, devDatabaseKind, managedNotices, prepareDatabaseEnv } from "./prepare-1rVNd2PF.js";
|
|
5
|
+
import { absolutizeLocalPathArgs, ensureDockerDatabase, n as argsFromCommand, spawnDriverCli, t as reportSpawnFailure } from "./db-9P6MnmdC.js";
|
|
7
6
|
import chalk from "chalk";
|
|
8
7
|
import arg from "arg";
|
|
9
8
|
//#region src/commands/schema.ts
|
|
@@ -148,4 +147,4 @@ ${chalk.green.bold("stale Options")}
|
|
|
148
147
|
//#endregion
|
|
149
148
|
export { SCHEMA_SUBCOMMANDS, schemaCommand };
|
|
150
149
|
|
|
151
|
-
//# sourceMappingURL=schema-
|
|
150
|
+
//# sourceMappingURL=schema-nuxvvc50.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema-BKdh6UoE.js","names":[],"sources":["../src/commands/schema.ts"],"sourcesContent":["/**\n * CLI command: rebase schema <action>\n */\nimport arg from \"arg\";\nimport chalk from \"chalk\";\nimport { ensureDockerDatabase, spawnDriverCli } from \"./db\";\nimport {\n requireProjectRoot,\n requireBackendDir,\n getActiveBackendPlugin,\n resolvePluginCliScript,\n resolveTsx,\n findEnvFile,\n exitDependenciesNotInstalled\n} from \"../utils/project\";\nimport { recordEvent } from \"../telemetry\";\nimport { wantsHelp } from \"../utils/args\";\nimport { reportSpawnFailure } from \"../utils/spawn-error\";\nimport { argsFromCommand } from \"../utils/command-words\";\nimport { unknownCommand } from \"../utils/unknown-command\";\nimport { DEV_DATABASE_KIND_ENV, devDatabaseKind, managedNotices, prepareDatabaseEnv } from \"../dev-db/prepare\";\nimport { absolutizeLocalPathArgs } from \"./db\";\nimport { COLLECTIONS_FLAG_HELP, refuseMissingCollectionsPath } from \"../utils/path-flags\";\n\n/**\n * The line handed to the driver, its paths resolved from where the command was\n * run (the driver runs in `backend/`). `--schema` is left alone: on\n * `introspect` it names a Postgres schema, not a file.\n */\nexport function schemaDriverArgs(rawArgs: string[], cwd: string): string[] {\n return absolutizeLocalPathArgs(argsFromCommand(rawArgs, \"schema\"), cwd, [\"--collections\", \"-c\", \"--output\", \"-o\", \"--out\"]);\n}\n\nexport async function schemaCommand(subcommand: string | undefined, rawArgs: string[]): Promise<void> {\n // `--help` is answered here, before `requireProjectRoot` and before the\n // driver is spawned — the same shape `db.ts` already uses, and for the same\n // reason.\n //\n // `cli.ts` rewrites the subcommand to `\"--help\"` only when the user named\n // none, so `rebase schema --help` was covered and `rebase schema generate\n // --help` was not: the flag travelled into `rawArgs.slice(2)` and reached\n // the driver, whose own `schemaCommand` has no `--help` case. It *ran the\n // generator* — overwriting `src/schema.generated.ts` — for a flag whose\n // entire job is to print text. Worse, the first thing it hit outside a\n // project was `requireProjectRoot`, so `rebase schema introspect --help` in\n // an empty directory exited 1 with \"Could not find a Rebase project root\":\n // help you cannot read until you already have a project is help for nobody.\n if (!subcommand || subcommand === \"--help\" || wantsHelp(rawArgs)) {\n printSchemaHelp(subcommand === \"--help\" ? undefined : subcommand);\n return;\n }\n\n // A typo is answered here, in the same words every other family uses.\n //\n // It used to travel to the driver, which said the bare line `Unknown schema\n // command.` — no list, no pointer, no did-you-mean, for a family with three\n // subcommands. The set comes from the help table, so what a typo is measured\n // against and what `--help` prints cannot drift apart.\n if (!SCHEMA_ACTION_HELP[subcommand]) {\n unknownCommand(subcommand, Object.keys(SCHEMA_ACTION_HELP), \"schema\");\n }\n\n const projectRoot = requireProjectRoot();\n\n // Fire-and-forget, and a no-op unless the developer opted in. Never awaited:\n // the command is what the user is waiting for, and a slow collector must not\n // sit in front of it.\n void recordEvent(\"cli.schema\", { subcommand: subcommand ?? \"none\" }, { projectRoot });\n const backendDir = requireBackendDir(projectRoot);\n\n const activePlugin = getActiveBackendPlugin(backendDir);\n if (!activePlugin) {\n console.error(chalk.red(\"✗ Could not detect an active database plugin.\"));\n console.error(chalk.gray(\" Make sure a package like @rebasepro/server-postgres is installed in backend/package.json.\"));\n process.exit(1);\n }\n\n const pluginCli = resolvePluginCliScript(backendDir, activePlugin);\n if (!pluginCli) {\n exitDependenciesNotInstalled(projectRoot);\n }\n\n // Set up environment with DOTENV_CONFIG_PATH\n const envFile = findEnvFile(projectRoot);\n const env: Record<string, string> = { ...process.env as Record<string, string> };\n if (envFile) {\n env.DOTENV_CONFIG_PATH = envFile;\n }\n // Which database this project is on, so the driver's closing line does not\n // recommend a command that database refuses. A pure decision — nothing is\n // started, which matters here above all: `schema generate` reads collection\n // files and writes one file, and booting a database to run it would be a\n // side effect nobody asked for.\n env[DEV_DATABASE_KIND_ENV] = devDatabaseKind(projectRoot) ?? \"\";\n\n refuseMissingCollectionsPath(rawArgs, process.cwd(), backendDir);\n\n // `introspect` is the one schema command that reads a database, and it\n // reads the project's — resolved the way every `db` command resolves it,\n // started if that is what it takes. It used to pass `.env` and nothing\n // else, so on the managed database or after `rebase dev --docker` (with\n // the scaffold's DATABASE_URL commented out, on purpose) it said\n // \"DATABASE_URL is not set\", and `--docker` and `--database-url` passed the\n // flag check only to be ignored.\n if (subcommand === \"introspect\") {\n const flags = arg(\n { \"--database-url\": String, \"--docker\": Boolean },\n { argv: rawArgs.slice(2), permissive: true }\n );\n await ensureDockerDatabase(projectRoot, rawArgs);\n const prepared = await prepareDatabaseEnv(projectRoot, {\n flagUrl: flags[\"--database-url\"] ?? null,\n flagDocker: flags[\"--docker\"] === true,\n onProgress: (message) => console.log(chalk.gray(` ${message}`))\n });\n Object.assign(env, prepared.env);\n env[DEV_DATABASE_KIND_ENV] = prepared.database.kind;\n for (const line of managedNotices(prepared)) console.log(chalk.gray(` ${line}`));\n }\n\n try {\n // The one spawn, shared with `db`. This file used to carry its own copy\n // of the tsx-or-node decision; three copies of that rule existed and two\n // were fixed while the third went on spawning plain node.\n await spawnDriverCli(\n { projectRoot, backendDir, pluginCli, env },\n schemaDriverArgs(rawArgs, process.cwd())\n );\n } catch (error) {\n // A child that ran and exited non-zero already printed its diagnostics\n // through inherited stdio; a child that never started (ENOENT on tsx,\n // EACCES on the script) printed nothing at all, and this used to exit 1\n // in silence.\n reportSpawnFailure(error);\n process.exit(1);\n }\n}\n\n/** One page per subcommand, so `rebase schema <action> --help` says something. */\nconst SCHEMA_ACTION_HELP: Record<string, { usage: string; summary: string; notes?: string[] }> = {\n generate: {\n usage: \"rebase schema generate [--collections <dir>] [--output <file>] [--watch]\",\n summary: \"Generate the Drizzle schema from the collection definitions.\",\n notes: [\"--watch regenerates on every change to a collection file.\"]\n },\n introspect: {\n usage: \"rebase schema introspect [--collections <dir>] [--output <dir>] [--schema <name>] [--force] [--data-inference | --no-data-inference]\",\n summary: \"Read an existing database and write Rebase collection definitions from it.\",\n notes: [\n \"--force overwrites collection files that are already there.\",\n \"--data-inference samples up to 100 rows per table to detect formats, constraints and UI settings; \"\n + \"--no-data-inference reads the structure only. Without either it asks, and without a terminal \"\n + \"it reads the structure only.\",\n \"Reads this project's database, the one `rebase db url` prints: --database-url <url> names another; \"\n + \"--docker uses the compose one, starting it if needed.\"\n ]\n },\n stale: {\n usage: \"rebase schema stale [--collections <dir>] [--output <file>] [--fix]\",\n summary: \"Report generated schema files that no longer match the collections.\",\n notes: [\"--fix regenerates them instead of only reporting.\"]\n }\n};\n\n/** Every subcommand the family dispatches — the help table's keys. */\nexport const SCHEMA_SUBCOMMANDS = Object.keys(SCHEMA_ACTION_HELP);\n\nfunction printSchemaHelp(action?: string) {\n const entry = action ? SCHEMA_ACTION_HELP[action] : undefined;\n if (entry) {\n console.log(`\n${chalk.bold(`rebase schema ${action}`)}\n\n ${entry.summary}\n\n${chalk.green.bold(\"Usage\")}\n ${chalk.blue(entry.usage)}\n${entry.notes?.length ? `\\n${chalk.green.bold(\"Notes\")}\\n${entry.notes.map(n => ` ${chalk.gray(`• ${n}`)}`).join(\"\\n\")}\\n` : \"\"}\n${chalk.gray(\"Run `rebase schema --help` for every subcommand.\")}\n`);\n return;\n }\n\n console.log(`\n${chalk.bold(\"rebase schema\")} — Schema management commands\n\n${chalk.green.bold(\"Usage\")}\n rebase schema ${chalk.blue(\"<command>\")} [options]\n\n${chalk.green.bold(\"Commands\")}\n ${chalk.gray(\"(Commands are provided by your active database driver plugin)\")}\n ${chalk.blue.bold(\"generate\")} Generate Schema from collection definitions\n ${chalk.blue.bold(\"introspect\")} Introspect an existing database to generate collection definitions\n ${chalk.blue.bold(\"stale\")} Report generated schema files that no longer match the collections\n\n${chalk.green.bold(\"generate Options\")}\n ${chalk.blue(\"--collections, -c\")} ${COLLECTIONS_FLAG_HELP}\n ${chalk.blue(\"--output, -o\")} Output path for generated schema\n ${chalk.blue(\"--watch, -w\")} Watch for changes and regenerate automatically\n\n${chalk.green.bold(\"introspect Options\")}\n ${chalk.blue(\"--output, -o\")} Output directory for generated collection files\n ${chalk.blue(\"--schema\")} Postgres schema to read (default: public)\n ${chalk.blue(\"--force, -f\")} Overwrite collection files that already exist\n ${chalk.blue(\"--database-url\")} Read this database instead of the project's own\n ${chalk.blue(\"--docker\")} Read the compose database, starting it if needed\n ${chalk.blue(\"--data-inference\")} Sample rows to detect formats and constraints ${chalk.gray(\"(asked when omitted)\")}\n ${chalk.blue(\"--no-data-inference\")} Read the structure only, without asking\n\n${chalk.green.bold(\"stale Options\")}\n ${chalk.blue(\"--fix\")} Regenerate the stale files instead of only reporting them\n`);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"schema-nuxvvc50.js","names":[],"sources":["../src/commands/schema.ts"],"sourcesContent":["/**\n * CLI command: rebase schema <action>\n */\nimport arg from \"arg\";\nimport chalk from \"chalk\";\nimport { ensureDockerDatabase, spawnDriverCli } from \"./db\";\nimport {\n requireProjectRoot,\n requireBackendDir,\n getActiveBackendPlugin,\n resolvePluginCliScript,\n resolveTsx,\n findEnvFile,\n exitDependenciesNotInstalled\n} from \"../utils/project\";\nimport { recordEvent } from \"../telemetry\";\nimport { wantsHelp } from \"../utils/args\";\nimport { reportSpawnFailure } from \"../utils/spawn-error\";\nimport { argsFromCommand } from \"../utils/command-words\";\nimport { unknownCommand } from \"../utils/unknown-command\";\nimport { DEV_DATABASE_KIND_ENV, devDatabaseKind, managedNotices, prepareDatabaseEnv } from \"../dev-db/prepare\";\nimport { absolutizeLocalPathArgs } from \"./db\";\nimport { COLLECTIONS_FLAG_HELP, refuseMissingCollectionsPath } from \"../utils/path-flags\";\n\n/**\n * The line handed to the driver, its paths resolved from where the command was\n * run (the driver runs in `backend/`). `--schema` is left alone: on\n * `introspect` it names a Postgres schema, not a file.\n */\nexport function schemaDriverArgs(rawArgs: string[], cwd: string): string[] {\n return absolutizeLocalPathArgs(argsFromCommand(rawArgs, \"schema\"), cwd, [\"--collections\", \"-c\", \"--output\", \"-o\", \"--out\"]);\n}\n\nexport async function schemaCommand(subcommand: string | undefined, rawArgs: string[]): Promise<void> {\n // `--help` is answered here, before `requireProjectRoot` and before the\n // driver is spawned — the same shape `db.ts` already uses, and for the same\n // reason.\n //\n // `cli.ts` rewrites the subcommand to `\"--help\"` only when the user named\n // none, so `rebase schema --help` was covered and `rebase schema generate\n // --help` was not: the flag travelled into `rawArgs.slice(2)` and reached\n // the driver, whose own `schemaCommand` has no `--help` case. It *ran the\n // generator* — overwriting `src/schema.generated.ts` — for a flag whose\n // entire job is to print text. Worse, the first thing it hit outside a\n // project was `requireProjectRoot`, so `rebase schema introspect --help` in\n // an empty directory exited 1 with \"Could not find a Rebase project root\":\n // help you cannot read until you already have a project is help for nobody.\n if (!subcommand || subcommand === \"--help\" || wantsHelp(rawArgs)) {\n printSchemaHelp(subcommand === \"--help\" ? undefined : subcommand);\n return;\n }\n\n // A typo is answered here, in the same words every other family uses.\n //\n // It used to travel to the driver, which said the bare line `Unknown schema\n // command.` — no list, no pointer, no did-you-mean, for a family with three\n // subcommands. The set comes from the help table, so what a typo is measured\n // against and what `--help` prints cannot drift apart.\n if (!SCHEMA_ACTION_HELP[subcommand]) {\n unknownCommand(subcommand, Object.keys(SCHEMA_ACTION_HELP), \"schema\");\n }\n\n const projectRoot = requireProjectRoot();\n\n // Fire-and-forget, and a no-op unless the developer opted in. Never awaited:\n // the command is what the user is waiting for, and a slow collector must not\n // sit in front of it.\n void recordEvent(\"cli.schema\", { subcommand: subcommand ?? \"none\" }, { projectRoot });\n const backendDir = requireBackendDir(projectRoot);\n\n const activePlugin = getActiveBackendPlugin(backendDir);\n if (!activePlugin) {\n console.error(chalk.red(\"✗ Could not detect an active database plugin.\"));\n console.error(chalk.gray(\" Make sure a package like @rebasepro/server-postgres is installed in backend/package.json.\"));\n process.exit(1);\n }\n\n const pluginCli = resolvePluginCliScript(backendDir, activePlugin);\n if (!pluginCli) {\n exitDependenciesNotInstalled(projectRoot);\n }\n\n // Set up environment with DOTENV_CONFIG_PATH\n const envFile = findEnvFile(projectRoot);\n const env: Record<string, string> = { ...process.env as Record<string, string> };\n if (envFile) {\n env.DOTENV_CONFIG_PATH = envFile;\n }\n // Which database this project is on, so the driver's closing line does not\n // recommend a command that database refuses. A pure decision — nothing is\n // started, which matters here above all: `schema generate` reads collection\n // files and writes one file, and booting a database to run it would be a\n // side effect nobody asked for.\n env[DEV_DATABASE_KIND_ENV] = devDatabaseKind(projectRoot) ?? \"\";\n\n refuseMissingCollectionsPath(rawArgs, process.cwd(), backendDir);\n\n // `introspect` is the one schema command that reads a database, and it\n // reads the project's — resolved the way every `db` command resolves it,\n // started if that is what it takes. It used to pass `.env` and nothing\n // else, so on the managed database or after `rebase dev --docker` (with\n // the scaffold's DATABASE_URL commented out, on purpose) it said\n // \"DATABASE_URL is not set\", and `--docker` and `--database-url` passed the\n // flag check only to be ignored.\n if (subcommand === \"introspect\") {\n const flags = arg(\n { \"--database-url\": String, \"--docker\": Boolean },\n { argv: rawArgs.slice(2), permissive: true }\n );\n await ensureDockerDatabase(projectRoot, rawArgs);\n const prepared = await prepareDatabaseEnv(projectRoot, {\n flagUrl: flags[\"--database-url\"] ?? null,\n flagDocker: flags[\"--docker\"] === true,\n onProgress: (message) => console.log(chalk.gray(` ${message}`))\n });\n Object.assign(env, prepared.env);\n env[DEV_DATABASE_KIND_ENV] = prepared.database.kind;\n for (const line of managedNotices(prepared)) console.log(chalk.gray(` ${line}`));\n }\n\n try {\n // The one spawn, shared with `db`. This file used to carry its own copy\n // of the tsx-or-node decision; three copies of that rule existed and two\n // were fixed while the third went on spawning plain node.\n await spawnDriverCli(\n { projectRoot, backendDir, pluginCli, env },\n schemaDriverArgs(rawArgs, process.cwd())\n );\n } catch (error) {\n // A child that ran and exited non-zero already printed its diagnostics\n // through inherited stdio; a child that never started (ENOENT on tsx,\n // EACCES on the script) printed nothing at all, and this used to exit 1\n // in silence.\n reportSpawnFailure(error);\n process.exit(1);\n }\n}\n\n/** One page per subcommand, so `rebase schema <action> --help` says something. */\nconst SCHEMA_ACTION_HELP: Record<string, { usage: string; summary: string; notes?: string[] }> = {\n generate: {\n usage: \"rebase schema generate [--collections <dir>] [--output <file>] [--watch]\",\n summary: \"Generate the Drizzle schema from the collection definitions.\",\n notes: [\"--watch regenerates on every change to a collection file.\"]\n },\n introspect: {\n usage: \"rebase schema introspect [--collections <dir>] [--output <dir>] [--schema <name>] [--force] [--data-inference | --no-data-inference]\",\n summary: \"Read an existing database and write Rebase collection definitions from it.\",\n notes: [\n \"--force overwrites collection files that are already there.\",\n \"--data-inference samples up to 100 rows per table to detect formats, constraints and UI settings; \"\n + \"--no-data-inference reads the structure only. Without either it asks, and without a terminal \"\n + \"it reads the structure only.\",\n \"Reads this project's database, the one `rebase db url` prints: --database-url <url> names another; \"\n + \"--docker uses the compose one, starting it if needed.\"\n ]\n },\n stale: {\n usage: \"rebase schema stale [--collections <dir>] [--output <file>] [--fix]\",\n summary: \"Report generated schema files that no longer match the collections.\",\n notes: [\"--fix regenerates them instead of only reporting.\"]\n }\n};\n\n/** Every subcommand the family dispatches — the help table's keys. */\nexport const SCHEMA_SUBCOMMANDS = Object.keys(SCHEMA_ACTION_HELP);\n\nfunction printSchemaHelp(action?: string) {\n const entry = action ? SCHEMA_ACTION_HELP[action] : undefined;\n if (entry) {\n console.log(`\n${chalk.bold(`rebase schema ${action}`)}\n\n ${entry.summary}\n\n${chalk.green.bold(\"Usage\")}\n ${chalk.blue(entry.usage)}\n${entry.notes?.length ? `\\n${chalk.green.bold(\"Notes\")}\\n${entry.notes.map(n => ` ${chalk.gray(`• ${n}`)}`).join(\"\\n\")}\\n` : \"\"}\n${chalk.gray(\"Run `rebase schema --help` for every subcommand.\")}\n`);\n return;\n }\n\n console.log(`\n${chalk.bold(\"rebase schema\")} — Schema management commands\n\n${chalk.green.bold(\"Usage\")}\n rebase schema ${chalk.blue(\"<command>\")} [options]\n\n${chalk.green.bold(\"Commands\")}\n ${chalk.gray(\"(Commands are provided by your active database driver plugin)\")}\n ${chalk.blue.bold(\"generate\")} Generate Schema from collection definitions\n ${chalk.blue.bold(\"introspect\")} Introspect an existing database to generate collection definitions\n ${chalk.blue.bold(\"stale\")} Report generated schema files that no longer match the collections\n\n${chalk.green.bold(\"generate Options\")}\n ${chalk.blue(\"--collections, -c\")} ${COLLECTIONS_FLAG_HELP}\n ${chalk.blue(\"--output, -o\")} Output path for generated schema\n ${chalk.blue(\"--watch, -w\")} Watch for changes and regenerate automatically\n\n${chalk.green.bold(\"introspect Options\")}\n ${chalk.blue(\"--output, -o\")} Output directory for generated collection files\n ${chalk.blue(\"--schema\")} Postgres schema to read (default: public)\n ${chalk.blue(\"--force, -f\")} Overwrite collection files that already exist\n ${chalk.blue(\"--database-url\")} Read this database instead of the project's own\n ${chalk.blue(\"--docker\")} Read the compose database, starting it if needed\n ${chalk.blue(\"--data-inference\")} Sample rows to detect formats and constraints ${chalk.gray(\"(asked when omitted)\")}\n ${chalk.blue(\"--no-data-inference\")} Read the structure only, without asking\n\n${chalk.green.bold(\"stale Options\")}\n ${chalk.blue(\"--fix\")} Regenerate the stale files instead of only reporting them\n`);\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { c as findProjectRoot } from "./project-
|
|
2
|
-
import { a as unknownCommand, n as parseCommandArgs, r as wantsHelp, t as UsageError } from "./args-CcBphFdj.js";
|
|
1
|
+
import { C as wantsHelp, T as unknownCommand, b as parseCommandArgs, c as findProjectRoot, y as UsageError } from "./project-g4K6kV1t.js";
|
|
3
2
|
import chalk from "chalk";
|
|
4
3
|
import fs from "fs";
|
|
5
4
|
import os from "os";
|
|
@@ -571,7 +570,7 @@ async function skillsInstall(rawArgs = []) {
|
|
|
571
570
|
console.log(chalk.yellow(" Edited files were left as they are. To replace them with the bundle's copy:"));
|
|
572
571
|
console.log(` ${chalk.cyan("rebase skills install --force")}`);
|
|
573
572
|
}
|
|
574
|
-
const { MCP_SERVER_NAME, ensureMcpDependency, mcpDependencyNote, mcpServerRegistered, writeMcpConfig } = await import("./agent-setup-
|
|
573
|
+
const { MCP_SERVER_NAME, ensureMcpDependency, mcpDependencyNote, mcpServerRegistered, writeMcpConfig } = await import("./agent-setup-BYb2Tbdz.js");
|
|
575
574
|
const { detectPackageManager } = await import("./package-manager-DSEOwTqM.js").then((n) => n.r);
|
|
576
575
|
const shownFile = (file) => path.relative(process.cwd(), path.join(projectDir, file)) || file;
|
|
577
576
|
if (withMcp) {
|
|
@@ -638,4 +637,4 @@ ${chalk.green.bold("Examples")}
|
|
|
638
637
|
//#endregion
|
|
639
638
|
export { AGENTS, AGENT_KEYS, SKILLS_SUBCOMMANDS, detectInstalledAgents, installSkills, loadBundledSkills, resolveAgentNames, skillsCommand };
|
|
640
639
|
|
|
641
|
-
//# sourceMappingURL=skills-
|
|
640
|
+
//# sourceMappingURL=skills-DeUIsZcT.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills-DEhYiPeO.js","names":[],"sources":["../src/commands/skills.ts"],"sourcesContent":["import chalk from \"chalk\";\nimport { createHash } from \"crypto\";\nimport fs from \"fs\";\nimport path from \"path\";\nimport inquirer from \"inquirer\";\nimport { createRequire } from \"module\";\nimport os from \"os\";\nimport { findProjectRoot } from \"../utils/project\";\nimport { parseCommandArgs, UsageError, wantsHelp } from \"../utils/args\";\nimport { unknownCommand } from \"../utils/unknown-command\";\n\nconst require = createRequire(import.meta.url);\n\n/**\n * Supported agent environments and their target directories.\n *\n * Every agent `rebase init` writes a pointer file for has an entry here. That\n * was not true: `rebase init` writes `CLAUDE.md`, `AGENTS.md`, `.cursorrules`,\n * `.windsurfrules` and `.github/copilot-instructions.md`, and the installer\n * covered four of the five — so a Codex or Copilot user was told, by a file in\n * their own repository, to run an installer that had nothing to offer them.\n *\n * `flatLayout` marks the agents whose rules directory is loaded *whole*, into\n * every request. Writing 21 skills there put ~84,000 characters of always-on\n * context in front of every question a person asked Cursor — more than the task\n * itself, on every turn, most of it about parts of Rebase they were not\n * touching. Those agents get one short index rule instead, and the skill bodies\n * go in per-skill subdirectories the index names, which the agent reads when it\n * needs one. `indexFile` is the name of that rule.\n *\n * A subdirectory layout has no such problem: the rule file already sits beside\n * its own assets, so `references/x.md` resolves as written and nothing is\n * loaded until it is opened.\n *\n * `homeMarkers` are the directories under `~` that say the assistant is\n * installed on this machine. They answer a different question from\n * `detectDir`: a fresh scaffold has no `.claude/` of its own, so `rebase init`\n * asks the machine which assistants the developer has and pre-selects those.\n *\n * `mcp` is where the assistant reads a *project-level* MCP server list, and in\n * which shape — see `agent-setup.ts`. `projectDir` is what `REBASE_PROJECT_DIR`\n * is set to: `\".\"` where the server is spawned in the project, the editor's own\n * workspace variable where it may not be. `null` means there is no project\n * file to write: Windsurf reads only a user-level config, and one entry there\n * cannot name every project on the machine.\n */\nexport const AGENTS = {\n cursor: {\n label: \"Cursor\",\n detectDir: \".cursor\",\n homeMarkers: [\".cursor\"],\n targetDir: \".cursor/rules\",\n flatLayout: true,\n indexFile: \"rebase.mdc\",\n mcp: {\n file: \".cursor/mcp.json\",\n format: \"mcpServers\",\n projectDir: \"${workspaceFolder}\"\n },\n /** The body is not a rule file here — `indexFile` is. */\n transformFile: (skillName: string, content: string) => ({\n fileName: path.join(skillName, \"SKILL.md\"),\n content\n })\n },\n claude: {\n label: \"Claude Code\",\n detectDir: \".claude\",\n homeMarkers: [\".claude\"],\n targetDir: \".claude/skills\",\n flatLayout: false,\n // The scaffold already ships this file; writing it is then a no-op.\n mcp: {\n file: \".mcp.json\",\n format: \"mcpServers\",\n projectDir: \".\"\n },\n /** Claude Code uses the standard SKILL.md format in subdirectories. */\n transformFile: (skillName: string, content: string) => ({\n fileName: path.join(skillName, \"SKILL.md\"),\n content\n })\n },\n windsurf: {\n label: \"Windsurf\",\n detectDir: \".windsurf\",\n homeMarkers: [\".codeium/windsurf\", \".windsurf\"],\n targetDir: \".windsurf/rules\",\n flatLayout: true,\n indexFile: \"rebase.md\",\n mcp: null,\n /** The body is not a rule file here — `indexFile` is. */\n transformFile: (skillName: string, content: string) => ({\n fileName: path.join(skillName, \"SKILL.md\"),\n content\n })\n },\n gemini: {\n label: \"Gemini CLI / Antigravity\",\n detectDir: \".agents\",\n homeMarkers: [\".gemini\"],\n targetDir: \".agents/skills\",\n flatLayout: false,\n mcp: {\n file: \".gemini/settings.json\",\n format: \"mcpServers\",\n projectDir: \".\"\n },\n /** Gemini uses the standard SKILL.md format in subdirectories. */\n transformFile: (skillName: string, content: string) => ({\n fileName: path.join(skillName, \"SKILL.md\"),\n content\n })\n },\n codex: {\n label: \"Codex CLI\",\n detectDir: \".codex\",\n homeMarkers: [\".codex\"],\n // Codex reads repository skills from `.agents/skills` — every directory\n // from the working directory up to the repository root — and nothing\n // under `.codex/`. This entry used to write `.codex/skills`, so `--agent\n // codex` reported 21 skills installed into a directory Codex never\n // opens. It shares the directory with Gemini; the installer writes it\n // once.\n targetDir: \".agents/skills\",\n flatLayout: false,\n // Project-scoped, and read only once the developer trusts the project.\n mcp: {\n file: \".codex/config.toml\",\n format: \"codexToml\",\n projectDir: \".\"\n },\n /** Codex uses the standard SKILL.md format in subdirectories. */\n transformFile: (skillName: string, content: string) => ({\n fileName: path.join(skillName, \"SKILL.md\"),\n content\n })\n },\n kiro: {\n label: \"Kiro\",\n detectDir: \".kiro\",\n homeMarkers: [\".kiro\"],\n targetDir: \".kiro/steering\",\n flatLayout: true,\n indexFile: \"rebase.md\",\n mcp: {\n file: \".kiro/settings/mcp.json\",\n format: \"mcpServers\",\n projectDir: \".\"\n },\n /** The body is not a rule file here — `indexFile` is. */\n transformFile: (skillName: string, content: string) => ({\n fileName: path.join(skillName, \"SKILL.md\"),\n content\n })\n },\n copilot: {\n label: \"GitHub Copilot\",\n // Deliberately undetectable. `.github/` is the one directory in this\n // table that is not evidence of an assistant: `rebase init` writes\n // `.github/copilot-instructions.md` into every scaffold, and half the\n // repositories on the internet have a `.github/` for workflows and\n // issue templates. Listing it made bare `rebase skills install` resolve\n // to `[copilot]` in every project — so a Claude Code user who ran the\n // command `rebase init` printed got a success message and nothing in\n // `.claude/skills`. Copilot is `--agent copilot`.\n detectDir: null,\n // Same reasoning on the machine: Copilot lives inside VS Code or a\n // JetBrains IDE, and neither's directory says the extension is there.\n homeMarkers: [],\n targetDir: \".github/instructions\",\n flatLayout: true,\n indexFile: \"rebase.instructions.md\",\n mcp: {\n file: \".vscode/mcp.json\",\n format: \"vscode\",\n projectDir: \"${workspaceFolder}\"\n },\n /** The body is not a rule file here — `indexFile` is. */\n transformFile: (skillName: string, content: string) => ({\n fileName: path.join(skillName, \"SKILL.md\"),\n content\n })\n }\n} as const;\n\nexport type AgentKey = keyof typeof AGENTS;\n\n/** Narrows a string to an agent name, by the table's own keys. */\nexport function isAgentKey(value: string): value is AgentKey {\n return Object.hasOwn(AGENTS, value);\n}\n\n/** Every agent, in table order. */\nexport const AGENT_KEYS: AgentKey[] = Object.keys(AGENTS).filter(isAgentKey);\n\n/**\n * Resolve the path to the skills directory from @rebasepro/agent-skills.\n * Works in both workspace (symlink) and published (real files) layouts.\n */\nfunction getSkillsSourceDir(): string {\n const pkgJsonPath = require.resolve(\"@rebasepro/agent-skills/package.json\");\n const pkgRoot = path.dirname(pkgJsonPath);\n const skillsDir = path.join(pkgRoot, \"skills\");\n\n if (!fs.existsSync(skillsDir)) {\n throw new Error(\n `Skills directory not found at ${skillsDir}. ` +\n \"Make sure @rebasepro/agent-skills is installed.\"\n );\n }\n\n return skillsDir;\n}\n\nexport interface LoadedSkill {\n name: string;\n /** Absolute path of the skill's source directory. */\n dir: string;\n content: string;\n /** Every file the skill ships besides SKILL.md, relative to `dir`. */\n assets: string[];\n}\n\n/**\n * Everything a skill ships alongside its SKILL.md — the `references/` tree the\n * Agent Skills format uses for progressive disclosure.\n *\n * These used to be dropped on install, because the installer read exactly\n * `<skill>/SKILL.md` and nothing else. That left `rebase-design-language`\n * telling the agent three separate times to read `references/view-patterns.md`\n * — 379 lines of view skeletons — in a project where the file had never\n * landed, and the instruction it carries is \"extend an existing pattern; do not\n * invent a layout\".\n */\nfunction loadSkillAssets(skillDir: string): string[] {\n const found: string[] = [];\n\n const walk = (dir: string, prefix: string) => {\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n // Dotfiles are bookkeeping — `.gitkeep` is what holds the empty\n // `references/` directories in git — and install nothing.\n if (entry.name.startsWith(\".\")) continue;\n const rel = prefix ? path.join(prefix, entry.name) : entry.name;\n if (entry.isDirectory()) walk(path.join(dir, entry.name), rel);\n else if (rel !== \"SKILL.md\") found.push(rel);\n }\n };\n\n walk(skillDir, \"\");\n return found.sort();\n}\n\n/** Read all skill directories and return their names, content and assets. */\nexport function loadSkills(skillsDir: string): LoadedSkill[] {\n const entries = fs.readdirSync(skillsDir, { withFileTypes: true });\n const skills: LoadedSkill[] = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n const skillDir = path.join(skillsDir, entry.name);\n const skillMdPath = path.join(skillDir, \"SKILL.md\");\n if (!fs.existsSync(skillMdPath)) continue;\n skills.push({\n name: entry.name,\n dir: skillDir,\n content: fs.readFileSync(skillMdPath, \"utf-8\"),\n assets: loadSkillAssets(skillDir)\n });\n }\n\n return skills;\n}\n\n/**\n * The skills this CLI ships, from its own `@rebasepro/agent-skills`.\n *\n * Throws rather than exiting, so `rebase init` can report a missing bundle as a\n * warning and still finish the scaffold.\n */\nexport function loadBundledSkills(): LoadedSkill[] {\n const skillsDir = getSkillsSourceDir();\n const skills = loadSkills(skillsDir);\n if (skills.length === 0) throw new Error(`No skills found in ${skillsDir}`);\n return skills;\n}\n\n/**\n * The one always-on rule a flat-layout agent gets, in place of every skill.\n *\n * Cursor and Windsurf load their whole rules directory into each request. With\n * a rule file per skill that was ~84,000 characters of Rebase reference in\n * front of every question, whether or not the question was about Rebase — and\n * an instruction an assistant skims is an instruction it does not follow.\n *\n * So the always-on part is this: a table of what exists and where to read it.\n * `alwaysApply: true` because knowing the skills are there costs a few hundred\n * characters and is the whole point; the bodies stay on disk until the agent\n * opens one.\n */\nexport function renderSkillIndex(skills: LoadedSkill[], agentKey: AgentKey): string {\n const agent = AGENTS[agentKey];\n const bodyPath = (name: string) => agent.transformFile(name, \"\").fileName.split(path.sep).join(\"/\");\n const rows = skills\n .map((skill) => `| \\`${skill.name}\\` | ${describe(skill)} | \\`${bodyPath(skill.name)}\\` |`)\n .join(\"\\n\");\n\n return [\n \"---\",\n \"description: Rebase — the skills index. Read the file named for the task before writing Rebase code.\",\n \"alwaysApply: true\",\n \"---\",\n \"\",\n \"# Rebase skills\",\n \"\",\n `This project uses [Rebase](https://rebase.pro). ${skills.length} reference skills are`,\n \"installed beside this file. **Read the one that covers the task before writing\",\n \"code** — they are the difference between a collection that compiles and one that\",\n \"does not.\",\n \"\",\n \"| Skill | Covers | Read |\",\n \"|---|---|---|\",\n rows,\n \"\",\n \"Start with `rebase-basics` if you are not sure: it opens with the recipes for\",\n \"adding a collection, a function and an RLS rule, and names the commands.\",\n \"\"\n ].join(\"\\n\");\n}\n\n/**\n * The body of a YAML block scalar, given the offset of its `description:` line.\n *\n * Everything indented more than the key belongs to the value; the first line\n * that is not blank and not indented ends it.\n */\nfunction blockScalarBody(frontMatter: string, keyOffset: number): string {\n const lines = frontMatter.slice(keyOffset).split(\"\\n\").slice(1);\n const body: string[] = [];\n for (const line of lines) {\n if (line.trim() === \"\") { body.push(\"\"); continue; }\n if (!/^[ \\t]/.test(line)) break;\n body.push(line.trim());\n }\n return body.join(\" \");\n}\n\n/**\n * A skill's one-line summary, from its own front matter.\n *\n * Read rather than written here so a new skill needs no edit in this file, and\n * truncated because the index is only worth having while it stays short.\n */\nfunction describe(skill: LoadedSkill): string {\n const frontMatter = skill.content.split(\"---\")[1] ?? \"\";\n const described = /^description:[ \\t]*(.*)$/m.exec(frontMatter);\n // `description: |` (or `>`) is a YAML block scalar: the value is the\n // indented lines that follow, and capturing the line itself captured the\n // `|`. That rendered an empty \"Covers\" cell for `rebase-design-language`,\n // the one skill whose description says agents MUST read it.\n const raw = /^[|>][-+]?$/.test((described?.[1] ?? \"\").trim())\n ? blockScalarBody(frontMatter, described?.index ?? 0)\n : (described?.[1] ?? \"\");\n const text = raw.trim().replace(/\\s+/g, \" \").replace(/\\|/g, \"\\\\|\");\n const firstSentence = /^.*?\\.(?:\\s|$)/.exec(text)?.[0]?.trim() ?? text;\n const fallback = skill.name.replace(/^rebase-/, \"\").replace(/-/g, \" \");\n if (!firstSentence) return fallback;\n if (firstSentence.length <= 140) return firstSentence;\n // Cut at a word boundary. A description sliced mid-word (\"using the collect\")\n // reads as a corrupted file rather than as a summary.\n const cut = firstSentence.slice(0, 140);\n return `${cut.slice(0, cut.lastIndexOf(\" \")).replace(/[,;:]$/, \"\")}…`;\n}\n\n/**\n * Detect which agent environments already exist in the project.\n *\n * A `detectDir` has to be evidence *the user* created, not something a scaffold\n * ships. An agent whose only marker fails that test declares `detectDir: null`\n * and is reachable by `--agent` alone; guessing wrong here is worse than not\n * guessing, because the wrong guess installs 21 files and reports success.\n */\nexport function detectAgents(projectDir: string): AgentKey[] {\n return AGENT_KEYS.filter((key) => {\n const { detectDir } = AGENTS[key];\n return detectDir !== null && fs.existsSync(path.join(projectDir, detectDir));\n });\n}\n\n/** What `detectInstalledAgents` found for one assistant. */\nexport interface InstalledAgent {\n key: AgentKey;\n label: string;\n /** The home directory checked, as `~/…` — the one found, else the first. */\n marker: string | null;\n found: boolean;\n}\n\n/**\n * Which assistants are installed on this machine, from their home directories.\n *\n * The question `rebase init` needs answered, and one `detectAgents` cannot: a\n * project that does not exist yet has no `.claude/` in it. What the machine has\n * is only a default — the developer confirms it — so a false positive costs an\n * unticked box, not 21 files nobody asked for.\n */\nexport function detectInstalledAgents(home: string = os.homedir()): InstalledAgent[] {\n return AGENT_KEYS.map((key) => {\n const agent = AGENTS[key];\n const markers: readonly string[] = agent.homeMarkers;\n const hit = markers.find((m) => fs.existsSync(path.join(home, m)));\n const shown = hit ?? markers[0];\n return {\n key,\n label: agent.label,\n marker: shown === undefined ? null : `~/${shown}`,\n found: hit !== undefined\n };\n });\n}\n\n/** Install skills for a specific agent into the project directory. */\n/**\n * The file in each target directory that records what the installer wrote:\n * relative path → sha256 of the bytes written. A dotfile, so no agent loads it\n * as a rule.\n */\nexport const SKILLS_MANIFEST = \".rebase-skills.json\";\n\ninterface SkillsManifest {\n version: 1;\n files: Record<string, string>;\n}\n\nfunction sha256(bytes: Buffer | string): string {\n return createHash(\"sha256\").update(bytes).digest(\"hex\");\n}\n\nfunction readManifest(targetBase: string): SkillsManifest | null {\n try {\n const parsed: unknown = JSON.parse(fs.readFileSync(path.join(targetBase, SKILLS_MANIFEST), \"utf-8\"));\n if (parsed && typeof parsed === \"object\" && \"files\" in parsed) {\n const files = (parsed as { files: unknown }).files;\n if (files && typeof files === \"object\") {\n const entries = Object.entries(files).filter((e): e is [string, string] => typeof e[1] === \"string\");\n return { version: 1, files: Object.fromEntries(entries) };\n }\n }\n } catch {\n // No manifest, or one that is not ours: the first install, or one made\n // before manifests existed.\n }\n return null;\n}\n\n/** What one agent's install did. */\nexport interface AgentInstallResult {\n skills: number;\n assets: number;\n /** Files left as they are because they were edited since the last install (relative to the target dir). */\n kept: string[];\n /** Files of skills the bundle no longer ships, removed because nobody edited them. */\n removed: string[];\n}\n\nexport function installForAgent(\n agentKey: AgentKey,\n skills: LoadedSkill[],\n projectDir: string,\n options: { force?: boolean } = {}\n): AgentInstallResult {\n const agent = AGENTS[agentKey];\n const targetBase = path.join(projectDir, agent.targetDir);\n\n // Ensure the target directory exists\n fs.mkdirSync(targetBase, { recursive: true });\n\n // A re-run used to overwrite every file unconditionally and never remove\n // one: a note a team appended to an installed skill and committed — as\n // the command tells them to — vanished on the next `skills install`, and a\n // skill a release retired stayed installed beside its replacement. The\n // manifest records what was written, so an edit is told apart from an\n // older bundle's copy. A file with no record (an install from before\n // manifests) is overwritten, as before.\n const previous = readManifest(targetBase);\n const recorded: Record<string, string> = {};\n const kept: string[] = [];\n\n const place = (relPath: string, bytes: Buffer | string) => {\n const target = path.join(targetBase, relPath);\n const wanted = sha256(bytes);\n const last = previous?.files[relPath];\n if (fs.existsSync(target)) {\n const current = sha256(fs.readFileSync(target));\n if (current === wanted) {\n recorded[relPath] = wanted;\n return;\n }\n if (last !== undefined && current !== last && !options.force) {\n // Edited since it was installed: left alone, and still recorded\n // as what was installed, so the next run says so again.\n kept.push(relPath);\n recorded[relPath] = last;\n return;\n }\n }\n fs.mkdirSync(path.dirname(target), { recursive: true });\n fs.writeFileSync(target, bytes);\n recorded[relPath] = wanted;\n };\n\n let count = 0;\n let assetCount = 0;\n for (const skill of skills) {\n // Every layout now writes the body into a per-skill subdirectory, so a\n // link the skill spells `references/x.md` resolves as written and no\n // rewriting is needed. What differs is whether that file is also the\n // agent's *rule* file (subdirectory layouts) or something the index\n // points at (flat ones).\n const { fileName, content } = agent.transformFile(skill.name, skill.content);\n place(fileName, content);\n count++;\n\n // A skill's assets always land in a directory named after the skill,\n // whatever the rule file's layout, so two skills' `references/` trees\n // cannot collide in a flat target directory.\n for (const asset of skill.assets) {\n place(path.join(skill.name, asset), fs.readFileSync(path.join(skill.dir, asset)));\n assetCount++;\n }\n }\n\n if (agent.flatLayout && agent.indexFile) {\n place(agent.indexFile, renderSkillIndex(skills, agentKey));\n }\n\n // Retired files: removed when they are exactly what was installed, kept\n // (and reported) when someone edited them.\n const removed: string[] = [];\n for (const [relPath, last] of Object.entries(previous?.files ?? {})) {\n if (relPath in recorded) continue;\n const target = path.join(targetBase, relPath);\n if (!fs.existsSync(target)) continue;\n if (sha256(fs.readFileSync(target)) !== last && !options.force) {\n kept.push(relPath);\n continue;\n }\n fs.rmSync(target);\n removed.push(relPath);\n // Empty directories the removal leaves behind, up to the target dir.\n for (let dir = path.dirname(target); dir.startsWith(targetBase + path.sep); dir = path.dirname(dir)) {\n if (fs.readdirSync(dir).length > 0) break;\n fs.rmdirSync(dir);\n }\n }\n\n fs.writeFileSync(\n path.join(targetBase, SKILLS_MANIFEST),\n JSON.stringify({ version: 1, files: recorded } satisfies SkillsManifest, null, 2) + \"\\n\",\n \"utf-8\"\n );\n\n return { skills: count, assets: assetCount, kept, removed };\n}\n\n/** What `installSkills` did for one agent. */\nexport interface SkillsInstallResult extends AgentInstallResult {\n agent: AgentKey;\n /** An earlier agent in the same run that already wrote this directory. */\n sharedWith?: AgentKey;\n}\n\n/**\n * Install for several agents, writing each target directory once.\n *\n * Gemini and Codex both read `.agents/skills`; installing twice would write the\n * same 21 files twice and report two installs of one directory.\n */\nexport function installSkills(\n agents: readonly AgentKey[],\n skills: LoadedSkill[],\n projectDir: string,\n options: { force?: boolean } = {}\n): SkillsInstallResult[] {\n const written = new Map<string, SkillsInstallResult>();\n return agents.map((agent) => {\n const earlier = written.get(AGENTS[agent].targetDir);\n if (earlier) return { ...earlier, agent, sharedWith: earlier.agent };\n const result = { agent, ...installForAgent(agent, skills, projectDir, options) };\n written.set(AGENTS[agent].targetDir, result);\n return result;\n });\n}\n\n/** Everything the switch below dispatches, for the did-you-mean. */\nexport const SKILLS_SUBCOMMANDS = [\"install\"] as const;\n\nexport async function skillsCommand(subcommand: string | undefined, rawArgs: string[]) {\n // `--help` cannot reach `skillsInstall`. `cli.ts` only rewrites the\n // subcommand to `\"--help\"` when none was named, so `rebase skills install\n // --help` used to run the install: it detected the agents and overwrote\n // `.claude/skills/*/SKILL.md`, `.cursor/rules/*.mdc` and the rest. A flag\n // that prints text must not write files.\n if (wantsHelp(rawArgs)) {\n printSkillsHelp();\n return;\n }\n\n switch (subcommand) {\n case \"install\":\n await skillsInstall(rawArgs);\n break;\n case \"--help\":\n case undefined:\n printSkillsHelp();\n break;\n default:\n unknownCommand(subcommand, SKILLS_SUBCOMMANDS, \"skills\");\n }\n}\n\n/**\n * Agents named explicitly on the command line, e.g. `--agent claude --agent cursor`\n * (also accepts a comma-separated list, and `all`). Returns null when none were\n * given.\n */\nexport function parseAgentFlags(rawArgs: string[]): AgentKey[] | null {\n return parseSkillsInstallLine(rawArgs).agents;\n}\n\n/** `rebase skills install`'s whole line: the agents it names, `--mcp` and `--force`. */\nexport function parseSkillsInstallLine(rawArgs: string[]): { agents: AgentKey[] | null; mcp: boolean; force: boolean } {\n // Strict, and before anything is written. This used to scan `rawArgs` for\n // `--agent` and ignore every other token, so `rebase skills install\n // --frobnicate --agent claude` exited 0 after writing 21 files — the CLI's\n // other families reject an unknown flag, and an installer is the last place\n // to guess what the person meant.\n const { flags } = parseCommandArgs({\n spec: { \"--agent\": [String], \"-a\": \"--agent\", \"--mcp\": Boolean, \"--force\": Boolean },\n rawArgs,\n commandWords: 2,\n command: \"skills install\",\n maxPositionals: 0\n });\n\n return {\n agents: resolveAgentNames(flags[\"--agent\"] ?? []),\n mcp: flags[\"--mcp\"] === true,\n force: flags[\"--force\"] === true\n };\n}\n\n/**\n * The agents a list of `--agent` values names, or null when it names none.\n *\n * Shared by `rebase skills install` and `rebase init`, so both accept the same\n * spellings. Throws a UsageError on a name that is not an agent.\n */\nexport function resolveAgentNames(values: readonly string[]): AgentKey[] | null {\n const requested = values\n .flatMap(value => value.split(\",\").map(v => v.trim()))\n .filter(Boolean);\n if (requested.length === 0) return null;\n\n // `all` exists for the non-interactive case. Detection cannot help there: a\n // scaffolded project ships `.cursorrules`, `CLAUDE.md`, `.windsurfrules`,\n // `AGENTS.md` and `.github/copilot-instructions.md` all at once, so every\n // pointer file is present and none of them says which assistant the\n // developer actually uses. Guessing from them would install several agents'\n // skills unasked; refusing leaves a scripted setup with no way through.\n // Naming `all` is the developer saying it out loud.\n if (requested.includes(\"all\")) return [...AGENT_KEYS];\n\n const unknown = requested.filter(a => !isAgentKey(a));\n if (unknown.length > 0) {\n throw new UsageError(`Unknown agent(s): ${unknown.join(\", \")}. Available: ${AGENT_KEYS.join(\", \")}, all`);\n }\n // Deduplicated, in the order given: `--agent claude,claude` is one install.\n return [...new Set(requested.filter(isAgentKey))];\n}\n\nasync function skillsInstall(rawArgs: string[] = []) {\n // Parse the line before anything else touches the disk: a bad flag must\n // cost nothing, and everything below this writes or resolves paths.\n const { agents: namedAgents, mcp: withMcp, force } = parseSkillsInstallLine(rawArgs);\n\n // The project root, not the cwd. Agent skills belong beside the repository's\n // other agent configuration — `.claude/`, `.cursor/` — which is both what\n // `detectAgents` looks for and where an assistant reads them from. Resolving\n // against wherever the command happened to be typed put them in\n // `backend/.claude/skills` when run from `backend/`, detected no agent\n // there, and left the skills somewhere nothing would look. Outside a project\n // the cwd is still the honest answer: this command is useful in a repository\n // that is not a Rebase one.\n const projectDir = findProjectRoot() ?? process.cwd();\n\n // 1. Load skills from @rebasepro/agent-skills\n let skills: LoadedSkill[];\n try {\n skills = loadBundledSkills();\n } catch (err) {\n console.error(`${chalk.red.bold(\"ERROR\")} ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n\n // 2. Explicit --agent wins; otherwise detect existing agent environments\n let agents = namedAgents ?? detectAgents(projectDir);\n\n // 3. If none detected, ask the user\n if (agents.length === 0) {\n // A scaffolded project ships `.cursorrules`, `CLAUDE.md`, `AGENTS.md`\n // and `.github/copilot-instructions.md`, but none of the *directories*\n // detectAgents looks for, so a fresh project always lands here — which\n // is correct: those files say what `rebase init` writes, not what the\n // developer uses. On a non-TTY that used to abort with a raw\n // ExitPromptError.\n if (!process.stdin.isTTY) {\n console.error(chalk.red(\"Cannot prompt: this is a non-interactive terminal (no TTY).\"));\n console.error(chalk.yellow(` Name the agents explicitly, e.g. rebase skills install --agent ${Object.keys(AGENTS)[0]}`));\n console.error(chalk.yellow(\" Or install for every supported agent: rebase skills install --agent all\"));\n console.error(chalk.gray(` Available: ${Object.keys(AGENTS).join(\", \")}`));\n process.exit(1);\n }\n\n // The project says nothing, but the machine may: pre-tick the agents\n // whose home directory exists, as `rebase init` does.\n const installed = detectInstalledAgents();\n const choices = installed.map(({ key, label, found }) => ({\n name: label,\n value: key,\n checked: found\n }));\n\n const { selectedAgents } = await inquirer.prompt([{\n type: \"checkbox\",\n name: \"selectedAgents\",\n message: \"No AI agent configuration in this project. Which agents do you use?\",\n choices,\n validate: (input: readonly unknown[]) => {\n if (input.length === 0) return \"Please select at least one agent.\";\n return true;\n }\n }]);\n\n agents = AGENT_KEYS.filter(key => selectedAgents.includes(key));\n }\n\n // 4. Install skills for each agent\n console.log(\"\");\n console.log(chalk.gray(` Found ${chalk.white(skills.length)} Rebase skills`));\n console.log(\"\");\n\n let anyKept = false;\n for (const result of installSkills(agents, skills, projectDir, { force })) {\n const agent = AGENTS[result.agent];\n // Relative to where the command was typed, now that the destination is\n // the project root rather than the cwd — otherwise `.claude/skills`\n // names a directory that is not the one it wrote to.\n const shown = path.relative(process.cwd(), path.join(projectDir, agent.targetDir)) || agent.targetDir;\n if (result.sharedWith) {\n console.log(` ${chalk.green(\"✓\")} ${chalk.bold(agent.label)} — reads the same ${chalk.gray(shown)} as ${AGENTS[result.sharedWith].label}`);\n continue;\n }\n const withAssets = result.assets > 0 ? ` (+ ${result.assets} reference file${result.assets === 1 ? \"\" : \"s\"})` : \"\";\n console.log(` ${chalk.green(\"✓\")} ${chalk.bold(agent.label)} — ${result.skills} skills installed${withAssets} to ${chalk.gray(shown)}`);\n for (const file of result.removed) {\n console.log(chalk.gray(` − removed ${path.join(shown, file)} (no longer in the bundle)`));\n }\n for (const file of result.kept) {\n anyKept = true;\n console.log(chalk.yellow(` ! kept ${path.join(shown, file)}: edited since it was installed`));\n }\n }\n if (anyKept) {\n console.log(chalk.yellow(\" Edited files were left as they are. To replace them with the bundle's copy:\"));\n console.log(` ${chalk.cyan(\"rebase skills install --force\")}`);\n }\n\n // The MCP server, as `rebase init --agent` registers it. Imported here\n // rather than at the top: agent-setup imports this module.\n const {\n MCP_SERVER_NAME, ensureMcpDependency, mcpDependencyNote, mcpServerRegistered, writeMcpConfig\n } = await import(\"./agent-setup\");\n const { detectPackageManager } = await import(\"../utils/package-manager\");\n const shownFile = (file: string) => path.relative(process.cwd(), path.join(projectDir, file)) || file;\n if (withMcp) {\n console.log(\"\");\n const pm = detectPackageManager(projectDir);\n let registered = false;\n for (const agentKey of agents) {\n const agent = AGENTS[agentKey];\n const result = writeMcpConfig(agentKey, projectDir, pm);\n if (result && result.status !== \"unreadable\") registered = true;\n if (!result) {\n console.log(chalk.gray(` · ${agent.label} has no project-level MCP config — add @rebasepro/mcp in its MCP settings.`));\n } else if (result.status === \"added\") {\n console.log(` ${chalk.green(\"✓\")} ${chalk.bold(agent.label)} — MCP server in ${chalk.gray(shownFile(result.file))}`);\n } else if (result.status === \"present\") {\n console.log(` ${chalk.green(\"✓\")} ${chalk.bold(agent.label)} — MCP server already in ${chalk.gray(shownFile(result.file))}`);\n } else {\n console.log(chalk.yellow(` ! ${agent.label}: ${shownFile(result.file)} is not plain JSON, so it was left alone — add the \"${MCP_SERVER_NAME}\" server by hand.`));\n }\n }\n // The configs run the project's own copy of the server.\n const note = registered ? mcpDependencyNote(ensureMcpDependency(projectDir), pm) : undefined;\n if (note) console.log(chalk.yellow(` ${note}`));\n }\n\n console.log(\"\");\n console.log(chalk.gray(\" Skills are project-local. Commit them to share with your team.\"));\n // The skills ship inside the CLI's own pinned `@rebasepro/agent-skills`,\n // so a re-run reinstalls that version; newer ones come with a newer CLI.\n console.log(chalk.gray(\" Re-run this command to restore them. Upgrade @rebasepro/cli for newer skills.\"));\n if (!withMcp) {\n // Only the agents whose config does not have the server yet: on a\n // project `init --agent` set up, a refresh says nothing about it.\n const missing = agents.filter(agentKey => mcpServerRegistered(agentKey, projectDir) === false);\n if (missing.length > 0) {\n console.log(chalk.gray(\" To register the Rebase MCP server for them too, as `rebase init --agent` does:\"));\n console.log(` ${chalk.cyan(`rebase skills install --agent ${missing.join(\",\")} --mcp`)}`);\n }\n }\n console.log(\"\");\n}\n\nfunction printSkillsHelp() {\n console.log(`\n${chalk.bold(\"rebase skills\")} — Manage AI agent skills\n\n${chalk.green.bold(\"Usage\")}\n rebase skills ${chalk.blue(\"<subcommand>\")}\n\n${chalk.green.bold(\"Subcommands\")}\n ${chalk.blue.bold(\"install\")} Install Rebase agent skills for your AI coding assistant\n Supports: ${Object.values(AGENTS).map(a => a.label).join(\", \")}\n\n${chalk.green.bold(\"Options\")}\n ${chalk.blue(\"--force\")} Replace installed skill files you edited, and remove edited files of\n skills the bundle no longer ships. Without it, edits are kept.\n ${chalk.blue(\"--mcp\")} Also register the Rebase MCP server in each agent's project config\n (.mcp.json, .cursor/mcp.json, …), as ${chalk.cyan(\"rebase init --agent\")} does.\n Servers already in the file are kept.\n ${chalk.blue(\"--agent, -a\")} Agent(s) to install for, skipping detection and the prompt.\n Repeat the flag or pass a comma-separated list, or ${chalk.bold(\"all\")}.\n Required without a TTY: detection looks for an agent's own\n directory (${Object.values(AGENTS).filter(a => a.detectDir).map(a => a.detectDir).join(\", \")}),\n and a fresh scaffold has none. GitHub Copilot is never detected\n — ${chalk.gray(\".github/\")} is not evidence anyone uses it — so name it.\n Available: ${Object.keys(AGENTS).join(\", \")}, all\n\n${chalk.green.bold(\"Examples\")}\n ${chalk.cyan(\"rebase skills install\")}\n ${chalk.cyan(\"rebase skills install --agent claude\")}\n ${chalk.cyan(\"rebase skills install --agent claude,cursor\")}\n ${chalk.cyan(\"rebase skills install --agent cursor --mcp\")} ${chalk.gray(\"# skills + the MCP server\")}\n ${chalk.cyan(\"rebase skills install --agent all\")} ${chalk.gray(\"# scripted / CI\")}\n`);\n}\n"],"mappings":";;;;;;;;;;AAWA,IAAM,UAAU,cAAc,OAAO,KAAK,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmC7C,IAAa,SAAS;CAClB,QAAQ;EACJ,OAAO;EACP,WAAW;EACX,aAAa,CAAC,SAAS;EACvB,WAAW;EACX,YAAY;EACZ,WAAW;EACX,KAAK;GACD,MAAM;GACN,QAAQ;GACR,YAAY;EAChB;;EAEA,gBAAgB,WAAmB,aAAqB;GACpD,UAAU,KAAK,KAAK,WAAW,UAAU;GACzC;EACJ;CACJ;CACA,QAAQ;EACJ,OAAO;EACP,WAAW;EACX,aAAa,CAAC,SAAS;EACvB,WAAW;EACX,YAAY;EAEZ,KAAK;GACD,MAAM;GACN,QAAQ;GACR,YAAY;EAChB;;EAEA,gBAAgB,WAAmB,aAAqB;GACpD,UAAU,KAAK,KAAK,WAAW,UAAU;GACzC;EACJ;CACJ;CACA,UAAU;EACN,OAAO;EACP,WAAW;EACX,aAAa,CAAC,qBAAqB,WAAW;EAC9C,WAAW;EACX,YAAY;EACZ,WAAW;EACX,KAAK;;EAEL,gBAAgB,WAAmB,aAAqB;GACpD,UAAU,KAAK,KAAK,WAAW,UAAU;GACzC;EACJ;CACJ;CACA,QAAQ;EACJ,OAAO;EACP,WAAW;EACX,aAAa,CAAC,SAAS;EACvB,WAAW;EACX,YAAY;EACZ,KAAK;GACD,MAAM;GACN,QAAQ;GACR,YAAY;EAChB;;EAEA,gBAAgB,WAAmB,aAAqB;GACpD,UAAU,KAAK,KAAK,WAAW,UAAU;GACzC;EACJ;CACJ;CACA,OAAO;EACH,OAAO;EACP,WAAW;EACX,aAAa,CAAC,QAAQ;EAOtB,WAAW;EACX,YAAY;EAEZ,KAAK;GACD,MAAM;GACN,QAAQ;GACR,YAAY;EAChB;;EAEA,gBAAgB,WAAmB,aAAqB;GACpD,UAAU,KAAK,KAAK,WAAW,UAAU;GACzC;EACJ;CACJ;CACA,MAAM;EACF,OAAO;EACP,WAAW;EACX,aAAa,CAAC,OAAO;EACrB,WAAW;EACX,YAAY;EACZ,WAAW;EACX,KAAK;GACD,MAAM;GACN,QAAQ;GACR,YAAY;EAChB;;EAEA,gBAAgB,WAAmB,aAAqB;GACpD,UAAU,KAAK,KAAK,WAAW,UAAU;GACzC;EACJ;CACJ;CACA,SAAS;EACL,OAAO;EASP,WAAW;EAGX,aAAa,CAAC;EACd,WAAW;EACX,YAAY;EACZ,WAAW;EACX,KAAK;GACD,MAAM;GACN,QAAQ;GACR,YAAY;EAChB;;EAEA,gBAAgB,WAAmB,aAAqB;GACpD,UAAU,KAAK,KAAK,WAAW,UAAU;GACzC;EACJ;CACJ;AACJ;;AAKA,SAAgB,WAAW,OAAkC;CACzD,OAAO,OAAO,OAAO,QAAQ,KAAK;AACtC;;AAGA,IAAa,aAAyB,OAAO,KAAK,MAAM,CAAC,CAAC,OAAO,UAAU;;;;;AAM3E,SAAS,qBAA6B;CAClC,MAAM,cAAc,QAAQ,QAAQ,sCAAsC;CAC1E,MAAM,UAAU,KAAK,QAAQ,WAAW;CACxC,MAAM,YAAY,KAAK,KAAK,SAAS,QAAQ;CAE7C,IAAI,CAAC,GAAG,WAAW,SAAS,GACxB,MAAM,IAAI,MACN,iCAAiC,UAAU,kDAE/C;CAGJ,OAAO;AACX;;;;;;;;;;;;AAsBA,SAAS,gBAAgB,UAA4B;CACjD,MAAM,QAAkB,CAAC;CAEzB,MAAM,QAAQ,KAAa,WAAmB;EAC1C,KAAK,MAAM,SAAS,GAAG,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC,GAAG;GAG9D,IAAI,MAAM,KAAK,WAAW,GAAG,GAAG;GAChC,MAAM,MAAM,SAAS,KAAK,KAAK,QAAQ,MAAM,IAAI,IAAI,MAAM;GAC3D,IAAI,MAAM,YAAY,GAAG,KAAK,KAAK,KAAK,KAAK,MAAM,IAAI,GAAG,GAAG;QACxD,IAAI,QAAQ,YAAY,MAAM,KAAK,GAAG;EAC/C;CACJ;CAEA,KAAK,UAAU,EAAE;CACjB,OAAO,MAAM,KAAK;AACtB;;AAGA,SAAgB,WAAW,WAAkC;CACzD,MAAM,UAAU,GAAG,YAAY,WAAW,EAAE,eAAe,KAAK,CAAC;CACjE,MAAM,SAAwB,CAAC;CAE/B,KAAK,MAAM,SAAS,SAAS;EACzB,IAAI,CAAC,MAAM,YAAY,GAAG;EAC1B,MAAM,WAAW,KAAK,KAAK,WAAW,MAAM,IAAI;EAChD,MAAM,cAAc,KAAK,KAAK,UAAU,UAAU;EAClD,IAAI,CAAC,GAAG,WAAW,WAAW,GAAG;EACjC,OAAO,KAAK;GACR,MAAM,MAAM;GACZ,KAAK;GACL,SAAS,GAAG,aAAa,aAAa,OAAO;GAC7C,QAAQ,gBAAgB,QAAQ;EACpC,CAAC;CACL;CAEA,OAAO;AACX;;;;;;;AAQA,SAAgB,oBAAmC;CAC/C,MAAM,YAAY,mBAAmB;CACrC,MAAM,SAAS,WAAW,SAAS;CACnC,IAAI,OAAO,WAAW,GAAG,MAAM,IAAI,MAAM,sBAAsB,WAAW;CAC1E,OAAO;AACX;;;;;;;;;;;;;;AAeA,SAAgB,iBAAiB,QAAuB,UAA4B;CAChF,MAAM,QAAQ,OAAO;CACrB,MAAM,YAAY,SAAiB,MAAM,cAAc,MAAM,EAAE,CAAC,CAAC,SAAS,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG;CAClG,MAAM,OAAO,OACR,KAAK,UAAU,OAAO,MAAM,KAAK,OAAO,SAAS,KAAK,EAAE,OAAO,SAAS,MAAM,IAAI,EAAE,KAAK,CAAC,CAC1F,KAAK,IAAI;CAEd,OAAO;EACH;EACA;EACA;EACA;EACA;EACA;EACA;EACA,mDAAmD,OAAO,OAAO;EACjE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACJ,CAAC,CAAC,KAAK,IAAI;AACf;;;;;;;AAQA,SAAS,gBAAgB,aAAqB,WAA2B;CACrE,MAAM,QAAQ,YAAY,MAAM,SAAS,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC;CAC9D,MAAM,OAAiB,CAAC;CACxB,KAAK,MAAM,QAAQ,OAAO;EACtB,IAAI,KAAK,KAAK,MAAM,IAAI;GAAE,KAAK,KAAK,EAAE;GAAG;EAAU;EACnD,IAAI,CAAC,SAAS,KAAK,IAAI,GAAG;EAC1B,KAAK,KAAK,KAAK,KAAK,CAAC;CACzB;CACA,OAAO,KAAK,KAAK,GAAG;AACxB;;;;;;;AAQA,SAAS,SAAS,OAA4B;CAC1C,MAAM,cAAc,MAAM,QAAQ,MAAM,KAAK,CAAC,CAAC,MAAM;CACrD,MAAM,YAAY,4BAA4B,KAAK,WAAW;CAQ9D,MAAM,QAHM,cAAc,MAAM,YAAY,MAAM,GAAA,CAAI,KAAK,CAAC,IACtD,gBAAgB,aAAa,WAAW,SAAS,CAAC,IACjD,YAAY,MAAM,GAAA,CACR,KAAK,CAAC,CAAC,QAAQ,QAAQ,GAAG,CAAC,CAAC,QAAQ,OAAO,KAAK;CACjE,MAAM,gBAAgB,iBAAiB,KAAK,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,KAAK;CAClE,MAAM,WAAW,MAAM,KAAK,QAAQ,YAAY,EAAE,CAAC,CAAC,QAAQ,MAAM,GAAG;CACrE,IAAI,CAAC,eAAe,OAAO;CAC3B,IAAI,cAAc,UAAU,KAAK,OAAO;CAGxC,MAAM,MAAM,cAAc,MAAM,GAAG,GAAG;CACtC,OAAO,GAAG,IAAI,MAAM,GAAG,IAAI,YAAY,GAAG,CAAC,CAAC,CAAC,QAAQ,UAAU,EAAE,EAAE;AACvE;;;;;;;;;AAUA,SAAgB,aAAa,YAAgC;CACzD,OAAO,WAAW,QAAQ,QAAQ;EAC9B,MAAM,EAAE,cAAc,OAAO;EAC7B,OAAO,cAAc,QAAQ,GAAG,WAAW,KAAK,KAAK,YAAY,SAAS,CAAC;CAC/E,CAAC;AACL;;;;;;;;;AAmBA,SAAgB,sBAAsB,OAAe,GAAG,QAAQ,GAAqB;CACjF,OAAO,WAAW,KAAK,QAAQ;EAC3B,MAAM,QAAQ,OAAO;EACrB,MAAM,UAA6B,MAAM;EACzC,MAAM,MAAM,QAAQ,MAAM,MAAM,GAAG,WAAW,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC;EACjE,MAAM,QAAQ,OAAO,QAAQ;EAC7B,OAAO;GACH;GACA,OAAO,MAAM;GACb,QAAQ,UAAU,KAAA,IAAY,OAAO,KAAK;GAC1C,OAAO,QAAQ,KAAA;EACnB;CACJ,CAAC;AACL;;;;;;;AAQA,IAAa,kBAAkB;AAO/B,SAAS,OAAO,OAAgC;CAC5C,OAAO,WAAW,QAAQ,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,KAAK;AAC1D;AAEA,SAAS,aAAa,YAA2C;CAC7D,IAAI;EACA,MAAM,SAAkB,KAAK,MAAM,GAAG,aAAa,KAAK,KAAK,YAAY,eAAe,GAAG,OAAO,CAAC;EACnG,IAAI,UAAU,OAAO,WAAW,YAAY,WAAW,QAAQ;GAC3D,MAAM,QAAS,OAA8B;GAC7C,IAAI,SAAS,OAAO,UAAU,UAAU;IACpC,MAAM,UAAU,OAAO,QAAQ,KAAK,CAAC,CAAC,QAAQ,MAA6B,OAAO,EAAE,OAAO,QAAQ;IACnG,OAAO;KAAE,SAAS;KAAG,OAAO,OAAO,YAAY,OAAO;IAAE;GAC5D;EACJ;CACJ,QAAQ,CAGR;CACA,OAAO;AACX;AAYA,SAAgB,gBACZ,UACA,QACA,YACA,UAA+B,CAAC,GACd;CAClB,MAAM,QAAQ,OAAO;CACrB,MAAM,aAAa,KAAK,KAAK,YAAY,MAAM,SAAS;CAGxD,GAAG,UAAU,YAAY,EAAE,WAAW,KAAK,CAAC;CAS5C,MAAM,WAAW,aAAa,UAAU;CACxC,MAAM,WAAmC,CAAC;CAC1C,MAAM,OAAiB,CAAC;CAExB,MAAM,SAAS,SAAiB,UAA2B;EACvD,MAAM,SAAS,KAAK,KAAK,YAAY,OAAO;EAC5C,MAAM,SAAS,OAAO,KAAK;EAC3B,MAAM,OAAO,UAAU,MAAM;EAC7B,IAAI,GAAG,WAAW,MAAM,GAAG;GACvB,MAAM,UAAU,OAAO,GAAG,aAAa,MAAM,CAAC;GAC9C,IAAI,YAAY,QAAQ;IACpB,SAAS,WAAW;IACpB;GACJ;GACA,IAAI,SAAS,KAAA,KAAa,YAAY,QAAQ,CAAC,QAAQ,OAAO;IAG1D,KAAK,KAAK,OAAO;IACjB,SAAS,WAAW;IACpB;GACJ;EACJ;EACA,GAAG,UAAU,KAAK,QAAQ,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;EACtD,GAAG,cAAc,QAAQ,KAAK;EAC9B,SAAS,WAAW;CACxB;CAEA,IAAI,QAAQ;CACZ,IAAI,aAAa;CACjB,KAAK,MAAM,SAAS,QAAQ;EAMxB,MAAM,EAAE,UAAU,YAAY,MAAM,cAAc,MAAM,MAAM,MAAM,OAAO;EAC3E,MAAM,UAAU,OAAO;EACvB;EAKA,KAAK,MAAM,SAAS,MAAM,QAAQ;GAC9B,MAAM,KAAK,KAAK,MAAM,MAAM,KAAK,GAAG,GAAG,aAAa,KAAK,KAAK,MAAM,KAAK,KAAK,CAAC,CAAC;GAChF;EACJ;CACJ;CAEA,IAAI,MAAM,cAAc,MAAM,WAC1B,MAAM,MAAM,WAAW,iBAAiB,QAAQ,QAAQ,CAAC;CAK7D,MAAM,UAAoB,CAAC;CAC3B,KAAK,MAAM,CAAC,SAAS,SAAS,OAAO,QAAQ,UAAU,SAAS,CAAC,CAAC,GAAG;EACjE,IAAI,WAAW,UAAU;EACzB,MAAM,SAAS,KAAK,KAAK,YAAY,OAAO;EAC5C,IAAI,CAAC,GAAG,WAAW,MAAM,GAAG;EAC5B,IAAI,OAAO,GAAG,aAAa,MAAM,CAAC,MAAM,QAAQ,CAAC,QAAQ,OAAO;GAC5D,KAAK,KAAK,OAAO;GACjB;EACJ;EACA,GAAG,OAAO,MAAM;EAChB,QAAQ,KAAK,OAAO;EAEpB,KAAK,IAAI,MAAM,KAAK,QAAQ,MAAM,GAAG,IAAI,WAAW,aAAa,KAAK,GAAG,GAAG,MAAM,KAAK,QAAQ,GAAG,GAAG;GACjG,IAAI,GAAG,YAAY,GAAG,CAAC,CAAC,SAAS,GAAG;GACpC,GAAG,UAAU,GAAG;EACpB;CACJ;CAEA,GAAG,cACC,KAAK,KAAK,YAAY,eAAe,GACrC,KAAK,UAAU;EAAE,SAAS;EAAG,OAAO;CAAS,GAA4B,MAAM,CAAC,IAAI,MACpF,OACJ;CAEA,OAAO;EAAE,QAAQ;EAAO,QAAQ;EAAY;EAAM;CAAQ;AAC9D;;;;;;;AAeA,SAAgB,cACZ,QACA,QACA,YACA,UAA+B,CAAC,GACX;CACrB,MAAM,0BAAU,IAAI,IAAiC;CACrD,OAAO,OAAO,KAAK,UAAU;EACzB,MAAM,UAAU,QAAQ,IAAI,OAAO,MAAM,CAAC,SAAS;EACnD,IAAI,SAAS,OAAO;GAAE,GAAG;GAAS;GAAO,YAAY,QAAQ;EAAM;EACnE,MAAM,SAAS;GAAE;GAAO,GAAG,gBAAgB,OAAO,QAAQ,YAAY,OAAO;EAAE;EAC/E,QAAQ,IAAI,OAAO,MAAM,CAAC,WAAW,MAAM;EAC3C,OAAO;CACX,CAAC;AACL;;AAGA,IAAa,qBAAqB,CAAC,SAAS;AAE5C,eAAsB,cAAc,YAAgC,SAAmB;CAMnF,IAAI,UAAU,OAAO,GAAG;EACpB,gBAAgB;EAChB;CACJ;CAEA,QAAQ,YAAR;EACI,KAAK;GACD,MAAM,cAAc,OAAO;GAC3B;EACJ,KAAK;EACL,KAAK,KAAA;GACD,gBAAgB;GAChB;EACJ,SACI,eAAe,YAAY,oBAAoB,QAAQ;CAC/D;AACJ;;AAYA,SAAgB,uBAAuB,SAAgF;CAMnH,MAAM,EAAE,UAAU,iBAAiB;EAC/B,MAAM;GAAE,WAAW,CAAC,MAAM;GAAG,MAAM;GAAW,SAAS;GAAS,WAAW;EAAQ;EACnF;EACA,cAAc;EACd,SAAS;EACT,gBAAgB;CACpB,CAAC;CAED,OAAO;EACH,QAAQ,kBAAkB,MAAM,cAAc,CAAC,CAAC;EAChD,KAAK,MAAM,aAAa;EACxB,OAAO,MAAM,eAAe;CAChC;AACJ;;;;;;;AAQA,SAAgB,kBAAkB,QAA8C;CAC5E,MAAM,YAAY,OACb,SAAQ,UAAS,MAAM,MAAM,GAAG,CAAC,CAAC,KAAI,MAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CACrD,OAAO,OAAO;CACnB,IAAI,UAAU,WAAW,GAAG,OAAO;CASnC,IAAI,UAAU,SAAS,KAAK,GAAG,OAAO,CAAC,GAAG,UAAU;CAEpD,MAAM,UAAU,UAAU,QAAO,MAAK,CAAC,WAAW,CAAC,CAAC;CACpD,IAAI,QAAQ,SAAS,GACjB,MAAM,IAAI,WAAW,qBAAqB,QAAQ,KAAK,IAAI,EAAE,eAAe,WAAW,KAAK,IAAI,EAAE,MAAM;CAG5G,OAAO,CAAC,GAAG,IAAI,IAAI,UAAU,OAAO,UAAU,CAAC,CAAC;AACpD;AAEA,eAAe,cAAc,UAAoB,CAAC,GAAG;CAGjD,MAAM,EAAE,QAAQ,aAAa,KAAK,SAAS,UAAU,uBAAuB,OAAO;CAUnF,MAAM,aAAa,gBAAgB,KAAK,QAAQ,IAAI;CAGpD,IAAI;CACJ,IAAI;EACA,SAAS,kBAAkB;CAC/B,SAAS,KAAK;EACV,QAAQ,MAAM,GAAG,MAAM,IAAI,KAAK,OAAO,EAAE,GAAG,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,GAAG;EAC9F,QAAQ,KAAK,CAAC;CAClB;CAGA,IAAI,SAAS,eAAe,aAAa,UAAU;CAGnD,IAAI,OAAO,WAAW,GAAG;EAOrB,IAAI,CAAC,QAAQ,MAAM,OAAO;GACtB,QAAQ,MAAM,MAAM,IAAI,6DAA6D,CAAC;GACtF,QAAQ,MAAM,MAAM,OAAO,oEAAoE,OAAO,KAAK,MAAM,CAAC,CAAC,IAAI,CAAC;GACxH,QAAQ,MAAM,MAAM,OAAO,4EAA4E,CAAC;GACxG,QAAQ,MAAM,MAAM,KAAK,gBAAgB,OAAO,KAAK,MAAM,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC;GAC1E,QAAQ,KAAK,CAAC;EAClB;EAKA,MAAM,UADY,sBACF,CAAA,CAAU,KAAK,EAAE,KAAK,OAAO,aAAa;GACtD,MAAM;GACN,OAAO;GACP,SAAS;EACb,EAAE;EAEF,MAAM,EAAE,mBAAmB,MAAM,SAAS,OAAO,CAAC;GAC9C,MAAM;GACN,MAAM;GACN,SAAS;GACT;GACA,WAAW,UAA8B;IACrC,IAAI,MAAM,WAAW,GAAG,OAAO;IAC/B,OAAO;GACX;EACJ,CAAC,CAAC;EAEF,SAAS,WAAW,QAAO,QAAO,eAAe,SAAS,GAAG,CAAC;CAClE;CAGA,QAAQ,IAAI,EAAE;CACd,QAAQ,IAAI,MAAM,KAAK,WAAW,MAAM,MAAM,OAAO,MAAM,EAAE,eAAe,CAAC;CAC7E,QAAQ,IAAI,EAAE;CAEd,IAAI,UAAU;CACd,KAAK,MAAM,UAAU,cAAc,QAAQ,QAAQ,YAAY,EAAE,MAAM,CAAC,GAAG;EACvE,MAAM,QAAQ,OAAO,OAAO;EAI5B,MAAM,QAAQ,KAAK,SAAS,QAAQ,IAAI,GAAG,KAAK,KAAK,YAAY,MAAM,SAAS,CAAC,KAAK,MAAM;EAC5F,IAAI,OAAO,YAAY;GACnB,QAAQ,IAAI,KAAK,MAAM,MAAM,GAAG,EAAE,GAAG,MAAM,KAAK,MAAM,KAAK,EAAE,oBAAoB,MAAM,KAAK,KAAK,EAAE,MAAM,OAAO,OAAO,WAAW,CAAC,OAAO;GAC1I;EACJ;EACA,MAAM,aAAa,OAAO,SAAS,IAAI,OAAO,OAAO,OAAO,iBAAiB,OAAO,WAAW,IAAI,KAAK,IAAI,KAAK;EACjH,QAAQ,IAAI,KAAK,MAAM,MAAM,GAAG,EAAE,GAAG,MAAM,KAAK,MAAM,KAAK,EAAE,KAAK,OAAO,OAAO,mBAAmB,WAAW,MAAM,MAAM,KAAK,KAAK,GAAG;EACvI,KAAK,MAAM,QAAQ,OAAO,SACtB,QAAQ,IAAI,MAAM,KAAK,iBAAiB,KAAK,KAAK,OAAO,IAAI,EAAE,2BAA2B,CAAC;EAE/F,KAAK,MAAM,QAAQ,OAAO,MAAM;GAC5B,UAAU;GACV,QAAQ,IAAI,MAAM,OAAO,cAAc,KAAK,KAAK,OAAO,IAAI,EAAE,gCAAgC,CAAC;EACnG;CACJ;CACA,IAAI,SAAS;EACT,QAAQ,IAAI,MAAM,OAAO,+EAA+E,CAAC;EACzG,QAAQ,IAAI,OAAO,MAAM,KAAK,+BAA+B,GAAG;CACpE;CAIA,MAAM,EACF,iBAAiB,qBAAqB,mBAAmB,qBAAqB,mBAC9E,MAAM,OAAO;CACjB,MAAM,EAAE,yBAAyB,MAAM,OAAO,gCAAA,CAAA,MAAA,MAAA,EAAA,CAAA;CAC9C,MAAM,aAAa,SAAiB,KAAK,SAAS,QAAQ,IAAI,GAAG,KAAK,KAAK,YAAY,IAAI,CAAC,KAAK;CACjG,IAAI,SAAS;EACT,QAAQ,IAAI,EAAE;EACd,MAAM,KAAK,qBAAqB,UAAU;EAC1C,IAAI,aAAa;EACjB,KAAK,MAAM,YAAY,QAAQ;GAC3B,MAAM,QAAQ,OAAO;GACrB,MAAM,SAAS,eAAe,UAAU,YAAY,EAAE;GACtD,IAAI,UAAU,OAAO,WAAW,cAAc,aAAa;GAC3D,IAAI,CAAC,QACD,QAAQ,IAAI,MAAM,KAAK,OAAO,MAAM,MAAM,2EAA2E,CAAC;QACnH,IAAI,OAAO,WAAW,SACzB,QAAQ,IAAI,KAAK,MAAM,MAAM,GAAG,EAAE,GAAG,MAAM,KAAK,MAAM,KAAK,EAAE,mBAAmB,MAAM,KAAK,UAAU,OAAO,IAAI,CAAC,GAAG;QACjH,IAAI,OAAO,WAAW,WACzB,QAAQ,IAAI,KAAK,MAAM,MAAM,GAAG,EAAE,GAAG,MAAM,KAAK,MAAM,KAAK,EAAE,2BAA2B,MAAM,KAAK,UAAU,OAAO,IAAI,CAAC,GAAG;QAE5H,QAAQ,IAAI,MAAM,OAAO,OAAO,MAAM,MAAM,IAAI,UAAU,OAAO,IAAI,EAAE,sDAAsD,gBAAgB,kBAAkB,CAAC;EAExK;EAEA,MAAM,OAAO,aAAa,kBAAkB,oBAAoB,UAAU,GAAG,EAAE,IAAI,KAAA;EACnF,IAAI,MAAM,QAAQ,IAAI,MAAM,OAAO,KAAK,MAAM,CAAC;CACnD;CAEA,QAAQ,IAAI,EAAE;CACd,QAAQ,IAAI,MAAM,KAAK,kEAAkE,CAAC;CAG1F,QAAQ,IAAI,MAAM,KAAK,iFAAiF,CAAC;CACzG,IAAI,CAAC,SAAS;EAGV,MAAM,UAAU,OAAO,QAAO,aAAY,oBAAoB,UAAU,UAAU,MAAM,KAAK;EAC7F,IAAI,QAAQ,SAAS,GAAG;GACpB,QAAQ,IAAI,MAAM,KAAK,kFAAkF,CAAC;GAC1G,QAAQ,IAAI,OAAO,MAAM,KAAK,iCAAiC,QAAQ,KAAK,GAAG,EAAE,OAAO,GAAG;EAC/F;CACJ;CACA,QAAQ,IAAI,EAAE;AAClB;AAEA,SAAS,kBAAkB;CACvB,QAAQ,IAAI;EACd,MAAM,KAAK,eAAe,EAAE;;EAE5B,MAAM,MAAM,KAAK,OAAO,EAAE;kBACV,MAAM,KAAK,cAAc,EAAE;;EAE3C,MAAM,MAAM,KAAK,aAAa,EAAE;IAC9B,MAAM,KAAK,KAAK,SAAS,EAAE;2BACJ,OAAO,OAAO,MAAM,CAAC,CAAC,KAAI,MAAK,EAAE,KAAK,CAAC,CAAC,KAAK,IAAI,EAAE;;EAE5E,MAAM,MAAM,KAAK,SAAS,EAAE;IAC1B,MAAM,KAAK,SAAS,EAAE;;IAEtB,MAAM,KAAK,OAAO,EAAE;uDAC+B,MAAM,KAAK,qBAAqB,EAAE;;IAErF,MAAM,KAAK,aAAa,EAAE;qEACuC,MAAM,KAAK,KAAK,EAAE;;6BAE1D,OAAO,OAAO,MAAM,CAAC,CAAC,QAAO,MAAK,EAAE,SAAS,CAAC,CAAC,KAAI,MAAK,EAAE,SAAS,CAAC,CAAC,KAAK,IAAI,EAAE;;oBAEzF,MAAM,KAAK,UAAU,EAAE;6BACd,OAAO,KAAK,MAAM,CAAC,CAAC,KAAK,IAAI,EAAE;;EAE1D,MAAM,MAAM,KAAK,UAAU,EAAE;IAC3B,MAAM,KAAK,uBAAuB,EAAE;IACpC,MAAM,KAAK,sCAAsC,EAAE;IACnD,MAAM,KAAK,6CAA6C,EAAE;IAC1D,MAAM,KAAK,4CAA4C,EAAE,KAAK,MAAM,KAAK,2BAA2B,EAAE;IACtG,MAAM,KAAK,mCAAmC,EAAE,KAAK,MAAM,KAAK,iBAAiB,EAAE;CACtF;AACD"}
|
|
1
|
+
{"version":3,"file":"skills-DeUIsZcT.js","names":[],"sources":["../src/commands/skills.ts"],"sourcesContent":["import chalk from \"chalk\";\nimport { createHash } from \"crypto\";\nimport fs from \"fs\";\nimport path from \"path\";\nimport inquirer from \"inquirer\";\nimport { createRequire } from \"module\";\nimport os from \"os\";\nimport { findProjectRoot } from \"../utils/project\";\nimport { parseCommandArgs, UsageError, wantsHelp } from \"../utils/args\";\nimport { unknownCommand } from \"../utils/unknown-command\";\n\nconst require = createRequire(import.meta.url);\n\n/**\n * Supported agent environments and their target directories.\n *\n * Every agent `rebase init` writes a pointer file for has an entry here. That\n * was not true: `rebase init` writes `CLAUDE.md`, `AGENTS.md`, `.cursorrules`,\n * `.windsurfrules` and `.github/copilot-instructions.md`, and the installer\n * covered four of the five — so a Codex or Copilot user was told, by a file in\n * their own repository, to run an installer that had nothing to offer them.\n *\n * `flatLayout` marks the agents whose rules directory is loaded *whole*, into\n * every request. Writing 21 skills there put ~84,000 characters of always-on\n * context in front of every question a person asked Cursor — more than the task\n * itself, on every turn, most of it about parts of Rebase they were not\n * touching. Those agents get one short index rule instead, and the skill bodies\n * go in per-skill subdirectories the index names, which the agent reads when it\n * needs one. `indexFile` is the name of that rule.\n *\n * A subdirectory layout has no such problem: the rule file already sits beside\n * its own assets, so `references/x.md` resolves as written and nothing is\n * loaded until it is opened.\n *\n * `homeMarkers` are the directories under `~` that say the assistant is\n * installed on this machine. They answer a different question from\n * `detectDir`: a fresh scaffold has no `.claude/` of its own, so `rebase init`\n * asks the machine which assistants the developer has and pre-selects those.\n *\n * `mcp` is where the assistant reads a *project-level* MCP server list, and in\n * which shape — see `agent-setup.ts`. `projectDir` is what `REBASE_PROJECT_DIR`\n * is set to: `\".\"` where the server is spawned in the project, the editor's own\n * workspace variable where it may not be. `null` means there is no project\n * file to write: Windsurf reads only a user-level config, and one entry there\n * cannot name every project on the machine.\n */\nexport const AGENTS = {\n cursor: {\n label: \"Cursor\",\n detectDir: \".cursor\",\n homeMarkers: [\".cursor\"],\n targetDir: \".cursor/rules\",\n flatLayout: true,\n indexFile: \"rebase.mdc\",\n mcp: {\n file: \".cursor/mcp.json\",\n format: \"mcpServers\",\n projectDir: \"${workspaceFolder}\"\n },\n /** The body is not a rule file here — `indexFile` is. */\n transformFile: (skillName: string, content: string) => ({\n fileName: path.join(skillName, \"SKILL.md\"),\n content\n })\n },\n claude: {\n label: \"Claude Code\",\n detectDir: \".claude\",\n homeMarkers: [\".claude\"],\n targetDir: \".claude/skills\",\n flatLayout: false,\n // The scaffold already ships this file; writing it is then a no-op.\n mcp: {\n file: \".mcp.json\",\n format: \"mcpServers\",\n projectDir: \".\"\n },\n /** Claude Code uses the standard SKILL.md format in subdirectories. */\n transformFile: (skillName: string, content: string) => ({\n fileName: path.join(skillName, \"SKILL.md\"),\n content\n })\n },\n windsurf: {\n label: \"Windsurf\",\n detectDir: \".windsurf\",\n homeMarkers: [\".codeium/windsurf\", \".windsurf\"],\n targetDir: \".windsurf/rules\",\n flatLayout: true,\n indexFile: \"rebase.md\",\n mcp: null,\n /** The body is not a rule file here — `indexFile` is. */\n transformFile: (skillName: string, content: string) => ({\n fileName: path.join(skillName, \"SKILL.md\"),\n content\n })\n },\n gemini: {\n label: \"Gemini CLI / Antigravity\",\n detectDir: \".agents\",\n homeMarkers: [\".gemini\"],\n targetDir: \".agents/skills\",\n flatLayout: false,\n mcp: {\n file: \".gemini/settings.json\",\n format: \"mcpServers\",\n projectDir: \".\"\n },\n /** Gemini uses the standard SKILL.md format in subdirectories. */\n transformFile: (skillName: string, content: string) => ({\n fileName: path.join(skillName, \"SKILL.md\"),\n content\n })\n },\n codex: {\n label: \"Codex CLI\",\n detectDir: \".codex\",\n homeMarkers: [\".codex\"],\n // Codex reads repository skills from `.agents/skills` — every directory\n // from the working directory up to the repository root — and nothing\n // under `.codex/`. This entry used to write `.codex/skills`, so `--agent\n // codex` reported 21 skills installed into a directory Codex never\n // opens. It shares the directory with Gemini; the installer writes it\n // once.\n targetDir: \".agents/skills\",\n flatLayout: false,\n // Project-scoped, and read only once the developer trusts the project.\n mcp: {\n file: \".codex/config.toml\",\n format: \"codexToml\",\n projectDir: \".\"\n },\n /** Codex uses the standard SKILL.md format in subdirectories. */\n transformFile: (skillName: string, content: string) => ({\n fileName: path.join(skillName, \"SKILL.md\"),\n content\n })\n },\n kiro: {\n label: \"Kiro\",\n detectDir: \".kiro\",\n homeMarkers: [\".kiro\"],\n targetDir: \".kiro/steering\",\n flatLayout: true,\n indexFile: \"rebase.md\",\n mcp: {\n file: \".kiro/settings/mcp.json\",\n format: \"mcpServers\",\n projectDir: \".\"\n },\n /** The body is not a rule file here — `indexFile` is. */\n transformFile: (skillName: string, content: string) => ({\n fileName: path.join(skillName, \"SKILL.md\"),\n content\n })\n },\n copilot: {\n label: \"GitHub Copilot\",\n // Deliberately undetectable. `.github/` is the one directory in this\n // table that is not evidence of an assistant: `rebase init` writes\n // `.github/copilot-instructions.md` into every scaffold, and half the\n // repositories on the internet have a `.github/` for workflows and\n // issue templates. Listing it made bare `rebase skills install` resolve\n // to `[copilot]` in every project — so a Claude Code user who ran the\n // command `rebase init` printed got a success message and nothing in\n // `.claude/skills`. Copilot is `--agent copilot`.\n detectDir: null,\n // Same reasoning on the machine: Copilot lives inside VS Code or a\n // JetBrains IDE, and neither's directory says the extension is there.\n homeMarkers: [],\n targetDir: \".github/instructions\",\n flatLayout: true,\n indexFile: \"rebase.instructions.md\",\n mcp: {\n file: \".vscode/mcp.json\",\n format: \"vscode\",\n projectDir: \"${workspaceFolder}\"\n },\n /** The body is not a rule file here — `indexFile` is. */\n transformFile: (skillName: string, content: string) => ({\n fileName: path.join(skillName, \"SKILL.md\"),\n content\n })\n }\n} as const;\n\nexport type AgentKey = keyof typeof AGENTS;\n\n/** Narrows a string to an agent name, by the table's own keys. */\nexport function isAgentKey(value: string): value is AgentKey {\n return Object.hasOwn(AGENTS, value);\n}\n\n/** Every agent, in table order. */\nexport const AGENT_KEYS: AgentKey[] = Object.keys(AGENTS).filter(isAgentKey);\n\n/**\n * Resolve the path to the skills directory from @rebasepro/agent-skills.\n * Works in both workspace (symlink) and published (real files) layouts.\n */\nfunction getSkillsSourceDir(): string {\n const pkgJsonPath = require.resolve(\"@rebasepro/agent-skills/package.json\");\n const pkgRoot = path.dirname(pkgJsonPath);\n const skillsDir = path.join(pkgRoot, \"skills\");\n\n if (!fs.existsSync(skillsDir)) {\n throw new Error(\n `Skills directory not found at ${skillsDir}. ` +\n \"Make sure @rebasepro/agent-skills is installed.\"\n );\n }\n\n return skillsDir;\n}\n\nexport interface LoadedSkill {\n name: string;\n /** Absolute path of the skill's source directory. */\n dir: string;\n content: string;\n /** Every file the skill ships besides SKILL.md, relative to `dir`. */\n assets: string[];\n}\n\n/**\n * Everything a skill ships alongside its SKILL.md — the `references/` tree the\n * Agent Skills format uses for progressive disclosure.\n *\n * These used to be dropped on install, because the installer read exactly\n * `<skill>/SKILL.md` and nothing else. That left `rebase-design-language`\n * telling the agent three separate times to read `references/view-patterns.md`\n * — 379 lines of view skeletons — in a project where the file had never\n * landed, and the instruction it carries is \"extend an existing pattern; do not\n * invent a layout\".\n */\nfunction loadSkillAssets(skillDir: string): string[] {\n const found: string[] = [];\n\n const walk = (dir: string, prefix: string) => {\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n // Dotfiles are bookkeeping — `.gitkeep` is what holds the empty\n // `references/` directories in git — and install nothing.\n if (entry.name.startsWith(\".\")) continue;\n const rel = prefix ? path.join(prefix, entry.name) : entry.name;\n if (entry.isDirectory()) walk(path.join(dir, entry.name), rel);\n else if (rel !== \"SKILL.md\") found.push(rel);\n }\n };\n\n walk(skillDir, \"\");\n return found.sort();\n}\n\n/** Read all skill directories and return their names, content and assets. */\nexport function loadSkills(skillsDir: string): LoadedSkill[] {\n const entries = fs.readdirSync(skillsDir, { withFileTypes: true });\n const skills: LoadedSkill[] = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n const skillDir = path.join(skillsDir, entry.name);\n const skillMdPath = path.join(skillDir, \"SKILL.md\");\n if (!fs.existsSync(skillMdPath)) continue;\n skills.push({\n name: entry.name,\n dir: skillDir,\n content: fs.readFileSync(skillMdPath, \"utf-8\"),\n assets: loadSkillAssets(skillDir)\n });\n }\n\n return skills;\n}\n\n/**\n * The skills this CLI ships, from its own `@rebasepro/agent-skills`.\n *\n * Throws rather than exiting, so `rebase init` can report a missing bundle as a\n * warning and still finish the scaffold.\n */\nexport function loadBundledSkills(): LoadedSkill[] {\n const skillsDir = getSkillsSourceDir();\n const skills = loadSkills(skillsDir);\n if (skills.length === 0) throw new Error(`No skills found in ${skillsDir}`);\n return skills;\n}\n\n/**\n * The one always-on rule a flat-layout agent gets, in place of every skill.\n *\n * Cursor and Windsurf load their whole rules directory into each request. With\n * a rule file per skill that was ~84,000 characters of Rebase reference in\n * front of every question, whether or not the question was about Rebase — and\n * an instruction an assistant skims is an instruction it does not follow.\n *\n * So the always-on part is this: a table of what exists and where to read it.\n * `alwaysApply: true` because knowing the skills are there costs a few hundred\n * characters and is the whole point; the bodies stay on disk until the agent\n * opens one.\n */\nexport function renderSkillIndex(skills: LoadedSkill[], agentKey: AgentKey): string {\n const agent = AGENTS[agentKey];\n const bodyPath = (name: string) => agent.transformFile(name, \"\").fileName.split(path.sep).join(\"/\");\n const rows = skills\n .map((skill) => `| \\`${skill.name}\\` | ${describe(skill)} | \\`${bodyPath(skill.name)}\\` |`)\n .join(\"\\n\");\n\n return [\n \"---\",\n \"description: Rebase — the skills index. Read the file named for the task before writing Rebase code.\",\n \"alwaysApply: true\",\n \"---\",\n \"\",\n \"# Rebase skills\",\n \"\",\n `This project uses [Rebase](https://rebase.pro). ${skills.length} reference skills are`,\n \"installed beside this file. **Read the one that covers the task before writing\",\n \"code** — they are the difference between a collection that compiles and one that\",\n \"does not.\",\n \"\",\n \"| Skill | Covers | Read |\",\n \"|---|---|---|\",\n rows,\n \"\",\n \"Start with `rebase-basics` if you are not sure: it opens with the recipes for\",\n \"adding a collection, a function and an RLS rule, and names the commands.\",\n \"\"\n ].join(\"\\n\");\n}\n\n/**\n * The body of a YAML block scalar, given the offset of its `description:` line.\n *\n * Everything indented more than the key belongs to the value; the first line\n * that is not blank and not indented ends it.\n */\nfunction blockScalarBody(frontMatter: string, keyOffset: number): string {\n const lines = frontMatter.slice(keyOffset).split(\"\\n\").slice(1);\n const body: string[] = [];\n for (const line of lines) {\n if (line.trim() === \"\") { body.push(\"\"); continue; }\n if (!/^[ \\t]/.test(line)) break;\n body.push(line.trim());\n }\n return body.join(\" \");\n}\n\n/**\n * A skill's one-line summary, from its own front matter.\n *\n * Read rather than written here so a new skill needs no edit in this file, and\n * truncated because the index is only worth having while it stays short.\n */\nfunction describe(skill: LoadedSkill): string {\n const frontMatter = skill.content.split(\"---\")[1] ?? \"\";\n const described = /^description:[ \\t]*(.*)$/m.exec(frontMatter);\n // `description: |` (or `>`) is a YAML block scalar: the value is the\n // indented lines that follow, and capturing the line itself captured the\n // `|`. That rendered an empty \"Covers\" cell for `rebase-design-language`,\n // the one skill whose description says agents MUST read it.\n const raw = /^[|>][-+]?$/.test((described?.[1] ?? \"\").trim())\n ? blockScalarBody(frontMatter, described?.index ?? 0)\n : (described?.[1] ?? \"\");\n const text = raw.trim().replace(/\\s+/g, \" \").replace(/\\|/g, \"\\\\|\");\n const firstSentence = /^.*?\\.(?:\\s|$)/.exec(text)?.[0]?.trim() ?? text;\n const fallback = skill.name.replace(/^rebase-/, \"\").replace(/-/g, \" \");\n if (!firstSentence) return fallback;\n if (firstSentence.length <= 140) return firstSentence;\n // Cut at a word boundary. A description sliced mid-word (\"using the collect\")\n // reads as a corrupted file rather than as a summary.\n const cut = firstSentence.slice(0, 140);\n return `${cut.slice(0, cut.lastIndexOf(\" \")).replace(/[,;:]$/, \"\")}…`;\n}\n\n/**\n * Detect which agent environments already exist in the project.\n *\n * A `detectDir` has to be evidence *the user* created, not something a scaffold\n * ships. An agent whose only marker fails that test declares `detectDir: null`\n * and is reachable by `--agent` alone; guessing wrong here is worse than not\n * guessing, because the wrong guess installs 21 files and reports success.\n */\nexport function detectAgents(projectDir: string): AgentKey[] {\n return AGENT_KEYS.filter((key) => {\n const { detectDir } = AGENTS[key];\n return detectDir !== null && fs.existsSync(path.join(projectDir, detectDir));\n });\n}\n\n/** What `detectInstalledAgents` found for one assistant. */\nexport interface InstalledAgent {\n key: AgentKey;\n label: string;\n /** The home directory checked, as `~/…` — the one found, else the first. */\n marker: string | null;\n found: boolean;\n}\n\n/**\n * Which assistants are installed on this machine, from their home directories.\n *\n * The question `rebase init` needs answered, and one `detectAgents` cannot: a\n * project that does not exist yet has no `.claude/` in it. What the machine has\n * is only a default — the developer confirms it — so a false positive costs an\n * unticked box, not 21 files nobody asked for.\n */\nexport function detectInstalledAgents(home: string = os.homedir()): InstalledAgent[] {\n return AGENT_KEYS.map((key) => {\n const agent = AGENTS[key];\n const markers: readonly string[] = agent.homeMarkers;\n const hit = markers.find((m) => fs.existsSync(path.join(home, m)));\n const shown = hit ?? markers[0];\n return {\n key,\n label: agent.label,\n marker: shown === undefined ? null : `~/${shown}`,\n found: hit !== undefined\n };\n });\n}\n\n/** Install skills for a specific agent into the project directory. */\n/**\n * The file in each target directory that records what the installer wrote:\n * relative path → sha256 of the bytes written. A dotfile, so no agent loads it\n * as a rule.\n */\nexport const SKILLS_MANIFEST = \".rebase-skills.json\";\n\ninterface SkillsManifest {\n version: 1;\n files: Record<string, string>;\n}\n\nfunction sha256(bytes: Buffer | string): string {\n return createHash(\"sha256\").update(bytes).digest(\"hex\");\n}\n\nfunction readManifest(targetBase: string): SkillsManifest | null {\n try {\n const parsed: unknown = JSON.parse(fs.readFileSync(path.join(targetBase, SKILLS_MANIFEST), \"utf-8\"));\n if (parsed && typeof parsed === \"object\" && \"files\" in parsed) {\n const files = (parsed as { files: unknown }).files;\n if (files && typeof files === \"object\") {\n const entries = Object.entries(files).filter((e): e is [string, string] => typeof e[1] === \"string\");\n return { version: 1, files: Object.fromEntries(entries) };\n }\n }\n } catch {\n // No manifest, or one that is not ours: the first install, or one made\n // before manifests existed.\n }\n return null;\n}\n\n/** What one agent's install did. */\nexport interface AgentInstallResult {\n skills: number;\n assets: number;\n /** Files left as they are because they were edited since the last install (relative to the target dir). */\n kept: string[];\n /** Files of skills the bundle no longer ships, removed because nobody edited them. */\n removed: string[];\n}\n\nexport function installForAgent(\n agentKey: AgentKey,\n skills: LoadedSkill[],\n projectDir: string,\n options: { force?: boolean } = {}\n): AgentInstallResult {\n const agent = AGENTS[agentKey];\n const targetBase = path.join(projectDir, agent.targetDir);\n\n // Ensure the target directory exists\n fs.mkdirSync(targetBase, { recursive: true });\n\n // A re-run used to overwrite every file unconditionally and never remove\n // one: a note a team appended to an installed skill and committed — as\n // the command tells them to — vanished on the next `skills install`, and a\n // skill a release retired stayed installed beside its replacement. The\n // manifest records what was written, so an edit is told apart from an\n // older bundle's copy. A file with no record (an install from before\n // manifests) is overwritten, as before.\n const previous = readManifest(targetBase);\n const recorded: Record<string, string> = {};\n const kept: string[] = [];\n\n const place = (relPath: string, bytes: Buffer | string) => {\n const target = path.join(targetBase, relPath);\n const wanted = sha256(bytes);\n const last = previous?.files[relPath];\n if (fs.existsSync(target)) {\n const current = sha256(fs.readFileSync(target));\n if (current === wanted) {\n recorded[relPath] = wanted;\n return;\n }\n if (last !== undefined && current !== last && !options.force) {\n // Edited since it was installed: left alone, and still recorded\n // as what was installed, so the next run says so again.\n kept.push(relPath);\n recorded[relPath] = last;\n return;\n }\n }\n fs.mkdirSync(path.dirname(target), { recursive: true });\n fs.writeFileSync(target, bytes);\n recorded[relPath] = wanted;\n };\n\n let count = 0;\n let assetCount = 0;\n for (const skill of skills) {\n // Every layout now writes the body into a per-skill subdirectory, so a\n // link the skill spells `references/x.md` resolves as written and no\n // rewriting is needed. What differs is whether that file is also the\n // agent's *rule* file (subdirectory layouts) or something the index\n // points at (flat ones).\n const { fileName, content } = agent.transformFile(skill.name, skill.content);\n place(fileName, content);\n count++;\n\n // A skill's assets always land in a directory named after the skill,\n // whatever the rule file's layout, so two skills' `references/` trees\n // cannot collide in a flat target directory.\n for (const asset of skill.assets) {\n place(path.join(skill.name, asset), fs.readFileSync(path.join(skill.dir, asset)));\n assetCount++;\n }\n }\n\n if (agent.flatLayout && agent.indexFile) {\n place(agent.indexFile, renderSkillIndex(skills, agentKey));\n }\n\n // Retired files: removed when they are exactly what was installed, kept\n // (and reported) when someone edited them.\n const removed: string[] = [];\n for (const [relPath, last] of Object.entries(previous?.files ?? {})) {\n if (relPath in recorded) continue;\n const target = path.join(targetBase, relPath);\n if (!fs.existsSync(target)) continue;\n if (sha256(fs.readFileSync(target)) !== last && !options.force) {\n kept.push(relPath);\n continue;\n }\n fs.rmSync(target);\n removed.push(relPath);\n // Empty directories the removal leaves behind, up to the target dir.\n for (let dir = path.dirname(target); dir.startsWith(targetBase + path.sep); dir = path.dirname(dir)) {\n if (fs.readdirSync(dir).length > 0) break;\n fs.rmdirSync(dir);\n }\n }\n\n fs.writeFileSync(\n path.join(targetBase, SKILLS_MANIFEST),\n JSON.stringify({ version: 1, files: recorded } satisfies SkillsManifest, null, 2) + \"\\n\",\n \"utf-8\"\n );\n\n return { skills: count, assets: assetCount, kept, removed };\n}\n\n/** What `installSkills` did for one agent. */\nexport interface SkillsInstallResult extends AgentInstallResult {\n agent: AgentKey;\n /** An earlier agent in the same run that already wrote this directory. */\n sharedWith?: AgentKey;\n}\n\n/**\n * Install for several agents, writing each target directory once.\n *\n * Gemini and Codex both read `.agents/skills`; installing twice would write the\n * same 21 files twice and report two installs of one directory.\n */\nexport function installSkills(\n agents: readonly AgentKey[],\n skills: LoadedSkill[],\n projectDir: string,\n options: { force?: boolean } = {}\n): SkillsInstallResult[] {\n const written = new Map<string, SkillsInstallResult>();\n return agents.map((agent) => {\n const earlier = written.get(AGENTS[agent].targetDir);\n if (earlier) return { ...earlier, agent, sharedWith: earlier.agent };\n const result = { agent, ...installForAgent(agent, skills, projectDir, options) };\n written.set(AGENTS[agent].targetDir, result);\n return result;\n });\n}\n\n/** Everything the switch below dispatches, for the did-you-mean. */\nexport const SKILLS_SUBCOMMANDS = [\"install\"] as const;\n\nexport async function skillsCommand(subcommand: string | undefined, rawArgs: string[]) {\n // `--help` cannot reach `skillsInstall`. `cli.ts` only rewrites the\n // subcommand to `\"--help\"` when none was named, so `rebase skills install\n // --help` used to run the install: it detected the agents and overwrote\n // `.claude/skills/*/SKILL.md`, `.cursor/rules/*.mdc` and the rest. A flag\n // that prints text must not write files.\n if (wantsHelp(rawArgs)) {\n printSkillsHelp();\n return;\n }\n\n switch (subcommand) {\n case \"install\":\n await skillsInstall(rawArgs);\n break;\n case \"--help\":\n case undefined:\n printSkillsHelp();\n break;\n default:\n unknownCommand(subcommand, SKILLS_SUBCOMMANDS, \"skills\");\n }\n}\n\n/**\n * Agents named explicitly on the command line, e.g. `--agent claude --agent cursor`\n * (also accepts a comma-separated list, and `all`). Returns null when none were\n * given.\n */\nexport function parseAgentFlags(rawArgs: string[]): AgentKey[] | null {\n return parseSkillsInstallLine(rawArgs).agents;\n}\n\n/** `rebase skills install`'s whole line: the agents it names, `--mcp` and `--force`. */\nexport function parseSkillsInstallLine(rawArgs: string[]): { agents: AgentKey[] | null; mcp: boolean; force: boolean } {\n // Strict, and before anything is written. This used to scan `rawArgs` for\n // `--agent` and ignore every other token, so `rebase skills install\n // --frobnicate --agent claude` exited 0 after writing 21 files — the CLI's\n // other families reject an unknown flag, and an installer is the last place\n // to guess what the person meant.\n const { flags } = parseCommandArgs({\n spec: { \"--agent\": [String], \"-a\": \"--agent\", \"--mcp\": Boolean, \"--force\": Boolean },\n rawArgs,\n commandWords: 2,\n command: \"skills install\",\n maxPositionals: 0\n });\n\n return {\n agents: resolveAgentNames(flags[\"--agent\"] ?? []),\n mcp: flags[\"--mcp\"] === true,\n force: flags[\"--force\"] === true\n };\n}\n\n/**\n * The agents a list of `--agent` values names, or null when it names none.\n *\n * Shared by `rebase skills install` and `rebase init`, so both accept the same\n * spellings. Throws a UsageError on a name that is not an agent.\n */\nexport function resolveAgentNames(values: readonly string[]): AgentKey[] | null {\n const requested = values\n .flatMap(value => value.split(\",\").map(v => v.trim()))\n .filter(Boolean);\n if (requested.length === 0) return null;\n\n // `all` exists for the non-interactive case. Detection cannot help there: a\n // scaffolded project ships `.cursorrules`, `CLAUDE.md`, `.windsurfrules`,\n // `AGENTS.md` and `.github/copilot-instructions.md` all at once, so every\n // pointer file is present and none of them says which assistant the\n // developer actually uses. Guessing from them would install several agents'\n // skills unasked; refusing leaves a scripted setup with no way through.\n // Naming `all` is the developer saying it out loud.\n if (requested.includes(\"all\")) return [...AGENT_KEYS];\n\n const unknown = requested.filter(a => !isAgentKey(a));\n if (unknown.length > 0) {\n throw new UsageError(`Unknown agent(s): ${unknown.join(\", \")}. Available: ${AGENT_KEYS.join(\", \")}, all`);\n }\n // Deduplicated, in the order given: `--agent claude,claude` is one install.\n return [...new Set(requested.filter(isAgentKey))];\n}\n\nasync function skillsInstall(rawArgs: string[] = []) {\n // Parse the line before anything else touches the disk: a bad flag must\n // cost nothing, and everything below this writes or resolves paths.\n const { agents: namedAgents, mcp: withMcp, force } = parseSkillsInstallLine(rawArgs);\n\n // The project root, not the cwd. Agent skills belong beside the repository's\n // other agent configuration — `.claude/`, `.cursor/` — which is both what\n // `detectAgents` looks for and where an assistant reads them from. Resolving\n // against wherever the command happened to be typed put them in\n // `backend/.claude/skills` when run from `backend/`, detected no agent\n // there, and left the skills somewhere nothing would look. Outside a project\n // the cwd is still the honest answer: this command is useful in a repository\n // that is not a Rebase one.\n const projectDir = findProjectRoot() ?? process.cwd();\n\n // 1. Load skills from @rebasepro/agent-skills\n let skills: LoadedSkill[];\n try {\n skills = loadBundledSkills();\n } catch (err) {\n console.error(`${chalk.red.bold(\"ERROR\")} ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n\n // 2. Explicit --agent wins; otherwise detect existing agent environments\n let agents = namedAgents ?? detectAgents(projectDir);\n\n // 3. If none detected, ask the user\n if (agents.length === 0) {\n // A scaffolded project ships `.cursorrules`, `CLAUDE.md`, `AGENTS.md`\n // and `.github/copilot-instructions.md`, but none of the *directories*\n // detectAgents looks for, so a fresh project always lands here — which\n // is correct: those files say what `rebase init` writes, not what the\n // developer uses. On a non-TTY that used to abort with a raw\n // ExitPromptError.\n if (!process.stdin.isTTY) {\n console.error(chalk.red(\"Cannot prompt: this is a non-interactive terminal (no TTY).\"));\n console.error(chalk.yellow(` Name the agents explicitly, e.g. rebase skills install --agent ${Object.keys(AGENTS)[0]}`));\n console.error(chalk.yellow(\" Or install for every supported agent: rebase skills install --agent all\"));\n console.error(chalk.gray(` Available: ${Object.keys(AGENTS).join(\", \")}`));\n process.exit(1);\n }\n\n // The project says nothing, but the machine may: pre-tick the agents\n // whose home directory exists, as `rebase init` does.\n const installed = detectInstalledAgents();\n const choices = installed.map(({ key, label, found }) => ({\n name: label,\n value: key,\n checked: found\n }));\n\n const { selectedAgents } = await inquirer.prompt([{\n type: \"checkbox\",\n name: \"selectedAgents\",\n message: \"No AI agent configuration in this project. Which agents do you use?\",\n choices,\n validate: (input: readonly unknown[]) => {\n if (input.length === 0) return \"Please select at least one agent.\";\n return true;\n }\n }]);\n\n agents = AGENT_KEYS.filter(key => selectedAgents.includes(key));\n }\n\n // 4. Install skills for each agent\n console.log(\"\");\n console.log(chalk.gray(` Found ${chalk.white(skills.length)} Rebase skills`));\n console.log(\"\");\n\n let anyKept = false;\n for (const result of installSkills(agents, skills, projectDir, { force })) {\n const agent = AGENTS[result.agent];\n // Relative to where the command was typed, now that the destination is\n // the project root rather than the cwd — otherwise `.claude/skills`\n // names a directory that is not the one it wrote to.\n const shown = path.relative(process.cwd(), path.join(projectDir, agent.targetDir)) || agent.targetDir;\n if (result.sharedWith) {\n console.log(` ${chalk.green(\"✓\")} ${chalk.bold(agent.label)} — reads the same ${chalk.gray(shown)} as ${AGENTS[result.sharedWith].label}`);\n continue;\n }\n const withAssets = result.assets > 0 ? ` (+ ${result.assets} reference file${result.assets === 1 ? \"\" : \"s\"})` : \"\";\n console.log(` ${chalk.green(\"✓\")} ${chalk.bold(agent.label)} — ${result.skills} skills installed${withAssets} to ${chalk.gray(shown)}`);\n for (const file of result.removed) {\n console.log(chalk.gray(` − removed ${path.join(shown, file)} (no longer in the bundle)`));\n }\n for (const file of result.kept) {\n anyKept = true;\n console.log(chalk.yellow(` ! kept ${path.join(shown, file)}: edited since it was installed`));\n }\n }\n if (anyKept) {\n console.log(chalk.yellow(\" Edited files were left as they are. To replace them with the bundle's copy:\"));\n console.log(` ${chalk.cyan(\"rebase skills install --force\")}`);\n }\n\n // The MCP server, as `rebase init --agent` registers it. Imported here\n // rather than at the top: agent-setup imports this module.\n const {\n MCP_SERVER_NAME, ensureMcpDependency, mcpDependencyNote, mcpServerRegistered, writeMcpConfig\n } = await import(\"./agent-setup\");\n const { detectPackageManager } = await import(\"../utils/package-manager\");\n const shownFile = (file: string) => path.relative(process.cwd(), path.join(projectDir, file)) || file;\n if (withMcp) {\n console.log(\"\");\n const pm = detectPackageManager(projectDir);\n let registered = false;\n for (const agentKey of agents) {\n const agent = AGENTS[agentKey];\n const result = writeMcpConfig(agentKey, projectDir, pm);\n if (result && result.status !== \"unreadable\") registered = true;\n if (!result) {\n console.log(chalk.gray(` · ${agent.label} has no project-level MCP config — add @rebasepro/mcp in its MCP settings.`));\n } else if (result.status === \"added\") {\n console.log(` ${chalk.green(\"✓\")} ${chalk.bold(agent.label)} — MCP server in ${chalk.gray(shownFile(result.file))}`);\n } else if (result.status === \"present\") {\n console.log(` ${chalk.green(\"✓\")} ${chalk.bold(agent.label)} — MCP server already in ${chalk.gray(shownFile(result.file))}`);\n } else {\n console.log(chalk.yellow(` ! ${agent.label}: ${shownFile(result.file)} is not plain JSON, so it was left alone — add the \"${MCP_SERVER_NAME}\" server by hand.`));\n }\n }\n // The configs run the project's own copy of the server.\n const note = registered ? mcpDependencyNote(ensureMcpDependency(projectDir), pm) : undefined;\n if (note) console.log(chalk.yellow(` ${note}`));\n }\n\n console.log(\"\");\n console.log(chalk.gray(\" Skills are project-local. Commit them to share with your team.\"));\n // The skills ship inside the CLI's own pinned `@rebasepro/agent-skills`,\n // so a re-run reinstalls that version; newer ones come with a newer CLI.\n console.log(chalk.gray(\" Re-run this command to restore them. Upgrade @rebasepro/cli for newer skills.\"));\n if (!withMcp) {\n // Only the agents whose config does not have the server yet: on a\n // project `init --agent` set up, a refresh says nothing about it.\n const missing = agents.filter(agentKey => mcpServerRegistered(agentKey, projectDir) === false);\n if (missing.length > 0) {\n console.log(chalk.gray(\" To register the Rebase MCP server for them too, as `rebase init --agent` does:\"));\n console.log(` ${chalk.cyan(`rebase skills install --agent ${missing.join(\",\")} --mcp`)}`);\n }\n }\n console.log(\"\");\n}\n\nfunction printSkillsHelp() {\n console.log(`\n${chalk.bold(\"rebase skills\")} — Manage AI agent skills\n\n${chalk.green.bold(\"Usage\")}\n rebase skills ${chalk.blue(\"<subcommand>\")}\n\n${chalk.green.bold(\"Subcommands\")}\n ${chalk.blue.bold(\"install\")} Install Rebase agent skills for your AI coding assistant\n Supports: ${Object.values(AGENTS).map(a => a.label).join(\", \")}\n\n${chalk.green.bold(\"Options\")}\n ${chalk.blue(\"--force\")} Replace installed skill files you edited, and remove edited files of\n skills the bundle no longer ships. Without it, edits are kept.\n ${chalk.blue(\"--mcp\")} Also register the Rebase MCP server in each agent's project config\n (.mcp.json, .cursor/mcp.json, …), as ${chalk.cyan(\"rebase init --agent\")} does.\n Servers already in the file are kept.\n ${chalk.blue(\"--agent, -a\")} Agent(s) to install for, skipping detection and the prompt.\n Repeat the flag or pass a comma-separated list, or ${chalk.bold(\"all\")}.\n Required without a TTY: detection looks for an agent's own\n directory (${Object.values(AGENTS).filter(a => a.detectDir).map(a => a.detectDir).join(\", \")}),\n and a fresh scaffold has none. GitHub Copilot is never detected\n — ${chalk.gray(\".github/\")} is not evidence anyone uses it — so name it.\n Available: ${Object.keys(AGENTS).join(\", \")}, all\n\n${chalk.green.bold(\"Examples\")}\n ${chalk.cyan(\"rebase skills install\")}\n ${chalk.cyan(\"rebase skills install --agent claude\")}\n ${chalk.cyan(\"rebase skills install --agent claude,cursor\")}\n ${chalk.cyan(\"rebase skills install --agent cursor --mcp\")} ${chalk.gray(\"# skills + the MCP server\")}\n ${chalk.cyan(\"rebase skills install --agent all\")} ${chalk.gray(\"# scripted / CI\")}\n`);\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as getPMCommands, t as detectPackageManager } from "./package-manager-DSEOwTqM.js";
|
|
2
|
-
import { d as readEnvFile, o as findEnvFile, p as requireProjectRoot } from "./project-
|
|
3
|
-
import {
|
|
4
|
-
import { t as
|
|
2
|
+
import { C as wantsHelp, b as parseCommandArgs, c as findProjectRoot, d as readEnvFile, o as findEnvFile, p as requireProjectRoot } from "./project-g4K6kV1t.js";
|
|
3
|
+
import { t as DEFAULT_BUNDLE_DIR } from "./bundle-DlqkDYSe.js";
|
|
4
|
+
import { t as invokedRebaseCommand } from "./invoked-command-CG_rIa_o.js";
|
|
5
5
|
import chalk from "chalk";
|
|
6
6
|
import fs from "fs";
|
|
7
7
|
import path from "path";
|
|
@@ -17,6 +17,19 @@ import { execa } from "execa";
|
|
|
17
17
|
* `rebase.json`) this falls back to the backend workspace's own `start` script,
|
|
18
18
|
* which is what such a project has always used.
|
|
19
19
|
*/
|
|
20
|
+
/**
|
|
21
|
+
* The help's line that runs `start` on the database `rebase dev` uses, spelled
|
|
22
|
+
* as the reader can type it.
|
|
23
|
+
*
|
|
24
|
+
* In a project, the project's package manager: a scaffold has `rebase` in
|
|
25
|
+
* `node_modules/.bin`, not on PATH, so a bare `rebase` is "command not found" —
|
|
26
|
+
* `pnpm exec rebase …`, as `missingDatabaseUrl` and the CLI's other hints say
|
|
27
|
+
* it. Outside one, the way this CLI was started (`invokedRebaseCommand`).
|
|
28
|
+
*/
|
|
29
|
+
function startHelpRunLine(projectRoot = findProjectRoot()) {
|
|
30
|
+
const rebase = (args) => (projectRoot ? getPMCommands(detectPackageManager(projectRoot)).exec("rebase", args) : [...invokedRebaseCommand(), ...args]).join(" ");
|
|
31
|
+
return `DATABASE_URL="$(${rebase(["db", "url"])})" ${rebase(["start"])}`;
|
|
32
|
+
}
|
|
20
33
|
function printHelp() {
|
|
21
34
|
console.log(`
|
|
22
35
|
${chalk.bold("rebase start")} — run a built bundle
|
|
@@ -36,7 +49,7 @@ register becomes the admin. For a production server, run it with
|
|
|
36
49
|
NODE_ENV=production; it says so at start when it is not one.
|
|
37
50
|
|
|
38
51
|
It needs a DATABASE_URL, and starts no database of its own. To run it on the
|
|
39
|
-
database ${chalk.cyan("rebase dev")} uses: ${chalk.cyan(
|
|
52
|
+
database ${chalk.cyan("rebase dev")} uses: ${chalk.cyan(startHelpRunLine())}
|
|
40
53
|
|
|
41
54
|
Build first with ${chalk.cyan("rebase build")}.
|
|
42
55
|
`.trim());
|
|
@@ -207,14 +220,14 @@ async function startCommand(rawArgs = []) {
|
|
|
207
220
|
quiet: true
|
|
208
221
|
});
|
|
209
222
|
if (!process.env.DATABASE_URL?.trim()) {
|
|
210
|
-
const { devDatabaseKind } = await import("./prepare-
|
|
223
|
+
const { devDatabaseKind } = await import("./prepare-1rVNd2PF.js");
|
|
211
224
|
const missing = missingDatabaseUrl(process.env, devDatabaseKind(projectRoot), getPMCommands(detectPackageManager(projectRoot)));
|
|
212
225
|
if (missing) {
|
|
213
226
|
for (const line of missing) console.error(line);
|
|
214
227
|
process.exit(1);
|
|
215
228
|
}
|
|
216
229
|
}
|
|
217
|
-
const { findRunningDaemon } = await import("./daemon-
|
|
230
|
+
const { findRunningDaemon } = await import("./daemon-DDMRbz4T.js").then((n) => n.t);
|
|
218
231
|
const managedEnv = managedDatabaseRuntimeEnv(process.env.DATABASE_URL, await findRunningDaemon(projectRoot), process.env);
|
|
219
232
|
if (managedEnv.REBASE_DB_POOL_MAX) {
|
|
220
233
|
Object.assign(process.env, managedEnv);
|
|
@@ -303,4 +316,4 @@ async function startWorkspaceBackend(projectRoot, env) {
|
|
|
303
316
|
//#endregion
|
|
304
317
|
export { startCommand };
|
|
305
318
|
|
|
306
|
-
//# sourceMappingURL=start-
|
|
319
|
+
//# sourceMappingURL=start-RzZqDroW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start-RzZqDroW.js","names":[],"sources":["../src/commands/start.ts"],"sourcesContent":["/**\n * CLI command: rebase start\n *\n * Runs a built bundle through the Rebase runtime — the same path the official\n * container image takes, so what you test locally is what a deployment runs.\n *\n * When there is no bundle (an ejected backend, or a project that has not adopted\n * `rebase.json`) this falls back to the backend workspace's own `start` script,\n * which is what such a project has always used.\n */\nimport fs from \"fs\";\nimport path from \"path\";\nimport chalk from \"chalk\";\nimport { execa } from \"execa\";\nimport { requireProjectRoot, findEnvFile, findProjectRoot, readEnvFile } from \"../utils/project\";\nimport { invokedRebaseCommand } from \"../utils/invoked-command\";\nimport { parseCommandArgs, wantsHelp } from \"../utils/args\";\nimport { detectPackageManager, getPMCommands, type PMCommands } from \"../utils/package-manager\";\nimport { DEFAULT_BUNDLE_DIR } from \"../bundle\";\nimport type { RebaseBundleStatic } from \"@rebasepro/types\";\nimport type { DevDatabase } from \"../dev-db/resolve\";\nimport type { DaemonState } from \"../dev-db/state\";\nimport { MANAGED_POOL_MAX } from \"../dev-db/constraints\";\n\n/**\n * The help's line that runs `start` on the database `rebase dev` uses, spelled\n * as the reader can type it.\n *\n * In a project, the project's package manager: a scaffold has `rebase` in\n * `node_modules/.bin`, not on PATH, so a bare `rebase` is \"command not found\" —\n * `pnpm exec rebase …`, as `missingDatabaseUrl` and the CLI's other hints say\n * it. Outside one, the way this CLI was started (`invokedRebaseCommand`).\n */\nexport function startHelpRunLine(projectRoot: string | null = findProjectRoot()): string {\n const rebase = (args: string[]): string => (projectRoot\n ? getPMCommands(detectPackageManager(projectRoot)).exec(\"rebase\", args)\n : [...invokedRebaseCommand(), ...args]).join(\" \");\n return `DATABASE_URL=\"$(${rebase([\"db\", \"url\"])})\" ${rebase([\"start\"])}`;\n}\n\nfunction printHelp(): void {\n console.log(`\n${chalk.bold(\"rebase start\")} — run a built bundle\n\n${chalk.bold(\"Usage\")}\n rebase start [options]\n\n${chalk.bold(\"Options\")}\n --bundle <dir> Bundle directory (default: ${DEFAULT_BUNDLE_DIR})\n --workspace Run the backend workspace's own start script\n -h, --help Show this help\n\nRuns the bundle the way a deployment does, reading PORT and the rest of .env,\nin whatever NODE_ENV the shell or .env sets. A scaffolded .env says\ndevelopment, which keeps development behaviour on — the first account to\nregister becomes the admin. For a production server, run it with\nNODE_ENV=production; it says so at start when it is not one.\n\nIt needs a DATABASE_URL, and starts no database of its own. To run it on the\ndatabase ${chalk.cyan(\"rebase dev\")} uses: ${chalk.cyan(startHelpRunLine())}\n\nBuild first with ${chalk.cyan(\"rebase build\")}.\n`.trim());\n}\n\n/** The NODE_ENV the runtime will see, and where it comes from. */\nexport interface StartNodeEnv {\n value: string | undefined;\n source: \"shell\" | \".env\" | \"unset\";\n}\n\n/**\n * What NODE_ENV the server will boot in. The shell wins — dotenv never\n * overrides a variable that is already set — then `.env`.\n */\nexport function startNodeEnv(projectRoot: string): StartNodeEnv {\n if (process.env.NODE_ENV !== undefined) return { value: process.env.NODE_ENV, source: \"shell\" };\n const fromFile = readEnvFile(projectRoot).NODE_ENV;\n return fromFile !== undefined ? { value: fromFile, source: \".env\" } : { value: undefined, source: \"unset\" };\n}\n\n/**\n * The banner for a `rebase start` that is not a production server, or `null`.\n *\n * Not forced to production: the scaffold's `.env` points at a loopback\n * database, which a production boot refuses, so forcing it would break the\n * documented local run. What must not happen is the silence — a command the\n * help called \"(production)\" booting with the first-registration window open.\n */\nexport function nonProductionWarning(nodeEnv: StartNodeEnv): string[] | null {\n if (nodeEnv.value === \"production\") return null;\n const what = nodeEnv.value === undefined\n ? \"NODE_ENV is not set\"\n : `NODE_ENV=${nodeEnv.value}${nodeEnv.source === \".env\" ? \" (from .env)\" : \"\"}`;\n return [\n chalk.yellow.bold(`⚠ ${what} — this is not a production server.`),\n chalk.yellow(\" Development behaviour is on: the first account to register becomes the admin\"),\n chalk.yellow(\" (REBASE_ADMIN_EMAIL is ignored), and with no SMTP configured, sign-in and\"),\n chalk.yellow(\" password-reset links are printed to this log instead of sent.\"),\n chalk.gray(\" For a production server, run it with NODE_ENV=production (in the shell or .env).\")\n ];\n}\n\n/**\n * What to say about the apps a bundle serves only on their own hostname.\n *\n * The runtime prints \"Server running at http://localhost:<port>\", and an app\n * whose `path` names a hostname answers only requests carrying that `Host` —\n * so opening the printed URL showed a 404 for an app that was running fine,\n * and nothing said why. One line per such app, with a command that reaches it.\n */\nexport function hostRoutedNotice(staticApps: readonly RebaseBundleStatic[], port: string | undefined): string[] {\n const routed = staticApps.filter(app => app.host);\n if (routed.length === 0) return [];\n const origin = `http://localhost:${port || \"<port>\"}`;\n return [\n ...routed.map(app => {\n const name = app.name ?? path.posix.basename(app.dir);\n return chalk.yellow(`⚠ ${name} answers only on ${app.host}, so ${origin}${app.path} will not show it here. Reach it with:`)\n + `\\n ${chalk.cyan(`curl -H \"Host: ${app.host}\" ${origin}${app.path}`)}`;\n }),\n chalk.gray(` (or point ${routed.map(app => app.host).join(\", \")} at 127.0.0.1 in /etc/hosts)`),\n \"\"\n ];\n}\n\n/**\n * What to say when there is no DATABASE_URL for the runtime, or `null`.\n *\n * The runtime requires one, and its refusal — `DATABASE_URL: is required`, and\n * a link to the self-hosting docs — is right for a deployment and says nothing\n * to the reader most likely to see it: someone running the scaffold's own\n * `.env`, which leaves DATABASE_URL commented out because `rebase dev` brings a\n * database of its own. That database is one command away, so this names it.\n *\n * `kind` is what `rebase dev` runs this project on, so the line can say which\n * database `rebase db url` will print. A blank value is unset, as the runtime\n * reads it. `pm` spells the command: a scaffold has `rebase` in\n * `node_modules/.bin`, not on PATH, so it is `pnpm exec rebase …` or\n * `npx rebase …`, as in the CLI's other hints.\n */\nexport function missingDatabaseUrl(\n env: Record<string, string | undefined>,\n kind: DevDatabase[\"kind\"] | null,\n pm: PMCommands\n): string[] | null {\n if (env.DATABASE_URL?.trim()) return null;\n\n const rebase = (args: string[]): string => pm.exec(\"rebase\", args).join(\" \");\n\n const which = kind === \"docker\"\n ? \"the Docker database `rebase dev --docker` uses\"\n : kind === \"managed\"\n ? \"the managed development database (PGlite) `rebase dev` uses\"\n : \"this project's development database\";\n return [\n chalk.red(\"✗ DATABASE_URL is not set, so the runtime has no database to start against.\"),\n chalk.gray(\" `rebase start` runs the bundle the way a deployment does, against the database you name;\"),\n chalk.gray(\" `rebase dev` is the command that brings one of its own.\"),\n \"\",\n ` To run it on ${which}:`,\n ` ${chalk.cyan(`DATABASE_URL=\"$(${rebase([\"db\", \"url\"])})\" ${rebase([\"start\"])}`)}`,\n \"\",\n chalk.gray(\" For a deployment, set DATABASE_URL in the environment or in .env.\"),\n chalk.gray(\" See https://rebase.pro/docs/deployment/self-hosting/ for the variables a deployment needs.\")\n ];\n}\n\n/**\n * What the runtime needs when DATABASE_URL is this project's managed\n * development database, or nothing.\n *\n * The connection ceiling `rebase dev` sets for it (`MANAGED_POOL_MAX`). PGlite\n * is one session behind a socket server that accepts only a few connections,\n * and a running `rebase dev` holds some. With an ordinary pool, the boot's\n * concurrent probes opened more than were left, the ones over were refused,\n * and a probe that could not connect read as a table that was not there:\n * `❌ rebase.cron_claims is unavailable`, beside tables that existed.\n *\n * Recognised by the running daemon's ports, which is what `rebase db url`\n * prints from. A ceiling set by hand is kept.\n */\nexport function managedDatabaseRuntimeEnv(\n databaseUrl: string | undefined,\n daemon: DaemonState | null,\n env: Record<string, string | undefined>\n): Record<string, string> {\n if (!databaseUrl || !daemon || env.REBASE_DB_POOL_MAX !== undefined) return {};\n let url: URL;\n try {\n url = new URL(databaseUrl);\n } catch {\n return {};\n }\n if (![\"127.0.0.1\", \"localhost\", \"[::1]\"].includes(url.hostname)) return {};\n const ports = [daemon.port, ...Object.values(daemon.databases ?? {}).map(database => database.port)];\n if (!ports.includes(Number(url.port))) return {};\n return { REBASE_DB_POOL_MAX: String(MANAGED_POOL_MAX) };\n}\n\nfunction readBundleStatic(bundleDir: string): RebaseBundleStatic[] {\n try {\n const manifest = JSON.parse(fs.readFileSync(path.join(bundleDir, \"manifest.json\"), \"utf8\")) as { entry?: { static?: RebaseBundleStatic[] } };\n return manifest.entry?.static ?? [];\n } catch {\n return [];\n }\n}\n\nfunction printNonProductionWarning(projectRoot: string): void {\n const warning = nonProductionWarning(startNodeEnv(projectRoot));\n if (!warning) return;\n console.log(warning.join(\"\\n\") + \"\\n\");\n}\n\nexport async function startCommand(rawArgs: string[] = []): Promise<void> {\n if (wantsHelp(rawArgs)) {\n printHelp();\n return;\n }\n\n const { flags: args } = parseCommandArgs({\n spec: {\n \"--bundle\": String,\n \"--workspace\": Boolean\n },\n rawArgs,\n commandWords: 1,\n command: \"start\",\n maxPositionals: 0\n });\n\n const projectRoot = requireProjectRoot();\n\n const envFile = findEnvFile(projectRoot);\n const env: Record<string, string> = { ...process.env as Record<string, string> };\n if (envFile) {\n env.DOTENV_CONFIG_PATH = envFile;\n }\n\n const bundleDir = path.resolve(projectRoot, args[\"--bundle\"] ?? DEFAULT_BUNDLE_DIR);\n const hasBundle = fs.existsSync(path.join(bundleDir, \"manifest.json\"));\n\n // Before either path, and before the runtime's own boot logs bury it.\n printNonProductionWarning(projectRoot);\n\n if (args[\"--workspace\"] || !hasBundle) {\n if (!args[\"--workspace\"] && !hasBundle) {\n console.log(chalk.dim(\n `No bundle at ${path.relative(projectRoot, bundleDir)}/ — ` +\n \"starting the backend workspace instead.\\n\"\n ));\n }\n await startWorkspaceBackend(projectRoot, env);\n return;\n }\n\n ensureBundleDependencies(projectRoot, bundleDir);\n\n console.log(`${chalk.bold(\"Rebase\")} — starting runtime from ${chalk.cyan(path.relative(projectRoot, bundleDir))}/\\n`);\n\n // Loaded in-process rather than spawned: the runtime is a library here, so\n // signals, exit codes and stdio need no forwarding, and there is one less\n // process between the developer and a stack trace.\n if (envFile && fs.existsSync(envFile)) {\n const dotenv = await import(\"dotenv\");\n dotenv.config({ path: envFile, quiet: true });\n }\n\n // Before the runtime, which would refuse with a message written for a\n // deployment. See `missingDatabaseUrl`.\n if (!process.env.DATABASE_URL?.trim()) {\n const { devDatabaseKind } = await import(\"../dev-db/prepare\");\n const missing = missingDatabaseUrl(process.env, devDatabaseKind(projectRoot), getPMCommands(detectPackageManager(projectRoot)));\n if (missing) {\n for (const line of missing) console.error(line);\n process.exit(1);\n }\n }\n\n // See `managedDatabaseRuntimeEnv`.\n const { findRunningDaemon } = await import(\"../dev-db/daemon\");\n const managedEnv = managedDatabaseRuntimeEnv(process.env.DATABASE_URL, await findRunningDaemon(projectRoot), process.env);\n if (managedEnv.REBASE_DB_POOL_MAX) {\n Object.assign(process.env, managedEnv);\n console.log(chalk.dim(\n \"DATABASE_URL is this project's managed development database: the runtime uses one connection,\\n\" +\n \"as `rebase dev` does, so requests are served one at a time.\\n\"\n ));\n }\n\n process.env.REBASE_BUNDLE = bundleDir;\n\n for (const line of hostRoutedNotice(readBundleStatic(bundleDir), process.env.PORT)) console.log(line);\n\n try {\n const { runFromBundle } = await import(\"@rebasepro/server\");\n await runFromBundle({ bundleDir });\n } catch (err) {\n console.error(chalk.red(\"\\n✗ Failed to start the runtime.\"));\n console.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n}\n\n/**\n * Make a bundle's imports resolvable for a local run.\n *\n * Node resolves a module by walking up from the *importing file*, so compiled\n * code sitting in `dist-bundle/` no longer sees the per-package `node_modules`\n * its source could: pnpm and npm both install a workspace package's\n * dependencies inside that package, and the bundle is not inside any of them.\n *\n * A deployment solves this by installing the bundle's own `package.json` beside\n * it — that is what the generated `package.json` is for. Locally, doing a second\n * install to run code whose dependencies are already on disk would be wasteful,\n * so this links what is already there instead.\n *\n * Only ever created when absent, and only under the bundle directory, so a real\n * install always wins and nothing here is ever uploaded (`rebase build` cleans\n * the directory and never writes this).\n */\nfunction ensureBundleDependencies(projectRoot: string, bundleDir: string): void {\n const target = path.join(bundleDir, \"node_modules\");\n if (fs.existsSync(target)) return;\n\n // Later sources fill gaps left by earlier ones; the backend's tree wins\n // because it holds the server and driver the runtime itself needs.\n const sources = [\"backend/node_modules\", \"config/node_modules\", \"node_modules\"]\n .map(relative => path.join(projectRoot, relative))\n .filter(dir => fs.existsSync(dir));\n\n if (sources.length === 0) return;\n\n let linked = 0;\n fs.mkdirSync(target, { recursive: true });\n\n const linkInto = (sourceDir: string, targetDir: string): void => {\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(sourceDir, { withFileTypes: true });\n } catch {\n return;\n }\n\n for (const entry of entries) {\n if (entry.name === \".bin\" || entry.name.startsWith(\".\")) continue;\n const from = path.join(sourceDir, entry.name);\n const to = path.join(targetDir, entry.name);\n\n // A scope is a directory of packages, not a package — merge into it\n // so `@a/one` from one tree and `@a/two` from another both resolve.\n if (entry.name.startsWith(\"@\") && entry.isDirectory()) {\n fs.mkdirSync(to, { recursive: true });\n linkInto(from, to);\n continue;\n }\n\n if (fs.existsSync(to)) continue;\n try {\n fs.symlinkSync(fs.realpathSync(from), to, \"junction\");\n linked++;\n } catch {\n // A package that cannot be linked simply stays unresolved, and\n // the runtime will say so by name if it actually needed it.\n }\n }\n };\n\n for (const source of sources) linkInto(source, target);\n\n if (linked > 0) {\n console.log(chalk.dim(\n ` linked ${linked} package(s) into the bundle for this local run\\n` +\n \" (a deployment installs the bundle's package.json instead)\\n\"\n ));\n }\n}\n\nasync function startWorkspaceBackend(projectRoot: string, env: Record<string, string>): Promise<void> {\n const pm = detectPackageManager(projectRoot);\n const cmds = getPMCommands(pm);\n const startCmd = cmds.runWorkspace(\"backend\", \"start\");\n\n console.log(`${chalk.bold(\"Rebase\")} — Starting backend server...\\n`);\n\n try {\n await execa(startCmd[0], startCmd.slice(1), {\n cwd: projectRoot,\n stdio: \"inherit\",\n env\n });\n } catch {\n console.error(chalk.red(\"\\n✗ Failed to start server.\"));\n process.exit(1);\n }\n}\n"],"mappings":"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"}
|