Skip to main content

PROGRAM

Constant PROGRAM 

Source
pub const PROGRAM: &str = r#""use strict";
const fs = require("node:fs");
const path = require("node:path");
const { DatabaseSync } = require("node:sqlite");
const KEYS = ["antigravityUnifiedStateSync.oauthToken", "antigravityUnifiedStateSync.userStatus"];
const [mode, from, to] = process.argv.slice(1);
const text = (value) => (typeof value === "string" ? value : Buffer.from(value).toString("utf8"));
const fields = (bytes) => {
  const out = [];
  let at = 0;
  const varint = () => {
    let value = 0n;
    let shift = 0n;
    for (;;) {
      const byte = bytes[at++];
      if (byte === undefined) throw new Error("short");
      value |= BigInt(byte & 127) << shift;
      shift += 7n;
      if (byte < 128) return value;
    }
  };
  while (at < bytes.length) {
    const tag = Number(varint());
    const kind = tag & 7;
    if (kind === 0) out.push([tag >> 3, varint()]);
    else if (kind === 2) {
      const length = Number(varint());
      if (at + length > bytes.length) throw new Error("short");
      out.push([tag >> 3, bytes.subarray(at, at + length)]);
      at += length;
    } else if (kind === 1) at += 8;
    else if (kind === 5) at += 4;
    else throw new Error("wire type");
  }
  return out;
};
const field = (message, wanted) => {
  try {
    for (const [number, value] of fields(Buffer.from(message, "base64"))) {
      if (number === wanted && typeof value !== "bigint") return text(value);
    }
  } catch (error) {
    return "";
  }
  return "";
};
const entry = (topic, wanted) => {
  try {
    for (const [number, data] of fields(Buffer.from(topic, "base64"))) {
      if (number !== 1 || typeof data === "bigint") continue;
      let key = "";
      let row = null;
      for (const [part, value] of fields(data)) {
        if (part === 1 && typeof value !== "bigint") key = text(value);
        if (part === 2 && typeof value !== "bigint") row = value;
      }
      if (key === wanted && row) {
        for (const [part, value] of fields(row)) if (part === 1 && typeof value !== "bigint") return text(value);
      }
    }
  } catch (error) {
    return "";
  }
  return "";
};
const entries = (topic) => {
  const out = [];
  try {
    for (const [number, data] of fields(Buffer.from(topic, "base64"))) {
      if (number !== 1 || typeof data === "bigint") continue;
      let key = "";
      let value = "";
      for (const [part, piece] of fields(data)) {
        if (part === 1 && typeof piece !== "bigint") key = text(piece);
        if (part === 2 && typeof piece !== "bigint") {
          for (const [held, row] of fields(piece)) if (held === 1 && typeof row !== "bigint") value = text(row);
        }
      }
      if (key) out.push([key, value]);
    }
  } catch (error) {
    return [];
  }
  return out;
};
const token = (login) => entry(login[KEYS[0]] || "", "oauthTokenInfoSentinelKey");
const signed = (login) => field(token(login), 1).length > 0 || field(token(login), 3).length > 0;
const account = (login) => field(entry(login[KEYS[1]] || "", "userStatusSentinelKey"), 7);
const whole = (login) => signed(login) && account(login).length > 0;
const read = (file) => {
  const found = {};
  if (!fs.existsSync(file)) return found;
  const db = new DatabaseSync(file, { readOnly: true });
  try {
    const row = db.prepare("SELECT value FROM ItemTable WHERE key = ?");
    for (const key of KEYS) {
      const hit = row.get(key);
      if (hit && hit.value !== null && hit.value !== undefined) found[key] = text(hit.value);
    }
  } catch (error) {
    return {};
  } finally {
    db.close();
  }
  return found;
};
const varint = (number) => {
  const out = [];
  while (number > 127) {
    out.push((number & 127) | 128);
    number = Math.floor(number / 128);
  }
  out.push(number);
  return out;
};
const bytes = (number, value) => [...varint((number << 3) | 2), ...varint(value.length), ...value];
const utf8 = (value) => [...Buffer.from(value, "utf8")];
const base64 = (value) => Buffer.from(value).toString("base64");
const topic = (entries) => base64(entries.flatMap(([key, value]) => bytes(1, [...bytes(1, utf8(key)), ...bytes(2, bytes(1, utf8(value)))])));
const whole_number = (number, value) => base64([...varint(number << 3), ...varint(value)]);
const AGENT = "antigravityUnifiedStateSync.agentPreferences";
const BROWSER = "antigravityUnifiedStateSync.browserPreferences";
const ONBOARDING = "antigravityOnboarding";
// What the agent panel asks of the agent: `Primitive.int32_value` (2) 3 is EAGER, 2 is TURBO,
// `bool_value` (1) true lets it at the files outside the workspace, and
// `PermissionGrantsConfig.allow` (1) is what the language server reads for everything.
const ANSWERS = {
  terminalAutoExecutionPolicySentinelKey: whole_number(2, 3),
  artifactReviewPolicySentinelKey: whole_number(2, 2),
  allowAgentAccessNonWorkspaceFilesSentinelKey: base64([8, 1]),
};
// What the language server itself asks for to be told "everything": each action with the `*`
// target. One of them is `execute_url(localhost)`, the address of the workspace itself.
const EVERY = ["read_file(*)", "write_file(*)", "command(*)", "unsandboxed(*)", "mcp(*)", "read_url(*)", "execute_url(*)"];
const number = (message, wanted) => {
  try {
    for (const [at, value] of fields(Buffer.from(message, "base64"))) if (at === wanted && typeof value === "bigint") return String(value);
  } catch (error) {
    return "";
  }
  return "";
};
const listed = (message, wanted) => {
  const out = [];
  try {
    for (const [at, value] of fields(Buffer.from(message, "base64"))) if (at === wanted && typeof value !== "bigint") out.push(text(value));
  } catch (error) {
    return [];
  }
  return out;
};
// The grants as the application reads them: what is allowed, then what is refused, and never an
// ask, since an ask is a question the person would have to be there for.
const grants = (allow, deny) => base64([
  ...allow.flatMap((one) => bytes(1, utf8(one))),
  ...deny.flatMap((one) => bytes(2, utf8(one))),
]);
// A topic with `wanted` in it and every other entry of the home exactly as it was: the
// settings the application keeps beside the approvals, such as the planning mode, are not ours to
// touch and would be lost by a row written from scratch.
const merged = (held, wanted) => {
  const kept = entries(held);
  const out = [];
  for (const [key, value] of kept) out.push([key, wanted[key] === undefined ? value : wanted[key]]);
  for (const [key, value] of Object.entries(wanted)) {
    if (!kept.some(([was]) => was === key)) out.push([key, value]);
  }
  return topic(out);
};
const prepared = (db) => {
  db.exec("CREATE TABLE IF NOT EXISTS ItemTable (key TEXT UNIQUE ON CONFLICT REPLACE, value BLOB)");
  return db.prepare("INSERT OR REPLACE INTO ItemTable (key, value) VALUES (?, ?)");
};
const row = (file, key) => {
  if (!fs.existsSync(file)) return "";
  const db = new DatabaseSync(file, { readOnly: true });
  try {
    const hit = db.prepare("SELECT value FROM ItemTable WHERE key = ?").get(key);
    return hit && hit.value !== null && hit.value !== undefined ? text(hit.value) : "";
  } catch (error) {
    return "";
  } finally {
    db.close();
  }
};
if (mode === "approvals") {
  const agent = row(from, AGENT);
  const browser = row(from, BROWSER);
  const granted = entry(agent, "permission_grants_global");
  console.log("terminal=" + number(entry(agent, "terminalAutoExecutionPolicySentinelKey"), 2));
  console.log("review=" + number(entry(agent, "artifactReviewPolicySentinelKey"), 2));
  console.log("javascript=" + number(entry(browser, "browser_js_execution_config_sentinel_key"), 1));
  console.log("files=" + number(entry(agent, "allowAgentAccessNonWorkspaceFilesSentinelKey"), 1));
  console.log("allow=" + listed(granted, 1).join(","));
  console.log("ask=" + listed(granted, 3).join(","));
  console.log("onboarding=" + row(from, ONBOARDING));
  process.exit(0);
}
if (mode === "seen") process.exit(whole(read(from)) ? 0 : 1);
if (mode === "take") {
  const login = read(from);
  if (!whole(login)) process.exit(1);
  fs.mkdirSync(path.dirname(to), { recursive: true });
  fs.writeFileSync(to + ".part", JSON.stringify(login), { mode: 0o600 });
  fs.renameSync(to + ".part", to);
  process.exit(0);
}
if (mode === "keep" || mode === "replace") {
  const login = JSON.parse(fs.readFileSync(from, "utf8"));
  if (!whole(login)) process.exit(1);
  if (mode === "keep" && signed(read(to))) process.exit(0);
  fs.mkdirSync(path.dirname(to), { recursive: true });
  const db = new DatabaseSync(to);
  const put = prepared(db);
  for (const key of KEYS) put.run(key, login[key]);
  db.close();
  process.exit(0);
}
if (mode === "approve") {
  fs.mkdirSync(path.dirname(from), { recursive: true });
  const db = new DatabaseSync(from);
  const put = prepared(db);
  const agent = row(from, AGENT);
  const granted = entry(agent, "permission_grants_global");
  const allow = listed(granted, 1);
  put.run(AGENT, merged(agent, {
    ...ANSWERS,
    permission_grants_global: grants([...allow, ...EVERY.filter((one) => !allow.includes(one))], listed(granted, 2)),
  }));
  put.run(BROWSER, merged(row(from, BROWSER), { browser_js_execution_config_sentinel_key: whole_number(1, 4) }));
  put.run(ONBOARDING, "true");
  db.close();
  process.exit(0);
}
process.exit(2);
"#;
Expand description

