@herbertgao/pi-extensions 2026.9.2 → 2026.9.4

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 (255) hide show
  1. package/README.md +4 -2
  2. package/THIRD_PARTY_NOTICES.md +49 -0
  3. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +3 -2
  4. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +16 -11
  5. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +20 -6
  6. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +12 -7
  7. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +98 -0
  8. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  9. package/node_modules/@herbertgao/sol-pi/LICENSE +19 -0
  10. package/node_modules/@herbertgao/sol-pi/README.md +159 -0
  11. package/node_modules/@herbertgao/sol-pi/SECURITY.md +26 -0
  12. package/node_modules/@herbertgao/sol-pi/THIRD_PARTY_NOTICES.md +19 -0
  13. package/node_modules/@herbertgao/sol-pi/agents-install.md +150 -0
  14. package/node_modules/@herbertgao/sol-pi/assets/sol-pi-hero.png +0 -0
  15. package/node_modules/@herbertgao/sol-pi/docs/compatibility.md +69 -0
  16. package/node_modules/@herbertgao/sol-pi/docs/configuration.md +75 -0
  17. package/node_modules/@herbertgao/sol-pi/package.json +76 -0
  18. package/node_modules/@herbertgao/sol-pi/scripts/check-pi-compat.mjs +32 -0
  19. package/node_modules/@herbertgao/sol-pi/scripts/check-sol-pi-config.mjs +120 -0
  20. package/node_modules/@herbertgao/sol-pi/sol-pi.example.json +10 -0
  21. package/node_modules/@herbertgao/sol-pi/src/sol-pi/config.ts +135 -0
  22. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/file-queue.ts +74 -0
  23. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/index.ts +185 -0
  24. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/then-run.ts +128 -0
  25. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/archive.ts +53 -0
  26. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/candidate.ts +101 -0
  27. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/config.ts +71 -0
  28. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/index.ts +220 -0
  29. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/journal.ts +25 -0
  30. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/provider.ts +164 -0
  31. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/receipt.ts +177 -0
  32. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/index.ts +227 -0
  33. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/ledger.ts +20 -0
  34. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/observation.ts +252 -0
  35. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/economics.ts +237 -0
  36. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/extension.ts +455 -0
  37. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/index.ts +49 -0
  38. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/plan.ts +79 -0
  39. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/state.ts +208 -0
  40. package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/tools.ts +100 -0
  41. package/node_modules/@herbertgao/sol-pi/src/sol-pi/index.ts +42 -0
  42. package/node_modules/@herbertgao/sol-pi/src/sol-pi/runtime-paths.ts +17 -0
  43. package/node_modules/@herbertgao/sol-pi/src/sol-pi/tui.ts +71 -0
  44. package/node_modules/@narumitw/pi-btw/dist/index.ts +12 -2
  45. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +2 -2
  46. package/node_modules/@narumitw/pi-btw/package.json +1 -1
  47. package/node_modules/@narumitw/pi-btw/src/btw.ts +13 -2
  48. package/node_modules/pi-antigravity/LICENSE +21 -0
  49. package/node_modules/pi-antigravity/README.md +194 -0
  50. package/node_modules/pi-antigravity/package.json +67 -0
  51. package/node_modules/pi-antigravity/src/auth/index.ts +14 -0
  52. package/node_modules/pi-antigravity/src/auth/oauth.ts +442 -0
  53. package/node_modules/pi-antigravity/src/client/client.ts +561 -0
  54. package/node_modules/pi-antigravity/src/client/index.ts +1 -0
  55. package/node_modules/pi-antigravity/src/diagnostics/diagnostics.ts +96 -0
  56. package/node_modules/pi-antigravity/src/diagnostics/index.ts +1 -0
  57. package/node_modules/pi-antigravity/src/image/image.ts +336 -0
  58. package/node_modules/pi-antigravity/src/image/index.ts +1 -0
  59. package/node_modules/pi-antigravity/src/index.ts +280 -0
  60. package/node_modules/pi-antigravity/src/models/discovery.ts +154 -0
  61. package/node_modules/pi-antigravity/src/models/grouping.ts +424 -0
  62. package/node_modules/pi-antigravity/src/models/index.ts +3 -0
  63. package/node_modules/pi-antigravity/src/models/models.ts +500 -0
  64. package/node_modules/pi-antigravity/src/stream/index.ts +1 -0
  65. package/node_modules/pi-antigravity/src/stream/stream.ts +1460 -0
  66. package/node_modules/pi-antigravity/src/types/enums.ts +42 -0
  67. package/node_modules/pi-antigravity/src/types/index.ts +2 -0
  68. package/node_modules/pi-antigravity/src/types/types.ts +292 -0
  69. package/node_modules/pi-antigravity/src/usage/index.ts +1 -0
  70. package/node_modules/pi-antigravity/src/usage/usage.ts +371 -0
  71. package/node_modules/pi-antigravity/src/utils/http.ts +91 -0
  72. package/node_modules/pi-antigravity/src/utils/index.ts +3 -0
  73. package/node_modules/pi-antigravity/src/utils/security.ts +73 -0
  74. package/node_modules/pi-antigravity/src/utils/util.ts +132 -0
  75. package/node_modules/pi-antigravity/tsconfig.json +21 -0
  76. package/node_modules/pi-lens/CHANGELOG.md +176 -0
  77. package/node_modules/pi-lens/README.md +13 -8
  78. package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +3 -1
  79. package/node_modules/pi-lens/dist/clients/analysed-root.js +1 -0
  80. package/node_modules/pi-lens/dist/clients/ast-grep-tool-logger.js +1 -1
  81. package/node_modules/pi-lens/dist/clients/biome-client.js +13 -2
  82. package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +2 -0
  83. package/node_modules/pi-lens/dist/clients/cache-observability.js +122 -1
  84. package/node_modules/pi-lens/dist/clients/complexity-client.js +5 -0
  85. package/node_modules/pi-lens/dist/clients/config-diagnostic-codes.js +2 -0
  86. package/node_modules/pi-lens/dist/clients/config-resolve.js +6 -3
  87. package/node_modules/pi-lens/dist/clients/config-schema.js +17 -0
  88. package/node_modules/pi-lens/dist/clients/config-warn.js +2 -2
  89. package/node_modules/pi-lens/dist/clients/dead-code-client.js +8 -1
  90. package/node_modules/pi-lens/dist/clients/dependency-checker.js +5 -1
  91. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +38 -15
  92. package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +1 -1
  93. package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +5 -1
  94. package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +2 -1
  95. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +2 -3
  96. package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +4 -3
  97. package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +2 -1
  98. package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +2 -1
  99. package/node_modules/pi-lens/dist/clients/dispatch/runners/dart-analyze.js +2 -1
  100. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +2 -1
  101. package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +2 -1
  102. package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +2 -1
  103. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +2 -1
  104. package/node_modules/pi-lens/dist/clients/dispatch/runners/fish-indent.js +2 -1
  105. package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +2 -1
  106. package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +2 -1
  107. package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +2 -1
  108. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +2 -1
  109. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +3 -1
  110. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +2 -1
  111. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +2 -1
  112. package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +2 -1
  113. package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +2 -1
  114. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +19 -1
  115. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +3 -2
  116. package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +2 -1
  117. package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +2 -1
  118. package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +2 -1
  119. package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +2 -1
  120. package/node_modules/pi-lens/dist/clients/dispatch/runners/prisma-validate.js +2 -1
  121. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +12 -12
  122. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +2 -1
  123. package/node_modules/pi-lens/dist/clients/dispatch/runners/rubocop.js +2 -1
  124. package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +2 -2
  125. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +12 -11
  126. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +2 -1
  127. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -1
  128. package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +2 -2
  129. package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
  130. package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +3 -2
  131. package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +3 -2
  132. package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +2 -1
  133. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +2 -1
  134. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +2 -1
  135. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +2 -1
  136. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +2 -1
  137. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +5 -0
  138. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +2 -2
  139. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +8 -2
  140. package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +2 -1
  141. package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +4 -3
  142. package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +2 -1
  143. package/node_modules/pi-lens/dist/clients/effective-config.js +12 -2
  144. package/node_modules/pi-lens/dist/clients/extension-log.js +2 -0
  145. package/node_modules/pi-lens/dist/clients/file-role.js +18 -1
  146. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +4 -0
  147. package/node_modules/pi-lens/dist/clients/formatters.js +54 -188
  148. package/node_modules/pi-lens/dist/clients/generation-guard.js +4 -0
  149. package/node_modules/pi-lens/dist/clients/gitleaks-client.js +42 -6
  150. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +48 -7
  151. package/node_modules/pi-lens/dist/clients/installer/index.js +196 -52
  152. package/node_modules/pi-lens/dist/clients/jscpd-client.js +9 -1
  153. package/node_modules/pi-lens/dist/clients/knip-client.js +9 -2
  154. package/node_modules/pi-lens/dist/clients/language-profile.js +12 -2
  155. package/node_modules/pi-lens/dist/clients/latency-logger.js +2 -0
  156. package/node_modules/pi-lens/dist/clients/lens-config.js +4 -0
  157. package/node_modules/pi-lens/dist/clients/lsp/config.js +36 -7
  158. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +24 -1
  159. package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +78 -0
  160. package/node_modules/pi-lens/dist/clients/lsp/index.js +281 -45
  161. package/node_modules/pi-lens/dist/clients/lsp/server.js +62 -15
  162. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +37 -4
  163. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +3 -0
  164. package/node_modules/pi-lens/dist/clients/mcp/session.js +2 -0
  165. package/node_modules/pi-lens/dist/clients/opengrep-client.js +2 -0
  166. package/node_modules/pi-lens/dist/clients/package-manager.js +2 -1
  167. package/node_modules/pi-lens/dist/clients/php-cs-fixer-config.js +8 -3
  168. package/node_modules/pi-lens/dist/clients/pipeline.js +3 -2
  169. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +38 -10
  170. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +10 -9
  171. package/node_modules/pi-lens/dist/clients/project-lens-config.js +3 -0
  172. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +2 -0
  173. package/node_modules/pi-lens/dist/clients/review-graph-logger.js +2 -0
  174. package/node_modules/pi-lens/dist/clients/ruff-client.js +18 -9
  175. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +9 -0
  176. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +5 -0
  177. package/node_modules/pi-lens/dist/clients/runtime-session.js +13 -4
  178. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +4 -1
  179. package/node_modules/pi-lens/dist/clients/runtime-turn.js +48 -1
  180. package/node_modules/pi-lens/dist/clients/security-scan-client.js +2 -2
  181. package/node_modules/pi-lens/dist/clients/session-event-guard.js +69 -1
  182. package/node_modules/pi-lens/dist/clients/sg-runner.js +2 -1
  183. package/node_modules/pi-lens/dist/clients/situational-tool-telemetry.js +108 -0
  184. package/node_modules/pi-lens/dist/clients/test-runner-client.js +291 -76
  185. package/node_modules/pi-lens/dist/clients/tool-config.js +199 -0
  186. package/node_modules/pi-lens/dist/clients/tool-cwd.js +299 -0
  187. package/node_modules/pi-lens/dist/clients/tool-probe.js +53 -0
  188. package/node_modules/pi-lens/dist/clients/tool-set-policy.js +42 -0
  189. package/node_modules/pi-lens/dist/clients/trivy-client.js +9 -1
  190. package/node_modules/pi-lens/dist/clients/turn-context.js +52 -0
  191. package/node_modules/pi-lens/dist/clients/widget-state.js +4 -3
  192. package/node_modules/pi-lens/dist/index.js +21969 -20005
  193. package/node_modules/pi-lens/dist/mcp/analyze-cli.js +3 -2
  194. package/node_modules/pi-lens/dist/mcp/server.js +135 -159
  195. package/node_modules/pi-lens/dist/tools/activate-tools.js +10 -7
  196. package/node_modules/pi-lens/dist/tools/ast-grep-outline.js +2 -13
  197. package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +8 -13
  198. package/node_modules/pi-lens/dist/tools/ast-grep-search.js +83 -39
  199. package/node_modules/pi-lens/dist/tools/effective-config.js +4 -3
  200. package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +1 -10
  201. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +353 -85
  202. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +21 -110
  203. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +20 -44
  204. package/node_modules/pi-lens/dist/tools/module-report.js +5 -9
  205. package/node_modules/pi-lens/dist/tools/project-report.js +9 -17
  206. package/node_modules/pi-lens/dist/tools/render-compact.js +280 -1
  207. package/node_modules/pi-lens/dist/tools/symbol-search.js +2 -2
  208. package/node_modules/pi-lens/docs/agent-guide.md +3 -4
  209. package/node_modules/pi-lens/docs/agent-tools.md +46 -22
  210. package/node_modules/pi-lens/docs/configuration.md +9 -0
  211. package/node_modules/pi-lens/docs/environment-variables.md +0 -5
  212. package/node_modules/pi-lens/docs/features.md +5 -5
  213. package/node_modules/pi-lens/docs/globalconfig.md +11 -1
  214. package/node_modules/pi-lens/docs/mcp.md +13 -1
  215. package/node_modules/pi-lens/docs/pi-lens-fixer.md +71 -0
  216. package/node_modules/pi-lens/docs/pi-lens-investigator.md +15 -0
  217. package/node_modules/pi-lens/docs/pi-lens-monitor.md +88 -0
  218. package/node_modules/pi-lens/docs/pi-lens-reviewer.md +35 -0
  219. package/node_modules/pi-lens/docs/pi-lens-subagent.md +12 -4
  220. package/node_modules/pi-lens/docs/public-api-stability.md +1 -0
  221. package/node_modules/pi-lens/docs/real-harness.md +46 -0
  222. package/node_modules/pi-lens/docs/release-qa-baseline.md +5 -1
  223. package/node_modules/pi-lens/docs/servercapabilities.md +1 -6
  224. package/node_modules/pi-lens/docs/settings.md +37 -2
  225. package/node_modules/pi-lens/docs/tools_improvement2.md +4 -4
  226. package/node_modules/pi-lens/docs/tree-sitter_rules_catalog.md +1 -1
  227. package/node_modules/pi-lens/docs/usage.md +13 -3
  228. package/node_modules/pi-lens/package.json +10 -1
  229. package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/sql-injection.yml +7 -3
  230. package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +8 -6
  231. package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +19 -9
  232. package/node_modules/pi-web-access/CHANGELOG.md +29 -0
  233. package/node_modules/pi-web-access/README.md +33 -22
  234. package/node_modules/pi-web-access/abortable.ts +17 -0
  235. package/node_modules/pi-web-access/crawl4ai.ts +204 -0
  236. package/node_modules/pi-web-access/credential-source.ts +1 -0
  237. package/node_modules/pi-web-access/curator-page.ts +20 -2
  238. package/node_modules/pi-web-access/curator-run.ts +44 -0
  239. package/node_modules/pi-web-access/curator-server.ts +3 -1
  240. package/node_modules/pi-web-access/duckduckgo.ts +1 -1
  241. package/node_modules/pi-web-access/extract.ts +57 -12
  242. package/node_modules/pi-web-access/fetch-params.ts +1 -1
  243. package/node_modules/pi-web-access/gemini-search.ts +9 -5
  244. package/node_modules/pi-web-access/index.ts +25 -18
  245. package/node_modules/pi-web-access/openai-search.ts +35 -13
  246. package/node_modules/pi-web-access/package.json +2 -2
  247. package/node_modules/pi-web-access/page-query.ts +5 -2
  248. package/node_modules/pi-web-access/query-rewrite.ts +5 -2
  249. package/node_modules/pi-web-access/serpapi.ts +220 -0
  250. package/node_modules/pi-web-access/ssrf-protection.ts +5 -1
  251. package/node_modules/pi-web-access/storage.ts +10 -0
  252. package/node_modules/pi-web-access/summary-review.ts +34 -21
  253. package/node_modules/pi-web-access/utils.ts +6 -4
  254. package/package.json +11 -5
  255. package/node_modules/pi-lens/dist/tools/ast-dump.js +0 -103
