@herbertgao/pi-extensions 2026.8.14 → 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 +16 -13
- package/THIRD_PARTY_NOTICES.md +0 -1
- package/node_modules/@czottmann/pi-automode/CHANGELOG.md +8 -1
- package/node_modules/@czottmann/pi-automode/README.md +4 -0
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/classifier.ts +71 -9
- package/node_modules/@czottmann/pi-automode/package.json +1 -1
- package/node_modules/@herbertgao/pi-bark/LICENSE +21 -0
- 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/@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-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 +15 -0
- package/node_modules/pi-mcp-adapter/README.md +2 -2
- package/node_modules/pi-mcp-adapter/commands.ts +1 -1
- package/node_modules/pi-mcp-adapter/dist/types.d.ts +1 -1
- package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +105 -32
- package/node_modules/pi-mcp-adapter/package.json +1 -1
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +22 -12
- package/node_modules/pi-mcp-adapter/server-manager.ts +6 -0
- package/node_modules/pi-mcp-adapter/types.ts +1 -1
- package/node_modules/pi-web-access/CHANGELOG.md +20 -0
- package/node_modules/pi-web-access/README.md +15 -2
- package/node_modules/pi-web-access/extract.ts +57 -12
- package/node_modules/pi-web-access/github-extract.ts +47 -3
- package/node_modules/pi-web-access/index.ts +1 -1
- package/node_modules/pi-web-access/package.json +1 -1
- package/node_modules/pi-web-access/page-query.ts +61 -8
- package/package.json +16 -16
- 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
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
[
|
|
2
|
+
"./clients/agent-nudge.js",
|
|
3
|
+
"./clients/ast-grep-client.js",
|
|
4
|
+
"./clients/bootstrap.js",
|
|
5
|
+
"./clients/bounded-telemetry.js",
|
|
6
|
+
"./clients/build-identity.js",
|
|
7
|
+
"./clients/bus-events-logger.js",
|
|
8
|
+
"./clients/bus-publish.js",
|
|
9
|
+
"./clients/cache-manager.js",
|
|
10
|
+
"./clients/cache-observability.js",
|
|
11
|
+
"./clients/cascade-format.js",
|
|
12
|
+
"./clients/console-guard-install.js",
|
|
13
|
+
"./clients/debug-handles.js",
|
|
14
|
+
"./clients/debug-heap.js",
|
|
15
|
+
"./clients/degradation-ledger.js",
|
|
16
|
+
"./clients/diagnostic-tracker.js",
|
|
17
|
+
"./clients/diagnostics-publish.js",
|
|
18
|
+
"./clients/dispatch/lazy.js",
|
|
19
|
+
"./clients/dispatch/runner-context.js",
|
|
20
|
+
"./clients/disposition-publish.js",
|
|
21
|
+
"./clients/event-loop-monitor.js",
|
|
22
|
+
"./clients/extension-log.js",
|
|
23
|
+
"./clients/extension-mode.js",
|
|
24
|
+
"./clients/file-utils.js",
|
|
25
|
+
"./clients/format-events-publish.js",
|
|
26
|
+
"./clients/format-service.js",
|
|
27
|
+
"./clients/formatters-lazy.js",
|
|
28
|
+
"./clients/git-guard.js",
|
|
29
|
+
"./clients/host-ports.js",
|
|
30
|
+
"./clients/installer/index.js",
|
|
31
|
+
"./clients/instance-reaper.js",
|
|
32
|
+
"./clients/instance-registry.js",
|
|
33
|
+
"./clients/latency-logger.js",
|
|
34
|
+
"./clients/lens-config.js",
|
|
35
|
+
"./clients/lens-events.js",
|
|
36
|
+
"./clients/lens-flag-registry.js",
|
|
37
|
+
"./clients/lsp-budget.js",
|
|
38
|
+
"./clients/lsp-lazy.js",
|
|
39
|
+
"./clients/lsp-status.js",
|
|
40
|
+
"./clients/lsp/cascade-tier.js",
|
|
41
|
+
"./clients/lsp/config.js",
|
|
42
|
+
"./clients/lsp/index.js",
|
|
43
|
+
"./clients/memory-sampler.js",
|
|
44
|
+
"./clients/message-end-attribution.js",
|
|
45
|
+
"./clients/package-root.js",
|
|
46
|
+
"./clients/path-attribution-telemetry.js",
|
|
47
|
+
"./clients/path-utils.js",
|
|
48
|
+
"./clients/project-lens-config.js",
|
|
49
|
+
"./clients/project-trust.js",
|
|
50
|
+
"./clients/quiet-window.js",
|
|
51
|
+
"./clients/read-bridge.js",
|
|
52
|
+
// index.ts:56 is type-only, but dependency-cruiser parses it as an edge.
|
|
53
|
+
"./clients/read-guard.js",
|
|
54
|
+
"./clients/recent-touches.js",
|
|
55
|
+
"./clients/runtime-agent-end.js",
|
|
56
|
+
"./clients/runtime-context.js",
|
|
57
|
+
"./clients/runtime-coordinator.js",
|
|
58
|
+
"./clients/runtime-session.js",
|
|
59
|
+
"./clients/runtime-tool-call.js",
|
|
60
|
+
"./clients/runtime-tool-result.js",
|
|
61
|
+
"./clients/runtime-turn.js",
|
|
62
|
+
"./clients/safe-spawn.js",
|
|
63
|
+
"./clients/session-event-guard.js",
|
|
64
|
+
"./clients/session-lifecycle.js",
|
|
65
|
+
"./clients/session-start-observability.js",
|
|
66
|
+
"./clients/session-state-store.js",
|
|
67
|
+
"./clients/sessionstart-logger.js",
|
|
68
|
+
"./clients/smells-rollup.js",
|
|
69
|
+
"./clients/startup-timing.js",
|
|
70
|
+
"./clients/tool-definition.js",
|
|
71
|
+
"./clients/tool-render.js",
|
|
72
|
+
"./clients/tool-set-policy.js",
|
|
73
|
+
"./clients/turn-summary-render.js",
|
|
74
|
+
"./clients/turn-summary.js",
|
|
75
|
+
"./clients/user-notify.js",
|
|
76
|
+
"./clients/vanished-instance-marker.js",
|
|
77
|
+
"./clients/warm-attach.js",
|
|
78
|
+
"./clients/widget-state.js"
|
|
79
|
+
]
|
|
@@ -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 AW_LOG_DIR = getGlobalPiLensDir();
|
|
6
7
|
const AW_LOG_FILE = path.join(AW_LOG_DIR, "actionable-warnings.log");
|
|
7
8
|
const AW_LOG_BACKUP_FILE = path.join(AW_LOG_DIR, "actionable-warnings.log.1");
|
|
@@ -12,11 +13,25 @@ const writer = createNdjsonLogger({
|
|
|
12
13
|
maxBytes: MAX_LOG_BYTES,
|
|
13
14
|
backupPath: AW_LOG_BACKUP_FILE,
|
|
14
15
|
});
|
|
16
|
+
/**
|
|
17
|
+
* #2219 (the #2141 class): `filePath` reaches here from
|
|
18
|
+
* `actionable-warnings.ts`'s raw `path.resolve(cwd, file)` — the file
|
|
19
|
+
* imports `normalizeMapKey` and uses it for map lookups on this same value,
|
|
20
|
+
* but never normalizes what gets logged. `filePath` is optional (several
|
|
21
|
+
* events, e.g. `report_started`/`report_complete`, carry none), so only
|
|
22
|
+
* normalize when present.
|
|
23
|
+
*/
|
|
15
24
|
export function logActionableWarningsEvent(entry) {
|
|
16
25
|
if (isTestMode()) {
|
|
17
26
|
return;
|
|
18
27
|
}
|
|
19
|
-
writer.log({
|
|
28
|
+
writer.log({
|
|
29
|
+
ts: new Date().toISOString(),
|
|
30
|
+
...entry,
|
|
31
|
+
...(entry.filePath !== undefined
|
|
32
|
+
? { filePath: normalizeFilePath(entry.filePath) }
|
|
33
|
+
: {}),
|
|
34
|
+
});
|
|
20
35
|
}
|
|
21
36
|
export function getActionableWarningsLogPath() {
|
|
22
37
|
return AW_LOG_FILE;
|
|
@@ -13,6 +13,7 @@ import * as os from "node:os";
|
|
|
13
13
|
import * as path from "node:path";
|
|
14
14
|
import { AstGrepRuleManager } from "./ast-grep-rule-manager.js";
|
|
15
15
|
import { resolvePackagePath } from "./package-root.js";
|
|
16
|
+
import { truncatedByOutputCap } from "./spawn-output-cap.js";
|
|
16
17
|
import { SgRunner, } from "./sg-runner.js";
|
|
17
18
|
// --- Client ---
|
|
18
19
|
function extractDebugAst(raw) {
|
|
@@ -263,6 +264,18 @@ export class AstGrepClient {
|
|
|
263
264
|
const result = await this.runner.execRaw(args, 10_000, options);
|
|
264
265
|
const stderr = result.stderr.trim();
|
|
265
266
|
const stdout = result.stdout.trim();
|
|
267
|
+
// FIRST (#2100): hitting `execRaw`'s cap SIGTERMs ast-grep, so a
|
|
268
|
+
// truncated run also carries the kill's error message. Read after the
|
|
269
|
+
// two checks below, this guard could only ever describe a run that
|
|
270
|
+
// exited before the signal reached it. `execRaw` re-spells `failure`
|
|
271
|
+
// in its own vocabulary but keeps the timeout/aborted spellings, so
|
|
272
|
+
// those runs still fall through to the error branch below.
|
|
273
|
+
if (truncatedByOutputCap(result)) {
|
|
274
|
+
return {
|
|
275
|
+
valid: false,
|
|
276
|
+
error: "ast-grep validation output was truncated",
|
|
277
|
+
};
|
|
278
|
+
}
|
|
266
279
|
if (result.error)
|
|
267
280
|
return { valid: false, error: result.error };
|
|
268
281
|
if (result.status !== 0 && !(result.status === 1 && !stderr)) {
|
|
@@ -272,12 +285,6 @@ export class AstGrepClient {
|
|
|
272
285
|
`ast-grep validation failed with exit code ${result.status}`,
|
|
273
286
|
};
|
|
274
287
|
}
|
|
275
|
-
if (result.outputTruncated) {
|
|
276
|
-
return {
|
|
277
|
-
valid: false,
|
|
278
|
-
error: "ast-grep validation output was truncated",
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
288
|
if (stderrHasError(stderr))
|
|
282
289
|
return { valid: false, error: stderr };
|
|
283
290
|
const warning = stderr || stdout || undefined;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createSingleFlight } from "./single-flight.js";
|
|
2
|
+
/** Create a flight registry whose lifetime belongs to the caller. */
|
|
3
|
+
export function createAvailabilityProbeFlight(options = {}) {
|
|
4
|
+
const flights = createSingleFlight(options);
|
|
5
|
+
return {
|
|
6
|
+
run(key, probe) {
|
|
7
|
+
const joined = flights.has(key);
|
|
8
|
+
return { promise: flights.run(key, probe), joined };
|
|
9
|
+
},
|
|
10
|
+
clear: () => flights.clear(),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
@@ -179,6 +179,7 @@ export class BiomeClient {
|
|
|
179
179
|
latched: true,
|
|
180
180
|
hostStallMs,
|
|
181
181
|
budgetMs: PROBE_TIMEOUT_MS,
|
|
182
|
+
classifiedBy: "probe",
|
|
182
183
|
});
|
|
183
184
|
return { outcome: "success", value: true };
|
|
184
185
|
}
|
|
@@ -225,6 +226,12 @@ export class BiomeClient {
|
|
|
225
226
|
latched: true,
|
|
226
227
|
hostStallMs: this.lastProbeHostStallMs,
|
|
227
228
|
budgetMs: PROBE_TIMEOUT_MS,
|
|
229
|
+
classifiedBy: "caller",
|
|
230
|
+
evidence: {
|
|
231
|
+
install: "succeeded",
|
|
232
|
+
binary: "biome",
|
|
233
|
+
source: "managed-dir",
|
|
234
|
+
},
|
|
228
235
|
});
|
|
229
236
|
}
|
|
230
237
|
return true;
|
|
@@ -43,12 +43,32 @@
|
|
|
43
43
|
* runtime condition — that edge is invisible to this gate, so a blocker whose only
|
|
44
44
|
* stale dependency arrives that way survives a replay. This is an honest boundary,
|
|
45
45
|
* not a silently-closed one.
|
|
46
|
+
*
|
|
47
|
+
* Delivery cap (#1950). A demoted-but-confirmable entry (`alreadyStale` above)
|
|
48
|
+
* is deliberately NOT retired after its past-EOF sibling's one-delivery rule
|
|
49
|
+
* (#1944, `blocker-past-eof.ts`) — its coordinates are still in bounds, so a
|
|
50
|
+
* fresh dispatch can genuinely confirm or clear it, and retiring on delivery
|
|
51
|
+
* one would discard a recoverable finding. But nothing capped how many times
|
|
52
|
+
* the SAME demoted record re-serves: incident data (#1944's lane sweep) showed
|
|
53
|
+
* 18 `alreadyStale` re-serves in one window, with repeat deliveries carrying
|
|
54
|
+
* near-zero information after the first. `runtime-turn.ts` counts each
|
|
55
|
+
* delivery (`InlineBlockerRecord.staleDeliveryCount`) and retires the record
|
|
56
|
+
* via `RuntimeCoordinator.retireDemotedDependencyDriftBlocker` once it reaches
|
|
57
|
+
* `DEPENDENCY_DRIFT_MAX_DELIVERIES` — a count, not a TTL or a session
|
|
58
|
+
* boundary, because "how many times has the agent already been told" is the
|
|
59
|
+
* quantity that actually went to zero information, not "how much time has
|
|
60
|
+
* passed". The ledger reason says "capped, re-run can still confirm" so it
|
|
61
|
+
* reads distinctly from #1944's "retired, unrecoverable" — a capped record
|
|
62
|
+
* COULD still resolve a fresh dispatch; it just stopped being handed one for
|
|
63
|
+
* free.
|
|
46
64
|
*/
|
|
47
65
|
import * as fs from "node:fs";
|
|
48
66
|
import { normalizeEphemeralMapKey } from "./path-utils.js";
|
|
49
67
|
import { resolveImportToFiles } from "./review-graph/import-resolvers.js";
|
|
50
68
|
import { getSharedTreeSitterClient, resolveTreeSitterLanguage, } from "./tree-sitter-shared.js";
|
|
51
69
|
import { TreeSitterSymbolExtractor } from "./tree-sitter-symbol-extractor.js";
|
|
70
|
+
/** See the module doc's "Delivery cap (#1950)" section above. */
|
|
71
|
+
export const DEPENDENCY_DRIFT_MAX_DELIVERIES = 3;
|
|
52
72
|
/**
|
|
53
73
|
* Upper bound on the number of forward imports stat-checked for a single blocker.
|
|
54
74
|
* Blocking entries are rare, but one file can import many modules; the sweep must
|
|
@@ -24,10 +24,9 @@
|
|
|
24
24
|
* that must re-arm at `session_start` and will eventually be forgotten
|
|
25
25
|
* (the #1266–#1625 defect class).
|
|
26
26
|
* 2. **A per-turn cap names its turn.** `capPerTurn` carries the caller's
|
|
27
|
-
* `turnIndex` in the same object as the limit
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* `noteImportResolutionMemoTurn` (`clients/blocker-freshness.ts`).
|
|
27
|
+
* `turnIndex` in the same object as the limit. A bounded 64-turn window
|
|
28
|
+
* keeps overlapping async turns independent; results older than that window
|
|
29
|
+
* fail closed. Session start clears the window when numbering restarts.
|
|
31
30
|
* 3. **Identity always survives.** Every emitted record carries the
|
|
32
31
|
* discriminating identity in `filePath` and in `metadata.identity`, so
|
|
33
32
|
* aggregation can still answer "which file, which method, which record is
|
|
@@ -85,6 +84,14 @@ export const BOUNDED_TELEMETRY_PHASES = [
|
|
|
85
84
|
* exact count.
|
|
86
85
|
*/
|
|
87
86
|
"lsp_warm_client_missing",
|
|
87
|
+
/** #2052: a file's nearest LSP root is outside the session ceiling. */
|
|
88
|
+
"lsp_capability_skip",
|
|
89
|
+
/**
|
|
90
|
+
* #2044: failed-first test state was retired after a confirmed missing path,
|
|
91
|
+
* retained because the filesystem verdict was indeterminate, or evicted at
|
|
92
|
+
* the state cap. Selection checks and detailed rows are both capped per turn.
|
|
93
|
+
*/
|
|
94
|
+
"test_runner_failed_target_state",
|
|
88
95
|
/**
|
|
89
96
|
* #1723: an event-loop block at or above the floor. Not a degradation, so
|
|
90
97
|
* no ledger kind; bounded by call cadence (one `turn_end` runs it once per
|
|
@@ -97,6 +104,17 @@ export const BOUNDED_TELEMETRY_PHASES = [
|
|
|
97
104
|
* queue of them, so it is rising-edge per event name.
|
|
98
105
|
*/
|
|
99
106
|
"session_event_stale_ctx_skip",
|
|
107
|
+
/**
|
|
108
|
+
* #2007: a worktree-mutating git command declined because another live
|
|
109
|
+
* session shares this dirty checkout. Rising edge per checkout root; the
|
|
110
|
+
* ledger keeps the exact repeat count.
|
|
111
|
+
*/
|
|
112
|
+
"shared_checkout_switch_blocked",
|
|
113
|
+
/**
|
|
114
|
+
* #2007: `git status` could not report the working-tree state, so the same
|
|
115
|
+
* command was declined on an UNKNOWN rather than assumed clean.
|
|
116
|
+
*/
|
|
117
|
+
"shared_checkout_probe_failed",
|
|
100
118
|
];
|
|
101
119
|
const REGISTERED_PHASES = new Set(BOUNDED_TELEMETRY_PHASES);
|
|
102
120
|
/** Report whether a phase name is in the registry (used by the sweep). */
|
|
@@ -104,14 +122,15 @@ export function isBoundedTelemetryPhase(phase) {
|
|
|
104
122
|
return REGISTERED_PHASES.has(phase);
|
|
105
123
|
}
|
|
106
124
|
/**
|
|
107
|
-
* Per-turn admission counters, keyed by phase.
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
* count across a session boundary that happened to land on the same index).
|
|
125
|
+
* Per-turn admission counters, keyed by turn and phase. Multiple turns remain
|
|
126
|
+
* live because async work can finish T1 after T2 has already emitted. The map
|
|
127
|
+
* retains a bounded recent window; work older than that window fails closed
|
|
128
|
+
* rather than reopening an exhausted budget. Session start clears all state.
|
|
112
129
|
*/
|
|
130
|
+
const MAX_TRACKED_TURN_CAPS = 64;
|
|
113
131
|
let turnCounts = new Map();
|
|
114
|
-
let
|
|
132
|
+
let latestCountedTurnIndex;
|
|
133
|
+
let retiredThroughTurnIndex = Number.NEGATIVE_INFINITY;
|
|
115
134
|
/**
|
|
116
135
|
* Decide whether this occurrence earns a detailed record, and count it in the
|
|
117
136
|
* ledger either way. Returns `true` when the caller should write the record.
|
|
@@ -180,14 +199,25 @@ export function emitBounded(phase, identity, payload, options = {}) {
|
|
|
180
199
|
function admitAgainstTurnCap(phase, cap) {
|
|
181
200
|
if (cap === undefined)
|
|
182
201
|
return true;
|
|
183
|
-
if (
|
|
184
|
-
|
|
185
|
-
|
|
202
|
+
if (cap.turnIndex <= retiredThroughTurnIndex)
|
|
203
|
+
return false;
|
|
204
|
+
let counts = turnCounts.get(cap.turnIndex);
|
|
205
|
+
if (!counts) {
|
|
206
|
+
if (turnCounts.size >= MAX_TRACKED_TURN_CAPS) {
|
|
207
|
+
const oldestTrackedTurn = Math.min(...turnCounts.keys());
|
|
208
|
+
if (cap.turnIndex < oldestTrackedTurn)
|
|
209
|
+
return false;
|
|
210
|
+
turnCounts.delete(oldestTrackedTurn);
|
|
211
|
+
retiredThroughTurnIndex = Math.max(retiredThroughTurnIndex, oldestTrackedTurn);
|
|
212
|
+
}
|
|
213
|
+
counts = new Map();
|
|
214
|
+
turnCounts.set(cap.turnIndex, counts);
|
|
186
215
|
}
|
|
187
|
-
|
|
216
|
+
latestCountedTurnIndex = Math.max(latestCountedTurnIndex ?? cap.turnIndex, cap.turnIndex);
|
|
217
|
+
const used = counts.get(phase) ?? 0;
|
|
188
218
|
if (used >= cap.limit)
|
|
189
219
|
return false;
|
|
190
|
-
|
|
220
|
+
counts.set(phase, used + 1);
|
|
191
221
|
return true;
|
|
192
222
|
}
|
|
193
223
|
/**
|
|
@@ -198,9 +228,16 @@ function admitAgainstTurnCap(phase, cap) {
|
|
|
198
228
|
*/
|
|
199
229
|
export function resetBoundedTelemetry() {
|
|
200
230
|
turnCounts = new Map();
|
|
201
|
-
|
|
231
|
+
latestCountedTurnIndex = undefined;
|
|
232
|
+
retiredThroughTurnIndex = Number.NEGATIVE_INFINITY;
|
|
233
|
+
}
|
|
234
|
+
/** Test-only: one turn's live admission count for a phase. */
|
|
235
|
+
export function _boundedTurnCountForTest(phase, turnIndex = latestCountedTurnIndex) {
|
|
236
|
+
if (turnIndex === undefined)
|
|
237
|
+
return 0;
|
|
238
|
+
return turnCounts.get(turnIndex)?.get(phase) ?? 0;
|
|
202
239
|
}
|
|
203
|
-
/** Test-only:
|
|
204
|
-
export function
|
|
205
|
-
return turnCounts.
|
|
240
|
+
/** Test-only: number of turn buckets retained by the bounded counter. */
|
|
241
|
+
export function _boundedTrackedTurnsForTest() {
|
|
242
|
+
return turnCounts.size;
|
|
206
243
|
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #1775: `sessionstart.log` recorded no build identity — no commit hash, no
|
|
3
|
+
* build timestamp. Dogfood forensics ("does this session include PR #1727?")
|
|
4
|
+
* had to reconstruct that by hand: run `git merge-base --is-ancestor` in the
|
|
5
|
+
* serving checkout and compare `dist/` mtimes against the session-start time.
|
|
6
|
+
*
|
|
7
|
+
* The running extension can be a different checkout than the repo an
|
|
8
|
+
* investigator is looking at, so identity is derived from the RUNNING
|
|
9
|
+
* build's own files — `getPackageRoot` (already used by grammar-source.ts to
|
|
10
|
+
* find pi-lens's own assets under both the unbundled dev layout and a
|
|
11
|
+
* packaged install) plus the mtime of the very entry file that is executing
|
|
12
|
+
* right now — never from `process.cwd()` and never assumed to be a git
|
|
13
|
+
* checkout.
|
|
14
|
+
*
|
|
15
|
+
* Commit resolution reuses `review-graph/git-identity.ts`'s
|
|
16
|
+
* `resolveGitIdentity` — a PURE filesystem read, no `git` subprocess. This
|
|
17
|
+
* runs inside the `session_start` handler, ahead of the #473
|
|
18
|
+
* concurrent-secondary classification, so every in-process subagent pays
|
|
19
|
+
* whatever this costs; a synchronous `git rev-parse`/`git status` spawn pair
|
|
20
|
+
* (fix round 1's approach, reverted here) measured 150-300ms typical and up
|
|
21
|
+
* to ~10s worst case on two 5s timeouts. `resolveGitIdentity` is a handful of
|
|
22
|
+
* `fs.readFileSync` calls, LRU-cached per process, so this path never spawns.
|
|
23
|
+
*
|
|
24
|
+
* The dirty working-tree flag genuinely needs `git status`, which has no
|
|
25
|
+
* spawn-free equivalent — so it is dropped from this record rather than
|
|
26
|
+
* reintroducing a spawn on the session-start hot path (refs #1775 followup
|
|
27
|
+
* comment: dirty flag deferred, commit + entryMtime + version shipped).
|
|
28
|
+
*/
|
|
29
|
+
import * as fs from "node:fs";
|
|
30
|
+
import * as path from "node:path";
|
|
31
|
+
import { fileURLToPath } from "node:url";
|
|
32
|
+
import { isTestMode } from "./env-utils.js";
|
|
33
|
+
import { getPackageRoot } from "./package-root.js";
|
|
34
|
+
import { normalizeFilePath } from "./path-utils.js";
|
|
35
|
+
import { resolveGitIdentity } from "./review-graph/git-identity.js";
|
|
36
|
+
/**
|
|
37
|
+
* A `.git` found by walking up from `root` only counts as owning `root` when
|
|
38
|
+
* its resolved worktree top-level IS `root` — not merely an ancestor of it.
|
|
39
|
+
* Without this check, a packaged install nested anywhere under an unrelated
|
|
40
|
+
* repo (a dotfiles checkout in $HOME is the common case) would confidently
|
|
41
|
+
* report that repo's HEAD as the running build's identity.
|
|
42
|
+
*/
|
|
43
|
+
function resolveOwnedCommit(root) {
|
|
44
|
+
const identity = resolveGitIdentity(root);
|
|
45
|
+
if (!identity)
|
|
46
|
+
return "unknown";
|
|
47
|
+
const normalizedRoot = normalizeFilePath(path.resolve(root));
|
|
48
|
+
if (identity.worktreeRoot !== normalizedRoot)
|
|
49
|
+
return "unknown";
|
|
50
|
+
return identity.headCommit.slice(0, 8);
|
|
51
|
+
}
|
|
52
|
+
function readPackageVersion(root) {
|
|
53
|
+
try {
|
|
54
|
+
const raw = fs.readFileSync(path.join(root, "package.json"), "utf-8");
|
|
55
|
+
const pkg = JSON.parse(raw);
|
|
56
|
+
return pkg.version ?? "unknown";
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return "unknown";
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function statEntryMtime(entryImportMetaUrl) {
|
|
63
|
+
try {
|
|
64
|
+
return fs.statSync(fileURLToPath(entryImportMetaUrl)).mtime.toISOString();
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// Entry path unresolvable (e.g. a non-file:// URL) — "unknown" rather
|
|
68
|
+
// than throw out of a session-start observability line.
|
|
69
|
+
return "unknown";
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Resolve the identity of the build currently running — pure filesystem
|
|
74
|
+
* reads, no subprocess. `entryImportMetaUrl` must be the ENTRY module's own
|
|
75
|
+
* `import.meta.url` (index.ts) — passing a different module's URL would
|
|
76
|
+
* report that module's mtime instead of the running build's.
|
|
77
|
+
*
|
|
78
|
+
* Returns `undefined` inside the test runner: nothing computed, nothing
|
|
79
|
+
* logged (`sessionstart-logger`'s writer is a no-op there too), so a caller
|
|
80
|
+
* on the session-start hot path never pays this cost during tests.
|
|
81
|
+
*/
|
|
82
|
+
export function getBuildIdentity(entryImportMetaUrl) {
|
|
83
|
+
if (isTestMode())
|
|
84
|
+
return undefined;
|
|
85
|
+
const root = getPackageRoot(entryImportMetaUrl);
|
|
86
|
+
return {
|
|
87
|
+
commit: resolveOwnedCommit(root),
|
|
88
|
+
entryMtime: statEntryMtime(entryImportMetaUrl),
|
|
89
|
+
version: readPackageVersion(root),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/** One bounded, human-readable line for sessionstart.log's free-text writer. */
|
|
93
|
+
export function formatBuildIdentity(identity) {
|
|
94
|
+
return `session_start: build identity — commit=${identity.commit} entryMtime=${identity.entryMtime} version=${identity.version}`;
|
|
95
|
+
}
|
|
@@ -23,6 +23,7 @@ import { appendRecentTouches } from "./recent-touches.js";
|
|
|
23
23
|
import { createLiveBusEmitter, recordStaleBusFailure, resolveLiveBusEmitter, } from "./live-bus-emitter.js";
|
|
24
24
|
export const BUS_FILES_TOUCHED_EVENT = "pilens:files:touched";
|
|
25
25
|
export const BUS_FILES_TOUCHED_VERSION = 1;
|
|
26
|
+
const BUS_LOG_PATH_CAP = 64;
|
|
26
27
|
const liveEmitter = createLiveBusEmitter();
|
|
27
28
|
let hasLoggedFailure = false;
|
|
28
29
|
// Log-once-per-process guards for the two structural-no-op outcomes below
|
|
@@ -148,6 +149,8 @@ export function publishFilesTouched(args) {
|
|
|
148
149
|
cwd: payload.cwd,
|
|
149
150
|
reason: args.reason,
|
|
150
151
|
fileCount: payload.paths.length,
|
|
152
|
+
writer: "pi-lens",
|
|
153
|
+
paths: payload.paths.slice(0, BUS_LOG_PATH_CAP),
|
|
151
154
|
});
|
|
152
155
|
}
|
|
153
156
|
catch (err) {
|
|
@@ -11,6 +11,7 @@ import { getProjectDataDir } from "../file-utils.js";
|
|
|
11
11
|
import { readJsonCache } from "../json-cache-read.js";
|
|
12
12
|
import { resolvePackagePath } from "../package-root.js";
|
|
13
13
|
import { writeFileAtomic } from "../atomic-write.js";
|
|
14
|
+
import { compareOrdinal } from "../string-utils.js";
|
|
14
15
|
// v4: cache skip_test_files + fix_action — v3 entries silently dropped them,
|
|
15
16
|
// and ruleHash (rule-file mtimes) never invalidates on a code-only fix.
|
|
16
17
|
// v5 (#675): rule SELECTION changed in code — javascript no longer inherits the
|
|
@@ -69,7 +70,7 @@ export class RuleCache {
|
|
|
69
70
|
}
|
|
70
71
|
computeRuleHash(ruleFiles) {
|
|
71
72
|
const hash = crypto.createHash("sha256");
|
|
72
|
-
for (const file of ruleFiles.sort(
|
|
73
|
+
for (const file of ruleFiles.sort(compareOrdinal)) {
|
|
73
74
|
const resolved = path.resolve(file);
|
|
74
75
|
if (!fs.existsSync(resolved))
|
|
75
76
|
continue;
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
import { createHash } from "node:crypto";
|
|
51
51
|
import { lazyEnvNumber } from "./env-utils.js";
|
|
52
52
|
import { logLatency } from "./latency-logger.js";
|
|
53
|
+
import { compareOrdinal } from "./string-utils.js";
|
|
53
54
|
/** RuntimeCoordinator's counter is process-global when sessions share a host. */
|
|
54
55
|
const PROCESS_TURN_SCOPE = "process-global-runtime";
|
|
55
56
|
const SECONDARY_TURN_SCOPE = "unavailable-concurrent-secondary";
|
|
@@ -490,7 +491,7 @@ function boundedHashArray(value, depth, seen, state) {
|
|
|
490
491
|
return `array:${value.length}:[${items.join(",")}]`;
|
|
491
492
|
}
|
|
492
493
|
function boundedHashObject(value, depth, seen, state) {
|
|
493
|
-
const keys = Object.keys(value).sort((left, right) => left
|
|
494
|
+
const keys = Object.keys(value).sort((left, right) => compareOrdinal(left, right));
|
|
494
495
|
if (keys.length > 24)
|
|
495
496
|
state.contentTruncated = true;
|
|
496
497
|
const fields = keys
|
|
@@ -3,17 +3,31 @@ import { isTestMode } from "./env-utils.js";
|
|
|
3
3
|
import { getGlobalPiLensDir } from "./file-utils.js";
|
|
4
4
|
import { createNdjsonLogger } from "./ndjson-logger.js";
|
|
5
5
|
import { getMaxLogSizeMB } from "./log-cleanup.js";
|
|
6
|
+
import { normalizeLoggedPath } from "./path-utils.js";
|
|
6
7
|
const CASCADE_LOG_DIR = getGlobalPiLensDir();
|
|
7
8
|
const CASCADE_LOG_FILE = path.join(CASCADE_LOG_DIR, "cascade.log");
|
|
8
9
|
const writer = createNdjsonLogger({
|
|
9
10
|
filePath: CASCADE_LOG_FILE,
|
|
10
11
|
maxBytes: getMaxLogSizeMB() * 1024 * 1024,
|
|
11
12
|
});
|
|
13
|
+
/**
|
|
14
|
+
* #2219 (the #2141 class): call sites across `dispatch/integration.ts`,
|
|
15
|
+
* `runtime-turn.ts`, and `runtime-coordinator.ts` feed a mix of raw
|
|
16
|
+
* `filePath`/`cwd` params and (for `lsp/cascade-tier.ts`) the
|
|
17
|
+
* `"<quiet-window>"` sentinel. Normalize once here, the single emit seam —
|
|
18
|
+
* same pattern as `review-graph-logger.ts`'s `logReviewGraph`, guarded via
|
|
19
|
+
* `normalizeLoggedPath` so the non-path sentinel passes through unchanged
|
|
20
|
+
* instead of being resolved against the process cwd.
|
|
21
|
+
*/
|
|
12
22
|
export function logCascade(entry) {
|
|
13
23
|
if (isTestMode()) {
|
|
14
24
|
return;
|
|
15
25
|
}
|
|
16
|
-
writer.log({
|
|
26
|
+
writer.log({
|
|
27
|
+
ts: new Date().toISOString(),
|
|
28
|
+
...entry,
|
|
29
|
+
filePath: normalizeLoggedPath(entry.filePath),
|
|
30
|
+
});
|
|
17
31
|
}
|
|
18
32
|
export function getCascadeLogPath() {
|
|
19
33
|
return CASCADE_LOG_FILE;
|
|
@@ -101,9 +101,9 @@ export function parseVultureOutput(output, root) {
|
|
|
101
101
|
*
|
|
102
102
|
* vulture finds unused functions, classes, methods, imports, variables and
|
|
103
103
|
* attributes by static analysis of the whole tree. It has no JSON reporter, so
|
|
104
|
-
* we parse its stable one-line-per-finding text output.
|
|
105
|
-
*
|
|
106
|
-
* output is success, not failure.
|
|
104
|
+
* we parse its stable one-line-per-finding text output. A clean run exits 0;
|
|
105
|
+
* found dead code exits 3 with findings on stdout. A non-zero exit with
|
|
106
|
+
* parseable output is success, not failure (see runAnalyze for the table).
|
|
107
107
|
*/
|
|
108
108
|
export class PythonDeadCodeClient {
|
|
109
109
|
id = "python";
|
|
@@ -245,6 +245,7 @@ export class PythonDeadCodeClient {
|
|
|
245
245
|
latched: true,
|
|
246
246
|
hostStallMs,
|
|
247
247
|
budgetMs: 5000,
|
|
248
|
+
classifiedBy: "probe",
|
|
248
249
|
});
|
|
249
250
|
return true;
|
|
250
251
|
}
|
|
@@ -370,14 +371,16 @@ export class PythonDeadCodeClient {
|
|
|
370
371
|
durationMs,
|
|
371
372
|
};
|
|
372
373
|
}
|
|
373
|
-
//
|
|
374
|
-
//
|
|
375
|
-
// findings on stdout
|
|
376
|
-
//
|
|
377
|
-
//
|
|
378
|
-
//
|
|
379
|
-
//
|
|
380
|
-
//
|
|
374
|
+
// Verified exit-code table (vulture 2.16, probed live during the #1758
|
|
375
|
+
// review): a clean run exits 0 with empty stdout; dead code found exits
|
|
376
|
+
// 3 with findings on stdout; invalid input or a parse error exits 1
|
|
377
|
+
// with empty stdout and the error on stderr. #1736 sweep: the ORIGINAL
|
|
378
|
+
// guard here required non-empty stderr to call it an error, so a
|
|
379
|
+
// nonzero exit with BOTH empty stdout and empty stderr (a silent crash)
|
|
380
|
+
// still fell through to "No dead code found" -- the same
|
|
381
|
+
// empty-distinguishes-clean-from-errored gap the knip fix closes. A
|
|
382
|
+
// nonzero exit with no findings on stdout is never clean now,
|
|
383
|
+
// regardless of whether stderr said anything.
|
|
381
384
|
const output = result.stdout || "";
|
|
382
385
|
if (!output.trim()) {
|
|
383
386
|
const stderr = (result.stderr || "").trim();
|