ai-credit 1.0.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.md +330 -0
- package/dist/analyzer.d.ts +37 -0
- package/dist/analyzer.js +357 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +383 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/reporter.d.ts +60 -0
- package/dist/reporter.js +372 -0
- package/dist/scanners/aider.d.ts +35 -0
- package/dist/scanners/aider.js +194 -0
- package/dist/scanners/base.d.ts +56 -0
- package/dist/scanners/base.js +88 -0
- package/dist/scanners/claude.d.ts +30 -0
- package/dist/scanners/claude.js +203 -0
- package/dist/scanners/codex.d.ts +54 -0
- package/dist/scanners/codex.js +311 -0
- package/dist/scanners/gemini.d.ts +35 -0
- package/dist/scanners/gemini.js +318 -0
- package/dist/scanners/index.d.ts +6 -0
- package/dist/scanners/index.js +6 -0
- package/dist/scanners/opencode.d.ts +40 -0
- package/dist/scanners/opencode.js +210 -0
- package/dist/types.d.ts +103 -0
- package/dist/types.js +11 -0
- package/package.json +46 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 AI Contribution Tracker
|
|
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.md
ADDED
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
# AI Contribution Tracker
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/ai-credit)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
A command-line tool to track and analyze AI coding assistants' contributions in your codebase. Supports **Claude Code**, **Codex CLI**, **Gemini CLI**, and **Aider**.
|
|
7
|
+
|
|
8
|
+
## Quick Start
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
# Run directly with npx (no installation required)
|
|
12
|
+
npx ai-credit
|
|
13
|
+
|
|
14
|
+
# Or install globally
|
|
15
|
+
npm install -g ai-credit
|
|
16
|
+
ai-credit
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Features
|
|
20
|
+
|
|
21
|
+
- 🔍 **Auto-detection**: Automatically finds AI tool session data on your system
|
|
22
|
+
- 📊 **Detailed Statistics**: Lines of code, files modified, contribution ratios
|
|
23
|
+
- 🤖 **Multi-tool Support**: Claude Code, Codex CLI, Gemini CLI, Aider
|
|
24
|
+
- 📈 **Visual Reports**: Console, JSON, and Markdown output formats
|
|
25
|
+
- 📅 **Timeline View**: Track AI contributions over time
|
|
26
|
+
- 📁 **File-level Analysis**: See which files have the most AI contributions
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# Analyze current directory
|
|
32
|
+
npx ai-credit
|
|
33
|
+
|
|
34
|
+
# Analyze a specific repository
|
|
35
|
+
npx ai-credit /path/to/your/repo
|
|
36
|
+
|
|
37
|
+
# Export as JSON
|
|
38
|
+
npx ai-credit -f json -o report.json
|
|
39
|
+
|
|
40
|
+
# Only analyze specific tools
|
|
41
|
+
npx ai-credit -t claude,codex
|
|
42
|
+
|
|
43
|
+
# Show detailed file-level analysis
|
|
44
|
+
npx ai-credit -v
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Commands
|
|
48
|
+
|
|
49
|
+
### Main Analysis
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npx ai-credit [path]
|
|
53
|
+
|
|
54
|
+
# Options:
|
|
55
|
+
# -f, --format Output format (console/json/markdown)
|
|
56
|
+
# -o, --output Output file path
|
|
57
|
+
# -t, --tools AI tools to analyze (claude,codex,gemini,aider,all)
|
|
58
|
+
# -v, --verbose Show detailed output
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### List Detected Tools
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
npx ai-credit list
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Shows which AI tools have data available on your system:
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
🔍 Detected AI Tools
|
|
71
|
+
|
|
72
|
+
Claude Code ~/.claude/projects/ ✓ Available
|
|
73
|
+
Codex CLI ~/.codex/sessions/ ✓ Available
|
|
74
|
+
Gemini CLI ~/.gemini/tmp/ ✗ Not found
|
|
75
|
+
Aider .aider.chat.history.md ✗ Not found
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### File-level Analysis
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npx ai-credit files [path] [-n LIMIT]
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Shows which files have the most AI contributions.
|
|
85
|
+
|
|
86
|
+
### Contribution History
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
npx ai-credit history [path] [-n LIMIT]
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Shows a timeline of AI contributions.
|
|
93
|
+
|
|
94
|
+
### Session List
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
npx ai-credit sessions [path] [-t TOOL]
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Lists all AI sessions for the repository.
|
|
101
|
+
|
|
102
|
+
## Output Example
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
╭─────────────────────────────────────────────────╮
|
|
106
|
+
│ AI Contribution Analysis │
|
|
107
|
+
│ Repository: /path/to/your/repo │
|
|
108
|
+
│ Scan time: 2024-01-15 14:30:00 │
|
|
109
|
+
╰─────────────────────────────────────────────────╯
|
|
110
|
+
|
|
111
|
+
📊 Overview
|
|
112
|
+
┏━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┓
|
|
113
|
+
┃ Metric ┃ Value ┃ AI Contribution ┃
|
|
114
|
+
┡━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━┩
|
|
115
|
+
│ Total Files │ 150 │ 45 (30.0%) │
|
|
116
|
+
│ Total Lines │ 12500 │ 3750 (30.0%) │
|
|
117
|
+
│ AI Sessions │ 28 │ - │
|
|
118
|
+
└──────────────┴─────────┴─────────────────────┘
|
|
119
|
+
|
|
120
|
+
🤖 Contribution by AI Tool
|
|
121
|
+
┏━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━━┓
|
|
122
|
+
┃ Tool ┃ Sessions ┃ Files ┃ Lines Added ┃
|
|
123
|
+
┡━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━━┩
|
|
124
|
+
│ Claude Code │ 15 │ 30 │ +2500 │
|
|
125
|
+
│ Codex CLI │ 10 │ 20 │ +1000 │
|
|
126
|
+
│ Aider │ 3 │ 5 │ +250 │
|
|
127
|
+
└──────────────┴──────────┴───────┴─────────────┘
|
|
128
|
+
|
|
129
|
+
📈 Contribution Distribution
|
|
130
|
+
|
|
131
|
+
Claude Code ████████████████████████████░░░░░░░░░░░░░░░░░░░░░░ 66.7%
|
|
132
|
+
Codex CLI ████████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 26.7%
|
|
133
|
+
Aider ███░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 6.7%
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Supported AI Tools
|
|
137
|
+
|
|
138
|
+
| Tool | Storage Location | Format |
|
|
139
|
+
|------|------------------|--------|
|
|
140
|
+
| Claude Code | `~/.claude/projects/<path>/` | JSONL |
|
|
141
|
+
| Codex CLI | `~/.codex/sessions/YYYY/MM/DD/` | JSONL |
|
|
142
|
+
| Gemini CLI | `~/.gemini/tmp/<hash>/chats/` | JSON |
|
|
143
|
+
| Aider | `.aider.chat.history.md` | Markdown |
|
|
144
|
+
|
|
145
|
+
## How It Works: The JSON Parsing Logic
|
|
146
|
+
|
|
147
|
+
`ai-credit`'s core is a multi-adapter parsing engine. It works by analyzing the session log files generated by different AI coding assistants. While each tool has a slightly different log format, they share a common pattern: recording interactions, especially AI tool calls (like file writing or editing), as structured data (JSON or JSONL). This tool identifies and parses these specific tool-call records to quantify code contributions.
|
|
148
|
+
|
|
149
|
+
Here's a detailed breakdown of the parsing method for each supported tool:
|
|
150
|
+
|
|
151
|
+
### 1. Claude Code
|
|
152
|
+
|
|
153
|
+
- **File Format**: JSONL (`.jsonl`), one JSON object per line.
|
|
154
|
+
- **Scan Path**: `~/.claude/projects/<path-encoded-project-name>/*.jsonl`
|
|
155
|
+
- **Parsing Logic**:
|
|
156
|
+
1. The scanner iterates through all `.jsonl` session files in the project's directory.
|
|
157
|
+
2. It reads the file line by line, parsing each line into a JSON object.
|
|
158
|
+
3. The scanner focuses on log entries with `"type": "assistant"`, as these represent the AI's responses.
|
|
159
|
+
4. Within the assistant's response (`message.content` array), it looks for blocks of `"type": "tool_use"`. This indicates the AI decided to use a tool.
|
|
160
|
+
5. In the `tool_use` block, the `"name"` field identifies the specific action, such as `write`, `write_file`, or `edit_file`.
|
|
161
|
+
6. It extracts parameters from the `"input"` field, including:
|
|
162
|
+
- `path` or `file_path`: The target file path.
|
|
163
|
+
- `content` or `new_str`: The new content to be written or to replace existing content.
|
|
164
|
+
- `old_str`: (In edit operations only) The old content being replaced.
|
|
165
|
+
|
|
166
|
+
- **Contribution Calculation**:
|
|
167
|
+
- **Lines Added**: Calculated by counting the lines in the `content` or `new_str`.
|
|
168
|
+
- **Lines Removed**: For edit operations, calculated by counting the lines in `old_str`.
|
|
169
|
+
|
|
170
|
+
**Example (Simplified Claude Code JSONL Entry):**
|
|
171
|
+
|
|
172
|
+
```json
|
|
173
|
+
{
|
|
174
|
+
"timestamp": 1706860810000,
|
|
175
|
+
"type": "assistant",
|
|
176
|
+
"message": {
|
|
177
|
+
"content": [
|
|
178
|
+
{
|
|
179
|
+
"type": "tool_use",
|
|
180
|
+
"name": "write",
|
|
181
|
+
"input": {
|
|
182
|
+
"path": "src/main.py",
|
|
183
|
+
"content": "def hello():\n print(\"Hello, AI!\")\n"
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
]
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### 2. OpenAI Codex CLI
|
|
192
|
+
|
|
193
|
+
- **File Format**: JSONL (`.jsonl`).
|
|
194
|
+
- **Scan Path**: `~/.codex/sessions/YYYY/MM/DD/*.jsonl`
|
|
195
|
+
- **Parsing Logic**:
|
|
196
|
+
1. The tool recursively scans the `sessions` directory for all `.jsonl` files.
|
|
197
|
+
2. In each JSON object, the scanner looks for a `"tool_calls"` array, which contains all tools called by the AI in that turn.
|
|
198
|
+
3. Each `tool_call` object contains a `"function"` field, where `"name"` specifies the function called (e.g., `write_file`, `apply_diff`) and `"arguments"` is a **JSON string** containing all parameters.
|
|
199
|
+
4. The scanner must first parse this `arguments` string into a JSON object.
|
|
200
|
+
5. From the parsed `arguments` object, it extracts the `path` (file path) and `content` (file content).
|
|
201
|
+
|
|
202
|
+
**Example (Simplified Codex CLI JSONL Entry):**
|
|
203
|
+
|
|
204
|
+
```json
|
|
205
|
+
{
|
|
206
|
+
"timestamp": 1706947210000,
|
|
207
|
+
"tool_calls": [
|
|
208
|
+
{
|
|
209
|
+
"function": {
|
|
210
|
+
"name": "write_file",
|
|
211
|
+
"arguments": "{\"path\": \"src/utils.py\", \"content\": \"def helper():\\n return True\\n\"}"
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
]
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### 3. Gemini CLI
|
|
219
|
+
|
|
220
|
+
- **File Format**: JSON (`.json`), where one file represents a complete session.
|
|
221
|
+
- **Scan Path**: `~/.gemini/tmp/<project_hash>/chats/*.json`
|
|
222
|
+
- **Parsing Logic**:
|
|
223
|
+
1. The tool first calculates the corresponding `<project_hash>` from the target project path to locate the specific `chats` directory.
|
|
224
|
+
2. It parses the entire JSON file, which typically contains a `"messages"` or `"turns"` array logging the conversation history.
|
|
225
|
+
3. It iterates through the `messages` array, looking for `"parts"` arrays within messages from the `"assistant"` role.
|
|
226
|
+
4. Within the `parts` array, it searches for an object containing a `"functionCall"`. This object's structure is similar to that of Codex CLI.
|
|
227
|
+
5. It extracts the `"name"` (function name) and `"args"` (arguments dictionary) from the `functionCall` object.
|
|
228
|
+
|
|
229
|
+
**Example (Simplified Gemini CLI JSON Fragment):**
|
|
230
|
+
|
|
231
|
+
```json
|
|
232
|
+
{
|
|
233
|
+
"created_at": 1707033600000,
|
|
234
|
+
"projectPath": "/home/ubuntu/my-project",
|
|
235
|
+
"messages": [
|
|
236
|
+
{
|
|
237
|
+
"role": "assistant",
|
|
238
|
+
"parts": [
|
|
239
|
+
{
|
|
240
|
+
"functionCall": {
|
|
241
|
+
"name": "write_file",
|
|
242
|
+
"args": {
|
|
243
|
+
"path": "src/scanner.py",
|
|
244
|
+
"content": "class Scanner:\n pass\n"
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
]
|
|
249
|
+
}
|
|
250
|
+
]
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Summary
|
|
255
|
+
|
|
256
|
+
In essence, `ai-credit` features a specialized scanner for each supported AI tool. Each scanner is programmed to know its corresponding tool's log storage location and data structure. During analysis, the main program invokes all available scanners, collects all `FileChange` events related to the target project, and then aggregates, deduplicates, and analyzes these events to generate the final contribution report.
|
|
257
|
+
|
|
258
|
+
## Contribution Statistics Methodology
|
|
259
|
+
|
|
260
|
+
### Core Principle: Verified Existence
|
|
261
|
+
|
|
262
|
+
The tool applies a strict verification rule when calculating AI contribution statistics:
|
|
263
|
+
|
|
264
|
+
> **Only lines that currently exist in the codebase with exactly the same content are counted as AI contributions.**
|
|
265
|
+
|
|
266
|
+
### How It Works
|
|
267
|
+
|
|
268
|
+
1. **Parse AI Session Logs**: The scanner reads session files from each AI tool and extracts file change events (writes, edits, patches).
|
|
269
|
+
|
|
270
|
+
2. **Extract Changed Content**: For each file change, the tool captures:
|
|
271
|
+
- The file path
|
|
272
|
+
- Lines added (new content)
|
|
273
|
+
- Lines removed (old content)
|
|
274
|
+
|
|
275
|
+
3. **Verify Against Current Codebase**: Before counting any line as an AI contribution, the tool:
|
|
276
|
+
- Reads the current content of the target file from the repository
|
|
277
|
+
- For each line that AI claims to have added, checks if an **identical line** exists in the current file
|
|
278
|
+
- Only lines that match exactly (character-for-character) are counted
|
|
279
|
+
|
|
280
|
+
4. **Calculate Statistics**: The verified lines are then aggregated into:
|
|
281
|
+
- Per-file contribution counts
|
|
282
|
+
- Per-tool contribution totals
|
|
283
|
+
- Overall repository contribution ratios
|
|
284
|
+
|
|
285
|
+
### Example
|
|
286
|
+
|
|
287
|
+
If an AI tool's log shows it added these lines to `src/utils.py`:
|
|
288
|
+
|
|
289
|
+
```python
|
|
290
|
+
def helper():
|
|
291
|
+
return True
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
But the current `src/utils.py` in the repository contains:
|
|
295
|
+
|
|
296
|
+
```python
|
|
297
|
+
def helper():
|
|
298
|
+
return False # Changed from True
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Then the line `return True` will **NOT** be counted as an AI contribution because it no longer exists in the codebase. Only if the line matches exactly will it be included in the statistics.
|
|
302
|
+
|
|
303
|
+
### Why This Approach?
|
|
304
|
+
|
|
305
|
+
This methodology ensures that:
|
|
306
|
+
- Statistics reflect **actual, surviving** AI contributions
|
|
307
|
+
- Code that was later modified or removed by humans (or other AI tools) is not attributed to the original AI
|
|
308
|
+
- Contribution ratios are accurate and meaningful for understanding the current state of the codebase
|
|
309
|
+
|
|
310
|
+
## Limitations
|
|
311
|
+
|
|
312
|
+
- Only tracks AI contributions that are recorded in local session files
|
|
313
|
+
- Cannot detect AI-generated code that was copy-pasted manually
|
|
314
|
+
- Accuracy depends on the completeness of AI tool session logs
|
|
315
|
+
- Some AI tools may not record all file operations
|
|
316
|
+
|
|
317
|
+
## Contributing
|
|
318
|
+
|
|
319
|
+
Contributions are welcome! Please feel free to submit issues and pull requests.
|
|
320
|
+
|
|
321
|
+
### Adding Support for New AI Tools
|
|
322
|
+
|
|
323
|
+
1. Create a new scanner in `src/scanners/`
|
|
324
|
+
2. Extend the `BaseScanner` class
|
|
325
|
+
3. Implement `tool`, `storagePath`, `scan()`, and `parseSessionFile()` methods
|
|
326
|
+
4. Add the scanner to `analyzer.ts`
|
|
327
|
+
|
|
328
|
+
## License
|
|
329
|
+
|
|
330
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { AISession, AITool, ContributionStats } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Main analyzer that coordinates all scanners and computes statistics
|
|
4
|
+
*/
|
|
5
|
+
export declare class ContributionAnalyzer {
|
|
6
|
+
private projectPath;
|
|
7
|
+
private scanners;
|
|
8
|
+
constructor(projectPath: string);
|
|
9
|
+
/**
|
|
10
|
+
* Get list of available AI tools
|
|
11
|
+
*/
|
|
12
|
+
getAvailableTools(): AITool[];
|
|
13
|
+
/**
|
|
14
|
+
* Scan all sessions from all tools
|
|
15
|
+
*/
|
|
16
|
+
scanAllSessions(tools?: AITool[]): AISession[];
|
|
17
|
+
/**
|
|
18
|
+
* Analyze the repository and compute contribution statistics
|
|
19
|
+
*/
|
|
20
|
+
analyze(tools?: AITool[]): ContributionStats;
|
|
21
|
+
/**
|
|
22
|
+
* Get all files in the repository (excluding common ignore patterns)
|
|
23
|
+
*/
|
|
24
|
+
private getRepoFiles;
|
|
25
|
+
/**
|
|
26
|
+
* Count total lines in all repository files
|
|
27
|
+
*/
|
|
28
|
+
private countTotalLines;
|
|
29
|
+
/**
|
|
30
|
+
* Compute statistics by AI tool
|
|
31
|
+
*/
|
|
32
|
+
private computeToolStats;
|
|
33
|
+
/**
|
|
34
|
+
* Compute statistics by file using Verified Existence logic
|
|
35
|
+
*/
|
|
36
|
+
private computeFileStats;
|
|
37
|
+
}
|