@rebasepro/cli 0.17.3 → 0.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/LICENSE +0 -1
  2. package/README.md +21 -3
  3. package/bin/rebase.js +93 -6
  4. package/dist/branch-pointer-dBiClJ0p.js +111 -0
  5. package/dist/branch-pointer-dBiClJ0p.js.map +1 -0
  6. package/dist/bundle.d.ts +80 -3
  7. package/dist/cli.d.ts +22 -0
  8. package/dist/commands/auth.d.ts +13 -0
  9. package/dist/commands/cloud/action-help.d.ts +0 -10
  10. package/dist/commands/cloud/auth.d.ts +37 -0
  11. package/dist/commands/cloud/context.d.ts +90 -2
  12. package/dist/commands/cloud/databases.d.ts +0 -2
  13. package/dist/commands/cloud/declared-resources.d.ts +3 -0
  14. package/dist/commands/cloud/deploy.d.ts +76 -6
  15. package/dist/commands/cloud/deployments.d.ts +9 -2
  16. package/dist/commands/cloud/index.d.ts +36 -0
  17. package/dist/commands/cloud/link.d.ts +1 -1
  18. package/dist/commands/cloud/orgs.d.ts +6 -0
  19. package/dist/commands/cloud/resources.d.ts +81 -3
  20. package/dist/commands/cloud/settings.d.ts +7 -0
  21. package/dist/commands/db.d.ts +119 -9
  22. package/dist/commands/dev.d.ts +216 -1
  23. package/dist/commands/doctor.d.ts +51 -0
  24. package/dist/commands/init.d.ts +1 -0
  25. package/dist/commands/skills.d.ts +82 -13
  26. package/dist/commands/status.d.ts +1 -0
  27. package/dist/commands/telemetry.d.ts +0 -8
  28. package/dist/{daemon-Bdl4lrdt.js → daemon-YDZK9NZ1.js} +88 -9
  29. package/dist/daemon-YDZK9NZ1.js.map +1 -0
  30. package/dist/{daemon-entry-CmJn83zu.js → daemon-entry-LTFKtpHy.js} +117 -44
  31. package/dist/daemon-entry-LTFKtpHy.js.map +1 -0
  32. package/dist/dev-db/branch-pointer.d.ts +71 -0
  33. package/dist/dev-db/daemon.d.ts +27 -0
  34. package/dist/dev-db/prepare.d.ts +62 -0
  35. package/dist/dev-db/pull.d.ts +28 -0
  36. package/dist/dev-db/resolve.d.ts +45 -6
  37. package/dist/dev-db/state.d.ts +21 -0
  38. package/dist/dev-preflight-CNLl4rdo.js +367 -0
  39. package/dist/dev-preflight-CNLl4rdo.js.map +1 -0
  40. package/dist/doctor-environment.d.ts +131 -0
  41. package/dist/function-portability.d.ts +7 -0
  42. package/dist/index.d.ts +25 -15
  43. package/dist/index.es.js +5594 -1741
  44. package/dist/index.es.js.map +1 -1
  45. package/dist/project-3WCbrrfW.js +499 -0
  46. package/dist/project-3WCbrrfW.js.map +1 -0
  47. package/dist/{pull-DqPRu1te.js → pull-Bj0XnH5s.js} +31 -2
  48. package/dist/pull-Bj0XnH5s.js.map +1 -0
  49. package/dist/resolve-Y56osuQH.js +74 -0
  50. package/dist/resolve-Y56osuQH.js.map +1 -0
  51. package/dist/resources/derive.d.ts +67 -1
  52. package/dist/resources/status.d.ts +128 -0
  53. package/dist/rolldown-runtime-D7D4PA-g.js +13 -0
  54. package/dist/{state-c0CJ6Kwb.js → state-C59Elrnt.js} +24 -15
  55. package/dist/state-C59Elrnt.js.map +1 -0
  56. package/dist/utils/args.d.ts +18 -0
  57. package/dist/utils/command-words.d.ts +45 -0
  58. package/dist/utils/dev-preflight.d.ts +46 -0
  59. package/dist/utils/package-manager.d.ts +23 -0
  60. package/dist/utils/project.d.ts +66 -0
  61. package/dist/utils/spawn-error.d.ts +1 -0
  62. package/dist/utils/unknown-command.d.ts +26 -0
  63. package/dist/utils/version.d.ts +10 -0
  64. package/package.json +36 -28
  65. package/templates/eject/backend/src/env.ts +9 -0
  66. package/templates/eject/backend/src/index.ts +46 -19
  67. package/templates/eject/config/resources.ts +1 -1
  68. package/templates/overlays/baas/README.md +31 -11
  69. package/templates/overlays/baas/backend/package.json +2 -2
  70. package/templates/overlays/baas/backend/tsconfig.json +1 -1
  71. package/templates/overlays/baas/package.json +5 -2
  72. package/templates/overlays/baas/pnpm-workspace.yaml +13 -0
  73. package/templates/template/.cursorrules +1 -0
  74. package/templates/template/.env.example +91 -8
  75. package/templates/template/.github/copilot-instructions.md +1 -0
  76. package/templates/template/.mcp.json +11 -0
  77. package/templates/template/.windsurfrules +1 -0
  78. package/templates/template/AGENTS.md +1 -0
  79. package/templates/template/CLAUDE.md +2 -1
  80. package/templates/template/README.md +59 -28
  81. package/templates/template/ai-instructions.md +29 -12
  82. package/templates/template/backend/functions/hello.ts +5 -1
  83. package/templates/template/backend/package.json +2 -2
  84. package/templates/template/backend/src/schema.generated.ts +8 -3
  85. package/templates/template/backend/tsconfig.json +1 -1
  86. package/templates/template/config/cms.d.ts +6 -0
  87. package/templates/template/config/package.json +1 -1
  88. package/templates/template/config/resources.ts +42 -3
  89. package/templates/template/config/storage.ts +2 -1
  90. package/templates/template/docker-compose.yml +50 -9
  91. package/templates/template/frontend/index.html +0 -1
  92. package/templates/template/frontend/package.json +1 -2
  93. package/templates/template/frontend/src/App.tsx +8 -2
  94. package/templates/template/frontend/vite.config.ts +8 -0
  95. package/templates/template/gitignore +19 -1
  96. package/templates/template/npmrc +13 -4
  97. package/templates/template/package.json +10 -1
  98. package/templates/template/pnpm-workspace.yaml +17 -0
  99. package/templates/template/scripts/example.ts +4 -1
  100. package/dist/daemon-Bdl4lrdt.js.map +0 -1
  101. package/dist/daemon-entry-CmJn83zu.js.map +0 -1
  102. package/dist/pull-DqPRu1te.js.map +0 -1
  103. package/dist/state-c0CJ6Kwb.js.map +0 -1
