@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.
Files changed (444) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/{dist/bridge.d.ts → bridge.d.ts} +1 -1
  3. package/bridge.d.ts.map +1 -0
  4. package/bridge.js +1877 -0
  5. package/bun.d.ts.map +1 -0
  6. package/bun.js +52329 -0
  7. package/caps/background.json +712 -0
  8. package/caps/cli.json +360 -0
  9. package/caps/library.json +3611 -0
  10. package/caps/mcp.json +126 -0
  11. package/caps/pagebridge.json +377 -0
  12. package/caps/popup.json +51 -0
  13. package/caps/sidepanel.json +522 -0
  14. package/checksums.txt +142 -0
  15. package/cli.d.ts.map +1 -0
  16. package/{dist/cli.js → cli.js} +2 -2
  17. package/companion.d.ts.map +1 -0
  18. package/companion.js +389 -0
  19. package/crossbrowser.d.ts.map +1 -0
  20. package/crossbrowser.js +1191 -0
  21. package/dashdone.d.ts.map +1 -0
  22. package/dashdone.js +368 -0
  23. package/deno.d.ts.map +1 -0
  24. package/deno.js +52325 -0
  25. package/devthink.umd.js +52346 -0
  26. package/fixtures/bun.ts +7 -0
  27. package/fixtures/cjs.js +6 -0
  28. package/fixtures/deno.ts +6 -0
  29. package/fixtures/example-org-pagestate.json +22 -0
  30. package/fixtures/importers/automa-workflow.json +18 -0
  31. package/fixtures/importers/selenium-side.json +20 -0
  32. package/fixtures/importers/tabular-plan.csv +7 -0
  33. package/fixtures/importers/uivision-macro.json +10 -0
  34. package/fixtures/importers/v1-plan.json +13 -0
  35. package/fixtures/mcp-client.mjs +14 -0
  36. package/fixtures/pages/checkout.html +192 -0
  37. package/fixtures/pages/dashboard.html +110 -0
  38. package/fixtures/pages/feed.html +113 -0
  39. package/fixtures/pages/product-grid.html +150 -0
  40. package/fixtures/plans/form-inventory-plan.json +11 -0
  41. package/fixtures/plans/release-notes-plan.json +11 -0
  42. package/fixtures/recipes/agentscompete.json +11 -0
  43. package/fixtures/recipes/agentsforms.json +11 -0
  44. package/fixtures/recipes/agentsmonitor.json +11 -0
  45. package/fixtures/recipes/agentsreview.json +29 -0
  46. package/fixtures/recipes/agentswarm.json +11 -0
  47. package/fixtures/recipes/fillcalendar.json +12 -0
  48. package/fixtures/recipes/fillcheckout.json +13 -0
  49. package/fixtures/recipes/filldependentdropdowns.json +12 -0
  50. package/fixtures/recipes/fillfromcsv.json +13 -0
  51. package/fixtures/recipes/fillloginform.json +12 -0
  52. package/fixtures/recipes/fillmultistepwizard.json +13 -0
  53. package/fixtures/recipes/fillregistration.json +12 -0
  54. package/fixtures/recipes/fillsearchfilters.json +12 -0
  55. package/fixtures/recipes/filltypeahead.json +11 -0
  56. package/fixtures/recipes/monitoralerts.json +12 -0
  57. package/fixtures/recipes/monitoravailability.json +11 -0
  58. package/fixtures/recipes/monitornetworkquiet.json +12 -0
  59. package/fixtures/recipes/monitorpagechanges.json +11 -0
  60. package/fixtures/recipes/monitorpricechange.json +11 -0
  61. package/fixtures/recipes/monitorschedule.json +12 -0
  62. package/fixtures/recipes/scrapedynamicprices.json +13 -0
  63. package/fixtures/recipes/scrapeimagegallery.json +12 -0
  64. package/fixtures/recipes/scrapeinfinitefeed.json +13 -0
  65. package/fixtures/recipes/scrapenestedlists.json +12 -0
  66. package/fixtures/recipes/scrapeproductgrid.json +12 -0
  67. package/fixtures/recipes/scrapereviews.json +12 -0
  68. package/fixtures/recipes/scrapesearchresults.json +12 -0
  69. package/fixtures/recipes/scrapetablepagination.json +12 -0
  70. package/fixtures/recipes/testaccessibility.json +34 -0
  71. package/fixtures/recipes/testconsoleerrors.json +12 -0
  72. package/fixtures/recipes/testdeeplinks.json +12 -0
  73. package/fixtures/recipes/testformvalidation.json +13 -0
  74. package/fixtures/recipes/testlayoutshift.json +12 -0
  75. package/fixtures/recipes/testlinkcheck.json +12 -0
  76. package/fixtures/recipes/testloadtiming.json +12 -0
  77. package/fixtures/recipes/testvisualdiff.json +12 -0
  78. package/fixtures/workflows/changelog-digest-workflow.json +13 -0
  79. package/fixtures/workflows/form-survey-workflow.json +13 -0
  80. package/gallery.json +706 -0
  81. package/hardening.d.ts.map +1 -0
  82. package/hardening.js +188 -0
  83. package/headless.d.ts.map +1 -0
  84. package/headless.js +11522 -0
  85. package/http.d.ts.map +1 -0
  86. package/http.js +2165 -0
  87. package/index.cjs +54682 -0
  88. package/index.d.ts.map +1 -0
  89. package/index.js +52310 -0
  90. package/index.neutral.js +46343 -0
  91. package/{web/manifest.json → manifest.json} +1 -1
  92. package/mcp.d.ts.map +1 -0
  93. package/mcp.js +20515 -0
  94. package/memory.d.ts.map +1 -0
  95. package/{memory.ts → memory.js} +2310 -3834
  96. package/nativehost.template.json +10 -0
  97. package/node.cjs +54686 -0
  98. package/node.d.ts.map +1 -0
  99. package/pack.d.ts.map +1 -0
  100. package/pack.js +805 -0
  101. package/package.json +83 -176
  102. package/policy.d.ts.map +1 -0
  103. package/{policy.ts → policy.js} +4679 -5073
  104. package/progress.d.ts.map +1 -0
  105. package/progress.js +645 -0
  106. package/protocol.d.ts.map +1 -0
  107. package/protocol.js +8334 -0
  108. package/schemas/audit.schema.json +226 -0
  109. package/schemas/capability.schema.json +113 -0
  110. package/schemas/envelope.schema.json +162 -0
  111. package/schemas/memory.schema.json +51 -0
  112. package/schemas/observation.schema.json +113 -0
  113. package/schemas/plan.schema.json +208 -0
  114. package/schemas/progress.schema.json +126 -0
  115. package/schemas/proposal.schema.json +68 -0
  116. package/schemas/session.schema.json +82 -0
  117. package/schemas/tool.schema.json +94 -0
  118. package/server.d.ts.map +1 -0
  119. package/server.js +28877 -0
  120. package/umd-example.html +18 -0
  121. package/umd.d.ts.map +1 -0
  122. package/accounts.ts +0 -2087
  123. package/agent.ts +0 -2331
  124. package/antigravity.ts +0 -2139
  125. package/apifreeze.ts +0 -4146
  126. package/auth.ts +0 -642
  127. package/background.ts +0 -16837
  128. package/bridge.ts +0 -2080
  129. package/build.ts +0 -54
  130. package/bun.ts +0 -26
  131. package/capture.ts +0 -1614
  132. package/checksecrets.ts +0 -72
  133. package/cjs.ts +0 -9
  134. package/cli.ts +0 -3500
  135. package/commands.ts +0 -1101
  136. package/companion.ts +0 -450
  137. package/compatibility.ts +0 -37
  138. package/config.ts +0 -3137
  139. package/constants.ts +0 -943
  140. package/core.ts +0 -1473
  141. package/crossbrowser.ts +0 -1359
  142. package/dashdone.ts +0 -605
  143. package/data.ts +0 -943
  144. package/database.ts +0 -133
  145. package/debug.ts +0 -850
  146. package/deno.ts +0 -27
  147. package/devthink.ts +0 -707
  148. package/dist/accounts.d.ts +0 -409
  149. package/dist/agent.d.ts +0 -837
  150. package/dist/antigravity.d.ts +0 -380
  151. package/dist/apifreeze.d.ts +0 -113
  152. package/dist/auth.d.ts +0 -224
  153. package/dist/capture.d.ts +0 -595
  154. package/dist/cjs.d.ts +0 -6
  155. package/dist/commands.d.ts +0 -310
  156. package/dist/compatibility.d.ts +0 -17
  157. package/dist/config.d.ts +0 -1853
  158. package/dist/constants.d.ts +0 -637
  159. package/dist/core.d.ts +0 -361
  160. package/dist/data.d.ts +0 -330
  161. package/dist/database.d.ts +0 -24
  162. package/dist/debug.d.ts +0 -270
  163. package/dist/engine.d.ts +0 -74
  164. package/dist/environments.d.ts +0 -244
  165. package/dist/evidence.d.ts +0 -277
  166. package/dist/export.d.ts +0 -311
  167. package/dist/fingerprint.d.ts +0 -594
  168. package/dist/flow.d.ts +0 -300
  169. package/dist/gates.d.ts +0 -103
  170. package/dist/identity.d.ts +0 -51
  171. package/dist/ids.d.ts +0 -7
  172. package/dist/llm.d.ts +0 -652
  173. package/dist/models.d.ts +0 -1807
  174. package/dist/net.d.ts +0 -325
  175. package/dist/neutral.d.ts +0 -41
  176. package/dist/oauth.d.ts +0 -703
  177. package/dist/page.d.ts +0 -1166
  178. package/dist/perf.d.ts +0 -481
  179. package/dist/plan.d.ts +0 -134
  180. package/dist/project.d.ts +0 -395
  181. package/dist/providers.d.ts +0 -37
  182. package/dist/quota.d.ts +0 -453
  183. package/dist/recovery.d.ts +0 -621
  184. package/dist/request.d.ts +0 -1492
  185. package/dist/run.d.ts +0 -779
  186. package/dist/runtime.d.ts +0 -212
  187. package/dist/search.d.ts +0 -375
  188. package/dist/security.d.ts +0 -534
  189. package/dist/serve.d.ts +0 -136
  190. package/dist/session.d.ts +0 -296
  191. package/dist/storage.d.ts +0 -53
  192. package/dist/streaming.d.ts +0 -1119
  193. package/dist/swarm.d.ts +0 -328
  194. package/dist/tools.d.ts +0 -170
  195. package/dist/types.d.ts +0 -8357
  196. package/dist/utils.d.ts +0 -82
  197. package/dist/version.d.ts +0 -7
  198. package/dist/versionregistry.d.ts +0 -406
  199. package/dist/views.d.ts +0 -579
  200. package/dist/workbenchsession.d.ts +0 -69
  201. package/dist/workflow.d.ts +0 -649
  202. package/docs/readme.md +0 -92
  203. package/docs/schemas/antigravity.json +0 -192
  204. package/engine.ts +0 -1524
  205. package/environments.ts +0 -1005
  206. package/evidence.ts +0 -643
  207. package/export.ts +0 -889
  208. package/fingerprint.ts +0 -1458
  209. package/flow.ts +0 -1190
  210. package/gates.ts +0 -307
  211. package/gateway.ts +0 -34
  212. package/hardening.ts +0 -191
  213. package/headless.ts +0 -369
  214. package/http.ts +0 -2110
  215. package/identity.ts +0 -246
  216. package/ids.ts +0 -26
  217. package/index.ts +0 -369
  218. package/llm.ts +0 -2682
  219. package/mcp.ts +0 -1835
  220. package/models.ts +0 -3805
  221. package/modes.ts +0 -43
  222. package/net.ts +0 -1214
  223. package/neutral.ts +0 -362
  224. package/node.ts +0 -26
  225. package/oauth.ts +0 -2216
  226. package/offscreen.ts +0 -170
  227. package/pack.ts +0 -956
  228. package/page.ts +0 -7824
  229. package/pagebridge.ts +0 -1116
  230. package/perf.ts +0 -957
  231. package/plan.ts +0 -672
  232. package/plugin.ts +0 -76
  233. package/prisma.config.ts +0 -27
  234. package/progress.ts +0 -1308
  235. package/project.ts +0 -1291
  236. package/protocol.ts +0 -4187
  237. package/providers.ts +0 -246
  238. package/quota.ts +0 -1887
  239. package/recovery.ts +0 -2433
  240. package/request.ts +0 -4482
  241. package/run.ts +0 -2135
  242. package/runtime.ts +0 -526
  243. package/search.ts +0 -1760
  244. package/security.ts +0 -1673
  245. package/serve.ts +0 -419
  246. package/server.ts +0 -5538
  247. package/session.ts +0 -1162
  248. package/storage.ts +0 -182
  249. package/streaming.ts +0 -4101
  250. package/swarm.ts +0 -884
  251. package/sync.ts +0 -56
  252. package/tests/agentcert.test.ts +0 -128
  253. package/tests/agentfleet.test.ts +0 -214
  254. package/tests/agentreview.test.ts +0 -241
  255. package/tests/agentstream.test.ts +0 -335
  256. package/tests/agentwork.test.ts +0 -356
  257. package/tests/apifreeze.test.ts +0 -290
  258. package/tests/apimap.test.ts +0 -112
  259. package/tests/approvalgate.test.ts +0 -175
  260. package/tests/artifactmanifest.test.ts +0 -204
  261. package/tests/attentionfeed.test.ts +0 -163
  262. package/tests/backgroundruns.test.ts +0 -100
  263. package/tests/batchscheduling.test.ts +0 -131
  264. package/tests/blackboard.test.ts +0 -238
  265. package/tests/bridge.test.ts +0 -1088
  266. package/tests/browsercoverage.test.ts +0 -134
  267. package/tests/browserpolyfills.test.ts +0 -124
  268. package/tests/build.mjs +0 -1260
  269. package/tests/clientauth.test.ts +0 -223
  270. package/tests/clitools.test.ts +0 -578
  271. package/tests/confirmgates.test.ts +0 -190
  272. package/tests/containerpack.test.ts +0 -143
  273. package/tests/controlflow.test.ts +0 -2120
  274. package/tests/coordination.test.ts +0 -345
  275. package/tests/copyscreen.test.ts +0 -139
  276. package/tests/core.test.ts +0 -417
  277. package/tests/costcert.test.ts +0 -95
  278. package/tests/crossbrowser.test.ts +0 -115
  279. package/tests/cspaudit.test.ts +0 -79
  280. package/tests/dashdone.test.ts +0 -615
  281. package/tests/datagrid.test.ts +0 -137
  282. package/tests/doccheck.test.ts +0 -107
  283. package/tests/dombatch.test.ts +0 -109
  284. package/tests/emulation.test.ts +0 -282
  285. package/tests/environments.test.ts +0 -259
  286. package/tests/evidenceviews.test.ts +0 -88
  287. package/tests/exporttools.test.ts +0 -185
  288. package/tests/firefoxprep.test.ts +0 -134
  289. package/tests/flowlibrary.test.ts +0 -242
  290. package/tests/flowrun.test.ts +0 -303
  291. package/tests/forensics.test.ts +0 -439
  292. package/tests/gateway.test.ts +0 -939
  293. package/tests/headlesslib.test.ts +0 -171
  294. package/tests/httpstream.test.ts +0 -277
  295. package/tests/immutablelog.test.ts +0 -157
  296. package/tests/inboundguard.test.ts +0 -177
  297. package/tests/lazyload.test.ts +0 -72
  298. package/tests/librarymodes.test.ts +0 -623
  299. package/tests/llm.test.ts +0 -696
  300. package/tests/manifest.test.ts +0 -226
  301. package/tests/maskinputs.test.ts +0 -150
  302. package/tests/matrixverify.test.ts +0 -111
  303. package/tests/mavenpack.test.ts +0 -75
  304. package/tests/mcpserver.test.ts +0 -704
  305. package/tests/memory.test.ts +0 -4155
  306. package/tests/memorycare.test.ts +0 -230
  307. package/tests/migrateplan.test.ts +0 -349
  308. package/tests/minimization.test.ts +0 -414
  309. package/tests/modelroute.test.ts +0 -112
  310. package/tests/multiagent.test.ts +0 -440
  311. package/tests/nativebridge.test.ts +0 -807
  312. package/tests/navigation.test.ts +0 -284
  313. package/tests/nugetpack.test.ts +0 -83
  314. package/tests/orchestration.test.ts +0 -449
  315. package/tests/originpolicy.test.ts +0 -405
  316. package/tests/outputcompare.test.ts +0 -97
  317. package/tests/package.test.ts +0 -91
  318. package/tests/pagebridge.test.ts +0 -5909
  319. package/tests/pentest.test.ts +0 -75
  320. package/tests/perfrecords.test.ts +0 -257
  321. package/tests/permdiff.test.ts +0 -85
  322. package/tests/phishguard.test.ts +0 -128
  323. package/tests/pickerviews.test.ts +0 -155
  324. package/tests/pipelines.test.ts +0 -381
  325. package/tests/planlint.test.ts +0 -240
  326. package/tests/planreview.test.ts +0 -383
  327. package/tests/platformtargets.test.ts +0 -56
  328. package/tests/policy.test.ts +0 -8284
  329. package/tests/portability.test.ts +0 -96
  330. package/tests/progress.test.ts +0 -1036
  331. package/tests/promptlibrary.test.ts +0 -116
  332. package/tests/protocol.test.ts +0 -4793
  333. package/tests/publishingpipeline.test.ts +0 -314
  334. package/tests/quickactions.test.ts +0 -164
  335. package/tests/readiness.test.ts +0 -78
  336. package/tests/recipes.test.ts +0 -163
  337. package/tests/redactshots.test.ts +0 -216
  338. package/tests/registernvidiakeys.ts +0 -51
  339. package/tests/relayserve.test.ts +0 -304
  340. package/tests/releasenotes.test.ts +0 -276
  341. package/tests/resilience.test.ts +0 -467
  342. package/tests/resourceaware.test.ts +0 -187
  343. package/tests/runbudget.test.ts +0 -125
  344. package/tests/runhistory.test.ts +0 -299
  345. package/tests/runreplay.test.ts +0 -113
  346. package/tests/runresume.test.ts +0 -184
  347. package/tests/runstate.test.ts +0 -288
  348. package/tests/runtimeadapters.test.ts +0 -251
  349. package/tests/safariskeleton.test.ts +0 -115
  350. package/tests/sandboxframe.test.ts +0 -196
  351. package/tests/sbom.test.ts +0 -105
  352. package/tests/secretvault.test.ts +0 -188
  353. package/tests/selcache.test.ts +0 -111
  354. package/tests/sessioninterface.test.ts +0 -791
  355. package/tests/sessions.test.ts +0 -591
  356. package/tests/siteprefs.test.ts +0 -228
  357. package/tests/snapshotdelta.test.ts +0 -165
  358. package/tests/statusviews.test.ts +0 -237
  359. package/tests/stepmeter.test.ts +0 -200
  360. package/tests/streamparse.test.ts +0 -163
  361. package/tests/stylepruning.test.ts +0 -90
  362. package/tests/surfaces.test.ts +0 -282
  363. package/tests/sweep.test.ts +0 -78
  364. package/tests/syncbridge.test.ts +0 -164
  365. package/tests/taskqueue.test.ts +0 -206
  366. package/tests/toolcalls.test.ts +0 -336
  367. package/tests/toolcatalog.test.ts +0 -201
  368. package/tests/torture-agent.test.ts +0 -706
  369. package/tests/torture-auth.test.ts +0 -461
  370. package/tests/torture-commands.test.ts +0 -895
  371. package/tests/torture-data.test.ts +0 -923
  372. package/tests/torture-environments.test.ts +0 -285
  373. package/tests/torture-export.test.ts +0 -263
  374. package/tests/torture-http.test.ts +0 -1379
  375. package/tests/torture-llm.test.ts +0 -808
  376. package/tests/torture-memory.test.ts +0 -1084
  377. package/tests/torture-plan.test.ts +0 -829
  378. package/tests/torture-run.test.ts +0 -626
  379. package/tests/torture-session.test.ts +0 -928
  380. package/tests/torture-swarm.test.ts +0 -1245
  381. package/tests/torture-tools.test.ts +0 -964
  382. package/tests/torture-workflow.test.ts +0 -2354
  383. package/tests/tourviews.test.ts +0 -52
  384. package/tests/transparency.test.ts +0 -147
  385. package/tests/trigger.test.ts +0 -941
  386. package/tests/v1sunset.test.ts +0 -428
  387. package/tests/virtlist.test.ts +0 -94
  388. package/tests/vision.test.ts +0 -540
  389. package/tests/vsixpack.test.ts +0 -145
  390. package/tests/webapi.test.ts +0 -523
  391. package/tests/workflow.test.ts +0 -1785
  392. package/tests/workfloweditor.test.ts +0 -759
  393. package/tests/xpipack.test.ts +0 -128
  394. package/tools.ts +0 -734
  395. package/types.ts +0 -9908
  396. package/umd.ts +0 -9
  397. package/utils.ts +0 -249
  398. package/version.ts +0 -8
  399. package/versionregistry.ts +0 -1310
  400. package/views.ts +0 -2153
  401. package/vitest.config.ts +0 -12
  402. package/web/App.tsx +0 -78
  403. package/web/README.md +0 -47
  404. package/web/capacitor.config.ts +0 -46
  405. package/web/const.ts +0 -19
  406. package/web/control.shell.tsx +0 -66
  407. package/web/dashboardpage.ts +0 -554
  408. package/web/db.ts +0 -493
  409. package/web/design.html +0 -541
  410. package/web/gatewayview/Gateway.tsx +0 -345
  411. package/web/gatewayview/config.ts +0 -1042
  412. package/web/gatewayview/definition.ts +0 -174
  413. package/web/icons.ts +0 -15
  414. package/web/optionspage.ts +0 -691
  415. package/web/popup.ts +0 -1651
  416. package/web/schema.prisma +0 -176
  417. package/web/sidepanel.ts +0 -7941
  418. package/web/sitemanifest.json +0 -13
  419. package/web/terminal-ui.tsx +0 -622
  420. package/web/transparencypage.ts +0 -541
  421. package/web/vite.config.ts +0 -39
  422. package/web/workspace.ts +0 -23
  423. package/workbenchmemory.ts +0 -104
  424. package/workbenchsession.ts +0 -304
  425. package/workflow.ts +0 -4495
  426. /package/{dist/bun.d.ts → bun.d.ts} +0 -0
  427. /package/{dist/cli.d.ts → cli.d.ts} +0 -0
  428. /package/{dist/companion.d.ts → companion.d.ts} +0 -0
  429. /package/{dist/crossbrowser.d.ts → crossbrowser.d.ts} +0 -0
  430. /package/{dist/dashdone.d.ts → dashdone.d.ts} +0 -0
  431. /package/{dist/deno.d.ts → deno.d.ts} +0 -0
  432. /package/{dist/hardening.d.ts → hardening.d.ts} +0 -0
  433. /package/{dist/headless.d.ts → headless.d.ts} +0 -0
  434. /package/{dist/http.d.ts → http.d.ts} +0 -0
  435. /package/{dist/index.d.ts → index.d.ts} +0 -0
  436. /package/{dist/mcp.d.ts → mcp.d.ts} +0 -0
  437. /package/{dist/memory.d.ts → memory.d.ts} +0 -0
  438. /package/{dist/node.d.ts → node.d.ts} +0 -0
  439. /package/{dist/pack.d.ts → pack.d.ts} +0 -0
  440. /package/{dist/policy.d.ts → policy.d.ts} +0 -0
  441. /package/{dist/progress.d.ts → progress.d.ts} +0 -0
  442. /package/{dist/protocol.d.ts → protocol.d.ts} +0 -0
  443. /package/{dist/server.d.ts → server.d.ts} +0 -0
  444. /package/{dist/umd.d.ts → umd.d.ts} +0 -0
