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": "Reads how much of your Claude Code usage limit is left, converts it into turns of headroom, and plans the work to fit inside it.",
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": ["usage", "limits", "cost", "planning"],
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.2",
5
- "description": "Reads how much of your Claude Code usage limit is left, converts it into turns of headroom, and plans the work to fit inside it. Includes a low power switch that keeps spending down even at high effort.",
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
  [![npm](https://img.shields.io/npm/v/claude-usage-limits)](https://www.npmjs.com/package/claude-usage-limits)
4
4
 
5
- A Claude Code plugin that reads how much of your usage limit is left and plans
6
- the work to fit inside it.
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 you have
9
- spent. It caches the numbers locally and shows them when you ask. What it does
10
- not do on its own is notice that the job in front of it is bigger than the
11
- budget behind it, and adjust. This adds that: a report you can act on, and a
12
- set of rules for what to do when the answer is "not enough".
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%, weekly 16%, about 75 turns of headroom, resets in
210
- 3h 52m, this session 229 turns, $64.16.
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
- > Weekly is at 16%, 5-hour at 47%, about 75 turns of headroom. This fits easily.
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.2",
4
- "description": "See how much of your Claude Code usage limit is left as turns of work rather than a percentage, and plan the job to fit inside it.",
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
- > Weekly is at 16%, 5-hour at 47%, about 75 turns of headroom. This fits easily.
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 summarise(windows) {
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((window) =>
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
- const facts = [];
174
- if (parts.windowSummary) facts.push(parts.windowSummary);
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
- facts.push('about ' + parts.turnsLeft + ' turns of headroom');
184
+ bound.push('about ' + parts.turnsLeft + ' turns of headroom');
177
185
  }
178
- if (parts.resetsIn) facts.push('resets in ' + 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
- facts.push(
181
- 'this session ' + parts.session.turns + ' turns, ' +
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
- return head + '\n' + instruction;
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
- windowSummary: summarise(windows),
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
- summarise,
284
+ describeWindow,
285
+ summariseOthers,
263
286
  briefText,
264
287
  settings,
265
288
  pickCached,