@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
|
@@ -6,6 +6,7 @@ import { clearGitGuardTestFailure, mergeGitGuardTestFailure, writeGitGuardRecord
|
|
|
6
6
|
import { cascadeSettleWaitMs } from "./cascade-budget.js";
|
|
7
7
|
import { logCascade } from "./cascade-logger.js";
|
|
8
8
|
import { normalizeMapKey } from "./path-utils.js";
|
|
9
|
+
import { compareOrdinal } from "./string-utils.js";
|
|
9
10
|
import { resolveRunnerPath, toRunnerDisplayPath, } from "./dispatch/runner-context.js";
|
|
10
11
|
import { getKnipIgnorePatterns } from "./file-utils.js";
|
|
11
12
|
import { formatCacheAgeLabel } from "./finding-delivery-gate.js";
|
|
@@ -29,19 +30,21 @@ import { RUNTIME_CONFIG } from "./runtime-config.js";
|
|
|
29
30
|
import { isSubagentSession } from "./subagent-mode.js";
|
|
30
31
|
import { formatRunDurationMs } from "./run-duration.js";
|
|
31
32
|
import { MAX_ADVISORY_AFFECTED_FILES, gateFindingsByPathFreshness, snapshotAdvisoryProvenance, } from "./advisory-provenance.js";
|
|
32
|
-
import { sweepInlineBlockerFreshness } from "./blocker-freshness.js";
|
|
33
|
+
import { DEPENDENCY_DRIFT_MAX_DELIVERIES, sweepInlineBlockerFreshness, } from "./blocker-freshness.js";
|
|
33
34
|
import { sweepInlineBlockerPastEof } from "./blocker-past-eof.js";
|
|
34
35
|
// #2001/#2002: collect-later delivery for slow auxiliary LSP servers.
|
|
35
36
|
import { getLSPService } from "./lsp/index.js";
|
|
36
|
-
import { drainPendingAuxiliaryCoverage, isPendingAuxiliaryPastRearmTtl,
|
|
37
|
+
import { drainPendingAuxCapEvictedCount, drainPendingAuxiliaryCoverage, isPendingAuxiliaryPastRearmTtl, rearmPendingAuxiliaryCoverage, MAX_LATE_AUX_REARMS, pendingAuxiliaryCoverageSize, } from "./lsp/pending-aux-coverage.js";
|
|
37
38
|
import { convertLspDiagnostics } from "./dispatch/utils/lsp-diagnostics.js";
|
|
39
|
+
import { drainPendingRunnerFindings, dropStaleRunnerFindings, pendingRunnerFindingsSize, } from "./dispatch/pending-runner-findings.js";
|
|
38
40
|
// #1631 review V2: moved to its own leaf module so a low-level store
|
|
39
41
|
// (widget-state.ts) can use the marker without importing this orchestrator —
|
|
40
42
|
// see clients/stale-marker.ts's doc comment.
|
|
41
43
|
import { incrementDegradationCount } from "./degradation-ledger.js";
|
|
42
|
-
import { degradeDemotedFindingBody, formatRetirementNote, } from "./demoted-finding-render.js";
|
|
44
|
+
import { degradeDemotedFindingBody, formatDeliveryCapNote, formatRetirementNote, } from "./demoted-finding-render.js";
|
|
43
45
|
import { STALE_LINE_MARKER } from "./stale-marker.js";
|
|
44
|
-
import {
|
|
46
|
+
import { getActiveSessionId } from "./session-lifecycle.js";
|
|
47
|
+
import { getWidgetBlockingFilesForSweep, markWidgetFileBlockersStale, recordRunner, } from "./widget-state.js";
|
|
45
48
|
/**
|
|
46
49
|
* #1617: turn_end reads gitleaks/govulncheck/trivy straight from their
|
|
47
50
|
* session-scan caches and formats them into advisory/blocker text — a
|
|
@@ -152,6 +155,9 @@ function scheduleLSPIdleReset(resetFn, delayMs, options = {}) {
|
|
|
152
155
|
if (options.isCurrentSession && !options.isCurrentSession()) {
|
|
153
156
|
return;
|
|
154
157
|
}
|
|
158
|
+
if (options.isPrimarySession && !options.isPrimarySession()) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
155
161
|
resetFn();
|
|
156
162
|
}
|
|
157
163
|
catch (err) {
|
|
@@ -286,6 +292,11 @@ export async function handleTurnEnd(deps) {
|
|
|
286
292
|
// instead of dying unrendered. `hasCascadeRuns()` is a cheap peek (no
|
|
287
293
|
// pending work almost every turn), so the common read-only turn still
|
|
288
294
|
// takes the early return below.
|
|
295
|
+
// A foreign live owner must not deliver another session's pending findings.
|
|
296
|
+
// A no-file turn falls through when this process has pending runner work so
|
|
297
|
+
// the ordinary freshness gate and delivery cache can run. Max-cycle cleanup
|
|
298
|
+
// below intentionally remains a terminal reset; its pending work stays in
|
|
299
|
+
// the bounded handoff store for the next eligible turn.
|
|
289
300
|
if (files.length === 0 && !runtime.hasCascadeRuns()) {
|
|
290
301
|
// A genuinely clean session must invalidate the persisted guard record.
|
|
291
302
|
// Blocker records are retained only while the runtime still reports one.
|
|
@@ -310,11 +321,20 @@ export async function handleTurnEnd(deps) {
|
|
|
310
321
|
const sessionGeneration = runtime.sessionGeneration;
|
|
311
322
|
scheduleLSPIdleReset(resetLSPService, idleResetMs, {
|
|
312
323
|
isCurrentSession: () => runtime.isCurrentSession(sessionGeneration),
|
|
324
|
+
// #2157 fix round 2: a secondary (subagent) evaluation's own timer
|
|
325
|
+
// must not release the primary's shared fleet — see the option's
|
|
326
|
+
// doc comment on `scheduleLSPIdleReset`.
|
|
327
|
+
isPrimarySession: () => {
|
|
328
|
+
const activePrimarySessionId = getActiveSessionId();
|
|
329
|
+
return (activePrimarySessionId === undefined ||
|
|
330
|
+
activePrimarySessionId === runtime.telemetrySessionId);
|
|
331
|
+
},
|
|
313
332
|
onError: (err) => dbg(`lsp idle reset failed: ${err}`),
|
|
314
333
|
});
|
|
315
334
|
}
|
|
316
335
|
resetFormatService();
|
|
317
|
-
|
|
336
|
+
if (pendingRunnerFindingsSize() === 0)
|
|
337
|
+
return;
|
|
318
338
|
}
|
|
319
339
|
// Cancel any pending idle reset since we're actively working. #1618: also
|
|
320
340
|
// checks `pendingSweepRearm` — a timer deferred behind an in-flight
|
|
@@ -323,7 +343,7 @@ export async function handleTurnEnd(deps) {
|
|
|
323
343
|
// read "nothing pending" and skip the cancel while a rearm was still
|
|
324
344
|
// queued to fire the instant the sweep released its hold — resurrecting
|
|
325
345
|
// idle reset on a session that had since gone back to active editing.
|
|
326
|
-
if (lspIdleResetTimeout || pendingSweepRearm) {
|
|
346
|
+
if (files.length > 0 && (lspIdleResetTimeout || pendingSweepRearm)) {
|
|
327
347
|
cancelLSPIdleReset();
|
|
328
348
|
dbg("turn_end: cancelled pending LSP idle reset (active editing)");
|
|
329
349
|
}
|
|
@@ -404,9 +424,20 @@ export async function handleTurnEnd(deps) {
|
|
|
404
424
|
// Re-surface inline blockers from this turn that the agent didn't fix.
|
|
405
425
|
// These were shown inline during write/edit but the agent moved on without resolving them.
|
|
406
426
|
const unresolvedBlockers = runtime.getInlineBlockersSnapshot();
|
|
407
|
-
/** #1944:
|
|
427
|
+
/** #1944/#1950: demotions retired after their delivery limit. */
|
|
408
428
|
let demotedFindingsRetired = 0;
|
|
409
|
-
|
|
429
|
+
/**
|
|
430
|
+
* #1950 fix-round F1: dependency-drift delivery-count commits, deferred
|
|
431
|
+
* until this turn's content is confirmed NOT suppressed by the
|
|
432
|
+
* `turn-end-findings-last` signature dedupe further down. That dedupe
|
|
433
|
+
* silences a turn whose rendered content is byte-identical to the last
|
|
434
|
+
* one actually delivered — the agent never sees a suppressed turn, so
|
|
435
|
+
* committing the counter for it would count a delivery that didn't
|
|
436
|
+
* happen. Each entry here is invoked only from the "not suppressed"
|
|
437
|
+
* branch below.
|
|
438
|
+
*/
|
|
439
|
+
const pendingDependencyDriftDeliveries = [];
|
|
440
|
+
for (const { filePath: bPath, summary, stale, staleReason, } of unresolvedBlockers) {
|
|
410
441
|
const displayPath = toRunnerDisplayPath(cwd, bPath);
|
|
411
442
|
if (stale) {
|
|
412
443
|
// #1631: demoted — out of the authoritative blocker channel and into the
|
|
@@ -423,6 +454,7 @@ export async function handleTurnEnd(deps) {
|
|
|
423
454
|
const deadLines = blockerPastEof.deadLinesByPath.get(bPath) ?? [];
|
|
424
455
|
const degraded = degradeDemotedFindingBody(summary, { deadLines });
|
|
425
456
|
const retired = runtime.retireDemotedPastEofBlocker(bPath, deadLines);
|
|
457
|
+
let retirementNote;
|
|
426
458
|
if (retired) {
|
|
427
459
|
demotedFindingsRetired += 1;
|
|
428
460
|
// Bounded by the ledger's own per-kind/subject tally, and the subject
|
|
@@ -432,10 +464,43 @@ export async function handleTurnEnd(deps) {
|
|
|
432
464
|
subject: `inline-blocker:${displayPath}`,
|
|
433
465
|
reason: `file shrank past cited line(s) ${deadLines.join(", ")}; retired after one degraded delivery`,
|
|
434
466
|
});
|
|
467
|
+
retirementNote = formatRetirementNote(deadLines);
|
|
468
|
+
}
|
|
469
|
+
else if (staleReason === "dependency-drift") {
|
|
470
|
+
// #1950: a dependency-drift demotion is recoverable (its coordinates
|
|
471
|
+
// are still in bounds), so it does NOT retire after one delivery like
|
|
472
|
+
// the past-EOF case above — but nothing capped how many times the
|
|
473
|
+
// SAME demoted-but-unconfirmed record re-serves, and incident data
|
|
474
|
+
// showed repeat deliveries carrying near-zero information after the
|
|
475
|
+
// first. Cap it at DEPENDENCY_DRIFT_MAX_DELIVERIES instead.
|
|
476
|
+
//
|
|
477
|
+
// The count driving THIS render is a peek (fix-round F1): the actual
|
|
478
|
+
// increment is deferred to `pendingDependencyDriftDeliveries` below,
|
|
479
|
+
// committed only once this turn's content is known to reach the
|
|
480
|
+
// agent, so a suppressed turn's tentative render never advances the
|
|
481
|
+
// stored count.
|
|
482
|
+
const tentativeCount = runtime.peekInlineBlockerStaleDeliveryCount(bPath) + 1;
|
|
483
|
+
if (tentativeCount >= DEPENDENCY_DRIFT_MAX_DELIVERIES) {
|
|
484
|
+
retirementNote = formatDeliveryCapNote(tentativeCount);
|
|
485
|
+
}
|
|
486
|
+
pendingDependencyDriftDeliveries.push(() => {
|
|
487
|
+
const deliveryCount = runtime.incrementInlineBlockerStaleDelivery(bPath);
|
|
488
|
+
if (deliveryCount >= DEPENDENCY_DRIFT_MAX_DELIVERIES) {
|
|
489
|
+
const capRetired = runtime.retireDemotedDependencyDriftBlocker(bPath);
|
|
490
|
+
if (capRetired) {
|
|
491
|
+
demotedFindingsRetired += 1;
|
|
492
|
+
incrementDegradationCount({
|
|
493
|
+
kind: "demoted-finding-retired",
|
|
494
|
+
subject: `inline-blocker:${displayPath}`,
|
|
495
|
+
reason: `capped after ${deliveryCount} deliveries with no re-run; re-run can still confirm`,
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
});
|
|
435
500
|
}
|
|
436
501
|
// @delivery-surface: runtime-turn:unresolved-inline-blocker
|
|
437
502
|
advisoryParts.push(`${STALE_LINE_MARKER} ${displayPath}:\n${degraded.body}` +
|
|
438
|
-
(
|
|
503
|
+
(retirementNote ? `\n${retirementNote}` : ""));
|
|
439
504
|
}
|
|
440
505
|
else {
|
|
441
506
|
// @delivery-surface: runtime-turn:unresolved-inline-blocker
|
|
@@ -1427,7 +1492,7 @@ export async function handleTurnEnd(deps) {
|
|
|
1427
1492
|
}
|
|
1428
1493
|
}
|
|
1429
1494
|
for (const { display, abs, isNeighbor } of candidates) {
|
|
1430
|
-
const target = testRunnerClient.getTestRunTarget(abs, cwd);
|
|
1495
|
+
const target = testRunnerClient.getTestRunTarget(abs, cwd, runtime.turnIndex);
|
|
1431
1496
|
if (target && !seen.has(target.testFile)) {
|
|
1432
1497
|
seen.add(target.testFile);
|
|
1433
1498
|
targets.push(target);
|
|
@@ -1460,7 +1525,11 @@ export async function handleTurnEnd(deps) {
|
|
|
1460
1525
|
files: provenanceFiles,
|
|
1461
1526
|
});
|
|
1462
1527
|
cacheManager.writeCache("test-runner-findings", { ...(priorTestCache ?? { content: "" }), testRunGeneration }, cwd);
|
|
1463
|
-
Promise.allSettled(targets.map((t) => testRunnerClient.runTestFileAsync(t.testFile, cwd,
|
|
1528
|
+
Promise.allSettled(targets.map((t) => testRunnerClient.runTestFileAsync(t.testFile, cwd, {
|
|
1529
|
+
runner: t.runner,
|
|
1530
|
+
config: t.config,
|
|
1531
|
+
turnIndex: firedAtTurn,
|
|
1532
|
+
})))
|
|
1464
1533
|
.then((results) => {
|
|
1465
1534
|
const publishedAgainst = snapshotAdvisoryProvenance({
|
|
1466
1535
|
cwd,
|
|
@@ -1809,6 +1878,78 @@ export async function handleTurnEnd(deps) {
|
|
|
1809
1878
|
});
|
|
1810
1879
|
}
|
|
1811
1880
|
cacheManager.incrementTurnCycle(cwd, currentOwner);
|
|
1881
|
+
// Collect-later CLI runners continue off the write path. Their completed
|
|
1882
|
+
// diagnostics use the same freshness gate as late auxiliary findings and
|
|
1883
|
+
// enter the ordinary turn-end advisory delivery channel.
|
|
1884
|
+
const runnerFindingsStart = Date.now();
|
|
1885
|
+
// Turn-end delivery is deliberately non-blocking. Collect already-settled
|
|
1886
|
+
// results and requeue the rest; the edit path already paid the deferral
|
|
1887
|
+
// decision, so another 2s wait would charge every turn while a runner is
|
|
1888
|
+
// still in flight (#2122 F5).
|
|
1889
|
+
const pendingRunnerFindings = await drainPendingRunnerFindings(0);
|
|
1890
|
+
let runnerFindingsDelivered = 0;
|
|
1891
|
+
let runnerFindingsStale = 0;
|
|
1892
|
+
let runnerFindingsFailed = 0;
|
|
1893
|
+
let runnerFindingsDropped = 0;
|
|
1894
|
+
const runnerFindingsDeliveredIds = [];
|
|
1895
|
+
for (const pending of pendingRunnerFindings) {
|
|
1896
|
+
const result = pending.result;
|
|
1897
|
+
if (!result)
|
|
1898
|
+
continue;
|
|
1899
|
+
recordRunner(pending.filePath, pending.runnerId, result.status, result.diagnostics.length, Date.now() - pending.markedAtMs, pending.writeIndex);
|
|
1900
|
+
if (result.status === "failed") {
|
|
1901
|
+
runnerFindingsFailed += 1;
|
|
1902
|
+
const detail = result.failureMessage ? `: ${result.failureMessage}` : "";
|
|
1903
|
+
// @delivery-surface: runtime-turn:late-runner-findings
|
|
1904
|
+
advisoryParts.push(`❌ Deferred runner ${pending.runnerId} failed (${result.failureKind ?? "unknown"})${detail}`);
|
|
1905
|
+
continue;
|
|
1906
|
+
}
|
|
1907
|
+
const findings = result.diagnostics;
|
|
1908
|
+
if (findings.length === 0)
|
|
1909
|
+
continue;
|
|
1910
|
+
const gate = gateFindingsByPathFreshness({
|
|
1911
|
+
store: "late-runner-findings",
|
|
1912
|
+
findings,
|
|
1913
|
+
cwd,
|
|
1914
|
+
scannedAt: pending.markedAtMs,
|
|
1915
|
+
citedPath: (finding) => finding.filePath,
|
|
1916
|
+
});
|
|
1917
|
+
runnerFindingsStale += gate.stale.length;
|
|
1918
|
+
if (gate.stale.length > 0) {
|
|
1919
|
+
// The runner answered for bytes older than the latest edit. Do not
|
|
1920
|
+
// re-arm this completed answer: only a new runner query can restore
|
|
1921
|
+
// coverage for the refreshed bytes.
|
|
1922
|
+
dropStaleRunnerFindings(pending);
|
|
1923
|
+
runnerFindingsDropped += 1;
|
|
1924
|
+
}
|
|
1925
|
+
if (gate.live.length === 0)
|
|
1926
|
+
continue;
|
|
1927
|
+
const displayPath = toRunnerDisplayPath(cwd, pending.filePath);
|
|
1928
|
+
const lines = gate.live.map((finding) => ` ${displayPath}:${finding.line ?? 1}:${finding.column ?? 1} [${finding.rule ?? finding.id}] ${finding.message}`);
|
|
1929
|
+
runnerFindingsDelivered += gate.live.length;
|
|
1930
|
+
for (const finding of gate.live) {
|
|
1931
|
+
if (runnerFindingsDeliveredIds.length < 50) {
|
|
1932
|
+
runnerFindingsDeliveredIds.push(finding.id);
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
// @delivery-surface: runtime-turn:late-runner-findings
|
|
1936
|
+
advisoryParts.push(`⏱️ Late runner diagnostics (${pending.runnerId} completed after the edit):\n${lines.join("\n")}`);
|
|
1937
|
+
}
|
|
1938
|
+
logLatency({
|
|
1939
|
+
type: "phase",
|
|
1940
|
+
toolName: "turn_end",
|
|
1941
|
+
filePath: cwd,
|
|
1942
|
+
phase: "late_runner_findings",
|
|
1943
|
+
durationMs: Date.now() - runnerFindingsStart,
|
|
1944
|
+
metadata: {
|
|
1945
|
+
pending: pendingRunnerFindings.length,
|
|
1946
|
+
delivered: runnerFindingsDelivered,
|
|
1947
|
+
stale: runnerFindingsStale,
|
|
1948
|
+
failed: runnerFindingsFailed,
|
|
1949
|
+
dropped: runnerFindingsDropped,
|
|
1950
|
+
deliveredIds: runnerFindingsDeliveredIds,
|
|
1951
|
+
},
|
|
1952
|
+
});
|
|
1812
1953
|
// #2001/#2002: collect-later delivery for auxiliary LSP servers whose
|
|
1813
1954
|
// aux-grace window expired without a publication (opengrep on Windows:
|
|
1814
1955
|
// ~8s per scan against a 2s grace — the scanner's eventual findings sat
|
|
@@ -1820,12 +1961,21 @@ export async function handleTurnEnd(deps) {
|
|
|
1820
1961
|
// client drops silently.
|
|
1821
1962
|
const lateAuxStart = Date.now();
|
|
1822
1963
|
const drainedPairs = drainPendingAuxiliaryCoverage();
|
|
1964
|
+
// #2168: cap evictions retire a pair before any drain can observe it — read
|
|
1965
|
+
// and reset that count here so it folds into this turn's reconciliation
|
|
1966
|
+
// sum instead of the pair vanishing uncounted.
|
|
1967
|
+
const lateAuxCapEvicted = drainPendingAuxCapEvictedCount();
|
|
1823
1968
|
let lateAuxDelivered = 0;
|
|
1824
1969
|
let lateAuxStale = 0;
|
|
1825
1970
|
let lateAuxMissing = 0;
|
|
1826
1971
|
let lateAuxRearmed = 0;
|
|
1827
1972
|
let lateAuxClientGone = 0;
|
|
1828
1973
|
let lateAuxProbeFailed = 0;
|
|
1974
|
+
let lateAuxCleanConfirmed = 0;
|
|
1975
|
+
let lateAuxExpired = 0;
|
|
1976
|
+
let lateAuxCeilingExhausted = 0;
|
|
1977
|
+
let lateAuxAnswered = 0;
|
|
1978
|
+
const lateAuxStuckPairs = [];
|
|
1829
1979
|
if (drainedPairs.length > 0) {
|
|
1830
1980
|
const byFile = new Map();
|
|
1831
1981
|
for (const pair of drainedPairs) {
|
|
@@ -1843,23 +1993,42 @@ export async function handleTurnEnd(deps) {
|
|
|
1843
1993
|
cached = await service.readCachedDiagnosticsForServers(lateAuxPath, new Set(pairs.map((p) => p.serverId)));
|
|
1844
1994
|
}
|
|
1845
1995
|
catch {
|
|
1846
|
-
// #2027 round-1 P3-2
|
|
1996
|
+
// #2027 round-1 P3-2 / #2167 R2-2: a transient probe rejection
|
|
1997
|
+
// tells us nothing about the pair's content, so treat it like the
|
|
1998
|
+
// "still scanning" branch below — re-arm under the SAME
|
|
1999
|
+
// ceiling/TTL bound rather than dropping the coverage outright.
|
|
2000
|
+
// `probeFailed` stays an honest per-turn failure count; it is
|
|
2001
|
+
// informational (like `stale`/`missing`), not a terminal bucket,
|
|
2002
|
+
// since the pair itself still resolves through rearmed/
|
|
2003
|
+
// ceilingExhausted/expired below.
|
|
1847
2004
|
lateAuxProbeFailed += pairs.length;
|
|
1848
2005
|
for (const pair of pairs) {
|
|
1849
|
-
|
|
2006
|
+
if (!isPendingAuxiliaryPastRearmTtl(pair) &&
|
|
2007
|
+
(pair.rearmCount ?? 0) < MAX_LATE_AUX_REARMS) {
|
|
2008
|
+
rearmPendingAuxiliaryCoverage(pair);
|
|
2009
|
+
lateAuxRearmed += 1;
|
|
2010
|
+
}
|
|
2011
|
+
else if (isPendingAuxiliaryPastRearmTtl(pair)) {
|
|
2012
|
+
lateAuxExpired += 1;
|
|
2013
|
+
}
|
|
2014
|
+
else {
|
|
2015
|
+
lateAuxCeilingExhausted += 1;
|
|
2016
|
+
}
|
|
1850
2017
|
}
|
|
1851
2018
|
continue;
|
|
1852
2019
|
}
|
|
1853
2020
|
const displayLateAuxPath = toRunnerDisplayPath(cwd, lateAuxPath);
|
|
1854
2021
|
for (const pair of pairs) {
|
|
1855
|
-
const
|
|
1856
|
-
if (
|
|
2022
|
+
const cachedEntry = cached.get(pair.serverId);
|
|
2023
|
+
if (cachedEntry === undefined) {
|
|
1857
2024
|
// No live client for this server any more — best-effort probe,
|
|
1858
2025
|
// drop the pair silently.
|
|
1859
2026
|
lateAuxClientGone += 1;
|
|
1860
2027
|
continue;
|
|
1861
2028
|
}
|
|
1862
|
-
|
|
2029
|
+
const rawDiags = cachedEntry.diags;
|
|
2030
|
+
if (cachedEntry.publishedAt === undefined ||
|
|
2031
|
+
cachedEntry.publishedAt <= pair.markedAtMs) {
|
|
1863
2032
|
// Still scanning (or published nothing yet) — keep waiting
|
|
1864
2033
|
// so a scan finishing before the NEXT turn end still
|
|
1865
2034
|
// delivers. Two clocks, deliberately decoupled: the
|
|
@@ -1867,17 +2036,36 @@ export async function handleTurnEnd(deps) {
|
|
|
1867
2036
|
// the delivery gate stats against — while the re-arm TTL is
|
|
1868
2037
|
// anchored on `lastRearmedAtMs`, advanced by every successful
|
|
1869
2038
|
// empty probe: the scanner is demonstrably alive, just slow.
|
|
1870
|
-
if (!isPendingAuxiliaryPastRearmTtl(pair)
|
|
1871
|
-
|
|
2039
|
+
if (!isPendingAuxiliaryPastRearmTtl(pair) &&
|
|
2040
|
+
(pair.rearmCount ?? 0) < MAX_LATE_AUX_REARMS) {
|
|
2041
|
+
rearmPendingAuxiliaryCoverage(pair);
|
|
1872
2042
|
lateAuxRearmed += 1;
|
|
2043
|
+
if (lateAuxStuckPairs.length < 20)
|
|
2044
|
+
lateAuxStuckPairs.push({
|
|
2045
|
+
filePath: pair.filePath,
|
|
2046
|
+
serverId: pair.serverId,
|
|
2047
|
+
});
|
|
2048
|
+
}
|
|
2049
|
+
else {
|
|
2050
|
+
if (isPendingAuxiliaryPastRearmTtl(pair))
|
|
2051
|
+
lateAuxExpired += 1;
|
|
2052
|
+
else
|
|
2053
|
+
lateAuxCeilingExhausted += 1;
|
|
1873
2054
|
}
|
|
1874
2055
|
continue;
|
|
1875
2056
|
}
|
|
2057
|
+
if (rawDiags.length === 0) {
|
|
2058
|
+
lateAuxCleanConfirmed += 1;
|
|
2059
|
+
continue;
|
|
2060
|
+
}
|
|
1876
2061
|
const converted = convertLspDiagnostics(rawDiags, lateAuxPath, {
|
|
1877
2062
|
tool: "lsp",
|
|
1878
2063
|
});
|
|
1879
|
-
if (converted.length === 0)
|
|
2064
|
+
if (converted.length === 0) {
|
|
2065
|
+
lateAuxMissing += rawDiags.length;
|
|
2066
|
+
lateAuxAnswered += 1;
|
|
1880
2067
|
continue;
|
|
2068
|
+
}
|
|
1881
2069
|
// Freshness kernel (#1634 gated surface): stat the cited file
|
|
1882
2070
|
// against the mark timestamp. Missing → drop (no remediation for
|
|
1883
2071
|
// a deleted file); mtime drifted past the mark → drop too, NOT
|
|
@@ -1897,16 +2085,30 @@ export async function handleTurnEnd(deps) {
|
|
|
1897
2085
|
lateAuxStale += gate.stale.length;
|
|
1898
2086
|
lateAuxMissing +=
|
|
1899
2087
|
converted.length - gate.live.length - gate.stale.length;
|
|
1900
|
-
if (gate.
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
2088
|
+
if (gate.live.length === 0) {
|
|
2089
|
+
if (gate.stale.length > 0) {
|
|
2090
|
+
// Stale findings mean the scan predates the last edit. Re-arm
|
|
2091
|
+
// with a refreshed baseline and carry the ceiling count.
|
|
2092
|
+
if (!isPendingAuxiliaryPastRearmTtl(pair) &&
|
|
2093
|
+
(pair.rearmCount ?? 0) < MAX_LATE_AUX_REARMS) {
|
|
2094
|
+
rearmPendingAuxiliaryCoverage(pair, Date.now(), true);
|
|
2095
|
+
lateAuxRearmed += 1;
|
|
2096
|
+
}
|
|
2097
|
+
else if (isPendingAuxiliaryPastRearmTtl(pair)) {
|
|
2098
|
+
lateAuxExpired += 1;
|
|
2099
|
+
}
|
|
2100
|
+
else {
|
|
2101
|
+
lateAuxCeilingExhausted += 1;
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
else {
|
|
2105
|
+
lateAuxAnswered += 1;
|
|
2106
|
+
}
|
|
1907
2107
|
continue;
|
|
2108
|
+
}
|
|
1908
2109
|
const lines = gate.live.map((f) => ` ${displayLateAuxPath}:${f.line}:${f.column} [${f.rule}] ${f.message}`);
|
|
1909
2110
|
lateAuxDelivered += gate.live.length;
|
|
2111
|
+
lateAuxAnswered += 1;
|
|
1910
2112
|
// @delivery-surface: runtime-turn:late-auxiliary-findings
|
|
1911
2113
|
advisoryParts.push(`🕐 Late auxiliary diagnostics (${pair.serverId} answered after its grace window):\n${lines.join("\n")}`);
|
|
1912
2114
|
}
|
|
@@ -1923,12 +2125,20 @@ export async function handleTurnEnd(deps) {
|
|
|
1923
2125
|
durationMs: Date.now() - lateAuxStart,
|
|
1924
2126
|
metadata: {
|
|
1925
2127
|
pending: drainedPairs.length,
|
|
2128
|
+
pairCreated: drainedPairs.length + lateAuxCapEvicted,
|
|
2129
|
+
pendingAfter: pendingAuxiliaryCoverageSize(),
|
|
1926
2130
|
delivered: lateAuxDelivered,
|
|
1927
2131
|
stale: lateAuxStale,
|
|
1928
2132
|
missing: lateAuxMissing,
|
|
1929
2133
|
rearmed: lateAuxRearmed,
|
|
1930
2134
|
clientGone: lateAuxClientGone,
|
|
1931
2135
|
probeFailed: lateAuxProbeFailed,
|
|
2136
|
+
cleanConfirmed: lateAuxCleanConfirmed,
|
|
2137
|
+
expired: lateAuxExpired,
|
|
2138
|
+
ceilingExhausted: lateAuxCeilingExhausted,
|
|
2139
|
+
answered: lateAuxAnswered,
|
|
2140
|
+
capEvicted: lateAuxCapEvicted,
|
|
2141
|
+
stuckPairs: lateAuxStuckPairs,
|
|
1932
2142
|
},
|
|
1933
2143
|
});
|
|
1934
2144
|
}
|
|
@@ -1945,7 +2155,7 @@ export async function handleTurnEnd(deps) {
|
|
|
1945
2155
|
const content = capTurnEndMessage(findingParts.join("\n\n"));
|
|
1946
2156
|
const signature = `${files
|
|
1947
2157
|
.slice()
|
|
1948
|
-
.sort((a, b) => a
|
|
2158
|
+
.sort((a, b) => compareOrdinal(a, b))
|
|
1949
2159
|
.join("|")}::${content}`;
|
|
1950
2160
|
const last = cacheManager.readCache("turn-end-findings-last", cwd);
|
|
1951
2161
|
if (last?.data?.signature === signature &&
|
|
@@ -1980,6 +2190,11 @@ export async function handleTurnEnd(deps) {
|
|
|
1980
2190
|
resetFormatService();
|
|
1981
2191
|
return;
|
|
1982
2192
|
}
|
|
2193
|
+
// #1950 fix-round F1: this turn's content is confirmed NOT suppressed —
|
|
2194
|
+
// it is about to reach the agent — so NOW commit the delivery-count
|
|
2195
|
+
// increments the per-blocker loop above only tentatively computed.
|
|
2196
|
+
for (const commit of pendingDependencyDriftDeliveries)
|
|
2197
|
+
commit();
|
|
1983
2198
|
const fileSeqByPath = {};
|
|
1984
2199
|
for (const [filePath, seq] of runtime.getFileSeqEntries()) {
|
|
1985
2200
|
fileSeqByPath[normalizeMapKey(path.resolve(filePath))] = seq;
|