@herbertgao/pi-extensions 2026.9.15 → 2026.9.17
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/@herbertgao/sol-pi/package.json +1 -1
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/extension.ts +11 -53
- 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 +9 -6
|
@@ -15,6 +15,21 @@ valid:
|
|
|
15
15
|
x()
|
|
16
16
|
except:
|
|
17
17
|
pass
|
|
18
|
+
- |
|
|
19
|
+
# #3211: body-only `or` must not be flagged — the handler condition
|
|
20
|
+
# itself is a plain exception type, only the return value uses `or`.
|
|
21
|
+
try:
|
|
22
|
+
x()
|
|
23
|
+
except Exception:
|
|
24
|
+
return 2 or 3
|
|
25
|
+
- |
|
|
26
|
+
# #3211: same shape one level deeper (an `if` inside the handler
|
|
27
|
+
# body) — still not a boolean-in-except-clause target.
|
|
28
|
+
try:
|
|
29
|
+
x()
|
|
30
|
+
except Exception:
|
|
31
|
+
if cond:
|
|
32
|
+
x = a or b
|
|
18
33
|
invalid:
|
|
19
34
|
- |
|
|
20
35
|
try:
|
|
@@ -26,3 +41,14 @@ invalid:
|
|
|
26
41
|
x()
|
|
27
42
|
except ValueError and KeyError:
|
|
28
43
|
pass
|
|
44
|
+
- |
|
|
45
|
+
# #3211: a nested try whose OWN except clause has the boolean
|
|
46
|
+
# condition must still be flagged, even though it sits inside an
|
|
47
|
+
# outer handler whose body also contains an `or`.
|
|
48
|
+
try:
|
|
49
|
+
outer()
|
|
50
|
+
except Exception:
|
|
51
|
+
try:
|
|
52
|
+
inner()
|
|
53
|
+
except (A or B):
|
|
54
|
+
return 3 or 4
|
package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-http-headers-bracket-access-test.yml
CHANGED
|
@@ -2,6 +2,16 @@ id: no-http-headers-bracket-access
|
|
|
2
2
|
valid:
|
|
3
3
|
- "auth = request.headers.get('Authorization')"
|
|
4
4
|
- "auth = request.headers.get('Authorization', '')"
|
|
5
|
+
- |
|
|
6
|
+
# #3211: a plain assignment through the bracket sets the header —
|
|
7
|
+
# it cannot raise KeyError, so it is not a read-site false positive.
|
|
8
|
+
resp.headers["X"] = "v"
|
|
9
|
+
- |
|
|
10
|
+
# #3211: augmented assignment is still a write, not a read.
|
|
11
|
+
resp.headers["X"] += "b"
|
|
12
|
+
- |
|
|
13
|
+
# #3211: `del` removes the key; it never raises KeyError either.
|
|
14
|
+
del resp.headers["Y"]
|
|
5
15
|
invalid:
|
|
6
16
|
- 'auth = request.headers["Authorization"]'
|
|
7
17
|
- 'auth = response.headers["X-Request-Id"]'
|
package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/unchecked-numeric-parse-python-test.yml
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
id: unchecked-numeric-parse-python
|
|
2
|
+
valid:
|
|
3
|
+
- |
|
|
4
|
+
# #3211: already-converted-by-construction — Decimal raises
|
|
5
|
+
# decimal.InvalidOperation, not ValueError, and is excluded here.
|
|
6
|
+
x = float(Decimal("1.5"))
|
|
7
|
+
- |
|
|
8
|
+
# #3211: a numeric literal argument can never raise ValueError.
|
|
9
|
+
x = int(3.7)
|
|
10
|
+
- |
|
|
11
|
+
try:
|
|
12
|
+
g = int(s)
|
|
13
|
+
except ValueError:
|
|
14
|
+
pass
|
|
15
|
+
invalid:
|
|
16
|
+
- 'int("42")'
|
|
17
|
+
- 'float("3.14")'
|
|
18
|
+
- 'int(user_input)'
|
package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/unchecked-throwing-call-python-test.yml
CHANGED
|
@@ -12,12 +12,13 @@ valid:
|
|
|
12
12
|
except OSError:
|
|
13
13
|
return None
|
|
14
14
|
- 'CONSTANT = 42'
|
|
15
|
+
- |
|
|
16
|
+
# #3211: int()/float() moved to unchecked-numeric-parse-python — this
|
|
17
|
+
# rule no longer fires on the numeric-parse shape.
|
|
18
|
+
x = int(s)
|
|
15
19
|
invalid:
|
|
16
20
|
- 'data = json.loads(raw)'
|
|
17
21
|
- 'f = open(path)'
|
|
18
22
|
- 'os.remove(path)'
|
|
19
23
|
- 'os.stat(path)'
|
|
20
24
|
- 'shutil.rmtree(path)'
|
|
21
|
-
- 'int("42")'
|
|
22
|
-
- 'float("3.14")'
|
|
23
|
-
- 'int(user_input)'
|
|
@@ -1,24 +1,34 @@
|
|
|
1
1
|
id: no-assert-tuple
|
|
2
2
|
language: Python
|
|
3
3
|
message: "Assert should not be called on a tuple literal"
|
|
4
|
-
severity:
|
|
4
|
+
severity: warning
|
|
5
5
|
note: |
|
|
6
6
|
Port of SonarCloud python:S5905.
|
|
7
7
|
|
|
8
8
|
`assert (a, b)` is always truthy because the tuple `(a, b)` is a
|
|
9
|
-
non-empty object.
|
|
10
|
-
|
|
11
|
-
`assert (a == b)`.
|
|
9
|
+
non-empty object. The developer probably meant `assert a, b` (an
|
|
10
|
+
assertion with a message) or `assert (a == b)`.
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
Bind the assertion's condition separately from its optional message,
|
|
13
|
+
then require that condition to be a tuple or a parentheses-only chain
|
|
14
|
+
ending in a tuple. Comparisons, calls, comprehensions, containers, and
|
|
15
|
+
tuple-valued assertion messages remain valid. The rule remains a
|
|
16
|
+
warning pending the multi-corpus false-positive audit required for
|
|
17
|
+
error severity.
|
|
17
18
|
metadata:
|
|
18
19
|
sonar: S5905
|
|
19
20
|
rule:
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
pattern: assert $COND
|
|
22
|
+
constraints:
|
|
23
|
+
COND:
|
|
24
|
+
any:
|
|
25
|
+
- kind: tuple
|
|
26
|
+
- all:
|
|
27
|
+
- kind: parenthesized_expression
|
|
28
|
+
- has:
|
|
29
|
+
kind: tuple
|
|
30
|
+
stopBy:
|
|
31
|
+
not:
|
|
32
|
+
any:
|
|
33
|
+
- kind: parenthesized_expression
|
|
34
|
+
- kind: tuple
|
|
@@ -11,8 +11,12 @@ note: |
|
|
|
11
11
|
developer meant `except (ValueError, KeyError):` (a tuple of
|
|
12
12
|
exception types).
|
|
13
13
|
|
|
14
|
-
Matches an `except_clause` whose
|
|
15
|
-
|
|
14
|
+
Matches an `except_clause` whose search for a `boolean_operator`
|
|
15
|
+
(and/or) descendant stops at the handler's own `block` — the
|
|
16
|
+
clause's condition, not anything inside the handler's body (a
|
|
17
|
+
`return x or y` or an `x = a or b` in the body is not a false
|
|
18
|
+
target; a nested `try`'s own `except` clause is checked on its
|
|
19
|
+
own merits when the walk reaches it).
|
|
16
20
|
metadata:
|
|
17
21
|
sonar: S5714
|
|
18
22
|
rule:
|
|
@@ -20,4 +24,4 @@ rule:
|
|
|
20
24
|
- kind: except_clause
|
|
21
25
|
- has:
|
|
22
26
|
kind: boolean_operator
|
|
23
|
-
stopBy:
|
|
27
|
+
stopBy: { kind: block }
|
|
@@ -11,8 +11,8 @@ note: |
|
|
|
11
11
|
just trains users to ignore the rule; `ignores` below carves those paths
|
|
12
12
|
out while application/library code elsewhere still gets flagged (#965).
|
|
13
13
|
ignores:
|
|
14
|
-
- "scripts/**"
|
|
15
|
-
- "bin/**"
|
|
14
|
+
- "**/scripts/**"
|
|
15
|
+
- "**/bin/**"
|
|
16
16
|
- "**/logger.ts"
|
|
17
17
|
- "**/logger.js"
|
|
18
18
|
- "**/logger.mjs"
|
|
@@ -11,8 +11,8 @@ note: |
|
|
|
11
11
|
just trains users to ignore the rule; `ignores` below carves those paths
|
|
12
12
|
out while application/library code elsewhere still gets flagged (#965).
|
|
13
13
|
ignores:
|
|
14
|
-
- "scripts/**"
|
|
15
|
-
- "bin/**"
|
|
14
|
+
- "**/scripts/**"
|
|
15
|
+
- "**/bin/**"
|
|
16
16
|
- "**/logger.ts"
|
|
17
17
|
- "**/logger.js"
|
|
18
18
|
- "**/logger.mjs"
|
|
@@ -9,14 +9,19 @@ note: |
|
|
|
9
9
|
missing. Use `request.headers.get("X-Foo")` (returns None) or
|
|
10
10
|
`request.headers["X-Foo"]` after a guard check.
|
|
11
11
|
|
|
12
|
-
Matches bracket-style subscript on a `headers` attribute
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
Matches bracket-style subscript READS on a `headers` attribute
|
|
13
|
+
(`$REQ.headers[$KEY]` already subsumes the `request.`/`response.`-
|
|
14
|
+
named forms). A write through the same bracket syntax —
|
|
15
|
+
`resp.headers["X"] = v`, `resp.headers["X"] += v`, or
|
|
16
|
+
`del resp.headers["X"]` — sets or removes the header and can never
|
|
17
|
+
raise KeyError, so those are excluded.
|
|
15
18
|
metadata:
|
|
16
19
|
sonar: S8371
|
|
17
20
|
rule:
|
|
18
|
-
|
|
21
|
+
all:
|
|
19
22
|
- pattern: "$REQ.headers[$KEY]"
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
- not:
|
|
24
|
+
any:
|
|
25
|
+
- inside: { kind: assignment, field: left }
|
|
26
|
+
- inside: { kind: augmented_assignment, field: left }
|
|
27
|
+
- inside: { kind: delete_statement }
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
id: unchecked-numeric-parse-python
|
|
2
|
+
language: Python
|
|
3
|
+
severity: warning
|
|
4
|
+
message: "int()/float() without try/except — raises ValueError on non-numeric input"
|
|
5
|
+
note: |
|
|
6
|
+
Split out of `unchecked-throwing-call-python` (#3211): `int()`/`float()`
|
|
7
|
+
raise `ValueError` on non-numeric strings, but whether a given call CAN
|
|
8
|
+
raise depends on the argument's runtime type — often undecidable from
|
|
9
|
+
syntax alone — so this ships at `warning`, separate from the
|
|
10
|
+
syntactically-certain `error`-level calls (open/json/os/shutil).
|
|
11
|
+
|
|
12
|
+
Excluded as already-safe by construction: a numeric literal argument
|
|
13
|
+
(`int(3.7)`), and an argument that is itself a call to `int()`/
|
|
14
|
+
`float()`/`Decimal()` (already-converted, or a `Decimal` — which raises
|
|
15
|
+
`decimal.InvalidOperation`, not `ValueError`, and is out of scope here).
|
|
16
|
+
|
|
17
|
+
Residual, undecidable false positive: a call whose argument is a typed
|
|
18
|
+
parameter already known to be numeric, e.g.
|
|
19
|
+
|
|
20
|
+
def f(valor: Decimal):
|
|
21
|
+
return float(valor) # valor is a Decimal, not a raw string
|
|
22
|
+
|
|
23
|
+
The rule cannot see the parameter's declared type from the call site.
|
|
24
|
+
Suppress that shape explicitly:
|
|
25
|
+
|
|
26
|
+
return float(valor) # pi-lens-ignore: unchecked-numeric-parse-python
|
|
27
|
+
rule:
|
|
28
|
+
any:
|
|
29
|
+
- pattern: int($EXPR)
|
|
30
|
+
- pattern: float($EXPR)
|
|
31
|
+
not:
|
|
32
|
+
any:
|
|
33
|
+
- inside:
|
|
34
|
+
stopBy: end
|
|
35
|
+
kind: try_statement
|
|
36
|
+
- has:
|
|
37
|
+
field: arguments
|
|
38
|
+
has:
|
|
39
|
+
any:
|
|
40
|
+
- kind: integer
|
|
41
|
+
- kind: float
|
|
42
|
+
- pattern: Decimal($$$)
|
|
43
|
+
- pattern: int($$$)
|
|
44
|
+
- pattern: float($$$)
|
|
@@ -9,7 +9,11 @@ note: |
|
|
|
9
9
|
json.loads(): raises json.JSONDecodeError on malformed JSON
|
|
10
10
|
os.stat(): raises FileNotFoundError, PermissionError
|
|
11
11
|
os.remove(): raises FileNotFoundError, PermissionError
|
|
12
|
-
|
|
12
|
+
|
|
13
|
+
`int()`/`float()` are a separate rule, `unchecked-numeric-parse-python`
|
|
14
|
+
(#3211): whether they can raise depends on the argument's runtime type,
|
|
15
|
+
which is often undecidable from syntax alone (a typed parameter, a prior
|
|
16
|
+
guard), so they ship at `warning` instead of `error` here.
|
|
13
17
|
|
|
14
18
|
✅ WRAP IN TRY/EXCEPT:
|
|
15
19
|
try:
|
|
@@ -40,8 +44,6 @@ rule:
|
|
|
40
44
|
- pattern: shutil.copy($$$)
|
|
41
45
|
- pattern: shutil.move($$$)
|
|
42
46
|
- pattern: shutil.rmtree($$$)
|
|
43
|
-
- pattern: int($EXPR)
|
|
44
|
-
- pattern: float($EXPR)
|
|
45
47
|
not:
|
|
46
48
|
inside:
|
|
47
49
|
stopBy: end
|
|
@@ -29,8 +29,8 @@ post_filter: not_in_test_block # skip test blocks — no-console-in-tests handl
|
|
|
29
29
|
# trains users to ignore the rule (#965). Application/library code outside
|
|
30
30
|
# these paths still gets flagged.
|
|
31
31
|
ignore_paths:
|
|
32
|
-
- "scripts/**"
|
|
33
|
-
- "bin/**"
|
|
32
|
+
- "**/scripts/**"
|
|
33
|
+
- "**/bin/**"
|
|
34
34
|
- "**/logger.ts"
|
|
35
35
|
- "**/logger.js"
|
|
36
36
|
- "**/logger.mjs"
|
|
@@ -50,6 +50,7 @@ import * as path from "node:path";
|
|
|
50
50
|
import { fileURLToPath } from "node:url";
|
|
51
51
|
import { HOST_PROVIDED_PACKAGES } from "./lib/host-provided-deps.mjs";
|
|
52
52
|
import { collectSkillEntryPaths } from "./lib/skills-predicate.mjs";
|
|
53
|
+
import { resolveWebTreeSitterPackageDir } from "./lib/web-tree-sitter-dir.mjs";
|
|
53
54
|
|
|
54
55
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
55
56
|
const pkgRoot = path.resolve(here, "..");
|
|
@@ -220,28 +221,31 @@ try {
|
|
|
220
221
|
}
|
|
221
222
|
|
|
222
223
|
// tree-sitter grammars — download-grammars.js postinstall writes them into
|
|
223
|
-
// node_modules/web-tree-sitter/grammars/. Locate that dir
|
|
224
|
-
//
|
|
224
|
+
// node_modules/web-tree-sitter/grammars/. Locate that dir through the SAME
|
|
225
|
+
// shared ladder the extension runtime uses (#3409 round 1, R3418-2): this probe
|
|
226
|
+
// used to resolve the BARE `web-tree-sitter` specifier and walk up, which throws
|
|
227
|
+
// MODULE_NOT_FOUND inside a `bun build --compile` host — so on the very hosts pi
|
|
228
|
+
// ships as, it reported the grammar asset missing while the exported wasm
|
|
229
|
+
// subpath resolved fine. One ladder, one answer, for the client, the pasted
|
|
230
|
+
// install fingerprint and this script.
|
|
225
231
|
let grammarDetail = "tree-sitter-*.wasm missing (postinstall skipped?)";
|
|
226
232
|
let hasCoreGrammar = false;
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
dir
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
}
|
|
238
|
-
const grammarDir = path.join(dir, "grammars");
|
|
233
|
+
const webTreeSitterDir = resolveWebTreeSitterPackageDir({
|
|
234
|
+
resolve: (specifier) => require.resolve(specifier),
|
|
235
|
+
packageRoot: () => pkgRoot,
|
|
236
|
+
cwd: () => process.cwd(),
|
|
237
|
+
});
|
|
238
|
+
if (!webTreeSitterDir) {
|
|
239
|
+
grammarDetail =
|
|
240
|
+
"web-tree-sitter package dir unresolvable (module resolver, package root and cwd)";
|
|
241
|
+
} else {
|
|
242
|
+
const grammarDir = path.join(webTreeSitterDir, "grammars");
|
|
239
243
|
hasCoreGrammar = fs.existsSync(
|
|
240
244
|
path.join(grammarDir, "tree-sitter-typescript.wasm"),
|
|
241
245
|
);
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
246
|
+
grammarDetail = hasCoreGrammar
|
|
247
|
+
? grammarDir
|
|
248
|
+
: `tree-sitter-*.wasm missing in ${grammarDir} (postinstall skipped?)`;
|
|
245
249
|
}
|
|
246
250
|
record("tree-sitter grammars", "asset", hasCoreGrammar, grammarDetail);
|
|
247
251
|
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where web-tree-sitter is installed — ONE ladder, for every caller that needs
|
|
3
|
+
* the answer (#3409).
|
|
4
|
+
*
|
|
5
|
+
* Callers: `clients/tree-sitter-client.ts` (the grammar read path and the
|
|
6
|
+
* lazy-fetch write target), `clients/install-diagnostics.ts` (the pasted
|
|
7
|
+
* environment fingerprint) and `scripts/install-selftest.mjs` (the installed
|
|
8
|
+
* host's own diagnostic). Each used to spell its own rungs, and the two that led
|
|
9
|
+
* with a BARE specifier were unconditionally broken on the host pi ships: inside
|
|
10
|
+
* a `bun build --compile` binary `require.resolve("web-tree-sitter")` throws
|
|
11
|
+
* MODULE_NOT_FOUND while `require.resolve("web-tree-sitter/tree-sitter.wasm")` —
|
|
12
|
+
* an explicit file subpath — still resolves.
|
|
13
|
+
*
|
|
14
|
+
* It lives in `scripts/lib/` rather than `clients/` because the installed
|
|
15
|
+
* selftest is packaged (`files[]`) without `clients/`, and this is the house
|
|
16
|
+
* pattern for logic a packaged .mjs script and the TypeScript runtime share
|
|
17
|
+
* (`scripts/lib/skills-predicate.mjs`, `scripts/lib/process-scan.mjs`). It
|
|
18
|
+
* imports nothing but `node:fs` and `node:path`, so it loads even on the hosts
|
|
19
|
+
* whose broken dependency graph the selftest exists to report.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import * as fs from "node:fs";
|
|
23
|
+
import * as path from "node:path";
|
|
24
|
+
|
|
25
|
+
/** The package this module is about. Also the name its manifest must carry. */
|
|
26
|
+
const WEB_TREE_SITTER = "web-tree-sitter";
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The wasm the runtime loads, at the package root — where 0.25.10's `exports`
|
|
30
|
+
* map puts it (`"./tree-sitter.wasm": "./tree-sitter.wasm"`). If a later release
|
|
31
|
+
* moves it (#381's 0.26 migration), the two FALLBACK rungs below stop matching
|
|
32
|
+
* and the resolver rungs, which ask Node for that same subpath, keep working;
|
|
33
|
+
* this constant is then the one line to update.
|
|
34
|
+
*/
|
|
35
|
+
const RUNTIME_WASM = "tree-sitter.wasm";
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* True when `dir` IS an installed web-tree-sitter package: its own manifest
|
|
39
|
+
* names it, and the wasm the runtime loads is in it.
|
|
40
|
+
*
|
|
41
|
+
* Round 1 review of #3409 (R3418-1): the constructed rungs used to accept any
|
|
42
|
+
* directory that merely EXISTED at `<base>/node_modules/web-tree-sitter`, so an
|
|
43
|
+
* empty or foreign directory of that name became the runtime fetch's write
|
|
44
|
+
* target and a downloaded grammar would land in an unrelated tree. Existence is
|
|
45
|
+
* not identity. The manifest name is the identity; the wasm is what makes the
|
|
46
|
+
* directory the right place to put grammars, since a grammar is only loadable by
|
|
47
|
+
* the web-tree-sitter runtime sitting next to it (the ABI drift #1564 is about).
|
|
48
|
+
*/
|
|
49
|
+
export function isWebTreeSitterPackageDir(dir) {
|
|
50
|
+
try {
|
|
51
|
+
if (!fs.existsSync(path.join(dir, RUNTIME_WASM))) return false;
|
|
52
|
+
const manifest = JSON.parse(
|
|
53
|
+
fs.readFileSync(path.join(dir, "package.json"), "utf8"),
|
|
54
|
+
);
|
|
55
|
+
return manifest?.name === WEB_TREE_SITTER;
|
|
56
|
+
} catch {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* The package directory owning `resolvedFile`: walk up until a directory passes
|
|
63
|
+
* the identity check, or the filesystem root is reached. The walk exists because
|
|
64
|
+
* an `exports` map may point into a subdirectory, so the file's own parent is
|
|
65
|
+
* not necessarily the package; the identity check is what stops the walk, so a
|
|
66
|
+
* resolver that answers outside any web-tree-sitter package yields nothing
|
|
67
|
+
* rather than an unrelated ancestor.
|
|
68
|
+
*/
|
|
69
|
+
function packageDirOf(resolvedFile) {
|
|
70
|
+
let dir = path.dirname(resolvedFile);
|
|
71
|
+
for (;;) {
|
|
72
|
+
if (isWebTreeSitterPackageDir(dir)) return dir;
|
|
73
|
+
const parent = path.dirname(dir);
|
|
74
|
+
if (parent === dir) return undefined;
|
|
75
|
+
dir = parent;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* web-tree-sitter's installed package directory, or undefined.
|
|
81
|
+
*
|
|
82
|
+
* Rung order, most authoritative first:
|
|
83
|
+
* 1. the `tree-sitter.wasm` SUBPATH, which resolves on a compiled host as well
|
|
84
|
+
* as a plain one. This is the rung that makes the non-core grammars
|
|
85
|
+
* fetchable there at all.
|
|
86
|
+
* 2. the BARE specifier, for a future web-tree-sitter whose exports map no
|
|
87
|
+
* longer carries `./tree-sitter.wasm`.
|
|
88
|
+
* 3. pi-lens's own package root, for the temp-dir compile layout (#20) where
|
|
89
|
+
* the resolver's context is a temp directory but the package root still has
|
|
90
|
+
* the right `node_modules`.
|
|
91
|
+
* 4. the working directory, the pre-#3409 last resort.
|
|
92
|
+
*
|
|
93
|
+
* Rungs 1-2 are the resolver's answer and outrank the constructed guesses: the
|
|
94
|
+
* grammars must come from the SAME package whose wasm the runtime loaded. Every
|
|
95
|
+
* rung's candidate passes `isWebTreeSitterPackageDir` before it is returned.
|
|
96
|
+
*
|
|
97
|
+
* `resolve`, `packageRoot` and `cwd` are injected, never defaulted: the caller's
|
|
98
|
+
* resolver context and package root are what differ on a compiled host, so they
|
|
99
|
+
* must not be silently replaced by this module's — and a rung nothing can vary
|
|
100
|
+
* is a rung no test can drive.
|
|
101
|
+
*/
|
|
102
|
+
export function resolveWebTreeSitterPackageDir(deps) {
|
|
103
|
+
for (const specifier of [
|
|
104
|
+
`${WEB_TREE_SITTER}/${RUNTIME_WASM}`,
|
|
105
|
+
WEB_TREE_SITTER,
|
|
106
|
+
]) {
|
|
107
|
+
try {
|
|
108
|
+
const dir = packageDirOf(deps.resolve(specifier));
|
|
109
|
+
if (dir) return dir;
|
|
110
|
+
} catch {
|
|
111
|
+
/* next rung */
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
for (const base of [deps.packageRoot, deps.cwd]) {
|
|
115
|
+
try {
|
|
116
|
+
const candidate = path.join(base(), "node_modules", WEB_TREE_SITTER);
|
|
117
|
+
if (isWebTreeSitterPackageDir(candidate)) return candidate;
|
|
118
|
+
} catch {
|
|
119
|
+
/* next rung */
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return undefined;
|
|
123
|
+
}
|
|
@@ -7,6 +7,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.38.0] - 2026-09-26
|
|
11
|
+
|
|
12
|
+
### Highlights
|
|
13
|
+
|
|
14
|
+
- Search-mode tools become full direct tools after a successful proxy call, without requiring a separate search first.
|
|
15
|
+
- Runtime-registered keep-alive servers now publish their tools even when Pi starts with no enabled MCP servers.
|
|
16
|
+
- Compact `mcpScript` results show which tools ran, how often they ran, and how many calls failed.
|
|
17
|
+
- Stdio configurations support home-relative paths, and MCP UI windows can open in Orca.
|
|
18
|
+
- OpenCode v2 imports, OAuth credential access, and Rust MCP schemas are more reliable.
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- A successful `mcp({ tool })` call now activates a held `directTools: "search"` tool, so later calls use its full schema even if the model skipped search. Thanks to [@chiptoe-svg](https://github.com/chiptoe-svg) for [PR #670](https://github.com/nicobailon/pi-mcp-adapter/pull/670).
|
|
23
|
+
- MCP stdio server commands, arguments, and working directories now support home-relative paths. Thanks to [@FRFlo](https://github.com/FRFlo) for [PR #655](https://github.com/nicobailon/pi-mcp-adapter/pull/655).
|
|
24
|
+
- Set `MCP_UI_VIEWER=orca` to open MCP UI windows in Orca. Thanks to [@jaesimio](https://github.com/jaesimio) for [PR #654](https://github.com/nicobailon/pi-mcp-adapter/pull/654).
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- Keep-alive servers registered at runtime now connect and publish their tools even when no configured servers are enabled at startup. Thanks to [@ahodges22](https://github.com/ahodges22) for [issue #671](https://github.com/nicobailon/pi-mcp-adapter/issues/671).
|
|
29
|
+
- Valid `ancestorConfigRoots` entries that do not contain the current working directory are ignored without warnings. Invalid entries still warn. Thanks to [@TheEdgeOfRage](https://github.com/TheEdgeOfRage) for [issue #668](https://github.com/nicobailon/pi-mcp-adapter/issues/668) and [PR #669](https://github.com/nicobailon/pi-mcp-adapter/pull/669).
|
|
30
|
+
- Collapsed `mcpScript` results now show the tools called, repeat counts, and a visible failure count instead of only the first output line. Unsafe or ambiguous tool names are quoted and escaped, and script code remains hidden. Thanks to [@sargismarkosyan](https://github.com/sargismarkosyan) for [PR #666](https://github.com/nicobailon/pi-mcp-adapter/pull/666).
|
|
31
|
+
- Metadata refreshes no longer reactivate an `mcp` gateway tool removed by the host. On hosts without `unregisterTool`, the adapter can still hide the gateway when direct tools cover the server and restore it when needed. Thanks to [@xulongwu4](https://github.com/xulongwu4) for [PR #665](https://github.com/nicobailon/pi-mcp-adapter/pull/665).
|
|
32
|
+
- `mcpScript` no longer asks models to load its intentionally hidden manual skill. Thanks to [@k03mad](https://github.com/k03mad) for [#659](https://github.com/nicobailon/pi-mcp-adapter/issues/659).
|
|
33
|
+
- OAuth credential reads now reuse a healthy keyring Entry without retaining secret values, avoiding repeated native sessions while still observing external updates. Thanks to [@mmarabel](https://github.com/mmarabel) for [#657](https://github.com/nicobailon/pi-mcp-adapter/issues/657).
|
|
34
|
+
- Suppressing MCP UI windows with `MCP_UI_VIEWER=none` / `off` / `disabled` no longer prints raw output into the TUI. Thanks to [@andreafspeziale](https://github.com/andreafspeziale) for [#656](https://github.com/nicobailon/pi-mcp-adapter/issues/656).
|
|
35
|
+
- The published package now includes the OAuth guide linked from the README. Thanks to [@dajiaohuang](https://github.com/dajiaohuang) for [PR #653](https://github.com/nicobailon/pi-mcp-adapter/pull/653).
|
|
36
|
+
- OpenCode v2 configs now import. Servers under `mcp.servers` are picked up, `disabled: true` servers are skipped, and the snake_case OAuth fields `client_id`, `client_secret`, and `auth_server_metadata_url` are mapped. OpenCode v1 configs keep working. Thanks to [@sleroq](https://github.com/sleroq) for [PR #650](https://github.com/nicobailon/pi-mcp-adapter/pull/650).
|
|
37
|
+
- Tools from Rust MCP servers, such as DBX, no longer print Ajv `unknown format "uint64" ignored` warnings on every call. Number formats like `uint64`, `uint32`, `uint`, and `uint8` are now recognized, and `type`/`minimum` still validate the values. Thanks to [@nightlitten](https://github.com/nightlitten) for [#649](https://github.com/nicobailon/pi-mcp-adapter/issues/649).
|
|
38
|
+
|
|
10
39
|
## [2.37.0] - 2026-09-23
|
|
11
40
|
|
|
12
41
|
### Highlights
|