@supacloud/cli 0.63.0 → 0.64.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 (3) hide show
  1. package/README.md +12 -3
  2. package/dist/index.js +633 -759
  3. package/package.json +4 -2
package/dist/index.js CHANGED
@@ -206727,7 +206727,7 @@ var ACTION_POLICY = {
206727
206727
  },
206728
206728
  ai: { local: ["show_skill", "install_skill"] },
206729
206729
  app: {
206730
- local: ["init", "generate", "dev", "compile", "check", "graph", "explain", "export-tools", "context", "doctor", "fix", "plan", "build"],
206730
+ local: ["init", "generate", "dev", "watch", "verify-plan", "compile", "check", "graph", "explain", "export-tools", "context", "doctor", "fix", "plan", "build"],
206731
206731
  read: ["status"],
206732
206732
  write: ["upload", "configure", "deploy", "rollback", "reconcile", "retire"]
206733
206733
  },
@@ -221520,8 +221520,8 @@ function registerAiTools(server2) {
221520
221520
 
221521
221521
  // src/shared/tools/app-tools.ts
221522
221522
  import { existsSync as existsSync12, readFileSync as readFileSync9 } from "node:fs";
221523
- import { mkdir as mkdir6, readFile as readFile8, readdir as readdir5, writeFile as writeFile5 } from "node:fs/promises";
221524
- import { basename as basename8, dirname as dirname12, join as join16, relative as relative12, resolve as resolve18 } from "node:path";
221523
+ import { mkdir as mkdir6, readFile as readFile9, readdir as readdir6, writeFile as writeFile5 } from "node:fs/promises";
221524
+ import { basename as basename8, dirname as dirname13, join as join17, relative as relative13, resolve as resolve21 } from "node:path";
221525
221525
 
221526
221526
  // node_modules/@supacloud/compiler/dist/index.js
221527
221527
  import { dirname as dirname22, relative as relative6, sep as sep4 } from "node:path";
@@ -246660,6 +246660,46 @@ function buildToolDefinitions(manifest) {
246660
246660
  }
246661
246661
  return { openai, mcp };
246662
246662
  }
246663
+ // src/shared/tools/starter-metadata.json
246664
+ var starter_metadata_default = {
246665
+ schemaVersion: 1,
246666
+ generatedBy: "supacloud/starter-metadata-v1",
246667
+ packages: {
246668
+ compiler: {
246669
+ version: "0.31.2"
246670
+ },
246671
+ app: {
246672
+ version: "0.22.0",
246673
+ dependencies: {
246674
+ rxjs: "7.8.2"
246675
+ }
246676
+ },
246677
+ elysia: {
246678
+ version: "0.23.1"
246679
+ },
246680
+ commands: {
246681
+ version: "0.9.0"
246682
+ },
246683
+ contracts: {
246684
+ version: "0.8.0"
246685
+ },
246686
+ db: {
246687
+ version: "0.13.0",
246688
+ peerDependencies: {
246689
+ "drizzle-orm": "1.0.0-rc.4"
246690
+ },
246691
+ devDependencies: {
246692
+ "drizzle-kit": "1.0.0-rc.4"
246693
+ }
246694
+ },
246695
+ sdk: {
246696
+ version: "0.36.1",
246697
+ peerDependencies: {
246698
+ "@supabase/supabase-js": "^2.115.0"
246699
+ }
246700
+ }
246701
+ }
246702
+ };
246663
246703
 
246664
246704
  // src/shared/tools/app-starter-reactive.ts
246665
246705
  var STARTER_REACTIVE_GUIDE = `# Reactive development / 响应式开发
@@ -246885,259 +246925,9 @@ test("partial and untagged inherited remote profiles cannot mix with selected fi
246885
246925
  expect(() => loadEnvironment("staging", root, {})).toThrow("Each remote file profile");
246886
246926
  });
246887
246927
  `;
246888
- // ../compiler/package.json
246889
- var package_default = {
246890
- name: "@supacloud/compiler",
246891
- version: "0.31.1",
246892
- description: "Static compiler for @supacloud/app metadata: builds the application graph from AST, validates it, and generates reflection-free factory code",
246893
- type: "module",
246894
- main: "./dist/index.js",
246895
- module: "./dist/index.js",
246896
- types: "./dist/index.d.ts",
246897
- bin: {
246898
- "supacloud-compiler": "./dist/cli.js"
246899
- },
246900
- exports: {
246901
- ".": {
246902
- types: "./dist/index.d.ts",
246903
- import: "./dist/index.js",
246904
- default: "./dist/index.js"
246905
- },
246906
- "./diagnostics": {
246907
- types: "./dist/diagnostics.d.ts",
246908
- import: "./dist/diagnostics.js",
246909
- default: "./dist/diagnostics.js"
246910
- }
246911
- },
246912
- files: [
246913
- "NOTICE",
246914
- "LICENSE-APACHE-2.0.txt",
246915
- "dist",
246916
- "README.md",
246917
- "DELIVERY.md"
246918
- ],
246919
- scripts: {
246920
- build: "bun run clean && bun run build:js && bun run build:types",
246921
- "build:js": "bun build src/index.ts src/diagnostics.ts src/cli.ts src/delivery-bundle-worker.ts --outdir dist --target node --conditions=supacloud-source --external @typescript/typescript6 --external graphql --external '@graphql-codegen/*'",
246922
- "build:types": "tsc -p tsconfig.json --emitDeclarationOnly",
246923
- clean: "rm -rf dist",
246924
- prepublishOnly: "bun run build && bun run test:package",
246925
- test: "bun test",
246926
- "test:package": 'SUPACLOUD_COMPILER_TEST_CLI="$PWD/dist/cli.js" bun test src/graphql-package.test.ts',
246927
- benchmark: "bun run src/benchmark.ts",
246928
- typecheck: "tsc -p tsconfig.json --noEmit",
246929
- "typecheck:test": "tsc -p tsconfig.test.json --noEmit"
246930
- },
246931
- keywords: [
246932
- "supacloud",
246933
- "compiler",
246934
- "di",
246935
- "codegen",
246936
- "elysia"
246937
- ],
246938
- license: "Apache-2.0",
246939
- repository: {
246940
- type: "git",
246941
- url: "https://github.com/vibeunion/supacloud.git",
246942
- directory: "packages/compiler"
246943
- },
246944
- dependencies: {
246945
- "@supacloud/delivery": "0.4.0",
246946
- typebox: "1.3.34",
246947
- "@graphql-codegen/core": "^6.2.0",
246948
- "@graphql-codegen/typed-document-node": "^7.1.0",
246949
- "@graphql-codegen/typescript-operations": "^6.1.6",
246950
- "@graphql-typed-document-node/core": "^3.2.0",
246951
- "@typescript/typescript6": "^6.0.2",
246952
- graphql: "^16"
246953
- },
246954
- devDependencies: {
246955
- "@supabase/supabase-js": "2.115.0",
246956
- "drizzle-orm": "1.0.0-rc.4",
246957
- "@types/bun": "^1.4.2",
246958
- typescript: "^7.0.2"
246959
- }
246960
- };
246961
- // ../app/package.json
246962
- var package_default2 = {
246963
- name: "@supacloud/app",
246964
- version: "0.21.1",
246965
- description: "Angular-style application metadata for SupaCloud: modules, DI tokens, providers, scopes, controllers and commands",
246966
- type: "module",
246967
- main: "./dist/index.js",
246968
- module: "./dist/index.js",
246969
- types: "./dist/index.d.ts",
246970
- exports: {
246971
- "./contracts": {
246972
- types: "./dist/contract_client.d.ts",
246973
- import: "./dist/contract_client.js",
246974
- default: "./dist/contract_client.js"
246975
- },
246976
- "./browser": {
246977
- types: "./dist/browser.d.ts",
246978
- import: "./dist/browser.js",
246979
- default: "./dist/browser.js"
246980
- },
246981
- ".": {
246982
- types: "./dist/index.d.ts",
246983
- import: "./dist/index.js",
246984
- default: "./dist/index.js"
246985
- },
246986
- "./execution": {
246987
- types: "./dist/execution.d.ts",
246988
- import: "./dist/execution.js",
246989
- default: "./dist/execution.js"
246990
- },
246991
- "./reactive": {
246992
- types: "./dist/reactive.d.ts",
246993
- import: "./dist/reactive.js",
246994
- default: "./dist/reactive.js"
246995
- },
246996
- "./rxjs": {
246997
- types: "./dist/rxjs.d.ts",
246998
- import: "./dist/rxjs.js",
246999
- default: "./dist/rxjs.js"
247000
- },
247001
- "./angular": {
247002
- types: "./dist/angular.d.ts",
247003
- import: "./dist/angular.js",
247004
- default: "./dist/angular.js"
247005
- },
247006
- "./http": {
247007
- types: "./dist/http.d.ts",
247008
- import: "./dist/http.js",
247009
- default: "./dist/http.js"
247010
- },
247011
- "./runtime": {
247012
- types: "./dist/runtime.d.ts",
247013
- import: "./dist/runtime.js",
247014
- default: "./dist/runtime.js"
247015
- }
247016
- },
247017
- files: [
247018
- "NOTICE",
247019
- "LICENSE-APACHE-2.0.txt",
247020
- "dist",
247021
- "README.md",
247022
- "EXECUTION.md",
247023
- "REACTIVE.md",
247024
- "ANGULAR.md"
247025
- ],
247026
- scripts: {
247027
- build: "bun run clean && bun run build:js && bun run build:types",
247028
- "build:js": "bun build src/index.ts src/execution.ts --outdir dist --target node --external @supacloud/contracts --external '@angular/*' --external rxjs --format esm && bun build src/contract_client.ts src/browser.ts --outdir dist --target browser --external @supacloud/contracts --format esm && bun build src/reactive.ts --outdir dist --target browser --external rxjs --format esm && bun build src/angular.ts src/rxjs.ts --outdir dist --target browser --external '@angular/*' --external rxjs --format esm && bun build src/http.ts --outdir dist --target node --external @supacloud/app --format esm && bun build src/runtime.ts --outdir dist --target browser --format esm",
247029
- "build:types": "tsc -p tsconfig.json --emitDeclarationOnly",
247030
- clean: "rm -rf dist",
247031
- "check:package": "node ../../.github/scripts/esm-package-policy.mjs --pack .",
247032
- prepublishOnly: "bun run build && bun run check:package",
247033
- test: "bun test",
247034
- typecheck: "tsc -p tsconfig.json --noEmit",
247035
- "typecheck:test": "tsc -p tsconfig.test.json --noEmit"
247036
- },
247037
- keywords: [
247038
- "supacloud",
247039
- "di",
247040
- "dependency-injection",
247041
- "module",
247042
- "elysia"
247043
- ],
247044
- license: "Apache-2.0",
247045
- repository: {
247046
- type: "git",
247047
- url: "https://github.com/vibeunion/supacloud.git",
247048
- directory: "packages/app"
247049
- },
247050
- dependencies: {
247051
- "@angular/core": "^22.1.5",
247052
- "@supacloud/contracts": "file:../contracts",
247053
- rxjs: "7.8.2",
247054
- typebox: "1.3.34"
247055
- },
247056
- devDependencies: {
247057
- "@types/bun": "^1.4.2",
247058
- "@types/node": "^26.5.0",
247059
- typescript: "^7.0.2",
247060
- "@angular/compiler": "22.1.5"
247061
- }
247062
- };
247063
- // ../elysia/package.json
247064
- var package_default3 = {
247065
- name: "@supacloud/elysia",
247066
- version: "0.23.1",
247067
- description: "Elysia runtime adapter for SupaCloud compiled modules: application/request scopes, route registration and validation",
247068
- type: "module",
247069
- main: "./dist/index.js",
247070
- module: "./dist/index.js",
247071
- types: "./dist/index.d.ts",
247072
- exports: {
247073
- ".": {
247074
- types: "./dist/index.d.ts",
247075
- import: "./dist/index.js",
247076
- default: "./dist/index.js"
247077
- }
247078
- },
247079
- files: [
247080
- "NOTICE",
247081
- "LICENSE-APACHE-2.0.txt",
247082
- "dist",
247083
- "README.md",
247084
- "compatibility.json"
247085
- ],
247086
- scripts: {
247087
- "generate:example": "bun src/generate-webhook-example.ts",
247088
- build: "bun run clean && bun run build:js && bun run build:types",
247089
- "build:js": "bun build src/index.ts --outdir dist --target node --external elysia --external jose --external @supacloud/app --external @supacloud/db --external @supacloud/contracts",
247090
- "build:types": "tsc -p tsconfig.json --emitDeclarationOnly",
247091
- clean: "rm -rf dist",
247092
- prepublishOnly: "bun run build",
247093
- test: "bun test",
247094
- "test:conformance": "bun test src/conformance.test.ts src/application-execution.test.ts ../app/src/execution.test.ts ../app/src/execution_bundle.test.ts",
247095
- "test:runtime-safety": "SUPACLOUD_REQUIRE_RUNTIME_SAFETY=1 bun test src/runtime-safety.test.ts",
247096
- "test:contract-upgrade": "bun test src/contract-upgrade.test.ts",
247097
- "bench:http-policy": "bun bench/http-policy.ts",
247098
- typecheck: "tsc -p tsconfig.json --noEmit",
247099
- "typecheck:test": "tsc -p tsconfig.test.json --noEmit"
247100
- },
247101
- keywords: [
247102
- "supacloud",
247103
- "elysia",
247104
- "adapter",
247105
- "dependency-injection",
247106
- "module"
247107
- ],
247108
- license: "Apache-2.0",
247109
- repository: {
247110
- type: "git",
247111
- url: "https://github.com/vibeunion/supacloud.git",
247112
- directory: "packages/elysia"
247113
- },
247114
- dependencies: {
247115
- "@supacloud/app": "file:../app",
247116
- "@supacloud/contracts": "file:../contracts",
247117
- "exact-mirror": "1.2.6",
247118
- jose: "^6.2.11",
247119
- typebox: "1.3.34"
247120
- },
247121
- overrides: {
247122
- "@supacloud/delivery": "file:../delivery",
247123
- "@supacloud/contracts": "file:../contracts",
247124
- "@supacloud/commands": "file:../commands"
247125
- },
247126
- peerDependencies: {
247127
- elysia: "2.0.0-beta.19"
247128
- },
247129
- devDependencies: {
247130
- "@supacloud/compiler": "file:../compiler",
247131
- "@supacloud/delivery": "file:../delivery",
247132
- "@supacloud/commands": "file:../commands",
247133
- "@supacloud/db": "file:../db",
247134
- "@types/bun": "^1.4.2",
247135
- elysia: "2.0.0-beta.19",
247136
- typescript: "^7.0.2"
247137
- }
247138
- };
247139
246928
 
247140
246929
  // src/shared/tools/app-starter-templates.ts
246930
+ var { compiler: compilerMetadata, app: appMetadata, elysia: elysiaMetadata } = starter_metadata_default.packages;
247141
246931
  var json = (value) => `${JSON.stringify(value, null, 2)}
247142
246932
  `;
247143
246933
  var DEV_SCRIPT = `import { watchProject, compileOptionsFromConfig, loadSupacloudConfig } from "@supacloud/compiler";
@@ -247213,7 +247003,8 @@ export function createCompiledModules(): never {
247213
247003
  throw new Error("Run bun run compile before starting the application");
247214
247004
  }
247215
247005
  `;