@@ -1,12 +1,199 @@
1
+ import { type PreparedDatabase } from "../dev-db/prepare.js";
2
+ /**
3
+ * The line the watcher prints when it is about to run the entry again.
4
+ *
5
+ * `rebase dev` has no exit code to read: the watcher outlives the process it
6
+ * started, so a backend that dies leaves it running and the CLI printing
7
+ * "Press Ctrl+C to stop all servers." under the stack trace, as if everything
8
+ * were fine.
9
+ *
10
+ * What used to be here was `/Waiting for file changes before restarting/` —
11
+ * **Node's** message, on the theory that `--watch=…` was passed through to
12
+ * Node. It is not: the backend is spawned as `tsx watch …` (see `watchArgs`),
13
+ * so tsx does the watching and Node's line is never printed. The marker
14
+ * matched nothing at all — and the test guarding it ran `node --watch`
15
+ * directly, so it kept proving that Node's wording was intact while the CLI
16
+ * watched a stream that never contained it. That is precisely the silent death
17
+ * the old comment warned about, reached by a different route.
18
+ *
19
+ * So this is tsx's, captured from tsx 4.23.1:
20
+ *
21
+ * 6:26:11 AM [tsx] change in ./src/index.ts Rerunning...
22
+ * 6:26:11 AM [tsx] change in ./src/index.ts Restarting...
23
+ *
24
+ * "Rerunning" when the previous run had already exited, "Restarting" when it
25
+ * was still up and had to be killed first. Both mean the same thing here: the
26
+ * backend that was announced is gone, and whether another one arrives is an
27
+ * open question again — so the readiness deadline is re-armed.
28
+ *
29
+ * Exported so `dev-crash-marker.test.ts` can hold the running tsx to it.
30
+ */
31
+ export declare const WATCHER_RESTART_MARKER: RegExp;
32
+ /**
33
+ * The corrected banner line, when the backend says it moved port.
34
+ *
35
+ * `↳ PORT = 3014` is printed before the server binds — the backend's
36
+ * environment has to be fixed before it spawns — so when the port turns out to
37
+ * be taken and the server moves, the banner two inches up is simply wrong. The
38
+ * true number then appears in a `[backend]` line a hundred lines of DDL later,
39
+ * which nobody scrolls back through, and the banner is where a reader looks for
40
+ * the port.
41
+ *
42
+ * A correction rather than a rewrite: the terminal is a transcript, and a line
43
+ * that changes after the fact is a line nobody can trust. So the old number is
44
+ * named too.
45
+ *
46
+ * Exported for its test.
47
+ */
48
+ export declare function portMovedNotice(line: string): {
49
+ from: string;
50
+ to: string;
51
+ } | null;
52
+ /**
53
+ * Directories `tsx watch` must be told about explicitly, as absolute paths.
54
+ *
55
+ * tsx restarts on a change to anything the entrypoint *imports*. Functions and
56
+ * crons are not imported: the runtime scans their directories at boot. So
57
+ * adding `backend/functions/new.ts` while `rebase dev` ran did nothing —
58
+ * `GET /api/functions/new` stayed 404, and a new cron never registered — until
59
+ * somebody restarted by hand. The same is true of `config/`, which is read as
60
+ * data.
61
+ *
62
+ * `--include` is tsx's own answer to this, it takes a directory rather than a
63
+ * glob, and it tolerates a directory that does not exist yet: a `crons/`
64
+ * created mid-session starts being watched when it appears.
65
+ *
66
+ * @param projectRoot Absolute path the relative entries are resolved against.
67
+ * @param paths The `REBASE_DEV_*` map from {@link devRuntimeEnv}.
68
+ * @param includeConfig Whether `config/` is watched here. It is only when
69
+ * auto-generation is off; with `--generate` a dedicated
70
+ * watcher already regenerates the schema and SDK, and tsx
71
+ * restarts on the files that produces.
72
+ */
73
+ export declare function devWatchIncludes(projectRoot: string, paths: {
74
+ REBASE_DEV_FUNCTIONS?: string;
75
+ REBASE_DEV_CRONS?: string;
76
+ }, includeConfig: boolean): string[];
1
77
  /** Well-known filename the backend writes its actual port to. */
2
78
  export declare const DEV_PORT_FILENAME = ".rebase-dev-port";
79
+ /**
80
+ * The `PORT` the scaffold's own `.env.example` ships.
81
+ *
82
+ * `rebase init` copies that file into `.env` verbatim, so every new project has
83
+ * this value whether or not anyone meant it. `init.test.ts` asserts the
84
+ * template still says this number, so the two cannot drift apart in silence.
85
+ */
86
+ export declare const SCAFFOLD_DEFAULT_PORT = 3001;
3
87
  /**
4
88
  * Compute a deterministic port from the project root path.
5
89
  * Range: 3001–3999 (avoids privileged ports and common services).
6
90
  * Two different project directories will almost always get different ports.
7
91
  */
