@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.
- package/README.md +4 -2
- package/THIRD_PARTY_NOTICES.md +49 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +3 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +16 -11
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +20 -6
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +12 -7
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +98 -0
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
- package/node_modules/@herbertgao/sol-pi/LICENSE +19 -0
- package/node_modules/@herbertgao/sol-pi/README.md +159 -0
- package/node_modules/@herbertgao/sol-pi/SECURITY.md +26 -0
- package/node_modules/@herbertgao/sol-pi/THIRD_PARTY_NOTICES.md +19 -0
- package/node_modules/@herbertgao/sol-pi/agents-install.md +150 -0
- package/node_modules/@herbertgao/sol-pi/assets/sol-pi-hero.png +0 -0
- package/node_modules/@herbertgao/sol-pi/docs/compatibility.md +69 -0
- package/node_modules/@herbertgao/sol-pi/docs/configuration.md +75 -0
- package/node_modules/@herbertgao/sol-pi/package.json +76 -0
- package/node_modules/@herbertgao/sol-pi/scripts/check-pi-compat.mjs +32 -0
- package/node_modules/@herbertgao/sol-pi/scripts/check-sol-pi-config.mjs +120 -0
- package/node_modules/@herbertgao/sol-pi/sol-pi.example.json +10 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/config.ts +135 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/file-queue.ts +74 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/index.ts +185 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/then-run.ts +128 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/archive.ts +53 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/candidate.ts +101 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/config.ts +71 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/index.ts +220 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/journal.ts +25 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/provider.ts +164 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/receipt.ts +177 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/index.ts +227 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/ledger.ts +20 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/observation.ts +252 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/economics.ts +237 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/extension.ts +455 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/index.ts +49 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/plan.ts +79 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/state.ts +208 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/tools.ts +100 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/index.ts +42 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/runtime-paths.ts +17 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/tui.ts +71 -0
- package/node_modules/@narumitw/pi-btw/dist/index.ts +12 -2
- package/node_modules/@narumitw/pi-btw/dist/index.ts.map +2 -2
- package/node_modules/@narumitw/pi-btw/package.json +1 -1
- package/node_modules/@narumitw/pi-btw/src/btw.ts +13 -2
- package/node_modules/pi-antigravity/LICENSE +21 -0
- package/node_modules/pi-antigravity/README.md +194 -0
- package/node_modules/pi-antigravity/package.json +67 -0
- package/node_modules/pi-antigravity/src/auth/index.ts +14 -0
- package/node_modules/pi-antigravity/src/auth/oauth.ts +442 -0
- package/node_modules/pi-antigravity/src/client/client.ts +561 -0
- package/node_modules/pi-antigravity/src/client/index.ts +1 -0
- package/node_modules/pi-antigravity/src/diagnostics/diagnostics.ts +96 -0
- package/node_modules/pi-antigravity/src/diagnostics/index.ts +1 -0
- package/node_modules/pi-antigravity/src/image/image.ts +336 -0
- package/node_modules/pi-antigravity/src/image/index.ts +1 -0
- package/node_modules/pi-antigravity/src/index.ts +280 -0
- package/node_modules/pi-antigravity/src/models/discovery.ts +154 -0
- package/node_modules/pi-antigravity/src/models/grouping.ts +424 -0
- package/node_modules/pi-antigravity/src/models/index.ts +3 -0
- package/node_modules/pi-antigravity/src/models/models.ts +500 -0
- package/node_modules/pi-antigravity/src/stream/index.ts +1 -0
- package/node_modules/pi-antigravity/src/stream/stream.ts +1460 -0
- package/node_modules/pi-antigravity/src/types/enums.ts +42 -0
- package/node_modules/pi-antigravity/src/types/index.ts +2 -0
- package/node_modules/pi-antigravity/src/types/types.ts +292 -0
- package/node_modules/pi-antigravity/src/usage/index.ts +1 -0
- package/node_modules/pi-antigravity/src/usage/usage.ts +371 -0
- package/node_modules/pi-antigravity/src/utils/http.ts +91 -0
- package/node_modules/pi-antigravity/src/utils/index.ts +3 -0
- package/node_modules/pi-antigravity/src/utils/security.ts +73 -0
- package/node_modules/pi-antigravity/src/utils/util.ts +132 -0
- package/node_modules/pi-antigravity/tsconfig.json +21 -0
- package/node_modules/pi-lens/CHANGELOG.md +176 -0
- package/node_modules/pi-lens/README.md +13 -8
- package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +3 -1
- package/node_modules/pi-lens/dist/clients/analysed-root.js +1 -0
- package/node_modules/pi-lens/dist/clients/ast-grep-tool-logger.js +1 -1
- package/node_modules/pi-lens/dist/clients/biome-client.js +13 -2
- package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +2 -0
- package/node_modules/pi-lens/dist/clients/cache-observability.js +122 -1
- package/node_modules/pi-lens/dist/clients/complexity-client.js +5 -0
- package/node_modules/pi-lens/dist/clients/config-diagnostic-codes.js +2 -0
- package/node_modules/pi-lens/dist/clients/config-resolve.js +6 -3
- package/node_modules/pi-lens/dist/clients/config-schema.js +17 -0
- package/node_modules/pi-lens/dist/clients/config-warn.js +2 -2
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +8 -1
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +5 -1
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +38 -15
- package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +5 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +2 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +4 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/dart-analyze.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/fish-indent.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +3 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +19 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/prisma-validate.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +12 -12
- package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rubocop.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +2 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +12 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +2 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +5 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +2 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +8 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +4 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +2 -1
- package/node_modules/pi-lens/dist/clients/effective-config.js +12 -2
- package/node_modules/pi-lens/dist/clients/extension-log.js +2 -0
- package/node_modules/pi-lens/dist/clients/file-role.js +18 -1
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +4 -0
- package/node_modules/pi-lens/dist/clients/formatters.js +54 -188
- package/node_modules/pi-lens/dist/clients/generation-guard.js +4 -0
- package/node_modules/pi-lens/dist/clients/gitleaks-client.js +42 -6
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +48 -7
- package/node_modules/pi-lens/dist/clients/installer/index.js +196 -52
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +9 -1
- package/node_modules/pi-lens/dist/clients/knip-client.js +9 -2
- package/node_modules/pi-lens/dist/clients/language-profile.js +12 -2
- package/node_modules/pi-lens/dist/clients/latency-logger.js +2 -0
- package/node_modules/pi-lens/dist/clients/lens-config.js +4 -0
- package/node_modules/pi-lens/dist/clients/lsp/config.js +36 -7
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +24 -1
- package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +78 -0
- package/node_modules/pi-lens/dist/clients/lsp/index.js +281 -45
- package/node_modules/pi-lens/dist/clients/lsp/server.js +62 -15
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +37 -4
- package/node_modules/pi-lens/dist/clients/mcp/analyze.js +3 -0
- package/node_modules/pi-lens/dist/clients/mcp/session.js +2 -0
- package/node_modules/pi-lens/dist/clients/opengrep-client.js +2 -0
- package/node_modules/pi-lens/dist/clients/package-manager.js +2 -1
- package/node_modules/pi-lens/dist/clients/php-cs-fixer-config.js +8 -3
- package/node_modules/pi-lens/dist/clients/pipeline.js +3 -2
- package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +38 -10
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +10 -9
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +3 -0
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +2 -0
- package/node_modules/pi-lens/dist/clients/review-graph-logger.js +2 -0
- package/node_modules/pi-lens/dist/clients/ruff-client.js +18 -9
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +9 -0
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +5 -0
- package/node_modules/pi-lens/dist/clients/runtime-session.js +13 -4
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +4 -1
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +48 -1
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +2 -2
- package/node_modules/pi-lens/dist/clients/session-event-guard.js +69 -1
- package/node_modules/pi-lens/dist/clients/sg-runner.js +2 -1
- package/node_modules/pi-lens/dist/clients/situational-tool-telemetry.js +108 -0
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +291 -76
- package/node_modules/pi-lens/dist/clients/tool-config.js +199 -0
- package/node_modules/pi-lens/dist/clients/tool-cwd.js +299 -0
- package/node_modules/pi-lens/dist/clients/tool-probe.js +53 -0
- package/node_modules/pi-lens/dist/clients/tool-set-policy.js +42 -0
- package/node_modules/pi-lens/dist/clients/trivy-client.js +9 -1
- package/node_modules/pi-lens/dist/clients/turn-context.js +52 -0
- package/node_modules/pi-lens/dist/clients/widget-state.js +4 -3
- package/node_modules/pi-lens/dist/index.js +21969 -20005
- package/node_modules/pi-lens/dist/mcp/analyze-cli.js +3 -2
- package/node_modules/pi-lens/dist/mcp/server.js +135 -159
- package/node_modules/pi-lens/dist/tools/activate-tools.js +10 -7
- package/node_modules/pi-lens/dist/tools/ast-grep-outline.js +2 -13
- package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +8 -13
- package/node_modules/pi-lens/dist/tools/ast-grep-search.js +83 -39
- package/node_modules/pi-lens/dist/tools/effective-config.js +4 -3
- package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +1 -10
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +353 -85
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +21 -110
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +20 -44
- package/node_modules/pi-lens/dist/tools/module-report.js +5 -9
- package/node_modules/pi-lens/dist/tools/project-report.js +9 -17
- package/node_modules/pi-lens/dist/tools/render-compact.js +280 -1
- package/node_modules/pi-lens/dist/tools/symbol-search.js +2 -2
- package/node_modules/pi-lens/docs/agent-guide.md +3 -4
- package/node_modules/pi-lens/docs/agent-tools.md +46 -22
- package/node_modules/pi-lens/docs/configuration.md +9 -0
- package/node_modules/pi-lens/docs/environment-variables.md +0 -5
- package/node_modules/pi-lens/docs/features.md +5 -5
- package/node_modules/pi-lens/docs/globalconfig.md +11 -1
- package/node_modules/pi-lens/docs/mcp.md +13 -1
- package/node_modules/pi-lens/docs/pi-lens-fixer.md +71 -0
- package/node_modules/pi-lens/docs/pi-lens-investigator.md +15 -0
- package/node_modules/pi-lens/docs/pi-lens-monitor.md +88 -0
- package/node_modules/pi-lens/docs/pi-lens-reviewer.md +35 -0
- package/node_modules/pi-lens/docs/pi-lens-subagent.md +12 -4
- package/node_modules/pi-lens/docs/public-api-stability.md +1 -0
- package/node_modules/pi-lens/docs/real-harness.md +46 -0
- package/node_modules/pi-lens/docs/release-qa-baseline.md +5 -1
- package/node_modules/pi-lens/docs/servercapabilities.md +1 -6
- package/node_modules/pi-lens/docs/settings.md +37 -2
- package/node_modules/pi-lens/docs/tools_improvement2.md +4 -4
- package/node_modules/pi-lens/docs/tree-sitter_rules_catalog.md +1 -1
- package/node_modules/pi-lens/docs/usage.md +13 -3
- package/node_modules/pi-lens/package.json +10 -1
- package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/sql-injection.yml +7 -3
- package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +8 -6
- package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +19 -9
- package/node_modules/pi-web-access/CHANGELOG.md +29 -0
- package/node_modules/pi-web-access/README.md +33 -22
- package/node_modules/pi-web-access/abortable.ts +17 -0
- package/node_modules/pi-web-access/crawl4ai.ts +204 -0
- package/node_modules/pi-web-access/credential-source.ts +1 -0
- package/node_modules/pi-web-access/curator-page.ts +20 -2
- package/node_modules/pi-web-access/curator-run.ts +44 -0
- package/node_modules/pi-web-access/curator-server.ts +3 -1
- package/node_modules/pi-web-access/duckduckgo.ts +1 -1
- package/node_modules/pi-web-access/extract.ts +57 -12
- package/node_modules/pi-web-access/fetch-params.ts +1 -1
- package/node_modules/pi-web-access/gemini-search.ts +9 -5
- package/node_modules/pi-web-access/index.ts +25 -18
- package/node_modules/pi-web-access/openai-search.ts +35 -13
- package/node_modules/pi-web-access/package.json +2 -2
- package/node_modules/pi-web-access/page-query.ts +5 -2
- package/node_modules/pi-web-access/query-rewrite.ts +5 -2
- package/node_modules/pi-web-access/serpapi.ts +220 -0
- package/node_modules/pi-web-access/ssrf-protection.ts +5 -1
- package/node_modules/pi-web-access/storage.ts +10 -0
- package/node_modules/pi-web-access/summary-review.ts +34 -21
- package/node_modules/pi-web-access/utils.ts +6 -4
- package/package.json +11 -5
- package/node_modules/pi-lens/dist/tools/ast-dump.js +0 -103
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { antigravityEnv } from "./util.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Node's built-in fetch keeps an idle socket for only 4 seconds unless the server
|
|
5
|
+
* advertises a longer `Keep-Alive: timeout=`. The Cloud Code Assist endpoint sends no
|
|
6
|
+
* such header, and interactive coding turns are almost always more than 4 seconds
|
|
7
|
+
* apart, so without a dedicated pool every message pays a fresh DNS + TCP + TLS
|
|
8
|
+
* handshake. A long-lived dispatcher removes that per-turn setup cost.
|
|
9
|
+
*
|
|
10
|
+
* The dispatcher is scoped to this provider's requests rather than installed with
|
|
11
|
+
* `setGlobalDispatcher`, so it never changes HTTP behaviour for the rest of the host
|
|
12
|
+
* process or for other extensions.
|
|
13
|
+
*
|
|
14
|
+
* Node 22+ global `fetch` cannot take an npm `undici.Agent` (handler mismatch).
|
|
15
|
+
* Those runtimes already pool connections natively, so we skip the custom Agent.
|
|
16
|
+
*/
|
|
17
|
+
const KEEP_ALIVE_TIMEOUT_MS = 60_000;
|
|
18
|
+
const KEEP_ALIVE_MAX_TIMEOUT_MS = 5 * 60_000;
|
|
19
|
+
const CONNECT_TIMEOUT_MS = 10_000;
|
|
20
|
+
const PREWARM_TIMEOUT_MS = 5_000;
|
|
21
|
+
|
|
22
|
+
/** `dispatcher` is an undici extension to RequestInit that Node's fetch honours. */
|
|
23
|
+
type DispatcherInit = RequestInit & { dispatcher?: unknown };
|
|
24
|
+
|
|
25
|
+
let dispatcherPromise: Promise<unknown> | undefined;
|
|
26
|
+
|
|
27
|
+
function hasProxyConfiguration(): boolean {
|
|
28
|
+
return ["HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY", "http_proxy", "https_proxy", "all_proxy"].some(
|
|
29
|
+
(name) => Boolean(process.env[name]?.trim()),
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function getDispatcher(): Promise<unknown> {
|
|
34
|
+
dispatcherPromise ??= (async () => {
|
|
35
|
+
// Pi configures a proxy-aware global dispatcher. Passing a private Agent here
|
|
36
|
+
// would bypass it and make Antigravity requests connect directly instead.
|
|
37
|
+
if (antigravityEnv("NO_KEEPALIVE") === "1" || hasProxyConfiguration()) {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
const nodeMajor = Number(process.versions.node?.split(".")[0]);
|
|
41
|
+
if (!Number.isNaN(nodeMajor) && nodeMajor >= 22) {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const { Agent } = await import("undici");
|
|
46
|
+
return new Agent({
|
|
47
|
+
keepAliveTimeout: KEEP_ALIVE_TIMEOUT_MS,
|
|
48
|
+
keepAliveMaxTimeout: KEEP_ALIVE_MAX_TIMEOUT_MS,
|
|
49
|
+
connections: 8,
|
|
50
|
+
connect: { timeout: CONNECT_TIMEOUT_MS },
|
|
51
|
+
// HTTP/2 is opt-in: the endpoint negotiates it, but moving SSE onto h2 is a
|
|
52
|
+
// transport change we do not want to force on every user.
|
|
53
|
+
allowH2: antigravityEnv("HTTP2") === "1",
|
|
54
|
+
});
|
|
55
|
+
} catch {
|
|
56
|
+
// undici unavailable — fall back to Node's default fetch behaviour.
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
})();
|
|
60
|
+
return dispatcherPromise;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** fetch() bound to this provider's keep-alive connection pool when available. */
|
|
64
|
+
export async function antigravityFetch(
|
|
65
|
+
input: string | URL,
|
|
66
|
+
init: RequestInit = {},
|
|
67
|
+
): Promise<Response> {
|
|
68
|
+
const dispatcher = await getDispatcher();
|
|
69
|
+
if (!dispatcher) return fetch(input, init);
|
|
70
|
+
return fetch(input, { ...init, dispatcher } as DispatcherInit);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Open the TLS connection when the extension loads so the first message of a session
|
|
75
|
+
* does not pay the handshake either. Best-effort: failures are ignored.
|
|
76
|
+
*/
|
|
77
|
+
export function prewarmConnection(url: string): void {
|
|
78
|
+
if (antigravityEnv("NO_PREWARM") === "1") return;
|
|
79
|
+
void (async () => {
|
|
80
|
+
try {
|
|
81
|
+
const res = await antigravityFetch(url, {
|
|
82
|
+
method: "HEAD",
|
|
83
|
+
signal: AbortSignal.timeout(PREWARM_TIMEOUT_MS),
|
|
84
|
+
});
|
|
85
|
+
// Release the socket back to the pool even though HEAD carries no body.
|
|
86
|
+
await res.arrayBuffer();
|
|
87
|
+
} catch {
|
|
88
|
+
// Warm-up only; the real request will establish the connection instead.
|
|
89
|
+
}
|
|
90
|
+
})();
|
|
91
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { antigravityEnv } from "./util.js";
|
|
2
|
+
|
|
3
|
+
const LOOPBACK_HOSTS = new Set(["127.0.0.1", "::1", "localhost"]);
|
|
4
|
+
const ALLOWED_API_HOST_SUFFIXES = [".googleapis.com", ".sandbox.googleapis.com"];
|
|
5
|
+
|
|
6
|
+
/** Only loopback binds are allowed so OAuth codes cannot be stolen off-machine. */
|
|
7
|
+
export function resolveCallbackHost(raw = antigravityEnv("CALLBACK_HOST")): string {
|
|
8
|
+
const host = (raw || "127.0.0.1").trim().toLowerCase();
|
|
9
|
+
if (!LOOPBACK_HOSTS.has(host)) {
|
|
10
|
+
throw new Error(
|
|
11
|
+
`Unsafe ANTIGRAVITY_CALLBACK_HOST="${host}". Only loopback hosts are allowed: 127.0.0.1, ::1, localhost.`,
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
return host === "localhost" ? "127.0.0.1" : host;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Prevent token exfiltration via poisoned BASE_URL (SSRF / credential leak). */
|
|
18
|
+
export function assertSafeApiBaseUrl(raw: string): string {
|
|
19
|
+
let url: URL;
|
|
20
|
+
try {
|
|
21
|
+
url = new URL(raw);
|
|
22
|
+
} catch {
|
|
23
|
+
throw new Error(`Invalid ANTIGRAVITY_BASE_URL: ${raw}`);
|
|
24
|
+
}
|
|
25
|
+
if (url.protocol !== "https:") {
|
|
26
|
+
throw new Error(`ANTIGRAVITY_BASE_URL must use https (got ${url.protocol})`);
|
|
27
|
+
}
|
|
28
|
+
if (url.username || url.password) {
|
|
29
|
+
throw new Error("ANTIGRAVITY_BASE_URL must not include credentials");
|
|
30
|
+
}
|
|
31
|
+
const host = url.hostname.toLowerCase();
|
|
32
|
+
const allowed =
|
|
33
|
+
host === "googleapis.com" || ALLOWED_API_HOST_SUFFIXES.some((suffix) => host.endsWith(suffix));
|
|
34
|
+
if (!allowed) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
`ANTIGRAVITY_BASE_URL host "${host}" is not allowed. Use a *.googleapis.com endpoint.`,
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
const path = url.pathname.replace(/\/+$/, "");
|
|
40
|
+
return `${url.origin}${path === "/" ? "" : path}`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Redact bearer tokens, refresh tokens, and similar secrets from diagnostics/errors. */
|
|
44
|
+
export function redactSecrets(text: string): string {
|
|
45
|
+
return text
|
|
46
|
+
.replace(/\bya29\.[A-Za-z0-9._~+/-]+=*/g, "[redacted-access-token]")
|
|
47
|
+
.replace(/\b1\/[A-Za-z0-9_-]{20,}/g, "[redacted-refresh-token]")
|
|
48
|
+
.replace(/\bBearer\s+[A-Za-z0-9._~+/-]+=*/gi, "Bearer [redacted]")
|
|
49
|
+
.replace(
|
|
50
|
+
/("?(?:access_token|refresh_token|id_token|token|client_secret|code_verifier|authorization)"?\s*[:=]\s*")[^"]*(")/gi,
|
|
51
|
+
"$1[redacted]$2",
|
|
52
|
+
)
|
|
53
|
+
.replace(
|
|
54
|
+
/("?(?:access_token|refresh_token|id_token|token|client_secret|code_verifier|authorization)"?\s*[:=]\s*)[^\s&,}]+/gi,
|
|
55
|
+
"$1[redacted]",
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function maskEmail(email: string | undefined): string | undefined {
|
|
60
|
+
if (!email || typeof email !== "string") return undefined;
|
|
61
|
+
const parts = email.split("@");
|
|
62
|
+
if (parts.length !== 2 || !parts[0] || !parts[1]) return "[redacted-email]";
|
|
63
|
+
const name = parts[0];
|
|
64
|
+
const domain = parts[1];
|
|
65
|
+
const lastChar = name.at(-1) || "";
|
|
66
|
+
const maskedName = name.length > 2 ? `${name[0]}***${lastChar}` : `${name[0]}***`;
|
|
67
|
+
return `${maskedName}@${domain}`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function safeError(error: unknown): string {
|
|
71
|
+
const raw = error instanceof Error ? error.message : String(error);
|
|
72
|
+
return redactSecrets(raw);
|
|
73
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { getModelEnum } from "../models/models.js";
|
|
3
|
+
|
|
4
|
+
export function antigravityEnv(name: string): string | undefined {
|
|
5
|
+
return process.env[`ANTIGRAVITY_${name}`] || process.env[`NOAGY_${name}`];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function isRecord(value: unknown): value is Record<string, unknown> {
|
|
9
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function asString(value: unknown): string | undefined {
|
|
13
|
+
return typeof value === "string" && value ? value : undefined;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function sanitizeText(text: unknown): string {
|
|
17
|
+
return String(text ?? "").replace(/[\uD800-\uDFFF]/g, "\uFFFD");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function escapeHtml(text: string): string {
|
|
21
|
+
return text
|
|
22
|
+
.replace(/&/g, "&")
|
|
23
|
+
.replace(/</g, "<")
|
|
24
|
+
.replace(/>/g, ">")
|
|
25
|
+
.replace(/"/g, """)
|
|
26
|
+
.replace(/'/g, "'");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function escapeRegExp(text: string): string {
|
|
30
|
+
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function nowRequestId(): string {
|
|
34
|
+
return antigravityRequestEnvelope("unknown", false).requestId;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Deterministic RFC 4122 v5 UUID from seed (survives restarts for the same session seed). */
|
|
38
|
+
export function stableUuid(seed: string): string {
|
|
39
|
+
const bytes = createHash("sha1").update(seed).digest().subarray(0, 16);
|
|
40
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x50;
|
|
41
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
42
|
+
const hex = [...bytes].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
43
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type AntigravityEnvelopeOptions = {
|
|
47
|
+
isClaude?: boolean;
|
|
48
|
+
isNonGemini?: boolean;
|
|
49
|
+
step?: number;
|
|
50
|
+
lastStepIndex?: string;
|
|
51
|
+
requestIndex?: number;
|
|
52
|
+
userTurnIndex?: number;
|
|
53
|
+
trajectoryId?: string;
|
|
54
|
+
conversationId?: string;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const sessionTrajectoryMap = new Map<string, { conversationId: string; trajectoryId: string }>();
|
|
58
|
+
|
|
59
|
+
/** Stable conversationId and trajectoryId within a multi-turn conversation session. */
|
|
60
|
+
export function resolveSessionTrajectory(context?: {
|
|
61
|
+
messages?: Array<{ role?: string; timestamp?: number; content?: unknown }>;
|
|
62
|
+
}): { conversationId: string; trajectoryId: string } {
|
|
63
|
+
const firstMsg = context?.messages?.[0];
|
|
64
|
+
if (!firstMsg) {
|
|
65
|
+
return { conversationId: crypto.randomUUID(), trajectoryId: crypto.randomUUID() };
|
|
66
|
+
}
|
|
67
|
+
const contentSeed =
|
|
68
|
+
typeof firstMsg.content === "string"
|
|
69
|
+
? firstMsg.content.slice(0, 64)
|
|
70
|
+
: Array.isArray(firstMsg.content)
|
|
71
|
+
? JSON.stringify(firstMsg.content[0] ?? "").slice(0, 64)
|
|
72
|
+
: "";
|
|
73
|
+
const seed = `${firstMsg.role || "user"}:${firstMsg.timestamp || ""}:${contentSeed}`;
|
|
74
|
+
let entry = sessionTrajectoryMap.get(seed);
|
|
75
|
+
if (!entry) {
|
|
76
|
+
entry = {
|
|
77
|
+
conversationId: stableUuid(`antigravity:conv:${seed}`),
|
|
78
|
+
trajectoryId: stableUuid(`antigravity:traj:${seed}`),
|
|
79
|
+
};
|
|
80
|
+
sessionTrajectoryMap.set(seed, entry);
|
|
81
|
+
if (sessionTrajectoryMap.size > 64) {
|
|
82
|
+
const oldestKey = sessionTrajectoryMap.keys().next().value;
|
|
83
|
+
if (oldestKey !== undefined) sessionTrajectoryMap.delete(oldestKey);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return entry;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function clearSessionTrajectoryMap(): void {
|
|
90
|
+
sessionTrajectoryMap.clear();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function antigravityRequestEnvelope(
|
|
94
|
+
wireModelId: string,
|
|
95
|
+
optionsOrIsClaude: boolean | AntigravityEnvelopeOptions = false,
|
|
96
|
+
): { requestId: string; sessionId: string; labels: Record<string, string> } {
|
|
97
|
+
const options: AntigravityEnvelopeOptions =
|
|
98
|
+
typeof optionsOrIsClaude === "boolean" ? { isClaude: optionsOrIsClaude } : optionsOrIsClaude;
|
|
99
|
+
|
|
100
|
+
const isClaude = Boolean(options.isClaude);
|
|
101
|
+
const isNonGemini = Boolean(options.isNonGemini || isClaude);
|
|
102
|
+
const step = Math.max(1, options.step ?? 1);
|
|
103
|
+
const lastStepIndex = options.lastStepIndex ?? String(Math.max(0, step - 1));
|
|
104
|
+
const requestIndex = options.requestIndex ?? options.userTurnIndex ?? Math.max(0, step - 1);
|
|
105
|
+
const agentId = options.conversationId || crypto.randomUUID();
|
|
106
|
+
const trajectoryId = options.trajectoryId || crypto.randomUUID();
|
|
107
|
+
const bytes = crypto.getRandomValues(new Uint8Array(8));
|
|
108
|
+
const sessionId = String(new DataView(bytes.buffer, bytes.byteOffset, 8).getBigInt64(0, true));
|
|
109
|
+
|
|
110
|
+
const claudeLabel = isClaude ? "true" : "false";
|
|
111
|
+
const nonGeminiLabel = isNonGemini ? "true" : "false";
|
|
112
|
+
|
|
113
|
+
const labels: Record<string, string> = {
|
|
114
|
+
last_step_index: lastStepIndex,
|
|
115
|
+
request_id: `${trajectoryId}-${requestIndex}`,
|
|
116
|
+
trajectory_id: trajectoryId,
|
|
117
|
+
used_claude: claudeLabel,
|
|
118
|
+
used_claude_conservative: claudeLabel,
|
|
119
|
+
used_non_gemini_model: nonGeminiLabel,
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const modelEnum = getModelEnum(wireModelId);
|
|
123
|
+
if (modelEnum) {
|
|
124
|
+
labels.model_enum = modelEnum;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
requestId: `agent/${agentId}/${Date.now()}/${trajectoryId}/${step}`,
|
|
129
|
+
sessionId,
|
|
130
|
+
labels,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "Bundler",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"strict": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"noEmit": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"resolveJsonModule": true,
|
|
12
|
+
"isolatedModules": true,
|
|
13
|
+
"noUnusedLocals": true,
|
|
14
|
+
"noUnusedParameters": true,
|
|
15
|
+
"noFallthroughCasesInSwitch": true,
|
|
16
|
+
"noImplicitOverride": true,
|
|
17
|
+
"forceConsistentCasingInFileNames": true,
|
|
18
|
+
"types": ["node"]
|
|
19
|
+
},
|
|
20
|
+
"include": ["src/**/*.ts"]
|
|
21
|
+
}
|
|
@@ -16,6 +16,182 @@ All notable changes to pi-lens will be documented in this file.
|
|
|
16
16
|
|
|
17
17
|
### Security
|
|
18
18
|
|
|
19
|
+
## [4.1.6] - 2026-09-10
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- **Add an advisory incremental Stryker lane for changed scripts (refs #1844)** — `npm run mutation:diff` and the pull-request mutation lane use Stryker's command runner over changed `scripts/**/*.mjs` files and their related tests, report uncovered files, retain incremental results under ignored paths, and publish the mutation report for review.
|
|
24
|
+
|
|
25
|
+
- **CI failures now distinguish infrastructure outages from real test failures and arm one rerun** (refs #2103, #2784) — the classifier recognizes exit-137 kills, CodeQL/SARIF outages, codeload throttling, and npm CI timeouts, while preserving assertion and TypeScript failures as real. It updates one PR comment, applies the manifest-managed CI label, and lets the verdict report an armed infrastructure rerun as pending; **Terminal CI rerun finalization now covers master push and repository-dispatch runs** (refs #2103, #2784) — the workflow finalizes second-attempt classifications for every supported event and records a bounded step summary when no associated PR exists.
|
|
26
|
+
|
|
27
|
+
- Add an AST governance sweep for `vi.mock` factories that omit production exports. Refs #2281.
|
|
28
|
+
|
|
29
|
+
- **Add an advisory Windows Vitest lane (refs #2536)** — Run the path-shape and configuration test subset on `windows-latest`.
|
|
30
|
+
|
|
31
|
+
- **Add the tool-smoke install lane to the release-QA baseline (refs #2663, #2784)** — a `tool-smoke-install` row installs every npm/pip installer-registry entry through the real smoke harness, so a dead registry entry is a red do-not-ship row, a registry-unreachable lane is INCONCLUSIVE, and neither reads as green.
|
|
32
|
+
|
|
33
|
+
- **Add a TypeScript strictness spike with scratch configs, per-directory counts, a two-sided ratchet, and an advisory report lane (refs #2697)** — the migration remains staged by directory instead of enabling either flag globally.
|
|
34
|
+
|
|
35
|
+
- **Add a cwd-sensitive yamllint tool-smoke row (refs #2697, refs #2691)** — the real runner proves yamllint uses the dispatch cwd instead of the host process cwd for config discovery.
|
|
36
|
+
|
|
37
|
+
- **Add tool-smoke cwd rows for nested discovery (refs #2777)** — the runner, formatter, and LSP smoke shapes assert their resolved cwd and reason log, while missing binaries remain visible skips.
|
|
38
|
+
|
|
39
|
+
- **Add one command for every mechanical PR gate (refs #2790, #2784)** — `npm run preflight` runs the ordered local build, lint, formatting, changelog, lockfile, governance, and PR-document checks.
|
|
40
|
+
|
|
41
|
+
- Stamp one session-scoped turn identifier on observability sink rows (refs #2815).
|
|
42
|
+
|
|
43
|
+
- **Add a real pi RPC harness for load, tool-set restore, and read-guard scenarios (refs #2825)** — the serialized `real-harness` lane drives the built extension with a deterministic scripted provider and hermetic sinks.
|
|
44
|
+
|
|
45
|
+
- **Make Knip a hard local preflight gate and cover every admitted test lane** (refs #2837) — `npm run preflight` runs Knip, while the Knip entry census covers real-harness, Windows, wall-clock, and workflow-invoked script populations with documented same-file export admissions.
|
|
46
|
+
|
|
47
|
+
- **Gate nightly LSP smoke rows on primary diagnostics** (refs #2780) — the tool-smoke workflow now drives opted-in seeded fixtures through the real `lsp_diagnostics` handler, reports unavailable toolchains correctly, and tracks gate failures.
|
|
48
|
+
|
|
49
|
+
- **`complexity (advisory)` CI job dogfoods pi-lens's own complexity client over `clients/`, `tools/` and `mcp/` (refs #2697)** — `npm run complexity` writes a Markdown report (top functions by cyclomatic/cognitive complexity, files over 1,000 lines, split candidates at the dispatch threshold of 15) to the step summary and an artifact; `ComplexityClient` exposes the per-function metrics it already computes, uses the dispatch cyclomatic metric for JS/TS, and fails when analysis produces no files or throws.
|
|
50
|
+
|
|
51
|
+
- **One session-end line names the tools never activated or called (refs #2800)** — a bounded debug record per session on both surfaces, keyed by the tool registry, so roster decisions can read which tools carried no weight in a session; the monitor readout gains the line. MCP owns the row for the connection and emits it at `pilens_session_end` or transport close, whichever comes first; repeated `pilens_session_start` calls refresh without clearing observations. Pi records the row for fresh sessions only: a reload, resume, or fork start suppresses the session's row entirely (conversation-owned accounting tracked in #2858).
|
|
52
|
+
|
|
53
|
+
- **Per-call tool-result observability**: the `usage tokens=<n> elapsed-ms=<n>` contract footer gains `bytes=<delivered payload bytes> truncated=<true|false>` on both host surfaces, the payload byte bound runs before the footer is stamped with the footer's own maximum size reserved so the delivered text (footer included) never exceeds 40 KiB for the single-text-block results production emits (the bound is per text block, inherited from #2852), and the per-turn `cache_usage` latency row aggregates `toolResultBytes` and `toolResultsTruncated` over the turn's tool calls (refs #2800)
|
|
54
|
+
|
|
55
|
+
- **Guard workflow shell portability (refs #2625, #2784)** — Reject bash 4-only constructs in steps that can run on macOS runners, including matrix and reusable-workflow input expansion and executable command substitutions nested inside double quotes.
|
|
56
|
+
|
|
57
|
+
- **Record injected bytes and repeated findings per turn (refs #2838)** — the existing cache attribution row records UTF-8 bytes by model-facing injection source and counts repeated finding identities with bounded per-session state.
|
|
58
|
+
|
|
59
|
+
- **Check lockfile completeness under CI's npm (refs #2803, #2784)** — preflight and `check:lockfile --complete` reject optional dependency drift before merge; **Pin the clean production install to npm@11.18.0 (refs #2803, #2784)** — use
|
|
60
|
+
the repository's exact npm pin so a different npm version cannot rewrite the
|
|
61
|
+
committed lockfile.
|
|
62
|
+
|
|
63
|
+
- **`tools.<name>.enabled` proven through a real pi RPC session (refs #2800)** — real-harness scenarios show a disabled tool absent from the tool list pi reports, the loader and MCP lifecycle tools refusing to be disabled with the config diagnostic, and `--no-tool` winning over config; the roster bytes pi receives per tool are measured on the wire.
|
|
64
|
+
|
|
65
|
+
### Changed
|
|
66
|
+
|
|
67
|
+
- Keep admission registries sorted and enforce declaration order with one shared sweep helper (refs #2671, #2784).
|
|
68
|
+
|
|
69
|
+
- **Skip the PR title, body and close-keyword checks for dependabot PRs (refs #2714)** — the `pr-title-lint` and `pr-body-lint` jobs in lint.yml and the lint job in close-keywords.yml now carry a `dependabot[bot]` skip condition. A bump can never carry an issue ref or the PR-body template, so these checks no longer go red on every bump and no merge-train pass has to ignore them by hand. Lint, Unit tests, the install tests and the advisory lanes still run on bumps.
|
|
70
|
+
|
|
71
|
+
- **Trim the three largest tool parameter schemas and pin both host rosters (refs #2800).**
|
|
72
|
+
|
|
73
|
+
- **Adaptively demote budget-hitting auxiliaries, re-promote fast late answers, and deliver findings through the deferred runner path (refs #2810).**
|
|
74
|
+
|
|
75
|
+
- **Tool probes and hand-derived package roots resolve through shared seams (refs #2894)** — a `probeToolAsync` seam owns the "a presence/version probe never gets a `cwd`" contract for 23 spawn sites that each decided it locally, `rust-clippy` takes its package root from `resolveRunnerCwd` (with `Cargo.toml` registered as its runner marker) instead of an uncapped `findNearestContaining` walk, and `ruff-client`'s autofix resolves its config root through `resolveToolCwd` so a file in a nested package gets that package's `pyproject.toml` rather than the workspace one.
|
|
76
|
+
|
|
77
|
+
- **Preserve per-row auxiliary publication evidence semantics (refs #2892)** — demoted waits accept an advanced per-path stamp alongside a content binding, while sibling and aggregate rows remain binding-only.
|
|
78
|
+
|
|
79
|
+
- **`ast_grep_dump` folded into `ast_grep_search` (refs #2800)** — AST inspection is `ast_grep_search` with `dump=true`, with the same result contract; the retired name answers for one session through a bounded compatibility response on both surfaces (one `ast-grep-dump-compatibility` record per session) and is absent from the tool registry and every tool listing.
|
|
80
|
+
|
|
81
|
+
- **Audit and update user-facing and contributor docs against master for the v4.1.6 cut.** `docs/agent-tools.md` now describes `lens_diagnostics`' `source`/`scope`/`severity`-threshold contract, the one-release MCP compatibility redirect, the `lsp_navigation` 19-operation roster with a link to its SKILL.md parameter reference, and the result-delivery contract (`finalizeToolResult`, 40 KiB bound, `bytes=`/`truncated=` usage footer). `docs/settings.md`, `docs/globalconfig.md`, and `docs/usage.md` now agree on all registry flags, including the seven analyzer toggles. `docs/features.md`'s formatter list is corrected to the current 34-entry autoformat registry (drops `fish_indent`, which is a check-only dispatch runner rather than an entry in that registry, and adds `ktfmt` and `terragrunt-hcl`). `docs/environment-variables.md` drops `PI_LENS_AUTO_INSTALL`, which no longer exists in code. (refs #2800)
|
|
82
|
+
|
|
83
|
+
- **Fold `lsp_diagnostics` into `lens_diagnostics` with source and scope modifiers; retain the MCP compatibility shim for one release.** (refs #2800)
|
|
84
|
+
Deprecated: `pilens_lsp_diagnostics` remains accepted by MCP for one release and maps to `source=lsp`.
|
|
85
|
+
|
|
86
|
+
- **Make the oxfmt format check a CI gate (refs #2790, #2784)** — the workflow job now uses the gating name `oxfmt format check`, matching the hard `fmt:check` preflight gate and keeping formatting drift out of master.
|
|
87
|
+
|
|
88
|
+
- **Fold `allowStamp` out of auxiliary coverage (closes #2914)** — The stamp-union predicate keeps one behaviour; the sibling and aggregate rows call the binding predicate directly.
|
|
89
|
+
|
|
90
|
+
- **One result renderer for pi tool results and the MCP mirror (refs #2800)** — result status, diagnostic severity and usage lines come from one shared renderer on both surfaces, pinned by a both-surfaces governance test that drives real inputs for every paired registry tool and explicitly covers pi-only rows.
|
|
91
|
+
The renderer runs after each tool has set `isError`, then applies stale warnings, and bounds the final MCP payload to 40 KiB.
|
|
92
|
+
|
|
93
|
+
- **Dropped a no-op string replacement in the tsgolint preflight test (refs #2709)** — CodeQL alert 49 (`js/identity-replacement`): the helper replaced `/package.json` with itself; the key lookup now only strips the `/tmp/` prefix.
|
|
94
|
+
|
|
95
|
+
- **Pin the tool-roster description budget and trim paid metadata (refs #2800)** — pi and MCP tool registration now use concise contract-plus-example descriptions, with a two-sided baseline covering descriptions and schemas on both surfaces; the model-facing contract sentences (read coverage, diagnostic suppression ordering, configuration redaction, cold-cache guidance) stay in the paid description and are pinned per surface so a later trim cannot drop them.
|
|
96
|
+
|
|
97
|
+
- **Add per-tool enablement (refs #2800)** — `tools.<name>.enabled` and repeatable `--no-tool=<name>` prevent disabled lens tools from registering on the pi and MCP surfaces. One registry now covers every model-facing tool, keeps the activation and MCP lifecycle tools non-disableable, and emits stable diagnostic code `PILENS_CFG_0009` for unknown or non-disableable keys. The resolved state appears in `effective_config`.
|
|
98
|
+
|
|
99
|
+
- **`sql-injection` (TypeScript tree-sitter rule) is a warning, not a blocking error.** The query keys on the callee name only (`query|execute|exec|run`), so any template literal passed to a same-named non-SQL function fired a blocking finding; it stays as a warning until the rule gains a receiver/type signal.
|
|
100
|
+
|
|
101
|
+
### Fixed
|
|
102
|
+
|
|
103
|
+
- **Windows lane enumerated zero files because six scripts detected "am I the entry module" by string-comparing `import.meta.url` with `file://${process.argv[1]}`** (refs #2536) — on Windows the two spellings never match, so the main block never ran; every gate now compares against `pathToFileURL(process.argv[1]).href`, the win32 gate scanner excludes fixtures by the platform separator, and a governance test rejects the hand-built comparison.
|
|
104
|
+
|
|
105
|
+
- **Bound turn-end Gitleaks classification (refs #2575)** — timed-out classification keeps raw findings fail-open. Thanks @stekman08.
|
|
106
|
+
|
|
107
|
+
- **Prune merged clean worktrees with a per-run cap; never a tree with untracked files (refs #2631, #2538, #2784)** — the agent-worktree hygiene sweep now also removes any registered worktree whose branch tip is an ancestor of `origin/master` and whose checkout is clean, clears `.claude/worktrees/agent-*` leftovers that hold nothing but git's own `.git` gitlink, and caps removals per run with `--max` (default 10). An untracked file counts as a deliverable: only an empty `git status --porcelain` is clean, and the keep record names the first entry it protected.
|
|
108
|
+
|
|
109
|
+
- **The format smoke lane installs the managed formatters it selects (refs #2767)** —
|
|
110
|
+
The `--install` path prefetches configured formatters through `ensureTool`
|
|
111
|
+
and the formatter pipeline resolves those managed binaries, with venv/local
|
|
112
|
+
→ PATH → managed precedence; every managed resolver returns the typed
|
|
113
|
+
unavailable outcome instead of falling through to a bare command; GitHub and
|
|
114
|
+
archive installs record a typed unavailable outcome when no asset exists for
|
|
115
|
+
the host platform and architecture; the formatter-absence tests pin the
|
|
116
|
+
installer's independent PATH lookup so npm's `node_modules/.bin` prefix on
|
|
117
|
+
CI cannot resolve a dev-dependency binary.
|
|
118
|
+
|
|
119
|
+
- **Unify tool cwd and root resolution (refs #2777)** — Runners, formatters, and LSP configuration walks now use one bounded, logged resolution seam.
|
|
120
|
+
|
|
121
|
+
- **Fix runner no-config advisories logging once per tool and root at debug level (refs #2811)** — Dispatch now bounds constant runner advisories to one record per tool and resolved root per session.
|
|
122
|
+
|
|
123
|
+
- **Key vi.mock export admissions by factory content and ratchet missing counts across line moves.** (refs #2816)
|
|
124
|
+
|
|
125
|
+
- Make vi.mock export sweep warnings visible in default Vitest output and keep baseline regeneration successful when admissions change.
|
|
126
|
+
|
|
127
|
+
- **Harden real pi harness waits and isolation (refs #2825)** — consume cursor-based events, honor scenario scripts, pin lane membership, and sweep shared scratch directories.
|
|
128
|
+
|
|
129
|
+
- **Verify explicit existing records in PR-body observability lint (refs #2855)** — require the named kind in the named source file and verify its cited line is within 20 lines of the literal.
|
|
130
|
+
|
|
131
|
+
- **Report peak RSS for exit-137 classifications (refs #2856)** — retain master’s real-failure precedence and include the three heaviest `[mem-file]` peaks in kill details.
|
|
132
|
+
|
|
133
|
+
- **Attribute pi situational-tool observations by session file and emit on replacement.** A shutdown with `targetSessionFile` emits the conversation that is ending; reload re-runs the extension factory but keeps the same file and row. (refs #2858)
|
|
134
|
+
|
|
135
|
+
- **Fail session-start tests when the awaited handler crashes or exceeds its test budget, instead of passing vacuously.** (refs #2859)
|
|
136
|
+
|
|
137
|
+
- **Bound joined tool-result text with one conservative footer reserve, write one complete-result log, and convert rejecting pi tool executions into contract errors.** (refs #2862)
|
|
138
|
+
|
|
139
|
+
- **Derive lens diagnostics limits and scope metadata from the LSP probe, preserve single-file names, and honor session severity tiers.** (refs #2864)
|
|
140
|
+
|
|
141
|
+
- **Test-runner selection is per file kind and per module root, and a go `[setup failed]` result is advisory (refs #2870)** — a repo carrying both a `go.mod` and a Gradle build no longer hands every `.java` file to `go test` (the `RUNNERS` declaration order used to decide), a `README.md` or `.yaml` under a test directory no longer becomes its own test target, a nested Gradle or Go module anchors at its own build while a single-language repo keeps the runner it selected before, and go's `FAIL <pkg> [setup failed]` verdict reports as "could not run tests" instead of a fabricated blocking failure whose classification depended on whether go printed the word "error".
|
|
142
|
+
|
|
143
|
+
- **The test runner spawns its child through `resolveToolCwd`, so a nested module's tests run from that module (refs #2871)** — a `.go` file in a nested `go.mod` module now runs `go test ./internal/…` from the module that owns the package instead of a root-relative path the root module cannot resolve, with the shared seam supplying marker discovery, the `.git`/dispatch-root fallbacks, the `$HOME` ceiling and one `tool-cwd` log line per resolution key; a whole-project build launches from the directory that owns its wrapper (`gradle`, `maven`), a child is never anchored on a config file the detector itself rejected as evidence (`pytest`'s `pyproject.toml`, `phpunit`'s `composer.json`), and the failed-target ledger stays keyed on the dispatch root.
|
|
144
|
+
|
|
145
|
+
- **Make the runner spawn-cwd sweep verify resolver origin across the child-spawn population (refs #2872).** Bindings resolve by the grammar's own scope rather than a list of node kinds, any later rebinding leaves the value unproven, promoted resolvers must be a single seam return, and each admitted site is keyed by its cwd expression and the locals that expression reads, so a laundered or edited cwd cannot inherit an admission.
|
|
146
|
+
|
|
147
|
+
- **Keep diagnostics visible for tolerant MCP severity inputs and apply one threshold across session and LSP sources, including error-only files at the warning threshold.** (refs #2864)
|
|
148
|
+
|
|
149
|
+
- **Surface a crashed pi hook handler instead of swallowing it silently (refs #2884)** — the nine `index.ts` catch sites that absorb a handler crash (`session_start`, `session_before_fork`, `observed_settled_sweep`, `observed_ledger_refresh`, `agent_end`, `turn_end`, the `agent_settled` deferred-mutation drain, `quiet_window`, and `message_end`) now route through one shared `surfaceHandlerCrash` guard: production keeps the swallow but leaves one bounded `hook-handler-crash` degradation row per handler per session, and under the test runner the crash is rethrown so the awaiting test fails instead of resolving as if the handler had completed. The fire-and-forget `quiet_window` catch records the row without rethrowing, so a crash cannot terminate the pi host with an unhandled rejection.
|
|
150
|
+
|
|
151
|
+
- **Resolve aliased child-process bindings (closes #2888)** — Extend the spawn-cwd test sweep to resolve aliased and namespaced child-process bindings.
|
|
152
|
+
|
|
153
|
+
- **Make pi RPC `session_start` idempotent per reason and session ID, with a session-file fallback (refs #2890)** — repeated replacement events no longer repeat tool restoration or session-state resets, while a different session identity starts a new mutation pass.
|
|
154
|
+
|
|
155
|
+
- **Deduplicate repeated RPC session starts (refs #2890)** — use the stable session ID, fall back to the session file, and re-run the restore when the host's active tool posture drifted.
|
|
156
|
+
|
|
157
|
+
- **`lens_diagnostics mode=full` retires a stale finding only when the result that replaces it is genuinely authoritative: an LSP write the ordering guard accepted, or a project runner that actually analysed the root this call. A runner that reported success without running — no project root, no source files, a scan that crashed before writing its report — is reported cold instead of silently deleting the finding, and a retained result that could not be reconciled is labelled stale rather than served as a current blocker (refs #2154).**
|
|
158
|
+
|
|
159
|
+
- **Require Windows-only test gates to name and enter the Windows Vitest lane (refs #2536, #2784)** — one shared population script drives the Windows job and governance sweep, with a job summary recording the executed gate count.
|
|
160
|
+
|
|
161
|
+
- **Require runtime Observability sections to name a diff record (refs #2543, #2784)** — the PR-body checker matches observability record literals against added runtime lines and rejects unsupported no-failure claims.
|
|
162
|
+
|
|
163
|
+
- **Make the merge-train warden label `red-ci` for any failing non-advisory check on the exact pull-request head (refs #2616, #2784)**.
|
|
164
|
+
|
|
165
|
+
- **CI failure classifier: a test timeout beside registry network failures is infra, not real (refs #2839)** — A Unit-tests job whose only test-level failure is a vitest `Test timed out in Nms` line (no `AssertionError`, no compiler diagnostic) now classifies `infra-net` when the log also carries registry-unreachable evidence (`npm error code ECONNRESET` through every `npm-retry` attempt, codeload/SARIF 429/503, `npm ci` ETIMEDOUT, `npm-retry: attempt N network error`), so the once-per-SHA automatic rerun arms instead of the job sitting `ci:real`; PRs #2834 and #2835 both hit this and were re-run by hand. An `AssertionError` or a TypeScript `error TS` line beside the same network noise still classifies `real`, and a lone timeout with no network evidence is unchanged.
|
|
166
|
+
|
|
167
|
+
- **`detectFileRole` recognises Go `_test.go` and the other table conventions (closes #2880)** — Editing `pkg/foo_test.go` produced no test target because the shared role classifier only knew `.test.`/`.spec.`/prefix/dir patterns. It now also matches the `_test.`/`_spec.` suffix infixes and the case-sensitive `*Test(s).<ext>` CamelCase suffix for Java/Kotlin/C#/F#/PHP, informed by the test-runner client's `SOURCE_TO_TEST_PATTERNS` + `RUNNERS` table; hand-written, see #2928 for the single-classifier fold, so an edited Go test file runs its own package tests.
|
|
168
|
+
|
|
169
|
+
- **Route helm-lint through the runner cwd resolver (closes #2882)** — Helm lint now runs with the cwd selected by the shared dispatch runner seam.
|
|
170
|
+
|
|
171
|
+
- **Preserve situational tool activations across pi rebuilds (refs #2889)** — Remember activations by session file so reload, resume, and fork restore the conversation's tool posture.
|
|
172
|
+
|
|
173
|
+
- Run the installed-registry release-QA smoke with a scratch-home pip policy and keep the measured registry deterministic.
|
|
174
|
+
|
|
175
|
+
- **Diagnostic verification guidance (closes #2792).** Agent and MCP descriptions distinguish cache-only reporting from active scans. Use `mode=full` with `paths` when changed files have absent or stale cached findings.
|
|
176
|
+
|
|
177
|
+
- **Partition LSP diagnostics by server provenance (refs #2776)** — custom language servers now render their diagnostics as primary findings even when their server-authored `source` value differs from the registered server id.
|
|
178
|
+
|
|
179
|
+
- **Re-sync LSP diagnostics after Git tree changes (refs #2817)** — open documents and bounded cached import dependencies are touched before scoped full diagnostics serve cached results; files without import-fact coverage receive a fresh requested-file touch; **Prove language-neutral LSP dependency resync through the real server path** (refs #2817); the language matrix derives its facts and fallback rows from the production import-facts predicate; the shared drift pass gives a Git-queued file one resync opportunity even when ordinary stat drift identifies the same file in that pass.
|
|
180
|
+
|
|
181
|
+
- **Bound MCP tool results through the shared pi result seam (refs #2799, #2800)** — oversized results retain head and tail context, report omitted characters, and preserve the complete payload in the session log; the roster budget rejects duplicate tool names; results above the documented 8 MiB input budget keep a bounded head, an explicit incomplete marker and the tail in the session log, with one `mcp-complete-result-budget-exceeded` degradation per session.
|
|
182
|
+
|
|
183
|
+
- **Flake-shape ratchet governs support-helper waits (refs #2563, #2784)** — the contention ratchet scans `.ts` and `.mts` support helpers, resolves aliased timers, and requires every support baseline row to carry a detector-specific reason, header, and serialized-lane proof through its importing tests; **Reduce flake-shape ratchet AST scanning cost (refs #2563, #2784)** — the whole-tree scan uses a comment/string-blanked textual pre-pass and parses each timer-bearing source file at most once per run.
|
|
184
|
+
|
|
185
|
+
- **Label-sync post-merge validation fails when the syncer deletes or loses any label (refs #2614)** — the `labels.yml` sync job now snapshots the live label set before `action-label-syncer` runs and re-validates after: any before-vs-after deletion, or any manifest label missing from the live set, fails the job through `::error::label sync deleted or missing labels:` with the names printed, instead of a silent success while prune deletes labels (the #2553 recurrence, twice for the priority labels).
|
|
186
|
+
|
|
187
|
+
- **Route built-in LSP roots through the tool-cwd seam and expose resolved cwd in `lens_diagnostics` (refs #2777)** — Built-in server marker tables now use the shared bounded resolver, and diagnostic rows identify the cwd used for their language server. Workspace-priority roots keep their complete marker tables through the seam (Go, JSON), and a server-computed root is the seam's input, never replaced (review rounds 2 and 4).
|
|
188
|
+
|
|
189
|
+
- **Run the release-QA tool smoke from the export root (closes #2893)** — the install lane now executes the smoke harness from the archived source tree while loading the installer registry from the installed package, and measures pip entries under its scratch-pinned package policy.
|
|
190
|
+
|
|
191
|
+
- **Docs membership guard asserts list members, not counts (closes #2919).** `tests/docs/features-counts.test.ts` now compares the `docs/features.md` formatter list member-by-member against `ALL_FORMATTERS`, the LSP language list against non-auxiliary `LSP_SERVERS` ids, and the `docs/mcp.md` tool table against `TOOL_REGISTRY`, and reports missing and extra names, so reinstating a removed member or swapping in a stale name fails the suite.
|
|
192
|
+
|
|
193
|
+
- **Route tool configuration diagnostics through the shared note seam (refs #2800)** — unknown and non-disableable tool names use the bounded config notice path, and `tools.<name>.enabled` is documented across the config references.
|
|
194
|
+
|
|
19
195
|
## [4.1.5] - 2026-09-08
|
|
20
196
|
|
|
21
197
|
### Added
|
|
@@ -155,6 +155,14 @@ pi install git:github.com/apmantza/pi-lens
|
|
|
155
155
|
Requires Node.js >=22.19.0 (matches the pi host's own floor — see `engines`
|
|
156
156
|
in `package.json`).
|
|
157
157
|
|
|
158
|
+
Letting a coding agent do it: paste this into its prompt.
|
|
159
|
+
|
|
160
|
+
```text
|
|
161
|
+
Install pi-lens (npm:pi-lens) into pi, then read AGENTS.md in
|
|
162
|
+
https://github.com/apmantza/pi-lens for how the extension works and how it
|
|
163
|
+
expects to be operated.
|
|
164
|
+
```
|
|
165
|
+
|
|
158
166
|
> **npm v12 users:** dependency lifecycle scripts (e.g. `@ast-grep/cli`'s
|
|
159
167
|
> `postinstall`) now require explicit approval — if `npm install` warns about
|
|
160
168
|
> unreviewed install scripts, review and allow them with
|
|
@@ -336,6 +344,11 @@ Thanks goes to these wonderful people:
|
|
|
336
344
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mjfaga"><img src="https://avatars.githubusercontent.com/u/7584015?v=4" width="100px;" alt=""/><br /><sub><b>Mark</b></sub></a><br /><a href="#code-mjfaga" title="Code">💻</a></td>
|
|
337
345
|
<td align="center" valign="top" width="14.28%"><a href="https://aeturnal.io/"><img src="https://avatars.githubusercontent.com/u/219271200?v=4" width="100px;" alt=""/><br /><sub><b>aeturnal</b></sub></a><br /><a href="#code-aeturnal" title="Code">💻</a></td>
|
|
338
346
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/floatGray"><img src="https://avatars.githubusercontent.com/u/44295302?v=4" width="100px;" alt=""/><br /><sub><b>floatGray</b></sub></a><br /><a href="#code-floatGray" title="Code">💻</a></td>
|
|
347
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/thomasfsteeples"><img src="https://avatars.githubusercontent.com/u/32720359?v=4" width="100px;" alt=""/><br /><sub><b>Thomas F Steeples</b></sub></a><br /><a href="#code-thomasfsteeples" title="Code">💻</a></td>
|
|
348
|
+
</tr>
|
|
349
|
+
<tr>
|
|
350
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/amasen02"><img src="https://avatars.githubusercontent.com/u/97525823?v=4" width="100px;" alt=""/><br /><sub><b>Ama Senevirathne</b></sub></a><br /><a href="#code-amasen02" title="Code">💻</a></td>
|
|
351
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/AcademyKUB8"><img src="https://avatars.githubusercontent.com/u/217174854?v=4" width="100px;" alt=""/><br /><sub><b>AcademyKUB8</b></sub></a><br /><a href="#code-AcademyKUB8" title="Code">💻</a></td>
|
|
339
352
|
</tr>
|
|
340
353
|
</tbody>
|
|
341
354
|
</table>
|
|
@@ -344,11 +357,3 @@ Thanks goes to these wonderful people:
|
|
|
344
357
|
<!-- prettier-ignore-end -->
|
|
345
358
|
|
|
346
359
|
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
|
347
|
-
|
|
348
|
-
The following commit identities also appear in `git shortlog -sne HEAD` but are
|
|
349
|
-
not represented in the generated table above: Anas Alsbei, Claude,
|
|
350
|
-
Christopher Patti,
|
|
351
|
-
dependabot[bot], Fabio-D, github-actions[bot], JSup, Kenny McCormick,
|
|
352
|
-
Max Lupus, Moritz Hofmann, ricardo, and root.
|
|
353
|
-
|
|
354
|
-
If you land a pull request or report an issue that gets fixed, we'll add you here.
|
|
@@ -26,7 +26,6 @@
|
|
|
26
26
|
"./clients/format-events-publish.js",
|
|
27
27
|
"./clients/format-service.js",
|
|
28
28
|
"./clients/formatters-lazy.js",
|
|
29
|
-
"./clients/git-guard.js",
|
|
30
29
|
"./clients/host-ports.js",
|
|
31
30
|
"./clients/installer/index.js",
|
|
32
31
|
"./clients/instance-reaper.js",
|
|
@@ -75,13 +74,16 @@
|
|
|
75
74
|
"./clients/session-start-observability.js",
|
|
76
75
|
"./clients/session-state-store.js",
|
|
77
76
|
"./clients/sessionstart-logger.js",
|
|
77
|
+
"./clients/situational-tool-telemetry.js",
|
|
78
78
|
"./clients/skills-resolver.js",
|
|
79
79
|
"./clients/smells-rollup.js",
|
|
80
80
|
"./clients/startup-timing.js",
|
|
81
81
|
"./clients/test-runner-delivery.js",
|
|
82
|
+
"./clients/tool-config.js",
|
|
82
83
|
"./clients/tool-definition.js",
|
|
83
84
|
"./clients/tool-render.js",
|
|
84
85
|
"./clients/tool-set-policy.js",
|
|
86
|
+
"./clients/turn-context.js",
|
|
85
87
|
"./clients/turn-summary-render.js",
|
|
86
88
|
"./clients/turn-summary.js",
|
|
87
89
|
"./clients/user-notify.js",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -99,7 +99,7 @@ export function astGrepRemediationHint(kind) {
|
|
|
99
99
|
case "json_parse_failed":
|
|
100
100
|
return "Hint: ast-grep produced output that could not be parsed — retry with a simpler pattern; the installed CLI version may be incompatible.";
|
|
101
101
|
default:
|
|
102
|
-
return "Hint: verify the pattern is a single valid AST node for this `lang` (use
|
|
102
|
+
return "Hint: verify the pattern is a single valid AST node for this `lang` (use ast_grep_search with dump=true to discover node kinds), or fall back to grep for plain-text search.";
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
export function logAstGrepToolEvent(event) {
|
|
@@ -14,8 +14,10 @@ import { isFileKind } from "./file-kinds.js";
|
|
|
14
14
|
import { getGlobalPiLensDir } from "./file-utils.js";
|
|
15
15
|
import { findGlobalBinary } from "./package-manager.js";
|
|
16
16
|
import { safeSpawnAsync } from "./safe-spawn.js";
|
|
17
|
+
import { probeToolAsync } from "./tool-probe.js";
|
|
17
18
|
import { createSingleFlight } from "./single-flight.js";
|
|
18
19
|
import { biomeConfigArgs } from "./tool-policy.js";
|
|
20
|
+
import { resolveToolCwd } from "./tool-cwd.js";
|
|
19
21
|
import { resolveManagedToolClient, } from "./dispatch/runners/utils/runner-helpers.js";
|
|
20
22
|
import { classifyProbeFailure, describeInstallAttempt, createAvailabilityLatch, logAvailabilityDecision, startHostStallSampler, } from "./dispatch/runners/utils/availability-policy.js";
|
|
21
23
|
// --- Client ---
|
|
@@ -169,7 +171,14 @@ export class BiomeClient {
|
|
|
169
171
|
let result;
|
|
170
172
|
let hostStallMs;
|
|
171
173
|
try {
|
|
172
|
-
|
|
174
|
+
// The presence probe asks whether biome answers at all, so it goes
|
|
175
|
+
// through the probe seam (no cwd) rather than through
|
|
176
|
+
// `spawnBiomeAsync`, whose optional `cwd` exists for the analysis
|
|
177
|
+
// spawns that DO resolve a project config (#2894).
|
|
178
|
+
const { cmd, args: prefix } = await this.getBiomeBinary();
|
|
179
|
+
result = await probeToolAsync(cmd, [...prefix, "--version"], {
|
|
180
|
+
timeout: PROBE_TIMEOUT_MS,
|
|
181
|
+
});
|
|
173
182
|
}
|
|
174
183
|
finally {
|
|
175
184
|
hostStallMs = sampler.stop();
|
|
@@ -314,7 +323,9 @@ export class BiomeClient {
|
|
|
314
323
|
}
|
|
315
324
|
try {
|
|
316
325
|
const before = await fs.promises.readFile(absolutePath, "utf-8");
|
|
317
|
-
const configCwd =
|
|
326
|
+
const configCwd = resolveToolCwd("runner", "biome", absolutePath, {
|
|
327
|
+
...(cwd !== undefined && { cwd }),
|
|
328
|
+
});
|
|
318
329
|
// Shared config-args seam (#1247): the lint runner consumes the same
|
|
319
330
|
// builder, so `lint --write` can never drift to biome's default
|
|
320
331
|
// config when a user config or the package fallback exists.
|