@codizelabs/agent-rewake 0.3.1 → 0.5.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.
- package/README.md +38 -27
- package/dist/agent-rewake.js +13124 -7070
- package/dist/hosts/claude-code/.claude-plugin/plugin.json +1 -1
- package/dist/hosts/claude-code/hooks/logic.js +268 -0
- package/dist/hosts/claude-code/hooks/register.js +206 -36
- package/package.json +1 -1
|
@@ -13,12 +13,20 @@
|
|
|
13
13
|
// offered (not answered) | armed | sent
|
|
14
14
|
// claim: { by, at }, the process sending the armed continue right now
|
|
15
15
|
// sched:<id> [{ at, text }]
|
|
16
|
+
// usage:<dir> { <kind>: { resetsAt, samples: [{ t, p }], high, pace } }, what the warnings
|
|
17
|
+
// before a limit have said. The figures are the account's, not the session's, so
|
|
18
|
+
// the key is the config dir (CLAUDE_CONFIG_DIR, which is one sign-in): a restart or
|
|
19
|
+
// another session of the same account doesn't repeat a warning.
|
|
16
20
|
// A copy of each limit record (no message text) goes to Rewake's shared state folder, so
|
|
17
|
-
// `agent-rewake doctor` and the schedules page can show it
|
|
18
|
-
//
|
|
21
|
+
// `agent-rewake doctor` and the schedules page can show it, and so Rewake can continue the session
|
|
22
|
+
// headless if Claude Code closes before the limit is answered (it adds `open`, the Claude Code
|
|
23
|
+
// process, the limit and the session's settings variables: src/hosts/sessions.ts SessionRecord).
|
|
24
|
+
// Installed by `agent-rewake install`, which writes that folder's path into rewake.json beside this
|
|
25
|
+
// plugin.
|
|
19
26
|
|
|
20
27
|
import {
|
|
21
28
|
AFTER_RESET_MS,
|
|
29
|
+
backoffMs,
|
|
22
30
|
blockedUntil,
|
|
23
31
|
blockingKind,
|
|
24
32
|
CONTINUE_TEXT,
|
|
@@ -28,22 +36,37 @@ import {
|
|
|
28
36
|
featureOf,
|
|
29
37
|
HOUR,
|
|
30
38
|
helpText,
|
|
39
|
+
holdArgv,
|
|
40
|
+
LINUX_MAINS,
|
|
41
|
+
levelText,
|
|
42
|
+
limitOf,
|
|
31
43
|
MAX_REARMS,
|
|
32
44
|
MAX_REHITS,
|
|
33
45
|
MINUTE,
|
|
46
|
+
mainsFrom,
|
|
34
47
|
mustAsk,
|
|
35
48
|
nativeLikely,
|
|
36
49
|
notHere,
|
|
50
|
+
paceText,
|
|
37
51
|
parseCommand,
|
|
52
|
+
parseProcess,
|
|
53
|
+
parseProgram,
|
|
54
|
+
parseWake,
|
|
38
55
|
parseWhen,
|
|
39
56
|
personAtPrompt,
|
|
40
57
|
REHIT_WINDOW_MS,
|
|
41
58
|
STALE_MS,
|
|
42
59
|
safeId,
|
|
60
|
+
sessionVars,
|
|
43
61
|
splitWhen,
|
|
44
62
|
surfaceOf,
|
|
63
|
+
usageStep,
|
|
45
64
|
WAITING_EXPIRES_MS,
|
|
46
65
|
WAKE_HORIZON_MS,
|
|
66
|
+
WAKE_PROBE,
|
|
67
|
+
WINDOWS_MAINS,
|
|
68
|
+
WINDOWS_POWERSHELL,
|
|
69
|
+
WINDOWS_PROBE,
|
|
47
70
|
when,
|
|
48
71
|
} from "./logic.js";
|
|
49
72
|
|
|
@@ -78,15 +101,25 @@ let mirrorDir;
|
|
|
78
101
|
let sharedAuto;
|
|
79
102
|
/** The session's folder, for where Rewake's CLI names it ("in the shop folder"). */
|
|
80
103
|
let sessionCwd;
|
|
104
|
+
/** This Claude Code process ({ pid, name }) and the session's settings variables, for the copy. */
|
|
105
|
+
let claudeProcess;
|
|
106
|
+
let claudeProgram;
|
|
107
|
+
let claudeVars = {};
|
|
108
|
+
/** Rewake's own headless continue (AGENT_REWAKE_FIRE): the plugin does nothing in it. */
|
|
109
|
+
let inert = false;
|
|
81
110
|
/** This process, in a send's claim: two Claude Code processes can have one session open. */
|
|
82
111
|
const ME = Math.random().toString(36).slice(2);
|
|
83
112
|
/** A claim older than this was left by a process that stopped mid-send. */
|
|
84
113
|
const CLAIM_MS = 5 * MINUTE;
|
|
85
114
|
/** Rewake's keep-awake setting: "plugged-in" (default), "always" or "never". */
|
|
86
115
|
let keepAwake = "plugged-in";
|
|
87
|
-
/**
|
|
88
|
-
let
|
|
89
|
-
/**
|
|
116
|
+
/** Rewake's usage-warnings setting: "on" (default) or "off". */
|
|
117
|
+
let usageWarnings = "on";
|
|
118
|
+
/** CLAUDE_CONFIG_DIR, which names the account's warnings in $.store ("" for the default). */
|
|
119
|
+
let configDir = "";
|
|
120
|
+
/** { kind, pid, program }: Claude Code's PID and the hold program (macOS, Linux with systemd-inhibit, Windows); null where there is none. */
|
|
121
|
+
let wakeTarget;
|
|
122
|
+
/** The running hold: { key, stream }. */
|
|
90
123
|
let wakeHold;
|
|
91
124
|
|
|
92
125
|
const limitKey = (id) => `limit:${id}`;
|
|
@@ -109,6 +142,8 @@ async function loadConfig($) {
|
|
|
109
142
|
if (["on", "off", "ask"].includes(settings.newThreads)) sharedAuto = settings.newThreads;
|
|
110
143
|
if (["plugged-in", "always", "never"].includes(settings.keepAwake))
|
|
111
144
|
keepAwake = settings.keepAwake;
|
|
145
|
+
if (settings.usageWarnings === "on" || settings.usageWarnings === "off")
|
|
146
|
+
usageWarnings = settings.usageWarnings;
|
|
112
147
|
} catch {
|
|
113
148
|
// No settings saved yet: the default clock.
|
|
114
149
|
}
|
|
@@ -117,17 +152,59 @@ async function loadConfig($) {
|
|
|
117
152
|
}
|
|
118
153
|
}
|
|
119
154
|
|
|
155
|
+
/** This process and the session's settings variables, for Rewake's copy of the record. */
|
|
156
|
+
async function loadSessionInfo($) {
|
|
157
|
+
if (!mirrorDir) return;
|
|
158
|
+
// $.env.get takes a literal name, so every variable the plugin reads can be listed (logic.js
|
|
159
|
+
// SETTINGS_VARS and KEY_VARS; a test in Rewake's repository compares them with these).
|
|
160
|
+
const read = (get) => get.catch(() => undefined);
|
|
161
|
+
const values = {
|
|
162
|
+
CLAUDE_CONFIG_DIR: configDir, // read once, at session start
|
|
163
|
+
CLAUDE_CODE_PROJECT_DIR_NAME: await read($.env.get("CLAUDE_CODE_PROJECT_DIR_NAME")),
|
|
164
|
+
ANTHROPIC_BASE_URL: await read($.env.get("ANTHROPIC_BASE_URL")),
|
|
165
|
+
ANTHROPIC_MODEL: await read($.env.get("ANTHROPIC_MODEL")),
|
|
166
|
+
CLAUDE_CODE_USE_BEDROCK: await read($.env.get("CLAUDE_CODE_USE_BEDROCK")),
|
|
167
|
+
CLAUDE_CODE_USE_VERTEX: await read($.env.get("CLAUDE_CODE_USE_VERTEX")),
|
|
168
|
+
CLAUDE_CODE_USE_FOUNDRY: await read($.env.get("CLAUDE_CODE_USE_FOUNDRY")),
|
|
169
|
+
ANTHROPIC_API_KEY: await read($.env.get("ANTHROPIC_API_KEY")),
|
|
170
|
+
ANTHROPIC_AUTH_TOKEN: await read($.env.get("ANTHROPIC_AUTH_TOKEN")),
|
|
171
|
+
CLAUDE_CODE_OAUTH_TOKEN: await read($.env.get("CLAUDE_CODE_OAUTH_TOKEN")),
|
|
172
|
+
};
|
|
173
|
+
claudeVars = sessionVars((name) => values[name]);
|
|
174
|
+
try {
|
|
175
|
+
// The shell's parent is Claude Code; no /bin/sh or ps (Windows) means no process to watch.
|
|
176
|
+
const r = await $.process.run([
|
|
177
|
+
"/bin/sh",
|
|
178
|
+
"-c",
|
|
179
|
+
'echo "$PPID"; ps -o comm= -p "$PPID"; command -v claude',
|
|
180
|
+
]);
|
|
181
|
+
claudeProcess = r.exitCode === 0 ? parseProcess(r.stdout) : undefined;
|
|
182
|
+
claudeProgram = r.exitCode === 0 ? parseProgram(r.stdout) : undefined;
|
|
183
|
+
} catch {
|
|
184
|
+
claudeProcess = undefined;
|
|
185
|
+
claudeProgram = undefined;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
120
189
|
/** Write the record's metadata (never text) where Rewake's CLI reads it. Best effort. */
|
|
121
|
-
async function mirror($, id, ep) {
|
|
190
|
+
async function mirror($, id, ep, lastPromptAt) {
|
|
122
191
|
if (!mirrorDir || !safeId(id)) return;
|
|
123
192
|
const { state, kind, resetAt, fireAt, createdAt, sentAt, rehits, attempts } = ep ?? {
|
|
124
193
|
state: "none",
|
|
125
194
|
};
|
|
195
|
+
const limit = limitOf(ep);
|
|
126
196
|
const record = {
|
|
127
197
|
schemaVersion: 1,
|
|
128
198
|
host: "claude-code",
|
|
129
199
|
sessionId: id,
|
|
130
|
-
|
|
200
|
+
cwd: typeof sessionCwd === "string" ? sessionCwd : "",
|
|
201
|
+
// Rewake's SessionRecord: open while this process runs (it finds out when the process is gone).
|
|
202
|
+
open: true,
|
|
203
|
+
...(claudeProcess && { agents: [claudeProcess] }),
|
|
204
|
+
...(claudeProgram && { program: claudeProgram }),
|
|
205
|
+
...(limit && { limit }),
|
|
206
|
+
...(lastPromptAt !== undefined && { lastPromptAt }),
|
|
207
|
+
...claudeVars,
|
|
131
208
|
state,
|
|
132
209
|
kind,
|
|
133
210
|
resetAt,
|
|
@@ -150,10 +227,10 @@ async function save($, id, ep) {
|
|
|
150
227
|
await mirror($, id, ep);
|
|
151
228
|
}
|
|
152
229
|
|
|
153
|
-
async function drop($, id) {
|
|
230
|
+
async function drop($, id, lastPromptAt) {
|
|
154
231
|
disarm(id);
|
|
155
232
|
await $.store.delete(limitKey(id));
|
|
156
|
-
await mirror($, id, undefined);
|
|
233
|
+
await mirror($, id, undefined, lastPromptAt);
|
|
157
234
|
}
|
|
158
235
|
|
|
159
236
|
function disarm(id) {
|
|
@@ -171,9 +248,53 @@ async function arm($, id, ep) {
|
|
|
171
248
|
}
|
|
172
249
|
|
|
173
250
|
/**
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
251
|
+
* Finds Claude Code's PID (the parent of the shell, or of PowerShell on Windows) and the hold
|
|
252
|
+
* program: caffeinate on macOS, systemd-inhibit on Linux, PowerShell on Windows. Null where the
|
|
253
|
+
* computer has none.
|
|
254
|
+
*/
|
|
255
|
+
async function findWake($) {
|
|
256
|
+
try {
|
|
257
|
+
const r = await $.process.run(["/bin/sh", "-c", WAKE_PROBE]);
|
|
258
|
+
if (r.exitCode === 0) return parseWake(r.stdout) ?? null;
|
|
259
|
+
} catch {
|
|
260
|
+
// No /bin/sh: Windows.
|
|
261
|
+
}
|
|
262
|
+
try {
|
|
263
|
+
const r = await $.process.run([
|
|
264
|
+
WINDOWS_POWERSHELL,
|
|
265
|
+
"-NoProfile",
|
|
266
|
+
"-NonInteractive",
|
|
267
|
+
"-Command",
|
|
268
|
+
WINDOWS_PROBE,
|
|
269
|
+
]);
|
|
270
|
+
const pid = r.stdout.trim();
|
|
271
|
+
return r.exitCode === 0 && /^\d+$/.test(pid)
|
|
272
|
+
? { kind: "win32", pid, program: WINDOWS_POWERSHELL }
|
|
273
|
+
: null;
|
|
274
|
+
} catch {
|
|
275
|
+
return null;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/** Whether a Linux or Windows computer is on mains power; unknown counts as mains. */
|
|
280
|
+
async function onMains($, kind) {
|
|
281
|
+
try {
|
|
282
|
+
const r = await $.process.run(
|
|
283
|
+
kind === "linux"
|
|
284
|
+
? ["/bin/sh", "-c", LINUX_MAINS]
|
|
285
|
+
: [WINDOWS_POWERSHELL, "-NoProfile", "-NonInteractive", "-Command", WINDOWS_MAINS],
|
|
286
|
+
);
|
|
287
|
+
return mainsFrom(kind, r.stdout);
|
|
288
|
+
} catch {
|
|
289
|
+
return true;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Keep this computer from idling to sleep while a continue is due within a few hours: Rewake's own,
|
|
295
|
+
* or Claude Code's (its wait holds nothing while the session sits idle). The hold is tied to Claude
|
|
296
|
+
* Code's process, so it ends with it even after a crash. "plugged-in" holds only on mains power
|
|
297
|
+
* (macOS's `caffeinate -s` does that itself). Returns whether a hold is running.
|
|
177
298
|
*/
|
|
178
299
|
async function updateWake($, ep, now) {
|
|
179
300
|
const due = ep?.state === "armed" ? ep.fireAt : ep?.state === "native" ? ep.resetAt : undefined;
|
|
@@ -182,34 +303,30 @@ async function updateWake($, ep, now) {
|
|
|
182
303
|
due !== undefined &&
|
|
183
304
|
due > now - STALE_MS &&
|
|
184
305
|
due - now <= WAKE_HORIZON_MS;
|
|
185
|
-
|
|
186
|
-
|
|
306
|
+
if (want && wakeTarget === undefined) wakeTarget = await findWake($);
|
|
307
|
+
const t = want ? wakeTarget : undefined;
|
|
308
|
+
const hold =
|
|
309
|
+
t && (keepAwake === "always" || t.kind === "darwin" || (await onMains($, t.kind)))
|
|
310
|
+
? holdArgv(t.kind, keepAwake, t.pid, t.program)
|
|
311
|
+
: undefined;
|
|
312
|
+
const key = hold?.join("\n");
|
|
313
|
+
if (wakeHold && wakeHold.key !== key) {
|
|
187
314
|
void wakeHold.stream.return?.();
|
|
188
315
|
wakeHold = undefined;
|
|
189
316
|
}
|
|
190
|
-
if (!
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
const r = await $.process.run(["/bin/sh", "-c", "test -x /usr/bin/caffeinate && echo $PPID"]);
|
|
195
|
-
wakePid = r.exitCode === 0 && /^\d+$/.test(r.stdout.trim()) ? r.stdout.trim() : null;
|
|
196
|
-
} catch {
|
|
197
|
-
wakePid = null;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
if (wakePid === null) return false;
|
|
201
|
-
const stream = $.process.spawn({ argv: ["/usr/bin/caffeinate", mode, "-w", wakePid] });
|
|
202
|
-
const hold = { mode, stream };
|
|
203
|
-
wakeHold = hold;
|
|
317
|
+
if (!hold || wakeHold) return wakeHold !== undefined;
|
|
318
|
+
const stream = $.process.spawn({ argv: hold });
|
|
319
|
+
const running = { key, stream };
|
|
320
|
+
wakeHold = running;
|
|
204
321
|
void (async () => {
|
|
205
322
|
try {
|
|
206
323
|
for await (const _ of stream) {
|
|
207
|
-
//
|
|
324
|
+
// The hold writes nothing; the loop is the hold's life.
|
|
208
325
|
}
|
|
209
326
|
} catch {
|
|
210
327
|
// It couldn't start: no hold.
|
|
211
328
|
}
|
|
212
|
-
if (wakeHold ===
|
|
329
|
+
if (wakeHold === running) wakeHold = undefined;
|
|
213
330
|
})();
|
|
214
331
|
return true;
|
|
215
332
|
}
|
|
@@ -217,7 +334,10 @@ async function updateWake($, ep, now) {
|
|
|
217
334
|
async function refreshStatus($, id, now) {
|
|
218
335
|
const ep = await $.store.get(limitKey(id));
|
|
219
336
|
const sched = (await $.store.get(schedKey(id))) ?? [];
|
|
220
|
-
const
|
|
337
|
+
const holding = await updateWake($, ep, now);
|
|
338
|
+
const awake = holding
|
|
339
|
+
? ` · keeping this ${wakeTarget?.kind === "darwin" ? "Mac" : "computer"} awake`
|
|
340
|
+
: "";
|
|
221
341
|
if (ep?.state === "armed" && ep.fireAt !== undefined) {
|
|
222
342
|
$.ui.status(`Continues at ${at(ep.fireAt, now)}${awake} · /rewake cancel`);
|
|
223
343
|
} else if (ep?.state === "offered") {
|
|
@@ -340,6 +460,22 @@ async function onLimitOnce($, id) {
|
|
|
340
460
|
await refreshStatus($, id, now);
|
|
341
461
|
return;
|
|
342
462
|
}
|
|
463
|
+
if (resetAt === undefined && rehits > 0) {
|
|
464
|
+
// The limit came back right after Rewake continued, with no new reset time: the first request
|
|
465
|
+
// after the reset was refused (seen at reset + 61 s). The person already said yes, so try
|
|
466
|
+
// again after the usual wait; the re-hit cap above bounds the tries.
|
|
467
|
+
const next = {
|
|
468
|
+
state: "armed",
|
|
469
|
+
createdAt: now,
|
|
470
|
+
rehits,
|
|
471
|
+
attempts: 0,
|
|
472
|
+
fireAt: now + backoffMs(rehits - 1),
|
|
473
|
+
};
|
|
474
|
+
await save($, id, next);
|
|
475
|
+
await arm($, id, next);
|
|
476
|
+
await refreshStatus($, id, now);
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
343
479
|
const ep = { state: "waiting", createdAt: now, rehits, attempts: 0 };
|
|
344
480
|
if (resetAt === undefined) {
|
|
345
481
|
// No reset time yet, or a limit that a wait doesn't fix (credits, a spending cap, an API
|
|
@@ -371,6 +507,26 @@ async function onMeasure($, rateLimits) {
|
|
|
371
507
|
);
|
|
372
508
|
}
|
|
373
509
|
|
|
510
|
+
/** Toasts at 80% and 95% of a usage window, and when the pace would reach the limit soon. */
|
|
511
|
+
async function warnUsage($, rateLimits) {
|
|
512
|
+
if (usageWarnings === "off" || !personAtPrompt({ isInteractive, entrypoint })) return;
|
|
513
|
+
const now = await $.clock.now();
|
|
514
|
+
const key = `usage:${configDir}`;
|
|
515
|
+
const state = (await $.store.get(key)) ?? {};
|
|
516
|
+
const toasts = [];
|
|
517
|
+
for (const w of rateLimits ?? []) {
|
|
518
|
+
const step = w && usageStep(state[w.kind], w, now);
|
|
519
|
+
if (!step) continue;
|
|
520
|
+
state[w.kind] = step.next;
|
|
521
|
+
const reset = atWhen(step.next.resetsAt, now);
|
|
522
|
+
if (step.level !== undefined) toasts.push(levelText(w.kind, w.percentUsed, reset));
|
|
523
|
+
else if (step.pace) toasts.push(paceText(w.kind, step.pace, reset));
|
|
524
|
+
}
|
|
525
|
+
// Saved before showing: a failure while showing must not make the same warning come back.
|
|
526
|
+
await $.store.set(key, state);
|
|
527
|
+
for (const text of toasts) $.ui.toast(text);
|
|
528
|
+
}
|
|
529
|
+
|
|
374
530
|
async function onNotification($, e) {
|
|
375
531
|
const id = e.session_id;
|
|
376
532
|
const ep = await $.store.get(limitKey(id));
|
|
@@ -391,7 +547,9 @@ async function onNotification($, e) {
|
|
|
391
547
|
async function standDown($) {
|
|
392
548
|
const id = await $.session.id();
|
|
393
549
|
const ep = await $.store.get(limitKey(id));
|
|
394
|
-
|
|
550
|
+
// The person (or Claude Code itself) moved on: also tells Rewake, in case it planned to continue
|
|
551
|
+
// this session after Claude Code was closed.
|
|
552
|
+
if (ep && ep.state !== "sent") await drop($, id, await $.clock.now());
|
|
395
553
|
await refreshStatus($, id, await $.clock.now());
|
|
396
554
|
}
|
|
397
555
|
|
|
@@ -511,6 +669,9 @@ async function reopen($) {
|
|
|
511
669
|
return;
|
|
512
670
|
}
|
|
513
671
|
}
|
|
672
|
+
// This process has the session open now: Rewake must not continue it headless meanwhile.
|
|
673
|
+
const open = await $.store.get(limitKey(id));
|
|
674
|
+
if (open) await mirror($, id, open);
|
|
514
675
|
await refreshStatus($, id, now);
|
|
515
676
|
}
|
|
516
677
|
|
|
@@ -731,6 +892,9 @@ export function register(on) {
|
|
|
731
892
|
isInteractive = e.isInteractive;
|
|
732
893
|
sessionCwd = e.cwd;
|
|
733
894
|
entrypoint = await $.env.get("CLAUDE_CODE_ENTRYPOINT").catch(() => undefined);
|
|
895
|
+
configDir = (await $.env.get("CLAUDE_CONFIG_DIR").catch(() => undefined)) ?? "";
|
|
896
|
+
inert = Boolean(await $.env.get("AGENT_REWAKE_FIRE").catch(() => undefined));
|
|
897
|
+
if (inert) return next(e);
|
|
734
898
|
surface = surfaceOf({ surface: e.surface, entrypoint });
|
|
735
899
|
try {
|
|
736
900
|
nativeSetting = { value: (await $.settings.read()).autoContinueAtUsageLimit };
|
|
@@ -738,6 +902,7 @@ export function register(on) {
|
|
|
738
902
|
nativeSetting = undefined;
|
|
739
903
|
}
|
|
740
904
|
await loadConfig($);
|
|
905
|
+
await loadSessionInfo($);
|
|
741
906
|
$.clock.every(TICK_MS, () => void tick($));
|
|
742
907
|
void reopen($);
|
|
743
908
|
for (const entry of [
|
|
@@ -757,6 +922,7 @@ export function register(on) {
|
|
|
757
922
|
});
|
|
758
923
|
|
|
759
924
|
on("classic.SessionStart", ($, e, next) => {
|
|
925
|
+
if (inert) return next(e);
|
|
760
926
|
// An in-process switch (/resume, /clear, /branch): the armed timer belongs to the old one.
|
|
761
927
|
if (e.source === "resume" || e.source === "clear" || e.source === "fork") {
|
|
762
928
|
disarm();
|
|
@@ -767,23 +933,27 @@ export function register(on) {
|
|
|
767
933
|
|
|
768
934
|
on("classic.StopFailure", ($, e, next) => {
|
|
769
935
|
// Main conversation only: helper and subagent failures carry agent_id.
|
|
770
|
-
if (e.error === "rate_limit" && e.agent_id === undefined)
|
|
936
|
+
if (!inert && e.error === "rate_limit" && e.agent_id === undefined)
|
|
937
|
+
void onLimit($, e.session_id);
|
|
771
938
|
return next(e);
|
|
772
939
|
}).catch(passOn);
|
|
773
940
|
|
|
774
941
|
on("session.measure", ($, e, next) => {
|
|
775
|
-
if (e.changed.includes("rateLimits"))
|
|
942
|
+
if (!inert && e.changed.includes("rateLimits")) {
|
|
943
|
+
void onMeasure($, e.rateLimits);
|
|
944
|
+
void warnUsage($, e.rateLimits).catch(() => undefined);
|
|
945
|
+
}
|
|
776
946
|
return next(e);
|
|
777
947
|
}).catch(passOn);
|
|
778
948
|
|
|
779
949
|
on("classic.Notification", ($, e, next) => {
|
|
780
|
-
if (e.notification_type.startsWith("quota_auto_resume_")) void onNotification($, e);
|
|
950
|
+
if (!inert && e.notification_type.startsWith("quota_auto_resume_")) void onNotification($, e);
|
|
781
951
|
return next(e);
|
|
782
952
|
}).catch(passOn);
|
|
783
953
|
|
|
784
954
|
on("prompt.submit", ($, e, next) => {
|
|
785
955
|
// Observe only: the person typed, or Claude Code's own auto-continue fired.
|
|
786
|
-
if (MOVED_ON.has(e.origin.kind)) void standDown($);
|
|
956
|
+
if (!inert && MOVED_ON.has(e.origin.kind)) void standDown($);
|
|
787
957
|
return next(e);
|
|
788
958
|
}).catch(passOn);
|
|
789
959
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codizelabs/agent-rewake",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Auto-resume Claude Code, Codex, Gemini CLI, GitHub Copilot, Grok or any Zed agent when its usage limit resets, in the same session, and schedule messages into your agent threads.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"zed",
|