supbuddy 3.3.2 → 3.3.3
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/bin.js +23 -7
- package/dist/daemon/worker.cjs +89 -28
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -19812,7 +19812,7 @@ function cliBuildKind(env3 = process.env) {
|
|
|
19812
19812
|
return raw === "host" || raw === "npm" ? raw : "dev";
|
|
19813
19813
|
}
|
|
19814
19814
|
function cliVersion(env3 = process.env) {
|
|
19815
|
-
return "3.3.
|
|
19815
|
+
return "3.3.3".trim() || "0.0.0-dev";
|
|
19816
19816
|
}
|
|
19817
19817
|
function isDevBuild(env3) {
|
|
19818
19818
|
return cliBuildKind(env3) === "dev";
|
|
@@ -41733,15 +41733,24 @@ loopback IP \u2014 target the app's **canonical** dev port (Next.js \`:3000\`, V
|
|
|
41733
41733
|
share \`127.0.0.1\` and need unique ports.
|
|
41734
41734
|
`;
|
|
41735
41735
|
}
|
|
41736
|
+
function supabaseServicePort(project, type2, managedKey, stock) {
|
|
41737
|
+
const svc = (project.services ?? []).find((s) => s.type === type2);
|
|
41738
|
+
const snapshot = svc?.port ?? svc?.ports?.[0];
|
|
41739
|
+
if (typeof snapshot === "number") return snapshot;
|
|
41740
|
+
const managed = project.supabaseManaged?.ports?.[managedKey];
|
|
41741
|
+
return typeof managed === "number" ? managed : stock;
|
|
41742
|
+
}
|
|
41736
41743
|
function renderServicesMd(ctx) {
|
|
41737
41744
|
const placeholder = ctx.write_secrets ? "<set; populated by Supbuddy>" : "<see Supbuddy \u2192 Configure, or use MCP tools>";
|
|
41745
|
+
const apiPort = supabaseServicePort(ctx.project, "supabase-kong", "api.port", 54321);
|
|
41746
|
+
const studioPort = supabaseServicePort(ctx.project, "supabase-studio", "studio.port", 54323);
|
|
41738
41747
|
return HEADER(".supbuddy/services.md") + `# Services
|
|
41739
41748
|
|
|
41740
41749
|
## Supabase
|
|
41741
41750
|
|
|
41742
41751
|
- **Status:** ${ctx.supabase_running ? "running" : "stopped"}
|
|
41743
|
-
- **API URL:** ${ctx.supabase_running ?
|
|
41744
|
-
- **Studio:** ${ctx.supabase_running ?
|
|
41752
|
+
- **API URL:** ${ctx.supabase_running ? `http://127.0.0.1:${apiPort}` : "<not running>"}
|
|
41753
|
+
- **Studio:** ${ctx.supabase_running ? `http://127.0.0.1:${studioPort}` : "<not running>"}
|
|
41745
41754
|
- **Anon key:** ${placeholder}
|
|
41746
41755
|
- **Service role key:** ${placeholder}
|
|
41747
41756
|
|
|
@@ -42311,10 +42320,17 @@ function buildContext(projectId, generatedAt) {
|
|
|
42311
42320
|
project,
|
|
42312
42321
|
mappings,
|
|
42313
42322
|
proxyState: s.proxyState,
|
|
42314
|
-
//
|
|
42315
|
-
//
|
|
42316
|
-
//
|
|
42317
|
-
|
|
42323
|
+
// Both statuses come off the SAME per-service snapshot the scanner writes
|
|
42324
|
+
// into `project.services`. Supabase used to be hardcoded `false` here — so
|
|
42325
|
+
// every `.supbuddy/services.md` in every registered repo said "Supabase:
|
|
42326
|
+
// stopped" whatever the truth, and `--force` re-rendered the same lie. An
|
|
42327
|
+
// agent reading that file on a project with the stack up concluded the DB
|
|
42328
|
+
// was down and acted on it. `startsWith('supabase')` (not an exact type)
|
|
42329
|
+
// because the snapshot carries one entry per container — supabase-kong,
|
|
42330
|
+
// -db, -studio, … — and matches get_supabase_status / the CLI / the TUI.
|
|
42331
|
+
supabase_running: (project.services ?? []).some(
|
|
42332
|
+
(sv) => typeof sv.type === "string" && sv.type.startsWith("supabase") && sv.status === "running"
|
|
42333
|
+
),
|
|
42318
42334
|
compose_running: (project.services ?? []).some((sv) => sv.type === "compose" && sv.status === "running"),
|
|
42319
42335
|
mcp_endpoint: `http://127.0.0.1:${s.mcpServerState.bound_port ?? s.settings.mcp.port}/mcp`,
|
|
42320
42336
|
mcp_running: !!s.mcpServerState.running,
|
package/dist/daemon/worker.cjs
CHANGED
|
@@ -48467,7 +48467,7 @@ headers = { Authorization = "Bearer ${token}" }
|
|
|
48467
48467
|
`;
|
|
48468
48468
|
let updated;
|
|
48469
48469
|
if (existing.includes("[mcp_servers.supbuddy]")) {
|
|
48470
|
-
updated = existing.replace(/\[mcp_servers\.supbuddy\][\s\S]*?(?=\n\[|$)/, block.trim());
|
|
48470
|
+
updated = existing.replace(/\[mcp_servers\.supbuddy\][\s\S]*?(?=\n\[|$)/, () => block.trim());
|
|
48471
48471
|
} else {
|
|
48472
48472
|
updated = (existing.endsWith("\n") ? existing : existing + "\n") + block;
|
|
48473
48473
|
}
|
|
@@ -48749,7 +48749,7 @@ const systemTools = {
|
|
|
48749
48749
|
return { ok: true, granted: missing, scopes: nextScopes };
|
|
48750
48750
|
}
|
|
48751
48751
|
};
|
|
48752
|
-
function requireProjectPath(projectId) {
|
|
48752
|
+
function requireProjectPath$1(projectId) {
|
|
48753
48753
|
const project = useStore.getState().getProject(projectId);
|
|
48754
48754
|
if (!project?.path) {
|
|
48755
48755
|
throw new McpError("invalid_args", `Project ${projectId} not found or has no path`);
|
|
@@ -48759,7 +48759,7 @@ function requireProjectPath(projectId) {
|
|
|
48759
48759
|
const addonTools = {
|
|
48760
48760
|
// Create a starter supbuddy.addons.yml (create-if-absent; never clobbers).
|
|
48761
48761
|
scaffold_addons: async (a) => {
|
|
48762
|
-
const projectPath = requireProjectPath(a.project_id);
|
|
48762
|
+
const projectPath = requireProjectPath$1(a.project_id);
|
|
48763
48763
|
const { scaffoldAddonsFile: scaffoldAddonsFile2 } = await __vitePreload(async () => {
|
|
48764
48764
|
const { scaffoldAddonsFile: scaffoldAddonsFile3 } = await Promise.resolve().then(() => addonManager);
|
|
48765
48765
|
return { scaffoldAddonsFile: scaffoldAddonsFile3 };
|
|
@@ -48769,7 +48769,7 @@ const addonTools = {
|
|
|
48769
48769
|
},
|
|
48770
48770
|
// Run the declared one-shot add-on seed step (idempotent unless force=true).
|
|
48771
48771
|
seed_addons: async (a) => {
|
|
48772
|
-
const projectPath = requireProjectPath(a.project_id);
|
|
48772
|
+
const projectPath = requireProjectPath$1(a.project_id);
|
|
48773
48773
|
const { runSeedIfNeeded: runSeedIfNeeded2 } = await __vitePreload(async () => {
|
|
48774
48774
|
const { runSeedIfNeeded: runSeedIfNeeded3 } = await Promise.resolve().then(() => addonManager);
|
|
48775
48775
|
return { runSeedIfNeeded: runSeedIfNeeded3 };
|
|
@@ -48964,14 +48964,26 @@ const supabaseExtrasTools = {
|
|
|
48964
48964
|
// Mirror supabase:analytics:set (worker/index.ts:2506)
|
|
48965
48965
|
// Does NOT trigger auto-restart (the IPC handler's autoRestart flag).
|
|
48966
48966
|
// Callers that want a restart should follow up with restart_supabase.
|
|
48967
|
+
// Enabling analytics can CREATE the `[analytics]` section, and a created section
|
|
48968
|
+
// carries the CLI's stock port — so a thin project's block is re-imposed over it
|
|
48969
|
+
// and reported here through the same shaping the other config-replacing tools use.
|
|
48970
|
+
// `thinBlock` is not spread into the result: it carries the whole config.toml.
|
|
48967
48971
|
set_supabase_analytics: async (args) => {
|
|
48968
48972
|
requireProject$1(args.project_id);
|
|
48969
48973
|
const { setAnalyticsEnabled: setAnalyticsEnabled2 } = await __vitePreload(async () => {
|
|
48970
48974
|
const { setAnalyticsEnabled: setAnalyticsEnabled3 } = await Promise.resolve().then(() => supabaseHealth);
|
|
48971
48975
|
return { setAnalyticsEnabled: setAnalyticsEnabled3 };
|
|
48972
48976
|
}, false ? __VITE_PRELOAD__ : void 0);
|
|
48973
|
-
const result = await setAnalyticsEnabled2(
|
|
48974
|
-
|
|
48977
|
+
const { thinBlock, thinBlockError, ...result } = await setAnalyticsEnabled2(
|
|
48978
|
+
args.project_id,
|
|
48979
|
+
args.enabled
|
|
48980
|
+
);
|
|
48981
|
+
return {
|
|
48982
|
+
ok: true,
|
|
48983
|
+
project_id: args.project_id,
|
|
48984
|
+
...result,
|
|
48985
|
+
...shapeThinBlock("set_supabase_analytics", thinBlock ?? null, thinBlockError ?? null)
|
|
48986
|
+
};
|
|
48975
48987
|
},
|
|
48976
48988
|
// Mirror bundle:validate (worker/index.ts:3145)
|
|
48977
48989
|
validate_bundle: async (args) => {
|
|
@@ -49472,11 +49484,11 @@ async function ensureHostedSnapshot(projectPath) {
|
|
|
49472
49484
|
function rewriteSiteUrl(raw, newValue) {
|
|
49473
49485
|
const re = /^(\s*site_url\s*=\s*)"[^"]*"/m;
|
|
49474
49486
|
if (re.test(raw)) {
|
|
49475
|
-
return raw.replace(re, `$
|
|
49487
|
+
return raw.replace(re, (_m, lead) => `${lead}"${newValue}"`);
|
|
49476
49488
|
}
|
|
49477
49489
|
const authRe = /^\[auth\]\s*$/m;
|
|
49478
49490
|
if (authRe.test(raw)) {
|
|
49479
|
-
return raw.replace(authRe, `[auth]
|
|
49491
|
+
return raw.replace(authRe, () => `[auth]
|
|
49480
49492
|
site_url = "${newValue}"`);
|
|
49481
49493
|
}
|
|
49482
49494
|
const sep = raw.endsWith("\n") ? "" : "\n";
|
|
@@ -49486,20 +49498,22 @@ site_url = "${newValue}"
|
|
|
49486
49498
|
`;
|
|
49487
49499
|
}
|
|
49488
49500
|
function rewriteStudioApiUrl(raw, newValue) {
|
|
49489
|
-
const sectionRe = /^\[studio\][\s\S]*?(?=^\[
|
|
49501
|
+
const sectionRe = /^\[studio\][\s\S]*?(?=^\[|$(?![\s\S]))/m;
|
|
49490
49502
|
const sectionMatch = raw.match(sectionRe);
|
|
49491
49503
|
if (sectionMatch) {
|
|
49492
49504
|
const section = sectionMatch[0];
|
|
49505
|
+
const start = sectionMatch.index ?? 0;
|
|
49506
|
+
const end = start + section.length;
|
|
49493
49507
|
const re = /^(\s*api_url\s*=\s*)"[^"]*"/m;
|
|
49494
49508
|
if (re.test(section)) {
|
|
49495
|
-
const updatedSection = section.replace(re, `$
|
|
49496
|
-
return raw.
|
|
49509
|
+
const updatedSection = section.replace(re, (_m, lead) => `${lead}"${newValue}"`);
|
|
49510
|
+
return raw.slice(0, start) + updatedSection + raw.slice(end);
|
|
49497
49511
|
}
|
|
49498
49512
|
const headerRe = /^\[studio\]\s*$/m;
|
|
49499
49513
|
if (headerRe.test(section)) {
|
|
49500
|
-
const updatedSection = section.replace(headerRe, `[studio]
|
|
49514
|
+
const updatedSection = section.replace(headerRe, () => `[studio]
|
|
49501
49515
|
api_url = "${newValue}"`);
|
|
49502
|
-
return raw.
|
|
49516
|
+
return raw.slice(0, start) + updatedSection + raw.slice(end);
|
|
49503
49517
|
}
|
|
49504
49518
|
}
|
|
49505
49519
|
const sep = raw.endsWith("\n") ? "" : "\n";
|
|
@@ -49512,16 +49526,16 @@ function rewriteAdditionalRedirectUrls(raw, values) {
|
|
|
49512
49526
|
const body = values.map((v) => `"${v}"`).join(", ");
|
|
49513
49527
|
const re = /^(\s*additional_redirect_urls\s*=\s*)\[[^\]]*\]/m;
|
|
49514
49528
|
if (re.test(raw)) {
|
|
49515
|
-
return raw.replace(re, `$
|
|
49529
|
+
return raw.replace(re, (_m, lead) => `${lead}[${body}]`);
|
|
49516
49530
|
}
|
|
49517
49531
|
const authWithSite = /^(\[auth\][\s\S]*?^(\s*site_url\s*=\s*"[^"]*")\s*$)/m;
|
|
49518
49532
|
if (authWithSite.test(raw)) {
|
|
49519
|
-
return raw.replace(authWithSite, `$
|
|
49533
|
+
return raw.replace(authWithSite, (_m, kept) => `${kept}
|
|
49520
49534
|
additional_redirect_urls = [${body}]`);
|
|
49521
49535
|
}
|
|
49522
49536
|
const authRe = /^\[auth\]\s*$/m;
|
|
49523
49537
|
if (authRe.test(raw)) {
|
|
49524
|
-
return raw.replace(authRe, `[auth]
|
|
49538
|
+
return raw.replace(authRe, () => `[auth]
|
|
49525
49539
|
additional_redirect_urls = [${body}]`);
|
|
49526
49540
|
}
|
|
49527
49541
|
const sep = raw.endsWith("\n") ? "" : "\n";
|
|
@@ -50814,15 +50828,24 @@ loopback IP — target the app's **canonical** dev port (Next.js \`:3000\`, Vite
|
|
|
50814
50828
|
share \`127.0.0.1\` and need unique ports.
|
|
50815
50829
|
`;
|
|
50816
50830
|
}
|
|
50831
|
+
function supabaseServicePort(project, type2, managedKey, stock) {
|
|
50832
|
+
const svc = (project.services ?? []).find((s) => s.type === type2);
|
|
50833
|
+
const snapshot2 = svc?.port ?? svc?.ports?.[0];
|
|
50834
|
+
if (typeof snapshot2 === "number") return snapshot2;
|
|
50835
|
+
const managed = project.supabaseManaged?.ports?.[managedKey];
|
|
50836
|
+
return typeof managed === "number" ? managed : stock;
|
|
50837
|
+
}
|
|
50817
50838
|
function renderServicesMd(ctx) {
|
|
50818
50839
|
const placeholder = ctx.write_secrets ? "<set; populated by Supbuddy>" : "<see Supbuddy → Configure, or use MCP tools>";
|
|
50840
|
+
const apiPort = supabaseServicePort(ctx.project, "supabase-kong", "api.port", 54321);
|
|
50841
|
+
const studioPort = supabaseServicePort(ctx.project, "supabase-studio", "studio.port", 54323);
|
|
50819
50842
|
return HEADER(".supbuddy/services.md") + `# Services
|
|
50820
50843
|
|
|
50821
50844
|
## Supabase
|
|
50822
50845
|
|
|
50823
50846
|
- **Status:** ${ctx.supabase_running ? "running" : "stopped"}
|
|
50824
|
-
- **API URL:** ${ctx.supabase_running ?
|
|
50825
|
-
- **Studio:** ${ctx.supabase_running ?
|
|
50847
|
+
- **API URL:** ${ctx.supabase_running ? `http://127.0.0.1:${apiPort}` : "<not running>"}
|
|
50848
|
+
- **Studio:** ${ctx.supabase_running ? `http://127.0.0.1:${studioPort}` : "<not running>"}
|
|
50826
50849
|
- **Anon key:** ${placeholder}
|
|
50827
50850
|
- **Service role key:** ${placeholder}
|
|
50828
50851
|
|
|
@@ -51397,10 +51420,17 @@ function buildContext(projectId, generatedAt) {
|
|
|
51397
51420
|
project,
|
|
51398
51421
|
mappings,
|
|
51399
51422
|
proxyState: s.proxyState,
|
|
51400
|
-
//
|
|
51401
|
-
//
|
|
51402
|
-
//
|
|
51403
|
-
|
|
51423
|
+
// Both statuses come off the SAME per-service snapshot the scanner writes
|
|
51424
|
+
// into `project.services`. Supabase used to be hardcoded `false` here — so
|
|
51425
|
+
// every `.supbuddy/services.md` in every registered repo said "Supabase:
|
|
51426
|
+
// stopped" whatever the truth, and `--force` re-rendered the same lie. An
|
|
51427
|
+
// agent reading that file on a project with the stack up concluded the DB
|
|
51428
|
+
// was down and acted on it. `startsWith('supabase')` (not an exact type)
|
|
51429
|
+
// because the snapshot carries one entry per container — supabase-kong,
|
|
51430
|
+
// -db, -studio, … — and matches get_supabase_status / the CLI / the TUI.
|
|
51431
|
+
supabase_running: (project.services ?? []).some(
|
|
51432
|
+
(sv) => typeof sv.type === "string" && sv.type.startsWith("supabase") && sv.status === "running"
|
|
51433
|
+
),
|
|
51404
51434
|
compose_running: (project.services ?? []).some((sv) => sv.type === "compose" && sv.status === "running"),
|
|
51405
51435
|
mcp_endpoint: `http://127.0.0.1:${s.mcpServerState.bound_port ?? s.settings.mcp.port}/mcp`,
|
|
51406
51436
|
mcp_running: !!s.mcpServerState.running,
|
|
@@ -51949,7 +51979,22 @@ function parseEnvText(text) {
|
|
|
51949
51979
|
}
|
|
51950
51980
|
return out;
|
|
51951
51981
|
}
|
|
51982
|
+
function requireProjectPath(project) {
|
|
51983
|
+
const p = project.path;
|
|
51984
|
+
if (typeof p !== "string" || p.trim() === "") {
|
|
51985
|
+
const label = project.name ? `"${project.name}" (${project.id})` : project.id;
|
|
51986
|
+
throw new Error(
|
|
51987
|
+
`Project ${label} has no recorded directory, so its env cannot be read. Refusing rather than returning an empty preview, which would read as "this project has no secrets". Re-add the project so its directory is recorded, then preview again.`
|
|
51988
|
+
);
|
|
51989
|
+
}
|
|
51990
|
+
return p;
|
|
51991
|
+
}
|
|
51952
51992
|
async function previewProjectEnv(projectPath, files = [".env", ".env.local", ".env.development"], inBoxEquivalent) {
|
|
51993
|
+
if (typeof projectPath !== "string" || projectPath.trim() === "") {
|
|
51994
|
+
throw new Error(
|
|
51995
|
+
`previewProjectEnv needs the project's directory, got ${JSON.stringify(projectPath)}. Callers holding a Project should go through requireProjectPath(), which names the project.`
|
|
51996
|
+
);
|
|
51997
|
+
}
|
|
51953
51998
|
const out = [];
|
|
51954
51999
|
const seen2 = /* @__PURE__ */ new Set();
|
|
51955
52000
|
for (const file of files) {
|
|
@@ -51988,7 +52033,13 @@ const cloudTools = {
|
|
|
51988
52033
|
preview_cloud_env: async (a) => {
|
|
51989
52034
|
const p = useStore.getState().getProject(a.project_id);
|
|
51990
52035
|
if (!p) throw new McpError("plan_not_found", `Project ${a.project_id} not found`);
|
|
51991
|
-
|
|
52036
|
+
let projectPath;
|
|
52037
|
+
try {
|
|
52038
|
+
projectPath = requireProjectPath(p);
|
|
52039
|
+
} catch (e) {
|
|
52040
|
+
throw new McpError("invalid_args", e.message);
|
|
52041
|
+
}
|
|
52042
|
+
const entries = await previewProjectEnv(projectPath, a.files);
|
|
51992
52043
|
const counts = entries.reduce((acc, e) => {
|
|
51993
52044
|
acc[e.verdict] = (acc[e.verdict] ?? 0) + 1;
|
|
51994
52045
|
return acc;
|
|
@@ -53126,6 +53177,7 @@ function filenameToImage(file) {
|
|
|
53126
53177
|
return file.replace(/\.tar$/, "").replace(/_/g, "/");
|
|
53127
53178
|
}
|
|
53128
53179
|
const execFileAsync$2 = util$1.promisify(child_process.execFile);
|
|
53180
|
+
const STOCK_ANALYTICS_PORT = SUPABASE_PORT_KEYS.find((k) => k.key === "analytics.port")?.stock ?? 54327;
|
|
53129
53181
|
function assertNotUnprovisionedVm(project, op) {
|
|
53130
53182
|
if (project?.isolation === "vm") {
|
|
53131
53183
|
throw new Error(
|
|
@@ -53179,6 +53231,7 @@ enabled = ${value}`);
|
|
|
53179
53231
|
return raw + `${sep}
|
|
53180
53232
|
[analytics]
|
|
53181
53233
|
enabled = ${value}
|
|
53234
|
+
port = ${STOCK_ANALYTICS_PORT}
|
|
53182
53235
|
`;
|
|
53183
53236
|
}
|
|
53184
53237
|
async function setAnalyticsEnabled(projectId, value) {
|
|
@@ -53188,9 +53241,17 @@ async function setAnalyticsEnabled(projectId, value) {
|
|
|
53188
53241
|
const configPath = path.join(project.path, "supabase", "config.toml");
|
|
53189
53242
|
const raw = await fs.readFile(configPath, "utf-8");
|
|
53190
53243
|
const next = rewriteAnalyticsEnabled(raw, value);
|
|
53191
|
-
if (next === raw)
|
|
53244
|
+
if (next === raw) {
|
|
53245
|
+
return { configPath, bytes: Buffer.byteLength(raw), thinBlock: null, thinBlockError: null };
|
|
53246
|
+
}
|
|
53192
53247
|
await fs.writeFile(configPath, next, "utf-8");
|
|
53193
|
-
|
|
53248
|
+
const { reapplyThinBlockAfterConfigReplace: reapplyThinBlockAfterConfigReplace2 } = await __vitePreload(async () => {
|
|
53249
|
+
const { reapplyThinBlockAfterConfigReplace: reapplyThinBlockAfterConfigReplace3 } = await Promise.resolve().then(() => supabaseManager);
|
|
53250
|
+
return { reapplyThinBlockAfterConfigReplace: reapplyThinBlockAfterConfigReplace3 };
|
|
53251
|
+
}, false ? __VITE_PRELOAD__ : void 0);
|
|
53252
|
+
const thin = await reapplyThinBlockAfterConfigReplace2(project.path, "analytics toggle");
|
|
53253
|
+
const bytes = await fs.stat(configPath).then((s) => s.size).catch(() => Buffer.byteLength(next));
|
|
53254
|
+
return { configPath, bytes, thinBlock: thin.block, thinBlockError: thin.error };
|
|
53194
53255
|
}
|
|
53195
53256
|
function recordSupabaseFailure(projectId, operation, error) {
|
|
53196
53257
|
const store2 = useStore.getState();
|
|
@@ -56417,10 +56478,10 @@ process.on("message", async (message) => {
|
|
|
56417
56478
|
case "supabase:analytics:set": {
|
|
56418
56479
|
try {
|
|
56419
56480
|
const { projectId, enabled, autoRestart } = message.data;
|
|
56420
|
-
const
|
|
56481
|
+
const { configPath, bytes } = await setAnalyticsEnabled(projectId, !!enabled);
|
|
56421
56482
|
process.send({
|
|
56422
56483
|
type: "supabase:analytics:set:response",
|
|
56423
|
-
data: {
|
|
56484
|
+
data: { configPath, bytes, restartScheduled: autoRestart !== false }
|
|
56424
56485
|
});
|
|
56425
56486
|
if (autoRestart !== false) {
|
|
56426
56487
|
restartSupabaseForProject(projectId, io).catch((err) => {
|
|
@@ -57112,7 +57173,7 @@ process.on("message", async (message) => {
|
|
|
57112
57173
|
if (typeof projectId !== "string" || !projectId) throw new Error("cloud:preview-env requires a projectId");
|
|
57113
57174
|
const project = useStore.getState().getProject(projectId);
|
|
57114
57175
|
if (!project) throw new Error(`Project ${projectId} not found`);
|
|
57115
|
-
const entries = await previewProjectEnv(project
|
|
57176
|
+
const entries = await previewProjectEnv(requireProjectPath(project));
|
|
57116
57177
|
process.send({
|
|
57117
57178
|
type: "cloud:preview-env:response",
|
|
57118
57179
|
_rid: message._rid,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "supbuddy",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.3",
|
|
4
4
|
"description": "Run multiple Supabase projects at once on custom local domains with HTTPS. A headless CLI and daemon (proxy, DNS, Supabase/Compose lifecycle, MCP) for macOS and Linux.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"supabase",
|