@shareworker/code-review-mcp 0.1.0
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/LICENSE +21 -0
- package/README +155 -0
- package/README.md +155 -0
- package/dist/bundler.d.ts +27 -0
- package/dist/bundler.d.ts.map +1 -0
- package/dist/bundler.js +203 -0
- package/dist/bundler.js.map +1 -0
- package/dist/diff-parser.d.ts +46 -0
- package/dist/diff-parser.d.ts.map +1 -0
- package/dist/diff-parser.js +322 -0
- package/dist/diff-parser.js.map +1 -0
- package/dist/filter.d.ts +31 -0
- package/dist/filter.d.ts.map +1 -0
- package/dist/filter.js +155 -0
- package/dist/filter.js.map +1 -0
- package/dist/git.d.ts +54 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +111 -0
- package/dist/git.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +296 -0
- package/dist/index.js.map +1 -0
- package/dist/position.d.ts +14 -0
- package/dist/position.d.ts.map +1 -0
- package/dist/position.js +179 -0
- package/dist/position.js.map +1 -0
- package/dist/reflect.d.ts +17 -0
- package/dist/reflect.d.ts.map +1 -0
- package/dist/reflect.js +208 -0
- package/dist/reflect.js.map +1 -0
- package/dist/rules.d.ts +14 -0
- package/dist/rules.d.ts.map +1 -0
- package/dist/rules.js +123 -0
- package/dist/rules.js.map +1 -0
- package/dist/types.d.ts +119 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +58 -0
- package/skills/code +139 -0
- package/skills/code-review/SK +139 -0
- package/skills/code-review/SKILL +139 -0
- package/skills/code-review/SKILL.md +139 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 shareworker
|
|
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.
|
package/README
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# @shareworker/code-review-mcp
|
|
2
|
+
|
|
3
|
+
An MCP server that exposes the deterministic engineering layer of code review as
|
|
4
|
+
tools, callable by host agents (Claude Code, Codex, Devin) within their own LLM
|
|
5
|
+
loops. The server never calls an LLM — all reasoning happens in the host session.
|
|
6
|
+
|
|
7
|
+
## Why
|
|
8
|
+
|
|
9
|
+
General-purpose agents doing code review via Skills suffer from: incomplete
|
|
10
|
+
coverage (skipping files on large changesets), position drift (line numbers
|
|
11
|
+
don't match actual code), and unstable quality (minor prompt variations cause
|
|
12
|
+
large quality swings). This server enforces hard constraints on the review
|
|
13
|
+
process — file selection, smart bundling, rule matching, comment positioning,
|
|
14
|
+
and comment reflection — so quality is stable regardless of host model variation.
|
|
15
|
+
|
|
16
|
+
## Tools
|
|
17
|
+
|
|
18
|
+
| Tool | Purpose |
|
|
19
|
+
|------|---------|
|
|
20
|
+
| `get_review_targets` | Git diff → file filtering → `diff_ref` + file list |
|
|
21
|
+
| `get_file_bundle` | Smart bundling (test/source + i18n) with 20000 char cap |
|
|
22
|
+
| `match_rules` | Path-based rule matching → `prompt_section` for host LLM |
|
|
23
|
+
| `position_comment` | Text match + hunk align → precise line numbers |
|
|
24
|
+
| `reflect_comment` | Deterministic validation (keep/drop) — no LLM |
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
### Claude Code
|
|
29
|
+
|
|
30
|
+
Add to `.claude/mcp.json`:
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"mcpServers": {
|
|
35
|
+
"code-review": {
|
|
36
|
+
"command": "npx",
|
|
37
|
+
"args": ["-y", "@shareworker/code-review-mcp"]
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Copy the skill to `.claude/skills/`:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
mkdir -p .claude/skills/code-review
|
|
47
|
+
cp skills/code-review/SKILL.md .claude/skills/code-review/SKILL.md
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Codex
|
|
51
|
+
|
|
52
|
+
Add to your Codex MCP configuration:
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"mcpServers": {
|
|
57
|
+
"code-review": {
|
|
58
|
+
"command": "npx",
|
|
59
|
+
"args": ["-y", "@shareworker/code-review-mcp"]
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Copy the skill to Codex's skill directory:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
cp skills/code-review/SKILL.md <codex-skills-dir>/code-review/SKILL.md
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Devin
|
|
72
|
+
|
|
73
|
+
Add to `.devin/config.json`:
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"mcpServers": {
|
|
78
|
+
"code-review": {
|
|
79
|
+
"command": "npx",
|
|
80
|
+
"args": ["-y", "@shareworker/code-review-mcp"]
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Copy the skill to `.devin/skills/`:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
mkdir -p .devin/skills/code-review
|
|
90
|
+
cp skills/code-review/SKILL.md .devin/skills/code-review/SKILL.md
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Configuration
|
|
94
|
+
|
|
95
|
+
Create `.code-review/rules.json` in your repo (or `~/.code-review/rules.json`
|
|
96
|
+
for global config):
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"filters": {
|
|
101
|
+
"exclude": ["**/*.lock", "**/*.min.js", "**/*.map"],
|
|
102
|
+
"include": ["**/*.ts", "**/*.js"]
|
|
103
|
+
},
|
|
104
|
+
"rules": [
|
|
105
|
+
{
|
|
106
|
+
"path": "**/*.ts",
|
|
107
|
+
"rule": "Check for any types and proper null handling"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"path": "**/*mapper*.xml",
|
|
111
|
+
"rule": "Check SQL for injection risks and missing closing tags"
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Configuration Resolution Priority
|
|
118
|
+
|
|
119
|
+
1. `--rule <path>` flag (highest) — not exposed via MCP, reserved for future CLI
|
|
120
|
+
2. `<repo>/.code-review/rules.json` — project-level
|
|
121
|
+
3. `~/.code-review/rules.json` — global/user-level
|
|
122
|
+
4. Built-in defaults (lowest) — covers correctness, security, performance,
|
|
123
|
+
maintainability, test coverage
|
|
124
|
+
|
|
125
|
+
For MVP, only layers 2-4 are active (no `--rule` flag since there's no CLI).
|
|
126
|
+
The first matching user rule replaces the built-in system rule at the same layer.
|
|
127
|
+
|
|
128
|
+
### `filters`
|
|
129
|
+
|
|
130
|
+
- `exclude`: glob patterns for files to exclude (merged with built-in defaults)
|
|
131
|
+
- `include`: glob patterns — when present, only matching files are reviewed
|
|
132
|
+
|
|
133
|
+
### `rules`
|
|
134
|
+
|
|
135
|
+
Array of `{ "path": "<glob>", "rule": "<text>" }`. First match wins. The `rule`
|
|
136
|
+
text is returned as `prompt_section` for the host LLM to inject into its review
|
|
137
|
+
prompt.
|
|
138
|
+
|
|
139
|
+
## Development
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
npm install
|
|
143
|
+
npm run build # compile TypeScript
|
|
144
|
+
npm test # run unit tests
|
|
145
|
+
npm run dev # watch mode
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Architecture
|
|
149
|
+
|
|
150
|
+
See `docs/superpowers/specs/2026-07-02-code-review-mcp-design.md` for the full
|
|
151
|
+
design spec and `docs/adr/` for architecture decision records.
|
|
152
|
+
|
|
153
|
+
## License
|
|
154
|
+
|
|
155
|
+
MIT
|
package/README.md
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# @shareworker/code-review-mcp
|
|
2
|
+
|
|
3
|
+
An MCP server that exposes the deterministic engineering layer of code review as
|
|
4
|
+
tools, callable by host agents (Claude Code, Codex, Devin) within their own LLM
|
|
5
|
+
loops. The server never calls an LLM — all reasoning happens in the host session.
|
|
6
|
+
|
|
7
|
+
## Why
|
|
8
|
+
|
|
9
|
+
General-purpose agents doing code review via Skills suffer from: incomplete
|
|
10
|
+
coverage (skipping files on large changesets), position drift (line numbers
|
|
11
|
+
don't match actual code), and unstable quality (minor prompt variations cause
|
|
12
|
+
large quality swings). This server enforces hard constraints on the review
|
|
13
|
+
process — file selection, smart bundling, rule matching, comment positioning,
|
|
14
|
+
and comment reflection — so quality is stable regardless of host model variation.
|
|
15
|
+
|
|
16
|
+
## Tools
|
|
17
|
+
|
|
18
|
+
| Tool | Purpose |
|
|
19
|
+
|------|---------|
|
|
20
|
+
| `get_review_targets` | Git diff → file filtering → `diff_ref` + file list |
|
|
21
|
+
| `get_file_bundle` | Smart bundling (test/source + i18n) with 20000 char cap |
|
|
22
|
+
| `match_rules` | Path-based rule matching → `prompt_section` for host LLM |
|
|
23
|
+
| `position_comment` | Text match + hunk align → precise line numbers |
|
|
24
|
+
| `reflect_comment` | Deterministic validation (keep/drop) — no LLM |
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
### Claude Code
|
|
29
|
+
|
|
30
|
+
Add to `.claude/mcp.json`:
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"mcpServers": {
|
|
35
|
+
"code-review": {
|
|
36
|
+
"command": "npx",
|
|
37
|
+
"args": ["-y", "@shareworker/code-review-mcp"]
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Copy the skill to `.claude/skills/`:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
mkdir -p .claude/skills/code-review
|
|
47
|
+
cp skills/code-review/SKILL.md .claude/skills/code-review/SKILL.md
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Codex
|
|
51
|
+
|
|
52
|
+
Add to your Codex MCP configuration:
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"mcpServers": {
|
|
57
|
+
"code-review": {
|
|
58
|
+
"command": "npx",
|
|
59
|
+
"args": ["-y", "@shareworker/code-review-mcp"]
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Copy the skill to Codex's skill directory:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
cp skills/code-review/SKILL.md <codex-skills-dir>/code-review/SKILL.md
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Devin
|
|
72
|
+
|
|
73
|
+
Add to `.devin/config.json`:
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"mcpServers": {
|
|
78
|
+
"code-review": {
|
|
79
|
+
"command": "npx",
|
|
80
|
+
"args": ["-y", "@shareworker/code-review-mcp"]
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Copy the skill to `.devin/skills/`:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
mkdir -p .devin/skills/code-review
|
|
90
|
+
cp skills/code-review/SKILL.md .devin/skills/code-review/SKILL.md
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Configuration
|
|
94
|
+
|
|
95
|
+
Create `.code-review/rules.json` in your repo (or `~/.code-review/rules.json`
|
|
96
|
+
for global config):
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"filters": {
|
|
101
|
+
"exclude": ["**/*.lock", "**/*.min.js", "**/*.map"],
|
|
102
|
+
"include": ["**/*.ts", "**/*.js"]
|
|
103
|
+
},
|
|
104
|
+
"rules": [
|
|
105
|
+
{
|
|
106
|
+
"path": "**/*.ts",
|
|
107
|
+
"rule": "Check for any types and proper null handling"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"path": "**/*mapper*.xml",
|
|
111
|
+
"rule": "Check SQL for injection risks and missing closing tags"
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Configuration Resolution Priority
|
|
118
|
+
|
|
119
|
+
1. `--rule <path>` flag (highest) — not exposed via MCP, reserved for future CLI
|
|
120
|
+
2. `<repo>/.code-review/rules.json` — project-level
|
|
121
|
+
3. `~/.code-review/rules.json` — global/user-level
|
|
122
|
+
4. Built-in defaults (lowest) — covers correctness, security, performance,
|
|
123
|
+
maintainability, test coverage
|
|
124
|
+
|
|
125
|
+
For MVP, only layers 2-4 are active (no `--rule` flag since there's no CLI).
|
|
126
|
+
The first matching user rule replaces the built-in system rule at the same layer.
|
|
127
|
+
|
|
128
|
+
### `filters`
|
|
129
|
+
|
|
130
|
+
- `exclude`: glob patterns for files to exclude (merged with built-in defaults)
|
|
131
|
+
- `include`: glob patterns — when present, only matching files are reviewed
|
|
132
|
+
|
|
133
|
+
### `rules`
|
|
134
|
+
|
|
135
|
+
Array of `{ "path": "<glob>", "rule": "<text>" }`. First match wins. The `rule`
|
|
136
|
+
text is returned as `prompt_section` for the host LLM to inject into its review
|
|
137
|
+
prompt.
|
|
138
|
+
|
|
139
|
+
## Development
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
npm install
|
|
143
|
+
npm run build # compile TypeScript
|
|
144
|
+
npm test # run unit tests
|
|
145
|
+
npm run dev # watch mode
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Architecture
|
|
149
|
+
|
|
150
|
+
See `docs/superpowers/specs/2026-07-02-code-review-mcp-design.md` for the full
|
|
151
|
+
design spec and `docs/adr/` for architecture decision records.
|
|
152
|
+
|
|
153
|
+
## License
|
|
154
|
+
|
|
155
|
+
MIT
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { FileBundle } from "./types.js";
|
|
2
|
+
/** Character cap per bundle (counting diff text only). */
|
|
3
|
+
export declare const BUNDLE_CHAR_CAP = 20000;
|
|
4
|
+
/**
|
|
5
|
+
* Identify the test counterpart of a source file, or vice versa.
|
|
6
|
+
* Returns the paired path or null.
|
|
7
|
+
*
|
|
8
|
+
* Conventions:
|
|
9
|
+
* foo.test.ts <-> foo.ts
|
|
10
|
+
* foo.spec.ts <-> foo.ts
|
|
11
|
+
* foo_test.go <-> foo.go
|
|
12
|
+
* foo_spec.go <-> foo.go
|
|
13
|
+
* TestFoo.java <-> Foo.java
|
|
14
|
+
* FooTest.java <-> Foo.java
|
|
15
|
+
*/
|
|
16
|
+
export declare function findTestSourcePair(path: string, allFiles: string[]): string | null;
|
|
17
|
+
export declare function findI18nVariants(path: string, allFiles: string[]): string[];
|
|
18
|
+
/**
|
|
19
|
+
* Bundle files by test/source pairing and i18n variants, with a 20000 char cap.
|
|
20
|
+
*
|
|
21
|
+
* Algorithm:
|
|
22
|
+
* 1. Build pairing groups (test/source pairs, i18n variant groups, singletons).
|
|
23
|
+
* 2. For each group, read diffs and pack into bundles respecting the char cap.
|
|
24
|
+
* 3. A single file whose diff alone exceeds the cap gets its own over-cap bundle.
|
|
25
|
+
*/
|
|
26
|
+
export declare function bundleFiles(repo: string, files: string[], diffRef: string): Promise<FileBundle[]>;
|
|
27
|
+
//# sourceMappingURL=bundler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundler.d.ts","sourceRoot":"","sources":["../src/bundler.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAA4B,UAAU,EAAE,MAAM,YAAY,CAAC;AAEvE,0DAA0D;AAC1D,eAAO,MAAM,eAAe,QAAQ,CAAC;AAErC;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAoClF;AASD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAa3E;AAuCD;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EAAE,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,UAAU,EAAE,CAAC,CAkCvB"}
|
package/dist/bundler.js
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { getDiffForFile } from "./git.js";
|
|
2
|
+
import { parseFileDiffs } from "./diff-parser.js";
|
|
3
|
+
/** Character cap per bundle (counting diff text only). */
|
|
4
|
+
export const BUNDLE_CHAR_CAP = 20000;
|
|
5
|
+
/**
|
|
6
|
+
* Identify the test counterpart of a source file, or vice versa.
|
|
7
|
+
* Returns the paired path or null.
|
|
8
|
+
*
|
|
9
|
+
* Conventions:
|
|
10
|
+
* foo.test.ts <-> foo.ts
|
|
11
|
+
* foo.spec.ts <-> foo.ts
|
|
12
|
+
* foo_test.go <-> foo.go
|
|
13
|
+
* foo_spec.go <-> foo.go
|
|
14
|
+
* TestFoo.java <-> Foo.java
|
|
15
|
+
* FooTest.java <-> Foo.java
|
|
16
|
+
*/
|
|
17
|
+
export function findTestSourcePair(path, allFiles) {
|
|
18
|
+
const base = stripExt(path);
|
|
19
|
+
const ext = getExt(path);
|
|
20
|
+
// Test file -> source file.
|
|
21
|
+
const testMatch = base.match(/^(.+)\.(test|spec)$/i) || base.match(/^(.+)[._](test|spec)$/i);
|
|
22
|
+
if (testMatch) {
|
|
23
|
+
const sourceBase = testMatch[1];
|
|
24
|
+
const sourcePath = `${sourceBase}.${ext}`;
|
|
25
|
+
if (allFiles.includes(sourcePath))
|
|
26
|
+
return sourcePath;
|
|
27
|
+
}
|
|
28
|
+
// Java: TestFoo.java <-> Foo.java, FooTest.java <-> Foo.java
|
|
29
|
+
const javaTestMatch = base.match(/^Test(.+)$/);
|
|
30
|
+
if (javaTestMatch && ext === "java") {
|
|
31
|
+
const sourcePath = `${javaTestMatch[1]}.java`;
|
|
32
|
+
if (allFiles.includes(sourcePath))
|
|
33
|
+
return sourcePath;
|
|
34
|
+
}
|
|
35
|
+
const javaTestSuffixMatch = base.match(/^(.+)Test$/);
|
|
36
|
+
if (javaTestSuffixMatch && ext === "java") {
|
|
37
|
+
const sourcePath = `${javaTestSuffixMatch[1]}.java`;
|
|
38
|
+
if (allFiles.includes(sourcePath))
|
|
39
|
+
return sourcePath;
|
|
40
|
+
}
|
|
41
|
+
// Source file -> test file.
|
|
42
|
+
for (const candidate of allFiles) {
|
|
43
|
+
if (candidate === path)
|
|
44
|
+
continue;
|
|
45
|
+
const cBase = stripExt(candidate);
|
|
46
|
+
const cExt = getExt(candidate);
|
|
47
|
+
if (cExt !== ext)
|
|
48
|
+
continue;
|
|
49
|
+
const cTestMatch = cBase.match(/^(.+)\.(test|spec)$/i) || cBase.match(/^(.+)[._](test|spec)$/i);
|
|
50
|
+
if (cTestMatch && cTestMatch[1] === base)
|
|
51
|
+
return candidate;
|
|
52
|
+
if (ext === "java") {
|
|
53
|
+
if (cBase === `Test${base}` || cBase === `${base}Test`)
|
|
54
|
+
return candidate;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Identify i18n variant files: same base name with different locale suffixes.
|
|
61
|
+
* Locale suffixes: _en, _zh, _ja, _ko, _fr, _de, _es, _pt, _ru, _ar, etc.
|
|
62
|
+
* The suffix sits before the file extension, e.g. messages_en.ts.
|
|
63
|
+
*/
|
|
64
|
+
const LOCALE_SUFFIX_RE = /[_-](en|zh|ja|ko|fr|de|es|pt|ru|ar|it|nl|pl|tr|vi|th|id|hi|bn|mx|tw|cn|hk|us|uk|br)(?:[_-][A-Z]{2})?(?=\.|$)/i;
|
|
65
|
+
export function findI18nVariants(path, allFiles) {
|
|
66
|
+
const base = path.replace(LOCALE_SUFFIX_RE, "");
|
|
67
|
+
if (base === path)
|
|
68
|
+
return []; // no locale suffix, not an i18n file
|
|
69
|
+
const ext = getExt(path);
|
|
70
|
+
const result = [];
|
|
71
|
+
for (const candidate of allFiles) {
|
|
72
|
+
if (candidate === path)
|
|
73
|
+
continue;
|
|
74
|
+
const cBase = candidate.replace(LOCALE_SUFFIX_RE, "");
|
|
75
|
+
if (cBase === base && getExt(candidate) === ext) {
|
|
76
|
+
result.push(candidate);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
function stripExt(path) {
|
|
82
|
+
const dot = path.lastIndexOf(".");
|
|
83
|
+
const slash = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
|
|
84
|
+
if (dot <= slash)
|
|
85
|
+
return path;
|
|
86
|
+
return path.slice(0, dot);
|
|
87
|
+
}
|
|
88
|
+
function getExt(path) {
|
|
89
|
+
const dot = path.lastIndexOf(".");
|
|
90
|
+
const slash = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
|
|
91
|
+
if (dot <= slash)
|
|
92
|
+
return "";
|
|
93
|
+
return path.slice(dot + 1);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Read a single file's diff and build a BundleFile.
|
|
97
|
+
* Returns null if the diff can't be read.
|
|
98
|
+
*/
|
|
99
|
+
async function buildBundleFile(repo, path, diffRef) {
|
|
100
|
+
try {
|
|
101
|
+
const diff = await getDiffForFile(repo, diffRef, path);
|
|
102
|
+
const parsed = parseFileDiffs(diff)[0];
|
|
103
|
+
return {
|
|
104
|
+
path,
|
|
105
|
+
diff,
|
|
106
|
+
additions: parsed?.insertions ?? 0,
|
|
107
|
+
deletions: parsed?.deletions ?? 0,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Bundle files by test/source pairing and i18n variants, with a 20000 char cap.
|
|
116
|
+
*
|
|
117
|
+
* Algorithm:
|
|
118
|
+
* 1. Build pairing groups (test/source pairs, i18n variant groups, singletons).
|
|
119
|
+
* 2. For each group, read diffs and pack into bundles respecting the char cap.
|
|
120
|
+
* 3. A single file whose diff alone exceeds the cap gets its own over-cap bundle.
|
|
121
|
+
*/
|
|
122
|
+
export async function bundleFiles(repo, files, diffRef) {
|
|
123
|
+
if (files.length === 0)
|
|
124
|
+
return [];
|
|
125
|
+
const groups = buildPairingGroups(files);
|
|
126
|
+
const bundles = [];
|
|
127
|
+
let bundleIndex = 0;
|
|
128
|
+
for (const group of groups) {
|
|
129
|
+
const bundleFiles = [];
|
|
130
|
+
for (const path of group.files) {
|
|
131
|
+
const bf = await buildBundleFile(repo, path, diffRef);
|
|
132
|
+
if (bf)
|
|
133
|
+
bundleFiles.push(bf);
|
|
134
|
+
}
|
|
135
|
+
if (bundleFiles.length === 0)
|
|
136
|
+
continue;
|
|
137
|
+
// Pack into bundles respecting the char cap.
|
|
138
|
+
let current = [];
|
|
139
|
+
let currentChars = 0;
|
|
140
|
+
for (const bf of bundleFiles) {
|
|
141
|
+
const bfChars = bf.diff.length;
|
|
142
|
+
if (current.length > 0 && currentChars + bfChars > BUNDLE_CHAR_CAP) {
|
|
143
|
+
bundles.push(makeBundle(bundleIndex++, current, group.reason));
|
|
144
|
+
current = [];
|
|
145
|
+
currentChars = 0;
|
|
146
|
+
}
|
|
147
|
+
current.push(bf);
|
|
148
|
+
currentChars += bfChars;
|
|
149
|
+
}
|
|
150
|
+
if (current.length > 0) {
|
|
151
|
+
bundles.push(makeBundle(bundleIndex++, current, group.reason));
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return bundles;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Build pairing groups from the file list.
|
|
158
|
+
* Each file appears in exactly one group.
|
|
159
|
+
*/
|
|
160
|
+
function buildPairingGroups(files) {
|
|
161
|
+
const remaining = new Set(files);
|
|
162
|
+
const groups = [];
|
|
163
|
+
// Pass 1: test/source pairs.
|
|
164
|
+
for (const file of files) {
|
|
165
|
+
if (!remaining.has(file))
|
|
166
|
+
continue;
|
|
167
|
+
const pair = findTestSourcePair(file, files);
|
|
168
|
+
if (pair && remaining.has(pair)) {
|
|
169
|
+
remaining.delete(file);
|
|
170
|
+
remaining.delete(pair);
|
|
171
|
+
groups.push({ files: [file, pair], reason: "test_source_pair" });
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// Pass 2: i18n variants.
|
|
175
|
+
for (const file of files) {
|
|
176
|
+
if (!remaining.has(file))
|
|
177
|
+
continue;
|
|
178
|
+
const variants = findI18nVariants(file, files).filter((v) => remaining.has(v));
|
|
179
|
+
if (variants.length > 0) {
|
|
180
|
+
remaining.delete(file);
|
|
181
|
+
for (const v of variants)
|
|
182
|
+
remaining.delete(v);
|
|
183
|
+
groups.push({ files: [file, ...variants], reason: "i18n_variants" });
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
// Pass 3: singletons.
|
|
187
|
+
for (const file of files) {
|
|
188
|
+
if (!remaining.has(file))
|
|
189
|
+
continue;
|
|
190
|
+
remaining.delete(file);
|
|
191
|
+
groups.push({ files: [file], reason: "single_file" });
|
|
192
|
+
}
|
|
193
|
+
return groups;
|
|
194
|
+
}
|
|
195
|
+
function makeBundle(id, files, reason) {
|
|
196
|
+
return {
|
|
197
|
+
id: `bundle-${id}`,
|
|
198
|
+
files,
|
|
199
|
+
totalChars: files.reduce((sum, f) => sum + f.diff.length, 0),
|
|
200
|
+
bundleReason: reason,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=bundler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundler.js","sourceRoot":"","sources":["../src/bundler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { FileDiff, Hunk } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Normalize a diff line: trim whitespace, strip leading +/- diff markers, trim \r.
|
|
4
|
+
* Mirrors open-code-review's normalizeLine.
|
|
5
|
+
*/
|
|
6
|
+
export declare function normalizeLine(line: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Split code text into normalized non-blank lines.
|
|
9
|
+
*/
|
|
10
|
+
export declare function splitAndNormalize(code: string): string[];
|
|
11
|
+
/**
|
|
12
|
+
* Parse @@ ... @@ blocks from raw diff text into Hunk[].
|
|
13
|
+
* Lines before the first @@ header (file-level headers) are ignored.
|
|
14
|
+
*/
|
|
15
|
+
export declare function parseHunks(rawDiffText: string): Hunk[];
|
|
16
|
+
/**
|
|
17
|
+
* Parse a full unified diff (possibly multiple files) into FileDiff[].
|
|
18
|
+
* Uses the `diff` library's parsePatch for hunk line splitting, and
|
|
19
|
+
* raw-text scanning for git edge cases (rename/binary/new-file/deleted-file).
|
|
20
|
+
*/
|
|
21
|
+
export declare function parseFileDiffs(diffText: string): FileDiff[];
|
|
22
|
+
/**
|
|
23
|
+
* Extract one side of a hunk as indexed lines (line number + normalized content).
|
|
24
|
+
* When newSide=true: context + added lines with new-file line numbers.
|
|
25
|
+
* When newSide=false: context + deleted lines with old-file line numbers.
|
|
26
|
+
* Mirrors open-code-review's extractSideLines.
|
|
27
|
+
*/
|
|
28
|
+
export interface IndexedLine {
|
|
29
|
+
lineNum: number;
|
|
30
|
+
content: string;
|
|
31
|
+
}
|
|
32
|
+
export declare function extractSideLines(hunk: Hunk, newSide: boolean): IndexedLine[];
|
|
33
|
+
/**
|
|
34
|
+
* Scan sideLines for a consecutive run matching all targetLines.
|
|
35
|
+
* Returns the start/end line numbers of the match, or null.
|
|
36
|
+
* Mirrors open-code-review's matchConsecutive.
|
|
37
|
+
*/
|
|
38
|
+
export declare function matchConsecutive(sideLines: IndexedLine[], targetLines: string[]): {
|
|
39
|
+
start: number;
|
|
40
|
+
end: number;
|
|
41
|
+
} | null;
|
|
42
|
+
/**
|
|
43
|
+
* Get the set of changed (added) line numbers in a hunk (new-file line numbers).
|
|
44
|
+
*/
|
|
45
|
+
export declare function getAddedLineNumbers(hunks: Hunk[]): Set<number>;
|
|
46
|
+
//# sourceMappingURL=diff-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff-parser.d.ts","sourceRoot":"","sources":["../src/diff-parser.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAA0B,MAAM,YAAY,CAAC;AAIzE;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMlD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAKxD;AAwBD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,EAAE,CAsCtD;AAoFD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,EAAE,CAuD3D;AAwBD;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,GAAG,WAAW,EAAE,CA8B5E;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,WAAW,EAAE,EACxB,WAAW,EAAE,MAAM,EAAE,GACpB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAoBvC;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,CAU9D"}
|