@herbertgao/pi-extensions 2026.8.13 → 2026.8.15
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 +19 -14
- package/THIRD_PARTY_NOTICES.md +0 -1
- package/node_modules/@czottmann/pi-automode/CHANGELOG.md +19 -0
- package/node_modules/@czottmann/pi-automode/README.md +5 -1
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/classifier.ts +126 -13
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/config.ts +7 -3
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/constants.ts +2 -0
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/hard-deny.ts +134 -23
- package/node_modules/@czottmann/pi-automode/package.json +1 -1
- package/node_modules/@herbertgao/{pi-stash → pi-bark}/LICENSE +4 -5
- package/node_modules/@herbertgao/pi-bark/README.md +44 -0
- package/node_modules/@herbertgao/pi-bark/assets/pi-icon.png +0 -0
- package/node_modules/@herbertgao/pi-bark/package.json +53 -0
- package/node_modules/@herbertgao/pi-bark/src/index.ts +178 -0
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
- package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +6 -0
- package/node_modules/@herbertgao/pi-subagents/package.json +2 -1
- package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +8 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
- package/node_modules/@narumitw/pi-btw/README.md +125 -88
- package/node_modules/@narumitw/pi-btw/dist/index.ts +140 -45
- package/node_modules/@narumitw/pi-btw/dist/index.ts.map +2 -2
- package/node_modules/@narumitw/pi-btw/package.json +5 -8
- package/node_modules/@narumitw/pi-btw/src/btw.ts +31 -26
- package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +106 -17
- package/node_modules/@narumitw/pi-btw/src/menu.ts +34 -2
- package/node_modules/@narumitw/pi-btw/src/settings.ts +16 -0
- package/node_modules/@tifan/pi-handoff/README.md +36 -13
- package/node_modules/@tifan/pi-handoff/package.json +2 -2
- package/node_modules/@tifan/pi-handoff/src/index.ts +160 -4
- package/node_modules/@tifan/pi-preferred-thinking/README.md +1 -1
- package/node_modules/@tifan/pi-preferred-thinking/package.json +1 -1
- package/node_modules/@tifan/pi-preferred-thinking/src/index.ts +15 -2
- package/node_modules/@tifan/pi-recap/README.md +1 -1
- package/node_modules/@tifan/pi-recap/package.json +2 -2
- package/node_modules/@tifan/pi-recap/src/index.ts +15 -0
- package/node_modules/@tifan/pi-rename/README.md +42 -21
- package/node_modules/@tifan/pi-rename/package.json +1 -1
- package/node_modules/@tifan/pi-rename/src/index.ts +62 -11
- package/node_modules/@tifan/pi-rename/src/language.ts +18 -0
- package/node_modules/@tifan/pi-rename/src/models.ts +69 -13
- package/node_modules/@tifan/pi-rename/src/naming.ts +36 -7
- package/node_modules/@tifan/pi-rename/src/sanitize.ts +22 -14
- package/node_modules/pi-lens/CHANGELOG.md +320 -0
- package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +79 -0
- package/node_modules/pi-lens/dist/clients/actionable-warnings-logger.js +16 -1
- package/node_modules/pi-lens/dist/clients/ast-grep-client.js +13 -6
- package/node_modules/pi-lens/dist/clients/availability-probe-flight.js +12 -0
- package/node_modules/pi-lens/dist/clients/biome-client.js +7 -0
- package/node_modules/pi-lens/dist/clients/blocker-freshness.js +20 -0
- package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +56 -19
- package/node_modules/pi-lens/dist/clients/build-identity.js +95 -0
- package/node_modules/pi-lens/dist/clients/bus-publish.js +3 -0
- package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +2 -1
- package/node_modules/pi-lens/dist/clients/cache-observability.js +2 -1
- package/node_modules/pi-lens/dist/clients/cascade-logger.js +15 -1
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +14 -11
- package/node_modules/pi-lens/dist/clients/degradation-ledger.js +56 -4
- package/node_modules/pi-lens/dist/clients/demoted-finding-render.js +14 -0
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +20 -3
- package/node_modules/pi-lens/dist/clients/deps/minimatch.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/collect-later-tier.js +39 -0
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +150 -9
- package/node_modules/pi-lens/dist/clients/dispatch/fact-store.js +231 -9
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +205 -100
- package/node_modules/pi-lens/dist/clients/dispatch/pending-runner-findings.js +87 -0
- package/node_modules/pi-lens/dist/clients/dispatch/plan.js +21 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +174 -55
- package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +5 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +16 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +54 -9
- package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +1 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +37 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +4 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +11 -4
- package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +4 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +8 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +76 -25
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +4 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +19 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +7 -13
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +51 -17
- package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +66 -1
- package/node_modules/pi-lens/dist/clients/file-utils.js +157 -7
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +5 -0
- package/node_modules/pi-lens/dist/clients/formatters.js +28 -3
- package/node_modules/pi-lens/dist/clients/git-guard.js +197 -47
- package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +32 -1
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +5 -1
- package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +7 -0
- package/node_modules/pi-lens/dist/clients/installer/index.js +131 -34
- package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +3 -1
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +4 -13
- package/node_modules/pi-lens/dist/clients/instance-registry-lock.js +145 -0
- package/node_modules/pi-lens/dist/clients/instance-registry.js +432 -122
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +6 -1
- package/node_modules/pi-lens/dist/clients/language-profile.js +4 -2
- package/node_modules/pi-lens/dist/clients/latency-logger.js +19 -1
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
- package/node_modules/pi-lens/dist/clients/lens-map.js +3 -1
- package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +4 -0
- package/node_modules/pi-lens/dist/clients/lsp/client.js +516 -31
- package/node_modules/pi-lens/dist/clients/lsp/config.js +25 -2
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +9 -4
- package/node_modules/pi-lens/dist/clients/lsp/index.js +509 -182
- package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +5 -0
- package/node_modules/pi-lens/dist/clients/lsp/launch.js +36 -8
- package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +116 -4
- package/node_modules/pi-lens/dist/clients/lsp/server.js +142 -13
- package/node_modules/pi-lens/dist/clients/lsp/session-roots.js +99 -0
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +16 -6
- package/node_modules/pi-lens/dist/clients/lsp/workspace-sweep-hold.js +32 -23
- package/node_modules/pi-lens/dist/clients/lsp-mutation.js +16 -2
- package/node_modules/pi-lens/dist/clients/mcp/analyze.js +12 -6
- package/node_modules/pi-lens/dist/clients/mcp/session.js +14 -1
- package/node_modules/pi-lens/dist/clients/memory-sampler.js +23 -1
- package/node_modules/pi-lens/dist/clients/message-end-attribution.js +30 -0
- package/node_modules/pi-lens/dist/clients/metrics-history.js +21 -4
- package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +232 -18
- package/node_modules/pi-lens/dist/clients/package-manager.js +6 -18
- package/node_modules/pi-lens/dist/clients/path-keyed-map.js +14 -1
- package/node_modules/pi-lens/dist/clients/path-utils.js +32 -0
- package/node_modules/pi-lens/dist/clients/pipeline.js +0 -8
- package/node_modules/pi-lens/dist/clients/process-singletons.js +210 -0
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/madge.js +2 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +10 -4
- package/node_modules/pi-lens/dist/clients/project-snapshot.js +33 -11
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +24 -2
- package/node_modules/pi-lens/dist/clients/read-guard.js +74 -7
- package/node_modules/pi-lens/dist/clients/recent-touches.js +17 -5
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +639 -62
- package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +5 -1
- package/node_modules/pi-lens/dist/clients/review-graph-logger.js +21 -1
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +68 -0
- package/node_modules/pi-lens/dist/clients/runtime-session.js +30 -12
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +15 -0
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +106 -7
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +242 -27
- package/node_modules/pi-lens/dist/clients/safe-spawn.js +158 -18
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +48 -17
- package/node_modules/pi-lens/dist/clients/session-lifecycle.js +238 -42
- package/node_modules/pi-lens/dist/clients/sg-runner.js +27 -15
- package/node_modules/pi-lens/dist/clients/shared-checkout-guard.js +338 -0
- package/node_modules/pi-lens/dist/clients/spawn-output-cap.js +37 -0
- package/node_modules/pi-lens/dist/clients/spawn-timeout-cooldown.js +15 -1
- package/node_modules/pi-lens/dist/clients/startup-scan.js +6 -7
- package/node_modules/pi-lens/dist/clients/startup-timing.js +69 -4
- package/node_modules/pi-lens/dist/clients/string-utils.js +20 -0
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +419 -88
- package/node_modules/pi-lens/dist/clients/tool-policy.js +1 -1
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +11 -5
- package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +17 -1
- package/node_modules/pi-lens/dist/clients/warm-attach.js +8 -10
- package/node_modules/pi-lens/dist/clients/word-index-logger.js +13 -1
- package/node_modules/pi-lens/dist/clients/word-index-store.js +448 -0
- package/node_modules/pi-lens/dist/clients/word-index.js +582 -104
- package/node_modules/pi-lens/dist/clients/workspace-topology.js +17 -0
- package/node_modules/pi-lens/dist/clients/zizmor-config.js +26 -6
- package/node_modules/pi-lens/dist/index.js +11243 -6651
- package/node_modules/pi-lens/dist/mcp/build-staleness.js +8 -7
- package/node_modules/pi-lens/dist/mcp/cli.js +3 -1
- package/node_modules/pi-lens/dist/mcp/server.js +6 -1
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +4 -0
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +14 -5
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +3 -1
- package/node_modules/pi-lens/docs/agent-guide.md +4 -2
- package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +41 -10
- package/node_modules/pi-lens/docs/astplayground.md +26 -17
- package/node_modules/pi-lens/package.json +5 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/c-no-malloc-free-test.yml +20 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/cpp-no-malloc-free-test.yml +25 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/cpp-no-printf-test.yml +19 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/go-no-fmt-println-test.yml +19 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/go-no-panic-in-lib-test.yml +17 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/go-no-underscore-func-name-test.yml +18 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/go-prefer-errors-is-test.yml +15 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/go-prefer-string-builder-test.yml +21 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/hyphenated-svg-attribute-test.yml +11 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-no-lateinit-test.yml +17 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-no-nullable-boolean-test.yml +15 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-no-println-test.yml +19 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-no-unnecessary-let-test.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-no-unsafe-cast-test.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-no-var-test.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-prefer-data-class-test.yml +25 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-prefer-is-empty-test.yml +11 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-important-test.yml +21 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-raw-types-test.yml +30 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-string-concat-in-loop-test.yml +100 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-system-out-println-test.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/prefer-string-is-empty-test.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/python-optional-type-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/reducible-list-comprehension-test.yml +11 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/ruby-symbol-to-proc-candidate-test.yml +10 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/rust-no-chars-enumerate-test.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/c-no-malloc-free.yml +39 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/cpp-no-malloc-free.yml +45 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/cpp-no-printf.yml +41 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/go-no-fmt-println.yml +43 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/go-no-panic-in-lib.yml +41 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/go-no-underscore-func-name.yml +35 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/go-prefer-errors-is.yml +40 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/go-prefer-string-builder.yml +43 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/hyphenated-svg-attribute.yml +32 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-no-lateinit.yml +37 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-no-nullable-boolean.yml +33 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-no-println.yml +42 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-no-unnecessary-let.yml +28 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-no-unsafe-cast.yml +28 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-no-var.yml +35 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-prefer-data-class.yml +66 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-prefer-is-empty.yml +35 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-important.yml +21 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-types.yml +33 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-string-concat-in-loop.yml +90 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-system-out-println.yml +16 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/prefer-string-is-empty.yml +11 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/python-optional-type.yml +22 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/reducible-list-comprehension.yml +29 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/ruby-symbol-to-proc-candidate.yml +25 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/rust-no-chars-enumerate.yml +19 -0
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +35 -0
- package/node_modules/pi-mcp-adapter/README.md +5 -2
- package/node_modules/pi-mcp-adapter/cli.js +4 -4
- package/node_modules/pi-mcp-adapter/commands.ts +1 -1
- package/node_modules/pi-mcp-adapter/config.ts +1 -0
- package/node_modules/pi-mcp-adapter/dist/config.js +1 -0
- package/node_modules/pi-mcp-adapter/dist/config.js.map +1 -1
- package/node_modules/pi-mcp-adapter/dist/mcp-bearer-store.d.ts +24 -0
- package/node_modules/pi-mcp-adapter/dist/mcp-bearer-store.js +336 -0
- package/node_modules/pi-mcp-adapter/dist/mcp-bearer-store.js.map +1 -0
- package/node_modules/pi-mcp-adapter/dist/types.d.ts +3 -1
- package/node_modules/pi-mcp-adapter/dist/types.js.map +1 -1
- package/node_modules/pi-mcp-adapter/index.ts +90 -6
- package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +124 -32
- package/node_modules/pi-mcp-adapter/mcp-bearer-store.ts +0 -2
- package/node_modules/pi-mcp-adapter/mcp-oauth-provider.ts +89 -0
- package/node_modules/pi-mcp-adapter/mcp-references.ts +9 -1
- package/node_modules/pi-mcp-adapter/package.json +1 -1
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +62 -22
- package/node_modules/pi-mcp-adapter/request-headers-command.ts +1 -1
- package/node_modules/pi-mcp-adapter/server-manager.ts +6 -0
- package/node_modules/pi-mcp-adapter/types.ts +3 -1
- package/node_modules/pi-web-access/CHANGELOG.md +42 -0
- package/node_modules/pi-web-access/README.md +26 -10
- package/node_modules/pi-web-access/curator-page.ts +12 -3
- package/node_modules/pi-web-access/curator-server.ts +3 -1
- package/node_modules/pi-web-access/extract.ts +88 -13
- package/node_modules/pi-web-access/gemini-search.ts +10 -5
- package/node_modules/pi-web-access/github-extract.ts +47 -3
- package/node_modules/pi-web-access/index.ts +40 -40
- package/node_modules/pi-web-access/package.json +1 -1
- package/node_modules/pi-web-access/page-query.ts +61 -8
- package/node_modules/pi-web-access/xcrawl.ts +264 -0
- package/package.json +19 -22
- package/node_modules/@herbertgao/pi-stash/README.md +0 -34
- package/node_modules/@herbertgao/pi-stash/package.json +0 -51
- package/node_modules/@herbertgao/pi-stash/src/index.ts +0 -118
- package/node_modules/@tifan/pi-titlebar-spinner/README.md +0 -24
- package/node_modules/@tifan/pi-titlebar-spinner/package.json +0 -39
- package/node_modules/@tifan/pi-titlebar-spinner/src/index.ts +0 -49
|
@@ -2,9 +2,13 @@ import * as fs from "node:fs";
|
|
|
2
2
|
import * as os from "node:os";
|
|
3
3
|
import { BoundedLruCache } from "../bounded-cache.js";
|
|
4
4
|
import * as path from "node:path";
|
|
5
|
-
import { findGoverningTsconfigDir, getDirectoryMarkers, } from "../workspace-topology.js";
|
|
5
|
+
import { findGoverningTsconfigDir, getDirectoryMarkers, registerWorkspaceTopologyReset, } from "../workspace-topology.js";
|
|
6
6
|
const cache = new BoundedLruCache(64);
|
|
7
7
|
const referencesCache = new BoundedLruCache(64);
|
|
8
|
+
registerWorkspaceTopologyReset(() => {
|
|
9
|
+
cache.clear();
|
|
10
|
+
referencesCache.clear();
|
|
11
|
+
});
|
|
8
12
|
/** Strip JSONC comments and trailing commas without touching string contents. */
|
|
9
13
|
function parseJsonc(content) {
|
|
10
14
|
let output = "";
|
|
@@ -2,6 +2,7 @@ import * as path from "node:path";
|
|
|
2
2
|
import { isTestMode } from "./env-utils.js";
|
|
3
3
|
import { getGlobalPiLensDir } from "./file-utils.js";
|
|
4
4
|
import { createNdjsonLogger } from "./ndjson-logger.js";
|
|
5
|
+
import { normalizeFilePath } from "./path-utils.js";
|
|
5
6
|
const REVIEW_GRAPH_LOG_DIR = getGlobalPiLensDir();
|
|
6
7
|
const REVIEW_GRAPH_LOG_FILE = path.join(REVIEW_GRAPH_LOG_DIR, "review-graph.log");
|
|
7
8
|
const writer = createNdjsonLogger({ filePath: REVIEW_GRAPH_LOG_FILE });
|
|
@@ -27,6 +28,9 @@ export function makeReviewGraphBuildMetadata(graph, options = {}) {
|
|
|
27
28
|
graph.persistCoverage?.sourceFilesTruncated
|
|
28
29
|
? { sourceFilesTruncated: true }
|
|
29
30
|
: {}),
|
|
31
|
+
...(options.pathNormalizeCalls === undefined
|
|
32
|
+
? {}
|
|
33
|
+
: { pathNormalizeCalls: options.pathNormalizeCalls }),
|
|
30
34
|
nodes: graph.nodes.size,
|
|
31
35
|
edges: graph.edges.length,
|
|
32
36
|
...(graph.persistCoverage
|
|
@@ -34,11 +38,27 @@ export function makeReviewGraphBuildMetadata(graph, options = {}) {
|
|
|
34
38
|
: {}),
|
|
35
39
|
};
|
|
36
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* #2141: call sites feed this a mix of raw `cwd` params and already-normalized
|
|
43
|
+
* cache keys (`normalizeMapKey(path.resolve(cwd))`), so the same project root
|
|
44
|
+
* showed up in the log as both `C:\...\pi-free` and `C:/.../pi-free`. Rather
|
|
45
|
+
* than auditing every call site, normalize once here — the single emit
|
|
46
|
+
* seam — matching the form `normalizeFilePath` already produces for every
|
|
47
|
+
* other structured log's `cwd` field (bus-publish, disposition-publish,
|
|
48
|
+
* diagnostics-publish, format-events-publish all normalize at their publish
|
|
49
|
+
* call sites; this pulls the same conversion in-house so no future call site
|
|
50
|
+
* can regress it).
|
|
51
|
+
*/
|
|
37
52
|
export function logReviewGraph(entry) {
|
|
38
53
|
if (isTestMode()) {
|
|
39
54
|
return;
|
|
40
55
|
}
|
|
41
|
-
writer.log({
|
|
56
|
+
writer.log({
|
|
57
|
+
ts: new Date().toISOString(),
|
|
58
|
+
...entry,
|
|
59
|
+
cwd: normalizeFilePath(entry.cwd),
|
|
60
|
+
pid: process.pid,
|
|
61
|
+
});
|
|
42
62
|
}
|
|
43
63
|
export function getReviewGraphLogPath() {
|
|
44
64
|
return REVIEW_GRAPH_LOG_FILE;
|
|
@@ -734,6 +734,74 @@ export class RuntimeCoordinator {
|
|
|
734
734
|
this._pendingInlineBlockers.delete(key);
|
|
735
735
|
return true;
|
|
736
736
|
}
|
|
737
|
+
/**
|
|
738
|
+
* #1950 fix-round F1: read the current delivery count WITHOUT committing
|
|
739
|
+
* an increment. `runtime-turn.ts` needs the count a delivery would reach
|
|
740
|
+
* BEFORE it knows whether that delivery will actually reach the agent —
|
|
741
|
+
* the turn-end signature dedupe (`turn-end-findings-last`) can suppress a
|
|
742
|
+
* turn whose rendered content is identical to the last one, and a
|
|
743
|
+
* suppressed turn must not advance the counter (the agent never saw it).
|
|
744
|
+
* The caller peeks, renders the tentative body, and only calls
|
|
745
|
+
* {@link incrementInlineBlockerStaleDelivery} once it knows the turn's
|
|
746
|
+
* content is NOT being suppressed.
|
|
747
|
+
*/
|
|
748
|
+
peekInlineBlockerStaleDeliveryCount(filePath) {
|
|
749
|
+
const key = path.resolve(filePath);
|
|
750
|
+
return this._pendingInlineBlockers.get(key)?.staleDeliveryCount ?? 0;
|
|
751
|
+
}
|
|
752
|
+
/**
|
|
753
|
+
* #1950: commit one more turn end that re-served this record while
|
|
754
|
+
* `stale`. The caller (`runtime-turn.ts`) only calls this for a
|
|
755
|
+
* `"dependency-drift"` demotion — a `"past-eof"` demotion retires after
|
|
756
|
+
* its own single delivery (#1944, `retireDemotedPastEofBlocker`) and
|
|
757
|
+
* never accumulates a count — and only AFTER confirming the turn's
|
|
758
|
+
* content will not be suppressed by the signature dedupe (see
|
|
759
|
+
* {@link peekInlineBlockerStaleDeliveryCount}), so this counts ACTUAL
|
|
760
|
+
* deliveries the agent saw, not turn-end loop iterations. Returns the new
|
|
761
|
+
* count, or 0 when there is no entry to count against (already retired,
|
|
762
|
+
* or never recorded).
|
|
763
|
+
*/
|
|
764
|
+
incrementInlineBlockerStaleDelivery(filePath) {
|
|
765
|
+
const key = path.resolve(filePath);
|
|
766
|
+
const existing = this._pendingInlineBlockers.get(key);
|
|
767
|
+
if (!existing)
|
|
768
|
+
return 0;
|
|
769
|
+
const next = (existing.staleDeliveryCount ?? 0) + 1;
|
|
770
|
+
this._pendingInlineBlockers.set(key, {
|
|
771
|
+
...existing,
|
|
772
|
+
staleDeliveryCount: next,
|
|
773
|
+
});
|
|
774
|
+
return next;
|
|
775
|
+
}
|
|
776
|
+
/**
|
|
777
|
+
* #1950: retire a dependency-drift demotion once it has been delivered
|
|
778
|
+
* `DEPENDENCY_DRIFT_MAX_DELIVERIES` times with no re-run confirming or
|
|
779
|
+
* clearing it. Unlike {@link retireDemotedPastEofBlocker}, the record is
|
|
780
|
+
* NOT provably unrecoverable — its coordinates are still in bounds, and a
|
|
781
|
+
* fresh dispatch of the file could still confirm or clear it. This is a
|
|
782
|
+
* bounded-noise cap, not a "this can never resolve" verdict, and the
|
|
783
|
+
* caller's ledger reason must say so (`demoted-finding-retired`'s "capped,
|
|
784
|
+
* re-run can still confirm" vs. past-EOF's "retired, unrecoverable").
|
|
785
|
+
*
|
|
786
|
+
* Only ever touches this gate's OWN demotion (`staleReason ===
|
|
787
|
+
* "dependency-drift"`) — a past-EOF demotion on the same file is that
|
|
788
|
+
* gate's own record to retire, not this one's.
|
|
789
|
+
*
|
|
790
|
+
* @returns true when an entry was retired — the caller records it, so the
|
|
791
|
+
* suppression is never silent (#1432 Gap 1).
|
|
792
|
+
*/
|
|
793
|
+
retireDemotedDependencyDriftBlocker(filePath) {
|
|
794
|
+
const key = path.resolve(filePath);
|
|
795
|
+
const existing = this._pendingInlineBlockers.get(key);
|
|
796
|
+
if (!existing)
|
|
797
|
+
return false;
|
|
798
|
+
if (!existing.stale)
|
|
799
|
+
return false;
|
|
800
|
+
if (existing.staleReason !== "dependency-drift")
|
|
801
|
+
return false;
|
|
802
|
+
this._pendingInlineBlockers.delete(key);
|
|
803
|
+
return true;
|
|
804
|
+
}
|
|
737
805
|
/**
|
|
738
806
|
* Retire a file's inline blocker because a FRESH, content-bound diagnostic
|
|
739
807
|
* verdict proved it gone (#1561).
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as nodeFs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { resetBoundedTelemetry } from "./bounded-telemetry.js";
|
|
4
|
+
import { rotateMessageEndAttribution } from "./message-end-attribution.js";
|
|
4
5
|
import { createDeadline, yieldIfOverBudget } from "./cooperative-budget.js";
|
|
5
6
|
import { deadCodeIssueCount } from "./dead-code-client.js";
|
|
6
7
|
import { logDeadCodeScan } from "./dead-code-logger.js";
|
|
@@ -10,6 +11,8 @@ import { resetPsScriptAnalyzerAvailability } from "./dispatch/runners/psscriptan
|
|
|
10
11
|
import { resetInstallRetryLatches } from "./dispatch/runners/utils/availability-policy.js";
|
|
11
12
|
import { resetLazyInstallAttempts } from "./dispatch/runners/utils/lazy-installer.js";
|
|
12
13
|
import { resetDispatchAvailabilityState } from "./dispatch/runners/utils/runner-helpers.js";
|
|
14
|
+
import { resetObservedRunnerLatency } from "./dispatch/collect-later-tier.js";
|
|
15
|
+
import { resetPendingRunnerFindings } from "./dispatch/pending-runner-findings.js";
|
|
13
16
|
import { clearAllSessions as clearFileTimeSessions } from "./file-time.js";
|
|
14
17
|
import { getGlobalPiLensDir, getKnipIgnorePatterns, getProjectDataDir, } from "./file-utils.js";
|
|
15
18
|
import { GitleaksClient } from "./gitleaks-client.js";
|
|
@@ -22,7 +25,7 @@ import { runLogCleanup } from "./log-cleanup.js";
|
|
|
22
25
|
import { resetCascadeTierSessionState } from "./lsp/cascade-tier.js";
|
|
23
26
|
import { initLSPConfig, loadLSPConfig } from "./lsp/config.js";
|
|
24
27
|
import { resetWorkspaceDiagnosticsCacheSession } from "./lsp/workspace-diagnostics-session.js";
|
|
25
|
-
import { resetDirectLspCommandAvailability } from "./lsp/server.js";
|
|
28
|
+
import { resetDirectLspCommandAvailability, resetLSPCaseSensitivityState, } from "./lsp/server.js";
|
|
26
29
|
import { loadLspService } from "./lsp-lazy.js";
|
|
27
30
|
import { resetManagedToolRefreshSession } from "./installer/managed-tool-refresh-session.js";
|
|
28
31
|
import { resetResolvedPathCache } from "./installer/index.js";
|
|
@@ -32,7 +35,6 @@ import { isAtOrAboveHomeDir } from "./path-utils.js";
|
|
|
32
35
|
import { isPrintMode } from "./print-mode.js";
|
|
33
36
|
import { readLatestProjectSequence, readLatestProjectSequenceAsync, } from "./project-changes.js";
|
|
34
37
|
import { getProjectSnapshotPath, getProjectSnapshotLegacyPath, hydrateRuntimeFromProjectSnapshot, hydrateRuntimeFromProjectSnapshotIfIdle, isProjectSnapshotFresh, isProjectSnapshotMetaStale, loadProjectSnapshot, loadProjectSnapshotExportsAndRules, PROJECT_SNAPSHOT_VERSION, readProjectSnapshotMeta, saveRuntimeProjectSnapshot, } from "./project-snapshot.js";
|
|
35
|
-
import { clearTsconfigPathsCache } from "./review-graph/tsconfig-paths.js";
|
|
36
38
|
import { scanProjectRules } from "./rules-scanner.js";
|
|
37
39
|
import { resetSafeSpawnWindowsCommandCache } from "./safe-spawn.js";
|
|
38
40
|
import { getSlowFsVerdict, isSlowFs, slowFsDegradationNotice, } from "./slow-fs.js";
|
|
@@ -623,7 +625,7 @@ async function buildOrRefreshWordIndex(args) {
|
|
|
623
625
|
const snapshot = loadProjectSnapshot(snapshotRoot);
|
|
624
626
|
const snapshotLoadMs = Date.now() - snapshotLoadStartMs;
|
|
625
627
|
if (snapshot?.wordIndex) {
|
|
626
|
-
const { deserializeWordIndex, refreshWordIndexIncrementally } = await import("./word-index.js");
|
|
628
|
+
const { deserializeWordIndex, refreshWordIndexIncrementally, countWordIndexPostingEntries, estimateWordIndexResidentBytes, } = await import("./word-index.js");
|
|
627
629
|
const deserializeStartMs = Date.now();
|
|
628
630
|
const index = deserializeWordIndex(snapshot.wordIndex);
|
|
629
631
|
const deserializeMs = Date.now() - deserializeStartMs;
|
|
@@ -675,6 +677,8 @@ async function buildOrRefreshWordIndex(args) {
|
|
|
675
677
|
durationMs: Date.now() - startMs,
|
|
676
678
|
indexedFileCount: index.docCount,
|
|
677
679
|
tokens: index.postings.size,
|
|
680
|
+
postingEntries: countWordIndexPostingEntries(index),
|
|
681
|
+
residentBytes: estimateWordIndexResidentBytes(index),
|
|
678
682
|
truncated: index.truncated,
|
|
679
683
|
phaseDurationsMs: {
|
|
680
684
|
snapshotLoadMs,
|
|
@@ -714,7 +718,7 @@ async function buildOrRefreshWordIndex(args) {
|
|
|
714
718
|
// implementation backs this task, the quick-mode warmup call below, AND the
|
|
715
719
|
// stateless cold-query background trigger in word-index.ts — a bound/skip
|
|
716
720
|
// -rule change lands once, not in three copies.
|
|
717
|
-
const { buildWordIndexAsync, collectWordIndexDocs } = await import("./word-index.js");
|
|
721
|
+
const { buildWordIndexAsync, collectWordIndexDocs, countWordIndexPostingEntries, estimateWordIndexResidentBytes, } = await import("./word-index.js");
|
|
718
722
|
const docs = await collectWordIndexDocs(analysisRoot, () => runtime.isCurrentSession(sessionGeneration), rebuildPreflightFiles);
|
|
719
723
|
if (!runtime.isCurrentSession(sessionGeneration))
|
|
720
724
|
return;
|
|
@@ -751,6 +755,8 @@ async function buildOrRefreshWordIndex(args) {
|
|
|
751
755
|
durationMs: Date.now() - startMs,
|
|
752
756
|
indexedFileCount: runtime.wordIndex.docCount,
|
|
753
757
|
tokens: runtime.wordIndex.postings.size,
|
|
758
|
+
postingEntries: countWordIndexPostingEntries(runtime.wordIndex),
|
|
759
|
+
residentBytes: estimateWordIndexResidentBytes(runtime.wordIndex),
|
|
754
760
|
truncated: runtime.wordIndex.truncated,
|
|
755
761
|
skipped: docs.skipped,
|
|
756
762
|
});
|
|
@@ -1150,7 +1156,12 @@ function scheduleStartupScans(deps, runtime, sessionGeneration, analysisRoot, sn
|
|
|
1150
1156
|
// Build (or hydrate) the canonical review graph first. The call graph is a
|
|
1151
1157
|
// derived projection of that graph, so its freshness is the review graph's
|
|
1152
1158
|
// version/signature—not a second source walk and mtime policy.
|
|
1153
|
-
|
|
1159
|
+
// Subject labels this store's capacity-eviction telemetry distinctly
|
|
1160
|
+
// from the other five production FactStore instances (#2243 review
|
|
1161
|
+
// round 3, F1) — this session-start walk runs BEFORE any dispatch and
|
|
1162
|
+
// can visit every file in the project, so a shared subject would let
|
|
1163
|
+
// it consume the dispatch store's once-per-session ledger slot first.
|
|
1164
|
+
const sessionFacts = new FactStore("runtime-session-call-graph");
|
|
1154
1165
|
const graph = await buildOrUpdateGraph(analysisRoot, [], sessionFacts);
|
|
1155
1166
|
if (!runtime.isCurrentSession(sessionGeneration))
|
|
1156
1167
|
return;
|
|
@@ -1294,6 +1305,10 @@ export async function handleSessionStart(deps) {
|
|
|
1294
1305
|
// numbering at 0, so without this a stale count could survive a session
|
|
1295
1306
|
// boundary that happened to land on the same index.
|
|
1296
1307
|
resetBoundedTelemetry();
|
|
1308
|
+
// #1956 R3: stale message_end events drain after replacement. Rotate the
|
|
1309
|
+
// live anchor into one bounded previous slot so the queued event keeps the
|
|
1310
|
+
// replaced session's attribution until a newer live message_end is seen.
|
|
1311
|
+
rotateMessageEndAttribution();
|
|
1297
1312
|
const handlerEnteredAt = Date.now();
|
|
1298
1313
|
const sessionStartMs = deps.sessionStartFiredAt ?? handlerEnteredAt;
|
|
1299
1314
|
const cwdForTelemetry = deps.ctxCwd ?? process.cwd();
|
|
@@ -1603,14 +1618,10 @@ export async function handleSessionStart(deps) {
|
|
|
1603
1618
|
clearFileTimeSessions();
|
|
1604
1619
|
runtime.complexityBaselines.clear();
|
|
1605
1620
|
resetDispatchBaselines(ctxCwd);
|
|
1606
|
-
// #806:
|
|
1607
|
-
//
|
|
1608
|
-
//
|
|
1609
|
-
// sessions is picked up fresh instead of only on process restart — this
|
|
1610
|
-
// also fixes #805's mid-session tsconfig staleness (the matcher cache was
|
|
1611
|
-
// previously session-lived with no reset hook at all).
|
|
1621
|
+
// #806: clear the shared per-directory marker index and registered
|
|
1622
|
+
// topology-derived caches only at session start. Mid-session edits are NOT
|
|
1623
|
+
// detected; #805's tsconfig matcher cache follows the same registry reset.
|
|
1612
1624
|
resetWorkspaceTopology();
|
|
1613
|
-
clearTsconfigPathsCache();
|
|
1614
1625
|
// #2000: opaque-recovery baselines are keyed cwd:generation (unreachable
|
|
1615
1626
|
// after reset) and the git-worktree memo must re-probe after a session
|
|
1616
1627
|
// that may have seen a non-git dir become one.
|
|
@@ -1630,6 +1641,10 @@ export async function handleSessionStart(deps) {
|
|
|
1630
1641
|
// the tool for the rest of the process lifetime. Clear it here, same
|
|
1631
1642
|
// boundary as the other per-session caches on this line.
|
|
1632
1643
|
resetDispatchAvailabilityState();
|
|
1644
|
+
// Runner collect-later observations and their late findings are session
|
|
1645
|
+
// scoped. A new session must re-probe rather than inherit a process latch.
|
|
1646
|
+
resetObservedRunnerLatency();
|
|
1647
|
+
resetPendingRunnerFindings();
|
|
1633
1648
|
// #1995: a command that TIMED OUT (not merely failed a probe) cools down
|
|
1634
1649
|
// for the rest of the session so a hot loop of edits cannot hand the same
|
|
1635
1650
|
// wedged .cmd shim a second budget. A new session may retry: the executable
|
|
@@ -1670,6 +1685,9 @@ export async function handleSessionStart(deps) {
|
|
|
1670
1685
|
// #1897: direct-LSP negative availability and bare installer paths are
|
|
1671
1686
|
// session facts. A command or PATH entry can appear between sessions.
|
|
1672
1687
|
resetDirectLspCommandAvailability();
|
|
1688
|
+
// #2052: a root may not exist when the case-sensitivity probe first sees it.
|
|
1689
|
+
// Re-probe it at the next session boundary after the workspace is created.
|
|
1690
|
+
resetLSPCaseSensitivityState();
|
|
1673
1691
|
resetResolvedPathCache();
|
|
1674
1692
|
// #1653: pnpm/yarn/bun/npm's availability latches (package-manager.ts) are
|
|
1675
1693
|
// module-local, same #1490/#1535 shape as the two lines above — the
|
|
@@ -5,6 +5,7 @@ import { recordDegradationOnce } from "./degradation-ledger.js";
|
|
|
5
5
|
import { detectFileKind } from "./file-kinds.js";
|
|
6
6
|
import { isPathIgnoredByProject } from "./file-utils.js";
|
|
7
7
|
import { evaluateGitGuard, isGitCommitOrPushAttempt } from "./git-guard.js";
|
|
8
|
+
import { evaluateSharedCheckoutGuard } from "./shared-checkout-guard.js";
|
|
8
9
|
import { logLatency } from "./latency-logger.js";
|
|
9
10
|
import { normalizeMapKey } from "./path-utils.js";
|
|
10
11
|
import { captureFileStats, getOpaqueBaselineStore, isGitWorktree, } from "./opaque-mutation-scan.js";
|
|
@@ -383,6 +384,20 @@ async function handleToolCallImpl(deps) {
|
|
|
383
384
|
};
|
|
384
385
|
}
|
|
385
386
|
}
|
|
387
|
+
// #2007: a sibling session's branch switch destroys uncommitted work in a
|
|
388
|
+
// shared checkout. Independent of `lens-guard`: that gate is about blocker
|
|
389
|
+
// hygiene before a commit, this one is about not deleting a peer's WIP.
|
|
390
|
+
// The evaluator short-circuits on a pure string classification, so a
|
|
391
|
+
// non-git bash command pays no I/O here.
|
|
392
|
+
if (getFlag("lens-checkout-guard")) {
|
|
393
|
+
const sharedCheckout = await evaluateSharedCheckoutGuard(toolName, event.input, ctx.cwd ?? runtime.projectRoot ?? process.cwd());
|
|
394
|
+
if (sharedCheckout.block) {
|
|
395
|
+
return {
|
|
396
|
+
block: true,
|
|
397
|
+
reason: sharedCheckout.reason,
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
}
|
|
386
401
|
const rawFilePath = getToolCallRawFilePath(toolName, event);
|
|
387
402
|
const pathResolution = resolveToolCallFilePath(rawFilePath, ctx.cwd, runtime.projectRoot);
|
|
388
403
|
filePath = pathResolution?.path;
|
|
@@ -4,11 +4,11 @@ import * as path from "node:path";
|
|
|
4
4
|
import { noteAuthoritativeContentAttachment } from "./agent-nudge.js";
|
|
5
5
|
import { captureFileStats, diffFileStats, getOpaqueBaselineStore, recoverOpaqueChangesViaGit, } from "./opaque-mutation-scan.js";
|
|
6
6
|
import { normalizeMapKey } from "./path-utils.js";
|
|
7
|
-
import { extractReadPathsFromCommand, extractDeletedPathsFromCommand, extractGrepSearchReadsFromOutput, extractWrittenPathsFromCommand, } from "./bash-file-access.js";
|
|
7
|
+
import { extractReadPathsFromCommand, extractDeletedPathsFromCommand, extractGrepSearchReadsFromOutput, extractWrittenPathsFromCommand, tokenizeShellCommand, } from "./bash-file-access.js";
|
|
8
8
|
import { registerSearchReads, } from "./search-read-registration.js";
|
|
9
9
|
import { createFileTime } from "./file-time.js";
|
|
10
10
|
import { publishFormatQueued } from "./format-events-publish.js";
|
|
11
|
-
import { isPathIgnoredByProject } from "./file-utils.js";
|
|
11
|
+
import { invalidateProjectIgnoreMatcherForPath, isPathIgnoredByProject, } from "./file-utils.js";
|
|
12
12
|
import { getFormatService } from "./format-service.js";
|
|
13
13
|
import { isExternalOrVendorFile, normalizeEphemeralMapKey, pathsEqual, } from "./path-utils.js";
|
|
14
14
|
import { PathKeyedMap } from "./path-keyed-map.js";
|
|
@@ -22,7 +22,72 @@ import { renderPostAutofixNotice, } from "./post-autofix-notice.js";
|
|
|
22
22
|
import { syncGitGuardRecord } from "./git-guard.js";
|
|
23
23
|
import { scheduleWordIndexPersist } from "./word-index.js";
|
|
24
24
|
import { RUNTIME_CONFIG } from "./runtime-config.js";
|
|
25
|
+
import { getActiveSessionId } from "./session-lifecycle.js";
|
|
25
26
|
const AUTHORITATIVE_CONTENT_MAX_BYTES = RUNTIME_CONFIG.pipeline.lspMaxFileBytes;
|
|
27
|
+
/**
|
|
28
|
+
* Git subcommands that import ANOTHER commit's content into the index. The
|
|
29
|
+
* whole family, with a verdict for each (#2060):
|
|
30
|
+
* - merge, rebase, cherry-pick, pull, revert, am: IN. Each stages the other
|
|
31
|
+
* side's clean files beside the unmerged ones. `pull` is fetch+merge and
|
|
32
|
+
* `am --3way` reaches the same unmerged state, both probed on git 2.55.
|
|
33
|
+
* - stash pop / stash apply: OUT. A conflicted pop leaves `M ` entries too,
|
|
34
|
+
* but that content is the agent's OWN stashed work. Excluding it would
|
|
35
|
+
* destroy exactly what opaque recovery exists to capture.
|
|
36
|
+
* - checkout -m: OUT. Its "incoming" side is the agent's local modifications
|
|
37
|
+
* carried across the switch, so the same reasoning applies.
|
|
38
|
+
* - apply -3 / --3way: OUT. The patch is normally one the agent wrote, and
|
|
39
|
+
* `apply` is far more often used without conflicts, so the narrower default
|
|
40
|
+
* is to keep capturing.
|
|
41
|
+
* Membership only ARMS the filter; it still needs a real unmerged entry to do
|
|
42
|
+
* anything, so a non-integration use of a listed subcommand is inert.
|
|
43
|
+
*/
|
|
44
|
+
const GIT_INTEGRATION_SUBCOMMANDS = new Set([
|
|
45
|
+
"merge",
|
|
46
|
+
"rebase",
|
|
47
|
+
"cherry-pick",
|
|
48
|
+
"pull",
|
|
49
|
+
"revert",
|
|
50
|
+
"am",
|
|
51
|
+
]);
|
|
52
|
+
const GIT_GLOBAL_OPTIONS_WITH_VALUE = new Set([
|
|
53
|
+
"-C",
|
|
54
|
+
"-c",
|
|
55
|
+
"--config-env",
|
|
56
|
+
"--git-dir",
|
|
57
|
+
"--namespace",
|
|
58
|
+
"--work-tree",
|
|
59
|
+
]);
|
|
60
|
+
/**
|
|
61
|
+
* Failed integration commands are the one opaque-recovery case where Git's
|
|
62
|
+
* index contains changes made by the other branch rather than the agent.
|
|
63
|
+
* Keep this narrow: ordinary scripts and successful Git operations retain the
|
|
64
|
+
* normal recovery contract.
|
|
65
|
+
*/
|
|
66
|
+
export function isFailedGitIntegrationCommand(command, isError) {
|
|
67
|
+
if (isError !== true)
|
|
68
|
+
return false;
|
|
69
|
+
return tokenizeShellCommand(command).some(({ tokens, unsupported }) => {
|
|
70
|
+
if (unsupported)
|
|
71
|
+
return false;
|
|
72
|
+
const executable = path.win32
|
|
73
|
+
.basename(tokens[0] ?? "")
|
|
74
|
+
.toLowerCase()
|
|
75
|
+
.replace(/\.(?:cmd|exe)$/, "");
|
|
76
|
+
if (executable !== "git")
|
|
77
|
+
return false;
|
|
78
|
+
for (let index = 1; index < tokens.length; index += 1) {
|
|
79
|
+
const token = tokens[index] ?? "";
|
|
80
|
+
if (GIT_GLOBAL_OPTIONS_WITH_VALUE.has(token)) {
|
|
81
|
+
index += 1;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (token.startsWith("-"))
|
|
85
|
+
continue;
|
|
86
|
+
return GIT_INTEGRATION_SUBCOMMANDS.has(token);
|
|
87
|
+
}
|
|
88
|
+
return false;
|
|
89
|
+
});
|
|
90
|
+
}
|
|
26
91
|
function parseDiffRanges(diff) {
|
|
27
92
|
const changedLines = [];
|
|
28
93
|
for (const line of diff.split("\n")) {
|
|
@@ -269,6 +334,8 @@ export async function handleToolResult(deps) {
|
|
|
269
334
|
? rawFilePath
|
|
270
335
|
: path.resolve(resolutionBasis, rawFilePath)
|
|
271
336
|
: rawFilePath;
|
|
337
|
+
if (filePath)
|
|
338
|
+
invalidateProjectIgnoreMatcherForPath(filePath);
|
|
272
339
|
// Purely diagnostic: tool_call's call-time verdict (computed on ITS OWN
|
|
273
340
|
// resolved path, which may since have been superseded) disagreed with
|
|
274
341
|
// what actually executed. This does NOT gate anything by itself — the
|
|
@@ -351,16 +418,41 @@ export async function handleToolResult(deps) {
|
|
|
351
418
|
}
|
|
352
419
|
else if (pending.strategy === "git") {
|
|
353
420
|
// Git-first: no universe cap - works on any repo size.
|
|
354
|
-
const recovery = await recoverOpaqueChangesViaGit(scanRoot, pending.startedAt
|
|
421
|
+
const recovery = await recoverOpaqueChangesViaGit(scanRoot, pending.startedAt, {
|
|
422
|
+
excludeIndexOnlyWhenUnmerged: isFailedGitIntegrationCommand(command, event.isError),
|
|
423
|
+
});
|
|
355
424
|
if (recovery.verdict === "recovered") {
|
|
356
425
|
opaquePaths = recovery.paths.filter((p) => !isExternalOrVendorFile(p, scanRoot) &&
|
|
357
426
|
!isPathIgnoredByProject(p, scanRoot, false));
|
|
358
427
|
}
|
|
359
|
-
else if (recovery.verdict === "unknown"
|
|
360
|
-
//
|
|
361
|
-
//
|
|
428
|
+
else if (recovery.verdict === "unknown") {
|
|
429
|
+
// #2060: deliberately WIDER than the old `recognized.length > 0`
|
|
430
|
+
// guard. A fully opaque command whose probe failed is the shape
|
|
431
|
+
// whose coverage is least knowable, and it used to record
|
|
432
|
+
// nothing at all.
|
|
362
433
|
unknownReason = recovery.unknownReason;
|
|
363
434
|
}
|
|
435
|
+
// #2060: both counts are bounded (one record per tool_result, no
|
|
436
|
+
// per-path logging) and exist because filtering is invisible in
|
|
437
|
+
// production otherwise - the dropped paths simply never appear.
|
|
438
|
+
if ((recovery.excludedIncomingCount ?? 0) > 0) {
|
|
439
|
+
logLatency({
|
|
440
|
+
type: "phase",
|
|
441
|
+
phase: "opaque_mutation_incoming_excluded",
|
|
442
|
+
filePath: command.slice(0, 80),
|
|
443
|
+
durationMs: Date.now() - started,
|
|
444
|
+
result: `excluded:${recovery.excludedIncomingCount}`,
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
if ((recovery.unknownStatusCount ?? 0) > 0) {
|
|
448
|
+
logLatency({
|
|
449
|
+
type: "phase",
|
|
450
|
+
phase: "opaque_mutation_status_pair_unknown",
|
|
451
|
+
filePath: command.slice(0, 80),
|
|
452
|
+
durationMs: Date.now() - started,
|
|
453
|
+
result: `kept:${recovery.unknownStatusCount}`,
|
|
454
|
+
});
|
|
455
|
+
}
|
|
364
456
|
}
|
|
365
457
|
else if (pending.stats) {
|
|
366
458
|
const outcome = await captureFileStats(scanRoot, {
|
|
@@ -831,7 +923,14 @@ export async function handleToolResult(deps) {
|
|
|
831
923
|
},
|
|
832
924
|
});
|
|
833
925
|
dbg(`runPipeline crash stack: ${pipelineErr.stack}`);
|
|
834
|
-
|
|
926
|
+
// The LSP fleet is process-wide, but a pipeline crash belongs to one
|
|
927
|
+
// evaluation. A registered primary owns the fleet; a known secondary
|
|
928
|
+
// must not tear it down. Keep the historical reset when no registration
|
|
929
|
+
// exists because synthetic callers and early startup have no role evidence.
|
|
930
|
+
const activePrimarySessionId = getActiveSessionId();
|
|
931
|
+
const crashBelongsToPrimary = activePrimarySessionId === undefined ||
|
|
932
|
+
activePrimarySessionId === runtime.telemetrySessionId;
|
|
933
|
+
if (!getFlag("no-lsp") && crashBelongsToPrimary) {
|
|
835
934
|
resetLSPService({ fast: true, reason: "pipeline_crash" });
|
|
836
935
|
}
|
|
837
936
|
logLatency({
|