claude-attribution 1.2.0 → 1.2.1

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 CHANGED
@@ -6,18 +6,14 @@
6
6
  > ```bash
7
7
  > npm install -g claude-attribution
8
8
  > claude-attribution install ~/Code/your-repo
9
- > git add .claude/settings.json .github/workflows/claude-attribution-pr.yml .gitignore && git commit -m "chore: install claude-attribution hooks"
9
+ > claude-attribution init --ai # repo built with Claude Code or --human if human/mixed
10
+ > git add .claude/settings.json .gitignore && git commit -m "chore: install claude-attribution hooks"
10
11
  > ```
11
- > From then on, just work normally. After each `git commit` you'll see a one-line attribution summary in your terminal. When you open a PR whether Claude creates it or you run `gh pr create` yourself metrics are injected into the PR body automatically, no command needed.
12
+ > From then on, just work normally. After each `git commit` you'll see a one-line attribution summary in your terminal. When you're ready to open a PR, run `/pr` in Claude Code (or `claude-attribution pr "feat: your title"`)it fills in the metrics automatically, no copy-paste needed.
12
13
  >
13
- > **Already using Claude Code before installing this?** Run `claude-attribution init` once to declare the baseline this enables the codebase-wide AI% signal in PR metrics:
14
- > - **All Claude Code:** `claude-attribution init --ai && git push origin refs/notes/claude-attribution-map`
15
- > - **All human (or mixed):** `claude-attribution init` (or `--human`) — prints a confirmation, no note written; human is the default
16
- > - **Not sure?** Default to `--human`. Attribution accumulates accurately from new commits forward.
14
+ > **Using Copilot?** The tool still works for tracking Claude usage alongside Copilot. Copilot line-level attribution isn't supported yet for Copilot-specific stats, use the GitHub Copilot usage dashboard. Both tools' org-level data flows into the VP Datadog dashboard automatically on every PR merge.
17
15
  >
