claude-usage-limits 1.24.0 → 1.25.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.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "usage-limits",
|
|
3
3
|
"displayName": "Usage Limits",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.25.0",
|
|
5
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",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "usage-limits",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.25.0",
|
|
4
4
|
"description": "Reports how much of your Codex usage limit is left as turns of work rather than a percentage, prices a job before you start it, and counts the other agents sharing the same budget.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Ridelink",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-usage-limits",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.25.0",
|
|
4
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",
|
|
@@ -643,7 +643,11 @@ function schedulePosix(when, argv, name, cwd) {
|
|
|
643
643
|
encoding: 'utf8',
|
|
644
644
|
timeout: 20000,
|
|
645
645
|
});
|
|
646
|
-
|
|
646
|
+
// macOS ships `at` but launchd leaves atrun DISABLED by default, so the
|
|
647
|
+
// command succeeds, prints a job id, and the wake never fires. Reporting
|
|
648
|
+
// ok for that is worse than not having it: it is a silent no-op that looks
|
|
649
|
+
// like a scheduled wake. Fall through to the sleeper, which at least runs.
|
|
650
|
+
if (run.status === 0 && process.platform !== 'darwin') return { ok: true, how: 'at' };
|
|
647
651
|
}
|
|
648
652
|
try {
|
|
649
653
|
const child = spawn('sh', ['-c', 'sleep ' + seconds + ' && ' + command], {
|
|
@@ -767,16 +771,41 @@ function arm(input) {
|
|
|
767
771
|
}
|
|
768
772
|
: null,
|
|
769
773
|
};
|
|
770
|
-
|
|
774
|
+
// Displacing somebody else's live relay is legitimate - one machine, one
|
|
775
|
+
// relay - but it must not be silent. A wake still in the future belonged to
|
|
776
|
+
// work that somebody expected to be picked up.
|
|
777
|
+
if (state.armed && state.armed.id !== id) {
|
|
778
|
+
if (Number.isFinite(state.armed.wakeAt) && state.armed.wakeAt > now) {
|
|
779
|
+
note('displacing the relay armed for ' + state.armed.id + ' (was due ' + new Date(state.armed.wakeAt).toISOString() + ')', now);
|
|
780
|
+
}
|
|
781
|
+
if (state.armed.task) cancelSchedule(state.armed.task);
|
|
782
|
+
}
|
|
771
783
|
state.armed = record;
|
|
772
784
|
write(state);
|
|
773
785
|
note('armed ' + id + ' for ' + new Date(when).toISOString() + ' via ' + scheduled.how, now);
|
|
774
786
|
return { ok: true, record };
|
|
775
787
|
}
|
|
776
788
|
|
|
777
|
-
|
|
789
|
+
// `id` is optional, and when it is given it is a guard rather than a lookup:
|
|
790
|
+
// clear the relay only if the thing armed is the thing the caller means.
|
|
791
|
+
//
|
|
792
|
+
// Without it, disarm clears whatever happens to be armed, and that is not
|
|
793
|
+
// hypothetical. Measured 2026-09-14: a second process armed a throwaway
|
|
794
|
+
// session at 04:57:04 and cleaned it up four seconds later, and the cleanup
|
|
795
|
+
// took a live relay for an unrelated session - armed seven seconds earlier,
|
|
796
|
+
// due to wake five hours later - with it. Nothing reported that, because from
|
|
797
|
+
// disarm's point of view it did exactly what it was asked.
|
|
798
|
+
//
|
|
799
|
+
// A person typing `relay cancel` means "whatever is armed", so the CLI passes
|
|
800
|
+
// no id and the old behaviour stands. Anything that knows which session it is
|
|
801
|
+
// tidying up should say so.
|
|
802
|
+
function disarm(reason, now, id) {
|
|
778
803
|
const state = read();
|
|
779
804
|
if (!state.armed) return { ok: true, changed: false };
|
|
805
|
+
if (id && state.armed.id !== id) {
|
|
806
|
+
note('refused to disarm ' + state.armed.id + ' on behalf of ' + id, Number.isFinite(now) ? now : Date.now());
|
|
807
|
+
return { ok: true, changed: false, refused: true, armed: state.armed.id };
|
|
808
|
+
}
|
|
780
809
|
const record = state.armed;
|
|
781
810
|
if (record.task) cancelSchedule(record.task);
|
|
782
811
|
state.history.push(Object.assign({}, record, { endedAt: Number.isFinite(now) ? now : Date.now(), outcome: reason || 'cancelled' }));
|
|
@@ -146,6 +146,10 @@ function userIsPresent(cli) {
|
|
|
146
146
|
function claudeArgs(record, prompt, config, fallback) {
|
|
147
147
|
const args = fallback ? ['--continue', '-p', prompt] : ['--resume', record.id, '-p', prompt];
|
|
148
148
|
if (config.permissionMode) args.push('--permission-mode', config.permissionMode);
|
|
149
|
+
// Nobody is awake to answer a prompt. Deny it rather than stall on it: a
|
|
150
|
+
// resumed run that sits waiting for a keystroke burns its whole timeout and
|
|
151
|
+
// reports nothing.
|
|
152
|
+
args.push('--permission-prompts', 'none');
|
|
149
153
|
if (!fallback && config.model) args.push('--model', config.model);
|
|
150
154
|
return args;
|
|
151
155
|
}
|
|
@@ -186,12 +190,29 @@ function deliverClaude(record, prompt, config, cli, runs) {
|
|
|
186
190
|
const run = appendRun(runs, 'claude --resume', spawnSync(cli, args, options));
|
|
187
191
|
if (run.status === 0) return { ok: true, how: 'claude --resume' };
|
|
188
192
|
const detail = ((run.stderr || run.stdout || '') + '').trim().split('\n')[0];
|
|
189
|
-
// A session id that no longer resolves
|
|
190
|
-
//
|
|
193
|
+
// A session id that no longer resolves used to fall back to `--continue`,
|
|
194
|
+
// on the reasoning that the work still needs doing and only the thread is
|
|
195
|
+
// gone. That fallback is removed, because of what `--continue` actually
|
|
196
|
+
// selects.
|
|
197
|
+
//
|
|
198
|
+
// `--continue` normally SKIPS sessions created by `claude -p`, the SDK and
|
|
199
|
+
// /loop - but `claude -p --continue`, which is exactly what this ran,
|
|
200
|
+
// INCLUDES them. So the most recent session it could land on is a previous
|
|
201
|
+
// relay's own headless run, not the user's work. Resuming that, unattended,
|
|
202
|
+
// at four in the morning, with permissionMode bypassPermissions, means an
|
|
203
|
+
// agent continuing a conversation nobody chose, in a directory it was not
|
|
204
|
+
// asked about.
|
|
205
|
+
//
|
|
206
|
+
// The plan is on disk either way. A wake that stops and says the thread is
|
|
207
|
+
// gone loses nothing; a wake that resumes the wrong conversation can.
|
|
191
208
|
if (/No conversation found/i.test(detail)) {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
209
|
+
return {
|
|
210
|
+
ok: false,
|
|
211
|
+
error:
|
|
212
|
+
'the session ' + String(record.id).slice(0, 8) + ' no longer exists, so there was nothing to resume. ' +
|
|
213
|
+
'The plan is still on disk: run "claude" in ' + record.cwd + ' and paste it in.',
|
|
214
|
+
permanent: true,
|
|
215
|
+
};
|
|
195
216
|
}
|
|
196
217
|
return { ok: false, error: detail || 'claude exited ' + run.status };
|
|
197
218
|
}
|