@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
|
@@ -10,7 +10,8 @@ import { detectFileKind } from "../file-kinds.js";
|
|
|
10
10
|
import { getLspCapableKinds, getPrimaryDispatchGroup, } from "../language-policy.js";
|
|
11
11
|
import { formatSlopScoreSummary, } from "../session-summary.js";
|
|
12
12
|
import { clearCoverageNoticeState, clearLatencyReports, createDispatchContext, dispatchForFile, formatLatencyReport, getLatencyReports, RunnerRegistry, } from "./dispatcher.js";
|
|
13
|
-
import {
|
|
13
|
+
import { recordDegradationOnce } from "../degradation-ledger.js";
|
|
14
|
+
import { FactStore, setFactStoreEvictionReporter } from "./fact-store.js";
|
|
14
15
|
import { TOOL_PLANS } from "./plan.js";
|
|
15
16
|
// Re-export latency tracking types and functions
|
|
16
17
|
export { clearLatencyReports, formatLatencyReport, getLatencyReports };
|
|
@@ -37,7 +38,7 @@ import { clearModuleGraphCache } from "../review-graph/workspace-modules.js";
|
|
|
37
38
|
import { releaseWorkspaceTopologyIdleTimers } from "../workspace-topology.js";
|
|
38
39
|
import { RUNTIME_CONFIG } from "../runtime-config.js";
|
|
39
40
|
import { findCompiledClassesDir, hasJavaBuildDescriptor, } from "../tool-policy.js";
|
|
40
|
-
import {
|
|
41
|
+
import { removeWordIndexDocumentAsync, updateWordIndexDocumentForEdit, WORD_INDEX_MAX_BYTES, } from "../word-index.js";
|
|
41
42
|
import { reconcileCascadeNeighborLspErrors } from "../widget-state.js";
|
|
42
43
|
import { findAuxiliaryProfileForSource } from "./auxiliary-lsp.js";
|
|
43
44
|
// Register fact providers. All register eagerly here (the dispatch entry) — the
|
|
@@ -98,7 +99,46 @@ registerRule(commentedCredentialsRule);
|
|
|
98
99
|
export function applyProjectLensConfig(cwd) {
|
|
99
100
|
return loadPiLensProjectConfig(cwd);
|
|
100
101
|
}
|
|
101
|
-
|
|
102
|
+
// "dispatch" labels this store's eviction telemetry (#2243 review round 3,
|
|
103
|
+
// F1) — five other production FactStore instances exist (mcp/analyze.ts,
|
|
104
|
+
// lens-map.ts, project-diagnostics/scanner.ts, runtime-session.ts's
|
|
105
|
+
// session-start call-graph task, mcp/cli.ts); a shared constant subject let
|
|
106
|
+
// runtime-session's session-start review-graph walk consume the once-per-
|
|
107
|
+
// session ledger slot before any dispatch ran, misattributing the record.
|
|
108
|
+
const sessionFacts = new FactStore("dispatch");
|
|
109
|
+
// #2243 item 4: wire the fact-store's capacity-eviction telemetry to the
|
|
110
|
+
// ledger from HERE, not from fact-store.ts. fact-store stays an import leaf so
|
|
111
|
+
// it cannot re-enter the safe-spawn ↔ degradation-ledger cycle (see
|
|
112
|
+
// `setFactStoreEvictionReporter`). The reporter forwards each store's own
|
|
113
|
+
// subject, so the ledger's per-kind+subject dedupe emits exactly ONE record
|
|
114
|
+
// per session PER STORE, re-arming when the ledger resets at session_start.
|
|
115
|
+
//
|
|
116
|
+
// #2247 review F1: the axis was previously dropped here, so
|
|
117
|
+
// `recordDegradationOnce`'s `${kind}\0${subject}` dedupe collapsed a store's
|
|
118
|
+
// count-axis and byte-axis evictions onto the SAME key — whichever axis
|
|
119
|
+
// tripped first (always count, since 1024 typical files land far under 64
|
|
120
|
+
// MiB) silently consumed the once-per-session slot and a later byte-axis
|
|
121
|
+
// eviction on that same store recorded nothing. Fold the axis into the
|
|
122
|
+
// subject (`<store>:<axis>`), matching this ledger's own `<store>:<file>`
|
|
123
|
+
// convention (see `demoted-finding-retired`'s doc comment) rather than
|
|
124
|
+
// growing the `kind` union per axis. `pinned-over-budget` (#2247 review F2)
|
|
125
|
+
// is a distinct condition, not an eviction, so it gets its own kind instead
|
|
126
|
+
// of sharing the eviction kind's subject convention.
|
|
127
|
+
setFactStoreEvictionReporter((subject, axis, reason) => {
|
|
128
|
+
if (axis === "pinned-over-budget") {
|
|
129
|
+
recordDegradationOnce({
|
|
130
|
+
kind: "fact-store-pinned-over-budget",
|
|
131
|
+
subject,
|
|
132
|
+
reason,
|
|
133
|
+
});
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
recordDegradationOnce({
|
|
137
|
+
kind: "fact-store-capacity-eviction",
|
|
138
|
+
subject: `${subject}:${axis}`,
|
|
139
|
+
reason,
|
|
140
|
+
});
|
|
141
|
+
});
|
|
102
142
|
const cascadeDiagnosticBaselines = new Map();
|
|
103
143
|
const sessionRunnerRegistry = new RunnerRegistry();
|
|
104
144
|
registerDefaultRunners(sessionRunnerRegistry);
|
|
@@ -137,32 +177,62 @@ function scheduleAstGrepWarningScan(filePath, cwd, pi, logContext) {
|
|
|
137
177
|
const existing = astGrepWarnDebounceTimers.get(filePath);
|
|
138
178
|
if (existing)
|
|
139
179
|
clearTimeout(existing);
|
|
140
|
-
const timer = setTimeout(
|
|
180
|
+
const timer = setTimeout(() => {
|
|
141
181
|
astGrepWarnDebounceTimers.delete(filePath);
|
|
142
|
-
|
|
143
|
-
const ctx = createDispatchContext(filePath, cwd, pi, sessionFacts, false);
|
|
144
|
-
if (ctx.kind !== "jsts")
|
|
145
|
-
return;
|
|
146
|
-
// Single-runner group: ast-grep only, warning mode (blockingOnly=false)
|
|
147
|
-
const group = {
|
|
148
|
-
mode: "all",
|
|
149
|
-
runnerIds: ["ast-grep"],
|
|
150
|
-
filterKinds: ["jsts"],
|
|
151
|
-
};
|
|
152
|
-
const result = await dispatchForFile(ctx, [group], sessionRunnerRegistry);
|
|
153
|
-
if (result.diagnostics.length === 0)
|
|
154
|
-
return;
|
|
155
|
-
const logger = getDiagnosticLogger();
|
|
156
|
-
for (const d of result.diagnostics) {
|
|
157
|
-
logger.logCaught(d, logContext, false);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
catch {
|
|
182
|
+
void runAstGrepWarningScan(filePath, cwd, pi, logContext).catch(() => {
|
|
161
183
|
// Non-critical background scan — swallow errors silently
|
|
162
|
-
}
|
|
184
|
+
});
|
|
163
185
|
}, AST_GREP_WARN_DEBOUNCE_MS);
|
|
164
186
|
astGrepWarnDebounceTimers.set(filePath, timer);
|
|
165
187
|
}
|
|
188
|
+
/**
|
|
189
|
+
* Run the debounced ast-grep warning scan for one jsts file.
|
|
190
|
+
*
|
|
191
|
+
* #2243 item 1: this is a dispatch entry point like dispatchLint*, so it must
|
|
192
|
+
* follow the same discipline. It fires ~2 s after the last write, and in that
|
|
193
|
+
* window the review-graph project walk (`buildOrUpdateGraph`) seeds facts for
|
|
194
|
+
* every file into the SAME `sessionFacts`, which can evict this file's
|
|
195
|
+
* `file.content`. `dispatcher.ts` reads that fact back with `?? ""` for inline
|
|
196
|
+
* suppressions, so a stale or evicted read silently stops applying
|
|
197
|
+
* `pi-lens-ignore`. Two guards, matching the other dispatch callers:
|
|
198
|
+
* 1. `beginDispatchFor` pins the file for the dispatch (released in the
|
|
199
|
+
* finally), so a concurrent walk cannot evict it mid-dispatch. This
|
|
200
|
+
* does NOT clear the file's existing facts the way `clearFileFactsFor`
|
|
201
|
+
* does for the other dispatch callers (#2243 review round 3, F5): this
|
|
202
|
+
* scan fires ~2s after the SAME edit's inline dispatch already
|
|
203
|
+
* re-derived every fact for this file, so a second clear+re-derive
|
|
204
|
+
* here bought nothing but ~51ms of redundant re-parsing across all
|
|
205
|
+
* five providers (measured; a warm-cache read is ~1ms).
|
|
206
|
+
* 2. `runProviders` still re-derives `file.content` when it's actually
|
|
207
|
+
* missing (a genuine miss — evicted, or never computed), so the read
|
|
208
|
+
* never depends on staleness.
|
|
209
|
+
* `facts` is injected only for tests; production always uses `sessionFacts`.
|
|
210
|
+
*/
|
|
211
|
+
export async function runAstGrepWarningScan(filePath, cwd, pi, logContext, facts = sessionFacts) {
|
|
212
|
+
const ctx = createDispatchContext(filePath, cwd, pi, facts, false);
|
|
213
|
+
if (ctx.kind !== "jsts")
|
|
214
|
+
return;
|
|
215
|
+
facts.beginDispatchFor(ctx.filePath);
|
|
216
|
+
try {
|
|
217
|
+
// Single-runner group: ast-grep only, warning mode (blockingOnly=false)
|
|
218
|
+
const group = {
|
|
219
|
+
mode: "all",
|
|
220
|
+
runnerIds: ["ast-grep"],
|
|
221
|
+
filterKinds: ["jsts"],
|
|
222
|
+
};
|
|
223
|
+
await runProviders(ctx);
|
|
224
|
+
const result = await dispatchForFile(ctx, [group], sessionRunnerRegistry);
|
|
225
|
+
if (result.diagnostics.length === 0)
|
|
226
|
+
return;
|
|
227
|
+
const logger = getDiagnosticLogger();
|
|
228
|
+
for (const d of result.diagnostics) {
|
|
229
|
+
logger.logCaught(d, logContext, false);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
finally {
|
|
233
|
+
facts.endDispatchFor(ctx.filePath);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
166
236
|
function resetSessionSlopScore() {
|
|
167
237
|
sessionSlopRuleCounts.clear();
|
|
168
238
|
sessionSlopDiagnosticCount = 0;
|
|
@@ -496,6 +566,11 @@ function touchReverseDepsEntry(key, entry, armIdleTimer = true) {
|
|
|
496
566
|
entry.idleTimer.unref?.();
|
|
497
567
|
}
|
|
498
568
|
function setReverseDepsEntry(key, entry, armIdleTimer = true) {
|
|
569
|
+
const previous = reverseDepsIndexCache.get(key);
|
|
570
|
+
if (previous?.idleTimer !== undefined) {
|
|
571
|
+
clearTimeout(previous.idleTimer);
|
|
572
|
+
previous.idleTimer = undefined;
|
|
573
|
+
}
|
|
499
574
|
const resident = { ...entry, lastUsedAt: Date.now() };
|
|
500
575
|
reverseDepsIndexCache.set(key, resident);
|
|
501
576
|
touchReverseDepsEntry(key, resident, armIdleTimer);
|
|
@@ -604,20 +679,28 @@ function isIgnoredCascadeNeighbor(filePath, cwd) {
|
|
|
604
679
|
* debounced persist (never a synchronous write per edit — same #260
|
|
605
680
|
* discipline as the graph).
|
|
606
681
|
*
|
|
607
|
-
* Race safety against a build-in-progress:
|
|
608
|
-
*
|
|
609
|
-
*
|
|
610
|
-
*
|
|
611
|
-
*
|
|
612
|
-
*
|
|
613
|
-
*
|
|
614
|
-
*
|
|
615
|
-
* and
|
|
616
|
-
*
|
|
617
|
-
*
|
|
618
|
-
*
|
|
682
|
+
* Race safety against a build-in-progress: the update runs cooperatively, on
|
|
683
|
+
* an 8 ms budget, through the word index's own per-index operation queue
|
|
684
|
+
* (#2067 AC4). It used to run synchronously here, on the reasoning that two
|
|
685
|
+
* overlapping cascades (#450's unawaited concurrency) could not interleave
|
|
686
|
+
* mid-mutation if nothing ever yielded — the reviewer's 300-document probe had
|
|
687
|
+
* lost 1,719 postings during an 8 ms yield. That hazard is what the queue
|
|
688
|
+
* closed: every async operation on one index is chained behind the previous
|
|
689
|
+
* one in call order, so overlapping cascades are ordered rather than
|
|
690
|
+
* interleaved, and the cooperative arena compactor is separately proof against
|
|
691
|
+
* a synchronous edit landing mid-copy (#2117 review F2). What the synchronous
|
|
692
|
+
* variant could not fix is its own cost: one replacement on a 2,600-document
|
|
693
|
+
* corpus held the event loop for the whole replacement, which is the block
|
|
694
|
+
* #2067 measured at 1.1 s before interning and still tens of ms after it.
|
|
695
|
+
*
|
|
696
|
+
* The only cross-build hazard is a full session-start rebuild REPLACING
|
|
697
|
+
* `runtime.wordIndex` with a new object between the caller reading
|
|
698
|
+
* `runtime.wordIndex` (in runtime-tool-result.ts, synchronous) and this
|
|
699
|
+
* function receiving it — in that case this call simply mutates whichever
|
|
700
|
+
* index object it was handed (old or new), and the other one is
|
|
701
|
+
* abandoned/superseded, never corrupted.
|
|
619
702
|
*/
|
|
620
|
-
function updateWordIndexForCascade(args) {
|
|
703
|
+
async function updateWordIndexForCascade(args) {
|
|
621
704
|
const { wordIndex, filePath, content, onUpdated, dbg } = args;
|
|
622
705
|
if (!wordIndex || !wordIndex.forward)
|
|
623
706
|
return;
|
|
@@ -625,11 +708,14 @@ function updateWordIndexForCascade(args) {
|
|
|
625
708
|
return;
|
|
626
709
|
const byteLength = Buffer.byteLength(content, "utf-8");
|
|
627
710
|
if (byteLength > WORD_INDEX_MAX_BYTES) {
|
|
628
|
-
|
|
711
|
+
await removeWordIndexDocumentAsync(wordIndex, filePath);
|
|
629
712
|
dbg?.(`word-index per-edit: dropped ${filePath} (over size cap)`);
|
|
630
713
|
}
|
|
631
714
|
else {
|
|
632
|
-
|
|
715
|
+
await updateWordIndexDocumentForEdit(wordIndex, {
|
|
716
|
+
path: filePath,
|
|
717
|
+
content,
|
|
718
|
+
});
|
|
633
719
|
dbg?.(`word-index per-edit: updated ${filePath}`);
|
|
634
720
|
}
|
|
635
721
|
onUpdated?.(wordIndex);
|
|
@@ -689,7 +775,7 @@ export async function computeCascadeForFile(filePath, cwd, options = {}) {
|
|
|
689
775
|
// The old hazard — this update silently orphaning a SECOND entry next to the
|
|
690
776
|
// walker's original-cased one — is now structurally impossible at the map
|
|
691
777
|
// layer, so this seam no longer has to hand-match the build path's key shape.
|
|
692
|
-
updateWordIndexForCascade({
|
|
778
|
+
await updateWordIndexForCascade({
|
|
693
779
|
wordIndex,
|
|
694
780
|
filePath: nodePath.resolve(filePath),
|
|
695
781
|
content: fileContent,
|
|
@@ -1982,16 +2068,23 @@ export async function dispatchLint(filePath, cwd, pi, modifiedRanges, projectRoo
|
|
|
1982
2068
|
// pre-existing issues after the first write.
|
|
1983
2069
|
const ctx = createDispatchContext(filePath, cwd, pi, sessionFacts, true, modifiedRanges, projectRoot);
|
|
1984
2070
|
sessionFacts.clearFileFactsFor(ctx.filePath);
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
2071
|
+
// #2243 item 2: release the pin when the dispatch settles, so the pin set
|
|
2072
|
+
// tracks in-flight dispatches rather than the last N files touched.
|
|
2073
|
+
try {
|
|
2074
|
+
const kind = ctx.kind;
|
|
2075
|
+
if (!kind)
|
|
2076
|
+
return "";
|
|
2077
|
+
const groups = withSpotbugsGroup(kind, getDispatchGroupsForKind(kind, pi), ctx);
|
|
2078
|
+
if (groups.length === 0)
|
|
2079
|
+
return "";
|
|
2080
|
+
await runProviders(ctx);
|
|
2081
|
+
const result = await dispatchForFile(ctx, groups, sessionRunnerRegistry);
|
|
2082
|
+
trackSessionSlopStats(ctx, result.diagnostics);
|
|
2083
|
+
return result.output;
|
|
2084
|
+
}
|
|
2085
|
+
finally {
|
|
2086
|
+
sessionFacts.endDispatchFor(ctx.filePath);
|
|
2087
|
+
}
|
|
1995
2088
|
}
|
|
1996
2089
|
/**
|
|
1997
2090
|
* Run linting and return full result (including diagnostics)
|
|
@@ -2002,44 +2095,50 @@ export async function dispatchLintWithResult(filePath, cwd, pi, modifiedRanges,
|
|
|
2002
2095
|
// facade, pass blockingOnly=false to run every runner.
|
|
2003
2096
|
const ctx = createDispatchContext(filePath, cwd, pi, sessionFacts, options?.blockingOnly ?? true, modifiedRanges, options?.projectRoot, options?.writeIndex, options?.telemetryModel, options?.telemetryProvider);
|
|
2004
2097
|
sessionFacts.clearFileFactsFor(ctx.filePath);
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2098
|
+
// #2243 item 2: release the pin when the dispatch settles.
|
|
2099
|
+
try {
|
|
2100
|
+
const kind = ctx.kind;
|
|
2101
|
+
if (!kind) {
|
|
2102
|
+
return {
|
|
2103
|
+
diagnostics: [],
|
|
2104
|
+
blockers: [],
|
|
2105
|
+
warnings: [],
|
|
2106
|
+
baselineWarningCount: 0,
|
|
2107
|
+
fixed: [],
|
|
2108
|
+
resolvedCount: 0,
|
|
2109
|
+
output: "",
|
|
2110
|
+
blockerOutput: "",
|
|
2111
|
+
hasBlockers: false,
|
|
2112
|
+
};
|
|
2113
|
+
}
|
|
2114
|
+
const groups = withSpotbugsGroup(kind, getDispatchGroupsForKind(kind, pi), ctx);
|
|
2115
|
+
if (groups.length === 0) {
|
|
2116
|
+
return {
|
|
2117
|
+
diagnostics: [],
|
|
2118
|
+
blockers: [],
|
|
2119
|
+
warnings: [],
|
|
2120
|
+
baselineWarningCount: 0,
|
|
2121
|
+
fixed: [],
|
|
2122
|
+
resolvedCount: 0,
|
|
2123
|
+
output: "",
|
|
2124
|
+
blockerOutput: "",
|
|
2125
|
+
hasBlockers: false,
|
|
2126
|
+
};
|
|
2127
|
+
}
|
|
2128
|
+
await runProviders(ctx);
|
|
2129
|
+
const result = await dispatchForFile(ctx, groups, sessionRunnerRegistry);
|
|
2130
|
+
trackSessionSlopStats(ctx, result.diagnostics);
|
|
2131
|
+
// Schedule debounced ast-grep warning scan for jsts files.
|
|
2132
|
+
// Runs 2s after the last write — collapses rapid sequential edits into one scan.
|
|
2133
|
+
// Results are logged only, never surfaced to the agent.
|
|
2134
|
+
if (kind === "jsts" && logContext) {
|
|
2135
|
+
scheduleAstGrepWarningScan(filePath, cwd, pi, logContext);
|
|
2136
|
+
}
|
|
2137
|
+
return result;
|
|
2032
2138
|
}
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
trackSessionSlopStats(ctx, result.diagnostics);
|
|
2036
|
-
// Schedule debounced ast-grep warning scan for jsts files.
|
|
2037
|
-
// Runs 2s after the last write — collapses rapid sequential edits into one scan.
|
|
2038
|
-
// Results are logged only, never surfaced to the agent.
|
|
2039
|
-
if (kind === "jsts" && logContext) {
|
|
2040
|
-
scheduleAstGrepWarningScan(filePath, cwd, pi, logContext);
|
|
2139
|
+
finally {
|
|
2140
|
+
sessionFacts.endDispatchFor(ctx.filePath);
|
|
2041
2141
|
}
|
|
2042
|
-
return result;
|
|
2043
2142
|
}
|
|
2044
2143
|
/**
|
|
2045
2144
|
* Same real dispatch path as {@link dispatchLintWithResult} (real context, real
|
|
@@ -2064,20 +2163,26 @@ export async function dispatchLintDetailed(filePath, cwd, pi, options) {
|
|
|
2064
2163
|
};
|
|
2065
2164
|
const ctx = createDispatchContext(filePath, cwd, pi, sessionFacts, options?.blockingOnly ?? false, options?.modifiedRanges, options?.projectRoot);
|
|
2066
2165
|
sessionFacts.clearFileFactsFor(ctx.filePath);
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
runners
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2166
|
+
// #2243 item 2: release the pin when the dispatch settles.
|
|
2167
|
+
try {
|
|
2168
|
+
const kind = ctx.kind;
|
|
2169
|
+
if (!kind)
|
|
2170
|
+
return { result: empty, runners: [] };
|
|
2171
|
+
const groups = withSpotbugsGroup(kind, getDispatchGroupsForKind(kind, pi), ctx);
|
|
2172
|
+
if (groups.length === 0)
|
|
2173
|
+
return { result: empty, runners: [] };
|
|
2174
|
+
const runners = [];
|
|
2175
|
+
const sink = (runnerId, result) => {
|
|
2176
|
+
runners.push({ runnerId, result });
|
|
2177
|
+
};
|
|
2178
|
+
await runProviders(ctx);
|
|
2179
|
+
const result = await dispatchForFile(ctx, groups, sessionRunnerRegistry, sink);
|
|
2180
|
+
trackSessionSlopStats(ctx, result.diagnostics);
|
|
2181
|
+
return { result, runners };
|
|
2182
|
+
}
|
|
2183
|
+
finally {
|
|
2184
|
+
sessionFacts.endDispatchFor(ctx.filePath);
|
|
2185
|
+
}
|
|
2081
2186
|
}
|
|
2082
2187
|
/**
|
|
2083
2188
|
* Check if a file should be processed by the dispatcher
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/** Turn-end handoff for runners moved off the post-write critical path. */
|
|
2
|
+
import { incrementDegradationCount } from "../degradation-ledger.js";
|
|
3
|
+
const pending = [];
|
|
4
|
+
export const MAX_PENDING_RUNNER_FINDINGS = 50;
|
|
5
|
+
export function deferRunnerFindings(entry) {
|
|
6
|
+
const tracked = { ...entry, settled: false };
|
|
7
|
+
// Attach exactly once at ownership time. Re-attaching at every turn end
|
|
8
|
+
// accumulates handlers on a promise that may never settle (#2122 F8).
|
|
9
|
+
void tracked.promise.then((result) => {
|
|
10
|
+
tracked.result = result;
|
|
11
|
+
tracked.settled = true;
|
|
12
|
+
}, (error) => {
|
|
13
|
+
tracked.result = {
|
|
14
|
+
status: "failed",
|
|
15
|
+
diagnostics: [],
|
|
16
|
+
semantic: "warning",
|
|
17
|
+
failureKind: "exception",
|
|
18
|
+
failureMessage: String(error).slice(0, 200),
|
|
19
|
+
};
|
|
20
|
+
tracked.settled = true;
|
|
21
|
+
});
|
|
22
|
+
pending.push(tracked);
|
|
23
|
+
if (pending.length > MAX_PENDING_RUNNER_FINDINGS) {
|
|
24
|
+
const evicted = pending.shift();
|
|
25
|
+
if (evicted) {
|
|
26
|
+
incrementDegradationCount({
|
|
27
|
+
kind: "runner-findings-evicted",
|
|
28
|
+
subject: `${evicted.runnerId}:${evicted.filePath}`,
|
|
29
|
+
reason: `pending runner cap ${MAX_PENDING_RUNNER_FINDINGS}`,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Resolve already-finished runner work for this turn. Unfinished work remains
|
|
36
|
+
* owned by the store and is retried at the next turn boundary.
|
|
37
|
+
*/
|
|
38
|
+
export async function drainPendingRunnerFindings(maxWaitMs = 2_000) {
|
|
39
|
+
if (pending.length === 0)
|
|
40
|
+
return [];
|
|
41
|
+
const current = pending.splice(0, pending.length);
|
|
42
|
+
const results = [];
|
|
43
|
+
// Give already-resolved promises one microtask turn without introducing a
|
|
44
|
+
// wall-clock wait. This observes completed work while preserving the F5
|
|
45
|
+
// zero-budget contract for in-flight runners.
|
|
46
|
+
if (maxWaitMs === 0)
|
|
47
|
+
await Promise.resolve();
|
|
48
|
+
if (maxWaitMs > 0 && current.some((entry) => !entry.settled)) {
|
|
49
|
+
await new Promise((resolve) => {
|
|
50
|
+
const timer = setTimeout(resolve, maxWaitMs);
|
|
51
|
+
timer.unref?.();
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
for (const entry of current) {
|
|
55
|
+
if (entry.settled && entry.result) {
|
|
56
|
+
results.push({
|
|
57
|
+
filePath: entry.filePath,
|
|
58
|
+
cwd: entry.cwd,
|
|
59
|
+
projectRoot: entry.projectRoot,
|
|
60
|
+
runnerId: entry.runnerId,
|
|
61
|
+
markedAtMs: entry.markedAtMs,
|
|
62
|
+
writeIndex: entry.writeIndex,
|
|
63
|
+
result: entry.result,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
pending.push(entry);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return results;
|
|
71
|
+
}
|
|
72
|
+
/** Drop a stale answer and record the lost re-run coverage. */
|
|
73
|
+
export function dropStaleRunnerFindings(entry) {
|
|
74
|
+
if (!entry.result)
|
|
75
|
+
return;
|
|
76
|
+
incrementDegradationCount({
|
|
77
|
+
kind: "runner-findings-stale",
|
|
78
|
+
subject: `${entry.runnerId}:${entry.filePath}`,
|
|
79
|
+
reason: "completed result was older than the latest file edit",
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
export function resetPendingRunnerFindings() {
|
|
83
|
+
pending.length = 0;
|
|
84
|
+
}
|
|
85
|
+
export function pendingRunnerFindingsSize() {
|
|
86
|
+
return pending.length;
|
|
87
|
+
}
|
|
@@ -95,7 +95,10 @@ export const LANGUAGE_CAPABILITY_MATRIX = {
|
|
|
95
95
|
json: {
|
|
96
96
|
name: "JSON Processing",
|
|
97
97
|
capabilities: ["format", "lint"],
|
|
98
|
-
writeGroups: [
|
|
98
|
+
writeGroups: [
|
|
99
|
+
primary("json"),
|
|
100
|
+
{ mode: "all", runnerIds: ["trivy-config"], filterKinds: ["json"] },
|
|
101
|
+
],
|
|
99
102
|
},
|
|
100
103
|
markdown: {
|
|
101
104
|
name: "Markdown Processing",
|
|
@@ -108,7 +111,11 @@ export const LANGUAGE_CAPABILITY_MATRIX = {
|
|
|
108
111
|
css: {
|
|
109
112
|
name: "CSS Processing",
|
|
110
113
|
capabilities: ["format", "lint"],
|
|
111
|
-
writeGroups: [
|
|
114
|
+
writeGroups: [
|
|
115
|
+
primary("css"),
|
|
116
|
+
{ mode: "all", runnerIds: ["tree-sitter"], filterKinds: ["css"] },
|
|
117
|
+
{ mode: "all", runnerIds: ["ast-grep-napi"], filterKinds: ["css"] },
|
|
118
|
+
],
|
|
112
119
|
},
|
|
113
120
|
yaml: {
|
|
114
121
|
name: "YAML Processing",
|
|
@@ -131,7 +138,10 @@ export const LANGUAGE_CAPABILITY_MATRIX = {
|
|
|
131
138
|
html: {
|
|
132
139
|
name: "HTML Linting",
|
|
133
140
|
capabilities: ["lint"],
|
|
134
|
-
writeGroups: [
|
|
141
|
+
writeGroups: [
|
|
142
|
+
primary("html"),
|
|
143
|
+
{ mode: "all", runnerIds: ["ast-grep-napi"], filterKinds: ["html"] },
|
|
144
|
+
],
|
|
135
145
|
},
|
|
136
146
|
docker: {
|
|
137
147
|
name: "Dockerfile Linting",
|
|
@@ -141,7 +151,10 @@ export const LANGUAGE_CAPABILITY_MATRIX = {
|
|
|
141
151
|
php: {
|
|
142
152
|
name: "PHP Linting",
|
|
143
153
|
capabilities: ["types", "lint"],
|
|
144
|
-
writeGroups: [
|
|
154
|
+
writeGroups: [
|
|
155
|
+
primary("php"),
|
|
156
|
+
{ mode: "all", runnerIds: ["tree-sitter"], filterKinds: ["php"] },
|
|
157
|
+
],
|
|
145
158
|
},
|
|
146
159
|
powershell: {
|
|
147
160
|
name: "PowerShell Linting",
|
|
@@ -156,7 +169,10 @@ export const LANGUAGE_CAPABILITY_MATRIX = {
|
|
|
156
169
|
csharp: {
|
|
157
170
|
name: "C# Linting",
|
|
158
171
|
capabilities: ["types", "lint"],
|
|
159
|
-
writeGroups: [
|
|
172
|
+
writeGroups: [
|
|
173
|
+
primary("csharp"),
|
|
174
|
+
{ mode: "all", runnerIds: ["tree-sitter"], filterKinds: ["csharp"] },
|
|
175
|
+
],
|
|
160
176
|
},
|
|
161
177
|
fsharp: {
|
|
162
178
|
name: "F# Linting",
|