8
92
  export declare function getProjectPort(projectRoot: string): number;
9
- export declare function resolveStartPort(projectRoot: string, explicitPort?: number): number;
93
+ /**
94
+ * Which rung of the ladder below decided the port.
95
+ *
96
+ * Reported because the ladder is invisible from the outside and the two middle
97
+ * rungs look identical from where the developer stands: `PORT` in the shell
98
+ * wins, `PORT` in `.env` does not — `rebase dev` never reads the file for it —
99
+ * and a saved affinity port looks exactly like a derived one. A developer who
100
+ * sets `PORT=3001` in `.env`, sees 3774, and has nothing to read but the number
101
+ * concludes the setting is broken rather than out of scope.
102
+ */
103
+ export type StartPortSource = "--port" | "PORT" | "affinity" | "derived";
104
+ /** What the banner says after the port, naming the rung. */
105
+ export declare const START_PORT_SOURCE_LABELS: Record<StartPortSource, string>;
106
+ /**
107
+ * The port this project's backend starts on, and the rung that decided it:
108
+ * 1. `--port` (highest priority)
109
+ * 2. `PORT` **in the shell environment** — a `PORT` in `.env` is not read here
110
+ * 3. the port a previous run saved in `.rebase-dev-port` (affinity)
111
+ * 4. a port derived from the project path, unique per project
112
+ */
113
+ export declare function resolveStartPort(projectRoot: string, explicitPort?: number): {
114
+ port: number;
115
+ source: StartPortSource;
116
+ };
117
+ /**
118
+ * Where a connection string actually points, as `host:port/name`.
119
+ *
120
+ * The banner used to name the database only by *provenance* — "your database
121
+ * (DATABASE_URL in the environment)" — and the boot that follows it writes
122
+ * thirty DDL statements. Which host, which port, which database name appeared
123
+ * nowhere on the success path; only a *failed* connection printed an address.
124
+ * So the one question after pointing a project at staging by accident — did it
125
+ * touch staging? — had no answer in a hundred and twenty lines of output.
126
+ *
127
+ * The password is never in it. `new URL` keeps the credentials in their own
128
+ * fields, so building the string out of `hostname`, `port` and `pathname`
129
+ * cannot carry them by accident, which string surgery on a DSN reliably does.
130
+ *
131
+ * A DSN with no host is a UNIX socket (`postgresql:///app?host=/tmp`), and the
132
+ * socket directory is the address there.
133
+ *
134
+ * Returns null for anything that is not a parseable URL rather than guessing:
135
+ * a banner line that is wrong about the database is worse than one that is
136
+ * missing.
137
+ *
138
+ * Exported for its test.
139
+ */
140
+ export declare function databaseEndpoint(url: string | null | undefined): string | null;
141
+ /**
142
+ * The `↳ Database =` line: which database, why it was chosen, and where it is.
143
+ *
144
+ * Provenance alone was what this line said, and the boot underneath it applies
145
+ * schema. "your database (DATABASE_URL in the environment)" and "Applied 30
146
+ * additive schema change(s) before boot" together still do not answer the
147
+ * question somebody asks after pointing a project at staging by accident.
148
+ *
149
+ * The managed database gets its address too — the daemon's port is what a
150
+ * `psql` in another terminal needs, and it is nowhere else in the banner.
151
+ *
152
+ * Exported for its test.
153
+ */
154
+ export declare function databaseBannerValue(prepared: PreparedDatabase | null): string;
155
+ /**
156
+ * Refuse a port the developer named and something else already answers on.
157
+ *
158
+ * `--port` used to be advice, not an instruction: `resolveStartPort` returned
159
+ * the number, the banner printed it, and the server then walked past the
160
+ * collision to 3141, 3142. Because dev ports are derived per project, the
161
+ * number typed into `--port` is very often *another Rebase backend*, so the
162
+ * curl that followed answered 200 from the wrong project rather than refusing
163
+ * — the one failure mode a port collision is supposed to rule out.
164
+ *
165
+ * Asked here as well as in the server (`listenWithPortRetry`'s `explicit`
166
+ * option, which `REBASE_DEV_PORT_EXPLICIT` below turns on) so the refusal
167
+ * arrives before a database is started and a schema is pushed, rather than a
168
+ * minute later underneath them.
169
+ *
170
+ * Both loopback addresses, because a listener on `::1` alone is the same
171
+ * collision and costs one more connect to rule out. Returns the sentence to
172
+ * print, or `null` when there is nothing to refuse.
173
+ *
174
+ * Exported for its test.
175
+ */
176
+ export declare function pinnedPortRefusal(port: number, pinned: boolean): Promise<string | null>;
177
+ /**
178
+ * The frontend port for this project, derived the same way the backend's is.
179
+ *
180
+ * `rebase dev` used to leave this entirely to Vite, which takes 5173 and, when
181
+ * that is busy, silently walks to 5174, 5175 and onward. The backend was then
182
+ * started with whatever `FRONTEND_URL` the scaffold's `.env` happened to say —
183
+ * `http://localhost:5173` — so the welcome email linked a port the app was not
184
+ * on. Deriving it here means the value handed to the backend describes the
185
+ * server we are about to start rather than a default nobody checked.
186
+ *
187
+ * Range 5173–5372, so the familiar port is still the common case for a single
188
+ * project and two projects rarely collide.
189
+ *
190
+ * Note this is passed to Vite WITHOUT `--strictPort` unless the developer
191
+ * pinned it explicitly. Vite keeps its fallback, so a busy port still starts —
192
+ * it just starts somewhere the email link does not name, which is exactly
193
+ * today's behaviour and no worse. Pinning REBASE_FRONTEND_PORT makes both
194
+ * exact.
195
+ */
196
+ export declare function getProjectFrontendPort(projectRoot: string): number;
10
197
  /**
11
198
  * The flags `rebase dev` takes.
12
199
  *
@@ -36,4 +223,32 @@ export declare const DEV_FLAGS: {
36
223
  readonly "-g": "--generate";
37
224
  readonly "--no-db": BooleanConstructor;
38
225
  };
226
+ /**
227
+ * One variable's value out of `.env` text, or undefined when it has none.
228
+ *
229
+ * The obvious `\s*(.+?)\s*$` does not do this, because `\s` matches a newline
230
+ * and `$` under /m matches at every line end: on `VITE_API_URL=` followed by
231
+ * `# VITE_GOOGLE_CLIENT_ID=`, the leading `\s*` ate the line break and the
232
+ * capture returned the *next* line. The scaffold ships `VITE_API_URL=` empty,
233
+ * so every first `rebase dev` read a comment as its value, decided it differed
234
+ * from the derived URL, and warned that a variable the developer had not set
235
+ * was being ignored.
236
+ *
237
+ * Horizontal whitespace only, so a value stops at its own line.
238
+ */
239
+ export declare function readEnvValue(envText: string, key: string): string | undefined;
240
+ /**
241
+ * The argv the first-boot schema push runs with.
242
+ *
243
+ * The database is named on the command line rather than left to be re-resolved.
244
+ * `runDriverDbCommand` runs the resolver again for whatever argv it is handed,
245
+ * and the argv it used to be handed (`["node","rebase","db","push"]`) carried
246
+ * nothing at all — so on the `--docker` path it read a `.env` whose
247
+ * `DATABASE_URL` is commented out, concluded "managed PGlite", and refused the
248
+ * push for a database that was not the one the preflight had just started.
249
+ *
250
+ * Exported for its test: the missing pair of arguments is the whole defect, and
251
+ * it is invisible in any assertion about the push's *outcome*.
252
+ */
253
+ export declare function schemaPushArgv(databaseUrl: string | undefined): string[];
39
254
  export declare function devCommand(rawArgs: string[]): Promise<void>;
