@abloatai/cli 0.40.0 → 0.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.cjs +704 -326
  2. package/package.json +3 -3
package/dist/cli.cjs CHANGED
@@ -3047,23 +3047,28 @@ function readProjectWriteDatabaseUrl(cwd = process.cwd()) {
3047
3047
  return readProjectEnvValue("ABLO_WRITE_DATABASE_URL", cwd);
3048
3048
  }
3049
3049
  function readProjectEnvValue(variable, cwd) {
3050
+ return readProjectEnvVariable(variable, cwd, false)?.value ?? null;
3051
+ }
3052
+ function readProjectEnvVariable(variable, cwd = process.cwd(), includeProcess = true) {
3053
+ if (includeProcess && process.env[variable]) {
3054
+ return { value: process.env[variable], source: "env" };
3055
+ }
3050
3056
  for (const filename of [".env.local", ".env"]) {
3051
3057
  const path = (0, import_path.resolve)(cwd, filename);
3052
3058
  if (!(0, import_fs2.existsSync)(path)) continue;
3053
3059
  const match = new RegExp(`^${variable}=(.+)$`, "m").exec((0, import_fs2.readFileSync)(path, "utf8"));
3054
- if (match?.[1]) return match[1].trim().replace(/^["']|["']$/g, "");
3060
+ if (match?.[1]) {
3061
+ return {
3062
+ value: match[1].trim().replace(/^["']|["']$/g, ""),
3063
+ source: filename
3064
+ };
3065
+ }
3055
3066
  }
3056
3067
  return null;
3057
3068
  }
3058
3069
  function readProjectApiKey(cwd = process.cwd()) {
3059
- if (process.env.ABLO_API_KEY) return { key: process.env.ABLO_API_KEY, source: "env" };
3060
- for (const name of [".env.local", ".env"]) {
3061
- const path = (0, import_path.resolve)(cwd, name);
3062
- if (!(0, import_fs2.existsSync)(path)) continue;
3063
- const match = /^ABLO_API_KEY=(.+)$/m.exec((0, import_fs2.readFileSync)(path, "utf8"));
3064
- if (match?.[1]) return { key: match[1].trim().replace(/^["']|["']$/g, ""), source: name };
3065
- }
3066
- return null;
3070
+ const found = readProjectEnvVariable("ABLO_API_KEY", cwd);
3071
+ return found ? { key: found.value, source: found.source } : null;
3067
3072
  }
3068
3073
  var import_crypto2, import_fs2, import_path, REPLICATION_URL_VARS, ADMIN_URL_VAR;
3069
3074
  var init_dbRole = __esm({
@@ -3361,6 +3366,11 @@ function clearCredential() {
3361
3366
  function resolveApiKey(modeOverride) {
3362
3367
  return resolveKey({ purpose: "data", mode: modeOverride }).key;
3363
3368
  }
3369
+ function ambientEnvKeyNote(cwd) {
3370
+ const ambient = readProjectApiKey(cwd);
3371
+ if (!ambient || ambient.source === "env") return null;
3372
+ return `Note: ${ambient.source} in this directory holds an ABLO_API_KEY, which this command does not load \u2014 it reads only the process environment and your stored login, so a file cannot silently choose the plane. Export the variable (or prefix the command with it) to use that key.`;
3373
+ }
3364
3374
  function resolveManagementKey() {
3365
3375
  if (process.env.ABLO_MANAGEMENT_KEY) return process.env.ABLO_MANAGEMENT_KEY;
3366
3376
  const cfg = readConfig();
@@ -3773,7 +3783,8 @@ async function confirmFromServer(opts) {
3773
3783
  branchId: identity.branchId ?? null,
3774
3784
  branchRoot: identity.branchRoot
3775
3785
  };
3776
- } catch {
3786
+ } catch (error) {
3787
+ if (opts.strict) throw error;
3777
3788
  return null;
3778
3789
  }
3779
3790
  }
@@ -5102,8 +5113,8 @@ var init_disconnect = __esm({
5102
5113
  npx ablo connect deregister Remove the active project's data source (confirms first)
5103
5114
  npx ablo connect deregister --yes Skip the confirmation
5104
5115
 
5105
- Acts on one plane \u2014 the active project (${import_picocolors8.default.bold("ablo projects use")}) in the active
5106
- environment (${import_picocolors8.default.bold("ablo mode")}), shown before it runs. Removes the registration and
5116
+ Acts on one plane \u2014 the active project (${import_picocolors8.default.bold("ablo projects use")}) in the key's
5117
+ environment (its ${import_picocolors8.default.bold("sk_test_")}/${import_picocolors8.default.bold("sk_live_")} prefix), shown before it runs. Removes the registration and
5107
5118
  Ablo's replication state for that plane, so Ablo stops reading and writing the
5108
5119
  database. Reconnect with ${import_picocolors8.default.bold("ablo connect")}.`;
5109
5120
  }
@@ -5600,7 +5611,8 @@ function rotateWithoutConnection(input) {
5600
5611
  return "Ablo did not accept this API key, so it cannot be told about a new password. Rotate changes the password in your database first, so running it with a key Ablo refuses would leave the database on a password nobody holds.";
5601
5612
  }
5602
5613
  if (!input.known || input.planeHasConnection) return null;
5603
- return "This plane has no connected database, so there is no credential to re-key. Rotate changes the password in your database before Ablo can be told about it, so running it here would leave the database on a password Ablo never receives.";
5614
+ if (input.existingRoles.length > 0) return null;
5615
+ return "This plane has no connected database and Ablo's roles are not in this database, so there is no credential to re-key. Connecting for the first time is `ablo connect apply`, which creates the roles and registers them in one run.";
5604
5616
  }
5605
5617
  async function locateExistingConnection(input) {
5606
5618
  const result = await tryControlPlane({
@@ -5678,7 +5690,7 @@ async function executePlan(sql, steps, rebuildPlaintext) {
5678
5690
  async function runConnectApply(args) {
5679
5691
  const rotating = args.rotate;
5680
5692
  const verb = rotating ? "connect rotate" : "connect apply";
5681
- const adminUrl = args.url ?? readProjectAdminDatabaseUrl();
5693
+ let adminUrl = args.url ?? readProjectAdminDatabaseUrl();
5682
5694
  if (!adminUrl) {
5683
5695
  throw new import_errors9.AbloValidationError(
5684
5696
  "No admin connection string. Pass --url <admin-conn> (or set DATABASE_URL) and re-run.",
@@ -5695,10 +5707,17 @@ async function runConnectApply(args) {
5695
5707
  const apiKey = resolveApiKey();
5696
5708
  if (!apiKey) {
5697
5709
  const loggedIn = resolveManagementKey() !== void 0;
5710
+ const ambient = ambientEnvKeyNote();
5698
5711
  throw new import_errors9.AbloAuthenticationError(
5699
- loggedIn ? `You are logged in, but this project has no data key for ${getMode()}.
5700
- Logging in stores a management credential, which can administer the project but cannot register a database. Registering needs a key scoped to the plane the database will belong to.
5701
- Start one with \`npx ablo dev\`, or set ABLO_API_KEY to that plane's key.` : "Not logged in. Run `ablo login` (or set ABLO_API_KEY) so Ablo knows which project to register this database for.",
5712
+ loggedIn ? `You are logged in, but this project has no ${getMode()} data key.
5713
+
5714
+ The key is looked for in ABLO_API_KEY, then in the credential stored for the active project in the active mode (${getMode()}). Logging in stores a management credential, which administers the project but cannot register a database \u2014 and a key for another mode is never used implicitly, so registering against production takes an explicit production key.
5715
+
5716
+ Mint a sandbox key with \`npx ablo dev\`, or set ABLO_API_KEY to the key of the plane this database should join (its sk_live_ key for production).${ambient ? `
5717
+
5718
+ ${ambient}` : ""}` : `Not logged in, and no ABLO_API_KEY is set. Run \`ablo login\` (or set ABLO_API_KEY) so Ablo knows which project to register this database for.${ambient ? `
5719
+
5720
+ ${ambient}` : ""}`,
5702
5721
  { code: "cli_api_key_missing" }
5703
5722
  );
5704
5723
  }
@@ -5713,23 +5732,39 @@ Start one with \`npx ablo dev\`, or set ABLO_API_KEY to that plane's key.` : "No
5713
5732
  );
5714
5733
  const pooledAdmin = detectPooler(adminUrl);
5715
5734
  if (pooledAdmin?.confidence === "host") {
5716
- console.error(
5717
- ` ${import_picocolors11.default.yellow("!")} ${import_picocolors11.default.bold(target)} is a connection pooler, not the database.
5735
+ if (pooledAdmin.direct) {
5736
+ adminUrl = pooledAdmin.direct;
5737
+ const pooledLabel = target;
5738
+ try {
5739
+ const parsed = new URL(adminUrl);
5740
+ target = `${parsed.host}${parsed.pathname === "/" ? "" : parsed.pathname}`;
5741
+ } catch {
5742
+ }
5743
+ console.log(
5744
+ ` ${import_picocolors11.default.yellow("!")} ${import_picocolors11.default.bold(pooledLabel)} is a connection pooler, so this run uses the direct host:
5745
+ ${import_picocolors11.default.bold(target)}
5746
+ ` + import_picocolors11.default.dim(
5747
+ ` A pooler terminates the session, so replication cannot run over it. Your app
5748
+ keeps the pooled URL; the setup needs the database itself.
5718
5749
  `
5719
- );
5720
- console.error(
5721
- import_picocolors11.default.dim(
5722
- ` A pooler terminates the session, so replication cannot run over it. Setting up
5723
- through it creates roles that Ablo then cannot use to stream.
5750
+ )
5751
+ );
5752
+ } else {
5753
+ console.error(
5754
+ ` ${import_picocolors11.default.yellow("!")} ${import_picocolors11.default.bold(target)} is a connection pooler, not the database.
5724
5755
  `
5725
- )
5726
- );
5727
- console.error(
5728
- pooledAdmin.direct ? ` Re-run against the direct host: ${import_picocolors11.default.bold(pooledAdmin.direct)}
5729
- ` : ` Re-run against the direct database host, not the pooled one.
5756
+ );
5757
+ console.error(
5758
+ import_picocolors11.default.dim(
5759
+ ` A pooler terminates the session, so replication cannot run over it. Setting up
5760
+ through it creates roles that Ablo then cannot use to stream.
5730
5761
  `
5731
- );
5732
- process.exit(1);
5762
+ )
5763
+ );
5764
+ console.error(` Re-run against the direct database host, not the pooled one.
5765
+ `);
5766
+ process.exit(1);
5767
+ }
5733
5768
  }
5734
5769
  if (pooledAdmin?.confidence === "port") {
5735
5770
  console.log(
@@ -5769,31 +5804,31 @@ Start one with \`npx ablo dev\`, or set ABLO_API_KEY to that plane's key.` : "No
5769
5804
  `);
5770
5805
  console.error(
5771
5806
  import_picocolors11.default.dim(` Your database is untouched.
5772
- `) + ` To move it here, disconnect it there first with ${import_picocolors11.default.cyan("ablo connect deregister")}.
5773
- `
5807
+ `) + ` To move it here, disconnect it there first with ${import_picocolors11.default.cyan("ablo connect deregister")}
5808
+ ` + import_picocolors11.default.dim(` (run with a key for that plane). Match the project id to a name with `) + import_picocolors11.default.bold("ablo projects list --json") + import_picocolors11.default.dim(".") + "\n"
5774
5809
  );
5775
5810
  process.exit(1);
5776
5811
  }
5812
+ let rotatePlane = null;
5777
5813
  if (rotating) {
5778
5814
  const state = await fetchDataSourceState(apiBaseUrl(), apiKey).catch(
5779
5815
  () => ({ kind: "unknown", detail: "unreachable" })
5780
5816
  );
5781
- const refusal = rotateWithoutConnection({
5782
- rotating,
5817
+ rotatePlane = {
5783
5818
  planeHasConnection: state.kind === "connected",
5784
5819
  known: state.kind !== "unknown",
5785
5820
  // 401/403 is Ablo answering and declining the key, not a network failure.
5786
5821
  keyRejected: state.kind === "unknown" && /HTTP 40[13]/.test(state.detail)
5787
- });
5788
- if (refusal) {
5789
- console.error(` ${import_picocolors11.default.yellow("!")} ${refusal}
5822
+ };
5823
+ if (rotatePlane.keyRejected) {
5824
+ const refusal = rotateWithoutConnection({ rotating, ...rotatePlane, existingRoles: [] });
5825
+ if (refusal) {
5826
+ console.error(` ${import_picocolors11.default.yellow("!")} ${refusal}
5790
5827
  `);
5791
- console.error(
5792
- import_picocolors11.default.dim(` Your database is untouched.
5793
- `) + ` Connect it instead: ${import_picocolors11.default.cyan("npx ablo connect apply")}
5794
- `
5795
- );
5796
- process.exit(1);
5828
+ console.error(import_picocolors11.default.dim(` Your database is untouched.
5829
+ `));
5830
+ process.exit(1);
5831
+ }
5797
5832
  }
5798
5833
  }
5799
5834
  const admin = src_default(adminUrl, {
@@ -5853,9 +5888,21 @@ Start one with \`npx ablo dev\`, or set ABLO_API_KEY to that plane's key.` : "No
5853
5888
  const pubReconcile = reconcilePublicationPlan(existingPublication, tables);
5854
5889
  const role = args.role && args.role.length > 0 ? args.role : import_footprint.ABLO_REPLICATION_ROLE;
5855
5890
  const writeRole = args.writeRole && args.writeRole.length > 0 ? args.writeRole : import_footprint.ABLO_WRITE_ROLE;
5891
+ const existingRoles = await presentRoles(admin, [role, writeRole]).catch(() => []);
5892
+ if (rotatePlane) {
5893
+ const refusal = rotateWithoutConnection({ rotating, ...rotatePlane, existingRoles });
5894
+ if (refusal) {
5895
+ await admin.end({ timeout: 2 });
5896
+ console.error(` ${import_picocolors11.default.yellow("!")} ${refusal}
5897
+ `);
5898
+ console.error(import_picocolors11.default.dim(` Your database is untouched.
5899
+ `));
5900
+ process.exit(1);
5901
+ }
5902
+ }
5856
5903
  const blocker = reapplyBlocker({
5857
5904
  rotating,
5858
- existingRoles: await presentRoles(admin, [role, writeRole]).catch(() => [])
5905
+ existingRoles
5859
5906
  });
5860
5907
  if (blocker) {
5861
5908
  await admin.end({ timeout: 2 });
@@ -6078,6 +6125,7 @@ function parseConnectArgs(argv) {
6078
6125
  let yes = false;
6079
6126
  let showSql = false;
6080
6127
  let scan = false;
6128
+ let locate = false;
6081
6129
  let manual = false;
6082
6130
  let tables = [];
6083
6131
  let role = import_footprint.ABLO_REPLICATION_ROLE;
@@ -6102,9 +6150,12 @@ function parseConnectArgs(argv) {
6102
6150
  case "scan":
6103
6151
  scan = true;
6104
6152
  break;
6153
+ case "locate":
6154
+ locate = true;
6155
+ break;
6105
6156
  default:
6106
6157
  throw new import_errors10.AbloValidationError(
6107
- `unknown connect subcommand: ${lead} (expected register, deregister, check, apply, rotate, scan)`,
6158
+ `unknown connect subcommand: ${lead} (expected register, deregister, check, apply, rotate, scan, locate)`,
6108
6159
  { code: "cli_invalid_arguments" }
6109
6160
  );
6110
6161
  }
@@ -6166,6 +6217,7 @@ function parseConnectArgs(argv) {
6166
6217
  yes,
6167
6218
  showSql,
6168
6219
  scan,
6220
+ locate,
6169
6221
  tables,
6170
6222
  role,
6171
6223
  writeRole,
@@ -6463,8 +6515,11 @@ async function runCheck() {
6463
6515
  );
6464
6516
  const apiKey = resolveApiKey();
6465
6517
  if (!apiKey) {
6518
+ const ambient = ambientEnvKeyNote();
6466
6519
  throw new import_errors10.AbloAuthenticationError(
6467
- "No API key found. Run `ablo login` (or set ABLO_API_KEY), then re-run `ablo connect check`.",
6520
+ `No API key found. Run \`ablo login\` (or set ABLO_API_KEY), then re-run \`ablo connect check\`.${ambient ? `
6521
+
6522
+ ${ambient}` : ""}`,
6468
6523
  { code: "cli_api_key_missing" }
6469
6524
  );
6470
6525
  }
@@ -6529,8 +6584,11 @@ async function runRegister(args) {
6529
6584
  const writeDbUrl = requireScopedUrl("write", "register");
6530
6585
  const apiKey = resolveApiKey();
6531
6586
  if (!apiKey) {
6587
+ const ambient = ambientEnvKeyNote();
6532
6588
  throw new import_errors10.AbloAuthenticationError(
6533
- "Not logged in. Run `ablo login` (or set ABLO_API_KEY) so Ablo knows which project to register this database for.",
6589
+ `Not logged in. Run \`ablo login\` (or set ABLO_API_KEY) so Ablo knows which project to register this database for.${ambient ? `
6590
+
6591
+ ${ambient}` : ""}`,
6534
6592
  { code: "cli_api_key_missing" }
6535
6593
  );
6536
6594
  }
@@ -6631,6 +6689,62 @@ async function runScan() {
6631
6689
  }
6632
6690
  process.exit(retired.length > 0 ? 1 : 0);
6633
6691
  }
6692
+ async function runLocate(args) {
6693
+ console.log(
6694
+ `
6695
+ ${brand("ablo")} ${import_picocolors12.default.dim("connect locate")} ${import_picocolors12.default.dim("which plane holds this database")}
6696
+ `
6697
+ );
6698
+ const url = args.url ?? readProjectAdminDatabaseUrl();
6699
+ if (!url) {
6700
+ throw new import_errors10.AbloValidationError(
6701
+ "Locating needs a connection string to identify the database. Pass --url <conn> (or set DATABASE_URL) and re-run.",
6702
+ { code: "cli_database_url_missing" }
6703
+ );
6704
+ }
6705
+ const apiKey = resolveApiKey();
6706
+ if (!apiKey) {
6707
+ const ambient = ambientEnvKeyNote();
6708
+ throw new import_errors10.AbloAuthenticationError(
6709
+ `No API key found. Run \`ablo login\` (or set ABLO_API_KEY), then re-run \`ablo connect locate\`.${ambient ? `
6710
+
6711
+ ${ambient}` : ""}`,
6712
+ { code: "cli_api_key_missing" }
6713
+ );
6714
+ }
6715
+ let label = "this database";
6716
+ try {
6717
+ const parsed = new URL(url);
6718
+ label = `${parsed.host}${parsed.pathname === "/" ? "" : parsed.pathname}`;
6719
+ } catch {
6720
+ }
6721
+ const answer = await requestControlPlane({
6722
+ path: "/v1/datasources/locate",
6723
+ method: "POST",
6724
+ apiKey,
6725
+ body: { connectionString: url },
6726
+ responseSchema: import_wire7.datasourceLocationResponseSchema
6727
+ });
6728
+ if (!answer.held) {
6729
+ console.log(
6730
+ ` ${import_picocolors12.default.green("\u2713")} No plane holds ${import_picocolors12.default.bold(label)} \u2014 ${import_picocolors12.default.bold("ablo connect apply")} can register it here.
6731
+ `
6732
+ );
6733
+ return;
6734
+ }
6735
+ console.log(
6736
+ ` ${import_picocolors12.default.yellow("!")} ${import_picocolors12.default.bold(label)} is connected to ${answer.held.project ? `project ${import_picocolors12.default.bold(answer.held.project)}, ` : ""}branch ${import_picocolors12.default.bold(answer.held.branch)}.
6737
+ `
6738
+ );
6739
+ console.log(
6740
+ import_picocolors12.default.dim(
6741
+ ` Ablo streams a database from one plane at a time. To move it, disconnect it there
6742
+ first \u2014 run `
6743
+ ) + import_picocolors12.default.cyan("ablo connect deregister") + import_picocolors12.default.dim(` with a key for that plane, then connect here.
6744
+ `) + import_picocolors12.default.dim(` Confirm a candidate key first with `) + import_picocolors12.default.bold("ablo whoami --key-env <NAME>") + import_picocolors12.default.dim(`.
6745
+ `) + import_picocolors12.default.dim(` Match the project id to a name with `) + import_picocolors12.default.bold("ablo projects list --json") + import_picocolors12.default.dim(".") + "\n"
6746
+ );
6747
+ }
6634
6748
  async function connect(argv) {
6635
6749
  if (argv[0] === "deregister") {
6636
6750
  const { disconnect: disconnect2 } = await Promise.resolve().then(() => (init_disconnect(), disconnect_exports));
@@ -6655,6 +6769,10 @@ async function connect(argv) {
6655
6769
  await runScan();
6656
6770
  return;
6657
6771
  }
6772
+ if (args.locate) {
6773
+ await runLocate(args);
6774
+ return;
6775
+ }
6658
6776
  const credentialReachable = (args.url ?? readProjectAdminDatabaseUrl()) != null;
6659
6777
  const canConfirm = process.stdout.isTTY || args.yes;
6660
6778
  if (!args.manual && credentialReachable && canConfirm) {
@@ -6664,7 +6782,7 @@ async function connect(argv) {
6664
6782
  }
6665
6783
  printConnectRecipe(args);
6666
6784
  }
6667
- var import_errors10, import_picocolors12, import_footprint2, FOOTPRINT_LOOKUP, CONNECT_USAGE;
6785
+ var import_errors10, import_picocolors12, import_footprint2, import_wire7, FOOTPRINT_LOOKUP, CONNECT_USAGE;
6668
6786
  var init_connect = __esm({
6669
6787
  "src/connect.ts"() {
6670
6788
  "use strict";
@@ -6676,6 +6794,7 @@ var init_connect = __esm({
6676
6794
  init_dbRole();
6677
6795
  init_config();
6678
6796
  init_controlPlane();
6797
+ import_wire7 = require("@abloatai/transaction/wire");
6679
6798
  init_theme();
6680
6799
  init_remoteValidation();
6681
6800
  init_connectSetup();
@@ -6699,6 +6818,7 @@ var init_connect = __esm({
6699
6818
  npx ablo connect check Confirm the connected database is ready, from Ablo's side (needs only ABLO_API_KEY)
6700
6819
  npx ablo connect rotate New passwords for both logins, then re-register
6701
6820
  npx ablo connect scan List anything Ablo ever set up in your database (read-only, never drops)
6821
+ npx ablo connect locate See which plane holds this database (read-only; nothing is changed)
6702
6822
 
6703
6823
  Running it: bare \`ablo connect\` sets everything up for you \u2014 creating the two
6704
6824
  scoped logins, sharing your tables, and registering \u2014 whenever it finds a
@@ -282700,7 +282820,7 @@ Node text: ${this.#forgottenText}`;
282700
282820
  // src/index.ts
282701
282821
  init_cjs_shims();
282702
282822
  init_dist2();
282703
- var import_picocolors27 = __toESM(require_picocolors(), 1);
282823
+ var import_picocolors28 = __toESM(require_picocolors(), 1);
282704
282824
  var import_fs13 = require("fs");
282705
282825
  var import_path8 = require("path");
282706
282826
  var import_child_process3 = require("child_process");
@@ -283734,6 +283854,223 @@ async function runBranchDev(argv, dependencies = {}) {
283734
283854
  });
283735
283855
  }
283736
283856
 
283857
+ // src/whoami.ts
283858
+ init_cjs_shims();
283859
+ var import_picocolors16 = __toESM(require_picocolors(), 1);
283860
+ var import_errors13 = require("@abloatai/transaction/errors");
283861
+ init_config();
283862
+ init_controlPlane();
283863
+
283864
+ // src/credentialCapability.ts
283865
+ init_cjs_shims();
283866
+ var import_credentialPolicy3 = require("@abloatai/transaction/auth/credentialPolicy");
283867
+ init_config();
283868
+ function secretCounterpart(key) {
283869
+ return modeFromKey(key) === "production" ? "sk_live_" : "sk_test_";
283870
+ }
283871
+ function credentialCapability(key) {
283872
+ const kind = key ? (0, import_credentialPolicy3.classifyCredentialKind)(key) : null;
283873
+ if (!key || kind === null) return { kind, label: "", note: null };
283874
+ const secret = `${secretCounterpart(key)}\u2026`;
283875
+ switch (kind) {
283876
+ case "secret":
283877
+ return { kind, label: "", note: null };
283878
+ case "restricted":
283879
+ return {
283880
+ kind,
283881
+ label: "scoped",
283882
+ note: `A scoped key does exactly what it was minted for. The production key \`ablo login\` stores is for observing your live plane with \`ablo status\` and \`ablo logs\`; authoring schema there takes a secret ${secret} key from the dashboard.`
283883
+ };
283884
+ case "publishable":
283885
+ return {
283886
+ kind,
283887
+ label: "read-only",
283888
+ note: `This is the key that is safe to ship in a browser bundle, and it reads. Work from a terminal wants a secret ${secret} key.`
283889
+ };
283890
+ case "ephemeral":
283891
+ return {
283892
+ kind,
283893
+ label: "session key",
283894
+ note: `This is a short-lived credential minted for one signed-in person, and it expires. Pushing a schema needs a secret ${secret} key.`
283895
+ };
283896
+ }
283897
+ }
283898
+
283899
+ // src/whoami.ts
283900
+ init_dbRole();
283901
+ init_theme();
283902
+ init_target();
283903
+ var WHOAMI_USAGE = ` ablo whoami \u2014 show the plane a credential acts on
283904
+
283905
+ Usage
283906
+ npx ablo whoami
283907
+ npx ablo whoami --key-env <NAME>
283908
+ npx ablo whoami --key <VALUE>
283909
+ npx ablo whoami --json
283910
+
283911
+ Credential choice
283912
+ With no flag, uses ABLO_API_KEY, then the active project's stored data key,
283913
+ then the stored login. This command does not load .env files implicitly.
283914
+
283915
+ --key-env reads a named variable from the process, .env.local, or .env
283916
+ without putting its value in shell history or the process list. Prefer it
283917
+ for comparing several keys.
283918
+ --key accepts a value directly for one-off use.
283919
+
283920
+ Output never prints the full credential. Identity is confirmed by the server;
283921
+ an invalid key, unreachable server, or unsupported server fails non-zero.`;
283922
+ function parseWhoamiArgs(argv) {
283923
+ let json = false;
283924
+ let key;
283925
+ let keyEnv;
283926
+ for (let i = 0; i < argv.length; i++) {
283927
+ const arg = argv[i];
283928
+ switch (arg) {
283929
+ case "--json":
283930
+ json = true;
283931
+ break;
283932
+ case "--key": {
283933
+ const value = argv[++i];
283934
+ if (!value || value.startsWith("--")) {
283935
+ throw new import_errors13.AbloValidationError("`--key` needs a credential value.", {
283936
+ code: "cli_invalid_arguments"
283937
+ });
283938
+ }
283939
+ key = value;
283940
+ break;
283941
+ }
283942
+ case "--key-env": {
283943
+ const value = argv[++i];
283944
+ if (!value || value.startsWith("--")) {
283945
+ throw new import_errors13.AbloValidationError("`--key-env` needs an environment variable name.", {
283946
+ code: "cli_invalid_arguments"
283947
+ });
283948
+ }
283949
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(value)) {
283950
+ throw new import_errors13.AbloValidationError(
283951
+ `\`${value}\` is not a valid environment variable name.`,
283952
+ { code: "cli_invalid_arguments" }
283953
+ );
283954
+ }
283955
+ keyEnv = value;
283956
+ break;
283957
+ }
283958
+ default:
283959
+ throw new import_errors13.AbloValidationError(`unknown whoami flag: ${arg}`, {
283960
+ code: "cli_invalid_arguments"
283961
+ });
283962
+ }
283963
+ }
283964
+ if (key && keyEnv) {
283965
+ throw new import_errors13.AbloValidationError("Choose one credential source: `--key` or `--key-env`.", {
283966
+ code: "cli_invalid_arguments"
283967
+ });
283968
+ }
283969
+ return { json, ...key ? { key } : {}, ...keyEnv ? { keyEnv } : {} };
283970
+ }
283971
+ function selectWhoamiCredential(args, cwd = process.cwd()) {
283972
+ if (args.key) return { key: args.key, source: "--key", targetSource: "env" };
283973
+ if (args.keyEnv) {
283974
+ const found = readProjectEnvVariable(args.keyEnv, cwd);
283975
+ if (!found) {
283976
+ throw new import_errors13.AbloAuthenticationError(
283977
+ `${args.keyEnv} is not set in the process environment, .env.local, or .env.`,
283978
+ { code: "cli_api_key_missing" }
283979
+ );
283980
+ }
283981
+ return {
283982
+ key: found.value,
283983
+ source: `${found.source}:${args.keyEnv}`,
283984
+ targetSource: "env"
283985
+ };
283986
+ }
283987
+ const dataKey = resolveApiKey();
283988
+ if (dataKey) {
283989
+ return {
283990
+ key: dataKey,
283991
+ source: process.env.ABLO_API_KEY ? "env:ABLO_API_KEY" : "stored data key",
283992
+ targetSource: process.env.ABLO_API_KEY ? "env" : "stored"
283993
+ };
283994
+ }
283995
+ const managementKey = resolveManagementKey();
283996
+ if (managementKey) {
283997
+ return {
283998
+ key: managementKey,
283999
+ source: process.env.ABLO_MANAGEMENT_KEY ? "env:ABLO_MANAGEMENT_KEY" : "stored login",
284000
+ targetSource: process.env.ABLO_MANAGEMENT_KEY ? "env" : "stored"
284001
+ };
284002
+ }
284003
+ const ambient = ambientEnvKeyNote();
284004
+ throw new import_errors13.AbloAuthenticationError(
284005
+ `No credential found. Run \`ablo login\`, set ABLO_API_KEY, or pass \`--key-env <NAME>\`.${ambient ? `
284006
+
284007
+ ${ambient}` : ""}`,
284008
+ { code: "cli_api_key_missing" }
284009
+ );
284010
+ }
284011
+ async function whoami(argv) {
284012
+ const args = parseWhoamiArgs(argv);
284013
+ const selected = selectWhoamiCredential(args);
284014
+ const target = await resolveTarget({
284015
+ url: apiBaseUrl(),
284016
+ apiKey: selected.key,
284017
+ keySource: selected.targetSource,
284018
+ strict: true
284019
+ });
284020
+ const confirmed = target.confirmed;
284021
+ if (!confirmed) {
284022
+ throw new import_errors13.AbloAuthenticationError(
284023
+ "The server did not confirm an identity for this credential.",
284024
+ { code: "identity_resolve_failed" }
284025
+ );
284026
+ }
284027
+ const project = confirmed.project;
284028
+ const projectLabel = project ? project.isDefault ? "default" : project.slug : "default";
284029
+ const actsOn = confirmed.branchId ? confirmed.branchRoot ? "production root" : `branch ${confirmed.branchId}` : confirmed.environment ?? "unknown";
284030
+ const capability = credentialCapability(selected.key);
284031
+ if (args.json) {
284032
+ console.log(
284033
+ JSON.stringify(
284034
+ {
284035
+ authenticated: true,
284036
+ key: {
284037
+ prefix: `${selected.key.slice(0, 12)}\u2026`,
284038
+ source: selected.source,
284039
+ kind: capability.kind
284040
+ },
284041
+ organizationId: confirmed.organizationId,
284042
+ project: project ? {
284043
+ id: project.id,
284044
+ slug: projectLabel,
284045
+ name: project.name,
284046
+ default: project.isDefault
284047
+ } : null,
284048
+ environment: confirmed.environment,
284049
+ branchId: confirmed.branchId ?? null,
284050
+ branchRoot: confirmed.branchRoot ?? false
284051
+ },
284052
+ null,
284053
+ 2
284054
+ )
284055
+ );
284056
+ return;
284057
+ }
284058
+ console.log(`
284059
+ ${brand("ablo")} ${import_picocolors16.default.dim("whoami")}
284060
+ `);
284061
+ console.log(
284062
+ ` ${import_picocolors16.default.dim("key")} ${selected.key.slice(0, 12)}\u2026 ${import_picocolors16.default.dim(`(${selected.source} \xB7 ${capability.label})`)}`
284063
+ );
284064
+ console.log(` ${import_picocolors16.default.dim("org")} ${import_picocolors16.default.dim(confirmed.organizationId)}`);
284065
+ console.log(
284066
+ ` ${import_picocolors16.default.dim("project")} ${import_picocolors16.default.bold(projectLabel)}${project ? ` ${import_picocolors16.default.dim(`(${project.id})`)}` : ""}`
284067
+ );
284068
+ console.log(` ${import_picocolors16.default.dim("acts on")} ${import_picocolors16.default.bold(actsOn)}`);
284069
+ console.log(`
284070
+ ${import_picocolors16.default.green("\u2713")} ${import_picocolors16.default.dim("credential accepted; target confirmed by the server")}
284071
+ `);
284072
+ }
284073
+
283737
284074
  // src/commands.ts
283738
284075
  var CORE_GROUPS = ["Start", "Every day", "More"];
283739
284076
  var FULL_GROUPS = [
@@ -283784,6 +284121,7 @@ var COMMANDS = [
283784
284121
  { run: "connect apply", does: "Run that setup for you, from a one-time admin URL" },
283785
284122
  { run: "connect check", does: "Confirm your database is ready to share changes with Ablo" },
283786
284123
  { run: "connect scan", does: "List anything Ablo ever set up in your database (read-only)" },
284124
+ { run: "connect locate", does: "See which plane holds a database before connecting it" },
283787
284125
  { run: "connect deregister", does: "Disconnect this project's database \u2014 Ablo stops reading and writing it" }
283788
284126
  ]
283789
284127
  }
@@ -283873,6 +284211,18 @@ var COMMANDS = [
283873
284211
  ]
283874
284212
  }
283875
284213
  },
284214
+ {
284215
+ name: "whoami",
284216
+ usage: WHOAMI_USAGE,
284217
+ full: {
284218
+ group: "See what's happening",
284219
+ rows: [
284220
+ { run: "whoami", does: "Show the server-confirmed plane the active credential acts on" },
284221
+ { run: "whoami --key-env <NAME>", does: "Inspect another key without exposing it in argv" },
284222
+ { run: "whoami --json", does: "Same, machine-readable" }
284223
+ ]
284224
+ }
284225
+ },
283876
284226
  {
283877
284227
  name: "status",
283878
284228
  core: { group: "Every day", does: "See what this key acts on, your pushed schema, and whether writes will work" },
@@ -283947,6 +284297,46 @@ var BY_NAME = new Map(ALL.map((c) => [c.name, c]));
283947
284297
  function parseCommandName(raw) {
283948
284298
  return raw !== void 0 && BY_NAME.has(raw) ? raw : null;
283949
284299
  }
284300
+ var REDIRECTS = /* @__PURE__ */ new Map([
284301
+ ["disconnect", "connect deregister"],
284302
+ ["deregister", "connect deregister"],
284303
+ ["register", "connect register"],
284304
+ ["rotate", "connect rotate"]
284305
+ ]);
284306
+ function editDistance(a, b4) {
284307
+ const cols = b4.length + 1;
284308
+ let prevPrev = new Int32Array(cols);
284309
+ let prev = new Int32Array(cols);
284310
+ let curr = new Int32Array(cols);
284311
+ const at = (row, index) => row[index] ?? 0;
284312
+ for (let j2 = 0; j2 < cols; j2++) prev[j2] = j2;
284313
+ for (let i = 1; i <= a.length; i++) {
284314
+ curr[0] = i;
284315
+ for (let j2 = 1; j2 < cols; j2++) {
284316
+ const cost = a.charCodeAt(i - 1) === b4.charCodeAt(j2 - 1) ? 0 : 1;
284317
+ let best = Math.min(at(prev, j2) + 1, at(curr, j2 - 1) + 1, at(prev, j2 - 1) + cost);
284318
+ if (i > 1 && j2 > 1 && a.charCodeAt(i - 1) === b4.charCodeAt(j2 - 2) && a.charCodeAt(i - 2) === b4.charCodeAt(j2 - 1)) {
284319
+ best = Math.min(best, at(prevPrev, j2 - 2) + 1);
284320
+ }
284321
+ curr[j2] = best;
284322
+ }
284323
+ [prevPrev, prev, curr] = [prev, curr, prevPrev];
284324
+ }
284325
+ return at(prev, b4.length);
284326
+ }
284327
+ function suggestCommand(raw) {
284328
+ const exact = REDIRECTS.get(raw);
284329
+ if (exact) return exact;
284330
+ let best = null;
284331
+ for (const name of [...BY_NAME.keys(), ...REDIRECTS.keys()]) {
284332
+ const distance = editDistance(raw.toLowerCase(), name);
284333
+ if (distance <= 2 && (best === null || distance < best.distance)) {
284334
+ best = { name, distance };
284335
+ }
284336
+ }
284337
+ if (best === null) return null;
284338
+ return REDIRECTS.get(best.name) ?? best.name;
284339
+ }
283950
284340
  function usageFor(name) {
283951
284341
  return BY_NAME.get(name)?.usage;
283952
284342
  }
@@ -283961,14 +284351,15 @@ function fullRows(group) {
283961
284351
  }
283962
284352
 
283963
284353
  // src/index.ts
284354
+ var import_errors21 = require("@abloatai/transaction/errors");
283964
284355
  init_push();
283965
284356
 
283966
284357
  // src/generate.ts
283967
284358
  init_cjs_shims();
283968
- var import_errors13 = require("@abloatai/transaction/errors");
284359
+ var import_errors14 = require("@abloatai/transaction/errors");
283969
284360
  var import_fs8 = require("fs");
283970
284361
  var import_path6 = require("path");
283971
- var import_picocolors16 = __toESM(require_picocolors(), 1);
284362
+ var import_picocolors17 = __toESM(require_picocolors(), 1);
283972
284363
  var import_schema7 = require("@abloatai/transaction/schema");
283973
284364
  init_push();
283974
284365
  var DEFAULT_SCHEMA_PATH4 = "ablo/schema.ts";
@@ -283991,7 +284382,7 @@ function parseGenerateArgs(argv) {
283991
284382
  out = argv[++i] ?? out;
283992
284383
  break;
283993
284384
  default:
283994
- throw new import_errors13.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
284385
+ throw new import_errors14.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
283995
284386
  }
283996
284387
  }
283997
284388
  return { schemaPath, exportName, out };
@@ -284001,7 +284392,7 @@ async function generate(argv) {
284001
284392
  try {
284002
284393
  args = parseGenerateArgs(argv);
284003
284394
  } catch (err) {
284004
- console.error(import_picocolors16.default.red(` ${err instanceof Error ? err.message : String(err)}`));
284395
+ console.error(import_picocolors17.default.red(` ${err instanceof Error ? err.message : String(err)}`));
284005
284396
  process.exit(1);
284006
284397
  }
284007
284398
  let source;
@@ -284010,22 +284401,22 @@ async function generate(argv) {
284010
284401
  const schemaJson = JSON.parse((0, import_schema7.serializeSchema)(schema));
284011
284402
  source = (0, import_schema7.generateTypes)(schemaJson);
284012
284403
  } catch (err) {
284013
- console.error(import_picocolors16.default.red(` ${err instanceof Error ? err.message : String(err)}`));
284404
+ console.error(import_picocolors17.default.red(` ${err instanceof Error ? err.message : String(err)}`));
284014
284405
  process.exit(1);
284015
284406
  }
284016
284407
  const abs = (0, import_path6.resolve)(process.cwd(), args.out);
284017
284408
  (0, import_fs8.mkdirSync)((0, import_path6.dirname)(abs), { recursive: true });
284018
284409
  (0, import_fs8.writeFileSync)(abs, source);
284019
- console.log(` ${import_picocolors16.default.green("\u2713")} Generated types \u2192 ${import_picocolors16.default.bold(args.out)}`);
284410
+ console.log(` ${import_picocolors17.default.green("\u2713")} Generated types \u2192 ${import_picocolors17.default.bold(args.out)}`);
284020
284411
  }
284021
284412
 
284022
284413
  // src/login.ts
284023
284414
  init_cjs_shims();
284024
284415
  var import_child_process2 = require("child_process");
284025
- var import_picocolors17 = __toESM(require_picocolors(), 1);
284416
+ var import_picocolors18 = __toESM(require_picocolors(), 1);
284026
284417
  init_dist2();
284027
- var import_errors14 = require("@abloatai/transaction/errors");
284028
- var import_wire7 = require("@abloatai/transaction/wire");
284418
+ var import_errors15 = require("@abloatai/transaction/errors");
284419
+ var import_wire8 = require("@abloatai/transaction/wire");
284029
284420
  init_config();
284030
284421
  init_theme();
284031
284422
  var CLIENT_ID = "ablo-cli";
@@ -284043,20 +284434,21 @@ function openBrowser(url) {
284043
284434
  } catch {
284044
284435
  }
284045
284436
  }
284046
- function parseProjectFlag(argv) {
284047
- const i = argv.indexOf("--project");
284437
+ function parseSlugFlag(argv, flag2) {
284438
+ const i = argv.indexOf(flag2);
284048
284439
  if (i >= 0) {
284049
284440
  const slug = argv[i + 1];
284050
284441
  if (slug && !slug.startsWith("-")) return slug;
284051
284442
  }
284052
- const eq = argv.find((a) => a.startsWith("--project="));
284053
- return eq ? eq.slice("--project=".length) || void 0 : void 0;
284443
+ const eq = argv.find((a) => a.startsWith(`${flag2}=`));
284444
+ return eq ? eq.slice(flag2.length + 1) || void 0 : void 0;
284054
284445
  }
284055
284446
  async function deviceLogin(argv, deps = {}) {
284056
284447
  const openUrl = deps.openUrl ?? openBrowser;
284057
284448
  Ie(`${brand("ablo")} login`);
284058
- const requested = parseProjectFlag(argv) ?? getActiveProject()?.slug;
284449
+ const requested = parseSlugFlag(argv, "--project") ?? getActiveProject()?.slug;
284059
284450
  const targetProject = requested === DEFAULT_PROFILE ? void 0 : requested;
284451
+ const targetOrg = parseSlugFlag(argv, "--org");
284060
284452
  const interactive = Boolean(process.stdout.isTTY && process.stdin.isTTY);
284061
284453
  let account = "login";
284062
284454
  if (interactive) {
@@ -284083,11 +284475,11 @@ async function deviceLogin(argv, deps = {}) {
284083
284475
  process.exit(1);
284084
284476
  }
284085
284477
  const code = await codeRes.json();
284086
- const approvePath = `/cli?user_code=${code.user_code}`;
284478
+ const approvePath = `/cli?user_code=${code.user_code}${targetOrg ? `&org=${encodeURIComponent(targetOrg)}` : ""}`;
284087
284479
  const url = account === "signup" ? `${DASHBOARD_URL}/signup?next=${encodeURIComponent(approvePath)}` : `${DASHBOARD_URL}${approvePath}`;
284088
- Me(`${import_picocolors17.default.bold(code.user_code)}
284480
+ Me(`${import_picocolors18.default.bold(code.user_code)}
284089
284481
 
284090
- ${import_picocolors17.default.dim(url)}`, "Approve in your browser");
284482
+ ${import_picocolors18.default.dim(url)}`, "Approve in your browser");
284091
284483
  openUrl(url);
284092
284484
  const s = Y2();
284093
284485
  s.start("Waiting for approval\u2026");
@@ -284157,7 +284549,7 @@ ${import_picocolors17.default.dim(url)}`, "Approve in your browser");
284157
284549
  }
284158
284550
  if (!provRes.ok) {
284159
284551
  s.stop("Could not provision a key.");
284160
- const err = (0, import_errors14.translateHttpError)(
284552
+ const err = (0, import_errors15.translateHttpError)(
284161
284553
  provRes.status,
284162
284554
  await provRes.json().catch(() => null),
284163
284555
  provRes.headers.get("x-request-id") ?? void 0
@@ -284165,30 +284557,36 @@ ${import_picocolors17.default.dim(url)}`, "Approve in your browser");
284165
284557
  M2.error(err.message);
284166
284558
  if (err.code === "entity_not_found" && targetProject) {
284167
284559
  M2.error(
284168
- `If that isn't the account you meant, run ${import_picocolors17.default.bold("npx ablo logout")} and sign in again. Otherwise create it with ${import_picocolors17.default.bold(`npx ablo projects create ${targetProject}`)}.`
284560
+ `If that isn't the account you meant, run ${import_picocolors18.default.bold("npx ablo logout")} and sign in again. Otherwise create it with ${import_picocolors18.default.bold(`npx ablo projects create ${targetProject}`)}.`
284169
284561
  );
284170
284562
  } else {
284171
284563
  M2.error(
284172
- `The browser approval succeeded but the credential handoff failed. Try ${import_picocolors17.default.bold("npx ablo login")} again.`
284564
+ `The browser approval succeeded but the credential handoff failed. Try ${import_picocolors18.default.bold("npx ablo login")} again.`
284173
284565
  );
284174
284566
  }
284175
284567
  process.exit(1);
284176
284568
  }
284177
- const parsedProv = import_wire7.provisionKeyResponseSchema.safeParse(
284569
+ const parsedProv = import_wire8.provisionKeyResponseSchema.safeParse(
284178
284570
  await provRes.json().catch(() => null)
284179
284571
  );
284180
284572
  if (!parsedProv.success) {
284181
284573
  s.stop("Could not provision a key.");
284182
284574
  M2.error("The key handoff returned something this version does not recognize.");
284183
- M2.error(`Try again, or upgrade with ${import_picocolors17.default.bold("npm i -g @abloatai/ablo")}.`);
284575
+ M2.error(`Try again, or upgrade with ${import_picocolors18.default.bold("npm i -g @abloatai/ablo")}.`);
284184
284576
  process.exit(1);
284185
284577
  }
284186
284578
  const prov = parsedProv.data;
284187
284579
  const entry = (k3) => ({
284188
284580
  apiKey: k3.apiKey,
284189
284581
  ...prov.organizationId ? { organizationId: prov.organizationId } : {},
284582
+ ...prov.organizationSlug ? { organizationSlug: prov.organizationSlug } : {},
284190
284583
  ...k3.expiresAt ? { expiresAt: k3.expiresAt } : {}
284191
284584
  });
284585
+ if (targetOrg && prov.organizationSlug && prov.organizationSlug !== targetOrg) {
284586
+ M2.warn(
284587
+ `The approval chose ${import_picocolors18.default.bold(prov.organizationSlug)}, not ${import_picocolors18.default.bold(targetOrg)}. The credential is scoped to ${import_picocolors18.default.bold(prov.organizationSlug)}.`
284588
+ );
284589
+ }
284192
284590
  const profileName = prov.project?.slug ?? DEFAULT_PROFILE;
284193
284591
  const path = setProfileKeys(
284194
284592
  profileName,
@@ -284198,9 +284596,10 @@ ${import_picocolors17.default.dim(url)}`, "Approve in your browser");
284198
284596
  { mode: "sandbox", activeProject: prov.project ?? void 0 }
284199
284597
  );
284200
284598
  s.stop(`Saved project credential to ${path}`);
284201
- const where = prov.project ? ` ${import_picocolors17.default.dim(`(project ${prov.project.slug})`)}` : "";
284599
+ const orgLabel = prov.organizationSlug ? ` to ${import_picocolors18.default.bold(prov.organizationSlug)}` : "";
284600
+ const where = prov.project ? ` ${import_picocolors18.default.dim(`(project ${prov.project.slug})`)}` : "";
284202
284601
  Se(
284203
- `${import_picocolors17.default.green("\u2713")} Logged in${where}. Run ${import_picocolors17.default.bold("npx ablo dev")} to create or resume your Git branch and start with an expiring runtime key.`
284602
+ `${import_picocolors18.default.green("\u2713")} Logged in${orgLabel}${where}. Run ${import_picocolors18.default.bold("npx ablo dev")} to create or resume your Git branch and start with an expiring runtime key.`
284204
284603
  );
284205
284604
  }
284206
284605
  async function login(argv = [], deps = {}) {
@@ -284209,14 +284608,14 @@ async function login(argv = [], deps = {}) {
284209
284608
  function logout() {
284210
284609
  const removed = clearCredential();
284211
284610
  if (removed) {
284212
- console.log(` ${import_picocolors17.default.green("\u2713")} Logged out ${import_picocolors17.default.dim(`(credentials removed from ${configDir()})`)}`);
284611
+ console.log(` ${import_picocolors18.default.green("\u2713")} Logged out ${import_picocolors18.default.dim(`(credentials removed from ${configDir()})`)}`);
284213
284612
  } else {
284214
- console.log(` ${import_picocolors17.default.dim("\u25CB")} Not logged in \u2014 nothing to remove.`);
284613
+ console.log(` ${import_picocolors18.default.dim("\u25CB")} Not logged in \u2014 nothing to remove.`);
284215
284614
  }
284216
284615
  if (process.env.ABLO_MANAGEMENT_KEY) {
284217
284616
  console.log(
284218
- import_picocolors17.default.dim(
284219
- ` Note: ${import_picocolors17.default.bold("ABLO_MANAGEMENT_KEY")} is still set in this shell and takes precedence.`
284617
+ import_picocolors18.default.dim(
284618
+ ` Note: ${import_picocolors18.default.bold("ABLO_MANAGEMENT_KEY")} is still set in this shell and takes precedence.`
284220
284619
  )
284221
284620
  );
284222
284621
  }
@@ -284228,46 +284627,9 @@ init_projects();
284228
284627
 
284229
284628
  // src/status.ts
284230
284629
  init_cjs_shims();
284231
- var import_picocolors18 = __toESM(require_picocolors(), 1);
284630
+ var import_picocolors19 = __toESM(require_picocolors(), 1);
284232
284631
  init_config();
284233
284632
  init_target();
284234
-
284235
- // src/credentialCapability.ts
284236
- init_cjs_shims();
284237
- var import_credentialPolicy3 = require("@abloatai/transaction/auth/credentialPolicy");
284238
- init_config();
284239
- function secretCounterpart(key) {
284240
- return modeFromKey(key) === "production" ? "sk_live_" : "sk_test_";
284241
- }
284242
- function credentialCapability(key) {
284243
- const kind = key ? (0, import_credentialPolicy3.classifyCredentialKind)(key) : null;
284244
- if (!key || kind === null) return { kind, label: "", note: null };
284245
- const secret = `${secretCounterpart(key)}\u2026`;
284246
- switch (kind) {
284247
- case "secret":
284248
- return { kind, label: "", note: null };
284249
- case "restricted":
284250
- return {
284251
- kind,
284252
- label: "scoped",
284253
- note: `A scoped key does exactly what it was minted for. The production key \`ablo login\` stores is for observing your live plane with \`ablo status\` and \`ablo logs\`; authoring schema there takes a secret ${secret} key from the dashboard.`
284254
- };
284255
- case "publishable":
284256
- return {
284257
- kind,
284258
- label: "read-only",
284259
- note: `This is the key that is safe to ship in a browser bundle, and it reads. Work from a terminal wants a secret ${secret} key.`
284260
- };
284261
- case "ephemeral":
284262
- return {
284263
- kind,
284264
- label: "session key",
284265
- note: `This is a short-lived credential minted for one signed-in person, and it expires. Pushing a schema needs a secret ${secret} key.`
284266
- };
284267
- }
284268
- }
284269
-
284270
- // src/status.ts
284271
284633
  init_theme();
284272
284634
  init_controlPlane();
284273
284635
  var import_schema8 = require("@abloatai/transaction/coordination/schema");
@@ -284275,9 +284637,9 @@ init_readiness();
284275
284637
  function expiryLabel(iso) {
284276
284638
  const ms = Date.parse(iso) - Date.now();
284277
284639
  if (Number.isNaN(ms)) return "";
284278
- if (ms <= 0) return import_picocolors18.default.red("expired");
284640
+ if (ms <= 0) return import_picocolors19.default.red("expired");
284279
284641
  const days = Math.floor(ms / (24 * 60 * 60 * 1e3));
284280
- return import_picocolors18.default.dim(days > 0 ? `expires in ${days}d` : "expires <1d");
284642
+ return import_picocolors19.default.dim(days > 0 ? `expires in ${days}d` : "expires <1d");
284281
284643
  }
284282
284644
  async function ping(apiUrl3) {
284283
284645
  const ctrl = new AbortController();
@@ -284298,40 +284660,42 @@ function formatConflict(conflict) {
284298
284660
  const parts = import_schema8.participantKindSchema.options.flatMap((k3) => conflict[k3] ? [`${k3}:${conflict[k3]}`] : []);
284299
284661
  return parts.length ? `{${parts.join(",")}}` : "";
284300
284662
  }
284301
- function printTargetLines(target, localProject, storedOrganizationId) {
284663
+ function printTargetLines(target, localProject, storedOrganizationId, storedOrganizationSlug) {
284302
284664
  const confirmed = target?.confirmed ?? null;
284303
284665
  const org = confirmed?.organizationId ?? storedOrganizationId;
284304
284666
  if (org) {
284305
- const suffix = confirmed?.organizationId ? "" : ` ${import_picocolors18.default.yellow("(unconfirmed)")}`;
284306
- console.log(` ${import_picocolors18.default.dim("org")} ${import_picocolors18.default.dim(org)}${suffix}`);
284667
+ const suffix = confirmed?.organizationId ? "" : ` ${import_picocolors19.default.yellow("(unconfirmed)")}`;
284668
+ const slug = org === storedOrganizationId ? storedOrganizationSlug : void 0;
284669
+ const label = slug ? `${import_picocolors19.default.bold(slug)} ${import_picocolors19.default.dim(`(${org})`)}` : import_picocolors19.default.dim(org);
284670
+ console.log(` ${import_picocolors19.default.dim("org")} ${label}${suffix}`);
284307
284671
  } else {
284308
284672
  console.log(
284309
- ` ${import_picocolors18.default.dim("org")} ${import_picocolors18.default.yellow("unknown")} ${import_picocolors18.default.dim("(the server did not confirm one for this key)")}`
284673
+ ` ${import_picocolors19.default.dim("org")} ${import_picocolors19.default.yellow("unknown")} ${import_picocolors19.default.dim("(the server did not confirm one for this key)")}`
284310
284674
  );
284311
284675
  }
284312
284676
  let projectLine;
284313
284677
  if (confirmed?.project) {
284314
284678
  const p2 = confirmed.project;
284315
- projectLine = p2.isDefault ? `${import_picocolors18.default.bold("default")} ${import_picocolors18.default.dim("(org-default)")}` : `${import_picocolors18.default.bold(p2.slug)} ${import_picocolors18.default.dim(`(${p2.id})`)}`;
284679
+ projectLine = p2.isDefault ? `${import_picocolors19.default.bold("default")} ${import_picocolors19.default.dim("(org-default)")}` : `${import_picocolors19.default.bold(p2.slug)} ${import_picocolors19.default.dim(`(${p2.id})`)}`;
284316
284680
  } else if (confirmed) {
284317
- projectLine = `${import_picocolors18.default.bold("default")} ${import_picocolors18.default.dim("(org-default)")}`;
284681
+ projectLine = `${import_picocolors19.default.bold("default")} ${import_picocolors19.default.dim("(org-default)")}`;
284318
284682
  } else if (localProject) {
284319
- projectLine = `${import_picocolors18.default.bold(localProject.slug)} ${import_picocolors18.default.dim(`(${localProject.id})`)} ${import_picocolors18.default.yellow("(unconfirmed)")}`;
284683
+ projectLine = `${import_picocolors19.default.bold(localProject.slug)} ${import_picocolors19.default.dim(`(${localProject.id})`)} ${import_picocolors19.default.yellow("(unconfirmed)")}`;
284320
284684
  } else {
284321
- projectLine = `${import_picocolors18.default.bold("default")} ${target ? import_picocolors18.default.yellow("(unconfirmed)") : import_picocolors18.default.dim("(org-default)")}`;
284685
+ projectLine = `${import_picocolors19.default.bold("default")} ${target ? import_picocolors19.default.yellow("(unconfirmed)") : import_picocolors19.default.dim("(org-default)")}`;
284322
284686
  }
284323
- console.log(` ${import_picocolors18.default.dim("project")} ${projectLine}`);
284687
+ console.log(` ${import_picocolors19.default.dim("project")} ${projectLine}`);
284324
284688
  const branch = confirmed?.branchId ?? null;
284325
284689
  const env = confirmed?.environment ?? target?.keyEnv ?? null;
284326
284690
  if (branch) {
284327
284691
  const label = confirmed?.branchRoot ? "production root" : `branch ${branch}`;
284328
- console.log(` ${import_picocolors18.default.dim("acts on")} ${import_picocolors18.default.bold(label)}`);
284692
+ console.log(` ${import_picocolors19.default.dim("acts on")} ${import_picocolors19.default.bold(label)}`);
284329
284693
  } else if (env) {
284330
- const suffix = confirmed ? "" : ` ${import_picocolors18.default.yellow("(unconfirmed)")}`;
284331
- console.log(` ${import_picocolors18.default.dim("acts on")} ${import_picocolors18.default.bold(env)}${suffix}`);
284694
+ const suffix = confirmed ? "" : ` ${import_picocolors19.default.yellow("(unconfirmed)")}`;
284695
+ console.log(` ${import_picocolors19.default.dim("acts on")} ${import_picocolors19.default.bold(env)}${suffix}`);
284332
284696
  }
284333
284697
  const divergence = describeMismatches(target?.mismatches ?? []);
284334
- if (divergence) console.log(` ${import_picocolors18.default.yellow(`\u26A0 ${divergence}`)}`);
284698
+ if (divergence) console.log(` ${import_picocolors19.default.yellow(`\u26A0 ${divergence}`)}`);
284335
284699
  }
284336
284700
  async function status(args = []) {
284337
284701
  const apiUrl3 = apiBaseUrl();
@@ -284420,23 +284784,28 @@ async function status(args = []) {
284420
284784
  return;
284421
284785
  }
284422
284786
  console.log(`
284423
- ${brand("ablo")} ${import_picocolors18.default.dim("status")}
284787
+ ${brand("ablo")} ${import_picocolors19.default.dim("status")}
284424
284788
  `);
284425
284789
  if (effective.key && effective.source && effective.source !== "stored") {
284426
284790
  const label = effective.source === "env" ? "ABLO_API_KEY env" : effective.source;
284427
284791
  console.log(
284428
- ` ${import_picocolors18.default.dim("key")} ${effective.key.slice(0, 12)}\u2026 ${import_picocolors18.default.dim(`(${label} \u2014 overrides stored)`)}`
284792
+ ` ${import_picocolors19.default.dim("key")} ${effective.key.slice(0, 12)}\u2026 ${import_picocolors19.default.dim(`(${label} \u2014 overrides stored)`)}`
284429
284793
  );
284430
284794
  } else if (!cfg) {
284431
- console.log(` ${import_picocolors18.default.yellow("!")} Not logged in \u2014 run ${import_picocolors18.default.bold("ablo login")}.`);
284795
+ console.log(` ${import_picocolors19.default.yellow("!")} Not logged in \u2014 run ${import_picocolors19.default.bold("ablo login")}.`);
284432
284796
  }
284433
284797
  const activeEntry = getKeyEntry(mode);
284434
284798
  const key = describeEffectiveKey(mode, process.env.ABLO_API_KEY, activeEntry);
284435
284799
  if (key.keyMismatch) {
284436
- console.log(` ${import_picocolors18.default.yellow(`! ${key.keyMismatch.message}`)}`);
284800
+ console.log(` ${import_picocolors19.default.yellow(`! ${key.keyMismatch.message}`)}`);
284437
284801
  }
284438
284802
  const activeProject = getActiveProject();
284439
- printTargetLines(target, activeProject, activeEntry?.organizationId);
284803
+ printTargetLines(
284804
+ target,
284805
+ activeProject,
284806
+ activeEntry?.organizationId,
284807
+ activeEntry?.organizationSlug
284808
+ );
284440
284809
  for (const { key: m2, label } of [
284441
284810
  { key: "sandbox", label: "management" },
284442
284811
  { key: "production", label: "observer" }
@@ -284447,68 +284816,68 @@ async function status(args = []) {
284447
284816
  credentialCapability(entry.apiKey).label,
284448
284817
  entry.expiresAt ? expiryLabel(entry.expiresAt) : ""
284449
284818
  ].filter(Boolean);
284450
- const trail = facts.length ? ` ${import_picocolors18.default.dim("\xB7")} ${facts.join(import_picocolors18.default.dim(" \xB7 "))}` : "";
284819
+ const trail = facts.length ? ` ${import_picocolors19.default.dim("\xB7")} ${facts.join(import_picocolors19.default.dim(" \xB7 "))}` : "";
284451
284820
  console.log(
284452
- ` ${import_picocolors18.default.dim("\u25CB")} ${label.padEnd(10)} ${import_picocolors18.default.dim(`${entry.apiKey.slice(0, 12)}\u2026`)}${trail}`
284821
+ ` ${import_picocolors19.default.dim("\u25CB")} ${label.padEnd(10)} ${import_picocolors19.default.dim(`${entry.apiKey.slice(0, 12)}\u2026`)}${trail}`
284453
284822
  );
284454
284823
  } else {
284455
- console.log(` ${import_picocolors18.default.dim("\u25CB")} ${label.padEnd(10)} ${import_picocolors18.default.dim("\u2014 no key")}`);
284824
+ console.log(` ${import_picocolors19.default.dim("\u25CB")} ${label.padEnd(10)} ${import_picocolors19.default.dim("\u2014 no key")}`);
284456
284825
  }
284457
284826
  }
284458
284827
  const plan = resolvePushPlan();
284459
284828
  console.log(
284460
- ` ${import_picocolors18.default.dim("push")} ${plan.apiKey ? `${import_picocolors18.default.bold(plan.flow)} ${import_picocolors18.default.dim(`with ${plan.apiKey.slice(0, 12)}\u2026 (${plan.source})`)}` : `${import_picocolors18.default.bold(plan.flow)} ${import_picocolors18.default.yellow("\u2014 no credential")} ${import_picocolors18.default.dim(`(run ${import_picocolors18.default.bold("ablo login")} or set ${import_picocolors18.default.bold("ABLO_API_KEY")})`)}`}`
284829
+ ` ${import_picocolors19.default.dim("push")} ${plan.apiKey ? `${import_picocolors19.default.bold(plan.flow)} ${import_picocolors19.default.dim(`with ${plan.apiKey.slice(0, 12)}\u2026 (${plan.source})`)}` : `${import_picocolors19.default.bold(plan.flow)} ${import_picocolors19.default.yellow("\u2014 no credential")} ${import_picocolors19.default.dim(`(run ${import_picocolors19.default.bold("ablo login")} or set ${import_picocolors19.default.bold("ABLO_API_KEY")})`)}`}`
284461
284830
  );
284462
284831
  const capability = credentialCapability(effective.key);
284463
- if (capability.note) console.log(` ${import_picocolors18.default.dim(capability.note)}`);
284464
- process.stdout.write(` ${import_picocolors18.default.dim("api")} ${apiUrl3} `);
284832
+ if (capability.note) console.log(` ${import_picocolors19.default.dim(capability.note)}`);
284833
+ process.stdout.write(` ${import_picocolors19.default.dim("api")} ${apiUrl3} `);
284465
284834
  const reachable = await ping(apiUrl3);
284466
- console.log(reachable ? import_picocolors18.default.green("reachable") : import_picocolors18.default.red("unreachable"));
284835
+ console.log(reachable ? import_picocolors19.default.green("reachable") : import_picocolors19.default.red("unreachable"));
284467
284836
  const introspectKey = effective.key;
284468
284837
  const { source: dataSource, validation } = reachable ? await fetchRoutingState(apiUrl3, introspectKey) : { source: { kind: "unknown", detail: "unreachable" }, validation: null };
284469
284838
  if (dataSource.kind === "connected") {
284470
284839
  const how = [...new Set(dataSource.connections)].join(" + ");
284471
284840
  const pooled = detectPoolerIn(dataSource.hosts);
284472
284841
  const unreachable = validation && !validation.ok ? validation.message : void 0;
284473
- console.log(` ${import_picocolors18.default.dim("data")} ${import_picocolors18.default.green("\u2713")} ${import_picocolors18.default.dim(`database connected to this plane (${how})`)}`);
284842
+ console.log(` ${import_picocolors19.default.dim("data")} ${import_picocolors19.default.green("\u2713")} ${import_picocolors19.default.dim(`database connected to this plane (${how})`)}`);
284474
284843
  if (pooled) {
284475
284844
  console.log(
284476
- ` ${import_picocolors18.default.yellow("\u26A0")} ${import_picocolors18.default.dim(
284845
+ ` ${import_picocolors19.default.yellow("\u26A0")} ${import_picocolors19.default.dim(
284477
284846
  `${pooled.host} is a connection pooler` + (pooled.direct ? `; register the direct host instead: ${pooled.direct}` : "; register the direct host instead")
284478
284847
  )}`
284479
284848
  );
284480
284849
  }
284481
284850
  if (unreachable) {
284482
- console.log(` ${import_picocolors18.default.red("\u2717")} ${import_picocolors18.default.dim(`Ablo could not reach it \u2014 ${unreachable}`)}`);
284851
+ console.log(` ${import_picocolors19.default.red("\u2717")} ${import_picocolors19.default.dim(`Ablo could not reach it \u2014 ${unreachable}`)}`);
284483
284852
  }
284484
284853
  } else if (dataSource.kind === "none") {
284485
284854
  console.log(
284486
- ` ${import_picocolors18.default.dim("data")} ${import_picocolors18.default.red("\u2717 no database connected to this plane")} ${import_picocolors18.default.dim("\u2014 writes are held")}`
284855
+ ` ${import_picocolors19.default.dim("data")} ${import_picocolors19.default.red("\u2717 no database connected to this plane")} ${import_picocolors19.default.dim("\u2014 writes are held")}`
284487
284856
  );
284488
284857
  } else if (reachable) {
284489
- console.log(` ${import_picocolors18.default.dim("data")} ${import_picocolors18.default.yellow("?")} ${import_picocolors18.default.dim(`could not read the plane's databases (${dataSource.detail})`)}`);
284858
+ console.log(` ${import_picocolors19.default.dim("data")} ${import_picocolors19.default.yellow("?")} ${import_picocolors19.default.dim(`could not read the plane's databases (${dataSource.detail})`)}`);
284490
284859
  }
284491
284860
  const pushed = reachable ? await fetchPushedSchema(apiUrl3, introspectKey) : null;
284492
284861
  if (reachable) {
284493
284862
  if (pushed?.active) {
284494
- const when = pushed.pushedAt ? ` ${import_picocolors18.default.dim(`@ ${pushed.pushedAt.slice(0, 10)}`)}` : "";
284495
- const ver = pushed.version != null ? ` ${import_picocolors18.default.dim(`(rev ${pushed.version})`)}` : "";
284496
- const hashLabel = pushed.hash ? ` ${import_picocolors18.default.dim(`hash ${pushed.hash}`)}` : "";
284497
- console.log(` ${import_picocolors18.default.dim("schema")} ${import_picocolors18.default.bold(`${pushed.models.length} models pushed`)}${ver}${hashLabel}${when}`);
284863
+ const when = pushed.pushedAt ? ` ${import_picocolors19.default.dim(`@ ${pushed.pushedAt.slice(0, 10)}`)}` : "";
284864
+ const ver = pushed.version != null ? ` ${import_picocolors19.default.dim(`(rev ${pushed.version})`)}` : "";
284865
+ const hashLabel = pushed.hash ? ` ${import_picocolors19.default.dim(`hash ${pushed.hash}`)}` : "";
284866
+ console.log(` ${import_picocolors19.default.dim("schema")} ${import_picocolors19.default.bold(`${pushed.models.length} models pushed`)}${ver}${hashLabel}${when}`);
284498
284867
  for (const m2 of pushed.models) {
284499
- const tn = m2.typename === m2.key ? import_picocolors18.default.dim(`typename=${m2.typename}`) : import_picocolors18.default.yellow(`typename=${m2.typename}`);
284868
+ const tn = m2.typename === m2.key ? import_picocolors19.default.dim(`typename=${m2.typename}`) : import_picocolors19.default.yellow(`typename=${m2.typename}`);
284500
284869
  const conflict = formatConflict(m2.conflict);
284501
- const conflictStr2 = conflict ? ` ${import_picocolors18.default.dim(`conflict=${conflict}`)}` : "";
284502
- console.log(` ${import_picocolors18.default.dim("\u2022")} ${m2.key.padEnd(14)} ${tn}${conflictStr2}`);
284870
+ const conflictStr2 = conflict ? ` ${import_picocolors19.default.dim(`conflict=${conflict}`)}` : "";
284871
+ console.log(` ${import_picocolors19.default.dim("\u2022")} ${m2.key.padEnd(14)} ${tn}${conflictStr2}`);
284503
284872
  }
284504
284873
  } else if (pushed && !pushed.active) {
284505
- console.log(` ${import_picocolors18.default.dim("schema")} ${import_picocolors18.default.yellow("none pushed")} ${import_picocolors18.default.dim(`(run ${import_picocolors18.default.bold("ablo push")} or ${import_picocolors18.default.bold("ablo dev")})`)}`);
284874
+ console.log(` ${import_picocolors19.default.dim("schema")} ${import_picocolors19.default.yellow("none pushed")} ${import_picocolors19.default.dim(`(run ${import_picocolors19.default.bold("ablo push")} or ${import_picocolors19.default.bold("ablo dev")})`)}`);
284506
284875
  }
284507
284876
  }
284508
284877
  const drift = schemaDrift(await readLocalSchemaHash(), pushed?.hash);
284509
284878
  if (drift) {
284510
284879
  console.log(
284511
- ` ${import_picocolors18.default.dim("drift")} ${import_picocolors18.default.red("\u2717 local schema differs from the server")} ` + import_picocolors18.default.dim(`(local ${drift.local}, server ${drift.server})`)
284880
+ ` ${import_picocolors19.default.dim("drift")} ${import_picocolors19.default.red("\u2717 local schema differs from the server")} ` + import_picocolors19.default.dim(`(local ${drift.local}, server ${drift.server})`)
284512
284881
  );
284513
284882
  }
284514
284883
  const found = blockers({
@@ -284520,33 +284889,33 @@ async function status(args = []) {
284520
284889
  });
284521
284890
  console.log();
284522
284891
  if (found.length > 0) {
284523
- console.log(` ${import_picocolors18.default.red("\u2717")} ${import_picocolors18.default.bold("writes would fail right now")}`);
284892
+ console.log(` ${import_picocolors19.default.red("\u2717")} ${import_picocolors19.default.bold("writes would fail right now")}`);
284524
284893
  for (const b4 of found) {
284525
- console.log(` ${import_picocolors18.default.dim("\xB7")} ${b4.problem}`);
284526
- console.log(` ${import_picocolors18.default.dim(b4.fix)}`);
284894
+ console.log(` ${import_picocolors19.default.dim("\xB7")} ${b4.problem}`);
284895
+ console.log(` ${import_picocolors19.default.dim(b4.fix)}`);
284527
284896
  }
284528
284897
  } else if (dataSource.kind === "unknown") {
284529
284898
  console.log(
284530
- ` ${import_picocolors18.default.yellow("?")} ${import_picocolors18.default.dim("nothing is blocking a write, but this key could not read the plane's databases \u2014 some checks were skipped")}`
284899
+ ` ${import_picocolors19.default.yellow("?")} ${import_picocolors19.default.dim("nothing is blocking a write, but this key could not read the plane's databases \u2014 some checks were skipped")}`
284531
284900
  );
284532
284901
  } else {
284533
- console.log(` ${import_picocolors18.default.green("\u2713")} ${import_picocolors18.default.dim("ready \u2014 a write should succeed")}`);
284902
+ console.log(` ${import_picocolors19.default.green("\u2713")} ${import_picocolors19.default.dim("ready \u2014 a write should succeed")}`);
284534
284903
  }
284535
284904
  console.log();
284536
284905
  }
284537
284906
 
284538
284907
  // src/doctor.ts
284539
284908
  init_cjs_shims();
284540
- var import_picocolors19 = __toESM(require_picocolors(), 1);
284909
+ var import_picocolors20 = __toESM(require_picocolors(), 1);
284541
284910
  init_theme();
284542
284911
  init_controlPlane();
284543
284912
  init_config();
284544
284913
  init_target();
284545
284914
  init_readiness();
284546
284915
  function render(check2) {
284547
- const mark = check2.state === "ok" ? import_picocolors19.default.green("\u2713") : check2.state === "fail" ? import_picocolors19.default.red("\u2717") : import_picocolors19.default.dim("\u2013");
284548
- console.log(` ${mark} ${check2.label.padEnd(10)} ${check2.state === "fail" ? check2.detail : import_picocolors19.default.dim(check2.detail)}`);
284549
- if (check2.fix) console.log(` ${" ".repeat(11)}${import_picocolors19.default.dim(`\u2192 ${check2.fix}`)}`);
284916
+ const mark = check2.state === "ok" ? import_picocolors20.default.green("\u2713") : check2.state === "fail" ? import_picocolors20.default.red("\u2717") : import_picocolors20.default.dim("\u2013");
284917
+ console.log(` ${mark} ${check2.label.padEnd(10)} ${check2.state === "fail" ? check2.detail : import_picocolors20.default.dim(check2.detail)}`);
284918
+ if (check2.fix) console.log(` ${" ".repeat(11)}${import_picocolors20.default.dim(`\u2192 ${check2.fix}`)}`);
284550
284919
  }
284551
284920
  async function ping2(apiUrl3) {
284552
284921
  const ctrl = new AbortController();
@@ -284564,7 +284933,7 @@ async function ping2(apiUrl3) {
284564
284933
  }
284565
284934
  async function doctor() {
284566
284935
  console.log(`
284567
- ${brand("ablo")} ${import_picocolors19.default.dim("doctor")}
284936
+ ${brand("ablo")} ${import_picocolors20.default.dim("doctor")}
284568
284937
  `);
284569
284938
  const apiUrl3 = apiBaseUrl();
284570
284939
  const effective = resolveEffectiveApiKey();
@@ -284679,15 +285048,15 @@ async function doctor() {
284679
285048
  console.log();
284680
285049
  if (failed > 0) {
284681
285050
  console.log(
284682
- ` ${import_picocolors19.default.red("\u2717")} ${import_picocolors19.default.bold(`${failed} problem${failed === 1 ? "" : "s"}`)}` + import_picocolors19.default.dim(skipped > 0 ? `, ${skipped} check${skipped === 1 ? "" : "s"} skipped` : "")
285051
+ ` ${import_picocolors20.default.red("\u2717")} ${import_picocolors20.default.bold(`${failed} problem${failed === 1 ? "" : "s"}`)}` + import_picocolors20.default.dim(skipped > 0 ? `, ${skipped} check${skipped === 1 ? "" : "s"} skipped` : "")
284683
285052
  );
284684
- console.log(import_picocolors19.default.dim(" Fix them in the order above \u2014 an earlier one often explains a later one."));
285053
+ console.log(import_picocolors20.default.dim(" Fix them in the order above \u2014 an earlier one often explains a later one."));
284685
285054
  } else if (skipped > 0) {
284686
285055
  console.log(
284687
- ` ${import_picocolors19.default.yellow("?")} ${import_picocolors19.default.dim(`nothing is blocking a write, but ${skipped} check${skipped === 1 ? "" : "s"} could not be run`)}`
285056
+ ` ${import_picocolors20.default.yellow("?")} ${import_picocolors20.default.dim(`nothing is blocking a write, but ${skipped} check${skipped === 1 ? "" : "s"} could not be run`)}`
284688
285057
  );
284689
285058
  } else {
284690
- console.log(` ${import_picocolors19.default.green("\u2713")} ${import_picocolors19.default.dim("everything checks out \u2014 a write should succeed")}`);
285059
+ console.log(` ${import_picocolors20.default.green("\u2713")} ${import_picocolors20.default.dim("everything checks out \u2014 a write should succeed")}`);
284691
285060
  }
284692
285061
  console.log();
284693
285062
  if (blocking.length > 0 || failed > 0) process.exitCode = 1;
@@ -284695,9 +285064,9 @@ async function doctor() {
284695
285064
 
284696
285065
  // src/logs.ts
284697
285066
  init_cjs_shims();
284698
- var import_errors15 = require("@abloatai/transaction/errors");
284699
- var import_wire8 = require("@abloatai/transaction/wire");
284700
- var import_picocolors20 = __toESM(require_picocolors(), 1);
285067
+ var import_errors16 = require("@abloatai/transaction/errors");
285068
+ var import_wire9 = require("@abloatai/transaction/wire");
285069
+ var import_picocolors21 = __toESM(require_picocolors(), 1);
284701
285070
  init_config();
284702
285071
  init_theme();
284703
285072
  init_controlPlane();
@@ -284740,12 +285109,12 @@ function parseLogsArgs(argv) {
284740
285109
  case "--mode": {
284741
285110
  const raw = argv[++i];
284742
285111
  const m2 = normalizeMode(raw);
284743
- if (!m2) throw new import_errors15.AbloValidationError(`--mode expects "sandbox" or "production", got "${raw}"`, { code: "cli_invalid_arguments" });
285112
+ if (!m2) throw new import_errors16.AbloValidationError(`--mode expects "sandbox" or "production", got "${raw}"`, { code: "cli_invalid_arguments" });
284744
285113
  args.mode = m2;
284745
285114
  break;
284746
285115
  }
284747
285116
  default:
284748
- throw new import_errors15.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
285117
+ throw new import_errors16.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
284749
285118
  }
284750
285119
  }
284751
285120
  return args;
@@ -284764,10 +285133,10 @@ function resolveSince(since) {
284764
285133
  var sleep2 = (ms) => new Promise((r2) => setTimeout(r2, ms));
284765
285134
  function colorOp(op) {
284766
285135
  const label = op.padEnd(6);
284767
- if (op === "create") return import_picocolors20.default.green(label);
284768
- if (op === "update") return import_picocolors20.default.yellow(label);
284769
- if (op === "delete") return import_picocolors20.default.red(label);
284770
- return import_picocolors20.default.dim(label);
285136
+ if (op === "create") return import_picocolors21.default.green(label);
285137
+ if (op === "update") return import_picocolors21.default.yellow(label);
285138
+ if (op === "delete") return import_picocolors21.default.red(label);
285139
+ return import_picocolors21.default.dim(label);
284771
285140
  }
284772
285141
  function render2(e2, json) {
284773
285142
  if (json) {
@@ -284776,21 +285145,21 @@ function render2(e2, json) {
284776
285145
  return;
284777
285146
  }
284778
285147
  const t = new Date(e2.at).toLocaleTimeString();
284779
- const actor = e2.actor ? import_picocolors20.default.dim(` ${e2.actor}`) : "";
284780
- console.log(` ${import_picocolors20.default.dim(t)} ${colorOp(e2.op)} ${import_picocolors20.default.bold(e2.model)} ${import_picocolors20.default.dim(e2.recordId)}${actor}`);
285148
+ const actor = e2.actor ? import_picocolors21.default.dim(` ${e2.actor}`) : "";
285149
+ console.log(` ${import_picocolors21.default.dim(t)} ${colorOp(e2.op)} ${import_picocolors21.default.bold(e2.model)} ${import_picocolors21.default.dim(e2.recordId)}${actor}`);
284781
285150
  }
284782
285151
  async function logs(argv) {
284783
285152
  let args;
284784
285153
  try {
284785
285154
  args = parseLogsArgs(argv);
284786
285155
  } catch (err) {
284787
- console.error(import_picocolors20.default.red(` ${err instanceof Error ? err.message : String(err)}`));
285156
+ console.error(import_picocolors21.default.red(` ${err instanceof Error ? err.message : String(err)}`));
284788
285157
  process.exit(1);
284789
285158
  }
284790
285159
  const apiKey = resolveApiKey(args.mode);
284791
285160
  if (!apiKey) {
284792
285161
  console.error(
284793
- import_picocolors20.default.red(` No API key.`) + import_picocolors20.default.dim(` Run ${import_picocolors20.default.bold("ablo login")} or set ${import_picocolors20.default.bold("ABLO_API_KEY")}.`)
285162
+ import_picocolors21.default.red(` No API key.`) + import_picocolors21.default.dim(` Run ${import_picocolors21.default.bold("ablo login")} or set ${import_picocolors21.default.bold("ABLO_API_KEY")}.`)
284794
285163
  );
284795
285164
  process.exit(1);
284796
285165
  }
@@ -284804,18 +285173,18 @@ async function logs(argv) {
284804
285173
  if (!res) return null;
284805
285174
  if (!res.ok) {
284806
285175
  const body = await res.json().catch(() => ({}));
284807
- console.error(import_picocolors20.default.red(` logs failed (${res.status}): ${body.reason ?? body.message ?? ""}`));
285176
+ console.error(import_picocolors21.default.red(` logs failed (${res.status}): ${body.reason ?? body.message ?? ""}`));
284808
285177
  process.exit(1);
284809
285178
  }
284810
285179
  const json = await res.json();
284811
285180
  return {
284812
285181
  events: json.data ?? json.events ?? [],
284813
- cursor: json.next_cursor ?? (json.cursor != null ? (0, import_wire8.formatFeedCursor)({ log: json.cursor, claims: 0 }) : (0, import_wire8.formatFeedCursor)(import_wire8.FEED_CURSOR_START))
285182
+ cursor: json.next_cursor ?? (json.cursor != null ? (0, import_wire9.formatFeedCursor)({ log: json.cursor, claims: 0 }) : (0, import_wire9.formatFeedCursor)(import_wire9.FEED_CURSOR_START))
284814
285183
  };
284815
285184
  }
284816
285185
  if (!args.json) {
284817
285186
  console.log(`
284818
- ${brand("ablo")} ${import_picocolors20.default.dim("logs")} ${import_picocolors20.default.dim(`(${args.mode ?? "active"} mode)`)}
285187
+ ${brand("ablo")} ${import_picocolors21.default.dim("logs")} ${import_picocolors21.default.dim(`(${args.mode ?? "active"} mode)`)}
284819
285188
  `);
284820
285189
  }
284821
285190
  const initial = await fetchPage({
@@ -284825,13 +285194,13 @@ async function logs(argv) {
284825
285194
  ...args.op ? { op: args.op } : {}
284826
285195
  });
284827
285196
  if (!initial) {
284828
- console.error(import_picocolors20.default.red(` Couldn't reach ${baseUrl2}.`));
285197
+ console.error(import_picocolors21.default.red(` Couldn't reach ${baseUrl2}.`));
284829
285198
  process.exit(1);
284830
285199
  }
284831
285200
  for (const e2 of initial.events) render2(e2, args.json);
284832
285201
  let cursor = initial.cursor;
284833
285202
  if (!args.follow) return;
284834
- if (!args.json) console.log(` ${import_picocolors20.default.dim("watching for new activity \u2026 (Ctrl-C to stop)")}
285203
+ if (!args.json) console.log(` ${import_picocolors21.default.dim("watching for new activity \u2026 (Ctrl-C to stop)")}
284835
285204
  `);
284836
285205
  for (; ; ) {
284837
285206
  await sleep2(1500);
@@ -284842,16 +285211,16 @@ async function logs(argv) {
284842
285211
  });
284843
285212
  if (!page) continue;
284844
285213
  for (const e2 of page.events) render2(e2, args.json);
284845
- const prev = (0, import_wire8.parseFeedCursor)(cursor);
284846
- const next = (0, import_wire8.parseFeedCursor)(page.cursor);
284847
- if (prev && next && (0, import_wire8.feedCursorAdvanced)(prev, next)) cursor = page.cursor;
285214
+ const prev = (0, import_wire9.parseFeedCursor)(cursor);
285215
+ const next = (0, import_wire9.parseFeedCursor)(page.cursor);
285216
+ if (prev && next && (0, import_wire9.feedCursorAdvanced)(prev, next)) cursor = page.cursor;
284848
285217
  }
284849
285218
  }
284850
285219
 
284851
285220
  // src/webhooks.ts
284852
285221
  init_cjs_shims();
284853
285222
  var import_fs9 = require("fs");
284854
- var import_picocolors21 = __toESM(require_picocolors(), 1);
285223
+ var import_picocolors22 = __toESM(require_picocolors(), 1);
284855
285224
  var import_credentialPolicy4 = require("@abloatai/transaction/auth/credentialPolicy");
284856
285225
  init_config();
284857
285226
  init_theme();
@@ -284884,12 +285253,12 @@ function requireKey3(mode) {
284884
285253
  const apiKey = resolveApiKey(mode);
284885
285254
  if (!apiKey) {
284886
285255
  console.error(
284887
- import_picocolors21.default.red(" No API key.") + import_picocolors21.default.dim(` Run ${import_picocolors21.default.bold("ablo login")} or set ${import_picocolors21.default.bold("ABLO_API_KEY")}.`)
285256
+ import_picocolors22.default.red(" No API key.") + import_picocolors22.default.dim(` Run ${import_picocolors22.default.bold("ablo login")} or set ${import_picocolors22.default.bold("ABLO_API_KEY")}.`)
284888
285257
  );
284889
285258
  process.exit(1);
284890
285259
  }
284891
285260
  if ((0, import_credentialPolicy4.classifyCredentialKind)(apiKey) !== "secret") {
284892
- console.error(import_picocolors21.default.red(" Managing webhooks requires a secret key ") + import_picocolors21.default.dim("(sk_test_ / sk_live_)."));
285261
+ console.error(import_picocolors22.default.red(" Managing webhooks requires a secret key ") + import_picocolors22.default.dim("(sk_test_ / sk_live_)."));
284893
285262
  process.exit(1);
284894
285263
  }
284895
285264
  return apiKey;
@@ -284905,12 +285274,12 @@ async function api(apiKey, method, path, body) {
284905
285274
  ...body ? { body: JSON.stringify(body) } : {}
284906
285275
  }).catch(() => null);
284907
285276
  if (!res) {
284908
- console.error(import_picocolors21.default.red(` Couldn't reach ${baseUrl()}.`));
285277
+ console.error(import_picocolors22.default.red(` Couldn't reach ${baseUrl()}.`));
284909
285278
  process.exit(1);
284910
285279
  }
284911
285280
  if (!res.ok) {
284912
285281
  const err = await res.json().catch(() => ({}));
284913
- console.error(import_picocolors21.default.red(` Request failed (${res.status}): ${err.message ?? err.reason ?? ""}`));
285282
+ console.error(import_picocolors22.default.red(` Request failed (${res.status}): ${err.message ?? err.reason ?? ""}`));
284914
285283
  process.exit(1);
284915
285284
  }
284916
285285
  return await res.json();
@@ -284932,11 +285301,11 @@ ${line}
284932
285301
  return file;
284933
285302
  }
284934
285303
  function printEndpoint(e2) {
284935
- const dot = e2.status === "enabled" ? import_picocolors21.default.green("\u25CF") : import_picocolors21.default.red("\u25CF");
284936
- const health = e2.last_error ? import_picocolors21.default.red(` last error: ${e2.last_error}`) : "";
284937
- console.log(` ${dot} ${import_picocolors21.default.bold(e2.id)} ${e2.url}`);
285304
+ const dot = e2.status === "enabled" ? import_picocolors22.default.green("\u25CF") : import_picocolors22.default.red("\u25CF");
285305
+ const health = e2.last_error ? import_picocolors22.default.red(` last error: ${e2.last_error}`) : "";
285306
+ console.log(` ${dot} ${import_picocolors22.default.bold(e2.id)} ${e2.url}`);
284938
285307
  console.log(
284939
- import_picocolors21.default.dim(
285308
+ import_picocolors22.default.dim(
284940
285309
  ` ${e2.status} \xB7 ${e2.environment} \xB7 events ${e2.enabled_events.join(",")} \xB7 cursor ${e2.cursor ?? "\u2014"}${health}`
284941
285310
  )
284942
285311
  );
@@ -284948,7 +285317,7 @@ async function webhooks(argv) {
284948
285317
  if (sub === "create") {
284949
285318
  const url = positional(rest);
284950
285319
  if (!url) {
284951
- console.error(import_picocolors21.default.red(" Usage: ") + brand("ablo webhooks create <url>"));
285320
+ console.error(import_picocolors22.default.red(" Usage: ") + brand("ablo webhooks create <url>"));
284952
285321
  process.exit(1);
284953
285322
  }
284954
285323
  const apiKey = requireKey3(mode);
@@ -284960,8 +285329,8 @@ async function webhooks(argv) {
284960
285329
  });
284961
285330
  const file = writeSecretToEnv(created.secret);
284962
285331
  console.log(`
284963
- ${import_picocolors21.default.green("\u2713")} Registered ${import_picocolors21.default.bold(created.id)} \u2192 ${created.url}`);
284964
- console.log(` ${import_picocolors21.default.green("\u2713")} Wrote ${import_picocolors21.default.bold(ENV_KEY)} to ${import_picocolors21.default.bold(file)} ${import_picocolors21.default.dim("(shown once)")}
285332
+ ${import_picocolors22.default.green("\u2713")} Registered ${import_picocolors22.default.bold(created.id)} \u2192 ${created.url}`);
285333
+ console.log(` ${import_picocolors22.default.green("\u2713")} Wrote ${import_picocolors22.default.bold(ENV_KEY)} to ${import_picocolors22.default.bold(file)} ${import_picocolors22.default.dim("(shown once)")}
284965
285334
  `);
284966
285335
  return;
284967
285336
  }
@@ -284969,7 +285338,7 @@ async function webhooks(argv) {
284969
285338
  const apiKey = requireKey3(mode);
284970
285339
  const { data } = await api(apiKey, "GET", "");
284971
285340
  if (data.length === 0) {
284972
- console.log(import_picocolors21.default.dim(" No webhook endpoints. ") + brand("ablo webhooks create <url>"));
285341
+ console.log(import_picocolors22.default.dim(" No webhook endpoints. ") + brand("ablo webhooks create <url>"));
284973
285342
  return;
284974
285343
  }
284975
285344
  console.log();
@@ -284980,40 +285349,40 @@ async function webhooks(argv) {
284980
285349
  if (sub === "roll") {
284981
285350
  const id = positional(rest);
284982
285351
  if (!id) {
284983
- console.error(import_picocolors21.default.red(" Usage: ") + brand("ablo webhooks roll <id>"));
285352
+ console.error(import_picocolors22.default.red(" Usage: ") + brand("ablo webhooks roll <id>"));
284984
285353
  process.exit(1);
284985
285354
  }
284986
285355
  const apiKey = requireKey3(mode);
284987
285356
  const rolled = await api(apiKey, "POST", `/${id}/roll_secret`);
284988
285357
  const file = writeSecretToEnv(rolled.secret);
284989
285358
  console.log(`
284990
- ${import_picocolors21.default.green("\u2713")} Rolled secret for ${import_picocolors21.default.bold(id)} \u2192 ${import_picocolors21.default.bold(file)} ${import_picocolors21.default.dim("(old secret now invalid)")}
285359
+ ${import_picocolors22.default.green("\u2713")} Rolled secret for ${import_picocolors22.default.bold(id)} \u2192 ${import_picocolors22.default.bold(file)} ${import_picocolors22.default.dim("(old secret now invalid)")}
284991
285360
  `);
284992
285361
  return;
284993
285362
  }
284994
285363
  if (sub === "enable") {
284995
285364
  const id = positional(rest);
284996
285365
  if (!id) {
284997
- console.error(import_picocolors21.default.red(" Usage: ") + brand("ablo webhooks enable <id>"));
285366
+ console.error(import_picocolors22.default.red(" Usage: ") + brand("ablo webhooks enable <id>"));
284998
285367
  process.exit(1);
284999
285368
  }
285000
285369
  const apiKey = requireKey3(mode);
285001
285370
  const e2 = await api(apiKey, "POST", `/${id}/enable`);
285002
- console.log(` ${import_picocolors21.default.green("\u2713")} Re-enabled ${import_picocolors21.default.bold(e2.id)}`);
285371
+ console.log(` ${import_picocolors22.default.green("\u2713")} Re-enabled ${import_picocolors22.default.bold(e2.id)}`);
285003
285372
  return;
285004
285373
  }
285005
285374
  if (sub === "rm" || sub === "delete") {
285006
285375
  const id = positional(rest);
285007
285376
  if (!id) {
285008
- console.error(import_picocolors21.default.red(" Usage: ") + brand("ablo webhooks rm <id>"));
285377
+ console.error(import_picocolors22.default.red(" Usage: ") + brand("ablo webhooks rm <id>"));
285009
285378
  process.exit(1);
285010
285379
  }
285011
285380
  const apiKey = requireKey3(mode);
285012
285381
  await api(apiKey, "DELETE", `/${id}`);
285013
- console.log(` ${import_picocolors21.default.green("\u2713")} Removed ${import_picocolors21.default.bold(id)}`);
285382
+ console.log(` ${import_picocolors22.default.green("\u2713")} Removed ${import_picocolors22.default.bold(id)}`);
285014
285383
  return;
285015
285384
  }
285016
- console.log(` ${import_picocolors21.default.bold("Usage:")}`);
285385
+ console.log(` ${import_picocolors22.default.bold("Usage:")}`);
285017
285386
  console.log(` ${brand("ablo webhooks create <url>")} Register an endpoint; writes ${ENV_KEY}`);
285018
285387
  console.log(` ${brand("ablo webhooks list")} List endpoints + delivery health`);
285019
285388
  console.log(` ${brand("ablo webhooks roll <id>")} Mint a fresh signing secret`);
@@ -285024,8 +285393,8 @@ async function webhooks(argv) {
285024
285393
 
285025
285394
  // src/check.ts
285026
285395
  init_cjs_shims();
285027
- var import_errors16 = require("@abloatai/transaction/errors");
285028
- var import_picocolors22 = __toESM(require_picocolors(), 1);
285396
+ var import_errors17 = require("@abloatai/transaction/errors");
285397
+ var import_picocolors23 = __toESM(require_picocolors(), 1);
285029
285398
  init_src();
285030
285399
  var import_schema9 = require("@abloatai/transaction/schema");
285031
285400
  init_push();
@@ -285172,7 +285541,7 @@ function parseCheckArgs(argv) {
285172
285541
  appSchema = argv[++i] ?? appSchema;
285173
285542
  break;
285174
285543
  default:
285175
- throw new import_errors16.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
285544
+ throw new import_errors17.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
285176
285545
  }
285177
285546
  }
285178
285547
  return { schemaPath, exportName, appSchema };
@@ -285186,22 +285555,22 @@ function hostOf(connectionString) {
285186
285555
  }
285187
285556
  async function reportReadSubject(dbUrl) {
285188
285557
  const host = hostOf(dbUrl);
285189
- console.log(` ${import_picocolors22.default.dim("reading")} ${import_picocolors22.default.bold(host ?? "your database")}`);
285558
+ console.log(` ${import_picocolors23.default.dim("reading")} ${import_picocolors23.default.bold(host ?? "your database")}`);
285190
285559
  const effective = resolveEffectiveApiKey();
285191
285560
  const state = await fetchDataSourceState(apiBaseUrl(), effective.key);
285192
285561
  if (state.kind === "unknown") {
285193
285562
  console.log(
285194
- ` ${import_picocolors22.default.dim("ablo")} ${import_picocolors22.default.yellow("?")} ${import_picocolors22.default.dim(`couldn't ask which database Ablo reads (${state.detail})`)}
285563
+ ` ${import_picocolors23.default.dim("ablo")} ${import_picocolors23.default.yellow("?")} ${import_picocolors23.default.dim(`couldn't ask which database Ablo reads (${state.detail})`)}
285195
285564
  `
285196
285565
  );
285197
285566
  return;
285198
285567
  }
285199
285568
  if (state.kind === "none") {
285200
285569
  console.log(
285201
- ` ${import_picocolors22.default.dim("ablo")} ${import_picocolors22.default.yellow("!")} no database is registered for this plane, so Ablo does not read this one`
285570
+ ` ${import_picocolors23.default.dim("ablo")} ${import_picocolors23.default.yellow("!")} no database is registered for this plane, so Ablo does not read this one`
285202
285571
  );
285203
285572
  console.log(
285204
- ` ${import_picocolors22.default.dim(`Connect it with ${import_picocolors22.default.bold("ablo connect apply")}. Until then a table here is invisible to the engine.`)}
285573
+ ` ${import_picocolors23.default.dim(`Connect it with ${import_picocolors23.default.bold("ablo connect apply")}. Until then a table here is invisible to the engine.`)}
285205
285574
  `
285206
285575
  );
285207
285576
  return;
@@ -285209,15 +285578,15 @@ async function reportReadSubject(dbUrl) {
285209
285578
  const registered = [...new Set(state.hosts)];
285210
285579
  if (host && registered.length > 0 && !registered.includes(host)) {
285211
285580
  console.log(
285212
- ` ${import_picocolors22.default.dim("ablo")} ${import_picocolors22.default.yellow("!")} Ablo reads ${import_picocolors22.default.bold(registered.join(", "))}`
285581
+ ` ${import_picocolors23.default.dim("ablo")} ${import_picocolors23.default.yellow("!")} Ablo reads ${import_picocolors23.default.bold(registered.join(", "))}`
285213
285582
  );
285214
285583
  console.log(
285215
- ` ${import_picocolors22.default.dim("If that is this database under a pooled hostname, this is fine \u2014 otherwise the report below describes a database Ablo never reads.")}
285584
+ ` ${import_picocolors23.default.dim("If that is this database under a pooled hostname, this is fine \u2014 otherwise the report below describes a database Ablo never reads.")}
285216
285585
  `
285217
285586
  );
285218
285587
  return;
285219
285588
  }
285220
- console.log(` ${import_picocolors22.default.dim("ablo")} ${import_picocolors22.default.green("\u2713")} ${import_picocolors22.default.dim("reads this database")}
285589
+ console.log(` ${import_picocolors23.default.dim("ablo")} ${import_picocolors23.default.green("\u2713")} ${import_picocolors23.default.dim("reads this database")}
285221
285590
  `);
285222
285591
  }
285223
285592
  async function check(argv) {
@@ -285225,20 +285594,20 @@ async function check(argv) {
285225
285594
  try {
285226
285595
  args = parseCheckArgs(argv);
285227
285596
  } catch (err) {
285228
- console.error(import_picocolors22.default.red(` ${err instanceof Error ? err.message : String(err)}`));
285597
+ console.error(import_picocolors23.default.red(` ${err instanceof Error ? err.message : String(err)}`));
285229
285598
  process.exit(1);
285230
285599
  }
285231
285600
  const dbUrl = readProjectAdminDatabaseUrl();
285232
285601
  if (!dbUrl) {
285233
285602
  console.error(
285234
- import_picocolors22.default.red(` No database.`) + import_picocolors22.default.dim(` Set ${import_picocolors22.default.bold(ADMIN_URL_VAR)} to the Postgres you want Ablo to adopt.`)
285603
+ import_picocolors23.default.red(` No database.`) + import_picocolors23.default.dim(` Set ${import_picocolors23.default.bold(ADMIN_URL_VAR)} to the Postgres you want Ablo to adopt.`)
285235
285604
  );
285236
285605
  process.exit(1);
285237
285606
  }
285238
285607
  const schema = await loadSchema(args.schemaPath, args.exportName);
285239
285608
  const schemaJson = JSON.parse((0, import_schema9.serializeSchema)(schema));
285240
285609
  console.log(`
285241
- ${brand("ablo")} ${import_picocolors22.default.dim("check")} ${import_picocolors22.default.dim(`schema "${args.appSchema}"`)}
285610
+ ${brand("ablo")} ${import_picocolors23.default.dim("check")} ${import_picocolors23.default.dim(`schema "${args.appSchema}"`)}
285242
285611
  `);
285243
285612
  await reportReadSubject(dbUrl);
285244
285613
  const sql = src_default(dbUrl, { max: 1, prepare: false, onnotice: () => {
@@ -285250,7 +285619,7 @@ async function check(argv) {
285250
285619
  [args.appSchema]
285251
285620
  );
285252
285621
  } catch (err) {
285253
- console.error(import_picocolors22.default.red(` Couldn't read the database: ${err instanceof Error ? err.message : String(err)}`));
285622
+ console.error(import_picocolors23.default.red(` Couldn't read the database: ${err instanceof Error ? err.message : String(err)}`));
285254
285623
  await sql.end({ timeout: 2 });
285255
285624
  process.exit(1);
285256
285625
  }
@@ -285272,7 +285641,7 @@ async function check(argv) {
285272
285641
  declaredTables.add(table);
285273
285642
  const present = colsByTable.get(table);
285274
285643
  if (!present) {
285275
- console.log(` ${import_picocolors22.default.red("\u2717")} ${import_picocolors22.default.bold(key)} ${import_picocolors22.default.dim("\u2192")} table ${import_picocolors22.default.bold(table)} ${import_picocolors22.default.red("not found")}`);
285644
+ console.log(` ${import_picocolors23.default.red("\u2717")} ${import_picocolors23.default.bold(key)} ${import_picocolors23.default.dim("\u2192")} table ${import_picocolors23.default.bold(table)} ${import_picocolors23.default.red("not found")}`);
285276
285645
  errors++;
285277
285646
  continue;
285278
285647
  }
@@ -285294,26 +285663,26 @@ async function check(argv) {
285294
285663
  if (!present.has(col)) problems.push(`missing column "${col}" (field ${fieldName})`);
285295
285664
  }
285296
285665
  if (problems.length > 0) {
285297
- console.log(` ${import_picocolors22.default.red("\u2717")} ${import_picocolors22.default.bold(key)} ${import_picocolors22.default.dim("\u2192")} ${table}`);
285298
- for (const p2 of problems) console.log(` ${import_picocolors22.default.red("\u2022")} ${p2}`);
285299
- for (const w2 of warns) console.log(` ${import_picocolors22.default.yellow("\u2022")} ${w2}`);
285666
+ console.log(` ${import_picocolors23.default.red("\u2717")} ${import_picocolors23.default.bold(key)} ${import_picocolors23.default.dim("\u2192")} ${table}`);
285667
+ for (const p2 of problems) console.log(` ${import_picocolors23.default.red("\u2022")} ${p2}`);
285668
+ for (const w2 of warns) console.log(` ${import_picocolors23.default.yellow("\u2022")} ${w2}`);
285300
285669
  errors++;
285301
285670
  } else if (warns.length > 0) {
285302
- console.log(` ${import_picocolors22.default.yellow("!")} ${import_picocolors22.default.bold(key)} ${import_picocolors22.default.dim("\u2192")} ${table}`);
285303
- for (const w2 of warns) console.log(` ${import_picocolors22.default.yellow("\u2022")} ${w2}`);
285671
+ console.log(` ${import_picocolors23.default.yellow("!")} ${import_picocolors23.default.bold(key)} ${import_picocolors23.default.dim("\u2192")} ${table}`);
285672
+ for (const w2 of warns) console.log(` ${import_picocolors23.default.yellow("\u2022")} ${w2}`);
285304
285673
  warnings++;
285305
285674
  } else {
285306
- console.log(` ${import_picocolors22.default.green("\u2713")} ${import_picocolors22.default.bold(key)} ${import_picocolors22.default.dim(`\u2192 ${table} (id, ${orgCol ?? "no org"} ok)`)}`);
285675
+ console.log(` ${import_picocolors23.default.green("\u2713")} ${import_picocolors23.default.bold(key)} ${import_picocolors23.default.dim(`\u2192 ${table} (id, ${orgCol ?? "no org"} ok)`)}`);
285307
285676
  }
285308
285677
  }
285309
285678
  const modelCount = Object.keys(schemaJson.models).length;
285310
285679
  const ignored = [...colsByTable.keys()].filter((t) => !declaredTables.has(t)).length;
285311
285680
  console.log(
285312
285681
  `
285313
- ${modelCount} model${modelCount === 1 ? "" : "s"} \xB7 ${import_picocolors22.default.green(`${modelCount - errors - warnings} ok`)}` + (warnings ? ` \xB7 ${import_picocolors22.default.yellow(`${warnings} warning${warnings === 1 ? "" : "s"}`)}` : "") + (errors ? ` \xB7 ${import_picocolors22.default.red(`${errors} error${errors === 1 ? "" : "s"}`)}` : "")
285682
+ ${modelCount} model${modelCount === 1 ? "" : "s"} \xB7 ${import_picocolors23.default.green(`${modelCount - errors - warnings} ok`)}` + (warnings ? ` \xB7 ${import_picocolors23.default.yellow(`${warnings} warning${warnings === 1 ? "" : "s"}`)}` : "") + (errors ? ` \xB7 ${import_picocolors23.default.red(`${errors} error${errors === 1 ? "" : "s"}`)}` : "")
285314
285683
  );
285315
285684
  if (ignored > 0) {
285316
- console.log(` ${import_picocolors22.default.dim(`${ignored} other table${ignored === 1 ? "" : "s"} in your database \u2014 ignored by Ablo`)}`);
285685
+ console.log(` ${import_picocolors23.default.dim(`${ignored} other table${ignored === 1 ? "" : "s"} in your database \u2014 ignored by Ablo`)}`);
285317
285686
  }
285318
285687
  console.log();
285319
285688
  process.exit(errors > 0 ? 1 : 0);
@@ -285324,7 +285693,7 @@ init_dbRole();
285324
285693
 
285325
285694
  // src/upgrade.ts
285326
285695
  init_cjs_shims();
285327
- var import_picocolors23 = __toESM(require_picocolors(), 1);
285696
+ var import_picocolors24 = __toESM(require_picocolors(), 1);
285328
285697
  var import_ts_morph = __toESM(require_ts_morph(), 1);
285329
285698
  var DEFAULT_GLOBS = ["app/**/*.{ts,tsx}", "src/**/*.{ts,tsx}", "ablo/**/*.{ts,tsx}", "lib/**/*.{ts,tsx}"];
285330
285699
  var VERB_ARGS = {
@@ -285402,7 +285771,7 @@ async function upgrade(argv) {
285402
285771
  project.addSourceFilesAtPaths(globs.length > 0 ? globs : DEFAULT_GLOBS);
285403
285772
  const files = project.getSourceFiles();
285404
285773
  if (files.length === 0) {
285405
- console.log(import_picocolors23.default.yellow(' No .ts/.tsx files found. Pass a glob, e.g. `ablo upgrade "src/**/*.tsx"`.'));
285774
+ console.log(import_picocolors24.default.yellow(' No .ts/.tsx files found. Pass a glob, e.g. `ablo upgrade "src/**/*.tsx"`.'));
285406
285775
  return;
285407
285776
  }
285408
285777
  const edits = [];
@@ -285476,39 +285845,39 @@ async function upgrade(argv) {
285476
285845
  const rel = (f) => f.replace(cwd + "/", "");
285477
285846
  console.log();
285478
285847
  if (edits.length === 0 && manual.length === 0) {
285479
- console.log(import_picocolors23.default.green(" \u2713 Nothing to migrate \u2014 your code is already on the current API."));
285848
+ console.log(import_picocolors24.default.green(" \u2713 Nothing to migrate \u2014 your code is already on the current API."));
285480
285849
  return;
285481
285850
  }
285482
285851
  if (edits.length > 0) {
285483
- console.log(import_picocolors23.default.bold(` ${write ? "Applied" : "Would apply"} ${edits.length} change${edits.length === 1 ? "" : "s"}:`));
285852
+ console.log(import_picocolors24.default.bold(` ${write ? "Applied" : "Would apply"} ${edits.length} change${edits.length === 1 ? "" : "s"}:`));
285484
285853
  for (const e2 of edits) {
285485
- console.log(` ${import_picocolors23.default.dim(`${rel(e2.file)}:${e2.line}`)} ${import_picocolors23.default.cyan(e2.rule)}`);
285486
- console.log(` ${import_picocolors23.default.red("-")} ${e2.before}`);
285487
- console.log(` ${import_picocolors23.default.green("+")} ${e2.after}`);
285854
+ console.log(` ${import_picocolors24.default.dim(`${rel(e2.file)}:${e2.line}`)} ${import_picocolors24.default.cyan(e2.rule)}`);
285855
+ console.log(` ${import_picocolors24.default.red("-")} ${e2.before}`);
285856
+ console.log(` ${import_picocolors24.default.green("+")} ${e2.after}`);
285488
285857
  }
285489
285858
  }
285490
285859
  if (manual.length > 0) {
285491
285860
  console.log();
285492
- console.log(import_picocolors23.default.bold(import_picocolors23.default.yellow(` ${manual.length} spot${manual.length === 1 ? "" : "s"} need manual review (structural):`)));
285861
+ console.log(import_picocolors24.default.bold(import_picocolors24.default.yellow(` ${manual.length} spot${manual.length === 1 ? "" : "s"} need manual review (structural):`)));
285493
285862
  for (const m2 of manual) {
285494
- console.log(` ${import_picocolors23.default.dim(`${rel(m2.file)}:${m2.line}`)} ${import_picocolors23.default.yellow(m2.rule)}`);
285495
- console.log(` ${import_picocolors23.default.dim(m2.snippet)}`);
285863
+ console.log(` ${import_picocolors24.default.dim(`${rel(m2.file)}:${m2.line}`)} ${import_picocolors24.default.yellow(m2.rule)}`);
285864
+ console.log(` ${import_picocolors24.default.dim(m2.snippet)}`);
285496
285865
  console.log(` \u2192 ${m2.hint}`);
285497
285866
  }
285498
285867
  }
285499
285868
  console.log();
285500
285869
  if (write) {
285501
285870
  await project.save();
285502
- console.log(import_picocolors23.default.green(` \u2713 Wrote ${edits.length} change${edits.length === 1 ? "" : "s"}. Review the diff, run your typecheck.`));
285871
+ console.log(import_picocolors24.default.green(` \u2713 Wrote ${edits.length} change${edits.length === 1 ? "" : "s"}. Review the diff, run your typecheck.`));
285503
285872
  } else {
285504
- console.log(import_picocolors23.default.dim(" Dry run. Re-run with `--write` to apply the auto-fixes above (manual items are never auto-written)."));
285873
+ console.log(import_picocolors24.default.dim(" Dry run. Re-run with `--write` to apply the auto-fixes above (manual items are never auto-written)."));
285505
285874
  }
285506
285875
  }
285507
285876
 
285508
285877
  // src/pull.ts
285509
285878
  init_cjs_shims();
285510
- var import_errors17 = require("@abloatai/transaction/errors");
285511
- var import_picocolors24 = __toESM(require_picocolors(), 1);
285879
+ var import_errors18 = require("@abloatai/transaction/errors");
285880
+ var import_picocolors25 = __toESM(require_picocolors(), 1);
285512
285881
  init_src();
285513
285882
  var import_fs10 = require("fs");
285514
285883
  init_theme();
@@ -285536,7 +285905,7 @@ function parsePullArgs(argv) {
285536
285905
  force = true;
285537
285906
  break;
285538
285907
  default:
285539
- throw new import_errors17.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
285908
+ throw new import_errors18.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
285540
285909
  }
285541
285910
  }
285542
285911
  return { out, appSchema, importPath, force };
@@ -285606,56 +285975,56 @@ async function pull(argv) {
285606
285975
  try {
285607
285976
  args = parsePullArgs(argv);
285608
285977
  } catch (err) {
285609
- console.error(import_picocolors24.default.red(` ${err instanceof Error ? err.message : String(err)}`));
285978
+ console.error(import_picocolors25.default.red(` ${err instanceof Error ? err.message : String(err)}`));
285610
285979
  process.exit(1);
285611
285980
  }
285612
285981
  const dbUrl = readProjectAdminDatabaseUrl();
285613
285982
  if (!dbUrl) {
285614
285983
  console.error(
285615
- import_picocolors24.default.red(` No database.`) + import_picocolors24.default.dim(` Set ${import_picocolors24.default.bold(ADMIN_URL_VAR)} to the Postgres to pull from.`)
285984
+ import_picocolors25.default.red(` No database.`) + import_picocolors25.default.dim(` Set ${import_picocolors25.default.bold(ADMIN_URL_VAR)} to the Postgres to pull from.`)
285616
285985
  );
285617
285986
  process.exit(1);
285618
285987
  }
285619
285988
  if ((0, import_fs10.existsSync)(args.out) && !args.force) {
285620
285989
  console.error(
285621
- import_picocolors24.default.red(` ${args.out} already exists.`) + import_picocolors24.default.dim(` Re-run with ${import_picocolors24.default.bold("--force")} to overwrite.`)
285990
+ import_picocolors25.default.red(` ${args.out} already exists.`) + import_picocolors25.default.dim(` Re-run with ${import_picocolors25.default.bold("--force")} to overwrite.`)
285622
285991
  );
285623
285992
  process.exit(1);
285624
285993
  }
285625
285994
  console.log(`
285626
- ${brand("ablo")} ${import_picocolors24.default.dim("pull")} ${import_picocolors24.default.dim(`schema "${args.appSchema}"`)}
285995
+ ${brand("ablo")} ${import_picocolors25.default.dim("pull")} ${import_picocolors25.default.dim(`schema "${args.appSchema}"`)}
285627
285996
  `);
285628
285997
  let result;
285629
285998
  try {
285630
285999
  result = await buildSchemaSourceFromDb({ dbUrl, appSchema: args.appSchema, importPath: args.importPath });
285631
286000
  } catch (err) {
285632
- console.error(import_picocolors24.default.red(` Couldn't read the database: ${err instanceof Error ? err.message : String(err)}`));
286001
+ console.error(import_picocolors25.default.red(` Couldn't read the database: ${err instanceof Error ? err.message : String(err)}`));
285633
286002
  process.exit(1);
285634
286003
  }
285635
286004
  if (result.models.length === 0) {
285636
286005
  console.error(
285637
- import_picocolors24.default.yellow(` No adoptable tables found`) + import_picocolors24.default.dim(` (a model needs an ${import_picocolors24.default.bold("id")} + ${import_picocolors24.default.bold("organization_id")} column).`)
286006
+ import_picocolors25.default.yellow(` No adoptable tables found`) + import_picocolors25.default.dim(` (a model needs an ${import_picocolors25.default.bold("id")} + ${import_picocolors25.default.bold("organization_id")} column).`)
285638
286007
  );
285639
286008
  process.exit(1);
285640
286009
  }
285641
286010
  (0, import_fs10.writeFileSync)(args.out, result.source);
285642
- console.log(` ${import_picocolors24.default.green("\u2713")} wrote ${import_picocolors24.default.bold(args.out)} ${import_picocolors24.default.dim(`(${result.models.length} models)`)}`);
285643
- console.log(` ${import_picocolors24.default.dim(`models: ${result.models.join(", ")}`)}`);
286011
+ console.log(` ${import_picocolors25.default.green("\u2713")} wrote ${import_picocolors25.default.bold(args.out)} ${import_picocolors25.default.dim(`(${result.models.length} models)`)}`);
286012
+ console.log(` ${import_picocolors25.default.dim(`models: ${result.models.join(", ")}`)}`);
285644
286013
  if (result.skipped.length > 0) {
285645
- console.log(` ${import_picocolors24.default.dim(`${result.skipped.length} table(s) skipped:`)}`);
285646
- for (const s of result.skipped) console.log(` ${import_picocolors24.default.dim(`- ${s.name}: ${s.reason}`)}`);
286014
+ console.log(` ${import_picocolors25.default.dim(`${result.skipped.length} table(s) skipped:`)}`);
286015
+ for (const s of result.skipped) console.log(` ${import_picocolors25.default.dim(`- ${s.name}: ${s.reason}`)}`);
285647
286016
  }
285648
286017
  console.log(
285649
286018
  `
285650
- ${import_picocolors24.default.dim("Introspection is lossy (enums, JSON shape, relations). Review the file, then")} ${import_picocolors24.default.bold("ablo check")}.
286019
+ ${import_picocolors25.default.dim("Introspection is lossy (enums, JSON shape, relations). Review the file, then")} ${import_picocolors25.default.bold("ablo check")}.
285651
286020
  `
285652
286021
  );
285653
286022
  }
285654
286023
 
285655
286024
  // src/prismaPull.ts
285656
286025
  init_cjs_shims();
285657
- var import_errors18 = require("@abloatai/transaction/errors");
285658
- var import_picocolors25 = __toESM(require_picocolors(), 1);
286026
+ var import_errors19 = require("@abloatai/transaction/errors");
286027
+ var import_picocolors26 = __toESM(require_picocolors(), 1);
285659
286028
  var import_fs11 = require("fs");
285660
286029
  init_theme();
285661
286030
  var DEFAULT_SCHEMA = "prisma/schema.prisma";
@@ -285852,7 +286221,7 @@ function parsePrismaPullArgs(argv) {
285852
286221
  force = true;
285853
286222
  break;
285854
286223
  default:
285855
- if (arg.startsWith("--")) throw new import_errors18.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
286224
+ if (arg.startsWith("--")) throw new import_errors19.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
285856
286225
  schema = arg;
285857
286226
  }
285858
286227
  }
@@ -285863,56 +286232,56 @@ async function prismaPull(argv) {
285863
286232
  try {
285864
286233
  args = parsePrismaPullArgs(argv);
285865
286234
  } catch (err) {
285866
- console.error(import_picocolors25.default.red(` ${err instanceof Error ? err.message : String(err)}`));
286235
+ console.error(import_picocolors26.default.red(` ${err instanceof Error ? err.message : String(err)}`));
285867
286236
  process.exit(1);
285868
286237
  }
285869
286238
  if (!(0, import_fs11.existsSync)(args.schema)) {
285870
286239
  console.error(
285871
- import_picocolors25.default.red(` No Prisma schema at ${import_picocolors25.default.bold(args.schema)}.`) + import_picocolors25.default.dim(` Pass a path: ${import_picocolors25.default.bold("ablo pull prisma <path>")}.`)
286240
+ import_picocolors26.default.red(` No Prisma schema at ${import_picocolors26.default.bold(args.schema)}.`) + import_picocolors26.default.dim(` Pass a path: ${import_picocolors26.default.bold("ablo pull prisma <path>")}.`)
285872
286241
  );
285873
286242
  process.exit(1);
285874
286243
  }
285875
286244
  if ((0, import_fs11.existsSync)(args.out) && !args.force) {
285876
286245
  console.error(
285877
- import_picocolors25.default.red(` ${args.out} already exists.`) + import_picocolors25.default.dim(` Re-run with ${import_picocolors25.default.bold("--force")} to overwrite.`)
286246
+ import_picocolors26.default.red(` ${args.out} already exists.`) + import_picocolors26.default.dim(` Re-run with ${import_picocolors26.default.bold("--force")} to overwrite.`)
285878
286247
  );
285879
286248
  process.exit(1);
285880
286249
  }
285881
286250
  console.log(`
285882
- ${brand("ablo")} ${import_picocolors25.default.dim("pull prisma")} ${import_picocolors25.default.dim(args.schema)}
286251
+ ${brand("ablo")} ${import_picocolors26.default.dim("pull prisma")} ${import_picocolors26.default.dim(args.schema)}
285883
286252
  `);
285884
286253
  let result;
285885
286254
  try {
285886
286255
  const src = (0, import_fs11.readFileSync)(args.schema, "utf8");
285887
286256
  result = buildSchemaSourceFromPrisma({ src, importPath: args.importPath });
285888
286257
  } catch (err) {
285889
- console.error(import_picocolors25.default.red(` Couldn't parse the schema: ${err instanceof Error ? err.message : String(err)}`));
286258
+ console.error(import_picocolors26.default.red(` Couldn't parse the schema: ${err instanceof Error ? err.message : String(err)}`));
285890
286259
  process.exit(1);
285891
286260
  }
285892
286261
  if (result.models.length === 0) {
285893
286262
  console.error(
285894
- import_picocolors25.default.yellow(` No adoptable models found`) + import_picocolors25.default.dim(` (a model needs an ${import_picocolors25.default.bold("id")} + ${import_picocolors25.default.bold("organizationId")} / ${import_picocolors25.default.bold("organization_id")}).`)
286263
+ import_picocolors26.default.yellow(` No adoptable models found`) + import_picocolors26.default.dim(` (a model needs an ${import_picocolors26.default.bold("id")} + ${import_picocolors26.default.bold("organizationId")} / ${import_picocolors26.default.bold("organization_id")}).`)
285895
286264
  );
285896
286265
  process.exit(1);
285897
286266
  }
285898
286267
  (0, import_fs11.writeFileSync)(args.out, result.source);
285899
- console.log(` ${import_picocolors25.default.green("\u2713")} wrote ${import_picocolors25.default.bold(args.out)} ${import_picocolors25.default.dim(`(${result.models.length} models)`)}`);
285900
- console.log(` ${import_picocolors25.default.dim(`models: ${result.models.join(", ")}`)}`);
286268
+ console.log(` ${import_picocolors26.default.green("\u2713")} wrote ${import_picocolors26.default.bold(args.out)} ${import_picocolors26.default.dim(`(${result.models.length} models)`)}`);
286269
+ console.log(` ${import_picocolors26.default.dim(`models: ${result.models.join(", ")}`)}`);
285901
286270
  if (result.skipped.length > 0) {
285902
- console.log(` ${import_picocolors25.default.dim(`${result.skipped.length} model(s) skipped:`)}`);
285903
- for (const s of result.skipped) console.log(` ${import_picocolors25.default.dim(`- ${s.name}: ${s.reason}`)}`);
286271
+ console.log(` ${import_picocolors26.default.dim(`${result.skipped.length} model(s) skipped:`)}`);
286272
+ for (const s of result.skipped) console.log(` ${import_picocolors26.default.dim(`- ${s.name}: ${s.reason}`)}`);
285904
286273
  }
285905
286274
  console.log(
285906
286275
  `
285907
- ${import_picocolors25.default.dim("Enums and relations were preserved. Review the file, then")} ${import_picocolors25.default.bold("ablo check")}.
286276
+ ${import_picocolors26.default.dim("Enums and relations were preserved. Review the file, then")} ${import_picocolors26.default.bold("ablo check")}.
285908
286277
  `
285909
286278
  );
285910
286279
  }
285911
286280
 
285912
286281
  // src/drizzlePull.ts
285913
286282
  init_cjs_shims();
285914
- var import_picocolors26 = __toESM(require_picocolors(), 1);
285915
- var import_errors19 = require("@abloatai/transaction/errors");
286283
+ var import_picocolors27 = __toESM(require_picocolors(), 1);
286284
+ var import_errors20 = require("@abloatai/transaction/errors");
285916
286285
  var import_fs12 = require("fs");
285917
286286
  var import_path7 = require("path");
285918
286287
  init_theme();
@@ -286019,7 +286388,7 @@ function parseDrizzlePullArgs(argv) {
286019
286388
  force = true;
286020
286389
  break;
286021
286390
  default:
286022
- if (arg.startsWith("--")) throw new import_errors19.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
286391
+ if (arg.startsWith("--")) throw new import_errors20.AbloValidationError(`unknown flag: ${arg}`, { code: "cli_invalid_arguments" });
286023
286392
  schema = arg;
286024
286393
  }
286025
286394
  }
@@ -286036,27 +286405,27 @@ async function drizzlePull(argv) {
286036
286405
  try {
286037
286406
  args = parseDrizzlePullArgs(argv);
286038
286407
  } catch (err) {
286039
- console.error(import_picocolors26.default.red(` ${err instanceof Error ? err.message : String(err)}`));
286408
+ console.error(import_picocolors27.default.red(` ${err instanceof Error ? err.message : String(err)}`));
286040
286409
  process.exit(1);
286041
286410
  }
286042
286411
  if (!args.schema) {
286043
286412
  console.error(
286044
- import_picocolors26.default.red(` No Drizzle schema given.`) + import_picocolors26.default.dim(` Pass the module: ${import_picocolors26.default.bold("ablo pull drizzle src/db/schema.ts")}.`)
286413
+ import_picocolors27.default.red(` No Drizzle schema given.`) + import_picocolors27.default.dim(` Pass the module: ${import_picocolors27.default.bold("ablo pull drizzle src/db/schema.ts")}.`)
286045
286414
  );
286046
286415
  process.exit(1);
286047
286416
  }
286048
286417
  if (!(0, import_fs12.existsSync)(args.schema)) {
286049
- console.error(import_picocolors26.default.red(` No file at ${import_picocolors26.default.bold(args.schema)}.`));
286418
+ console.error(import_picocolors27.default.red(` No file at ${import_picocolors27.default.bold(args.schema)}.`));
286050
286419
  process.exit(1);
286051
286420
  }
286052
286421
  if ((0, import_fs12.existsSync)(args.out) && !args.force) {
286053
286422
  console.error(
286054
- import_picocolors26.default.red(` ${args.out} already exists.`) + import_picocolors26.default.dim(` Re-run with ${import_picocolors26.default.bold("--force")} to overwrite.`)
286423
+ import_picocolors27.default.red(` ${args.out} already exists.`) + import_picocolors27.default.dim(` Re-run with ${import_picocolors27.default.bold("--force")} to overwrite.`)
286055
286424
  );
286056
286425
  process.exit(1);
286057
286426
  }
286058
286427
  console.log(`
286059
- ${brand("ablo")} ${import_picocolors26.default.dim("pull drizzle")} ${import_picocolors26.default.dim(args.schema)}
286428
+ ${brand("ablo")} ${import_picocolors27.default.dim("pull drizzle")} ${import_picocolors27.default.dim(args.schema)}
286060
286429
  `);
286061
286430
  let result;
286062
286431
  try {
@@ -286064,26 +286433,26 @@ async function drizzlePull(argv) {
286064
286433
  result = await buildSchemaSourceFromDrizzle({ mod, importPath: args.importPath });
286065
286434
  } catch (err) {
286066
286435
  const msg = err instanceof Error ? err.message : String(err);
286067
- const hint = msg.includes("Cannot find package 'drizzle-orm'") ? import_picocolors26.default.dim(` (install ${import_picocolors26.default.bold("drizzle-orm")} in this project)`) : "";
286068
- console.error(import_picocolors26.default.red(` Couldn't load the schema: ${msg}`) + hint);
286436
+ const hint = msg.includes("Cannot find package 'drizzle-orm'") ? import_picocolors27.default.dim(` (install ${import_picocolors27.default.bold("drizzle-orm")} in this project)`) : "";
286437
+ console.error(import_picocolors27.default.red(` Couldn't load the schema: ${msg}`) + hint);
286069
286438
  process.exit(1);
286070
286439
  }
286071
286440
  if (result.models.length === 0) {
286072
286441
  console.error(
286073
- import_picocolors26.default.yellow(` No adoptable tables found`) + import_picocolors26.default.dim(` (a table needs an ${import_picocolors26.default.bold("id")} + ${import_picocolors26.default.bold("organization_id")} column).`)
286442
+ import_picocolors27.default.yellow(` No adoptable tables found`) + import_picocolors27.default.dim(` (a table needs an ${import_picocolors27.default.bold("id")} + ${import_picocolors27.default.bold("organization_id")} column).`)
286074
286443
  );
286075
286444
  process.exit(1);
286076
286445
  }
286077
286446
  (0, import_fs12.writeFileSync)(args.out, result.source);
286078
- console.log(` ${import_picocolors26.default.green("\u2713")} wrote ${import_picocolors26.default.bold(args.out)} ${import_picocolors26.default.dim(`(${result.models.length} models)`)}`);
286079
- console.log(` ${import_picocolors26.default.dim(`models: ${result.models.join(", ")}`)}`);
286447
+ console.log(` ${import_picocolors27.default.green("\u2713")} wrote ${import_picocolors27.default.bold(args.out)} ${import_picocolors27.default.dim(`(${result.models.length} models)`)}`);
286448
+ console.log(` ${import_picocolors27.default.dim(`models: ${result.models.join(", ")}`)}`);
286080
286449
  if (result.skipped.length > 0) {
286081
- console.log(` ${import_picocolors26.default.dim(`${result.skipped.length} table(s) skipped:`)}`);
286082
- for (const s of result.skipped) console.log(` ${import_picocolors26.default.dim(`- ${s.name}: ${s.reason}`)}`);
286450
+ console.log(` ${import_picocolors27.default.dim(`${result.skipped.length} table(s) skipped:`)}`);
286451
+ for (const s of result.skipped) console.log(` ${import_picocolors27.default.dim(`- ${s.name}: ${s.reason}`)}`);
286083
286452
  }
286084
286453
  console.log(
286085
286454
  `
286086
- ${import_picocolors26.default.dim("Enums and relations were preserved. Review the file, then")} ${import_picocolors26.default.bold("ablo check")}.
286455
+ ${import_picocolors27.default.dim("Enums and relations were preserved. Review the file, then")} ${import_picocolors27.default.bold("ablo check")}.
286087
286456
  `
286088
286457
  );
286089
286458
  }
@@ -286169,7 +286538,7 @@ async function getCurrentUser(): Promise<{ id: string } | null> {
286169
286538
 
286170
286539
  // src/index.ts
286171
286540
  var LOGO = `
286172
- ${brand("ablo")} ${import_picocolors27.default.dim("sync engine")}
286541
+ ${brand("ablo")} ${import_picocolors28.default.dim("sync engine")}
286173
286542
  `;
286174
286543
  var HANDLERS = {
286175
286544
  init: (argv) => init([...argv]),
@@ -286178,6 +286547,7 @@ var HANDLERS = {
286178
286547
  projects: (argv) => projects([...argv]),
286179
286548
  branch: (argv) => branches([...argv]),
286180
286549
  status: (argv) => status([...argv]),
286550
+ whoami: (argv) => whoami([...argv]),
286181
286551
  doctor: () => doctor(),
286182
286552
  logs: (argv) => logs([...argv]),
286183
286553
  webhooks: (argv) => webhooks([...argv]),
@@ -286196,7 +286566,7 @@ async function runDev(argv) {
286196
286566
  const devArgs = [...argv];
286197
286567
  const oneShot = devArgs.includes("--no-watch");
286198
286568
  console.log(
286199
- import_picocolors27.default.dim(
286569
+ import_picocolors28.default.dim(
286200
286570
  oneShot ? " `ablo dev --no-watch` prepares this Git branch and pushes once." : " `ablo dev` prepares this Git branch and watches the schema."
286201
286571
  )
286202
286572
  );
@@ -286217,13 +286587,13 @@ async function runPush2(argv) {
286217
286587
  const guard = guardActiveProjectKey();
286218
286588
  if (!guard.ok && guard.available.length > 0 && !rest.includes("--url")) {
286219
286589
  console.error(
286220
- ` ${import_picocolors27.default.yellow("\u26A0")} active project ${import_picocolors27.default.bold(guard.activeProfile)} has no stored key ${import_picocolors27.default.dim(
286590
+ ` ${import_picocolors28.default.yellow("\u26A0")} active project ${import_picocolors28.default.bold(guard.activeProfile)} has no stored key ${import_picocolors28.default.dim(
286221
286591
  `(you have keys for: ${guard.available.join(", ")})`
286222
286592
  )}`
286223
286593
  );
286224
286594
  const loginCmd = guard.activeProfile === "default" ? "ablo login" : `ablo login --project ${guard.activeProfile}`;
286225
286595
  console.error(
286226
- import_picocolors27.default.dim(` Mint one with ${import_picocolors27.default.bold(loginCmd)}, or switch with ${import_picocolors27.default.bold("ablo projects use <slug>")}.`)
286596
+ import_picocolors28.default.dim(` Mint one with ${import_picocolors28.default.bold(loginCmd)}, or switch with ${import_picocolors28.default.bold("ablo projects use <slug>")}.`)
286227
286597
  );
286228
286598
  process.exitCode = 1;
286229
286599
  return;
@@ -286234,13 +286604,21 @@ async function runPush2(argv) {
286234
286604
  }
286235
286605
  function runRenamedSchema(argv) {
286236
286606
  const forwarded = argv.slice(1).join(" ");
286237
- console.error(` ${import_picocolors27.default.red("\u2717")} \`ablo schema push\` was renamed to \`${brand("ablo push")}\`.`);
286607
+ console.error(` ${import_picocolors28.default.red("\u2717")} \`ablo schema push\` was renamed to \`${brand("ablo push")}\`.`);
286238
286608
  console.error(` Run \`ablo push${forwarded ? " " + forwarded : ""}\` instead.`);
286239
286609
  process.exitCode = 1;
286240
286610
  }
286241
286611
  async function main() {
286242
- const command = parseCommandName(process.argv[2]);
286612
+ const raw = process.argv[2];
286613
+ const command = parseCommandName(raw);
286243
286614
  const argv = process.argv.slice(3);
286615
+ if (!command && raw !== void 0 && raw !== "help" && !raw.startsWith("-")) {
286616
+ const suggestion = suggestCommand(raw);
286617
+ throw new import_errors21.AbloValidationError(
286618
+ `\`${raw}\` isn't an ablo command.` + (suggestion ? ` Did you mean \`ablo ${suggestion}\`?` : " Run `ablo help --all` to see every command."),
286619
+ { code: "cli_invalid_arguments" }
286620
+ );
286621
+ }
286244
286622
  if (command && argv.some((a) => a === "--help" || a === "-h")) {
286245
286623
  const usage = usageFor(command);
286246
286624
  if (usage) {
@@ -286267,7 +286645,7 @@ function printCoreHelp() {
286267
286645
  const width = Math.max(...rows.map((r2) => r2.run.length)) + 4;
286268
286646
  console.log(LOGO);
286269
286647
  for (const group of CORE_GROUPS) {
286270
- console.log(` ${import_picocolors27.default.bold(group)}`);
286648
+ console.log(` ${import_picocolors28.default.bold(group)}`);
286271
286649
  const printed = group === "More" ? [...coreRows(group), ...extra] : coreRows(group);
286272
286650
  for (const row of printed) console.log(` npx ablo ${row.run.padEnd(width)}${row.does}`);
286273
286651
  console.log();
@@ -286276,7 +286654,7 @@ function printCoreHelp() {
286276
286654
  }
286277
286655
  function printSchemaReminder() {
286278
286656
  console.log(
286279
- import_picocolors27.default.dim(` Edit ${import_picocolors27.default.bold("ablo/schema.ts")}, then push \u2014 writes to models you haven't pushed fail with `) + import_picocolors27.default.yellow("server_execute_unknown_model") + import_picocolors27.default.dim(".")
286657
+ import_picocolors28.default.dim(` Edit ${import_picocolors28.default.bold("ablo/schema.ts")}, then push \u2014 writes to models you haven't pushed fail with `) + import_picocolors28.default.yellow("server_execute_unknown_model") + import_picocolors28.default.dim(".")
286280
286658
  );
286281
286659
  console.log();
286282
286660
  }
@@ -286286,7 +286664,7 @@ function printFullHelp() {
286286
286664
  ) + 2;
286287
286665
  console.log(LOGO);
286288
286666
  for (const group of FULL_GROUPS) {
286289
- console.log(` ${import_picocolors27.default.bold(group)}`);
286667
+ console.log(` ${import_picocolors28.default.bold(group)}`);
286290
286668
  for (const row of fullRows(group)) {
286291
286669
  console.log(row.does === void 0 ? ` ${" ".repeat(9)}${row.run}` : ` npx ablo ${row.run.padEnd(width)}${row.does}`);
286292
286670
  }
@@ -286341,7 +286719,7 @@ async function ensureInitProject(opts) {
286341
286719
  const ensured = await ensureProject(slug);
286342
286720
  if (ensured) {
286343
286721
  console.log(
286344
- ` ${import_picocolors27.default.green("\u2713")} ${ensured.created ? "Created" : "Using"} project ${import_picocolors27.default.bold(ensured.slug)} ${import_picocolors27.default.dim(`(${ensured.id})`)} \u2014 keys you mint for it are isolated from the org's other apps.`
286722
+ ` ${import_picocolors28.default.green("\u2713")} ${ensured.created ? "Created" : "Using"} project ${import_picocolors28.default.bold(ensured.slug)} ${import_picocolors28.default.dim(`(${ensured.id})`)} \u2014 keys you mint for it are isolated from the org's other apps.`
286345
286723
  );
286346
286724
  }
286347
286725
  }
@@ -286383,7 +286761,7 @@ async function chooseBool(flagValue, fallback, interactive, prompt) {
286383
286761
  async function init(args = []) {
286384
286762
  const opts = parseInitArgs(args);
286385
286763
  const interactive = Boolean(process.stdin.isTTY) && !opts.yes && !process.env.CI;
286386
- Ie(`${brand("ablo")} ${import_picocolors27.default.dim("sync engine")}`);
286764
+ Ie(`${brand("ablo")} ${import_picocolors28.default.dim("sync engine")}`);
286387
286765
  if (!(0, import_fs13.existsSync)("package.json")) {
286388
286766
  xe("No package.json found. Run this from your project root.");
286389
286767
  process.exit(1);
@@ -286461,7 +286839,7 @@ async function init(args = []) {
286461
286839
  if (pullExisting) {
286462
286840
  const dbUrl = readProjectAdminDatabaseUrl();
286463
286841
  if (!dbUrl) {
286464
- schemaNote = import_picocolors27.default.dim(` (no ${ADMIN_URL_VAR} \u2014 wrote starter; run \`ablo pull\` later)`);
286842
+ schemaNote = import_picocolors28.default.dim(` (no ${ADMIN_URL_VAR} \u2014 wrote starter; run \`ablo pull\` later)`);
286465
286843
  } else {
286466
286844
  try {
286467
286845
  const pulled = await buildSchemaSourceFromDb({
@@ -286471,12 +286849,12 @@ async function init(args = []) {
286471
286849
  });
286472
286850
  if (pulled.models.length > 0) {
286473
286851
  schemaSource = pulled.source;
286474
- schemaNote = import_picocolors27.default.dim(` (pulled ${pulled.models.length} models)`);
286852
+ schemaNote = import_picocolors28.default.dim(` (pulled ${pulled.models.length} models)`);
286475
286853
  } else {
286476
- schemaNote = import_picocolors27.default.dim(" (no adoptable tables \u2014 wrote starter)");
286854
+ schemaNote = import_picocolors28.default.dim(" (no adoptable tables \u2014 wrote starter)");
286477
286855
  }
286478
286856
  } catch {
286479
- schemaNote = import_picocolors27.default.dim(" (pull failed \u2014 wrote starter)");
286857
+ schemaNote = import_picocolors28.default.dim(" (pull failed \u2014 wrote starter)");
286480
286858
  }
286481
286859
  }
286482
286860
  }
@@ -286500,9 +286878,9 @@ async function init(args = []) {
286500
286878
  const existing = (0, import_fs13.readFileSync)(envFile, "utf-8");
286501
286879
  if (!existing.includes("ABLO_")) {
286502
286880
  (0, import_fs13.writeFileSync)(envFile, existing + "\n" + envBody);
286503
- created.push(`${envFile} ${import_picocolors27.default.dim("(appended)")}`);
286881
+ created.push(`${envFile} ${import_picocolors28.default.dim("(appended)")}`);
286504
286882
  } else {
286505
- created.push(`${envFile} ${import_picocolors27.default.dim("(already configured)")}`);
286883
+ created.push(`${envFile} ${import_picocolors28.default.dim("(already configured)")}`);
286506
286884
  }
286507
286885
  }
286508
286886
  if (agent) {
@@ -286518,17 +286896,17 @@ async function init(args = []) {
286518
286896
  }
286519
286897
  const providersPath = (0, import_path8.join)(layout.appBase, "providers.tsx");
286520
286898
  (0, import_fs13.writeFileSync)(providersPath, generateProviders());
286521
- created.push(`${providersPath} ${import_picocolors27.default.dim(`(wrap ${(0, import_path8.join)(layout.appBase, "layout.tsx")} in <Providers>)`)}`);
286899
+ created.push(`${providersPath} ${import_picocolors28.default.dim(`(wrap ${(0, import_path8.join)(layout.appBase, "layout.tsx")} in <Providers>)`)}`);
286522
286900
  const sessionDir = (0, import_path8.join)(layout.appBase, "api", "ablo-session");
286523
286901
  (0, import_fs13.mkdirSync)(sessionDir, { recursive: true });
286524
286902
  (0, import_fs13.writeFileSync)((0, import_path8.join)(sessionDir, "route.ts"), generateSessionRoute());
286525
- created.push(`${(0, import_path8.join)(sessionDir, "route.ts")} ${import_picocolors27.default.dim("(wire your auth)")}`);
286903
+ created.push(`${(0, import_path8.join)(sessionDir, "route.ts")} ${import_picocolors28.default.dim("(wire your auth)")}`);
286526
286904
  }
286527
286905
  if (framework !== "vanilla") {
286528
286906
  (0, import_fs13.writeFileSync)((0, import_path8.join)(abloDir, "TaskList.tsx"), generateComponent());
286529
286907
  created.push(`${abloDir}/TaskList.tsx`);
286530
286908
  }
286531
- Me(created.map((f) => `${import_picocolors27.default.green("\u2713")} ${f}`).join("\n"), "Created");
286909
+ Me(created.map((f) => `${import_picocolors28.default.green("\u2713")} ${f}`).join("\n"), "Created");
286532
286910
  const pm = detectPackageManager();
286533
286911
  if (opts.install) {
286534
286912
  const s = Y2();
@@ -286537,46 +286915,46 @@ async function init(args = []) {
286537
286915
  (0, import_child_process3.execSync)(`${pm} add @abloatai/ablo`, { stdio: "ignore" });
286538
286916
  s.stop("Installed @abloatai/ablo");
286539
286917
  } catch {
286540
- s.stop(`${import_picocolors27.default.yellow("!")} Couldn't auto-install \u2014 run ${import_picocolors27.default.bold(`${pm} install @abloatai/ablo`)}`);
286918
+ s.stop(`${import_picocolors28.default.yellow("!")} Couldn't auto-install \u2014 run ${import_picocolors28.default.bold(`${pm} install @abloatai/ablo`)}`);
286541
286919
  }
286542
286920
  }
286543
286921
  const steps = [
286544
- `Run ${import_picocolors27.default.bold("npx ablo login")} to authorize branch management`,
286545
- `Set ${import_picocolors27.default.bold("DATABASE_URL")} in ${import_picocolors27.default.bold(envFile)} \u2014 your Postgres is the system of record; rows live there, never with Ablo`,
286546
- `Run ${import_picocolors27.default.bold("npx ablo dev")} \u2014 pushes your schema definition and watches for changes`,
286922
+ `Run ${import_picocolors28.default.bold("npx ablo login")} to authorize branch management`,
286923
+ `Set ${import_picocolors28.default.bold("DATABASE_URL")} in ${import_picocolors28.default.bold(envFile)} \u2014 your Postgres is the system of record; rows live there, never with Ablo`,
286924
+ `Run ${import_picocolors28.default.bold("npx ablo dev")} \u2014 pushes your schema definition and watches for changes`,
286547
286925
  ...storage === "replication" ? [
286548
- `Connect your database \u2014 ${import_picocolors27.default.bold("npx ablo connect")} prints the one-time logical-replication setup SQL to run on your Postgres`,
286549
- `Verify it \u2014 ${import_picocolors27.default.bold("npx ablo connect check")} walks wal_level, the publication, the role, and replica identity, with the exact fix for anything missing`,
286550
- `Register it \u2014 ${import_picocolors27.default.bold("npx ablo connect register")} tells Ablo to start replicating; your app keeps writing through your own backend while Ablo tails the WAL`
286926
+ `Connect your database \u2014 ${import_picocolors28.default.bold("npx ablo connect")} prints the one-time logical-replication setup SQL to run on your Postgres`,
286927
+ `Verify it \u2014 ${import_picocolors28.default.bold("npx ablo connect check")} walks wal_level, the publication, the role, and replica identity, with the exact fix for anything missing`,
286928
+ `Register it \u2014 ${import_picocolors28.default.bold("npx ablo connect register")} tells Ablo to start replicating; your app keeps writing through your own backend while Ablo tails the WAL`
286551
286929
  ] : [
286552
- `Provision your DB: ${import_picocolors27.default.bold("npx ablo migrate")} (creates your Ablo-model tables + the adapter tables; keep your own migrations for everything else), then mount ${import_picocolors27.default.bold(`${abloDir}/data-source.ts`)} at ${import_picocolors27.default.bold("/api/ablo/source")}`
286930
+ `Provision your DB: ${import_picocolors28.default.bold("npx ablo migrate")} (creates your Ablo-model tables + the adapter tables; keep your own migrations for everything else), then mount ${import_picocolors28.default.bold(`${abloDir}/data-source.ts`)} at ${import_picocolors28.default.bold("/api/ablo/source")}`
286553
286931
  ],
286554
286932
  ...framework === "nextjs" ? [
286555
- `Wrap ${import_picocolors27.default.bold((0, import_path8.join)(layout.appBase, "layout.tsx"))} in ${import_picocolors27.default.bold("<Providers>")} (${(0, import_path8.join)(layout.appBase, "providers.tsx")}) and add your auth to ${import_picocolors27.default.bold((0, import_path8.join)(layout.appBase, "api", "ablo-session", "route.ts"))}`
286933
+ `Wrap ${import_picocolors28.default.bold((0, import_path8.join)(layout.appBase, "layout.tsx"))} in ${import_picocolors28.default.bold("<Providers>")} (${(0, import_path8.join)(layout.appBase, "providers.tsx")}) and add your auth to ${import_picocolors28.default.bold((0, import_path8.join)(layout.appBase, "api", "ablo-session", "route.ts"))}`
286556
286934
  ] : [],
286557
- `Run ${import_picocolors27.default.bold(`${pm} run dev`)} and open two browser tabs \u2014 changes sync in real-time`,
286935
+ `Run ${import_picocolors28.default.bold(`${pm} run dev`)} and open two browser tabs \u2014 changes sync in real-time`,
286558
286936
  ...agent ? [
286559
- `Run ${import_picocolors27.default.bold(`npx tsx ${abloDir}/agent.ts`)} \u2014 an AI teammate edits the same tasks`,
286560
- `Run ${import_picocolors27.default.bold("npx ablo logs")} to watch human + agent commits stream by`
286937
+ `Run ${import_picocolors28.default.bold(`npx tsx ${abloDir}/agent.ts`)} \u2014 an AI teammate edits the same tasks`,
286938
+ `Run ${import_picocolors28.default.bold("npx ablo logs")} to watch human + agent commits stream by`
286561
286939
  ] : []
286562
286940
  ];
286563
286941
  Me(steps.map((s, i) => `${i + 1}. ${s}`).join("\n"), "Next steps");
286564
286942
  const existingKey = resolveManagementKey();
286565
286943
  if (existingKey) {
286566
286944
  await ensureInitProject(opts);
286567
- Se(`Already authorized ${import_picocolors27.default.dim(`(${existingKey.slice(0, 11)}\u2026)`)}. Run ${import_picocolors27.default.bold("npx ablo dev")} next. ${import_picocolors27.default.dim("Docs:")} https://abloatai.com/docs`);
286945
+ Se(`Already authorized ${import_picocolors28.default.dim(`(${existingKey.slice(0, 11)}\u2026)`)}. Run ${import_picocolors28.default.bold("npx ablo dev")} next. ${import_picocolors28.default.dim("Docs:")} https://abloatai.com/docs`);
286568
286946
  return;
286569
286947
  }
286570
286948
  if (interactive && opts.login) {
286571
286949
  const loginNow = await ye({ message: "Log in now? (opens your browser)", initialValue: true });
286572
286950
  if (!pD(loginNow) && loginNow) {
286573
- Se(`${import_picocolors27.default.dim("Docs:")} https://abloatai.com/docs`);
286951
+ Se(`${import_picocolors28.default.dim("Docs:")} https://abloatai.com/docs`);
286574
286952
  await login();
286575
286953
  await ensureInitProject(opts);
286576
286954
  return;
286577
286955
  }
286578
286956
  }
286579
- Se(`Run ${import_picocolors27.default.bold("npx ablo login")} when ready. ${import_picocolors27.default.dim("Docs:")} https://abloatai.com/docs`);
286957
+ Se(`Run ${import_picocolors28.default.bold("npx ablo login")} when ready. ${import_picocolors28.default.dim("Docs:")} https://abloatai.com/docs`);
286580
286958
  }
286581
286959
  function generateSchema() {
286582
286960
  return `import { defineSchema, model, relation, z } from '@abloatai/ablo/schema';