@codizelabs/agent-rewake 0.4.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/dist/agent-rewake.js
CHANGED
|
@@ -2366,6 +2366,68 @@ var init_options_bridge = __esm({
|
|
|
2366
2366
|
}
|
|
2367
2367
|
});
|
|
2368
2368
|
|
|
2369
|
+
// src/util/workspace.ts
|
|
2370
|
+
import { execFileSync } from "node:child_process";
|
|
2371
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
2372
|
+
function gitEnv() {
|
|
2373
|
+
const { GIT_DIR: _d, GIT_WORK_TREE: _w, GIT_INDEX_FILE: _i, ...rest } = process.env;
|
|
2374
|
+
return rest;
|
|
2375
|
+
}
|
|
2376
|
+
function git(cwd, args, deadline) {
|
|
2377
|
+
const left = deadline - Date.now();
|
|
2378
|
+
if (left <= 0) return void 0;
|
|
2379
|
+
try {
|
|
2380
|
+
return execFileSync(
|
|
2381
|
+
"git",
|
|
2382
|
+
["--no-optional-locks", "-c", "core.fsmonitor=false", "-C", cwd, ...args],
|
|
2383
|
+
{
|
|
2384
|
+
encoding: "utf8",
|
|
2385
|
+
timeout: left,
|
|
2386
|
+
maxBuffer: MAX_OUTPUT_BYTES,
|
|
2387
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
2388
|
+
windowsHide: true,
|
|
2389
|
+
env: gitEnv()
|
|
2390
|
+
}
|
|
2391
|
+
);
|
|
2392
|
+
} catch {
|
|
2393
|
+
return void 0;
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2396
|
+
function fingerprintWorkspace(cwd, budgetMs = FIRE_BUDGET_MS) {
|
|
2397
|
+
if (!cwd) return void 0;
|
|
2398
|
+
const deadline = Date.now() + budgetMs;
|
|
2399
|
+
const commit = git(cwd, ["rev-parse", "HEAD"], deadline)?.trim();
|
|
2400
|
+
if (!commit || !/^[0-9a-f]{40,64}$/.test(commit)) return void 0;
|
|
2401
|
+
const status = git(cwd, ["status", "--porcelain", "--untracked-files=no"], deadline);
|
|
2402
|
+
if (status === void 0) return void 0;
|
|
2403
|
+
const lines = status.split("\n").filter(Boolean).sort();
|
|
2404
|
+
return {
|
|
2405
|
+
commit,
|
|
2406
|
+
hash: createHash2("sha256").update(lines.join("\n")).digest("hex"),
|
|
2407
|
+
dirty: lines.length > 0
|
|
2408
|
+
};
|
|
2409
|
+
}
|
|
2410
|
+
function workspaceChange(before, after) {
|
|
2411
|
+
const commit = before.commit !== after.commit;
|
|
2412
|
+
const changes = before.hash !== after.hash;
|
|
2413
|
+
return commit || changes ? { commit, changes } : void 0;
|
|
2414
|
+
}
|
|
2415
|
+
function validFingerprint(w) {
|
|
2416
|
+
if (typeof w !== "object" || w === null) return false;
|
|
2417
|
+
const x = w;
|
|
2418
|
+
return typeof x.commit === "string" && x.commit.length <= 64 && typeof x.hash === "string" && x.hash.length <= 64 && typeof x.dirty === "boolean";
|
|
2419
|
+
}
|
|
2420
|
+
var ARM_BUDGET_MS, FIRE_BUDGET_MS, MAX_OUTPUT_BYTES, WORKSPACE_NOTE;
|
|
2421
|
+
var init_workspace = __esm({
|
|
2422
|
+
"src/util/workspace.ts"() {
|
|
2423
|
+
"use strict";
|
|
2424
|
+
ARM_BUDGET_MS = 1e3;
|
|
2425
|
+
FIRE_BUDGET_MS = 2e3;
|
|
2426
|
+
MAX_OUTPUT_BYTES = 16 * 1024 * 1024;
|
|
2427
|
+
WORKSPACE_NOTE = "Note from Rewake: the project changed while this session waited for the usage limit to reset. Re-read any files before editing them.";
|
|
2428
|
+
}
|
|
2429
|
+
});
|
|
2430
|
+
|
|
2369
2431
|
// src/core/store.ts
|
|
2370
2432
|
import { randomUUID } from "node:crypto";
|
|
2371
2433
|
import {
|
|
@@ -2399,7 +2461,7 @@ function validFollowUps(t) {
|
|
|
2399
2461
|
function validateSchedule(value) {
|
|
2400
2462
|
if (value === null || typeof value !== "object") return void 0;
|
|
2401
2463
|
const s = value;
|
|
2402
|
-
const ok = s.schemaVersion === 1 && typeof s.scheduleId === "string" && /^[0-9a-f-]{36}$/.test(s.scheduleId) && typeof s.sessionId === "string" && s.sessionId.length > 0 && typeof s.cwd === "string" && (s.kind === "user" || s.kind === "limit_resume" || s.kind === "auto_limit_resume") && typeof s.text === "string" && s.text.trim().length > 0 && Buffer.byteLength(s.text) <= MAX_TEXT_BYTES && typeof s.dueAt === "number" && Number.isFinite(s.dueAt) && typeof s.status === "string" && STATUSES.has(s.status) && Array.isArray(s.attempts) && typeof s.createdAt === "number" && typeof s.updatedAt === "number" && (s.repeat === void 0 || validRepeat(s.repeat)) && (s.followUps === void 0 || validFollowUps(s.followUps)) && (s.host === void 0 || typeof s.host === "string" && KNOWN_HOSTS.has(s.host)) && (s.sessionRef === void 0 || validSessionRef(s.sessionRef)) && (s.rearms === void 0 || typeof s.rearms === "number" && Number.isInteger(s.rearms) && s.rearms >= 0) && (s.earlyRearms === void 0 || typeof s.earlyRearms === "number" && Number.isInteger(s.earlyRearms) && s.earlyRearms >= 0);
|
|
2464
|
+
const ok = s.schemaVersion === 1 && typeof s.scheduleId === "string" && /^[0-9a-f-]{36}$/.test(s.scheduleId) && typeof s.sessionId === "string" && s.sessionId.length > 0 && typeof s.cwd === "string" && (s.kind === "user" || s.kind === "limit_resume" || s.kind === "auto_limit_resume") && typeof s.text === "string" && s.text.trim().length > 0 && Buffer.byteLength(s.text) <= MAX_TEXT_BYTES && typeof s.dueAt === "number" && Number.isFinite(s.dueAt) && typeof s.status === "string" && STATUSES.has(s.status) && Array.isArray(s.attempts) && typeof s.createdAt === "number" && typeof s.updatedAt === "number" && (s.repeat === void 0 || validRepeat(s.repeat)) && (s.followUps === void 0 || validFollowUps(s.followUps)) && (s.host === void 0 || typeof s.host === "string" && KNOWN_HOSTS.has(s.host)) && (s.sessionRef === void 0 || validSessionRef(s.sessionRef)) && (s.rearms === void 0 || typeof s.rearms === "number" && Number.isInteger(s.rearms) && s.rearms >= 0) && (s.earlyRearms === void 0 || typeof s.earlyRearms === "number" && Number.isInteger(s.earlyRearms) && s.earlyRearms >= 0) && (s.workspace === void 0 || validFingerprint(s.workspace));
|
|
2403
2465
|
return ok ? value : void 0;
|
|
2404
2466
|
}
|
|
2405
2467
|
function writeFileAtomic(dir, name, data) {
|
|
@@ -2420,6 +2482,7 @@ var init_store = __esm({
|
|
|
2420
2482
|
"use strict";
|
|
2421
2483
|
init_fs();
|
|
2422
2484
|
init_paths();
|
|
2485
|
+
init_workspace();
|
|
2423
2486
|
init_cron();
|
|
2424
2487
|
init_lock();
|
|
2425
2488
|
PAUSE = new Int32Array(new SharedArrayBuffer(4));
|
|
@@ -2719,6 +2782,8 @@ function loadSettings(stateDir2) {
|
|
|
2719
2782
|
const autoWhenPromptsSkipped = raw.autoWhenPromptsSkipped !== false;
|
|
2720
2783
|
const keepAwake = KEEP_AWAKE_VALUES.find((v) => v === raw.keepAwake) ?? DEFAULT_SETTINGS.keepAwake;
|
|
2721
2784
|
const errorReports = raw.errorReports === "on" ? "on" : DEFAULT_SETTINGS.errorReports;
|
|
2785
|
+
const workspaceChanged = WORKSPACE_CHANGED_VALUES.find((v) => v === raw.workspaceChanged) ?? DEFAULT_SETTINGS.workspaceChanged;
|
|
2786
|
+
const usageWarnings = raw.usageWarnings === "off" ? "off" : DEFAULT_SETTINGS.usageWarnings;
|
|
2722
2787
|
const errorReportsAsked = raw.errorReportsAsked === true;
|
|
2723
2788
|
return {
|
|
2724
2789
|
clock: clock2,
|
|
@@ -2726,6 +2791,8 @@ function loadSettings(stateDir2) {
|
|
|
2726
2791
|
autoWhenPromptsSkipped,
|
|
2727
2792
|
keepAwake,
|
|
2728
2793
|
errorReports,
|
|
2794
|
+
workspaceChanged,
|
|
2795
|
+
usageWarnings,
|
|
2729
2796
|
...resumePrompt && { resumePrompt },
|
|
2730
2797
|
...errorReportsAsked && { errorReportsAsked }
|
|
2731
2798
|
};
|
|
@@ -2746,7 +2813,7 @@ function applySettings(stateDir2) {
|
|
|
2746
2813
|
setClock(s.clock);
|
|
2747
2814
|
return s;
|
|
2748
2815
|
}
|
|
2749
|
-
var CLOCKS, NEW_THREADS_VALUES, KEEP_AWAKE_VALUES, MAX_RESUME_PROMPT, KEEP_AWAKE_SAVED, DEFAULT_SETTINGS;
|
|
2816
|
+
var CLOCKS, NEW_THREADS_VALUES, KEEP_AWAKE_VALUES, WORKSPACE_CHANGED_VALUES, USAGE_WARNINGS_VALUES, MAX_RESUME_PROMPT, KEEP_AWAKE_SAVED, DEFAULT_SETTINGS;
|
|
2750
2817
|
var init_settings = __esm({
|
|
2751
2818
|
"src/core/settings.ts"() {
|
|
2752
2819
|
"use strict";
|
|
@@ -2756,6 +2823,13 @@ var init_settings = __esm({
|
|
|
2756
2823
|
CLOCKS = ["12h", "24h"];
|
|
2757
2824
|
NEW_THREADS_VALUES = ["ask", "on", "off"];
|
|
2758
2825
|
KEEP_AWAKE_VALUES = ["plugged-in", "always", "never"];
|
|
2826
|
+
WORKSPACE_CHANGED_VALUES = [
|
|
2827
|
+
"tell",
|
|
2828
|
+
"note",
|
|
2829
|
+
"hold",
|
|
2830
|
+
"off"
|
|
2831
|
+
];
|
|
2832
|
+
USAGE_WARNINGS_VALUES = ["on", "off"];
|
|
2759
2833
|
MAX_RESUME_PROMPT = 16384;
|
|
2760
2834
|
KEEP_AWAKE_SAVED = {
|
|
2761
2835
|
"plugged-in": "Rewake keeps this computer awake for resumes and scheduled messages while it's plugged in.",
|
|
@@ -2767,13 +2841,15 @@ var init_settings = __esm({
|
|
|
2767
2841
|
newThreads: "ask",
|
|
2768
2842
|
autoWhenPromptsSkipped: true,
|
|
2769
2843
|
keepAwake: "plugged-in",
|
|
2770
|
-
errorReports: "off"
|
|
2844
|
+
errorReports: "off",
|
|
2845
|
+
workspaceChanged: "tell",
|
|
2846
|
+
usageWarnings: "on"
|
|
2771
2847
|
};
|
|
2772
2848
|
}
|
|
2773
2849
|
});
|
|
2774
2850
|
|
|
2775
2851
|
// src/core/threads.ts
|
|
2776
|
-
import { createHash as
|
|
2852
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
2777
2853
|
import { readdirSync as readdirSync4, readFileSync as readFileSync7, rmSync as rmSync5 } from "node:fs";
|
|
2778
2854
|
import { join as join8 } from "node:path";
|
|
2779
2855
|
var DEFAULT_RESUME_PROMPT, ThreadStore;
|
|
@@ -2789,7 +2865,7 @@ var init_threads = __esm({
|
|
|
2789
2865
|
this.dir = join8(stateDir2, "threads");
|
|
2790
2866
|
}
|
|
2791
2867
|
file(sessionId) {
|
|
2792
|
-
return `${
|
|
2868
|
+
return `${createHash3("sha256").update(sessionId).digest("hex").slice(0, 32)}.json`;
|
|
2793
2869
|
}
|
|
2794
2870
|
get(sessionId) {
|
|
2795
2871
|
try {
|
|
@@ -4479,20 +4555,20 @@ function killTree(child, p = osPlatform2(), signal = "SIGTERM", run3 = taskkill)
|
|
|
4479
4555
|
}
|
|
4480
4556
|
child.kill(signal);
|
|
4481
4557
|
}
|
|
4482
|
-
function killPidTree(pid, p = osPlatform2(), run3 = taskkill) {
|
|
4558
|
+
function killPidTree(pid, p = osPlatform2(), run3 = taskkill, signal = "SIGTERM") {
|
|
4483
4559
|
killTree(
|
|
4484
4560
|
{
|
|
4485
4561
|
pid,
|
|
4486
|
-
kill: (
|
|
4562
|
+
kill: (signal2) => {
|
|
4487
4563
|
try {
|
|
4488
|
-
return process.kill(pid,
|
|
4564
|
+
return process.kill(pid, signal2);
|
|
4489
4565
|
} catch {
|
|
4490
4566
|
return false;
|
|
4491
4567
|
}
|
|
4492
4568
|
}
|
|
4493
4569
|
},
|
|
4494
4570
|
p,
|
|
4495
|
-
|
|
4571
|
+
signal,
|
|
4496
4572
|
run3
|
|
4497
4573
|
);
|
|
4498
4574
|
}
|
|
@@ -4892,7 +4968,7 @@ var init_version = __esm({
|
|
|
4892
4968
|
return {};
|
|
4893
4969
|
}
|
|
4894
4970
|
})();
|
|
4895
|
-
VERSION2 = pkg.version ?? (true ? "0.
|
|
4971
|
+
VERSION2 = pkg.version ?? (true ? "0.6.0" : "0.0.0");
|
|
4896
4972
|
PACKAGE_NAME = pkg.name ?? "@codizelabs/agent-rewake";
|
|
4897
4973
|
FROM_SOURCE = false;
|
|
4898
4974
|
}
|
|
@@ -5498,6 +5574,11 @@ function armedText(host, cwd, at, now) {
|
|
|
5498
5574
|
const typing = host.keepOpen ? `Typing in the ${host.noun ?? "session"} before then cancels this continue.` : `Reopening that ${host.noun ?? "session"} and typing in it before then cancels this resume.`;
|
|
5499
5575
|
return `Rewake will continue ${placeOf(host, cwd)} ${formatAt(at, now)}. Keep this computer on and awake until then.${keep} ${typing} To cancel all planned resumes: ${rewake("continue --cancel")}`;
|
|
5500
5576
|
}
|
|
5577
|
+
function withWorkspace(store, s, now) {
|
|
5578
|
+
const workspace = fingerprintWorkspace(s.cwd, ARM_BUDGET_MS);
|
|
5579
|
+
if (!workspace) return s;
|
|
5580
|
+
return store.update(s.scheduleId, (x) => ({ ...x, workspace }), now) ?? s;
|
|
5581
|
+
}
|
|
5501
5582
|
function armClosed(host, r, at, d) {
|
|
5502
5583
|
const store = new ScheduleStore(d.stateDir);
|
|
5503
5584
|
const settings = loadSettings(d.stateDir);
|
|
@@ -5517,7 +5598,7 @@ function armClosed(host, r, at, d) {
|
|
|
5517
5598
|
};
|
|
5518
5599
|
store.put(resume);
|
|
5519
5600
|
d.arm(resume.scheduleId, at + (host.fallbackDelayMs ?? 0));
|
|
5520
|
-
return resume;
|
|
5601
|
+
return withWorkspace(store, resume, d.now);
|
|
5521
5602
|
}
|
|
5522
5603
|
function onSessionStart(host, sessionId, cwd, d, program) {
|
|
5523
5604
|
if (d.env[FIRE_ENV]) return;
|
|
@@ -5692,6 +5773,7 @@ var init_closed = __esm({
|
|
|
5692
5773
|
init_command2();
|
|
5693
5774
|
init_proc();
|
|
5694
5775
|
init_secrets();
|
|
5776
|
+
init_workspace();
|
|
5695
5777
|
init_sessions();
|
|
5696
5778
|
FIRE_ENV = "AGENT_REWAKE_FIRE";
|
|
5697
5779
|
COMMON_VARS = ["XDG_CONFIG_HOME", "XDG_DATA_HOME", "XDG_STATE_HOME", "XDG_CACHE_HOME"];
|
|
@@ -6848,6 +6930,31 @@ function chooseSnapshot(snapshots, last, nowSec) {
|
|
|
6848
6930
|
const fullest = (s) => Math.max(...[s.primary, s.secondary].map((w) => w ? w.used_percent ?? 0 : 0));
|
|
6849
6931
|
return withWindows.reduce((a, b) => fullest(b) > fullest(a) ? b : a);
|
|
6850
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
|
+
}
|
|
6851
6958
|
function spentWindowReset(rl, nowSec) {
|
|
6852
6959
|
if (!rl || !/^workspace_/.test(rl.rate_limit_reached_type ?? "") || rl.spend_control_reached)
|
|
6853
6960
|
return {};
|
|
@@ -8205,7 +8312,7 @@ var init_install6 = __esm({
|
|
|
8205
8312
|
|
|
8206
8313
|
// src/wrap.ts
|
|
8207
8314
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
8208
|
-
import { createHash as
|
|
8315
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
8209
8316
|
import {
|
|
8210
8317
|
chmodSync as chmodSync2,
|
|
8211
8318
|
existsSync as existsSync14,
|
|
@@ -8359,7 +8466,7 @@ function ensureNpxAgent(id, npx, stateDir2, env, logFile) {
|
|
|
8359
8466
|
);
|
|
8360
8467
|
}
|
|
8361
8468
|
function zedBinaryDir(id, version, target, env) {
|
|
8362
|
-
const sha = (s) =>
|
|
8469
|
+
const sha = (s) => createHash4("sha256").update(s).digest("hex").slice(0, 16);
|
|
8363
8470
|
const archiveKey = target.sha256 ? `${target.archive}\0sha256:${target.sha256.toLowerCase()}` : target.archive;
|
|
8364
8471
|
return join24(
|
|
8365
8472
|
zedDataDir(env),
|
|
@@ -8430,7 +8537,7 @@ async function downloadBinaryAgent(id, version, target, stateDir2, fetchImpl = f
|
|
|
8430
8537
|
if (!res.ok) throw new Error(`download failed (HTTP ${res.status})`);
|
|
8431
8538
|
const bytes = Buffer.from(await res.arrayBuffer());
|
|
8432
8539
|
if (target.sha256) {
|
|
8433
|
-
const got =
|
|
8540
|
+
const got = createHash4("sha256").update(bytes).digest("hex");
|
|
8434
8541
|
if (got !== target.sha256.toLowerCase())
|
|
8435
8542
|
throw new Error("the download doesn't match the registry's checksum");
|
|
8436
8543
|
}
|
|
@@ -9803,6 +9910,9 @@ function quitZed(p = platform3()) {
|
|
|
9803
9910
|
if (p === "win32") return "close every Zed window so Zed exits";
|
|
9804
9911
|
return "quit Zed completely (Ctrl+Q)";
|
|
9805
9912
|
}
|
|
9913
|
+
function reloadAgent(p = platform3()) {
|
|
9914
|
+
return `choose "Reload Agent" in the Agent Panel's menu in each open thread (Zed 1.18 or newer), or ${quitZed(p)} and open it again`;
|
|
9915
|
+
}
|
|
9806
9916
|
function nextSteps(reachShown = false) {
|
|
9807
9917
|
return [
|
|
9808
9918
|
"",
|
|
@@ -10011,7 +10121,8 @@ function explainResume(r, now, locale) {
|
|
|
10011
10121
|
lines.push(
|
|
10012
10122
|
` When: ${when2}`,
|
|
10013
10123
|
` What Rewake will do: send your message "${oneLine(r.text)}" into the ${r.noun} once.`,
|
|
10014
|
-
` Nothing is sent now: this view only reads. ${r.cancel}
|
|
10124
|
+
` Nothing is sent now: this view only reads. ${r.cancel}`,
|
|
10125
|
+
...r.now ? [` ${r.now}`] : []
|
|
10015
10126
|
);
|
|
10016
10127
|
return lines;
|
|
10017
10128
|
}
|
|
@@ -10029,6 +10140,10 @@ function explainResume(r, now, locale) {
|
|
|
10029
10140
|
lines.push(
|
|
10030
10141
|
" Its time has already passed by too long, so Rewake won't send it by itself. It will tell you."
|
|
10031
10142
|
);
|
|
10143
|
+
if (r.workspaceChanged === "tell" || r.workspaceChanged === "note")
|
|
10144
|
+
lines.push(
|
|
10145
|
+
` Before sending, Rewake checks whether the project's latest git commit or tracked files differ from when this was planned (only the commit id and a summary of file names and status, never contents). If they do, ${r.workspaceChanged === "note" ? "it adds a line to the message asking the agent to re-read files before editing, and tells you" : "it tells you and sends the message as it is"}.`
|
|
10146
|
+
);
|
|
10032
10147
|
lines.push(" What could stop it:");
|
|
10033
10148
|
lines.push(
|
|
10034
10149
|
` - You type in the ${r.noun} before then: Rewake sends nothing.`,
|
|
@@ -10038,12 +10153,17 @@ function explainResume(r, now, locale) {
|
|
|
10038
10153
|
lines.push(
|
|
10039
10154
|
` - The ${r.noun} is open in a window or terminal then: Rewake sends nothing and tells you.`
|
|
10040
10155
|
);
|
|
10156
|
+
if (r.workspaceChanged === "hold")
|
|
10157
|
+
lines.push(
|
|
10158
|
+
" - The project's latest git commit or tracked files differ from when this was planned (Rewake reads only the commit id and a summary of file names and status, never contents): Rewake sends nothing and tells you."
|
|
10159
|
+
);
|
|
10041
10160
|
lines.push(
|
|
10042
10161
|
" - The agent is still at its usage limit: Rewake waits for the new reset and tries again, or tells you if it can't.",
|
|
10043
10162
|
" - The computer is off or asleep then: Rewake sends nothing if it runs much later, and tells you.",
|
|
10044
10163
|
" - A credit or billing limit: Rewake never resumes it, because waiting doesn't fix it.",
|
|
10045
10164
|
` Nothing is sent now: this view only reads. ${r.cancel}`
|
|
10046
10165
|
);
|
|
10166
|
+
if (r.now) lines.push(` ${r.now}`);
|
|
10047
10167
|
return lines;
|
|
10048
10168
|
}
|
|
10049
10169
|
var PENDING, oneLine;
|
|
@@ -10268,6 +10388,7 @@ function explainSchedule(stateDir2, idPrefix, now, hostOf, locale) {
|
|
|
10268
10388
|
const folder = s.cwd ? basename7(s.cwd) : "";
|
|
10269
10389
|
const title = new ThreadStore(stateDir2).get(s.sessionId)?.title;
|
|
10270
10390
|
const where2 = host ? folder ? `${host.name} in the "${folder}" folder` : host.name : title ? `The Zed thread "${title}"` : `The Zed thread ${s.sessionId.slice(0, 8)}`;
|
|
10391
|
+
const workspaceSetting = loadSettings(stateDir2).workspaceChanged;
|
|
10271
10392
|
const lines = explainResume(
|
|
10272
10393
|
{
|
|
10273
10394
|
dueAt: s.dueAt,
|
|
@@ -10279,7 +10400,11 @@ function explainSchedule(stateDir2, idPrefix, now, hostOf, locale) {
|
|
|
10279
10400
|
noun: host?.noun ?? "thread",
|
|
10280
10401
|
outsideZed: host !== void 0,
|
|
10281
10402
|
...host === void 0 && { lateMs: ZED_LATE_MS },
|
|
10282
|
-
|
|
10403
|
+
...host !== void 0 && s.workspace && workspaceSetting !== "off" && { workspaceChanged: workspaceSetting },
|
|
10404
|
+
cancel: host ? `To cancel it: ${rewake(`continue --cancel ${s.scheduleId.slice(0, 8)}`)}` : `To cancel it, use the schedules page: ${rewake("ui")}`,
|
|
10405
|
+
...host && {
|
|
10406
|
+
now: `To continue it now instead of waiting for the reset: ${rewake(`continue --now ${s.scheduleId.slice(0, 8)}`)}`
|
|
10407
|
+
}
|
|
10283
10408
|
},
|
|
10284
10409
|
now,
|
|
10285
10410
|
locale
|
|
@@ -10321,6 +10446,7 @@ var init_overview = __esm({
|
|
|
10321
10446
|
"src/ui/overview.ts"() {
|
|
10322
10447
|
"use strict";
|
|
10323
10448
|
init_explain();
|
|
10449
|
+
init_settings();
|
|
10324
10450
|
init_store();
|
|
10325
10451
|
init_threads();
|
|
10326
10452
|
init_time();
|
|
@@ -13681,6 +13807,7 @@ ${pending.map((s, i) => ` ${i + 1}. ${about(o, s)} [${s.scheduleId.slice(0, 8)
|
|
|
13681
13807
|
for (const s of chosen3) await cancel(o, store, s);
|
|
13682
13808
|
return 0;
|
|
13683
13809
|
}
|
|
13810
|
+
if (o.mode === "now") return runNow(o);
|
|
13684
13811
|
const list2 = waiting(o);
|
|
13685
13812
|
if (list2.length === 0) {
|
|
13686
13813
|
o.out("Nothing to continue: no closed session is stopped at a usage limit.\n");
|
|
@@ -13835,7 +13962,7 @@ function about(o, s) {
|
|
|
13835
13962
|
const host = hostFor(o, s.host);
|
|
13836
13963
|
return `${host ? `${placeOf(host, s.cwd)} ` : s.host === void 0 ? "Zed thread " : ""}${formatAt(s.dueAt, o.deps.now)}`;
|
|
13837
13964
|
}
|
|
13838
|
-
|
|
13965
|
+
function findOne(o, store, id) {
|
|
13839
13966
|
const wanted = id.trim().toLowerCase();
|
|
13840
13967
|
const found = wanted ? store.list().filter((s2) => s2.scheduleId.toLowerCase().startsWith(wanted)) : [];
|
|
13841
13968
|
const fail2 = (text2) => {
|
|
@@ -13857,6 +13984,11 @@ ${found.map((s2) => ` ${s2.scheduleId.slice(0, 8)} ${about(o, s2)}`).join("\n"
|
|
|
13857
13984
|
return fail2(
|
|
13858
13985
|
`That's a message in a Zed thread: change or delete it on the schedules page (${rewake("ui")}), or in the thread's Rewake menu.`
|
|
13859
13986
|
);
|
|
13987
|
+
return s;
|
|
13988
|
+
}
|
|
13989
|
+
async function cancelOne(o, store, id) {
|
|
13990
|
+
const s = findOne(o, store, id);
|
|
13991
|
+
if (typeof s === "number") return s;
|
|
13860
13992
|
if (TERMINAL_STATUSES.has(s.status)) {
|
|
13861
13993
|
const host = hostFor(o, s.host);
|
|
13862
13994
|
o.out(
|
|
@@ -13867,6 +13999,150 @@ ${found.map((s2) => ` ${s2.scheduleId.slice(0, 8)} ${about(o, s2)}`).join("\n"
|
|
|
13867
13999
|
}
|
|
13868
14000
|
return await cancel(o, store, s) ? 0 : 1;
|
|
13869
14001
|
}
|
|
14002
|
+
async function runNow(o) {
|
|
14003
|
+
const now = o.deps.now;
|
|
14004
|
+
const store = new ScheduleStore(o.deps.stateDir);
|
|
14005
|
+
if (!o.interactive && (o.nowId === void 0 || o.yes !== true)) {
|
|
14006
|
+
(o.err ?? o.out)(
|
|
14007
|
+
`agent-rewake: There is no terminal to ask in, so nothing was sent. Give the id and --yes: ${rewake("continue --now <id> --yes")}. The ids are in ${rewake("schedules")}, in square brackets.
|
|
14008
|
+
`
|
|
14009
|
+
);
|
|
14010
|
+
return 1;
|
|
14011
|
+
}
|
|
14012
|
+
let s;
|
|
14013
|
+
if (o.nowId !== void 0) {
|
|
14014
|
+
const found = findOne(o, store, o.nowId);
|
|
14015
|
+
if (typeof found === "number") return found;
|
|
14016
|
+
s = found;
|
|
14017
|
+
} else {
|
|
14018
|
+
const windowOf = (x) => o.hosts.find((h) => h.id === x.host && h.maxWaitAfterLimitMs !== void 0);
|
|
14019
|
+
const waitingHere = store.list().filter((x) => x.host !== void 0 && x.host !== "acp" && WAITING.has(x.status));
|
|
14020
|
+
const pending = waitingHere.filter((x) => !windowOf(x));
|
|
14021
|
+
if (pending.length === 0) {
|
|
14022
|
+
const blocked = waitingHere.map(windowOf).find((h) => h !== void 0);
|
|
14023
|
+
o.out(
|
|
14024
|
+
blocked ? `Nothing here can be continued now: ${windowReason(blocked)}.
|
|
14025
|
+
` : "Nothing to resume now: Rewake isn't set to continue any session.\n"
|
|
14026
|
+
);
|
|
14027
|
+
return 0;
|
|
14028
|
+
}
|
|
14029
|
+
s = pending[0];
|
|
14030
|
+
if (pending.length > 1) {
|
|
14031
|
+
const placeIn = (x) => {
|
|
14032
|
+
const h = hostFor(o, x.host);
|
|
14033
|
+
return h ? placeOf(h, x.cwd) : "";
|
|
14034
|
+
};
|
|
14035
|
+
const twin = (x) => pending.filter((y) => placeIn(y) === placeIn(x)).length > 1;
|
|
14036
|
+
o.out(
|
|
14037
|
+
`Planned resumes:
|
|
14038
|
+
${pending.map((x, i) => ` ${i + 1}. ${about(o, x)}${twin(x) ? ` (${printable(x.cwd)})` : ""} [${x.scheduleId.slice(0, 8)}]`).join("\n")}
|
|
14039
|
+
`
|
|
14040
|
+
);
|
|
14041
|
+
const answer = await o.ask(
|
|
14042
|
+
`Which one should Rewake continue now? (1-${pending.length}, or Enter to keep waiting) `
|
|
14043
|
+
);
|
|
14044
|
+
const one = pending[Number(answer.trim()) - 1];
|
|
14045
|
+
if (!one) {
|
|
14046
|
+
o.out("Nothing was changed.\n");
|
|
14047
|
+
return 1;
|
|
14048
|
+
}
|
|
14049
|
+
s = one;
|
|
14050
|
+
}
|
|
14051
|
+
}
|
|
14052
|
+
const host = hostFor(o, s.host);
|
|
14053
|
+
const noun = host?.noun ?? "session";
|
|
14054
|
+
const place = host ? placeOf(host, s.cwd) : "that session";
|
|
14055
|
+
const reopen = host?.reopen ?? `open the ${noun}`;
|
|
14056
|
+
if (TERMINAL_STATUSES.has(s.status)) {
|
|
14057
|
+
o.out(
|
|
14058
|
+
`Nothing to continue: the resume of ${place} ${s.status === "sent" ? "was already sent" : s.status === "cancelled" ? "was cancelled" : "has already ended"}.
|
|
14059
|
+
`
|
|
14060
|
+
);
|
|
14061
|
+
return 0;
|
|
14062
|
+
}
|
|
14063
|
+
if (s.status === "sending") {
|
|
14064
|
+
o.out(`Rewake is already continuing ${place}. It finishes on its own.
|
|
14065
|
+
`);
|
|
14066
|
+
return 1;
|
|
14067
|
+
}
|
|
14068
|
+
if (!WAITING.has(s.status)) {
|
|
14069
|
+
o.out(
|
|
14070
|
+
`The resume of ${place} isn't waiting for the reset any more (${s.status.replace("_", " ")}), so there is nothing to run now. ${capital2(reopen)} to continue it yourself.
|
|
14071
|
+
`
|
|
14072
|
+
);
|
|
14073
|
+
return 1;
|
|
14074
|
+
}
|
|
14075
|
+
const window = o.hosts.find((h) => h.id === s.host && h.maxWaitAfterLimitMs !== void 0);
|
|
14076
|
+
if (window) {
|
|
14077
|
+
o.out(
|
|
14078
|
+
`Rewake can't continue ${place} from here: ${windowReason(window)}. Type /rewake in the ${noun}, or ${reopen} to continue it yourself.
|
|
14079
|
+
`
|
|
14080
|
+
);
|
|
14081
|
+
return 1;
|
|
14082
|
+
}
|
|
14083
|
+
o.out(
|
|
14084
|
+
`Rewake will continue ${place} now, without waiting for the reset (planned ${formatAt(s.dueAt, now)}).
|
|
14085
|
+
Message, sent once as if you had typed it: "${oneLine2(s.text)}"
|
|
14086
|
+
Nothing is sent, and your resume stays planned for its time, if you typed in the ${noun} since the limit, if it is open or has changed, if the agent has already continued, if the usage limit is still on, or if the message can't reach the agent (signed out, session deleted or archived, folder gone).
|
|
14087
|
+
This window stays busy until the agent finishes (up to 3 hours); waiting for a free place to run can take a few minutes. Ctrl+C stops it and cancels this planned resume.
|
|
14088
|
+
`
|
|
14089
|
+
);
|
|
14090
|
+
if (o.yes !== true && !/^y(es)?$/i.test((await o.ask("Continue it now? [y/N] ")).trim())) {
|
|
14091
|
+
o.out("Nothing was changed.\n");
|
|
14092
|
+
return 1;
|
|
14093
|
+
}
|
|
14094
|
+
const outcome2 = await o.fireNow?.(s.scheduleId) ?? "not-ours";
|
|
14095
|
+
const after = store.get(s.scheduleId);
|
|
14096
|
+
switch (outcome2) {
|
|
14097
|
+
case "sent":
|
|
14098
|
+
o.out(`Rewake continued ${place}. ${capital2(reopen)} to see what it did.
|
|
14099
|
+
`);
|
|
14100
|
+
return 0;
|
|
14101
|
+
case "limited":
|
|
14102
|
+
o.out(
|
|
14103
|
+
`The usage limit is still on, so nothing was sent. Your resume is still planned for ${formatAt(s.dueAt, now)}.
|
|
14104
|
+
`
|
|
14105
|
+
);
|
|
14106
|
+
return 0;
|
|
14107
|
+
case "open":
|
|
14108
|
+
o.out(
|
|
14109
|
+
`The ${noun} is open, so nothing was sent. Close it and run this again, or it still resumes at ${formatAt(s.dueAt, now)}.
|
|
14110
|
+
`
|
|
14111
|
+
);
|
|
14112
|
+
return 1;
|
|
14113
|
+
case "changed":
|
|
14114
|
+
o.out(
|
|
14115
|
+
`The ${noun} has changed since it stopped, so nothing was sent. Your resume is still planned for ${formatAt(s.dueAt, now)}, and will send nothing then either. ${capital2(reopen)} to continue it yourself, or cancel the plan: ${rewake(`continue --cancel ${s.scheduleId.slice(0, 8)}`)}
|
|
14116
|
+
`
|
|
14117
|
+
);
|
|
14118
|
+
return 1;
|
|
14119
|
+
case "typed":
|
|
14120
|
+
case "native":
|
|
14121
|
+
o.out(
|
|
14122
|
+
`${outcome2 === "typed" ? `You typed in the ${noun} after the limit` : "The agent has already continued by itself"}, so nothing was sent. Your resume is still planned for ${formatAt(s.dueAt, now)}, and will send nothing then either. To remove it: ${rewake(`continue --cancel ${s.scheduleId.slice(0, 8)}`)}
|
|
14123
|
+
`
|
|
14124
|
+
);
|
|
14125
|
+
return 1;
|
|
14126
|
+
case "skipped":
|
|
14127
|
+
if (after?.failureReason !== "you") o.out("Rewake sent nothing.\n");
|
|
14128
|
+
return 1;
|
|
14129
|
+
case "busy":
|
|
14130
|
+
o.out(`Rewake is already working on ${place}. Try again in a minute.
|
|
14131
|
+
`);
|
|
14132
|
+
return 1;
|
|
14133
|
+
case "notified":
|
|
14134
|
+
case "failed":
|
|
14135
|
+
if (after && WAITING.has(after.status))
|
|
14136
|
+
o.out(`Your resume is still planned for ${formatAt(after.dueAt, now)}.
|
|
14137
|
+
`);
|
|
14138
|
+
return 1;
|
|
14139
|
+
default:
|
|
14140
|
+
o.out(`Nothing was sent: the resume of ${place} had changed or ended.
|
|
14141
|
+
`);
|
|
14142
|
+
return 1;
|
|
14143
|
+
}
|
|
14144
|
+
}
|
|
14145
|
+
var windowReason, WAITING, capital2;
|
|
13870
14146
|
var init_continue = __esm({
|
|
13871
14147
|
"src/continue.ts"() {
|
|
13872
14148
|
"use strict";
|
|
@@ -13876,9 +14152,13 @@ var init_continue = __esm({
|
|
|
13876
14152
|
init_time();
|
|
13877
14153
|
init_closed();
|
|
13878
14154
|
init_sessions();
|
|
14155
|
+
init_overview();
|
|
13879
14156
|
init_command2();
|
|
13880
14157
|
init_printable();
|
|
13881
14158
|
init_sleep_settings();
|
|
14159
|
+
windowReason = (h) => `${h.name} can only be continued from the window that is waiting for it, within 4 hours of its usage limit`;
|
|
14160
|
+
WAITING = /* @__PURE__ */ new Set(["scheduled", "waiting_for_limit"]);
|
|
14161
|
+
capital2 = (text2) => `${text2.charAt(0).toUpperCase()}${text2.slice(1)}`;
|
|
13882
14162
|
}
|
|
13883
14163
|
});
|
|
13884
14164
|
|
|
@@ -14364,7 +14644,7 @@ function diagnose(ctx) {
|
|
|
14364
14644
|
area: "Rewake",
|
|
14365
14645
|
level: "todo",
|
|
14366
14646
|
text: "Zed starts Rewake through npm or one Node.js folder. An upgrade of that Node.js, or no network, can stop those agents from starting.",
|
|
14367
|
-
fix: `Run the install command again
|
|
14647
|
+
fix: `Run the install command again: ${update} Then ${reloadAgent(platform6)}.`
|
|
14368
14648
|
});
|
|
14369
14649
|
const pins = /* @__PURE__ */ new Set();
|
|
14370
14650
|
for (const entry of wrappedEntries) {
|
|
@@ -14377,7 +14657,7 @@ function diagnose(ctx) {
|
|
|
14377
14657
|
area: "Rewake",
|
|
14378
14658
|
level: "todo",
|
|
14379
14659
|
text: `Zed starts Rewake ${pin}; this is Rewake ${ctx.version}.`,
|
|
14380
|
-
fix: `To update, run: ${update} Then
|
|
14660
|
+
fix: `To update, run: ${update} Then ${reloadAgent(platform6)}.`
|
|
14381
14661
|
});
|
|
14382
14662
|
else if (compareVersions(pin, ctx.version) > 0)
|
|
14383
14663
|
add({
|
|
@@ -14846,7 +15126,7 @@ var init_doctor = __esm({
|
|
|
14846
15126
|
});
|
|
14847
15127
|
|
|
14848
15128
|
// src/doctor-report.ts
|
|
14849
|
-
import { createHash as
|
|
15129
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
14850
15130
|
import { join as join37 } from "node:path";
|
|
14851
15131
|
function redactor(home, ids) {
|
|
14852
15132
|
const homes = [.../* @__PURE__ */ new Set([home, home.replace(/\\/g, "/")])].filter((h) => h.length > 1);
|
|
@@ -14949,7 +15229,7 @@ var init_doctor_report = __esm({
|
|
|
14949
15229
|
LEFT_OUT = /* @__PURE__ */ new Set(["pid", "text", "prompt", "body", "content", "title", "cwd", "folder"]);
|
|
14950
15230
|
FIRE_EVENTS = /^(fire\.|hook$|hook\.|limit\.|schedule\.settled|schedule\.delivering)/;
|
|
14951
15231
|
short2 = (s) => s.slice(0, 8);
|
|
14952
|
-
hash = (id) =>
|
|
15232
|
+
hash = (id) => createHash5("sha256").update(id).digest("hex");
|
|
14953
15233
|
iso = (t) => new Date(t).toISOString();
|
|
14954
15234
|
}
|
|
14955
15235
|
});
|
|
@@ -15411,7 +15691,9 @@ var init_settings_command = __esm({
|
|
|
15411
15691
|
"auto-when-prompts-skipped",
|
|
15412
15692
|
"clock",
|
|
15413
15693
|
"keep-awake",
|
|
15414
|
-
"resume-prompt"
|
|
15694
|
+
"resume-prompt",
|
|
15695
|
+
"workspace-changed",
|
|
15696
|
+
"usage-warnings"
|
|
15415
15697
|
];
|
|
15416
15698
|
SETTINGS = [
|
|
15417
15699
|
{
|
|
@@ -15478,6 +15760,40 @@ var init_settings_command = __esm({
|
|
|
15478
15760
|
return v && v !== DEFAULT_RESUME_PROMPT ? { ...rest, resumePrompt: v } : rest;
|
|
15479
15761
|
},
|
|
15480
15762
|
saved: (v) => v && v !== DEFAULT_RESUME_PROMPT ? "Resumes send your message from now on." : "Resumes send Rewake's own message again."
|
|
15763
|
+
},
|
|
15764
|
+
{
|
|
15765
|
+
name: "workspace-changed",
|
|
15766
|
+
title: "Project changed while waiting",
|
|
15767
|
+
short: "What Rewake does when the project changed while a resume waited, outside Zed.",
|
|
15768
|
+
more: "It compares the project's latest git commit and its tracked files (their names and status, never their contents, only on this computer).",
|
|
15769
|
+
choices: () => [
|
|
15770
|
+
["tell", "Only tell you, and send the message as it is"],
|
|
15771
|
+
["note", "Also add a line asking the agent to re-read files before editing"],
|
|
15772
|
+
["hold", "Send nothing and ask you first"],
|
|
15773
|
+
["off", "Don't check"]
|
|
15774
|
+
],
|
|
15775
|
+
get: (s) => s.workspaceChanged,
|
|
15776
|
+
set: (s, v) => ({
|
|
15777
|
+
...s,
|
|
15778
|
+
workspaceChanged: WORKSPACE_CHANGED_VALUES.find((x) => x === v) ?? s.workspaceChanged
|
|
15779
|
+
}),
|
|
15780
|
+
saved: (v) => v === "hold" ? "When the project changed while a resume waited, Rewake sends nothing and tells you." : v === "off" ? "Rewake won't check whether the project changed while a resume waited." : v === "note" ? "When the project changed while a resume waited, Rewake tells you and adds a line asking the agent to re-read files." : "When the project changed while a resume waited, Rewake tells you and sends the message as it is."
|
|
15781
|
+
},
|
|
15782
|
+
{
|
|
15783
|
+
name: "usage-warnings",
|
|
15784
|
+
title: "Warnings before a usage limit",
|
|
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.",
|
|
15787
|
+
choices: () => [
|
|
15788
|
+
["on", "Warn at 80% and 95% used, and when the pace would reach the limit within 45 minutes"],
|
|
15789
|
+
["off", "Don't warn"]
|
|
15790
|
+
],
|
|
15791
|
+
get: (s) => s.usageWarnings,
|
|
15792
|
+
set: (s, v) => ({
|
|
15793
|
+
...s,
|
|
15794
|
+
usageWarnings: USAGE_WARNINGS_VALUES.find((x) => x === v) ?? s.usageWarnings
|
|
15795
|
+
}),
|
|
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."
|
|
15481
15797
|
}
|
|
15482
15798
|
];
|
|
15483
15799
|
orList2 = (v) => v.length < 2 ? v[0] ?? "" : `${v.slice(0, -1).join(", ")} or ${v.at(-1)}`;
|
|
@@ -15781,10 +16097,12 @@ var init_help = __esm({
|
|
|
15781
16097
|
{
|
|
15782
16098
|
name: "continue",
|
|
15783
16099
|
summary: "Continue a closed agent session after its usage limit",
|
|
15784
|
-
usage: ["continue [--always | --ask | --cancel [<id>]]"],
|
|
16100
|
+
usage: ["continue [--always | --ask | --cancel [<id>] | --now [<id>] [--yes]]"],
|
|
15785
16101
|
about: [
|
|
15786
16102
|
"Continues a session you closed at its usage limit, when the limit resets. Run alone, it asks",
|
|
15787
|
-
"which session and when."
|
|
16103
|
+
"which session and when.",
|
|
16104
|
+
"--now is for a planned resume outside Zed that shouldn't wait for the reset (you upgraded",
|
|
16105
|
+
"your plan, or the limit lifted early). In Zed, use Rewake \u2192 Change a scheduled message\u2026."
|
|
15788
16106
|
],
|
|
15789
16107
|
options: [
|
|
15790
16108
|
{ flag: "--always", text: "Continue sessions by itself from now on" },
|
|
@@ -15792,11 +16110,27 @@ var init_help = __esm({
|
|
|
15792
16110
|
{
|
|
15793
16111
|
flag: "--cancel",
|
|
15794
16112
|
text: "Cancel a planned resume: pick it, or give its id"
|
|
16113
|
+
},
|
|
16114
|
+
{
|
|
16115
|
+
flag: "--now",
|
|
16116
|
+
arg: "[<id>]",
|
|
16117
|
+
text: "Continue a planned resume now, without waiting for the reset (outside Zed)"
|
|
16118
|
+
},
|
|
16119
|
+
{
|
|
16120
|
+
flag: "--yes",
|
|
16121
|
+
alias: "-y",
|
|
16122
|
+
text: "With --now: don't ask first (needed without a terminal)"
|
|
15795
16123
|
}
|
|
15796
16124
|
],
|
|
15797
16125
|
footer: [
|
|
15798
|
-
"With several planned and a terminal, --cancel
|
|
15799
|
-
"
|
|
16126
|
+
"With several planned and a terminal, --cancel and --now list them to pick one (--cancel also",
|
|
16127
|
+
"all). --now shows what it will send and asks first; without a terminal it needs the id and",
|
|
16128
|
+
"--yes. It stays busy until the agent finishes; Ctrl+C stops it and cancels that resume. If the",
|
|
16129
|
+
"limit is still on, the session is open or changed, you typed after the limit, the agent",
|
|
16130
|
+
"continued, or the message can't reach the agent (signed out, session deleted or archived,",
|
|
16131
|
+
"folder gone), nothing is sent and the resume stays planned. Other errors end it as failed.",
|
|
16132
|
+
"The ids are in square",
|
|
16133
|
+
"brackets in `agent-rewake schedules`."
|
|
15800
16134
|
]
|
|
15801
16135
|
},
|
|
15802
16136
|
{
|
|
@@ -16916,7 +17250,10 @@ function codexAdapter(deps) {
|
|
|
16916
17250
|
try {
|
|
16917
17251
|
const started = s.attempts.length > 0 ? Math.min(...s.attempts.map((a) => a.startedAt)) : void 0;
|
|
16918
17252
|
if (started === void 0) return void 0;
|
|
16919
|
-
|
|
17253
|
+
const sent = [s.text, `${s.text}
|
|
17254
|
+
|
|
17255
|
+
${WORKSPACE_NOTE}`];
|
|
17256
|
+
return userMessages(readTail2(transcript, 512 * 1024), started).some((m) => sent.includes(m)) || void 0;
|
|
16920
17257
|
} catch {
|
|
16921
17258
|
return void 0;
|
|
16922
17259
|
}
|
|
@@ -16943,11 +17280,138 @@ var init_adapter = __esm({
|
|
|
16943
17280
|
"src/hosts/codex/adapter.ts"() {
|
|
16944
17281
|
"use strict";
|
|
16945
17282
|
init_resume();
|
|
17283
|
+
init_workspace();
|
|
16946
17284
|
init_cli();
|
|
16947
17285
|
init_rollout();
|
|
16948
17286
|
}
|
|
16949
17287
|
});
|
|
16950
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
|
+
|
|
16951
17415
|
// src/hosts/codex/hooks.ts
|
|
16952
17416
|
import { basename as basename9 } from "node:path";
|
|
16953
17417
|
function threadOf(input) {
|
|
@@ -16994,7 +17458,10 @@ function codexHooks(deps) {
|
|
|
16994
17458
|
}
|
|
16995
17459
|
};
|
|
16996
17460
|
store.put(resume);
|
|
16997
|
-
if (deps.arm(resume.scheduleId, at) !== false)
|
|
17461
|
+
if (deps.arm(resume.scheduleId, at) !== false) {
|
|
17462
|
+
withWorkspace(store, resume, ctx.now);
|
|
17463
|
+
return true;
|
|
17464
|
+
}
|
|
16998
17465
|
store.cancel(resume.scheduleId, ctx.now);
|
|
16999
17466
|
return false;
|
|
17000
17467
|
};
|
|
@@ -17016,7 +17483,7 @@ function codexHooks(deps) {
|
|
|
17016
17483
|
const m = REWAKE2.exec(prompt2);
|
|
17017
17484
|
if (!m) {
|
|
17018
17485
|
cancelPending(ctx, thread.id);
|
|
17019
|
-
return void 0;
|
|
17486
|
+
return applySettings(ctx.stateDir).usageWarnings === "off" ? void 0 : usageWarning(ctx.stateDir, thread.path, ctx.now);
|
|
17020
17487
|
}
|
|
17021
17488
|
const c = continueOnly(CODEX_PLACE, m[1] ?? "", ctx.now);
|
|
17022
17489
|
if (c.kind === "reply") return block2(c.text);
|
|
@@ -17118,6 +17585,7 @@ var init_hooks = __esm({
|
|
|
17118
17585
|
init_time();
|
|
17119
17586
|
init_closed();
|
|
17120
17587
|
init_rollout();
|
|
17588
|
+
init_usage();
|
|
17121
17589
|
CODEX_PLACE = { name: "Codex", typed: "rewake", features: /* @__PURE__ */ new Set() };
|
|
17122
17590
|
REWAKE2 = /^\s*\/?rewake(?:\s+([\s\S]*?))?\s*$/i;
|
|
17123
17591
|
block2 = (reason) => JSON.stringify({ decision: "block", reason });
|
|
@@ -17276,14 +17744,14 @@ var init_host6 = __esm({
|
|
|
17276
17744
|
});
|
|
17277
17745
|
|
|
17278
17746
|
// src/hosts/cursor/host.ts
|
|
17279
|
-
import { readFileSync as
|
|
17747
|
+
import { readFileSync as readFileSync34 } from "node:fs";
|
|
17280
17748
|
function block3(userMessage) {
|
|
17281
17749
|
return JSON.stringify({ continue: false, user_message: userMessage });
|
|
17282
17750
|
}
|
|
17283
17751
|
function transcriptError(path) {
|
|
17284
17752
|
if (typeof path !== "string" || path === "") return void 0;
|
|
17285
17753
|
try {
|
|
17286
|
-
const lines =
|
|
17754
|
+
const lines = readFileSync34(path, "utf8").trimEnd().split("\n");
|
|
17287
17755
|
const last = JSON.parse(lines.at(-1) ?? "{}");
|
|
17288
17756
|
if (last.type === "turn_ended" && last.status === "error" && typeof last.error === "string")
|
|
17289
17757
|
return last.error;
|
|
@@ -17861,7 +18329,7 @@ var init_hook = __esm({
|
|
|
17861
18329
|
|
|
17862
18330
|
// src/install/cleanup.ts
|
|
17863
18331
|
import { existsSync as existsSync27, readdirSync as readdirSync19, rmdirSync, rmSync as rmSync20 } from "node:fs";
|
|
17864
|
-
import { dirname as
|
|
18332
|
+
import { dirname as dirname8, join as join45 } from "node:path";
|
|
17865
18333
|
function removeHelpers(stateDir2, timers) {
|
|
17866
18334
|
for (const id of timerIds(timers)) {
|
|
17867
18335
|
try {
|
|
@@ -17869,16 +18337,16 @@ function removeHelpers(stateDir2, timers) {
|
|
|
17869
18337
|
} catch {
|
|
17870
18338
|
}
|
|
17871
18339
|
}
|
|
17872
|
-
rmSync20(
|
|
18340
|
+
rmSync20(join45(stateDir2, "timers"), { recursive: true, force: true });
|
|
17873
18341
|
for (const file of [launcherPath(stateDir2), nodeShimPath(stateDir2)])
|
|
17874
18342
|
rmSync20(file, { force: true });
|
|
17875
|
-
rmSync20(
|
|
18343
|
+
rmSync20(join45(stateDir2, "bin", "agent-rewake.version"), { force: true });
|
|
17876
18344
|
try {
|
|
17877
|
-
rmdirSync(
|
|
18345
|
+
rmdirSync(join45(stateDir2, "bin"));
|
|
17878
18346
|
} catch {
|
|
17879
18347
|
}
|
|
17880
|
-
rmSync20(
|
|
17881
|
-
rmSync20(
|
|
18348
|
+
rmSync20(join45(stateDir2, "locks"), { recursive: true, force: true });
|
|
18349
|
+
rmSync20(join45(stateDir2, ".pruned"), { force: true });
|
|
17882
18350
|
}
|
|
17883
18351
|
function findBackups(dirs) {
|
|
17884
18352
|
const found = /* @__PURE__ */ new Set();
|
|
@@ -17889,7 +18357,7 @@ function findBackups(dirs) {
|
|
|
17889
18357
|
} catch {
|
|
17890
18358
|
continue;
|
|
17891
18359
|
}
|
|
17892
|
-
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));
|
|
17893
18361
|
}
|
|
17894
18362
|
return [...found].sort();
|
|
17895
18363
|
}
|
|
@@ -17900,11 +18368,11 @@ Rewake is still set up in ${list(f.stillIn)}, so its folder and the files those
|
|
|
17900
18368
|
`;
|
|
17901
18369
|
const kept = [];
|
|
17902
18370
|
const mine = [
|
|
17903
|
-
hasFiles(
|
|
17904
|
-
hasFiles(
|
|
17905
|
-
existsSync27(
|
|
17906
|
-
hasFiles(
|
|
17907
|
-
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"
|
|
17908
18376
|
].filter((x) => typeof x === "string");
|
|
17909
18377
|
if (mine.length > 0) kept.push(`Rewake's folder, with ${list(mine)}: ${f.stateDir}`);
|
|
17910
18378
|
for (const b of f.backups) kept.push(`A copy Rewake made of a file before changing it: ${b}`);
|
|
@@ -17930,9 +18398,9 @@ function finishUninstall(o) {
|
|
|
17930
18398
|
removeHelpers(state, defaultTimerHost(state, "node", launcherPath(state)));
|
|
17931
18399
|
const backups = findBackups([
|
|
17932
18400
|
zedDir,
|
|
17933
|
-
|
|
17934
|
-
|
|
17935
|
-
|
|
18401
|
+
join45(o.home, ".cursor"),
|
|
18402
|
+
dirname8(jetbrainsFile(o.env, o.home)),
|
|
18403
|
+
dirname8(devinFile(o.env, o.home, o.platform))
|
|
17936
18404
|
]);
|
|
17937
18405
|
const text2 = existsSync27(state) ? leftoverText({ stateDir: state, stillIn, backups, codex: o.chosen.includes("codex") }) : void 0;
|
|
17938
18406
|
return { text: text2, remains: stillIn.length > 0 };
|
|
@@ -18747,11 +19215,11 @@ var init_report = __esm({
|
|
|
18747
19215
|
});
|
|
18748
19216
|
|
|
18749
19217
|
// src/timers/slots.ts
|
|
18750
|
-
import { readFileSync as
|
|
18751
|
-
import { join as
|
|
19218
|
+
import { readFileSync as readFileSync35 } from "node:fs";
|
|
19219
|
+
import { join as join46 } from "node:path";
|
|
18752
19220
|
function lastStart2(stateDir2) {
|
|
18753
19221
|
try {
|
|
18754
|
-
const n = Number(
|
|
19222
|
+
const n = Number(readFileSync35(join46(stateDir2, "locks", START_FILE), "utf8").trim());
|
|
18755
19223
|
return Number.isFinite(n) ? n : 0;
|
|
18756
19224
|
} catch {
|
|
18757
19225
|
return 0;
|
|
@@ -18781,7 +19249,7 @@ async function takeSlot(o) {
|
|
|
18781
19249
|
try {
|
|
18782
19250
|
const wait2 = Math.min(lastStart2(o.stateDir) + gap - clock2(), deadline - clock2());
|
|
18783
19251
|
if (wait2 > 0) await sleep(wait2);
|
|
18784
|
-
writeFileAtomic(ensurePrivateDir(
|
|
19252
|
+
writeFileAtomic(ensurePrivateDir(join46(o.stateDir, "locks")), START_FILE, `${clock2()}
|
|
18785
19253
|
`);
|
|
18786
19254
|
} finally {
|
|
18787
19255
|
if (mine) lock.release(START_KEY);
|
|
@@ -18816,9 +19284,17 @@ import { basename as basename10 } from "node:path";
|
|
|
18816
19284
|
function runningText(at, noun = "session") {
|
|
18817
19285
|
return `${at}: Rewake is continuing the ${noun} now. You'll get a notification when it's done. To stop it: "${rewake("continue --cancel")}".`;
|
|
18818
19286
|
}
|
|
19287
|
+
function foregroundText(at, noun = "session") {
|
|
19288
|
+
return `${at}: Rewake is continuing the ${noun} now. Press Ctrl+C to stop it.`;
|
|
19289
|
+
}
|
|
18819
19290
|
function doneText(at, noun = "session", now = Date.now()) {
|
|
18820
19291
|
return `${at}: Rewake's run ended normally ${formatAt(now, now)}. Open the ${noun} to see what it did.`;
|
|
18821
19292
|
}
|
|
19293
|
+
function workspaceNoteText(noun, added) {
|
|
19294
|
+
const what = `The project's tracked files or latest commit changed while the ${noun} waited`;
|
|
19295
|
+
const how = added ? "so Rewake added a line to its message asking the agent to re-read files before editing." : "Rewake sent its message as it was. To have it add a line asking the agent to re-read files, choose note; to have it ask you first, choose hold.";
|
|
19296
|
+
return `${what}${added ? "," : "."} ${how} Change this with: ${rewake("settings workspace-changed")} (tell, note, hold or off).`;
|
|
19297
|
+
}
|
|
18822
19298
|
function where(host, s) {
|
|
18823
19299
|
const folder = s.cwd ? basename10(s.cwd) : "";
|
|
18824
19300
|
return folder ? `${host.name} in the "${folder}" folder` : host.name;
|
|
@@ -18832,6 +19308,13 @@ function notice(why, agent, now, f) {
|
|
|
18832
19308
|
return `${agent}: the usage limit has reset. The ${n} is open, so Rewake didn't send anything. Continue it there.`;
|
|
18833
19309
|
case "changed":
|
|
18834
19310
|
return `${agent}: the usage limit has reset, but the ${n} has changed since it stopped, so Rewake didn't send anything. ${cap(reopen)} to see where it stands and continue.`;
|
|
19311
|
+
case "workspace": {
|
|
19312
|
+
const what = [
|
|
19313
|
+
...f.workspace?.commit ? ["its latest commit moved"] : [],
|
|
19314
|
+
...f.workspace?.changes ? ["its tracked files differ"] : []
|
|
19315
|
+
].join(" and ");
|
|
19316
|
+
return `${agent}: the usage limit has reset, but the project changed while the ${n} waited (${what}), so Rewake didn't send anything. ${f.again ? f.again(void 0) : `To continue anyway, run "${rewake("continue")}", or ${reopen}.`} Change this check with: ${rewake("settings workspace-changed")} (tell, note, hold or off).`;
|
|
19317
|
+
}
|
|
18835
19318
|
case "late":
|
|
18836
19319
|
return `${agent}: Rewake was due to continue the ${n}${f.dueAt ? ` ${formatAt(f.dueAt, now)}` : ""}, but couldn't run then (the computer may have been off or asleep). ${cap(reopen)} to continue.`;
|
|
18837
19320
|
case "far-reset":
|
|
@@ -18880,6 +19363,14 @@ function rearmEarly(id, store, deps, now) {
|
|
|
18880
19363
|
deps.log?.("fire.early", { armed: armed.ok });
|
|
18881
19364
|
return "early";
|
|
18882
19365
|
}
|
|
19366
|
+
function keptOutcome(d) {
|
|
19367
|
+
if (d.action === "notify") return d.why === "open" || d.why === "changed" ? d.why : "limited";
|
|
19368
|
+
if (d.action === "skip") {
|
|
19369
|
+
if (d.why === "typed" || d.why === "native") return d.why;
|
|
19370
|
+
return d.why === "expired" ? "limited" : "gone";
|
|
19371
|
+
}
|
|
19372
|
+
return "limited";
|
|
19373
|
+
}
|
|
18883
19374
|
async function fire(id, deps) {
|
|
18884
19375
|
const store = new ScheduleStore(deps.stateDir);
|
|
18885
19376
|
const log = deps.log ?? (() => {
|
|
@@ -18905,7 +19396,7 @@ async function fire(id, deps) {
|
|
|
18905
19396
|
}
|
|
18906
19397
|
const lock = new SessionLock(deps.stateDir);
|
|
18907
19398
|
const lockKey = `fire:${id}`;
|
|
18908
|
-
if (first.status !== "cancelled" && now < first.dueAt - EARLY_MS) {
|
|
19399
|
+
if (!deps.immediate && first.status !== "cancelled" && now < first.dueAt - EARLY_MS) {
|
|
18909
19400
|
if (!lock.acquire(lockKey)) return "early";
|
|
18910
19401
|
try {
|
|
18911
19402
|
return rearmEarly(id, store, deps, now);
|
|
@@ -18931,7 +19422,7 @@ async function fire(id, deps) {
|
|
|
18931
19422
|
removeTimer();
|
|
18932
19423
|
return "gone";
|
|
18933
19424
|
}
|
|
18934
|
-
if (s.status !== "cancelled" && now < s.dueAt - EARLY_MS)
|
|
19425
|
+
if (!deps.immediate && s.status !== "cancelled" && now < s.dueAt - EARLY_MS)
|
|
18935
19426
|
return rearmEarly(id, store, deps, now);
|
|
18936
19427
|
const wait2 = (until, why, count = true) => {
|
|
18937
19428
|
const next = Math.max(until, now + MIN_ARM_MS);
|
|
@@ -18964,7 +19455,10 @@ async function fire(id, deps) {
|
|
|
18964
19455
|
const place = await takeSlot({ stateDir: deps.stateDir, ...deps.slots }).catch(
|
|
18965
19456
|
() => "error"
|
|
18966
19457
|
);
|
|
18967
|
-
if (place === void 0)
|
|
19458
|
+
if (place === void 0) {
|
|
19459
|
+
if (deps.immediate) return "busy";
|
|
19460
|
+
return wait2(now + MIN_ARM_MS, "no-free-place", false);
|
|
19461
|
+
}
|
|
18968
19462
|
if (place !== "error") slot.release = place;
|
|
18969
19463
|
}
|
|
18970
19464
|
const settings = loadSettings(deps.stateDir);
|
|
@@ -18977,7 +19471,7 @@ async function fire(id, deps) {
|
|
|
18977
19471
|
}
|
|
18978
19472
|
const decision = decideFire({
|
|
18979
19473
|
resume: {
|
|
18980
|
-
dueAt: s.dueAt,
|
|
19474
|
+
dueAt: deps.immediate ? now : s.dueAt,
|
|
18981
19475
|
status: s.status,
|
|
18982
19476
|
...s.rearms !== void 0 && { rearms: s.rearms }
|
|
18983
19477
|
},
|
|
@@ -18997,7 +19491,7 @@ async function fire(id, deps) {
|
|
|
18997
19491
|
}),
|
|
18998
19492
|
now
|
|
18999
19493
|
);
|
|
19000
|
-
const tell = (why, status, cause, message) => {
|
|
19494
|
+
const tell = (why, status, cause, message, workspace) => {
|
|
19001
19495
|
settle(status, cause ?? why, message);
|
|
19002
19496
|
if (facts.newResetsAt !== void 0 && (why === "far-reset" || why === "expired"))
|
|
19003
19497
|
store.update(id, (x) => ({ ...x, dueAt: (facts.newResetsAt ?? 0) + RESET_MARGIN_MS }), now);
|
|
@@ -19010,12 +19504,17 @@ async function fire(id, deps) {
|
|
|
19010
19504
|
...host.again !== void 0 && { again: host.again },
|
|
19011
19505
|
dueAt: s.dueAt,
|
|
19012
19506
|
...facts.newResetsAt !== void 0 && { resetsAt: facts.newResetsAt },
|
|
19013
|
-
...cause && { cause }
|
|
19507
|
+
...cause && { cause },
|
|
19508
|
+
...workspace && { workspace }
|
|
19014
19509
|
})
|
|
19015
19510
|
);
|
|
19016
19511
|
removeTimer();
|
|
19017
19512
|
return why === "failed" || why === "expired" ? "failed" : "notified";
|
|
19018
19513
|
};
|
|
19514
|
+
if (deps.immediate && decision.action !== "send") {
|
|
19515
|
+
log("fire.kept", { host: host.id, action: decision.action });
|
|
19516
|
+
return keptOutcome(decision);
|
|
19517
|
+
}
|
|
19019
19518
|
log("fire.decide", {
|
|
19020
19519
|
host: host.id,
|
|
19021
19520
|
action: decision.action,
|
|
@@ -19023,6 +19522,19 @@ async function fire(id, deps) {
|
|
|
19023
19522
|
});
|
|
19024
19523
|
switch (decision.action) {
|
|
19025
19524
|
case "send": {
|
|
19525
|
+
let noted = false;
|
|
19526
|
+
let changed = false;
|
|
19527
|
+
if (s.workspace && settings.workspaceChanged !== "off") {
|
|
19528
|
+
const here = fingerprintWorkspace(s.cwd, FIRE_BUDGET_MS);
|
|
19529
|
+
const differs = here && workspaceChange(s.workspace, here);
|
|
19530
|
+
if (differs) {
|
|
19531
|
+
log("fire.workspace", { action: settings.workspaceChanged });
|
|
19532
|
+
if (settings.workspaceChanged === "hold")
|
|
19533
|
+
return tell("workspace", "needs_attention", void 0, void 0, differs);
|
|
19534
|
+
changed = true;
|
|
19535
|
+
noted = settings.workspaceChanged === "note";
|
|
19536
|
+
}
|
|
19537
|
+
}
|
|
19026
19538
|
const claimed = store.update(
|
|
19027
19539
|
id,
|
|
19028
19540
|
(x) => x.status !== s.status || x.dueAt !== s.dueAt ? void 0 : {
|
|
@@ -19050,6 +19562,7 @@ async function fire(id, deps) {
|
|
|
19050
19562
|
const wake = deps.wake ?? new Wakefulness();
|
|
19051
19563
|
wake.set(true, settings.keepAwake);
|
|
19052
19564
|
let watch2;
|
|
19565
|
+
let told = false;
|
|
19053
19566
|
onResumeRun((pid) => {
|
|
19054
19567
|
store.update(
|
|
19055
19568
|
id,
|
|
@@ -19059,7 +19572,12 @@ async function fire(id, deps) {
|
|
|
19059
19572
|
}),
|
|
19060
19573
|
now
|
|
19061
19574
|
);
|
|
19062
|
-
|
|
19575
|
+
told = changed;
|
|
19576
|
+
const running = deps.immediate ? foregroundText(at, host.noun) : runningText(at, host.noun);
|
|
19577
|
+
deps.notify(
|
|
19578
|
+
"Agent Rewake",
|
|
19579
|
+
changed ? `${running} ${workspaceNoteText(host.noun, noted)}` : running
|
|
19580
|
+
);
|
|
19063
19581
|
watch2 = setInterval(() => {
|
|
19064
19582
|
if (!store.get(id)?.attempts.find((a) => a.idempotencyKey === key2)?.stopped) return;
|
|
19065
19583
|
clearInterval(watch2);
|
|
@@ -19067,7 +19585,12 @@ async function fire(id, deps) {
|
|
|
19067
19585
|
}, deps.stopPollMs ?? STOP_POLL_MS);
|
|
19068
19586
|
});
|
|
19069
19587
|
try {
|
|
19070
|
-
result = await host.send(
|
|
19588
|
+
result = await host.send(
|
|
19589
|
+
noted ? { ...s, text: `${s.text}
|
|
19590
|
+
|
|
19591
|
+
${WORKSPACE_NOTE}` } : s,
|
|
19592
|
+
key2
|
|
19593
|
+
);
|
|
19071
19594
|
} catch (err) {
|
|
19072
19595
|
result = { ok: false, reason: "failed", detail: err.message };
|
|
19073
19596
|
} finally {
|
|
@@ -19075,7 +19598,7 @@ async function fire(id, deps) {
|
|
|
19075
19598
|
if (watch2) clearInterval(watch2);
|
|
19076
19599
|
wake.release();
|
|
19077
19600
|
}
|
|
19078
|
-
if (store.get(id)?.attempts.find((a) => a.idempotencyKey === key2)?.stopped) {
|
|
19601
|
+
if (store.get(id)?.attempts.find((a) => a.idempotencyKey === key2)?.stopped && !(deps.immediate && result.ok)) {
|
|
19079
19602
|
settle("stopped", "you");
|
|
19080
19603
|
removeTimer();
|
|
19081
19604
|
log("fire.stopped", {});
|
|
@@ -19093,10 +19616,25 @@ async function fire(id, deps) {
|
|
|
19093
19616
|
if (result.ok) {
|
|
19094
19617
|
settle("sent");
|
|
19095
19618
|
removeTimer();
|
|
19096
|
-
if (
|
|
19619
|
+
if (changed && !told)
|
|
19620
|
+
deps.notify("Agent Rewake", `${at}: ${workspaceNoteText(host.noun, noted)}`);
|
|
19621
|
+
if (!deps.immediate && store.get(id)?.attempts.find((a) => a.idempotencyKey === key2)?.pid !== void 0)
|
|
19097
19622
|
deps.notify("Agent Rewake", doneText(at, host.noun, deps.now()));
|
|
19098
19623
|
return "sent";
|
|
19099
19624
|
}
|
|
19625
|
+
if (deps.immediate && (result.reason === "limited" || result.reason === "busy")) {
|
|
19626
|
+
store.update(
|
|
19627
|
+
id,
|
|
19628
|
+
(x) => ({
|
|
19629
|
+
...x,
|
|
19630
|
+
status: s.status,
|
|
19631
|
+
attempts: x.attempts.filter((a) => a.idempotencyKey !== key2)
|
|
19632
|
+
}),
|
|
19633
|
+
now
|
|
19634
|
+
);
|
|
19635
|
+
log("fire.still-limited", { host: host.id, now: true });
|
|
19636
|
+
return result.reason === "limited" ? "limited" : "busy";
|
|
19637
|
+
}
|
|
19100
19638
|
if (result.reason === "limited" || result.reason === "busy") {
|
|
19101
19639
|
const rearms = s.rearms ?? 0;
|
|
19102
19640
|
const reset = result.reason === "limited" ? result.resetsAt : void 0;
|
|
@@ -19118,6 +19656,27 @@ async function fire(id, deps) {
|
|
|
19118
19656
|
"needs-approval",
|
|
19119
19657
|
"folder-gone"
|
|
19120
19658
|
].includes(result.detail ?? "") ? result.detail : void 0;
|
|
19659
|
+
if (deps.immediate && cause !== void 0 && !["timeout", "needs-approval"].includes(cause)) {
|
|
19660
|
+
store.update(
|
|
19661
|
+
id,
|
|
19662
|
+
(x) => ({
|
|
19663
|
+
...x,
|
|
19664
|
+
status: s.status,
|
|
19665
|
+
attempts: x.attempts.filter((a) => a.idempotencyKey !== key2)
|
|
19666
|
+
}),
|
|
19667
|
+
now
|
|
19668
|
+
);
|
|
19669
|
+
deps.notify(
|
|
19670
|
+
"Agent Rewake",
|
|
19671
|
+
notice("failed", at, now, {
|
|
19672
|
+
noun: host.noun,
|
|
19673
|
+
agentName: host.name,
|
|
19674
|
+
...host.reopen !== void 0 && { reopen: host.reopen },
|
|
19675
|
+
cause
|
|
19676
|
+
})
|
|
19677
|
+
);
|
|
19678
|
+
return "failed";
|
|
19679
|
+
}
|
|
19121
19680
|
return tell("failed", "failed", cause, result.message);
|
|
19122
19681
|
}
|
|
19123
19682
|
case "wait":
|
|
@@ -19193,6 +19752,7 @@ var init_fire = __esm({
|
|
|
19193
19752
|
init_command2();
|
|
19194
19753
|
init_keep_awake();
|
|
19195
19754
|
init_spawn2();
|
|
19755
|
+
init_workspace();
|
|
19196
19756
|
init_slots();
|
|
19197
19757
|
init_timers();
|
|
19198
19758
|
EARLY_MS = 3e4;
|
|
@@ -19206,14 +19766,14 @@ var init_fire = __esm({
|
|
|
19206
19766
|
});
|
|
19207
19767
|
|
|
19208
19768
|
// src/timers/login.ts
|
|
19209
|
-
import { existsSync as existsSync29, mkdirSync as mkdirSync3, readFileSync as
|
|
19210
|
-
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";
|
|
19211
19771
|
function loginItem(h) {
|
|
19212
19772
|
const args = [h.node, h.cli, "sweep", "--state-dir", h.stateDir];
|
|
19213
19773
|
if (h.platform === "darwin")
|
|
19214
19774
|
return {
|
|
19215
19775
|
kind: "launchd",
|
|
19216
|
-
path:
|
|
19776
|
+
path: join47(h.home, "Library", "LaunchAgents", `${LOGIN_LABEL}.plist`),
|
|
19217
19777
|
text: `<?xml version="1.0" encoding="UTF-8"?>
|
|
19218
19778
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
19219
19779
|
<plist version="1.0">
|
|
@@ -19233,7 +19793,7 @@ function loginItem(h) {
|
|
|
19233
19793
|
if (h.exists("/run/systemd/system"))
|
|
19234
19794
|
return {
|
|
19235
19795
|
kind: "systemd",
|
|
19236
|
-
path:
|
|
19796
|
+
path: join47(h.home, ".config", "systemd", "user", UNIT),
|
|
19237
19797
|
text: `[Unit]
|
|
19238
19798
|
Description=Agent Rewake: set planned resumes again after a restart
|
|
19239
19799
|
|
|
@@ -19247,7 +19807,7 @@ WantedBy=default.target
|
|
|
19247
19807
|
};
|
|
19248
19808
|
return {
|
|
19249
19809
|
kind: "autostart",
|
|
19250
|
-
path:
|
|
19810
|
+
path: join47(h.home, ".config", "autostart", "agent-rewake-sweep.desktop"),
|
|
19251
19811
|
text: `[Desktop Entry]
|
|
19252
19812
|
Type=Application
|
|
19253
19813
|
Name=Agent Rewake
|
|
@@ -19265,9 +19825,9 @@ function syncLoginItem(h, wanted) {
|
|
|
19265
19825
|
if (!item) return "unchanged";
|
|
19266
19826
|
const had = existsSync29(item.path);
|
|
19267
19827
|
if (wanted) {
|
|
19268
|
-
const same2 = had &&
|
|
19828
|
+
const same2 = had && readFileSync36(item.path, "utf8") === item.text;
|
|
19269
19829
|
if (same2) return "unchanged";
|
|
19270
|
-
mkdirSync3(
|
|
19830
|
+
mkdirSync3(dirname9(item.path), { recursive: true });
|
|
19271
19831
|
replaceFileExclusive(item.path, item.text, 420);
|
|
19272
19832
|
if (item.kind === "systemd") {
|
|
19273
19833
|
h.run("systemctl", ["--user", "daemon-reload"]);
|
|
@@ -19313,10 +19873,10 @@ import {
|
|
|
19313
19873
|
utimesSync,
|
|
19314
19874
|
writeFileSync as writeFileSync7
|
|
19315
19875
|
} from "node:fs";
|
|
19316
|
-
import { join as
|
|
19876
|
+
import { join as join48 } from "node:path";
|
|
19317
19877
|
function pruneState(stateDir2, now, opts = {}) {
|
|
19318
19878
|
if (!existsSync30(stateDir2)) return void 0;
|
|
19319
|
-
const marker =
|
|
19879
|
+
const marker = join48(stateDir2, MARKER);
|
|
19320
19880
|
if (!opts.force)
|
|
19321
19881
|
try {
|
|
19322
19882
|
if (now - statSync10(marker).mtimeMs < EVERY_MS) return void 0;
|
|
@@ -19347,7 +19907,7 @@ function pruneState(stateDir2, now, opts = {}) {
|
|
|
19347
19907
|
function pruneSessions(stateDir2, cutoff, needed) {
|
|
19348
19908
|
let hosts;
|
|
19349
19909
|
try {
|
|
19350
|
-
hosts = readdirSync20(
|
|
19910
|
+
hosts = readdirSync20(join48(stateDir2, "hosts"));
|
|
19351
19911
|
} catch {
|
|
19352
19912
|
return 0;
|
|
19353
19913
|
}
|
|
@@ -19363,7 +19923,7 @@ function pruneSessions(stateDir2, cutoff, needed) {
|
|
|
19363
19923
|
return n;
|
|
19364
19924
|
}
|
|
19365
19925
|
function pruneLogs(stateDir2, cutoff) {
|
|
19366
|
-
const dir =
|
|
19926
|
+
const dir = join48(stateDir2, "logs");
|
|
19367
19927
|
let names;
|
|
19368
19928
|
try {
|
|
19369
19929
|
names = readdirSync20(dir);
|
|
@@ -19376,7 +19936,7 @@ function pruneLogs(stateDir2, cutoff) {
|
|
|
19376
19936
|
const m = /^rewake-(\d{4}-\d{2}-\d{2})\.jsonl$/.exec(f);
|
|
19377
19937
|
if (!m || m[1] >= oldest) continue;
|
|
19378
19938
|
try {
|
|
19379
|
-
rmSync22(
|
|
19939
|
+
rmSync22(join48(dir, f), { force: true });
|
|
19380
19940
|
n++;
|
|
19381
19941
|
} catch {
|
|
19382
19942
|
}
|
|
@@ -19392,7 +19952,7 @@ function pruneTemp(dir, before, depth = 0) {
|
|
|
19392
19952
|
}
|
|
19393
19953
|
let n = 0;
|
|
19394
19954
|
for (const e of entries) {
|
|
19395
|
-
const path =
|
|
19955
|
+
const path = join48(dir, e.name);
|
|
19396
19956
|
if (e.isDirectory()) {
|
|
19397
19957
|
if (depth < MAX_DEPTH && !SKIP_DIRS.has(e.name)) n += pruneTemp(path, before, depth + 1);
|
|
19398
19958
|
} else if (e.isFile() && TEMP_NAME.test(e.name)) {
|
|
@@ -19647,8 +20207,8 @@ var init_input = __esm({
|
|
|
19647
20207
|
});
|
|
19648
20208
|
|
|
19649
20209
|
// src/ui/page.ts
|
|
19650
|
-
import { readFileSync as
|
|
19651
|
-
import { join as
|
|
20210
|
+
import { readFileSync as readFileSync37, writeFileSync as writeFileSync8 } from "node:fs";
|
|
20211
|
+
import { join as join49 } from "node:path";
|
|
19652
20212
|
function rowLabel(r) {
|
|
19653
20213
|
if (r.host === void 0) return threadLabel(r.thread, r.schedule);
|
|
19654
20214
|
const title = r.thread?.title ?? `${capital(r.noun)} ${r.schedule.sessionId.slice(0, 8)}`;
|
|
@@ -19906,11 +20466,11 @@ var init_page = __esm({
|
|
|
19906
20466
|
return this.rows[this.selected];
|
|
19907
20467
|
}
|
|
19908
20468
|
prefsFile() {
|
|
19909
|
-
return
|
|
20469
|
+
return join49(this.opts.stateDir, "ui.json");
|
|
19910
20470
|
}
|
|
19911
20471
|
prefs() {
|
|
19912
20472
|
try {
|
|
19913
|
-
return JSON.parse(
|
|
20473
|
+
return JSON.parse(readFileSync37(this.prefsFile(), "utf8"));
|
|
19914
20474
|
} catch {
|
|
19915
20475
|
return {};
|
|
19916
20476
|
}
|
|
@@ -20840,11 +21400,11 @@ var init_tui = __esm({
|
|
|
20840
21400
|
});
|
|
20841
21401
|
|
|
20842
21402
|
// src/util/installed.ts
|
|
20843
|
-
import { readFileSync as
|
|
20844
|
-
import { join as
|
|
21403
|
+
import { readFileSync as readFileSync38 } from "node:fs";
|
|
21404
|
+
import { join as join50 } from "node:path";
|
|
20845
21405
|
function readInstalled(stateDir2) {
|
|
20846
21406
|
try {
|
|
20847
|
-
const v = JSON.parse(
|
|
21407
|
+
const v = JSON.parse(readFileSync38(join50(stateDir2, FILE2), "utf8"));
|
|
20848
21408
|
return typeof v.version === "string" && typeof v.at === "number" && Number.isFinite(v.at) ? { version: v.version, at: v.at } : void 0;
|
|
20849
21409
|
} catch {
|
|
20850
21410
|
return void 0;
|
|
@@ -20855,26 +21415,26 @@ function recordInstall(stateDir2, version, now) {
|
|
|
20855
21415
|
try {
|
|
20856
21416
|
writeFileAtomic(
|
|
20857
21417
|
ensurePrivateDir(stateDir2),
|
|
20858
|
-
|
|
21418
|
+
FILE2,
|
|
20859
21419
|
`${JSON.stringify({ version, at: now })}
|
|
20860
21420
|
`
|
|
20861
21421
|
);
|
|
20862
21422
|
} catch {
|
|
20863
21423
|
}
|
|
20864
21424
|
}
|
|
20865
|
-
var
|
|
21425
|
+
var FILE2;
|
|
20866
21426
|
var init_installed = __esm({
|
|
20867
21427
|
"src/util/installed.ts"() {
|
|
20868
21428
|
"use strict";
|
|
20869
21429
|
init_store();
|
|
20870
21430
|
init_paths();
|
|
20871
|
-
|
|
21431
|
+
FILE2 = "installed.json";
|
|
20872
21432
|
}
|
|
20873
21433
|
});
|
|
20874
21434
|
|
|
20875
21435
|
// src/util/log.ts
|
|
20876
21436
|
import { appendFileSync } from "node:fs";
|
|
20877
|
-
import { join as
|
|
21437
|
+
import { join as join51 } from "node:path";
|
|
20878
21438
|
var Logger;
|
|
20879
21439
|
var init_log = __esm({
|
|
20880
21440
|
"src/util/log.ts"() {
|
|
@@ -20911,8 +21471,8 @@ var init_log = __esm({
|
|
|
20911
21471
|
try {
|
|
20912
21472
|
const day = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
20913
21473
|
if (!this.file?.endsWith(`rewake-${day}.jsonl`)) {
|
|
20914
|
-
const dir = ensurePrivateDir(
|
|
20915
|
-
this.file =
|
|
21474
|
+
const dir = ensurePrivateDir(join51(stateDir(this.env), "logs"));
|
|
21475
|
+
this.file = join51(dir, `rewake-${day}.jsonl`);
|
|
20916
21476
|
}
|
|
20917
21477
|
const record = { t: (/* @__PURE__ */ new Date()).toISOString(), level, event, pid: process.pid, ...fields2 };
|
|
20918
21478
|
appendFileSync(this.file, `${JSON.stringify(record)}
|
|
@@ -20935,9 +21495,9 @@ __export(cli_exports, {
|
|
|
20935
21495
|
testTiming: () => testTiming
|
|
20936
21496
|
});
|
|
20937
21497
|
import { spawnSync as spawnSync13 } from "node:child_process";
|
|
20938
|
-
import { existsSync as existsSync31, readdirSync as readdirSync21, readFileSync as
|
|
21498
|
+
import { existsSync as existsSync31, readdirSync as readdirSync21, readFileSync as readFileSync39 } from "node:fs";
|
|
20939
21499
|
import { homedir as homedir23 } from "node:os";
|
|
20940
|
-
import { join as
|
|
21500
|
+
import { join as join52 } from "node:path";
|
|
20941
21501
|
import { emitKeypressEvents } from "node:readline";
|
|
20942
21502
|
import { createInterface as createInterface6 } from "node:readline/promises";
|
|
20943
21503
|
function agentIdentity(target, env) {
|
|
@@ -21277,14 +21837,23 @@ ${loginItemPlanText(process.platform)}`);
|
|
|
21277
21837
|
return code3;
|
|
21278
21838
|
}
|
|
21279
21839
|
if (first === "continue") {
|
|
21840
|
+
if (argv.includes("--now")) {
|
|
21841
|
+
const rest = argv.slice(1).filter((a) => a !== "--now");
|
|
21842
|
+
const yes = rest.some((a) => a === "--yes" || a === "-y");
|
|
21843
|
+
const names = rest.filter((a) => a !== "--yes" && a !== "-y");
|
|
21844
|
+
const nowId = names[0];
|
|
21845
|
+
if (names.length > 1 || nowId?.startsWith("-")) {
|
|
21846
|
+
process.stderr.write(CONTINUE_USAGE);
|
|
21847
|
+
return 2;
|
|
21848
|
+
}
|
|
21849
|
+
return runContinueCommand(env, "now", void 0, nowId, yes);
|
|
21850
|
+
}
|
|
21280
21851
|
const flag = argv[1];
|
|
21281
21852
|
const mode = flag === "--always" ? "always" : flag === "--ask" ? "ask" : flag === "--cancel" ? "cancel" : void 0;
|
|
21282
21853
|
const cancelId = mode === "cancel" ? argv[2] : void 0;
|
|
21283
21854
|
const extra = argv.length > (cancelId === void 0 ? 2 : 3);
|
|
21284
21855
|
if (flag !== void 0 && mode === void 0 || extra || cancelId?.startsWith("-")) {
|
|
21285
|
-
process.stderr.write(
|
|
21286
|
-
"agent-rewake: usage: agent-rewake continue [--always | --ask | --cancel [<id>]]\n"
|
|
21287
|
-
);
|
|
21856
|
+
process.stderr.write(CONTINUE_USAGE);
|
|
21288
21857
|
return 2;
|
|
21289
21858
|
}
|
|
21290
21859
|
return runContinueCommand(env, mode, cancelId);
|
|
@@ -21337,7 +21906,7 @@ ${loginItemPlanText(process.platform)}`);
|
|
|
21337
21906
|
const sep2 = argv.indexOf("--");
|
|
21338
21907
|
if (wrap) {
|
|
21339
21908
|
try {
|
|
21340
|
-
const npmLog =
|
|
21909
|
+
const npmLog = join52(ensurePrivateDir(join52(stateDir(env), "logs")), "npm-install.log");
|
|
21341
21910
|
agent = await wrappedAgentCommand(wrap.target, wrap.extra, env, stateDir(env), npmLog);
|
|
21342
21911
|
} catch (err) {
|
|
21343
21912
|
log.error("agent.resolve_failed", {
|
|
@@ -21543,7 +22112,7 @@ ${usageText()}
|
|
|
21543
22112
|
return void 0;
|
|
21544
22113
|
}
|
|
21545
22114
|
function toolsRefused(state) {
|
|
21546
|
-
const dir =
|
|
22115
|
+
const dir = join52(state, "logs");
|
|
21547
22116
|
const agents = /* @__PURE__ */ new Set();
|
|
21548
22117
|
let files = [];
|
|
21549
22118
|
try {
|
|
@@ -21552,7 +22121,7 @@ function toolsRefused(state) {
|
|
|
21552
22121
|
return [];
|
|
21553
22122
|
}
|
|
21554
22123
|
for (const f of files) {
|
|
21555
|
-
for (const line2 of
|
|
22124
|
+
for (const line2 of readFileSync39(join52(dir, f), "utf8").split("\n")) {
|
|
21556
22125
|
if (!line2.includes("agent_tools.refused")) continue;
|
|
21557
22126
|
try {
|
|
21558
22127
|
const r = JSON.parse(line2);
|
|
@@ -21579,7 +22148,7 @@ function setupZedText(env) {
|
|
|
21579
22148
|
const task = [taskEntry(launch)];
|
|
21580
22149
|
const keymap = [{ bindings: { [keyChord()]: ["task::Spawn", { task_name: TASK_LABEL }] } }];
|
|
21581
22150
|
const dir = zedConfigDir();
|
|
21582
|
-
const file = (name) =>
|
|
22151
|
+
const file = (name) => join52(dir, name);
|
|
21583
22152
|
return [
|
|
21584
22153
|
`Easiest: run \`${rewake("install")}\`, which adds these for you after asking.`,
|
|
21585
22154
|
"To add them by hand instead:",
|
|
@@ -22014,14 +22583,70 @@ async function prompt(question) {
|
|
|
22014
22583
|
rl.close();
|
|
22015
22584
|
}
|
|
22016
22585
|
}
|
|
22017
|
-
async function runContinueCommand(env, mode, cancelId) {
|
|
22586
|
+
async function runContinueCommand(env, mode, cancelId, nowId, yes = false) {
|
|
22018
22587
|
const { state, timers, sweepDeps, node } = timerDeps(env);
|
|
22019
22588
|
sweepQuietly(env);
|
|
22020
22589
|
const adapters = hostAdapters(env, node, state);
|
|
22021
|
-
|
|
22590
|
+
const log = new Logger(env);
|
|
22591
|
+
let interrupted = false;
|
|
22592
|
+
let sentAnyway = false;
|
|
22593
|
+
const code2 = await runContinue({
|
|
22022
22594
|
sleepSettings: () => readSleepSettings({ env }),
|
|
22023
22595
|
...mode && { mode },
|
|
22024
22596
|
...cancelId !== void 0 && { cancelId },
|
|
22597
|
+
...nowId !== void 0 && { nowId },
|
|
22598
|
+
yes,
|
|
22599
|
+
// The resume's own timer run, at once; what it would tell by notification is said here.
|
|
22600
|
+
fireNow: async (id) => {
|
|
22601
|
+
const store = new ScheduleStore(state);
|
|
22602
|
+
const onInterrupt = () => {
|
|
22603
|
+
if (interrupted) {
|
|
22604
|
+
const pid = store.get(id)?.attempts.at(-1)?.pid;
|
|
22605
|
+
if (pid !== void 0) {
|
|
22606
|
+
killPidTree(pid, void 0, void 0, "SIGKILL");
|
|
22607
|
+
process.stdout.write("Ended the agent now.\n");
|
|
22608
|
+
}
|
|
22609
|
+
return;
|
|
22610
|
+
}
|
|
22611
|
+
interrupted = true;
|
|
22612
|
+
const s = store.get(id);
|
|
22613
|
+
if (s !== void 0 && s.status !== "sending" && !WAITING_STATES.has(s.status)) return;
|
|
22614
|
+
if (s?.status !== "sending") {
|
|
22615
|
+
process.stdout.write("Stopped. Nothing was sent, and your resume is still planned.\n");
|
|
22616
|
+
process.exit(130);
|
|
22617
|
+
}
|
|
22618
|
+
store.update(
|
|
22619
|
+
id,
|
|
22620
|
+
(x) => ({
|
|
22621
|
+
...x,
|
|
22622
|
+
attempts: x.attempts.map(
|
|
22623
|
+
(a, i) => i === x.attempts.length - 1 ? { ...a, stopped: true } : a
|
|
22624
|
+
)
|
|
22625
|
+
}),
|
|
22626
|
+
Date.now()
|
|
22627
|
+
);
|
|
22628
|
+
process.stdout.write(
|
|
22629
|
+
"Stopping. The agent ends within a few seconds; what it has done so far stays. The planned resume is cancelled too.\n"
|
|
22630
|
+
);
|
|
22631
|
+
};
|
|
22632
|
+
process.on("SIGINT", onInterrupt);
|
|
22633
|
+
try {
|
|
22634
|
+
const outcome2 = await fire(id, {
|
|
22635
|
+
stateDir: state,
|
|
22636
|
+
now: Date.now,
|
|
22637
|
+
hosts: adapters,
|
|
22638
|
+
timers,
|
|
22639
|
+
notify: (_title, body) => process.stdout.write(`${body}
|
|
22640
|
+
`),
|
|
22641
|
+
log: (event, fields2) => log.info(event, fields2),
|
|
22642
|
+
immediate: true
|
|
22643
|
+
});
|
|
22644
|
+
sentAnyway = outcome2 === "sent";
|
|
22645
|
+
return outcome2;
|
|
22646
|
+
} finally {
|
|
22647
|
+
process.off("SIGINT", onInterrupt);
|
|
22648
|
+
}
|
|
22649
|
+
},
|
|
22025
22650
|
// Codex's resumes too, which `continue` doesn't arm itself.
|
|
22026
22651
|
hostOf: (id) => adapters.get(id),
|
|
22027
22652
|
hosts: CLOSED_HOSTS,
|
|
@@ -22041,11 +22666,12 @@ async function runContinueCommand(env, mode, cancelId) {
|
|
|
22041
22666
|
err: (t) => process.stderr.write(t),
|
|
22042
22667
|
ask: prompt
|
|
22043
22668
|
});
|
|
22669
|
+
return interrupted && !sentAnyway ? 130 : code2;
|
|
22044
22670
|
}
|
|
22045
22671
|
function previewNames(env) {
|
|
22046
22672
|
return installedPreviews(env, homedir23(), stateDir(env)).map((id) => PREVIEW_NAMES[id] ?? id);
|
|
22047
22673
|
}
|
|
22048
|
-
var INSTALL_PLACES, KNOWN_OPTIONS, TIMER_PLACES;
|
|
22674
|
+
var INSTALL_PLACES, KNOWN_OPTIONS, WAITING_STATES, CONTINUE_USAGE, TIMER_PLACES;
|
|
22049
22675
|
var init_cli2 = __esm({
|
|
22050
22676
|
"src/cli.ts"() {
|
|
22051
22677
|
"use strict";
|
|
@@ -22120,6 +22746,8 @@ var init_cli2 = __esm({
|
|
|
22120
22746
|
schedules: ["--all", "--json", "--explain"],
|
|
22121
22747
|
history: ["--days"]
|
|
22122
22748
|
};
|
|
22749
|
+
WAITING_STATES = /* @__PURE__ */ new Set(["scheduled", "waiting_for_limit"]);
|
|
22750
|
+
CONTINUE_USAGE = "agent-rewake: usage: agent-rewake continue [--always | --ask | --cancel [<id>] | --now [<id>] [--yes]]\n";
|
|
22123
22751
|
TIMER_PLACES = /* @__PURE__ */ new Set([
|
|
22124
22752
|
"codex",
|
|
22125
22753
|
"copilot-cli",
|