@@ -1,1310 +0,0 @@
1
- /* ── Merged: the grand merge section ── the correlated antigravity version resolution logics of the merged repository interned here, one surface without duplicate variations ── */
2
- /**
3
- * @module versions/registry
4
- * @description
5
- * Dynamic Antigravity version resolver of the merged repository
6
- * (merged superset of the two prior variants).
7
- *
8
- * Two complementary resolution chains are unified here:
9
- *
10
- * Legacy chain (4 tiers):
11
- * 1. Remote auto-updater manifests (linux_amd64.json / ide updater API)
12
- * 2. Changelog scrape (antigravity.google.com, cloud.google.com, updater)
13
- * 3. Stale disk cache (~/.config/opencode/antigravity-version.json)
14
- * 4. Hardcoded fallback 1.15.8 / 2.0.11
15
- *
16
- * Observer chain (replicating Antigravity Manager startup):
17
- * 1. Memory Map cache (6h TTL)
18
- * 2. Remote registries: npm registry, GitHub Releases, storage.googleapis
19
- * 3. Local cache file written atomically (tmp + rename, chmod 0600)
20
- * 4. Governed fallback 1.19.2 (>= min supported, not blocked)
21
- *
22
- * Governance constants: ANTIGRAVITY_BLOCKED_VERSIONS hard-ban list,
23
- * ANTIGRAVITY_VERSION_MIN_SUPPORTED ("1.15.8") and semver utilities
24
- * (cleanSemver / compareSemver / shouldUpdate / isValidSemver /
25
- * isBlockedVersion / isSupportedVersion).
26
- *
27
- * Reconciliation notes:
28
- * - getVersion()/getVersionSync() accept BOTH call shapes (no args or options
29
- * object) and consult both chains plus both cache stores. The observer
30
- * chain is gated by min-supported/blocked checks; legacy chain results are
31
- * honored unless explicitly blocked. When everything fails offline, the
32
- * governed fallback 1.19.2 is returned by the merged getters, while the
33
- * dedicated legacy getters (getVersionInfo*, fetchAntigravityVersion) keep
34
- * their original 1.15.8 fallback untouched.
35
- * - Cache persistence uses atomic tmp-file + rename with chmod 0600.
36
- *
37
- * Runtime: only node:* builtins + global fetch. Zero external deps. The
38
- * registry is server and cli surface — the neutral core barrel never
39
- * carries it, so the browser bundles stay free of node imports.
40
- *
41
- * @license MIT
42
- */
43
-
44
- import * as fs from "node:fs";
45
- import * as fsp from "node:fs/promises";
46
- import * as path from "node:path";
47
- import * as os from "node:os";
48
- import * as crypto from "node:crypto";
49
-
50
- // Deduplicated against the frozen owner (constants.ts): symbols whose local
51
- // definitions were value-identical are imported and re-exported below, so each
52
- // has exactly one definition (library dedupe task 2-d1).
53
- import {
54
- ANTIGRAVITY_VERSION_FALLBACK,
55
- ANTIGRAVITY_VERSION_MIN_SUPPORTED,
56
- ANTIGRAVITY_BLOCKED_VERSIONS,
57
- ANTIGRAVITY_VERSION_REMOTE_URLS,
58
- VERSION_FETCH_TIMEOUT_MS,
59
- FETCH_TIMEOUT_MS,
60
- GEMINI_CLI_OAUTH_CLIENT_ID,
61
- GEMINI_CLI_OAUTH_CLIENT_SECRET,
62
- GEMINI_CLI_SCOPES,
63
- GEMINI_CLI_USER_AGENT,
64
- CLIENT_METADATA_STRING,
65
- CLOUDCODE_BASE_URL,
66
- CODE_ASSIST_PATH_MAP,
67
- PROJECT_FALLBACK,
68
- } from "./constants.js";
69
- // v2.1.16 single-owner fix: the MODELS_2026 reference list comes from
70
- // models.js (model identification owner — the 11-id legacy list).
71
- import { MODELS_2026_LEGACY as MODELS_2026_REFERENCE } from "./models.js";
72
- import { X_GOOG_API_CLIENT_GEMINI_CLI } from "./fingerprint.js";
73
- import { fetchWithTimeout } from "./core.js";
74
- import { isValidSemver } from "./config.js";
75
- export { isValidSemver };
76
-
77
- // Re-exports preserve this module's public surface after the dedupe.
78
- export {
79
- ANTIGRAVITY_VERSION_FALLBACK,
80
- ANTIGRAVITY_VERSION_MIN_SUPPORTED,
81
- ANTIGRAVITY_BLOCKED_VERSIONS,
82
- ANTIGRAVITY_VERSION_REMOTE_URLS,
83
- VERSION_FETCH_TIMEOUT_MS,
84
- };
85
-
86
- // ---------------------------------------------------------------------------
87
- // Section: Constants / fallbacks (legacy chain)
88
- // ---------------------------------------------------------------------------
89
-
90
- /**
91
- * Official Antigravity auto-updater endpoints (same infra as Gemini CLI /
92
- * Antigravity IDE). Both return JSON with `version` shaped "1.15.8-57246...".
93
- */
94
- export const REMOTE_MANIFEST_URLS = [
95
- "https://antigravity-auto-updater-974169037036.us-central1.run.app/manifests/linux_amd64.json",
96
- "https://antigravity-ide-auto-updater-974169037036.us-central1.run.app/api/update/linux/x64/stable/0",
97
- ] as const;
98
-
99
- /** Changelog URLs for secondary scrape when manifests fail. */
100
- export const CHANGELOG_URLS = [
101
- "https://antigravity.google.com/docs/changelog",
102
- "https://antigravity.google.com/changelog",
103
- "https://cloud.google.com/antigravity/docs/release-notes",
104
- "https://antigravity-auto-updater-974169037036.us-central1.run.app/changelog",
105
- ] as const;
106
-
107
- /** Hardened fallback - last known stable IDE version. */
108
- export const FALLBACK_VERSION = "1.15.8" as const;
109
- export const FALLBACK_FULL_VERSION = "1.15.8-5724687216017408" as const;
110
-
111
- /** Alternative fallback - CLI/Antigravity v2 track compatibility. */
112
- export const FALLBACK_ALTERNATIVE_VERSION = "2.0.11" as const;
113
- export const FALLBACK_ALTERNATIVE_FULL = "2.0.11-0000000000000000" as const;
114
-
115
- /** Legacy cache TTL: 6 hours in ms. */
116
- export const VERSION_CACHE_TTL_MS = 6 * 60 * 60 * 1000;
117
-
118
- /** Legacy cache file location - XDG style. */
119
- export const VERSION_CACHE_FILE = path.join(os.homedir(), ".config", "opencode", "antigravity-version.json");
120
-
121
- /** Default fetch timeout. */
122
- // local variant: diverges from models (5s legacy-chain default vs models' 10s FETCH_TIMEOUT_MS)
123
-
124
- // ---------------------------------------------------------------------------
125
- // Section: Constants / governance (observer chain)
126
- // ---------------------------------------------------------------------------
127
-
128
- /**
129
- * Governed fallback version, verified safe on 2026-08-25:
130
- * versions below 1.15.8 are banned; 1.19.2 avoids the forced-update prompt.
131
- */
132
- // ANTIGRAVITY_VERSION_FALLBACK / ANTIGRAVITY_VERSION_MIN_SUPPORTED /
133
- // ANTIGRAVITY_BLOCKED_VERSIONS / ANTIGRAVITY_VERSION_REMOTE_URLS /
134
- // VERSION_FETCH_TIMEOUT_MS: identical values — imported and re-exported above.
135
-
136
- /** Observer memory cache TTL - 6h. */
137
- export const VERSION_MEMORY_TTL_MS = 6 * 60 * 60 * 1000;
138
-
139
- /** Observer file cache TTL - 24h before considered stale (still usable). */
140
- export const VERSION_FILE_TTL_MS = 24 * 60 * 60 * 1000;
141
-
142
- const OBSERVER_CACHE_FILE_NAME = "antigravity-version.json";
143
- const OBSERVER_FILE_MODE = 0o600;
144
- const OBSERVER_DIR_MODE = 0o755;
145
- const MEMORY_CACHE_KEY = "latest";
146
-
147
- const SEMVER_RE = /^(\d+)\.(\d+)\.(\d+)(?:-[\w.-]+)?(?:\+[\w.-]+)?$/;
148
- const SEMVER_EXTRACT_RE = /(\d+\.\d+\.\d+(?:-[\w.-]+)?(?:\+[\w.-]+)?)/;
149
-
150
- // ---------------------------------------------------------------------------
151
- // Section: Auth constants (plugin integration reference, not used in fetch)
152
- // v2.1.16 single-owner fix: every member is imported from its owner
153
- // (constants.js raw values; models.js for the model-id list) — the former
154
- // local literals were byte-identical duplicates.
155
- // ---------------------------------------------------------------------------
156
-
157
- export const ANTIGRAVITY_AUTH_CONSTANTS = {
158
- CLIENT_ID: GEMINI_CLI_OAUTH_CLIENT_ID,
159
- CLIENT_SECRET: GEMINI_CLI_OAUTH_CLIENT_SECRET,
160
- SCOPES: GEMINI_CLI_SCOPES,
161
- /** UA templates - production should vary platform dynamically.
162
- * v2.1.16: derived from the canonical full UA by platform substitution
163
- * (single owner: constants.GEMINI_CLI_USER_AGENT). */
164
- USER_AGENT_TEMPLATES: {
165
- darwin_arm64: GEMINI_CLI_USER_AGENT.replace("(linux; x64; GitHub)", "(darwin; arm64; GitHub)"),
166
- darwin_x64: GEMINI_CLI_USER_AGENT.replace("(linux; x64; GitHub)", "(darwin; x64; GitHub)"),
167
- linux_x64: GEMINI_CLI_USER_AGENT,
168
- win32_x64: GEMINI_CLI_USER_AGENT.replace("(linux; x64; GitHub)", "(win32; x64; GitHub)"),
169
- },
170
- X_GOOG_API_CLIENT: X_GOOG_API_CLIENT_GEMINI_CLI,
171
- CLIENT_METADATA: CLIENT_METADATA_STRING,
172
- ENDPOINT_BASE: CLOUDCODE_BASE_URL,
173
- ENDPOINTS: CODE_ASSIST_PATH_MAP,
174
- PROJECT_FALLBACK: PROJECT_FALLBACK,
175
- MODELS_2026: MODELS_2026_REFERENCE,
176
- } as const;
177
-
178
- // ---------------------------------------------------------------------------
179
- // Section: Types
180
- // ---------------------------------------------------------------------------
181
-
182
- export type VersionSource =
183
- | "remote-manifest"
184
- | "ide-updater"
185
- | "changelog"
186
- | "cache-file"
187
- | "memory-cache"
188
- | "hardcoded-fallback";
189
-
190
- export interface AntigravityVersionInfo {
191
- /** Normalized version without build metadata, e.g. "1.15.8" */
192
- version: string;
193
- /** Full original version, e.g. "1.15.8-5724687216017408" */
194
- fullVersion: string;
195
- /** Where this version came from */
196
- source: VersionSource;
197
- /** Epoch ms */
198
- fetchedAt: number;
199
- /** Computed expiration */
200
- expiresAt: number;
201
- /** Optional URL that produced the version */
202
- url?: string;
203
- }
204
-
205
- /** Observer memory-cache entry shape. */
206
- export interface CacheEntry {
207
- version: string;
208
- fetchedAt: number; // epoch ms
209
- source: string; // url or "file" or "memory"
210
- }
211
-
212
- /** Observer on-disk cache file shape. */
213
- export interface VersionCacheFile {
214
- version: string;
215
- fetchedAt: number;
216
- source: string;
217
- expiresAt: number;
218
- }
219
-
220
- /** Observer fetch overrides. */
221
- export interface FetchOptions {
222
- /** Timeout per request ms - defaults to 5000 */
223
- timeoutMs?: number;
224
- /** Force remote fetch bypassing memory cache */
225
- force?: boolean;
226
- /** Custom remote URLs override (testing) */
227
- remoteUrls?: readonly string[];
228
- /** Custom cache path override */
229
- cachePath?: string;
230
- /** Extra User-Agent header value (GitHub rate-limit friendly) */
231
- userAgent?: string;
232
- }
233
-
234
- export interface GetVersionOptions extends FetchOptions {
235
- /** Allow returning stale file cache when remote fails - default true */
236
- allowStale?: boolean;
237
- }
238
-
239
- /** Shape persisted on disk for the legacy chain. */
240
- interface CachedFilePayload extends AntigravityVersionInfo {}
241
-
242
- // ---------------------------------------------------------------------------
243
- // Section: Internal state (legacy memory cache + dedup, observer Map)
244
- // ---------------------------------------------------------------------------
245
-
246
- let memoryCache: AntigravityVersionInfo | null = null;
247
- let inflightPromise: Promise<AntigravityVersionInfo> | null = null;
248
-
249
- /**
250
- * Observer memory cache keyed by MEMORY_CACHE_KEY ("latest").
251
- * Exported for introspection/testing; treat as read-only in production.
252
- */
253
- export const versionMemoryCache = new Map<string, CacheEntry>();
254
-
255
- // ---------------------------------------------------------------------------
256
- // Section: Semver utilities (observer chain, dependency-free)
257
- // ---------------------------------------------------------------------------
258
-
259
- /** Validates strict semver shape. */
260
- // v2.1.15 Phase C: isValidSemver moved to config.js (validator owner) — re-exported below.
261
-
262
- /**
263
- * Extracts the first semver token from dirty input such as "v1.19.2" or
264
- * "antigravity/1.19.2 darwin/arm64".
265
- * @returns cleaned semver or null
266
- */
267
- export function cleanSemver(raw: unknown): string | null {
268
- if (!raw || typeof raw !== "string") return null;
269
- const trimmed = raw.trim();
270
- if (SEMVER_RE.test(trimmed)) return trimmed;
271
- const m = trimmed.match(SEMVER_EXTRACT_RE);
272
- if (m && m[1] && SEMVER_RE.test(m[1])) return m[1];
273
- return null;
274
- }
275
-
276
- /**
277
- * Compares two semver strings.
278
- * @returns -1 if a < b, 0 if equal, 1 if a > b (invalid sorts lowest)
279
- */
280
- export function compareSemver(a: string, b: string): -1 | 0 | 1 {
281
- const ca = cleanSemver(a);
282
- const cb = cleanSemver(b);
283
- if (!ca && !cb) return 0;
284
- if (!ca) return -1;
285
- if (!cb) return 1;
286
-
287
- const pa = ca.split(/[.-]/);
288
- const pb = cb.split(/[.-]/);
289
-
290
- for (let i = 0; i < 3; i++) {
291
- const na = Number.parseInt(pa[i] ?? "0", 10);
292
- const nb = Number.parseInt(pb[i] ?? "0", 10);
293
- if (Number.isNaN(na) || Number.isNaN(nb)) continue;
294
- if (na < nb) return -1;
295
- if (na > nb) return 1;
296
- }
297
- // Prerelease suffix ordering: 1.19.2-preview < 1.19.2
298
- const hasPreA = ca.includes("-");
299
- const hasPreB = cb.includes("-");
300
- if (hasPreA && !hasPreB) return -1;
301
- if (!hasPreA && hasPreB) return 1;
302
- return 0;
303
- }
304
-
305
- /** True when latest > current - triggers an update notification. */
306
- export function shouldUpdate(current: string, latest: string): boolean {
307
- const c = cleanSemver(current);
308
- const l = cleanSemver(latest);
309
- if (!c || !l) return false;
310
- return compareSemver(c, l) === -1;
311
- }
312
-
313
- /** Checks whether a version is on the hard block list. */
314
- export function isBlockedVersion(v: string): boolean {
315
- const cleaned = cleanSemver(v);
316
- if (!cleaned) return false;
317
- return (ANTIGRAVITY_BLOCKED_VERSIONS as readonly string[]).includes(cleaned);
318
- }
319
-
320
- /** True when version >= min supported and not blocked. */
321
- export function isSupportedVersion(v: string): boolean {
322
- const cleaned = cleanSemver(v);
323
- if (!cleaned) return false;
324
- if (isBlockedVersion(cleaned)) return false;
325
- return compareSemver(cleaned, ANTIGRAVITY_VERSION_MIN_SUPPORTED) >= 0;
326
- }
327
-
328
- // ---------------------------------------------------------------------------
329
- // Section: Payload parsing - heterogeneous JSON shapes (npm/GitHub/GCS)
330
- // ---------------------------------------------------------------------------
331
-
332
- /**
333
- * Extracts a version from unknown JSON payload shapes:
334
- * npm `{version}`, GitHub `{tag_name}` / `{name}`, GCS `{version|latest|
335
- * latestVersion}`, nested `{data:{version}}`; falls back to regex over the
336
- * serialized payload.
337
- */
338
- export function parseVersionFromPayload(payload: unknown): string | null {
339
- if (!payload || typeof payload !== "object") return null;
340
- const obj = payload as Record<string, unknown>;
341
-
342
- const candidates: unknown[] = [
343
- obj["version"],
344
- obj["latestVersion"],
345
- obj["latest"],
346
- obj["tag_name"],
347
- obj["name"],
348
- (obj["data"] as Record<string, unknown> | undefined)?.["version"],
349
- (obj["data"] as Record<string, unknown> | undefined)?.["latestVersion"],
350
- ];
351
-
352
- for (const cand of candidates) {
353
- if (typeof cand === "string") {
354
- const cleaned = cleanSemver(cand);
355
- if (cleaned) return cleaned;
356
- }
357
- }
358
-
359
- try {
360
- const asString = JSON.stringify(payload);
361
- const m = asString.match(SEMVER_EXTRACT_RE);
362
- if (m && m[1]) {
363
- const cleaned = cleanSemver(m[1]);
364
- if (cleaned) return cleaned;
365
- }
366
- } catch {
367
- // ignore
368
- }
369
- return null;
370
- }
371
-
372
- // ---------------------------------------------------------------------------
373
- // Section: Helpers (legacy chain)
374
- // ---------------------------------------------------------------------------
375
-
376
- /**
377
- * Parses "1.15.8-5724687216017408" into normalized + full forms,
378
- * keeping a safe fallback when the regex does not match.
379
- */
380
- export function parseAntigravityVersion(raw: string): {
381
- normalized: string;
382
- full: string;
383
- } {
384
- if (!raw || typeof raw !== "string") {
385
- return { normalized: FALLBACK_VERSION, full: FALLBACK_FULL_VERSION };
386
- }
387
- const trimmed = raw.trim();
388
- const m = trimmed.match(/(\d+\.\d+\.\d+(?:\.\d+)?)/);
389
- if (!m) {
390
- const cleaned = trimmed.replace(/[^0-9.\-]/g, "");
391
- return {
392
- normalized: cleaned.split("-")[0] || FALLBACK_VERSION,
393
- full: trimmed,
394
- };
395
- }
396
- return { normalized: m[1] || FALLBACK_VERSION, full: trimmed };
397
- }
398
-
399
- /**
400
- * Fetch with timeout via AbortController (global fetch, Node 18+).
401
- * Injects Gemini-CLI-like baseline headers; caller headers take precedence.
402
- */
403
- // local variant: diverges from models (injects Gemini-CLI baseline headers; no external-signal merge; 5s default)
404
-
405
- /** Ensures the legacy cache directory exists. */
406
- function ensureCacheDirSync(): void {
407
- try {
408
- const dir = path.dirname(VERSION_CACHE_FILE);
409
- if (!fs.existsSync(dir)) {
410
- fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
411
- }
412
- } catch {
413
- // silent - disk may be read-only, memory cache still works
414
- }
415
- }
416
-
417
- /** Reads the legacy cache from disk synchronously when valid. */
418
- export function readCacheFileSync(): AntigravityVersionInfo | null {
419
- try {
420
- if (!fs.existsSync(VERSION_CACHE_FILE)) return null;
421
- const raw = fs.readFileSync(VERSION_CACHE_FILE, "utf8");
422
- const parsed = JSON.parse(raw) as CachedFilePayload;
423
- if (!parsed.version || !parsed.fetchedAt) return null;
424
- if (Date.now() > parsed.expiresAt) return null;
425
- return parsed;
426
- } catch {
427
- return null;
428
- }
429
- }
430
-
431
- /** Reads the legacy cache from disk asynchronously. */
432
- export async function readCacheFile(): Promise<AntigravityVersionInfo | null> {
433
- try {
434
- await fs.promises.access(VERSION_CACHE_FILE, fs.constants.R_OK);
435
- const raw = await fs.promises.readFile(VERSION_CACHE_FILE, "utf8");
436
- const parsed = JSON.parse(raw) as CachedFilePayload;
437
- if (!parsed.version || !parsed.fetchedAt) return null;
438
- if (Date.now() > parsed.expiresAt) return null;
439
- return { ...parsed, source: "cache-file" };
440
- } catch {
441
- return null;
442
- }
443
- }
444
-
445
- /**
446
- * Writes the legacy cache file atomically: content goes to a unique temp
447
- * file (chmod 0600), then rename over the destination. Best-effort, never
448
- * throws into the caller.
449
- */
450
- export async function writeCacheFile(info: AntigravityVersionInfo): Promise<void> {
451
- const dir = path.dirname(VERSION_CACHE_FILE);
452
- try {
453
- ensureCacheDirSync();
454
- const payload: CachedFilePayload = { ...info };
455
- const content = JSON.stringify(payload, null, 2);
456
- const rand = crypto.randomBytes(6).toString("hex");
457
- const tmp = path.join(dir, `.${path.basename(VERSION_CACHE_FILE)}.${process.pid}.${rand}.tmp`);
458
- try {
459
- await fsp.writeFile(tmp, content, { encoding: "utf8", mode: 0o600 });
460
- try {
461
- await fsp.chmod(tmp, 0o600);
462
- } catch {
463
- /* best effort */
464
- }
465
- await fsp.rename(tmp, VERSION_CACHE_FILE);
466
- try {
467
- await fsp.chmod(VERSION_CACHE_FILE, 0o600);
468
- } catch {
469
- /* best effort */
470
- }
471
- } finally {
472
- try {
473
- await fsp.unlink(tmp);
474
- } catch {
475
- /* temp may not exist anymore */
476
- }
477
- }
478
- } catch {
479
- // ignore - memory cache still works
480
- }
481
- }
482
-
483
- // ---------------------------------------------------------------------------
484
- // Section: Observer filesystem helpers
485
- // ---------------------------------------------------------------------------
486
-
487
- /**
488
- * Resolves the observer cache dir, honoring OPENCODE_CONFIG_DIR and
489
- * XDG_CONFIG_HOME (same contract as config.ts).
490
- */
491
- function resolveConfigDir(): string {
492
- const envDir = process.env.OPENCODE_CONFIG_DIR?.trim();
493
- if (envDir) return envDir;
494
- const xdg = process.env.XDG_CONFIG_HOME?.trim();
495
- if (xdg) return path.join(xdg, "opencode");
496
- return path.join(os.homedir(), ".config", "opencode");
497
- }
498
-
499
- function resolveObserverCachePath(customPath?: string): string {
500
- if (customPath?.trim()) return path.resolve(customPath.trim());
501
- return path.join(resolveConfigDir(), OBSERVER_CACHE_FILE_NAME);
502
- }
503
-
504
- async function readObserverCacheFileAsync(cachePath: string): Promise<VersionCacheFile | null> {
505
- try {
506
- await fsp.access(cachePath, fs.constants.F_OK);
507
- } catch {
508
- return null;
509
- }
510
- try {
511
- const text = await fsp.readFile(cachePath, "utf8");
512
- if (!text.trim()) return null;
513
- const parsed = JSON.parse(text) as VersionCacheFile;
514
- const cleaned = cleanSemver(parsed?.version);
515
- if (!cleaned) return null;
516
- return {
517
- version: cleaned,
518
- fetchedAt: typeof parsed.fetchedAt === "number" ? parsed.fetchedAt : Date.now(),
519
- source: typeof parsed.source === "string" ? parsed.source : "file",
520
- expiresAt: typeof parsed.expiresAt === "number" ? parsed.expiresAt : Date.now() + VERSION_FILE_TTL_MS,
521
- };
522
- } catch {
523
- return null;
524
- }
525
- }
526
-
527
- function readObserverCacheFileSync(cachePath: string): VersionCacheFile | null {
528
- try {
529
- fs.accessSync(cachePath, fs.constants.F_OK);
530
- } catch {
531
- return null;
532
- }
533
- try {
534
- const text = fs.readFileSync(cachePath, "utf8");
535
- if (!text.trim()) return null;
536
- const parsed = JSON.parse(text) as VersionCacheFile;
537
- const cleaned = cleanSemver(parsed?.version);
538
- if (!cleaned) return null;
539
- return {
540
- version: cleaned,
541
- fetchedAt: typeof parsed.fetchedAt === "number" ? parsed.fetchedAt : Date.now(),
542
- source: typeof parsed.source === "string" ? parsed.source : "file",
543
- expiresAt: typeof parsed.expiresAt === "number" ? parsed.expiresAt : Date.now() + VERSION_FILE_TTL_MS,
544
- };
545
- } catch {
546
- return null;
547
- }
548
- }
549
-
550
- /**
551
- * Atomic observer cache write: mkdir dir, unique tmp file with mode 0600,
552
- * chmod hardening, rename over destination, tmp cleanup in finally.
553
- */
554
- async function writeObserverCacheFileAtomic(cachePath: string, entry: VersionCacheFile): Promise<void> {
555
- const dir = path.dirname(cachePath);
556
- try {
557
- await fsp.mkdir(dir, { recursive: true, mode: OBSERVER_DIR_MODE });
558
- } catch {
559
- // best effort
560
- }
561
- try {
562
- await fsp.chmod(dir, OBSERVER_DIR_MODE);
563
- } catch {
564
- // ignore chmod failures on some filesystems
565
- }
566
-
567
- const content = JSON.stringify(entry, null, 2) + "\n";
568
- const rand = crypto.randomBytes(6).toString("hex");
569
- const tmp = path.join(dir, `.${path.basename(cachePath)}.${process.pid}.${rand}.tmp`);
570
-
571
- try {
572
- await fsp.writeFile(tmp, content, { encoding: "utf8", mode: OBSERVER_FILE_MODE });
573
- try {
574
- await fsp.chmod(tmp, OBSERVER_FILE_MODE);
575
- } catch {
576
- /* best effort */
577
- }
578
- await fsp.rename(tmp, cachePath);
579
- try {
580
- await fsp.chmod(cachePath, OBSERVER_FILE_MODE);
581
- } catch {
582
- /* best effort */
583
- }
584
- } finally {
585
- try {
586
- await fsp.unlink(tmp);
587
- } catch {
588
- /* temp already renamed */
589
- }
590
- }
591
- }
592
-
593
- // ---------------------------------------------------------------------------
594
- // Section: Remote fetchers - legacy chain (manifests + changelog)
595
- // ---------------------------------------------------------------------------
596
-
597
- /** Chain tier 1a: auto-updater manifests (heterogeneous JSON shapes). */
598
- async function fetchFromManifest(url: string): Promise<AntigravityVersionInfo | null> {
599
- try {
600
- const res = await fetchWithTimeout(url, { method: "GET" });
601
- if (!res.ok) return null;
602
-
603
- const text = await res.text();
604
- let json: any = null;
605
- try {
606
- json = JSON.parse(text);
607
- } catch {
608
- // Response may be plain text containing a version.
609
- const parsed = parseAntigravityVersion(text);
610
- if (parsed.normalized !== FALLBACK_VERSION || text.includes(".")) {
611
- const now = Date.now();
612
- return {
613
- version: parsed.normalized,
614
- fullVersion: parsed.full,
615
- source: url.includes("ide-auto-updater") ? "ide-updater" : "remote-manifest",
616
- fetchedAt: now,
617
- expiresAt: now + VERSION_CACHE_TTL_MS,
618
- url,
619
- };
620
- }
621
- return null;
622
- }
623
-
624
- const candidates: (string | undefined)[] = [
625
- json?.version,
626
- json?.latestVersion,
627
- json?.latest,
628
- json?.stable?.version,
629
- json?.manifest?.version,
630
- json?.manifests?.linux_amd64?.version,
631
- json?.manifests?.["linux/amd64"]?.version,
632
- json?.data?.version,
633
- json?.result?.version,
634
- ];
635
-
636
- if (Array.isArray(json?.manifests)) {
637
- for (const m of json.manifests) {
638
- if (m?.version) candidates.push(m.version);
639
- }
640
- }
641
-
642
- // Bounded deep scan looking for any version-looking string.
643
- if (candidates.every((c) => !c)) {
644
- const stack = [json];
645
- let depth = 0;
646
- while (stack.length && depth < 20) {
647
- const cur = stack.pop();
648
- depth++;
649
- if (cur && typeof cur === "object") {
650
- for (const v of Object.values(cur)) {
651
- if (typeof v === "string" && /^\d+\.\d+\.\d+-?\d*/.test(v)) {
652
- candidates.push(v);
653
- break;
654
- }
655
- if (v && typeof v === "object") stack.push(v);
656
- }
657
- }
658
- if (candidates.filter(Boolean).length) break;
659
- }
660
- }
661
-
662
- const rawVersion = candidates.find((c): c is string => !!c && typeof c === "string");
663
- if (!rawVersion) return null;
664
-
665
- const { normalized, full } = parseAntigravityVersion(rawVersion);
666
- if (!normalized) return null;
667
-
668
- const now = Date.now();
669
- return {
670
- version: normalized,
671
- fullVersion: full,
672
- source: url.includes("ide-auto-updater") ? "ide-updater" : "remote-manifest",
673
- fetchedAt: now,
674
- expiresAt: now + VERSION_CACHE_TTL_MS,
675
- url,
676
- };
677
- } catch {
678
- return null;
679
- }
680
- }
681
-
682
- /** Chain tier 2: changelog scrape (best-effort regex extraction). */
683
- async function fetchFromChangelog(): Promise<AntigravityVersionInfo | null> {
684
- const versionRegex = /(?:antigravity[^0-9]{0,20}|version[^0-9]{0,10}|release[^0-9]{0,10})?(\d+\.\d+\.\d+(?:-\d+)?)/gi;
685
- const semverOnly = /(\d+\.\d+\.\d+)/g;
686
-
687
- for (const url of CHANGELOG_URLS) {
688
- try {
689
- const res = await fetchWithTimeout(url, { method: "GET" }, 5000);
690
- if (!res.ok) continue;
691
- const text = await res.text();
692
- if (!text || text.length < 10) continue;
693
-
694
- let match: RegExpExecArray | null;
695
- const found: string[] = [];
696
- while ((match = versionRegex.exec(text)) !== null) {
697
- if (match[1]) found.push(match[1]);
698
- if (found.length >= 10) break;
699
- }
700
-
701
- if (found.length === 0) {
702
- let m2: RegExpExecArray | null;
703
- while ((m2 = semverOnly.exec(text)) !== null) {
704
- if (m2 && m2[1]) {
705
- // Heuristic: skip tiny generic versions unless context matched.
706
- const parts = m2[1].split(".").map(Number);
707
- if ((parts[0] ?? 0) >= 1) found.push(m2[1]);
708
- }
709
- if (found.length >= 20) break;
710
- }
711
- }
712
-
713
- if (found.length === 0) continue;
714
-
715
- const raw = found[0] ?? "";
716
- const { normalized, full } = parseAntigravityVersion(raw);
717
- const now = Date.now();
718
- return {
719
- version: normalized,
720
- fullVersion: full.includes("-") ? full : `${normalized}-0000000000000000`,
721
- source: "changelog",
722
- fetchedAt: now,
723
- expiresAt: now + VERSION_CACHE_TTL_MS,
724
- url,
725
- };
726
- } catch {
727
- continue;
728
- }
729
- }
730
- return null;
731
- }
732
-
733
- // ---------------------------------------------------------------------------
734
- // Section: Remote fetch - observer chain (npm / GitHub / GCS)
735
- // ---------------------------------------------------------------------------
736
-
737
- /** Independent timeout fetch used by the observer chain. */
738
- async function fetchLatestWithTimeout(url: string, timeoutMs: number, userAgent: string): Promise<Response> {
739
- const controller = new AbortController();
740
- const t = setTimeout(() => controller.abort(), timeoutMs);
741
- try {
742
- const res = await fetch(url, {
743
- signal: controller.signal,
744
- headers: {
745
- Accept: "application/json, text/plain, */*",
746
- "User-Agent": userAgent,
747
- },
748
- });
749
- return res;
750
- } finally {
751
- clearTimeout(t);
752
- }
753
- }
754
-
755
- /**
756
- * Attempts to fetch the latest Antigravity version from the observer remote
757
- * chain. Each URL gets an independent AbortController timeout. Valid semver
758
- * results are stored in the memory Map and persisted atomically to disk.
759
- *
760
- * @param opts - optional overrides
761
- * @returns latest version string or null when every remote fails
762
- */
763
- export async function fetchLatestVersion(opts: FetchOptions = {}): Promise<string | null> {
764
- const timeoutMs = opts.timeoutMs ?? VERSION_FETCH_TIMEOUT_MS;
765
- const remoteUrls = opts.remoteUrls ?? ANTIGRAVITY_VERSION_REMOTE_URLS;
766
- const cachePath = resolveObserverCachePath(opts.cachePath);
767
- const userAgent = opts.userAgent ?? `antigravity/${ANTIGRAVITY_VERSION_FALLBACK}`;
768
-
769
- // Memory fast path unless forced.
770
- if (!opts.force) {
771
- const mem = versionMemoryCache.get(MEMORY_CACHE_KEY);
772
- if (mem) {
773
- const cleaned = cleanSemver(mem.version);
774
- if (cleaned && Date.now() - mem.fetchedAt < VERSION_MEMORY_TTL_MS && isSupportedVersion(cleaned)) {
775
- return cleaned;
776
- }
777
- }
778
- }
779
-
780
- for (const url of remoteUrls) {
781
- try {
782
- const res = await fetchLatestWithTimeout(url, timeoutMs, userAgent);
783
- if (!res.ok) continue;
784
-
785
- let payload: unknown;
786
- const ct = res.headers.get("content-type") ?? "";
787
- if (ct.includes("application/json") || ct.includes("text/json")) {
788
- try {
789
- payload = await res.json();
790
- } catch {
791
- const txt = await res.text();
792
- try {
793
- payload = JSON.parse(txt);
794
- } catch {
795
- payload = { version: txt.trim() };
796
- }
797
- }
798
- } else {
799
- // Some GCS buckets serve text/plain versions.
800
- const txt = await res.text();
801
- const trimmed = txt.trim();
802
- try {
803
- payload = JSON.parse(trimmed);
804
- } catch {
805
- payload = { version: trimmed };
806
- }
807
- }
808
-
809
- const parsedVersion = parseVersionFromPayload(payload);
810
- if (!parsedVersion) continue;
811
- if (!isValidSemver(parsedVersion)) continue;
812
- if (isBlockedVersion(parsedVersion)) continue;
813
-
814
- // Success - populate both cache layers.
815
- const entry: CacheEntry = {
816
- version: parsedVersion,
817
- fetchedAt: Date.now(),
818
- source: url,
819
- };
820
- versionMemoryCache.set(MEMORY_CACHE_KEY, entry);
821
-
822
- const fileEntry: VersionCacheFile = {
823
- version: parsedVersion,
824
- fetchedAt: entry.fetchedAt,
825
- source: url,
826
- expiresAt: Date.now() + VERSION_FILE_TTL_MS,
827
- };
828
- // Fire-and-forget persistence; observer never throws on cache writes.
829
- try {
830
- await writeObserverCacheFileAtomic(cachePath, fileEntry);
831
- } catch {
832
- // swallow - memory cache already saved
833
- }
834
-
835
- return parsedVersion;
836
- } catch {
837
- // Per-URL failure swallowed - continue down the chain.
838
- continue;
839
- }
840
- }
841
-
842
- return null;
843
- }
844
-
845
- // ---------------------------------------------------------------------------
846
- // Section: Public API - legacy chain
847
- // ---------------------------------------------------------------------------
848
-
849
- /**
850
- * Legacy main fetcher - resilient chain:
851
- * 1. remote manifests (parallel, sequential consumption)
852
- * 2. changelog scrape
853
- * 3. expired disk cache as last resort before fallback
854
- * 4. hardcoded fallback 1.15.8
855
- *
856
- * Always resolves with an AntigravityVersionInfo (fallback guaranteed).
857
- */
858
- export async function fetchAntigravityVersion(): Promise<AntigravityVersionInfo> {
859
- const manifestPromises = REMOTE_MANIFEST_URLS.map((url) => fetchFromManifest(url));
860
-
861
- for (const p of manifestPromises) {
862
- try {
863
- const result = await p;
864
- if (result && result.version) {
865
- memoryCache = result;
866
- await writeCacheFile(result);
867
- return result;
868
- }
869
- } catch {
870
- // continue chain
871
- }
872
- }
873
-
874
- try {
875
- const changelogResult = await fetchFromChangelog();
876
- if (changelogResult && changelogResult.version) {
877
- memoryCache = changelogResult;
878
- await writeCacheFile(changelogResult);
879
- return changelogResult;
880
- }
881
- } catch {
882
- // ignored
883
- }
884
-
885
- try {
886
- if (fs.existsSync(VERSION_CACHE_FILE)) {
887
- const raw = await fs.promises.readFile(VERSION_CACHE_FILE, "utf8");
888
- const parsed = JSON.parse(raw) as CachedFilePayload;
889
- if (parsed.version) {
890
- const now = Date.now();
891
- const reused: AntigravityVersionInfo = {
892
- ...parsed,
893
- fetchedAt: now,
894
- expiresAt: now + VERSION_CACHE_TTL_MS,
895
- source: "cache-file",
896
- };
897
- memoryCache = reused;
898
- return reused;
899
- }
900
- }
901
- } catch {
902
- // ignored
903
- }
904
-
905
- const now = Date.now();
906
- const fallback: AntigravityVersionInfo = {
907
- version: FALLBACK_VERSION,
908
- fullVersion: FALLBACK_FULL_VERSION,
909
- source: "hardcoded-fallback",
910
- fetchedAt: now,
911
- expiresAt: now + VERSION_CACHE_TTL_MS,
912
- };
913
- memoryCache = fallback;
914
- await writeCacheFile(fallback);
915
- return fallback;
916
- }
917
-
918
- /**
919
- * Legacy lazy getter - memory, then file, then fetch with promise dedup so
920
- * concurrent calls share one inflight request.
921
- */
922
- export async function getVersionInfo(): Promise<AntigravityVersionInfo> {
923
- if (memoryCache && Date.now() < memoryCache.expiresAt) {
924
- return {
925
- ...memoryCache,
926
- source: memoryCache.source === "hardcoded-fallback" ? memoryCache.source : ("memory-cache" as VersionSource),
927
- };
928
- }
929
-
930
- if (inflightPromise) {
931
- return inflightPromise;
932
- }
933
-
934
- const fileCache = await readCacheFile();
935
- if (fileCache) {
936
- memoryCache = fileCache;
937
- return fileCache;
938
- }
939
-
940
- inflightPromise = fetchAntigravityVersion().finally(() => {
941
- inflightPromise = null;
942
- });
943
-
944
- return inflightPromise;
945
- }
946
-
947
- /**
948
- * Synchronous complete-info getter - cache when present, otherwise the
949
- * legacy fallback object (never touches the network).
950
- */
951
- export function getVersionInfoSync(): AntigravityVersionInfo {
952
- if (memoryCache && Date.now() < memoryCache.expiresAt) {
953
- return memoryCache;
954
- }
955
- const file = readCacheFileSync();
956
- if (file) {
957
- memoryCache = file;
958
- return file;
959
- }
960
- const now = Date.now();
961
- return {
962
- version: FALLBACK_VERSION,
963
- fullVersion: FALLBACK_FULL_VERSION,
964
- source: "hardcoded-fallback",
965
- fetchedAt: now,
966
- expiresAt: now + VERSION_CACHE_TTL_MS,
967
- };
968
- }
969
-
970
- /** Invalidates both legacy caches (memory + disk). */
971
- export async function invalidateVersionCache(): Promise<void> {
972
- memoryCache = null;
973
- inflightPromise = null;
974
- try {
975
- await fs.promises.unlink(VERSION_CACHE_FILE);
976
- } catch {
977
- // missing or no permission - ignored
978
- }
979
- }
980
-
981
- /** Invalidates only the legacy memory cache. */
982
- export function invalidateMemoryCache(): void {
983
- memoryCache = null;
984
- inflightPromise = null;
985
- }
986
-
987
- // ---------------------------------------------------------------------------
988
- // Section: Public API - merged getters (both behaviors preserved)
989
- // ---------------------------------------------------------------------------
990
-
991
- /**
992
- * Merged lazy getter supporting BOTH historical call shapes:
993
- *
994
- * - `getVersion()` - legacy behavior: resolves through manifests/changelog,
995
- * caches 6h in memory + disk, never rejects.
996
- * - `getVersion({...})` - observer behavior: honors force/timeoutMs/
997
- * remoteUrls/cachePath/userAgent/allowStale, gates results through
998
- * isSupportedVersion/isBlockedVersion, persists atomically.
999
- *
1000
- * Resolution order: observer memory Map -> legacy memory info ->
1001
- * observer remote chain (npm/GitHub/GCS) -> legacy remote chain
1002
- * (manifests/changelog, results rejected only when explicitly blocked or
1003
- * merely the legacy hardcoded fallback) -> both file caches ->
1004
- * governed fallback ANTIGRAVITY_VERSION_FALLBACK ("1.19.2").
1005
- */
1006
- export async function getVersion(opts: GetVersionOptions = {}): Promise<string> {
1007
- const force = opts.force === true;
1008
-
1009
- // 0a) observer memory cache
1010
- if (!force) {
1011
- const mem = versionMemoryCache.get(MEMORY_CACHE_KEY);
1012
- if (mem) {
1013
- const cleaned = cleanSemver(mem.version);
1014
- if (cleaned && Date.now() - mem.fetchedAt < VERSION_MEMORY_TTL_MS && isSupportedVersion(cleaned)) {
1015
- return cleaned;
1016
- }
1017
- }
1018
- // 0b) legacy memory info cache
1019
- if (memoryCache && Date.now() < memoryCache.expiresAt && !isBlockedVersion(memoryCache.version)) {
1020
- return memoryCache.version;
1021
- }
1022
- }
1023
-
1024
- // 1) remote chains: observer first (gated), then legacy manifests/changelog.
1025
- let resolved: string | null = null;
1026
- try {
1027
- const remote = await fetchLatestVersion(opts);
1028
- if (remote && isSupportedVersion(remote)) {
1029
- resolved = remote;
1030
- }
1031
- } catch {
1032
- // swallowed - fall through
1033
- }
1034
-
1035
- if (!resolved) {
1036
- try {
1037
- const legacy = await fetchAntigravityVersion();
1038
- if (legacy && legacy.version && legacy.source !== "hardcoded-fallback" && !isBlockedVersion(legacy.version)) {
1039
- resolved = legacy.version;
1040
- versionMemoryCache.set(MEMORY_CACHE_KEY, {
1041
- version: legacy.version,
1042
- fetchedAt: legacy.fetchedAt,
1043
- source: legacy.url ?? legacy.source,
1044
- });
1045
- }
1046
- } catch {
1047
- // swallowed - fall through
1048
- }
1049
- }
1050
-
1051
- if (resolved) return resolved;
1052
-
1053
- // 2) file caches: observer path (stale allowed by default) + legacy path.
1054
- const allowStale = opts.allowStale ?? true;
1055
- const observerPath = resolveObserverCachePath(opts.cachePath);
1056
-
1057
- try {
1058
- const fileCache = await readObserverCacheFileAsync(observerPath);
1059
- if (fileCache) {
1060
- const fresh = Date.now() < fileCache.expiresAt;
1061
- if (fresh || allowStale) {
1062
- const cleaned = cleanSemver(fileCache.version);
1063
- if (cleaned && isSupportedVersion(cleaned)) {
1064
- versionMemoryCache.set(MEMORY_CACHE_KEY, {
1065
- version: cleaned,
1066
- fetchedAt: fileCache.fetchedAt,
1067
- source: fileCache.source,
1068
- });
1069
- return cleaned;
1070
- }
1071
- }
1072
- }
1073
- } catch {
1074
- // swallowed
1075
- }
1076
-
1077
- try {
1078
- const legacyFile = await readCacheFile();
1079
- if (legacyFile && !isBlockedVersion(legacyFile.version)) {
1080
- return legacyFile.version;
1081
- }
1082
- } catch {
1083
- // swallowed
1084
- }
1085
-
1086
- // 3) governed fallback - guaranteed valid semver.
1087
- const fallback = ANTIGRAVITY_VERSION_FALLBACK;
1088
- versionMemoryCache.set(MEMORY_CACHE_KEY, {
1089
- version: fallback,
1090
- fetchedAt: Date.now(),
1091
- source: "fallback",
1092
- });
1093
- return fallback;
1094
- }
1095
-
1096
- /**
1097
- * Merged synchronous getter (no network). Supports both call shapes:
1098
- * `getVersionSync()` (legacy) and `getVersionSync({cachePath,allowStale})`
1099
- * (observer). Reads observer Map -> legacy memory -> observer file ->
1100
- * legacy file -> governed fallback 1.19.2.
1101
- */
1102
- export function getVersionSync(opts: { cachePath?: string; allowStale?: boolean } = {}): string {
1103
- const allowStale = opts.allowStale ?? true;
1104
- const observerPath = resolveObserverCachePath(opts.cachePath);
1105
-
1106
- const mem = versionMemoryCache.get(MEMORY_CACHE_KEY);
1107
- if (mem) {
1108
- const cleaned = cleanSemver(mem.version);
1109
- if (cleaned && Date.now() - mem.fetchedAt < VERSION_MEMORY_TTL_MS && isSupportedVersion(cleaned)) {
1110
- return cleaned;
1111
- }
1112
- }
1113
-
1114
- if (memoryCache && Date.now() < memoryCache.expiresAt && !isBlockedVersion(memoryCache.version)) {
1115
- return memoryCache.version;
1116
- }
1117
-
1118
- const fileCache = readObserverCacheFileSync(observerPath);
1119
- if (fileCache) {
1120
- const fresh = Date.now() < fileCache.expiresAt;
1121
- if (fresh || allowStale) {
1122
- const cleaned = cleanSemver(fileCache.version);
1123
- if (cleaned && isSupportedVersion(cleaned)) {
1124
- versionMemoryCache.set(MEMORY_CACHE_KEY, {
1125
- version: cleaned,
1126
- fetchedAt: fileCache.fetchedAt,
1127
- source: fileCache.source,
1128
- });
1129
- return cleaned;
1130
- }
1131
- }
1132
- }
1133
-
1134
- const legacyFile = readCacheFileSync();
1135
- if (legacyFile && !isBlockedVersion(legacyFile.version)) {
1136
- return legacyFile.version;
1137
- }
1138
-
1139
- return ANTIGRAVITY_VERSION_FALLBACK;
1140
- }
1141
-
1142
- // ---------------------------------------------------------------------------
1143
- // Section: Cache invalidation - observer chain
1144
- // ---------------------------------------------------------------------------
1145
-
1146
- /**
1147
- * Clears the observer memory entry and removes its cache file.
1148
- * Use {@link invalidateVersionCache} for the legacy stores.
1149
- */
1150
- export async function clearVersionCache(opts: { cachePath?: string } = {}): Promise<void> {
1151
- versionMemoryCache.delete(MEMORY_CACHE_KEY);
1152
- const cachePath = resolveObserverCachePath(opts.cachePath);
1153
- try {
1154
- await fsp.unlink(cachePath);
1155
- } catch {
1156
- // ignore missing
1157
- }
1158
- }
1159
-
1160
- /** Synchronous variant of {@link clearVersionCache}. */
1161
- export function clearVersionCacheSync(opts: { cachePath?: string } = {}): void {
1162
- versionMemoryCache.delete(MEMORY_CACHE_KEY);
1163
- const cachePath = resolveObserverCachePath(opts.cachePath);
1164
- try {
1165
- fs.unlinkSync(cachePath);
1166
- } catch {
1167
- // ignore missing
1168
- }
1169
- }
1170
-
1171
- // ---------------------------------------------------------------------------
1172
- // Section: User-Agent helpers
1173
- // ---------------------------------------------------------------------------
1174
-
1175
- /**
1176
- * Dynamic legacy UA varying platform (darwin/linux/win32) for coherent
1177
- * bypass; embeds the fetched Antigravity version as a safe comment segment.
1178
- */
1179
- // local variant: diverges from constants (async template-based GeminiCLI UA vs constants' sync antigravity/{ver} {os}/{arch} UA)
1180
- export async function getVersionedUserAgent(): Promise<string> {
1181
- const platform = os.platform();
1182
- const arch = os.arch();
1183
- const key = `${platform}_${arch}` as keyof typeof ANTIGRAVITY_AUTH_CONSTANTS.USER_AGENT_TEMPLATES;
1184
- const template =
1185
- ANTIGRAVITY_AUTH_CONSTANTS.USER_AGENT_TEMPLATES[key] ||
1186
- (platform === "darwin"
1187
- ? ANTIGRAVITY_AUTH_CONSTANTS.USER_AGENT_TEMPLATES.darwin_arm64
1188
- : ANTIGRAVITY_AUTH_CONSTANTS.USER_AGENT_TEMPLATES.linux_x64);
1189
-
1190
- const ver = await getVersion().catch(() => FALLBACK_VERSION);
1191
- return template.replace("GitHub)", `GitHub; Antigravity/${ver})`);
1192
- }
1193
-
1194
- /** Simple semver gt comparison retained from the legacy API. */
1195
- export function isNewerVersion(a: string, b: string): boolean {
1196
- const toNums = (s: string) => (s.split("-")[0] ?? "").split(".").map((n) => parseInt(n, 10) || 0);
1197
- const A = toNums(a);
1198
- const B = toNums(b);
1199
- for (let i = 0; i < Math.max(A.length, B.length); i++) {
1200
- const av = A[i] || 0;
1201
- const bv = B[i] || 0;
1202
- if (av > bv) return true;
1203
- if (av < bv) return false;
1204
- }
1205
- return false;
1206
- }
1207
-
1208
- /**
1209
- * Observer-style User-Agent for a given version:
1210
- * `antigravity/{version} {platform}/{arch}` (coherent per host).
1211
- * @param version - semver; falls back to ANTIGRAVITY_VERSION_FALLBACK
1212
- */
1213
- export function getAntigravityUserAgent(version?: string): string {
1214
- const ver = cleanSemver(version ?? "") ?? ANTIGRAVITY_VERSION_FALLBACK;
1215
- const plat = os.platform();
1216
- const arch = os.arch();
1217
- return `antigravity/${ver} ${plat}/${arch}`;
1218
- }
1219
-
1220
- /**
1221
- * Async observer UA ensuring the latest version first. Pass cachedVersion to
1222
- * avoid network round-trips.
1223
- */
1224
- export async function getDynamicUserAgentVersioned(cachedVersion?: string, opts: FetchOptions = {}): Promise<string> {
1225
- const ver = cachedVersion && isValidSemver(cachedVersion) ? cachedVersion : await getVersion(opts);
1226
- return getAntigravityUserAgent(ver);
1227
- }
1228
-
1229
- // ---------------------------------------------------------------------------
1230
- // Section: Barrels
1231
- // ---------------------------------------------------------------------------
1232
-
1233
- /** Observer barrel export. */
1234
- export const Version = {
1235
- fallback: ANTIGRAVITY_VERSION_FALLBACK,
1236
- minSupported: ANTIGRAVITY_VERSION_MIN_SUPPORTED,
1237
- blocked: ANTIGRAVITY_BLOCKED_VERSIONS,
1238
- remoteUrls: ANTIGRAVITY_VERSION_REMOTE_URLS,
1239
- timeoutMs: VERSION_FETCH_TIMEOUT_MS,
1240
- memoryTtlMs: VERSION_MEMORY_TTL_MS,
1241
- fileTtlMs: VERSION_FILE_TTL_MS,
1242
- memoryCache: versionMemoryCache,
1243
- isValidSemver,
1244
- cleanSemver,
1245
- compareSemver,
1246
- shouldUpdate,
1247
- isBlockedVersion,
1248
- isSupportedVersion,
1249
- parseVersionFromPayload,
1250
- fetchLatestVersion,
1251
- getVersion,
1252
- getVersionSync,
1253
- clearVersionCache,
1254
- clearVersionCacheSync,
1255
- getAntigravityUserAgent,
1256
- getDynamicUserAgentVersioned,
1257
- } as const;
1258
-
1259
- /** Default export - full merged module barrel (legacy + observer). */
1260
- const versionModule = {
1261
- // Legacy surface
1262
- REMOTE_MANIFEST_URLS,
1263
- CHANGELOG_URLS,
1264
- FALLBACK_VERSION,
1265
- FALLBACK_FULL_VERSION,
1266
- FALLBACK_ALTERNATIVE_VERSION,
1267
- FALLBACK_ALTERNATIVE_FULL,
1268
- VERSION_CACHE_FILE,
1269
- VERSION_CACHE_TTL_MS,
1270
- FETCH_TIMEOUT_MS,
1271
- ANTIGRAVITY_AUTH_CONSTANTS,
1272
- fetchAntigravityVersion,
1273
- getVersion,
1274
- getVersionInfo,
1275
- getVersionSync,
1276
- getVersionInfoSync,
1277
- parseAntigravityVersion,
1278
- fetchWithTimeout,
1279
- readCacheFile,
1280
- readCacheFileSync,
1281
- writeCacheFile,
1282
- invalidateVersionCache,
1283
- invalidateMemoryCache,
1284
- getVersionedUserAgent,
1285
- isNewerVersion,
1286
- // Observer surface
1287
- ANTIGRAVITY_VERSION_FALLBACK,
1288
- ANTIGRAVITY_VERSION_MIN_SUPPORTED,
1289
- ANTIGRAVITY_BLOCKED_VERSIONS,
1290
- ANTIGRAVITY_VERSION_REMOTE_URLS,
1291
- VERSION_FETCH_TIMEOUT_MS,
1292
- VERSION_MEMORY_TTL_MS,
1293
- VERSION_FILE_TTL_MS,
1294
- versionMemoryCache,
1295
- isValidSemver,
1296
- cleanSemver,
1297
- compareSemver,
1298
- shouldUpdate,
1299
- isBlockedVersion,
1300
- isSupportedVersion,
1301
- parseVersionFromPayload,
1302
- fetchLatestVersion,
1303
- clearVersionCache,
1304
- clearVersionCacheSync,
1305
- getAntigravityUserAgent,
1306
- getDynamicUserAgentVersioned,
1307
- Version,
1308
- };
1309
-
1310
- export default versionModule;