@overaihq/cli 0.14.6 → 0.14.8

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
@@ -6,7 +6,7 @@ import {
6
6
  itemFilterExpressionRootSchema,
7
7
  reactDefaultTemplate,
8
8
  webPageConfigSchema
9
- } from "./chunk-4QWKERK2.js";
9
+ } from "./chunk-7BY65TM4.js";
10
10
  import {
11
11
  external_exports
12
12
  } from "./chunk-PF6GZFT4.js";
@@ -8000,12 +8000,12 @@ var require_dom = __commonJS({
8000
8000
  if (node !== base && node.nodeType === ELEMENT_NODE) {
8001
8001
  var nodeClassNames = node.getAttribute("class");
8002
8002
  if (nodeClassNames) {
8003
- var matches = classNames === nodeClassNames;
8004
- if (!matches) {
8003
+ var matches2 = classNames === nodeClassNames;
8004
+ if (!matches2) {
8005
8005
  var nodeClassNamesSet = toOrderedSet(nodeClassNames);
8006
- matches = classNamesSet.every(arrayIncludes2(nodeClassNamesSet));
8006
+ matches2 = classNamesSet.every(arrayIncludes2(nodeClassNamesSet));
8007
8007
  }
8008
- if (matches) {
8008
+ if (matches2) {
8009
8009
  ls.push(node);
8010
8010
  }
8011
8011
  }
@@ -13757,11 +13757,11 @@ var require_lib2 = __commonJS({
13757
13757
  }
13758
13758
  addComment(comment) {
13759
13759
  if (this.flowPragma === void 0) {
13760
- const matches = FLOW_PRAGMA_REGEX.exec(comment.value);
13761
- if (!matches) ;
13762
- else if (matches[1] === "flow") {
13760
+ const matches2 = FLOW_PRAGMA_REGEX.exec(comment.value);
13761
+ if (!matches2) ;
13762
+ else if (matches2[1] === "flow") {
13763
13763
  this.flowPragma = "flow";
13764
- } else if (matches[1] === "noflow") {
13764
+ } else if (matches2[1] === "noflow") {
13765
13765
  this.flowPragma = "noflow";
13766
13766
  } else {
13767
13767
  throw new Error("Unexpected flow pragma");
@@ -26793,42 +26793,8 @@ var expiresIn = (at) => {
26793
26793
  return hours < 48 ? `${String(hours)}h` : `${String(Math.floor(hours / 24))}d`;
26794
26794
  };
26795
26795
 
26796
- // ../common/src/stdlib/iife.ts
26797
- var iife = (fn2) => fn2();
26798
-
26799
- // ../common/src/stdlib/omit.ts
26800
- var omit = (obj, ...keys) => {
26801
- const result = { ...obj };
26802
- keys.forEach((key) => delete result[key]);
26803
- return result;
26804
- };
26805
-
26806
- // src/api.ts
26807
- var commandApiBaseUrl;
26808
- var explicitRemote;
26809
- var cloneRemote;
26810
- var setRemoteScope = (apiBaseUrl_) => {
26811
- if (commandApiBaseUrl != null && commandApiBaseUrl !== apiBaseUrl_)
26812
- throw new Error("Cannot change remote after a command has started.");
26813
- explicitRemote = apiBaseUrl_;
26814
- };
26815
- var setCloneRemote = (apiBaseUrl_, organizationId) => {
26816
- cloneRemote = { apiBaseUrl: apiBaseUrl_, organizationId };
26817
- };
26818
- var apiBaseUrl = () => commandApiBaseUrl ??= iife(() => {
26819
- if (apiBaseUrlOverride != null) return apiBaseUrlOverride;
26820
- if (explicitRemote != null) return explicitRemote;
26821
- const store = readStore();
26822
- const override = orgOverride();
26823
- if (override?.apiBaseUrl != null) return override.apiBaseUrl;
26824
- if (cloneRemote != null && (override == null || override.orgId === cloneRemote.organizationId))
26825
- return cloneRemote.apiBaseUrl;
26826
- const overrideHome = override == null ? void 0 : remoteForOrg(override.orgId, store);
26827
- if (overrideHome != null) return overrideHome;
26828
- if (cloneRemote != null) return cloneRemote.apiBaseUrl;
26829
- return (orgScopeOverride == null ? void 0 : remoteForOrg(orgScopeOverride, store)) ?? defaultApiBaseUrl(store);
26830
- });
26831
- var AuthRpcError = class extends Error {
26796
+ // ../sdk/src/trpc.ts
26797
+ var TrpcError = class extends Error {
26832
26798
  constructor(status, message) {
26833
26799
  super(message);
26834
26800
  this.status = status;
@@ -26838,7 +26804,7 @@ var AuthRpcError = class extends Error {
26838
26804
  var trpcResult = async (res, procedure) => {
26839
26805
  const body = await res.json().catch(() => null);
26840
26806
  if (body != null && "error" in body) {
26841
- throw new AuthRpcError(
26807
+ throw new TrpcError(
26842
26808
  res.status,
26843
26809
  body.error.message || `${procedure} failed (${String(res.status)})`
26844
26810
  );
@@ -26848,7 +26814,7 @@ var trpcResult = async (res, procedure) => {
26848
26814
  }
26849
26815
  return body.result.data;
26850
26816
  };
26851
- var trpcMutation = async (procedure, input, baseUrl = apiBaseUrl()) => {
26817
+ var unauthenticatedTrpc = async (baseUrl, procedure, input) => {
26852
26818
  const res = await fetch(
26853
26819
  `${baseUrl}/v1/utils/trpc/unauthenticated/${procedure}`,
26854
26820
  {
@@ -26860,33 +26826,215 @@ var trpcMutation = async (procedure, input, baseUrl = apiBaseUrl()) => {
26860
26826
  );
26861
26827
  return trpcResult(res, procedure);
26862
26828
  };
26863
- var exchangeCliAuthCode = (code, codeVerifier) => trpcMutation("exchangeCliAuthCode", { code, codeVerifier });
26864
- var exchangeSessionToken = (refreshToken, destinationOrgId, backend = apiBaseUrl()) => trpcMutation(
26865
- "exchangeSessionToken",
26866
- { refreshToken, destinationOrgId },
26867
- backend
26868
- );
26869
- var signOutHeadless = (refreshToken, baseUrl = apiBaseUrl()) => trpcMutation(
26870
- "signOutHeadless",
26871
- { refreshToken },
26872
- baseUrl
26873
- );
26874
- var cancelCliOrgSession = (sourceSessionId, sourceRefreshToken, destinationOrgId, requestId, backend = apiBaseUrl()) => trpcMutation(
26875
- "cancelCliOrgSession",
26876
- { sourceSessionId, sourceRefreshToken, destinationOrgId, requestId },
26877
- backend
26878
- );
26879
- var InteractiveSignInRequired = class extends Error {
26829
+
26830
+ // ../sdk/src/auth.ts
26831
+ var exchangeSessionToken = (baseUrl, refreshToken, destinationOrgId) => unauthenticatedTrpc(baseUrl, "exchangeSessionToken", {
26832
+ refreshToken,
26833
+ destinationOrgId
26834
+ });
26835
+
26836
+ // ../sdk/src/error.ts
26837
+ var OverAIError = class extends Error {
26838
+ /** HTTP status; 200 for a GraphQL errors-array failure. */
26839
+ status;
26840
+ /** URL pathname of the request, "" when unknown. */
26841
+ path;
26842
+ /** Parsed JSON body, the raw string when not JSON, or null. */
26843
+ body;
26844
+ /** The org the request ran as, when known. */
26845
+ organizationId;
26846
+ /** GraphQL errors array, when that is the cause. */
26847
+ errors;
26848
+ constructor(message, fields) {
26849
+ super(message);
26850
+ this.status = fields.status;
26851
+ this.path = fields.path;
26852
+ this.body = fields.body;
26853
+ this.organizationId = fields.organizationId;
26854
+ if (fields.errors != null) this.errors = fields.errors;
26855
+ }
26856
+ };
26857
+ var responsePath = (res) => {
26858
+ try {
26859
+ return new URL(res.url).pathname;
26860
+ } catch {
26861
+ return "";
26862
+ }
26863
+ };
26864
+ var STATUS_TEXT = {
26865
+ 400: "Bad Request",
26866
+ 401: "Unauthorized",
26867
+ 403: "Forbidden",
26868
+ 404: "Not Found",
26869
+ 409: "Conflict",
26870
+ 413: "Payload Too Large",
26871
+ 429: "Too Many Requests",
26872
+ 500: "Internal Server Error",
26873
+ 503: "Service Unavailable"
26880
26874
  };
26875
+ var apiError = (label, res, rawBody, organizationId) => {
26876
+ const body = (() => {
26877
+ try {
26878
+ return JSON.parse(rawBody);
26879
+ } catch {
26880
+ return rawBody;
26881
+ }
26882
+ })();
26883
+ const structured = typeof body === "object" && body != null ? body : null;
26884
+ const field = structured?.error ?? structured?.message;
26885
+ const claimed = (typeof field === "string" ? field : rawBody).trim().slice(0, 500);
26886
+ const reason = claimed.length === 0 || claimed === "Error" || claimed === "null" || claimed === "undefined" || claimed.toLowerCase() === STATUS_TEXT[res.status]?.toLowerCase() ? null : claimed;
26887
+ const path = responsePath(res);
26888
+ const fields = { status: res.status, path, body, organizationId };
26889
+ if (reason != null) return new OverAIError(reason, fields);
26890
+ return new OverAIError(
26891
+ `${label}: HTTP ${String(res.status)}, no reason given by the server.${path === "" ? "" : `
26892
+ ${path}`}${organizationId == null ? "" : `
26893
+ Asked as org ${organizationId}.`}`,
26894
+ fields
26895
+ );
26896
+ };
26897
+
26898
+ // ../sdk/src/jwt.ts
26881
26899
  var decodeJwtClaims = (token) => {
26882
26900
  const payload = token.split(".")[1];
26883
26901
  if (payload == null) return {};
26884
26902
  try {
26885
- return JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
26903
+ const binary = atob(payload.replaceAll("-", "+").replaceAll("_", "/"));
26904
+ return JSON.parse(
26905
+ new TextDecoder().decode(
26906
+ Uint8Array.from(binary, (char) => char.charCodeAt(0))
26907
+ )
26908
+ );
26886
26909
  } catch {
26887
26910
  return {};
26888
26911
  }
26889
26912
  };
26913
+
26914
+ // ../sdk/src/tokens.ts
26915
+ var exchangeSchema = external_exports.object({ token: external_exports.string(), expiresIn: external_exports.number() });
26916
+ var staticToken = (jwt) => () => jwt;
26917
+
26918
+ // ../sdk/src/client.ts
26919
+ var OverAIClient = class {
26920
+ baseUrl;
26921
+ #token;
26922
+ #claims = null;
26923
+ constructor(options) {
26924
+ this.baseUrl = options.baseUrl.replace(/\/+$/, "");
26925
+ this.#token = typeof options.token === "string" ? staticToken(options.token) : options.token;
26926
+ }
26927
+ /** Authenticated fetch to `${baseUrl}${path}`; sets Authorization: Bearer <token>. Does not throw on non-2xx. */
26928
+ async fetch(path, init) {
26929
+ const token = await this.#token();
26930
+ this.#claims = decodeJwtClaims(token);
26931
+ const headers = new Headers(init?.headers);
26932
+ headers.set("Authorization", `Bearer ${token}`);
26933
+ return fetch(`${this.baseUrl}${path}`, { ...init, headers });
26934
+ }
26935
+ /**
26936
+ * POST /v2/graphql. Throws with the server's error messages — callers (and
26937
+ * agents driving them) need the actual reason, not a status code.
26938
+ */
26939
+ async graphql(query, variables) {
26940
+ const res = await this.fetch("/v2/graphql", {
26941
+ method: "POST",
26942
+ headers: { "Content-Type": "application/json" },
26943
+ body: JSON.stringify({ query, variables })
26944
+ });
26945
+ const raw2 = await res.text();
26946
+ const body = (() => {
26947
+ try {
26948
+ return JSON.parse(raw2);
26949
+ } catch {
26950
+ return null;
26951
+ }
26952
+ })();
26953
+ const organizationId = this.claims()?.org ?? null;
26954
+ if (body?.errors != null && body.errors.length > 0) {
26955
+ throw new OverAIError(body.errors.map((e) => e.message).join("; "), {
26956
+ status: res.status,
26957
+ path: responsePath(res),
26958
+ body,
26959
+ organizationId,
26960
+ errors: body.errors
26961
+ });
26962
+ }
26963
+ if (!res.ok) throw apiError("graphql", res, raw2, organizationId);
26964
+ if (body?.data == null) {
26965
+ throw new OverAIError("graphql returned no data and no errors.", {
26966
+ status: res.status,
26967
+ path: responsePath(res),
26968
+ body,
26969
+ organizationId
26970
+ });
26971
+ }
26972
+ return body.data;
26973
+ }
26974
+ /** POST to the JWT-gated user tRPC router; returns the procedure's data. */
26975
+ async trpc(procedure, input) {
26976
+ const res = await this.fetch(`/v1/utils/trpc/${procedure}`, {
26977
+ method: "POST",
26978
+ headers: { "Content-Type": "application/json" },
26979
+ body: JSON.stringify(input)
26980
+ });
26981
+ return trpcResult(res, procedure);
26982
+ }
26983
+ /** Claims of the JWT most recently obtained from the token source, or null before any request. Display only. */
26984
+ claims() {
26985
+ return this.#claims;
26986
+ }
26987
+ };
26988
+ var createClient = (options) => new OverAIClient(options);
26989
+
26990
+ // ../common/src/stdlib/iife.ts
26991
+ var iife = (fn2) => fn2();
26992
+
26993
+ // ../common/src/stdlib/omit.ts
26994
+ var omit = (obj, ...keys) => {
26995
+ const result = { ...obj };
26996
+ keys.forEach((key) => delete result[key]);
26997
+ return result;
26998
+ };
26999
+
27000
+ // src/api.ts
27001
+ var commandApiBaseUrl;
27002
+ var explicitRemote;
27003
+ var cloneRemote;
27004
+ var setRemoteScope = (apiBaseUrl_) => {
27005
+ if (commandApiBaseUrl != null && commandApiBaseUrl !== apiBaseUrl_)
27006
+ throw new Error("Cannot change remote after a command has started.");
27007
+ explicitRemote = apiBaseUrl_;
27008
+ };
27009
+ var setCloneRemote = (apiBaseUrl_, organizationId) => {
27010
+ cloneRemote = { apiBaseUrl: apiBaseUrl_, organizationId };
27011
+ };
27012
+ var apiBaseUrl = () => commandApiBaseUrl ??= iife(() => {
27013
+ if (apiBaseUrlOverride != null) return apiBaseUrlOverride;
27014
+ if (explicitRemote != null) return explicitRemote;
27015
+ const store = readStore();
27016
+ const override = orgOverride();
27017
+ if (override?.apiBaseUrl != null) return override.apiBaseUrl;
27018
+ if (cloneRemote != null && (override == null || override.orgId === cloneRemote.organizationId))
27019
+ return cloneRemote.apiBaseUrl;
27020
+ const overrideHome = override == null ? void 0 : remoteForOrg(override.orgId, store);
27021
+ if (overrideHome != null) return overrideHome;
27022
+ if (cloneRemote != null) return cloneRemote.apiBaseUrl;
27023
+ return (orgScopeOverride == null ? void 0 : remoteForOrg(orgScopeOverride, store)) ?? defaultApiBaseUrl(store);
27024
+ });
27025
+ var exchangeCliAuthCode = (code, codeVerifier) => unauthenticatedTrpc(apiBaseUrl(), "exchangeCliAuthCode", { code, codeVerifier });
27026
+ var exchangeSessionToken2 = (refreshToken, destinationOrgId, backend = apiBaseUrl()) => exchangeSessionToken(backend, refreshToken, destinationOrgId);
27027
+ var signOutHeadless = (refreshToken, baseUrl = apiBaseUrl()) => unauthenticatedTrpc(baseUrl, "signOutHeadless", {
27028
+ refreshToken
27029
+ });
27030
+ var cancelCliOrgSession = (sourceSessionId, sourceRefreshToken, destinationOrgId, requestId, backend = apiBaseUrl()) => unauthenticatedTrpc(backend, "cancelCliOrgSession", {
27031
+ sourceSessionId,
27032
+ sourceRefreshToken,
27033
+ destinationOrgId,
27034
+ requestId
27035
+ });
27036
+ var InteractiveSignInRequired = class extends Error {
27037
+ };
26890
27038
  var orgScopeOverride = null;
26891
27039
  var commandContext;
26892
27040
  var setOrgScope = (organizationId) => {
@@ -26961,9 +27109,9 @@ var getAccessToken = async () => {
26961
27109
  }
26962
27110
  const result = await (async () => {
26963
27111
  if (existing != null) {
26964
- return exchangeSessionToken(existing.refreshToken, null).catch(
27112
+ return exchangeSessionToken2(existing.refreshToken, null).catch(
26965
27113
  (error) => {
26966
- if (error instanceof AuthRpcError && (error.status === 400 || error.status === 401))
27114
+ if (error instanceof TrpcError && (error.status === 400 || error.status === 401))
26967
27115
  throw new InteractiveSignInRequired(
26968
27116
  `Session expired or revoked. ${signin}`
26969
27117
  );
@@ -26977,11 +27125,11 @@ var getAccessToken = async () => {
26977
27125
  );
26978
27126
  for (const source of candidates) {
26979
27127
  if (source.accessToken == null || decodeJwtClaims(source.accessToken).sid == null) {
26980
- const refreshed = await exchangeSessionToken(
27128
+ const refreshed = await exchangeSessionToken2(
26981
27129
  source.refreshToken,
26982
27130
  null
26983
27131
  ).catch((error) => {
26984
- if (error instanceof AuthRpcError && (error.status === 400 || error.status === 401))
27132
+ if (error instanceof TrpcError && (error.status === 400 || error.status === 401))
26985
27133
  return null;
26986
27134
  throw error;
26987
27135
  });
@@ -27018,7 +27166,8 @@ var getAccessToken = async () => {
27018
27166
  };
27019
27167
  deployment.pending[target.organizationId] = operation;
27020
27168
  writeStore(store);
27021
- const response = await trpcMutation(
27169
+ const response = await unauthenticatedTrpc(
27170
+ baseUrl,
27022
27171
  "establishCliOrgSession",
27023
27172
  {
27024
27173
  refreshToken: source.refreshToken,
@@ -27026,8 +27175,7 @@ var getAccessToken = async () => {
27026
27175
  requestId: operation.requestId
27027
27176
  }
27028
27177
  ).catch((error) => {
27029
- if (error instanceof AuthRpcError && error.status === 401)
27030
- return null;
27178
+ if (error instanceof TrpcError && error.status === 401) return null;
27031
27179
  throw new Error(
27032
27180
  `Could not establish an independent org session: ${error instanceof Error ? error.message : String(error)}. No legacy switch was attempted.`
27033
27181
  );
@@ -27080,20 +27228,16 @@ var getAccessToken = async () => {
27080
27228
  var accessTokenForSavedSession = async (backend, organizationId) => withStoreLock(async (store) => {
27081
27229
  const session = store.deployments[backend]?.sessions[organizationId];
27082
27230
  if (session == null)
27083
- throw new InteractiveSignInRequired(
27084
- signinHint(organizationId, backend)
27085
- );
27231
+ throw new InteractiveSignInRequired(signinHint(organizationId, backend));
27086
27232
  if (session.accessToken != null && (session.accessTokenExpiresAt ?? 0) > Date.now() + 6e4)
27087
27233
  return session.accessToken;
27088
- const result = await exchangeSessionToken(
27234
+ const result = await exchangeSessionToken2(
27089
27235
  session.refreshToken,
27090
27236
  null,
27091
27237
  backend
27092
27238
  );
27093
27239
  if (result.type !== "success")
27094
- throw new InteractiveSignInRequired(
27095
- signinHint(organizationId, backend)
27096
- );
27240
+ throw new InteractiveSignInRequired(signinHint(organizationId, backend));
27097
27241
  if (decodeJwtClaims(result.token).org !== organizationId)
27098
27242
  throw new Error(
27099
27243
  "The auth server returned a session for a different org or identity."
@@ -27105,59 +27249,19 @@ var accessTokenForSavedSession = async (backend, organizationId) => withStoreLoc
27105
27249
  writeStore(store);
27106
27250
  return result.token;
27107
27251
  });
27108
- var v2Fetch = async (path, init) => {
27109
- const auth = await getAccessToken();
27110
- const headers = new Headers(init?.headers);
27111
- headers.set("Authorization", `Bearer ${auth.token}`);
27112
- return fetch(`${apiBaseUrl()}${path}`, { ...init, headers });
27113
- };
27114
- var STATUS_TEXT = {
27115
- 400: "Bad Request",
27116
- 401: "Unauthorized",
27117
- 403: "Forbidden",
27118
- 404: "Not Found",
27119
- 409: "Conflict",
27120
- 413: "Payload Too Large",
27121
- 429: "Too Many Requests",
27122
- 500: "Internal Server Error",
27123
- 503: "Service Unavailable"
27124
- };
27125
- var v2Error = (label, res, rawBody) => {
27126
- const structured = (() => {
27127
- try {
27128
- return JSON.parse(rawBody);
27129
- } catch {
27130
- return null;
27131
- }
27132
- })();
27133
- const field = structured?.error ?? structured?.message;
27134
- const claimed = (typeof field === "string" ? field : rawBody).trim().slice(0, 500);
27135
- const reason = claimed.length === 0 || claimed === "Error" || claimed === "null" || claimed === "undefined" || claimed.toLowerCase() === STATUS_TEXT[res.status]?.toLowerCase() ? null : claimed;
27136
- const orgHint = res.status === 404 || res.status === 403 ? `
27137
- If it lives in another org, name that org: overai --org <ref> ... (\`overai org list\` shows them, \`overai org alias\` your shorthands).` : "";
27138
- if (reason != null) return new Error(`${reason}${orgHint}`);
27139
- const path = (() => {
27140
- try {
27141
- return new URL(res.url).pathname;
27142
- } catch {
27143
- return "";
27144
- }
27145
- })();
27146
- const org = scopedOrgId();
27147
- return new Error(
27148
- `${label}: HTTP ${String(res.status)}, no reason given by the server.${path === "" ? "" : `
27149
- ${path}`}${org == null ? "" : `
27150
- Asked as org ${org}.`}${orgHint}`
27151
- );
27152
- };
27153
- var userTrpcMutation = async (procedure, input) => {
27154
- const res = await v2Fetch(`/v1/utils/trpc/${procedure}`, {
27155
- method: "POST",
27156
- headers: { "Content-Type": "application/json" },
27157
- body: JSON.stringify(input)
27158
- });
27159
- return trpcResult(res, procedure);
27160
- };
27252
+ var cliClient = () => createClient({
27253
+ baseUrl: apiBaseUrl(),
27254
+ token: async () => (await getAccessToken()).token
27255
+ });
27256
+ var v2Fetch = async (path, init) => cliClient().fetch(path, init);
27257
+ var v2Error = (label, res, rawBody) => withOrgHint(apiError(label, res, rawBody, scopedOrgId()));
27258
+ var withOrgHint = (error) => {
27259
+ if (error.status === 404 || error.status === 403)
27260
+ error.message = `${error.message}
27261
+ If it lives in another org, name that org: overai --org <ref> ... (\`overai org list\` shows them, \`overai org alias\` your shorthands).`;
27262
+ return error;
27263
+ };
27264
+ var userTrpcMutation = async (procedure, input) => cliClient().trpc(procedure, input);
27161
27265
 
27162
27266
  // src/auth.ts
27163
27267
  import { randomBytes as randomBytes2 } from "crypto";
@@ -27707,30 +27811,11 @@ import { createInterface } from "readline";
27707
27811
 
27708
27812
  // src/gql.ts
27709
27813
  var gqlRequest = async (query, variables) => {
27710
- const res = await v2Fetch("/v2/graphql", {
27711
- method: "POST",
27712
- headers: { "Content-Type": "application/json" },
27713
- body: JSON.stringify({ query, variables })
27714
- });
27715
- const raw2 = await res.text();
27716
- const body = (() => {
27717
- try {
27718
- return JSON.parse(raw2);
27719
- } catch {
27720
- return null;
27721
- }
27722
- })();
27723
- if (body?.errors != null && body.errors.length > 0) {
27724
- throw Object.assign(
27725
- new Error(body.errors.map((e) => e.message).join("; ")),
27726
- { errors: body.errors }
27727
- );
27728
- }
27729
- if (!res.ok) throw v2Error("graphql", res, raw2);
27730
- if (body?.data == null) {
27731
- throw new Error("graphql returned no data and no errors.");
27814
+ try {
27815
+ return await cliClient().graphql(query, variables);
27816
+ } catch (error) {
27817
+ throw error instanceof OverAIError && error.errors == null ? withOrgHint(error) : error;
27732
27818
  }
27733
- return body.data;
27734
27819
  };
27735
27820
 
27736
27821
  // src/commands/agent.ts
@@ -28210,7 +28295,7 @@ var validateAutomationElements = async (elements) => {
28210
28295
  return findings(automationNodesSchema.safeParse(elements));
28211
28296
  };
28212
28297
  var validateWebPageConfig = async (config) => {
28213
- const { webPageConfigWriteSchema } = await import("./webPage-ICODVQMY.js");
28298
+ const { webPageConfigWriteSchema } = await import("./webPage-SH7GBOWZ.js");
28214
28299
  return findings(webPageConfigWriteSchema.safeParse(config));
28215
28300
  };
28216
28301
 
@@ -28970,7 +29055,7 @@ var runRunner = async (args) => {
28970
29055
  // ../common/src/liquidjs/liquidjs.ts
28971
29056
  var import_jmespath = __toESM(require_jmespath(), 1);
28972
29057
 
28973
- // ../../node_modules/.pnpm/liquidjs@10.29.0/node_modules/liquidjs/dist/liquid.node.mjs
29058
+ // ../../node_modules/.pnpm/liquidjs@10.30.0/node_modules/liquidjs/dist/liquid.node.mjs
28974
29059
  import { PassThrough } from "stream";
28975
29060
  import { sep, extname, resolve as resolve$1, dirname as dirname$1 } from "path";
28976
29061
  import { statSync, readFileSync as readFileSync$1, realpathSync, stat, readFile as readFile$1, realpath } from "fs";
@@ -29318,8 +29403,8 @@ function assertEmpty(predicate, message = `unexpected ${JSON.stringify(predicate
29318
29403
  assert(!predicate, message);
29319
29404
  }
29320
29405
  var NullDrop = class extends Drop {
29321
- equals(value) {
29322
- return isNil(toValue(value));
29406
+ *equals(value) {
29407
+ return isNil(yield toValue(value));
29323
29408
  }
29324
29409
  gt() {
29325
29410
  return false;
@@ -29338,10 +29423,10 @@ var NullDrop = class extends Drop {
29338
29423
  }
29339
29424
  };
29340
29425
  var EmptyDrop = class _EmptyDrop extends Drop {
29341
- equals(value) {
29426
+ *equals(value) {
29342
29427
  if (value instanceof _EmptyDrop)
29343
29428
  return false;
29344
- value = toValue(value);
29429
+ value = yield toValue(value);
29345
29430
  if (isString(value) || isArray(value))
29346
29431
  return value.length === 0;
29347
29432
  if (isObject(value))
@@ -29368,14 +29453,14 @@ var EmptyDrop = class _EmptyDrop extends Drop {
29368
29453
  }
29369
29454
  };
29370
29455
  var BlankDrop = class _BlankDrop extends EmptyDrop {
29371
- equals(value) {
29456
+ *equals(value) {
29372
29457
  if (value === false)
29373
29458
  return true;
29374
- if (isNil(toValue(value)))
29459
+ if (isNil(yield toValue(value)))
29375
29460
  return true;
29376
29461
  if (isString(value))
29377
29462
  return /^\s*$/.test(value);
29378
- return super.equals(value);
29463
+ return yield super.equals(value);
29379
29464
  }
29380
29465
  static is(value) {
29381
29466
  return value instanceof _BlankDrop;
@@ -29601,10 +29686,8 @@ function getDayOfYear(d) {
29601
29686
  return num + d.getDate();
29602
29687
  }
29603
29688
  function getWeekOfYear(d, startDay) {
29604
- const now = getDayOfYear(d) + (startDay - d.getDay());
29605
- const jan1 = new Date(d.getFullYear(), 0, 1);
29606
- const then = 7 - jan1.getDay() + startDay;
29607
- return String(Math.floor((now - then) / 7) + 1);
29689
+ const daysSinceStartDay = (d.getDay() - startDay + 7) % 7;
29690
+ return String(Math.floor((getDayOfYear(d) - 1 - daysSinceStartDay + 7) / 7));
29608
29691
  }
29609
29692
  function isLeapYear(d) {
29610
29693
  const year = d.getFullYear();
@@ -29626,9 +29709,10 @@ function ordinal(d) {
29626
29709
  }
29627
29710
  }
29628
29711
  function century(d) {
29629
- return parseInt(d.getFullYear().toString().substring(0, 2), 10);
29712
+ return Math.floor(d.getFullYear() / 100);
29630
29713
  }
29631
29714
  var padWidths = {
29715
+ C: 2,
29632
29716
  d: 2,
29633
29717
  e: 2,
29634
29718
  H: 2,
@@ -29641,7 +29725,8 @@ var padWidths = {
29641
29725
  M: 2,
29642
29726
  S: 2,
29643
29727
  U: 2,
29644
- W: 2
29728
+ W: 2,
29729
+ y: 2
29645
29730
  };
29646
29731
  var padSpaceChars = new Set("aAbBceklpP");
29647
29732
  function getTimezoneOffset(d, opts) {
@@ -29685,7 +29770,7 @@ var formatCodes = {
29685
29770
  W: (d) => getWeekOfYear(d, 1),
29686
29771
  x: (d) => d.toLocaleDateString(),
29687
29772
  X: (d) => d.toLocaleTimeString(),
29688
- y: (d) => d.getFullYear().toString().slice(2, 4),
29773
+ y: (d) => (d.getFullYear() % 100 + 100) % 100,
29689
29774
  Y: (d) => d.getFullYear(),
29690
29775
  z: getTimezoneOffset,
29691
29776
  Z: (d, opts) => d.getTimeZoneName() || getTimezoneOffset(d, opts),
@@ -30260,10 +30345,13 @@ function* evalFilteredValueToken(token, ctx, lenient) {
30260
30345
  }
30261
30346
  return val;
30262
30347
  }
30348
+ function* evalTokenValue(token, ctx, lenient = false) {
30349
+ return yield toValue(yield evalToken(token, ctx, lenient));
30350
+ }
30263
30351
  function* evalPropertyAccessToken(token, ctx, lenient) {
30264
30352
  const props = [];
30265
30353
  for (const prop of token.props) {
30266
- props.push(yield evalToken(prop, ctx, false));
30354
+ props.push(yield evalTokenValue(prop, ctx, false));
30267
30355
  }
30268
30356
  try {
30269
30357
  if (token.variable) {
@@ -30282,8 +30370,8 @@ function evalQuotedToken(token) {
30282
30370
  return token.content;
30283
30371
  }
30284
30372
  function* evalRangeToken(token, ctx) {
30285
- const low = yield evalToken(token.lhs, ctx);
30286
- const high = yield evalToken(token.rhs, ctx);
30373
+ const low = yield evalTokenValue(token.lhs, ctx);
30374
+ const high = yield evalTokenValue(token.rhs, ctx);
30287
30375
  ctx.memoryLimit.use(high - low + 1);
30288
30376
  return range(+low, +high + 1);
30289
30377
  }
@@ -30314,67 +30402,85 @@ function isFalsy(val, ctx) {
30314
30402
  }
30315
30403
  }
30316
30404
  var defaultOperators = {
30317
- "==": equals,
30318
- "!=": (l, r) => !equals(l, r),
30319
- ">": (l, r) => {
30405
+ "==": function* (l, r) {
30406
+ return yield equals(l, r);
30407
+ },
30408
+ "!=": function* (l, r) {
30409
+ return !(yield equals(l, r));
30410
+ },
30411
+ ">": function* (l, r) {
30320
30412
  if (isComparable(l))
30321
- return l.gt(r);
30413
+ return yield l.gt(r);
30322
30414
  if (isComparable(r))
30323
- return r.lt(l);
30324
- return toValue(l) > toValue(r);
30415
+ return yield r.lt(l);
30416
+ return (yield toValue(l)) > (yield toValue(r));
30325
30417
  },
30326
- "<": (l, r) => {
30418
+ "<": function* (l, r) {
30327
30419
  if (isComparable(l))
30328
- return l.lt(r);
30420
+ return yield l.lt(r);
30329
30421
  if (isComparable(r))
30330
- return r.gt(l);
30331
- return toValue(l) < toValue(r);
30422
+ return yield r.gt(l);
30423
+ return (yield toValue(l)) < (yield toValue(r));
30332
30424
  },
30333
- ">=": (l, r) => {
30425
+ ">=": function* (l, r) {
30334
30426
  if (isComparable(l))
30335
- return l.geq(r);
30427
+ return yield l.geq(r);
30336
30428
  if (isComparable(r))
30337
- return r.leq(l);
30338
- return toValue(l) >= toValue(r);
30429
+ return yield r.leq(l);
30430
+ return (yield toValue(l)) >= (yield toValue(r));
30339
30431
  },
30340
- "<=": (l, r) => {
30432
+ "<=": function* (l, r) {
30341
30433
  if (isComparable(l))
30342
- return l.leq(r);
30434
+ return yield l.leq(r);
30343
30435
  if (isComparable(r))
30344
- return r.geq(l);
30345
- return toValue(l) <= toValue(r);
30436
+ return yield r.geq(l);
30437
+ return (yield toValue(l)) <= (yield toValue(r));
30346
30438
  },
30347
- "contains": (l, r) => {
30348
- l = toValue(l);
30439
+ "contains": function* (l, r) {
30440
+ l = yield toValue(l);
30349
30441
  if (isArray(l))
30350
- return l.some((i) => equals(i, r));
30442
+ return yield arrayIncludes(l, r);
30351
30443
  if (isFunction(l === null || l === void 0 ? void 0 : l.indexOf))
30352
- return l.indexOf(toValue(r)) > -1;
30444
+ return l.indexOf(yield toValue(r)) > -1;
30353
30445
  return false;
30354
30446
  },
30355
- "not": (v, ctx) => isFalsy(toValue(v), ctx),
30356
- "and": (l, r, ctx) => isTruthy(toValue(l), ctx) && isTruthy(toValue(r), ctx),
30357
- "or": (l, r, ctx) => isTruthy(toValue(l), ctx) || isTruthy(toValue(r), ctx)
30447
+ "not": function* (v, ctx) {
30448
+ return isFalsy(yield toValue(v), ctx);
30449
+ },
30450
+ "and": function* (l, r, ctx) {
30451
+ return isTruthy(yield toValue(l), ctx) && isTruthy(yield toValue(r), ctx);
30452
+ },
30453
+ "or": function* (l, r, ctx) {
30454
+ return isTruthy(yield toValue(l), ctx) || isTruthy(yield toValue(r), ctx);
30455
+ }
30358
30456
  };
30359
- function equals(lhs, rhs) {
30457
+ function* equals(lhs, rhs) {
30360
30458
  if (isComparable(lhs))
30361
- return lhs.equals(rhs);
30459
+ return yield lhs.equals(rhs);
30362
30460
  if (isComparable(rhs))
30363
- return rhs.equals(lhs);
30364
- lhs = toValue(lhs);
30365
- rhs = toValue(rhs);
30461
+ return yield rhs.equals(lhs);
30462
+ lhs = yield toValue(lhs);
30463
+ rhs = yield toValue(rhs);
30366
30464
  if (isArray(lhs)) {
30367
- return isArray(rhs) && arrayEquals(lhs, rhs);
30465
+ return isArray(rhs) && (yield arrayEquals(lhs, rhs));
30368
30466
  }
30369
30467
  return lhs === rhs;
30370
30468
  }
30371
- function arrayEquals(lhs, rhs) {
30469
+ function* arrayEquals(lhs, rhs) {
30372
30470
  if (lhs.length !== rhs.length)
30373
30471
  return false;
30374
- return !lhs.some((value, i) => !equals(value, rhs[i]));
30472
+ for (let i = 0; i < lhs.length; i++) {
30473
+ if (!(yield equals(lhs[i], rhs[i])))
30474
+ return false;
30475
+ }
30476
+ return true;
30375
30477
  }
30376
- function arrayIncludes(arr, item) {
30377
- return arr.some((value) => equals(value, item));
30478
+ function* arrayIncludes(arr, item) {
30479
+ for (const value of arr) {
30480
+ if (yield equals(value, item))
30481
+ return true;
30482
+ }
30483
+ return false;
30378
30484
  }
30379
30485
  var Node = class {
30380
30486
  constructor(key, value, next, prev) {
@@ -31383,7 +31489,7 @@ var Output = class extends TemplateImpl {
31383
31489
  }
31384
31490
  }
31385
31491
  *render(ctx, emitter) {
31386
- const val = yield this.value.value(ctx, false);
31492
+ const val = yield toValue(yield this.value.value(ctx, false));
31387
31493
  emitter.write(val);
31388
31494
  }
31389
31495
  *arguments() {
@@ -32107,7 +32213,7 @@ var mathFilters = /* @__PURE__ */ Object.freeze({
32107
32213
  times,
32108
32214
  round
32109
32215
  });
32110
- var url_decode = (x) => decodeURIComponent(stringify(x)).replace(/\+/g, " ");
32216
+ var url_decode = (x) => decodeURIComponent(stringify(x).replace(/\+/g, " "));
32111
32217
  var url_encode = (x) => encodeURIComponent(stringify(x)).replace(/%20/g, "+");
32112
32218
  var cgi_escape = (x) => encodeURIComponent(stringify(x)).replace(/%20/g, "+").replace(/[!'()*]/g, (c) => "%" + c.charCodeAt(0).toString(16).toUpperCase());
32113
32219
  var uri_escape = (x) => encodeURI(stringify(x)).replace(/%5B/g, "[").replace(/%5D/g, "]");
@@ -32245,25 +32351,29 @@ function slice(v, begin, length = 1) {
32245
32351
  this.context.memoryLimit.use(length);
32246
32352
  return isArray(v) ? Array.prototype.slice.call(v, begin, begin + length) : String.prototype.slice.call(v, begin, begin + length);
32247
32353
  }
32248
- function expectedMatcher(expected) {
32354
+ function* matches(value, expected) {
32249
32355
  if (this.context.opts.jekyllWhere) {
32250
- return (v) => EmptyDrop.is(expected) ? equals(v, expected) : isArray(v) ? arrayIncludes(v, expected) : equals(v, expected);
32251
- } else if (expected === void 0) {
32252
- return (v) => isTruthy(v, this.context);
32253
- } else {
32254
- return (v) => equals(v, expected);
32255
- }
32356
+ if (EmptyDrop.is(expected))
32357
+ return yield equals(value, expected);
32358
+ if (isArray(value))
32359
+ return yield arrayIncludes(value, expected);
32360
+ return yield equals(value, expected);
32361
+ }
32362
+ if (expected === void 0)
32363
+ return isTruthy(value, this.context);
32364
+ return yield equals(value, expected);
32256
32365
  }
32257
32366
  function* filter(include, arr, property, expected) {
32258
- const values = [];
32259
32367
  arr = toArray(arr);
32260
32368
  this.context.memoryLimit.use(arr.length);
32261
32369
  const token = new Tokenizer(stringify(property)).readScopeValue();
32370
+ const result = [];
32262
32371
  for (const item of arr) {
32263
- values.push(yield evalToken(token, this.context.spawn(item)));
32372
+ const value = yield evalToken(token, this.context.spawn(item));
32373
+ if ((yield matches.call(this, value, expected)) === include)
32374
+ result.push(item);
32264
32375
  }
32265
- const matcher = expectedMatcher.call(this, expected);
32266
- return Array.prototype.filter.call(arr, (_, i) => matcher(values[i]) === include);
32376
+ return result;
32267
32377
  }
32268
32378
  function* filter_exp(include, arr, itemName, exp) {
32269
32379
  const filtered = [];
@@ -32322,10 +32432,9 @@ function* group_by_exp(arr, itemName, exp) {
32322
32432
  function* search(arr, property, expected) {
32323
32433
  const token = new Tokenizer(stringify(property)).readScopeValue();
32324
32434
  const array = toArray(arr);
32325
- const matcher = expectedMatcher.call(this, expected);
32326
32435
  for (let index = 0; index < array.length; index++) {
32327
32436
  const value = yield evalToken(token, this.context.spawn(array[index]));
32328
- if (matcher(value))
32437
+ if (yield matches.call(this, value, expected))
32329
32438
  return [index, array[index]];
32330
32439
  }
32331
32440
  }
@@ -32497,17 +32606,32 @@ function prepend(v, arg) {
32497
32606
  this.context.memoryLimit.use(lhs.length + rhs.length);
32498
32607
  return rhs + lhs;
32499
32608
  }
32609
+ function getTrimStart(str, chars) {
32610
+ let start = 0;
32611
+ for (const char of str) {
32612
+ if (!chars.has(char))
32613
+ break;
32614
+ start += char.length;
32615
+ }
32616
+ return start;
32617
+ }
32618
+ function getTrimEnd(str, chars, start = 0) {
32619
+ let end = str.length;
32620
+ while (end > start) {
32621
+ const size2 = end - start >= 2 && str.codePointAt(end - 2) > 65535 ? 2 : 1;
32622
+ if (!chars.has(str.slice(end - size2, end)))
32623
+ break;
32624
+ end -= size2;
32625
+ }
32626
+ return end;
32627
+ }
32500
32628
  function lstrip(v, chars) {
32501
32629
  const str = stringify(v);
32502
32630
  this.context.memoryLimit.use(str.length);
32503
32631
  if (chars) {
32504
32632
  chars = stringify(chars);
32505
32633
  this.context.memoryLimit.use(chars.length);
32506
- for (let i = 0, set = new Set(chars); i < str.length; i++) {
32507
- if (!set.has(str[i]))
32508
- return str.slice(i);
32509
- }
32510
- return "";
32634
+ return str.slice(getTrimStart(str, new Set(chars)));
32511
32635
  }
32512
32636
  return str.trimStart();
32513
32637
  }
@@ -32548,11 +32672,7 @@ function rstrip(str, chars) {
32548
32672
  if (chars) {
32549
32673
  chars = stringify(chars);
32550
32674
  this.context.memoryLimit.use(chars.length);
32551
- for (let i = str.length - 1, set = new Set(chars); i >= 0; i--) {
32552
- if (!set.has(str[i]))
32553
- return str.slice(0, i + 1);
32554
- }
32555
- return "";
32675
+ return str.slice(0, getTrimEnd(str, new Set(chars)));
32556
32676
  }
32557
32677
  return str.trimEnd();
32558
32678
  }
@@ -32570,13 +32690,8 @@ function strip(v, chars) {
32570
32690
  if (chars) {
32571
32691
  const set = new Set(stringify(chars));
32572
32692
  this.context.memoryLimit.use(set.size);
32573
- let i = 0;
32574
- let j = str.length - 1;
32575
- while (set.has(str[i]))
32576
- i++;
32577
- while (j >= i && set.has(str[j]))
32578
- j--;
32579
- return str.slice(i, j + 1);
32693
+ const start = getTrimStart(str, set);
32694
+ return str.slice(start, getTrimEnd(str, set, start));
32580
32695
  }
32581
32696
  return str.trim();
32582
32697
  }
@@ -32633,7 +32748,7 @@ function truncatewords(v, words = 15, o = "...") {
32633
32748
  const str = stringify(v);
32634
32749
  o = stringify(o);
32635
32750
  this.context.memoryLimit.use(str.length + o.length);
32636
- const arr = str.split(/\s+/);
32751
+ const arr = str.trimStart().split(/\s+/);
32637
32752
  if (words <= 0)
32638
32753
  words = 1;
32639
32754
  let ret = arr.slice(0, words).join(" ");
@@ -32937,12 +33052,12 @@ var CaseTag = class extends Tag {
32937
33052
  }
32938
33053
  *render(ctx, emitter) {
32939
33054
  const r = this.liquid.renderer;
32940
- const target = toValue(yield this.value.value(ctx, ctx.opts.lenientIf));
33055
+ const target = yield toValue(yield this.value.value(ctx, ctx.opts.lenientIf));
32941
33056
  let branchHit = false;
32942
33057
  for (const branch of this.branches) {
32943
33058
  for (const valueToken of branch.values) {
32944
33059
  const value = yield evalToken(valueToken, ctx, ctx.opts.lenientIf);
32945
- if (equals(target, value)) {
33060
+ if (yield equals(target, value)) {
32946
33061
  yield r.renderTemplates(branch.templates, ctx, emitter);
32947
33062
  branchHit = true;
32948
33063
  break;
@@ -33270,7 +33385,7 @@ var IfTag = class extends Tag {
33270
33385
  *render(ctx, emitter) {
33271
33386
  const r = this.liquid.renderer;
33272
33387
  for (const { value, templates } of this.branches) {
33273
- const v = yield value.value(ctx, ctx.opts.lenientIf);
33388
+ const v = yield toValue(yield value.value(ctx, ctx.opts.lenientIf));
33274
33389
  if (isTruthy(v, ctx)) {
33275
33390
  yield r.renderTemplates(templates, ctx, emitter);
33276
33391
  return;
@@ -33542,7 +33657,7 @@ var UnlessTag = class extends Tag {
33542
33657
  *render(ctx, emitter) {
33543
33658
  const r = this.liquid.renderer;
33544
33659
  for (const { value, test, templates } of this.branches) {
33545
- const v = yield value.value(ctx, ctx.opts.lenientIf);
33660
+ const v = yield toValue(yield value.value(ctx, ctx.opts.lenientIf));
33546
33661
  if (test(v, ctx)) {
33547
33662
  yield r.renderTemplates(templates, ctx, emitter);
33548
33663
  return;
@@ -33582,7 +33697,7 @@ var EchoTag = class extends Tag {
33582
33697
  *render(ctx, emitter) {
33583
33698
  if (!this.value)
33584
33699
  return;
33585
- const val = yield this.value.value(ctx, false);
33700
+ const val = yield toValue(yield this.value.value(ctx, false));
33586
33701
  emitter.write(val);
33587
33702
  }
33588
33703
  *arguments() {
@@ -34013,12 +34128,12 @@ var intervalToMilliseconds = (interval, timeUnits = defaultTimeUnits) => {
34013
34128
  if (interval === null) {
34014
34129
  return null;
34015
34130
  }
34016
- const matches = interval.match(intervalRegex);
34017
- if (matches === null) {
34131
+ const matches2 = interval.match(intervalRegex);
34132
+ if (matches2 === null) {
34018
34133
  return null;
34019
34134
  }
34020
34135
  let milliseconds = 0;
34021
- matches.forEach((m) => {
34136
+ matches2.forEach((m) => {
34022
34137
  const numericPart = /(\d+(?:\.\d+)?)/.exec(m)?.[1];
34023
34138
  const unitPart = m.replace(/\d+(?:\.\d+)?/, "").trim();
34024
34139
  if (numericPart && !isNaN(parseFloat(numericPart))) {
@@ -35733,6 +35848,7 @@ var ID_PREFIXES = {
35733
35848
  automation_email_address: { prefix: "aea", body: 10 },
35734
35849
  automation_email_alert: { prefix: "aes", body: 10 },
35735
35850
  automation_error_alert_queue: { prefix: "aeaq", body: 10 },
35851
+ billing_period: { prefix: "bpd", body: 12 },
35736
35852
  browser_automation: { prefix: "bra", body: 10 },
35737
35853
  browser_automation_run: { prefix: "brr", body: 20 },
35738
35854
  browser_session_usage: { prefix: "bsu", body: 12 },
@@ -35837,6 +35953,108 @@ var idTableByPrefix = (id) => {
35837
35953
  return best?.table ?? null;
35838
35954
  };
35839
35955
 
35956
+ // src/commands/resource.ts
35957
+ var resources = {
35958
+ workspace: { collection: "workspaces", mutation: "updateWorkspace", result: "workspace", patch: "WorkspacePatch", fields: "id name description isArchived", editable: ["name", "description", "isArchived"] },
35959
+ automation: { collection: "automations", mutation: "updateAutomation", result: "automation", patch: "AutomationPatch", fields: "id name description isArchived isActive workspaceId", editable: ["name", "description", "isArchived", "isActive"] },
35960
+ function: { collection: "functions", mutation: "updateFunction", result: "function", patch: "FunctionPatch", fields: "id name description isArchived isEnabled workspaceId", editable: ["name", "description", "isArchived", "isEnabled"] },
35961
+ web_page: { collection: "webPages", mutation: "updateWebPage", result: "webPage", patch: "WebPagePatch", fields: "id name isArchived workspaceId", editable: ["name", "isArchived"] },
35962
+ printable_page: { collection: "printablePages", mutation: "updatePrintablePage", result: "printablePage", patch: "PrintablePagePatch", fields: "id name isArchived workspaceId", editable: ["name", "isArchived"] },
35963
+ agent: { collection: "agents", mutation: "updateAgent", result: "agent", patch: "AgentPatch", fields: "id name description isArchived isEnabled workspaceId", editable: ["name", "description", "isArchived", "isEnabled"] },
35964
+ integration: { collection: "integrations", mutation: "updateIntegration", result: "integration", patch: "IntegrationPatch", fields: "id name description isArchived integrationTypeId workspaceId", editable: ["name", "description", "isArchived", "integrationTypeId"] },
35965
+ table_space: { collection: "tableSpaces", mutation: "updateTableSpace", result: "tableSpace", patch: "TableSpacePatch", fields: "id name description isArchived workspaceId", editable: ["name", "description", "isArchived"] },
35966
+ data_stream: { collection: "dataStreams", mutation: "updateDataStream", result: "dataStream", patch: "DataStreamPatch", fields: "id name description isArchived workspaceId", editable: ["name", "description", "isArchived"] },
35967
+ knowledge_base: { collection: "knowledgeBases", mutation: "updateKnowledgeBase", result: "knowledgeBase", patch: "KnowledgeBasePatch", fields: "id name description isArchived embeddingModel workspaceId", editable: ["name", "description", "isArchived"] },
35968
+ data_file: { collection: "dataFiles", mutation: "updateDataFile", result: "dataFile", patch: "DataFilePatch", fields: "id name description isArchived workspaceId", editable: ["name", "description", "isArchived"] },
35969
+ action_runner: { collection: "actionRunners", mutation: "updateActionRunner", result: "actionRunner", patch: "ActionRunnerPatch", fields: "id isArchived actionTimeoutSeconds config workspaceId identityId identity { name }", editable: ["isArchived", "actionTimeoutSeconds", "config"] }
35970
+ // Keyed by table so `idTableByPrefix` can index it; `satisfies` rejects a key
35971
+ // the registry does not know.
35972
+ };
35973
+ var resourceFor = (id) => {
35974
+ const table = idTableByPrefix(id);
35975
+ const resource = table == null ? void 0 : resources[table];
35976
+ if (resource == null) throw new Error(`Unsupported resource id: ${id}`);
35977
+ return resource;
35978
+ };
35979
+ var readResource = async (id, resource) => {
35980
+ const data = await gqlRequest(
35981
+ `query CliResource($id: String!) {
35982
+ ${resource.collection}(condition: { idIgnoringCase: $id }, includeArchived: YES, first: 1) {
35983
+ nodes { ${resource.fields} }
35984
+ }
35985
+ }`,
35986
+ { id }
35987
+ );
35988
+ const row = data[resource.collection]?.nodes[0];
35989
+ if (row == null) throw new Error(`Resource ${id} not found.`);
35990
+ return row;
35991
+ };
35992
+ var runResource = async (args) => {
35993
+ const [operation, id] = args;
35994
+ if (operation !== "show" && operation !== "update" || id == null) {
35995
+ throw new Error("Usage: overai resource show <id> | resource update <id> [--name <name>] [--description <text>] [--archive|--restore] [--enable|--disable] [--active|--inactive]");
35996
+ }
35997
+ const resource = resourceFor(id);
35998
+ if (operation === "show") {
35999
+ printResult(await readResource(id, resource), resolveFormat(flagValue(args, "-o", "--output")));
36000
+ return;
36001
+ }
36002
+ const patch = {};
36003
+ const scalarFlags = [
36004
+ ["name", "--name"],
36005
+ ["description", "--description"],
36006
+ ["integrationTypeId", "--type"],
36007
+ ["actionTimeoutSeconds", "--timeout"]
36008
+ ];
36009
+ scalarFlags.forEach(([field, flag]) => {
36010
+ const value = flagValue(args, flag);
36011
+ if (value != null && resource.editable.includes(field)) {
36012
+ patch[field] = field === "actionTimeoutSeconds" ? Number(value) : value;
36013
+ }
36014
+ });
36015
+ [
36016
+ ["isArchived", "--archive", true],
36017
+ ["isArchived", "--restore", false],
36018
+ ["isEnabled", "--enable", true],
36019
+ ["isEnabled", "--disable", false],
36020
+ ["isActive", "--active", true],
36021
+ ["isActive", "--inactive", false]
36022
+ ].forEach(([field, flag, value]) => {
36023
+ if (args.includes(flag) && resource.editable.includes(field)) patch[field] = value;
36024
+ });
36025
+ const config = await readValue(flagValue(args, "--config"), "--config");
36026
+ if (config != null && resource.editable.includes("config")) {
36027
+ try {
36028
+ patch.config = JSON.parse(config);
36029
+ } catch {
36030
+ throw new Error("--config must be valid JSON (or @<file> containing JSON).");
36031
+ }
36032
+ }
36033
+ const current = await readResource(id, resource);
36034
+ const name2 = flagValue(args, "--name");
36035
+ if (name2 != null && idTableByPrefix(id) === "action_runner") {
36036
+ const result = await gqlRequest(
36037
+ `mutation CliRenameRunner($id: String!, $name: String!) {
36038
+ updateIdentity(input: { id: $id, patch: { name: $name } }) { identity { id } }
36039
+ }`,
36040
+ { id: current.identityId, name: name2 }
36041
+ );
36042
+ if (result.updateIdentity?.identity == null) throw new Error(`Runner ${id} could not be renamed; check your workspace role.`);
36043
+ }
36044
+ if (Object.keys(patch).length > 0) {
36045
+ const result = await gqlRequest(
36046
+ `mutation CliUpdateResource($id: String!, $patch: ${resource.patch}!) {
36047
+ ${resource.mutation}(input: { id: $id, patch: $patch }) { updated: ${resource.result} { id } }
36048
+ }`,
36049
+ { id: current.id, patch }
36050
+ );
36051
+ if (result[resource.mutation]?.updated == null) throw new Error(`Resource ${id} was not updated; check that it exists and your workspace role allows editing.`);
36052
+ } else if (!(name2 != null && idTableByPrefix(id) === "action_runner")) {
36053
+ throw new Error(`No supported changes supplied for ${id}.`);
36054
+ }
36055
+ printResult(await readResource(current.id, resource), resolveFormat(flagValue(args, "-o", "--output")));
36056
+ };
36057
+
35840
36058
  // src/commands/open.ts
35841
36059
  var ROUTE_BY_TYPE = {
35842
36060
  automation: "automations",
@@ -35862,7 +36080,7 @@ var ROUTE_BY_TABLE = {
35862
36080
  var runOpen = async (args) => {
35863
36081
  const filter2 = args.find((a) => !a.startsWith("-"));
35864
36082
  const { organizationId } = await getAccessToken();
35865
- const url = (() => {
36083
+ const url = await (async () => {
35866
36084
  const manifest = (() => {
35867
36085
  try {
35868
36086
  return readManifest(findWorkspaceRoot());
@@ -35875,11 +36093,11 @@ var runOpen = async (args) => {
35875
36093
  return `${appBaseUrl(apiBaseUrl())}/${manifest.organizationId}/workspaces/${manifest.workspaceId}`;
35876
36094
  }
35877
36095
  const match = Object.entries(manifest.resources).find(
35878
- ([id, r]) => id === filter2 || r.name.toLowerCase().includes(filter2.toLowerCase()) || r.files.some((f) => f.includes(filter2))
36096
+ ([id2, r]) => id2.toLowerCase() === filter2.toLowerCase() || r.name.toLowerCase().includes(filter2.toLowerCase()) || r.files.some((f) => f.includes(filter2))
35879
36097
  );
35880
36098
  if (match != null) {
35881
- const [id, resource] = match;
35882
- return `${appBaseUrl(apiBaseUrl())}/${manifest.organizationId}/${ROUTE_BY_TYPE[resource.type]}/${id}`;
36099
+ const [id2, resource2] = match;
36100
+ return `${appBaseUrl(apiBaseUrl())}/${manifest.organizationId}/${ROUTE_BY_TYPE[resource2.type]}/${id2}`;
35883
36101
  }
35884
36102
  }
35885
36103
  if (filter2 == null) {
@@ -35894,7 +36112,9 @@ var runOpen = async (args) => {
35894
36112
  `Nothing matched "${filter2}" (not a tracked resource or a recognized id prefix).`
35895
36113
  );
35896
36114
  }
35897
- return `${appBaseUrl(apiBaseUrl())}/${organizationId}/${route}/${filter2}`;
36115
+ const resource = table == null ? void 0 : resources[table];
36116
+ const id = resource == null ? filter2 : (await readResource(filter2, resource)).id;
36117
+ return `${appBaseUrl(apiBaseUrl())}/${organizationId}/${route}/${id}`;
35898
36118
  })();
35899
36119
  process.stdout.write(`${url}
35900
36120
  `);
@@ -36427,15 +36647,15 @@ var parseRef = (raw2) => {
36427
36647
  return n;
36428
36648
  };
36429
36649
  var findResource = (manifest, filter2) => {
36430
- const matches = Object.entries(manifest.resources).filter(
36650
+ const matches2 = Object.entries(manifest.resources).filter(
36431
36651
  ([id, r]) => id === filter2 || r.name.toLowerCase().includes(filter2.toLowerCase()) || r.files.some((f) => f.includes(filter2))
36432
36652
  );
36433
- if (matches.length === 0) throw new Error(`Nothing matched "${filter2}".`);
36434
- const match = matches[0];
36435
- if (match == null || matches.length > 1) {
36653
+ if (matches2.length === 0) throw new Error(`Nothing matched "${filter2}".`);
36654
+ const match = matches2[0];
36655
+ if (match == null || matches2.length > 1) {
36436
36656
  throw new Error(
36437
36657
  `"${filter2}" is ambiguous:
36438
- ${matches.map(([id, r]) => ` ${r.name} (${id})`).join("\n")}`
36658
+ ${matches2.map(([id, r]) => ` ${r.name} (${id})`).join("\n")}`
36439
36659
  );
36440
36660
  }
36441
36661
  return match;
@@ -36839,108 +37059,6 @@ var runReport = async (args) => {
36839
37059
  );
36840
37060
  };
36841
37061
 
36842
- // src/commands/resource.ts
36843
- var resources = {
36844
- workspace: { collection: "workspaces", mutation: "updateWorkspace", result: "workspace", patch: "WorkspacePatch", fields: "id name description isArchived", editable: ["name", "description", "isArchived"] },
36845
- automation: { collection: "automations", mutation: "updateAutomation", result: "automation", patch: "AutomationPatch", fields: "id name description isArchived isActive workspaceId", editable: ["name", "description", "isArchived", "isActive"] },
36846
- function: { collection: "functions", mutation: "updateFunction", result: "function", patch: "FunctionPatch", fields: "id name description isArchived isEnabled workspaceId", editable: ["name", "description", "isArchived", "isEnabled"] },
36847
- web_page: { collection: "webPages", mutation: "updateWebPage", result: "webPage", patch: "WebPagePatch", fields: "id name isArchived workspaceId", editable: ["name", "isArchived"] },
36848
- printable_page: { collection: "printablePages", mutation: "updatePrintablePage", result: "printablePage", patch: "PrintablePagePatch", fields: "id name isArchived workspaceId", editable: ["name", "isArchived"] },
36849
- agent: { collection: "agents", mutation: "updateAgent", result: "agent", patch: "AgentPatch", fields: "id name description isArchived isEnabled workspaceId", editable: ["name", "description", "isArchived", "isEnabled"] },
36850
- integration: { collection: "integrations", mutation: "updateIntegration", result: "integration", patch: "IntegrationPatch", fields: "id name description isArchived integrationTypeId workspaceId", editable: ["name", "description", "isArchived", "integrationTypeId"] },
36851
- table_space: { collection: "tableSpaces", mutation: "updateTableSpace", result: "tableSpace", patch: "TableSpacePatch", fields: "id name description isArchived workspaceId", editable: ["name", "description", "isArchived"] },
36852
- data_stream: { collection: "dataStreams", mutation: "updateDataStream", result: "dataStream", patch: "DataStreamPatch", fields: "id name description isArchived workspaceId", editable: ["name", "description", "isArchived"] },
36853
- knowledge_base: { collection: "knowledgeBases", mutation: "updateKnowledgeBase", result: "knowledgeBase", patch: "KnowledgeBasePatch", fields: "id name description isArchived embeddingModel workspaceId", editable: ["name", "description", "isArchived"] },
36854
- data_file: { collection: "dataFiles", mutation: "updateDataFile", result: "dataFile", patch: "DataFilePatch", fields: "id name description isArchived workspaceId", editable: ["name", "description", "isArchived"] },
36855
- action_runner: { collection: "actionRunners", mutation: "updateActionRunner", result: "actionRunner", patch: "ActionRunnerPatch", fields: "id isArchived actionTimeoutSeconds config workspaceId identityId identity { name }", editable: ["isArchived", "actionTimeoutSeconds", "config"] }
36856
- // Keyed by table so `idTableByPrefix` can index it; `satisfies` rejects a key
36857
- // the registry does not know.
36858
- };
36859
- var resourceFor = (id) => {
36860
- const table = idTableByPrefix(id);
36861
- const resource = table == null ? void 0 : resources[table];
36862
- if (resource == null) throw new Error(`Unsupported resource id: ${id}`);
36863
- return resource;
36864
- };
36865
- var readResource = async (id, resource) => {
36866
- const data = await gqlRequest(
36867
- `query CliResource($id: String!) {
36868
- ${resource.collection}(condition: { id: $id }, includeArchived: YES, first: 1) {
36869
- nodes { ${resource.fields} }
36870
- }
36871
- }`,
36872
- { id }
36873
- );
36874
- const row = data[resource.collection]?.nodes[0];
36875
- if (row == null) throw new Error(`Resource ${id} not found.`);
36876
- return row;
36877
- };
36878
- var runResource = async (args) => {
36879
- const [operation, id] = args;
36880
- if (operation !== "show" && operation !== "update" || id == null) {
36881
- throw new Error("Usage: overai resource show <id> | resource update <id> [--name <name>] [--description <text>] [--archive|--restore] [--enable|--disable] [--active|--inactive]");
36882
- }
36883
- const resource = resourceFor(id);
36884
- if (operation === "show") {
36885
- printResult(await readResource(id, resource), resolveFormat(flagValue(args, "-o", "--output")));
36886
- return;
36887
- }
36888
- const patch = {};
36889
- const scalarFlags = [
36890
- ["name", "--name"],
36891
- ["description", "--description"],
36892
- ["integrationTypeId", "--type"],
36893
- ["actionTimeoutSeconds", "--timeout"]
36894
- ];
36895
- scalarFlags.forEach(([field, flag]) => {
36896
- const value = flagValue(args, flag);
36897
- if (value != null && resource.editable.includes(field)) {
36898
- patch[field] = field === "actionTimeoutSeconds" ? Number(value) : value;
36899
- }
36900
- });
36901
- [
36902
- ["isArchived", "--archive", true],
36903
- ["isArchived", "--restore", false],
36904
- ["isEnabled", "--enable", true],
36905
- ["isEnabled", "--disable", false],
36906
- ["isActive", "--active", true],
36907
- ["isActive", "--inactive", false]
36908
- ].forEach(([field, flag, value]) => {
36909
- if (args.includes(flag) && resource.editable.includes(field)) patch[field] = value;
36910
- });
36911
- const config = await readValue(flagValue(args, "--config"), "--config");
36912
- if (config != null && resource.editable.includes("config")) {
36913
- try {
36914
- patch.config = JSON.parse(config);
36915
- } catch {
36916
- throw new Error("--config must be valid JSON (or @<file> containing JSON).");
36917
- }
36918
- }
36919
- const name2 = flagValue(args, "--name");
36920
- if (name2 != null && idTableByPrefix(id) === "action_runner") {
36921
- const current = await readResource(id, resource);
36922
- const result = await gqlRequest(
36923
- `mutation CliRenameRunner($id: String!, $name: String!) {
36924
- updateIdentity(input: { id: $id, patch: { name: $name } }) { identity { id } }
36925
- }`,
36926
- { id: current.identityId, name: name2 }
36927
- );
36928
- if (result.updateIdentity?.identity == null) throw new Error(`Runner ${id} could not be renamed; check your workspace role.`);
36929
- }
36930
- if (Object.keys(patch).length > 0) {
36931
- const result = await gqlRequest(
36932
- `mutation CliUpdateResource($id: String!, $patch: ${resource.patch}!) {
36933
- ${resource.mutation}(input: { id: $id, patch: $patch }) { updated: ${resource.result} { id } }
36934
- }`,
36935
- { id, patch }
36936
- );
36937
- if (result[resource.mutation]?.updated == null) throw new Error(`Resource ${id} was not updated; check that it exists and your workspace role allows editing.`);
36938
- } else if (!(name2 != null && idTableByPrefix(id) === "action_runner")) {
36939
- throw new Error(`No supported changes supplied for ${id}.`);
36940
- }
36941
- printResult(await readResource(id, resource), resolveFormat(flagValue(args, "-o", "--output")));
36942
- };
36943
-
36944
37062
  // src/docs/bestPractices.ts
36945
37063
  var platform2 = `# OverAI platform primer
36946
37064
 
@@ -37056,7 +37174,20 @@ A page version's config JSON carries the code; the CLI splits it into
37056
37174
  language, customTitle, hideTopBar, ...). Push reassembles them.
37057
37175
 
37058
37176
  - Web pages are React (TSX). Printable pages are React or Liquid.
37059
- - Web page config authorizationMode defaults to "workspace" for shared access.
37177
+ - Web page config authorizationMode defaults to "workspace": every end user
37178
+ who opens the page gets a workspace token that can read AND write every
37179
+ table space in the workspace and any shared into it, call any function it
37180
+ reaches, trigger any of its automations, and call any agent visible to it.
37181
+ Four rules follow:
37182
+ 1. The workspace is the unit of trust. Everything in it trusts everything
37183
+ else, and a page's end users count as "in it."
37184
+ 2. A public workspace is public all the way down. Public (or
37185
+ password-protected) is a workspace setting, not a page setting; every table space, function, automation
37186
+ and agent in it is reachable by anyone who can open a page.
37187
+ 3. Sharing into a workspace extends its trust. A table space shared into a
37188
+ public or password-protected workspace is public.
37189
+ 4. Cross a trust line with a function, not a table. Keep data in a private
37190
+ workspace and share a function into the page's workspace.
37060
37191
  Opt into "viewer" for personal pages spanning the signed-in viewer's workspaces.
37061
37192
  Page code uses their permissions; results/access errors can differ by user.
37062
37193
  Public links require sign-in. Save and deploy publishes the mode with the code.
@@ -37102,11 +37233,15 @@ language, customTitle, hideTopBar, ...). Push reassembles them.
37102
37233
  null. Identity-scoped features degrade: useAgentChat streams but persists
37103
37234
  nothing (conversationId stays null, useAgentConversations is empty, the
37104
37235
  conversation helpers throw), and author-requiring writes like
37105
- env.DFxxx.saveVersion 401. Reads use the workspace's own access, so treat
37106
- anything the page can query as public.
37236
+ env.DFxxx.saveVersion 401. The page runs on the workspace token, so anyone
37237
+ with the link can read and write every table space and call every function,
37238
+ automation and agent the workspace reaches (rule 2 above).
37107
37239
  - meta.json \`runtime\`: "v2" serves the page from its own origin (separate
37108
37240
  process, real localStorage/cookies \u2014 no noSandbox needed); absent or "v1" is
37109
37241
  the sandboxed srcdoc iframe. Anything else is rejected on push.
37242
+ - meta.json \`permissions\` (v2 only): array of "camera", "microphone",
37243
+ "geolocation", "display-capture", "fullscreen", "screen-wake-lock" the page
37244
+ may prompt for; declare only what it uses. Web Serial/USB/HID need none.
37110
37245
  - Write meta.json flags (noSandbox, hideTopBar) as JSON booleans. A page cloned
37111
37246
  before the shape settled may hold the strings "true"/"false" \u2014 those still
37112
37247
  push, anything else is rejected. noSandbox drops the iframe sandbox, which
@@ -37149,11 +37284,15 @@ esm.sh imports allowed. The CLI materializes <slug>.<id>.ts (code) and
37149
37284
  executionMemory MB, callerAccess).
37150
37285
 
37151
37286
  - New functions allow only callers with workspace access by default. Set
37152
- callerAccess to "public" in meta.json only when an unauthenticated endpoint is
37153
- intended. Existing functions retain their saved policy when older meta.json
37154
- files omit this field. The policy is versioned: deploy the saved version to
37155
- change who can call the live endpoint. Workspace uses Authorization for the
37156
- platform bearer token; put additional application credentials in another header.
37287
+ callerAccess to "organization" to accept members of the function's organization
37288
+ or tokens from any private workspace in that organization without a share.
37289
+ A public-workspace token does not qualify; when a token has both workspace and
37290
+ user claims, the workspace claim takes precedence. Set callerAccess to "public"
37291
+ only when an unauthenticated endpoint is intended. Existing functions retain
37292
+ their saved policy when older meta.json files omit this field. The policy is
37293
+ versioned: deploy the saved version to change live access. Use Authorization
37294
+ for the platform bearer token; put application credentials in another header.
37295
+ Test as a user, a workspace, and anonymous before deploying.
37157
37296
  - Functions are full HTTP apps: method + sub-path are forwarded to your code,
37158
37297
  and each execution records requestMethod/requestPath. Callers reach a route
37159
37298
  with env.FNxxx.call({ method, path: "/features/123" }) \u2014 path defaults to the