@herbertgao/pi-extensions 2026.9.15 → 2026.9.16
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 +5 -0
- package/THIRD_PARTY_NOTICES.md +26 -0
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +1 -1
- package/node_modules/@narumitw/pi-btw/dist/index.ts +12 -6
- package/node_modules/@narumitw/pi-btw/dist/index.ts.map +3 -3
- package/node_modules/@narumitw/pi-btw/package.json +4 -4
- package/node_modules/@narumitw/pi-btw/src/main-tree-picker.ts +2 -0
- package/node_modules/@narumitw/pi-btw/src/side-thread.ts +16 -4
- package/node_modules/pi-lens/CHANGELOG.md +498 -0
- package/node_modules/pi-lens/README.md +45 -2
- package/node_modules/pi-lens/dist/clients/actionable-warnings.js +23 -7
- package/node_modules/pi-lens/dist/clients/advisory-provenance.js +187 -51
- package/node_modules/pi-lens/dist/clients/cache-manager.js +64 -5
- package/node_modules/pi-lens/dist/clients/child-unref.js +17 -8
- package/node_modules/pi-lens/dist/clients/config-diagnostic-codes.js +2 -0
- package/node_modules/pi-lens/dist/clients/config-locations.js +237 -9
- package/node_modules/pi-lens/dist/clients/config-resolve.js +7 -1
- package/node_modules/pi-lens/dist/clients/degradation-ledger.js +33 -3
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +87 -64
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +39 -3
- package/node_modules/pi-lens/dist/clients/dispatch/finding-policy.js +118 -1
- package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +8 -2
- package/node_modules/pi-lens/dist/clients/dispatch/inline-suppressions.js +23 -4
- package/node_modules/pi-lens/dist/clients/dispatch/rule-ignores.js +14 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +26 -28
- package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +38 -25
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +32 -49
- package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +16 -14
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +25 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/dart-analyze.js +28 -47
- package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +11 -4
- package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +27 -22
- package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +31 -46
- package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +29 -46
- package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +91 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +16 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +38 -23
- package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +27 -15
- package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +17 -8
- package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +31 -21
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +34 -60
- package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +6 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +12 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +22 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +39 -16
- package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rubocop.js +27 -18
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +18 -19
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +6 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +6 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +10 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +11 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +10 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +11 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +12 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +30 -15
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +23 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +8 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +11 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +15 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +12 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +27 -39
- package/node_modules/pi-lens/dist/clients/dispatch/suppress-writer.js +13 -3
- package/node_modules/pi-lens/dist/clients/effective-config.js +3 -1
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +42 -11
- package/node_modules/pi-lens/dist/clients/formatters.js +49 -11
- package/node_modules/pi-lens/dist/clients/git-guard.js +247 -34
- package/node_modules/pi-lens/dist/clients/gradle-ktfmt-style.js +121 -25
- package/node_modules/pi-lens/dist/clients/inline-blocker-dispositions.js +186 -0
- package/node_modules/pi-lens/dist/clients/install-diagnostics.js +19 -6
- package/node_modules/pi-lens/dist/clients/installer/index.js +281 -32
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +8 -0
- package/node_modules/pi-lens/dist/clients/latency-logger.js +8 -0
- package/node_modules/pi-lens/dist/clients/lens-config.js +66 -8
- package/node_modules/pi-lens/dist/clients/lsp/client.js +139 -11
- package/node_modules/pi-lens/dist/clients/lsp/config.js +9 -7
- package/node_modules/pi-lens/dist/clients/lsp/content-limits.js +41 -0
- package/node_modules/pi-lens/dist/clients/lsp/index.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/launch.js +23 -2
- package/node_modules/pi-lens/dist/clients/lsp/server.js +106 -25
- package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +14 -0
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +105 -16
- package/node_modules/pi-lens/dist/clients/mcp/ipc.js +232 -44
- package/node_modules/pi-lens/dist/clients/mcp/review.js +53 -7
- package/node_modules/pi-lens/dist/clients/opengrep-client.js +11 -6
- package/node_modules/pi-lens/dist/clients/pipeline.js +121 -66
- package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +21 -3
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +11 -3
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +34 -26
- package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +16 -10
- package/node_modules/pi-lens/dist/clients/ruff-client.js +31 -4
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +38 -4
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +16 -5
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +27 -12
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +447 -280
- package/node_modules/pi-lens/dist/clients/safe-spawn.js +256 -65
- package/node_modules/pi-lens/dist/clients/spawn-output-cap.js +84 -1
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +119 -58
- package/node_modules/pi-lens/dist/clients/turn-end/lane.js +51 -0
- package/node_modules/pi-lens/dist/clients/turn-end/lanes/govulncheck.js +112 -0
- package/node_modules/pi-lens/dist/clients/turn-end/lanes/secrets.js +204 -0
- package/node_modules/pi-lens/dist/clients/warm-attach.js +59 -0
- package/node_modules/pi-lens/dist/clients/widget-state.js +145 -14
- package/node_modules/pi-lens/dist/clients/workspace-topology.js +57 -3
- package/node_modules/pi-lens/dist/clients/zizmor-config.js +26 -13
- package/node_modules/pi-lens/dist/index.js +5695 -3733
- package/node_modules/pi-lens/dist/mcp/analyze-cli.js +4 -0
- package/node_modules/pi-lens/dist/mcp/server.js +33 -21
- package/node_modules/pi-lens/dist/scripts/lib/web-tree-sitter-dir.mjs +123 -0
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +43 -16
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +118 -7
- package/node_modules/pi-lens/docs/adr/0001-stale-advisory-live-arm.md +29 -0
- package/node_modules/pi-lens/docs/adr/0002-workspace-hash-rendezvous.md +30 -0
- package/node_modules/pi-lens/docs/adr/0003-git-guard-latch-writer.md +203 -0
- package/node_modules/pi-lens/docs/adr/0004-disposition-policy-seam.md +38 -0
- package/node_modules/pi-lens/docs/adr/0005-tool-availability-enforcement-seam.md +29 -0
- package/node_modules/pi-lens/docs/adr/0006-derived-state-benchmark-first.md +31 -0
- package/node_modules/pi-lens/docs/adr/0007-end-to-end-witness-per-seam-slice.md +38 -0
- package/node_modules/pi-lens/docs/adr/0008-turn-end-lane-interface.md +165 -0
- package/node_modules/pi-lens/docs/adr/0009-reported-path-attribution.md +114 -0
- package/node_modules/pi-lens/docs/adr/README.md +26 -0
- package/node_modules/pi-lens/docs/agent-tools.md +18 -1
- package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +4 -3
- package/node_modules/pi-lens/docs/configuration.md +55 -1
- package/node_modules/pi-lens/docs/engineering-principles.md +202 -0
- package/node_modules/pi-lens/docs/environment-variables.md +61 -4
- package/node_modules/pi-lens/docs/features.md +2 -2
- package/node_modules/pi-lens/docs/globalconfig.md +6 -1
- package/node_modules/pi-lens/docs/language-coverage.md +17 -0
- package/node_modules/pi-lens/docs/lsp-capability-matrix.md +98 -31
- package/node_modules/pi-lens/docs/pi-lens-fixer.md +57 -3
- package/node_modules/pi-lens/docs/pi-lens-investigator.md +9 -0
- package/node_modules/pi-lens/docs/pi-lens-reviewer.md +16 -0
- package/node_modules/pi-lens/docs/pi-lens-subagent.md +9 -0
- package/node_modules/pi-lens/docs/public-api-stability.md +1 -0
- package/node_modules/pi-lens/docs/release-qa-baseline.md +2 -0
- package/node_modules/pi-lens/docs/servercapabilities.md +21 -11
- package/node_modules/pi-lens/docs/settings.md +12 -3
- package/node_modules/pi-lens/docs/subagent-compat.md +1 -1
- package/node_modules/pi-lens/package.json +5 -3
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-assert-tuple-test.yml +13 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-boolean-in-except-test.yml +26 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-http-headers-bracket-access-test.yml +10 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/unchecked-numeric-parse-python-test.yml +18 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/unchecked-throwing-call-python-test.yml +4 -3
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/go-no-fmt-println.yml +2 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-assert-tuple.yml +23 -13
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-boolean-in-except.yml +7 -3
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-console-except-error-js.yml +2 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-console-except-error.yml +2 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-http-headers-bracket-access.yml +12 -7
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/unchecked-numeric-parse-python.yml +44 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/unchecked-throwing-call-python.yml +5 -3
- package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/console-statement.yml +2 -2
- package/node_modules/pi-lens/scripts/install-selftest.mjs +21 -17
- package/node_modules/pi-lens/scripts/lib/web-tree-sitter-dir.mjs +123 -0
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +29 -0
- package/node_modules/pi-mcp-adapter/OAUTH.md +369 -0
- package/node_modules/pi-mcp-adapter/README.md +12 -5
- package/node_modules/pi-mcp-adapter/config.ts +31 -8
- package/node_modules/pi-mcp-adapter/direct-tool-surface.ts +1 -1
- package/node_modules/pi-mcp-adapter/dist/config.js +33 -8
- package/node_modules/pi-mcp-adapter/dist/config.js.map +1 -1
- package/node_modules/pi-mcp-adapter/dist/json-schema-validator.js +15 -2
- package/node_modules/pi-mcp-adapter/dist/json-schema-validator.js.map +1 -1
- package/node_modules/pi-mcp-adapter/dist/mcp-auth.d.ts +2 -0
- package/node_modules/pi-mcp-adapter/dist/mcp-auth.js +27 -2
- package/node_modules/pi-mcp-adapter/dist/mcp-auth.js.map +1 -1
- package/node_modules/pi-mcp-adapter/dist/metadata-cache.js +1 -1
- package/node_modules/pi-mcp-adapter/dist/metadata-cache.js.map +1 -1
- package/node_modules/pi-mcp-adapter/dist/server-manager.js +6 -4
- package/node_modules/pi-mcp-adapter/dist/server-manager.js.map +1 -1
- package/node_modules/pi-mcp-adapter/dist/types.d.ts +2 -2
- package/node_modules/pi-mcp-adapter/dist/utils.d.ts +2 -0
- package/node_modules/pi-mcp-adapter/dist/utils.js +10 -3
- package/node_modules/pi-mcp-adapter/dist/utils.js.map +1 -1
- package/node_modules/pi-mcp-adapter/index.ts +37 -20
- package/node_modules/pi-mcp-adapter/init.ts +14 -15
- package/node_modules/pi-mcp-adapter/json-schema-validator.ts +16 -2
- package/node_modules/pi-mcp-adapter/mcp-auth.ts +27 -2
- package/node_modules/pi-mcp-adapter/metadata-cache.ts +1 -1
- package/node_modules/pi-mcp-adapter/package.json +3 -2
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +1 -1
- package/node_modules/pi-mcp-adapter/server-manager.ts +6 -3
- package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +99 -6
- package/node_modules/pi-mcp-adapter/types.ts +2 -2
- package/node_modules/pi-mcp-adapter/ui-session.ts +60 -27
- package/node_modules/pi-mcp-adapter/utils.ts +11 -3
- package/node_modules/pi-next-cue/.github/workflows/publish.yml +20 -0
- package/node_modules/pi-next-cue/LICENSE +21 -0
- package/node_modules/pi-next-cue/README.md +81 -0
- package/node_modules/pi-next-cue/index.ts +358 -0
- package/node_modules/pi-next-cue/package.json +28 -0
- package/package.json +8 -5
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@narumitw/pi-btw",
|
|
3
|
-
"version": "0.61.
|
|
3
|
+
"version": "0.61.1",
|
|
4
4
|
"description": "Pi extension that adds a /btw side-question command.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -32,9 +32,9 @@
|
|
|
32
32
|
"prepack": "npm run build"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@earendil-works/pi-ai": "0.
|
|
36
|
-
"@earendil-works/pi-coding-agent": "0.
|
|
37
|
-
"@earendil-works/pi-tui": "0.
|
|
35
|
+
"@earendil-works/pi-ai": "0.87.1",
|
|
36
|
+
"@earendil-works/pi-coding-agent": "0.87.1",
|
|
37
|
+
"@earendil-works/pi-tui": "0.87.1",
|
|
38
38
|
"esbuild": "0.28.2",
|
|
39
39
|
"typescript": "7.0.2"
|
|
40
40
|
},
|
|
@@ -245,6 +245,8 @@ function sanitizeEntryForDisplay(entry: SessionEntry): SessionEntry {
|
|
|
245
245
|
return { ...entry, thinkingLevel: sanitizeSingleLine(entry.thinkingLevel) };
|
|
246
246
|
case "custom":
|
|
247
247
|
return { ...entry, customType: sanitizeSingleLine(entry.customType) };
|
|
248
|
+
case "context_edit":
|
|
249
|
+
return { ...entry, targetId: sanitizeSingleLine(entry.targetId) };
|
|
248
250
|
case "label":
|
|
249
251
|
return {
|
|
250
252
|
...entry,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
1
2
|
import type {
|
|
2
3
|
Api,
|
|
3
4
|
AssistantMessage,
|
|
@@ -45,10 +46,15 @@ export type SideThreadTurn =
|
|
|
45
46
|
export interface SideThread {
|
|
46
47
|
conversationContext: string;
|
|
47
48
|
turns: SideThreadTurn[];
|
|
49
|
+
/**
|
|
50
|
+
* Provider routing ID (`options.sessionId`) shared by this thread's turns.
|
|
51
|
+
* Kept separate from the main Pi session so side requests never share its cache or affinity lane.
|
|
52
|
+
*/
|
|
53
|
+
routingSessionId: string;
|
|
48
54
|
}
|
|
49
55
|
|
|
50
56
|
export function createSideThread(conversationContext: string): SideThread {
|
|
51
|
-
return { conversationContext, turns: [] };
|
|
57
|
+
return { conversationContext, turns: [], routingSessionId: randomUUID() };
|
|
52
58
|
}
|
|
53
59
|
|
|
54
60
|
export function buildSideThreadMessages(thread: SideThread, question: string): Message[] {
|
|
@@ -104,7 +110,7 @@ export async function completeSideThreadTurn({
|
|
|
104
110
|
{ systemPrompt: SYSTEM_PROMPT, messages: buildSideThreadMessages(thread, question) },
|
|
105
111
|
buildStreamOptions(
|
|
106
112
|
auth,
|
|
107
|
-
{ thinkingLevel, signal, model, sessionId },
|
|
113
|
+
{ thinkingLevel, signal, model, sessionId, routingSessionId: thread.routingSessionId },
|
|
108
114
|
completeSimple.appliesRequestHeaderTransforms === true,
|
|
109
115
|
),
|
|
110
116
|
);
|
|
@@ -157,7 +163,7 @@ export async function completeSideQuestion({
|
|
|
157
163
|
},
|
|
158
164
|
buildStreamOptions(
|
|
159
165
|
auth,
|
|
160
|
-
{ thinkingLevel, signal, model, sessionId },
|
|
166
|
+
{ thinkingLevel, signal, model, sessionId, routingSessionId: randomUUID() },
|
|
161
167
|
completeSimple.appliesRequestHeaderTransforms === true,
|
|
162
168
|
),
|
|
163
169
|
);
|
|
@@ -234,12 +240,15 @@ interface BuildSideThreadStreamOptions {
|
|
|
234
240
|
thinkingLevel: BtwThinkingLevel;
|
|
235
241
|
signal?: AbortSignal;
|
|
236
242
|
model?: Pick<Model<Api>, "provider">;
|
|
243
|
+
/** Main Pi session ID, used only for OpenCode attribution headers. */
|
|
237
244
|
sessionId?: string;
|
|
245
|
+
/** Side-request routing ID sent as `options.sessionId`; never the main session ID. */
|
|
246
|
+
routingSessionId: string;
|
|
238
247
|
}
|
|
239
248
|
|
|
240
249
|
function buildStreamOptions(
|
|
241
250
|
auth: SideQuestionAuth | undefined,
|
|
242
|
-
{ thinkingLevel, signal, model, sessionId }: BuildSideThreadStreamOptions,
|
|
251
|
+
{ thinkingLevel, signal, model, sessionId, routingSessionId }: BuildSideThreadStreamOptions,
|
|
243
252
|
applyRequestHeaderTransforms: boolean,
|
|
244
253
|
): ModelsSimpleStreamOptions {
|
|
245
254
|
const sessionHeaders = model ? getOpencodeSessionHeaders(model, sessionId) : undefined;
|
|
@@ -248,6 +257,9 @@ function buildStreamOptions(
|
|
|
248
257
|
headers: applyRequestHeaderTransforms ? auth?.headers : mergeSessionHeaders(auth?.headers, sessionHeaders),
|
|
249
258
|
env: auth?.env,
|
|
250
259
|
signal,
|
|
260
|
+
// Pi documents sessionId as optional, but providers use it for request routing and
|
|
261
|
+
// some provider overrides require it. Pi core also mints a fresh ID for one-off requests.
|
|
262
|
+
sessionId: routingSessionId,
|
|
251
263
|
};
|
|
252
264
|
if (applyRequestHeaderTransforms && sessionHeaders) {
|
|
253
265
|
options.transformHeaders = (headers) => mergeSessionHeaders(headers, sessionHeaders) ?? {};
|
|
@@ -16,6 +16,504 @@ All notable changes to pi-lens will be documented in this file.
|
|
|
16
16
|
|
|
17
17
|
### Security
|
|
18
18
|
|
|
19
|
+
## [4.3.0] - 2026-09-25
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- Read SonarCloud's master quality gate and open vulnerabilities in the nightly tool-smoke workflow, failing loudly for quality errors while treating SonarCloud outages as visible, fail-open warnings (closes #3319).
|
|
24
|
+
|
|
25
|
+
- **Report shadowed global config files (closes #3299)** — When both supported global config files exist, pi-lens keeps the legacy winner and records the shadowed agent-dir path once per session.
|
|
26
|
+
|
|
27
|
+
- **Read (and edit) the global config from the host's config dir (refs #2457)** — When `PI_CODING_AGENT_DIR` is set, `$PI_CODING_AGENT_DIR/extensions/pi-lens.json` is read when it exists and the legacy `~/.pi-lens/config.json` does not; a file at the legacy default keeps winning while it exists, so current users never move. Settings editors resolve through the same seam and create in the agent-dir location when NEITHER file exists ("edit the one that exists; prefer the new one if neither does"). The canonical default and `PI_LENS_CONFIG_PATH` semantics are unchanged.
|
|
28
|
+
|
|
29
|
+
- Added an advisory CI lane that runs the existing capped targeted-test selector on every pull request and publishes its selection result in the step summary (refs #3215).
|
|
30
|
+
|
|
31
|
+
- **Durable CI test history.** Record bounded per-file Vitest results for nightly flake analysis.
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
|
|
35
|
+
- Folded three hand-rolled path-key transformations in the LSP server, LSP
|
|
36
|
+
launch and tool-call seams onto `clients/path-utils.ts` and added a
|
|
37
|
+
comment- and string-blanked source sweep that pins every remaining raw `\` → `/` fold and
|
|
38
|
+
path-key case fold per file, so a new copy fails CI (refs #1193). The PATH
|
|
39
|
+
entry dedupe key now parses with `path.win32`/`path.posix` chosen from its own
|
|
40
|
+
`platform` argument instead of the host default, so two spellings of one
|
|
41
|
+
Windows directory dedupe on every lane.
|
|
42
|
+
|
|
43
|
+
- Extracted the turn-end govulncheck delivery (the 🛡️ Go CVE advisory tier) out
|
|
44
|
+
of `clients/runtime-turn.ts` into `clients/turn-end/lanes/govulncheck.ts`
|
|
45
|
+
behind the same `TurnEndLane` interface as the secrets lane, and added the
|
|
46
|
+
advisory tier to `TurnEndLaneParts` with it — the first lane that renders one,
|
|
47
|
+
so the field, the composer's tagged push and the registered surface arrive
|
|
48
|
+
together rather than as a slot nothing reads (refs #1892, ADR 0008
|
|
49
|
+
amendment). The six rules the block stated inline — the `onMissing: "demote"`
|
|
50
|
+
first-trace-frame freshness declaration, the disposition anchor over both
|
|
51
|
+
freshness arms, the withheld stale line and its marker, the module/package
|
|
52
|
+
fallback, the upgrade hint and the display cap — now live once, in the lane.
|
|
53
|
+
Agent-facing text is byte-identical: both committed witness goldens are
|
|
54
|
+
unchanged and a third pins this lane's live rows, demoted rows, deleted
|
|
55
|
+
call-site demotion, module fallback, cap and suppression notice through the
|
|
56
|
+
real pi host entry.
|
|
57
|
+
|
|
58
|
+
- Extracted the turn-end secrets delivery (the gitleaks and trivy-secrets
|
|
59
|
+
blocker and demoted tiers) out of `clients/runtime-turn.ts` into
|
|
60
|
+
`clients/turn-end/lanes/secrets.ts` behind one `TurnEndLane` interface —
|
|
61
|
+
collect the stores, gate them with the composer's shared freshness pass, then
|
|
62
|
+
render — so the ten rendering and disposition rules that block used to state
|
|
63
|
+
inline now live once, in the lane, and the composer states none of them
|
|
64
|
+
(refs #1892, ADR 0008). Agent-facing text is byte-identical: the committed
|
|
65
|
+
witness golden for the scanner lanes is unchanged and a second golden pins the
|
|
66
|
+
lane's own live tier, demoted tier, combined ast-grep provenance and
|
|
67
|
+
suppressed-by-disposition notice through the real pi host entry.
|
|
68
|
+
|
|
69
|
+
- **Type-aware async and optional-chain checks now lint the test population (refs #3244)** — `npm run lint` now runs the pinned type-aware test lane, using a stable Unix formatter compatible with the repository's oxlint-tsgolint toolchain.
|
|
70
|
+
|
|
71
|
+
- Restrict tool-smoke drift ticket side effects to scheduled and default-branch runs while preserving branch-dispatch reports.
|
|
72
|
+
|
|
73
|
+
- Internal-only maintenance: extend the socket listener sweep to reusable test support fixtures and remove an inert MCP socket teardown call.
|
|
74
|
+
|
|
75
|
+
- Reuse the shared directory-mtime freshness predicate for project-config discovery.
|
|
76
|
+
|
|
77
|
+
- **Mechanise train lessons (refs #3426)** — pre-commit now checks staged files with the pinned formatter, and pre-push selects production tree-scanning governance suites. Real-spawn suites that exceed the pre-push budget move to a reasoned CI-only tier, and a mechanical tree-scanner census fails any unregistered scanner rather than trusting a hand list.
|
|
78
|
+
|
|
79
|
+
- **Close the pre-4.3.0 docs gap audit (closes #3431)** — document the LSP
|
|
80
|
+
sync content bound (2 MiB / 5000 lines) and the new `textDocument/didSave`
|
|
81
|
+
behaviour in `docs/agent-tools.md`; add the missing `pilens_session_end`
|
|
82
|
+
row and the review-graph/config-core nodes to the README architecture
|
|
83
|
+
diagram; correct the "a dozen-plus language servers" figure to 46; index
|
|
84
|
+
ADR 0008; document the `PILENS_PROBE`/`PILENS_UNSAFE_FORCE_GRAMMAR_LOAD`/
|
|
85
|
+
`PILENS_PUB_DEBUG` diagnostic env vars and widen the recovery grep; bring
|
|
86
|
+
the pre-commit hook description and the contributor path (guard-bash.mjs,
|
|
87
|
+
`PI_LENS_TEST_MAX_WORKERS`, the mutation lane, release-QA) up to date; and
|
|
88
|
+
rename the retired `lsp_diagnostics` tool name to `lens_diagnostics` in two
|
|
89
|
+
earlier changelog fragments.
|
|
90
|
+
|
|
91
|
+
- Make nightly LSP capability documentation deterministic and skip byte-identical refresh PRs.
|
|
92
|
+
|
|
93
|
+
- **Glossary, witness, and seam contracts (refs #3259, refs #3260)** — Document the shared pi-lens vocabulary and seven accepted architecture decisions, add the end-to-end witness ADR and adapter heuristic, require the fixer boundaries and PR-body structure, and make the `Why` section's one-sentence contract executable.
|
|
94
|
+
|
|
95
|
+
- **Docs: require exact-pin sweeps on the merge with master (refs #3259, refs #3260)** — Fixer, reviewer, and merge-train contracts now require glossary synonym sweeps on both the PR head and the merge with `origin/master`, with same-PR re-pinning from the sweep's `UNPINNED`/`STALE` evidence.
|
|
96
|
+
|
|
97
|
+
- **Trigger-based agent guidance (refs #3259)** — Group the recurring defect
|
|
98
|
+
catalog and conditional repository procedures under explicit `<important if>`
|
|
99
|
+
triggers, require investigator slices to verify already-shipped work, and
|
|
100
|
+
enforce standalone paired markers plus Markdown-comment- and string-blanked
|
|
101
|
+
catalog scanning so hidden counterfeits cannot satisfy the 52-shape contract.
|
|
102
|
+
|
|
103
|
+
- **Docs contract pre-flight and reviewer/fixer mechanics (refs #3260)** —
|
|
104
|
+
Record the merge-train pre-flight rows, reviewer continuity rule, and
|
|
105
|
+
evidence-pass mechanics harvested from the 2026-09-22/23 train.
|
|
106
|
+
|
|
107
|
+
- Docs: the winning global-config-location table (every combination of `PI_LENS_CONFIG_PATH`, the legacy file and the agent-dir file), the probe-error tier note, and the XDG-like setup recipe with the migration order (closes #3250).
|
|
108
|
+
|
|
109
|
+
- AGENTS.md points at the engineering-principles repository first, and a vendored copy of PRINCIPLES.md lives at docs/engineering-principles.md for readers without a global instruction file (regenerated by that repo's sync script).
|
|
110
|
+
|
|
111
|
+
- The three cached scanner lanes turn_end reads — gitleaks, trivy secrets and
|
|
112
|
+
govulncheck — now share ONE cited-path freshness pass instead of calling the
|
|
113
|
+
gate once each (refs #1892). A file both secret scanners flag was stat'd
|
|
114
|
+
twice and wrote two `finding_stale_line_demote` rows for one decision about
|
|
115
|
+
one file; it is now one stat and one bounded record per delivery, carrying a
|
|
116
|
+
`byStore` breakdown so the row still says which store's findings were
|
|
117
|
+
retired. The stat allowance stays per store — a shared pool would let one
|
|
118
|
+
lane spend it and leave another re-rendering an edited cited line as current
|
|
119
|
+
— and a delivery that exhausts one now writes a bounded
|
|
120
|
+
`finding_path_stat_budget_exhausted` row naming every store affected, which
|
|
121
|
+
nothing disclosed before. Source identity survives the fold: each store's own `scannedAt`
|
|
122
|
+
decides its own findings' staleness, and each store's own missing-path policy
|
|
123
|
+
decides its own findings' deletion, so a govulncheck CVE still survives a
|
|
124
|
+
deleted call site on the same path that drops a gitleaks secret. Scanner
|
|
125
|
+
cache records written by 4.2.1 parse and render unchanged.
|
|
126
|
+
|
|
127
|
+
- **Pin the glossary synonym-retirement inventory (refs #3259)** — A
|
|
128
|
+
comment- and string-blanked governance sweep now holds the per-file retired
|
|
129
|
+
identifier population to exact equality across the runtime TypeScript
|
|
130
|
+
sources, with distinct failures for an unpinned new use and for a stale pin,
|
|
131
|
+
and it pins the canonical-collision exclusions with the module that owns each
|
|
132
|
+
canonical sense.
|
|
133
|
+
|
|
134
|
+
- Every `parseToolRun` runner now documents its nonzero exit table, its
|
|
135
|
+
documented `ran` codes are pinned exactly so neither adding nor removing one
|
|
136
|
+
passes silently, and each documented code needs an executable status fixture
|
|
137
|
+
in the runner's test matrix (refs #3292).
|
|
138
|
+
|
|
139
|
+
- Improve nightly LSP clean-gate fixture coverage for project-backed Vue, Svelte, F#, and Mix workspaces.
|
|
140
|
+
|
|
141
|
+
- Refreshed measured LSP clean-transition markers: cue retains its publish
|
|
142
|
+
signal, while lua-language-server and marksman are recognized as silent on
|
|
143
|
+
clean transitions (refs #3347).
|
|
144
|
+
|
|
145
|
+
- The lint workflow installs yamllint with `--only-binary=:all:`, so pip can never fall back to running a source distribution's setup script on the runner (SonarCloud githubactions:S8541; the only open finding failing the master quality gate since 2026-09-08).
|
|
146
|
+
|
|
147
|
+
- **Release-QA rows for the global config location and the shadowed-global record (refs #2608)** — the matrix now drives a real pi-lens MCP server with `PI_CODING_AGENT_DIR` set and `extensions/pi-lens.json` present and witnesses that the agent-dir file supplies the global tier, and with both global files present witnesses the once-per-session `config-location-shadowed` record (`PILENS_CFG_0010`) holding its count at 1 across repeated config loads.
|
|
148
|
+
|
|
149
|
+
### Fixed
|
|
150
|
+
|
|
151
|
+
- `elixir-check` now decides whether a compiler diagnostic belongs to the
|
|
152
|
+
edited file through `pathsEqual`, the shared on-disk path identity seam,
|
|
153
|
+
instead of its own win32 case fold. Findings whose reported spelling differs
|
|
154
|
+
from the dispatched one — a lowercase drive letter on Windows, a backslash
|
|
155
|
+
segment anywhere — reach the agent as the blocking error they are instead of
|
|
156
|
+
a generic unparseable-output warning (refs #1193).
|
|
157
|
+
|
|
158
|
+
- **Share actionlint and Credo runner outcome parsing (refs #1816)** — failed
|
|
159
|
+
CLI output now reaches the common empty-result and parsed-nothing gates.
|
|
160
|
+
|
|
161
|
+
- **Share ESLint and golangci-lint runner outcome parsing (refs #1816)** — failed
|
|
162
|
+
JSON output now reaches the common empty-result and parsed-nothing gates.
|
|
163
|
+
|
|
164
|
+
- The marker-root seam's "a nearer project marker created below an
|
|
165
|
+
already-resolved root wins" behaviour is now pinned through the production
|
|
166
|
+
paths that consume it: the real `rust-clippy` runner (so `cargo clippy`
|
|
167
|
+
follows a crate scaffolded by `cargo init crates/engine` mid-session instead
|
|
168
|
+
of staying at the workspace root), the real `BiomeClient` autofix as a
|
|
169
|
+
non-runner consumer, and one derived case over every runner in the marker
|
|
170
|
+
vocabulary baseline. The behaviour itself shipped in #2948; nothing above the
|
|
171
|
+
seam had proven it, and the positive-hit direction was untested (refs #2922).
|
|
172
|
+
|
|
173
|
+
- `lens_diagnostics mode=full` no longer retires retained opengrep findings
|
|
174
|
+
across the whole project when an opengrep scan completed but scanned zero
|
|
175
|
+
files (an empty `paths.scanned`, e.g. no rule language matched the root).
|
|
176
|
+
A coverage producer that declares zero scanned files now has file-level
|
|
177
|
+
authority over nothing instead of falling back to whole-root authority, so
|
|
178
|
+
a finding is only retired when a scan actually covered its file. The
|
|
179
|
+
one-per-session `runner-coverage-empty` ledger row says when that happened
|
|
180
|
+
(refs #2962).
|
|
181
|
+
|
|
182
|
+
- Make the mutation-diff lane actually evaluate mutants: mutate only the diff's changed lines, give instrumented related tests their own timeout, and bound the run below the job cap so a lane that evaluated nothing says so.
|
|
183
|
+
|
|
184
|
+
- **The `suppressed: N` chip counts a mark for as long as the mark stands (closes #3183)** —
|
|
185
|
+
a `false-positive`/`suppress` mark stopped contributing to the pi-lens footer's
|
|
186
|
+
suppressed count at the marked file's next edit, even an edit that left the
|
|
187
|
+
marked line byte-identical and the mark still applying, with no way to get it
|
|
188
|
+
back. The retained row's lifetime is now the mark's own: it stands while the
|
|
189
|
+
marked line is still in the file and is retired when that line changes, the
|
|
190
|
+
file is deleted, a scan reports the finding again, or the per-file retention
|
|
191
|
+
cap truncates it. A second finding of the same rule with the same message no
|
|
192
|
+
longer displaces the marked one, and `lens_diagnostics mode=all` never lists a
|
|
193
|
+
marked finding as a live warning.
|
|
194
|
+
|
|
195
|
+
- A blocking finding whose cited file no longer exists is now retracted from
|
|
196
|
+
every surface, not just the tool result it was rendered into: the durable
|
|
197
|
+
record `pi-lens` re-serves at turn end (`Unresolved from this turn — <path>`)
|
|
198
|
+
and the verdict that latches the `--lens-guard` commit gate are both built
|
|
199
|
+
from the same deleted-path-gated set the per-edit 🔴 STOP block renders. A
|
|
200
|
+
retracted finding no longer comes back a moment later, and no longer blocks
|
|
201
|
+
`git commit` under a summary quoting the pipeline's own all-clear line
|
|
202
|
+
(closes #3190).
|
|
203
|
+
|
|
204
|
+
- **CSS, SCSS, LESS, SASS and Prisma files get LSP diagnostics again (refs #3217)** — pi-lens answered a language server's `workspace/configuration` request with `null` when it had no value for the requested section. `vscode-css-language-server` passes that answer straight into its own lint configuration and threw `Cannot read properties of null (reading 'validProperties')` inside its diagnostics computation, returning an empty report for every css-kind file and surfacing the error only as a `window/logMessage`; `@prisma/language-server` reads `settings.enableDiagnostics` unguarded and its process exited outright. pi-lens now answers an unresolvable section with an empty settings object, which is what "no value for this section" means, and still never leaks the whole configuration blob for a section the server did not ask for (#983). The nightly `Tool smoke` clean gate had reported 0 diagnostics for css on every run since the gate landed; it now reports real findings for both servers, and the gate itself went from 7 opted-in fixtures to 41 with a `gated N / handshake-only M / unavailable K` census line and a governance test that refuses a new fixture carrying neither `lspGate` nor an explicit `lspGateExempt` reason.
|
|
205
|
+
|
|
206
|
+
- Keep the subagent compatibility smoke aligned with pi-subagents' compiled contract source layout.
|
|
207
|
+
|
|
208
|
+
- **Preserve opaque mutation ownership (refs #3226)** — Opaque bash recovery
|
|
209
|
+
still records freshness and runs analysis, but observed paths no longer
|
|
210
|
+
receive read-guard authorship, autonomous format/autofix, or edit-directed
|
|
211
|
+
blocker/actionable delivery. Explicit native and recognized direct bash writes
|
|
212
|
+
retain their configured writer policy. Repeated opaque paths use one counted
|
|
213
|
+
ledger subject with bounded representative evidence instead of retaining one
|
|
214
|
+
once-key per artifact path.
|
|
215
|
+
|
|
216
|
+
- **Nested bundled rule ignores (refs #3240)** — Console and Go rule directory carve-outs now apply at nested package depths without hiding similarly named application paths; the shared matcher now treats POSIX, drive-letter, and UNC paths with segment-aware containment on every host OS.
|
|
217
|
+
|
|
218
|
+
- **Turn-end scanner-cache reads no longer block the hook (refs #3274)** — the
|
|
219
|
+
gitleaks, trivy and govulncheck stores `turn_end` reads once per delivery were
|
|
220
|
+
read synchronously, so a slow or wedged filesystem held the whole hook and no
|
|
221
|
+
deadline or Escape could release it. They now read through
|
|
222
|
+
`CacheManager.readCacheAsync` under the turn_end budget and the hook's abort
|
|
223
|
+
signal; a read that cannot finish inside the budget is abandoned, delivers the
|
|
224
|
+
same output as a cold cache, and is recorded — once per turn, naming the
|
|
225
|
+
stores the turn was composed without — instead of stalling the turn.
|
|
226
|
+
|
|
227
|
+
- `go vet` findings for the file you just edited are no longer dropped when
|
|
228
|
+
go's spelling of that file's path differs from the dispatcher's. The runner
|
|
229
|
+
now decides "is this line about the edited file?" through `pathsEqual`, the
|
|
230
|
+
shared on-disk path identity seam, instead of a bare string compare, so a
|
|
231
|
+
differently-cased path on Windows or a case-folding macOS volume is
|
|
232
|
+
recognised as the same file and the run is no longer reported clean
|
|
233
|
+
(closes #3277, refs #1193).
|
|
234
|
+
|
|
235
|
+
- The go-vet filesystem case-identity regression test is explicitly admitted to
|
|
236
|
+
the Windows Vitest lane, so its real Windows case-folding arm is executed.
|
|
237
|
+
|
|
238
|
+
- Runner diagnostics are attributed to the edited file through one seam:
|
|
239
|
+
`pathsEqual` against the path the tool itself reported, resolved from the cwd
|
|
240
|
+
the tool ran in. `golangci-lint`, `rust-clippy`, `javac`, `zig-check`,
|
|
241
|
+
`detekt`, `cpp-check`, `dotnet-build`, `dart-analyze` and `cue-vet` each
|
|
242
|
+
decided it locally before — a bare `===`, a `path.resolve` with no base, a
|
|
243
|
+
basename compare, an `endsWith` — so a `golangci-lint` run in any project
|
|
244
|
+
whose Go module root is not the extension's own working directory dropped
|
|
245
|
+
every finding for the edited file and reported it clean, and a `cue vet` error
|
|
246
|
+
in a sibling directory whose file shared the touched file's name was reported
|
|
247
|
+
as the touched file's own failure (refs #3278).
|
|
248
|
+
|
|
249
|
+
- `gleam check` diagnostics and `ruff` autofix findings are now attributed to the
|
|
250
|
+
edited file through the same seam every other tool uses (`pathsEqual` against
|
|
251
|
+
the path the tool reported, resolved from the cwd it ran in). gleam's location
|
|
252
|
+
line arrives inside `codespan_reporting`'s `┌─` gutter, which a suffix compare
|
|
253
|
+
was tolerating, so on Windows — and on any case-folding mount — a spelling
|
|
254
|
+
that differed only in case dropped every gleam diagnostic for the edited file;
|
|
255
|
+
ruff's JSON `filename` was compared with a bare `!==` against a path resolved
|
|
256
|
+
with no base at all, which silently meant the extension's own working
|
|
257
|
+
directory (refs #3285, refs #3286).
|
|
258
|
+
|
|
259
|
+
- Gleam diagnostics now carry their error or warning title and inline label instead of codespan's border glyph, and locationless project output is left unattributed rather than charged to the dispatched file (refs #3293).
|
|
260
|
+
|
|
261
|
+
- LSP workspace-edit changed paths are compared with the dispatched file through
|
|
262
|
+
the filesystem-aware path identity seam instead of a bare string equality, so a
|
|
263
|
+
differently spelled path to the same file is no longer announced as a
|
|
264
|
+
collateral change of itself (refs #3294).
|
|
265
|
+
|
|
266
|
+
- The LSP clean gate now reuses the handshake layer's per-server availability decision, so unavailable servers remain ⚠ while handshaking servers are gated (refs #3309).
|
|
267
|
+
|
|
268
|
+
- Added real LSP gate-entry coverage for handshake-census admission and handler-owned unavailability.
|
|
269
|
+
|
|
270
|
+
- A language server that answers `didOpen` with an empty diagnostic set while it
|
|
271
|
+
indexes no longer makes pi-lens report the file clean. intelephense publishes
|
|
272
|
+
`[]` before its whole-workspace index is warm and the real findings once
|
|
273
|
+
indexing ends, so `lsp_diagnostics` reported a php file carrying an undefined
|
|
274
|
+
variable as "confirmed clean". pi-lens now holds such a server's empty first
|
|
275
|
+
publish — once per session, released by the server's own next publish — so the
|
|
276
|
+
finding is reported, while every server that publishes `[]` for a genuinely
|
|
277
|
+
clean file keeps confirming it with no added wait (refs #3310).
|
|
278
|
+
|
|
279
|
+
- Launch fish-lsp through its stdio transport so standalone Fish diagnostics reach the LSP smoke gate (refs #3311).
|
|
280
|
+
|
|
281
|
+
- Prepare LSP smoke fixtures before gating C#, F#, Elixir, Expert, and Vue diagnostics, and give csharp-ls the measured 6s diagnostic budget its restored project needs (the 1.5s default read a real compiler error as clean).
|
|
282
|
+
|
|
283
|
+
- A tool the installer finds on `PATH` is now probed with that tool's own
|
|
284
|
+
check before it is resolved, the way every other rung of the resolution
|
|
285
|
+
ladder already was. A file on `PATH` that cannot actually run — rustup's
|
|
286
|
+
`rust-analyzer` proxy on a box where that component was never installed, a
|
|
287
|
+
`pipx`-installed `cmake-language-server` whose venv resolved a pygls that
|
|
288
|
+
removed the symbol it imports — no longer shadows the managed install that
|
|
289
|
+
works, and no longer reports as an available server that then never answers.
|
|
290
|
+
A probe that stalls or cannot be read still resolves as before: a kill is not
|
|
291
|
+
a verdict. `cmake-language-server` also pins its pygls floor, and that pin now
|
|
292
|
+
reaches whichever resolver pipx picked — pip and uv each read the same
|
|
293
|
+
constraints file through their own environment variable — so the install stops
|
|
294
|
+
producing a launcher that cannot start (refs #3311).
|
|
295
|
+
|
|
296
|
+
- The tmp-fixture hygiene census now judges only the temp entries the running
|
|
297
|
+
vitest invocation created: a root left by another invocation sharing the same
|
|
298
|
+
`TMPDIR` is neither reported as this run's leak nor deleted from under it, a
|
|
299
|
+
leak report names the test file behind a raw `mkdtempSync` prefix instead of
|
|
300
|
+
`owner: tests/unknown`, and the owner-marker liveness cases read only the
|
|
301
|
+
markers they wrote, so a fully skipped test file in the same invocation no
|
|
302
|
+
longer reds them (refs #3314, refs #3316, refs #3306).
|
|
303
|
+
|
|
304
|
+
- Provision the pinned `fish` executable in the nightly tool-smoke runner so `fish-lsp` can complete its handshake and clean-gate diagnostics.
|
|
305
|
+
|
|
306
|
+
- `scripts/ci-verdict.mjs` now reads every check-run page and reports an exact rerun command for a latest cancelled check (closes #3373).
|
|
307
|
+
|
|
308
|
+
- A child process that writes without limit can no longer terminate the Pi
|
|
309
|
+
host. `safeSpawnAsync` now caps retained output at 32 MiB when the caller
|
|
310
|
+
passes no `maxOutputBytes` — 98 of its 110 call sites passed none, and an
|
|
311
|
+
absent cap grew one JavaScript string until V8 threw `RangeError: Invalid
|
|
312
|
+
string length` from inside a stdout/stderr `data` handler, where no caller's
|
|
313
|
+
`try`/`catch` could reach it. The noisy child is now truncated, terminated
|
|
314
|
+
and reported through the existing `outputTruncated` / `killedForOutputCap`
|
|
315
|
+
result, and any other fault in that handler becomes the same bounded result
|
|
316
|
+
instead of an uncaught exception. A ledger row names the command, the cap,
|
|
317
|
+
the bytes observed and whether the child was terminated (closes #3375).
|
|
318
|
+
|
|
319
|
+
- Fix `ci-verdict` rerun hints to pass the workflow run id instead of the check-run job id.
|
|
320
|
+
|
|
321
|
+
- A degradation row whose subject is blank now reads `unknown` instead of
|
|
322
|
+
rendering as `⚠ <kind>: 1 — : <reason>` with an empty discriminator, and its
|
|
323
|
+
once-latch and tally key agree with the row. Any subject that normalizes to
|
|
324
|
+
empty or whitespace is folded at the ledger's write paths; metadata values and
|
|
325
|
+
reasons are untouched, so a genuinely empty value is still recorded as itself
|
|
326
|
+
(refs #3389).
|
|
327
|
+
|
|
328
|
+
- A pi session serving warm diagnostics to a peer no longer dies when a client
|
|
329
|
+
disconnects mid-reply. Every `requestWarmDiagnostics` timeout, schema refusal
|
|
330
|
+
and validation refusal destroys the client's socket, and the incumbent's
|
|
331
|
+
accepted socket had no `error` listener — so a routine `read ECONNRESET`
|
|
332
|
+
became an uncaught exception in the host. The event is now handled and
|
|
333
|
+
counted in the degradation ledger as `warm-attach-socket-error`, keyed by
|
|
334
|
+
errno (closes #3389).
|
|
335
|
+
|
|
336
|
+
- **Elixir diagnostics refresh again after an edit (refs [#3405](https://github.com/apmantza/pi-lens/issues/3405))** — pi-lens advertised `textDocument/didSave` but never sent one, so a language server whose diagnose pass runs on save (Expert, which recompiles the Mix project on save and on nothing else) never reported anything for a file edited through pi-lens. The post-write sync and the explicit `lens_diagnostics` (`source=lsp`) query now send the notification to every server that asked for it, carrying the document text when the server requested it and the file is inside the same 2 MiB / 5000-line bound the rest of the LSP sync already honours; servers that declare no `save` capability are unaffected, as are warm-up, cascade and workspace-sweep touches.
|
|
337
|
+
|
|
338
|
+
- **Non-core tree-sitter grammars on a compiled host (closes #3409)** — On a
|
|
339
|
+
runtime that cannot resolve a bare package specifier — pi ships as a
|
|
340
|
+
`bun build --compile` binary — pi-lens could not work out where to put a
|
|
341
|
+
lazily fetched grammar, so no non-core language (C#, C++, OCaml, …) could
|
|
342
|
+
ever be analysed: symbol search, module reports and structural rules stayed
|
|
343
|
+
degraded forever while the notification blamed package-manager build scripts
|
|
344
|
+
and the network. Both the read and the write path now resolve web-tree-sitter
|
|
345
|
+
through a subpath that works there — and only accept a directory that really is
|
|
346
|
+
that package, so a fetched grammar can never land in an unrelated tree — the
|
|
347
|
+
report names the real cause (nothing resolved, or the directory is not
|
|
348
|
+
writable), a tree-sitter run whose grammar never loaded is recorded as a skip
|
|
349
|
+
instead of a clean pass, and `scripts/install-selftest.mjs` stops reporting the
|
|
350
|
+
grammar asset missing on those same hosts.
|
|
351
|
+
|
|
352
|
+
- LSP root detection no longer trusts a resolved project root for the rest of
|
|
353
|
+
the session. Every memoized root carries the mtime of each directory its
|
|
354
|
+
marker walk probed and is re-walked as soon as one of them changes, so a
|
|
355
|
+
manifest scaffolded below an already-resolved root (`swift package init` in a
|
|
356
|
+
subdirectory, a new `package.json`, `prisma/schema.prisma` written into an
|
|
357
|
+
existing `prisma/`) moves the root on the next file touch, and a manifest
|
|
358
|
+
deleted at the resolved root falls back to the outer project. A hit also
|
|
359
|
+
expires on the shared 2 s re-check cadence, so even a change a directory mtime
|
|
360
|
+
cannot see — one made inside the same timestamp tick on a 1 s-granularity
|
|
361
|
+
volume — costs one window instead of a restart. All 45 marker detectors share
|
|
362
|
+
the one seam (refs #3412).
|
|
363
|
+
|
|
364
|
+
- Revalidate Git repository identity when repository metadata is created or removed during a process (closes #3417).
|
|
365
|
+
|
|
366
|
+
- **`lens_diagnostics mode=full` pointed circular-dependency findings at a file that does not exist (closes [#3428](https://github.com/apmantza/pi-lens/issues/3428))** — the project scan read madge's `--circular --json` output as a dependency graph while the turn-end lane read it correctly as an array of cycle arrays, so `Object.entries([["src/a.ts","src/b.ts"]])` handed the scan the array INDEX as the file name: every cycle was reported on `<root>/0`, `<root>/1`, … with its members resolved against the extension host's working directory instead of the scanned project root. The cycle COUNT was right either way, which is why it went unnoticed. Both sites now share one reader of madge's contract — the hand-rolled parses are deleted, so the number of readers goes from two to one — anchored at the cycle's first real file and resolved against the root that was scanned. The shape is pinned by fixtures captured from madge 8.0.0 (the install pi-lens manages) driven with the client's own argv, and the new test asserts the client still spawns that argv, so the captured bytes cannot silently become evidence for an invocation the client abandoned. Two neighbouring defects the upstream read surfaced are filed rather than folded in: madge resolves a single-file scan's members against that file's directory, not the project root ([#3435](https://github.com/apmantza/pi-lens/issues/3435)), and `--warning` is inert under `--json`, so the "skipped local file" count was structurally always zero ([#3436](https://github.com/apmantza/pi-lens/issues/3436)).
|
|
367
|
+
|
|
368
|
+
- **The turn-end circular-dependency pass keyed nested files by paths that do not exist (closes [#3435](https://github.com/apmantza/pi-lens/issues/3435))** — the single-file madge lane (`checkFilesBatch`, the pass `runtime-turn` runs) points madge at one file, and madge prints that file's cycle members relative to the target's directory. The client resolved them against the project root instead, so a cycle between `src/a.ts` and `src/b.ts` seeded the shared circular-file set with `<root>/a.ts` and `<root>/b.ts` — neither exists — and `isInCircular`/`getCircularForFile` answered false for the real nested files (`hasCircular` was right by accident, since it counts parsed cycles). Members now resolve against the target file's directory through the shared `parseMadgeCycles` reader, including `../` members for cycles that leave that directory. Pinned by fixtures captured from madge 8.0.0 with the client's own argv.
|
|
369
|
+
|
|
370
|
+
- **The madge circular-dependency pass reported a "skipped local file" count that was always zero (closes [#3436](https://github.com/apmantza/pi-lens/issues/3436))** — `buildMadgeArgs` passed `--warning`, but madge 8.0.0 gates that flag on `!program.json` (bin/cli.js) and the client always passes `--json`, so nothing reached stderr and `parseMadgeSkips` / `DepCheckResult.localSkips` could only ever return `{ total: 0, local: [] }`; ungated, the skip list prints to stdout and would corrupt the JSON this reader parses. The flag, the parser, the count field and the "possible silent cycle-miss" log line are deleted. Because madge cannot be asked for its skipped-file list under `--json`, that lost visibility is recorded once per session/root as `madge-skip-visibility-unavailable`, from `parseMadgeCycles` — the one reader both the turn-end and session-start lanes pass through — instead of being read as a clean graph. Pinned by a captured madge 8.0.0 invocation from a workspace with an unresolvable local import.
|
|
371
|
+
|
|
372
|
+
- Keep preserved LSP capability rows and bullets deterministic across locales.
|
|
373
|
+
|
|
374
|
+
- Share runner outcome parsing for ktlint and PHP lint so nonzero findings are
|
|
375
|
+
delivered instead of being mistaken for skipped output (refs #1816).
|
|
376
|
+
|
|
377
|
+
- **Share runner outcome parsing for Dart Analyze and Elixir Check (refs #1816)** — Nonzero empty, malformed, stderr-only, or signaled runs no longer report a clean file; valid findings remain visible through the shared bounded outcome path.
|
|
378
|
+
|
|
379
|
+
- **Share compiler runner outcome parsing (refs #1816)** — `cpp-check` and `zig-check` now distinguish failed, skipped, and clean invocations through the shared runner outcome seam.
|
|
380
|
+
|
|
381
|
+
- **Share compiler runner outcome parsing (refs #1816)** — Route `javac` and `dotnet-build` through the shared runner outcome parser so failed compiler invocations cannot be reported as clean files.
|
|
382
|
+
|
|
383
|
+
- **Consolidate RuboCop and Ruff run outcomes (refs #1816)** — Nonzero empty or unparsable tool output no longer reports a clean file, while status-2 findings and bounded failure context retain their existing semantics.
|
|
384
|
+
|
|
385
|
+
- **Carry Spotless ktfmt styles into the standalone formatter (closes #2481)** — `googleStyle()` and `kotlinlangStyle()` now map to ktfmt CLI flags. `dropboxStyle()` records the CLI limitation and falls back to the bare invocation.
|
|
386
|
+
|
|
387
|
+
- **Worker-side test diagnostics now reach passing-run logs (closes #3128)** — replaced the scoped warning/error paths with newline-terminated `process.stderr.write` records, including the tests-tree guard's two sites, so Vitest's default worker reporter cannot silently drop them.
|
|
388
|
+
|
|
389
|
+
- Skip formatter style inference when indentation exists only inside masked comment or template interiors.
|
|
390
|
+
|
|
391
|
+
- The temporary-fixture hygiene sweep now waits for live test owners to finish
|
|
392
|
+
their bounded cleanup drain and attributes remaining entries to the owner
|
|
393
|
+
file, preventing cross-worker false leaks without adding prefix admissions.
|
|
394
|
+
Owner markers authenticate themselves with a heartbeat the worker refreshes
|
|
395
|
+
from its own test lifecycle, so an orphaned or PID-reused worker is attributed
|
|
396
|
+
after the bound on every platform, not only where `/proc` exists (refs #3186).
|
|
397
|
+
|
|
398
|
+
- **Three Python ast-grep rules no longer false-positive (closes #3211)** —
|
|
399
|
+
`no-boolean-in-except` stops its `boolean_operator` search at the handler's
|
|
400
|
+
own block, so an `or`/`and` inside the handler *body* (`return 2 or 3`) is
|
|
401
|
+
no longer mistaken for a boolean exception-type condition.
|
|
402
|
+
`no-http-headers-bracket-access` now excludes `headers[...]` writes
|
|
403
|
+
(`resp.headers["X"] = v`, `+=`, `del`) — only reads can raise `KeyError`.
|
|
404
|
+
`unchecked-throwing-call-python`'s `int()`/`float()` patterns moved to a
|
|
405
|
+
new `unchecked-numeric-parse-python` rule (`warning` severity) that also
|
|
406
|
+
excludes numeric-literal and already-numeric-constructor (`int`/`float`/
|
|
407
|
+
`Decimal`) arguments.
|
|
408
|
+
|
|
409
|
+
- **Parse inline suppression reasons (closes #3213)** - `pi-lens-ignore` comments now suppress their listed rule ids when followed by a supported trailing reason.
|
|
410
|
+
|
|
411
|
+
- **GitHub CLI authentication for release tools (closes #3221)** — GitHub-release
|
|
412
|
+
tool installation and refresh now reuse authenticated `gh` CLI credentials for
|
|
413
|
+
API metadata requests, while keeping release asset downloads unauthenticated
|
|
414
|
+
and reporting evidence-supported anonymous rate-limit failures with an
|
|
415
|
+
actionable remedy.
|
|
416
|
+
|
|
417
|
+
- **`no-assert-tuple` now checks only the assertion condition (closes #3223).**
|
|
418
|
+
Tuple literals used in comparisons, calls, comprehensions, containers, and
|
|
419
|
+
assertion messages no longer produce false-positive diagnostics.
|
|
420
|
+
|
|
421
|
+
- **Avoid unsupported Windows SIGHUP re-raise (refs #3239)** — Console-close cleanup now preserves tracked-child termination without recording a false crash from `kill ENOSYS`.
|
|
422
|
+
|
|
423
|
+
- **Honor `lens_diagnostic_mark` on turn-end unresolved blockers (refs #3246)** — The "Unresolved from this turn" section now applies the shared disposition/rule/inline-suppression policy to the blockers it re-serves, so a finding marked `false-positive` stops coming back on later turns; when every blocker on a file is marked, the section and its `🔴 STOP` text are dropped entirely.
|
|
424
|
+
|
|
425
|
+
- **Filter the built actionable-warnings advisory (closes #3270, refs #3248)** — the turn-end advisory now applies stored dispositions and suppresses ast-grep secret duplicates after LSP enrichment, while the raw cache remains available for `mode=delta`.
|
|
426
|
+
|
|
427
|
+
- **The commit gate honors a turn-end disposition mark (refs #3248)** — when every blocker on a file is marked `false-positive`, turn end now recomputes the `--lens-guard` commit-gate latch from the surviving findings instead of from the raw blocker map, so the gate stops quoting findings pi-lens no longer prints, and the persisted turn-end record stops re-serving them; a blocker the policy did not suppress, a file demoted by the freshness sweep, and a freshly dispatched blocker all keep gating exactly as before, and a marked file whose bytes change outside pi-lens blocks again as `blocker state is unknown` until a fresh check judges the new content, rather than committing on a verdict that no longer describes the file.
|
|
428
|
+
|
|
429
|
+
- **Apply stored dispositions at six more turn-end surfaces (refs #3248)** — knip's blocker and advisory, the dead-code advisory, the call-graph impact advisory, the late-runner drain and the code-quality warnings advisory now filter through the shared disposition/rule policy before rendering, so a finding marked `false-positive` stops re-reporting there; a mark that names no tool — the only spelling those surfaces' own text can carry — is honored too.
|
|
430
|
+
|
|
431
|
+
- **Two case-distinct workspaces no longer share one warm-IPC endpoint (closes #3255)**
|
|
432
|
+
— the per-workspace id behind the warm socket/pipe and the
|
|
433
|
+
`pi-lens-turn-end-*.json` status file lowercased the resolved cwd on every
|
|
434
|
+
platform, so on a case-sensitive filesystem `/repo/Alpha` and `/repo/alpha`
|
|
435
|
+
collided: a PostToolUse or Stop hook in one project could reach the other
|
|
436
|
+
project's warm server, and `pilens_health` reported one workspace's turn-end
|
|
437
|
+
activity under the other's name. The fold now runs only on the platforms
|
|
438
|
+
whose filesystem folds case (Windows, macOS), where it is what lets the
|
|
439
|
+
server and the hook meet. On Linux and the BSDs the id changes for any
|
|
440
|
+
workspace path containing an uppercase letter, so the upgrade is now
|
|
441
|
+
reported rather than silent: a warm endpoint with nothing listening is its
|
|
442
|
+
own skip reason (`no-listener`) instead of the generic `ipc-error`, the Stop
|
|
443
|
+
hook prints and records it for `pilens_health` with the remedy (an MCP
|
|
444
|
+
server that was already running owns the previous endpoint name — restart
|
|
445
|
+
it), and a warm-attached session records it once per session, now also shown
|
|
446
|
+
by `/lens-health`. A status file written before the upgrade is simply left
|
|
447
|
+
alone: it is no longer derived by anything, and on a case-sensitive host that
|
|
448
|
+
name can belong to a live case-variant sibling workspace.
|
|
449
|
+
|
|
450
|
+
- The finding-delivery governance detector no longer lets an arm-shaped
|
|
451
|
+
evidence read borrow a nearby, unrelated gate call; it now follows the
|
|
452
|
+
occurrence's binding chain, while preserving genuine inline gate results
|
|
453
|
+
and existing surface coverage (refs #3266).
|
|
454
|
+
|
|
455
|
+
- `--lens-guard` no longer blocks every `git commit` for the rest of a session
|
|
456
|
+
once pi-lens has reported a blocker. The commit gate validated its own
|
|
457
|
+
persisted blocker record one line at a time while both writers of that record
|
|
458
|
+
render multi-line blocker text, so from the first blocker onward every commit
|
|
459
|
+
was refused with `blocker state is unknown
|
|
460
|
+
(blocking_provenance_untrusted)` — including after the blocker was fixed, and
|
|
461
|
+
with no re-run able to clear it (#3282).
|
|
462
|
+
|
|
463
|
+
- **Restore strictness in the actionable-warnings advisory (refs #3248)** —
|
|
464
|
+
disposition identity fields that are absent from a warning are no longer
|
|
465
|
+
emitted as explicit `undefined` values, keeping the strict optional-property
|
|
466
|
+
ratchet at its existing floor.
|
|
467
|
+
|
|
468
|
+
- Runner parsers now attribute a diagnostic only when the tool-reported path
|
|
469
|
+
matches the dispatched file, resolved from the cwd the tool actually ran in:
|
|
470
|
+
taplo, yamllint, htmlhint, oxlint, shellcheck, trivy-config, stylelint,
|
|
471
|
+
rubocop, eslint, biome, tflint, swiftlint, ktlint, hadolint, actionlint,
|
|
472
|
+
typos, sqlfluff, vale, markdownlint, php -l, and the shared line-parser
|
|
473
|
+
factory behind ruff's text fallback. A second file's finding is no longer
|
|
474
|
+
delivered as the edited file's problem (refs #3295, #3278, #1193).
|
|
475
|
+
|
|
476
|
+
- Gate Terraform and Svelte tool-smoke fixtures with seeded diagnostics, correcting the Terraform defect seed and the Svelte diagnostic wait budget (refs #3311).
|
|
477
|
+
|
|
478
|
+
- Install `cmake-format` as `cmakelang[yaml]` so it can read a
|
|
479
|
+
`.cmake-format.yaml` project config instead of dying with
|
|
480
|
+
`ModuleNotFoundError: No module named 'yaml'`, force a pipx install that would
|
|
481
|
+
otherwise be a silent no-op over an existing venv, and keep a bounded,
|
|
482
|
+
banner-free formatter traceback tail for actionable failures (refs #3312).
|
|
483
|
+
|
|
484
|
+
- **Align shown-inline telemetry with deleted-path filtering (closes #3361)** — Retracted blockers are no longer recorded as shown to the agent.
|
|
485
|
+
|
|
486
|
+
- Make the hook-await exemption rekey script work on Node builds without built-in TypeScript support.
|
|
487
|
+
|
|
488
|
+
- **Nightly LSP docs refreshes now ignore date-only changes and never open refresh PRs from branch dispatches (closes #3380).**
|
|
489
|
+
|
|
490
|
+
- Bounded every remaining stream `data` handler that grew a string without a
|
|
491
|
+
ceiling (#3383): the forked analyze worker's pipes, the unref'd process-table
|
|
492
|
+
collector, the installer's two interpreter user-base probes, and all four
|
|
493
|
+
newline-framing readers (the MCP host's stdin loop, the warm IPC clients and
|
|
494
|
+
the shared server-side reader). A peer that never sends a newline, or a child
|
|
495
|
+
that never stops writing, now ends in a bounded failure with a ledger row
|
|
496
|
+
instead of an uncatchable `RangeError` raised inside the handler. The
|
|
497
|
+
self-signal re-raise at host shutdown is likewise total.
|
|
498
|
+
|
|
499
|
+
- Scope clean-signal probe publishes to the server measured by each row, and reset the vue capability-matrix row that had counted another server's publishes.
|
|
500
|
+
|
|
501
|
+
- Prevented the Elixir smoke row from reporting a fallback Expert handshake as ElixirLS success.
|
|
502
|
+
|
|
503
|
+
- Files over the shared LSP content bound now receive an explicit message from `lens_diagnostics` (`source=lsp`) instead of being synced in full.
|
|
504
|
+
|
|
505
|
+
- The installer now gives users the same jscpd 5.3.0 version used by pi-lens itself.
|
|
506
|
+
|
|
507
|
+
- Await in-flight jscpd scans before test fixture cleanup so deferred report-directory work cannot leave temporary roots behind.
|
|
508
|
+
|
|
509
|
+
- Await LSP workspace-diagnostics service shutdown before removing sweep test fixtures.
|
|
510
|
+
|
|
511
|
+
- Keep nightly fish runner provisioning resilient to distro package version bumps by installing the apt package unpinned.
|
|
512
|
+
|
|
513
|
+
- **Ignore abbreviations, versions, and file paths in the PR-body Why sentence check (refs #3262)** — The gate now recognizes sentence boundaries by following context instead of counting every terminator.
|
|
514
|
+
|
|
515
|
+
- The tool-smoke workflow's SonarCloud master-gate read now runs only on the nightly schedule and on master, so a branch dispatch no longer goes red on master's Sonar state; the advisory targeted-tests CI job installs lockfile-locked and script-free (refs #3319, #3346).
|
|
516
|
+
|
|
19
517
|
## [4.2.1] - 2026-09-17
|
|
20
518
|
|
|
21
519
|
### Added
|