@selfagency/beans-mcp 0.1.3 → 0.1.4

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.
Files changed (58) hide show
  1. package/{dist/beans-mcp-server.cjs → beans-mcp-server.cjs} +2 -1
  2. package/{dist/index.cjs → index.cjs} +2 -1
  3. package/{dist/index.js → index.js} +2 -1
  4. package/package.json +28 -64
  5. package/.beans.yml +0 -6
  6. package/.claude/settings.local.json +0 -18
  7. package/.editorconfig +0 -13
  8. package/.github/dependabot.yml +0 -11
  9. package/.github/workflows/release.yml +0 -235
  10. package/.github/workflows/test.yml +0 -84
  11. package/.husky/pre-commit +0 -1
  12. package/.nvmrc +0 -1
  13. package/.oxfmtrc.json +0 -11
  14. package/.oxlintrc.json +0 -37
  15. package/.vscode/settings.json +0 -3
  16. package/CHANGELOG.md +0 -160
  17. package/CONTRIBUTING.md +0 -139
  18. package/LICENSE.txt +0 -21
  19. package/codeql/codeql-custom-queries-actions/README.md +0 -14
  20. package/codeql/codeql-custom-queries-actions/codeql-pack.lock.yml +0 -32
  21. package/codeql/codeql-custom-queries-actions/codeql-pack.yml +0 -7
  22. package/codeql/codeql-custom-queries-actions/qlpack.yml +0 -6
  23. package/codeql/codeql-custom-queries-actions/queries/github-script-without-tojson.ql +0 -18
  24. package/codeql/codeql-custom-queries-actions/queries/strict-external-action-pinning.ql +0 -18
  25. package/codeql/codeql-custom-queries-javascript/README.md +0 -14
  26. package/codeql/codeql-custom-queries-javascript/codeql-pack.lock.yml +0 -30
  27. package/codeql/codeql-custom-queries-javascript/codeql-pack.yml +0 -7
  28. package/codeql/codeql-custom-queries-javascript/qlpack.yml +0 -6
  29. package/codeql/codeql-custom-queries-javascript/queries/child-process-shell-apis.ql +0 -26
  30. package/codeql/codeql-custom-queries-javascript/queries/innerhtml-assignment.ql +0 -24
  31. package/dist/README.md +0 -307
  32. package/dist/beans-mcp-server.cjs.map +0 -1
  33. package/dist/index.cjs.map +0 -1
  34. package/dist/index.js.map +0 -1
  35. package/dist/package.json +0 -43
  36. package/pnpm-workspace.yaml +0 -2
  37. package/scripts/release.js +0 -433
  38. package/scripts/write-dist-package.js +0 -53
  39. package/src/cli.ts +0 -14
  40. package/src/index.ts +0 -21
  41. package/src/internal/graphql.ts +0 -33
  42. package/src/internal/queryHelpers.ts +0 -157
  43. package/src/server/BeansMcpServer.ts +0 -623
  44. package/src/server/backend.ts +0 -364
  45. package/src/test/BeansMcpServer.test.ts +0 -514
  46. package/src/test/handlers.unit.test.ts +0 -201
  47. package/src/test/parseCliArgs.test.ts +0 -69
  48. package/src/test/protocol.e2e.test.ts +0 -884
  49. package/src/test/queryHelpers.test.ts +0 -524
  50. package/src/test/startBeansMcpServer.test.ts +0 -146
  51. package/src/test/tools-integration.test.ts +0 -912
  52. package/src/test/utils.test.ts +0 -81
  53. package/src/types.ts +0 -46
  54. package/src/utils.ts +0 -20
  55. package/tsconfig.json +0 -24
  56. package/tsup.config.ts +0 -42
  57. package/vitest.config.ts +0 -18
  58. /package/{dist/index.d.ts → index.d.ts} +0 -0
