@codizelabs/agent-rewake 0.5.0 → 0.6.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
CHANGED
|
@@ -37,7 +37,7 @@ Coding agents stop at their usage limit: Claude's 5-hour session limit, Codex's
|
|
|
37
37
|
- **Automatic, if you want.** Choose *from now on* when Rewake asks (Claude Code), turn on auto-resume in Zed's **Rewake** menu, or run `agent-rewake continue --always` (Copilot CLI, Gemini CLI, Grok Build, Qwen Code, OpenCode, Antigravity CLI), and Rewake resumes without asking. It asks first when a limit resets more than a day away, never resumes credit or billing limits (and says so), and never approves permission prompts for you.
|
|
38
38
|
- **Sends messages later.** `/rewake in 1h Run the tests` schedules a message into the session (Zed and Claude Code; in Zed also on a repeat, such as every weekday at 9).
|
|
39
39
|
- **Keeps the computer awake, if it can.** On macOS, and on Linux (with systemd) and Windows, while a resume is due within six hours, Rewake stops the computer from idling to sleep (while plugged in, by default). Only macOS has been tried by hand. Closing the lid still puts it to sleep. `agent-rewake doctor` tells you if your computer's own sleep settings would let it sleep, and [which settings to change](https://codizelabs.github.io/agent-rewake/docs/#keep-your-computer-awake).
|
|
40
|
-
- **Warns you before a usage limit (Claude Code).** The plugin tells you when a usage window passes 80% and 95%, and when your pace over the last hour would reach the limit within about 45 minutes (as a range, "in about 20 to 40 minutes"). It uses only the usage figures Claude Code already gives it: no network, no sign-in. It only tells you; at 80% it mentions `/compact` (which uses some quota itself)
|
|
40
|
+
- **Warns you before a usage limit (Claude Code and Codex).** The plugin tells you when a usage window passes 80% and 95%, and when your pace over the last hour would reach the limit within about 45 minutes (as a range, "in about 20 to 40 minutes"). It uses only the usage figures Claude Code or Codex already gives it: no network, no sign-in. It only tells you; in Claude Code, at 80% it mentions `/compact` (which uses some quota itself); at 95% it says it is a good moment to wrap up. It never types or compacts for you. Turn it off with `agent-rewake settings usage-warnings off`. In Codex the same warnings come with your next prompt, from the figures of Codex's previous reply (so one turn late); they are not yet seen in the Codex desktop app or the VS Code extension. Not built for the other agents.
|
|
41
41
|
- **Tells you when the project changed while it waited.** Outside Zed, if the session's folder is a git folder and its latest commit or tracked files differ by the time Rewake sends, it tells you, and sends the message as it was. You can instead have it add one fixed line asking the agent to re-read files (`agent-rewake settings workspace-changed note`), or send nothing and ask you first (`hold`). It reads only the commit id and the names-and-status summary from `git status --porcelain --untracked-files=no`, never file contents, and only on your computer.
|
|
42
42
|
- **Same agent, same session.** No new agent to pick: Rewake works inside or in front of the agents you already use, so your sessions and threads keep going where they stopped.
|
|
43
43
|
|
|
@@ -152,7 +152,7 @@ This takes Rewake out of every place it's set up in, after showing every change
|
|
|
152
152
|
|
|
153
153
|
## Status
|
|
154
154
|
|
|
155
|
-
Version 0.
|
|
155
|
+
Version 0.6. Rewake's automated tests run on macOS, Linux and Windows with Node.js 22 and 24, and the author uses it daily in Zed. The previews outside Zed are new: the docs say [what's been tried for each](https://codizelabs.github.io/agent-rewake/docs/#outside-zed-previews), and what hasn't. What changed in each release is in the [changelog](https://codizelabs.github.io/agent-rewake/changelog/). Feedback and bug reports are very welcome: [open an issue](https://github.com/codizelabs/agent-rewake/issues/new/choose). If Rewake missed a usage limit, [say how](https://codizelabs.github.io/agent-rewake/docs/#report-a-limit-rewake-missed).
|
|
156
156
|
|
|
157
157
|
## Contributing
|
|
158
158
|
|
package/dist/agent-rewake.js
CHANGED
|
@@ -4968,7 +4968,7 @@ var init_version = __esm({
|
|
|
4968
4968
|
return {};
|
|
4969
4969
|
}
|
|
4970
4970
|
})();
|
|
4971
|
-
VERSION2 = pkg.version ?? (true ? "0.
|
|
4971
|
+
VERSION2 = pkg.version ?? (true ? "0.6.0" : "0.0.0");
|
|
4972
4972
|
PACKAGE_NAME = pkg.name ?? "@codizelabs/agent-rewake";
|
|
4973
4973
|
FROM_SOURCE = false;
|
|
4974
4974
|
}
|
|
@@ -6930,6 +6930,31 @@ function chooseSnapshot(snapshots, last, nowSec) {
|
|
|
6930
6930
|
const fullest = (s) => Math.max(...[s.primary, s.secondary].map((w) => w ? w.used_percent ?? 0 : 0));
|
|
6931
6931
|
return withWindows.reduce((a, b) => fullest(b) > fullest(a) ? b : a);
|
|
6932
6932
|
}
|
|
6933
|
+
function lastWindows(tail) {
|
|
6934
|
+
let found;
|
|
6935
|
+
for (const line2 of tail.split("\n")) {
|
|
6936
|
+
if (!line2.startsWith("{") || !line2.includes('"token_count"')) continue;
|
|
6937
|
+
try {
|
|
6938
|
+
const p = JSON.parse(line2).payload;
|
|
6939
|
+
const rl = p?.type === "token_count" ? p.rate_limits : void 0;
|
|
6940
|
+
if (!rl || typeof rl !== "object") continue;
|
|
6941
|
+
if (rl.limit_id && rl.limit_id !== "codex") continue;
|
|
6942
|
+
if (rl.primary || rl.secondary) found = rl;
|
|
6943
|
+
} catch {
|
|
6944
|
+
}
|
|
6945
|
+
}
|
|
6946
|
+
const out = [];
|
|
6947
|
+
for (const w of [found?.primary, found?.secondary]) {
|
|
6948
|
+
const m = w?.window_minutes;
|
|
6949
|
+
if (!w || typeof m !== "number" || !(m > 0) || typeof w.used_percent !== "number") continue;
|
|
6950
|
+
out.push({
|
|
6951
|
+
kind: m >= 270 && m <= 330 ? "five_hour" : m >= 9e3 && m <= 11e3 ? "seven_day" : `${Math.max(1, Math.round(m / 60))}_hour`,
|
|
6952
|
+
percentUsed: w.used_percent,
|
|
6953
|
+
...typeof w.resets_at === "number" && { resetsAt: w.resets_at * 1e3 }
|
|
6954
|
+
});
|
|
6955
|
+
}
|
|
6956
|
+
return out;
|
|
6957
|
+
}
|
|
6933
6958
|
function spentWindowReset(rl, nowSec) {
|
|
6934
6959
|
if (!rl || !/^workspace_/.test(rl.rate_limit_reached_type ?? "") || rl.spend_control_reached)
|
|
6935
6960
|
return {};
|
|
@@ -15757,8 +15782,8 @@ var init_settings_command = __esm({
|
|
|
15757
15782
|
{
|
|
15758
15783
|
name: "usage-warnings",
|
|
15759
15784
|
title: "Warnings before a usage limit",
|
|
15760
|
-
short: "
|
|
15761
|
-
more: "Claude Code only. It uses
|
|
15785
|
+
short: "Warn me when a usage limit is nearly used up (Claude Code, at the moment it happens; Codex, with your next prompt).",
|
|
15786
|
+
more: "Claude Code and Codex only. It uses their own usage figures, with no network and no sign-in, and never types anything for you.",
|
|
15762
15787
|
choices: () => [
|
|
15763
15788
|
["on", "Warn at 80% and 95% used, and when the pace would reach the limit within 45 minutes"],
|
|
15764
15789
|
["off", "Don't warn"]
|
|
@@ -15768,7 +15793,7 @@ var init_settings_command = __esm({
|
|
|
15768
15793
|
...s,
|
|
15769
15794
|
usageWarnings: USAGE_WARNINGS_VALUES.find((x) => x === v) ?? s.usageWarnings
|
|
15770
15795
|
}),
|
|
15771
|
-
saved: (v) => v === "off" ? "Claude Code won't warn you before a usage limit." : "Claude Code
|
|
15796
|
+
saved: (v) => v === "off" ? "Claude Code and Codex won't warn you before a usage limit." : "Claude Code and Codex warn you at 80% and 95% of a usage limit, and when your pace would reach it within 45 minutes."
|
|
15772
15797
|
}
|
|
15773
15798
|
];
|
|
15774
15799
|
orList2 = (v) => v.length < 2 ? v[0] ?? "" : `${v.slice(0, -1).join(", ")} or ${v.at(-1)}`;
|
|
@@ -17261,6 +17286,132 @@ var init_adapter = __esm({
|
|
|
17261
17286
|
}
|
|
17262
17287
|
});
|
|
17263
17288
|
|
|
17289
|
+
// src/core/usage-warn.ts
|
|
17290
|
+
function timeToLimit(samples, now) {
|
|
17291
|
+
const recent = samples.filter((s) => s.t >= now - RECENT_MS);
|
|
17292
|
+
const first = recent[0];
|
|
17293
|
+
const last = recent.at(-1);
|
|
17294
|
+
if (!first || !last || last.t !== now || last.t - first.t < MIN_SPAN_MS) return void 0;
|
|
17295
|
+
const rate = (last.p - first.p) / (last.t - first.t);
|
|
17296
|
+
return rate > 0 ? (100 - last.p) / rate : void 0;
|
|
17297
|
+
}
|
|
17298
|
+
function paceRange(ms) {
|
|
17299
|
+
const five = (x) => Math.max(5, Math.round(x / (5 * MINUTE)) * 5);
|
|
17300
|
+
const lo = five(ms * 0.7);
|
|
17301
|
+
return [lo, Math.max(lo + 5, five(ms * 1.4))];
|
|
17302
|
+
}
|
|
17303
|
+
function usageStep(prev, w, now) {
|
|
17304
|
+
const reset = w.resetsAt;
|
|
17305
|
+
const p = w.percentUsed;
|
|
17306
|
+
if (reset === void 0 || !Number.isFinite(reset) || reset <= now) return void 0;
|
|
17307
|
+
if (!(p >= 0 && p < 100)) return void 0;
|
|
17308
|
+
const base = prev && Math.abs(prev.resetsAt - reset) < SAME_WINDOW_MS ? prev : { resetsAt: reset, samples: [], high: 0, pace: false };
|
|
17309
|
+
const last = base.samples.at(-1);
|
|
17310
|
+
const samples = last?.p === p ? base.samples : [...last && p < last.p ? [] : base.samples, { t: now, p }];
|
|
17311
|
+
const kept = samples.slice(-SAMPLE_CAP);
|
|
17312
|
+
const level = WARN_AT.filter((l) => p >= l && l > base.high).pop();
|
|
17313
|
+
const ms = level === void 0 && !base.pace ? timeToLimit(kept, now) : void 0;
|
|
17314
|
+
const pace = ms !== void 0 && ms <= PACE_HORIZON_MS && now + ms < reset ? paceRange(ms) : void 0;
|
|
17315
|
+
return {
|
|
17316
|
+
next: {
|
|
17317
|
+
resetsAt: reset,
|
|
17318
|
+
samples: kept,
|
|
17319
|
+
high: level ?? base.high,
|
|
17320
|
+
pace: base.pace || pace !== void 0
|
|
17321
|
+
},
|
|
17322
|
+
...level !== void 0 && { level },
|
|
17323
|
+
...pace && { pace }
|
|
17324
|
+
};
|
|
17325
|
+
}
|
|
17326
|
+
function limitName(kind) {
|
|
17327
|
+
const hours = /^(\d+)_hour$/.exec(kind)?.[1];
|
|
17328
|
+
const name = kind === "five_hour" ? "5-hour" : kind === "seven_day" ? "7-day" : hours ? `${hours}-hour` : kind.replace(/_/g, " ");
|
|
17329
|
+
return `${name} limit`;
|
|
17330
|
+
}
|
|
17331
|
+
function levelText(kind, percent, reset) {
|
|
17332
|
+
const head = `${limitName(kind)}: ${Math.floor(percent)}% used, as of Codex's last reply. It resets ${reset}.`;
|
|
17333
|
+
return percent >= 95 ? `${head} A good moment to wrap up or save what you are doing.` : head;
|
|
17334
|
+
}
|
|
17335
|
+
function paceText(kind, [lo, hi], reset) {
|
|
17336
|
+
return `At this pace you reach the ${limitName(kind)} in about ${lo} to ${hi} minutes, before it resets ${reset}.`;
|
|
17337
|
+
}
|
|
17338
|
+
var MINUTE, WARN_AT, SAMPLE_CAP, MIN_SPAN_MS, RECENT_MS, PACE_HORIZON_MS, SAME_WINDOW_MS;
|
|
17339
|
+
var init_usage_warn = __esm({
|
|
17340
|
+
"src/core/usage-warn.ts"() {
|
|
17341
|
+
"use strict";
|
|
17342
|
+
MINUTE = 6e4;
|
|
17343
|
+
WARN_AT = [80, 95];
|
|
17344
|
+
SAMPLE_CAP = 12;
|
|
17345
|
+
MIN_SPAN_MS = 10 * MINUTE;
|
|
17346
|
+
RECENT_MS = 60 * MINUTE;
|
|
17347
|
+
PACE_HORIZON_MS = 45 * MINUTE;
|
|
17348
|
+
SAME_WINDOW_MS = 30 * MINUTE;
|
|
17349
|
+
}
|
|
17350
|
+
});
|
|
17351
|
+
|
|
17352
|
+
// src/hosts/codex/usage.ts
|
|
17353
|
+
import { readFileSync as readFileSync33 } from "node:fs";
|
|
17354
|
+
import { dirname as dirname7, join as join44 } from "node:path";
|
|
17355
|
+
function validStored(v) {
|
|
17356
|
+
const out = {};
|
|
17357
|
+
for (const [home, kinds] of Object.entries(v)) {
|
|
17358
|
+
if (typeof kinds !== "object" || kinds === null || Array.isArray(kinds)) continue;
|
|
17359
|
+
const ok = {};
|
|
17360
|
+
for (const [kind, st] of Object.entries(kinds)) {
|
|
17361
|
+
const s = st;
|
|
17362
|
+
if (s && typeof s.resetsAt === "number" && Array.isArray(s.samples)) ok[kind] = st;
|
|
17363
|
+
}
|
|
17364
|
+
out[home] = ok;
|
|
17365
|
+
}
|
|
17366
|
+
return out;
|
|
17367
|
+
}
|
|
17368
|
+
function load(file) {
|
|
17369
|
+
try {
|
|
17370
|
+
const v = JSON.parse(readFileSync33(file, "utf8"));
|
|
17371
|
+
return typeof v === "object" && v !== null && !Array.isArray(v) ? validStored(v) : {};
|
|
17372
|
+
} catch {
|
|
17373
|
+
return {};
|
|
17374
|
+
}
|
|
17375
|
+
}
|
|
17376
|
+
function usageWarning(stateDir2, rollout, now) {
|
|
17377
|
+
try {
|
|
17378
|
+
const windows = lastWindows(readTail2(rollout));
|
|
17379
|
+
if (windows.length === 0) return void 0;
|
|
17380
|
+
const file = join44(stateDir2, FILE);
|
|
17381
|
+
const all = load(file);
|
|
17382
|
+
const home = homeOf(rollout);
|
|
17383
|
+
const kept = { ...all[home] };
|
|
17384
|
+
const texts = [];
|
|
17385
|
+
for (const w of windows) {
|
|
17386
|
+
const step = usageStep(kept[w.kind], w, now);
|
|
17387
|
+
if (!step) continue;
|
|
17388
|
+
kept[w.kind] = step.next;
|
|
17389
|
+
const reset = formatAt(step.next.resetsAt, now);
|
|
17390
|
+
if (step.level !== void 0) texts.push(levelText(w.kind, w.percentUsed, reset));
|
|
17391
|
+
else if (step.pace) texts.push(paceText(w.kind, step.pace, reset));
|
|
17392
|
+
}
|
|
17393
|
+
ensurePrivateDir(stateDir2);
|
|
17394
|
+
replaceFileExclusive(file, `${JSON.stringify({ ...all, [home]: kept })}
|
|
17395
|
+
`, 384);
|
|
17396
|
+
return texts.length > 0 ? JSON.stringify({ systemMessage: `Rewake: ${texts.join(" ")}` }) : void 0;
|
|
17397
|
+
} catch {
|
|
17398
|
+
return void 0;
|
|
17399
|
+
}
|
|
17400
|
+
}
|
|
17401
|
+
var FILE, homeOf;
|
|
17402
|
+
var init_usage = __esm({
|
|
17403
|
+
"src/hosts/codex/usage.ts"() {
|
|
17404
|
+
"use strict";
|
|
17405
|
+
init_time();
|
|
17406
|
+
init_usage_warn();
|
|
17407
|
+
init_fs();
|
|
17408
|
+
init_paths();
|
|
17409
|
+
init_rollout();
|
|
17410
|
+
FILE = "codex-usage.json";
|
|
17411
|
+
homeOf = (rollout) => dirname7(dirname7(dirname7(dirname7(dirname7(rollout)))));
|
|
17412
|
+
}
|
|
17413
|
+
});
|
|
17414
|
+
|
|
17264
17415
|
// src/hosts/codex/hooks.ts
|
|
17265
17416
|
import { basename as basename9 } from "node:path";
|
|
17266
17417
|
function threadOf(input) {
|
|
@@ -17332,7 +17483,7 @@ function codexHooks(deps) {
|
|
|
17332
17483
|
const m = REWAKE2.exec(prompt2);
|
|
17333
17484
|
if (!m) {
|
|
17334
17485
|
cancelPending(ctx, thread.id);
|
|
17335
|
-
return void 0;
|
|
17486
|
+
return applySettings(ctx.stateDir).usageWarnings === "off" ? void 0 : usageWarning(ctx.stateDir, thread.path, ctx.now);
|
|
17336
17487
|
}
|
|
17337
17488
|
const c = continueOnly(CODEX_PLACE, m[1] ?? "", ctx.now);
|
|
17338
17489
|
if (c.kind === "reply") return block2(c.text);
|
|
@@ -17434,6 +17585,7 @@ var init_hooks = __esm({
|
|
|
17434
17585
|
init_time();
|
|
17435
17586
|
init_closed();
|
|
17436
17587
|
init_rollout();
|
|
17588
|
+
init_usage();
|
|
17437
17589
|
CODEX_PLACE = { name: "Codex", typed: "rewake", features: /* @__PURE__ */ new Set() };
|
|
17438
17590
|
REWAKE2 = /^\s*\/?rewake(?:\s+([\s\S]*?))?\s*$/i;
|
|
17439
17591
|
block2 = (reason) => JSON.stringify({ decision: "block", reason });
|
|
@@ -17592,14 +17744,14 @@ var init_host6 = __esm({
|
|
|
17592
17744
|
});
|
|
17593
17745
|
|
|
17594
17746
|
// src/hosts/cursor/host.ts
|
|
17595
|
-
import { readFileSync as
|
|
17747
|
+
import { readFileSync as readFileSync34 } from "node:fs";
|
|
17596
17748
|
function block3(userMessage) {
|
|
17597
17749
|
return JSON.stringify({ continue: false, user_message: userMessage });
|
|
17598
17750
|
}
|
|
17599
17751
|
function transcriptError(path) {
|
|
17600
17752
|
if (typeof path !== "string" || path === "") return void 0;
|
|
17601
17753
|
try {
|
|
17602
|
-
const lines =
|
|
17754
|
+
const lines = readFileSync34(path, "utf8").trimEnd().split("\n");
|
|
17603
17755
|
const last = JSON.parse(lines.at(-1) ?? "{}");
|
|
17604
17756
|
if (last.type === "turn_ended" && last.status === "error" && typeof last.error === "string")
|
|
17605
17757
|
return last.error;
|
|
@@ -18177,7 +18329,7 @@ var init_hook = __esm({
|
|
|
18177
18329
|
|
|
18178
18330
|
// src/install/cleanup.ts
|
|
18179
18331
|
import { existsSync as existsSync27, readdirSync as readdirSync19, rmdirSync, rmSync as rmSync20 } from "node:fs";
|
|
18180
|
-
import { dirname as
|
|
18332
|
+
import { dirname as dirname8, join as join45 } from "node:path";
|
|
18181
18333
|
function removeHelpers(stateDir2, timers) {
|
|
18182
18334
|
for (const id of timerIds(timers)) {
|
|
18183
18335
|
try {
|
|
@@ -18185,16 +18337,16 @@ function removeHelpers(stateDir2, timers) {
|
|
|
18185
18337
|
} catch {
|
|
18186
18338
|
}
|
|
18187
18339
|
}
|
|
18188
|
-
rmSync20(
|
|
18340
|
+
rmSync20(join45(stateDir2, "timers"), { recursive: true, force: true });
|
|
18189
18341
|
for (const file of [launcherPath(stateDir2), nodeShimPath(stateDir2)])
|
|
18190
18342
|
rmSync20(file, { force: true });
|
|
18191
|
-
rmSync20(
|
|
18343
|
+
rmSync20(join45(stateDir2, "bin", "agent-rewake.version"), { force: true });
|
|
18192
18344
|
try {
|
|
18193
|
-
rmdirSync(
|
|
18345
|
+
rmdirSync(join45(stateDir2, "bin"));
|
|
18194
18346
|
} catch {
|
|
18195
18347
|
}
|
|
18196
|
-
rmSync20(
|
|
18197
|
-
rmSync20(
|
|
18348
|
+
rmSync20(join45(stateDir2, "locks"), { recursive: true, force: true });
|
|
18349
|
+
rmSync20(join45(stateDir2, ".pruned"), { force: true });
|
|
18198
18350
|
}
|
|
18199
18351
|
function findBackups(dirs) {
|
|
18200
18352
|
const found = /* @__PURE__ */ new Set();
|
|
@@ -18205,7 +18357,7 @@ function findBackups(dirs) {
|
|
|
18205
18357
|
} catch {
|
|
18206
18358
|
continue;
|
|
18207
18359
|
}
|
|
18208
|
-
for (const n of names) if (n.includes(".agent-rewake-backup-")) found.add(
|
|
18360
|
+
for (const n of names) if (n.includes(".agent-rewake-backup-")) found.add(join45(dir, n));
|
|
18209
18361
|
}
|
|
18210
18362
|
return [...found].sort();
|
|
18211
18363
|
}
|
|
@@ -18216,11 +18368,11 @@ Rewake is still set up in ${list(f.stillIn)}, so its folder and the files those
|
|
|
18216
18368
|
`;
|
|
18217
18369
|
const kept = [];
|
|
18218
18370
|
const mine = [
|
|
18219
|
-
hasFiles(
|
|
18220
|
-
hasFiles(
|
|
18221
|
-
existsSync27(
|
|
18222
|
-
hasFiles(
|
|
18223
|
-
hasFiles(
|
|
18371
|
+
hasFiles(join45(f.stateDir, "schedules")) && "your scheduled messages",
|
|
18372
|
+
hasFiles(join45(f.stateDir, "threads")) && "your thread settings",
|
|
18373
|
+
existsSync27(join45(f.stateDir, "settings.json")) && "your settings",
|
|
18374
|
+
hasFiles(join45(f.stateDir, "logs")) && "logs (no message text)",
|
|
18375
|
+
hasFiles(join45(f.stateDir, "agents")) && "agents Rewake downloaded"
|
|
18224
18376
|
].filter((x) => typeof x === "string");
|
|
18225
18377
|
if (mine.length > 0) kept.push(`Rewake's folder, with ${list(mine)}: ${f.stateDir}`);
|
|
18226
18378
|
for (const b of f.backups) kept.push(`A copy Rewake made of a file before changing it: ${b}`);
|
|
@@ -18246,9 +18398,9 @@ function finishUninstall(o) {
|
|
|
18246
18398
|
removeHelpers(state, defaultTimerHost(state, "node", launcherPath(state)));
|
|
18247
18399
|
const backups = findBackups([
|
|
18248
18400
|
zedDir,
|
|
18249
|
-
|
|
18250
|
-
|
|
18251
|
-
|
|
18401
|
+
join45(o.home, ".cursor"),
|
|
18402
|
+
dirname8(jetbrainsFile(o.env, o.home)),
|
|
18403
|
+
dirname8(devinFile(o.env, o.home, o.platform))
|
|
18252
18404
|
]);
|
|
18253
18405
|
const text2 = existsSync27(state) ? leftoverText({ stateDir: state, stillIn, backups, codex: o.chosen.includes("codex") }) : void 0;
|
|
18254
18406
|
return { text: text2, remains: stillIn.length > 0 };
|
|
@@ -19063,11 +19215,11 @@ var init_report = __esm({
|
|
|
19063
19215
|
});
|
|
19064
19216
|
|
|
19065
19217
|
// src/timers/slots.ts
|
|
19066
|
-
import { readFileSync as
|
|
19067
|
-
import { join as
|
|
19218
|
+
import { readFileSync as readFileSync35 } from "node:fs";
|
|
19219
|
+
import { join as join46 } from "node:path";
|
|
19068
19220
|
function lastStart2(stateDir2) {
|
|
19069
19221
|
try {
|
|
19070
|
-
const n = Number(
|
|
19222
|
+
const n = Number(readFileSync35(join46(stateDir2, "locks", START_FILE), "utf8").trim());
|
|
19071
19223
|
return Number.isFinite(n) ? n : 0;
|
|
19072
19224
|
} catch {
|
|
19073
19225
|
return 0;
|
|
@@ -19097,7 +19249,7 @@ async function takeSlot(o) {
|
|
|
19097
19249
|
try {
|
|
19098
19250
|
const wait2 = Math.min(lastStart2(o.stateDir) + gap - clock2(), deadline - clock2());
|
|
19099
19251
|
if (wait2 > 0) await sleep(wait2);
|
|
19100
|
-
writeFileAtomic(ensurePrivateDir(
|
|
19252
|
+
writeFileAtomic(ensurePrivateDir(join46(o.stateDir, "locks")), START_FILE, `${clock2()}
|
|
19101
19253
|
`);
|
|
19102
19254
|
} finally {
|
|
19103
19255
|
if (mine) lock.release(START_KEY);
|
|
@@ -19614,14 +19766,14 @@ var init_fire = __esm({
|
|
|
19614
19766
|
});
|
|
19615
19767
|
|
|
19616
19768
|
// src/timers/login.ts
|
|
19617
|
-
import { existsSync as existsSync29, mkdirSync as mkdirSync3, readFileSync as
|
|
19618
|
-
import { dirname as
|
|
19769
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync3, readFileSync as readFileSync36, rmSync as rmSync21 } from "node:fs";
|
|
19770
|
+
import { dirname as dirname9, join as join47 } from "node:path";
|
|
19619
19771
|
function loginItem(h) {
|
|
19620
19772
|
const args = [h.node, h.cli, "sweep", "--state-dir", h.stateDir];
|
|
19621
19773
|
if (h.platform === "darwin")
|
|
19622
19774
|
return {
|
|
19623
19775
|
kind: "launchd",
|
|
19624
|
-
path:
|
|
19776
|
+
path: join47(h.home, "Library", "LaunchAgents", `${LOGIN_LABEL}.plist`),
|
|
19625
19777
|
text: `<?xml version="1.0" encoding="UTF-8"?>
|
|
19626
19778
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
19627
19779
|
<plist version="1.0">
|
|
@@ -19641,7 +19793,7 @@ function loginItem(h) {
|
|
|
19641
19793
|
if (h.exists("/run/systemd/system"))
|
|
19642
19794
|
return {
|
|
19643
19795
|
kind: "systemd",
|
|
19644
|
-
path:
|
|
19796
|
+
path: join47(h.home, ".config", "systemd", "user", UNIT),
|
|
19645
19797
|
text: `[Unit]
|
|
19646
19798
|
Description=Agent Rewake: set planned resumes again after a restart
|
|
19647
19799
|
|
|
@@ -19655,7 +19807,7 @@ WantedBy=default.target
|
|
|
19655
19807
|
};
|
|
19656
19808
|
return {
|
|
19657
19809
|
kind: "autostart",
|
|
19658
|
-
path:
|
|
19810
|
+
path: join47(h.home, ".config", "autostart", "agent-rewake-sweep.desktop"),
|
|
19659
19811
|
text: `[Desktop Entry]
|
|
19660
19812
|
Type=Application
|
|
19661
19813
|
Name=Agent Rewake
|
|
@@ -19673,9 +19825,9 @@ function syncLoginItem(h, wanted) {
|
|
|
19673
19825
|
if (!item) return "unchanged";
|
|
19674
19826
|
const had = existsSync29(item.path);
|
|
19675
19827
|
if (wanted) {
|
|
19676
|
-
const same2 = had &&
|
|
19828
|
+
const same2 = had && readFileSync36(item.path, "utf8") === item.text;
|
|
19677
19829
|
if (same2) return "unchanged";
|
|
19678
|
-
mkdirSync3(
|
|
19830
|
+
mkdirSync3(dirname9(item.path), { recursive: true });
|
|
19679
19831
|
replaceFileExclusive(item.path, item.text, 420);
|
|
19680
19832
|
if (item.kind === "systemd") {
|
|
19681
19833
|
h.run("systemctl", ["--user", "daemon-reload"]);
|
|
@@ -19721,10 +19873,10 @@ import {
|
|
|
19721
19873
|
utimesSync,
|
|
19722
19874
|
writeFileSync as writeFileSync7
|
|
19723
19875
|
} from "node:fs";
|
|
19724
|
-
import { join as
|
|
19876
|
+
import { join as join48 } from "node:path";
|
|
19725
19877
|
function pruneState(stateDir2, now, opts = {}) {
|
|
19726
19878
|
if (!existsSync30(stateDir2)) return void 0;
|
|
19727
|
-
const marker =
|
|
19879
|
+
const marker = join48(stateDir2, MARKER);
|
|
19728
19880
|
if (!opts.force)
|
|
19729
19881
|
try {
|
|
19730
19882
|
if (now - statSync10(marker).mtimeMs < EVERY_MS) return void 0;
|
|
@@ -19755,7 +19907,7 @@ function pruneState(stateDir2, now, opts = {}) {
|
|
|
19755
19907
|
function pruneSessions(stateDir2, cutoff, needed) {
|
|
19756
19908
|
let hosts;
|
|
19757
19909
|
try {
|
|
19758
|
-
hosts = readdirSync20(
|
|
19910
|
+
hosts = readdirSync20(join48(stateDir2, "hosts"));
|
|
19759
19911
|
} catch {
|
|
19760
19912
|
return 0;
|
|
19761
19913
|
}
|
|
@@ -19771,7 +19923,7 @@ function pruneSessions(stateDir2, cutoff, needed) {
|
|
|
19771
19923
|
return n;
|
|
19772
19924
|
}
|
|
19773
19925
|
function pruneLogs(stateDir2, cutoff) {
|
|
19774
|
-
const dir =
|
|
19926
|
+
const dir = join48(stateDir2, "logs");
|
|
19775
19927
|
let names;
|
|
19776
19928
|
try {
|
|
19777
19929
|
names = readdirSync20(dir);
|
|
@@ -19784,7 +19936,7 @@ function pruneLogs(stateDir2, cutoff) {
|
|
|
19784
19936
|
const m = /^rewake-(\d{4}-\d{2}-\d{2})\.jsonl$/.exec(f);
|
|
19785
19937
|
if (!m || m[1] >= oldest) continue;
|
|
19786
19938
|
try {
|
|
19787
|
-
rmSync22(
|
|
19939
|
+
rmSync22(join48(dir, f), { force: true });
|
|
19788
19940
|
n++;
|
|
19789
19941
|
} catch {
|
|
19790
19942
|
}
|
|
@@ -19800,7 +19952,7 @@ function pruneTemp(dir, before, depth = 0) {
|
|
|
19800
19952
|
}
|
|
19801
19953
|
let n = 0;
|
|
19802
19954
|
for (const e of entries) {
|
|
19803
|
-
const path =
|
|
19955
|
+
const path = join48(dir, e.name);
|
|
19804
19956
|
if (e.isDirectory()) {
|
|
19805
19957
|
if (depth < MAX_DEPTH && !SKIP_DIRS.has(e.name)) n += pruneTemp(path, before, depth + 1);
|
|
19806
19958
|
} else if (e.isFile() && TEMP_NAME.test(e.name)) {
|
|
@@ -20055,8 +20207,8 @@ var init_input = __esm({
|
|
|
20055
20207
|
});
|
|
20056
20208
|
|
|
20057
20209
|
// src/ui/page.ts
|
|
20058
|
-
import { readFileSync as
|
|
20059
|
-
import { join as
|
|
20210
|
+
import { readFileSync as readFileSync37, writeFileSync as writeFileSync8 } from "node:fs";
|
|
20211
|
+
import { join as join49 } from "node:path";
|
|
20060
20212
|
function rowLabel(r) {
|
|
20061
20213
|
if (r.host === void 0) return threadLabel(r.thread, r.schedule);
|
|
20062
20214
|
const title = r.thread?.title ?? `${capital(r.noun)} ${r.schedule.sessionId.slice(0, 8)}`;
|
|
@@ -20314,11 +20466,11 @@ var init_page = __esm({
|
|
|
20314
20466
|
return this.rows[this.selected];
|
|
20315
20467
|
}
|
|
20316
20468
|
prefsFile() {
|
|
20317
|
-
return
|
|
20469
|
+
return join49(this.opts.stateDir, "ui.json");
|
|
20318
20470
|
}
|
|
20319
20471
|
prefs() {
|
|
20320
20472
|
try {
|
|
20321
|
-
return JSON.parse(
|
|
20473
|
+
return JSON.parse(readFileSync37(this.prefsFile(), "utf8"));
|
|
20322
20474
|
} catch {
|
|
20323
20475
|
return {};
|
|
20324
20476
|
}
|
|
@@ -21248,11 +21400,11 @@ var init_tui = __esm({
|
|
|
21248
21400
|
});
|
|
21249
21401
|
|
|
21250
21402
|
// src/util/installed.ts
|
|
21251
|
-
import { readFileSync as
|
|
21252
|
-
import { join as
|
|
21403
|
+
import { readFileSync as readFileSync38 } from "node:fs";
|
|
21404
|
+
import { join as join50 } from "node:path";
|
|
21253
21405
|
function readInstalled(stateDir2) {
|
|
21254
21406
|
try {
|
|
21255
|
-
const v = JSON.parse(
|
|
21407
|
+
const v = JSON.parse(readFileSync38(join50(stateDir2, FILE2), "utf8"));
|
|
21256
21408
|
return typeof v.version === "string" && typeof v.at === "number" && Number.isFinite(v.at) ? { version: v.version, at: v.at } : void 0;
|
|
21257
21409
|
} catch {
|
|
21258
21410
|
return void 0;
|
|
@@ -21263,26 +21415,26 @@ function recordInstall(stateDir2, version, now) {
|
|
|
21263
21415
|
try {
|
|
21264
21416
|
writeFileAtomic(
|
|
21265
21417
|
ensurePrivateDir(stateDir2),
|
|
21266
|
-
|
|
21418
|
+
FILE2,
|
|
21267
21419
|
`${JSON.stringify({ version, at: now })}
|
|
21268
21420
|
`
|
|
21269
21421
|
);
|
|
21270
21422
|
} catch {
|
|
21271
21423
|
}
|
|
21272
21424
|
}
|
|
21273
|
-
var
|
|
21425
|
+
var FILE2;
|
|
21274
21426
|
var init_installed = __esm({
|
|
21275
21427
|
"src/util/installed.ts"() {
|
|
21276
21428
|
"use strict";
|
|
21277
21429
|
init_store();
|
|
21278
21430
|
init_paths();
|
|
21279
|
-
|
|
21431
|
+
FILE2 = "installed.json";
|
|
21280
21432
|
}
|
|
21281
21433
|
});
|
|
21282
21434
|
|
|
21283
21435
|
// src/util/log.ts
|
|
21284
21436
|
import { appendFileSync } from "node:fs";
|
|
21285
|
-
import { join as
|
|
21437
|
+
import { join as join51 } from "node:path";
|
|
21286
21438
|
var Logger;
|
|
21287
21439
|
var init_log = __esm({
|
|
21288
21440
|
"src/util/log.ts"() {
|
|
@@ -21319,8 +21471,8 @@ var init_log = __esm({
|
|
|
21319
21471
|
try {
|
|
21320
21472
|
const day = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
21321
21473
|
if (!this.file?.endsWith(`rewake-${day}.jsonl`)) {
|
|
21322
|
-
const dir = ensurePrivateDir(
|
|
21323
|
-
this.file =
|
|
21474
|
+
const dir = ensurePrivateDir(join51(stateDir(this.env), "logs"));
|
|
21475
|
+
this.file = join51(dir, `rewake-${day}.jsonl`);
|
|
21324
21476
|
}
|
|
21325
21477
|
const record = { t: (/* @__PURE__ */ new Date()).toISOString(), level, event, pid: process.pid, ...fields2 };
|
|
21326
21478
|
appendFileSync(this.file, `${JSON.stringify(record)}
|
|
@@ -21343,9 +21495,9 @@ __export(cli_exports, {
|
|
|
21343
21495
|
testTiming: () => testTiming
|
|
21344
21496
|
});
|
|
21345
21497
|
import { spawnSync as spawnSync13 } from "node:child_process";
|
|
21346
|
-
import { existsSync as existsSync31, readdirSync as readdirSync21, readFileSync as
|
|
21498
|
+
import { existsSync as existsSync31, readdirSync as readdirSync21, readFileSync as readFileSync39 } from "node:fs";
|
|
21347
21499
|
import { homedir as homedir23 } from "node:os";
|
|
21348
|
-
import { join as
|
|
21500
|
+
import { join as join52 } from "node:path";
|
|
21349
21501
|
import { emitKeypressEvents } from "node:readline";
|
|
21350
21502
|
import { createInterface as createInterface6 } from "node:readline/promises";
|
|
21351
21503
|
function agentIdentity(target, env) {
|
|
@@ -21754,7 +21906,7 @@ ${loginItemPlanText(process.platform)}`);
|
|
|
21754
21906
|
const sep2 = argv.indexOf("--");
|
|
21755
21907
|
if (wrap) {
|
|
21756
21908
|
try {
|
|
21757
|
-
const npmLog =
|
|
21909
|
+
const npmLog = join52(ensurePrivateDir(join52(stateDir(env), "logs")), "npm-install.log");
|
|
21758
21910
|
agent = await wrappedAgentCommand(wrap.target, wrap.extra, env, stateDir(env), npmLog);
|
|
21759
21911
|
} catch (err) {
|
|
21760
21912
|
log.error("agent.resolve_failed", {
|
|
@@ -21960,7 +22112,7 @@ ${usageText()}
|
|
|
21960
22112
|
return void 0;
|
|
21961
22113
|
}
|
|
21962
22114
|
function toolsRefused(state) {
|
|
21963
|
-
const dir =
|
|
22115
|
+
const dir = join52(state, "logs");
|
|
21964
22116
|
const agents = /* @__PURE__ */ new Set();
|
|
21965
22117
|
let files = [];
|
|
21966
22118
|
try {
|
|
@@ -21969,7 +22121,7 @@ function toolsRefused(state) {
|
|
|
21969
22121
|
return [];
|
|
21970
22122
|
}
|
|
21971
22123
|
for (const f of files) {
|
|
21972
|
-
for (const line2 of
|
|
22124
|
+
for (const line2 of readFileSync39(join52(dir, f), "utf8").split("\n")) {
|
|
21973
22125
|
if (!line2.includes("agent_tools.refused")) continue;
|
|
21974
22126
|
try {
|
|
21975
22127
|
const r = JSON.parse(line2);
|
|
@@ -21996,7 +22148,7 @@ function setupZedText(env) {
|
|
|
21996
22148
|
const task = [taskEntry(launch)];
|
|
21997
22149
|
const keymap = [{ bindings: { [keyChord()]: ["task::Spawn", { task_name: TASK_LABEL }] } }];
|
|
21998
22150
|
const dir = zedConfigDir();
|
|
21999
|
-
const file = (name) =>
|
|
22151
|
+
const file = (name) => join52(dir, name);
|
|
22000
22152
|
return [
|
|
22001
22153
|
`Easiest: run \`${rewake("install")}\`, which adds these for you after asking.`,
|
|
22002
22154
|
"To add them by hand instead:",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codizelabs/agent-rewake",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.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",
|