claude-carbon 1.1.2 โ 1.5.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/README.md +159 -15
- package/bin/claude-carbon.js +44 -5
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -12,17 +12,25 @@ Track the carbon footprint of your Claude Code sessions.
|
|
|
12
12
|
|
|
13
13
|
**1. Install (or update):**
|
|
14
14
|
|
|
15
|
+
macOS, Linux, WSL:
|
|
16
|
+
|
|
15
17
|
```bash
|
|
16
18
|
curl -fsSL https://raw.githubusercontent.com/gwittebolle/claude-carbon/main/install.sh | bash
|
|
17
19
|
```
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
Windows (PowerShell), which needs [Git for Windows](https://git-scm.com/downloads/win) and two packages first - see [Windows](#windows):
|
|
22
|
+
|
|
23
|
+
```powershell
|
|
24
|
+
irm https://raw.githubusercontent.com/gwittebolle/claude-carbon/main/install.ps1 | iex
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Or, on any platform with Node.js:
|
|
20
28
|
|
|
21
29
|
```bash
|
|
22
30
|
npx claude-carbon
|
|
23
31
|
```
|
|
24
32
|
|
|
25
|
-
Same command to install and to update to the latest version (
|
|
33
|
+
Same command to install and to update to the latest version (all three run the same installer).
|
|
26
34
|
|
|
27
35
|
**2. Restart Claude Code.** Your CO2 appears in the status line:
|
|
28
36
|
|
|
@@ -32,7 +40,7 @@ claude-carbon โฅ main | ๐ข Opus 4.7 โโโโโโโโโโ 35% | $0.5
|
|
|
32
40
|
|
|
33
41
|
Segments, left to right: project + git branch, model + context window %, session cost + CO2, 5h block usage % + reset time. A ๐ฅ prefix appears when the sustained burn rate would overshoot 100% of the limit by the end of the 5h block (after a 15 min grace window, only once usage reaches 15%).
|
|
34
42
|
|
|
35
|
-
> **
|
|
43
|
+
> **Where the CO2 shows up.** The status line is a feature of the Claude Code terminal UI. It is displayed only when you run `claude` in a terminal, including the integrated terminal of VS Code or JetBrains. The IDE extensions' chat panel has no status line at all, so nothing is displayed there even though the hooks still run and your sessions are recorded: `/carbon-report` covers them. If you use the VS Code panel and want the live CO2, open a terminal in VS Code (`` Ctrl+` ``) and run `claude` from there. The web app (claude.ai/code) and the desktop app run neither the status line nor the hooks, so nothing is displayed or recorded there.
|
|
36
44
|
|
|
37
45
|
**5h quota source.** The percentage comes directly from Anthropic's `/api/oauth/usage` endpoint (the same data Claude Code displays in `/usage`). No heuristic, no token-limit file to seed. Two sources in order:
|
|
38
46
|
|
|
@@ -60,7 +68,11 @@ Accurate on every plan, including Max 20x.
|
|
|
60
68
|
<img src="docs/example-report-v2.png" alt="Claude Carbon Report" width="540">
|
|
61
69
|
</p>
|
|
62
70
|
|
|
63
|
-
Generate yours with `/carbon-card` in Claude Code.
|
|
71
|
+
Generate yours with `/carbon-card` in Claude Code. The summary and detailed PNGs land in
|
|
72
|
+
`~/Downloads/claude-carbon/` (the Windows Downloads folder follows the system setting, so a
|
|
73
|
+
OneDrive-redirected one is honoured) and the folder opens in your file manager, with the
|
|
74
|
+
card selected on macOS. `CLAUDE_CARBON_EXPORT_DIR` picks another folder;
|
|
75
|
+
`CLAUDE_CARBON_NO_OPEN=1` skips the opening.
|
|
64
76
|
|
|
65
77
|
<details>
|
|
66
78
|
<summary>Advanced options (CLI)</summary>
|
|
@@ -104,7 +116,7 @@ install claude-carbon into that same directory by passing `CLAUDE_CONFIG_DIR` to
|
|
|
104
116
|
curl -fsSL https://raw.githubusercontent.com/gwittebolle/claude-carbon/main/install.sh | CLAUDE_CONFIG_DIR=~/.claude-work bash
|
|
105
117
|
```
|
|
106
118
|
|
|
107
|
-
The status line, the
|
|
119
|
+
The status line, the hooks, the database and the `/carbon-*` commands all live under that config dir, so each environment tracks its own sessions independently. When `CLAUDE_CONFIG_DIR` is unset everything falls back to `~/.claude` as before.
|
|
108
120
|
|
|
109
121
|
</details>
|
|
110
122
|
|
|
@@ -114,9 +126,10 @@ The status line, the Stop hook, the database and the `/carbon-*` commands all li
|
|
|
114
126
|
```bash
|
|
115
127
|
git clone https://github.com/gwittebolle/claude-carbon.git ~/code/claude-carbon
|
|
116
128
|
bash ~/code/claude-carbon/scripts/setup.sh
|
|
129
|
+
bash ~/code/claude-carbon/scripts/configure-settings.sh
|
|
117
130
|
```
|
|
118
131
|
|
|
119
|
-
|
|
132
|
+
The second script merges the block below into `~/.claude/settings.json` (additively: an existing status line or third-party hooks are left alone) and symlinks the `/carbon-*` commands. To wire it by hand instead, skip it and add:
|
|
120
133
|
|
|
121
134
|
```json
|
|
122
135
|
{
|
|
@@ -135,11 +148,24 @@ Then add to `~/.claude/settings.json`:
|
|
|
135
148
|
}
|
|
136
149
|
]
|
|
137
150
|
}
|
|
151
|
+
],
|
|
152
|
+
"SessionStart": [
|
|
153
|
+
{
|
|
154
|
+
"matcher": "",
|
|
155
|
+
"hooks": [
|
|
156
|
+
{
|
|
157
|
+
"type": "command",
|
|
158
|
+
"command": "~/code/claude-carbon/scripts/safety-rescan.sh"
|
|
159
|
+
}
|
|
160
|
+
]
|
|
161
|
+
}
|
|
138
162
|
]
|
|
139
163
|
}
|
|
140
164
|
}
|
|
141
165
|
```
|
|
142
166
|
|
|
167
|
+
The `Stop` hook records the session that just ended. The `SessionStart` one re-scans for sessions that hook missed (crash, kill) and drives the daily update check the status line reads; without it you are never told a new version exists.
|
|
168
|
+
|
|
143
169
|
Restart Claude Code.
|
|
144
170
|
|
|
145
171
|
</details>
|
|
@@ -148,15 +174,28 @@ Restart Claude Code.
|
|
|
148
174
|
|
|
149
175
|
claude-carbon measures one developer's sessions, locally. If the question comes from your CTO, a client RFP or a CSR committee, the same methodology exists as a hosted layer:
|
|
150
176
|
|
|
151
|
-
- [Free calculator and per-model factor sheets](https://tokenclimate.com/
|
|
152
|
-
- [
|
|
153
|
-
- [TokenClimate](https://tokenclimate.com) - hosted team dashboards. Both sides share this repo's golden vectors, verified weekly in CI.
|
|
177
|
+
- [Free calculator](https://tokenclimate.com/en/calculator?ref=github) and [per-model factor sheets](https://tokenclimate.com/en/models?ref=github) - the exact versioned factors of this repo, browsable.
|
|
178
|
+
- [AI usage report](https://tokenclimate.com/bilan/en?ref=github) - a self-serve, shareable report of your organisation's real Claude usage (cost, CO2e, water, energy), generated in minutes from an Anthropic admin key. The key is never stored; the methodology annex is citation-ready.
|
|
179
|
+
- [TokenClimate](https://tokenclimate.com/en?ref=github) - hosted team dashboards. Both sides share this repo's golden vectors, verified weekly in CI.
|
|
154
180
|
|
|
155
181
|
The only places the OSS points there are a one-line footer in `/carbon-report` and a small credit on the `/carbon-card` PNGs. No status-line promo, no email capture: nothing leaves your machine.
|
|
156
182
|
|
|
183
|
+
### PR dev footprint (/carbon-pr)
|
|
184
|
+
|
|
185
|
+
The number reviewers rarely see is what the PR cost to develop: your local Claude Code sessions while building the branch. `/carbon-pr` (or `scripts/generate-pr-report.sh`) sums the recorded sessions of the current branch and posts one sticky comment on its open PR, through your own `gh` auth. Run it after your push; running it again updates the same comment in place.
|
|
186
|
+
|
|
187
|
+
```
|
|
188
|
+
**Claude Code carbon report** ยท developing this PR
|
|
189
|
+
124 g CO2e ยท $3.00 ยท 180k tokens ยท 1.5M cache reads ยท 2 sessions
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
How the sessions are attributed: the Stop hook stores each session's git branch (read from the transcript), and the report selects `project + branch`. Sessions recorded before this column existed carry no branch; `scripts/backfill.sh` repairs them while their transcripts are still on disk (about 30 days). Sessions started from a subdirectory of the repo are stored under the subdirectory's name and stay out of the sum. A session that ends on another branch than it started is attributed to where it finished.
|
|
193
|
+
|
|
194
|
+
Turning it off is the default: nothing is posted unless you run it. `--dry-run` previews the comment, `--pr <number>` targets a specific PR, and deleting the comment on GitHub is the full cleanup.
|
|
195
|
+
|
|
157
196
|
## How it works
|
|
158
197
|
|
|
159
|
-

