@wenathlan/devthink 2.0.14 → 2.0.19
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/CHANGELOG.md +60 -0
- package/{dist/bridge.d.ts → bridge.d.ts} +1 -1
- package/bridge.d.ts.map +1 -0
- package/bridge.js +1877 -0
- package/bun.d.ts.map +1 -0
- package/bun.js +52329 -0
- package/caps/background.json +712 -0
- package/caps/cli.json +360 -0
- package/caps/library.json +3611 -0
- package/caps/mcp.json +126 -0
- package/caps/pagebridge.json +377 -0
- package/caps/popup.json +51 -0
- package/caps/sidepanel.json +522 -0
- package/checksums.txt +142 -0
- package/cli.d.ts.map +1 -0
- package/{dist/cli.js → cli.js} +2 -2
- package/companion.d.ts.map +1 -0
- package/companion.js +389 -0
- package/crossbrowser.d.ts.map +1 -0
- package/crossbrowser.js +1191 -0
- package/dashdone.d.ts.map +1 -0
- package/dashdone.js +368 -0
- package/deno.d.ts.map +1 -0
- package/deno.js +52325 -0
- package/devthink.umd.js +52346 -0
- package/fixtures/bun.ts +7 -0
- package/fixtures/cjs.js +6 -0
- package/fixtures/deno.ts +6 -0
- package/fixtures/example-org-pagestate.json +22 -0
- package/fixtures/importers/automa-workflow.json +18 -0
- package/fixtures/importers/selenium-side.json +20 -0
- package/fixtures/importers/tabular-plan.csv +7 -0
- package/fixtures/importers/uivision-macro.json +10 -0
- package/fixtures/importers/v1-plan.json +13 -0
- package/fixtures/mcp-client.mjs +14 -0
- package/fixtures/pages/checkout.html +192 -0
- package/fixtures/pages/dashboard.html +110 -0
- package/fixtures/pages/feed.html +113 -0
- package/fixtures/pages/product-grid.html +150 -0
- package/fixtures/plans/form-inventory-plan.json +11 -0
- package/fixtures/plans/release-notes-plan.json +11 -0
- package/fixtures/recipes/agentscompete.json +11 -0
- package/fixtures/recipes/agentsforms.json +11 -0
- package/fixtures/recipes/agentsmonitor.json +11 -0
- package/fixtures/recipes/agentsreview.json +29 -0
- package/fixtures/recipes/agentswarm.json +11 -0
- package/fixtures/recipes/fillcalendar.json +12 -0
- package/fixtures/recipes/fillcheckout.json +13 -0
- package/fixtures/recipes/filldependentdropdowns.json +12 -0
- package/fixtures/recipes/fillfromcsv.json +13 -0
- package/fixtures/recipes/fillloginform.json +12 -0
- package/fixtures/recipes/fillmultistepwizard.json +13 -0
- package/fixtures/recipes/fillregistration.json +12 -0
- package/fixtures/recipes/fillsearchfilters.json +12 -0
- package/fixtures/recipes/filltypeahead.json +11 -0
- package/fixtures/recipes/monitoralerts.json +12 -0
- package/fixtures/recipes/monitoravailability.json +11 -0
- package/fixtures/recipes/monitornetworkquiet.json +12 -0
- package/fixtures/recipes/monitorpagechanges.json +11 -0
- package/fixtures/recipes/monitorpricechange.json +11 -0
- package/fixtures/recipes/monitorschedule.json +12 -0
- package/fixtures/recipes/scrapedynamicprices.json +13 -0
- package/fixtures/recipes/scrapeimagegallery.json +12 -0
- package/fixtures/recipes/scrapeinfinitefeed.json +13 -0
- package/fixtures/recipes/scrapenestedlists.json +12 -0
- package/fixtures/recipes/scrapeproductgrid.json +12 -0
- package/fixtures/recipes/scrapereviews.json +12 -0
- package/fixtures/recipes/scrapesearchresults.json +12 -0
- package/fixtures/recipes/scrapetablepagination.json +12 -0
- package/fixtures/recipes/testaccessibility.json +34 -0
- package/fixtures/recipes/testconsoleerrors.json +12 -0
- package/fixtures/recipes/testdeeplinks.json +12 -0
- package/fixtures/recipes/testformvalidation.json +13 -0
- package/fixtures/recipes/testlayoutshift.json +12 -0
- package/fixtures/recipes/testlinkcheck.json +12 -0
- package/fixtures/recipes/testloadtiming.json +12 -0
- package/fixtures/recipes/testvisualdiff.json +12 -0
- package/fixtures/workflows/changelog-digest-workflow.json +13 -0
- package/fixtures/workflows/form-survey-workflow.json +13 -0
- package/gallery.json +706 -0
- package/hardening.d.ts.map +1 -0
- package/hardening.js +188 -0
- package/headless.d.ts.map +1 -0
- package/headless.js +11522 -0
- package/http.d.ts.map +1 -0
- package/http.js +2165 -0
- package/index.cjs +54682 -0
- package/index.d.ts.map +1 -0
- package/index.js +52310 -0
- package/index.neutral.js +46343 -0
- package/{web/manifest.json → manifest.json} +1 -1
- package/mcp.d.ts.map +1 -0
- package/mcp.js +20515 -0
- package/memory.d.ts.map +1 -0
- package/{memory.ts → memory.js} +2310 -3834
- package/nativehost.template.json +10 -0
- package/node.cjs +54686 -0
- package/node.d.ts.map +1 -0
- package/pack.d.ts.map +1 -0
- package/pack.js +805 -0
- package/package.json +83 -176
- package/policy.d.ts.map +1 -0
- package/{policy.ts → policy.js} +4679 -5073
- package/progress.d.ts.map +1 -0
- package/progress.js +645 -0
- package/protocol.d.ts.map +1 -0
- package/protocol.js +8334 -0
- package/schemas/audit.schema.json +226 -0
- package/schemas/capability.schema.json +113 -0
- package/schemas/envelope.schema.json +162 -0
- package/schemas/memory.schema.json +51 -0
- package/schemas/observation.schema.json +113 -0
- package/schemas/plan.schema.json +208 -0
- package/schemas/progress.schema.json +126 -0
- package/schemas/proposal.schema.json +68 -0
- package/schemas/session.schema.json +82 -0
- package/schemas/tool.schema.json +94 -0
- package/server.d.ts.map +1 -0
- package/server.js +28877 -0
- package/umd-example.html +18 -0
- package/umd.d.ts.map +1 -0
- package/accounts.ts +0 -2087
- package/agent.ts +0 -2331
- package/antigravity.ts +0 -2139
- package/apifreeze.ts +0 -4146
- package/auth.ts +0 -642
- package/background.ts +0 -16837
- package/bridge.ts +0 -2080
- package/build.ts +0 -54
- package/bun.ts +0 -26
- package/capture.ts +0 -1614
- package/checksecrets.ts +0 -72
- package/cjs.ts +0 -9
- package/cli.ts +0 -3500
- package/commands.ts +0 -1101
- package/companion.ts +0 -450
- package/compatibility.ts +0 -37
- package/config.ts +0 -3137
- package/constants.ts +0 -943
- package/core.ts +0 -1473
- package/crossbrowser.ts +0 -1359
- package/dashdone.ts +0 -605
- package/data.ts +0 -943
- package/database.ts +0 -133
- package/debug.ts +0 -850
- package/deno.ts +0 -27
- package/devthink.ts +0 -707
- package/dist/accounts.d.ts +0 -409
- package/dist/agent.d.ts +0 -837
- package/dist/antigravity.d.ts +0 -380
- package/dist/apifreeze.d.ts +0 -113
- package/dist/auth.d.ts +0 -224
- package/dist/capture.d.ts +0 -595
- package/dist/cjs.d.ts +0 -6
- package/dist/commands.d.ts +0 -310
- package/dist/compatibility.d.ts +0 -17
- package/dist/config.d.ts +0 -1853
- package/dist/constants.d.ts +0 -637
- package/dist/core.d.ts +0 -361
- package/dist/data.d.ts +0 -330
- package/dist/database.d.ts +0 -24
- package/dist/debug.d.ts +0 -270
- package/dist/engine.d.ts +0 -74
- package/dist/environments.d.ts +0 -244
- package/dist/evidence.d.ts +0 -277
- package/dist/export.d.ts +0 -311
- package/dist/fingerprint.d.ts +0 -594
- package/dist/flow.d.ts +0 -300
- package/dist/gates.d.ts +0 -103
- package/dist/identity.d.ts +0 -51
- package/dist/ids.d.ts +0 -7
- package/dist/llm.d.ts +0 -652
- package/dist/models.d.ts +0 -1807
- package/dist/net.d.ts +0 -325
- package/dist/neutral.d.ts +0 -41
- package/dist/oauth.d.ts +0 -703
- package/dist/page.d.ts +0 -1166
- package/dist/perf.d.ts +0 -481
- package/dist/plan.d.ts +0 -134
- package/dist/project.d.ts +0 -395
- package/dist/providers.d.ts +0 -37
- package/dist/quota.d.ts +0 -453
- package/dist/recovery.d.ts +0 -621
- package/dist/request.d.ts +0 -1492
- package/dist/run.d.ts +0 -779
- package/dist/runtime.d.ts +0 -212
- package/dist/search.d.ts +0 -375
- package/dist/security.d.ts +0 -534
- package/dist/serve.d.ts +0 -136
- package/dist/session.d.ts +0 -296
- package/dist/storage.d.ts +0 -53
- package/dist/streaming.d.ts +0 -1119
- package/dist/swarm.d.ts +0 -328
- package/dist/tools.d.ts +0 -170
- package/dist/types.d.ts +0 -8357
- package/dist/utils.d.ts +0 -82
- package/dist/version.d.ts +0 -7
- package/dist/versionregistry.d.ts +0 -406
- package/dist/views.d.ts +0 -579
- package/dist/workbenchsession.d.ts +0 -69
- package/dist/workflow.d.ts +0 -649
- package/docs/readme.md +0 -92
- package/docs/schemas/antigravity.json +0 -192
- package/engine.ts +0 -1524
- package/environments.ts +0 -1005
- package/evidence.ts +0 -643
- package/export.ts +0 -889
- package/fingerprint.ts +0 -1458
- package/flow.ts +0 -1190
- package/gates.ts +0 -307
- package/gateway.ts +0 -34
- package/hardening.ts +0 -191
- package/headless.ts +0 -369
- package/http.ts +0 -2110
- package/identity.ts +0 -246
- package/ids.ts +0 -26
- package/index.ts +0 -369
- package/llm.ts +0 -2682
- package/mcp.ts +0 -1835
- package/models.ts +0 -3805
- package/modes.ts +0 -43
- package/net.ts +0 -1214
- package/neutral.ts +0 -362
- package/node.ts +0 -26
- package/oauth.ts +0 -2216
- package/offscreen.ts +0 -170
- package/pack.ts +0 -956
- package/page.ts +0 -7824
- package/pagebridge.ts +0 -1116
- package/perf.ts +0 -957
- package/plan.ts +0 -672
- package/plugin.ts +0 -76
- package/prisma.config.ts +0 -27
- package/progress.ts +0 -1308
- package/project.ts +0 -1291
- package/protocol.ts +0 -4187
- package/providers.ts +0 -246
- package/quota.ts +0 -1887
- package/recovery.ts +0 -2433
- package/request.ts +0 -4482
- package/run.ts +0 -2135
- package/runtime.ts +0 -526
- package/search.ts +0 -1760
- package/security.ts +0 -1673
- package/serve.ts +0 -419
- package/server.ts +0 -5538
- package/session.ts +0 -1162
- package/storage.ts +0 -182
- package/streaming.ts +0 -4101
- package/swarm.ts +0 -884
- package/sync.ts +0 -56
- package/tests/agentcert.test.ts +0 -128
- package/tests/agentfleet.test.ts +0 -214
- package/tests/agentreview.test.ts +0 -241
- package/tests/agentstream.test.ts +0 -335
- package/tests/agentwork.test.ts +0 -356
- package/tests/apifreeze.test.ts +0 -290
- package/tests/apimap.test.ts +0 -112
- package/tests/approvalgate.test.ts +0 -175
- package/tests/artifactmanifest.test.ts +0 -204
- package/tests/attentionfeed.test.ts +0 -163
- package/tests/backgroundruns.test.ts +0 -100
- package/tests/batchscheduling.test.ts +0 -131
- package/tests/blackboard.test.ts +0 -238
- package/tests/bridge.test.ts +0 -1088
- package/tests/browsercoverage.test.ts +0 -134
- package/tests/browserpolyfills.test.ts +0 -124
- package/tests/build.mjs +0 -1260
- package/tests/clientauth.test.ts +0 -223
- package/tests/clitools.test.ts +0 -578
- package/tests/confirmgates.test.ts +0 -190
- package/tests/containerpack.test.ts +0 -143
- package/tests/controlflow.test.ts +0 -2120
- package/tests/coordination.test.ts +0 -345
- package/tests/copyscreen.test.ts +0 -139
- package/tests/core.test.ts +0 -417
- package/tests/costcert.test.ts +0 -95
- package/tests/crossbrowser.test.ts +0 -115
- package/tests/cspaudit.test.ts +0 -79
- package/tests/dashdone.test.ts +0 -615
- package/tests/datagrid.test.ts +0 -137
- package/tests/doccheck.test.ts +0 -107
- package/tests/dombatch.test.ts +0 -109
- package/tests/emulation.test.ts +0 -282
- package/tests/environments.test.ts +0 -259
- package/tests/evidenceviews.test.ts +0 -88
- package/tests/exporttools.test.ts +0 -185
- package/tests/firefoxprep.test.ts +0 -134
- package/tests/flowlibrary.test.ts +0 -242
- package/tests/flowrun.test.ts +0 -303
- package/tests/forensics.test.ts +0 -439
- package/tests/gateway.test.ts +0 -939
- package/tests/headlesslib.test.ts +0 -171
- package/tests/httpstream.test.ts +0 -277
- package/tests/immutablelog.test.ts +0 -157
- package/tests/inboundguard.test.ts +0 -177
- package/tests/lazyload.test.ts +0 -72
- package/tests/librarymodes.test.ts +0 -623
- package/tests/llm.test.ts +0 -696
- package/tests/manifest.test.ts +0 -226
- package/tests/maskinputs.test.ts +0 -150
- package/tests/matrixverify.test.ts +0 -111
- package/tests/mavenpack.test.ts +0 -75
- package/tests/mcpserver.test.ts +0 -704
- package/tests/memory.test.ts +0 -4155
- package/tests/memorycare.test.ts +0 -230
- package/tests/migrateplan.test.ts +0 -349
- package/tests/minimization.test.ts +0 -414
- package/tests/modelroute.test.ts +0 -112
- package/tests/multiagent.test.ts +0 -440
- package/tests/nativebridge.test.ts +0 -807
- package/tests/navigation.test.ts +0 -284
- package/tests/nugetpack.test.ts +0 -83
- package/tests/orchestration.test.ts +0 -449
- package/tests/originpolicy.test.ts +0 -405
- package/tests/outputcompare.test.ts +0 -97
- package/tests/package.test.ts +0 -91
- package/tests/pagebridge.test.ts +0 -5909
- package/tests/pentest.test.ts +0 -75
- package/tests/perfrecords.test.ts +0 -257
- package/tests/permdiff.test.ts +0 -85
- package/tests/phishguard.test.ts +0 -128
- package/tests/pickerviews.test.ts +0 -155
- package/tests/pipelines.test.ts +0 -381
- package/tests/planlint.test.ts +0 -240
- package/tests/planreview.test.ts +0 -383
- package/tests/platformtargets.test.ts +0 -56
- package/tests/policy.test.ts +0 -8284
- package/tests/portability.test.ts +0 -96
- package/tests/progress.test.ts +0 -1036
- package/tests/promptlibrary.test.ts +0 -116
- package/tests/protocol.test.ts +0 -4793
- package/tests/publishingpipeline.test.ts +0 -314
- package/tests/quickactions.test.ts +0 -164
- package/tests/readiness.test.ts +0 -78
- package/tests/recipes.test.ts +0 -163
- package/tests/redactshots.test.ts +0 -216
- package/tests/registernvidiakeys.ts +0 -51
- package/tests/relayserve.test.ts +0 -304
- package/tests/releasenotes.test.ts +0 -276
- package/tests/resilience.test.ts +0 -467
- package/tests/resourceaware.test.ts +0 -187
- package/tests/runbudget.test.ts +0 -125
- package/tests/runhistory.test.ts +0 -299
- package/tests/runreplay.test.ts +0 -113
- package/tests/runresume.test.ts +0 -184
- package/tests/runstate.test.ts +0 -288
- package/tests/runtimeadapters.test.ts +0 -251
- package/tests/safariskeleton.test.ts +0 -115
- package/tests/sandboxframe.test.ts +0 -196
- package/tests/sbom.test.ts +0 -105
- package/tests/secretvault.test.ts +0 -188
- package/tests/selcache.test.ts +0 -111
- package/tests/sessioninterface.test.ts +0 -791
- package/tests/sessions.test.ts +0 -591
- package/tests/siteprefs.test.ts +0 -228
- package/tests/snapshotdelta.test.ts +0 -165
- package/tests/statusviews.test.ts +0 -237
- package/tests/stepmeter.test.ts +0 -200
- package/tests/streamparse.test.ts +0 -163
- package/tests/stylepruning.test.ts +0 -90
- package/tests/surfaces.test.ts +0 -282
- package/tests/sweep.test.ts +0 -78
- package/tests/syncbridge.test.ts +0 -164
- package/tests/taskqueue.test.ts +0 -206
- package/tests/toolcalls.test.ts +0 -336
- package/tests/toolcatalog.test.ts +0 -201
- package/tests/torture-agent.test.ts +0 -706
- package/tests/torture-auth.test.ts +0 -461
- package/tests/torture-commands.test.ts +0 -895
- package/tests/torture-data.test.ts +0 -923
- package/tests/torture-environments.test.ts +0 -285
- package/tests/torture-export.test.ts +0 -263
- package/tests/torture-http.test.ts +0 -1379
- package/tests/torture-llm.test.ts +0 -808
- package/tests/torture-memory.test.ts +0 -1084
- package/tests/torture-plan.test.ts +0 -829
- package/tests/torture-run.test.ts +0 -626
- package/tests/torture-session.test.ts +0 -928
- package/tests/torture-swarm.test.ts +0 -1245
- package/tests/torture-tools.test.ts +0 -964
- package/tests/torture-workflow.test.ts +0 -2354
- package/tests/tourviews.test.ts +0 -52
- package/tests/transparency.test.ts +0 -147
- package/tests/trigger.test.ts +0 -941
- package/tests/v1sunset.test.ts +0 -428
- package/tests/virtlist.test.ts +0 -94
- package/tests/vision.test.ts +0 -540
- package/tests/vsixpack.test.ts +0 -145
- package/tests/webapi.test.ts +0 -523
- package/tests/workflow.test.ts +0 -1785
- package/tests/workfloweditor.test.ts +0 -759
- package/tests/xpipack.test.ts +0 -128
- package/tools.ts +0 -734
- package/types.ts +0 -9908
- package/umd.ts +0 -9
- package/utils.ts +0 -249
- package/version.ts +0 -8
- package/versionregistry.ts +0 -1310
- package/views.ts +0 -2153
- package/vitest.config.ts +0 -12
- package/web/App.tsx +0 -78
- package/web/README.md +0 -47
- package/web/capacitor.config.ts +0 -46
- package/web/const.ts +0 -19
- package/web/control.shell.tsx +0 -66
- package/web/dashboardpage.ts +0 -554
- package/web/db.ts +0 -493
- package/web/design.html +0 -541
- package/web/gatewayview/Gateway.tsx +0 -345
- package/web/gatewayview/config.ts +0 -1042
- package/web/gatewayview/definition.ts +0 -174
- package/web/icons.ts +0 -15
- package/web/optionspage.ts +0 -691
- package/web/popup.ts +0 -1651
- package/web/schema.prisma +0 -176
- package/web/sidepanel.ts +0 -7941
- package/web/sitemanifest.json +0 -13
- package/web/terminal-ui.tsx +0 -622
- package/web/transparencypage.ts +0 -541
- package/web/vite.config.ts +0 -39
- package/web/workspace.ts +0 -23
- package/workbenchmemory.ts +0 -104
- package/workbenchsession.ts +0 -304
- package/workflow.ts +0 -4495
- /package/{dist/bun.d.ts → bun.d.ts} +0 -0
- /package/{dist/cli.d.ts → cli.d.ts} +0 -0
- /package/{dist/companion.d.ts → companion.d.ts} +0 -0
- /package/{dist/crossbrowser.d.ts → crossbrowser.d.ts} +0 -0
- /package/{dist/dashdone.d.ts → dashdone.d.ts} +0 -0
- /package/{dist/deno.d.ts → deno.d.ts} +0 -0
- /package/{dist/hardening.d.ts → hardening.d.ts} +0 -0
- /package/{dist/headless.d.ts → headless.d.ts} +0 -0
- /package/{dist/http.d.ts → http.d.ts} +0 -0
- /package/{dist/index.d.ts → index.d.ts} +0 -0
- /package/{dist/mcp.d.ts → mcp.d.ts} +0 -0
- /package/{dist/memory.d.ts → memory.d.ts} +0 -0
- /package/{dist/node.d.ts → node.d.ts} +0 -0
- /package/{dist/pack.d.ts → pack.d.ts} +0 -0
- /package/{dist/policy.d.ts → policy.d.ts} +0 -0
- /package/{dist/progress.d.ts → progress.d.ts} +0 -0
- /package/{dist/protocol.d.ts → protocol.d.ts} +0 -0
- /package/{dist/server.d.ts → server.d.ts} +0 -0
- /package/{dist/umd.d.ts → umd.d.ts} +0 -0
package/fingerprint.ts
DELETED
|
@@ -1,1458 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file fingerprint.ts
|
|
3
|
-
* @module provider/fingerprint
|
|
4
|
-
* @description
|
|
5
|
-
* Anti-detection fingerprint generator mimicking Gemini CLI / Antigravity
|
|
6
|
-
* traffic against cloudcode-pa.googleapis.com (merged superset of the two
|
|
7
|
-
* prior variants).
|
|
8
|
-
*
|
|
9
|
-
* v2.1.15 Phase B: this module is THE single owner of identity masquerade —
|
|
10
|
-
* it absorbed getDynamicUserAgent (+Async), fetchRemoteAntigravityVersion,
|
|
11
|
-
* normalizePlatform/normalizeArch, getXGoogApiClient + X_GOOG_API_CLIENT (+
|
|
12
|
-
* the accurately split X_GOOG_API_CLIENT_GEMINI_CLI snapshot),
|
|
13
|
-
* buildClientMetadata, buildGeminiUserAgent, ua/apiClient (auth lineage),
|
|
14
|
-
* getRandomPlatformString, getGeminiCLIHeaders(WithOptions),
|
|
15
|
-
* getAntigravityHeaders(WithOptions), buildAntagravityHeaders (canonical of
|
|
16
|
-
* the five plugin/project/quota/search/models variants) and the hex/limit
|
|
17
|
-
* utility re-exports from core.js. Raw values stay in constants.ts; generic
|
|
18
|
-
* utilities live in core.js.
|
|
19
|
-
*
|
|
20
|
-
* Merged responsibilities:
|
|
21
|
-
* - OAuth constants, endpoints, 2026 model list
|
|
22
|
-
* - Weighted coherent platform pools (win32/x64, linux/x64, darwin/arm64)
|
|
23
|
-
* plus a keyed PLATFORM_POOLS record with Go-style amd64 naming
|
|
24
|
-
* - Deterministic FNV-1a hashing for session_id / user_prompt_id
|
|
25
|
-
* - Jitter 0-80ms anti-rate-limit (sync value + async sleep + instance API)
|
|
26
|
-
* - Gemini CLI style User-Agent with google-api-nodejs-client pairing
|
|
27
|
-
* - Antigravity style User-Agent (`antigravity/{version} {os}/{arch}`)
|
|
28
|
-
* - X-Goog-Api-Client generation (simplified and full chains)
|
|
29
|
-
* - Client-Metadata (fixed IDE_UNSPECIFIED form and structured JSON form)
|
|
30
|
-
* - Unified FingerprintGenerator constructor accepting BOTH option shapes:
|
|
31
|
-
* new FingerprintGenerator({ directory, allowExtendedPlatforms, ... })
|
|
32
|
-
* new FingerprintGenerator("1.19.2" | "antigravity/1.19.2 darwin/arm64")
|
|
33
|
-
* - defaultFingerprintGenerator singleton + getFingerprintHeaders() wrapper
|
|
34
|
-
*
|
|
35
|
-
* Runtime constraint: only node:* builtins + global fetch/Headers.
|
|
36
|
-
*
|
|
37
|
-
* @license MIT
|
|
38
|
-
*/
|
|
39
|
-
|
|
40
|
-
import * as os from "node:os";
|
|
41
|
-
import * as path from "node:path";
|
|
42
|
-
import * as crypto from "node:crypto";
|
|
43
|
-
|
|
44
|
-
// ============================================================================
|
|
45
|
-
// Section: Mandatory constants (OAuth bypass context) — identical values are
|
|
46
|
-
// imported from the frozen owner constants.ts; divergent local variants are
|
|
47
|
-
// kept below with an explicit marker
|
|
48
|
-
// ============================================================================
|
|
49
|
-
|
|
50
|
-
import {
|
|
51
|
-
ANTIGRAVITY_CLI_VERSION_POOL,
|
|
52
|
-
ANTIGRAVITY_CLIENT_METADATA_TEMPLATE,
|
|
53
|
-
ANTIGRAVITY_USER_AGENT_FALLBACK,
|
|
54
|
-
ANTIGRAVITY_VERSION_FALLBACK,
|
|
55
|
-
ANTIGRAVITY_VERSION_REMOTE_URLS,
|
|
56
|
-
ARCH_POOL,
|
|
57
|
-
CLOUDCODE_BASE_URL,
|
|
58
|
-
CURRENT_GAPI_CLIENT_VERSION,
|
|
59
|
-
CURRENT_GEMINI_CLI_VERSION,
|
|
60
|
-
CURRENT_GL_NODE_VERSION,
|
|
61
|
-
FINGERPRINT_IDE_TYPES,
|
|
62
|
-
FINGERPRINT_PLATFORMS,
|
|
63
|
-
FINGERPRINT_PLUGIN_TYPES,
|
|
64
|
-
FINGERPRINT_USER_AGENT_SOURCES,
|
|
65
|
-
GAPI_CLIENT_VERSION_POOL,
|
|
66
|
-
GEMINI_CLI_OAUTH_CLIENT_ID as OAUTH_CLIENT_ID,
|
|
67
|
-
GEMINI_CLI_OAUTH_CLIENT_SECRET as OAUTH_CLIENT_SECRET,
|
|
68
|
-
GEMINI_CLI_SCOPES,
|
|
69
|
-
GEMINI_CLI_VERSION_POOL,
|
|
70
|
-
GL_NODE_VERSION_POOL,
|
|
71
|
-
PLATFORM_POOL,
|
|
72
|
-
PROJECT_FALLBACK,
|
|
73
|
-
VERSION_FETCH_TIMEOUT_MS,
|
|
74
|
-
} from "./constants.js";
|
|
75
|
-
import type { AntigravityVersion, SupportedArch, SupportedPlatform } from "./constants.js";
|
|
76
|
-
export { ANTIGRAVITY_VERSION_FALLBACK, OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET, PROJECT_FALLBACK };
|
|
77
|
-
|
|
78
|
-
// local variant: diverges from constants (constants.GEMINI_CLI_SCOPES is the 9-scope antigravity set with openid/email/profile/cclog; this is the 3-scope Gemini CLI set — value equals constants.GEMINI_CLI_SCOPES)
|
|
79
|
-
/** Scopes required by the Gemini CLI auth flow. */
|
|
80
|
-
// v2.1.15 Phase C: GEMINI_CLI_SCOPES (3-scope Gemini CLI set) is constants.js
|
|
81
|
-
// GEMINI_CLI_SCOPES — imported from the owner.
|
|
82
|
-
|
|
83
|
-
/** Base URL for the Cloud Code API (imported from constants.js — canonical owner since v2.1.15 Phase B). */
|
|
84
|
-
export { CLOUDCODE_BASE_URL };
|
|
85
|
-
export type { AntigravityVersion, SupportedArch, SupportedPlatform };
|
|
86
|
-
|
|
87
|
-
// local variant: diverges from core (core.ENDPOINTS is the {PROD,DAILY,SANDBOX} base-URL map; this is the full v1internal URL map keyed by RPC name)
|
|
88
|
-
/**
|
|
89
|
-
* v1internal endpoints used by Gemini CLI.
|
|
90
|
-
* All POST, requiring OAuth2 auth plus fingerprint headers.
|
|
91
|
-
*/
|
|
92
|
-
// v2.1.15 Phase D: the method-path map moved to request.ts as API_PATHS;
|
|
93
|
-
// this module derives its private copy from the constants.js parts (layer
|
|
94
|
-
// rules forbid importing request.js from here).
|
|
95
|
-
const FINGERPRINT_API_PATHS = {
|
|
96
|
-
loadCodeAssist: `${CLOUDCODE_BASE_URL}/v1internal:loadCodeAssist`,
|
|
97
|
-
} as const;
|
|
98
|
-
|
|
99
|
-
// v2.1.15 Phase A: MODELS_2026 (the 11-id legacy bypass list) and the
|
|
100
|
-
// ModelId2026 union moved to models.ts (MODELS_2026_LEGACY / ModelId2026) —
|
|
101
|
-
// imported under the historical name and re-exported so the public surface
|
|
102
|
-
// is unchanged.
|
|
103
|
-
import { MODELS_2026_LEGACY as MODELS_2026, UA_DEFAULT_MODEL } from "./models.js";
|
|
104
|
-
import type { ModelId2026 } from "./models.js";
|
|
105
|
-
export { MODELS_2026 };
|
|
106
|
-
export type { ModelId2026 };
|
|
107
|
-
|
|
108
|
-
// ============================================================================
|
|
109
|
-
// Section: Platform types - coherent anti-ban pools
|
|
110
|
-
// ============================================================================
|
|
111
|
-
|
|
112
|
-
export type PlatformOS = "win32" | "linux" | "darwin";
|
|
113
|
-
export type PlatformArch = "x64" | "arm64";
|
|
114
|
-
export type FingerprintType = "gemini-cli" | "antigravity";
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Supported header generation styles (observer naming for FingerprintType).
|
|
118
|
-
* - antigravity: emulates Antigravity Manager content requests
|
|
119
|
-
* - gemini-cli: emulates Gemini CLI quota pool (includes X-Goog-Api-Client)
|
|
120
|
-
*/
|
|
121
|
-
export type HeaderStyle = "antigravity" | "gemini-cli";
|
|
122
|
-
|
|
123
|
-
/** OS name normalized for keyed fingerprint pools. */
|
|
124
|
-
export type OsName = "windows" | "darwin" | "linux";
|
|
125
|
-
|
|
126
|
-
/** Architecture name normalized for keyed fingerprint pools. */
|
|
127
|
-
export type ArchName = "amd64" | "arm64" | "x64";
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Coherent platform profile for the weighted UA pools.
|
|
131
|
-
* Guarantees win32 never pairs with arm64 and that darwin prefers arm64.
|
|
132
|
-
*/
|
|
133
|
-
export interface PlatformProfile {
|
|
134
|
-
/** Node.js OS identifier, exact `process.platform` value */
|
|
135
|
-
os: PlatformOS;
|
|
136
|
-
/** Node.js architecture identifier */
|
|
137
|
-
arch: PlatformArch;
|
|
138
|
-
/** Formatted string inside the UA parenthesis: "win32; x64" */
|
|
139
|
-
uaSegment: string;
|
|
140
|
-
/** Distribution source - GitHub dominant for coherence */
|
|
141
|
-
source: string;
|
|
142
|
-
/** Randomization weight - darwin arm64 more common among developers */
|
|
143
|
-
weight: number;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Keyed coherent platform pool entry (Go-style amd64 naming on Windows,
|
|
148
|
-
* matching observed AM traffic).
|
|
149
|
-
*/
|
|
150
|
-
export interface PlatformPool {
|
|
151
|
-
/** Logical key e.g. "windows/amd64" */
|
|
152
|
-
readonly key: string;
|
|
153
|
-
/** Normalized OS name used in User-Agent */
|
|
154
|
-
readonly os: OsName;
|
|
155
|
-
/** Normalized arch name used in User-Agent */
|
|
156
|
-
readonly arch: ArchName;
|
|
157
|
-
/** Node.js platform identifier */
|
|
158
|
-
readonly nodePlatform: NodeJS.Platform;
|
|
159
|
-
/** Node.js arch identifier */
|
|
160
|
-
readonly nodeArch: string;
|
|
161
|
-
/** Electron/Chrome OS display fragment */
|
|
162
|
-
readonly displayOs: string;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/** Map of all known keyed pools. */
|
|
166
|
-
export type PoolMap = Record<string, PlatformPool>;
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Keyed pool record. Windows uses Go-convention amd64 naming to match AM
|
|
170
|
-
* traffic; darwin uses arm64 (Apple Silicon primary for 2026); linux x64.
|
|
171
|
-
*/
|
|
172
|
-
// local variant: diverges from constants (constants.FINGERPRINT_POOLS is the flat cli/gapi/node/platform pool record; this is the keyed Go-style platform map)
|
|
173
|
-
export const PLATFORM_POOLS: PoolMap = {
|
|
174
|
-
"windows/amd64": {
|
|
175
|
-
key: "windows/amd64",
|
|
176
|
-
os: "windows",
|
|
177
|
-
arch: "amd64",
|
|
178
|
-
nodePlatform: "win32",
|
|
179
|
-
nodeArch: "x64",
|
|
180
|
-
displayOs: "Windows_NT",
|
|
181
|
-
},
|
|
182
|
-
"darwin/arm64": {
|
|
183
|
-
key: "darwin/arm64",
|
|
184
|
-
os: "darwin",
|
|
185
|
-
arch: "arm64",
|
|
186
|
-
nodePlatform: "darwin",
|
|
187
|
-
nodeArch: "arm64",
|
|
188
|
-
displayOs: "Darwin",
|
|
189
|
-
},
|
|
190
|
-
"linux/x64": {
|
|
191
|
-
key: "linux/x64",
|
|
192
|
-
os: "linux",
|
|
193
|
-
arch: "x64",
|
|
194
|
-
nodePlatform: "linux",
|
|
195
|
-
nodeArch: "x64",
|
|
196
|
-
displayOs: "Linux",
|
|
197
|
-
},
|
|
198
|
-
} as const;
|
|
199
|
-
|
|
200
|
-
// v2.1.15 Phase B: the weighted PlatformProfile pool renamed from the
|
|
201
|
-
// historical name PLATFORM_POOL (which now resolves to the constants.ts raw
|
|
202
|
-
// string list ["linux","darwin","win32"] re-exported below). The two
|
|
203
|
-
// same-named values had different shapes, so the accurate split keeps each
|
|
204
|
-
// semantic under an honest name.
|
|
205
|
-
/** Weighted pool of real-world valid combinations. */
|
|
206
|
-
export const PLATFORM_PROFILE_POOL: readonly PlatformProfile[] = [
|
|
207
|
-
{ os: "linux", arch: "x64", uaSegment: "linux; x64", source: "GitHub", weight: 35 },
|
|
208
|
-
{ os: "darwin", arch: "arm64", uaSegment: "darwin; arm64", source: "GitHub", weight: 40 },
|
|
209
|
-
{ os: "win32", arch: "x64", uaSegment: "win32; x64", source: "GitHub", weight: 25 },
|
|
210
|
-
] as const;
|
|
211
|
-
|
|
212
|
-
export { PLATFORM_POOL };
|
|
213
|
-
|
|
214
|
-
export const PLATFORM_POOL_EXTENDED: readonly PlatformProfile[] = [
|
|
215
|
-
{ os: "linux", arch: "x64", uaSegment: "linux; x64", source: "GitHub", weight: 30 },
|
|
216
|
-
{ os: "darwin", arch: "arm64", uaSegment: "darwin; arm64", source: "GitHub", weight: 35 },
|
|
217
|
-
{ os: "darwin", arch: "x64", uaSegment: "darwin; x64", source: "Homebrew", weight: 10 },
|
|
218
|
-
{ os: "win32", arch: "x64", uaSegment: "win32; x64", source: "GitHub", weight: 20 },
|
|
219
|
-
{ os: "linux", arch: "arm64", uaSegment: "linux; arm64", source: "GitHub", weight: 5 },
|
|
220
|
-
] as const;
|
|
221
|
-
|
|
222
|
-
// ============================================================================
|
|
223
|
-
// Section: Version governance fallbacks
|
|
224
|
-
// ============================================================================
|
|
225
|
-
|
|
226
|
-
// ANTIGRAVITY_VERSION_FALLBACK ('1.19.2') is imported from constants.js
|
|
227
|
-
// (identical value) and re-exported above.
|
|
228
|
-
|
|
229
|
-
/** Preferred plugin version for new installs / Client-Metadata payloads. */
|
|
230
|
-
export const PLUGIN_VERSION_FALLBACK = "2.1.16";
|
|
231
|
-
|
|
232
|
-
// ============================================================================
|
|
233
|
-
// Section: Version pools - anti-ban randomized OS/version pairs
|
|
234
|
-
// (v2.1.15 Phase B: GEMINI_CLI_VERSION_POOL, GL_NODE_VERSION_POOL and
|
|
235
|
-
// ANTIGRAVITY_CLI_VERSION_POOL are imported from constants.js — the raw-value
|
|
236
|
-
// owner; the former local telemetry copies merged there.)
|
|
237
|
-
// ============================================================================
|
|
238
|
-
|
|
239
|
-
export { ANTIGRAVITY_CLI_VERSION_POOL, GEMINI_CLI_VERSION_POOL, GL_NODE_VERSION_POOL };
|
|
240
|
-
|
|
241
|
-
export const ANTIGRAVITY_VERSION_POOL = ["1.12.8", "1.12.7", "1.12.5", "1.11.9", "1.11.4"] as const;
|
|
242
|
-
|
|
243
|
-
// local variant: diverges from constants (constants.GAPI_CLIENT_VERSION_POOL is [9.15.1,9.14.0,9.15.0,9.13.0]; this pool adds 9.14.1 and orders 9.15.0 before 9.14.0)
|
|
244
|
-
/** google-api-nodejs-client versions - lockstep with GeminiCLI releases. */
|
|
245
|
-
export const GOOGLE_API_CLIENT_VERSION_POOL = ["9.15.1", "9.15.0", "9.14.1", "9.14.0", "9.13.0"] as const;
|
|
246
|
-
|
|
247
|
-
/** Complementary gax version pool. */
|
|
248
|
-
export const GAX_VERSION_POOL = ["5.0.4", "5.0.3", "4.3.6"] as const;
|
|
249
|
-
|
|
250
|
-
// ============================================================================
|
|
251
|
-
// Section: Crypto utilities - FNV-1a + secure random
|
|
252
|
-
// (v2.1.15 Phase B: fnv1a32/fnv1a32Hex/fnv1a64/pickRandom/getJitterMs are
|
|
253
|
-
// owned by core.js — the former local hex-string fnv1a32 was exactly core's
|
|
254
|
-
// fnv1a32Hex under the legacy name, so this module now imports and
|
|
255
|
-
// re-exports the canonical bindings.)
|
|
256
|
-
// ============================================================================
|
|
257
|
-
|
|
258
|
-
import { fnv1a32, fnv1a32Hex, fnv1a64, getJitterMs, pickRandom } from "./core.js";
|
|
259
|
-
|
|
260
|
-
export { fnv1a32, fnv1a32Hex, fnv1a64, getJitterMs, pickRandom };
|
|
261
|
-
|
|
262
|
-
// v2.1.16: the private fnv1a32Num was deleted — its output was verified
|
|
263
|
-
// byte-identical to core.fnv1a32 over ascii/non-ascii/empty/long inputs (same
|
|
264
|
-
// UTF-16 code-unit FNV-1a); the instance helpers below now delegate to the
|
|
265
|
-
// core import directly.
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* Raw numeric 64-bit FNV-1a over UTF-16 code units.
|
|
269
|
-
* Divergence from core.fnv1a64 (kept deliberately): the core export computes
|
|
270
|
-
* the same digest but returns it as a 16-char zero-padded hex string, while
|
|
271
|
-
* this private returns the bigint form because the instance helpers format
|
|
272
|
-
* and slice it themselves.
|
|
273
|
-
*/
|
|
274
|
-
function fnv1a64Big(input: string): bigint {
|
|
275
|
-
let hash = 14695981039346656037n;
|
|
276
|
-
const prime = 1099511628211n;
|
|
277
|
-
for (let i = 0; i < input.length; i++) {
|
|
278
|
-
hash ^= BigInt(input.charCodeAt(i));
|
|
279
|
-
hash = (hash * prime) & 0xffffffffffffffffn;
|
|
280
|
-
}
|
|
281
|
-
return hash;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* Generates a deterministic session_id based on the current directory.
|
|
286
|
-
* Same folder => same session_id => avoids device-hopping flags.
|
|
287
|
-
*
|
|
288
|
-
* @param directory - base path (defaults to process.cwd())
|
|
289
|
-
*/
|
|
290
|
-
export function generateSessionUuid(directory?: string): string {
|
|
291
|
-
const dir = directory ?? process.cwd() ?? os.homedir();
|
|
292
|
-
const normalized = path.resolve(dir).toLowerCase();
|
|
293
|
-
const shortHash = fnv1a32Hex(normalized);
|
|
294
|
-
const longHash = fnv1a64(normalized + "|antigravity");
|
|
295
|
-
// Pseudo-UUID deterministic format, not reversible.
|
|
296
|
-
return `${shortHash.slice(0, 8)}-${longHash.slice(0, 4)}-${longHash.slice(4, 8)}-${longHash.slice(8, 12)}-${longHash.slice(12, 16)}${shortHash.slice(0, 4)}`;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
/**
|
|
300
|
-
* Secure random float in [0,1) using crypto.randomInt with Math.random fallback.
|
|
301
|
-
*/
|
|
302
|
-
export function secureRandom(): number {
|
|
303
|
-
try {
|
|
304
|
-
return crypto.randomInt(0, 1_000_000) / 1_000_000;
|
|
305
|
-
} catch {
|
|
306
|
-
return Math.random();
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
/** Picks a random element honoring optional weights. */
|
|
311
|
-
export function pickRandomWeighted<T extends { weight: number }>(pool: readonly T[]): T {
|
|
312
|
-
const total = pool.reduce((s, p) => s + p.weight, 0);
|
|
313
|
-
let r = secureRandom() * total;
|
|
314
|
-
for (const item of pool) {
|
|
315
|
-
if (r < item.weight) return item;
|
|
316
|
-
r -= item.weight;
|
|
317
|
-
}
|
|
318
|
-
return pool[pool.length - 1] as T;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
/**
|
|
322
|
-
* Async jitter SLEEP in [minMs, maxMs] for anti-rate-limit / anti-ban delays
|
|
323
|
-
* (renamed from `jitter` in v2.1.15 Phase B: core.js owns the sync `jitter`
|
|
324
|
-
* number draw, so this async sleep variant carries an accurate distinct name).
|
|
325
|
-
*/
|
|
326
|
-
export async function jitterSleep(minMs = 0, maxMs = 80): Promise<void> {
|
|
327
|
-
const delta = maxMs - minMs;
|
|
328
|
-
const wait = minMs + Math.floor(secureRandom() * (delta + 1));
|
|
329
|
-
if (wait <= 0) return;
|
|
330
|
-
await new Promise<void>((res) => setTimeout(res, wait));
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
// ============================================================================
|
|
334
|
-
// Section: Identity masquerade families (v2.1.15 Phase B absorption)
|
|
335
|
-
// — getDynamicUserAgent (constants/models/plugin/quota), buildGeminiUserAgent
|
|
336
|
-
// (auth/config), buildClientMetadata (constants/quota/request/search),
|
|
337
|
-
// getXGoogApiClient + X_GOOG_API_CLIENT (constants), ua/apiClient (auth),
|
|
338
|
-
// getGeminiCLIHeaders/getAntigravityHeaders (constants/plugin),
|
|
339
|
-
// buildAntagravityHeaders (models/plugin/project/quota/search) and
|
|
340
|
-
// getRandomPlatformString (constants) all live HERE now — the single home of
|
|
341
|
-
// identity/UA/header masquerade logic. Raw values stay in constants.ts.
|
|
342
|
-
// ============================================================================
|
|
343
|
-
|
|
344
|
-
/**
|
|
345
|
-
* Normalizes a Node platform identifier for UA emission (identity-form
|
|
346
|
-
* canonical: darwin/win32/linux pass through; exotic values pass through
|
|
347
|
-
* unchanged as well — this is a stable lowercase identity map, not a filter).
|
|
348
|
-
*/
|
|
349
|
-
export function normalizePlatform(p: string): string {
|
|
350
|
-
switch (p) {
|
|
351
|
-
case "darwin":
|
|
352
|
-
return "darwin";
|
|
353
|
-
case "win32":
|
|
354
|
-
return "win32";
|
|
355
|
-
case "linux":
|
|
356
|
-
return "linux";
|
|
357
|
-
default:
|
|
358
|
-
return p;
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
/**
|
|
363
|
-
* Normalizes a Node arch identifier for UA emission
|
|
364
|
-
* (arm64/x64/ia32 identity; exotic values pass through unchanged).
|
|
365
|
-
*/
|
|
366
|
-
export function normalizeArch(a: string): string {
|
|
367
|
-
switch (a) {
|
|
368
|
-
case "arm64":
|
|
369
|
-
return "arm64";
|
|
370
|
-
case "x64":
|
|
371
|
-
return "x64";
|
|
372
|
-
case "ia32":
|
|
373
|
-
return "ia32";
|
|
374
|
-
default:
|
|
375
|
-
return a;
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
/**
|
|
380
|
-
* Dynamic Antigravity User-Agent: `antigravity/{version} {os}/{arch}`.
|
|
381
|
-
* Invalid/absent versions fall back to ANTIGRAVITY_VERSION_FALLBACK.
|
|
382
|
-
* Canonical of the getDynamicUserAgent family (v2.1.15 Phase B: the
|
|
383
|
-
* constants.ts, models.ts, plugin.ts and quota.ts locals deleted; the
|
|
384
|
-
* async version.ts GeminiCLI-template variant stays in version.ts under its
|
|
385
|
-
* own accurate name because it is a semantically distinct async builder).
|
|
386
|
-
*/
|
|
387
|
-
export function getDynamicUserAgent(version?: string, opts?: { os?: string; arch?: string }): string {
|
|
388
|
-
const ver = (version && /^\d+\.\d+\.\d+/.test(version) ? version : ANTIGRAVITY_VERSION_FALLBACK).trim();
|
|
389
|
-
const plat = normalizePlatform(opts?.os ?? os.platform());
|
|
390
|
-
const arc = normalizeArch(opts?.arch ?? os.arch());
|
|
391
|
-
return `antigravity/${ver} ${plat}/${arc}`;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
/**
|
|
395
|
-
* Async dynamic Antigravity User-Agent — resolves the remote Antigravity
|
|
396
|
-
* version when no cached version qualifies, then builds the UA via
|
|
397
|
-
* {@link getDynamicUserAgent}. (Absorbed from constants.ts in v2.1.15
|
|
398
|
-
* Phase B; version.ts's own remote chain remains the version-detection
|
|
399
|
-
* owner and may dedupe with {@link fetchRemoteAntigravityVersion} later.)
|
|
400
|
-
*/
|
|
401
|
-
export async function getDynamicUserAgentAsync(cachedVersion?: string): Promise<string> {
|
|
402
|
-
if (cachedVersion && /^\d+\.\d+\.\d+/.test(cachedVersion)) {
|
|
403
|
-
return getDynamicUserAgent(cachedVersion);
|
|
404
|
-
}
|
|
405
|
-
try {
|
|
406
|
-
const latest = await fetchRemoteAntigravityVersion();
|
|
407
|
-
if (latest) return getDynamicUserAgent(latest);
|
|
408
|
-
} catch {
|
|
409
|
-
/* the guarded best-effort operation falls through: the outer flow owns the failure */
|
|
410
|
-
}
|
|
411
|
-
return getDynamicUserAgent();
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
/**
|
|
415
|
-
* Fetches the latest Antigravity version across the known update sources
|
|
416
|
-
* (absorbed from constants.ts in v2.1.15 Phase B). Returns null when every
|
|
417
|
-
* source fails; never throws.
|
|
418
|
-
*/
|
|
419
|
-
export async function fetchRemoteAntigravityVersion(): Promise<string | null> {
|
|
420
|
-
const controller = new AbortController();
|
|
421
|
-
const to = setTimeout(() => controller.abort(), VERSION_FETCH_TIMEOUT_MS);
|
|
422
|
-
try {
|
|
423
|
-
for (const url of ANTIGRAVITY_VERSION_REMOTE_URLS) {
|
|
424
|
-
try {
|
|
425
|
-
const res = await fetch(url, {
|
|
426
|
-
signal: controller.signal,
|
|
427
|
-
headers: { Accept: "application/json", "User-Agent": ANTIGRAVITY_USER_AGENT_FALLBACK },
|
|
428
|
-
});
|
|
429
|
-
if (!res.ok) continue;
|
|
430
|
-
const json = (await res.json()) as any;
|
|
431
|
-
if (json?.version && /^\d+\.\d+\.\d+/.test(json.version)) return json.version;
|
|
432
|
-
if (json?.tag_name) {
|
|
433
|
-
const m = String(json.tag_name).match(/(\d+\.\d+\.\d+)/);
|
|
434
|
-
if (m) return m[1] ?? null;
|
|
435
|
-
}
|
|
436
|
-
if (json?.latest && /^\d+\.\d+\.\d+/.test(json.latest)) return json.latest;
|
|
437
|
-
} catch {
|
|
438
|
-
continue;
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
return null;
|
|
442
|
-
} finally {
|
|
443
|
-
clearTimeout(to);
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
/**
|
|
448
|
-
* Builds the antigravity-style X-Goog-Api-Client chain:
|
|
449
|
-
* `antigravity/{version} gl-node/{node} gax/4.9.0 grpc/1.14.0`.
|
|
450
|
-
* Canonical of the getXGoogApiClient family (constants.ts lineage — the same
|
|
451
|
-
* chain request.ts's buildApiClient and plugin.ts's buildCommonHeaders
|
|
452
|
-
* compose inline; the bare `gl-node/22.19.0` snapshot has its own accurate
|
|
453
|
-
* name below).
|
|
454
|
-
*/
|
|
455
|
-
export function getXGoogApiClient(version?: string): string {
|
|
456
|
-
const ver = version ?? ANTIGRAVITY_VERSION_FALLBACK;
|
|
457
|
-
const nodeVer = process.versions.node;
|
|
458
|
-
return `antigravity/${ver} gl-node/${nodeVer} gax/4.9.0 grpc/1.14.0`;
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
/**
|
|
462
|
-
* Canonical X_GOOG_API_CLIENT computed value — the dynamic
|
|
463
|
-
* {@link getXGoogApiClient} result (v2.1.15 Phase B: the constants.ts
|
|
464
|
-
* computed export moved here; the static "gl-node/22.19.0" copies in
|
|
465
|
-
* config/project/recovery/request/streaming were NOT the same value and
|
|
466
|
-
* keep their exact wire behavior through the accurately named
|
|
467
|
-
* {@link X_GOOG_API_CLIENT_GEMINI_CLI}).
|
|
468
|
-
*/
|
|
469
|
-
export const X_GOOG_API_CLIENT: string = getXGoogApiClient();
|
|
470
|
-
|
|
471
|
-
/**
|
|
472
|
-
* Bare gl-node X-Goog-Api-Client snapshot observed on real Gemini CLI
|
|
473
|
-
* traffic (`gl-node/22.19.0`). Distinct value from {@link X_GOOG_API_CLIENT}
|
|
474
|
-
* — the former static "stale" copies in project.ts, quota.ts, request.ts,
|
|
475
|
-
* streaming.ts, recovery.ts, accounts.ts and config.ts resolve HERE so every
|
|
476
|
-
* live chain keeps sending exactly the bytes it sent before the merge.
|
|
477
|
-
*/
|
|
478
|
-
export const X_GOOG_API_CLIENT_GEMINI_CLI = `gl-node/${CURRENT_GL_NODE_VERSION ?? "22.19.0"}` as const;
|
|
479
|
-
|
|
480
|
-
/**
|
|
481
|
-
* Builds the Antigravity Client-Metadata header string — the quota.ts
|
|
482
|
-
* lineage (live-validated quota chain): uppercase platform/arch,
|
|
483
|
-
* pluginVersion taken from the constants template, osVersion before arch.
|
|
484
|
-
* Canonical of the buildClientMetadata family (v2.1.15 Phase B: the
|
|
485
|
-
* constants.ts, quota.ts, request.ts and search.ts locals deleted).
|
|
486
|
-
*/
|
|
487
|
-
export function buildClientMetadata(version?: string): string {
|
|
488
|
-
const ver = version ?? ANTIGRAVITY_VERSION_FALLBACK;
|
|
489
|
-
const plat = normalizePlatform(os.platform()).toUpperCase();
|
|
490
|
-
const arch = normalizeArch(os.arch()).toUpperCase();
|
|
491
|
-
const parts = [
|
|
492
|
-
`ideType=${ANTIGRAVITY_CLIENT_METADATA_TEMPLATE.ideType}`,
|
|
493
|
-
`platform=${plat}`,
|
|
494
|
-
`ideVersion=${ver}`,
|
|
495
|
-
`pluginVersion=${ANTIGRAVITY_CLIENT_METADATA_TEMPLATE.pluginVersion}`,
|
|
496
|
-
`osVersion=${os.release()}`,
|
|
497
|
-
`arch=${arch}`,
|
|
498
|
-
];
|
|
499
|
-
return parts.join(",");
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
/**
|
|
503
|
-
* Builds the GeminiCLI User-Agent dynamically, varying the platform:
|
|
504
|
-
* `GeminiCLI/<cliVersion>/<model> (<platform>; <arch>; GitHub)
|
|
505
|
-
* google-api-nodejs-client/<gclientVersion>`. Canonical of the
|
|
506
|
-
* buildGeminiUserAgent family (v2.1.15 Phase B: config.ts lineage body —
|
|
507
|
-
* overrides accepted; the auth.ts win32->"windows" mapping is expressed by
|
|
508
|
-
* auth.ts passing the pre-mapped platform, so one implementation serves
|
|
509
|
-
* both historical call shapes).
|
|
510
|
-
*/
|
|
511
|
-
export function buildGeminiUserAgent(overrides?: {
|
|
512
|
-
cliVersion?: string;
|
|
513
|
-
model?: string;
|
|
514
|
-
platform?: string;
|
|
515
|
-
arch?: string;
|
|
516
|
-
gclientVersion?: string;
|
|
517
|
-
}): string {
|
|
518
|
-
const cliVersion = overrides?.cliVersion ?? CURRENT_GEMINI_CLI_VERSION;
|
|
519
|
-
const model = overrides?.model ?? UA_DEFAULT_MODEL;
|
|
520
|
-
const platform = overrides?.platform ?? normalizePlatform(os.platform());
|
|
521
|
-
const arch = overrides?.arch ?? normalizeArch(os.arch());
|
|
522
|
-
const gclientVersion = overrides?.gclientVersion ?? CURRENT_GAPI_CLIENT_VERSION;
|
|
523
|
-
|
|
524
|
-
// Exact format of the real Gemini CLI
|
|
525
|
-
return `GeminiCLI/${cliVersion}/${model} (${platform}; ${arch}; GitHub) google-api-nodejs-client/${gclientVersion}`;
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
/**
|
|
529
|
-
* Antigravity User-Agent short form (auth.ts lineage):
|
|
530
|
-
* `antigravity/{version} {platform}/{arch}`. Thin alias of
|
|
531
|
-
* {@link getDynamicUserAgent} kept under its historical auth surface name;
|
|
532
|
-
* the auth call sites always invoke it without arguments, where the two
|
|
533
|
-
* implementations are byte-identical.
|
|
534
|
-
*/
|
|
535
|
-
export const ua = (v?: string): string => getDynamicUserAgent(v ?? ANTIGRAVITY_VERSION_FALLBACK);
|
|
536
|
-
|
|
537
|
-
/**
|
|
538
|
-
* Antigravity X-Goog-Api-Client short form (auth.ts lineage):
|
|
539
|
-
* `antigravity/{version} gl-node/{node} gccl/1.0.0 gax/1.0.0`. Distinct
|
|
540
|
-
* segment chain from {@link getXGoogApiClient} (gccl/gax-1.0.0 vs
|
|
541
|
-
* gax-4.9.0/grpc) — the live auth retrieveQuota path sends exactly this
|
|
542
|
-
* form, so it keeps its own accurate implementation here.
|
|
543
|
-
*/
|
|
544
|
-
export const apiClient = (v = "1.19.2"): string =>
|
|
545
|
-
`antigravity/${v} gl-node/${process.versions.node} gccl/1.0.0 gax/1.0.0`;
|
|
546
|
-
|
|
547
|
-
/**
|
|
548
|
-
* Builds a platform string in the format expected by the Gemini CLI
|
|
549
|
-
* User-Agent, e.g. "linux; x64; GitHub" (absorbed from constants.ts in
|
|
550
|
-
* v2.1.15 Phase B).
|
|
551
|
-
*/
|
|
552
|
-
export function getRandomPlatformString(platformOverride?: SupportedPlatform, archOverride?: SupportedArch): string {
|
|
553
|
-
const plat: SupportedPlatform = platformOverride ?? pickRandom(PLATFORM_POOL);
|
|
554
|
-
const arch: SupportedArch = archOverride ?? pickRandom(ARCH_POOL);
|
|
555
|
-
|
|
556
|
-
const source = pickRandom(FINGERPRINT_USER_AGENT_SOURCES);
|
|
557
|
-
|
|
558
|
-
// win32 maps to win in the gemini-cli UA
|
|
559
|
-
const uaPlatform = plat === "win32" ? "win32" : plat;
|
|
560
|
-
return `${uaPlatform}; ${arch}; ${source}`;
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
// ---------------------------------------------------------------------------
|
|
564
|
-
// Gemini CLI header generators (absorbed from constants.ts)
|
|
565
|
-
// ---------------------------------------------------------------------------
|
|
566
|
-
|
|
567
|
-
export interface GeminiCliHeaderOptions {
|
|
568
|
-
/** model to include in the User-Agent (e.g. gemini-3-pro-preview) */
|
|
569
|
-
model?: string | undefined;
|
|
570
|
-
/** platform override (randomizes / uses process.platform when absent) */
|
|
571
|
-
platform?: SupportedPlatform | undefined;
|
|
572
|
-
/** arch override */
|
|
573
|
-
arch?: SupportedArch;
|
|
574
|
-
/** specific Gemini CLI version to spoof */
|
|
575
|
-
cliVersion?: string;
|
|
576
|
-
/** specific gapi client version */
|
|
577
|
-
gapiVersion?: string;
|
|
578
|
-
/** specific gl-node version */
|
|
579
|
-
glNodeVersion?: string;
|
|
580
|
-
/** access token for Authorization */
|
|
581
|
-
accessToken?: string;
|
|
582
|
-
/** custom ideType */
|
|
583
|
-
ideType?: (typeof FINGERPRINT_IDE_TYPES)[number];
|
|
584
|
-
/** custom platform metadata */
|
|
585
|
-
platformMeta?: (typeof FINGERPRINT_PLATFORMS)[number];
|
|
586
|
-
/** custom pluginType */
|
|
587
|
-
pluginType?: (typeof FINGERPRINT_PLUGIN_TYPES)[number];
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
/**
|
|
591
|
-
* Generates headers identical to the official Gemini CLI for detection
|
|
592
|
-
* bypass (canonical of the family: the richer constants.ts WithOptions
|
|
593
|
-
* lineage; plugin.ts's legacy terminal-platform variant had zero callers
|
|
594
|
-
* and was deleted in v2.1.15 Phase B).
|
|
595
|
-
*
|
|
596
|
-
* @param model - optional, defaults to gemini-3-pro-preview
|
|
597
|
-
* @param platform - optional, randomized with linux bias by default
|
|
598
|
-
*/
|
|
599
|
-
export function getGeminiCLIHeaders(model?: string, platform?: SupportedPlatform): Record<string, string> {
|
|
600
|
-
// opts-object overload also supported for compat
|
|
601
|
-
return getGeminiCLIHeadersWithOptions({
|
|
602
|
-
model,
|
|
603
|
-
platform,
|
|
604
|
-
});
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
/** Object-style variant, more robust for internal plugin usage. */
|
|
608
|
-
export function getGeminiCLIHeadersWithOptions(opts: GeminiCliHeaderOptions = {}): Record<string, string> {
|
|
609
|
-
const {
|
|
610
|
-
model = UA_DEFAULT_MODEL,
|
|
611
|
-
platform,
|
|
612
|
-
arch,
|
|
613
|
-
cliVersion = pickRandom(GEMINI_CLI_VERSION_POOL),
|
|
614
|
-
gapiVersion = pickRandom(GAPI_CLIENT_VERSION_POOL),
|
|
615
|
-
glNodeVersion = pickRandom(GL_NODE_VERSION_POOL),
|
|
616
|
-
accessToken,
|
|
617
|
-
ideType = "IDE_UNSPECIFIED",
|
|
618
|
-
platformMeta = "PLATFORM_UNSPECIFIED",
|
|
619
|
-
pluginType = "GEMINI",
|
|
620
|
-
} = opts;
|
|
621
|
-
|
|
622
|
-
const platformString = getRandomPlatformString(platform, arch);
|
|
623
|
-
|
|
624
|
-
const userAgent = `GeminiCLI/${cliVersion}/${model} (${platformString}) google-api-nodejs-client/${gapiVersion}`;
|
|
625
|
-
|
|
626
|
-
const headers: Record<string, string> = {
|
|
627
|
-
"User-Agent": userAgent,
|
|
628
|
-
"X-Goog-Api-Client": `gl-node/${glNodeVersion}`,
|
|
629
|
-
"Client-Metadata": `ideType=${ideType},platform=${platformMeta},pluginType=${pluginType}`,
|
|
630
|
-
"Content-Type": "application/json",
|
|
631
|
-
Accept: "application/json",
|
|
632
|
-
"Accept-Encoding": "gzip, deflate, br",
|
|
633
|
-
"Accept-Language": "en-US,en;q=0.9",
|
|
634
|
-
};
|
|
635
|
-
|
|
636
|
-
if (accessToken) {
|
|
637
|
-
headers["Authorization"] = `Bearer ${accessToken}`;
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
return headers;
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
/** Headers specialized for Antigravity versioning. */
|
|
644
|
-
export interface AntigravityHeaderOptions {
|
|
645
|
-
version?: AntigravityVersion;
|
|
646
|
-
accessToken?: string;
|
|
647
|
-
cliVersion?: string;
|
|
648
|
-
model?: string;
|
|
649
|
-
platform?: SupportedPlatform;
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
export function getAntigravityHeaders(version?: AntigravityVersion | string): Record<string, string> {
|
|
653
|
-
return getAntigravityHeadersWithOptions({ version: version as AntigravityVersion });
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
export function getAntigravityHeadersWithOptions(opts: AntigravityHeaderOptions = {}): Record<string, string> {
|
|
657
|
-
const {
|
|
658
|
-
version = "v1internal" as AntigravityVersion,
|
|
659
|
-
accessToken,
|
|
660
|
-
cliVersion = CURRENT_GEMINI_CLI_VERSION,
|
|
661
|
-
model = UA_DEFAULT_MODEL,
|
|
662
|
-
platform,
|
|
663
|
-
} = opts;
|
|
664
|
-
|
|
665
|
-
// Base Gemini CLI headers + antigravity overrides
|
|
666
|
-
const base = getGeminiCLIHeadersWithOptions({
|
|
667
|
-
model,
|
|
668
|
-
platform,
|
|
669
|
-
cliVersion,
|
|
670
|
-
});
|
|
671
|
-
|
|
672
|
-
const versionMeta = version === "daily-v1internal" ? "daily" : version === "v1" ? "v1" : "v1internal";
|
|
673
|
-
|
|
674
|
-
return {
|
|
675
|
-
...base,
|
|
676
|
-
"X-Goog-Api-Client": base["X-Goog-Api-Client"] ?? `gl-node/${pickRandom(GL_NODE_VERSION_POOL)}`,
|
|
677
|
-
"X-Antigravity-Version": versionMeta,
|
|
678
|
-
"X-Antigravity-Client": `antigravity-gemini-cli/${cliVersion}`,
|
|
679
|
-
...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}),
|
|
680
|
-
};
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
// ---------------------------------------------------------------------------
|
|
684
|
-
// Antigravity content header builder (canonical of the five-variant family)
|
|
685
|
-
// ---------------------------------------------------------------------------
|
|
686
|
-
|
|
687
|
-
/**
|
|
688
|
-
* Options for {@link buildAntagravityHeaders} — the canonical of the
|
|
689
|
-
* buildAntagravityHeaders family (v2.1.15 Phase B). The flags preserve each
|
|
690
|
-
* historical variant's exact effective header set:
|
|
691
|
-
* - plugin.ts / project.ts lineage (default): Authorization, Content-Type,
|
|
692
|
-
* User-Agent + extras;
|
|
693
|
-
* - quota.ts lineage: `accept: true` adds Accept: application/json;
|
|
694
|
-
* - search.ts lineage: `identityHeaders: true` adds X-Goog-Api-Client
|
|
695
|
-
* (dynamic getXGoogApiClient) and Client-Metadata (buildClientMetadata);
|
|
696
|
-
* - the models.ts strip-variant had zero consumers and was deleted.
|
|
697
|
-
*/
|
|
698
|
-
export interface AntigravityHeadersOptions {
|
|
699
|
-
userAgent?: string | undefined;
|
|
700
|
-
extra?: Record<string, string>;
|
|
701
|
-
/** Include Accept: application/json (quota/search lineage). Default false. */
|
|
702
|
-
accept?: boolean;
|
|
703
|
-
/** Include X-Goog-Api-Client + Client-Metadata (search lineage). Default false. */
|
|
704
|
-
identityHeaders?: boolean;
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
/**
|
|
708
|
-
* Builds the Antigravity content-request header map (Authorization bearer,
|
|
709
|
-
* JSON content type, dynamic Antigravity UA, optional Accept and bypass
|
|
710
|
-
* identity headers, extras merged last with x-goog-user-project always
|
|
711
|
-
* filtered per the observer requirement).
|
|
712
|
-
*/
|
|
713
|
-
export function buildAntagravityHeaders(
|
|
714
|
-
accessToken: string,
|
|
715
|
-
opts: AntigravityHeadersOptions = {},
|
|
716
|
-
): Record<string, string> {
|
|
717
|
-
const userAgent = opts.userAgent ?? getDynamicUserAgent();
|
|
718
|
-
const headers: Record<string, string> = {
|
|
719
|
-
Authorization: `Bearer ${accessToken}`,
|
|
720
|
-
"Content-Type": "application/json",
|
|
721
|
-
"User-Agent": userAgent,
|
|
722
|
-
};
|
|
723
|
-
if (opts.accept) {
|
|
724
|
-
headers["Accept"] = "application/json";
|
|
725
|
-
}
|
|
726
|
-
if (opts.identityHeaders) {
|
|
727
|
-
headers["X-Goog-Api-Client"] = getXGoogApiClient();
|
|
728
|
-
headers["Client-Metadata"] = buildClientMetadata();
|
|
729
|
-
}
|
|
730
|
-
if (opts.extra) {
|
|
731
|
-
for (const [k, v] of Object.entries(opts.extra)) {
|
|
732
|
-
if (!k) continue;
|
|
733
|
-
if (k.toLowerCase() === "x-goog-user-project") continue; // observer strips this header per spec
|
|
734
|
-
headers[k] = v;
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
return headers;
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
// ============================================================================
|
|
741
|
-
// Section: Main class - unified FingerprintGenerator
|
|
742
|
-
// ============================================================================
|
|
743
|
-
|
|
744
|
-
export interface FingerprintOptions {
|
|
745
|
-
/** Directory for deterministic seed (defaults to cwd) */
|
|
746
|
-
directory?: string;
|
|
747
|
-
/** Allow rare extended platform combos (default false) */
|
|
748
|
-
allowExtendedPlatforms?: boolean;
|
|
749
|
-
/** Pin a specific platform (for tests) */
|
|
750
|
-
fixedPlatform?: PlatformProfile | undefined;
|
|
751
|
-
/** Pin the Gemini CLI version */
|
|
752
|
-
fixedCliVersion?: string | undefined;
|
|
753
|
-
/** Pin the google-api-client version */
|
|
754
|
-
fixedGoogleApiVersion?: string | undefined;
|
|
755
|
-
/** Pin the gl-node version */
|
|
756
|
-
fixedNodeVersion?: string | undefined;
|
|
757
|
-
/**
|
|
758
|
-
* Antigravity app version embedded in observer-style UAs.
|
|
759
|
-
* Accepts bare semver ("1.19.2") or full UA strings
|
|
760
|
-
* ("antigravity/1.19.2 darwin/arm64"); invalid values fall back to
|
|
761
|
-
* ANTIGRAVITY_VERSION_FALLBACK.
|
|
762
|
-
*/
|
|
763
|
-
antigravityVersion?: string;
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
export interface FullHeadersResult {
|
|
767
|
-
/** Exact Gemini CLI User-Agent */
|
|
768
|
-
"User-Agent": string;
|
|
769
|
-
/** X-Goog-Api-Client fingerprint */
|
|
770
|
-
"X-Goog-Api-Client": string;
|
|
771
|
-
/** Hardened Client-Metadata */
|
|
772
|
-
"Client-Metadata": string;
|
|
773
|
-
/** Standard Content-Type */
|
|
774
|
-
"Content-Type": string;
|
|
775
|
-
/** Accept */
|
|
776
|
-
Accept: string;
|
|
777
|
-
/** Optional for some endpoints */
|
|
778
|
-
"X-Client-Details"?: string;
|
|
779
|
-
/** Extra metadata for internal debug/tracing */
|
|
780
|
-
__meta: {
|
|
781
|
-
platform: PlatformProfile;
|
|
782
|
-
cliVersion: string;
|
|
783
|
-
googleApiVersion: string;
|
|
784
|
-
glNodeVersion: string;
|
|
785
|
-
gaxVersion: string;
|
|
786
|
-
sessionId: string;
|
|
787
|
-
model: string;
|
|
788
|
-
type: FingerprintType;
|
|
789
|
-
jitterMs: number;
|
|
790
|
-
};
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
/**
|
|
794
|
-
* Anti-detection generator that mimics Gemini CLI exactly while also exposing
|
|
795
|
-
* the observer-style Antigravity header set.
|
|
796
|
-
*
|
|
797
|
-
* Coherence guarantees:
|
|
798
|
-
* - Chosen platform drives the UA segment consistently
|
|
799
|
-
* - Node / gax / google-api-client versions pair like a real release
|
|
800
|
-
* - session_id is deterministic per directory (avoids device hopping)
|
|
801
|
-
* - Observer mode never mutates global state
|
|
802
|
-
*
|
|
803
|
-
* Usage:
|
|
804
|
-
* ```ts
|
|
805
|
-
* const fp = new FingerprintGenerator({ directory: process.cwd() });
|
|
806
|
-
* const headers = fp.getFullHeaders('gemini-3-pro-preview', 'gemini-cli');
|
|
807
|
-
* // or observer style:
|
|
808
|
-
* const fp2 = new FingerprintGenerator('1.19.2');
|
|
809
|
-
* const h2 = fp2.getFingerprintHeaders('gemini-cli');
|
|
810
|
-
* ```
|
|
811
|
-
*/
|
|
812
|
-
export class FingerprintGenerator {
|
|
813
|
-
// Legacy weighted-pool state
|
|
814
|
-
private readonly directory: string;
|
|
815
|
-
private readonly allowExtended: boolean;
|
|
816
|
-
private readonly fixedPlatform?: PlatformProfile | undefined;
|
|
817
|
-
private readonly fixedCliVersion?: string | undefined;
|
|
818
|
-
private readonly fixedGoogleApiVersion?: string | undefined;
|
|
819
|
-
private readonly fixedNodeVersion?: string | undefined;
|
|
820
|
-
private readonly sessionId: string;
|
|
821
|
-
private cachedPlatform: PlatformProfile | null = null;
|
|
822
|
-
|
|
823
|
-
// Observer-style state
|
|
824
|
-
/** Antigravity app version used in observer User-Agents. */
|
|
825
|
-
private readonly version: string;
|
|
826
|
-
private poolCache: PlatformPool | null = null;
|
|
827
|
-
|
|
828
|
-
/**
|
|
829
|
-
* Unified constructor accepting BOTH historical option shapes:
|
|
830
|
-
*
|
|
831
|
-
* @param opts - either an options object ({@link FingerprintOptions}) or a
|
|
832
|
-
* plain version string ("1.19.2", "antigravity/1.19.2 ...",
|
|
833
|
-
* falls back to ANTIGRAVITY_VERSION_FALLBACK when invalid).
|
|
834
|
-
*/
|
|
835
|
-
constructor(opts?: FingerprintOptions | string) {
|
|
836
|
-
const o: FingerprintOptions = typeof opts === "string" ? { antigravityVersion: opts } : (opts ?? {});
|
|
837
|
-
|
|
838
|
-
this.directory = o.directory ? path.resolve(o.directory) : process.cwd();
|
|
839
|
-
this.allowExtended = o.allowExtendedPlatforms ?? false;
|
|
840
|
-
this.fixedPlatform = o.fixedPlatform;
|
|
841
|
-
this.fixedCliVersion = o.fixedCliVersion;
|
|
842
|
-
this.fixedGoogleApiVersion = o.fixedGoogleApiVersion;
|
|
843
|
-
this.fixedNodeVersion = o.fixedNodeVersion;
|
|
844
|
-
this.sessionId = generateSessionUuid(this.directory);
|
|
845
|
-
this.version = this.normalizeAntigravityVersion(o.antigravityVersion);
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
/** Validates / extracts the Antigravity version from raw input. */
|
|
849
|
-
private normalizeAntigravityVersion(raw?: string): string {
|
|
850
|
-
const v = (raw ?? "").trim();
|
|
851
|
-
if (!v) return ANTIGRAVITY_VERSION_FALLBACK;
|
|
852
|
-
if (/^\d+\.\d+\.\d+/.test(v)) return v;
|
|
853
|
-
if (/^antigravity\//i.test(v)) {
|
|
854
|
-
// Allow passing a full UA string - extract the version part.
|
|
855
|
-
const m = v.match(/antigravity\/([0-9]+\.[0-9]+\.[0-9]+[^\s]*)/i);
|
|
856
|
-
return m && m[1] ? m[1] : ANTIGRAVITY_VERSION_FALLBACK;
|
|
857
|
-
}
|
|
858
|
-
return ANTIGRAVITY_VERSION_FALLBACK;
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
// --------------------------------------------------------------------------
|
|
862
|
-
// Hashing helpers (instance level)
|
|
863
|
-
// --------------------------------------------------------------------------
|
|
864
|
-
|
|
865
|
-
/** Numeric 32-bit FNV-1a (deterministic, fast, no crypto overhead). */
|
|
866
|
-
private fnv1a32m(input: string): number {
|
|
867
|
-
if (typeof input !== "string") throw new TypeError("fnv1a32 input must be string");
|
|
868
|
-
return fnv1a32(input);
|
|
869
|
-
}
|
|
870
|
-
|
|
871
|
-
/** Numeric 64-bit FNV-1a for longer session identifiers. */
|
|
872
|
-
private fnv1a64b(input: string): bigint {
|
|
873
|
-
if (typeof input !== "string") throw new TypeError("fnv1a64 input must be string");
|
|
874
|
-
return fnv1a64Big(input);
|
|
875
|
-
}
|
|
876
|
-
|
|
877
|
-
/** Hex representation (8 chars) of the 32-bit FNV-1a hash. */
|
|
878
|
-
public fnv1aHex(input: string): string {
|
|
879
|
-
return this.fnv1a32m(input).toString(16).padStart(8, "0");
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
/**
|
|
883
|
-
* Deterministic session id from a seed (sess_ prefixed, FNV-based). When no
|
|
884
|
-
* seed is supplied, falls back to randomUUID + hostname + timestamp hashed
|
|
885
|
-
* into the same format. Never throws.
|
|
886
|
-
*
|
|
887
|
-
* v2.1.16 divergence note: {@link generateUserPromptId} below is the
|
|
888
|
-
* structural twin of this method, kept separate (not parametrized into one
|
|
889
|
-
* prefix+salt helper) because the outputs intentionally differ in four
|
|
890
|
-
* places: the prefix (sess_ vs up_), the secondary hash salt (`:sess` vs
|
|
891
|
-
* `:up`), the unseeded base (Date.now() vs process.pid) and the catch-path
|
|
892
|
-
* fallback shape (sess_ appends a base36 timestamp, up_ does not).
|
|
893
|
-
*/
|
|
894
|
-
public generateSessionId(seed?: string): string {
|
|
895
|
-
try {
|
|
896
|
-
if (seed && typeof seed === "string" && seed.length > 0) {
|
|
897
|
-
const h = this.fnv1a64b(seed);
|
|
898
|
-
const hex = h.toString(16).padStart(16, "0");
|
|
899
|
-
const h2 = this.fnv1a32m(`${seed}:sess`);
|
|
900
|
-
const suffix = h2.toString(16).padStart(8, "0");
|
|
901
|
-
return `sess_${hex}${suffix}`;
|
|
902
|
-
}
|
|
903
|
-
const randomBase = `${crypto.randomUUID()}:${os.hostname()}:${Date.now()}`;
|
|
904
|
-
const h = this.fnv1a64b(randomBase);
|
|
905
|
-
const timeFrag = Date.now().toString(36);
|
|
906
|
-
return `sess_${h.toString(16).padStart(16, "0")}_${timeFrag}`;
|
|
907
|
-
} catch {
|
|
908
|
-
const fallback = `${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
909
|
-
return `sess_${this.fnv1aHex(fallback)}_${Date.now().toString(36)}`;
|
|
910
|
-
}
|
|
911
|
-
}
|
|
912
|
-
|
|
913
|
-
/**
|
|
914
|
-
* Deterministic user_prompt_id mirroring Antigravity Manager behavior where
|
|
915
|
-
* prompt IDs stay stable per request content. Never throws.
|
|
916
|
-
*/
|
|
917
|
-
public generateUserPromptId(seed?: string): string {
|
|
918
|
-
try {
|
|
919
|
-
if (seed && typeof seed === "string" && seed.length > 0) {
|
|
920
|
-
const h = this.fnv1a64b(seed);
|
|
921
|
-
const hex = h.toString(16).padStart(16, "0");
|
|
922
|
-
const h2 = this.fnv1a32m(`${seed}:up`);
|
|
923
|
-
return `up_${hex}${h2.toString(16).padStart(8, "0")}`;
|
|
924
|
-
}
|
|
925
|
-
const randomBase = `${crypto.randomUUID()}:${os.hostname()}:${process.pid}`;
|
|
926
|
-
const h = this.fnv1a64b(randomBase);
|
|
927
|
-
return `up_${h.toString(16).padStart(16, "0")}_${Date.now().toString(36)}`;
|
|
928
|
-
} catch {
|
|
929
|
-
const fallback = `${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
930
|
-
return `up_${this.fnv1aHex(fallback)}`;
|
|
931
|
-
}
|
|
932
|
-
}
|
|
933
|
-
|
|
934
|
-
// --------------------------------------------------------------------------
|
|
935
|
-
// Platform selection - coherent + weighted
|
|
936
|
-
// --------------------------------------------------------------------------
|
|
937
|
-
|
|
938
|
-
/**
|
|
939
|
-
* Returns a coherent platform with per-instance caching for stability.
|
|
940
|
-
* A fixedPlatform always wins (deterministic tests); an explicit override
|
|
941
|
-
* bypasses the cache entirely.
|
|
942
|
-
*/
|
|
943
|
-
getPlatform(override?: PlatformProfile): PlatformProfile {
|
|
944
|
-
if (override) return override;
|
|
945
|
-
if (this.fixedPlatform) return this.fixedPlatform;
|
|
946
|
-
if (this.cachedPlatform) return this.cachedPlatform;
|
|
947
|
-
|
|
948
|
-
const pool = this.allowExtended ? PLATFORM_POOL_EXTENDED : PLATFORM_PROFILE_POOL;
|
|
949
|
-
const chosen = pickRandomWeighted(pool);
|
|
950
|
-
this.cachedPlatform = chosen;
|
|
951
|
-
return chosen;
|
|
952
|
-
}
|
|
953
|
-
|
|
954
|
-
/** Forces a platform rotation (useful for anti-ban testing). */
|
|
955
|
-
rotatePlatform(): PlatformProfile {
|
|
956
|
-
const pool = this.allowExtended ? PLATFORM_POOL_EXTENDED : PLATFORM_PROFILE_POOL;
|
|
957
|
-
const chosen = pickRandomWeighted(pool);
|
|
958
|
-
this.cachedPlatform = chosen;
|
|
959
|
-
return chosen;
|
|
960
|
-
}
|
|
961
|
-
|
|
962
|
-
/**
|
|
963
|
-
* Runtime-detected keyed pool (cached):
|
|
964
|
-
* win32 -> windows/amd64, darwin -> darwin/arm64 (even under Rosetta),
|
|
965
|
-
* everything else -> linux/x64.
|
|
966
|
-
*/
|
|
967
|
-
public getPlatformPool(): PlatformPool {
|
|
968
|
-
if (this.poolCache) return this.poolCache;
|
|
969
|
-
|
|
970
|
-
const plat = os.platform();
|
|
971
|
-
let key: string;
|
|
972
|
-
if (plat === "win32") key = "windows/amd64";
|
|
973
|
-
else if (plat === "darwin") key = "darwin/arm64";
|
|
974
|
-
else key = "linux/x64";
|
|
975
|
-
|
|
976
|
-
const pool = PLATFORM_POOLS[key];
|
|
977
|
-
const fallbackPool = PLATFORM_POOLS["linux/x64"];
|
|
978
|
-
// Defensive: both entries are static constants, so at least one exists.
|
|
979
|
-
this.poolCache = (pool ?? fallbackPool) as PlatformPool;
|
|
980
|
-
return this.poolCache;
|
|
981
|
-
}
|
|
982
|
-
|
|
983
|
-
/** Static accessor for all keyed pools (testing / CLI listing). */
|
|
984
|
-
public static getPlatformPools(): PoolMap {
|
|
985
|
-
return { ...PLATFORM_POOLS };
|
|
986
|
-
}
|
|
987
|
-
|
|
988
|
-
/** Current keyed pool key, e.g. "darwin/arm64". */
|
|
989
|
-
public getCurrentPoolKey(): string {
|
|
990
|
-
return this.getPlatformPool().key;
|
|
991
|
-
}
|
|
992
|
-
|
|
993
|
-
// --------------------------------------------------------------------------
|
|
994
|
-
// Jitter (instance API)
|
|
995
|
-
// --------------------------------------------------------------------------
|
|
996
|
-
|
|
997
|
-
/** Cryptographically strong jitter in the inclusive 0..80ms range. */
|
|
998
|
-
public getJitterMs(): number {
|
|
999
|
-
try {
|
|
1000
|
-
const v = crypto.randomInt(0, 81);
|
|
1001
|
-
if (typeof v === "number" && Number.isFinite(v)) return v;
|
|
1002
|
-
} catch {
|
|
1003
|
-
// fall through to Math.random
|
|
1004
|
-
}
|
|
1005
|
-
return Math.floor(Math.random() * 81);
|
|
1006
|
-
}
|
|
1007
|
-
|
|
1008
|
-
/** Applies jitter asynchronously - awaits 0..80ms. */
|
|
1009
|
-
public async applyJitter(): Promise<void> {
|
|
1010
|
-
const ms = this.getJitterMs();
|
|
1011
|
-
if (ms <= 0) return;
|
|
1012
|
-
await new Promise<void>((resolve) => setTimeout(resolve, ms));
|
|
1013
|
-
}
|
|
1014
|
-
|
|
1015
|
-
// --------------------------------------------------------------------------
|
|
1016
|
-
// Version pairs - anti-ban randomized
|
|
1017
|
-
// --------------------------------------------------------------------------
|
|
1018
|
-
|
|
1019
|
-
/**
|
|
1020
|
-
* Produces a coherent version set that actually shipped together.
|
|
1021
|
-
* 70% recent-user slice, 30% long-tail for realistic distribution.
|
|
1022
|
-
*/
|
|
1023
|
-
private getCoherentVersionPair(): {
|
|
1024
|
-
cliVersion: string;
|
|
1025
|
-
googleApiVersion: string;
|
|
1026
|
-
glNodeVersion: string;
|
|
1027
|
-
gaxVersion: string;
|
|
1028
|
-
} {
|
|
1029
|
-
if (this.fixedCliVersion || this.fixedGoogleApiVersion || this.fixedNodeVersion) {
|
|
1030
|
-
return {
|
|
1031
|
-
cliVersion: this.fixedCliVersion ?? pickRandom(GEMINI_CLI_VERSION_POOL),
|
|
1032
|
-
googleApiVersion: this.fixedGoogleApiVersion ?? pickRandom(GOOGLE_API_CLIENT_VERSION_POOL),
|
|
1033
|
-
glNodeVersion: this.fixedNodeVersion ?? pickRandom(GL_NODE_VERSION_POOL),
|
|
1034
|
-
gaxVersion: pickRandom(GAX_VERSION_POOL),
|
|
1035
|
-
};
|
|
1036
|
-
}
|
|
1037
|
-
|
|
1038
|
-
const isRecentUser = secureRandom() < 0.7;
|
|
1039
|
-
|
|
1040
|
-
if (isRecentUser) {
|
|
1041
|
-
return {
|
|
1042
|
-
cliVersion: pickRandom(GEMINI_CLI_VERSION_POOL.slice(0, 3)),
|
|
1043
|
-
googleApiVersion: pickRandom(GOOGLE_API_CLIENT_VERSION_POOL.slice(0, 2)),
|
|
1044
|
-
glNodeVersion: pickRandom(GL_NODE_VERSION_POOL.slice(0, 3)),
|
|
1045
|
-
gaxVersion: GAX_VERSION_POOL[0],
|
|
1046
|
-
};
|
|
1047
|
-
}
|
|
1048
|
-
return {
|
|
1049
|
-
cliVersion: pickRandom(GEMINI_CLI_VERSION_POOL.slice(2)),
|
|
1050
|
-
googleApiVersion: pickRandom(GOOGLE_API_CLIENT_VERSION_POOL.slice(2)),
|
|
1051
|
-
glNodeVersion: pickRandom(GL_NODE_VERSION_POOL.slice(2)),
|
|
1052
|
-
gaxVersion: pickRandom(GAX_VERSION_POOL.slice(1)),
|
|
1053
|
-
};
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1056
|
-
// --------------------------------------------------------------------------
|
|
1057
|
-
// User-Agent generators
|
|
1058
|
-
// --------------------------------------------------------------------------
|
|
1059
|
-
|
|
1060
|
-
/**
|
|
1061
|
-
* User-Agent identical to the official Gemini CLI:
|
|
1062
|
-
* `GeminiCLI/0.57.0/gemini-3-pro-preview (win32; x64; GitHub) google-api-nodejs-client/9.15.1`
|
|
1063
|
-
*/
|
|
1064
|
-
getGeminiCLIUserAgent(model: string = UA_DEFAULT_MODEL, platform?: PlatformProfile): string {
|
|
1065
|
-
const plat = this.getPlatform(platform);
|
|
1066
|
-
const { cliVersion, googleApiVersion } = this.getCoherentVersionPair();
|
|
1067
|
-
|
|
1068
|
-
// antigravity-* models are kept whole; the backend accepts them.
|
|
1069
|
-
const modelSegment = model.trim();
|
|
1070
|
-
return `GeminiCLI/${cliVersion}/${modelSegment} (${plat.uaSegment}; ${plat.source}) google-api-nodejs-client/${googleApiVersion}`;
|
|
1071
|
-
}
|
|
1072
|
-
|
|
1073
|
-
/**
|
|
1074
|
-
* Antigravity-flavored User-Agent observed in fetchAvailableModels traces:
|
|
1075
|
-
* `Antigravity/1.12.8 (linux; x64) CodeAssist/0.9.2 google-api-nodejs-client/9.15.1 gl-node/22.19.0`
|
|
1076
|
-
*/
|
|
1077
|
-
getAntigravityUserAgent(version?: string, platform?: PlatformProfile): string {
|
|
1078
|
-
const plat = this.getPlatform(platform);
|
|
1079
|
-
const coherent = this.getCoherentVersionPair();
|
|
1080
|
-
const agVersion = version ?? pickRandom(ANTIGRAVITY_VERSION_POOL);
|
|
1081
|
-
const googleVer = coherent.googleApiVersion;
|
|
1082
|
-
const glNode = coherent.glNodeVersion;
|
|
1083
|
-
|
|
1084
|
-
// Real traces include a CodeAssist sub-version.
|
|
1085
|
-
const codeAssistVersions = ["0.9.2", "0.9.1", "0.8.7"];
|
|
1086
|
-
const caVer = pickRandom(codeAssistVersions);
|
|
1087
|
-
|
|
1088
|
-
return `Antigravity/${agVersion} (${plat.uaSegment}) CodeAssist/${caVer} google-api-nodejs-client/${googleVer} gl-node/${glNode}`;
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
// --------------------------------------------------------------------------
|
|
1092
|
-
// X-Goog-Api-Client + Client-Metadata
|
|
1093
|
-
// --------------------------------------------------------------------------
|
|
1094
|
-
|
|
1095
|
-
/**
|
|
1096
|
-
* X-Goog-Api-Client identical to the Node.js Google client. 80% simplified
|
|
1097
|
-
* (`gl-node/22.19.0`), 20% full chain with gccl/gax/grpc segments.
|
|
1098
|
-
*/
|
|
1099
|
-
getXGoogApiClient(): string {
|
|
1100
|
-
const { glNodeVersion, gaxVersion } = this.getCoherentVersionPair();
|
|
1101
|
-
|
|
1102
|
-
const useFull = secureRandom() < 0.2;
|
|
1103
|
-
if (!useFull) {
|
|
1104
|
-
return `gl-node/${glNodeVersion}`;
|
|
1105
|
-
}
|
|
1106
|
-
|
|
1107
|
-
const gcclPool = ["0.2.0", "0.2.1"];
|
|
1108
|
-
const grpcPool = ["1.13.4", "1.13.3", "1.10.8"];
|
|
1109
|
-
const gccl = pickRandom(gcclPool);
|
|
1110
|
-
const grpc = pickRandom(grpcPool);
|
|
1111
|
-
|
|
1112
|
-
return `gl-node/${glNodeVersion} gccl/${gccl} gax/${gaxVersion} grpc/${grpc}`;
|
|
1113
|
-
}
|
|
1114
|
-
|
|
1115
|
-
/**
|
|
1116
|
-
* Hardened fixed Client-Metadata validated by onboarding/loadCodeAssist:
|
|
1117
|
-
* `ideType=IDE_UNSPECIFIED,platform=PLATFORM_UNSPECIFIED,pluginType=GEMINI`
|
|
1118
|
-
*/
|
|
1119
|
-
getClientMetadata(): string {
|
|
1120
|
-
return "ideType=IDE_UNSPECIFIED,platform=PLATFORM_UNSPECIFIED,pluginType=GEMINI";
|
|
1121
|
-
}
|
|
1122
|
-
|
|
1123
|
-
/**
|
|
1124
|
-
* Structured JSON Client-Metadata used by observer-style requests
|
|
1125
|
-
* (ideType ANTIGRAVITY + plugin/arch/node details). Falls back to a compact
|
|
1126
|
-
* key=value form and never throws.
|
|
1127
|
-
*/
|
|
1128
|
-
private buildClientMetadata(pool?: PlatformPool): string {
|
|
1129
|
-
const p = pool ?? this.getPlatformPool();
|
|
1130
|
-
try {
|
|
1131
|
-
const nodeVer = process.version;
|
|
1132
|
-
const payload = {
|
|
1133
|
-
ideType: "ANTIGRAVITY",
|
|
1134
|
-
ideVersion: this.version,
|
|
1135
|
-
platform: p.os.toUpperCase(),
|
|
1136
|
-
arch: p.arch.toUpperCase(),
|
|
1137
|
-
pluginVersion: PLUGIN_VERSION_FALLBACK,
|
|
1138
|
-
nodeVersion: nodeVer,
|
|
1139
|
-
osDisplay: p.displayOs,
|
|
1140
|
-
};
|
|
1141
|
-
return JSON.stringify(payload);
|
|
1142
|
-
} catch {
|
|
1143
|
-
return `ideType=antigravity,platform=${p.os},arch=${p.arch},version=${this.version}`;
|
|
1144
|
-
}
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
|
-
/**
|
|
1148
|
-
* Observer-style X-Goog-Api-Client:
|
|
1149
|
-
* `gl-node/<node> antigravity/<version> gccl/1.0.0`. Never throws.
|
|
1150
|
-
*/
|
|
1151
|
-
private buildApiClient(): string {
|
|
1152
|
-
try {
|
|
1153
|
-
const nodeVer = process.version.replace(/^v/, "");
|
|
1154
|
-
return `gl-node/${nodeVer} antigravity/${this.version} gccl/1.0.0`;
|
|
1155
|
-
} catch {
|
|
1156
|
-
return `antigravity/${this.version}`;
|
|
1157
|
-
}
|
|
1158
|
-
}
|
|
1159
|
-
|
|
1160
|
-
// --------------------------------------------------------------------------
|
|
1161
|
-
// Full headers - legacy Gemini CLI shape
|
|
1162
|
-
// --------------------------------------------------------------------------
|
|
1163
|
-
|
|
1164
|
-
/**
|
|
1165
|
-
* Complete Gemini CLI-compatible header set including coherent UA,
|
|
1166
|
-
* X-Goog-Api-Client jitter, hardened Client-Metadata and Content-Type.
|
|
1167
|
-
*/
|
|
1168
|
-
getFullHeaders(
|
|
1169
|
-
model: string = UA_DEFAULT_MODEL,
|
|
1170
|
-
type: FingerprintType = "gemini-cli",
|
|
1171
|
-
platformOverride?: PlatformProfile,
|
|
1172
|
-
): FullHeadersResult {
|
|
1173
|
-
const plat = this.getPlatform(platformOverride);
|
|
1174
|
-
const versions = this.getCoherentVersionPair();
|
|
1175
|
-
const jitterMs = getJitterMs(0, 80);
|
|
1176
|
-
|
|
1177
|
-
const userAgent =
|
|
1178
|
-
type === "gemini-cli"
|
|
1179
|
-
? this.getGeminiCLIUserAgent(model, plat)
|
|
1180
|
-
: this.getAntigravityUserAgent(versions.cliVersion, plat);
|
|
1181
|
-
|
|
1182
|
-
const xGoogClient = this.getXGoogApiClient();
|
|
1183
|
-
const clientMetadata = this.getClientMetadata();
|
|
1184
|
-
const xClientDetails = `session_id=${this.sessionId},platform=${plat.os}`;
|
|
1185
|
-
|
|
1186
|
-
return {
|
|
1187
|
-
"User-Agent": userAgent,
|
|
1188
|
-
"X-Goog-Api-Client": xGoogClient,
|
|
1189
|
-
"Client-Metadata": clientMetadata,
|
|
1190
|
-
"Content-Type": "application/json",
|
|
1191
|
-
Accept: "application/json",
|
|
1192
|
-
"X-Client-Details": xClientDetails,
|
|
1193
|
-
__meta: {
|
|
1194
|
-
platform: plat,
|
|
1195
|
-
cliVersion: versions.cliVersion,
|
|
1196
|
-
googleApiVersion: versions.googleApiVersion,
|
|
1197
|
-
glNodeVersion: versions.glNodeVersion,
|
|
1198
|
-
gaxVersion: versions.gaxVersion,
|
|
1199
|
-
sessionId: this.sessionId,
|
|
1200
|
-
model,
|
|
1201
|
-
type,
|
|
1202
|
-
jitterMs,
|
|
1203
|
-
},
|
|
1204
|
-
};
|
|
1205
|
-
}
|
|
1206
|
-
|
|
1207
|
-
/** Native Fetch API Headers instance ready for direct fetch() usage. */
|
|
1208
|
-
toFetchHeaders(model?: string, type?: FingerprintType): Headers {
|
|
1209
|
-
const full = this.getFullHeaders(model, type);
|
|
1210
|
-
const h = new Headers();
|
|
1211
|
-
h.set("User-Agent", full["User-Agent"]);
|
|
1212
|
-
h.set("X-Goog-Api-Client", full["X-Goog-Api-Client"]);
|
|
1213
|
-
h.set("Client-Metadata", full["Client-Metadata"]);
|
|
1214
|
-
h.set("Content-Type", full["Content-Type"]);
|
|
1215
|
-
h.set("Accept", full["Accept"]);
|
|
1216
|
-
if (full["X-Client-Details"]) h.set("X-Client-Details", full["X-Client-Details"]);
|
|
1217
|
-
return h;
|
|
1218
|
-
}
|
|
1219
|
-
|
|
1220
|
-
// --------------------------------------------------------------------------
|
|
1221
|
-
// Observer-style fingerprint headers
|
|
1222
|
-
// --------------------------------------------------------------------------
|
|
1223
|
-
|
|
1224
|
-
/**
|
|
1225
|
-
* Generates observer-style fingerprint headers.
|
|
1226
|
-
*
|
|
1227
|
-
* Enforced requirements:
|
|
1228
|
-
* - User-Agent: `antigravity/{version} {os}/{arch}` (coherent keyed pool)
|
|
1229
|
-
* - Client-Metadata: always included (structured JSON, AM observed)
|
|
1230
|
-
* - X-Goog-Api-Client ONLY when headerStyle === 'gemini-cli'
|
|
1231
|
-
* - Never includes X-Goog-QuotaUser nor X-Client-Device-Id
|
|
1232
|
-
*
|
|
1233
|
-
* @param headerStyle - 'antigravity' (default content path) or 'gemini-cli'
|
|
1234
|
-
*/
|
|
1235
|
-
public getFingerprintHeaders(headerStyle: HeaderStyle = "antigravity"): Record<string, string> {
|
|
1236
|
-
if (headerStyle !== "antigravity" && headerStyle !== "gemini-cli") {
|
|
1237
|
-
throw new TypeError(`headerStyle must be 'antigravity' or 'gemini-cli', got ${String(headerStyle)}`);
|
|
1238
|
-
}
|
|
1239
|
-
|
|
1240
|
-
const pool = this.getPlatformPool();
|
|
1241
|
-
|
|
1242
|
-
// Coherence-critical: outdated versions triggered backend bans.
|
|
1243
|
-
const userAgent = `antigravity/${this.version} ${pool.os}/${pool.arch}`;
|
|
1244
|
-
|
|
1245
|
-
const headers: Record<string, string> = {
|
|
1246
|
-
"User-Agent": userAgent,
|
|
1247
|
-
"Content-Type": "application/json",
|
|
1248
|
-
"Client-Metadata": this.buildClientMetadata(pool),
|
|
1249
|
-
Accept: "application/json",
|
|
1250
|
-
};
|
|
1251
|
-
|
|
1252
|
-
if (headerStyle === "gemini-cli") {
|
|
1253
|
-
headers["X-Goog-Api-Client"] = this.buildApiClient();
|
|
1254
|
-
}
|
|
1255
|
-
|
|
1256
|
-
return headers;
|
|
1257
|
-
}
|
|
1258
|
-
|
|
1259
|
-
/** Antigravity version currently embedded in observer fingerprints. */
|
|
1260
|
-
public getVersion(): string {
|
|
1261
|
-
return this.version;
|
|
1262
|
-
}
|
|
1263
|
-
|
|
1264
|
-
// --------------------------------------------------------------------------
|
|
1265
|
-
// Accessors
|
|
1266
|
-
// --------------------------------------------------------------------------
|
|
1267
|
-
|
|
1268
|
-
/** Deterministic session_id of this instance. */
|
|
1269
|
-
getSessionId(): string {
|
|
1270
|
-
return this.sessionId;
|
|
1271
|
-
}
|
|
1272
|
-
|
|
1273
|
-
/** Full OAuth config for the auth flow. */
|
|
1274
|
-
getOAuthConfig(): {
|
|
1275
|
-
clientId: string;
|
|
1276
|
-
clientSecret: string;
|
|
1277
|
-
scopes: readonly string[];
|
|
1278
|
-
projectFallback: string;
|
|
1279
|
-
} {
|
|
1280
|
-
return {
|
|
1281
|
-
clientId: OAUTH_CLIENT_ID,
|
|
1282
|
-
clientSecret: OAUTH_CLIENT_SECRET,
|
|
1283
|
-
scopes: GEMINI_CLI_SCOPES,
|
|
1284
|
-
projectFallback: PROJECT_FALLBACK,
|
|
1285
|
-
};
|
|
1286
|
-
}
|
|
1287
|
-
|
|
1288
|
-
/** Endpoint map (v2.1.15 Phase D: derives from the constants.js parts). */
|
|
1289
|
-
getEndpoints(): typeof FINGERPRINT_API_PATHS {
|
|
1290
|
-
return FINGERPRINT_API_PATHS;
|
|
1291
|
-
}
|
|
1292
|
-
}
|
|
1293
|
-
|
|
1294
|
-
// ============================================================================
|
|
1295
|
-
// Section: Standalone exported API (short blind helpers)
|
|
1296
|
-
// ============================================================================
|
|
1297
|
-
|
|
1298
|
-
/** Lazy singleton bound to the current cwd; stable session_id per process. */
|
|
1299
|
-
let cachedgenerator: FingerprintGenerator | null = null;
|
|
1300
|
-
|
|
1301
|
-
function getDefaultInstance(): FingerprintGenerator {
|
|
1302
|
-
if (!cachedgenerator) {
|
|
1303
|
-
cachedgenerator = new FingerprintGenerator();
|
|
1304
|
-
}
|
|
1305
|
-
return cachedgenerator;
|
|
1306
|
-
}
|
|
1307
|
-
|
|
1308
|
-
/**
|
|
1309
|
-
* Default shared generator using ANTIGRAVITY_VERSION_FALLBACK until
|
|
1310
|
-
* version.ts resolves the remote version. Consumers may create their own
|
|
1311
|
-
* instances with a dynamic version. The grand merge folded this module into
|
|
1312
|
-
* the shared core graph the platform-portable bundles ship, so the singleton
|
|
1313
|
-
* constructs on first use (the constructor resolves the cwd through the node
|
|
1314
|
-
* path builtin): under node and bun the behavior is identical while a stubbed
|
|
1315
|
-
* browser bundle never instantiates the generator at import time.
|
|
1316
|
-
*/
|
|
1317
|
-
export const defaultFingerprintGenerator: FingerprintGenerator = new Proxy({} as FingerprintGenerator, {
|
|
1318
|
-
get(_target: FingerprintGenerator, property: string | symbol): unknown {
|
|
1319
|
-
if (!cachedgenerator) {
|
|
1320
|
-
cachedgenerator = new FingerprintGenerator(ANTIGRAVITY_VERSION_FALLBACK);
|
|
1321
|
-
}
|
|
1322
|
-
const value = Reflect.get(cachedgenerator, property, cachedgenerator) as unknown;
|
|
1323
|
-
return typeof value === "function" ? (value as (...args: unknown[]) => unknown).bind(cachedgenerator) : value;
|
|
1324
|
-
},
|
|
1325
|
-
});
|
|
1326
|
-
|
|
1327
|
-
/**
|
|
1328
|
-
* Convenience wrapper matching the original plugin export names. Uses the
|
|
1329
|
-
* default singleton, or a temporary generator when a version is supplied.
|
|
1330
|
-
*
|
|
1331
|
-
* @param style - 'antigravity' (default) or 'gemini-cli'
|
|
1332
|
-
* @param version - optional Antigravity version override
|
|
1333
|
-
*/
|
|
1334
|
-
export function getFingerprintHeaders(style: HeaderStyle = "antigravity", version?: string): Record<string, string> {
|
|
1335
|
-
if (version) {
|
|
1336
|
-
return new FingerprintGenerator(version).getFingerprintHeaders(style);
|
|
1337
|
-
}
|
|
1338
|
-
return defaultFingerprintGenerator.getFingerprintHeaders(style);
|
|
1339
|
-
}
|
|
1340
|
-
|
|
1341
|
-
/**
|
|
1342
|
-
* Short helper generating Gemini CLI compatible headers for project bypass.
|
|
1343
|
-
*
|
|
1344
|
-
* @param model - model id (default gemini-3-pro-preview)
|
|
1345
|
-
* @param type - 'gemini-cli' or 'antigravity'
|
|
1346
|
-
* @param platform - profile object, "win32 x64" string, or plain OS string
|
|
1347
|
-
*/
|
|
1348
|
-
export function generateHeaders(
|
|
1349
|
-
model: string = UA_DEFAULT_MODEL,
|
|
1350
|
-
type: FingerprintType = "gemini-cli",
|
|
1351
|
-
platform?: PlatformProfile | `${PlatformOS} ${PlatformArch}` | PlatformOS,
|
|
1352
|
-
): Record<string, string> {
|
|
1353
|
-
const fp = getDefaultInstance();
|
|
1354
|
-
|
|
1355
|
-
let platformProfile: PlatformProfile | undefined;
|
|
1356
|
-
if (platform) {
|
|
1357
|
-
if (typeof platform === "object") {
|
|
1358
|
-
platformProfile = platform;
|
|
1359
|
-
} else if (typeof platform === "string") {
|
|
1360
|
-
// Short parser: "win32 x64" or "win32".
|
|
1361
|
-
const parts = platform.toLowerCase().split(/\s+/);
|
|
1362
|
-
const osPart = parts[0] as PlatformOS;
|
|
1363
|
-
const archPart = (parts[1] as PlatformArch) ?? (osPart === "darwin" ? "arm64" : "x64");
|
|
1364
|
-
const found = PLATFORM_PROFILE_POOL.find((p) => p.os === osPart && p.arch === archPart);
|
|
1365
|
-
if (found) platformProfile = found;
|
|
1366
|
-
}
|
|
1367
|
-
}
|
|
1368
|
-
|
|
1369
|
-
const full = fp.getFullHeaders(model, type, platformProfile);
|
|
1370
|
-
// Strip the internal __meta block - only real HTTP headers are returned.
|
|
1371
|
-
const { __meta, ...httpHeaders } = full;
|
|
1372
|
-
return httpHeaders as Record<string, string>;
|
|
1373
|
-
}
|
|
1374
|
-
|
|
1375
|
-
/** Variant returning a native Fetch API Headers instance (Node 20+). */
|
|
1376
|
-
export function generateFetchHeaders(
|
|
1377
|
-
model?: string,
|
|
1378
|
-
type?: FingerprintType,
|
|
1379
|
-
platform?: PlatformProfile | `${PlatformOS} ${PlatformArch}`,
|
|
1380
|
-
): Headers {
|
|
1381
|
-
const record = generateHeaders(model, type, platform);
|
|
1382
|
-
const h = new Headers();
|
|
1383
|
-
for (const [k, v] of Object.entries(record)) {
|
|
1384
|
-
if (v) h.set(k, v);
|
|
1385
|
-
}
|
|
1386
|
-
return h;
|
|
1387
|
-
}
|
|
1388
|
-
|
|
1389
|
-
/**
|
|
1390
|
-
* Full fingerprint with metadata for debugging/tracing; validates bypasses
|
|
1391
|
-
* during development.
|
|
1392
|
-
*/
|
|
1393
|
-
export function generateFullFingerprint(model?: string, type?: FingerprintType, directory?: string): FullHeadersResult {
|
|
1394
|
-
const fp = directory ? new FingerprintGenerator({ directory }) : getDefaultInstance();
|
|
1395
|
-
return fp.getFullHeaders(model, type);
|
|
1396
|
-
}
|
|
1397
|
-
|
|
1398
|
-
/**
|
|
1399
|
-
* Creates an instance bound to a specific directory (deterministic
|
|
1400
|
-
* session_id). Essential for multi-workspace setups.
|
|
1401
|
-
*/
|
|
1402
|
-
export function createFingerprintForDirectory(directory: string): FingerprintGenerator {
|
|
1403
|
-
return new FingerprintGenerator({ directory });
|
|
1404
|
-
}
|
|
1405
|
-
|
|
1406
|
-
/**
|
|
1407
|
-
* Bypass helper producing headers plus the base body for loadCodeAssist,
|
|
1408
|
-
* including the blinded project fallback.
|
|
1409
|
-
*/
|
|
1410
|
-
export function buildLoadCodeAssistRequest(
|
|
1411
|
-
projectId: string = PROJECT_FALLBACK,
|
|
1412
|
-
model: string = UA_DEFAULT_MODEL,
|
|
1413
|
-
): { url: string; method: "POST"; headers: Record<string, string>; body: string; sessionId: string } {
|
|
1414
|
-
const fp = getDefaultInstance();
|
|
1415
|
-
const headersRec = generateHeaders(model, "gemini-cli");
|
|
1416
|
-
const sessionId = fp.getSessionId();
|
|
1417
|
-
|
|
1418
|
-
return {
|
|
1419
|
-
url: FINGERPRINT_API_PATHS.loadCodeAssist,
|
|
1420
|
-
method: "POST",
|
|
1421
|
-
headers: headersRec,
|
|
1422
|
-
body: JSON.stringify({
|
|
1423
|
-
cloudaicompanionProject: projectId,
|
|
1424
|
-
metadata: {
|
|
1425
|
-
ideType: "IDE_UNSPECIFIED",
|
|
1426
|
-
platform: "PLATFORM_UNSPECIFIED",
|
|
1427
|
-
pluginType: "GEMINI",
|
|
1428
|
-
},
|
|
1429
|
-
session_id: sessionId,
|
|
1430
|
-
}),
|
|
1431
|
-
sessionId,
|
|
1432
|
-
};
|
|
1433
|
-
}
|
|
1434
|
-
|
|
1435
|
-
// ============================================================================
|
|
1436
|
-
// Section: Re-export barrel for plugin consumption
|
|
1437
|
-
// ============================================================================
|
|
1438
|
-
|
|
1439
|
-
export const FingerprintConstants = {
|
|
1440
|
-
OAUTH_CLIENT_ID,
|
|
1441
|
-
OAUTH_CLIENT_SECRET,
|
|
1442
|
-
GEMINI_CLI_SCOPES,
|
|
1443
|
-
PROJECT_FALLBACK,
|
|
1444
|
-
CLOUDCODE_BASE_URL,
|
|
1445
|
-
/** Lazy through the models.js import cycle: the aggregate reads the owner at access time, so every module evaluation order stays legal (the models → core → config → fingerprint cycle of the merged graph never evaluates this read during import). */
|
|
1446
|
-
get MODELS_2026() {
|
|
1447
|
-
return MODELS_2026;
|
|
1448
|
-
},
|
|
1449
|
-
PLATFORM_PROFILE_POOL,
|
|
1450
|
-
PLATFORM_POOLS,
|
|
1451
|
-
GEMINI_CLI_VERSION_POOL,
|
|
1452
|
-
GOOGLE_API_CLIENT_VERSION_POOL,
|
|
1453
|
-
GL_NODE_VERSION_POOL,
|
|
1454
|
-
ANTIGRAVITY_VERSION_FALLBACK,
|
|
1455
|
-
PLUGIN_VERSION_FALLBACK,
|
|
1456
|
-
} as const;
|
|
1457
|
-
|
|
1458
|
-
export default FingerprintGenerator;
|