247216
- function baseFiles(name) {
247006
+ function baseFiles(name, sdkDependencies) {
247007
+ const minimal = sdkDependencies !== undefined;
247217
247008
  return {
247218
247009
  "package.json": json({
247219
247010
  name,
@@ -247236,13 +247027,13 @@ function baseFiles(name) {
247236
247027
  "env:production": "bun --no-env-file scripts/environment.ts production"
247237
247028
  },
247238
247029
  dependencies: {
247239
- "@supacloud/app": `^${package_default2.version}`,
247240
- "@supacloud/elysia": `^${package_default3.version}`,
247030
+ "@supacloud/app": `^${appMetadata.version}`,
247031
+ "@supacloud/elysia": `^${elysiaMetadata.version}`,
247241
247032
  elysia: "2.0.0-beta.19",
247242
- rxjs: package_default2.dependencies.rxjs
247033
+ ...sdkDependencies ?? { rxjs: appMetadata.dependencies.rxjs }
247243
247034
  },
247244
247035
  devDependencies: {
247245
- "@supacloud/compiler": `^${package_default.version}`,
247036
+ "@supacloud/compiler": `^${compilerMetadata.version}`,
247246
247037
  "@types/bun": "^1.4.2",
247247
247038
  typescript: "^7.0.2"
247248
247039
  }
@@ -247290,9 +247081,11 @@ export default defineSupacloudConfig({
247290
247081
  `,
247291
247082
  "src/application.ts": APPLICATION_SOURCE(name),
247292
247083
  "generated/application.ts": GENERATED_BOOTSTRAP,
247293
- "REACTIVE.md": STARTER_REACTIVE_GUIDE,
247294
- "AGENTS.md": STARTER_REACTIVE_AGENTS,
247295
- "tests/reactive.test.ts": STARTER_REACTIVE_TEST,
247084
+ ...minimal ? {} : {
247085
+ "REACTIVE.md": STARTER_REACTIVE_GUIDE,
247086
+ "AGENTS.md": STARTER_REACTIVE_AGENTS,
247087
+ "tests/reactive.test.ts": STARTER_REACTIVE_TEST
247088
+ },
247296
247089
  "scripts/environment.ts": STARTER_ENVIRONMENT,
247297
247090
  "tests/environment.test.ts": STARTER_ENVIRONMENT_TEST,
247298
247091
  "scripts/dev.ts": DEV_SCRIPT,
@@ -247488,7 +247281,111 @@ supacloud doctor --root .
247488
247281
  `
247489
247282
  };
247490
247283
  }
247491
- function appTemplateFiles(name, template) {
247284
+ function minimalTemplate(name, sdkDependencies) {
247285
+ return {
247286
+ ...baseFiles(name, sdkDependencies),
247287
+ "src/features/health/health.ts": `import { Controller, Get, Module } from "@supacloud/app/core";
247288
+ import { t } from "elysia";
247289
+
247290
+ export const HealthResult = t.Object({ ok: t.Boolean() });
247291
+
247292
+ @Controller("/health")
247293
+ export class HealthController {
247294
+ @Get("/", { responses: { 200: HealthResult } })
247295
+ health(): { ok: boolean } { return { ok: true }; }
247296
+ }
247297
+
247298
+ @Module({ name: "health", tags: ["type:feature"], controllers: [HealthController] })
247299
+ export class HealthModule {}
247300
+ `,
247301
+ "src/features/health/health.test.ts": `import { expect, test } from "bun:test";
247302
+ import { HealthController } from "./health";
247303
+
247304
+ test("health is a public, side-effect-free operation", () => {
247305
+ expect(new HealthController().health()).toEqual({ ok: true });
247306
+ });
247307
+ `,
247308
+ "src/app.module.ts": `import { Module } from "@supacloud/app/core";
247309
+ import { HealthModule } from "./features/health/health";
247310
+
247311
+ @Module({ name: "application-root", tags: ["type:app"], imports: [HealthModule] })
247312
+ export class AppModule {}
247313
+ `,
247314
+ "scripts/sandbox.ts": `import { createMemorySandbox } from "@supacloud/elysia";
247315
+ import { createCompiledModules } from "../generated/application";
247316
+
247317
+ export function createDemo() {
247318
+ if (process.env.APP_ENV !== "development" && process.env.APP_ENV !== "test") {
247319
+ throw new Error("Local adapters are restricted to development and test");
247320
+ }
247321
+ return createMemorySandbox({ modules: createCompiledModules() });
247322
+ }
247323
+ `,
247324
+ "AGENTS.md": `# Application changes
247325
+
247326
+ - Business code and its tests belong in src/features/<feature>.
247327
+ - Use @supacloud/app/core for metadata; keep UI in the selected frontend framework.
247328
+ - Reuse @supacloud/js and the existing Supabase session for platform access.
247329
+ - Ordinary reads use the RLS-protected Supabase client. GraphQL is opt-in.
247330
+ - Cross-table business writes require trusted authorization, transactions,
247331
+ idempotency and audit. Never put service-role or Management tokens in a browser.
247332
+ - Do not edit generated/. Do not rewrite historical migrations.
247333
+ - Run the directly related single test file and git diff --check for daily changes.
247334
+ - Use app verify-plan --target <module> to inspect the focused verification plan.
247335
+ - Do not introduce another workflow engine, DI container or session store.
247336
+ `,
247337
+ "README.md": `# ${name}
247338
+
247339
+ ## Local development
247340
+
247341
+ \`\`\`sh
247342
+ bun install
247343
+ bun run compile
247344
+ bun test src/features/health/health.test.ts
247345
+ bun run dev
247346
+ \`\`\`
247347
+
247348
+ The local server binds to 127.0.0.1:3000 and exposes GET /health.
247349
+ The dev script compiles, watches and restarts after successful compilation.
247350
+ Memory adapters are local-only; this is not production identity or persistence.
247351
+
247352
+ ## Add a feature
247353
+
247354
+ Keep code, contracts and tests in src/features/<feature>; register modules in
247355
+ src/app.module.ts. Use @supacloud/app/core, not a frontend compatibility API.
247356
+ Use app generate --kind resource for an authorized read-port skeleton.
247357
+ It fails closed until the application supplies its data adapter.
247358
+
247359
+ ## Frontend and database
247360
+
247361
+ @supacloud/js wraps your existing @supabase/supabase-js client. Reuse its session,
247362
+ Storage and RLS-protected PostgREST reads. Generated business clients can use
247363
+ createAuthenticatedFetch from @supacloud/js/contracts with that same session.
247364
+ Use fixed trusted HTTPS endpoints and never retry an uncertain write.
247365
+
247366
+ GraphQL is optional; this starter has no synthetic GraphQL schema.
247367
+ For a complete persistent command/attachment example, create a separate reference
247368
+ project with app init --template command. The http and edge recipes also remain
247369
+ explicit options; do not install every recipe into this application.
247370
+
247371
+ ## Integration and delivery
247372
+
247373
+ createApp requires application-owned trusted identity and durable adapters.
247374
+ Database migrations and seed data require an explicitly selected development
247375
+ database and a reviewed application script; the CLI never infers a production target.
247376
+ Commit generated/ after compilation. At release, check generated drift before
247377
+ regeneration, then validate types, database permissions and authenticated behavior.
247378
+ `
247379
+ };
247380
+ }
247381
+ function appTemplateFiles(name, template, sdkDependencies) {
247382
+ if (template === "minimal") {
247383
+ if (!sdkDependencies)
247384
+ throw new Error("Minimal template requires the initializer's SDK dependency versions");
247385
+ return minimalTemplate(name, sdkDependencies);
247386
+ }
247387
+ if (template !== "http" && template !== "edge")
247388
+ throw new Error("Use appStarterFiles for the command recipe");
247492
247389
  const files = template === "http" ? httpTemplate(name) : edgeTemplate(name);
247493
247390
  const feature = template === "http" ? "OrdersFeature" : "SyncFeature";
247494
247391
  const source = template === "http" ? "./orders/orders" : "./sync/sync";
@@ -248522,330 +248419,6 @@ export async function createDeliveryApplication(modules: CompiledModule[], lifec
248522
248419
  }
248523
248420
  }
248524
248421
  `;
248525
- // ../commands/package.json
248526
- var package_default4 = {
248527
- name: "@supacloud/commands",
248528
- version: "0.9.0",
248529
- description: "Storage-independent durable command execution and recovery",
248530
- type: "module",
248531
- main: "./dist/index.js",
248532
- types: "./dist/index.d.ts",
248533
- exports: {
248534
- "./typebox": {
248535
- types: "./dist/typebox.d.ts",
248536
- import: "./dist/typebox.js"
248537
- },
248538
- ".": {
248539
- types: "./dist/index.d.ts",
248540
- import: "./dist/index.js"
248541
- }
248542
- },
248543
- files: [
248544
- "NOTICE",
248545
- "LICENSE-APACHE-2.0.txt",
248546
- "dist",
248547
- "README.md"
248548
- ],
248549
- scripts: {
248550
- build: "bun run build:js && bun run build:types",
248551
- "build:js": "bun build src/index.ts src/typebox.ts --outdir dist --target node --external @supacloud/contracts --external @sinclair/typebox",
248552
- "build:types": "tsc -p tsconfig.json --emitDeclarationOnly",
248553
- typecheck: "tsc -p tsconfig.json --noEmit",
248554
- "typecheck:test": "tsc -p tsconfig.test.json --noEmit",
248555
- test: "bun test",
248556
- prepublishOnly: "bun run build"
248557
- },
248558
- dependencies: {
248559
- "@supacloud/contracts": "file:../contracts"
248560
- },
248561
- devDependencies: {
248562
- "@sinclair/typebox": "0.34.52",
248563
- "@types/bun": "1.4.2",
248564
- typescript: "7.0.2"
248565
- },
248566
- peerDependencies: {
248567
- "@sinclair/typebox": "0.34.52"
248568
- },
248569
- peerDependenciesMeta: {
248570
- "@sinclair/typebox": {
248571
- optional: true
248572
- }
248573
- },
248574
- license: "Apache-2.0",
248575
- repository: {
248576
- type: "git",
248577
- url: "https://github.com/vibeunion/supacloud.git",
248578
- directory: "packages/commands"
248579
- }
248580
- };
248581
- // ../contracts/package.json
248582
- var package_default5 = {
248583
- name: "@supacloud/contracts",
248584
- version: "0.8.0",
248585
- description: "SupaCloud command protocol with optional client and browser entrypoints",
248586
- type: "module",
248587
- main: "./dist/index.cjs",
248588
- types: "./dist/index.d.mts",
248589
- exports: {
248590
- ".": {
248591
- import: {
248592
- types: "./dist/index.d.mts",
248593
- default: "./dist/index.mjs"
248594
- },
248595
- require: {
248596
- types: "./dist/index.d.cts",
248597
- default: "./dist/index.cjs"
248598
- }
248599
- },
248600
- "./client": {
248601
- import: {
248602
- types: "./dist/client.d.mts",
248603
- default: "./dist/client.mjs"
248604
- },
248605
- require: {
248606
- types: "./dist/client.d.cts",
248607
- default: "./dist/client.cjs"
248608
- }
248609
- },
248610
- "./browser": {
248611
- import: {
248612
- types: "./dist/browser.d.mts",
248613
- default: "./dist/browser.mjs"
248614
- },
248615
- require: {
248616
- types: "./dist/browser.d.cts",
248617
- default: "./dist/browser.cjs"
248618
- }
248619
- }
248620
- },
248621
- files: [
248622
- "NOTICE",
248623
- "LICENSE-APACHE-2.0.txt",
248624
- "dist",
248625
- "README.md"
248626
- ],
248627
- scripts: {
248628
- build: "bun run clean && bun run build:js && bun run build:types",
248629
- "build:js": "bun run build:js:esm && bun run build:js:cjs",
248630
- "build:types": "tsc -p tsconfig.json --emitDeclarationOnly && node ../../scripts/copy-dual-declarations.mjs dist",
248631
- typecheck: "tsc -p tsconfig.json --noEmit",
248632
- "typecheck:test": "tsc -p tsconfig.test.json --noEmit",
248633
- test: "bun test",
248634
- prepublishOnly: "bun run build",
248635
- "build:js:esm": 'bun build src/index.ts src/client.ts src/browser.ts --outdir dist --format esm --entry-naming "[name].mjs" --chunk-naming "[name]-[hash].mjs" --target browser --splitting',
248636
- "build:js:cjs": 'bun build src/index.ts src/client.ts src/browser.ts --outdir dist --format cjs --entry-naming "[name].cjs" --chunk-naming "[name]-[hash].cjs" --target browser',
248637
- clean: "rm -rf dist"
248638
- },
248639
- devDependencies: {
248640
- "@types/bun": "1.4.2",
248641
- typescript: "7.0.2"
248642
- },
248643
- license: "Apache-2.0",
248644
- repository: {
248645
- type: "git",
248646
- url: "https://github.com/vibeunion/supacloud.git",
248647
- directory: "packages/contracts"
248648
- },
248649
- module: "./dist/index.mjs"
248650
- };
248651
- // ../db/package.json
248652
- var package_default6 = {
248653
- name: "@supacloud/db",
248654
- version: "0.12.0",
248655
- description: "Database governance layer for SupaCloud: RLS policies, RPC functions and grants as first-class resources, with manifest/catalog reconciliation",
248656
- type: "module",
248657
- main: "./dist/index.js",
248658
- module: "./dist/index.js",
248659
- types: "./dist/index.d.ts",
248660
- bin: {
248661
- "supacloud-sql-impact": "./dist/sql-impact-cli.js",
248662
- "supacloud-db": "./dist/source-contracts-cli.js"
248663
- },
248664
- exports: {
248665
- "./source-contracts": {
248666
- types: "./dist/source-contracts.d.ts",
248667
- import: "./dist/source-contracts.js"
248668
- },
248669
- "./source-contracts-cli": "./dist/source-contracts-cli.js",
248670
- "./sql-analysis": {
248671
- types: "./dist/sql-analysis.d.ts",
248672
- import: "./dist/sql-analysis.js"
248673
- },
248674
- "./drizzle": {
248675
- types: "./dist/drizzle.d.ts",
248676
- import: "./dist/drizzle.js"
248677
- },
248678
- "./drizzle-bun": {
248679
- types: "./dist/drizzle-bun.d.ts",
248680
- import: "./dist/drizzle-bun.js"
248681
- },
248682
- "./bun": {
248683
- types: "./dist/command-bun.d.ts",
248684
- import: "./dist/command-bun.js"
248685
- },
248686
- ".": {
248687
- types: "./dist/index.d.ts",
248688
- import: "./dist/index.js",
248689
- default: "./dist/index.js"
248690
- }
248691
- },
248692
- files: [
248693
- "NOTICE",
248694
- "LICENSE-APACHE-2.0.txt",
248695
- "dist",
248696
- "README.md",
248697
- "MIGRATION_BINDINGS.md"
248698
- ],
248699
- scripts: {
248700
- build: "bun run clean && bun run build:js && bun run build:types",
248701
- "build:js": "bun build src/index.ts src/command-bun.ts src/drizzle.ts src/drizzle-bun.ts src/sql-analysis.ts src/sql-impact-cli.ts src/source-contracts.ts src/source-contracts-cli.ts --outdir dist --target node --external bun --external @supacloud/contracts --external drizzle-orm --external libpg-query --external @typescript/typescript6",
248702
- "build:types": "tsc -p tsconfig.json --emitDeclarationOnly",
248703
- clean: "rm -rf dist",
248704
- prepublishOnly: "bun run build",
248705
- test: "bun test",
248706
- typecheck: "tsc -p tsconfig.json --noEmit",
248707
- "typecheck:test": "tsc -p tsconfig.test.json --noEmit",
248708
- "typecheck:drizzle": "tsc -p tsconfig.drizzle.json --noEmit"
248709
- },
248710
- keywords: [
248711
- "supacloud",
248712
- "database",
248713
- "governance",
248714
- "rls",
248715
- "postgresql"
248716
- ],
248717
- license: "Apache-2.0",
248718
- repository: {
248719
- type: "git",
248720
- url: "https://github.com/vibeunion/supacloud.git",
248721
- directory: "packages/db"
248722
- },
248723
- devDependencies: {
248724
- "@sinclair/typebox": "0.34.52",
248725
- "drizzle-orm": "1.0.0-rc.4",
248726
- "drizzle-kit": "1.0.0-rc.4",
248727
- "@types/bun": "^1.4.2",
248728
- typescript: "^7.0.2"
248729
- },
248730
- dependencies: {
248731
- "@typescript/typescript6": "^6.0.2",
248732
- "libpg-query": "18.1.4",
248733
- "@supacloud/contracts": "0.8.0"
248734
- },
248735
- peerDependencies: {
248736
- "drizzle-orm": "1.0.0-rc.4"
248737
- },
248738
- peerDependenciesMeta: {
248739
- "drizzle-orm": {
248740
- optional: true
248741
- }
248742
- },
248743
- overrides: {
248744
- "@supacloud/contracts": "0.8.0"
248745
- }
248746
- };
248747
- // ../supacloud-js/package.json
248748
- var package_default7 = {
248749
- name: "@supacloud/js",
248750
- version: "0.36.1",
248751
- description: "Platform SDK for SupaCloud, built on top of supabase-js",
248752
- type: "module",
248753
- main: "./dist/index.cjs",
248754
- module: "./dist/index.mjs",
248755
- types: "./dist/index.d.mts",
248756
- exports: {
248757
- ".": {
248758
- import: {
248759
- types: "./dist/index.d.mts",
248760
- default: "./dist/index.mjs"
248761
- },
248762
- require: {
248763
- types: "./dist/index.d.cts",
248764
- default: "./dist/index.cjs"
248765
- }
248766
- },
248767
- "./task-events": {
248768
- import: {
248769
- types: "./dist/task-events.d.mts",
248770
- default: "./dist/task-events.mjs"
248771
- },
248772
- require: {
248773
- types: "./dist/task-events.d.cts",
248774
- default: "./dist/task-events.cjs"
248775
- }
248776
- },
248777
- "./contracts": {
248778
- import: {
248779
- types: "./dist/contracts.d.mts",
248780
- default: "./dist/contracts.mjs"
248781
- },
248782
- require: {
248783
- types: "./dist/contracts.d.cts",
248784
- default: "./dist/contracts.cjs"
248785
- }
248786
- },
248787
- "./reactive": {
248788
- import: {
248789
- types: "./dist/reactive.d.mts",
248790
- default: "./dist/reactive.mjs"
248791
- },
248792
- require: {
248793
- types: "./dist/reactive.d.cts",
248794
- default: "./dist/reactive.cjs"
248795
- }
248796
- }
248797
- },
248798
- files: [
248799
- "NOTICE",
248800
- "LICENSE-APACHE-2.0.txt",
248801
- "dist",
248802
- "README.md",
248803
- "COMPATIBILITY.md",
248804
- "REACTIVE.md"
248805
- ],
248806
- scripts: {
248807
- test: "bun test",
248808
- build: "bun run clean && bun run build:js && bun run build:types",
248809
- "build:js": "bun run build:js:esm && bun run build:js:cjs",
248810
- "build:types": "tsc -p tsconfig.json --emitDeclarationOnly && node ../../scripts/copy-dual-declarations.mjs dist",
248811
- clean: "rm -rf dist",
248812
- prepublishOnly: "bun run build && bun run check:package",
248813
- "typecheck:consumer": "tsc -p tsconfig.consumer.json --noEmit",
248814
- typecheck: "tsc -p tsconfig.json --noEmit",
248815
- "typecheck:test": "tsc -p tsconfig.test.json --noEmit",
248816
- "check:package": "node ../../.github/scripts/esm-package-policy.mjs --pack .",
248817
- "build:js:esm": 'bun build src/index.ts src/task-events.ts --outdir dist --format esm --entry-naming "[name].mjs" --chunk-naming "[name]-[hash].mjs" --target node --external @supabase/supabase-js --external @supacloud/contracts && bun build src/contracts.ts --outdir dist --format esm --entry-naming "[name].mjs" --chunk-naming "[name]-[hash].mjs" --target browser --external @supacloud/contracts && bun build src/reactive.ts --outdir dist --format esm --entry-naming "[name].mjs" --chunk-naming "[name]-[hash].mjs" --target browser --external rxjs',
248818
- "build:js:cjs": 'bun build src/index.ts src/task-events.ts --outdir dist --format cjs --entry-naming "[name].cjs" --chunk-naming "[name]-[hash].cjs" --target node --external @supabase/supabase-js --external @supacloud/contracts && bun build src/contracts.ts --outdir dist --format cjs --entry-naming "[name].cjs" --chunk-naming "[name]-[hash].cjs" --target browser --external @supacloud/contracts && bun build src/reactive.ts --outdir dist --format cjs --entry-naming "[name].cjs" --chunk-naming "[name]-[hash].cjs" --target browser --external rxjs'
248819
- },
248820
- keywords: [
248821
- "supacloud",
248822
- "supabase",
248823
- "sdk",
248824
- "background-tasks",
248825
- "realtime"
248826
- ],
248827
- license: "Apache-2.0",
248828
- repository: {
248829
- type: "git",
248830
- url: "https://github.com/vibeunion/supacloud.git",
248831
- directory: "packages/supacloud-js"
248832
- },
248833
- peerDependencies: {
248834
- "@supabase/supabase-js": "^2.115.0"
248835
- },
248836
- dependencies: {
248837
- "@supacloud/contracts": "0.8.0",
248838
- rxjs: "7.8.2"
248839
- },
248840
- devDependencies: {
248841
- "@types/bun": "^1.4.2",
248842
- "@supabase/supabase-js": "^2.115.0",
248843
- typescript: "^7.0.2"
248844
- },
248845
- engines: {
248846
- node: ">=22.12.0"
248847
- }
248848
- };
248849
248422
 
248850
248423
  // src/shared/tools/app-starter-database.ts
248851
248424
  var STARTER_DATABASE_CONFIG = {
@@ -248969,6 +248542,7 @@ export default defineConfig({
248969
248542
  }
248970
248543
 
248971
248544
  // src/shared/tools/app-starter.ts
248545
+ var { compiler: compilerMetadata2, app: appMetadata2, elysia: elysiaMetadata2, commands: commandsMetadata, contracts: contractsMetadata, db: dbMetadata, sdk: sdkMetadata } = starter_metadata_default.packages;
248972
248546
  var json2 = (value) => `${JSON.stringify(value, null, 2)}
248973
248547
  `;
248974
248548
  function appStarterFiles(name) {
@@ -248992,6 +248566,7 @@ function appStarterFiles(name) {
248992
248566
  check: "bun run db:check && bun run compile && bun run check:generated && bun run typecheck && bun run test",
248993
248567
  test: "bun run compile && bun --no-env-file scripts/environment.ts test bun test",
248994
248568
  dev: "bun --no-env-file scripts/environment.ts development bun scripts/dev.ts",
248569
+ "dev:integration": "bun --no-env-file scripts/environment.ts development bun scripts/integration.ts",
248995
248570
  build: "bun run db:check && bun run compile && bun run typecheck && bun build src/application.ts --target bun --minify --outdir dist",
248996
248571
  "env:development": "bun --no-env-file scripts/environment.ts development",
248997
248572
  "env:test": "bun --no-env-file scripts/environment.ts test",
@@ -248999,20 +248574,20 @@ function appStarterFiles(name) {
248999
248574
  "env:production": "bun --no-env-file scripts/environment.ts production"
249000
248575
  },
249001
248576
  dependencies: {
249002
- "@supacloud/app": `^${package_default2.version}`,
249003
- "@supacloud/elysia": `^${package_default3.version}`,
249004
- "@supacloud/commands": `^${package_default4.version}`,
249005
- "@supacloud/contracts": `^${package_default5.version}`,
249006
- "@supacloud/db": `^${package_default6.version}`,
249007
- "drizzle-orm": package_default6.peerDependencies["drizzle-orm"],
249008
- "@supacloud/js": `^${package_default7.version}`,
249009
- "@supabase/supabase-js": package_default7.peerDependencies["@supabase/supabase-js"],
248577
+ "@supacloud/app": `^${appMetadata2.version}`,
248578
+ "@supacloud/elysia": `^${elysiaMetadata2.version}`,
248579
+ "@supacloud/commands": `^${commandsMetadata.version}`,
248580
+ "@supacloud/contracts": `^${contractsMetadata.version}`,
248581
+ "@supacloud/db": `^${dbMetadata.version}`,
248582
+ "drizzle-orm": dbMetadata.peerDependencies["drizzle-orm"],
248583
+ "@supacloud/js": `^${sdkMetadata.version}`,
248584
+ "@supabase/supabase-js": sdkMetadata.peerDependencies["@supabase/supabase-js"],
249010
248585
  elysia: "2.0.0-beta.19",
249011
- rxjs: package_default2.dependencies.rxjs
248586
+ rxjs: appMetadata2.dependencies.rxjs
249012
248587
  },
249013
248588
  devDependencies: {
249014
- "@supacloud/compiler": `^${package_default.version}`,
249015
- "drizzle-kit": package_default6.devDependencies["drizzle-kit"],
248589
+ "@supacloud/compiler": `^${compilerMetadata2.version}`,
248590
+ "drizzle-kit": dbMetadata.devDependencies["drizzle-kit"],
249016
248591
  "@types/bun": "^1.4.2",
249017
248592
  typescript: "^7.0.2"
249018
248593
  }
@@ -249144,7 +248719,8 @@ const watcher = watchProject({
249144
248719
  restarts = restarts.then(async () => {
249145
248720
  if (server) { server.kill(); await server.exited; }
249146
248721
  if (closing) return;
249147
- server = Bun.spawn([process.execPath, "--no-env-file", "scripts/serve.ts"], {
248722
+ const entry = process.env.SUPACLOUD_DEV_PROFILE === "integration" ? "scripts/serve-integration.ts" : "scripts/serve.ts";
248723
+ server = Bun.spawn([process.execPath, "--no-env-file", entry], {
249148
248724
  stdin: "inherit", stdout: "inherit", stderr: "inherit", env: process.env,
249149
248725
  });
249150
248726
  }).catch((error) => { console.error(error); process.exitCode = 1; });
@@ -249160,6 +248736,48 @@ const close = async () => {
249160
248736
  process.once("SIGINT", close);
249161
248737
  process.once("SIGTERM", close);
249162
248738
  await watcher.ready;
248739
+ `,
248740
+ "scripts/integration.ts": `if (process.env.APP_ENV !== "development") throw new Error("Integration is development-only");
248741
+ process.env.SUPACLOUD_DEV_PROFILE = "integration";
248742
+ await import("./dev");
248743
+ export {};
248744
+ `,
248745
+ "scripts/serve-integration.ts": `import { createCompiledModules } from "../generated/application";
248746
+ import { createDeliveryApplication } from "../src/delivery-host";
248747
+
248748
+ if (process.env.APP_ENV !== "development") throw new Error("Integration is development-only");
248749
+ const databaseUrl = process.env.SUPACLOUD_DEV_DATABASE_URL;
248750
+ try {
248751
+ if (!databaseUrl) throw new Error();
248752
+ const url = new URL(databaseUrl);
248753
+ if (!["postgres:", "postgresql:"].includes(url.protocol)
248754
+ || !["127.0.0.1", "localhost", "[::1]"].includes(url.hostname)
248755
+ || url.pathname.length <= 1 || url.search || url.hash) throw new Error();
248756
+ } catch {
248757
+ throw new Error("Integration requires an explicit loopback PostgreSQL database");
248758
+ }
248759
+ if (process.env.DATABASE_SOCKET_PATH
248760
+ || (process.env.DATABASE_URL && process.env.DATABASE_URL !== databaseUrl)) {
248761
+ throw new Error("Conflicting integration database settings");
248762
+ }
248763
+ process.env.DATABASE_URL = databaseUrl;
248764
+ const port = Number(process.env.PORT ?? "3000");
248765
+ if (!Number.isInteger(port) || port < 0 || port > 65535) throw new Error("Invalid PORT");
248766
+ const abort = new AbortController();
248767
+ const stopStartup = () => abort.abort();
248768
+ process.once("SIGINT", stopStartup);
248769
+ process.once("SIGTERM", stopStartup);
248770
+ const application = await createDeliveryApplication(createCompiledModules(), { signal: abort.signal });
248771
+ if (abort.signal.aborted) { await application.close(); throw new Error("Integration startup cancelled"); }
248772
+ const server = Bun.serve({ hostname: "127.0.0.1", port, fetch: application.fetch });
248773
+ const close = async () => {
248774
+ abort.abort();
248775
+ server.stop(true);
248776
+ await application.close();
248777
+ };
248778
+ process.once("SIGINT", close);
248779
+ process.once("SIGTERM", close);
248780
+ console.log("Local integration: " + server.url);
249163
248781
  `,
249164
248782
  "scripts/serve.ts": `import { createDemo } from "./sandbox";
249165
248783
 
@@ -249729,8 +249347,11 @@ async function initializeAppProject(options) {
249729
249347
  if ((await readdir4(root)).some((entry) => entry !== ".git")) {
249730
249348
  throw new Error("app init requires an empty directory (an existing .git directory is allowed)");
249731
249349
  }
249732
- const template = options.template ?? "command";
249733
- const files = template === "command" ? appStarterFiles(name) : appTemplateFiles(name, template);
249350
+ const template = options.template ?? "minimal";
249351
+ const files = template === "command" ? appStarterFiles(name) : appTemplateFiles(name, template, {
249352
+ "@supacloud/js": `^${sdkMetadata.version}`,
249353
+ "@supabase/supabase-js": sdkMetadata.peerDependencies["@supabase/supabase-js"]
249354
+ });
249734
249355
  for (const [relativePath, content] of Object.entries(files)) {
249735
249356
  const path = join13(root, relativePath);
249736
249357
  await mkdir4(dirname10(path), { recursive: true });
@@ -249792,22 +249413,30 @@ function checkAppDatabaseSources(projectRoot) {
249792
249413
  function resourceScaffold(name, className) {
249793
249414
  return {
249794
249415
  [`${name}.model.ts`]: `import { t } from "elysia";
249795
- import type { RouteHandlerOutput } from "@supacloud/app";
249416
+ import { InjectionToken, type RouteHandlerOutput } from "@supacloud/app";
249796
249417
 
249797
249418
  // HTTP contracts are the single source of field types. Services import types only.
249798
249419
  export const ${className}Params = t.Object({ id: t.String({ minLength: 1, maxLength: 128, pattern: "^[A-Za-z0-9_-]+$" }) });
249799
249420
  export const ${className}Response = t.Object({ id: t.String() });
249800
249421
  export type ${className}Result = RouteHandlerOutput<{ responses: { 200: typeof ${className}Response } }>;
249422
+
249423
+ // Bind a request-scoped adapter using the verified user and RLS. It must reject
249424
+ // denied/not-found reads; never bind a browser-supplied identity or service-role fallback.
249425
+ export interface ${className}ReadPort {
249426
+ readAuthorized(id: string): Promise<${className}Result>;
249427
+ }
249428
+ export const ${className}Reader = new InjectionToken<${className}ReadPort>("${name}.reader", { scope: "request" });
249801
249429
  `,
249802
- [`${name}.service.ts`]: `import { Injectable } from "@supacloud/app";
249803
- import type { ${className}Result } from "./${name}.model";
249430
+ [`${name}.service.ts`]: `import { Inject, Injectable, Optional } from "@supacloud/app";
249431
+ import { ${className}Reader, type ${className}ReadPort, type ${className}Result } from "./${name}.model";
249804
249432
 
249805
- @Injectable()
249433
+ @Injectable({ scope: "request" })
249806
249434
  export class ${className}Service {
249807
- async find(_id: string): Promise<${className}Result> {
249808
- // Supply your project's authorized read port before exposing this route.
249809
- // Writes must use a governed Command; this scaffold never fakes persistence.
249810
- throw new Error("Implement ${className}Service.find before exposing this resource");
249435
+ constructor(@Inject(${className}Reader) @Optional() readonly reader?: ${className}ReadPort) {}
249436
+
249437
+ async find(id: string): Promise<${className}Result> {
249438
+ if (!this.reader) throw new Error("Bind ${className}Reader before exposing this resource");
249439
+ return this.reader.readAuthorized(id);
249811
249440
  }
249812
249441
  }
249813
249442
  `,
@@ -249817,7 +249446,7 @@ import { ${className}Service } from "./${name}.service";
249817
249446
 
249818
249447
  @Controller("/${name}")
249819
249448
  export class ${className}Controller {
249820
- constructor(@Inject(${className}Service) readonly service: ${className}Service) {}
249449
+ constructor(@Inject(${className}Service) readonly service: Pick<${className}Service, "find">) {}
249821
249450
 
249822
249451
  @Get("/:id", { params: ${className}Params, responses: { 200: ${className}Response } })
249823
249452
  find(@Param("id") id: string): Promise<${className}Result> {
@@ -249842,7 +249471,18 @@ import { ${className}Service } from "./${name}.service";
249842
249471
 
249843
249472
  test("${name} does not claim a read adapter has been implemented", async () => {
249844
249473
  await expect(new ${className}Service().find("example"))
249845
- .rejects.toThrow("Implement ${className}Service.find");
249474
+ .rejects.toThrow("Bind ${className}Reader");
249475
+ });
249476
+
249477
+ test("${name} returns only the supplied authorized read result", async () => {
249478
+ const service = new ${className}Service({ readAuthorized: async id => ({ id }) });
249479
+ expect(await service.find("example")).toEqual({ id: "example" });
249480
+ });
249481
+
249482
+ test("${name} preserves permission denial without a privileged fallback", async () => {
249483
+ const denied = new Error("denied");
249484
+ const service = new ${className}Service({ readAuthorized: async () => { throw denied; } });
249485
+ await expect(service.find("example")).rejects.toBe(denied);
249846
249486
  });
249847
249487
  `,
249848
249488
  [`${name}.controller.test.ts`]: `import { expect, test } from "bun:test";
@@ -249863,10 +249503,220 @@ test("${name} controller preserves an asynchronous read failure", async () => {
249863
249503
  };
249864
249504
  }
249865
249505
 
249506
+ // src/shared/tools/app-local-dev.ts
249507
+ import { execFile as execFile2, spawn as spawn3 } from "node:child_process";
249508
+ import { readFile as readFile4 } from "node:fs/promises";
249509
+ import { join as join15, resolve as resolve17 } from "node:path";
249510
+ function localDatabaseUrl(value) {
249511
+ try {
249512
+ if (!value || /[\x00-\x20\x7f]/.test(value))
249513
+ throw new Error;
249514
+ const url = new URL(value);
249515
+ if (!["postgres:", "postgresql:"].includes(url.protocol) || !["127.0.0.1", "localhost", "[::1]"].includes(url.hostname) || url.pathname.length <= 1 || url.search || url.hash)
249516
+ throw new Error;
249517
+ return value;
249518
+ } catch {
249519
+ throw new Error("Integration requires an explicit loopback PostgreSQL URL with a database name and no query or fragment");
249520
+ }
249521
+ }
249522
+ async function probeDatabase(url, signal) {
249523
+ const source = `const database = new Bun.SQL(process.env.SUPACLOUD_DEV_DATABASE_URL, {
249524
+ max: 1, connectionTimeout: 5,
249525
+ });
249526
+ try {
249527
+ const rows = await database\`SELECT current_database() AS name,
249528
+ r.rolsuper AS superuser, r.rolbypassrls AS bypass_rls
249529
+ FROM pg_roles r WHERE r.rolname = current_user\`;
249530
+ console.log(JSON.stringify(rows));
249531
+ } finally {
249532
+ await database.close({ timeout: 1 });
249533
+ }`;
249534
+ try {
249535
+ const stdout = await new Promise((resolveOutput, reject) => {
249536
+ execFile2(process.versions.bun ? process.execPath : "bun", ["--no-env-file", "-e", source], {
249537
+ env: { ...process.env, SUPACLOUD_DEV_DATABASE_URL: url },
249538
+ timeout: 12000,
249539
+ killSignal: "SIGKILL",
249540
+ maxBuffer: 4096,
249541
+ encoding: "utf8",
249542
+ signal
249543
+ }, (error, output) => error ? reject(error) : resolveOutput(output));
249544
+ });
249545
+ const rows = JSON.parse(stdout);
249546
+ const expected = decodeURIComponent(new URL(url).pathname.slice(1));
249547
+ if (!Array.isArray(rows) || rows.length !== 1)
249548
+ throw new Error;
249549
+ const row = rows[0];
249550
+ if (!row || typeof row !== "object" || !("name" in row) || row.name !== expected || !("superuser" in row) || row.superuser !== false || !("bypass_rls" in row) || row.bypass_rls !== false)
249551
+ throw new Error;
249552
+ } catch {
249553
+ throw new Error("Integration database verification failed; check connectivity, database identity and non-privileged application role");
249554
+ }
249555
+ }
249556
+ async function runLocalDevelopment(options) {
249557
+ const root = resolve17(options.root);
249558
+ const profile = options.profile ?? "fast";
249559
+ if (profile !== "fast" && profile !== "integration")
249560
+ throw new Error("Unknown development profile");
249561
+ if (["production", "staging"].includes(process.env.APP_ENV ?? "") || process.env.SUPACLOUD_ENV === "production") {
249562
+ throw new Error("Local development refuses production or staging environment selectors");
249563
+ }
249564
+ const remoteKeys = ["SUPACLOUD_API_URL", "SUPACLOUD_API_TOKEN", "SUPACLOUD_PROJECT_REF"];
249565
+ if (remoteKeys.some((key) => process.env[key] !== undefined) && (process.env.SUPACLOUD_ENV !== "test" || remoteKeys.some((key) => !process.env[key]?.trim()))) {
249566
+ throw new Error("Inherited remote context must be complete and explicitly tagged with SUPACLOUD_ENV=test");
249567
+ }
249568
+ const script = profile === "integration" ? "dev:integration" : "dev";
249569
+ const manifest = JSON.parse(await readFile4(join15(root, "package.json"), "utf8"));
249570
+ const scripts = manifest && typeof manifest === "object" && "scripts" in manifest ? manifest.scripts : undefined;
249571
+ const command = scripts && typeof scripts === "object" ? Reflect.get(scripts, script) : undefined;
249572
+ if (typeof command !== "string" || !command.trim()) {
249573
+ throw new Error(`Project must declare ${script}; use app watch for compile-only inspection`);
249574
+ }
249575
+ let databaseUrl;
249576
+ if (profile === "integration") {
249577
+ databaseUrl = localDatabaseUrl(options.databaseUrl ?? process.env.SUPACLOUD_DEV_DATABASE_URL);
249578
+ } else if (options.databaseUrl !== undefined) {
249579
+ throw new Error("A database URL requires the integration profile");
249580
+ }
249581
+ if (options.signal?.aborted)
249582
+ return { profile, script, exitCode: 0, state: "stopped" };
249583
+ if (databaseUrl)
249584
+ await probeDatabase(databaseUrl, options.signal);
249585
+ if (options.signal?.aborted)
249586
+ return { profile, script, exitCode: 0, state: "stopped" };
249587
+ const env = {
249588
+ ...process.env,
249589
+ APP_ENV: "development",
249590
+ SUPACLOUD_ENV: "test",
249591
+ SUPACLOUD_DEV_PROFILE: profile
249592
+ };
249593
+ delete env.SUPACLOUD_DEV_DATABASE_URL;
249594
+ if (databaseUrl)
249595
+ env.SUPACLOUD_DEV_DATABASE_URL = databaseUrl;
249596
+ const executable = process.versions.bun ? process.execPath : "bun";
249597
+ const child = spawn3(executable, ["--no-env-file", "run", script], {
249598
+ cwd: root,
249599
+ env,
249600
+ detached: process.platform !== "win32",
249601
+ stdio: ["ignore", "pipe", "pipe"]
249602
+ });
249603
+ let timer;
249604
+ let outputError;
249605
+ let stopping = false;
249606
+ const kill = (signal) => {
249607
+ try {
249608
+ if (process.platform !== "win32" && child.pid)
249609
+ process.kill(-child.pid, signal);
249610
+ else
249611
+ child.kill(signal);
249612
+ } catch (error) {
249613
+ if (!(error instanceof Error) || !("code" in error) || error.code !== "ESRCH")
249614
+ throw error;
249615
+ }
249616
+ };
249617
+ const stop = () => {
249618
+ if (stopping)
249619
+ return;
249620
+ stopping = true;
249621
+ kill("SIGTERM");
249622
+ timer = setTimeout(() => kill("SIGKILL"), 1500);
249623
+ };
249624
+ const output = (chunk) => {
249625
+ try {
249626
+ options.onOutput?.(chunk.toString("utf8"));
249627
+ } catch (error) {
249628
+ outputError = { error };
249629
+ stop();
249630
+ }
249631
+ };
249632
+ child.stdout.on("data", output);
249633
+ child.stderr.on("data", output);
249634
+ options.signal?.addEventListener("abort", stop, { once: true });
249635
+ process.once("SIGINT", stop);
249636
+ process.once("SIGTERM", stop);
249637
+ if (options.signal?.aborted)
249638
+ stop();
249639
+ try {
249640
+ const exitCode = await new Promise((resolveExit, reject) => {
249641
+ child.once("error", reject);
249642
+ child.once("close", (code) => resolveExit(stopping ? 0 : code ?? 1));
249643
+ });
249644
+ if (outputError)
249645
+ throw outputError.error;
249646
+ return { profile, script, exitCode, state: "stopped" };
249647
+ } finally {
249648
+ if (timer)
249649
+ clearTimeout(timer);
249650
+ options.signal?.removeEventListener("abort", stop);
249651
+ process.removeListener("SIGINT", stop);
249652
+ process.removeListener("SIGTERM", stop);
249653
+ }
249654
+ }
249655
+
249656
+ // src/shared/tools/app-verification-plan.ts
249657
+ import { readdir as readdir5, realpath as realpath5 } from "node:fs/promises";
249658
+ import { dirname as dirname11, isAbsolute as isAbsolute6, relative as relative11, resolve as resolve18 } from "node:path";
249659
+ function inside3(root, file) {
249660
+ const path = relative11(root, file).replaceAll("\\", "/");
249661
+ return path !== ".." && !path.startsWith("../") && !isAbsolute6(path);
249662
+ }
249663
+ async function createVerificationPlan(root, graph, target, sourceRoot = root) {
249664
+ const owners = graph.modules.filter((module) => module.name === target || module.className === target || [...module.providers, ...module.controllers, ...module.commands, ...module.jobs ?? [], ...module.queries ?? []].some((item) => ("className" in item) && item.className === target || ("name" in item) && item.name === target || ("token" in item) && item.token === target || ("useClass" in item) && item.useClass === target));
249665
+ if (owners.length !== 1)
249666
+ throw new Error("Select one unambiguous module or owned symbol for verification");
249667
+ const owner = owners[0];
249668
+ const project = await realpath5(root);
249669
+ const requestedRoot = resolve18(root);
249670
+ const sources = [
249671
+ owner.file,
249672
+ ...owner.providers.map((item) => item.file),
249673
+ ...owner.controllers.map((item) => item.file)
249674
+ ].filter((file) => typeof file === "string");
249675
+ const directories = [...new Set(sources.map((file) => dirname11(resolve18(sourceRoot, file))))].sort();
249676
+ const tests = new Set;
249677
+ const manual = [];
249678
+ for (const directory of directories) {
249679
+ if (!inside3(requestedRoot, directory)) {
249680
+ manual.push("A source directory is outside the project; select its owning project explicitly");
249681
+ continue;
249682
+ }
249683
+ const actual = await realpath5(directory);
249684
+ if (!inside3(project, actual)) {
249685
+ manual.push("A source directory is outside the project; select its owning project explicitly");
249686
+ continue;
249687
+ }
249688
+ for (const entry of await readdir5(actual, { withFileTypes: true })) {
249689
+ if (entry.isFile() && /\.(test|spec)\.[cm]?[jt]sx?$/.test(entry.name)) {
249690
+ tests.add(relative11(project, resolve18(actual, entry.name)).replaceAll("\\", "/"));
249691
+ }
249692
+ }
249693
+ }
249694
+ const selected = [...tests].sort();
249695
+ if (!selected.length)
249696
+ manual.push("No colocated tests found; declare a focused test before changing this module");
249697
+ if (selected.length > 32)
249698
+ manual.push("More than 32 local tests; narrow module ownership before execution");
249699
+ return {
249700
+ version: 1,
249701
+ source: "declaration",
249702
+ target: owner.name,
249703
+ ready: manual.length === 0,
249704
+ files: [...new Set(sources.map((file) => relative11(requestedRoot, resolve18(sourceRoot, file)).replaceAll("\\", "/")))].sort(),
249705
+ tests: selected.slice(0, 32),
249706
+ commands: selected.length <= 32 ? [
249707
+ ...selected.map((file) => ["bun", "test", `./${file}`]),
249708
+ ["git", "diff", "--check"]
249709
+ ] : [],
249710
+ manual,
249711
+ releaseOnly: ["generated artifact drift", "consumer types", "database/RLS and authenticated integration", "delivery read-back"],
249712
+ executed: false
249713
+ };
249714
+ }
249715
+
249866
249716
  // src/shared/tools/app-scaffold-writes.ts
249867
249717
  import { randomUUID as randomUUID2 } from "node:crypto";
249868
- import { link, lstat as lstat4, mkdir as mkdir5, open as open4, readFile as readFile4, realpath as realpath5, rename as rename5, rmdir, unlink as unlink3 } from "node:fs/promises";
249869
- import { dirname as dirname11, isAbsolute as isAbsolute6, join as join15, relative as relative11, resolve as resolve17, sep as sep11, win32 } from "node:path";
249718
+ import { link, lstat as lstat4, mkdir as mkdir5, open as open4, readFile as readFile8, realpath as realpath6, rename as rename5, rmdir, unlink as unlink3 } from "node:fs/promises";
249719
+ import { dirname as dirname12, isAbsolute as isAbsolute7, join as join16, relative as relative12, resolve as resolve20, sep as sep11, win32 } from "node:path";
249870
249720
 
249871
249721
  class ScaffoldError extends Error {
249872
249722
  code;
@@ -249880,26 +249730,26 @@ function fsCode(error) {
249880
249730
  return error instanceof Error && "code" in error && typeof error.code === "string" ? error.code : undefined;
249881
249731
  }
249882
249732
  function scaffoldPath(root, path) {
249883
- if (!path || path.includes("\x00") || path.includes("\\") || isAbsolute6(path) || win32.isAbsolute(path)) {
249733
+ if (!path || path.includes("\x00") || path.includes("\\") || isAbsolute7(path) || win32.isAbsolute(path)) {
249884
249734
  throw new ScaffoldError("SCAFFOLD_PATH_INVALID", "Scaffold paths must be relative to the project root");
249885
249735
  }
249886
249736
  const parts = path.split("/");
249887
249737
  if (parts.some((part) => /[<>:"|?*\u0000-\u001f]/.test(part) || /[ .]$/.test(part) && part !== "." && part !== ".." || /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i.test(part) || part.toLowerCase() === ".git" || part.toLowerCase() === ".supacloud-generate.lock")) {
249888
249738
  throw new ScaffoldError("SCAFFOLD_PATH_INVALID", "Scaffold path is reserved or not portable");
249889
249739
  }
249890
- const target = resolve17(root, path);
249891
- const local = relative11(root, target);
249892
- if (!local || local === ".." || local.startsWith(`..${sep11}`) || isAbsolute6(local)) {
249740
+ const target = resolve20(root, path);
249741
+ const local = relative12(root, target);
249742
+ if (!local || local === ".." || local.startsWith(`..${sep11}`) || isAbsolute7(local)) {
249893
249743
  throw new ScaffoldError("SCAFFOLD_PATH_INVALID", "Scaffold path is outside the project root");
249894
249744
  }
249895
249745
  return target;
249896
249746
  }
249897
249747
  async function snapshot(root, path) {
249898
249748
  const target = scaffoldPath(root, path);
249899
- const parts = relative11(root, target).split(sep11);
249749
+ const parts = relative12(root, target).split(sep11);
249900
249750
  let current = root;
249901
249751
  for (const [index, part] of parts.entries()) {
249902
- current = join15(current, part);
249752
+ current = join16(current, part);
249903
249753
  let stat;
249904
249754
  try {
249905
249755
  stat = await lstat4(current);
@@ -249917,7 +249767,7 @@ async function snapshot(root, path) {
249917
249767
  if (!stat.isFile() || stat.nlink !== 1) {
249918
249768
  throw new ScaffoldError("SCAFFOLD_PATH_INVALID", `Scaffold target must be a regular, unlinked file: ${current}`);
249919
249769
  }
249920
- return { content: await readFile4(current, "utf8"), mode: stat.mode, dev: stat.dev, ino: stat.ino };
249770
+ return { content: await readFile8(current, "utf8"), mode: stat.mode, dev: stat.dev, ino: stat.ino };
249921
249771
  }
249922
249772
  }
249923
249773
  return null;
@@ -249926,7 +249776,7 @@ function sameFile(a, b) {
249926
249776
  return a === null ? b === null : b !== null && a.content === b.content && a.dev === b.dev && a.ino === b.ino && a.mode === b.mode;
249927
249777
  }
249928
249778
  async function planScaffoldWrites(root, writes) {
249929
- const canonical = await realpath5(resolve17(root));
249779
+ const canonical = await realpath6(resolve20(root));
249930
249780
  const targets = new Set;
249931
249781
  const planned = [];
249932
249782
  for (const write of writes) {
@@ -249949,7 +249799,7 @@ async function planScaffoldWrites(root, writes) {
249949
249799
  return Object.freeze({ root: canonical, writes: Object.freeze(planned) });
249950
249800
  }
249951
249801
  async function applyScaffoldWrites(plan) {
249952
- const lockPath = join15(plan.root, ".supacloud-generate.lock");
249802
+ const lockPath = join16(plan.root, ".supacloud-generate.lock");
249953
249803
  const lock = await open4(lockPath, "wx").catch((error) => {
249954
249804
  if (fsCode(error) === "EEXIST")
249955
249805
  throw new ScaffoldError("SCAFFOLD_BUSY", "Another generator owns .supacloud-generate.lock; no files written");
@@ -249959,7 +249809,7 @@ async function applyScaffoldWrites(plan) {
249959
249809
  const applied = [];
249960
249810
  const temporary = [];
249961
249811
  try {
249962
- if (await realpath5(plan.root) !== plan.root)
249812
+ if (await realpath6(plan.root) !== plan.root)
249963
249813
  throw new ScaffoldError("SCAFFOLD_CHANGED", "Project root changed");
249964
249814
  for (const write of plan.writes) {
249965
249815
  if (!sameFile(write.before, await snapshot(plan.root, write.path))) {
@@ -249969,8 +249819,8 @@ async function applyScaffoldWrites(plan) {
249969
249819
  for (const write of plan.writes) {
249970
249820
  const target = scaffoldPath(plan.root, write.path);
249971
249821
  let current = plan.root;
249972
- for (const part of relative11(plan.root, dirname11(target)).split(sep11).filter(Boolean)) {
249973
- current = join15(current, part);
249822
+ for (const part of relative12(plan.root, dirname12(target)).split(sep11).filter(Boolean)) {
249823
+ current = join16(current, part);
249974
249824
  try {
249975
249825
  await mkdir5(current);
249976
249826
  directories.push(current);
@@ -250073,7 +249923,7 @@ var REMOTE_APP_SCHEMA = Object.fromEntries(Object.entries(APPLICATION_TOOL_SCHEM
250073
249923
  async function initProject(args) {
250074
249924
  if (args.force)
250075
249925
  throw new Error("app init never overwrites files; choose an empty directory");
250076
- const template = args.template ?? "command";
249926
+ const template = args.template ?? "minimal";
250077
249927
  const { root, name, files } = await initializeAppProject({ root: args.root, name: args.name, template });
250078
249928
  return textResult([
250079
249929
  `Initialized ${name} in ${root} (${files.length} files, template: ${template}).`,
@@ -250186,7 +250036,7 @@ async function generateScaffold(args) {
250186
250036
  throw new ScaffoldError("SCAFFOLD_OPTION_INVALID", `--${flag.replaceAll("_", "-")} must be boolean`);
250187
250037
  }
250188
250038
  }
250189
- const root = resolve18(args.root || process.cwd());
250039
+ const root = resolve21(args.root || process.cwd());
250190
250040
  const dir = args.dir ?? "src/features";
250191
250041
  if (dir !== ".")
250192
250042
  scaffoldPath(root, dir);
@@ -250202,19 +250052,19 @@ async function generateScaffold(args) {
250202
250052
  let contractName;
250203
250053
  if (kind === "module" || kind === "resource") {
250204
250054
  const name = requireIdentifier(args.name, "name");
250205
- modulePath = join16(dir, name, `${name}.module.ts`).replaceAll("\\", "/");
250055
+ modulePath = join17(dir, name, `${name}.module.ts`).replaceAll("\\", "/");
250206
250056
  moduleSymbol = `${pascalName2(name)}Module`;
250207
250057
  if (kind === "module")
250208
250058
  writes.push({ path: modulePath, content: moduleScaffold(name), overwrite: args.force === true });
250209
250059
  else
250210
250060
  for (const [file, content] of Object.entries(resourceScaffold(name, pascalName2(name)))) {
250211
- writes.push({ path: join16(dir, name, file).replaceAll("\\", "/"), content });
250061
+ writes.push({ path: join17(dir, name, file).replaceAll("\\", "/"), content });
250212
250062
  }
250213
250063
  } else {
250214
250064
  const moduleName = requireIdentifier(args.module, "module");
250215
250065
  const name = kind === "controller" ? moduleName : requireIdentifier(args.name, "name");
250216
250066
  const subdir = kind === "command" ? "commands" : kind === "query" ? "queries" : kind === "job" ? "jobs" : kind === "contract" ? "contracts" : "";
250217
- const path = join16(dir, moduleName, subdir, `${name}.${kind}.ts`).replaceAll("\\", "/");
250067
+ const path = join17(dir, moduleName, subdir, `${name}.${kind}.ts`).replaceAll("\\", "/");
250218
250068
  if (kind === "controller" && existsSync12(scaffoldPath(root, path))) {
250219
250069
  throw new ScaffoldError("SCAFFOLD_EXISTS", `Controller already exists: ${path}(请手工合并路由到现有 controller)`);
250220
250070
  }
@@ -250233,7 +250083,7 @@ async function generateScaffold(args) {
250233
250083
  if (new RegExp(`\\b${moduleSymbol}\\b`).test(original)) {
250234
250084
  throw new ScaffoldError("SCAFFOLD_REGISTRATION_CONFLICT", `Registration target already references ${moduleSymbol}; review the import manually`);
250235
250085
  }
250236
- let importPath = relative12(dirname12(target), resolve18(root, modulePath)).replaceAll("\\", "/").replace(/\.ts$/, "");
250086
+ let importPath = relative13(dirname13(target), resolve21(root, modulePath)).replaceAll("\\", "/").replace(/\.ts$/, "");
250237
250087
  if (!importPath.startsWith("."))
250238
250088
  importPath = `./${importPath}`;
250239
250089
  const edit = await applyDiagnosticFix({
@@ -250243,7 +250093,7 @@ async function generateScaffold(args) {
250243
250093
  importPath,
250244
250094
  symbol: moduleSymbol
250245
250095
  }, { rootDir: root, dryRun: true });
250246
- if (await readFile8(target, "utf8") !== original)
250096
+ if (await readFile9(target, "utf8") !== original)
250247
250097
  throw new ScaffoldError("SCAFFOLD_CHANGED", "Registration source changed during planning");
250248
250098
  writes.push({ path: args.register_in, content: edit.content, expected: original });
250249
250099
  }
@@ -250264,7 +250114,7 @@ async function generateScaffold(args) {
250264
250114
  written: !args.dry_run,
250265
250115
  changes
250266
250116
  }, null, 2));
250267
- const lines = changes.map((change) => `${args.dry_run ? "PREVIEW" : "✅"} ${change.action}: ${join16(plan.root, change.path)}`);
250117
+ const lines = changes.map((change) => `${args.dry_run ? "PREVIEW" : "✅"} ${change.action}: ${join17(plan.root, change.path)}`);
250268
250118
  if (args.dry_run)
250269
250119
  lines.push("No files written. Omit --dry-run to apply this generation.");
250270
250120
  if (kind === "resource")
@@ -250300,32 +250150,33 @@ function parseInclude(include) {
250300
250150
  return patterns && patterns.length > 0 ? patterns : undefined;
250301
250151
  }
250302
250152
  function sourceRoot(args, root, configured) {
250303
- const hasConfig = ["ts", "mts", "js", "mjs"].some((extension) => existsSync12(join16(root, `supacloud.config.${extension}`)));
250153
+ const hasConfig = ["ts", "mts", "js", "mjs"].some((extension) => existsSync12(join17(root, `supacloud.config.${extension}`)));
250304
250154
  return args.root && !hasConfig ? "." : configured;
250305
250155
  }
250306
250156
  async function projectCompileConfig(args) {
250307
- const root = resolve18(args.root || process.cwd());
250308
- const configFile = ["ts", "mts", "js", "mjs"].map((extension) => join16(root, `supacloud.config.${extension}`)).find((candidate) => existsSync12(candidate)) ?? null;
250157
+ const root = resolve21(args.root || process.cwd());
250158
+ const configFile = ["ts", "mts", "js", "mjs"].map((extension) => join17(root, `supacloud.config.${extension}`)).find((candidate) => existsSync12(candidate)) ?? null;
250309
250159
  const loadedConfig = await loadSupacloudConfig(root);
250310
250160
  const defaults = resolveSupacloudConfig(loadedConfig, root);
250311
250161
  const configuredRoot = sourceRoot(args, root, loadedConfig.root);
250312
250162
  const include = parseInclude(args.include) ?? loadedConfig.include;
250313
- const outDir = args.out_dir ? resolve18(root, args.out_dir) : defaults.outDir;
250314
- const result = await checkProject(compileOptionsFromConfig({
250163
+ const outDir = args.out_dir ? resolve21(root, args.out_dir) : defaults.outDir;
250164
+ const compileOptions = compileOptionsFromConfig({
250315
250165
  ...loadedConfig,
250316
250166
  ...configuredRoot === undefined ? {} : { root: configuredRoot },
250317
250167
  outDir,
250318
250168
  ...include === undefined ? {} : { include },
250319
250169
  strict: args.strict ?? loadedConfig.strict ?? false
250320
- }, root));
250321
- return { root, configFile, outDir, result };
250170
+ }, root);
250171
+ const result = await checkProject(compileOptions);
250172
+ return { root, sourceDir: compileOptions.rootDir, configFile, outDir, result };
250322
250173
  }
250323
250174
  async function readAllowedDependencies(root) {
250324
- const path = join16(root, "package.json");
250175
+ const path = join17(root, "package.json");
250325
250176
  if (!existsSync12(path))
250326
250177
  return { dependencies: [], devDependencies: [] };
250327
250178
  try {
250328
- const parsed = JSON.parse(await readFile8(path, "utf8"));
250179
+ const parsed = JSON.parse(await readFile9(path, "utf8"));
250329
250180
  return {
250330
250181
  dependencies: Object.keys(parsed.dependencies ?? {}).sort(),
250331
250182
  devDependencies: Object.keys(parsed.devDependencies ?? {}).sort()
@@ -250402,14 +250253,14 @@ async function findUnwiredContracts(rootDir) {
250402
250253
  async function walk(directory) {
250403
250254
  let entries;
250404
250255
  try {
250405
- entries = await readdir5(directory, { withFileTypes: true });
250256
+ entries = await readdir6(directory, { withFileTypes: true });
250406
250257
  } catch {
250407
250258
  return;
250408
250259
  }
250409
250260
  for (const entry of entries) {
250410
250261
  if (skip.has(entry.name))
250411
250262
  continue;
250412
- const path = join16(directory, entry.name);
250263
+ const path = join17(directory, entry.name);
250413
250264
  if (entry.isDirectory())
250414
250265
  await walk(path);
250415
250266
  else if (entry.isFile() && entry.name.endsWith(".ts"))
@@ -250420,17 +250271,17 @@ async function findUnwiredContracts(rootDir) {
250420
250271
  const contracts = files.filter((file) => file.endsWith(".contract.ts"));
250421
250272
  if (contracts.length === 0)
250422
250273
  return [];
250423
- const otherSources = await Promise.all(files.filter((file) => !contracts.includes(file)).map(async (file) => await readFile8(file, "utf8").catch(() => "")));
250274
+ const otherSources = await Promise.all(files.filter((file) => !contracts.includes(file)).map(async (file) => await readFile9(file, "utf8").catch(() => "")));
250424
250275
  const unwired = [];
250425
250276
  for (const contract of contracts) {
250426
- const source = await readFile8(contract, "utf8").catch(() => "");
250277
+ const source = await readFile9(contract, "utf8").catch(() => "");
250427
250278
  const symbols = [...source.matchAll(/export\s+const\s+([A-Za-z_$][A-Za-z0-9_$]*)/g)].map((match) => match[1]);
250428
250279
  if (symbols.length === 0)
250429
250280
  continue;
250430
250281
  const moduleName = basename8(contract).replace(/\.ts$/, "");
250431
250282
  const wired = otherSources.some((text) => text.includes(moduleName) || symbols.some((symbol) => new RegExp(`\\b${symbol}\\b`).test(text)));
250432
250283
  if (!wired)
250433
- unwired.push({ file: relative12(rootDir, contract), symbols });
250284
+ unwired.push({ file: relative13(rootDir, contract), symbols });
250434
250285
  }
250435
250286
  return unwired;
250436
250287
  }
@@ -250473,11 +250324,11 @@ async function runDoctor(args) {
250473
250324
  `), doctor.errors > 0);
250474
250325
  }
250475
250326
  async function runFix(args) {
250476
- const root = resolve18(args.root || process.cwd());
250327
+ const root = resolve21(args.root || process.cwd());
250477
250328
  const fixPath = args.fix?.trim();
250478
250329
  if (!fixPath)
250479
250330
  throw new Error("app fix requires --fix <path-to-diagnostic-fix.json>");
250480
- const parsed = JSON.parse(await readFile8(resolve18(root, fixPath), "utf8"));
250331
+ const parsed = JSON.parse(await readFile9(resolve21(root, fixPath), "utf8"));
250481
250332
  const write = args.write === true;
250482
250333
  const applied = await applyDiagnosticFix(parsed, { rootDir: root, dryRun: !write });
250483
250334
  return textResult(JSON.stringify({
@@ -250520,7 +250371,7 @@ function devDatabase(profile, explicit) {
250520
250371
  }
250521
250372
  function readManifestModules(outDir) {
250522
250373
  try {
250523
- const parsed = JSON.parse(readFileSync9(join16(outDir, "app.manifest.json"), "utf8"));
250374
+ const parsed = JSON.parse(readFileSync9(join17(outDir, "app.manifest.json"), "utf8"));
250524
250375
  return Array.isArray(parsed.modules) ? parsed.modules.map((module) => module.name) : [];
250525
250376
  } catch {
250526
250377
  return [];
@@ -250548,17 +250399,27 @@ function shutdownWaiter(signal) {
250548
250399
  return { done, stop, dispose };
250549
250400
  }
250550
250401
  async function runAppDev(args, options) {
250402
+ if (args.action === "dev" && args.once !== true && args.watch !== false) {
250403
+ const result = await runLocalDevelopment({
250404
+ root: args.root || process.cwd(),
250405
+ profile: args.profile,
250406
+ databaseUrl: args.database_url,
250407
+ signal: options.signal,
250408
+ onOutput: (text) => options.onDevProgress?.(textResult(args.format === "json" ? JSON.stringify({ version: 1, source: "application", output: text }) : text))
250409
+ });
250410
+ return textResult(JSON.stringify({ version: 1, ok: result.exitCode === 0, ...result }), result.exitCode !== 0);
250411
+ }
250551
250412
  const profile = args.profile ?? "fast";
250552
250413
  if (profile !== "fast" && profile !== "integration") {
250553
250414
  throw new ScaffoldError("SCAFFOLD_OPTION_INVALID", "app dev --profile must be fast or integration");
250554
250415
  }
250555
250416
  const database = devDatabase(profile, args.database_url);
250556
- const root = resolve18(args.root || process.cwd());
250417
+ const root = resolve21(args.root || process.cwd());
250557
250418
  const loadedConfig = await loadSupacloudConfig(root);
250558
250419
  const defaults = resolveSupacloudConfig(loadedConfig, root);
250559
250420
  const configuredRoot = sourceRoot(args, root, loadedConfig.root);
250560
250421
  const include = parseInclude(args.include) ?? loadedConfig.include;
250561
- const outDir = args.out_dir ? resolve18(root, args.out_dir) : defaults.outDir;
250422
+ const outDir = args.out_dir ? resolve21(root, args.out_dir) : defaults.outDir;
250562
250423
  const watch = args.once !== true && args.watch !== false;
250563
250424
  const compileOptions = compileOptionsFromConfig({
250564
250425
  ...loadedConfig,
@@ -250590,7 +250451,7 @@ async function runAppDev(args, options) {
250590
250451
  }, null, progress ? undefined : 2), hasError);
250591
250452
  }
250592
250453
  return textResult([
250593
- `app dev (profile: ${profile}, watch: ${watch ? "on" : "off"}, state: ${state})`,
250454
+ `app watch (compile-only, profile: ${profile}, watch: ${watch ? "on" : "off"}, state: ${state})`,
250594
250455
  ` root: ${root}`,
250595
250456
  ` outDir: ${outDir}`,
250596
250457
  ` database: ${profile === "fast" ? "local profile (no database provisioned or connected)" : `explicit ${database.url} (credentials omitted; not connected)`}`,
@@ -250644,7 +250505,7 @@ async function runAppDev(args, options) {
250644
250505
  return report(lastEvent, "stopped");
250645
250506
  }
250646
250507
  async function runCompile(args) {
250647
- const root = resolve18(args.root || process.cwd());
250508
+ const root = resolve21(args.root || process.cwd());
250648
250509
  const loadedConfig = await loadSupacloudConfig(root);
250649
250510
  const defaults = resolveSupacloudConfig(loadedConfig, root);
250650
250511
  const configuredRoot = sourceRoot(args, root, loadedConfig.root);
@@ -250653,7 +250514,7 @@ async function runCompile(args) {
250653
250514
  ...compileOptionsFromConfig({
250654
250515
  ...loadedConfig,
250655
250516
  ...configuredRoot === undefined ? {} : { root: configuredRoot },
250656
- outDir: args.out_dir ? resolve18(root, args.out_dir) : defaults.outDir,
250517
+ outDir: args.out_dir ? resolve21(root, args.out_dir) : defaults.outDir,
250657
250518
  ...include === undefined ? {} : { include },
250658
250519
  strict: args.strict ?? loadedConfig.strict ?? false
250659
250520
  }, root),
@@ -250677,7 +250538,7 @@ async function runCompile(args) {
250677
250538
  return textResult(text, hasError);
250678
250539
  }
250679
250540
  async function runCheck(args) {
250680
- const root = resolve18(args.root || process.cwd());
250541
+ const root = resolve21(args.root || process.cwd());
250681
250542
  const database = checkAppDatabaseSources(root);
250682
250543
  const loadedConfig = await loadSupacloudConfig(root);
250683
250544
  const defaults = resolveSupacloudConfig(loadedConfig, root);
@@ -250686,7 +250547,7 @@ async function runCheck(args) {
250686
250547
  const config = compileOptionsFromConfig({
250687
250548
  ...loadedConfig,
250688
250549
  ...configuredRoot === undefined ? {} : { root: configuredRoot },
250689
- outDir: args.out_dir ? resolve18(root, args.out_dir) : defaults.outDir,
250550
+ outDir: args.out_dir ? resolve21(root, args.out_dir) : defaults.outDir,
250690
250551
  ...include === undefined ? {} : { include },
250691
250552
  strict: args.strict ?? loadedConfig.strict ?? false
250692
250553
  }, root);
@@ -250716,12 +250577,12 @@ async function runCheck(args) {
250716
250577
  }
250717
250578
  async function readManifest(root, args) {
250718
250579
  const config = await loadSupacloudConfig(root);
250719
- const outDir = args.out_dir ? resolve18(root, args.out_dir) : resolveSupacloudConfig(config, root).outDir;
250720
- const manifestPath = join16(outDir, "app.manifest.json");
250580
+ const outDir = args.out_dir ? resolve21(root, args.out_dir) : resolveSupacloudConfig(config, root).outDir;
250581
+ const manifestPath = join17(outDir, "app.manifest.json");
250721
250582
  if (!existsSync12(manifestPath)) {
250722
250583
  throw new Error(`Manifest not found: ${manifestPath}(先运行 app compile 生成)`);
250723
250584
  }
250724
- const parsed = JSON.parse(await readFile8(manifestPath, "utf8"));
250585
+ const parsed = JSON.parse(await readFile9(manifestPath, "utf8"));
250725
250586
  if (!Array.isArray(parsed.modules)) {
250726
250587
  throw new Error(`Invalid manifest: ${manifestPath}`);
250727
250588
  }
@@ -250761,7 +250622,7 @@ function formatGraphText(manifest) {
250761
250622
  `);
250762
250623
  }
250763
250624
  async function runGraph(args) {
250764
- const root = resolve18(args.root || process.cwd());
250625
+ const root = resolve21(args.root || process.cwd());
250765
250626
  const manifest = await readManifest(root, args);
250766
250627
  if (args.format === "json")
250767
250628
  return textResult(JSON.stringify(manifest, null, 2));
@@ -250829,7 +250690,7 @@ async function runExplain(args) {
250829
250690
  const target = args.target?.trim();
250830
250691
  if (!target)
250831
250692
  throw new Error("app explain requires --target(provider 类名 / token 名 / command 名 / job 名)");
250832
- const root = resolve18(args.root || process.cwd());
250693
+ const root = resolve21(args.root || process.cwd());
250833
250694
  const manifest = await readManifest(root, args);
250834
250695
  for (const module of manifest.modules) {
250835
250696
  const job = module.jobs?.find((entry) => entry.name === target || entry.className === target);
@@ -250904,16 +250765,16 @@ async function runExplain(args) {
250904
250765
  return textResult(`未找到对象: ${target}`, true);
250905
250766
  }
250906
250767
  async function runExportTools(args) {
250907
- const root = resolve18(args.root || process.cwd());
250768
+ const root = resolve21(args.root || process.cwd());
250908
250769
  const manifest = await readManifest(root, { ...args, out_dir: undefined });
250909
250770
  const definitions = buildToolDefinitions(manifest);
250910
- const outDir = resolve18(args.out_dir || join16(root, "generated"));
250771
+ const outDir = resolve21(args.out_dir || join17(root, "generated"));
250911
250772
  if (args.format === "json") {
250912
250773
  return textResult(JSON.stringify(definitions, null, 2));
250913
250774
  }
250914
250775
  await mkdir6(outDir, { recursive: true });
250915
- const openaiPath = join16(outDir, "tool-definitions.openai.json");
250916
- const mcpPath = join16(outDir, "tool-definitions.mcp.json");
250776
+ const openaiPath = join17(outDir, "tool-definitions.openai.json");
250777
+ const mcpPath = join17(outDir, "tool-definitions.mcp.json");
250917
250778
  await writeFile5(openaiPath, JSON.stringify(definitions.openai, null, 2), "utf8");
250918
250779
  await writeFile5(mcpPath, JSON.stringify(definitions.mcp, null, 2), "utf8");
250919
250780
  const summary = [
@@ -250928,7 +250789,7 @@ async function runExportTools(args) {
250928
250789
  return textResult(summary);
250929
250790
  }
250930
250791
  async function runDelivery(args) {
250931
- const root = resolve18(args.root || process.cwd());
250792
+ const root = resolve21(args.root || process.cwd());
250932
250793
  if (args.action === "build") {
250933
250794
  const database = checkAppDatabaseSources(root);
250934
250795
  if (database && !database.ok) {
@@ -250938,7 +250799,7 @@ async function runDelivery(args) {
250938
250799
  const loaded = await loadSupacloudConfig(root);
250939
250800
  const options = compileOptionsFromConfig({
250940
250801
  ...loaded,
250941
- ...args.out_dir === undefined ? {} : { outDir: resolve18(root, args.out_dir) },
250802
+ ...args.out_dir === undefined ? {} : { outDir: resolve21(root, args.out_dir) },
250942
250803
  ...args.include === undefined ? {} : { include: parseInclude(args.include) },
250943
250804
  ...args.strict === undefined ? {} : { strict: args.strict }
250944
250805
  }, root);
@@ -250962,7 +250823,7 @@ async function runAppTool(request, options = {}) {
250962
250823
  if ((request.dry_run !== undefined || request.register_in !== undefined) && request.action !== "generate") {
250963
250824
  throw new ScaffoldError("SCAFFOLD_OPTION_INVALID", "--dry-run and --register-in apply only to app generate");
250964
250825
  }
250965
- if (request.database_url !== undefined && request.action !== "dev") {
250826
+ if (request.database_url !== undefined && request.action !== "dev" && request.action !== "watch") {
250966
250827
  throw new ScaffoldError("SCAFFOLD_OPTION_INVALID", "--database-url applies only to app dev --profile integration");
250967
250828
  }
250968
250829
  if (Object.hasOwn(REMOTE_APP_ACTIONS, request.action)) {
@@ -250978,7 +250839,16 @@ async function runAppTool(request, options = {}) {
250978
250839
  return delegate(args);
250979
250840
  }
250980
250841
  switch (request.action) {
250842
+ case "verify-plan": {
250843
+ if (!request.target?.trim())
250844
+ throw new Error("verify-plan requires --target; it never defaults to a full test suite");
250845
+ const { root, sourceDir, result } = await projectCompileConfig(request);
250846
+ const plan = await createVerificationPlan(root, result.graph, request.target.trim(), sourceDir);
250847
+ const ready = plan.ready && !result.diagnostics.some((item) => item.severity === "error");
250848
+ return textResult(JSON.stringify({ ...plan, ready, diagnostics: result.diagnostics }, null, 2), !ready);
250849
+ }
250981
250850
  case "dev":
250851
+ case "watch":
250982
250852
  return runAppDev(request, options);
250983
250853
  case "plan":
250984
250854
  case "build":
@@ -251026,6 +250896,8 @@ function registerAppTools(server2, options = {}) {
251026
250896
  "init",
251027
250897
  "generate",
251028
250898
  "dev",
250899
+ "watch",
250900
+ "verify-plan",
251029
250901
  "compile",
251030
250902
  "check",
251031
250903
  "graph",
@@ -251045,7 +250917,7 @@ function registerAppTools(server2, options = {}) {
251045
250917
  "retire"
251046
250918
  ]), "App action; upload/configure only prepare, rollback activates an explicit old release without schema downgrade"),
251047
250919
  kind: optional(stringEnum(["module", "command", "query", "controller", "job", "contract", "resource"]), "[generate] Scaffold kind"),
251048
- template: optional(stringEnum(["http", "command", "edge"]), "[init] Golden-path template (default: command)"),
250920
+ template: optional(stringEnum(["minimal", "http", "command", "edge"]), "[init] Minimal application by default; explicit http/command/edge recipes"),
251049
250921
  name: optional(Type.String(), "[init/generate] Project or object name"),
251050
250922
  module: optional(Type.String(), "[generate] Target feature module (required for command/query/controller)"),
251051
250923
  dir: optional(Type.String(), "[generate] Feature root directory (default: src/features)"),
@@ -251059,12 +250931,12 @@ function registerAppTools(server2, options = {}) {
251059
250931
  out_dir: optional(Type.String(), "[dev/compile/plan/build/export-tools] Output directory (default: configured outDir)"),
251060
250932
  strict: optional(Type.Boolean(), "[dev/compile/check] Promote warnings to errors"),
251061
250933
  format: optional(stringEnum(["text", "json"]), "[dev/generate/compile/check/plan/graph/export-tools] Output format (default: text)"),
251062
- profile: optional(stringEnum(["fast", "integration"]), "[dev] Local development profile (default: fast); integration requires an explicit database URL"),
250934
+ profile: optional(stringEnum(["fast", "integration"]), "[dev] Run dev or dev:integration; integration verifies an explicit loopback database"),
251063
250935
  once: optional(Type.Boolean(), "[dev] Validate and report once without watching"),
251064
250936
  watch: optional(Type.Boolean(), "[dev] Watch for changes (default: true; --once disables)"),
251065
- database_url: optional(Type.String(), "[dev] Explicit integration database URL (validated shape only; never connected)"),
250937
+ database_url: optional(Type.String(), "[dev] Explicit loopback integration URL; watch/once only inspect its shape"),
251066
250938
  "database-url": optional(Type.String(), "[dev] CLI alias of database_url"),
251067
- target: optional(Type.String(), "[explain/context] Provider class name / token name / command name / job name / module name"),
250939
+ target: optional(Type.String(), "[explain/context/verify-plan] Provider class name / token name / command name / job name / module name"),
251068
250940
  fix: optional(Type.String(), "[fix] Path to a DiagnosticFix JSON file produced by `doctor --format json`"),
251069
250941
  write: optional(Type.Boolean(), "[fix] Write the fix to disk (default: preview only)")
251070
250942
  }, (request) => runAppTool(request, options));
@@ -251097,7 +250969,7 @@ function registerAppAliases(server2) {
251097
250969
 
251098
250970
  // src/shared/tools/db-governance-tools.ts
251099
250971
  import { existsSync as existsSync13 } from "node:fs";
251100
- import { join as join17, resolve as resolve20 } from "node:path";
250972
+ import { join as join18, resolve as resolve23 } from "node:path";
251101
250973
 
251102
250974
  // node_modules/@supacloud/db/dist/index.js
251103
250975
  var TABLES_SQL = `
@@ -251549,7 +251421,7 @@ function normalizeModule(candidate, sourcePath) {
251549
251421
  };
251550
251422
  }
251551
251423
  async function loadDatabaseModules(root, moduleFile) {
251552
- const filePath = moduleFile ? resolve20(root, moduleFile) : join17(root, "db", "modules.ts");
251424
+ const filePath = moduleFile ? resolve23(root, moduleFile) : join18(root, "db", "modules.ts");
251553
251425
  if (!existsSync13(filePath)) {
251554
251426
  throw new Error(moduleFile ? `Module file not found: ${filePath}` : `Module file not found: ${filePath}(用 --module_file 指定一个导出 defineDatabaseModule(...) 的文件)`);
251555
251427
  }
@@ -251598,7 +251470,7 @@ async function runLint(args, root) {
251598
251470
  const issues = [];
251599
251471
  for (const module of selected) {
251600
251472
  const readSqlFile = async (path) => {
251601
- const absolute = resolve20(root, path);
251473
+ const absolute = resolve23(root, path);
251602
251474
  try {
251603
251475
  return await Bun.file(absolute).text();
251604
251476
  } catch (error) {
@@ -251634,14 +251506,14 @@ var defaultLiteSpawn = async (command, cwd) => {
251634
251506
  return { exitCode, stdout, stderr };
251635
251507
  };
251636
251508
  async function runModuleCheckLite(args, root, spawn, liteBinary) {
251637
- const projectDir = resolve20(args.project_dir?.trim() || root);
251509
+ const projectDir = resolve23(args.project_dir?.trim() || root);
251638
251510
  const binary = liteBinary === undefined ? Bun.which("supacloud-lite") : liteBinary;
251639
251511
  if (!binary) {
251640
251512
  throw new Error("db module_check --lite 需要本机可用的 supacloud-lite(npm i -g @supacloud/lite,或加入 PATH)");
251641
251513
  }
251642
251514
  const command = [binary, "db", "check", "--project-dir", projectDir];
251643
251515
  if (args.module_file?.trim())
251644
- command.push("--module-file", resolve20(root, args.module_file.trim()));
251516
+ command.push("--module-file", resolve23(root, args.module_file.trim()));
251645
251517
  const result = await spawn(command, projectDir);
251646
251518
  const output = [result.stdout.trim(), result.stderr.trim()].filter(Boolean).join(`
251647
251519
  `);
@@ -251692,7 +251564,7 @@ function registerDbGovernanceTools(server2, options = {}) {
251692
251564
  lite: optional(Type.Boolean(), "[module_check] Reconcile against a local SupaCloud Lite project (runs supacloud-lite db check)"),
251693
251565
  project_dir: optional(Type.String(), "[module_check] Lite project directory (with --lite; default: --root)")
251694
251566
  }, async (request) => {
251695
- const root = resolve20(request.root || fallbackRoot);
251567
+ const root = resolve23(request.root || fallbackRoot);
251696
251568
  switch (request.action) {
251697
251569
  case "lint":
251698
251570
  return runLint(request, root);
@@ -251709,7 +251581,7 @@ function registerDbGovernanceTools(server2, options = {}) {
251709
251581
  // src/shared/tools/scheduled-function-tools.ts
251710
251582
  import { randomUUID as randomUUID3 } from "node:crypto";
251711
251583
  import { readFileSync as readFileSync10, statSync as statSync7 } from "node:fs";
251712
- import { resolve as resolve21 } from "node:path";
251584
+ import { resolve as resolve24 } from "node:path";
251713
251585
  import { isDeepStrictEqual } from "node:util";
251714
251586
  var HEADER_NAME_PATTERN = /^[!#$%&'*+.^_`|~0-9A-Za-z-]{1,128}$/;
251715
251587
  var ENVIRONMENT_NAME_PATTERN2 = /^[A-Za-z_][A-Za-z0-9_]{0,255}$/;
@@ -251793,7 +251665,7 @@ function validScheduledFunctionCron(expression) {
251793
251665
  function readScheduleBodyFile(bodyPathInput) {
251794
251666
  if (!bodyPathInput.trim())
251795
251667
  throw new Error("'body_file' must be a path");
251796
- const bodyPath = resolve21(bodyPathInput);
251668
+ const bodyPath = resolve24(bodyPathInput);
251797
251669
  const bodyStat = statSync7(bodyPath);
251798
251670
  if (!bodyStat.isFile() || bodyStat.size > MAX_BODY_FILE_BYTES) {
251799
251671
  throw new Error("Scheduled Function body file must be a regular file no larger than 1 MiB");
@@ -252377,7 +252249,7 @@ var MUTATION_TOOL_SCHEMA = {
252377
252249
  import { execFileSync } from "node:child_process";
252378
252250
  import { createHash as createHash10 } from "node:crypto";
252379
252251
  import { existsSync as existsSync14, mkdirSync as mkdirSync4, readdirSync as readdirSync4, readFileSync as readFileSync11, writeFileSync as writeFileSync3 } from "node:fs";
252380
- import { dirname as dirname13, join as join18, relative as relative13, resolve as resolve23 } from "node:path";
252252
+ import { dirname as dirname14, join as join19, relative as relative14, resolve as resolve25 } from "node:path";
252381
252253
  var SAFE_PROJECT_REF = /^[A-Za-z0-9_-]{1,64}$/;
252382
252254
  var BACKUP_ID = /^logical-full_[A-Za-z0-9_-]{1,64}_[a-f0-9]{32}$/;
252383
252255
  var SHA256 = /^[a-f0-9]{64}$/;
@@ -252671,13 +252543,13 @@ function collectScopeFiles(cwd, file, files, dir, task) {
252671
252543
  const results = [];
252672
252544
  const resolvePathWithFallbacks = (filePath) => {
252673
252545
  const trimmed = filePath.trim();
252674
- const resolved = resolve23(cwd, trimmed);
252546
+ const resolved = resolve25(cwd, trimmed);
252675
252547
  if (existsSync14(resolved))
252676
252548
  return resolved;
252677
252549
  const candidates = [
252678
- resolve23(cwd, "supacloud/fa/release-scopes", trimmed),
252679
- resolve23(cwd, "release-scopes", trimmed),
252680
- resolve23(cwd, "scopes", trimmed)
252550
+ resolve25(cwd, "supacloud/fa/release-scopes", trimmed),
252551
+ resolve25(cwd, "release-scopes", trimmed),
252552
+ resolve25(cwd, "scopes", trimmed)
252681
252553
  ];
252682
252554
  const found = candidates.find(existsSync14);
252683
252555
  if (found)
@@ -252700,10 +252572,10 @@ function collectScopeFiles(cwd, file, files, dir, task) {
252700
252572
  if (!taskFilter && (!dir || typeof dir !== "string" || !dir.trim())) {
252701
252573
  throw new Error("At least one of --file, --files, or --task is required for scope_rebind");
252702
252574
  }
252703
- const candidates = typeof dir === "string" && dir.trim() ? [resolve23(cwd, dir.trim())] : [
252704
- resolve23(cwd, "supacloud/fa/release-scopes"),
252705
- resolve23(cwd, "release-scopes"),
252706
- resolve23(cwd, "scopes")
252575
+ const candidates = typeof dir === "string" && dir.trim() ? [resolve25(cwd, dir.trim())] : [
252576
+ resolve25(cwd, "supacloud/fa/release-scopes"),
252577
+ resolve25(cwd, "release-scopes"),
252578
+ resolve25(cwd, "scopes")
252707
252579
  ];
252708
252580
  for (const directory of candidates) {
252709
252581
  if (existsSync14(directory)) {
@@ -252711,7 +252583,7 @@ function collectScopeFiles(cwd, file, files, dir, task) {
252711
252583
  const entries = readdirSync4(directory, { withFileTypes: true });
252712
252584
  for (const entry of entries) {
252713
252585
  if (entry.isFile() && entry.name.endsWith(".json")) {
252714
- const fullPath = join18(directory, entry.name);
252586
+ const fullPath = join19(directory, entry.name);
252715
252587
  if (!taskFilter) {
252716
252588
  results.push(fullPath);
252717
252589
  } else if (entry.name.toLowerCase().includes(taskFilter)) {
@@ -252737,7 +252609,7 @@ function collectScopeFiles(cwd, file, files, dir, task) {
252737
252609
  return [...new Set(results)];
252738
252610
  }
252739
252611
  function handleScopeRebind(args) {
252740
- const cwd = typeof args.cwd === "string" && args.cwd.trim() ? resolve23(args.cwd.trim()) : process.cwd();
252612
+ const cwd = typeof args.cwd === "string" && args.cwd.trim() ? resolve25(args.cwd.trim()) : process.cwd();
252741
252613
  const targetBaseCommit = resolveGitBaseCommit(cwd, args.base_commit);
252742
252614
  const scopeFiles = collectScopeFiles(cwd, args.file, args.files, args.dir, args.task);
252743
252615
  const dryRun = args.dry_run === true;
@@ -252771,7 +252643,7 @@ function handleScopeRebind(args) {
252771
252643
  writeFileSync3(filePath, formatted, "utf8");
252772
252644
  }
252773
252645
  scopes.push({
252774
- file: relative13(cwd, filePath),
252646
+ file: relative14(cwd, filePath),
252775
252647
  task_id: typeof parsed.taskId === "string" ? parsed.taskId : "",
252776
252648
  target_project_ref: typeof parsed.targetProjectRef === "string" ? parsed.targetProjectRef : "",
252777
252649
  previous_base_commit: previousBaseCommit,
@@ -252789,17 +252661,17 @@ function handleScopeRebind(args) {
252789
252661
  });
252790
252662
  }
252791
252663
  function handleScopeInspect(args) {
252792
- const cwd = typeof args.cwd === "string" && args.cwd.trim() ? resolve23(args.cwd.trim()) : process.cwd();
252664
+ const cwd = typeof args.cwd === "string" && args.cwd.trim() ? resolve25(args.cwd.trim()) : process.cwd();
252793
252665
  if (typeof args.file !== "string" || !args.file.trim()) {
252794
252666
  throw new Error("'file' is required for scope_inspect");
252795
252667
  }
252796
252668
  const trimmed = args.file.trim();
252797
- let filePath = resolve23(cwd, trimmed);
252669
+ let filePath = resolve25(cwd, trimmed);
252798
252670
  if (!existsSync14(filePath)) {
252799
252671
  const candidates = [
252800
- resolve23(cwd, "supacloud/fa/release-scopes", trimmed),
252801
- resolve23(cwd, "release-scopes", trimmed),
252802
- resolve23(cwd, "scopes", trimmed)
252672
+ resolve25(cwd, "supacloud/fa/release-scopes", trimmed),
252673
+ resolve25(cwd, "release-scopes", trimmed),
252674
+ resolve25(cwd, "scopes", trimmed)
252803
252675
  ];
252804
252676
  const found = candidates.find(existsSync14);
252805
252677
  if (found)
@@ -252825,7 +252697,7 @@ function handleScopeInspect(args) {
252825
252697
  const scopeSha256 = genericScopedReleaseScopeSha256(parsed);
252826
252698
  const git = gitCommitInfo(cwd);
252827
252699
  return releaseControlSuccess("release.scope_inspect", {
252828
- file: relative13(cwd, filePath),
252700
+ file: relative14(cwd, filePath),
252829
252701
  scope: {
252830
252702
  task_id: parsed.taskId,
252831
252703
  target_project_ref: parsed.targetProjectRef,
@@ -252859,7 +252731,7 @@ function parseCommaList(value) {
252859
252731
  return [];
252860
252732
  }
252861
252733
  function handleScopeCreate(args, fallbackRef) {
252862
- const cwd = typeof args.cwd === "string" && args.cwd.trim() ? resolve23(args.cwd.trim()) : process.cwd();
252734
+ const cwd = typeof args.cwd === "string" && args.cwd.trim() ? resolve25(args.cwd.trim()) : process.cwd();
252863
252735
  if (typeof args.file !== "string" || !args.file.trim()) {
252864
252736
  throw new Error("'file' is required for scope_create");
252865
252737
  }
@@ -252874,8 +252746,8 @@ function handleScopeCreate(args, fallbackRef) {
252874
252746
  throw new Error("'ref' is invalid for release controls");
252875
252747
  }
252876
252748
  const targetBaseCommit = resolveGitBaseCommit(cwd, args.base_commit);
252877
- const filePath = resolve23(cwd, args.file.trim());
252878
- mkdirSync4(dirname13(filePath), { recursive: true });
252749
+ const filePath = resolve25(cwd, args.file.trim());
252750
+ mkdirSync4(dirname14(filePath), { recursive: true });
252879
252751
  const scope = {
252880
252752
  baseCommit: targetBaseCommit,
252881
252753
  excludedFunctions: parseCommaList(args.excluded_functions),
@@ -252891,7 +252763,7 @@ function handleScopeCreate(args, fallbackRef) {
252891
252763
  `;
252892
252764
  writeFileSync3(filePath, formatted, "utf8");
252893
252765
  return releaseControlSuccess("release.scope_create", {
252894
- file: relative13(cwd, filePath),
252766
+ file: relative14(cwd, filePath),
252895
252767
  task_id: scope.taskId,
252896
252768
  target_project_ref: projectRef,
252897
252769
  base_commit: targetBaseCommit,
@@ -253096,11 +252968,11 @@ function registerReleaseTools(server2, http, options = {}) {
253096
252968
  }
253097
252969
 
253098
252970
  // src/shared/tools/deploy-tools.ts
253099
- import { access as access4, lstat as lstat5, mkdtemp as mkdtemp2, opendir, readFile as readFile9, rm as rm3, writeFile as writeFile6 } from "node:fs/promises";
252971
+ import { access as access4, lstat as lstat5, mkdtemp as mkdtemp2, opendir, readFile as readFile10, rm as rm3, writeFile as writeFile6 } from "node:fs/promises";
253100
252972
  import { createHash as createHash11 } from "node:crypto";
253101
252973
  import { tmpdir as tmpdir2 } from "node:os";
253102
- import { basename as basename9, dirname as dirname14, join as join19, relative as relative14, resolve as resolve24, sep as sep12 } from "node:path";
253103
- import { spawn as spawn3 } from "node:child_process";
252974
+ import { basename as basename9, dirname as dirname15, join as join20, relative as relative15, resolve as resolve26, sep as sep12 } from "node:path";
252975
+ import { spawn as spawn4 } from "node:child_process";
253104
252976
 
253105
252977
  // node_modules/fflate/esm/index.mjs
253106
252978
  import { createRequire as createRequire3 } from "module";
@@ -253783,7 +253655,7 @@ function frontendDeployment(candidate) {
253783
253655
  }
253784
253656
  async function readJson(path) {
253785
253657
  try {
253786
- return JSON.parse(await readFile9(path, "utf8"));
253658
+ return JSON.parse(await readFile10(path, "utf8"));
253787
253659
  } catch (error) {
253788
253660
  if (error instanceof Error && "code" in error && error.code === "ENOENT")
253789
253661
  return null;
@@ -253791,13 +253663,13 @@ async function readJson(path) {
253791
253663
  }
253792
253664
  }
253793
253665
  async function findDeployConfigRoot(startDirectory) {
253794
- let directory = resolve24(startDirectory);
253666
+ let directory = resolve26(startDirectory);
253795
253667
  while (true) {
253796
- if (await pathExists(join19(directory, "supacloud.json")))
253668
+ if (await pathExists(join20(directory, "supacloud.json")))
253797
253669
  return directory;
253798
- const parent = dirname14(directory);
253670
+ const parent = dirname15(directory);
253799
253671
  if (parent === directory)
253800
- return resolve24(startDirectory);
253672
+ return resolve26(startDirectory);
253801
253673
  directory = parent;
253802
253674
  }
253803
253675
  }
@@ -253840,7 +253712,7 @@ function deployTargetConfig(candidate, name) {
253840
253712
  };
253841
253713
  }
253842
253714
  async function readDeployConfig(configRoot) {
253843
- const configPath = join19(configRoot, "supacloud.json");
253715
+ const configPath = join20(configRoot, "supacloud.json");
253844
253716
  const candidate = await readJson(configPath);
253845
253717
  if (candidate === null)
253846
253718
  return {};
@@ -253862,29 +253734,29 @@ async function readDeployConfig(configRoot) {
253862
253734
  };
253863
253735
  }
253864
253736
  async function packageName(projectDirectory) {
253865
- const candidate = record4(await readJson(join19(projectDirectory, "package.json")));
253737
+ const candidate = record4(await readJson(join20(projectDirectory, "package.json")));
253866
253738
  return typeof candidate?.name === "string" && candidate.name.trim() ? candidate.name.trim() : null;
253867
253739
  }
253868
253740
  async function pathExists(path) {
253869
253741
  return access4(path).then(() => true, () => false);
253870
253742
  }
253871
253743
  async function defaultBuildCommand(projectDirectory, configRoot) {
253872
- const packageJson = record4(await readJson(join19(projectDirectory, "package.json")));
253744
+ const packageJson = record4(await readJson(join20(projectDirectory, "package.json")));
253873
253745
  const scripts = record4(packageJson?.scripts);
253874
253746
  if (typeof scripts?.build !== "string" || !scripts.build.trim()) {
253875
253747
  throw new Error("No build command was configured and package.json has no build script");
253876
253748
  }
253877
253749
  let directory = projectDirectory;
253878
253750
  while (true) {
253879
- if (await pathExists(join19(directory, "bun.lock")) || await pathExists(join19(directory, "bun.lockb")))
253751
+ if (await pathExists(join20(directory, "bun.lock")) || await pathExists(join20(directory, "bun.lockb")))
253880
253752
  return "bun run build";
253881
- if (await pathExists(join19(directory, "pnpm-lock.yaml")))
253753
+ if (await pathExists(join20(directory, "pnpm-lock.yaml")))
253882
253754
  return "pnpm run build";
253883
- if (await pathExists(join19(directory, "yarn.lock")))
253755
+ if (await pathExists(join20(directory, "yarn.lock")))
253884
253756
  return "yarn build";
253885
253757
  if (directory === configRoot)
253886
253758
  break;
253887
- const parent = dirname14(directory);
253759
+ const parent = dirname15(directory);
253888
253760
  if (parent === directory || !directory.startsWith(`${configRoot}${sep12}`))
253889
253761
  break;
253890
253762
  directory = parent;
@@ -253915,9 +253787,9 @@ function selectDeployment(deployments, requestedId, projectName) {
253915
253787
  throw new Error(deployments.length === 0 ? "No frontend deployments exist for this project" : `Multiple frontend deployments found (${ids}). Set frontend.id in supacloud.json or pass --id`);
253916
253788
  }
253917
253789
  function targetRoot(configRoot, target, name) {
253918
- const root = resolve24(configRoot, target.root || (name === "frontend" ? "." : name));
253919
- const prefix = `${resolve24(configRoot)}${sep12}`;
253920
- if (root !== resolve24(configRoot) && !root.startsWith(prefix)) {
253790
+ const root = resolve26(configRoot, target.root || (name === "frontend" ? "." : name));
253791
+ const prefix = `${resolve26(configRoot)}${sep12}`;
253792
+ if (root !== resolve26(configRoot) && !root.startsWith(prefix)) {
253921
253793
  throw new Error(`Deploy target '${name}' root must stay inside the repository root`);
253922
253794
  }
253923
253795
  return root;
@@ -253968,8 +253840,8 @@ function defaultOutputDirectory(framework) {
253968
253840
  }
253969
253841
  }
253970
253842
  function resolveInsideProject(projectDirectory, candidate, allowRoot = false) {
253971
- const resolved = resolve24(projectDirectory, candidate);
253972
- const projectRoot = resolve24(projectDirectory);
253843
+ const resolved = resolve26(projectDirectory, candidate);
253844
+ const projectRoot = resolve26(projectDirectory);
253973
253845
  const projectPrefix = `${projectRoot}${sep12}`;
253974
253846
  if (!allowRoot && resolved === projectRoot || resolved !== projectRoot && !resolved.startsWith(projectPrefix)) {
253975
253847
  throw new Error("Frontend output directory must stay inside the project directory");
@@ -253978,7 +253850,7 @@ function resolveInsideProject(projectDirectory, candidate, allowRoot = false) {
253978
253850
  }
253979
253851
  async function runBuild(command, cwd) {
253980
253852
  await new Promise((resolvePromise, reject) => {
253981
- const child = spawn3(command, { cwd, env: process.env, shell: true, stdio: "inherit" });
253853
+ const child = spawn4(command, { cwd, env: process.env, shell: true, stdio: "inherit" });
253982
253854
  child.once("error", reject);
253983
253855
  child.once("exit", (code, signal) => {
253984
253856
  if (code === 0)
@@ -254000,7 +253872,7 @@ async function collectArchiveFiles(root) {
254000
253872
  entries.push(entry);
254001
253873
  entries.sort((left, right) => left.name.localeCompare(right.name, "en"));
254002
253874
  for (const entry of entries) {
254003
- const path = join19(directory, entry.name);
253875
+ const path = join20(directory, entry.name);
254004
253876
  const stats = await lstat5(path);
254005
253877
  if (stats.isSymbolicLink())
254006
253878
  throw new Error(`Frontend output cannot contain symbolic links: ${path}`);
@@ -254018,19 +253890,19 @@ async function collectArchiveFiles(root) {
254018
253890
  let bytes = 0;
254019
253891
  const files = {};
254020
253892
  for (const path of paths) {
254021
- const data = new Uint8Array(await readFile9(path));
253893
+ const data = new Uint8Array(await readFile10(path));
254022
253894
  bytes += data.byteLength;
254023
253895
  if (bytes > MAX_SOURCE_BYTES)
254024
253896
  throw new Error(`Frontend output exceeds ${MAX_SOURCE_BYTES} bytes`);
254025
- const archivePath = relative14(root, path).split(sep12).join("/");
253897
+ const archivePath = relative15(root, path).split(sep12).join("/");
254026
253898
  files[archivePath] = [data, { mtime: FIXED_ZIP_MTIME }];
254027
253899
  }
254028
253900
  return { files, bytes, count: paths.length };
254029
253901
  }
254030
253902
  async function createFrontendArchive(outputDirectory) {
254031
253903
  const collected = await collectArchiveFiles(outputDirectory);
254032
- const temporaryDirectory = await mkdtemp2(join19(tmpdir2(), "supacloud-deploy-"));
254033
- const archivePath = join19(temporaryDirectory, `${basename9(outputDirectory)}.zip`);
253904
+ const temporaryDirectory = await mkdtemp2(join20(tmpdir2(), "supacloud-deploy-"));
253905
+ const archivePath = join20(temporaryDirectory, `${basename9(outputDirectory)}.zip`);
254034
253906
  try {
254035
253907
  const archiveBytes = zipSync(collected.files, { level: 6, mtime: FIXED_ZIP_MTIME });
254036
253908
  await writeFile6(archivePath, archiveBytes);
@@ -254080,7 +253952,7 @@ function deployResponse(result, json) {
254080
253952
  }
254081
253953
  function registerDeployTools(server2, http, options = {}) {
254082
253954
  server2.tool("deploy", "Build and publish the linked frontend with one command", deployToolSchema, async (args) => {
254083
- const invocationDirectory = resolve24(String(args.cwd || options.cwd || process.cwd()));
253955
+ const invocationDirectory = resolve26(String(args.cwd || options.cwd || process.cwd()));
254084
253956
  const projectRef = String(args.ref || options.projectRef || "").trim();
254085
253957
  if (!projectRef)
254086
253958
  throw new Error("A linked project ref is required. Set SUPACLOUD_PROJECT_REF or pass --ref");
@@ -254194,7 +254066,7 @@ function registerDeployTools(server2, http, options = {}) {
254194
254066
  } else {
254195
254067
  report("build", "skipped");
254196
254068
  }
254197
- report("package", relative14(projectDirectory, outputDirectory) || ".");
254069
+ report("package", relative15(projectDirectory, outputDirectory) || ".");
254198
254070
  const archive = await createFrontendArchive(outputDirectory);
254199
254071
  try {
254200
254072
  const inventory = payload(await listFrontendReleases(http, projectRef, selected.id, undefined, 100));
@@ -254252,12 +254124,12 @@ function registerDeployTools(server2, http, options = {}) {
254252
254124
  }
254253
254125
 
254254
254126
  // src/shared/tools/remote-dev-tools.ts
254255
- import { spawn as spawn4 } from "node:child_process";
254127
+ import { spawn as spawn5 } from "node:child_process";
254256
254128
  import { existsSync as existsSync15 } from "node:fs";
254257
- import { readFile as readFile10 } from "node:fs/promises";
254258
- import { readdir as readdir6 } from "node:fs/promises";
254129
+ import { readFile as readFile11 } from "node:fs/promises";
254130
+ import { readdir as readdir7 } from "node:fs/promises";
254259
254131
  import { createHash as createHash12 } from "node:crypto";
254260
- import { join as join20, resolve as resolve25 } from "node:path";
254132
+ import { join as join21, resolve as resolve27 } from "node:path";
254261
254133
  var SAFE_TOKEN = /^[A-Za-z0-9._:@/+,-]+$/;
254262
254134
  var SAFE_REMOTE_ROOT = /^\/(?:[A-Za-z0-9._-]+\/)*[A-Za-z0-9._-]+\/?$/;
254263
254135
  var remoteDevToolSchema = {
@@ -254281,7 +254153,7 @@ var remoteDevToolSchema = {
254281
254153
  };
254282
254154
  function runProcess(executable, args, cwd) {
254283
254155
  return new Promise((resolveResult, reject) => {
254284
- const child = spawn4(executable, args, { cwd, shell: false, stdio: ["ignore", "pipe", "pipe"] });
254156
+ const child = spawn5(executable, args, { cwd, shell: false, stdio: ["ignore", "pipe", "pipe"] });
254285
254157
  let stdout = "";
254286
254158
  let stderr = "";
254287
254159
  child.stdout?.setEncoding("utf8");
@@ -254299,19 +254171,19 @@ function runProcess(executable, args, cwd) {
254299
254171
  function resolveDrizzleCommand(root, configured) {
254300
254172
  if (configured?.trim())
254301
254173
  return configured.trim();
254302
- const local = join20(root, "node_modules", ".bin", "drizzle-kit");
254174
+ const local = join21(root, "node_modules", ".bin", "drizzle-kit");
254303
254175
  return existsSync15(local) ? local : "drizzle-kit";
254304
254176
  }
254305
254177
  function toolFailed(value) {
254306
254178
  return value?.isError === true || value?.content?.some((chunk) => typeof chunk?.text === "string" && chunk.text.trimStart().startsWith("❌"));
254307
254179
  }
254308
254180
  async function migrateDatabase(args, options) {
254309
- const root = resolve25(String(args.project_dir || options.cwd || process.cwd()));
254181
+ const root = resolve27(String(args.project_dir || options.cwd || process.cwd()));
254310
254182
  const projectConfig = await readProjectConfig3(root);
254311
254183
  const config = projectConfig.dev || {};
254312
254184
  const database = config.database || {};
254313
254185
  const execute = options.execute || ((command, commandArgs, cwd) => runProcess(command, commandArgs, cwd));
254314
- const drizzleConfig = resolve25(root, String(args.drizzle_config || database.drizzleConfig || "drizzle.config.ts"));
254186
+ const drizzleConfig = resolve27(root, String(args.drizzle_config || database.drizzleConfig || "drizzle.config.ts"));
254315
254187
  const migrationsDir = String(args.migrations_dir || database.migrationsDir || "supabase/migrations");
254316
254188
  if (!existsSync15(drizzleConfig))
254317
254189
  throw new Error(`Drizzle config not found: ${drizzleConfig}`);
@@ -254331,11 +254203,11 @@ async function migrateDatabase(args, options) {
254331
254203
  return { ok: true, mode: "dev", action: "migrate", generated: true, applied: true, migrations_dir: migrationsDir, result: applied };
254332
254204
  }
254333
254205
  async function readProjectConfig3(root) {
254334
- const file = join20(root, "supacloud.json");
254206
+ const file = join21(root, "supacloud.json");
254335
254207
  if (!existsSync15(file))
254336
254208
  return {};
254337
254209
  try {
254338
- const parsed = JSON.parse(await readFile10(file, "utf8"));
254210
+ const parsed = JSON.parse(await readFile11(file, "utf8"));
254339
254211
  return parsed && typeof parsed === "object" ? parsed : {};
254340
254212
  } catch (error) {
254341
254213
  throw new Error(`Invalid supacloud.json: ${error instanceof Error ? error.message : String(error)}`);
@@ -254348,9 +254220,9 @@ async function readDevConfig(root) {
254348
254220
  async function sourceFingerprint(root) {
254349
254221
  const files = [];
254350
254222
  const visit = async (directory) => {
254351
- const entries = await readdir6(directory, { withFileTypes: true });
254223
+ const entries = await readdir7(directory, { withFileTypes: true });
254352
254224
  for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
254353
- const path = join20(directory, entry.name);
254225
+ const path = join21(directory, entry.name);
254354
254226
  if (entry.isDirectory() && ![".git", "node_modules", "dist", "generated", ".supacloud"].includes(entry.name))
254355
254227
  await visit(path);
254356
254228
  else if (entry.isFile())
@@ -254361,7 +254233,7 @@ async function sourceFingerprint(root) {
254361
254233
  const hash = createHash12("sha256");
254362
254234
  for (const file of files) {
254363
254235
  hash.update(file.slice(root.length).replace(/\\/g, "/"));
254364
- hash.update(await readFile10(file));
254236
+ hash.update(await readFile11(file));
254365
254237
  }
254366
254238
  return hash.digest("hex");
254367
254239
  }
@@ -254378,17 +254250,17 @@ function remoteRoot(value) {
254378
254250
  }
254379
254251
  function targetDirectory(root, target, functionSlug, config = {}) {
254380
254252
  if (target === "db")
254381
- return join20(root, "supabase", "migrations");
254253
+ return join21(root, "supabase", "migrations");
254382
254254
  if (target === "functions") {
254383
254255
  const targets = config.targets && typeof config.targets === "object" ? config.targets : {};
254384
254256
  const match = Object.values(targets).find((entry) => entry?.type === "edge_function" && (!functionSlug || String(entry.slug || "") === functionSlug));
254385
- const base = match?.root ? resolve25(root, String(match.root)) : join20(root, "supabase", "functions");
254386
- return match?.root ? base : functionSlug ? join20(base, safeToken(functionSlug, "function")) : base;
254257
+ const base = match?.root ? resolve27(root, String(match.root)) : join21(root, "supabase", "functions");
254258
+ return match?.root ? base : functionSlug ? join21(base, safeToken(functionSlug, "function")) : base;
254387
254259
  }
254388
254260
  if (target === "frontend") {
254389
254261
  const targets = config.targets && typeof config.targets === "object" ? config.targets : {};
254390
254262
  const match = Object.values(targets).find((entry) => entry?.type === "frontend");
254391
- return match?.root ? resolve25(root, String(match.root)) : join20(root, "apps", "web");
254263
+ return match?.root ? resolve27(root, String(match.root)) : join21(root, "apps", "web");
254392
254264
  }
254393
254265
  return root;
254394
254266
  }
@@ -254427,10 +254299,10 @@ function reloadCommand(config, target, projectRef, functionSlug) {
254427
254299
  return [...command.split(" "), "--project-ref", safeToken(projectRef || "test", "project_ref"), "--target", targetConfigPath(target), ...functionSlug ? ["--function", safeToken(functionSlug, "function")] : []];
254428
254300
  }
254429
254301
  function sshArgs(connection, remoteCommand) {
254430
- return ["-p", String(connection.port), "-i", resolve25(connection.key), "-o", "BatchMode=yes", "-o", "StrictHostKeyChecking=yes", `${connection.user}@${connection.host}`, ...remoteCommand];
254302
+ return ["-p", String(connection.port), "-i", resolve27(connection.key), "-o", "BatchMode=yes", "-o", "StrictHostKeyChecking=yes", `${connection.user}@${connection.host}`, ...remoteCommand];
254431
254303
  }
254432
254304
  function rsyncArgs(connection, source, destination, excludes, deleteRemote) {
254433
- const args = ["-az", "--checksum", "--partial", "--protect-args", "-e", `ssh -p ${connection.port} -i ${resolve25(connection.key)} -o BatchMode=yes -o StrictHostKeyChecking=yes`];
254305
+ const args = ["-az", "--checksum", "--partial", "--protect-args", "-e", `ssh -p ${connection.port} -i ${resolve27(connection.key)} -o BatchMode=yes -o StrictHostKeyChecking=yes`];
254434
254306
  if (deleteRemote)
254435
254307
  args.push("--delete-delay");
254436
254308
  for (const exclude of excludes) {
@@ -254442,7 +254314,7 @@ function rsyncArgs(connection, source, destination, excludes, deleteRemote) {
254442
254314
  return args;
254443
254315
  }
254444
254316
  async function syncOnce(args, options) {
254445
- const root = resolve25(String(args.project_dir || options.cwd || process.cwd()));
254317
+ const root = resolve27(String(args.project_dir || options.cwd || process.cwd()));
254446
254318
  const projectConfig = await readProjectConfig3(root);
254447
254319
  const config = projectConfig.dev || {};
254448
254320
  const target = String(args.target || "project");
@@ -254451,8 +254323,8 @@ async function syncOnce(args, options) {
254451
254323
  throw new Error(`Dev source directory not found: ${source}`);
254452
254324
  let compiled = false;
254453
254325
  if (config.compile === true && target !== "db") {
254454
- const compileRoot = resolve25(root, config.compileRoot || ".");
254455
- const compileOutDir = resolve25(root, config.compileOutDir || "generated");
254326
+ const compileRoot = resolve27(root, config.compileRoot || ".");
254327
+ const compileOutDir = resolve27(root, config.compileOutDir || "generated");
254456
254328
  const compilation = await compileProject({
254457
254329
  rootDir: compileRoot,
254458
254330
  outDir: compileOutDir,
@@ -254490,7 +254362,7 @@ function registerRemoteDevTools(server2, options = {}) {
254490
254362
  if (["production", "prod"].includes((options.environment || "").toLowerCase()))
254491
254363
  throw new Error("Remote dev mode is forbidden for production environments");
254492
254364
  if (args.action === "status") {
254493
- const root = resolve25(String(args.project_dir || options.cwd || process.cwd()));
254365
+ const root = resolve27(String(args.project_dir || options.cwd || process.cwd()));
254494
254366
  const config = await readDevConfig(root);
254495
254367
  const connection = connectionArgs(options, config, args);
254496
254368
  const execute = options.execute || ((command, commandArgs, cwd) => runProcess(command, commandArgs, cwd));
@@ -254504,7 +254376,7 @@ function registerRemoteDevTools(server2, options = {}) {
254504
254376
  return { content: [{ type: "text", text: JSON.stringify(await migrateDatabase(args, options), null, 2) }] };
254505
254377
  }
254506
254378
  if (args.action === "watch") {
254507
- const root = resolve25(String(args.project_dir || options.cwd || process.cwd()));
254379
+ const root = resolve27(String(args.project_dir || options.cwd || process.cwd()));
254508
254380
  const interval = Math.max(100, Math.min(1e4, Number(args.interval_ms || 300)));
254509
254381
  let fingerprint = "";
254510
254382
  let lastSync = null;
@@ -254523,9 +254395,9 @@ function registerRemoteDevTools(server2, options = {}) {
254523
254395
  });
254524
254396
  }
254525
254397
  // package.json
254526
- var package_default8 = {
254398
+ var package_default = {
254527
254399
  name: "@supacloud/cli",
254528
- version: "0.63.0",
254400
+ version: "0.64.1",
254529
254401
  description: "Project-scoped CLI for SupaCloud users",
254530
254402
  type: "module",
254531
254403
  main: "./dist/index.js",
@@ -254560,7 +254432,7 @@ var package_default8 = {
254560
254432
  },
254561
254433
  dependencies: {
254562
254434
  "@sinclair/typebox": "^0.34.52",
254563
- "@supacloud/compiler": "^0.31.1",
254435
+ "@supacloud/compiler": "^0.31.2",
254564
254436
  "@supacloud/delivery": "0.4.0",
254565
254437
  "@supacloud/db": "^0.2.0",
254566
254438
  fflate: "^0.8.3",
@@ -254570,7 +254442,9 @@ var package_default8 = {
254570
254442
  "@supacloud/delivery": "0.4.0"
254571
254443
  },
254572
254444
  devDependencies: {
254445
+ "@supacloud/elysia": "^0.23.1",
254573
254446
  "@types/bun": "^1.4.2",
254447
+ elysia: "2.0.0-beta.19",
254574
254448
  typescript: "^7.0.2"
254575
254449
  }
254576
254450
  };
@@ -255109,7 +254983,7 @@ function createCliTools(context, confirmProduction) {
255109
254983
  async function main() {
255110
254984
  const rawArgs = process.argv.slice(2);
255111
254985
  if (rawArgs.length === 1 && rawArgs[0] === "--version") {
255112
- console.log(package_default8.version);
254986
+ console.log(package_default.version);
255113
254987
  return;
255114
254988
  }
255115
254989
  const globalOptions = parseGlobalOptions(rawArgs);