@rebasepro/cli 0.13.0 → 0.13.1-canary.g3660bd5
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/dist/commands/auth.d.ts +31 -0
- package/dist/commands/init.d.ts +22 -0
- package/dist/index.es.js +157 -53
- package/dist/index.es.js.map +1 -1
- package/dist/telemetry/payload.d.ts +1 -1
- package/dist/utils/project.d.ts +20 -0
- package/package.json +7 -7
- package/templates/template/config/package.json +1 -0
package/dist/commands/auth.d.ts
CHANGED
|
@@ -1 +1,32 @@
|
|
|
1
|
+
/** A user as the admin API returns it, reduced to what this command needs. */
|
|
2
|
+
export interface ResolvedUser {
|
|
3
|
+
id: string;
|
|
4
|
+
email: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Pick the user with exactly this email out of a search response.
|
|
8
|
+
*
|
|
9
|
+
* `/api/admin/users?search=` is an `ILIKE '%…%'` over email **or display
|
|
10
|
+
* name**, ordered by role count descending. This used to take row `[0]` and
|
|
11
|
+
* reset it, then print the email it had been *given* as confirmation — so two
|
|
12
|
+
* ordinary situations ended in a successful-looking reset of somebody else's
|
|
13
|
+
* account:
|
|
14
|
+
*
|
|
15
|
+
* - a substring collision: `bob@example.com` also matches
|
|
16
|
+
* `robert.bob@example.com`;
|
|
17
|
+
* - a display name, which is user-controlled and accepted up to 255
|
|
18
|
+
* characters with no constraint on its content, containing an address
|
|
19
|
+
* belonging to someone else.
|
|
20
|
+
*
|
|
21
|
+
* The ordering makes it worse rather than better — `array_length(roles) DESC
|
|
22
|
+
* NULLS LAST` puts the most privileged match first, so the account most likely
|
|
23
|
+
* to be reset by mistake is an admin's.
|
|
24
|
+
*
|
|
25
|
+
* Returns `undefined` when nothing matched exactly, which the caller reports
|
|
26
|
+
* rather than falling through to a guess. The direct-database fallback below
|
|
27
|
+
* has always matched with `eq(usersTable.email, email)`; this is the same
|
|
28
|
+
* definition, so the command no longer resets different accounts depending on
|
|
29
|
+
* whether the backend happened to be running.
|
|
30
|
+
*/
|
|
31
|
+
export declare function selectUserForEmail(payload: unknown, email: string): ResolvedUser | undefined;
|
|
1
32
|
export declare function authCommand(subcommand: string | undefined, rawArgs: string[]): Promise<void>;
|
package/dist/commands/init.d.ts
CHANGED
|
@@ -68,4 +68,26 @@ export declare function formatCdTarget(cwd: string, targetDirectory: string): st
|
|
|
68
68
|
* triggering the non-TTY error. */
|
|
69
69
|
export declare function printInitHelp(): void;
|
|
70
70
|
export declare function createRebaseApp(rawArgs: string[]): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* The runtime image tag to pin, given the version of the CLI doing the scaffolding.
|
|
73
|
+
*
|
|
74
|
+
* Only a stable release publishes `rebasepro/server` — a multi-arch build on
|
|
75
|
+
* every push to main would cost minutes per commit for an image nobody pulls.
|
|
76
|
+
* So pinning a prerelease CLI's own version writes a tag that cannot exist, and
|
|
77
|
+
* `docker compose up` fails on `manifest unknown`, which is the same dead end
|
|
78
|
+
* as the missing-repository bug this pinning was added to prevent.
|
|
79
|
+
*
|
|
80
|
+
* A prerelease therefore falls back to `latest`, which is correct rather than
|
|
81
|
+
* merely available: a bundle's manifest declares the runtime range it needs
|
|
82
|
+
* (`^1`), the image supplies only `@rebasepro/server`, and the framework a
|
|
83
|
+
* bundle runs is installed from its own `deps.declared` at boot. The current
|
|
84
|
+
* stable runtime boots a canary bundle by design.
|
|
85
|
+
*
|
|
86
|
+
* A floating tag is a real cost — it is what pinning exists to avoid — so say
|
|
87
|
+
* so in the file rather than leaving a reader to discover it.
|
|
88
|
+
*/
|
|
89
|
+
export declare function resolveRuntimeImageTag(cliVersion: string): {
|
|
90
|
+
tag: string;
|
|
91
|
+
note?: string;
|
|
92
|
+
};
|
|
71
93
|
export declare function configureEnvFile(targetDirectory: string, databaseUrl?: string): Promise<void>;
|
package/dist/index.es.js
CHANGED
|
@@ -12,6 +12,7 @@ import crypto from "crypto";
|
|
|
12
12
|
import { execSync, spawn, spawnSync } from "child_process";
|
|
13
13
|
import os from "os";
|
|
14
14
|
import { createRebaseClient } from "@rebasepro/client";
|
|
15
|
+
import dotenv from "dotenv";
|
|
15
16
|
import { createRequire } from "module";
|
|
16
17
|
import { BUNDLE_FORMAT_VERSION, RUNTIME_CONTRACT_VERSION, computeSchemaVersion, deserializeCollections, findStorageSuffixCollision, normalizeStorageSources, storageEnvSuffix } from "@rebasepro/types";
|
|
17
18
|
import { generateSDK } from "@rebasepro/codegen";
|
|
@@ -289,6 +290,34 @@ function findEnvFile(projectRoot) {
|
|
|
289
290
|
return null;
|
|
290
291
|
}
|
|
291
292
|
/**
|
|
293
|
+
* Read the project's `.env` into a plain object.
|
|
294
|
+
*
|
|
295
|
+
* One reader, because there were four: `dotenv` in `start`, a hand-rolled
|
|
296
|
+
* `indexOf("=")` loop in `api-keys`, a single-key regex in `auth`, and its own
|
|
297
|
+
* splitting in `cloud env`. `dotenv` is a declared dependency of this package,
|
|
298
|
+
* so the other three existed for no reason and disagreed with the correct one
|
|
299
|
+
* on the two things people actually write in a `.env`:
|
|
300
|
+
*
|
|
301
|
+
* - `export KEY=value`, which the hand-rolled parser keyed as
|
|
302
|
+
* `export KEY` — so the command reported the key as unset while it was
|
|
303
|
+
* right there in the file;
|
|
304
|
+
* - `KEY=value # comment`, whose comment travelled into the value and then
|
|
305
|
+
* into an `Authorization` header, coming back as a 401 with nothing
|
|
306
|
+
* pointing at the cause.
|
|
307
|
+
*
|
|
308
|
+
* Returns `{}` when the project has no `.env`, so callers can treat "absent"
|
|
309
|
+
* and "empty" alike.
|
|
310
|
+
*/
|
|
311
|
+
function readEnvFile(projectRoot) {
|
|
312
|
+
const envFile = findEnvFile(projectRoot);
|
|
313
|
+
if (!envFile || !fs.existsSync(envFile)) return {};
|
|
314
|
+
try {
|
|
315
|
+
return dotenv.parse(fs.readFileSync(envFile, "utf-8"));
|
|
316
|
+
} catch {
|
|
317
|
+
return {};
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
292
321
|
* Resolve a binary from the project's node_modules/.bin.
|
|
293
322
|
* Checks backend, root, parent monorepo root, then falls back to PATH.
|
|
294
323
|
*/
|
|
@@ -1789,7 +1818,7 @@ async function createProject$1(options) {
|
|
|
1789
1818
|
console.log(` ${chalk.cyan(runDev.join(" "))}`);
|
|
1790
1819
|
}
|
|
1791
1820
|
console.log("");
|
|
1792
|
-
console.log(isBaas ? chalk.gray("This starts a headless API (Hono + PostgreSQL). There are no collection files: ") + chalk.gray("the API is derived from your database schema. Once it serves a table, docs are at /api/swagger.") : chalk.gray("This starts both the backend (Hono + PostgreSQL)") + chalk.gray(" and the frontend (Vite + React) concurrently."));
|
|
1821
|
+
console.log(isBaas ? introspected ? chalk.gray("This starts a headless API (Hono + PostgreSQL) over the collections just ") + chalk.gray("generated from your database in config/collections. Edit them to change what the ") + chalk.gray("API exposes; docs are at /api/swagger.") : chalk.gray("This starts a headless API (Hono + PostgreSQL). There are no collection files: ") + chalk.gray("the API is derived from your database schema. Once it serves a table, docs are at /api/swagger.") : chalk.gray("This starts both the backend (Hono + PostgreSQL)") + chalk.gray(" and the frontend (Vite + React) concurrently."));
|
|
1793
1822
|
console.log("");
|
|
1794
1823
|
console.log(chalk.gray("Docs: https://rebase.pro/docs"));
|
|
1795
1824
|
console.log(chalk.gray("GitHub: https://github.com/rebasepro/rebase"));
|
|
@@ -2013,6 +2042,32 @@ function readCliVersion() {
|
|
|
2013
2042
|
} catch {}
|
|
2014
2043
|
return "latest";
|
|
2015
2044
|
}
|
|
2045
|
+
/**
|
|
2046
|
+
* The runtime image tag to pin, given the version of the CLI doing the scaffolding.
|
|
2047
|
+
*
|
|
2048
|
+
* Only a stable release publishes `rebasepro/server` — a multi-arch build on
|
|
2049
|
+
* every push to main would cost minutes per commit for an image nobody pulls.
|
|
2050
|
+
* So pinning a prerelease CLI's own version writes a tag that cannot exist, and
|
|
2051
|
+
* `docker compose up` fails on `manifest unknown`, which is the same dead end
|
|
2052
|
+
* as the missing-repository bug this pinning was added to prevent.
|
|
2053
|
+
*
|
|
2054
|
+
* A prerelease therefore falls back to `latest`, which is correct rather than
|
|
2055
|
+
* merely available: a bundle's manifest declares the runtime range it needs
|
|
2056
|
+
* (`^1`), the image supplies only `@rebasepro/server`, and the framework a
|
|
2057
|
+
* bundle runs is installed from its own `deps.declared` at boot. The current
|
|
2058
|
+
* stable runtime boots a canary bundle by design.
|
|
2059
|
+
*
|
|
2060
|
+
* A floating tag is a real cost — it is what pinning exists to avoid — so say
|
|
2061
|
+
* so in the file rather than leaving a reader to discover it.
|
|
2062
|
+
*/
|
|
2063
|
+
function resolveRuntimeImageTag(cliVersion) {
|
|
2064
|
+
if (/^\d+\.\d+\.\d+-/.test(cliVersion)) return {
|
|
2065
|
+
tag: "latest",
|
|
2066
|
+
note: `# Scaffolded by a prerelease CLI (${cliVersion}), which publishes no runtime image,\n# so this floats to the newest stable runtime. Pin an exact version once you
|
|
2067
|
+
# deploy: a moving tag changes what you are running with no version changing.`
|
|
2068
|
+
};
|
|
2069
|
+
return { tag: cliVersion };
|
|
2070
|
+
}
|
|
2016
2071
|
async function configureEnvFile(targetDirectory, databaseUrl) {
|
|
2017
2072
|
const envExamplePath = path.join(targetDirectory, ".env.example");
|
|
2018
2073
|
const envPath = path.join(targetDirectory, ".env");
|
|
@@ -2031,8 +2086,9 @@ async function configureEnvFile(targetDirectory, databaseUrl) {
|
|
|
2031
2086
|
envContent = envContent.replace(/^#\s*REBASE_SERVICE_KEY=.*$/m, `REBASE_SERVICE_KEY=${serviceKey}`);
|
|
2032
2087
|
const composeApiPort = /^PORT=(\d+)/m.exec(envContent)?.[1] ?? "3001";
|
|
2033
2088
|
envContent = envContent.replace(/^#\s*CORS_ORIGINS=.*$/m, `CORS_ORIGINS=http://localhost:${composeApiPort}`);
|
|
2034
|
-
const runtimeVersion = readCliVersion();
|
|
2035
|
-
|
|
2089
|
+
const { tag: runtimeVersion, note } = resolveRuntimeImageTag(readCliVersion());
|
|
2090
|
+
const pinned = `${note ? `${note}\n` : ""}REBASE_VERSION=${runtimeVersion}`;
|
|
2091
|
+
envContent = /^#?\s*REBASE_VERSION=.*$/m.test(envContent) ? envContent.replace(/^#?\s*REBASE_VERSION=.*$/m, pinned) : `${envContent.trimEnd()}\n\n# The Rebase runtime image tag docker-compose.yml pulls.\n# Change this and restart to upgrade; your project bundle is untouched.\n${pinned}\n`;
|
|
2036
2092
|
if (databaseUrl) {
|
|
2037
2093
|
if (/[\r\n]/.test(databaseUrl)) throw new Error("Invalid DATABASE_URL: multiline values are not allowed.");
|
|
2038
2094
|
const { pinSearchPath } = await import("@rebasepro/server-postgres");
|
|
@@ -2367,7 +2423,7 @@ async function schemaCommand(subcommand, rawArgs) {
|
|
|
2367
2423
|
return;
|
|
2368
2424
|
}
|
|
2369
2425
|
const projectRoot = requireProjectRoot();
|
|
2370
|
-
recordEvent("cli.
|
|
2426
|
+
recordEvent("cli.schema", { subcommand: subcommand ?? "none" }, { projectRoot });
|
|
2371
2427
|
const backendDir = requireBackendDir(projectRoot);
|
|
2372
2428
|
const activePlugin = getActiveBackendPlugin(backendDir);
|
|
2373
2429
|
if (!activePlugin) {
|
|
@@ -2436,7 +2492,7 @@ async function dbCommand(subcommand, rawArgs) {
|
|
|
2436
2492
|
return;
|
|
2437
2493
|
}
|
|
2438
2494
|
const projectRoot = requireProjectRoot();
|
|
2439
|
-
recordEvent("cli.
|
|
2495
|
+
recordEvent("cli.db", { subcommand: subcommand ?? "none" }, { projectRoot });
|
|
2440
2496
|
const backendDir = requireBackendDir(projectRoot);
|
|
2441
2497
|
const activePlugin = getActiveBackendPlugin(backendDir);
|
|
2442
2498
|
if (!activePlugin) {
|
|
@@ -3345,6 +3401,20 @@ async function devCommand(rawArgs) {
|
|
|
3345
3401
|
} catch {}
|
|
3346
3402
|
/** Whether the frontend has been launched (we only launch it once). */
|
|
3347
3403
|
let frontendLaunched = false;
|
|
3404
|
+
try {
|
|
3405
|
+
const activePlugin = getActiveBackendPlugin(backendDir);
|
|
3406
|
+
const pluginCli = activePlugin ? resolvePluginCliScript(backendDir, activePlugin) : null;
|
|
3407
|
+
if (pluginCli) await execa(tsxBin, [
|
|
3408
|
+
pluginCli,
|
|
3409
|
+
"schema",
|
|
3410
|
+
"stale",
|
|
3411
|
+
"--fix"
|
|
3412
|
+
], {
|
|
3413
|
+
cwd: backendDir,
|
|
3414
|
+
stdio: "inherit",
|
|
3415
|
+
env
|
|
3416
|
+
});
|
|
3417
|
+
} catch {}
|
|
3348
3418
|
if (shouldGenerate) {
|
|
3349
3419
|
console.log(chalk.gray(" → Ensuring schema and SDK are generated on start..."));
|
|
3350
3420
|
try {
|
|
@@ -5286,6 +5356,48 @@ async function startWorkspaceBackend(projectRoot, env) {
|
|
|
5286
5356
|
* Subcommands:
|
|
5287
5357
|
* reset-password — Reset a user's password
|
|
5288
5358
|
*/
|
|
5359
|
+
/**
|
|
5360
|
+
* Pick the user with exactly this email out of a search response.
|
|
5361
|
+
*
|
|
5362
|
+
* `/api/admin/users?search=` is an `ILIKE '%…%'` over email **or display
|
|
5363
|
+
* name**, ordered by role count descending. This used to take row `[0]` and
|
|
5364
|
+
* reset it, then print the email it had been *given* as confirmation — so two
|
|
5365
|
+
* ordinary situations ended in a successful-looking reset of somebody else's
|
|
5366
|
+
* account:
|
|
5367
|
+
*
|
|
5368
|
+
* - a substring collision: `bob@example.com` also matches
|
|
5369
|
+
* `robert.bob@example.com`;
|
|
5370
|
+
* - a display name, which is user-controlled and accepted up to 255
|
|
5371
|
+
* characters with no constraint on its content, containing an address
|
|
5372
|
+
* belonging to someone else.
|
|
5373
|
+
*
|
|
5374
|
+
* The ordering makes it worse rather than better — `array_length(roles) DESC
|
|
5375
|
+
* NULLS LAST` puts the most privileged match first, so the account most likely
|
|
5376
|
+
* to be reset by mistake is an admin's.
|
|
5377
|
+
*
|
|
5378
|
+
* Returns `undefined` when nothing matched exactly, which the caller reports
|
|
5379
|
+
* rather than falling through to a guess. The direct-database fallback below
|
|
5380
|
+
* has always matched with `eq(usersTable.email, email)`; this is the same
|
|
5381
|
+
* definition, so the command no longer resets different accounts depending on
|
|
5382
|
+
* whether the backend happened to be running.
|
|
5383
|
+
*/
|
|
5384
|
+
function selectUserForEmail(payload, email) {
|
|
5385
|
+
const wanted = email.trim().toLowerCase();
|
|
5386
|
+
if (!wanted) return void 0;
|
|
5387
|
+
const rows = Array.isArray(payload) ? payload : payload && typeof payload === "object" && Array.isArray(payload.users) ? payload.users : [];
|
|
5388
|
+
for (const row of rows) {
|
|
5389
|
+
if (!row || typeof row !== "object") continue;
|
|
5390
|
+
const record = row;
|
|
5391
|
+
const rowEmail = typeof record.email === "string" ? record.email.trim().toLowerCase() : void 0;
|
|
5392
|
+
if (!rowEmail || rowEmail !== wanted) continue;
|
|
5393
|
+
const id = typeof record.id === "string" ? record.id : typeof record.uid === "string" ? record.uid : void 0;
|
|
5394
|
+
if (!id) continue;
|
|
5395
|
+
return {
|
|
5396
|
+
id,
|
|
5397
|
+
email: record.email
|
|
5398
|
+
};
|
|
5399
|
+
}
|
|
5400
|
+
}
|
|
5289
5401
|
async function authCommand(subcommand, rawArgs) {
|
|
5290
5402
|
if (!subcommand || subcommand === "--help") {
|
|
5291
5403
|
printAuthHelp();
|
|
@@ -5322,12 +5434,8 @@ async function resetPassword(rawArgs) {
|
|
|
5322
5434
|
process.exit(1);
|
|
5323
5435
|
}
|
|
5324
5436
|
const projectRoot = requireProjectRoot();
|
|
5325
|
-
let envServiceKey;
|
|
5326
5437
|
const envFile = findEnvFile(projectRoot);
|
|
5327
|
-
|
|
5328
|
-
const match = fs.readFileSync(envFile, "utf8").match(/^\s*REBASE_SERVICE_KEY\s*=\s*['"]?(.*?)['"]?\s*$/m);
|
|
5329
|
-
if (match && match[1]) envServiceKey = match[1];
|
|
5330
|
-
} catch {}
|
|
5438
|
+
const envServiceKey = readEnvFile(projectRoot).REBASE_SERVICE_KEY;
|
|
5331
5439
|
let baseUrl = process.env.REBASE_BASE_URL;
|
|
5332
5440
|
let serviceKey = process.env.REBASE_SERVICE_KEY || envServiceKey;
|
|
5333
5441
|
const statePath = path.join(projectRoot, ".rebase", "state.json");
|
|
@@ -5347,7 +5455,7 @@ async function resetPassword(rawArgs) {
|
|
|
5347
5455
|
try {
|
|
5348
5456
|
const finalPass = newPassword || "NewPassword123!";
|
|
5349
5457
|
const cleanBaseUrl = baseUrl.replace(/\/+$/, "");
|
|
5350
|
-
const searchUrl = `${cleanBaseUrl}/api/admin/users?search=${encodeURIComponent(email)}&limit=
|
|
5458
|
+
const searchUrl = `${cleanBaseUrl}/api/admin/users?search=${encodeURIComponent(email)}&limit=50`;
|
|
5351
5459
|
const searchRes = await fetch(searchUrl, { headers: {
|
|
5352
5460
|
"Authorization": `Bearer ${serviceKey}`,
|
|
5353
5461
|
"Accept": "application/json"
|
|
@@ -5355,18 +5463,9 @@ async function resetPassword(rawArgs) {
|
|
|
5355
5463
|
if (!searchRes.ok) throw new Error(`Failed to list users: ${searchRes.statusText}`);
|
|
5356
5464
|
const searchData = await searchRes.json();
|
|
5357
5465
|
if (!searchData || typeof searchData !== "object") throw new Error("Invalid response format from user search API.");
|
|
5358
|
-
|
|
5359
|
-
if (
|
|
5360
|
-
|
|
5361
|
-
if (firstUser && typeof firstUser === "object" && "id" in firstUser && typeof firstUser.id === "string") userId = firstUser.id;
|
|
5362
|
-
else if (firstUser && typeof firstUser === "object" && "uid" in firstUser && typeof firstUser.uid === "string") userId = firstUser.uid;
|
|
5363
|
-
} else if ("users" in searchData && Array.isArray(searchData.users)) {
|
|
5364
|
-
const firstUser = searchData.users[0];
|
|
5365
|
-
if (firstUser && typeof firstUser === "object" && "id" in firstUser && typeof firstUser.id === "string") userId = firstUser.id;
|
|
5366
|
-
else if (firstUser && typeof firstUser === "object" && "uid" in firstUser && typeof firstUser.uid === "string") userId = firstUser.uid;
|
|
5367
|
-
}
|
|
5368
|
-
if (!userId) throw new Error(`User not found with email: ${email}`);
|
|
5369
|
-
const resetUrl = `${cleanBaseUrl}/api/admin/users/${userId}/reset-password`;
|
|
5466
|
+
const matched = selectUserForEmail(searchData, email);
|
|
5467
|
+
if (!matched) throw new Error(`No user has the email ${email}.`);
|
|
5468
|
+
const resetUrl = `${cleanBaseUrl}/api/admin/users/${matched.id}/reset-password`;
|
|
5370
5469
|
const resetRes = await fetch(resetUrl, {
|
|
5371
5470
|
method: "POST",
|
|
5372
5471
|
headers: {
|
|
@@ -5383,7 +5482,7 @@ async function resetPassword(rawArgs) {
|
|
|
5383
5482
|
console.log("API reset successful.");
|
|
5384
5483
|
console.log(chalk.bold(" 🔑 Rebase Auth — Reset Password (via API)"));
|
|
5385
5484
|
console.log("");
|
|
5386
|
-
console.log(` ${chalk.gray("Email:")} ${email}`);
|
|
5485
|
+
console.log(` ${chalk.gray("Email:")} ${matched.email}`);
|
|
5387
5486
|
console.log(` ${chalk.gray("Password:")} ${finalPass}`);
|
|
5388
5487
|
console.log("");
|
|
5389
5488
|
return;
|
|
@@ -5451,10 +5550,12 @@ async function resetPassword() {
|
|
|
5451
5550
|
if (result.length > 0) {
|
|
5452
5551
|
console.log("✅ Password reset for: " + result[0].email);
|
|
5453
5552
|
${!newPassword ? "console.log(\" New password: \" + newPassword);" : ""}
|
|
5454
|
-
|
|
5455
|
-
console.log("✗ User not found: " + email);
|
|
5553
|
+
process.exit(0);
|
|
5456
5554
|
}
|
|
5457
|
-
|
|
5555
|
+
// Nothing was updated, so nothing was reset. Exiting 0 here reported
|
|
5556
|
+
// success for a no-op, which is what a script would have believed.
|
|
5557
|
+
console.error("✗ User not found: " + email);
|
|
5558
|
+
process.exit(1);
|
|
5458
5559
|
}
|
|
5459
5560
|
|
|
5460
5561
|
resetPassword().catch(console.error);
|
|
@@ -5472,11 +5573,20 @@ resetPassword().catch(console.error);
|
|
|
5472
5573
|
stdio: "inherit",
|
|
5473
5574
|
env
|
|
5474
5575
|
});
|
|
5576
|
+
const cleanup = () => {
|
|
5577
|
+
try {
|
|
5578
|
+
fs.unlinkSync(tmpScriptPath);
|
|
5579
|
+
} catch {}
|
|
5580
|
+
};
|
|
5475
5581
|
return new Promise((resolve) => {
|
|
5582
|
+
child.on("error", (err) => {
|
|
5583
|
+
cleanup();
|
|
5584
|
+
console.error(chalk.red("✗ Could not run the reset script."));
|
|
5585
|
+
console.error(chalk.gray(` ${err.message}`));
|
|
5586
|
+
process.exit(1);
|
|
5587
|
+
});
|
|
5476
5588
|
child.on("close", (code) => {
|
|
5477
|
-
|
|
5478
|
-
fs.unlinkSync(tmpScriptPath);
|
|
5479
|
-
} catch {}
|
|
5589
|
+
cleanup();
|
|
5480
5590
|
if (code !== 0) process.exit(code ?? 1);
|
|
5481
5591
|
resolve();
|
|
5482
5592
|
});
|
|
@@ -5663,7 +5773,8 @@ async function skillsCommand(subcommand, rawArgs) {
|
|
|
5663
5773
|
}
|
|
5664
5774
|
/**
|
|
5665
5775
|
* Agents named explicitly on the command line, e.g. `--agent claude --agent cursor`
|
|
5666
|
-
* (also accepts a comma-separated list). Returns null when none were
|
|
5776
|
+
* (also accepts a comma-separated list, and `all`). Returns null when none were
|
|
5777
|
+
* given.
|
|
5667
5778
|
*/
|
|
5668
5779
|
function parseAgentFlags(rawArgs) {
|
|
5669
5780
|
const requested = [];
|
|
@@ -5673,6 +5784,7 @@ function parseAgentFlags(rawArgs) {
|
|
|
5673
5784
|
if (value && !value.startsWith("-")) requested.push(...value.split(",").map((v) => v.trim()).filter(Boolean));
|
|
5674
5785
|
}
|
|
5675
5786
|
if (requested.length === 0) return null;
|
|
5787
|
+
if (requested.includes("all")) return Object.keys(AGENTS);
|
|
5676
5788
|
const valid = Object.keys(AGENTS);
|
|
5677
5789
|
const unknown = requested.filter((a) => !valid.includes(a));
|
|
5678
5790
|
if (unknown.length > 0) {
|
|
@@ -5700,6 +5812,7 @@ async function skillsInstall(rawArgs = []) {
|
|
|
5700
5812
|
if (!process.stdin.isTTY) {
|
|
5701
5813
|
console.error(chalk.red("Cannot prompt: this is a non-interactive terminal (no TTY)."));
|
|
5702
5814
|
console.error(chalk.yellow(` Name the agents explicitly, e.g. rebase skills install --agent ${Object.keys(AGENTS)[0]}`));
|
|
5815
|
+
console.error(chalk.yellow(" Or install for every supported agent: rebase skills install --agent all"));
|
|
5703
5816
|
console.error(chalk.gray(` Available: ${Object.keys(AGENTS).join(", ")}`));
|
|
5704
5817
|
process.exit(1);
|
|
5705
5818
|
}
|
|
@@ -5747,13 +5860,16 @@ ${chalk.green.bold("Subcommands")}
|
|
|
5747
5860
|
|
|
5748
5861
|
${chalk.green.bold("Options")}
|
|
5749
5862
|
${chalk.blue("--agent, -a")} Agent(s) to install for, skipping detection and the prompt.
|
|
5750
|
-
Repeat the flag or pass a comma-separated list.
|
|
5751
|
-
|
|
5863
|
+
Repeat the flag or pass a comma-separated list, or ${chalk.bold("all")}.
|
|
5864
|
+
Required without a TTY: a scaffolded project carries a marker
|
|
5865
|
+
file for every agent, so detection cannot pick one for you.
|
|
5866
|
+
Available: ${Object.keys(AGENTS).join(", ")}, all
|
|
5752
5867
|
|
|
5753
5868
|
${chalk.green.bold("Examples")}
|
|
5754
5869
|
${chalk.cyan("rebase skills install")}
|
|
5755
5870
|
${chalk.cyan("rebase skills install --agent claude")}
|
|
5756
5871
|
${chalk.cyan("rebase skills install --agent claude,cursor")}
|
|
5872
|
+
${chalk.cyan("rebase skills install --agent all")} ${chalk.gray("# scripted / CI")}
|
|
5757
5873
|
`);
|
|
5758
5874
|
}
|
|
5759
5875
|
//#endregion
|
|
@@ -5766,25 +5882,13 @@ ${chalk.green.bold("Examples")}
|
|
|
5766
5882
|
* create — Create a new API key
|
|
5767
5883
|
* revoke — Revoke an existing API key
|
|
5768
5884
|
*/
|
|
5769
|
-
|
|
5770
|
-
|
|
5771
|
-
|
|
5772
|
-
|
|
5773
|
-
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
5777
|
-
const idx = trimmed.indexOf("=");
|
|
5778
|
-
if (idx > 0) {
|
|
5779
|
-
const key = trimmed.slice(0, idx).trim();
|
|
5780
|
-
let value = trimmed.slice(idx + 1).trim();
|
|
5781
|
-
if (value.startsWith("\"") && value.endsWith("\"") || value.startsWith("'") && value.endsWith("'")) value = value.slice(1, -1);
|
|
5782
|
-
env[key] = value;
|
|
5783
|
-
}
|
|
5784
|
-
}
|
|
5785
|
-
}
|
|
5786
|
-
return env;
|
|
5787
|
-
}
|
|
5885
|
+
/**
|
|
5886
|
+
* Was a hand-rolled `indexOf("=")` loop. It keyed `export KEY=value` as
|
|
5887
|
+
* `export KEY` and carried a trailing `# comment` into the value — so a key
|
|
5888
|
+
* that was present read as absent, or reached an `Authorization` header with a
|
|
5889
|
+
* comment attached and came back 401. See `readEnvFile`.
|
|
5890
|
+
*/
|
|
5891
|
+
var loadEnv = readEnvFile;
|
|
5788
5892
|
function resolveBaseUrl(env, projectRoot) {
|
|
5789
5893
|
if (env.REBASE_BASE_URL) return env.REBASE_BASE_URL;
|
|
5790
5894
|
if (projectRoot) try {
|
|
@@ -10893,6 +10997,6 @@ function telemetryNotice() {
|
|
|
10893
10997
|
return chalk.gray(`Usage sharing: ${sharing ? "on" : "off"} — ${chalk.cyan("rebase telemetry")} to inspect or change\n`);
|
|
10894
10998
|
}
|
|
10895
10999
|
//#endregion
|
|
10896
|
-
export { CURRENT_RUNTIME_RANGE, DEFAULT_BUNDLE_DIR, DEFAULT_CONFIG_DIR, DEFAULT_CRONS_DIR, DEFAULT_FUNCTIONS_DIR, DEFAULT_SCHEMA_FILE, DEV_PORT_FILENAME, MANIFEST_FILENAME, ManifestError, TEMPLATE_PLACEHOLDER_FILES, appsCommand, assessManagedCompatibility, authCommand, buildBundle, buildCommand, buildInitQuestions, buildStaticBundle, buildableApps, cloudCommand, collectDeclaredDependencies, configureEnvFile, createRebaseApp, dbCommand, detectFrameworkDepDrift, detectNativeDependencies, detectPackageManager, detectStorageAuthorize, devCommand, doctorCommand, ejectCommand, entry, findBackendApp, findBackendDir, findEnvFile, findFrontendDir, findProjectRoot, findUnusedServerEntry, foldStaticIntoBundle, formatCdTarget, generateSdkCommand, getActiveBackendPlugin, getPMCommands, getProjectPort, isIdentifierLike, isPnpmAvailable, loadManifest, manifestExists, manifestPath, normalizeEsmSpecifiers, pnpmAvailabilityFromProbe, positionals, printInitHelp, requireBackendDir, requireProjectRoot, resetPnpmAvailabilityCache, resolveBackendPaths, resolveCliVersion, resolveExampleBaseUrl, resolveLocalBin, resolvePluginCliScript, resolveStartPort, resolveTsx, schemaCommand, startCommand, synthesizeManifest, validateManifest, validateProjectName, validateTsxInstallation, writeManifest };
|
|
11000
|
+
export { CURRENT_RUNTIME_RANGE, DEFAULT_BUNDLE_DIR, DEFAULT_CONFIG_DIR, DEFAULT_CRONS_DIR, DEFAULT_FUNCTIONS_DIR, DEFAULT_SCHEMA_FILE, DEV_PORT_FILENAME, MANIFEST_FILENAME, ManifestError, TEMPLATE_PLACEHOLDER_FILES, appsCommand, assessManagedCompatibility, authCommand, buildBundle, buildCommand, buildInitQuestions, buildStaticBundle, buildableApps, cloudCommand, collectDeclaredDependencies, configureEnvFile, createRebaseApp, dbCommand, detectFrameworkDepDrift, detectNativeDependencies, detectPackageManager, detectStorageAuthorize, devCommand, doctorCommand, ejectCommand, entry, findBackendApp, findBackendDir, findEnvFile, findFrontendDir, findProjectRoot, findUnusedServerEntry, foldStaticIntoBundle, formatCdTarget, generateSdkCommand, getActiveBackendPlugin, getPMCommands, getProjectPort, isIdentifierLike, isPnpmAvailable, loadManifest, manifestExists, manifestPath, normalizeEsmSpecifiers, pnpmAvailabilityFromProbe, positionals, printInitHelp, readEnvFile, requireBackendDir, requireProjectRoot, resetPnpmAvailabilityCache, resolveBackendPaths, resolveCliVersion, resolveExampleBaseUrl, resolveLocalBin, resolvePluginCliScript, resolveRuntimeImageTag, resolveStartPort, resolveTsx, schemaCommand, selectUserForEmail, startCommand, synthesizeManifest, validateManifest, validateProjectName, validateTsxInstallation, writeManifest };
|
|
10897
11001
|
|
|
10898
11002
|
//# sourceMappingURL=index.es.js.map
|