@supacloud/cli 0.31.0 → 0.33.0
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/README.md +29 -0
- package/dist/index.js +287 -33
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -440,6 +440,35 @@ Use `--data_mode full_clone` only for an explicitly approved non-sensitive or
|
|
|
440
440
|
masked debugging dataset. Whole-database replacement is an administrator-only
|
|
441
441
|
break-glass API mode and is intentionally not exposed by this project CLI.
|
|
442
442
|
|
|
443
|
+
## SupaCloud Lite CLI adapter
|
|
444
|
+
|
|
445
|
+
Lite can be used from its standalone `supacloud-lite` CLI and from the main
|
|
446
|
+
`supacloud-cli` through the local-only `lite` module. The adapter never calls
|
|
447
|
+
the Management API, never invokes the official Supabase CLI, and never treats a
|
|
448
|
+
PGlite data directory as a Postgres DSN.
|
|
449
|
+
|
|
450
|
+
```bash
|
|
451
|
+
supacloud-cli lite migrate --project_dir .
|
|
452
|
+
supacloud-cli lite status --project_dir .
|
|
453
|
+
supacloud-cli lite db_diff --project_dir . --file add_accounts
|
|
454
|
+
supacloud-cli lite db_pull --project_dir . --file remote_schema
|
|
455
|
+
supacloud-cli lite gen_types --project_dir . --output src/database.types.ts
|
|
456
|
+
supacloud-cli lite snapshot_create --project_dir . --output backups/lite.tar.gz
|
|
457
|
+
supacloud-cli lite doctor --project_dir . --json
|
|
458
|
+
supacloud-cli lite start --project_dir . --port 54321
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
The adapter resolves the executable in this order:
|
|
462
|
+
|
|
463
|
+
1. `SUPACLOUD_LITE_CLI_BIN`
|
|
464
|
+
2. `<workdir>/node_modules/@supacloud/lite/dist/launcher.cjs`
|
|
465
|
+
3. `supacloud-lite` on `PATH`
|
|
466
|
+
|
|
467
|
+
Install `@supacloud/lite` or provide an explicit binary before using the
|
|
468
|
+
adapter. Lite actions are local-only, so Management API context and project
|
|
469
|
+
refs are not required. The `supabase` module remains the official CLI adapter;
|
|
470
|
+
use it for upstream Supabase CLI actions and Management-backed remote pushes.
|
|
471
|
+
|
|
443
472
|
## Official Supabase CLI adapter
|
|
444
473
|
|
|
445
474
|
The `supabase` command group is a thin, allowlisted adapter around the official
|
package/dist/index.js
CHANGED
|
@@ -6471,6 +6471,24 @@ var ACTION_POLICY = {
|
|
|
6471
6471
|
local: ["version", "migration_new", "db_diff", "db_reset", "db_pull", "db_dump", "migration_list", "gen_types"],
|
|
6472
6472
|
write: ["push"]
|
|
6473
6473
|
},
|
|
6474
|
+
lite: {
|
|
6475
|
+
local: [
|
|
6476
|
+
"version",
|
|
6477
|
+
"start",
|
|
6478
|
+
"migrate",
|
|
6479
|
+
"status",
|
|
6480
|
+
"keys",
|
|
6481
|
+
"gen_types",
|
|
6482
|
+
"db_reset",
|
|
6483
|
+
"db_diff",
|
|
6484
|
+
"db_pull",
|
|
6485
|
+
"snapshot_create",
|
|
6486
|
+
"snapshot_restore",
|
|
6487
|
+
"upgrade",
|
|
6488
|
+
"inspect",
|
|
6489
|
+
"doctor"
|
|
6490
|
+
]
|
|
6491
|
+
},
|
|
6474
6492
|
auth: {
|
|
6475
6493
|
read: ["list_users", "get_user", "list_providers", "get_provider", "supported_providers", "get_settings", "get_config", "get_oauth_server"],
|
|
6476
6494
|
write: ["generate_link", "configure_provider", "update_provider", "disable_provider", "wechat_mini", "wechat_open", "update_settings", "update_config", "migrate_oauth_server"]
|
|
@@ -12100,6 +12118,7 @@ Actions: routes, upsert_route, update_route, delete_route, config, get_certifica
|
|
|
12100
12118
|
managed_upstream: optional(stringEnum(["edge-functions"]), "[upsert_route/update_route] 托管上游(同步 Edge Function)"),
|
|
12101
12119
|
upstream_tls_insecure_skip_verify: optional(Type.Boolean(), "[upsert_route/update_route] 上游 TLS 跳过校验"),
|
|
12102
12120
|
static_root: optional(Type.String(), "[upsert_route/update_route] 静态站点根目录"),
|
|
12121
|
+
spa: optional(Type.Boolean(), "[upsert_route/update_route] 是否启用 SPA 单页回退"),
|
|
12103
12122
|
protocol: optional(stringEnum(["http", "https"]), "[upsert_route/update_route] 可选请求协议匹配"),
|
|
12104
12123
|
redirect_to: optional(Type.String(), "[upsert_route/update_route] 带固定 host 的绝对 http(s) 目标,可在末尾使用 {http.request.uri}"),
|
|
12105
12124
|
redirect_status: withDescription(redirectStatus, "[upsert_route/update_route] 重定向状态码,默认 308"),
|
|
@@ -12146,6 +12165,7 @@ Actions: routes, upsert_route, update_route, delete_route, config, get_certifica
|
|
|
12146
12165
|
managed_upstream,
|
|
12147
12166
|
upstream_tls_insecure_skip_verify,
|
|
12148
12167
|
static_root,
|
|
12168
|
+
spa,
|
|
12149
12169
|
protocol,
|
|
12150
12170
|
redirect_to,
|
|
12151
12171
|
redirect_status,
|
|
@@ -12195,6 +12215,8 @@ Actions: routes, upsert_route, update_route, delete_route, config, get_certifica
|
|
|
12195
12215
|
body.upstream_tls_insecure_skip_verify = upstream_tls_insecure_skip_verify;
|
|
12196
12216
|
if (static_root !== undefined)
|
|
12197
12217
|
body.static_root = static_root;
|
|
12218
|
+
if (spa !== undefined)
|
|
12219
|
+
body.spa = spa;
|
|
12198
12220
|
if (protocol !== undefined)
|
|
12199
12221
|
body.protocol = protocol;
|
|
12200
12222
|
if (redirect_to !== undefined)
|
|
@@ -12232,6 +12254,8 @@ Actions: routes, upsert_route, update_route, delete_route, config, get_certifica
|
|
|
12232
12254
|
body.upstream_tls_insecure_skip_verify = upstream_tls_insecure_skip_verify;
|
|
12233
12255
|
if (static_root !== undefined)
|
|
12234
12256
|
body.static_root = static_root;
|
|
12257
|
+
if (spa !== undefined)
|
|
12258
|
+
body.spa = spa;
|
|
12235
12259
|
if (protocol !== undefined)
|
|
12236
12260
|
body.protocol = protocol;
|
|
12237
12261
|
if (redirect_to !== undefined)
|
|
@@ -12888,10 +12912,236 @@ function registerSupabaseCliTools(server, options = {}) {
|
|
|
12888
12912
|
}, (request) => executeSupabaseAction(request, runtime));
|
|
12889
12913
|
}
|
|
12890
12914
|
|
|
12915
|
+
// src/shared/tools/lite-cli-tools.ts
|
|
12916
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
12917
|
+
import { existsSync as existsSync6, statSync as statSync4 } from "node:fs";
|
|
12918
|
+
import { join as join4, resolve as resolve4 } from "node:path";
|
|
12919
|
+
function requireWorkdir(workdir, fallback) {
|
|
12920
|
+
const resolved = resolve4(workdir || fallback);
|
|
12921
|
+
if (!existsSync6(resolved) || !statSync4(resolved).isDirectory()) {
|
|
12922
|
+
throw new Error(`Lite workdir not found: ${resolved}`);
|
|
12923
|
+
}
|
|
12924
|
+
return resolved;
|
|
12925
|
+
}
|
|
12926
|
+
function optionalFlag(args, flag, value) {
|
|
12927
|
+
if (value !== undefined)
|
|
12928
|
+
args.push(flag, String(value));
|
|
12929
|
+
}
|
|
12930
|
+
function booleanFlag(args, flag, value) {
|
|
12931
|
+
if (value === true)
|
|
12932
|
+
args.push(flag);
|
|
12933
|
+
}
|
|
12934
|
+
function buildLiteArgs(request) {
|
|
12935
|
+
const args = [];
|
|
12936
|
+
if (request.action === "version")
|
|
12937
|
+
return ["--version"];
|
|
12938
|
+
switch (request.action) {
|
|
12939
|
+
case "start":
|
|
12940
|
+
case "migrate":
|
|
12941
|
+
case "status":
|
|
12942
|
+
case "keys":
|
|
12943
|
+
case "upgrade":
|
|
12944
|
+
case "inspect":
|
|
12945
|
+
case "doctor":
|
|
12946
|
+
args.push(request.action);
|
|
12947
|
+
break;
|
|
12948
|
+
case "gen_types":
|
|
12949
|
+
args.push("gen", "types");
|
|
12950
|
+
break;
|
|
12951
|
+
case "db_reset":
|
|
12952
|
+
args.push("db", "reset");
|
|
12953
|
+
break;
|
|
12954
|
+
case "db_diff":
|
|
12955
|
+
args.push("db", "diff");
|
|
12956
|
+
break;
|
|
12957
|
+
case "db_pull":
|
|
12958
|
+
args.push("db", "pull");
|
|
12959
|
+
if (request.file)
|
|
12960
|
+
args.push(request.file);
|
|
12961
|
+
break;
|
|
12962
|
+
case "snapshot_create":
|
|
12963
|
+
args.push("snapshot", "create");
|
|
12964
|
+
break;
|
|
12965
|
+
case "snapshot_restore":
|
|
12966
|
+
if (!request.snapshot_file)
|
|
12967
|
+
throw new Error("snapshot_restore requires --snapshot_file");
|
|
12968
|
+
args.push("snapshot", "restore", request.snapshot_file);
|
|
12969
|
+
break;
|
|
12970
|
+
default:
|
|
12971
|
+
throw new Error(`Unsupported Lite CLI action: ${String(request.action)}`);
|
|
12972
|
+
}
|
|
12973
|
+
optionalFlag(args, "--project-dir", request.project_dir);
|
|
12974
|
+
optionalFlag(args, "--state-dir", request.state_dir);
|
|
12975
|
+
optionalFlag(args, "--data-dir", request.data_dir);
|
|
12976
|
+
optionalFlag(args, "--storage-dir", request.storage_dir);
|
|
12977
|
+
optionalFlag(args, "--storage-backend", request.storage_backend);
|
|
12978
|
+
optionalFlag(args, "--s3-prefix", request.s3_prefix);
|
|
12979
|
+
optionalFlag(args, "--engine", request.engine);
|
|
12980
|
+
optionalFlag(args, "--host", request.host);
|
|
12981
|
+
optionalFlag(args, "--port", request.port);
|
|
12982
|
+
optionalFlag(args, "--api-url", request.api_url);
|
|
12983
|
+
optionalFlag(args, "--site-url", request.site_url);
|
|
12984
|
+
optionalFlag(args, "--replication-profile", request.replication_profile);
|
|
12985
|
+
optionalFlag(args, "--replication-host", request.replication_host);
|
|
12986
|
+
optionalFlag(args, "--replication-port", request.replication_port);
|
|
12987
|
+
optionalFlag(args, "--replication-allow-cidrs", request.replication_allow_cidrs);
|
|
12988
|
+
optionalFlag(args, "--powersync-tables", request.powersync_tables);
|
|
12989
|
+
optionalFlag(args, "--replication-tls-cert", request.replication_tls_cert);
|
|
12990
|
+
optionalFlag(args, "--replication-tls-key", request.replication_tls_key);
|
|
12991
|
+
optionalFlag(args, "--output", request.output);
|
|
12992
|
+
optionalFlag(args, "--file", request.action === "db_diff" ? request.file : undefined);
|
|
12993
|
+
booleanFlag(args, "--service-role", request.service_role);
|
|
12994
|
+
booleanFlag(args, "--force", request.force);
|
|
12995
|
+
booleanFlag(args, "--memory", request.memory);
|
|
12996
|
+
booleanFlag(args, "--json", request.json);
|
|
12997
|
+
return args;
|
|
12998
|
+
}
|
|
12999
|
+
function resolveLiteCommand(workdir, environment = process.env) {
|
|
13000
|
+
const explicitBinary = environment.SUPACLOUD_LITE_CLI_BIN?.trim();
|
|
13001
|
+
if (explicitBinary) {
|
|
13002
|
+
if (explicitBinary.includes("\x00"))
|
|
13003
|
+
throw new Error("Invalid SUPACLOUD_LITE_CLI_BIN");
|
|
13004
|
+
return [explicitBinary];
|
|
13005
|
+
}
|
|
13006
|
+
const localPackageEntry = join4(resolve4(workdir), "node_modules", "@supacloud", "lite", "dist", "launcher.cjs");
|
|
13007
|
+
if (existsSync6(localPackageEntry))
|
|
13008
|
+
return [process.execPath, localPackageEntry];
|
|
13009
|
+
return ["supacloud-lite"];
|
|
13010
|
+
}
|
|
13011
|
+
function spawnLiteCommand(command, workdir, environment, inheritOutput) {
|
|
13012
|
+
const [executable, ...commandArguments] = command;
|
|
13013
|
+
return new Promise((resolveExecution, rejectExecution) => {
|
|
13014
|
+
const child = spawn2(executable, commandArguments, {
|
|
13015
|
+
cwd: workdir,
|
|
13016
|
+
env: { ...environment, NO_COLOR: "1" },
|
|
13017
|
+
shell: false,
|
|
13018
|
+
stdio: inheritOutput ? ["inherit", "inherit", "inherit"] : ["ignore", "pipe", "pipe"],
|
|
13019
|
+
windowsHide: true
|
|
13020
|
+
});
|
|
13021
|
+
const forwardSignal = (signal) => child.kill(signal);
|
|
13022
|
+
process.once("SIGINT", forwardSignal);
|
|
13023
|
+
process.once("SIGTERM", forwardSignal);
|
|
13024
|
+
const cleanup = () => {
|
|
13025
|
+
process.off("SIGINT", forwardSignal);
|
|
13026
|
+
process.off("SIGTERM", forwardSignal);
|
|
13027
|
+
};
|
|
13028
|
+
if (inheritOutput) {
|
|
13029
|
+
child.once("error", (error) => {
|
|
13030
|
+
cleanup();
|
|
13031
|
+
rejectExecution(error);
|
|
13032
|
+
});
|
|
13033
|
+
child.once("close", (exitCode) => {
|
|
13034
|
+
cleanup();
|
|
13035
|
+
resolveExecution({ exitCode: exitCode ?? 1, stdout: "", stderr: "" });
|
|
13036
|
+
});
|
|
13037
|
+
return;
|
|
13038
|
+
}
|
|
13039
|
+
if (!child.stdout || !child.stderr) {
|
|
13040
|
+
cleanup();
|
|
13041
|
+
rejectExecution(new Error("Lite CLI child process did not expose piped output"));
|
|
13042
|
+
return;
|
|
13043
|
+
}
|
|
13044
|
+
let standardOutput = "";
|
|
13045
|
+
let standardError = "";
|
|
13046
|
+
child.stdout.setEncoding("utf8");
|
|
13047
|
+
child.stderr.setEncoding("utf8");
|
|
13048
|
+
child.stdout.on("data", (chunk) => {
|
|
13049
|
+
standardOutput += chunk;
|
|
13050
|
+
});
|
|
13051
|
+
child.stderr.on("data", (chunk) => {
|
|
13052
|
+
standardError += chunk;
|
|
13053
|
+
});
|
|
13054
|
+
child.once("error", (error) => {
|
|
13055
|
+
cleanup();
|
|
13056
|
+
rejectExecution(error);
|
|
13057
|
+
});
|
|
13058
|
+
child.once("close", (exitCode) => {
|
|
13059
|
+
cleanup();
|
|
13060
|
+
resolveExecution({ exitCode: exitCode ?? 1, stdout: standardOutput, stderr: standardError });
|
|
13061
|
+
});
|
|
13062
|
+
});
|
|
13063
|
+
}
|
|
13064
|
+
async function executeLiteCli(request, environment, fallbackWorkdir) {
|
|
13065
|
+
const workdir = requireWorkdir(request.workdir, fallbackWorkdir);
|
|
13066
|
+
const command = [...resolveLiteCommand(workdir, environment), ...buildLiteArgs({ ...request, workdir })];
|
|
13067
|
+
try {
|
|
13068
|
+
return await spawnLiteCommand(command, workdir, environment, request.action === "start");
|
|
13069
|
+
} catch (error) {
|
|
13070
|
+
const failureMessage = error instanceof Error ? error.message : String(error);
|
|
13071
|
+
throw new Error([
|
|
13072
|
+
"SupaCloud Lite CLI could not be started.",
|
|
13073
|
+
"Install @supacloud/lite, put supacloud-lite on PATH, or set SUPACLOUD_LITE_CLI_BIN.",
|
|
13074
|
+
failureMessage
|
|
13075
|
+
].join(" "));
|
|
13076
|
+
}
|
|
13077
|
+
}
|
|
13078
|
+
function formatExecutionText2(action, execution) {
|
|
13079
|
+
const combinedOutput = [execution.stdout.trim(), execution.stderr.trim()].filter(Boolean).join(`
|
|
13080
|
+
`);
|
|
13081
|
+
const heading = execution.exitCode === 0 ? `✅ SupaCloud Lite ${action} completed` : `❌ SupaCloud Lite ${action} failed (exit ${execution.exitCode})`;
|
|
13082
|
+
return combinedOutput ? `${heading}
|
|
13083
|
+
${combinedOutput}` : heading;
|
|
13084
|
+
}
|
|
13085
|
+
function registerLiteCliTools(server, options = {}) {
|
|
13086
|
+
const environment = options.environment || process.env;
|
|
13087
|
+
const fallbackWorkdir = options.currentWorkingDirectory || process.cwd();
|
|
13088
|
+
const execute = options.executeLiteCli || ((request) => executeLiteCli(request, environment, fallbackWorkdir));
|
|
13089
|
+
server.tool("lite", "Controlled adapter for the local SupaCloud Lite CLI. Lite actions are local-only and never use the Management API or official Supabase CLI.", {
|
|
13090
|
+
action: withDescription(stringEnum([
|
|
13091
|
+
"version",
|
|
13092
|
+
"start",
|
|
13093
|
+
"migrate",
|
|
13094
|
+
"status",
|
|
13095
|
+
"keys",
|
|
13096
|
+
"gen_types",
|
|
13097
|
+
"db_reset",
|
|
13098
|
+
"db_diff",
|
|
13099
|
+
"db_pull",
|
|
13100
|
+
"snapshot_create",
|
|
13101
|
+
"snapshot_restore",
|
|
13102
|
+
"upgrade",
|
|
13103
|
+
"inspect",
|
|
13104
|
+
"doctor"
|
|
13105
|
+
]), "Lite CLI action"),
|
|
13106
|
+
workdir: optional(Type.String(), "[*] Process working directory (default: current directory)"),
|
|
13107
|
+
project_dir: optional(Type.String(), "[*] Project containing supabase/"),
|
|
13108
|
+
state_dir: optional(Type.String(), "[*] Lite state root"),
|
|
13109
|
+
data_dir: optional(Type.String(), "[*] PGlite/native data directory"),
|
|
13110
|
+
storage_dir: optional(Type.String(), "[*] Object storage directory"),
|
|
13111
|
+
storage_backend: optional(stringEnum(["fs", "memory", "s3"]), "[*] Storage backend"),
|
|
13112
|
+
s3_prefix: optional(Type.String(), "[*] S3 object key prefix"),
|
|
13113
|
+
engine: optional(stringEnum(["pglite", "native"]), "[*] Database engine"),
|
|
13114
|
+
host: optional(Type.String(), "[start] Listen host"),
|
|
13115
|
+
port: optional(Type.Number(), "[start] Listen port"),
|
|
13116
|
+
api_url: optional(Type.String(), "[start] Public API URL"),
|
|
13117
|
+
site_url: optional(Type.String(), "[start] Auth site URL"),
|
|
13118
|
+
replication_profile: optional(stringEnum(["powersync"]), "[start/doctor] Replication profile"),
|
|
13119
|
+
replication_host: optional(Type.String(), "[start] Replication listener host"),
|
|
13120
|
+
replication_port: optional(Type.Number(), "[start] Replication listener port"),
|
|
13121
|
+
replication_allow_cidrs: optional(Type.String(), "[start] Replication client CIDRs"),
|
|
13122
|
+
powersync_tables: optional(Type.String(), "[start] PowerSync publication tables"),
|
|
13123
|
+
replication_tls_cert: optional(Type.String(), "[start] Replication TLS certificate"),
|
|
13124
|
+
replication_tls_key: optional(Type.String(), "[start] Replication TLS private key"),
|
|
13125
|
+
output: optional(Type.String(), "[gen_types/snapshot_create/upgrade] Output path"),
|
|
13126
|
+
file: optional(Type.String(), "[db_diff/db_pull] Migration suffix or name"),
|
|
13127
|
+
snapshot_file: optional(Type.String(), "[snapshot_restore] Snapshot archive"),
|
|
13128
|
+
service_role: optional(Type.Boolean(), "[keys] Also print the service_role key"),
|
|
13129
|
+
force: optional(Type.Boolean(), "[snapshot_restore] Replace non-empty restore targets"),
|
|
13130
|
+
memory: optional(Type.Boolean(), "[*] Use an in-memory PGlite database"),
|
|
13131
|
+
json: optional(Type.Boolean(), "[doctor] Emit machine-readable output")
|
|
13132
|
+
}, async (request) => {
|
|
13133
|
+
const execution = await execute(request);
|
|
13134
|
+
return {
|
|
13135
|
+
isError: execution.exitCode !== 0,
|
|
13136
|
+
content: [{ type: "text", text: formatExecutionText2(request.action, execution) }]
|
|
13137
|
+
};
|
|
13138
|
+
});
|
|
13139
|
+
}
|
|
13140
|
+
|
|
12891
13141
|
// src/shared/tools/ai-tools.ts
|
|
12892
13142
|
import {
|
|
12893
13143
|
cpSync,
|
|
12894
|
-
existsSync as
|
|
13144
|
+
existsSync as existsSync7,
|
|
12895
13145
|
lstatSync as lstatSync2,
|
|
12896
13146
|
mkdirSync as mkdirSync2,
|
|
12897
13147
|
mkdtempSync as mkdtempSync2,
|
|
@@ -12901,13 +13151,13 @@ import {
|
|
|
12901
13151
|
rmSync as rmSync2
|
|
12902
13152
|
} from "node:fs";
|
|
12903
13153
|
import { homedir as homedir2 } from "node:os";
|
|
12904
|
-
import { dirname as dirname2, join as
|
|
13154
|
+
import { dirname as dirname2, join as join5, relative as relative2, resolve as resolve5, sep as sep2 } from "node:path";
|
|
12905
13155
|
import { fileURLToPath } from "node:url";
|
|
12906
13156
|
var SKILL_NAME = "supacloud-cli";
|
|
12907
13157
|
function regularFiles(rootDirectory, currentDirectory = rootDirectory) {
|
|
12908
13158
|
const files = [];
|
|
12909
13159
|
for (const directoryEntry of readdirSync3(currentDirectory, { withFileTypes: true })) {
|
|
12910
|
-
const entryPath =
|
|
13160
|
+
const entryPath = join5(currentDirectory, directoryEntry.name);
|
|
12911
13161
|
if (directoryEntry.isSymbolicLink())
|
|
12912
13162
|
throw new Error(`Skill directories cannot contain symlinks: ${entryPath}`);
|
|
12913
13163
|
if (directoryEntry.isDirectory())
|
|
@@ -12918,13 +13168,13 @@ function regularFiles(rootDirectory, currentDirectory = rootDirectory) {
|
|
|
12918
13168
|
return files.sort();
|
|
12919
13169
|
}
|
|
12920
13170
|
function directoriesMatch(sourceDirectory, destinationDirectory) {
|
|
12921
|
-
if (!
|
|
13171
|
+
if (!existsSync7(destinationDirectory) || !lstatSync2(destinationDirectory).isDirectory())
|
|
12922
13172
|
return false;
|
|
12923
13173
|
const sourceFiles = regularFiles(sourceDirectory);
|
|
12924
13174
|
const destinationFiles = regularFiles(destinationDirectory);
|
|
12925
13175
|
if (sourceFiles.join("\x00") !== destinationFiles.join("\x00"))
|
|
12926
13176
|
return false;
|
|
12927
|
-
return sourceFiles.every((file) => readFileSync5(
|
|
13177
|
+
return sourceFiles.every((file) => readFileSync5(join5(sourceDirectory, file)).equals(readFileSync5(join5(destinationDirectory, file))));
|
|
12928
13178
|
}
|
|
12929
13179
|
function backupTimestamp(now) {
|
|
12930
13180
|
return now.toISOString().replace(/[-:.]/g, "");
|
|
@@ -12933,7 +13183,7 @@ function availableBackupDirectory(destinationDirectory, now) {
|
|
|
12933
13183
|
const baseDirectory = `${destinationDirectory}.backup-${backupTimestamp(now)}`;
|
|
12934
13184
|
let candidate = baseDirectory;
|
|
12935
13185
|
let suffix = 2;
|
|
12936
|
-
while (
|
|
13186
|
+
while (existsSync7(candidate)) {
|
|
12937
13187
|
candidate = `${baseDirectory}-${suffix}`;
|
|
12938
13188
|
suffix += 1;
|
|
12939
13189
|
}
|
|
@@ -12941,8 +13191,8 @@ function availableBackupDirectory(destinationDirectory, now) {
|
|
|
12941
13191
|
}
|
|
12942
13192
|
function stagedSkill(sourceDirectory, targetRoot) {
|
|
12943
13193
|
mkdirSync2(targetRoot, { recursive: true });
|
|
12944
|
-
const stagingRoot = mkdtempSync2(
|
|
12945
|
-
const stagingSkill =
|
|
13194
|
+
const stagingRoot = mkdtempSync2(join5(targetRoot, ".supacloud-cli-install-"));
|
|
13195
|
+
const stagingSkill = join5(stagingRoot, SKILL_NAME);
|
|
12946
13196
|
try {
|
|
12947
13197
|
cpSync(sourceDirectory, stagingSkill, { recursive: true, errorOnExist: true });
|
|
12948
13198
|
} catch (error) {
|
|
@@ -12974,13 +13224,13 @@ function replaceSkill(sourceDirectory, targetRoot, destinationDirectory, backupD
|
|
|
12974
13224
|
}
|
|
12975
13225
|
}
|
|
12976
13226
|
function skillSummary(request, action, files, backupDirectory) {
|
|
12977
|
-
const sourceDirectory =
|
|
12978
|
-
const targetRoot =
|
|
13227
|
+
const sourceDirectory = resolve5(request.sourceDirectory);
|
|
13228
|
+
const targetRoot = resolve5(request.targetRoot);
|
|
12979
13229
|
return {
|
|
12980
13230
|
name: SKILL_NAME,
|
|
12981
13231
|
sourceDirectory,
|
|
12982
13232
|
targetRoot,
|
|
12983
|
-
destinationDirectory:
|
|
13233
|
+
destinationDirectory: join5(targetRoot, SKILL_NAME),
|
|
12984
13234
|
action,
|
|
12985
13235
|
mode: request.mode,
|
|
12986
13236
|
changed: action !== "none",
|
|
@@ -12989,14 +13239,14 @@ function skillSummary(request, action, files, backupDirectory) {
|
|
|
12989
13239
|
};
|
|
12990
13240
|
}
|
|
12991
13241
|
function installSkill(request) {
|
|
12992
|
-
const sourceDirectory =
|
|
12993
|
-
const targetRoot =
|
|
12994
|
-
const destinationDirectory =
|
|
12995
|
-
if (!
|
|
13242
|
+
const sourceDirectory = resolve5(request.sourceDirectory);
|
|
13243
|
+
const targetRoot = resolve5(request.targetRoot);
|
|
13244
|
+
const destinationDirectory = join5(targetRoot, SKILL_NAME);
|
|
13245
|
+
if (!existsSync7(join5(sourceDirectory, "SKILL.md"))) {
|
|
12996
13246
|
throw new Error(`Bundled SupaCloud CLI skill not found: ${sourceDirectory}`);
|
|
12997
13247
|
}
|
|
12998
13248
|
const files = regularFiles(sourceDirectory);
|
|
12999
|
-
if (!
|
|
13249
|
+
if (!existsSync7(destinationDirectory))
|
|
13000
13250
|
return installNewSkill(request, files);
|
|
13001
13251
|
if (directoriesMatch(sourceDirectory, destinationDirectory)) {
|
|
13002
13252
|
return skillSummary(request, "none", files, null);
|
|
@@ -13007,17 +13257,17 @@ function installSkill(request) {
|
|
|
13007
13257
|
return installReplacementSkill(request, files);
|
|
13008
13258
|
}
|
|
13009
13259
|
function installNewSkill(request, files) {
|
|
13010
|
-
const sourceDirectory =
|
|
13011
|
-
const targetRoot =
|
|
13260
|
+
const sourceDirectory = resolve5(request.sourceDirectory);
|
|
13261
|
+
const targetRoot = resolve5(request.targetRoot);
|
|
13012
13262
|
if (request.mode === "write") {
|
|
13013
|
-
createSkill(sourceDirectory, targetRoot,
|
|
13263
|
+
createSkill(sourceDirectory, targetRoot, join5(targetRoot, SKILL_NAME));
|
|
13014
13264
|
}
|
|
13015
13265
|
return skillSummary(request, "create", files, null);
|
|
13016
13266
|
}
|
|
13017
13267
|
function installReplacementSkill(request, files) {
|
|
13018
|
-
const sourceDirectory =
|
|
13019
|
-
const targetRoot =
|
|
13020
|
-
const destinationDirectory =
|
|
13268
|
+
const sourceDirectory = resolve5(request.sourceDirectory);
|
|
13269
|
+
const targetRoot = resolve5(request.targetRoot);
|
|
13270
|
+
const destinationDirectory = join5(targetRoot, SKILL_NAME);
|
|
13021
13271
|
const backupDirectory = availableBackupDirectory(destinationDirectory, request.now);
|
|
13022
13272
|
if (request.mode === "write") {
|
|
13023
13273
|
replaceSkill(sourceDirectory, targetRoot, destinationDirectory, backupDirectory);
|
|
@@ -13026,15 +13276,15 @@ function installReplacementSkill(request, files) {
|
|
|
13026
13276
|
}
|
|
13027
13277
|
function resolveDefaultCodexSkillRoot(environment = process.env, homeDirectory = homedir2()) {
|
|
13028
13278
|
const codexHome = environment.CODEX_HOME?.trim();
|
|
13029
|
-
return
|
|
13279
|
+
return join5(resolve5(codexHome || join5(homeDirectory, ".codex")), "skills");
|
|
13030
13280
|
}
|
|
13031
13281
|
function resolveBundledSkillDirectory(moduleUrl = import.meta.url) {
|
|
13032
13282
|
const moduleDirectory = dirname2(fileURLToPath(moduleUrl));
|
|
13033
13283
|
const candidates = [
|
|
13034
|
-
|
|
13035
|
-
|
|
13284
|
+
resolve5(moduleDirectory, "../../../skills", SKILL_NAME),
|
|
13285
|
+
resolve5(moduleDirectory, "../skills", SKILL_NAME)
|
|
13036
13286
|
];
|
|
13037
|
-
const skillDirectory = candidates.find((candidate) =>
|
|
13287
|
+
const skillDirectory = candidates.find((candidate) => existsSync7(join5(candidate, "SKILL.md")));
|
|
13038
13288
|
if (!skillDirectory)
|
|
13039
13289
|
throw new Error("Bundled SupaCloud CLI skill is missing from this installation");
|
|
13040
13290
|
return skillDirectory;
|
|
@@ -13056,7 +13306,7 @@ function registerAiTools(server) {
|
|
|
13056
13306
|
name: SKILL_NAME,
|
|
13057
13307
|
sourceDirectory,
|
|
13058
13308
|
defaultTargetRoot,
|
|
13059
|
-
defaultDestination:
|
|
13309
|
+
defaultDestination: join5(defaultTargetRoot, SKILL_NAME)
|
|
13060
13310
|
});
|
|
13061
13311
|
}
|
|
13062
13312
|
return textResponse(installSkill({
|
|
@@ -13071,8 +13321,8 @@ function registerAiTools(server) {
|
|
|
13071
13321
|
|
|
13072
13322
|
// src/shared/tools/scheduled-function-tools.ts
|
|
13073
13323
|
import { randomUUID } from "node:crypto";
|
|
13074
|
-
import { readFileSync as readFileSync6, statSync as
|
|
13075
|
-
import { resolve as
|
|
13324
|
+
import { readFileSync as readFileSync6, statSync as statSync5 } from "node:fs";
|
|
13325
|
+
import { resolve as resolve6 } from "node:path";
|
|
13076
13326
|
import { isDeepStrictEqual } from "node:util";
|
|
13077
13327
|
var HEADER_NAME_PATTERN = /^[!#$%&'*+.^_`|~0-9A-Za-z-]{1,128}$/;
|
|
13078
13328
|
var ENVIRONMENT_NAME_PATTERN2 = /^[A-Za-z_][A-Za-z0-9_]{0,255}$/;
|
|
@@ -13156,8 +13406,8 @@ function validScheduledFunctionCron(expression) {
|
|
|
13156
13406
|
function readScheduleBodyFile(bodyPathInput) {
|
|
13157
13407
|
if (!bodyPathInput.trim())
|
|
13158
13408
|
throw new Error("'body_file' must be a path");
|
|
13159
|
-
const bodyPath =
|
|
13160
|
-
const bodyStat =
|
|
13409
|
+
const bodyPath = resolve6(bodyPathInput);
|
|
13410
|
+
const bodyStat = statSync5(bodyPath);
|
|
13161
13411
|
if (!bodyStat.isFile() || bodyStat.size > MAX_BODY_FILE_BYTES) {
|
|
13162
13412
|
throw new Error("Scheduled Function body file must be a regular file no larger than 1 MiB");
|
|
13163
13413
|
}
|
|
@@ -14115,7 +14365,7 @@ function registerReleaseTools(server, http, options = {}) {
|
|
|
14115
14365
|
// package.json
|
|
14116
14366
|
var package_default = {
|
|
14117
14367
|
name: "@supacloud/cli",
|
|
14118
|
-
version: "0.
|
|
14368
|
+
version: "0.33.0",
|
|
14119
14369
|
description: "Project-scoped CLI for SupaCloud users",
|
|
14120
14370
|
type: "module",
|
|
14121
14371
|
main: "./dist/index.js",
|
|
@@ -14380,6 +14630,9 @@ EXAMPLES
|
|
|
14380
14630
|
${preferredCommand} supabase db_diff --schema public --name add_accounts
|
|
14381
14631
|
${preferredCommand} supabase push --ref abc123 --dir supabase/migrations --dry_run
|
|
14382
14632
|
${preferredCommand} supabase db_dump --db_url "postgresql://..." --file backups/schema.sql
|
|
14633
|
+
${preferredCommand} lite migrate --project_dir .
|
|
14634
|
+
${preferredCommand} lite start --project_dir . --port 54321
|
|
14635
|
+
${preferredCommand} lite doctor --project_dir . --json
|
|
14383
14636
|
${preferredCommand} branch create --name feature-auth --data_mode schema_only
|
|
14384
14637
|
${preferredCommand} branch promotion_plan --branch_ref preview123
|
|
14385
14638
|
${preferredCommand} branch promote --branch_ref preview123 --plan_checksum <sha256>
|
|
@@ -14432,6 +14685,7 @@ function createCliTools(context, confirmProduction) {
|
|
|
14432
14685
|
projectRef: context.projectRef || undefined,
|
|
14433
14686
|
readOnly: context.readOnly
|
|
14434
14687
|
})));
|
|
14688
|
+
Object.assign(tools, captureTools((server) => registerLiteCliTools(server)));
|
|
14435
14689
|
Object.assign(tools, captureTools((server) => registerAiTools(server)));
|
|
14436
14690
|
const registerContextAwareHelp = () => {
|
|
14437
14691
|
tools.project = {
|
|
@@ -14593,7 +14847,7 @@ async function main() {
|
|
|
14593
14847
|
return;
|
|
14594
14848
|
}
|
|
14595
14849
|
const cliTools = createCliTools(context, globalOptions.confirmProduction);
|
|
14596
|
-
if (args.length === 1 && !["ai", "supabase"].includes(args[0]) && cliTools[args[0]]) {
|
|
14850
|
+
if (args.length === 1 && !["ai", "supabase", "lite"].includes(args[0]) && cliTools[args[0]]) {
|
|
14597
14851
|
const result = await cliTools[args[0]].callback({});
|
|
14598
14852
|
if (result?.content && Array.isArray(result.content)) {
|
|
14599
14853
|
for (const chunk of result.content) {
|