@overaihq/cli 0.13.8 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -5,10 +5,10 @@ import {
5
5
  import {
6
6
  itemFilterExpressionRootSchema,
7
7
  webPageConfigSchema
8
- } from "./chunk-M2NX2CHG.js";
8
+ } from "./chunk-FTBTDB2B.js";
9
9
  import {
10
10
  external_exports
11
- } from "./chunk-XCJJTK3H.js";
11
+ } from "./chunk-PF6GZFT4.js";
12
12
  import {
13
13
  __commonJS,
14
14
  __toESM
@@ -11911,9 +11911,9 @@ var require_lib = __commonJS({
11911
11911
  }
11912
11912
  });
11913
11913
 
11914
- // ../../node_modules/.pnpm/@babel+parser@7.29.8/node_modules/@babel/parser/lib/index.js
11914
+ // ../../node_modules/.pnpm/@babel+parser@7.29.9/node_modules/@babel/parser/lib/index.js
11915
11915
  var require_lib2 = __commonJS({
11916
- "../../node_modules/.pnpm/@babel+parser@7.29.8/node_modules/@babel/parser/lib/index.js"(exports) {
11916
+ "../../node_modules/.pnpm/@babel+parser@7.29.9/node_modules/@babel/parser/lib/index.js"(exports) {
11917
11917
  "use strict";
11918
11918
  Object.defineProperty(exports, "__esModule", {
11919
11919
  value: true
@@ -14965,13 +14965,15 @@ var require_lib2 = __commonJS({
14965
14965
  const arrows = [];
14966
14966
  while (stack.length !== 0) {
14967
14967
  const node2 = stack.pop();
14968
- if (node2.type === "ArrowFunctionExpression" && node2.body.type !== "BlockStatement") {
14968
+ if (node2.type === "ArrowFunctionExpression") {
14969
14969
  if (node2.typeParameters || !node2.returnType) {
14970
14970
  this.finishArrowValidation(node2);
14971
14971
  } else {
14972
14972
  arrows.push(node2);
14973
14973
  }
14974
- stack.push(node2.body);
14974
+ if (node2.body.type !== "BlockStatement") {
14975
+ stack.push(node2.body);
14976
+ }
14975
14977
  } else if (node2.type === "ConditionalExpression") {
14976
14978
  stack.push(node2.consequent);
14977
14979
  stack.push(node2.alternate);
@@ -22127,8 +22129,11 @@ var require_lib2 = __commonJS({
22127
22129
  }
22128
22130
  }
22129
22131
  fillOptionalPropertiesForTSESLint(node) {
22130
- var _node$directive, _node$decorators, _node$optional, _node$typeAnnotation, _node$accessibility, _node$decorators2, _node$override, _node$readonly, _node$static, _node$declare, _node$returnType, _node$typeParameters, _node$optional2, _node$optional3, _node$accessibility2, _node$readonly2, _node$static2, _node$declare2, _node$definite, _node$readonly3, _node$typeAnnotation2, _node$accessibility3, _node$decorators3, _node$override2, _node$optional4, _node$id, _node$abstract, _node$declare3, _node$decorators4, _node$implements, _node$superTypeArgume, _node$typeParameters2, _node$declare4, _node$definite2, _node$const, _node$declare5, _node$computed, _node$qualifier, _node$options, _node$declare6, _node$extends, _node$optional5, _node$readonly4, _node$declare7, _node$global, _node$const2, _node$in, _node$out;
22132
+ var _node$phase, _node$directive, _node$decorators, _node$optional, _node$typeAnnotation, _node$accessibility, _node$decorators2, _node$override, _node$readonly, _node$static, _node$declare, _node$returnType, _node$typeParameters, _node$optional2, _node$optional3, _node$accessibility2, _node$readonly2, _node$static2, _node$declare2, _node$definite, _node$readonly3, _node$typeAnnotation2, _node$accessibility3, _node$decorators3, _node$override2, _node$optional4, _node$id, _node$abstract, _node$declare3, _node$decorators4, _node$implements, _node$superTypeArgume, _node$typeParameters2, _node$declare4, _node$definite2, _node$const, _node$declare5, _node$computed, _node$qualifier, _node$options, _node$declare6, _node$extends, _node$optional5, _node$readonly4, _node$declare7, _node$global, _node$const2, _node$in, _node$out;
22131
22133
  switch (node.type) {
22134
+ case "ImportDeclaration":
22135
+ (_node$phase = node.phase) != null ? _node$phase : node.phase = null;
22136
+ return;
22132
22137
  case "ExpressionStatement":
22133
22138
  (_node$directive = node.directive) != null ? _node$directive : node.directive = void 0;
22134
22139
  return;
@@ -26521,12 +26526,31 @@ var sessionSchema = external_exports.object({
26521
26526
  identityId: external_exports.string().optional(),
26522
26527
  email: external_exports.string().optional(),
26523
26528
  accessToken: external_exports.string().optional(),
26524
- accessTokenExpiresAt: external_exports.number().optional()
26529
+ accessTokenExpiresAt: external_exports.number().optional(),
26530
+ // When the refresh token itself dies. Sessions saved before this was recorded
26531
+ // have none, which reads as "unknown" rather than "expired".
26532
+ refreshTokenExpiresAt: external_exports.number().optional(),
26533
+ // Cached from `org list` so tables and the switch picker can name an org
26534
+ // without a network round trip.
26535
+ organizationName: external_exports.string().optional()
26525
26536
  });
26526
26537
  var storeSchema = external_exports.object({
26527
26538
  version: external_exports.literal(2),
26528
26539
  generation: external_exports.number().default(0),
26529
26540
  defaultApiBaseUrl: external_exports.string().optional(),
26541
+ /*
26542
+ * Remote name -> API base URL. Names exist so a tenant's cluster can be typed
26543
+ * instead of pasted; `prod` and `local` are built in (see remotes.ts) and a
26544
+ * name in use is never silently repointed. The app URL stays on the deployment
26545
+ * below, keyed by the API URL that identifies the backend.
26546
+ */
26547
+ remotes: external_exports.record(external_exports.string(), external_exports.string()).default({}),
26548
+ /*
26549
+ * Alias -> org ref (`[<remote>:]<orgId>`), expanded textually wherever an org
26550
+ * can be named. Purely local, like a shell alias: ids stay canonical in the
26551
+ * store, in clone manifests, and in everything the CLI prints.
26552
+ */
26553
+ aliases: external_exports.record(external_exports.string(), external_exports.string()).default({}),
26530
26554
  deployments: external_exports.record(
26531
26555
  external_exports.string(),
26532
26556
  external_exports.object({
@@ -26558,7 +26582,14 @@ var readStore = () => {
26558
26582
  throw error;
26559
26583
  }
26560
26584
  })();
26561
- if (raw2 == null) return { version: 2, generation: 0, deployments: {} };
26585
+ if (raw2 == null)
26586
+ return {
26587
+ version: 2,
26588
+ generation: 0,
26589
+ remotes: {},
26590
+ aliases: {},
26591
+ deployments: {}
26592
+ };
26562
26593
  const invalidStoreMessage = `Invalid credential store at ${configFilePath}. Restore a valid copy before continuing.`;
26563
26594
  const [value, parseError] = resultOfSync(() => JSON.parse(raw2));
26564
26595
  if (parseError != null) throw new Error(invalidStoreMessage);
@@ -26573,6 +26604,8 @@ var readStore = () => {
26573
26604
  version: 2,
26574
26605
  generation: 0,
26575
26606
  defaultApiBaseUrl: session.apiBaseUrl,
26607
+ remotes: {},
26608
+ aliases: {},
26576
26609
  deployments: {
26577
26610
  [session.apiBaseUrl]: {
26578
26611
  defaultOrgId: session.organizationId,
@@ -26623,7 +26656,17 @@ var appBaseUrlFromApiHost = (apiHost) => {
26623
26656
  var trimSlash = (url) => url.replace(/\/+$/, "");
26624
26657
  var DEFAULT_API_BASE_URL = "https://api.overai.com";
26625
26658
  var apiBaseUrlOverride = process.env.OVERAI_API_URL != null ? trimSlash(process.env.OVERAI_API_URL) : void 0;
26626
- var orgIdOverride = process.env.OVERAI_ORG_ID != null && process.env.OVERAI_ORG_ID !== "" ? process.env.OVERAI_ORG_ID : void 0;
26659
+ var leadingFlag = (name2) => {
26660
+ const argv = process.argv.slice(2);
26661
+ for (let i = 0; i < argv.length; i += 2) {
26662
+ if (argv[i]?.startsWith("--") !== true) return void 0;
26663
+ if (argv[i] === name2) return argv[i + 1];
26664
+ }
26665
+ return void 0;
26666
+ };
26667
+ var LEADING_FLAGS = ["--org"];
26668
+ var orgRefOverride = leadingFlag("--org") ?? (process.env.OVERAI_ORG_ID != null && process.env.OVERAI_ORG_ID !== "" ? process.env.OVERAI_ORG_ID : void 0);
26669
+ var orgRefSource = leadingFlag("--org") != null ? "--org" : orgRefOverride != null ? "OVERAI_ORG_ID" : void 0;
26627
26670
  var appBaseUrl = (backend) => {
26628
26671
  const saved = readStore();
26629
26672
  return trimSlash(
@@ -26631,6 +26674,126 @@ var appBaseUrl = (backend) => {
26631
26674
  );
26632
26675
  };
26633
26676
 
26677
+ // src/remotes.ts
26678
+ var BUILT_IN_REMOTES = {
26679
+ prod: DEFAULT_API_BASE_URL,
26680
+ local: "http://localhost:3001"
26681
+ };
26682
+ var remoteUrl = (name2, store = readStore()) => {
26683
+ const url = store.remotes[name2] ?? BUILT_IN_REMOTES[name2];
26684
+ return url == null ? void 0 : trimSlash(url);
26685
+ };
26686
+ var knownRemotes = (store = readStore()) => {
26687
+ const byUrl = new Map(
26688
+ Object.entries({ ...BUILT_IN_REMOTES, ...store.remotes }).map(
26689
+ ([name2, url]) => [trimSlash(url), name2]
26690
+ )
26691
+ );
26692
+ for (const url of Object.keys(store.deployments)) {
26693
+ const trimmed = trimSlash(url);
26694
+ if (!byUrl.has(trimmed)) byUrl.set(trimmed, remoteName(trimmed, store));
26695
+ }
26696
+ return [...byUrl].map(([apiBaseUrl2, name2]) => ({ name: name2, apiBaseUrl: apiBaseUrl2 })).sort((a, b) => a.name.localeCompare(b.name));
26697
+ };
26698
+ var derivedRemoteName = (apiBaseUrl2) => {
26699
+ const [url] = resultOfSync(() => new URL(apiBaseUrl2));
26700
+ if (url == null) return void 0;
26701
+ if ((url.hostname === "localhost" || url.hostname === "127.0.0.1") && url.port === "3001")
26702
+ return "local";
26703
+ const match = /^api\.(?:([a-z0-9-]+)\.)?(?:overai|perygee)\.com$/.exec(
26704
+ url.hostname
26705
+ );
26706
+ if (match == null) return void 0;
26707
+ return match[1] ?? "prod";
26708
+ };
26709
+ var remoteName = (apiBaseUrl2, store = readStore()) => {
26710
+ const url = trimSlash(apiBaseUrl2);
26711
+ const registered = Object.entries(store.remotes).find(
26712
+ ([, value]) => trimSlash(value) === url
26713
+ );
26714
+ if (registered != null) return registered[0];
26715
+ const builtIn = Object.entries(BUILT_IN_REMOTES).find(
26716
+ ([, value]) => value === url
26717
+ );
26718
+ if (builtIn != null) return builtIn[0];
26719
+ const derived = derivedRemoteName(url);
26720
+ return derived != null && remoteUrl(derived, store) === url ? derived : url;
26721
+ };
26722
+ var defaultApiBaseUrl = (store = readStore()) => store.defaultApiBaseUrl ?? DEFAULT_API_BASE_URL;
26723
+ var remoteForOrg = (orgId, store = readStore()) => {
26724
+ const holders = Object.entries(store.deployments).filter(([, deployment]) => deployment.sessions[orgId] != null).map(([url]) => url);
26725
+ if (holders.length <= 1) return holders[0];
26726
+ const preferred = holders.find((url) => url === store.defaultApiBaseUrl);
26727
+ if (preferred != null) return preferred;
26728
+ throw new Error(
26729
+ `Org ${orgId} is signed in on ${holders.map((url) => remoteName(url, store)).join(" and ")}. Name one, e.g. --org ${remoteName(holders[0] ?? "", store)}:${orgId}.`
26730
+ );
26731
+ };
26732
+ var remoteOnlyRef = (text, store = readStore()) => {
26733
+ const trimmed = text.trim().replace(/:$/, "");
26734
+ if (store.aliases[trimmed] != null) return void 0;
26735
+ return remoteUrl(trimmed, store);
26736
+ };
26737
+ var parseOrgRef = (text, store = readStore()) => {
26738
+ const trimmed = text.trim();
26739
+ if (trimmed === "") throw new Error("Empty organization reference.");
26740
+ const expanded = store.aliases[trimmed] ?? trimmed;
26741
+ const colon = expanded.indexOf(":");
26742
+ if (colon === -1) return { orgId: expanded };
26743
+ const name2 = expanded.slice(0, colon);
26744
+ const orgPart = expanded.slice(colon + 1).trim();
26745
+ const apiBaseUrl2 = remoteUrl(name2, store);
26746
+ if (apiBaseUrl2 == null)
26747
+ throw new Error(
26748
+ `Unknown remote "${name2}". Known: ${knownRemotes(store).map((remote) => remote.name).join(", ")}. Add one with: overai remote add ${name2} <apiUrl>`
26749
+ );
26750
+ if (orgPart === "")
26751
+ throw new Error(`Missing org id in "${expanded}". Use ${name2}:<orgId>.`);
26752
+ const aliased = store.aliases[orgPart];
26753
+ const orgId = aliased == null ? orgPart : aliased.split(":").at(-1) ?? orgPart;
26754
+ return { orgId, apiBaseUrl: apiBaseUrl2 };
26755
+ };
26756
+ var resolveOrgRef = (text, store = readStore()) => {
26757
+ const ref = parseOrgRef(text, store);
26758
+ return {
26759
+ orgId: ref.orgId,
26760
+ apiBaseUrl: ref.apiBaseUrl ?? remoteForOrg(ref.orgId, store) ?? defaultApiBaseUrl(store)
26761
+ };
26762
+ };
26763
+ var cachedOverride;
26764
+ var orgOverride = () => {
26765
+ if (cachedOverride !== void 0) return cachedOverride;
26766
+ cachedOverride = orgRefOverride == null ? null : { ...parseOrgRef(orgRefOverride), source: orgRefSource ?? "--org" };
26767
+ return cachedOverride;
26768
+ };
26769
+ var orgRefText = (orgId, apiBaseUrl2, store = readStore()) => {
26770
+ const alias = Object.entries(store.aliases).find(([name3]) => {
26771
+ const [ref] = resultOfSync(() => resolveOrgRef(name3, store));
26772
+ return ref?.orgId === orgId && ref.apiBaseUrl === trimSlash(apiBaseUrl2);
26773
+ })?.[0];
26774
+ if (alias != null) return alias;
26775
+ if (trimSlash(apiBaseUrl2) === trimSlash(defaultApiBaseUrl(store)))
26776
+ return orgId;
26777
+ const name2 = remoteName(apiBaseUrl2, store);
26778
+ return name2 === trimSlash(apiBaseUrl2) ? orgId : `${name2}:${orgId}`;
26779
+ };
26780
+ var signinHint = (orgId, apiBaseUrl2) => {
26781
+ const store = readStore();
26782
+ const url = trimSlash(apiBaseUrl2);
26783
+ return remoteName(url, store) === url && url !== trimSlash(defaultApiBaseUrl(store)) ? `Run OVERAI_API_URL=${url} overai signin ${orgId}.` : `Run overai signin ${orgRefText(orgId, apiBaseUrl2, store)}.`;
26784
+ };
26785
+ var expiresIn = (at) => {
26786
+ if (at == null) return void 0;
26787
+ const ms = at - Date.now();
26788
+ if (ms <= 0) return "expired";
26789
+ const hours = Math.floor(ms / 36e5);
26790
+ if (hours < 1) return `${String(Math.max(1, Math.floor(ms / 6e4)))}m`;
26791
+ return hours < 48 ? `${String(hours)}h` : `${String(Math.floor(hours / 24))}d`;
26792
+ };
26793
+
26794
+ // ../common/src/stdlib/iife.ts
26795
+ var iife = (fn2) => fn2();
26796
+
26634
26797
  // ../common/src/stdlib/omit.ts
26635
26798
  var omit = (obj, ...keys) => {
26636
26799
  const result = { ...obj };
@@ -26640,7 +26803,29 @@ var omit = (obj, ...keys) => {
26640
26803
 
26641
26804
  // src/api.ts
26642
26805
  var commandApiBaseUrl;
26643
- var apiBaseUrl = () => commandApiBaseUrl ??= apiBaseUrlOverride ?? readStore().defaultApiBaseUrl ?? DEFAULT_API_BASE_URL;
26806
+ var explicitRemote;
26807
+ var cloneRemote;
26808
+ var setRemoteScope = (apiBaseUrl_) => {
26809
+ if (commandApiBaseUrl != null && commandApiBaseUrl !== apiBaseUrl_)
26810
+ throw new Error("Cannot change remote after a command has started.");
26811
+ explicitRemote = apiBaseUrl_;
26812
+ };
26813
+ var setCloneRemote = (apiBaseUrl_, organizationId) => {
26814
+ cloneRemote = { apiBaseUrl: apiBaseUrl_, organizationId };
26815
+ };
26816
+ var apiBaseUrl = () => commandApiBaseUrl ??= iife(() => {
26817
+ if (apiBaseUrlOverride != null) return apiBaseUrlOverride;
26818
+ if (explicitRemote != null) return explicitRemote;
26819
+ const store = readStore();
26820
+ const override = orgOverride();
26821
+ if (override?.apiBaseUrl != null) return override.apiBaseUrl;
26822
+ if (cloneRemote != null && (override == null || override.orgId === cloneRemote.organizationId))
26823
+ return cloneRemote.apiBaseUrl;
26824
+ const overrideHome = override == null ? void 0 : remoteForOrg(override.orgId, store);
26825
+ if (overrideHome != null) return overrideHome;
26826
+ if (cloneRemote != null) return cloneRemote.apiBaseUrl;
26827
+ return (orgScopeOverride == null ? void 0 : remoteForOrg(orgScopeOverride, store)) ?? defaultApiBaseUrl(store);
26828
+ });
26644
26829
  var AuthRpcError = class extends Error {
26645
26830
  constructor(status, message) {
26646
26831
  super(message);
@@ -26674,10 +26859,11 @@ var trpcMutation = async (procedure, input, baseUrl = apiBaseUrl()) => {
26674
26859
  return trpcResult(res, procedure);
26675
26860
  };
26676
26861
  var exchangeCliAuthCode = (code, codeVerifier) => trpcMutation("exchangeCliAuthCode", { code, codeVerifier });
26677
- var exchangeSessionToken = (refreshToken, destinationOrgId) => trpcMutation("exchangeSessionToken", {
26678
- refreshToken,
26679
- destinationOrgId
26680
- });
26862
+ var exchangeSessionToken = (refreshToken, destinationOrgId, backend = apiBaseUrl()) => trpcMutation(
26863
+ "exchangeSessionToken",
26864
+ { refreshToken, destinationOrgId },
26865
+ backend
26866
+ );
26681
26867
  var signOutHeadless = (refreshToken, baseUrl = apiBaseUrl()) => trpcMutation(
26682
26868
  "signOutHeadless",
26683
26869
  { refreshToken },
@@ -26711,7 +26897,7 @@ var context = () => {
26711
26897
  if (commandContext != null) return commandContext;
26712
26898
  const store = readStore();
26713
26899
  const deployment = store.deployments[apiBaseUrl()];
26714
- const organizationId = orgIdOverride ?? orgScopeOverride ?? deployment?.defaultOrgId;
26900
+ const organizationId = orgOverride()?.orgId ?? orgScopeOverride ?? deployment?.defaultOrgId;
26715
26901
  if (organizationId == null)
26716
26902
  throw new InteractiveSignInRequired("Not signed in. Run `overai signin`.");
26717
26903
  const session = deployment?.sessions[organizationId] ?? Object.values(deployment?.sessions ?? {})[0];
@@ -26736,7 +26922,7 @@ var announceOrgScope = () => {
26736
26922
  const org = scopedOrgId();
26737
26923
  if (org == null) return;
26738
26924
  process.stderr.write(
26739
- `Using org ${org} (${orgIdOverride != null ? "OVERAI_ORG_ID" : orgScopeOverride != null ? ".overai/manifest.json" : "saved default"}).
26925
+ `Using org ${org} on ${remoteName(apiBaseUrl())} (${orgOverride()?.source ?? (orgScopeOverride != null ? ".overai/manifest.json" : "saved default")}).
26740
26926
  `
26741
26927
  );
26742
26928
  };
@@ -26749,7 +26935,7 @@ var getAccessToken = async () => {
26749
26935
  "All CLI sessions were signed out in another process. Run the command again."
26750
26936
  );
26751
26937
  const deployment = store.deployments[baseUrl];
26752
- const signin = `Run OVERAI_ORG_ID=${target.organizationId} overai signin.`;
26938
+ const signin = signinHint(target.organizationId, baseUrl);
26753
26939
  if (deployment == null) throw new InteractiveSignInRequired(signin);
26754
26940
  if ((deployment.signedOut[target.organizationId] ?? 0) !== target.signedOut)
26755
26941
  throw new Error(`This org was signed out in another process. ${signin}`);
@@ -26815,6 +27001,7 @@ var getAccessToken = async () => {
26815
27001
  source.refreshToken = refreshed.refreshToken;
26816
27002
  source.accessToken = refreshed.token;
26817
27003
  source.accessTokenExpiresAt = Date.now() + refreshed.accessTokenValiditySeconds * 1e3;
27004
+ source.refreshTokenExpiresAt = refreshed.refreshTokenValiditySeconds == null ? void 0 : Date.now() + refreshed.refreshTokenValiditySeconds * 1e3;
26818
27005
  writeStore(store);
26819
27006
  }
26820
27007
  const sourceSessionId = decodeJwtClaims(source.accessToken).sid;
@@ -26875,9 +27062,11 @@ var getAccessToken = async () => {
26875
27062
  apiBaseUrl: baseUrl,
26876
27063
  identityId: claims.user_id,
26877
27064
  email: claims.email ?? target.email,
27065
+ organizationName: existing?.organizationName,
26878
27066
  refreshToken: result.refreshToken,
26879
27067
  accessToken: result.token,
26880
- accessTokenExpiresAt: Date.now() + result.accessTokenValiditySeconds * 1e3
27068
+ accessTokenExpiresAt: Date.now() + result.accessTokenValiditySeconds * 1e3,
27069
+ refreshTokenExpiresAt: result.refreshTokenValiditySeconds == null ? void 0 : Date.now() + result.refreshTokenValiditySeconds * 1e3
26881
27070
  };
26882
27071
  deployment.pending = omit(deployment.pending, target.organizationId);
26883
27072
  writeStore(store);
@@ -26885,6 +27074,34 @@ var getAccessToken = async () => {
26885
27074
  return { token: result.token, organizationId: target.organizationId };
26886
27075
  });
26887
27076
  };
27077
+ var accessTokenForSavedSession = async (backend, organizationId) => withStoreLock(async (store) => {
27078
+ const session = store.deployments[backend]?.sessions[organizationId];
27079
+ if (session == null)
27080
+ throw new InteractiveSignInRequired(
27081
+ signinHint(organizationId, backend)
27082
+ );
27083
+ if (session.accessToken != null && (session.accessTokenExpiresAt ?? 0) > Date.now() + 6e4)
27084
+ return session.accessToken;
27085
+ const result = await exchangeSessionToken(
27086
+ session.refreshToken,
27087
+ null,
27088
+ backend
27089
+ );
27090
+ if (result.type !== "success")
27091
+ throw new InteractiveSignInRequired(
27092
+ signinHint(organizationId, backend)
27093
+ );
27094
+ if (decodeJwtClaims(result.token).org !== organizationId)
27095
+ throw new Error(
27096
+ "The auth server returned a session for a different org or identity."
27097
+ );
27098
+ session.refreshToken = result.refreshToken;
27099
+ session.accessToken = result.token;
27100
+ session.accessTokenExpiresAt = Date.now() + result.accessTokenValiditySeconds * 1e3;
27101
+ session.refreshTokenExpiresAt = result.refreshTokenValiditySeconds == null ? void 0 : Date.now() + result.refreshTokenValiditySeconds * 1e3;
27102
+ writeStore(store);
27103
+ return result.token;
27104
+ });
26888
27105
  var v2Fetch = async (path, init) => {
26889
27106
  const auth = await getAccessToken();
26890
27107
  const headers = new Headers(init?.headers);
@@ -26944,6 +27161,43 @@ import { randomBytes as randomBytes2 } from "crypto";
26944
27161
  import { createServer } from "http";
26945
27162
  import { hostname } from "os";
26946
27163
 
27164
+ // src/args.ts
27165
+ import { readFileSync as readFileSync2 } from "fs";
27166
+ var flagValue = (args, ...names) => {
27167
+ for (const name2 of names) {
27168
+ const i = args.indexOf(name2);
27169
+ if (i !== -1 && i + 1 < args.length) return args[i + 1];
27170
+ }
27171
+ return void 0;
27172
+ };
27173
+ var stdinClaimedBy = null;
27174
+ var readStdin = async (claimant = "stdin") => {
27175
+ if (stdinClaimedBy != null) {
27176
+ throw new Error(
27177
+ `Only one value can be read from stdin; ${stdinClaimedBy} already consumed it.`
27178
+ );
27179
+ }
27180
+ stdinClaimedBy = claimant;
27181
+ const chunks = [];
27182
+ for await (const chunk of process.stdin) {
27183
+ chunks.push(chunk);
27184
+ }
27185
+ return Buffer.concat(chunks).toString("utf8");
27186
+ };
27187
+ var readValue = async (value, label) => {
27188
+ if (value?.startsWith("@") !== true) return value;
27189
+ if (value.startsWith("@@")) return value.slice(1);
27190
+ const path = value.slice(1);
27191
+ if (path === "-") return (await readStdin(`${label} @-`)).trim();
27192
+ try {
27193
+ return readFileSync2(path, "utf8").trim();
27194
+ } catch {
27195
+ throw new Error(
27196
+ `${label}: could not read file "${path}". Write "@@" to send a literal value starting with "@".`
27197
+ );
27198
+ }
27199
+ };
27200
+
26947
27201
  // src/browser.ts
26948
27202
  import { spawn } from "child_process";
26949
27203
  import { platform } from "os";
@@ -26958,6 +27212,60 @@ var openBrowser = (url) => {
26958
27212
  }
26959
27213
  };
26960
27214
 
27215
+ // src/output.ts
27216
+ var resolveFormat = (explicit) => {
27217
+ if (explicit === "json" || explicit === "csv" || explicit === "table") {
27218
+ return explicit;
27219
+ }
27220
+ if (explicit != null) {
27221
+ throw new Error(
27222
+ `Unknown output format "${explicit}". Use json, table, or csv.`
27223
+ );
27224
+ }
27225
+ return process.stdout.isTTY ? "table" : "json";
27226
+ };
27227
+ var cell = (value) => {
27228
+ if (value == null) return "";
27229
+ if (typeof value === "string") return value;
27230
+ if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
27231
+ return String(value);
27232
+ }
27233
+ return JSON.stringify(value);
27234
+ };
27235
+ var formatResult = (data, format2) => {
27236
+ if (format2 === "json" || !Array.isArray(data)) {
27237
+ return JSON.stringify(data, null, 2);
27238
+ }
27239
+ const records = data.map(
27240
+ (row) => row != null && typeof row === "object" ? row : { value: row }
27241
+ );
27242
+ if (records.length === 0) return "(no rows)";
27243
+ const columns = [...new Set(records.flatMap((r) => Object.keys(r)))];
27244
+ if (format2 === "csv") {
27245
+ const escape2 = (value) => {
27246
+ const text = cell(value);
27247
+ return /[",\n\r]/.test(text) ? `"${text.replace(/"/g, '""')}"` : text;
27248
+ };
27249
+ return [
27250
+ columns.join(","),
27251
+ ...records.map((r) => columns.map((c) => escape2(r[c])).join(","))
27252
+ ].join("\n");
27253
+ }
27254
+ const widths = columns.map(
27255
+ (c) => Math.max(c.length, ...records.map((r) => cell(r[c]).length))
27256
+ );
27257
+ const line = (cells) => cells.map((text, i) => text.padEnd(widths[i] ?? 0)).join(" ");
27258
+ return [
27259
+ line(columns),
27260
+ line(widths.map((w) => "-".repeat(w))),
27261
+ ...records.map((r) => line(columns.map((c) => cell(r[c]))))
27262
+ ].join("\n");
27263
+ };
27264
+ var printResult = (data, format2) => {
27265
+ process.stdout.write(`${formatResult(data, format2)}
27266
+ `);
27267
+ };
27268
+
26961
27269
  // src/pkce.ts
26962
27270
  import { createHash, randomBytes } from "crypto";
26963
27271
  var createPkcePair = () => {
@@ -26967,7 +27275,7 @@ var createPkcePair = () => {
26967
27275
  };
26968
27276
 
26969
27277
  // src/workspace/manifest.ts
26970
- import { existsSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
27278
+ import { existsSync, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
26971
27279
  import { dirname, join as join2, resolve } from "path";
26972
27280
  var MANIFEST_DIR = ".overai";
26973
27281
  var MANIFEST_FILE = "manifest.json";
@@ -26986,22 +27294,34 @@ var findWorkspaceRoot = (from = process.cwd()) => {
26986
27294
  }
26987
27295
  };
26988
27296
  var readManifest = (root) => JSON.parse(
26989
- readFileSync2(join2(root, MANIFEST_DIR, MANIFEST_FILE), "utf8")
27297
+ readFileSync3(join2(root, MANIFEST_DIR, MANIFEST_FILE), "utf8")
26990
27298
  );
26991
27299
  var openClone = () => {
26992
27300
  const root = findWorkspaceRoot();
26993
27301
  const manifest = readManifest(root);
26994
- if (orgIdOverride != null && orgIdOverride !== manifest.organizationId) {
27302
+ const override = orgOverride();
27303
+ if (override != null && override.orgId !== manifest.organizationId) {
27304
+ throw new Error(
27305
+ `${override.source}=${override.orgId} conflicts with this clone's org ${manifest.organizationId}. Drop it before syncing.`
27306
+ );
27307
+ }
27308
+ const namedRemote = override?.apiBaseUrl ?? apiBaseUrlOverride;
27309
+ if (namedRemote != null && manifest.apiBaseUrl != null && namedRemote !== manifest.apiBaseUrl) {
26995
27310
  throw new Error(
26996
- `OVERAI_ORG_ID=${orgIdOverride} conflicts with this clone's org ${manifest.organizationId}. Unset it before syncing.`
27311
+ `${override?.apiBaseUrl == null ? "OVERAI_API_URL" : override.source} names remote ${remoteName(namedRemote)}; this clone came from ${remoteName(manifest.apiBaseUrl)}.`
26997
27312
  );
26998
27313
  }
27314
+ if (manifest.apiBaseUrl != null)
27315
+ setCloneRemote(manifest.apiBaseUrl, manifest.organizationId);
26999
27316
  setOrgScope(manifest.organizationId);
27000
27317
  return { root, manifest };
27001
27318
  };
27002
27319
  var pinOrgFromClone = () => {
27003
27320
  try {
27004
- setOrgScope(readManifest(findWorkspaceRoot()).organizationId);
27321
+ const manifest = readManifest(findWorkspaceRoot());
27322
+ if (manifest.apiBaseUrl != null)
27323
+ setCloneRemote(manifest.apiBaseUrl, manifest.organizationId);
27324
+ setOrgScope(manifest.organizationId);
27005
27325
  } catch {
27006
27326
  }
27007
27327
  };
@@ -27022,14 +27342,14 @@ var writeSynced = (root, relPath, content) => {
27022
27342
  };
27023
27343
  var readWorkingFile = (root, relPath) => {
27024
27344
  try {
27025
- return readFileSync2(join2(root, relPath), "utf8");
27345
+ return readFileSync3(join2(root, relPath), "utf8");
27026
27346
  } catch {
27027
27347
  return null;
27028
27348
  }
27029
27349
  };
27030
27350
  var readBaseFile = (root, relPath) => {
27031
27351
  try {
27032
- return readFileSync2(basePath(root, relPath), "utf8");
27352
+ return readFileSync3(basePath(root, relPath), "utf8");
27033
27353
  } catch {
27034
27354
  return null;
27035
27355
  }
@@ -27116,11 +27436,28 @@ var startCallbackServer = (expectedState) => {
27116
27436
  });
27117
27437
  });
27118
27438
  };
27119
- var signIn = async (requestedOrgId = orgIdOverride) => {
27439
+ var signIn = async (target = orgRefOverride) => {
27440
+ const requestedOrgId = (() => {
27441
+ if (target == null) return void 0;
27442
+ if (target.startsWith("http://") || target.startsWith("https://")) {
27443
+ setRemoteScope(trimSlash(target));
27444
+ return orgOverride()?.orgId;
27445
+ }
27446
+ const remote = remoteOnlyRef(target);
27447
+ if (remote != null) {
27448
+ setRemoteScope(remote);
27449
+ return orgOverride()?.orgId;
27450
+ }
27451
+ const ref = parseOrgRef(target);
27452
+ if (ref.apiBaseUrl != null) setRemoteScope(ref.apiBaseUrl);
27453
+ return ref.orgId;
27454
+ })();
27120
27455
  const baseUrl = apiBaseUrl();
27121
27456
  const browserBaseUrl = appBaseUrl(baseUrl);
27122
27457
  if (browserBaseUrl === "")
27123
- throw new Error("Set OVERAI_APP_URL for this backend before signing in.");
27458
+ throw new Error(
27459
+ `No web address known for ${remoteName(baseUrl)}. Record one with: overai remote add <name> ${baseUrl} --app <appUrl>`
27460
+ );
27124
27461
  const initialStore = readStore();
27125
27462
  const { verifier, challenge } = createPkcePair();
27126
27463
  const state = randomBytes2(16).toString("base64url");
@@ -27183,12 +27520,16 @@ ${authorizeUrl}
27183
27520
  identityId: claims.user_id,
27184
27521
  email,
27185
27522
  accessToken: session.token,
27186
- accessTokenExpiresAt: Date.now() + session.accessTokenValiditySeconds * 1e3
27523
+ accessTokenExpiresAt: Date.now() + session.accessTokenValiditySeconds * 1e3,
27524
+ refreshTokenExpiresAt: Date.now() + session.refreshTokenValiditySeconds * 1e3
27187
27525
  };
27188
27526
  deployment.pending = omit(deployment.pending, session.organizationId);
27189
27527
  deployment.appBaseUrl = browserBaseUrl;
27190
27528
  deployment.defaultOrgId = session.organizationId;
27191
27529
  store.defaultApiBaseUrl = baseUrl;
27530
+ const derived = derivedRemoteName(baseUrl);
27531
+ if (derived != null && remoteUrl(derived, store) == null && !Object.values(store.remotes).some((url) => trimSlash(url) === baseUrl))
27532
+ store.remotes[derived] = baseUrl;
27192
27533
  writeStore(store);
27193
27534
  });
27194
27535
  } catch (error) {
@@ -27196,22 +27537,40 @@ ${authorizeUrl}
27196
27537
  throw error;
27197
27538
  }
27198
27539
  process.stdout.write(
27199
- `Signed in${email != null ? ` as ${email}` : ""} (org ${session.organizationId}).
27540
+ `Signed in${email != null ? ` as ${email}` : ""} to org ${session.organizationId} on ${remoteName(baseUrl)}.
27541
+ This is now the default for commands that don't name an org.
27200
27542
  `
27201
27543
  );
27202
27544
  } finally {
27203
27545
  close();
27204
27546
  }
27205
27547
  };
27206
- var signOut = async (all = false) => {
27207
- const root = (() => {
27208
- try {
27209
- return findWorkspaceRoot();
27210
- } catch {
27211
- return null;
27548
+ var signOut = async (all = false, target) => {
27549
+ if (target != null) {
27550
+ const ref = resolveOrgRef(target);
27551
+ const override = orgOverride();
27552
+ if (override != null && override.orgId !== ref.orgId) {
27553
+ throw new Error(
27554
+ `${override.source}=${override.orgId} conflicts with the requested org ${ref.orgId}. Drop it first.`
27555
+ );
27212
27556
  }
27213
- })();
27214
- if (root != null) setOrgScope(readManifest(root).organizationId);
27557
+ setRemoteScope(ref.apiBaseUrl);
27558
+ setOrgScope(ref.orgId);
27559
+ } else {
27560
+ const root = (() => {
27561
+ try {
27562
+ return findWorkspaceRoot();
27563
+ } catch {
27564
+ return null;
27565
+ }
27566
+ })();
27567
+ if (root != null) {
27568
+ const manifest = readManifest(root);
27569
+ if (manifest.apiBaseUrl != null)
27570
+ setCloneRemote(manifest.apiBaseUrl, manifest.organizationId);
27571
+ setOrgScope(manifest.organizationId);
27572
+ }
27573
+ }
27215
27574
  const baseUrl = apiBaseUrl();
27216
27575
  const orgId = scopedOrgId();
27217
27576
  await withStoreLock(async (store) => {
@@ -27265,11 +27624,11 @@ var signOut = async (all = false) => {
27265
27624
  );
27266
27625
  });
27267
27626
  process.stdout.write(
27268
- all ? "Signed out of all locally saved CLI sessions.\n" : `Signed out of org ${orgId ?? "(none selected)"}.
27627
+ all ? "Signed out of all locally saved CLI sessions.\n" : `Signed out of org ${orgId ?? "(none selected)"}${orgId == null ? "" : ` on ${remoteName(baseUrl)}`}.
27269
27628
  `
27270
27629
  );
27271
27630
  };
27272
- var whoami = () => {
27631
+ var whoami = (args = []) => {
27273
27632
  const root = (() => {
27274
27633
  try {
27275
27634
  return findWorkspaceRoot();
@@ -27277,108 +27636,40 @@ var whoami = () => {
27277
27636
  return null;
27278
27637
  }
27279
27638
  })();
27280
- if (root != null) setOrgScope(readManifest(root).organizationId);
27281
- const org = scopedOrgId();
27282
- const deployment = readStore().deployments[apiBaseUrl()];
27283
- const session = org == null ? void 0 : deployment?.sessions[org];
27284
- process.stdout.write(
27285
- `Backend: ${apiBaseUrl()}
27286
- Org: ${org ?? "none"}
27287
- Selected by: ${orgIdOverride != null ? "OVERAI_ORG_ID" : root != null ? ".overai/manifest.json" : "saved default"}
27288
- Identity: ${session?.email ?? session?.identityId ?? "no saved session for this org"}
27289
- `
27290
- );
27291
- };
27292
-
27293
- // src/args.ts
27294
- import { readFileSync as readFileSync3 } from "fs";
27295
- var flagValue = (args, ...names) => {
27296
- for (const name2 of names) {
27297
- const i = args.indexOf(name2);
27298
- if (i !== -1 && i + 1 < args.length) return args[i + 1];
27299
- }
27300
- return void 0;
27301
- };
27302
- var stdinClaimedBy = null;
27303
- var readStdin = async (claimant = "stdin") => {
27304
- if (stdinClaimedBy != null) {
27305
- throw new Error(
27306
- `Only one value can be read from stdin; ${stdinClaimedBy} already consumed it.`
27307
- );
27308
- }
27309
- stdinClaimedBy = claimant;
27310
- const chunks = [];
27311
- for await (const chunk of process.stdin) {
27312
- chunks.push(chunk);
27313
- }
27314
- return Buffer.concat(chunks).toString("utf8");
27315
- };
27316
- var readValue = async (value, label) => {
27317
- if (value?.startsWith("@") !== true) return value;
27318
- if (value.startsWith("@@")) return value.slice(1);
27319
- const path = value.slice(1);
27320
- if (path === "-") return (await readStdin(`${label} @-`)).trim();
27321
- try {
27322
- return readFileSync3(path, "utf8").trim();
27323
- } catch {
27324
- throw new Error(
27325
- `${label}: could not read file "${path}". Write "@@" to send a literal value starting with "@".`
27326
- );
27327
- }
27328
- };
27329
-
27330
- // src/output.ts
27331
- var resolveFormat = (explicit) => {
27332
- if (explicit === "json" || explicit === "csv" || explicit === "table") {
27333
- return explicit;
27334
- }
27335
- if (explicit != null) {
27336
- throw new Error(
27337
- `Unknown output format "${explicit}". Use json, table, or csv.`
27338
- );
27339
- }
27340
- return process.stdout.isTTY ? "table" : "json";
27341
- };
27342
- var cell = (value) => {
27343
- if (value == null) return "";
27344
- if (typeof value === "string") return value;
27345
- if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
27346
- return String(value);
27639
+ if (root != null) {
27640
+ const manifest = readManifest(root);
27641
+ if (manifest.apiBaseUrl != null)
27642
+ setCloneRemote(manifest.apiBaseUrl, manifest.organizationId);
27643
+ setOrgScope(manifest.organizationId);
27347
27644
  }
27348
- return JSON.stringify(value);
27349
- };
27350
- var formatResult = (data, format2) => {
27351
- if (format2 === "json" || !Array.isArray(data)) {
27352
- return JSON.stringify(data, null, 2);
27353
- }
27354
- const records = data.map(
27355
- (row) => row != null && typeof row === "object" ? row : { value: row }
27356
- );
27357
- if (records.length === 0) return "(no rows)";
27358
- const columns = [...new Set(records.flatMap((r) => Object.keys(r)))];
27359
- if (format2 === "csv") {
27360
- const escape2 = (value) => {
27361
- const text = cell(value);
27362
- return /[",\n\r]/.test(text) ? `"${text.replace(/"/g, '""')}"` : text;
27363
- };
27364
- return [
27365
- columns.join(","),
27366
- ...records.map((r) => columns.map((c) => escape2(r[c])).join(","))
27367
- ].join("\n");
27645
+ const store = readStore();
27646
+ const org = scopedOrgId();
27647
+ const backend = apiBaseUrl();
27648
+ const session = org == null ? void 0 : store.deployments[backend]?.sessions[org];
27649
+ const facts = {
27650
+ remote: remoteName(backend, store),
27651
+ apiBaseUrl: backend,
27652
+ org: org ?? "none",
27653
+ orgName: session?.organizationName ?? "",
27654
+ ref: org == null ? "" : orgRefText(org, backend, store),
27655
+ selectedBy: orgOverride()?.source ?? (root != null ? ".overai/manifest.json" : "saved default"),
27656
+ identity: session?.email ?? session?.identityId ?? "no saved session for this org",
27657
+ sessionExpires: expiresIn(session?.refreshTokenExpiresAt) ?? "unknown"
27658
+ };
27659
+ const format2 = resolveFormat(flagValue(args, "-o", "--output"));
27660
+ if (format2 !== "table") {
27661
+ printResult(facts, format2);
27662
+ return;
27368
27663
  }
27369
- const widths = columns.map(
27370
- (c) => Math.max(c.length, ...records.map((r) => cell(r[c]).length))
27664
+ process.stdout.write(
27665
+ [
27666
+ `Remote: ${facts.remote} (${facts.apiBaseUrl})`,
27667
+ `Org: ${facts.org}${facts.orgName === "" ? "" : ` (${facts.orgName})`}`,
27668
+ `Selected: ${facts.selectedBy}`,
27669
+ `Identity: ${facts.identity}`,
27670
+ `Session: ${facts.sessionExpires === "unknown" ? "expiry unknown" : facts.sessionExpires === "expired" ? "expired \u2014 sign in again" : `expires in ${facts.sessionExpires}`}`
27671
+ ].join("\n") + "\n"
27371
27672
  );
27372
- const line = (cells) => cells.map((text, i) => text.padEnd(widths[i] ?? 0)).join(" ");
27373
- return [
27374
- line(columns),
27375
- line(widths.map((w) => "-".repeat(w))),
27376
- ...records.map((r) => line(columns.map((c) => cell(r[c]))))
27377
- ].join("\n");
27378
- };
27379
- var printResult = (data, format2) => {
27380
- process.stdout.write(`${formatResult(data, format2)}
27381
- `);
27382
27673
  };
27383
27674
 
27384
27675
  // src/commands/agent.ts
@@ -27517,11 +27808,11 @@ var runAutomation = async (args) => {
27517
27808
  // src/workspace/validateElements.ts
27518
27809
  var findings = (parsed) => parsed.success ? [] : parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`);
27519
27810
  var validateAutomationElements = async (elements) => {
27520
- const { automationNodesSchema } = await import("./types-WI2WSJ3F.js");
27811
+ const { automationNodesSchema } = await import("./types-3BS55ING.js");
27521
27812
  return findings(automationNodesSchema.safeParse(elements));
27522
27813
  };
27523
27814
  var validateWebPageConfig = async (config) => {
27524
- const { webPageConfigWriteSchema } = await import("./webPage-3MNCKCRX.js");
27815
+ const { webPageConfigWriteSchema } = await import("./webPage-7BXDGWX5.js");
27525
27816
  return findings(webPageConfigWriteSchema.safeParse(config));
27526
27817
  };
27527
27818
 
@@ -34257,6 +34548,7 @@ var runClone = async (args, isShallow = false) => {
34257
34548
  workspaceId: entry.workspace.id,
34258
34549
  workspaceName: entry.workspace.name,
34259
34550
  organizationId: entry.workspace.organizationId,
34551
+ apiBaseUrl: apiBaseUrl(),
34260
34552
  resources: {}
34261
34553
  },
34262
34554
  resourcesByAdapter
@@ -35130,6 +35422,7 @@ var ID_PREFIXES = {
35130
35422
  },
35131
35423
  snaptrade_user: { prefix: "stu", body: 12 },
35132
35424
  storage_transcription: { prefix: "stc", body: 10 },
35425
+ storage_transcription_job: { prefix: "stj", body: 10 },
35133
35426
  storage_vision_conversion: {
35134
35427
  prefix: "svc",
35135
35428
  body: 20,
@@ -35249,6 +35542,7 @@ var runOpen = async (args) => {
35249
35542
  };
35250
35543
 
35251
35544
  // src/commands/org.ts
35545
+ import { createInterface } from "readline/promises";
35252
35546
  var USER_ORGS_QUERY = `
35253
35547
  query UserOrganizations($identityId: String!) {
35254
35548
  identityOrganizations(condition: { identityId: $identityId }) {
@@ -35259,55 +35553,369 @@ var USER_ORGS_QUERY = `
35259
35553
  }
35260
35554
  }
35261
35555
  `;
35262
- var listOrgRows = async () => {
35263
- const auth = await getAccessToken();
35264
- const identityId = decodeJwtClaims(auth.token).user_id;
35265
- if (identityId == null) {
35556
+ var collectOrgs = async () => {
35557
+ const store = readStore();
35558
+ const aliasFor = (orgId, backend) => Object.entries(store.aliases).find(([alias]) => {
35559
+ const [ref] = resultOfSync(() => resolveOrgRef(alias, store));
35560
+ return ref?.orgId === orgId && trimSlash(ref.apiBaseUrl) === backend;
35561
+ })?.[0] ?? "";
35562
+ const activeBackend = defaultApiBaseUrl(store);
35563
+ const rows = await Promise.all(
35564
+ Object.entries(store.deployments).filter(([, deployment]) => Object.keys(deployment.sessions).length > 0).map(async ([backend, deployment]) => {
35565
+ const name2 = remoteName(backend, store);
35566
+ const asOrg = deployment.defaultOrgId != null && deployment.sessions[deployment.defaultOrgId] != null ? deployment.defaultOrgId : Object.keys(deployment.sessions)[0] ?? "";
35567
+ const [memberships, failure] = await fetchOrgNames(backend, asOrg).then(
35568
+ (names) => [names, void 0],
35569
+ (error) => [
35570
+ /* @__PURE__ */ new Map(),
35571
+ error instanceof Error ? error.message : String(error)
35572
+ ]
35573
+ );
35574
+ const ids = /* @__PURE__ */ new Set([
35575
+ ...Object.keys(deployment.sessions),
35576
+ ...memberships.keys()
35577
+ ]);
35578
+ return [...ids].map((id) => {
35579
+ const session = deployment.sessions[id];
35580
+ return {
35581
+ active: backend === activeBackend && deployment.defaultOrgId === id,
35582
+ alias: aliasFor(id, backend),
35583
+ name: memberships.get(id) ?? session?.organizationName ?? "",
35584
+ id,
35585
+ remote: name2,
35586
+ apiBaseUrl: backend,
35587
+ session: failure ?? (session == null ? "signin required" : expiresIn(session.refreshTokenExpiresAt) ?? "saved")
35588
+ };
35589
+ });
35590
+ })
35591
+ );
35592
+ return rows.flat().sort(
35593
+ (a, b) => a.remote.localeCompare(b.remote) || a.name.localeCompare(b.name) || a.id.localeCompare(b.id)
35594
+ );
35595
+ };
35596
+ var fetchOrgNames = async (backend, organizationId) => {
35597
+ const token = await accessTokenForSavedSession(backend, organizationId);
35598
+ const identityId = decodeJwtClaims(token).user_id;
35599
+ if (identityId == null)
35266
35600
  throw new Error("Could not read identity from the current session.");
35267
- }
35268
- const data = await gqlRequest(USER_ORGS_QUERY, { identityId });
35269
- return data.identityOrganizations.nodes.filter((node) => node != null && !node.disabled).map((node) => node?.organization).filter((org) => org != null);
35601
+ const response = await fetch(`${backend}/v2/graphql`, {
35602
+ method: "POST",
35603
+ headers: {
35604
+ "Content-Type": "application/json",
35605
+ Authorization: `Bearer ${token}`
35606
+ },
35607
+ body: JSON.stringify({
35608
+ query: USER_ORGS_QUERY,
35609
+ variables: { identityId }
35610
+ }),
35611
+ signal: AbortSignal.timeout(3e4)
35612
+ });
35613
+ const body = await response.json().catch(() => null);
35614
+ const failure = body?.errors?.[0]?.message;
35615
+ if (failure != null) throw new Error(failure);
35616
+ if (body?.data == null)
35617
+ throw new Error(`HTTP ${String(response.status)} listing organizations`);
35618
+ return new Map(
35619
+ body.data.identityOrganizations.nodes.filter((node) => node != null && !node.disabled).map((node) => node?.organization).filter((org) => org != null).map((org) => [org.id, org.name ?? ""])
35620
+ );
35270
35621
  };
35271
- var listOrgs = async (args) => {
35272
- const active = scopedOrgId();
35622
+ var cacheOrgNames = async (rows) => {
35623
+ const named = rows.filter((row) => row.name !== "");
35624
+ if (named.length === 0) return;
35625
+ await withStoreLock((store) => {
35626
+ let changed = false;
35627
+ for (const row of named) {
35628
+ const session = store.deployments[row.apiBaseUrl]?.sessions[row.id];
35629
+ if (session == null || session.organizationName === row.name) continue;
35630
+ session.organizationName = row.name;
35631
+ changed = true;
35632
+ }
35633
+ if (changed) writeStore(store);
35634
+ });
35635
+ };
35636
+ var printOrgs = (rows, format2) => {
35637
+ const resolved = resolveFormat(format2);
35638
+ if (resolved !== "table") {
35639
+ printResult(rows, resolved);
35640
+ return;
35641
+ }
35642
+ const multiRemote = new Set(rows.map((row) => row.remote)).size > 1;
35643
+ const aliased = rows.some((row) => row.alias !== "");
35273
35644
  printResult(
35274
- (await listOrgRows()).map((org) => ({
35275
- id: org.id,
35276
- name: org.name ?? "",
35277
- active: org.id === active,
35278
- sessionSaved: readStore().deployments[apiBaseUrl()]?.sessions[org.id] != null
35645
+ rows.map((row) => ({
35646
+ "": row.active ? "*" : "",
35647
+ ...aliased ? { alias: row.alias } : {},
35648
+ name: row.name,
35649
+ id: row.id,
35650
+ ...multiRemote ? { remote: row.remote } : {},
35651
+ session: row.session
35279
35652
  })),
35280
- resolveFormat(flagValue(args, "-o", "--output"))
35653
+ resolved
35281
35654
  );
35282
35655
  };
35283
- var switchOrg = async (orgId) => {
35284
- if (orgIdOverride != null && orgIdOverride !== orgId) {
35656
+ var listOrgs = async (args) => {
35657
+ const rows = await collectOrgs();
35658
+ await cacheOrgNames(rows);
35659
+ printOrgs(rows, flagValue(args, "-o", "--output"));
35660
+ };
35661
+ var promptForOrg = async () => {
35662
+ if (!process.stdin.isTTY || !process.stdout.isTTY)
35285
35663
  throw new Error(
35286
- `OVERAI_ORG_ID=${orgIdOverride} conflicts with the requested org ${orgId}. Unset it first.`
35664
+ "Name the org to switch to: overai org switch <alias|orgId|remote:orgId>"
35665
+ );
35666
+ const rows = await collectOrgs();
35667
+ if (rows.length === 0)
35668
+ throw new Error("No organizations found. Run overai signin first.");
35669
+ rows.forEach((row, index) => {
35670
+ process.stdout.write(
35671
+ `${String(index + 1).padStart(2)}. ${row.active ? "*" : " "} ${row.name || row.id} ${row.id} ${row.remote}${row.alias === "" ? "" : ` (${row.alias})`}
35672
+ `
35287
35673
  );
35674
+ });
35675
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
35676
+ try {
35677
+ const answer = await rl.question("Switch to: ");
35678
+ const chosen = rows[Number(answer.trim()) - 1];
35679
+ if (chosen == null) throw new Error(`No org numbered "${answer.trim()}".`);
35680
+ return { orgId: chosen.id, apiBaseUrl: chosen.apiBaseUrl };
35681
+ } finally {
35682
+ rl.close();
35288
35683
  }
35289
- setOrgScope(orgId);
35684
+ };
35685
+ var switchOrg = async (target) => {
35686
+ const override = orgOverride();
35687
+ const ref = await iife(async () => {
35688
+ if (target == null) return promptForOrg();
35689
+ const remote = remoteOnlyRef(target);
35690
+ if (remote == null) return resolveOrgRef(target);
35691
+ const orgId = readStore().deployments[remote]?.defaultOrgId;
35692
+ if (orgId == null)
35693
+ throw new Error(
35694
+ `No default org saved for ${target}. Name one: overai org switch ${target}:<orgId>`
35695
+ );
35696
+ return { orgId, apiBaseUrl: remote };
35697
+ });
35698
+ if (override != null && override.orgId !== ref.orgId) {
35699
+ throw new Error(
35700
+ `${override.source}=${override.orgId} conflicts with the requested org ${ref.orgId}. Drop it first.`
35701
+ );
35702
+ }
35703
+ setRemoteScope(ref.apiBaseUrl);
35704
+ setOrgScope(ref.orgId);
35290
35705
  try {
35291
35706
  await getAccessToken();
35292
35707
  } catch (error) {
35293
35708
  if (!(error instanceof InteractiveSignInRequired)) throw error;
35294
- await signIn(orgId);
35709
+ await signIn(ref.orgId);
35295
35710
  }
35296
35711
  await withStoreLock((store) => {
35297
- const deployment = store.deployments[apiBaseUrl()];
35298
- if (deployment?.sessions[orgId] == null)
35712
+ const deployment = store.deployments[ref.apiBaseUrl];
35713
+ if (deployment?.sessions[ref.orgId] == null)
35299
35714
  throw new Error(
35300
35715
  "Session was signed out before the default could be changed."
35301
35716
  );
35302
- deployment.defaultOrgId = orgId;
35717
+ deployment.defaultOrgId = ref.orgId;
35718
+ store.defaultApiBaseUrl = ref.apiBaseUrl;
35303
35719
  writeStore(store);
35304
35720
  });
35305
35721
  process.stdout.write(
35306
- `Default org set to ${orgId}. Other org sessions are unchanged.
35307
- This default is machine-global; workspace folders and OVERAI_ORG_ID override it.
35722
+ `Default org set to ${ref.orgId} on ${remoteName(ref.apiBaseUrl)}. Other org sessions are unchanged.
35723
+ This default is machine-global; a clone folder, --org, and OVERAI_ORG_ID all override it.
35308
35724
  `
35309
35725
  );
35310
35726
  };
35727
+ var aliasRows = (store) => Object.entries(store.aliases).map(([alias, ref]) => ({ alias, ref })).sort((a, b) => a.alias.localeCompare(b.alias));
35728
+ var aliasOrg = async (args) => {
35729
+ const format2 = flagValue(args, "-o", "--output");
35730
+ const [alias, target] = args.filter(
35731
+ (arg, index) => !arg.startsWith("-") && args[index - 1] !== "-o" && args[index - 1] !== "--output"
35732
+ );
35733
+ if (alias == null) {
35734
+ printResult(aliasRows(readStore()), resolveFormat(format2));
35735
+ return;
35736
+ }
35737
+ if (target == null)
35738
+ throw new Error("Usage: overai org alias <name> <alias|orgId|remote:orgId>");
35739
+ if (alias.includes(":") || /\s/.test(alias))
35740
+ throw new Error(`Alias "${alias}" cannot contain ":" or whitespace.`);
35741
+ const ref = resolveOrgRef(target);
35742
+ await withStoreLock((store) => {
35743
+ const name2 = remoteName(ref.apiBaseUrl, store);
35744
+ store.aliases[alias] = name2 === trimSlash(ref.apiBaseUrl) ? ref.orgId : `${name2}:${ref.orgId}`;
35745
+ writeStore(store);
35746
+ });
35747
+ process.stdout.write(
35748
+ `${alias} \u2192 ${ref.orgId} on ${remoteName(ref.apiBaseUrl)}
35749
+ `
35750
+ );
35751
+ };
35752
+ var unaliasOrg = async (alias) => {
35753
+ await withStoreLock((store) => {
35754
+ if (store.aliases[alias] == null)
35755
+ throw new Error(`No alias named "${alias}".`);
35756
+ store.aliases = omit(store.aliases, alias);
35757
+ writeStore(store);
35758
+ });
35759
+ process.stdout.write(`Removed alias ${alias}.
35760
+ `);
35761
+ };
35762
+
35763
+ // src/commands/remote.ts
35764
+ var listRemotes = (args) => {
35765
+ const store = readStore();
35766
+ const active = defaultApiBaseUrl(store);
35767
+ const rows = knownRemotes(store).map((remote) => {
35768
+ const deployment = store.deployments[remote.apiBaseUrl];
35769
+ return {
35770
+ active: remote.apiBaseUrl === active,
35771
+ name: remote.name,
35772
+ apiBaseUrl: remote.apiBaseUrl,
35773
+ appBaseUrl: deployment?.appBaseUrl ?? "",
35774
+ signedInOrgs: Object.keys(deployment?.sessions ?? {}).length
35775
+ };
35776
+ });
35777
+ const format2 = resolveFormat(flagValue(args, "-o", "--output"));
35778
+ if (format2 !== "table") {
35779
+ printResult(rows, format2);
35780
+ return;
35781
+ }
35782
+ const customApp = rows.some((row) => row.appBaseUrl !== "");
35783
+ printResult(
35784
+ rows.map((row) => ({
35785
+ "": row.active ? "*" : "",
35786
+ name: row.name,
35787
+ api: row.apiBaseUrl,
35788
+ ...customApp ? { app: row.appBaseUrl } : {},
35789
+ orgs: row.signedInOrgs === 0 ? "" : String(row.signedInOrgs)
35790
+ })),
35791
+ format2
35792
+ );
35793
+ };
35794
+ var addRemote = async (args) => {
35795
+ const [name2, url] = args;
35796
+ if (name2 == null || url == null)
35797
+ throw new Error(
35798
+ "Usage: overai remote add <name> <apiUrl> [--app <appUrl>]"
35799
+ );
35800
+ if (name2.includes(":") || /\s/.test(name2))
35801
+ throw new Error(`Remote name "${name2}" cannot contain ":" or whitespace.`);
35802
+ if (!url.startsWith("http://") && !url.startsWith("https://"))
35803
+ throw new Error(`"${url}" is not an http(s) URL.`);
35804
+ const apiBaseUrl2 = trimSlash(url);
35805
+ const app = flagValue(args, "--app");
35806
+ await withStoreLock((store) => {
35807
+ const existing = remoteUrl(name2, store);
35808
+ if (existing != null && existing !== apiBaseUrl2)
35809
+ throw new Error(
35810
+ `"${name2}" already names ${existing}. Remove that remote first, or choose another name.`
35811
+ );
35812
+ store.remotes[name2] = apiBaseUrl2;
35813
+ if (app != null) {
35814
+ const deployment = store.deployments[apiBaseUrl2] ??= {
35815
+ sessions: {},
35816
+ pending: {},
35817
+ signedOut: {}
35818
+ };
35819
+ deployment.appBaseUrl = trimSlash(app);
35820
+ }
35821
+ writeStore(store);
35822
+ });
35823
+ process.stdout.write(
35824
+ `Added remote ${name2} \u2192 ${apiBaseUrl2}. Sign in with: overai signin ${name2}
35825
+ `
35826
+ );
35827
+ };
35828
+ var removeRemote = async (name2) => {
35829
+ const apiBaseUrl2 = remoteUrl(name2, readStore());
35830
+ if (apiBaseUrl2 == null) throw new Error(`No remote named "${name2}".`);
35831
+ if (BUILT_IN_REMOTES[name2] != null)
35832
+ throw new Error(
35833
+ `"${name2}" is built in and cannot be removed. Run overai signout --all to drop its sessions.`
35834
+ );
35835
+ await withStoreLock(async (store) => {
35836
+ const deployment = store.deployments[apiBaseUrl2];
35837
+ if (Object.keys(deployment?.pending ?? {}).length > 0)
35838
+ throw new Error(
35839
+ `${name2} has an unfinished org exchange. Run overai signout --all first.`
35840
+ );
35841
+ const failures = [];
35842
+ for (const [orgId, session] of Object.entries(deployment?.sessions ?? {})) {
35843
+ try {
35844
+ await signOutHeadless(session.refreshToken, apiBaseUrl2);
35845
+ if (deployment != null)
35846
+ deployment.sessions = omit(deployment.sessions, orgId);
35847
+ } catch {
35848
+ failures.push(orgId);
35849
+ }
35850
+ }
35851
+ if (failures.length > 0) {
35852
+ writeStore(store);
35853
+ throw new Error(
35854
+ `Could not revoke ${name2} org ${failures.join(", ")}. Credentials retained; retry.`
35855
+ );
35856
+ }
35857
+ store.remotes = omit(store.remotes, name2);
35858
+ store.deployments = omit(store.deployments, apiBaseUrl2);
35859
+ store.aliases = Object.fromEntries(
35860
+ Object.entries(store.aliases).filter(
35861
+ ([, ref]) => !ref.startsWith(`${name2}:`)
35862
+ )
35863
+ );
35864
+ if (store.defaultApiBaseUrl === apiBaseUrl2) delete store.defaultApiBaseUrl;
35865
+ writeStore(store);
35866
+ });
35867
+ process.stdout.write(`Removed remote ${name2}.
35868
+ `);
35869
+ };
35870
+ var renameRemote = async (from, to) => {
35871
+ if (BUILT_IN_REMOTES[from] != null)
35872
+ throw new Error(`"${from}" is built in and cannot be renamed.`);
35873
+ if (to.includes(":") || /\s/.test(to))
35874
+ throw new Error(`Remote name "${to}" cannot contain ":" or whitespace.`);
35875
+ await withStoreLock((store) => {
35876
+ const url = remoteUrl(from, store);
35877
+ if (url == null) throw new Error(`No remote named "${from}".`);
35878
+ const taken = remoteUrl(to, store);
35879
+ if (taken != null)
35880
+ throw new Error(`"${to}" already names ${taken}. Choose another name.`);
35881
+ store.remotes = { ...omit(store.remotes, from), [to]: url };
35882
+ store.aliases = Object.fromEntries(
35883
+ Object.entries(store.aliases).map(([alias, ref]) => [
35884
+ alias,
35885
+ ref.startsWith(`${from}:`) ? `${to}:${ref.slice(from.length + 1)}` : ref
35886
+ ])
35887
+ );
35888
+ writeStore(store);
35889
+ });
35890
+ process.stdout.write(`Renamed remote ${from} to ${to}.
35891
+ `);
35892
+ };
35893
+ var runRemote = async (args) => {
35894
+ const [subcommand, ...rest] = args;
35895
+ switch (subcommand) {
35896
+ case void 0:
35897
+ case "list":
35898
+ listRemotes(rest);
35899
+ return;
35900
+ case "add":
35901
+ await addRemote(rest);
35902
+ return;
35903
+ case "remove":
35904
+ case "rm":
35905
+ if (rest[0] == null) throw new Error("Usage: overai remote remove <name>");
35906
+ await removeRemote(rest[0]);
35907
+ return;
35908
+ case "rename":
35909
+ if (rest[0] == null || rest[1] == null)
35910
+ throw new Error("Usage: overai remote rename <old> <new>");
35911
+ await renameRemote(rest[0], rest[1]);
35912
+ return;
35913
+ default:
35914
+ throw new Error(
35915
+ "Usage: overai remote list | add <name> <apiUrl> [--app <url>] | remove <name> | rename <old> <new>"
35916
+ );
35917
+ }
35918
+ };
35311
35919
 
35312
35920
  // src/commands/printablePage.ts
35313
35921
  var runPrintablePage = async (args) => {
@@ -35978,10 +36586,13 @@ var platform2 = `# OverAI platform primer
35978
36586
  Saves reject a stale editing base without discarding your draft. Incorporate the latest saved changes before retrying; never retry with a newer base unless those changes have been reconciled. A save conflict does not deploy anything. Normal push sends the manifest base to an atomic server check. Only explicit --force omits it; never use --force as automatic conflict recovery.
35979
36587
 
35980
36588
  Organization context: Commands in a clone select its org automatically. Outside a clone,
35981
- use OVERAI_ORG_ID=<orgId>. Each backend/org has an independent saved session; org switch
35982
- changes only the machine-global default. Use whoami to inspect the effective scope.
35983
- If browser authorization is required, ask the user to run the suggested signin command.
35984
- Never change org to work around a clone-sync mismatch; use the correct workspace folder.
36589
+ put --org <ref> before the command (overai --org acme sql ...), or set OVERAI_ORG_ID for a
36590
+ whole shell. A ref is an org id, a local alias, or <remote>:<orgId>, and a named org
36591
+ selects its own deployment \u2014 never switch the machine-global default to reach another org,
36592
+ because every other session on the machine shares it. Each remote/org has an independent
36593
+ saved session. Use whoami to inspect the effective scope. If browser authorization is
36594
+ required, ask the user to run the suggested signin command. Never change org to work
36595
+ around a clone-sync mismatch; use the correct workspace folder.
35985
36596
 
35986
36597
  Resources live in Workspaces. The runtime always executes the DEPLOYED version
35987
36598
  of a resource, never the latest \u2014 \`overai push\` creates a version, \`overai
@@ -36444,7 +37055,7 @@ var runReview = async () => {
36444
37055
  };
36445
37056
 
36446
37057
  // src/commands/sql.ts
36447
- import { createInterface } from "readline";
37058
+ import { createInterface as createInterface2 } from "readline";
36448
37059
 
36449
37060
  // src/commands/sqlCredential.ts
36450
37061
  var connectionString = async (tableSpaceId, secret) => {
@@ -36475,11 +37086,11 @@ var runSqlCredential = async (args) => {
36475
37086
  const tableSpaceId = id;
36476
37087
  const name2 = flagValue(args, "--name");
36477
37088
  if (!name2) throw new Error("create requires --name <name>");
36478
- const expiresIn = flagValue(args, "--expires-in");
36479
- if (expiresIn && args.includes("--never")) {
37089
+ const expiresIn2 = flagValue(args, "--expires-in");
37090
+ if (expiresIn2 && args.includes("--never")) {
36480
37091
  throw new Error("Use either --expires-in <days> or --never, not both");
36481
37092
  }
36482
- const days = expiresIn ? Number(expiresIn) : 365;
37093
+ const days = expiresIn2 ? Number(expiresIn2) : 365;
36483
37094
  if (!args.includes("--never") && (!Number.isInteger(days) || days < 1)) {
36484
37095
  throw new Error("--expires-in must be a positive whole number of days");
36485
37096
  }
@@ -36588,7 +37199,7 @@ transaction \u2014 BEGIN/SET/temp tables don't carry across statements.
36588
37199
  `;
36589
37200
  var runRepl = async (organizationId, tableSpaceId, format2) => {
36590
37201
  const interactive = process.stdin.isTTY;
36591
- const rl = createInterface({
37202
+ const rl = createInterface2({
36592
37203
  input: process.stdin,
36593
37204
  ...interactive ? { output: process.stdout, historySize: 1e3, terminal: true } : {}
36594
37205
  });
@@ -36916,13 +37527,22 @@ var printUpdateNotice = async (check) => {
36916
37527
  var HELP = `overai \u2014 OverAI command-line interface
36917
37528
 
36918
37529
  Usage:
36919
- overai signin Sign in via your browser; choose your
36920
- organization there to complete SSO
36921
- overai signout [--all] Revoke this org\u2019s saved CLI session;
37530
+ overai signin [<ref> | <apiUrl>] Sign in via your browser; choose your
37531
+ organization there to complete SSO.
37532
+ A URL signs in to that deployment and
37533
+ remembers it as a remote
37534
+ overai signout [<ref>] [--all] Revoke one org\u2019s saved CLI session;
36922
37535
  --all revokes all locally saved sessions
36923
- overai whoami Show the current identity and org
36924
- overai org list List your organizations
36925
- overai org switch <orgId> Select the default org
37536
+ overai whoami Show the current remote, identity, and org
37537
+ overai org list Your organizations, on every remote
37538
+ overai org switch [<ref>] Select the default org and remote;
37539
+ no argument picks from a list
37540
+ overai org alias [<name> <ref>] Name an org locally, or list the names
37541
+ overai org unalias <name>
37542
+ overai remote list Deployments you can reach
37543
+ overai remote add <name> <apiUrl> [--app <url>]
37544
+ overai remote remove <name> Forget it and revoke its sessions
37545
+ overai remote rename <old> <new>
36926
37546
  overai workspace list [--archived] List workspaces you can see in this org
36927
37547
  overai workspace show [workspaceId] Show a workspace's name and overview
36928
37548
  overai workspace users [workspaceId] List users and effective/direct roles
@@ -37010,17 +37630,21 @@ it from stdin. Prefer that for anything long or quote-heavy: an inline value is
37010
37630
  parsed by your shell first, and one apostrophe inside it silently truncates the
37011
37631
  rest. Write @@ to send a literal value that starts with "@".
37012
37632
 
37013
- Organizations: OVERAI_ORG_ID selects an org for one command or shell, else commands
37014
- use the clone\u2019s org (.overai/manifest.json), else the saved default. Each backend
37015
- and org has its own session. Entering another org preserves existing sessions;
37016
- org switch changes only the machine-global default. Clone sync commands reject
37017
- conflicting overrides. SSO prompts name the signin command to run explicitly.
37018
- whoami shows the backend, org, identity, and selection source.
37633
+ Organizations: an org is named by a ref \u2014 <orgId>, an alias, or <remote>:<orgId> \u2014
37634
+ wherever one is accepted. --org (before the command) selects one for a single
37635
+ invocation and OVERAI_ORG_ID for a shell; else commands use the clone\u2019s org
37636
+ (.overai/manifest.json), else the saved default. A named org picks its own
37637
+ remote, so concurrent agents in different orgs never need a second variable.
37638
+ Each remote and org has its own session; entering another org preserves the
37639
+ existing ones, and org switch changes only the machine-global default.
37640
+ Clone sync commands reject conflicting overrides. whoami shows the effective
37641
+ remote, org, identity, and what selected them.
37019
37642
 
37020
37643
  Output: table on a TTY, JSON when piped; -o json|table|csv to force.
37021
37644
  Aliases: login = signin, logout = signout, ws = workspace.
37022
37645
  Env: OVERAI_API_URL, OVERAI_APP_URL override the target deployment.
37023
37646
  OVERAI_ORG_ID overrides the organization for this shell.
37647
+ Global flags (before the command): --org <ref>
37024
37648
  `;
37025
37649
  process.stdout.on("error", (error) => {
37026
37650
  if (error.code === "EPIPE") process.exit(0);
@@ -37033,6 +37657,7 @@ var ORG_AGNOSTIC_COMMANDS = /* @__PURE__ */ new Set([
37033
37657
  "logout",
37034
37658
  "whoami",
37035
37659
  "org",
37660
+ "remote",
37036
37661
  "clone",
37037
37662
  "update",
37038
37663
  "upgrade",
@@ -37054,8 +37679,23 @@ var SKIP_UPDATE_CHECK = /* @__PURE__ */ new Set([
37054
37679
  "--help",
37055
37680
  "-h"
37056
37681
  ]);
37682
+ var withoutLeadingFlags = (argv) => {
37683
+ let index = 0;
37684
+ while (argv[index]?.startsWith("--") === true) {
37685
+ const flag = argv[index] ?? "";
37686
+ if (!LEADING_FLAGS.includes(flag)) break;
37687
+ if (argv[index + 1] == null) throw new Error(`${flag} needs a value.`);
37688
+ index += 2;
37689
+ }
37690
+ return argv.slice(index);
37691
+ };
37057
37692
  var run = async () => {
37058
- const [command2, ...rest] = process.argv.slice(2);
37693
+ const [command2, ...rest] = withoutLeadingFlags(process.argv.slice(2));
37694
+ const misplaced = rest.find((arg) => LEADING_FLAGS.includes(arg));
37695
+ if (misplaced != null)
37696
+ throw new Error(
37697
+ `${misplaced} goes before the command: overai ${misplaced} <ref> ${command2 ?? "<command>"} ...`
37698
+ );
37059
37699
  if (command2 != null && !ORG_AGNOSTIC_COMMANDS.has(command2)) {
37060
37700
  pinOrgFromClone();
37061
37701
  announceOrgScope();
@@ -37074,25 +37714,41 @@ var run = async () => {
37074
37714
  switch (command2) {
37075
37715
  case "signin":
37076
37716
  case "login":
37077
- await signIn();
37717
+ await signIn(rest.find((arg) => !arg.startsWith("-")));
37078
37718
  return;
37079
37719
  case "signout":
37080
37720
  case "logout":
37081
- await signOut(rest.includes("--all"));
37721
+ await signOut(
37722
+ rest.includes("--all"),
37723
+ rest.find((arg) => !arg.startsWith("-"))
37724
+ );
37082
37725
  return;
37083
37726
  case "whoami":
37084
- whoami();
37727
+ whoami(rest);
37728
+ return;
37729
+ case "remote":
37730
+ await runRemote(rest);
37085
37731
  return;
37086
37732
  case "org":
37087
37733
  if (rest[0] === "list") {
37088
37734
  await listOrgs(rest.slice(1));
37089
37735
  return;
37090
37736
  }
37091
- if (rest[0] === "switch" && rest[1] != null) {
37737
+ if (rest[0] === "switch") {
37092
37738
  await switchOrg(rest[1]);
37093
37739
  return;
37094
37740
  }
37095
- process.stderr.write("Usage: overai org list | org switch <orgId>\n");
37741
+ if (rest[0] === "alias") {
37742
+ await aliasOrg(rest.slice(1));
37743
+ return;
37744
+ }
37745
+ if (rest[0] === "unalias" && rest[1] != null) {
37746
+ await unaliasOrg(rest[1]);
37747
+ return;
37748
+ }
37749
+ process.stderr.write(
37750
+ "Usage: overai org list | org switch [<ref>] | org alias [<name> <ref>] | org unalias <name>\n"
37751
+ );
37096
37752
  process.exitCode = 1;
37097
37753
  return;
37098
37754
  case "workspace":
@@ -37203,7 +37859,10 @@ ${HELP}`);
37203
37859
  process.exitCode = 1;
37204
37860
  }
37205
37861
  };
37206
- var [command] = process.argv.slice(2);
37862
+ var [parsedArgv] = resultOfSync(
37863
+ () => withoutLeadingFlags(process.argv.slice(2))
37864
+ );
37865
+ var [command] = parsedArgv ?? ["help"];
37207
37866
  var updateNotice2 = process.env.OVERAI_SKIP_UPDATE_CHECK === "1" || !process.stderr.isTTY || SKIP_UPDATE_CHECK.has(command) ? null : startUpdateCheck();
37208
37867
  run().catch((error) => {
37209
37868
  process.stderr.write(