The program that reads and writes the two rows, run by Node inside a container.

A row being there is not a login: the application writes the token’s row as soon as it has looked whether it is signed in, holding only “signed out” when it is not (measured: a window that never signed in had the row, with authStateWithContextSentinelKey in it and no token). So the rows are read the way the application reads them. Each is a Topic of the application’s state sync, data (1) a map of key (1) to a Row whose value (1) is the entry, all written as base64 of the protocol buffer (exa.unified_state_sync_pb, read out of the descriptors in main.js). A login is the token row’s oauthTokenInfoSentinelKey entry, an OAuthTokenInfo with an access (1) or refresh (3) token, beside the account row’s userStatusSentinelKey entry, a UserStatus with an e-mail (7) — the two things the extension asks for.

With a third word approve, the agent’s own approvals are merged into the database: what makes the window’s agent run a command, write a file, go past a plan and act in its browser without asking, and what the language server is told it may do on its own — see ANSWERED for the rows and approve_command for where the program is run. A database that is not there is made with them, as keep and replace make it for a login. approvals <database> prints every one of those settings as the application would read them, one name=value line each, empty for one that is not there.

seen <database> answers 0 when there is a login; take <database> <file> writes the two rows into the file and fails when there is none; keep <file> <database> puts them into the database unless it holds a token of its own, and replace <file> <database> puts them in whatever it holds. A database that is not there is made, with the table the application makes. Written with double quotes only, so that a shell can carry it inside single ones.