18
- > **Using Copilot?** The tool still works for tracking Claude usage alongside Copilot. Copilot line-level attribution isn't supported yet — for Copilot-specific stats, use the GitHub Copilot usage dashboard under your organization's Settings → Copilot. Both tools' org-level data flows into the VP Datadog dashboard automatically on every PR merge.
19
- >
20
- > **Requirements:** [Bun](https://bun.sh) (preferred) or Node 18+, and `gh` (GitHub CLI) authenticated.
16
+ > **Requirements:** [Bun](https://bun.sh) (preferred) or Node 18+, and `gh` (GitHub CLI) authenticated for the `/pr` command.
21
17
 
22
18
  ---
23
19
 
@@ -51,17 +47,45 @@ bun install
51
47
 
52
48
  ### Install into a repo (per repo, per developer)
53
49
 
54
- **npm install:**
50
+ **Step 1 — Run the installer:**
51
+
55
52
  ```bash
53
+ # npm install:
56
54
  claude-attribution install ~/Code/your-repo
55
+
56
+ # clone install:
57
+ bun ~/Code/claude-attribution/src/setup/install.ts ~/Code/your-repo
57
58
  ```
58
59
 
59
- **Clone install:**
60
+ **Step 2 — Declare your attribution baseline (`init`):**
61
+
62
+ This step tells the tool whether the codebase was written by Claude or by humans before this install. It only needs to be run once.
63
+
60
64
  ```bash
61
- bun ~/Code/claude-attribution/src/setup/install.ts ~/Code/your-repo
65
+ # Repo was built entirely with Claude Code — mark all files as AI-written:
66
+ claude-attribution init --ai
67
+
68
+ # Repo is human-written, or a mix — confirm the default (no note written):
69
+ claude-attribution init --human
70
+
71
+ # Not sure? Run with no flag — same as --human, prints a confirmation:
72
+ claude-attribution init
73
+ ```
74
+
75
+ > **Why this matters:** Without `init`, the codebase-wide AI% starts at 0% and grows only from new commits. If your repo is all Claude Code, run `init --ai` now or the metrics will be misleading until the entire codebase has been re-committed line by line.
76
+
77
+ **Step 3 — Commit and push:**
78
+
79
+ ```bash
80
+ git add .claude/settings.json .github/workflows/claude-attribution-pr.yml .gitignore
81
+ git commit -m "chore: install claude-attribution hooks"
82
+ git push
83
+
84
+ # If you ran init --ai, also push the minimap notes:
85
+ git push origin refs/notes/claude-attribution-map
62
86
  ```
63
87
 
64
- The installer makes six changes to the target repo:
88
+ The installer makes the following changes to the target repo:
65
89
 
66
90
  **`.claude/settings.json`** — merges six Claude Code hooks:
67
91
 
@@ -85,17 +109,7 @@ The installer makes six changes to the target repo:
85
109
 
86
110
  **`.gitignore`** — adds `.claude/logs/` so tool usage logs don't end up in version control.
87
111
 
88
- ### Committing the settings change
89
-
90
- The `.claude/settings.json` and workflow changes should be committed so all developers get the hooks and all PRs get metrics automatically.
91
-
92
- ```bash
93
- # After running the installer:
94
- git add .claude/settings.json .github/workflows/claude-attribution-pr.yml .gitignore
95
- git commit -m "chore: install claude-attribution hooks"
96
- ```
97
-
98
- ### Backfilling the attribution minimap
112
+ ### Attribution minimap detailed options
99
113
 
100
114
  The attribution minimap tracks cumulative AI% across the entire codebase, carrying attribution forward across sessions and developers. For new commits it is updated automatically. For the history that predates the install, you declare the baseline once using `claude-attribution init`.
101
115
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-attribution",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "AI code attribution tracking for Claude Code sessions — checkpoint-based line diff approach",
5
5
  "type": "module",
6
6
  "bin": {
@@ -18,6 +18,9 @@
18
18
  */
19
19
  import { execFile } from "child_process";
20
20
  import { promisify } from "util";
21
+ import { writeFile, unlink, mkdtemp, rmdir } from "fs/promises";
22
+ import { tmpdir } from "os";
23
+ import { join } from "path";
21
24
  import { hashLine } from "./differ.ts";
22
25
 
23
26
  const execFileAsync = promisify(execFile);
@@ -107,21 +110,38 @@ export async function writeMinimap(
107
110
  repoRoot: string,
108
111
  commitSha = "HEAD",
109
112
  ): Promise<void> {
110
- const json = JSON.stringify(result, null, 2);
111
- await run(
112
- "git",
113
- [
114
- "notes",
115
- "--ref",
116
- MINIMAP_NOTES_REF,
117
- "add",
118
- "--force",
119
- "-m",
120
- json,
121
- commitSha,
122
- ],
123
- repoRoot,
124
- );
113
+ // Write JSON to a temp file and use -F to avoid E2BIG on large repos.
114
+ // Passing the full minimap as a -m argument fails when the JSON exceeds
115
+ // the OS argument size limit (~500KB on macOS).
116
+ //
117
+ // Use mkdtemp to create a unique, isolated temp directory rather than a
118
+ // predictable filename in the shared OS temp dir — prevents collisions
119
+ // under concurrent runs and symlink/race attacks.
120
+ const tmpDir = await mkdtemp(join(tmpdir(), "claude-attribution-minimap-"));
121
+ const tmpFile = join(tmpDir, "minimap.json");
122
+ try {
123
+ await writeFile(tmpFile, JSON.stringify(result, null, 2), {
124
+ encoding: "utf8",
125
+ flag: "wx",
126
+ });
127
+ await run(
128
+ "git",
129
+ [
130
+ "notes",
131
+ "--ref",
132
+ MINIMAP_NOTES_REF,
133
+ "add",
134
+ "--force",
135
+ "-F",
136
+ tmpFile,
137
+ commitSha,
138
+ ],
139
+ repoRoot,
140
+ );
141
+ } finally {
142
+ await unlink(tmpFile).catch(() => {});
143
+ await rmdir(tmpDir).catch(() => {});
144
+ }
125
145
  }
126
146
 
127
147
  export async function readMinimap(