claude-usage-limits 1.1.2 → 1.1.3
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.
|
@@ -9,9 +9,14 @@
|
|
|
9
9
|
{
|
|
10
10
|
"name": "usage-limits",
|
|
11
11
|
"source": "./",
|
|
12
|
-
"description": "
|
|
12
|
+
"description": "Puts your remaining Claude Code usage limit into Claude's context before every prompt, so it opens with what fits in the budget instead of starting work that gets cut off. Reports headroom as turns rather than percentages, prices a job before you start it, and detects your plan tier.",
|
|
13
13
|
"category": "productivity",
|
|
14
|
-
"tags": [
|
|
14
|
+
"tags": [
|
|
15
|
+
"usage",
|
|
16
|
+
"limits",
|
|
17
|
+
"cost",
|
|
18
|
+
"planning"
|
|
19
|
+
],
|
|
15
20
|
"license": "MIT"
|
|
16
21
|
}
|
|
17
22
|
]
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "usage-limits",
|
|
3
3
|
"displayName": "Usage Limits",
|
|
4
|
-
"version": "1.1.
|
|
5
|
-
"description": "
|
|
4
|
+
"version": "1.1.3",
|
|
5
|
+
"description": "Puts your remaining Claude Code usage limit into Claude's context before every prompt, so it opens with what fits in the budget instead of starting work that gets cut off. Reports headroom as turns rather than percentages, prices a job before you start it, and detects your plan tier.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Ridelink",
|
|
8
8
|
"url": "https://github.com/ridelink0"
|
package/README.md
CHANGED
|
@@ -2,14 +2,46 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/claude-usage-limits)
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
Most usage tools for Claude Code show **you** the numbers. This one shows them
|
|
6
|
+
to **Claude**, before every prompt, and changes what it does about them.
|
|
7
7
|
|
|
8
|
-
Claude Code already knows how much of your 5-hour and weekly limit
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
Claude Code already knows how much of your 5-hour and weekly limit is gone. It
|
|
9
|
+
caches those numbers locally and will show them if you ask. What it does not do
|
|
10
|
+
is notice that the job in front of it is larger than the budget behind it. So
|
|
11
|
+
it starts anyway, and stops halfway through an edit.
|
|
12
|
+
|
|
13
|
+
This puts the budget in front of Claude before your prompt lands, so the reply
|
|
14
|
+
opens with the answer instead:
|
|
15
|
+
|
|
16
|
+
> The weekly window has about 22 turns left. That covers the parser change and
|
|
17
|
+
> its tests, but not the migration or the docs pass, so I will do the first two
|
|
18
|
+
> and leave the rest for after the reset at 09:00.
|
|
19
|
+
|
|
20
|
+
Nobody read a chart to get that. The numbers reached the model, not you.
|
|
21
|
+
|
|
22
|
+
## How this differs from a usage dashboard
|
|
23
|
+
|
|
24
|
+
There are a lot of good tools that read the same local files this does and draw
|
|
25
|
+
you a picture: status lines, menu bar apps, terminal dashboards. They are worth
|
|
26
|
+
having, and this is not trying to replace them. The difference is who the
|
|
27
|
+
output is for.
|
|
28
|
+
|
|
29
|
+
| A usage dashboard | This |
|
|
30
|
+
| --- | --- |
|
|
31
|
+
| Renders numbers for a person to read | Puts numbers in the model's context |
|
|
32
|
+
| You notice, then you interrupt | Claude notices, and adjusts on its own |
|
|
33
|
+
| Tells you 78 percent is gone | Tells you 22 turns are left, and whether what you asked for fits in them |
|
|
34
|
+
| Runs beside Claude Code | Runs inside it, as a skill and a hook |
|
|
35
|
+
| Shows what already happened | Says what to do now, and what to drop |
|
|
36
|
+
|
|
37
|
+
A percentage is a fact about the past. The useful question is whether the thing
|
|
38
|
+
you just asked for is going to finish, and answering that needs the request and
|
|
39
|
+
the budget in the same place. That place is the model's context, which is where
|
|
40
|
+
this puts them.
|
|
41
|
+
|
|
42
|
+
So: if you want to watch your usage, install a status line. This ships one too.
|
|
43
|
+
If you want the thing spending the budget to know it is spending the budget,
|
|
44
|
+
that is what this is for.
|
|
13
45
|
|
|
14
46
|
## What it prints
|
|
15
47
|
|
|
@@ -206,13 +238,19 @@ Installed as a plugin, a hook measures the budget before each prompt and puts
|
|
|
206
238
|
one line into Claude's context:
|
|
207
239
|
|
|
208
240
|
```
|
|
209
|
-
[usage-limits] 5-hour 47
|
|
210
|
-
3h 52m
|
|
241
|
+
[usage-limits] binding window is 5-hour 47% used, about 75 turns of headroom,
|
|
242
|
+
resets in 3h 52m. Other windows: weekly 16%. This session: 229 turns, $64.16.
|
|
211
243
|
```
|
|
212
244
|
|
|
245
|
+
It names the window that will stop the work first and hangs the figures off
|
|
246
|
+
that one. Two windows run at once and they are rarely in the same place, so
|
|
247
|
+
"weekly 16%" sitting next to "75 turns" would read as far more room than
|
|
248
|
+
exists.
|
|
249
|
+
|
|
213
250
|
Claude opens with it. When there is room that is a single line and it moves on:
|
|
214
251
|
|
|
215
|
-
>
|
|
252
|
+
> The 5-hour window is the binding one: 47% used, about 75 turns of headroom.
|
|
253
|
+
> This fits easily.
|
|
216
254
|
|
|
217
255
|
When there is not, the line becomes a plan rather than a status:
|
|
218
256
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-usage-limits",
|
|
3
|
-
"version": "1.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.1.3",
|
|
4
|
+
"description": "Puts your remaining Claude Code usage limit into Claude's context before every prompt, so it opens with what fits in the budget instead of starting work that gets cut off. Reports headroom as turns rather than percentages, prices a job before you start it, and detects your plan tier.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude",
|
|
7
7
|
"claude-code",
|
|
@@ -100,7 +100,8 @@ there is nothing to go and look up.
|
|
|
100
100
|
|
|
101
101
|
When there is room, one line, then get on with it:
|
|
102
102
|
|
|
103
|
-
>
|
|
103
|
+
> The 5-hour window is the binding one: 47% used, about 75 turns of headroom.
|
|
104
|
+
> This fits easily.
|
|
104
105
|
|
|
105
106
|
When it does not fit, that line becomes the plan:
|
|
106
107
|
|
|
@@ -116,6 +117,13 @@ Keep it to one line unless the work genuinely does not fit. The budget note is
|
|
|
116
117
|
a header, not a section, and it must never push the actual answer down the
|
|
117
118
|
page.
|
|
118
119
|
|
|
120
|
+
One thing to get right: **quote the binding window, not the roomiest one.**
|
|
121
|
+
Two windows run at once and they are rarely in the same place. The turns of
|
|
122
|
+
headroom and the reset time belong to whichever runs out first. Putting the
|
|
123
|
+
other window's percentage next to those figures claims far more room than
|
|
124
|
+
exists, and that is how a session ends mid-edit while the weekly number still
|
|
125
|
+
looks comfortable.
|
|
126
|
+
|
|
119
127
|
### Pricing the job before starting it
|
|
120
128
|
|
|
121
129
|
Size the work in turns using the table above, then price it:
|
|
@@ -158,33 +158,47 @@ function sessionSpend(events, sessionId) {
|
|
|
158
158
|
return turns ? { turns, cost } : null;
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
-
function
|
|
161
|
+
function describeWindow(window) {
|
|
162
|
+
if (!window) return null;
|
|
163
|
+
return window.stale
|
|
164
|
+
? window.label + ' rolling over'
|
|
165
|
+
: window.label + ' ' + window.percentUsed + '%';
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Everything except the window that will actually stop the work.
|
|
169
|
+
function summariseOthers(windows, bindingKey) {
|
|
162
170
|
return windows
|
|
163
|
-
.filter((window) => window.percentUsed !== null)
|
|
164
|
-
.map(
|
|
165
|
-
window.stale
|
|
166
|
-
? window.label + ' rolling over'
|
|
167
|
-
: window.label + ' ' + window.percentUsed + '%'
|
|
168
|
-
)
|
|
171
|
+
.filter((window) => window.percentUsed !== null && window.key !== bindingKey)
|
|
172
|
+
.map(describeWindow)
|
|
169
173
|
.join(', ');
|
|
170
174
|
}
|
|
171
175
|
|
|
172
176
|
function briefText(parts) {
|
|
173
|
-
|
|
174
|
-
|
|
177
|
+
// The turns and the reset time belong to one specific window. Listing every
|
|
178
|
+
// window and then the numbers invites reading them against the wrong one, so
|
|
179
|
+
// the binding window is named and its figures are attached to it.
|
|
180
|
+
const bound = [];
|
|
181
|
+
const described = describeWindow(parts.binding);
|
|
182
|
+
if (described) bound.push(described + (parts.binding.stale ? '' : ' used'));
|
|
175
183
|
if (Number.isFinite(parts.turnsLeft)) {
|
|
176
|
-
|
|
184
|
+
bound.push('about ' + parts.turnsLeft + ' turns of headroom');
|
|
177
185
|
}
|
|
178
|
-
if (parts.resetsIn)
|
|
186
|
+
if (parts.resetsIn) bound.push('resets in ' + parts.resetsIn);
|
|
187
|
+
|
|
188
|
+
const sentences = [];
|
|
189
|
+
sentences.push(
|
|
190
|
+
bound.length
|
|
191
|
+
? '[usage-limits] binding window is ' + bound.join(', ') + '.'
|
|
192
|
+
: '[usage-limits] no usable window reading.'
|
|
193
|
+
);
|
|
194
|
+
if (parts.othersSummary) sentences.push('Other windows: ' + parts.othersSummary + '.');
|
|
179
195
|
if (parts.session) {
|
|
180
|
-
|
|
181
|
-
'
|
|
182
|
-
usage.formatUSD(parts.session.cost)
|
|
196
|
+
sentences.push(
|
|
197
|
+
'This session: ' + parts.session.turns + ' turns, ' +
|
|
198
|
+
usage.formatUSD(parts.session.cost) + '.'
|
|
183
199
|
);
|
|
184
200
|
}
|
|
185
201
|
|
|
186
|
-
const head = '[usage-limits] ' + facts.join(', ') + '.';
|
|
187
|
-
|
|
188
202
|
const instruction =
|
|
189
203
|
parts.pressure === 'tight' || parts.pressure === 'gone'
|
|
190
204
|
? 'Open your reply with one line on where this leaves the budget, then say ' +
|
|
@@ -193,7 +207,14 @@ function briefText(parts) {
|
|
|
193
207
|
: 'Open your reply with one short line stating this and confirming the ' +
|
|
194
208
|
'request fits, then get on with the work. Keep it to a single line.';
|
|
195
209
|
|
|
196
|
-
|
|
210
|
+
// The mistake this guards against: quoting the roomiest window and pinning
|
|
211
|
+
// the binding window figures to it.
|
|
212
|
+
const care =
|
|
213
|
+
' Quote the binding window, not whichever one has the most left. The turns ' +
|
|
214
|
+
'and reset time above belong to the binding window alone; do not read them ' +
|
|
215
|
+
'against another window percentage.';
|
|
216
|
+
|
|
217
|
+
return sentences.join(' ') + '\n' + instruction + care;
|
|
197
218
|
}
|
|
198
219
|
|
|
199
220
|
async function run(now, hookInput) {
|
|
@@ -228,7 +249,8 @@ async function run(now, hookInput) {
|
|
|
228
249
|
const binding = usage.bindingWindow(windows) || windows[0];
|
|
229
250
|
|
|
230
251
|
return briefText({
|
|
231
|
-
|
|
252
|
+
binding,
|
|
253
|
+
othersSummary: summariseOthers(windows, binding && binding.key),
|
|
232
254
|
turnsLeft,
|
|
233
255
|
resetsIn:
|
|
234
256
|
binding && !binding.stale && binding.msToReset !== null
|
|
@@ -259,7 +281,8 @@ module.exports = {
|
|
|
259
281
|
aheadOfPace,
|
|
260
282
|
pressure,
|
|
261
283
|
sessionSpend,
|
|
262
|
-
|
|
284
|
+
describeWindow,
|
|
285
|
+
summariseOthers,
|
|
263
286
|
briefText,
|
|
264
287
|
settings,
|
|
265
288
|
pickCached,
|