@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,154 @@
1
+ import type {
2
+ Api,
3
+ Credential,
4
+ Model,
5
+ ModelsStoreEntry,
6
+ RefreshModelsContext,
7
+ } from "@earendil-works/pi-ai";
8
+ import type { ProviderModelConfig } from "@earendil-works/pi-coding-agent";
9
+ import { getApiKey } from "../auth/index.js";
10
+ import { DEFAULT_ENDPOINT, fetchAvailableModelsCatalog, parseApiKey } from "../client/index.js";
11
+ import { ANTIGRAVITY_API } from "../types/types.js";
12
+ import { antigravityEnv, isRecord } from "../utils/util.js";
13
+ import { buildAntigravityCatalog, resolvedCatalog, type AntigravityCatalog } from "./grouping.js";
14
+ import {
15
+ ANTIGRAVITY_MODELS,
16
+ ANTIGRAVITY_ROUTING,
17
+ applyAntigravityCatalog,
18
+ getCurrentAntigravityCatalog,
19
+ registerDiscoveredModelEnums,
20
+ restoreDynamicModelEnums,
21
+ snapshotDynamicModelEnums,
22
+ } from "./models.js";
23
+
24
+ export const DEFAULT_CATALOG_REFRESH_INTERVAL_MS = 4 * 60 * 60 * 1000;
25
+ export const ANTIGRAVITY_PERSIST_KEY = "pi-antigravity";
26
+
27
+ type PersistedAntigravityCatalog = {
28
+ catalog: AntigravityCatalog;
29
+ checkedAt: number;
30
+ modelEnums: Record<string, string>;
31
+ };
32
+
33
+ export function getCatalogRefreshIntervalMs(): number {
34
+ const envVal =
35
+ antigravityEnv("CATALOG_REFRESH_INTERVAL_MS") ?? antigravityEnv("REFRESH_INTERVAL_MS");
36
+ if (envVal) {
37
+ const parsed = Number.parseInt(envVal, 10);
38
+ if (!Number.isNaN(parsed) && parsed >= 0) return parsed;
39
+ }
40
+ return DEFAULT_CATALOG_REFRESH_INTERVAL_MS;
41
+ }
42
+
43
+ const fallbackCatalog = (): AntigravityCatalog => ({
44
+ models: ANTIGRAVITY_MODELS,
45
+ routing: { ...ANTIGRAVITY_ROUTING },
46
+ });
47
+
48
+ /** Restore provider state supplied by Pi before checking offline mode or refresh TTL. */
49
+ export function hydrateAntigravityCatalog(stored: unknown): number {
50
+ if (!isRecord(stored)) return 0;
51
+ const persisted = stored[ANTIGRAVITY_PERSIST_KEY];
52
+ if (!isRecord(persisted)) return 0;
53
+
54
+ if (isStringMap(persisted.modelEnums)) restoreDynamicModelEnums(persisted.modelEnums);
55
+ if (isCatalog(persisted.catalog)) applyAntigravityCatalog(persisted.catalog);
56
+ return typeof persisted.checkedAt === "number" && persisted.checkedAt > 0
57
+ ? persisted.checkedAt
58
+ : 0;
59
+ }
60
+
61
+ export async function discoverAntigravityModels(
62
+ apiKey: string,
63
+ signal?: AbortSignal,
64
+ ): Promise<AntigravityCatalog> {
65
+ const creds = parseApiKey(apiKey);
66
+ const available = await fetchAvailableModelsCatalog(creds.token, creds.projectId, signal);
67
+ const models = available.data.models;
68
+ if (!models || Object.keys(models).length === 0) {
69
+ return { models: [], routing: {} };
70
+ }
71
+ registerDiscoveredModelEnums(models);
72
+ return buildAntigravityCatalog(models, fallbackCatalog());
73
+ }
74
+
75
+ export async function refreshAntigravityModels(
76
+ context: RefreshModelsContext,
77
+ ): Promise<ProviderModelConfig[]> {
78
+ const checkedAt = hydrateAntigravityCatalog(context.stored);
79
+ const current = getCurrentAntigravityCatalog();
80
+ if (!context.allowNetwork) return current.models;
81
+
82
+ const apiKey = apiKeyFromCredential(context.credential);
83
+ if (!apiKey || context.signal.aborted) return current.models;
84
+
85
+ const now = Date.now();
86
+ if (
87
+ !context.force &&
88
+ checkedAt > 0 &&
89
+ now >= checkedAt &&
90
+ now - checkedAt < getCatalogRefreshIntervalMs()
91
+ ) {
92
+ return current.models;
93
+ }
94
+
95
+ try {
96
+ const discovered = await discoverAntigravityModels(apiKey, context.signal);
97
+ if (context.signal.aborted) return current.models;
98
+ const next = resolvedCatalog(discovered, current);
99
+ if (next.models.length > 0 && discovered.models.length > 0) {
100
+ applyAntigravityCatalog(next);
101
+ const refreshedAt = Date.now();
102
+ await context.publish({
103
+ persist: {
104
+ models: toStoredModels(next.models),
105
+ [ANTIGRAVITY_PERSIST_KEY]: {
106
+ catalog: next,
107
+ checkedAt: refreshedAt,
108
+ modelEnums: snapshotDynamicModelEnums(),
109
+ } satisfies PersistedAntigravityCatalog,
110
+ } as unknown as ModelsStoreEntry,
111
+ });
112
+ return next.models;
113
+ }
114
+ } catch (error) {
115
+ // Keep last-known-good models; a failed refresh must not wipe the catalog.
116
+ // Forced/manual refreshes must still report the failure to their caller.
117
+ if (context.force) throw error;
118
+ }
119
+
120
+ return getCurrentAntigravityCatalog().models;
121
+ }
122
+
123
+ function isCatalog(value: unknown): value is AntigravityCatalog {
124
+ return (
125
+ isRecord(value) &&
126
+ Array.isArray(value.models) &&
127
+ value.models.length > 0 &&
128
+ isRecord(value.routing)
129
+ );
130
+ }
131
+
132
+ function isStringMap(value: unknown): value is Record<string, string> {
133
+ return isRecord(value) && Object.values(value).every((entry) => typeof entry === "string");
134
+ }
135
+
136
+ function apiKeyFromCredential(credential: Credential | undefined): string | undefined {
137
+ if (!credential) return undefined;
138
+ if (credential.type === "api_key") {
139
+ return typeof credential.key === "string" && credential.key ? credential.key : undefined;
140
+ }
141
+ if (credential.type === "oauth" && typeof credential.access === "string") {
142
+ return getApiKey(credential);
143
+ }
144
+ return undefined;
145
+ }
146
+
147
+ function toStoredModels(models: ProviderModelConfig[]): Model<Api>[] {
148
+ return models.map((model) => ({
149
+ ...model,
150
+ api: ANTIGRAVITY_API,
151
+ provider: "antigravity",
152
+ baseUrl: DEFAULT_ENDPOINT,
153
+ }));
154
+ }
@@ -0,0 +1,424 @@
1
+ import type { ProviderModelConfig } from "@earendil-works/pi-coding-agent";
2
+ import { ThinkingEffort } from "../types/enums.js";
3
+ import type { AntigravityRouting, ModelInfoRaw } from "../types/types.js";
4
+
5
+ export type AntigravityCatalog = {
6
+ models: ProviderModelConfig[];
7
+ routing: Record<string, AntigravityRouting>;
8
+ };
9
+
10
+ type ThinkingLevel = ThinkingEffort;
11
+
12
+ type RuntimeGroup = {
13
+ publicId: string;
14
+ variants: Partial<Record<ThinkingLevel, string>>;
15
+ unsuffixed?: string;
16
+ displayNames: string[];
17
+ /** Catalog capability: true/false when advertised, undefined when omitted. */
18
+ supportsThinking?: boolean;
19
+ supportsImages?: boolean;
20
+ };
21
+
22
+ const THINKING_SUFFIXES: Array<{ suffix: string; level: ThinkingLevel }> = [
23
+ { suffix: "extra-low", level: ThinkingEffort.Low },
24
+ { suffix: "extra-high", level: ThinkingEffort.Xhigh },
25
+ { suffix: "thinking", level: ThinkingEffort.High },
26
+ { suffix: "minimal", level: ThinkingEffort.Minimal },
27
+ { suffix: "medium", level: ThinkingEffort.Medium },
28
+ { suffix: "high", level: ThinkingEffort.High },
29
+ { suffix: "low", level: ThinkingEffort.Low },
30
+ ];
31
+
32
+ const DISPLAY_LEVELS: Array<{ pattern: RegExp; level: ThinkingLevel }> = [
33
+ { pattern: /\(\s*extra\s*low\s*\)/i, level: ThinkingEffort.Low },
34
+ { pattern: /\(\s*extra\s*high\s*\)/i, level: ThinkingEffort.Xhigh },
35
+ { pattern: /\(\s*thinking\s*\)/i, level: ThinkingEffort.High },
36
+ { pattern: /\(\s*minimal\s*\)/i, level: ThinkingEffort.Minimal },
37
+ { pattern: /\(\s*medium\s*\)/i, level: ThinkingEffort.Medium },
38
+ { pattern: /\(\s*high\s*\)/i, level: ThinkingEffort.High },
39
+ { pattern: /\(\s*low\s*\)/i, level: ThinkingEffort.Low },
40
+ ];
41
+
42
+ /** Known backend aliases whose runtime IDs do not share a thinking suffix with the public family. */
43
+ const RUNTIME_ALIASES: Record<string, { publicId: string; level: ThinkingLevel }> = {
44
+ "gemini-3-flash-agent": { publicId: "gemini-3.5-flash", level: ThinkingEffort.High },
45
+ "gemini-pro-agent": { publicId: "gemini-3.1-pro", level: ThinkingEffort.High },
46
+ };
47
+
48
+ const PI_LEVELS = [
49
+ ThinkingEffort.Off,
50
+ ThinkingEffort.Minimal,
51
+ ThinkingEffort.Low,
52
+ ThinkingEffort.Medium,
53
+ ThinkingEffort.High,
54
+ ThinkingEffort.Xhigh,
55
+ "max",
56
+ ] as const;
57
+
58
+ const ZERO_COST = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
59
+
60
+ export function isSelectableRuntimeModelId(id: string): boolean {
61
+ if (!/^(gemini-|claude-|gpt-oss-)/i.test(id) || /\s/.test(id) || /^MODEL_/i.test(id)) {
62
+ return false;
63
+ }
64
+ if (/^(chat_|tab_)/i.test(id)) return false;
65
+ if (/image/i.test(id)) return false;
66
+ return true;
67
+ }
68
+
69
+ export function resolvedCatalog(
70
+ discovered: AntigravityCatalog | undefined,
71
+ current: AntigravityCatalog,
72
+ ): AntigravityCatalog {
73
+ if (discovered && discovered.models.length > 0) return discovered;
74
+ return current;
75
+ }
76
+
77
+ export function buildAntigravityCatalog(
78
+ rawModels: Record<string, ModelInfoRaw>,
79
+ fallback: AntigravityCatalog,
80
+ ): AntigravityCatalog {
81
+ const groups = new Map<string, RuntimeGroup>();
82
+
83
+ for (const [runtimeId, info] of Object.entries(rawModels)) {
84
+ if (!isSelectableRuntimeModelId(runtimeId)) continue;
85
+ if (info?.isInternal) continue;
86
+
87
+ const displayName = modelDisplayName(info);
88
+ if (runtimeId.endsWith("-tiered")) {
89
+ const baseId = runtimeId.slice(0, -"-tiered".length);
90
+ const group = ensureGroup(groups, baseId);
91
+ absorbMetadata(group, info, displayName);
92
+ if (!group.unsuffixed) group.unsuffixed = runtimeId;
93
+ continue;
94
+ }
95
+
96
+ const alias = RUNTIME_ALIASES[runtimeId];
97
+ const suffix = alias ? undefined : parseThinkingSuffix(runtimeId);
98
+ const publicId = alias?.publicId ?? suffix?.baseId ?? runtimeId;
99
+ const group = ensureGroup(groups, publicId);
100
+ absorbMetadata(group, info, displayName);
101
+
102
+ const level = alias?.level ?? levelFromDisplayName(displayName) ?? suffix?.level;
103
+ if (level) group.variants[level] = runtimeId;
104
+ else group.unsuffixed = runtimeId;
105
+ }
106
+
107
+ mergeAgentSingletons(groups);
108
+
109
+ if (groups.size === 0) return fallback;
110
+
111
+ const models: ProviderModelConfig[] = [];
112
+ const routing: Record<string, AntigravityRouting> = {};
113
+
114
+ for (const group of groups.values()) {
115
+ const fallbackModel = fallback.models.find((model) => model.id === group.publicId);
116
+ const fallbackRouting = fallback.routing[group.publicId];
117
+ if (fallbackModel && fallbackRouting) {
118
+ models.push(fallbackModel);
119
+ routing[group.publicId] = fallbackRouting;
120
+ continue;
121
+ }
122
+
123
+ const synthesized = synthesizeModel(group, fallback.models);
124
+ models.push(synthesized.model);
125
+ routing[group.publicId] = synthesized.routing;
126
+ }
127
+
128
+ for (const fallbackModel of fallback.models) {
129
+ if (routing[fallbackModel.id]) continue;
130
+ const fallbackRouting = fallback.routing[fallbackModel.id];
131
+ if (!fallbackRouting) continue;
132
+ models.push(fallbackModel);
133
+ routing[fallbackModel.id] = fallbackRouting;
134
+ }
135
+
136
+ models.sort(comparePublicModels);
137
+ return { models, routing };
138
+ }
139
+
140
+ function ensureGroup(groups: Map<string, RuntimeGroup>, publicId: string): RuntimeGroup {
141
+ const existing = groups.get(publicId);
142
+ if (existing) return existing;
143
+ const created: RuntimeGroup = {
144
+ publicId,
145
+ variants: {},
146
+ displayNames: [],
147
+ };
148
+ groups.set(publicId, created);
149
+ return created;
150
+ }
151
+
152
+ function absorbMetadata(
153
+ group: RuntimeGroup,
154
+ info: ModelInfoRaw | undefined,
155
+ displayName: string | undefined,
156
+ ): void {
157
+ if (displayName) group.displayNames.push(displayName);
158
+ if (info?.supportsThinking === true) group.supportsThinking = true;
159
+ else if (info?.supportsThinking === false && group.supportsThinking !== true) {
160
+ group.supportsThinking = false;
161
+ }
162
+ if (info?.supportsImages === true) group.supportsImages = true;
163
+ if (info?.supportsImages === false && group.supportsImages === undefined) {
164
+ group.supportsImages = false;
165
+ }
166
+ }
167
+
168
+ function mergeAgentSingletons(groups: Map<string, RuntimeGroup>): void {
169
+ for (const [publicId, group] of [...groups.entries()]) {
170
+ if (!publicId.endsWith("-agent")) continue;
171
+ if (Object.keys(group.variants).length > 0) continue;
172
+ const family = displayFamily(group.displayNames[0]);
173
+ if (!family) continue;
174
+ const target = [...groups.values()].find(
175
+ (candidate) =>
176
+ candidate.publicId !== publicId &&
177
+ candidate.displayNames.some((name) => displayFamily(name) === family),
178
+ );
179
+ if (!target || !group.unsuffixed) continue;
180
+ const level = levelFromDisplayName(group.displayNames[0]) ?? ThinkingEffort.High;
181
+ target.variants[level] = group.unsuffixed;
182
+ absorbMetadata(target, { supportsThinking: group.supportsThinking }, group.displayNames[0]);
183
+ groups.delete(publicId);
184
+ }
185
+ }
186
+
187
+ function parseThinkingSuffix(
188
+ runtimeId: string,
189
+ ): { baseId: string; level: ThinkingLevel } | undefined {
190
+ const lower = runtimeId.toLowerCase();
191
+ for (const { suffix, level } of THINKING_SUFFIXES) {
192
+ if (lower.endsWith(`-${suffix}`)) {
193
+ return { baseId: runtimeId.slice(0, -(suffix.length + 1)), level };
194
+ }
195
+ }
196
+ return undefined;
197
+ }
198
+
199
+ function levelFromDisplayName(displayName: string | undefined): ThinkingLevel | undefined {
200
+ if (!displayName) return undefined;
201
+ for (const { pattern, level } of DISPLAY_LEVELS) {
202
+ if (pattern.test(displayName)) return level;
203
+ }
204
+ return undefined;
205
+ }
206
+
207
+ function modelDisplayName(info: ModelInfoRaw | undefined): string | undefined {
208
+ if (!info) return undefined;
209
+ if (typeof info.displayName === "string" && info.displayName) return info.displayName;
210
+ if (typeof info.label === "string" && info.label) return info.label;
211
+ if (typeof info.modelName === "string" && info.modelName) return info.modelName;
212
+ return undefined;
213
+ }
214
+
215
+ function displayFamily(displayName: string | undefined): string | undefined {
216
+ if (!displayName) return undefined;
217
+ return displayName
218
+ .replace(/\s*\((?:extra\s*low|extra\s*high|low|medium|high|minimal|thinking)\)\s*$/i, "")
219
+ .trim()
220
+ .toLowerCase();
221
+ }
222
+
223
+ function synthesizeModel(
224
+ group: RuntimeGroup,
225
+ fallbackModels: ProviderModelConfig[],
226
+ ): { model: ProviderModelConfig; routing: AntigravityRouting } {
227
+ const template = familyTemplate(group.publicId, fallbackModels);
228
+ const advertisedLevels = advertisedThinkingLevels(group);
229
+ const routing = routingFromVariants(group.publicId, group.variants, group.unsuffixed);
230
+ const supportsImages = group.supportsImages ?? template?.input.includes("image") ?? true;
231
+ const reasoning =
232
+ advertisedLevels.size > 0 ||
233
+ group.supportsThinking === true ||
234
+ (group.supportsThinking === undefined && Boolean(template?.reasoning));
235
+ return {
236
+ model: {
237
+ id: group.publicId,
238
+ name: publicModelName(group),
239
+ reasoning,
240
+ thinkingLevelMap: reasoning ? thinkingLevelMapFromLevels(advertisedLevels) : undefined,
241
+ input: supportsImages ? ["text", "image"] : ["text"],
242
+ cost: template?.cost ?? ZERO_COST,
243
+ contextWindow: template?.contextWindow ?? 128000,
244
+ maxTokens: template?.maxTokens ?? 8192,
245
+ },
246
+ routing,
247
+ };
248
+ }
249
+
250
+ function advertisedThinkingLevels(group: RuntimeGroup): Set<string> {
251
+ const levels = new Set(Object.keys(group.variants));
252
+ if (levels.size > 0) return levels;
253
+ // Explicit false from the catalog must not grow a fake High control.
254
+ if (group.supportsThinking === false) return levels;
255
+ if (group.supportsThinking === true || group.unsuffixed) {
256
+ levels.add(ThinkingEffort.High);
257
+ }
258
+ return levels;
259
+ }
260
+
261
+ function routingFromVariants(
262
+ publicId: string,
263
+ variants: Partial<Record<ThinkingLevel, string>>,
264
+ unsuffixed?: string,
265
+ ): AntigravityRouting {
266
+ const defaultRequestId =
267
+ variants[ThinkingEffort.Low] ??
268
+ variants[ThinkingEffort.Minimal] ??
269
+ variants[ThinkingEffort.Medium] ??
270
+ variants[ThinkingEffort.High] ??
271
+ unsuffixed ??
272
+ publicId;
273
+
274
+ const pick = (...keys: ThinkingLevel[]): string => {
275
+ for (const key of keys) {
276
+ const id = variants[key];
277
+ if (id) return id;
278
+ }
279
+ return unsuffixed ?? defaultRequestId;
280
+ };
281
+
282
+ return {
283
+ off: pick(
284
+ ThinkingEffort.Low,
285
+ ThinkingEffort.Minimal,
286
+ ThinkingEffort.Medium,
287
+ ThinkingEffort.High,
288
+ ),
289
+ routing: {
290
+ minimal: pick(
291
+ ThinkingEffort.Minimal,
292
+ ThinkingEffort.Low,
293
+ ThinkingEffort.Medium,
294
+ ThinkingEffort.High,
295
+ ),
296
+ low: pick(
297
+ ThinkingEffort.Low,
298
+ ThinkingEffort.Minimal,
299
+ ThinkingEffort.Medium,
300
+ ThinkingEffort.High,
301
+ ),
302
+ medium: pick(
303
+ ThinkingEffort.Medium,
304
+ ThinkingEffort.Low,
305
+ ThinkingEffort.High,
306
+ ThinkingEffort.Minimal,
307
+ ),
308
+ high: pick(
309
+ ThinkingEffort.High,
310
+ ThinkingEffort.Medium,
311
+ ThinkingEffort.Low,
312
+ ThinkingEffort.Minimal,
313
+ ),
314
+ xhigh: pick(
315
+ ThinkingEffort.Xhigh,
316
+ ThinkingEffort.High,
317
+ ThinkingEffort.Medium,
318
+ ThinkingEffort.Low,
319
+ ),
320
+ },
321
+ defaultRequestId,
322
+ };
323
+ }
324
+
325
+ function thinkingLevelMapFromLevels(levels: Set<string>): ProviderModelConfig["thinkingLevelMap"] {
326
+ const map: NonNullable<ProviderModelConfig["thinkingLevelMap"]> = {};
327
+ for (const level of PI_LEVELS) {
328
+ map[level] = levels.has(level) ? level : null;
329
+ }
330
+ if (levels.size === 0) map.high = "high";
331
+ return map;
332
+ }
333
+
334
+ function familyTemplate(
335
+ publicId: string,
336
+ fallbackModels: ProviderModelConfig[],
337
+ ): ProviderModelConfig | undefined {
338
+ if (/^gemini-.*-flash/i.test(publicId)) {
339
+ return fallbackModels.find((model) => /^gemini-.*-flash/i.test(model.id));
340
+ }
341
+ if (/^gemini-.*-pro/i.test(publicId)) {
342
+ return fallbackModels.find((model) => /^gemini-.*-pro/i.test(model.id));
343
+ }
344
+ if (publicId.startsWith("claude-opus")) {
345
+ return fallbackModels.find((model) => model.id.startsWith("claude-opus"));
346
+ }
347
+ if (publicId.startsWith("claude-")) {
348
+ return (
349
+ fallbackModels.find((model) => model.id.startsWith("claude-sonnet")) ??
350
+ fallbackModels.find((model) => model.id.startsWith("claude-"))
351
+ );
352
+ }
353
+ if (publicId.startsWith("gpt-oss")) {
354
+ return fallbackModels.find((model) => model.id.startsWith("gpt-oss"));
355
+ }
356
+ if (publicId.startsWith("gemini-")) {
357
+ return fallbackModels.find((model) => model.id.startsWith("gemini-"));
358
+ }
359
+ return undefined;
360
+ }
361
+
362
+ function publicModelName(group: RuntimeGroup): string {
363
+ const family = group.displayNames.map((name) => displayFamily(name)).find(Boolean);
364
+ if (family) {
365
+ return `${titleCase(family)} (Antigravity)`;
366
+ }
367
+ return `${humanizePublicId(group.publicId)} (Antigravity)`;
368
+ }
369
+
370
+ function titleCase(value: string): string {
371
+ return value.replace(/\b([a-z])/g, (char) => char.toUpperCase());
372
+ }
373
+
374
+ export function humanizePublicId(id: string): string {
375
+ const tokens = id.split("-");
376
+ const words: string[] = [];
377
+ for (let i = 0; i < tokens.length; i++) {
378
+ const token = tokens[i];
379
+ if (!token) continue;
380
+ const next = tokens[i + 1];
381
+ if (token === "gpt" && next === "oss") {
382
+ words.push("GPT-OSS");
383
+ i++;
384
+ continue;
385
+ }
386
+ if (/^\d+$/.test(token) && next && /^\d+$/.test(next)) {
387
+ words.push(`${token}.${next}`);
388
+ i++;
389
+ continue;
390
+ }
391
+ if (/^\d/.test(token)) {
392
+ words.push(token.toUpperCase());
393
+ continue;
394
+ }
395
+ words.push(token.charAt(0).toUpperCase() + token.slice(1));
396
+ }
397
+ return words.join(" ");
398
+ }
399
+
400
+ function parseGeminiVersion(id: string): number {
401
+ const match = id.match(/^gemini-(\d+)(?:\.(\d+))?/i);
402
+ if (!match) return 0;
403
+ return Number(match[1]) * 1000 + Number(match[2] || 0);
404
+ }
405
+
406
+ function comparePublicModels(a: ProviderModelConfig, b: ProviderModelConfig): number {
407
+ const rankA = modelRank(a.id);
408
+ const rankB = modelRank(b.id);
409
+ if (rankA[0] !== rankB[0]) return rankA[0] - rankB[0];
410
+ if (rankA[1] !== rankB[1]) return rankA[1] - rankB[1];
411
+ return a.id.localeCompare(b.id);
412
+ }
413
+
414
+ function modelRank(id: string): [number, number] {
415
+ const version = parseGeminiVersion(id);
416
+ if (/^gemini-.*flash/i.test(id) && !/pro/i.test(id)) return [0, -version];
417
+ if (id.startsWith("claude-opus")) return [1, 0];
418
+ if (id.startsWith("claude-sonnet")) return [2, 0];
419
+ if (id.startsWith("claude-")) return [3, 0];
420
+ if (/^gemini-.*pro/i.test(id)) return [4, -version];
421
+ if (id.startsWith("gemini-")) return [5, -version];
422
+ if (id.startsWith("gpt-oss")) return [6, 0];
423
+ return [7, 0];
424
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./models.js";
2
+ export * from "./grouping.js";
3
+ export * from "./discovery.js";