package/CHANGELOG.md DELETED
@@ -1,160 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to this project will be documented in this file.
4
-
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
-
8
- ## [Unreleased]
9
-
10
- ## [0.1.3] - 2026-02-27
11
-
12
- **Full Changelog**: https://github.com/selfagency/beans-mcp/compare/v0.1.2...v0.1.3
13
-
14
- _Source: changes from v0.1.2 to v0.1.3._
15
-
16
-
17
- ## [0.1.2] - 2026-02-27
18
-
19
- ## What's Changed
20
- * feat: support body updates and de-duplicate MCP results by @selfagency in https://github.com/selfagency/beans-mcp/pull/1
21
-
22
- ## New Contributors
23
- * @selfagency made their first contribution in https://github.com/selfagency/beans-mcp/pull/1
24
-
25
- **Full Changelog**: https://github.com/selfagency/beans-mcp/compare/v0.1.1...v0.1.2
26
-
27
- _Source: changes from v0.1.1 to v0.1.2._
28
-
29
-
30
- ## [0.1.1] - 2026-02-25
31
-
32
- **Full Changelog**: https://github.com/selfagency/beans-mcp/compare/v0.1.0...v0.1.1
33
-
34
- _Source: changes from v0.1.0 to v0.1.1._
35
-
36
-
37
- ## [0.1.0] - 2026-02-25
38
-
39
- **Full Changelog**: https://github.com/selfagency/beans-mcp/commits/v0.1.0
40
-
41
-
42
- Initial public release. Extracted and substantially reworked from the
43
- [selfagency.beans-vscode](https://marketplace.visualstudio.com/items?itemName=selfagency.beans-vscode)
44
- VS Code extension's embedded MCP server into a standalone, independently
45
- installable package.
46
-
47
- ### Added
48
-
49
- #### MCP Tools
50
-
51
- All 14 Beans MCP tools are implemented and registered:
52
-
53
- - `beans_init` — Initialize the workspace (optional prefix).
54
- - `beans_list` — List beans with filtering by status, type, tags, and search.
55
- - `beans_view` — View a single bean by ID.
56
- - `beans_create` — Create a new bean.
57
- - `beans_update` / `beans_edit` — Update an existing bean (aliases).
58
- - `beans_reopen` — Reopen a completed or scrapped bean.
59
- - `beans_delete` — Delete a draft or scrapped bean.
60
- - `beans_set_status` — Set a bean's status directly.
61
- - `beans_query` — Run llm_context, refresh, and workspace-instructions operations.
62
- - `beans_bean_file` — Read, edit, create, or delete raw bean markdown files.
63
- - `beans_output` — Read the Beans CLI output log.
64
- - `beans_open_config` — Return the workspace config file path and content.
65
- - `beans_graphql_schema` — Return the Beans GraphQL schema.
66
-
67
- #### Public API
68
-
69
- - `createBeansMcpServer(opts)` — Programmatic factory for embedding a Beans
70
- MCP server in other applications; accepts an optional `backend` parameter
71
- for dependency injection.
72
- - `startBeansMcpServer(argv)` — CLI entrypoint; launches the server with a
73
- `StdioServerTransport`.
74
- - `parseCliArgs(argv)` — Parse and validate CLI arguments; returns a
75
- `workspaceExplicit` flag so callers can distinguish user-supplied roots from
76
- the cwd default.
77
- - `BeansCliBackend` — Concrete backend that shells out to the `beans` CLI.
78
- - `BackendInterface` — Interface for custom backend implementations.
79
- - `MutableBackend` — Thin delegation wrapper whose inner backend can be
80
- hot-swapped after MCP roots discovery without re-registering tools.
81
- - `resolveWorkspaceFromRoots(server)` — Queries the connected client's
82
- declared MCP roots and returns the first `file://` path as a local workspace
83
- path, or `null` if none are declared.
84
- - `sortBeans`, `isPathWithinRoot`, `makeTextAndStructured` — Utility helpers.
85
-
86
- #### Workspace Resolution
87
-
88
- The server resolves its workspace in priority order:
89
-
90
- 1. `--workspace-root` / positional CLI argument (explicit)
91
- 2. MCP roots declared by the connected client (`roots/list`)
92
- 3. `process.cwd()` (fallback)
93
-
94
- This enables using the server without CLI arguments: AI clients that declare
95
- MCP roots (e.g. Cursor, Claude Desktop) automatically provide the workspace
96
- path after connecting.
97
-
98
- #### CLI
99
-
100
- - `beans-mcp` binary accepts:
101
- - Positional or `--workspace-root` for the workspace path.
102
- - `--cli-path` — path to the `beans` executable (default: `beans`).
103
- - `--port` — MCP server port (default: 39173).
104
- - `--log-dir` — log directory (defaults to workspace root).
105
- - `-h` / `--help` — print usage and exit.
106
-
107
- #### Build
108
-
109
- - Multi-config `tsup.config.ts` produces three outputs:
110
- - ESM library (`dist/index.js` + `dist/index.d.ts`)
111
- - CJS library (`dist/index.cjs`)
112
- - CJS CLI binary (`dist/beans-mcp-server.cjs`) with `#!/usr/bin/env node` shebang
113
- - All CJS configs use `target: 'node18'`, `splitting: false`, `cjsInterop: true`.
114
- - `postbuild` script writes a trimmed `dist/package.json` with correct `bin`,
115
- `exports`, `main`, `module`, and `types` fields.
116
-
117
- #### Tests
118
-
119
- - **Protocol E2E tests** (`src/test/protocol.e2e.test.ts`) — 52 tests using
120
- `InMemoryTransport` + MCP `Client` to exercise the full JSON-RPC wire format,
121
- Zod input validation, backend error surfacing as `{ isError: true }` tool
122
- results, and the MCP roots protocol.
123
- - **`startBeansMcpServer` integration tests** (`src/test/startBeansMcpServer.test.ts`)
124
- — mocked dynamic imports for `BeansCliBackend` and `StdioServerTransport`.
125
- - Handler unit tests — exported handler factories tested in isolation.
126
- - `MutableBackend` unit tests — delegation and `setInner` swap behaviour.
127
- - `resolveWorkspaceFromRoots` unit tests — all branches (found, skipped,
128
- empty list, throws).
129
- - `parseCliArgs` tests — `workspaceExplicit` flag, `--help`/`-h` output and
130
- exit code.
131
- - Statement and function coverage: **100%** for `BeansMcpServer.ts`.
132
-
133
- #### CI
134
-
135
- - GitHub Actions workflow runs lint, type-check, build, and test on Node 18
136
- and 22 across Ubuntu and macOS.
137
- - pnpm store cache keyed on lockfile hash with `~/.pnpm-store` fallback.
138
-
139
- ### Changed
140
-
141
- - Tool IDs renamed to remove the `_vscode` suffix carried over from the
142
- extension (e.g. `beans_init_vscode` → `beans_init`).
143
- - `--log-dir` now defaults to the workspace root when omitted.
144
- - `cli.ts` simplified: removed the `isMainModule` guard; always invokes
145
- `startBeansMcpServer`.
146
- - Bin command renamed from `beans-mcp-server` to `beans-mcp`.
147
-
148
- ### Fixed
149
-
150
- - Build script was overriding `tsup.config.ts` with inline CLI flags, causing
151
- the CLI binary to never be produced. Fixed by setting `"build": "tsup"`.
152
- - `package.json` exports paths corrected to include the `dist/` prefix.
153
- - Eliminated all `any` types: `queryHandler` opts, `backend.ts` filter
154
- parameter, and `queryHelpers.ts` return type narrowed to
155
- `Record<string, unknown>`.
156
- - README: corrected package import name (`@selfagency/beans-mcp`), server
157
- default name (`beans-mcp-server`), removed the non-existent `allowedRoots`
158
- option from the `createBeansMcpServer` docs.
159
-
160
- [Unreleased]: https://github.com/selfagency/beans-mcp/compare/v0.1.0...HEAD
package/CONTRIBUTING.md DELETED
@@ -1,139 +0,0 @@
1
- # Contributing to beans-mcp-server
2
-
3
- Thank you for your interest in contributing to the Beans MCP server! This document provides guidelines and instructions for contributing.
4
-
5
- ## Development Setup
6
-
7
- ### Prerequisites
8
-
9
- - Node.js 18+
10
- - pnpm 9+
11
- - Beans CLI installed and in PATH (or specify via `--cli-path`)
12
-
13
- ### Getting Started
14
-
15
- 1. Clone the repository
16
- 2. Install dependencies:
17
-
18
- ```bash
19
- pnpm install
20
- ```
21
-
22
- 3. Build the project:
23
-
24
- ```bash
25
- pnpm build
26
- ```
27
-
28
- 4. Run tests:
29
-
30
- ```bash
31
- pnpm test
32
- ```
33
-
34
- ## Development Workflow
35
-
36
- ### Running Tests
37
-
38
- ```bash
39
- # Run all tests
40
- pnpm test
41
-
42
- # Run specific test file
43
- pnpm test src/test/utils.test.ts
44
-
45
- # Run with coverage
46
- pnpm test --coverage
47
- ```
48
-
49
- ### Building
50
-
51
- The project uses `tsup` for bundling:
52
-
53
- ```bash
54
- # Build all formats (ESM, CJS, CLI)
55
- pnpm build
56
-
57
- # Watch mode (development)
58
- pnpm build --watch
59
- ```
60
-
61
- Build outputs:
62
-
63
- - `dist/index.js` - ESM entry point
64
- - `dist/index.cjs` - CommonJS entry point
65
- - `dist/beans-mcp-server.cjs` - CLI executable (with shebang)
66
- - `dist/index.d.ts` - TypeScript type definitions
67
-
68
- ### Code Style
69
-
70
- - Use TypeScript for all source code
71
- - Format with Prettier (configured in project)
72
- - Lint with ESLint
73
- - Follow existing patterns in the codebase
74
-
75
- ### Testing Requirements
76
-
77
- - All changes should include tests
78
- - Use Vitest for unit tests
79
- - Tests should use Arrange-Act-Assert pattern
80
- - Aim for high test coverage
81
-
82
- ## Architecture
83
-
84
- ### Project Structure
85
-
86
- ```text
87
- src/
88
- ├── index.ts # Public API exports
89
- ├── cli.ts # CLI entry point
90
- ├── types.ts # TypeScript types and constants
91
- ├── utils.ts # Utility functions
92
- ├── server/
93
- │ ├── BeansMcpServer.ts # Main MCP server implementation
94
- │ └── backend.ts # Backend interface and Beans CLI backend
95
- ├── internal/
96
- │ ├── graphql.ts # GraphQL queries/mutations
97
- │ └── queryHelpers.ts # Query and sorting utilities
98
- └── test/
99
- ├── utils.test.ts
100
- └── parseCliArgs.test.ts
101
- ```
102
-
103
- ### Key Modules
104
-
105
- - **BeansMcpServer.ts**: Main server class that manages MCP tools and backend interaction
106
- - **backend.ts**: Interface for backend implementations; includes BeansCliBackend that wraps Beans CLI
107
- - **graphql.ts**: GraphQL queries and mutations for bean operations
108
- - **queryHelpers.ts**: Sorting, filtering, and query handling utilities
109
-
110
- ## Submitting Changes
111
-
112
- 1. Create a feature branch from `main`
113
- 2. Make your changes with clear, atomic commits
114
- 3. Add or update tests as needed
115
- 4. Run `pnpm test` to ensure all tests pass
116
- 5. Run `pnpm build` to verify the build succeeds
117
- 6. Submit a pull request with a clear description
118
-
119
- ## Pull Request Guidelines
120
-
121
- - Include a clear description of what changed and why
122
- - Reference any related issues
123
- - Ensure all tests pass
124
- - Update documentation if needed
125
- - Keep commits focused and atomic
126
-
127
- ## Reporting Issues
128
-
129
- When reporting bugs, please include:
130
-
131
- - Steps to reproduce
132
- - Expected behavior
133
- - Actual behavior
134
- - Node.js and pnpm versions
135
- - Relevant error messages or logs
136
-
137
- ## License
138
-
139
- By contributing, you agree that your contributions will be licensed under the MIT License.
package/LICENSE.txt DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 The Self Agency, LLC
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
@@ -1,14 +0,0 @@
1
- # Custom CodeQL Queries (GitHub Actions)
2
-
3
- This pack adds repository-specific hardening checks for workflow security.
4
-
5
- ## Queries
6
-
7
- - `queries/strict-external-action-pinning.ql`
8
- - Flags external `uses:` steps that are not pinned to a full 40-character commit SHA.
9
- - `queries/github-script-without-tojson.ql`
10
- - Flags `actions/github-script` steps whose `script` argument does not appear to use `toJson(...)`.
11
-
12
- ## Why these checks
13
-
14
- These checks focus on practical workflow hardening against supply-chain and interpolation risks while keeping alerts actionable.
@@ -1,32 +0,0 @@
1
- ---
2
- lockVersion: 1.0.0
3
- dependencies:
4
- codeql/actions-all:
5
- version: 0.4.27
6
- codeql/concepts:
7
- version: 0.0.15
8
- codeql/controlflow:
9
- version: 2.0.25
10
- codeql/dataflow:
11
- version: 2.0.25
12
- codeql/javascript-all:
13
- version: 2.6.21
14
- codeql/mad:
15
- version: 1.0.41
16
- codeql/regex:
17
- version: 1.0.41
18
- codeql/ssa:
19
- version: 2.0.17
20
- codeql/threat-models:
21
- version: 1.0.41
22
- codeql/tutorial:
23
- version: 1.0.41
24
- codeql/typetracking:
25
- version: 2.0.25
26
- codeql/util:
27
- version: 2.0.28
28
- codeql/xml:
29
- version: 1.0.41
30
- codeql/yaml:
31
- version: 1.0.41
32
- compiled: false
@@ -1,7 +0,0 @@
1
- ---
2
- library: false
3
- warnOnImplicitThis: false
4
- name: getting-started/codeql-extra-queries-actions
5
- version: 1.0.0
6
- dependencies:
7
- codeql/actions-all: ^0.4.27
@@ -1,6 +0,0 @@
1
- library: false
2
- warnOnImplicitThis: false
3
- name: selfagency/beans-vscode-codeql-extra-queries-actions
4
- version: 1.0.0
5
- dependencies:
6
- codeql/actions-all: ^0.4.27
@@ -1,18 +0,0 @@
1
- /**
2
- * @name github-script step without toJson hardening
3
- * @description Inline scripts passed to actions/github-script should use toJson when handling expression values.
4
- * @kind problem
5
- * @problem.severity recommendation
6
- * @precision medium
7
- * @id actions/custom/github-script-without-tojson
8
- * @tags actions
9
- * security
10
- * external/cwe/cwe-116
11
- */
12
-
13
- import actions
14
-
15
- from UsesStep step
16
- where step.getCallee() = "actions/github-script"
17
- select step,
18
- "Review this github-script step for safe interpolation, validation, and least-privilege token use."
@@ -1,18 +0,0 @@
1
- /**
2
- * @name Uses step not pinned to a full commit SHA
3
- * @description Detects workflow/action `uses:` steps that are not pinned to a 40-character commit SHA.
4
- * @kind problem
5
- * @problem.severity warning
6
- * @precision high
7
- * @id actions/custom/strict-external-action-pinning
8
- * @tags actions
9
- * security
10
- * external/cwe/cwe-829
11
- */
12
-
13
- import actions
14
-
15
- from UsesStep uses
16
- where not uses.getVersion().regexpMatch("^[A-Fa-f0-9]{40}$")
17
- select uses,
18
- "Action version is not pinned to a full commit SHA; review and pin to an immutable revision."
@@ -1,14 +0,0 @@
1
- # Custom CodeQL Queries (JavaScript / TypeScript)
2
-
3
- This pack adds repository-specific hardening checks for Node.js/TypeScript code.
4
-
5
- ## Queries
6
-
7
- - `queries/child-process-shell-apis.ql`
8
- - Flags `exec`/`execSync` usage outside tests.
9
- - `queries/innerhtml-assignment.ql`
10
- - Flags assignment to `innerHTML` outside tests.
11
-
12
- ## Why these checks
13
-
14
- These checks focus on high-signal security hotspots that often benefit from stricter review in extensions and tooling codebases.
@@ -1,30 +0,0 @@
1
- ---
2
- lockVersion: 1.0.0
3
- dependencies:
4
- codeql/concepts:
5
- version: 0.0.15
6
- codeql/controlflow:
7
- version: 2.0.25
8
- codeql/dataflow:
9
- version: 2.0.25
10
- codeql/javascript-all:
11
- version: 2.6.21
12
- codeql/mad:
13
- version: 1.0.41
14
- codeql/regex:
15
- version: 1.0.41
16
- codeql/ssa:
17
- version: 2.0.17
18
- codeql/threat-models:
19
- version: 1.0.41
20
- codeql/tutorial:
21
- version: 1.0.41
22
- codeql/typetracking:
23
- version: 2.0.25
24
- codeql/util:
25
- version: 2.0.28
26
- codeql/xml:
27
- version: 1.0.41
28
- codeql/yaml:
29
- version: 1.0.41
30
- compiled: false
@@ -1,7 +0,0 @@
1
- ---
2
- library: false
3
- warnOnImplicitThis: false
4
- name: getting-started/codeql-extra-queries-javascript
5
- version: 1.0.0
6
- dependencies:
7
- codeql/javascript-all: ^2.6.21
@@ -1,6 +0,0 @@
1
- library: false
2
- warnOnImplicitThis: false
3
- name: selfagency/beans-vscode-codeql-extra-queries-javascript
4
- version: 1.0.0
5
- dependencies:
6
- codeql/javascript-all: ^2.6.21
@@ -1,26 +0,0 @@
1
- /**
2
- * @name Use of shell-based child_process APIs
3
- * @description Calls to exec/execSync run through a shell and are riskier than argument-array alternatives.
4
- * @kind problem
5
- * @problem.severity warning
6
- * @precision high
7
- * @id js/custom/child-process-shell-apis
8
- * @tags security
9
- * external/cwe/cwe-078
10
- */
11
-
12
- import javascript
13
-
14
- private predicate inUserSource(InvokeExpr call) {
15
- not call.getTopLevel().getFile().getRelativePath().regexpMatch("(^|.*/)(test|tests|__tests__|mocks?)/.*")
16
- }
17
-
18
- from CallExpr call
19
- where
20
- inUserSource(call) and
21
- not call.getCallee() instanceof PropAccess and
22
- call.getCalleeName() = ["exec", "execSync"]
23
- select call,
24
- "Shell-based process execution ($@) is harder to secure. Prefer execFile/spawn with argument arrays and strict input validation.",
25
- call,
26
- call.getCalleeName()
@@ -1,24 +0,0 @@
1
- /**
2
- * @name Assignment to innerHTML
3
- * @description Assigning to innerHTML can introduce XSS risk if any untrusted content reaches the sink.
4
- * @kind problem
5
- * @problem.severity warning
6
- * @precision medium
7
- * @id js/custom/innerhtml-assignment
8
- * @tags security
9
- * external/cwe/cwe-079
10
- */
11
-
12
- import javascript
13
-
14
- private predicate inUserSource(AssignExpr assign) {
15
- not assign.getTopLevel().getFile().getRelativePath().regexpMatch("(^|.*/)(test|tests|__tests__|mocks?)/.*")
16
- }
17
-
18
- from AssignExpr assign, PropAccess lhs
19
- where
20
- inUserSource(assign) and
21
- lhs = assign.getLhs() and
22
- lhs.getPropertyName() = "innerHTML"
23
- select assign,
24
- "Assignment to innerHTML can be unsafe. Prefer textContent or sanitization before rendering HTML."