@@ -1,4 +1,5 @@
1
1
  import { type LibpqUrlFinding } from "../utils/libpq-url.js";
2
+ import { type AtlasBinaryState, type EnvironmentFinding } from "../doctor-environment.js";
2
3
  /**
3
4
  * Find connection strings libpq cannot parse, anywhere in the project.
4
5
  *
@@ -6,4 +7,54 @@ import { type LibpqUrlFinding } from "../utils/libpq-url.js";
6
7
  * keep its `.env` outside the root (see `findEnvFile`).
7
8
  */
8
9
  export declare function findLibpqUrlProblems(projectRoot: string, envFile?: string | null): LibpqUrlFinding[];
10
+ /**
11
+ * Read everything the environment checks need, then run them.
12
+ *
13
+ * The reading is here and the deciding is in `doctor-environment.ts`, so every
14
+ * check has a fixture that fails it without a project on disk.
15
+ */
16
+ export declare function collectEnvironmentFindings(projectRoot: string, envFile: string | null | undefined): EnvironmentFinding[];
17
+ /**
18
+ * What is actually on disk for `@ariga/atlas`, from the project's point of view.
19
+ *
20
+ * Three separate questions, because the three states they distinguish need
21
+ * three different remedies — see `checkAtlasBinary`. Directories are searched
22
+ * from the project root upwards and through the workspaces a scaffold has,
23
+ * because `db push` runs from `backend/` and the install may be hoisted to the
24
+ * root.
25
+ */
26
+ export declare function readAtlasBinaryState(projectRoot: string): AtlasBinaryState | null;
27
+ /**
28
+ * Does this project declare its collections in code?
29
+ *
30
+ * `resolveBackendPaths` answers it against the manifest's own `config` path
31
+ * rather than the convention, because a project may move the directory. A
32
+ * project with no manifest, or one shaped differently, is treated as declaring
33
+ * them: the wrong answer there would silently skip the drift report, which is
34
+ * the reason the command exists.
35
+ */
36
+ export declare function hasDeclaredCollections(projectRoot: string): boolean;
37
+ /**
38
+ * The flags `rebase doctor` takes, and what each is for.
39
+ *
40
+ * One table, read by both the parser and the help page, because they were two
41
+ * things that had to agree and did not: the page listed no flags at all, so
42
+ * `--policies` — the form `cli/index.md` calls "the form to use as a CI gate" —
43
+ * was invisible to anyone who ran `rebase doctor --help` to find it. And with
44
+ * nothing parsing the line here, a typo travelled to the driver's permissive
45
+ * parser and was silently dropped, so `rebase doctor --polices` ran the ordinary
46
+ * doctor and reported success on a gate that never ran.
47
+ *
48
+ * The spec mirrors the driver's own (`doctorPluginCommand` in
49
+ * `server-postgres/src/cli.ts`), because the line is relayed to it verbatim.
50
+ */
51
+ export declare const DOCTOR_FLAGS: {
52
+ readonly "--policies": BooleanConstructor;
53
+ readonly "--collections": StringConstructor;
54
+ readonly "-c": "--collections";
55
+ readonly "--schema": StringConstructor;
56
+ readonly "-s": "--schema";
57
+ readonly "--sdk": StringConstructor;
58
+ readonly "-k": "--sdk";
59
+ };
9
60
  export declare function doctorCommand(rawArgs: string[]): Promise<void>;