|
|
160
199
|
|
|
161
200
|
**Three data paths, two levels of accuracy:**
|
|
162
201
|
|
|
@@ -164,13 +203,13 @@ The only places the OSS points there are a one-line footer in `/carbon-report` a
|
|
|
164
203
|
| -------------------- | ----------------------- | --------------------- | ------------ | ------------------- | ------------- |
|
|
165
204
|
| `backfill.sh` | Manual / setup | JSONL files | Included | Counted (8% energy) | Best estimate |
|
|
166
205
|
| `persist-session.sh` | Stop hook (session end) | JSONL files | Included | Counted (8% energy) | Best estimate |
|
|
167
|
-
| `statusline.sh` | Every turn (live) | `
|
|
206
|
+
| `statusline.sh` | Every turn (live) | `carbon.db` row | Included | Counted (8% energy) | One turn late |
|
|
168
207
|
|
|
169
208
|
**backfill** and **persist-session** parse the raw JSONL transcripts (main session + subagent files), applying per-model emission factors. They deduplicate assistant messages by `(message.id, requestId)`, so resumed and compacted sessions are not double-counted (this matches `ccusage`; without it the token sum inflates roughly 3x). Each session stores its raw token breakdown (input, cache write, cache read, output), which feeds the SQLite database used by reports.
|
|
170
209
|
|
|
171
|
-
**Cost** is the theoretical API list value (pay-as-you-go), not your subscription price: input, output, cache write
|
|
210
|
+
**Cost** is the theoretical API list value (pay-as-you-go), not your subscription price: input, output, cache write, and cache read (0.1x input) at current Anthropic rates, set in `data/prices.json`. Cache writes are billed per TTL tier, 1.25x input for the 5-minute tier and 2x for the 1-hour one; each session's split is read from its transcript rather than assumed (Claude Code writes at the 1-hour tier). On deduplicated data it matches `ccusage`.
|
|
172
211
|
|
|
173
|
-
**statusline** reads `
|
|
212
|
+
**statusline** reads this session's row from `carbon.db` at each turn, so the CO2 it shows is the session total on the same basis as the reports, one turn behind at most. Before that row exists (first turn, or no database yet) it falls back to an estimate from `context_window.total_input_tokens`, which is the size of the current context rather than a running total: subagents are invisible to it and every compaction sends it back down. Either way the status line displays, it never feeds the reports.
|
|
174
213
|
|
|
175
214
|
### Surviving the 30-day transcript purge
|
|
176
215
|
|
|
@@ -186,6 +225,8 @@ bash scripts/recompute.sh
|
|
|
186
225
|
| ---------------- | --------------------------------------------------- |
|
|
187
226
|
| `/carbon-report` | Text report with totals, equivalences, top sessions |
|
|
188
227
|
| `/carbon-card` | Generate shareable PNG report cards |
|
|
228
|
+
| `/carbon-badge` | Shields.io badge of your total footprint for your READMEs |
|
|
229
|
+
| `/carbon-pr` | Post the dev footprint of the current branch on its PR |
|
|
189
230
|
| `/carbon-update` | Update to the latest version and re-price history |
|
|
190
231
|
|
|
191
232
|
<details>
|
|
@@ -200,11 +241,29 @@ bash scripts/recompute.sh
|
|
|
200
241
|
| `backfill.sh` | Re-parse all historical JSONL transcripts (incl. subagents) |
|
|
201
242
|
| `recompute.sh` | Re-derive cost/CO2 from stored tokens after a price/factor change (no transcripts needed) |
|
|
202
243
|
| `generate-report.sh` | Export PNG report cards (CLI, with `--since` / `--until` / `--all`) |
|
|
244
|
+
| `generate-badge.sh` | Print the shields.io badge markdown + URL (CLI) |
|
|
245
|
+
| `generate-pr-report.sh` | Post the branch's dev footprint on its PR (CLI, `--dry-run` / `--pr`) |
|
|
203
246
|
|
|
204
247
|
Note: backfill now derives project names from the transcript's `cwd` (matching the live hook). Sessions backfilled before this change keep their old, possibly truncated names; delete those rows and re-run `backfill.sh` to normalize them.
|
|
205
248
|
|
|
206
249
|
</details>
|
|
207
250
|
|
|
251
|
+
## Badge
|
|
252
|
+
|
|
253
|
+
`/carbon-badge` prints a ready-to-paste shields.io badge with your measured all-time footprint, clickable back to this repo:
|
|
254
|
+
|
|
255
|
+
[](https://github.com/gwittebolle/claude-carbon)
|
|
256
|
+
|
|
257
|
+
<sub>That badge is live, not a mockup: the author's own total, 1,025 sessions measured between 15 January 2026 and 20 August 2026. It is one developer's footprint, not the project's.</sub>
|
|
258
|
+
|
|
259
|
+
```markdown
|
|
260
|
+
[](https://github.com/gwittebolle/claude-carbon)
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
The badge is a static image built from your local database, so the number is measured, not estimated on the fly. Re-run `/carbon-badge` whenever you want to refresh it.
|
|
264
|
+
|
|
265
|
+
Numbers follow the locale the report uses (`fr` prints `12,4 kg`, `us` and the world default print `12.4 kg`); `CLAUDE_CARBON_LOCALE` forces a set.
|
|
266
|
+
|
|
208
267
|
## Using with ccstatusline
|
|
209
268
|
|
|
210
269
|
Claude Code accepts a single `statusLine` command, so claude-carbon's full status line and [ccstatusline](https://github.com/sirmalloc/ccstatusline) cannot run side by side. If ccstatusline drives your status line, embed the CO2 segment instead: in the ccstatusline TUI, add a `Custom Command` widget pointing to
|
|
@@ -234,6 +293,8 @@ Factors from [Jegham et al. 2025](https://arxiv.org/abs/2505.09598), an arXiv pr
|
|
|
234
293
|
- Carbon intensity uses the AWS region grid (location-based, 0.287 kgCO2e/kWh), not real-time grid data. This sits at the low end of the location-based range; the US national average is ~380 g/kWh.
|
|
235
294
|
- Anthropic does not publish Scope 1, 2, or 3 emissions. These estimates are independent and based on academic research, not provider data.
|
|
236
295
|
|
|
296
|
+
Report equivalences follow your locale, since a car and a kWh differ by ~2x between countries: ADEME/SNCF factors on a French or undetected locale, EPA ones in miles on a US locale, world-average ones otherwise (200 gCO2/km by car, 8.7 g per smartphone charge). Force a set with `CLAUDE_CARBON_LOCALE` (`fr`, `us`, `world`, or any locale string). The factors live in `data/factors.json` under `equivalences`.
|
|
297
|
+
|
|
237
298
|
Factors are editable in `data/factors.json`. See [METHODOLOGY.md](METHODOLOGY.md) for the full scientific basis, formula, and equivalences.
|
|
238
299
|
|
|
239
300
|
### Golden vectors
|
|
@@ -260,9 +321,9 @@ curl -fsSL https://raw.githubusercontent.com/gwittebolle/claude-carbon/main/inst
|
|
|
260
321
|
- `sqlite3` - local database
|
|
261
322
|
- `git` - branch detection in status line (optional)
|
|
262
323
|
- `curl` - 5h quota usage via Anthropic's `/api/oauth/usage` endpoint (optional, 60s cache)
|
|
263
|
-
- `playwright-core` + Chromium - PNG export for `/carbon-card` (optional)
|
|
324
|
+
- `node` + `playwright-core` + Chromium - PNG export for `/carbon-card` (optional)
|
|
264
325
|
|
|
265
|
-
`jq` and `sqlite3` are pre-installed on macOS. On Linux: `apt install jq sqlite3`.
|
|
326
|
+
`jq` and `sqlite3` are pre-installed on macOS. On Linux: `apt install jq sqlite3`. On Windows, see below.
|
|
266
327
|
|
|
267
328
|
To use `/carbon-card`, install Playwright and its Chromium browser:
|
|
268
329
|
|
|
@@ -271,6 +332,72 @@ npm install -g playwright-core
|
|
|
271
332
|
npx playwright install chromium
|
|
272
333
|
```
|
|
273
334
|
|
|
335
|
+
## Windows
|
|
336
|
+
|
|
337
|
+
claude-carbon is bash, and stays bash on Windows. That is deliberate rather than a
|
|
338
|
+
shortcut: on native Windows, Claude Code runs status line and hook commands through
|
|
339
|
+
the bash that ships with [Git for Windows](https://git-scm.com/downloads/win), falling
|
|
340
|
+
back to PowerShell only when Git Bash is absent
|
|
341
|
+
([status line docs](https://code.claude.com/docs/en/statusline#windows-configuration),
|
|
342
|
+
[hooks docs](https://code.claude.com/docs/en/hooks)). The plugin speaks the shell its
|
|
343
|
+
host already spawns.
|
|
344
|
+
|
|
345
|
+
**Native Windows.** Install Git for Windows, plus the two commands it does not ship:
|
|
346
|
+
|
|
347
|
+
```powershell
|
|
348
|
+
winget install Git.Git --source winget
|
|
349
|
+
winget install jqlang.jq --source winget
|
|
350
|
+
winget install SQLite.SQLite --source winget
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
Then, in the same terminal:
|
|
354
|
+
|
|
355
|
+
```powershell
|
|
356
|
+
irm https://raw.githubusercontent.com/gwittebolle/claude-carbon/main/install.ps1 | iex
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
Everything else the plugin needs - `bash`, `awk`, `sed`, `grep`, `date`, `curl`,
|
|
360
|
+
`git`, `cygpath` - comes with Git for Windows.
|
|
361
|
+
|
|
362
|
+
**WSL 2.** Nothing special: run the `curl | bash` installer inside your distribution.
|
|
363
|
+
Claude Code, its transcripts and claude-carbon all live on the Linux side. This is
|
|
364
|
+
the path to pick if your projects are already in WSL. VS Code reaches it through the
|
|
365
|
+
Remote - WSL extension.
|
|
366
|
+
|
|
367
|
+
**Marketplace install.** `/plugin install claude-carbon@claude-carbon` behaves the
|
|
368
|
+
same as on macOS, once Git for Windows, `jq` and `sqlite3` are present.
|
|
369
|
+
|
|
370
|
+
### Windows specifics
|
|
371
|
+
|
|
372
|
+
- **Git Bash is required.** Without it Claude Code routes commands to PowerShell,
|
|
373
|
+
which cannot run a `.sh` file. `claude doctor` tells you which shell it picked. If
|
|
374
|
+
Git is installed somewhere unusual, point Claude Code at it in `settings.json`:
|
|
375
|
+
`{"env": {"CLAUDE_CODE_GIT_BASH_PATH": "C:\\Program Files\\Git\\bin\\bash.exe"}}`.
|
|
376
|
+
- **Paths in `settings.json` use forward slashes** (`C:/Users/you/code/claude-carbon/...`).
|
|
377
|
+
Git Bash eats unquoted backslashes, and the command then fails with no visible error.
|
|
378
|
+
The installer writes them correctly; only hand-edits need the care.
|
|
379
|
+
- **Slash commands are copied, not symlinked.** Git Bash cannot create a real symlink
|
|
380
|
+
without Developer Mode, so `/carbon-report` and friends are copied into
|
|
381
|
+
`~/.claude/commands/` and refreshed on every update.
|
|
382
|
+
- **Sandboxing is not available** on native Windows (a Claude Code limitation, not
|
|
383
|
+
this plugin's). Use WSL 2 if you need it.
|
|
384
|
+
- **`/carbon-card` additionally needs Node.js**: `winget install OpenJS.NodeJS --source winget`.
|
|
385
|
+
- **Behind a TLS-inspecting proxy or antivirus**, the clone fails with
|
|
386
|
+
`SSL certificate problem: unable to get local issuer certificate`. Git for Windows
|
|
387
|
+
checks certificates against its own bundled CA list, which does not know the root
|
|
388
|
+
such tools re-sign traffic with; the Windows certificate store does. Switch git to
|
|
389
|
+
it (verification stays on) and rerun the installer:
|
|
390
|
+
`git config --global http.sslBackend schannel`. The installer prints this hint
|
|
391
|
+
when it detects the case. The same interception is why `winget` needs
|
|
392
|
+
`--source winget` on those machines: the Microsoft Store source fails its
|
|
393
|
+
certificate check and, without an explicit source, winget aborts instead of
|
|
394
|
+
falling back.
|
|
395
|
+
|
|
396
|
+
CI runs the full test suite on `windows-latest` under Git Bash, alongside Ubuntu,
|
|
397
|
+
plus two Windows-only suites: `tests/run-windows-e2e.sh` (native paths through the Stop
|
|
398
|
+
hook and the status line, hook manifests spawned the way Claude Code spawns them) and
|
|
399
|
+
`tests/run-install-ps1-tests.ps1`.
|
|
400
|
+
|
|
274
401
|
## Reduce your footprint
|
|
275
402
|
|
|
276
403
|
Measuring is step one. Here are concrete levers to reduce your AI carbon footprint, ranked by impact.
|
|
@@ -322,6 +449,16 @@ By default, Claude Code compacts context at 95% usage. Compacting earlier keeps
|
|
|
322
449
|
}
|
|
323
450
|
```
|
|
324
451
|
|
|
452
|
+
### Disconnect unused MCP servers
|
|
453
|
+
|
|
454
|
+
Every connected MCP server ships its full tool schemas into the context window with every request, whether the session uses them or not. Most of that overhead is served from prompt cache after the first turn, and cache reads carry a much lower energy factor (see METHODOLOGY.md), so the saving per turn is modest; the gain comes from repetition across every turn of every session.
|
|
455
|
+
|
|
456
|
+
```bash
|
|
457
|
+
claude mcp list
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
Keep the servers the project actually uses, remove the rest with `claude mcp remove <name>`.
|
|
461
|
+
|
|
325
462
|
### Write concise instructions
|
|
326
463
|
|
|
327
464
|
Add to your project's CLAUDE.md:
|
|
@@ -344,6 +481,13 @@ These reductions are indicative estimates, not measurements on a benchmark workl
|
|
|
344
481
|
| Haiku subagents | -75% vs Opus, -50% vs Sonnet |
|
|
345
482
|
| **All combined** | **-50 to 70% total** |
|
|
346
483
|
|
|
484
|
+
### Related projects
|
|
485
|
+
|
|
486
|
+
- [EcoLogits](https://ecologits.ai) - Python library estimating the footprint of GenAI API calls across providers.
|
|
487
|
+
- [CodeCarbon](https://github.com/mlco2/codecarbon) - measures the emissions of compute you run yourself (training, local inference).
|
|
488
|
+
- [ImpactIA](https://github.com/SNCFdevelopers/ImpactIA) - AI impact calculator and guide by SNCF, Wavestone and Resilio.
|
|
489
|
+
- [green-claude](https://github.com/Institut-du-Numerique-Responsable/green-claude) - Claude Code skill that steers generated code toward eco-design rules (RGESN, GR491).
|
|
490
|
+
|
|
347
491
|
### Further reading
|
|
348
492
|
|
|
349
493
|
- [IEA - Energy and AI (2025)](https://www.iea.org/reports/energy-and-ai/) - data center projections
|
package/bin/claude-carbon.js
CHANGED
|
@@ -6,11 +6,45 @@
|
|
|
6
6
|
"use strict";
|
|
7
7
|
|
|
8
8
|
const { spawnSync } = require("node:child_process");
|
|
9
|
-
const { mkdtempSync, writeFileSync } = require("node:fs");
|
|
9
|
+
const { existsSync, mkdtempSync, writeFileSync } = require("node:fs");
|
|
10
10
|
const { tmpdir } = require("node:os");
|
|
11
11
|
const { join } = require("node:path");
|
|
12
12
|
const pkg = require("../package.json");
|
|
13
13
|
|
|
14
|
+
// The installer, the hooks and the status line are all bash. On macOS and Linux
|
|
15
|
+
// that is simply "bash"; on Windows it is the bash.exe that ships with Git for
|
|
16
|
+
// Windows, which is also the shell Claude Code itself spawns for hooks and the
|
|
17
|
+
// status line. Returns null when nothing usable is found.
|
|
18
|
+
function findBash() {
|
|
19
|
+
if (process.platform !== "win32") return "bash";
|
|
20
|
+
|
|
21
|
+
const candidates = [
|
|
22
|
+
// Same variable Claude Code reads, so a user who already pointed Claude Code
|
|
23
|
+
// at a non-default Git install does not have to say it twice.
|
|
24
|
+
process.env.CLAUDE_CODE_GIT_BASH_PATH,
|
|
25
|
+
join(process.env.ProgramFiles || "C:\\Program Files", "Git", "bin", "bash.exe"),
|
|
26
|
+
join(process.env["ProgramFiles(x86)"] || "C:\\Program Files (x86)", "Git", "bin", "bash.exe"),
|
|
27
|
+
join(process.env.LOCALAPPDATA || "", "Programs", "Git", "bin", "bash.exe"),
|
|
28
|
+
].filter(Boolean);
|
|
29
|
+
|
|
30
|
+
for (const candidate of candidates) {
|
|
31
|
+
if (existsSync(candidate)) return candidate;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Last resort: ask PATH. C:\Windows\System32\bash.exe is excluded on purpose โ
|
|
35
|
+
// that one is the WSL launcher, and running the installer through it would set
|
|
36
|
+
// claude-carbon up inside the Linux distribution instead of on Windows.
|
|
37
|
+
const where = spawnSync("where.exe", ["bash"], { encoding: "utf8" });
|
|
38
|
+
if (where.status === 0 && where.stdout) {
|
|
39
|
+
for (const line of where.stdout.split(/\r?\n/)) {
|
|
40
|
+
const path = line.trim();
|
|
41
|
+
if (path && !/\\System32\\/i.test(path) && existsSync(path)) return path;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
|
|
14
48
|
const INSTALL_URL =
|
|
15
49
|
process.env.CLAUDE_CARBON_INSTALL_URL ||
|
|
16
50
|
"https://raw.githubusercontent.com/gwittebolle/claude-carbon/main/install.sh";
|
|
@@ -46,9 +80,14 @@ if (arg !== undefined && arg !== "--dry-run") {
|
|
|
46
80
|
}
|
|
47
81
|
|
|
48
82
|
async function main() {
|
|
49
|
-
|
|
83
|
+
const bash = findBash();
|
|
84
|
+
if (!bash) {
|
|
50
85
|
console.error(
|
|
51
|
-
"claude-carbon
|
|
86
|
+
"claude-carbon runs on bash. On Windows that means Git for Windows, which\n" +
|
|
87
|
+
"Claude Code also uses for its own Bash tool.\n\n" +
|
|
88
|
+
" Install it: winget install Git.Git\n" +
|
|
89
|
+
" Or, if it is already installed somewhere unusual, point at it:\n" +
|
|
90
|
+
' set CLAUDE_CODE_GIT_BASH_PATH="C:\\Program Files\\Git\\bin\\bash.exe"',
|
|
52
91
|
);
|
|
53
92
|
process.exit(1);
|
|
54
93
|
}
|
|
@@ -73,9 +112,9 @@ async function main() {
|
|
|
73
112
|
process.exit(0);
|
|
74
113
|
}
|
|
75
114
|
|
|
76
|
-
const { status, error } = spawnSync(
|
|
115
|
+
const { status, error } = spawnSync(bash, [file], { stdio: "inherit" });
|
|
77
116
|
if (error) {
|
|
78
|
-
console.error(`Could not run bash: ${error.message}`);
|
|
117
|
+
console.error(`Could not run ${bash}: ${error.message}`);
|
|
79
118
|
process.exit(1);
|
|
80
119
|
}
|
|
81
120
|
process.exit(status ?? 1);
|
package/package.json
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-carbon",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Track the carbon footprint of your Claude Code sessions",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"diagram": "node docs/render-diagram.mjs",
|
|
7
|
+
"diagram:png": "node docs/render-diagram.mjs --png"
|
|
8
|
+
},
|
|
5
9
|
"bin": {
|
|
6
10
|
"claude-carbon": "bin/claude-carbon.js"
|
|
7
11
|
},
|