@vibecodemax/cli 0.1.11 → 0.1.13
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/cli.js +159 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -473,6 +473,132 @@ function runSupabaseCommand(args, dependencyManager) {
|
|
|
473
473
|
fail("SUPABASE_CLI_ERROR", [result.stderr, result.stdout].find(isNonEmptyString) || `Supabase CLI ${args.join(" ")} failed.`, 1, { exitCode: result.status ?? 1 });
|
|
474
474
|
}
|
|
475
475
|
}
|
|
476
|
+
function runSupabaseCommandResult(args, dependencyManager) {
|
|
477
|
+
const runner = getSupabaseRunnerCommand(dependencyManager);
|
|
478
|
+
return spawnSync(runner.command, [...runner.args, ...args], {
|
|
479
|
+
cwd: process.cwd(),
|
|
480
|
+
encoding: "utf8",
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
function runSupabaseCommandCapture(args, dependencyManager) {
|
|
484
|
+
const result = runSupabaseCommandResult(args, dependencyManager);
|
|
485
|
+
if (result.status !== 0) {
|
|
486
|
+
fail("SUPABASE_CLI_ERROR", [result.stderr, result.stdout].find(isNonEmptyString) || `Supabase CLI ${args.join(" ")} failed.`, 1, { exitCode: result.status ?? 1 });
|
|
487
|
+
}
|
|
488
|
+
return result.stdout || "";
|
|
489
|
+
}
|
|
490
|
+
function extractMigrationVersion(value) {
|
|
491
|
+
if (!isNonEmptyString(value))
|
|
492
|
+
return "";
|
|
493
|
+
const match = value.trim().match(/^(\d{14})/);
|
|
494
|
+
return match ? match[1] : "";
|
|
495
|
+
}
|
|
496
|
+
function listLocalMigrationVersions(cwd = process.cwd()) {
|
|
497
|
+
const migrationsDir = path.join(cwd, "supabase", "migrations");
|
|
498
|
+
let entries = [];
|
|
499
|
+
try {
|
|
500
|
+
entries = fs.readdirSync(migrationsDir);
|
|
501
|
+
}
|
|
502
|
+
catch {
|
|
503
|
+
return [];
|
|
504
|
+
}
|
|
505
|
+
return [...new Set(entries.map((entry) => extractMigrationVersion(entry)).filter(Boolean))].sort();
|
|
506
|
+
}
|
|
507
|
+
function collectVersionsFromRows(rows, keyCandidates) {
|
|
508
|
+
const values = new Set();
|
|
509
|
+
for (const row of rows) {
|
|
510
|
+
if (!row || typeof row !== "object")
|
|
511
|
+
continue;
|
|
512
|
+
const record = row;
|
|
513
|
+
for (const key of keyCandidates) {
|
|
514
|
+
const version = extractMigrationVersion(record[key]);
|
|
515
|
+
if (version) {
|
|
516
|
+
values.add(version);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
return Array.from(values).sort();
|
|
521
|
+
}
|
|
522
|
+
function parseMigrationListTableOutput(raw) {
|
|
523
|
+
const localVersions = new Set();
|
|
524
|
+
const remoteVersions = new Set();
|
|
525
|
+
for (const line of raw.split(/\r?\n/)) {
|
|
526
|
+
if (!line.includes("|"))
|
|
527
|
+
continue;
|
|
528
|
+
const columns = line.split("|").map((value) => value.trim());
|
|
529
|
+
if (columns.length < 2)
|
|
530
|
+
continue;
|
|
531
|
+
const [localCell, remoteCell] = columns;
|
|
532
|
+
const normalizedLocal = localCell.toLowerCase();
|
|
533
|
+
const normalizedRemote = remoteCell.toLowerCase();
|
|
534
|
+
if ((normalizedLocal === "local" && normalizedRemote === "remote")
|
|
535
|
+
|| (/^-+$/.test(localCell.replace(/\s/g, "")) && /^-+$/.test(remoteCell.replace(/\s/g, "")))) {
|
|
536
|
+
continue;
|
|
537
|
+
}
|
|
538
|
+
const localVersion = extractMigrationVersion(localCell);
|
|
539
|
+
const remoteVersion = extractMigrationVersion(remoteCell);
|
|
540
|
+
if (localVersion)
|
|
541
|
+
localVersions.add(localVersion);
|
|
542
|
+
if (remoteVersion)
|
|
543
|
+
remoteVersions.add(remoteVersion);
|
|
544
|
+
}
|
|
545
|
+
if (localVersions.size === 0 && remoteVersions.size === 0)
|
|
546
|
+
return null;
|
|
547
|
+
return {
|
|
548
|
+
localVersions: Array.from(localVersions).sort(),
|
|
549
|
+
remoteVersions: Array.from(remoteVersions).sort(),
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
function parseMigrationListOutput(raw) {
|
|
553
|
+
const trimmed = raw.trim();
|
|
554
|
+
if (!trimmed) {
|
|
555
|
+
return { localVersions: [], remoteVersions: [] };
|
|
556
|
+
}
|
|
557
|
+
try {
|
|
558
|
+
const parsed = JSON.parse(trimmed);
|
|
559
|
+
const rows = Array.isArray(parsed)
|
|
560
|
+
? parsed
|
|
561
|
+
: Array.isArray(parsed?.migrations)
|
|
562
|
+
? (parsed.migrations)
|
|
563
|
+
: Array.isArray(parsed?.data)
|
|
564
|
+
? (parsed.data)
|
|
565
|
+
: null;
|
|
566
|
+
if (!rows) {
|
|
567
|
+
fail("INVALID_MIGRATION_LIST_OUTPUT", "Supabase migration list JSON output did not contain a rows array.");
|
|
568
|
+
}
|
|
569
|
+
const localVersions = collectVersionsFromRows(rows, [
|
|
570
|
+
"local",
|
|
571
|
+
"local_version",
|
|
572
|
+
"localVersion",
|
|
573
|
+
"localMigration",
|
|
574
|
+
"local_migration",
|
|
575
|
+
]);
|
|
576
|
+
const remoteVersions = collectVersionsFromRows(rows, [
|
|
577
|
+
"remote",
|
|
578
|
+
"remote_version",
|
|
579
|
+
"remoteVersion",
|
|
580
|
+
"remoteMigration",
|
|
581
|
+
"remote_migration",
|
|
582
|
+
]);
|
|
583
|
+
if (localVersions.length === 0 && remoteVersions.length === 0) {
|
|
584
|
+
fail("INVALID_MIGRATION_LIST_OUTPUT", "Supabase migration list JSON output did not include recognizable local or remote migration version fields.");
|
|
585
|
+
}
|
|
586
|
+
return { localVersions, remoteVersions };
|
|
587
|
+
}
|
|
588
|
+
catch (error) {
|
|
589
|
+
if (error instanceof SyntaxError) {
|
|
590
|
+
const fallback = parseMigrationListTableOutput(trimmed);
|
|
591
|
+
if (fallback)
|
|
592
|
+
return fallback;
|
|
593
|
+
fail("INVALID_MIGRATION_LIST_OUTPUT", "Supabase migration list output was neither valid JSON nor a recognizable table. Upgrade the local Supabase CLI if its migration list format is unsupported.");
|
|
594
|
+
}
|
|
595
|
+
throw error;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
function supportsJsonMigrationListFailure(result) {
|
|
599
|
+
const combined = [result.stderr, result.stdout].filter(isNonEmptyString).join("\n").toLowerCase();
|
|
600
|
+
return combined.includes("--output") || combined.includes("unknown flag") || combined.includes("unknown option");
|
|
601
|
+
}
|
|
476
602
|
async function supabaseManagementApiRequest(params) {
|
|
477
603
|
const response = await fetch(`${MANAGEMENT_API_BASE}${params.endpoint}`, {
|
|
478
604
|
method: params.method,
|
|
@@ -752,6 +878,36 @@ async function linkBaseSupabaseProject(flags) {
|
|
|
752
878
|
bootstrapKeysWritten: writes.bootstrapKeysWritten,
|
|
753
879
|
});
|
|
754
880
|
}
|
|
881
|
+
function preflightBaseMigrationState(flags) {
|
|
882
|
+
const dependencyManager = normalizeDependencyManagerFlag(flags);
|
|
883
|
+
const localVersions = listLocalMigrationVersions();
|
|
884
|
+
let result = runSupabaseCommandResult(["migration", "list", "--linked", "--output", "json"], dependencyManager);
|
|
885
|
+
if (result.status !== 0 && supportsJsonMigrationListFailure(result)) {
|
|
886
|
+
result = runSupabaseCommandResult(["migration", "list", "--linked"], dependencyManager);
|
|
887
|
+
}
|
|
888
|
+
if (result.status !== 0) {
|
|
889
|
+
fail("SUPABASE_CLI_ERROR", [result.stderr, result.stdout].find(isNonEmptyString) || "Supabase CLI migration list failed.", 1, { exitCode: result.status ?? 1 });
|
|
890
|
+
}
|
|
891
|
+
const raw = result.stdout || "";
|
|
892
|
+
const parsed = parseMigrationListOutput(raw);
|
|
893
|
+
const localSet = new Set(localVersions);
|
|
894
|
+
const remoteSet = new Set(parsed.remoteVersions);
|
|
895
|
+
const localOnlyVersions = localVersions.filter((version) => !remoteSet.has(version));
|
|
896
|
+
const remoteOnlyVersions = parsed.remoteVersions.filter((version) => !localSet.has(version));
|
|
897
|
+
const blocked = remoteOnlyVersions.length > 0;
|
|
898
|
+
printJson({
|
|
899
|
+
ok: true,
|
|
900
|
+
command: "base preflight-migration-state",
|
|
901
|
+
localVersions,
|
|
902
|
+
remoteVersions: parsed.remoteVersions,
|
|
903
|
+
localOnlyVersions,
|
|
904
|
+
remoteOnlyVersions,
|
|
905
|
+
blocked,
|
|
906
|
+
requiresUserDecision: blocked,
|
|
907
|
+
decisionOptions: blocked ? ["reset", "repair", "relink"] : ["continue"],
|
|
908
|
+
status: blocked ? "diverged" : "aligned_or_recoverable",
|
|
909
|
+
});
|
|
910
|
+
}
|
|
755
911
|
async function supabaseAdminRequest(params) {
|
|
756
912
|
const response = await fetch(`${params.supabaseUrl}${params.endpoint}`, {
|
|
757
913
|
method: params.method,
|
|
@@ -1952,6 +2108,7 @@ async function main() {
|
|
|
1952
2108
|
"base check-supabase-access-token",
|
|
1953
2109
|
"base create-supabase-project",
|
|
1954
2110
|
"base link-supabase-project",
|
|
2111
|
+
"base preflight-migration-state",
|
|
1955
2112
|
"admin ensure-admin",
|
|
1956
2113
|
"storage check-supabase-context",
|
|
1957
2114
|
"storage setup-supabase",
|
|
@@ -1987,6 +2144,8 @@ async function main() {
|
|
|
1987
2144
|
return createBaseSupabaseProject(flags);
|
|
1988
2145
|
if (command === "base" && subcommand === "link-supabase-project")
|
|
1989
2146
|
return linkBaseSupabaseProject(flags);
|
|
2147
|
+
if (command === "base" && subcommand === "preflight-migration-state")
|
|
2148
|
+
return preflightBaseMigrationState(flags);
|
|
1990
2149
|
if (command === "admin" && subcommand === "ensure-admin")
|
|
1991
2150
|
return ensureAdmin(flags);
|
|
1992
2151
|
if (command === "storage" && subcommand === "check-supabase-context")
|