@@ -72,6 +72,7 @@ export declare function createRebaseApp(rawArgs: string[]): Promise<void>;
72
72
  export declare const INIT_FLAGS: {
73
73
  readonly "--git": BooleanConstructor;
74
74
  readonly "--install": BooleanConstructor;
75
+ readonly "--no-install": BooleanConstructor;
75
76
  readonly "--database-url": StringConstructor;
76
77
  readonly "--introspect": BooleanConstructor;
77
78
  readonly "--template": StringConstructor;
@@ -1,11 +1,23 @@
1
1
  /**
2
2
  * Supported agent environments and their target directories.
3
3
  *
4
- * `flatLayout` says where the installed rule file sits relative to the skill's
5
- * own assets. A subdirectory layout writes `<skill>/SKILL.md`, so a link the
6
- * skill spells `references/x.md` resolves as written; a flat layout writes
7
- * `<skill>.md` one level up, so those links have to be re-pointed at the
8
- * per-skill asset directory. See `rewriteAssetLinks`.
4
+ * Every agent `rebase init` writes a pointer file for has an entry here. That
5
+ * was not true: `rebase init` writes `CLAUDE.md`, `AGENTS.md`, `.cursorrules`,
6
+ * `.windsurfrules` and `.github/copilot-instructions.md`, and the installer
7
+ * covered four of the five — so a Codex or Copilot user was told, by a file in
8
+ * their own repository, to run an installer that had nothing to offer them.
9
+ *
10
+ * `flatLayout` marks the agents whose rules directory is loaded *whole*, into
11
+ * every request. Writing 21 skills there put ~84,000 characters of always-on
12
+ * context in front of every question a person asked Cursor — more than the task
13
+ * itself, on every turn, most of it about parts of Rebase they were not
14
+ * touching. Those agents get one short index rule instead, and the skill bodies
15
+ * go in per-skill subdirectories the index names, which the agent reads when it
16
+ * needs one. `indexFile` is the name of that rule.
17
+ *
18
+ * A subdirectory layout has no such problem: the rule file already sits beside
19
+ * its own assets, so `references/x.md` resolves as written and nothing is
20
+ * loaded until it is opened.
9
21
  */
10
22
  declare const AGENTS: {
11
23
  readonly cursor: {
@@ -13,7 +25,8 @@ declare const AGENTS: {
13
25
  readonly detectDir: ".cursor";
14
26
  readonly targetDir: ".cursor/rules";
15
27
  readonly flatLayout: true;
16
- /** Cursor uses .mdc files (Markdown with Context). */
28
+ readonly indexFile: "rebase.mdc";
29
+ /** The body is not a rule file here — `indexFile` is. */
17
30
  readonly transformFile: (skillName: string, content: string) => {
18
31
  fileName: string;
19
32
  content: string;
@@ -35,7 +48,8 @@ declare const AGENTS: {
35
48
  readonly detectDir: ".windsurf";
36
49
  readonly targetDir: ".windsurf/rules";
37
50
  readonly flatLayout: true;
38
- /** Windsurf uses plain .md files. */
51
+ readonly indexFile: "rebase.md";
52
+ /** The body is not a rule file here — `indexFile` is. */
39
53
  readonly transformFile: (skillName: string, content: string) => {
40
54
  fileName: string;
41
55
  content: string;
@@ -52,6 +66,41 @@ declare const AGENTS: {
52
66
  content: string;
53
67
  };
54
68
  };
69
+ readonly codex: {
70
+ readonly label: "Codex CLI";
71
+ readonly detectDir: ".codex";
72
+ readonly targetDir: ".codex/skills";
73
+ readonly flatLayout: false;
74
+ /** Codex reads AGENTS.md; the skills sit beside its own config. */
75
+ readonly transformFile: (skillName: string, content: string) => {
76
+ fileName: string;
77
+ content: string;
78
+ };
79
+ };
80
+ readonly kiro: {
81
+ readonly label: "Kiro";
82
+ readonly detectDir: ".kiro";
83
+ readonly targetDir: ".kiro/steering";
84
+ readonly flatLayout: true;
85
+ readonly indexFile: "rebase.md";
86
+ /** The body is not a rule file here — `indexFile` is. */
87
+ readonly transformFile: (skillName: string, content: string) => {
88
+ fileName: string;
89
+ content: string;
90
+ };
91
+ };
92
+ readonly copilot: {
93
+ readonly label: "GitHub Copilot";
94
+ readonly detectDir: null;
95
+ readonly targetDir: ".github/instructions";
96
+ readonly flatLayout: true;
97
+ readonly indexFile: "rebase.instructions.md";
98
+ /** The body is not a rule file here — `indexFile` is. */
99
+ readonly transformFile: (skillName: string, content: string) => {
100
+ fileName: string;
101
+ content: string;
102
+ };
103
+ };
55
104
  };
56
105
  type AgentKey = keyof typeof AGENTS;
57
106
  export interface LoadedSkill {
@@ -65,18 +114,38 @@ export interface LoadedSkill {
65
114
  /** Read all skill directories and return their names, content and assets. */
66
115
  export declare function loadSkills(skillsDir: string): LoadedSkill[];
67
116
  /**
68
- * Re-point a skill's own asset links at the per-skill subdirectory, for the
69
- * agents whose rule file does not live in it.
117
+ * The one always-on rule a flat-layout agent gets, in place of every skill.
70
118
  *
71
- * Only paths that name a file the skill actually ships are rewritten, and only
72
- * where they start a path segment so prose that happens to contain the same
73
- * words is left alone.
119
+ * Cursor and Windsurf load their whole rules directory into each request. With
120
+ * a rule file per skill that was ~84,000 characters of Rebase reference in
121
+ * front of every question, whether or not the question was about Rebase — and
122
+ * an instruction an assistant skims is an instruction it does not follow.
123
+ *
124
+ * So the always-on part is this: a table of what exists and where to read it.
125
+ * `alwaysApply: true` because knowing the skills are there costs a few hundred
126
+ * characters and is the whole point; the bodies stay on disk until the agent
127
+ * opens one.
128
+ */
129
+ export declare function renderSkillIndex(skills: LoadedSkill[], agentKey: AgentKey): string;
130
+ /**
131
+ * Detect which agent environments already exist in the project.
132
+ *
133
+ * A `detectDir` has to be evidence *the user* created, not something a scaffold
134
+ * ships. An agent whose only marker fails that test declares `detectDir: null`
135
+ * and is reachable by `--agent` alone; guessing wrong here is worse than not
136
+ * guessing, because the wrong guess installs 21 files and reports success.
74
137
  */
75
- export declare function rewriteAssetLinks(content: string, assets: string[], skillName: string): string;
138
+ export declare function detectAgents(projectDir: string): AgentKey[];
76
139
  /** Install skills for a specific agent into the project directory. */
77
140
  export declare function installForAgent(agentKey: AgentKey, skills: LoadedSkill[], projectDir: string): {
78
141
  skills: number;
79
142
  assets: number;
80
143
  };
81
144
  export declare function skillsCommand(subcommand: string | undefined, rawArgs: string[]): Promise<void>;
145
+ /**
146
+ * Agents named explicitly on the command line, e.g. `--agent claude --agent cursor`
147
+ * (also accepts a comma-separated list, and `all`). Returns null when none were
148
+ * given.
149
+ */
150
+ export declare function parseAgentFlags(rawArgs: string[]): AgentKey[] | null;
82
151
  export {};
@@ -0,0 +1 @@
1
+ export declare function statusCommand(rawArgs: string[]): Promise<void>;
@@ -1,9 +1 @@
1
- /**
2
- * `rebase telemetry` — the command that makes the rest of it inspectable.
3
- *
4
- * The whole subsystem asks for trust it cannot otherwise earn, and the cheapest
5
- * way to earn it is to stop describing the payload and print it. `show` runs
6
- * the same builder the sender uses, so what appears here is what would go, not
7
- * a documentation comment that quietly fell out of date two releases ago.
8
- */
9
1
  export declare function telemetryCommand(rawArgs: string[]): Promise<void>;
@@ -1,4 +1,5 @@
1
- import { a as findFreePort, c as releaseStartLock, f as __exportAll, i as devDbDir, l as stateFile, n as clearState, o as pidRunning, r as dataDir, s as readState, t as acquireStartLock } from "./state-c0CJ6Kwb.js";
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
+ import { a as devDbDir, c as readState, i as dataDir, l as releaseStartLock, o as findFreePort, r as clearState, s as pidRunning, t as acquireStartLock, u as stateFile } from "./state-C59Elrnt.js";
2
3
  import path from "path";
3
4
  import fs from "fs";
4
5
  import net from "net";
@@ -45,8 +46,22 @@ var IDENTITY_TIMEOUT_MS = 1500;
45
46
  */
46
47
  var MANAGED_USER = "postgres";
47
48
  var MANAGED_DATABASE = "postgres";
49
+ /**
50
+ * The DSN for the managed development database.
51
+ *
52
+ * **`sslmode=disable` is not decoration.** PGlite's socket server speaks no TLS,
53
+ * and libpq-family clients try SSL first — so Atlas, which `rebase db push`
54
+ * shells out to, failed the whole push with
55
+ * `pq: SSL is not enabled on the server`. Its remedy box then told the reader to
56
+ * append `sslmode=disable` to `DATABASE_URL`, which on this path is not set at
57
+ * all: `rebase init` leaves it commented out precisely so the managed database
58
+ * is used. The advice was correct and unfollowable.
59
+ *
60
+ * Putting it in the URL fixes every consumer at once — Atlas, `pg`, and anything
61
+ * a driver shells out to later — rather than teaching each one about PGlite.
62
+ */
48
63
  function managedUrl(port) {
49
- return `postgresql://${MANAGED_USER}@127.0.0.1:${port}/${MANAGED_DATABASE}`;
64
+ return `postgresql://${MANAGED_USER}@127.0.0.1:${port}/${MANAGED_DATABASE}?sslmode=disable`;
50
65
  }
51
66
  /**
52
67
  * Ask the process behind a state record to prove it is the one we wrote down.
@@ -96,7 +111,7 @@ async function findRunningDaemon(projectRoot) {
96
111
  function resolveCliEntry() {
97
112
  const argvEntry = process.argv[1];
98
113
  if (argvEntry && fs.existsSync(argvEntry)) return argvEntry;
99
- return fileURLToPath(new URL("data:video/mp2t;base64,ZXhwb3J0ICogZnJvbSAiLi9jbGkiOwpleHBvcnQgKiBmcm9tICIuL2NvbW1hbmRzL2luaXQiOwpleHBvcnQgKiBmcm9tICIuL2NvbW1hbmRzL3NjaGVtYSI7CmV4cG9ydCAqIGZyb20gIi4vY29tbWFuZHMvZGIiOwpleHBvcnQgKiBmcm9tICIuL2NvbW1hbmRzL2RldiI7CmV4cG9ydCAqIGZyb20gIi4vY29tbWFuZHMvYnVpbGQiOwpleHBvcnQgKiBmcm9tICIuL2NvbW1hbmRzL2VqZWN0IjsKZXhwb3J0ICogZnJvbSAiLi9jb21tYW5kcy9zdGFydCI7CmV4cG9ydCAqIGZyb20gIi4vY29tbWFuZHMvYXV0aCI7CmV4cG9ydCAqIGZyb20gIi4vY29tbWFuZHMvZG9jdG9yIjsKZXhwb3J0ICogZnJvbSAiLi9jb21tYW5kcy9nZW5lcmF0ZV9zZGsiOwpleHBvcnQgKiBmcm9tICIuL2NvbW1hbmRzL2Nsb3VkIjsKZXhwb3J0ICogZnJvbSAiLi9jb21tYW5kcy9hcHBzIjsKZXhwb3J0ICogZnJvbSAiLi91dGlscy9wcm9qZWN0IjsKZXhwb3J0ICogZnJvbSAiLi91dGlscy9wYWNrYWdlLW1hbmFnZXIiOwoKLy8gVGhlIG1hbmlmZXN0IGFuZCBidW5kbGUgY29udHJhY3RzLgovLwovLyBFeHBvcnRlZCBiZWNhdXNlIHZhbGlkYXRpbmcgdGhlbSBpcyBub3Qgb25seSB0aGUgQ0xJJ3Mgam9iOiBhIGNvbnRyb2wgcGxhbmUKLy8gaGFzIHRvIGRlY2lkZSB3aGV0aGVyIGEgc3VibWl0dGVkIGJ1bmRsZSBjYW4gcnVuIGJlZm9yZSBpdCBkZXBsb3lzIGl0LCBhbmQgaXQKLy8gbXVzdCByZWFjaCB0aGF0IHZlcmRpY3Qgd2l0aCB0aGUgc2FtZSBjb2RlIHRoYXQgcHJvZHVjZWQgdGhlIGFydGlmYWN0LgpleHBvcnQgKiBmcm9tICIuL21hbmlmZXN0IjsKZXhwb3J0ICogZnJvbSAiLi9idW5kbGUiOwo=", "" + import.meta.url));
114
+ return fileURLToPath(new URL("data:video/mp2t;base64,LyoqCiAqIFRoZSBDTEkncyBwdWJsaWMgZW50cnkg4oCUIGRlbGliZXJhdGVseSBzbWFsbC4KICoKICogVGhpcyBmaWxlIHVzZWQgdG8gYGV4cG9ydCAqYCBmcm9tIHNpeHRlZW4gbW9kdWxlczogZXZlcnkgY29tbWFuZCBmdW5jdGlvbiwKICogYGRldGVjdFBhY2thZ2VNYW5hZ2VyYCwgYGZpbmRQcm9qZWN0Um9vdGAsIHRoZSB3aG9sZSBvZiBgY29tbWFuZHMvY2xvdWRgLiBOb25lCiAqIG9mIGl0IHdhcyBpbXBvcnRlZCBieSBhbnl0aGluZywgaW4gdGhpcyByZXBvc2l0b3J5IG9yIHRoZSBjb250cm9sIHBsYW5lLCBhbmQKICogbm9uZSBvZiBpdCB3YXMgbWVhbnQgdG8gYmU6IGBAcmViYXNlcHJvL2NsaWAgaXMgYSBwcm9ncmFtLCBhbmQgYSBwcm9ncmFtJ3MKICogaW50ZXJuYWxzIGJlY29tZSBhbiBBUEkgdGhlIG1vbWVudCB0aGV5IGFyZSBleHBvcnRlZCBhbmQgcHVibGlzaGVkLiBUaGUKICogYmFycmVsIHdhcyB3cml0dGVuIHRoZSB3YXkgYmFycmVscyBnZXQgd3JpdHRlbiDigJQgb25lIGxpbmUgcGVyIGZpbGUg4oCUIGFuZCB0aGUKICogc3VyZmFjZSBpdCBjcmVhdGVkIHdhcyBhbiBhY2NpZGVudCBvZiB0aGF0IGNvbnZlbnRpb24gcmF0aGVyIHRoYW4gYSBkZWNpc2lvbi4KICoKICogVGhyZWUgdGhpbmdzIGFyZSBleHBvcnRlZCwgZWFjaCBmb3IgYSBzdGF0ZWQgcmVhc29uLgogKi8KCi8qKgogKiBXaGF0IGBiaW4vcmViYXNlLmpzYCBjYWxscy4gVGhlIGJpbmFyeSBpbXBvcnRzIGBkaXN0L2luZGV4LmVzLmpzYCBhbmQgaW52b2tlcwogKiBgZW50cnkoKWAsIHNvIHRoaXMgaXMgdGhlIG9uZSBleHBvcnQgdGhlIENMSSBjYW5ub3QgcnVuIHdpdGhvdXQuCiAqLwpleHBvcnQgeyBlbnRyeSB9IGZyb20gIi4vY2xpIjsKCi8qKgogKiBUaGUgbWFuaWZlc3QgYW5kIGJ1bmRsZSBjb250cmFjdHMuCiAqCiAqIEV4cG9ydGVkIGJlY2F1c2UgdmFsaWRhdGluZyB0aGVtIGlzIG5vdCBvbmx5IHRoZSBDTEkncyBqb2I6IGEgY29udHJvbCBwbGFuZQogKiBoYXMgdG8gZGVjaWRlIHdoZXRoZXIgYSBzdWJtaXR0ZWQgYnVuZGxlIGNhbiBydW4gYmVmb3JlIGl0IGRlcGxveXMgaXQsIGFuZCBpdAogKiBtdXN0IHJlYWNoIHRoYXQgdmVyZGljdCB3aXRoIHRoZSBzYW1lIGNvZGUgdGhhdCBwcm9kdWNlZCB0aGUgYXJ0aWZhY3QuCiAqLwpleHBvcnQgKiBmcm9tICIuL21hbmlmZXN0IjsKZXhwb3J0ICogZnJvbSAiLi9idW5kbGUiOwo=", "" + import.meta.url));
100
115
  }
101
116
  /**
102
117
  * How to re-invoke ourselves, which differs between a published CLI and this
@@ -119,6 +134,61 @@ function resolveSpawn(entry) {
119
134
  };
120
135
  }
121
136
  /**
137
+ * Ask the running daemon for one additional database, and get its port.
138
+ *
139
+ * The identity socket doubles as the command channel: the daemon answers
140
+ * with its token first, which is how the caller knows it is talking to the
141
+ * daemon the state file describes and not to a stranger on a recycled port.
142
+ */
143
+ function ensureAdditionalDatabase(state, key) {
144
+ return new Promise((resolve, reject) => {
145
+ const socket = new net.Socket();
146
+ let answer = "";
147
+ let identified = false;
148
+ const fail = (message) => {
149
+ socket.removeAllListeners();
150
+ socket.destroy();
151
+ reject(new Error(message));
152
+ };
153
+ socket.setTimeout(START_TIMEOUT_MS);
154
+ socket.once("timeout", () => fail(`The development database did not answer for "${key}" within ${Math.round(START_TIMEOUT_MS / 1e3)}s.`));
155
+ socket.once("error", (err) => fail(`Could not reach the development database for "${key}": ${err.message}`));
156
+ socket.on("data", (chunk) => {
157
+ answer += chunk.toString("utf8");
158
+ let newline = answer.indexOf("\n");
159
+ while (newline !== -1) {
160
+ const line = answer.slice(0, newline).trim();
161
+ answer = answer.slice(newline + 1);
162
+ if (!identified) {
163
+ if (line !== `rebase-dev-db ${state.token}`) return fail("The process on the development database's port is not the daemon.");
164
+ identified = true;
165
+ socket.write(`ensure ${key}\n`);
166
+ } else if (line.startsWith("ok ")) {
167
+ const port = Number(line.slice(3));
168
+ socket.removeAllListeners();
169
+ socket.destroy();
170
+ if (!Number.isInteger(port) || port <= 0) return reject(/* @__PURE__ */ new Error(`The development database answered with an invalid port for "${key}": ${line}`));
171
+ return resolve(port);
172
+ } else return fail(`The development database could not serve "${key}": ${line.replace(/^error\s*/, "")}`);
173
+ newline = answer.indexOf("\n");
174
+ }
175
+ });
176
+ socket.connect(state.identityPort, "127.0.0.1");
177
+ });
178
+ }
179
+ /** Every additional database the caller asked for, as connection strings. */
180
+ async function adoptWithAdditional(state, started, keys) {
181
+ const additional = {};
182
+ for (const key of keys) {
183
+ const known = state.databases?.[key];
184
+ additional[key] = managedUrl(known ? known.port : await ensureAdditionalDatabase(state, key));
185
+ }
186
+ return {
187
+ ...adopt(state, started),
188
+ additional
189
+ };
190
+ }
191
+ /**
122
192
  * The project's managed database, started if it is not already running.
123
193
  *
124
194
  * Safe to call concurrently from several commands: the loser of the race finds
@@ -126,13 +196,14 @@ function resolveSpawn(entry) {
126
196
  * second daemon.
127
197
  */
128
198
  async function ensureManagedDatabase(projectRoot, options = {}) {
199
+ const keys = options.additionalKeys ?? [];
129
200
  const existing = await findRunningDaemon(projectRoot);
130
- if (existing) return adopt(existing, false);
201
+ if (existing) return adoptWithAdditional(existing, false, keys);
131
202
  fs.mkdirSync(devDbDir(projectRoot), { recursive: true });
132
203
  ensureGitignore(projectRoot);
133
204
  if (!acquireStartLock(projectRoot, START_TIMEOUT_MS)) {
134
205
  const adopted = await waitForDaemon(projectRoot, START_TIMEOUT_MS);
135
- if (adopted) return adopt(adopted, false);
206
+ if (adopted) return adoptWithAdditional(adopted, false, keys);
136
207
  if (!acquireStartLock(projectRoot, 0)) throw new Error(`Another process is starting the development database and did not finish.
137
208
  Remove ${path.join(devDbDir(projectRoot), "starting.lock")} if nothing is running.`);
138
209
  }
@@ -167,7 +238,7 @@ async function ensureManagedDatabase(projectRoot, options = {}) {
167
238
  let announced = false;
168
239
  while (Date.now() < deadline) {
169
240
  const state = readState(projectRoot);
170
- if (state && await isDaemonAlive(state)) return adopt(state, true);
241
+ if (state && await isDaemonAlive(state)) return adoptWithAdditional(state, true, keys);
171
242
  if (!announced && !options.quiet) {
172
243
  announced = true;
173
244
  options.onProgress?.("Starting the development database…");
@@ -187,7 +258,8 @@ function adopt(state, started) {
187
258
  dataDir: state.dataDir,
188
259
  port: state.port,
189
260
  pid: state.pid,
190
- started
261
+ started,
262
+ additional: {}
191
263
  };
192
264
  }
193
265
  /** Poll until another process publishes a live daemon, or give up. */
@@ -231,6 +303,13 @@ async function resetManagedDatabase(projectRoot) {
231
303
  recursive: true,
232
304
  force: true
233
305
  });
306
+ const dir = devDbDir(projectRoot);
307
+ if (fs.existsSync(dir)) {
308
+ for (const entry of fs.readdirSync(dir)) if (entry.startsWith("pgdata__")) fs.rmSync(path.join(dir, entry), {
309
+ recursive: true,
310
+ force: true
311
+ });
312
+ }
234
313
  clearState(projectRoot);
235
314
  }
236
315
  /**
@@ -247,6 +326,6 @@ function ensureGitignore(projectRoot) {
247
326
  fs.writeFileSync(target, "# Generated by `rebase dev` — a local Postgres data directory and its log.\n# Machine-specific and large; never commit it.\n*\n", "utf8");
248
327
  }
249
328
  //#endregion
250
- export { ensureManagedDatabase as n, daemon_exports as t };
329
+ export { managedUrl as i, ensureManagedDatabase as n, findRunningDaemon as r, daemon_exports as t };
251
330
 
252
- //# sourceMappingURL=daemon-Bdl4lrdt.js.map
331
+ //# sourceMappingURL=daemon-YDZK9NZ1.js.map