cc-cream 0.1.3 → 0.1.5
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 +13 -0
- package/package.json +1 -1
- package/src/install.js +2 -5
- package/src/segments.js +20 -10
- package/src/state.js +6 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,17 @@ All notable changes to cc-cream are documented here. Format follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow
|
|
5
5
|
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.1.5] — 2026-05-29
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- **TTL falsely resets after non-API Claude Code events** (e.g. `/plugin update`). The TTL anchor was the `mtime` of the transcript file, which updates whenever Claude Code writes any event to the transcript — not just API turns. The anchor is now derived from session state: when `total_input_tokens` grows between renders (indicating a real API turn), `last_api_ts` is stored and used as the anchor on subsequent renders. Falls back to transcript mtime only on the first render before any state exists.
|
|
11
|
+
- **Plugin command paths fixed for real** (reverts the `../` change from 0.1.3). The Claude Code plugin validator rejects `..` path traversal; command paths in `plugin.json` resolve from the plugin root, not from `.claude-plugin/`, so `./commands/setup.md` is correct.
|
|
12
|
+
|
|
13
|
+
## [0.1.4] — 2026-05-29
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- **Node DEP0190 deprecation warning during setup.** `resolveNodePath()` called `execFileSync('command', ['-v', 'node'], { shell: true })`, which Node warns about because args are concatenated rather than escaped when `shell` is true. Switched to `execSync('command -v node')` — no behavior change, warning gone.
|
|
17
|
+
|
|
7
18
|
## [0.1.3] — 2026-05-29
|
|
8
19
|
|
|
9
20
|
### Fixed
|
|
@@ -64,6 +75,8 @@ line and prints a colored ≤3-row bar — zero tokens, the model never sees it.
|
|
|
64
75
|
- Supports **macOS and Linux**; Windows is a planned fast-follow.
|
|
65
76
|
- Requires Claude Code **2.1.132+** (`effort` / `thinking` need 2.1.145+).
|
|
66
77
|
|
|
78
|
+
[0.1.5]: https://github.com/bart-turczynski/cc-cream/compare/v0.1.4...v0.1.5
|
|
79
|
+
[0.1.4]: https://github.com/bart-turczynski/cc-cream/compare/v0.1.3...v0.1.4
|
|
67
80
|
[0.1.3]: https://github.com/bart-turczynski/cc-cream/compare/v0.1.2...v0.1.3
|
|
68
81
|
[0.1.2]: https://github.com/bart-turczynski/cc-cream/compare/v0.1.1...v0.1.2
|
|
69
82
|
[0.1.1]: https://github.com/bart-turczynski/cc-cream/compare/v0.1.0...v0.1.1
|
package/package.json
CHANGED
package/src/install.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// The pure `plan()` function does all the decision-making (no I/O) so it is
|
|
9
9
|
// testable; the CLI wrapper at the bottom handles reading/prompting/writing.
|
|
10
10
|
|
|
11
|
-
import {
|
|
11
|
+
import { execSync } from 'node:child_process';
|
|
12
12
|
import fs from 'node:fs';
|
|
13
13
|
import os from 'node:os';
|
|
14
14
|
import path from 'node:path';
|
|
@@ -188,10 +188,7 @@ function copyRuntimeFiles(sourceFile, destDir) {
|
|
|
188
188
|
// process.execPath (the node currently running setup) if that fails.
|
|
189
189
|
function resolveNodePath() {
|
|
190
190
|
try {
|
|
191
|
-
const found =
|
|
192
|
-
shell: true,
|
|
193
|
-
encoding: 'utf8',
|
|
194
|
-
}).trim();
|
|
191
|
+
const found = execSync('command -v node', { encoding: 'utf8' }).trim();
|
|
195
192
|
if (found) return found;
|
|
196
193
|
} catch {
|
|
197
194
|
// fall through
|
package/src/segments.js
CHANGED
|
@@ -56,16 +56,26 @@ function segCache(data, cfg, prevCachePct, recovering) {
|
|
|
56
56
|
return { text: `cache:${pct}%`, color };
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
function segTtl(data, cfg, ttlMin, now) {
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
59
|
+
function segTtl(data, cfg, ttlMin, now, prevSessionState) {
|
|
60
|
+
const prevTokens = prevSessionState?.total_input_tokens;
|
|
61
|
+
const curTokens = data?.context_window?.total_input_tokens;
|
|
62
|
+
const tokensGrew = isNum(curTokens) && isNum(prevTokens) && curTokens > prevTokens;
|
|
63
|
+
|
|
64
|
+
let anchorMs;
|
|
65
|
+
if (tokensGrew) {
|
|
66
|
+
anchorMs = now;
|
|
67
|
+
} else if (isNum(prevSessionState?.last_api_ts)) {
|
|
68
|
+
anchorMs = prevSessionState.last_api_ts;
|
|
69
|
+
} else {
|
|
70
|
+
const tp = data?.transcript_path;
|
|
71
|
+
if (typeof tp !== 'string' || tp === '') return null;
|
|
72
|
+
try {
|
|
73
|
+
anchorMs = fs.statSync(tp).mtimeMs;
|
|
74
|
+
} catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
67
77
|
}
|
|
68
|
-
const elapsedMin = Math.floor(Math.max(0, now -
|
|
78
|
+
const elapsedMin = Math.floor(Math.max(0, now - anchorMs) / 60000);
|
|
69
79
|
const remainingMin = Math.max(0, ttlMin - elapsedMin);
|
|
70
80
|
const text = `ttl:${pad2(Math.floor(remainingMin / 60))}:${pad2(remainingMin % 60)}`;
|
|
71
81
|
const s = cfg.segments.ttl;
|
|
@@ -158,7 +168,7 @@ export function renderSegments(data, cfg, ttlMin, now, prevSessionState = null,
|
|
|
158
168
|
prevSessionState && isNum(prevSessionState.cache_pct) ? prevSessionState.cache_pct : undefined,
|
|
159
169
|
prevSessionState?.recovering === true,
|
|
160
170
|
),
|
|
161
|
-
ttl: segTtl(data, cfg, ttlMin, now),
|
|
171
|
+
ttl: segTtl(data, cfg, ttlMin, now, prevSessionState),
|
|
162
172
|
cost: segCost(data),
|
|
163
173
|
'5h': segRate(data?.rate_limits?.five_hour, '5h', cfg, '5h', now),
|
|
164
174
|
'7d': segRate(data?.rate_limits?.seven_day, '7d', cfg, '7d', now),
|
package/src/state.js
CHANGED
|
@@ -53,5 +53,11 @@ export function nextSessionPatch(data, prevSessionState, cfg, now) {
|
|
|
53
53
|
}
|
|
54
54
|
const fh = data?.rate_limits?.five_hour;
|
|
55
55
|
if (fh && isNum(fh.used_percentage)) patch.five_hour_pct = fh.used_percentage;
|
|
56
|
+
const curTokens = data?.context_window?.total_input_tokens;
|
|
57
|
+
const prevTokens = prevSessionState?.total_input_tokens;
|
|
58
|
+
if (isNum(curTokens)) {
|
|
59
|
+
patch.total_input_tokens = curTokens;
|
|
60
|
+
if (isNum(prevTokens) && curTokens > prevTokens) patch.last_api_ts = now;
|
|
61
|
+
}
|
|
56
62
|
return patch;
|
|
57
63
|
}
|