@@ -0,0 +1,42 @@
1
+ export enum ThinkingEffort {
2
+ Off = "off",
3
+ Minimal = "minimal",
4
+ Low = "low",
5
+ Medium = "medium",
6
+ High = "high",
7
+ Xhigh = "xhigh",
8
+ }
9
+
10
+ export enum ToolChoice {
11
+ Auto = "auto",
12
+ None = "none",
13
+ Any = "any",
14
+ Required = "required",
15
+ }
16
+
17
+ export enum GeminiToolCallingMode {
18
+ None = "NONE",
19
+ Any = "ANY",
20
+ Auto = "AUTO",
21
+ Validated = "VALIDATED",
22
+ }
23
+
24
+ export enum GeminiRole {
25
+ User = "user",
26
+ Model = "model",
27
+ }
28
+
29
+ export enum AntigravityRequestType {
30
+ Agent = "agent",
31
+ }
32
+
33
+ export enum AntigravityUserAgent {
34
+ Antigravity = "antigravity",
35
+ }
36
+
37
+ export enum StopReason {
38
+ Stop = "stop",
39
+ Length = "length",
40
+ ToolUse = "toolUse",
41
+ Error = "error",
42
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./enums.js";
2
+ export * from "./types.js";
@@ -0,0 +1,292 @@
1
+ import type { Server } from "node:http";
2
+ import type {
3
+ OAuthCredentials,
4
+ SimpleStreamOptions,
5
+ TextContent,
6
+ ThinkingContent,
7
+ ToolCall,
8
+ } from "@earendil-works/pi-ai";
9
+ import type {
10
+ AntigravityRequestType,
11
+ AntigravityUserAgent,
12
+ GeminiRole,
13
+ GeminiToolCallingMode,
14
+ ThinkingEffort,
15
+ ToolChoice,
16
+ } from "./enums.js";
17
+
18
+ // OAuth & Auth Types
19
+ export type AntigravityOAuthCredentials = OAuthCredentials & {
20
+ projectId?: string;
21
+ email?: string;
22
+ };
23
+
24
+ export type AntigravityApiKey = {
25
+ token: string;
26
+ projectId: string;
27
+ };
28
+
29
+ export type DynamicModelInfo = {
30
+ id: string;
31
+ experiments?: string[];
32
+ apiProvider?: string;
33
+ modelProvider?: string;
34
+ model?: string;
35
+ };
36
+
37
+ export type CallbackServer = {
38
+ server: Server;
39
+ waitForCode: () => Promise<{ code: string; state: string }>;
40
+ cleanup: () => void;
41
+ };
42
+
43
+ // Model Types
44
+ export type AntigravityRouting = {
45
+ off?: string;
46
+ routing?: Partial<Record<ThinkingEffort, string>>;
47
+ defaultRequestId?: string;
48
+ };
49
+
50
+ // Stream & API Types
51
+ export const ANTIGRAVITY_API = "antigravity-api" as const;
52
+ export type AntigravityApi = typeof ANTIGRAVITY_API;
53
+
54
+ export type AntigravityStreamOptions = Omit<SimpleStreamOptions, "toolChoice"> & {
55
+ toolChoice?: ToolChoice | `${ToolChoice}`;
56
+ };
57
+
58
+ export type GeminiTextPart = { text: string; thoughtSignature?: string };
59
+ export type GeminiInlineDataPart = { inlineData: { mimeType: string; data: string } };
60
+ export type GeminiThoughtPart = {
61
+ thought: true;
62
+ text: string;
63
+ thoughtSignature?: string;
64
+ };
65
+ export type GeminiFunctionCallPart = {
66
+ functionCall: {
67
+ name: string;
68
+ args: Record<string, unknown>;
69
+ id?: string;
70
+ };
71
+ thoughtSignature?: string;
72
+ };
73
+ export type GeminiFunctionResponsePart = {
74
+ functionResponse: {
75
+ name: string;
76
+ response: { error: string } | { output: string };
77
+ id?: string;
78
+ };
79
+ };
80
+ export type GeminiPart =
81
+ | GeminiTextPart
82
+ | GeminiInlineDataPart
83
+ | GeminiThoughtPart
84
+ | GeminiFunctionCallPart
85
+ | GeminiFunctionResponsePart;
86
+
87
+ export type GeminiContent = {
88
+ role: GeminiRole;
89
+ parts: GeminiPart[];
90
+ };
91
+
92
+ export type GeminiFunctionDeclaration = {
93
+ name: string;
94
+ description: string;
95
+ parameters?: unknown;
96
+ parametersJsonSchema?: unknown;
97
+ };
98
+
99
+ export type GeminiToolConfig = {
100
+ functionCallingConfig: {
101
+ mode: GeminiToolCallingMode;
102
+ };
103
+ };
104
+
105
+ export type ThinkingWire = {
106
+ includeThoughts: boolean;
107
+ thinkingBudget: number;
108
+ };
109
+
110
+ export type GeminiGenerationConfig = {
111
+ temperature?: number;
112
+ maxOutputTokens?: number;
113
+ thinkingConfig?: ThinkingWire;
114
+ };
115
+
116
+ export type GeminiRequestBody = {
117
+ contents: GeminiContent[];
118
+ systemInstruction: {
119
+ role: GeminiRole.User;
120
+ parts: GeminiTextPart[];
121
+ };
122
+ generationConfig?: GeminiGenerationConfig;
123
+ tools?: { functionDeclarations: GeminiFunctionDeclaration[] }[];
124
+ toolConfig?: GeminiToolConfig;
125
+ sessionId?: string;
126
+ labels?: Record<string, string>;
127
+ };
128
+
129
+ export type AntigravityGenerateRequest = {
130
+ project: string;
131
+ model: string;
132
+ request: GeminiRequestBody;
133
+ requestType: AntigravityRequestType.Agent;
134
+ userAgent: AntigravityUserAgent.Antigravity;
135
+ requestId: string;
136
+ };
137
+
138
+ export type StreamPart = {
139
+ text?: string;
140
+ thought?: boolean;
141
+ thoughtSignature?: string;
142
+ functionCall?: {
143
+ id?: string;
144
+ name?: string;
145
+ args?: Record<string, unknown>;
146
+ };
147
+ };
148
+
149
+ export type StreamUsageMetadata = {
150
+ promptTokenCount?: number;
151
+ cachedContentTokenCount?: number;
152
+ candidatesTokenCount?: number;
153
+ thoughtsTokenCount?: number;
154
+ totalTokenCount?: number;
155
+ };
156
+
157
+ export type StreamCandidate = {
158
+ content?: { parts?: StreamPart[] };
159
+ finishReason?: string;
160
+ };
161
+
162
+ export type StreamResponseData = {
163
+ candidates?: StreamCandidate[];
164
+ usageMetadata?: StreamUsageMetadata;
165
+ };
166
+
167
+ export type StreamChunk = StreamResponseData & {
168
+ error?: { message?: string };
169
+ response?: StreamResponseData;
170
+ };
171
+
172
+ export type LooseImageBlock = {
173
+ type: "image";
174
+ data?: string;
175
+ mimeType?: string;
176
+ mediaType?: string;
177
+ source?: { data?: string; mediaType?: string };
178
+ };
179
+
180
+ export type ContentBlock = TextContent | ThinkingContent | ToolCall | LooseImageBlock;
181
+
182
+ export type ActiveTextBlock = TextContent;
183
+ export type ActiveThinkingBlock = ThinkingContent;
184
+ export type ActiveBlock = ActiveTextBlock | ActiveThinkingBlock;
185
+
186
+ // Usage & Quota Types
187
+ export type QuotaBucket = {
188
+ bucketId: string;
189
+ displayName: string;
190
+ window?: string;
191
+ resetTime?: string;
192
+ description?: string;
193
+ remainingFraction: number;
194
+ };
195
+
196
+ export type QuotaGroup = {
197
+ displayName: string;
198
+ description?: string;
199
+ buckets: QuotaBucket[];
200
+ };
201
+
202
+ export type ModelQuotaRow = {
203
+ modelId: string;
204
+ displayName?: string;
205
+ remainingFraction?: number;
206
+ resetTime?: string;
207
+ modelProvider?: string;
208
+ supportsThinking?: boolean;
209
+ supportsImages?: boolean;
210
+ recommended?: boolean;
211
+ };
212
+
213
+ export type TierInfo = {
214
+ id?: string;
215
+ name?: string;
216
+ description?: string;
217
+ };
218
+
219
+ export type AccountUsage = {
220
+ projectId: string;
221
+ endpoint: string;
222
+ email?: string;
223
+ productTier?: TierInfo;
224
+ paidTier?: TierInfo;
225
+ planLabel?: string;
226
+ groups: QuotaGroup[];
227
+ groupDescription?: string;
228
+ /** Set when the (subscription-gated) quota-summary RPC was unavailable, e.g. free-tier SUBSCRIPTION_REQUIRED. */
229
+ quotaSummaryError?: string;
230
+ models: ModelQuotaRow[];
231
+ defaultAgentModelId?: string;
232
+ fetchedAt: number;
233
+ };
234
+
235
+ export type ApiErrorBody = {
236
+ error?: { message?: string };
237
+ raw?: string;
238
+ };
239
+
240
+ export type QuotaBucketRaw = {
241
+ bucketId?: unknown;
242
+ displayName?: unknown;
243
+ window?: unknown;
244
+ resetTime?: unknown;
245
+ description?: unknown;
246
+ remainingFraction?: unknown;
247
+ };
248
+
249
+ export type QuotaGroupRaw = {
250
+ displayName?: unknown;
251
+ description?: unknown;
252
+ buckets?: QuotaBucketRaw[];
253
+ };
254
+
255
+ export type QuotaSummaryRaw = {
256
+ description?: unknown;
257
+ groups?: QuotaGroupRaw[];
258
+ };
259
+
260
+ export type ModelInfoRaw = {
261
+ isInternal?: unknown;
262
+ displayName?: unknown;
263
+ label?: unknown;
264
+ modelName?: unknown;
265
+ model?: unknown;
266
+ modelProvider?: unknown;
267
+ apiProvider?: unknown;
268
+ supportsThinking?: unknown;
269
+ supportsImages?: unknown;
270
+ recommended?: unknown;
271
+ quotaInfo?: {
272
+ remainingFraction?: unknown;
273
+ resetTime?: unknown;
274
+ };
275
+ };
276
+
277
+ export type AvailableModelsRaw = {
278
+ models?: Record<string, ModelInfoRaw>;
279
+ defaultAgentModelId?: unknown;
280
+ defaultAgentModel?: unknown;
281
+ };
282
+
283
+ export type TierRaw = {
284
+ id?: unknown;
285
+ name?: unknown;
286
+ description?: unknown;
287
+ };
288
+
289
+ export type LoadCodeAssistRaw = {
290
+ currentTier?: TierRaw;
291
+ paidTier?: TierRaw;
292
+ };
@@ -0,0 +1 @@
1
+ export * from "./usage.js";
@@ -0,0 +1,371 @@
1
+ import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
2
+ import {
3
+ antigravityHeaders,
4
+ endpointCandidates,
5
+ extractProjectId,
6
+ fetchAvailableModelsCatalog,
7
+ parseApiKey,
8
+ resolveProjectId,
9
+ } from "../client/client.js";
10
+ import {
11
+ setLastEndpoint,
12
+ setLastError,
13
+ setLastProjectId,
14
+ setLastStatus,
15
+ } from "../diagnostics/diagnostics.js";
16
+ import { isRecord } from "../utils/util.js";
17
+ import { safeError } from "../utils/security.js";
18
+ import { antigravityFetch } from "../utils/http.js";
19
+ import type {
20
+ AccountUsage,
21
+ ApiErrorBody,
22
+ AvailableModelsRaw,
23
+ LoadCodeAssistRaw,
24
+ ModelQuotaRow,
25
+ QuotaBucket,
26
+ QuotaGroup,
27
+ QuotaSummaryRaw,
28
+ TierInfo,
29
+ TierRaw,
30
+ } from "../types/types.js";
31
+
32
+ function clampFraction(value: unknown): number | undefined {
33
+ if (typeof value !== "number" || !Number.isFinite(value)) return undefined;
34
+ if (value < 0) return 0;
35
+ if (value > 1) return 1;
36
+ return value;
37
+ }
38
+
39
+ function remainingPercent(remaining?: number): number | undefined {
40
+ if (remaining === undefined) return undefined;
41
+ return Math.round(remaining * 1000) / 10;
42
+ }
43
+
44
+ function progressBar(remaining?: number, width = 20): string {
45
+ if (remaining === undefined) return `[${"?".repeat(width)}]`;
46
+ const filled = Math.max(0, Math.min(width, Math.round(remaining * width)));
47
+ return `[${"#".repeat(filled)}${"-".repeat(width - filled)}]`;
48
+ }
49
+
50
+ function formatReset(resetTime?: string): string {
51
+ if (!resetTime) return "n/a";
52
+ const ts = Date.parse(resetTime);
53
+ if (!Number.isFinite(ts)) return resetTime;
54
+ const delta = ts - Date.now();
55
+ if (delta <= 0) return "now";
56
+ const totalMin = Math.round(delta / 60000);
57
+ const days = Math.floor(totalMin / (60 * 24));
58
+ const hours = Math.floor((totalMin % (60 * 24)) / 60);
59
+ const mins = totalMin % 60;
60
+ if (days > 0) return `${days}d ${hours}h`;
61
+ if (hours > 0) return `${hours}h ${mins}m`;
62
+ return `${mins}m`;
63
+ }
64
+
65
+ function jsonHeaders(token: string): Record<string, string> {
66
+ return {
67
+ ...antigravityHeaders(token),
68
+ Accept: "application/json",
69
+ };
70
+ }
71
+
72
+ async function postJson(
73
+ path: string,
74
+ token: string,
75
+ body: Record<string, unknown>,
76
+ ): Promise<{ endpoint: string; status: number; data: unknown }> {
77
+ let lastErrorText = "";
78
+ for (const endpoint of endpointCandidates()) {
79
+ try {
80
+ const res = await antigravityFetch(`${endpoint}${path}`, {
81
+ method: "POST",
82
+ headers: jsonHeaders(token),
83
+ body: JSON.stringify(body),
84
+ });
85
+ setLastEndpoint(endpoint);
86
+ setLastStatus(res.status);
87
+ const text = await res.text();
88
+ let data: unknown;
89
+ try {
90
+ data = JSON.parse(text) as unknown;
91
+ } catch {
92
+ data = { raw: text } satisfies ApiErrorBody;
93
+ }
94
+ if (!res.ok) {
95
+ const errorBody = isRecord(data) ? (data as ApiErrorBody) : undefined;
96
+ lastErrorText =
97
+ typeof errorBody?.error?.message === "string" ? errorBody.error.message : text;
98
+ if (![403, 404, 429, 500, 502, 503, 504].includes(res.status)) {
99
+ throw new Error(`${path} failed (${String(res.status)}): ${lastErrorText.slice(0, 300)}`);
100
+ }
101
+ continue;
102
+ }
103
+ return { endpoint, status: res.status, data };
104
+ } catch (error) {
105
+ lastErrorText = safeError(error);
106
+ setLastError(lastErrorText);
107
+ }
108
+ }
109
+ throw new Error(`${path} failed: ${lastErrorText || "no endpoint available"}`);
110
+ }
111
+
112
+ function parseQuotaSummary(data: unknown): { groups: QuotaGroup[]; description?: string } {
113
+ const summary = (isRecord(data) ? data : {}) as QuotaSummaryRaw;
114
+ const groups: QuotaGroup[] = [];
115
+ for (const group of summary.groups || []) {
116
+ const buckets: QuotaBucket[] = [];
117
+ for (const bucket of group.buckets || []) {
118
+ const remaining = clampFraction(bucket.remainingFraction);
119
+ if (remaining === undefined && !bucket.bucketId) continue;
120
+ buckets.push({
121
+ bucketId: String(bucket.bucketId || bucket.displayName || "unknown"),
122
+ displayName: String(bucket.displayName || bucket.bucketId || "Limit"),
123
+ window: bucket.window ? String(bucket.window) : undefined,
124
+ resetTime: bucket.resetTime ? String(bucket.resetTime) : undefined,
125
+ description: bucket.description ? String(bucket.description) : undefined,
126
+ remainingFraction: remaining ?? 0,
127
+ });
128
+ }
129
+ if (!buckets.length && !group.displayName) continue;
130
+ groups.push({
131
+ displayName: String(group.displayName || "Quota group"),
132
+ description: group.description ? String(group.description) : undefined,
133
+ buckets,
134
+ });
135
+ }
136
+ return {
137
+ groups,
138
+ description: summary.description ? String(summary.description) : undefined,
139
+ };
140
+ }
141
+
142
+ function parseModels(data: unknown): {
143
+ models: ModelQuotaRow[];
144
+ defaultAgentModelId?: string;
145
+ } {
146
+ const raw = (isRecord(data) ? data : {}) as AvailableModelsRaw;
147
+ const modelsObj = raw.models && isRecord(raw.models) ? raw.models : {};
148
+ const models: ModelQuotaRow[] = [];
149
+ for (const [modelId, info] of Object.entries(modelsObj)) {
150
+ if (!info || !isRecord(info)) continue;
151
+ if (info.isInternal || String(modelId).startsWith("chat_")) continue;
152
+ const qi = isRecord(info.quotaInfo) ? info.quotaInfo : {};
153
+ models.push({
154
+ modelId,
155
+ displayName:
156
+ typeof info.displayName === "string"
157
+ ? info.displayName
158
+ : typeof info.label === "string"
159
+ ? info.label
160
+ : typeof info.modelName === "string"
161
+ ? info.modelName
162
+ : undefined,
163
+ remainingFraction: clampFraction(qi.remainingFraction),
164
+ resetTime: qi.resetTime ? String(qi.resetTime) : undefined,
165
+ modelProvider:
166
+ typeof info.modelProvider === "string"
167
+ ? info.modelProvider
168
+ : typeof info.apiProvider === "string"
169
+ ? info.apiProvider
170
+ : undefined,
171
+ supportsThinking: !!info.supportsThinking,
172
+ supportsImages: !!info.supportsImages,
173
+ recommended: !!info.recommended,
174
+ });
175
+ }
176
+ models.sort((a, b) => a.modelId.localeCompare(b.modelId));
177
+ return {
178
+ models,
179
+ defaultAgentModelId:
180
+ raw.defaultAgentModelId || raw.defaultAgentModel
181
+ ? String(raw.defaultAgentModelId || raw.defaultAgentModel)
182
+ : undefined,
183
+ };
184
+ }
185
+
186
+ function parseTier(value: unknown): TierInfo | undefined {
187
+ if (!isRecord(value)) return undefined;
188
+ const tier = value as TierRaw;
189
+ if (!tier.id && !tier.name) return undefined;
190
+ return {
191
+ id: tier.id ? String(tier.id) : undefined,
192
+ name: tier.name ? String(tier.name) : undefined,
193
+ description: tier.description ? String(tier.description) : undefined,
194
+ };
195
+ }
196
+
197
+ async function loadCodeAssistSafe(token: string) {
198
+ try {
199
+ return await postJson("/v1internal:loadCodeAssist", token, {
200
+ metadata: {
201
+ ideType: "ANTIGRAVITY",
202
+ platform: "PLATFORM_UNSPECIFIED",
203
+ pluginType: "GEMINI",
204
+ },
205
+ });
206
+ } catch {
207
+ return null;
208
+ }
209
+ }
210
+
211
+ /**
212
+ * The user-quota-summary RPC is gated behind a paid subscription: free-tier
213
+ * accounts get 403 SUBSCRIPTION_REQUIRED (#3501). It is best-effort diagnostics
214
+ * only — never let it block the rest of the account data (models, tier, project).
215
+ */
216
+ async function fetchQuotaSummarySafe(token: string): Promise<
217
+ | { ok: true; result: { endpoint: string; status: number; data: unknown } }
218
+ | {
219
+ ok: false;
220
+ error: string;
221
+ }
222
+ > {
223
+ try {
224
+ return { ok: true, result: await postJson("/v1internal:retrieveUserQuotaSummary", token, {}) };
225
+ } catch (error) {
226
+ const msg = safeError(error);
227
+ setLastError(msg);
228
+ return { ok: false, error: msg };
229
+ }
230
+ }
231
+
232
+ export async function fetchAccountUsage(apiKeyRaw?: string): Promise<AccountUsage> {
233
+ const creds = parseApiKey(apiKeyRaw);
234
+ const initialProjectId =
235
+ creds.projectId ||
236
+ resolveProjectId({
237
+ token: creds.token,
238
+ credentialProjectId: creds.projectId,
239
+ });
240
+
241
+ // Fetch loadCodeAssist, quota summary, and available models all in parallel
242
+ // to minimize command execution latency.
243
+ const [assistResult, summaryRes, available] = await Promise.all([
244
+ loadCodeAssistSafe(creds.token),
245
+ fetchQuotaSummarySafe(creds.token),
246
+ fetchAvailableModelsCatalog(creds.token, initialProjectId),
247
+ ]);
248
+
249
+ // Derive project ID from the loadCodeAssist response or stored project ID.
250
+ const discoveredProject = assistResult ? extractProjectId(assistResult.data) : undefined;
251
+ const projectId = resolveProjectId({
252
+ token: creds.token,
253
+ warmedProject: discoveredProject ?? null,
254
+ credentialProjectId: creds.projectId,
255
+ });
256
+ setLastProjectId(projectId);
257
+
258
+ const summary = summaryRes.ok ? summaryRes.result : null;
259
+ const quotaSummaryError = summaryRes.ok ? undefined : summaryRes.error;
260
+ const { groups, description } = summary
261
+ ? parseQuotaSummary(summary.data)
262
+ : { groups: [], description: undefined };
263
+ const { models, defaultAgentModelId } = parseModels(available.data);
264
+
265
+ const assistData = (isRecord(assistResult?.data) ? assistResult.data : {}) as LoadCodeAssistRaw;
266
+ const productTier = parseTier(assistData.currentTier);
267
+ const paidTier = parseTier(assistData.paidTier);
268
+
269
+ // Google returns currentTier=free-tier even for Google AI Pro accounts.
270
+ // The real subscription lives in paidTier (e.g. g1-pro-tier / Google AI Pro).
271
+ const planLabel = paidTier?.name
272
+ ? `${paidTier.name}${paidTier.id ? ` (${paidTier.id})` : ""}`
273
+ : productTier?.name
274
+ ? `${productTier.name}${productTier.id ? ` (${productTier.id})` : ""}`
275
+ : undefined;
276
+
277
+ return {
278
+ projectId,
279
+ endpoint: summary?.endpoint ?? available.endpoint ?? assistResult?.endpoint,
280
+ productTier,
281
+ paidTier,
282
+ planLabel,
283
+ groups,
284
+ groupDescription: description,
285
+ quotaSummaryError,
286
+ models,
287
+ defaultAgentModelId,
288
+ fetchedAt: Date.now(),
289
+ };
290
+ }
291
+
292
+ function quotaErrorNote(msg: string): string {
293
+ if (/SUBSCRIPTION_REQUIRED|#3501|(?:lack|missing).*license/i.test(msg)) {
294
+ return "Aggregate quota summary needs a paid subscription (free-tier can't use that endpoint). Per-model usage is still available via /antigravity.models.";
295
+ }
296
+ return `Aggregate quota summary unavailable: ${msg.slice(0, 160)}`;
297
+ }
298
+
299
+ export function formatUsageSummary(usage: AccountUsage): string {
300
+ const lines: string[] = [];
301
+
302
+ if (usage.planLabel) lines.push(usage.planLabel);
303
+
304
+ if (!usage.groups.length) {
305
+ if (usage.quotaSummaryError) {
306
+ lines.push(quotaErrorNote(usage.quotaSummaryError));
307
+ } else {
308
+ lines.push("No quota groups returned.");
309
+ }
310
+ return lines.join("\n");
311
+ }
312
+
313
+ for (const group of usage.groups) {
314
+ if (lines.length) lines.push("");
315
+ lines.push(group.displayName);
316
+ for (const bucket of group.buckets) {
317
+ const rem = remainingPercent(bucket.remainingFraction);
318
+ lines.push(
319
+ ` ${progressBar(bucket.remainingFraction)} ${bucket.displayName}: ${rem ?? "?"}% left · resets ${formatReset(bucket.resetTime)}`,
320
+ );
321
+ }
322
+ }
323
+
324
+ return lines.join("\n").trimEnd();
325
+ }
326
+
327
+ export function formatModelsList(usage: AccountUsage, opts?: { all?: boolean }): string {
328
+ const lines: string[] = [];
329
+ lines.push("Antigravity available models");
330
+ lines.push(`project=${usage.projectId}`);
331
+ if (usage.defaultAgentModelId) lines.push(`defaultAgentModel=${usage.defaultAgentModelId}`);
332
+ lines.push("");
333
+
334
+ const rows = opts?.all
335
+ ? usage.models
336
+ : usage.models.filter((m) => !/tab_|chat_/i.test(m.modelId));
337
+
338
+ if (!rows.length) {
339
+ lines.push("No models returned.");
340
+ return lines.join("\n");
341
+ }
342
+
343
+ const maxId = Math.max(...rows.map((m) => m.modelId.length), 8);
344
+ for (const m of rows) {
345
+ const rem = remainingPercent(m.remainingFraction);
346
+ const flags = [
347
+ m.recommended ? "recommended" : "",
348
+ m.supportsThinking ? "thinking" : "",
349
+ m.supportsImages ? "images" : "",
350
+ ]
351
+ .filter(Boolean)
352
+ .join(",");
353
+ const name = m.displayName && m.displayName !== m.modelId ? ` ${m.displayName}` : "";
354
+ lines.push(
355
+ `${m.modelId.padEnd(maxId)} rem ${rem === undefined ? " ?" : String(rem).padStart(5)}% reset ${formatReset(m.resetTime).padEnd(8)}${flags ? ` [${flags}]` : ""}${name}`,
356
+ );
357
+ }
358
+ lines.push("");
359
+ lines.push("Note: remaining % is pool-shared (not a private per-model budget).");
360
+ return lines.join("\n");
361
+ }
362
+
363
+ export async function resolveApiKeyFromContext(
364
+ ctx: ExtensionCommandContext,
365
+ ): Promise<string | undefined> {
366
+ try {
367
+ return await ctx.modelRegistry.getApiKeyForProvider("antigravity");
368
+ } catch {
369
+ return undefined;
370
+ }
371
+ }