cc-cream 0.3.4 → 0.3.6
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/CHANGELOG.md +17 -0
- package/README.md +2 -2
- package/package.json +6 -6
- package/{src → plugin/src}/config.js +1 -0
- package/{src → plugin/src}/defaults.js +6 -4
- package/{src → plugin/src}/segments.js +7 -3
- package/{src → plugin/src}/utils.js +31 -7
- /package/{src → plugin/src}/cc-cream.js +0 -0
- /package/{src → plugin/src}/install.js +0 -0
- /package/{src → plugin/src}/render.js +0 -0
- /package/{src → plugin/src}/settings.js +0 -0
- /package/{src → plugin/src}/state.js +0 -0
- /package/{src → plugin/src}/ttl.js +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,23 @@ All notable changes to cc-cream are documented here. Format follows
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.3.6] — 2026-06-04
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
- **Plugin is now distributed via a lean catalogue repo (`bart-turczynski/claude-plugins`) instead of the full dev repo.** Previously the marketplace pointed at `bart-turczynski/cc-cream`, so every user who registered the marketplace got a full clone of the development repository — `features/`, `fixtures/`, `package-lock.json` (114 KB), `CHANGELOG.md` (31 KB), and the full git history — landing in `~/.claude/plugins/marketplaces/`. The marketplace source is now `bart-turczynski/claude-plugins`, a purpose-built catalogue containing only the plugin payload and `marketplace.json`. The marketplaces clone shrinks from ~1 MB to ~260 KB (irreducible floor: `.git/` + `.claude-plugin/`). Existing installs should remove and re-add the marketplace: `claude plugin marketplace remove bart-turczynski && claude plugin marketplace add bart-turczynski/claude-plugins`.
|
|
13
|
+
|
|
14
|
+
### Infrastructure
|
|
15
|
+
- Added `.github/workflows/sync-catalogue.yml`: on each GitHub Release, syncs `plugin/` contents to `cc-cream/` in the `bart-turczynski/claude-plugins` catalogue repo so the distribution copy stays current without manual maintenance.
|
|
16
|
+
|
|
17
|
+
## [0.3.5] — 2026-06-04
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
- **`/cc-cream:setup --force` now actually replaces an existing statusLine.** The setup slash command shelled out to `install.js --plugin` but never forwarded `$ARGUMENTS`, so `--force` (and any other flag) was silently dropped — `--force` appeared to do nothing when another tool already owned the statusLine. `commands/setup.md` now passes `$ARGUMENTS` through, matching `uninstall.md`. `install.js` already honored `--force`; only the command wiring was broken.
|
|
21
|
+
- **Plugin install no longer balloons the cache to ~114 MB.** Claude Code's plugin installer runs `npm install` whenever it finds a `package.json` in the cached plugin tree, which pulled the entire devDependency tree (Biome, Cucumber, knip, c8, …) into `~/.claude/plugins/cache/cc-cream/`. The plugin payload now lives in a `plugin/` subdirectory and the marketplace `source` points to `"./plugin"`, so only `plugin/`'s contents (`src/`, `commands/`, `hooks/`, `.claude-plugin/plugin.json`) are copied to the cache — with no `package.json` there, the installer has nothing to install. `package.json`, dev configs, and `marketplace.json` stay at the repo root; npm `bin`/`files` now point at `plugin/src/`. No behavior change to the rendered bar.
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
- **The `peak` segment now shows when the window closes and when the next one opens (CREAM-scwwzbxh).** Inside the faster-drain window it reads `peak until HH:MM` — the close time in your **local** timezone, not PT — so you can see how long the elevated drain lasts. In the hour before the window opens it counts down `peak in Nm`. The new `peak.lead` config key sets how many minutes ahead the countdown appears (default `60`). Previously the segment showed only the bare word `peak` while in-window and nothing otherwise.
|
|
25
|
+
|
|
9
26
|
## [0.3.4] — 2026-05-31
|
|
10
27
|
|
|
11
28
|
### Changed
|
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ With all segments enabled:
|
|
|
19
19
|
|
|
20
20
|
```
|
|
21
21
|
ctx:21% [43k] | cache:99% | write:2% | ttl:60 | effort:high | think:on | ∿ api:74% | ~$0.23
|
|
22
|
-
5h:13% ↺2h57m | ~3h12m | 7d:6% ↺Sat 21:00 | peak
|
|
22
|
+
5h:13% ↺2h57m | ~3h12m | 7d:6% ↺Sat 21:00 | peak until 11:00
|
|
23
23
|
Sonnet 4.6 | My project session
|
|
24
24
|
```
|
|
25
25
|
|
|
@@ -35,7 +35,7 @@ Sonnet 4.6 | My project session
|
|
|
35
35
|
|
|
36
36
|
**Rate-limit budgets.** `5h` and `7d` show how much of your rolling usage is gone and when each window resets. `burn` adds a live projection based on your current pace — useful before committing to a long agent run.
|
|
37
37
|
|
|
38
|
-
**Peak hours.** Anthropic's rate-limit drain accelerates Mon–Fri during Pacific business hours. The `peak` segment
|
|
38
|
+
**Peak hours.** Anthropic's rate-limit drain accelerates Mon–Fri during Pacific business hours. The `peak` segment tells you when the current window closes (`peak until 11:00`, in your local time) while you're in it, and counts down to the next one (`peak in 47m`) in the hour before it opens — so you can pace yourself or wait it out. No other Claude Code status tool surfaces this.
|
|
39
39
|
|
|
40
40
|
**Context window.** `ctx` shows occupancy and input-token magnitude. On large-context models where "50% of window" still means 500k tokens, you can set a fixed-token ceiling instead — warnings fire at the same absolute count regardless of window size.
|
|
41
41
|
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cc-cream",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.6",
|
|
4
4
|
"description": "See cache health, context fill, token burn, rate limits, and peak hours in Claude Code CLI. The status line for tokenminning - cache rules everything around me - dolla, dolla bill, y'all.",
|
|
5
5
|
"directories": {
|
|
6
6
|
"doc": "docs"
|
|
7
7
|
},
|
|
8
8
|
"scripts": {
|
|
9
|
-
"lint": "biome lint src/ hooks/",
|
|
9
|
+
"lint": "biome lint plugin/src/ plugin/hooks/",
|
|
10
10
|
"knip": "knip",
|
|
11
|
-
"validate": "command -v claude >/dev/null 2>&1 && claude plugin validate
|
|
11
|
+
"validate": "command -v claude >/dev/null 2>&1 && claude plugin validate plugin || echo 'cc-cream: claude CLI not found — skipping plugin validation'",
|
|
12
12
|
"pretest": "npm run lint && npm run knip && npm run validate",
|
|
13
13
|
"test": "cucumber-js",
|
|
14
14
|
"test:manual": "cucumber-js --profile manual",
|
|
@@ -23,11 +23,11 @@
|
|
|
23
23
|
"pre-push": "npm run coverage"
|
|
24
24
|
},
|
|
25
25
|
"bin": {
|
|
26
|
-
"cc-cream": "src/cc-cream.js",
|
|
27
|
-
"cc-cream-setup": "src/install.js"
|
|
26
|
+
"cc-cream": "plugin/src/cc-cream.js",
|
|
27
|
+
"cc-cream-setup": "plugin/src/install.js"
|
|
28
28
|
},
|
|
29
29
|
"files": [
|
|
30
|
-
"src/",
|
|
30
|
+
"plugin/src/",
|
|
31
31
|
"LICENSE",
|
|
32
32
|
"README.md",
|
|
33
33
|
"CHANGELOG.md"
|
|
@@ -19,10 +19,12 @@ export const DEFAULTS = {
|
|
|
19
19
|
cost: { on: true, row: 1, order: 5 },
|
|
20
20
|
'5h': { on: true, row: 2, order: 1, amber: 75, red: 90 },
|
|
21
21
|
'7d': { on: true, row: 2, order: 2, amber: 75, red: 90 },
|
|
22
|
-
// peak: amber
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
peak
|
|
22
|
+
// peak: amber peak-window indicator (PRDv2 §2). start/end are Pacific-time
|
|
23
|
+
// hours (0–23, exclusive end); weekday (Mon–Fri) and the America/Los_Angeles
|
|
24
|
+
// timezone are hardcoded policy facts, not config. Inside the window it reads
|
|
25
|
+
// "peak until HH:MM" (local close time); the `lead` minutes before it opens it
|
|
26
|
+
// counts down "peak in Nm".
|
|
27
|
+
peak: { on: true, row: 2, order: 3, start: 5, end: 11, lead: 60 },
|
|
26
28
|
burn: { on: true, row: 2, order: 1.5 },
|
|
27
29
|
effort: { on: false, row: 1, order: 6 },
|
|
28
30
|
thinking: { on: false, row: 1, order: 7 },
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { band, countdown, flipPct, fmtNum, isNum,
|
|
1
|
+
import { band, countdown, flipPct, fmtNum, isNum, localHM, numOr, pad2, peakStatus } from './utils.js';
|
|
2
2
|
import { hasWindow } from './ttl.js';
|
|
3
3
|
|
|
4
4
|
function magnitudeTokens(cw) {
|
|
@@ -125,8 +125,12 @@ function segCacheWrite(data) {
|
|
|
125
125
|
function segPeak(data, cfg, now, tz) {
|
|
126
126
|
// peak rides the account-budget row, so it shows only when that row has windows.
|
|
127
127
|
if (!hasWindow(data?.rate_limits)) return null;
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
const st = peakStatus(now, cfg, tz);
|
|
129
|
+
if (!st) return null;
|
|
130
|
+
const text = st.state === 'approaching'
|
|
131
|
+
? `peak in ${st.startsInMin}m` // counting down to the window opening
|
|
132
|
+
: `peak until ${localHM(st.endsAtMs)}`; // inside it: local clock time it closes
|
|
133
|
+
return { text, color: 'amber' };
|
|
130
134
|
}
|
|
131
135
|
|
|
132
136
|
function segBurn(fiveHour, prev, now) {
|
|
@@ -75,24 +75,48 @@ export const flipPct = (consumedShown, cfg) => (
|
|
|
75
75
|
cfg.percentage === 'remaining' ? 100 - consumedShown : consumedShown
|
|
76
76
|
);
|
|
77
77
|
|
|
78
|
-
//
|
|
79
|
-
// (Mon–Fri) within [start, end) Pacific-time hours.
|
|
80
|
-
|
|
78
|
+
// Resolve the "peak" window (PRDv2 §2) relative to `now`. Anthropic drains the
|
|
79
|
+
// 5h budget faster on weekdays (Mon–Fri) within [start, end) Pacific-time hours.
|
|
80
|
+
// Returns one of:
|
|
81
|
+
// { state: 'in', endsAtMs } — inside [start, end); endsAtMs is the
|
|
82
|
+
// window close as an epoch (format local)
|
|
83
|
+
// { state: 'approaching', startsInMin } — inside [start-lead, start)
|
|
84
|
+
// null — off-window, weekend, or Intl failure
|
|
85
|
+
// `lead` (minutes, default 60) is how early the approaching countdown appears.
|
|
86
|
+
export function peakStatus(now, cfg, tz = 'America/Los_Angeles') {
|
|
81
87
|
const s = cfg?.segments?.peak ?? {};
|
|
82
88
|
const start = isNum(s.start) ? s.start : 5;
|
|
83
89
|
const end = isNum(s.end) ? s.end : 11;
|
|
90
|
+
const lead = isNum(s.lead) && s.lead > 0 ? s.lead : 60;
|
|
84
91
|
try {
|
|
85
92
|
const parts = new Intl.DateTimeFormat('en-US', {
|
|
86
|
-
timeZone: tz, hour: 'numeric', hour12: false, weekday: 'short',
|
|
93
|
+
timeZone: tz, hour: 'numeric', minute: 'numeric', hour12: false, weekday: 'short',
|
|
87
94
|
}).formatToParts(new Date(now));
|
|
88
95
|
const p = Object.fromEntries(parts.map((x) => [x.type, x.value]));
|
|
89
|
-
|
|
90
|
-
|
|
96
|
+
if (['Sat', 'Sun'].includes(p.weekday)) return null;
|
|
97
|
+
const ptMin = (Number(p.hour) % 24) * 60 + Number(p.minute); // some ICU builds emit "24" for midnight
|
|
98
|
+
const startMin = start * 60;
|
|
99
|
+
const endMin = end * 60;
|
|
100
|
+
if (ptMin >= startMin && ptMin < endMin) {
|
|
101
|
+
return { state: 'in', endsAtMs: now + (endMin - ptMin) * 60000 };
|
|
102
|
+
}
|
|
103
|
+
if (ptMin >= startMin - lead && ptMin < startMin) {
|
|
104
|
+
return { state: 'approaching', startsInMin: startMin - ptMin };
|
|
105
|
+
}
|
|
106
|
+
return null;
|
|
91
107
|
} catch {
|
|
92
|
-
return
|
|
108
|
+
return null;
|
|
93
109
|
}
|
|
94
110
|
}
|
|
95
111
|
|
|
112
|
+
// Back-compat predicate: true only inside the window itself (not while approaching).
|
|
113
|
+
export const isPeak = (now, cfg, tz = 'America/Los_Angeles') => peakStatus(now, cfg, tz)?.state === 'in';
|
|
114
|
+
|
|
115
|
+
// Wall-clock HH:MM in the host's local timezone (TZ-driven, like countdown's day branch).
|
|
116
|
+
export const localHM = (ms) => new Date(ms).toLocaleTimeString(undefined, {
|
|
117
|
+
hour: '2-digit', minute: '2-digit', hour12: false,
|
|
118
|
+
});
|
|
119
|
+
|
|
96
120
|
// resets_at - now, on the §4.4 format ladder: >=1d -> "Fri 23:45", >=1h -> HhMMm, else MMm.
|
|
97
121
|
export function countdown(resetsAt, now) {
|
|
98
122
|
const t = toEpochMs(resetsAt);
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|