Anigravity 1.23.2 will not start

I cannot confirm this fixed yet (on Windows 11. I had to create a patch of the minified JS file (now get a warning that my Antigravity may be corrupt, but it’s working flawlessly so far.

AG-PATCH — Antigravity infinite Preact re-render fix

Fixes the startup freeze caused by the server-synced “Gemini 3.6” tiered model catalog poisoning uss-userStatus (and uss-theme / uss-sidebarWorkspaces) and flooding Preact’s render queue (Z_t / PJr in the unresponsive stack).

Why a script instead of a .diff

The bundle is minified into lines up to ~800 KB long. A unified diff would embed each changed line twice (~4 MB) and break on any whitespace nuance, so the patch ships as an idempotent string-replacement script with exact-match anchors that aborts if the bundle doesn’t match.

What it changes (4 edits)

  1. Prepends globalThis.__agDeepEq — bounded (depth 20, 20k-op budget), BigInt/Uint8Array/Date-aware deep-equality helper; bails to “not equal” (= original behavior) on cycles or functions.
  2. z0.setState (provider store feeding Preact): no-op when the new state deep-equals the current state → identical payloads no longer re-render.
  3. Unified-state-sync ingestion handler: drops no-op topic updates before they touch the reactive store, for all uss-* topics.
  4. uss-userStatus decoder: filters model-catalog entries with no valid modelOrAlias and any label matching /gemini[\s._-]?3.6/i.

Apply

  1. Quit Antigravity completely (check no background processes remain).

  2. Locate the bundle, e.g. on Windows: %LOCALAPPDATA%\Programs\Antigravity\resources\app\out\vs\workbench\workbench.desktop.main.js (macOS: Antigravity.app/Contents/Resources/app/out/vs/workbench/...)

  3. Run:

    python apply-antigravity-patch.py "<path>\workbench.desktop.main.js"
    
    

    It creates workbench.desktop.main.js.bak beside the original and prints applied: ... for each edit. Re-running prints “Already patched”.

  4. Optional sanity check: node --check "<path>\workbench.desktop.main.js"

  5. Launch Antigravity. The server can keep re-syncing the corrupted state; identical payloads are now no-ops and the 3.6 entries never reach the sidebar component.

Roll back

Restore the .bak file over the patched one.

Caveats

  • Any Antigravity update overwrites the bundle → re-run the script.
  • Anchors are tied to this build’s minified identifiers (z0, E2, hBe, Rp, hs). On a new build the script aborts safely with an anchor-count error rather than corrupting the file; anchors must then be re-derived.
  • If the app caches compiled code (Code Cache/CachedData in the user data dir), delete it if the patch doesn’t seem to take effect.

Python Script

#!/usr/bin/env python3
"""
AG-PATCH: fixes infinite Preact re-render loop in Antigravity IDE caused by
unvalidated 'Gemini 3.6' tiered model catalog in uss-userStatus sync payloads.

Applies 4 changes to workbench.desktop.main.js:
  0. Prepends a bounded, cycle-safe deep-equality helper (globalThis.__agDeepEq)
  1. z0.setState: skips firing when new provider state deep-equals current state
  2. Unified-state-sync ingestion: drops no-op topic updates (identical row /
     delete of missing key) before they hit the reactive store
  3. uss-userStatus decoder (bYt): filters catalog entries with no valid
     modelOrAlias and anything matching /gemini[\\s._-]?3.6/i

Usage:
    python apply-antigravity-patch.py <path-to-workbench.desktop.main.js>

Idempotent: safe to re-run. Creates <file>.bak on first apply.
"""
import sys, os, shutil

MARKER = "/* AG-PATCH: deep-equality helper to dedupe identical state-sync payloads */"

HELPER = (
 MARKER +
 'globalThis.__agDeepEq||(globalThis.__agDeepEq=function(t,e){var B={n:2e4};'
 'function q(a,b,d){if(B.n--<0)return!1;if(a===b)return!0;if(d>20)return!1;'
 'if(!a||!b||typeof a!="object"||typeof b!="object")return a!==a&&b!==b;'
 'if(Array.isArray(a)){if(!Array.isArray(b)||a.length!==b.length)return!1;'
 'for(var i=0;i<a.length;i++)if(!q(a[i],b[i],d+1))return!1;return!0}'
 'if(a instanceof Uint8Array||b instanceof Uint8Array){'
 'if(!(a instanceof Uint8Array&&b instanceof Uint8Array)||a.length!==b.length)return!1;'
 'for(var j=0;j<a.length;j++)if(a[j]!==b[j])return!1;return!0}'
 'if(a instanceof Date||b instanceof Date)return a instanceof Date&&b instanceof Date&&a.getTime()===b.getTime();'
 'if(Object.getPrototypeOf(a)!==Object.getPrototypeOf(b))return!1;'
 'var ka=Object.keys(a),kb=Object.keys(b);if(ka.length!==kb.length)return!1;'
 'for(var m=0;m<ka.length;m++){var k=ka[m];'
 'if(!Object.prototype.hasOwnProperty.call(b,k)||!q(a[k],b[k],d+1))return!1}return!0}'
 'return q(t,e,0)});\n'
)

# (name, old, new) — each `old` must occur exactly once in the unpatched bundle.
# NOTE: identifiers (z0, E2, hBe, Rp, hs...) are minifier-generated and will
# change between Antigravity releases; anchors must be re-derived after updates.
EDITS = [
    ("z0.setState equality guard",
     'setState(t){this.state=t,this._onDidChange.fire(t)}',
     'setState(t){if(globalThis.__agDeepEq&&globalThis.__agDeepEq(this.state,t))return;'
     'this.state=t,this._onDidChange.fire(t)}'),

    ("uss ingestion dedupe",
     'a.newRow?l.data[a.key]=a.newRow:delete l.data[a.key],r.set(l,void 0)',
     'if(a.newRow?l.data[a.key]&&globalThis.__agDeepEq&&globalThis.__agDeepEq(l.data[a.key],a.newRow):!(a.key in l.data))return;'
     'a.newRow?l.data[a.key]=a.newRow:delete l.data[a.key],r.set(l,void 0)'),

    ("uss-userStatus payload sanitizer",
     'try{return E2(e,hBe)}catch{return hs(hBe)}',
     'try{const w=E2(e,hBe),cf=w&&w.cascadeModelConfigData;'
     'if(cf&&Array.isArray(cf.clientModelConfigs)){'
     'const ok=q=>{try{return!!(q&&q.modelOrAlias&&q.modelOrAlias.choice&&q.modelOrAlias.choice.case)'
     '&&!/gemini[\\s._-]?3\\.6/i.test(String(q.label||""))}catch{return!1}};'
     'cf.clientModelConfigs=cf.clientModelConfigs.filter(ok)}'
     'return w}catch{return hs(hBe)}'),
]


def main():
    if len(sys.argv) != 2:
        sys.exit(__doc__)
    path = sys.argv[1]
    if not os.path.isfile(path):
        sys.exit(f"error: no such file: {path}")

    with open(path, encoding="utf-8") as f:
        s = f.read()

    if MARKER in s:
        sys.exit("Already patched — nothing to do.")

    for name, old, _ in EDITS:
        n = s.count(old)
        if n != 1:
            sys.exit(f"error: anchor for '{name}' found {n} times (expected 1).\n"
                     "The bundle version differs from the one this patch targets; "
                     "identifiers must be re-derived.")

    bak = path + ".bak"
    if not os.path.exists(bak):
        shutil.copy2(path, bak)
        print(f"backup: {bak}")

    s = HELPER + s
    for name, old, new in EDITS:
        s = s.replace(old, new)
        print(f"applied: {name}")

    with open(path, "w", encoding="utf-8") as f:
        f.write(s)
    print(f"patched: {path}")


if __name__ == "__main__":
    main()