@codizelabs/agent-rewake 0.3.0 → 0.3.1
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 +3 -2
- package/dist/agent-rewake.js +613 -478
- package/dist/hosts/claude-code/.claude-plugin/plugin.json +1 -1
- package/package.json +1 -1
package/dist/agent-rewake.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
4
|
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
5
|
-
import { existsSync as
|
|
5
|
+
import { existsSync as existsSync24, readdirSync as readdirSync14, readFileSync as readFileSync32 } from "node:fs";
|
|
6
6
|
import { homedir as homedir19 } from "node:os";
|
|
7
|
-
import { join as
|
|
7
|
+
import { join as join38 } from "node:path";
|
|
8
8
|
import { createInterface as createInterface6 } from "node:readline/promises";
|
|
9
9
|
|
|
10
10
|
// src/adapters/claude/spawn.ts
|
|
@@ -32,7 +32,7 @@ function claudeAdapterCommand(extraArgs, env) {
|
|
|
32
32
|
// src/addon.ts
|
|
33
33
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
34
34
|
import { watch, writeFileSync as writeFileSync3 } from "node:fs";
|
|
35
|
-
import { join as
|
|
35
|
+
import { join as join29 } from "node:path";
|
|
36
36
|
import { pathToFileURL } from "node:url";
|
|
37
37
|
|
|
38
38
|
// src/acp/ndjson.ts
|
|
@@ -287,10 +287,22 @@ function kindOf(m) {
|
|
|
287
287
|
// src/adapters/claude/sources.ts
|
|
288
288
|
import { closeSync as closeSync2, constants, fstatSync, openSync as openSync2, readdirSync, readSync } from "node:fs";
|
|
289
289
|
import { homedir, platform } from "node:os";
|
|
290
|
-
import { join as
|
|
290
|
+
import { join as join3, win32 } from "node:path";
|
|
291
291
|
|
|
292
292
|
// src/util/fs.ts
|
|
293
|
-
import {
|
|
293
|
+
import { randomBytes } from "node:crypto";
|
|
294
|
+
import {
|
|
295
|
+
closeSync,
|
|
296
|
+
fsyncSync,
|
|
297
|
+
mkdtempSync,
|
|
298
|
+
openSync,
|
|
299
|
+
readFileSync as readFileSync2,
|
|
300
|
+
renameSync,
|
|
301
|
+
rmSync,
|
|
302
|
+
writeSync
|
|
303
|
+
} from "node:fs";
|
|
304
|
+
import { tmpdir } from "node:os";
|
|
305
|
+
import { basename, dirname as dirname2, join as join2 } from "node:path";
|
|
294
306
|
var RETRYABLE = /* @__PURE__ */ new Set(["EPERM", "EACCES", "EBUSY"]);
|
|
295
307
|
function sleepSync(ms) {
|
|
296
308
|
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
@@ -326,10 +338,55 @@ function fsyncDir(dir, p = process.platform) {
|
|
|
326
338
|
var stripBom = (text2) => text2.charCodeAt(0) === 65279 ? text2.slice(1) : text2;
|
|
327
339
|
var readText = (file) => stripBom(readFileSync2(file, "utf8"));
|
|
328
340
|
var readJsonFile = (file) => JSON.parse(readText(file));
|
|
341
|
+
function writeTempExclusive(target, data, mode) {
|
|
342
|
+
const tmp = join2(
|
|
343
|
+
dirname2(target),
|
|
344
|
+
`.${basename(target)}.agent-rewake.${process.pid}.${randomBytes(8).toString("hex")}.tmp`
|
|
345
|
+
);
|
|
346
|
+
const fd = openSync(tmp, "wx", mode);
|
|
347
|
+
try {
|
|
348
|
+
writeSync(fd, data);
|
|
349
|
+
fsyncSync(fd);
|
|
350
|
+
} catch (err) {
|
|
351
|
+
closeSync(fd);
|
|
352
|
+
rmSync(tmp, { force: true });
|
|
353
|
+
throw err;
|
|
354
|
+
}
|
|
355
|
+
closeSync(fd);
|
|
356
|
+
return tmp;
|
|
357
|
+
}
|
|
358
|
+
function replaceFileExclusive(target, data, mode) {
|
|
359
|
+
const tmp = writeTempExclusive(target, data, mode);
|
|
360
|
+
try {
|
|
361
|
+
renameWithRetry(tmp, target);
|
|
362
|
+
} catch (err) {
|
|
363
|
+
rmSync(tmp, { force: true });
|
|
364
|
+
throw err;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
function privateTempFile(prefix, name, data) {
|
|
368
|
+
const dir = mkdtempSync(join2(tmpdir(), prefix));
|
|
369
|
+
const path = join2(dir, name);
|
|
370
|
+
const fd = openSync(path, "wx", 384);
|
|
371
|
+
try {
|
|
372
|
+
writeSync(fd, data);
|
|
373
|
+
} finally {
|
|
374
|
+
closeSync(fd);
|
|
375
|
+
}
|
|
376
|
+
return {
|
|
377
|
+
path,
|
|
378
|
+
remove: () => {
|
|
379
|
+
try {
|
|
380
|
+
rmSync(dir, { recursive: true, force: true });
|
|
381
|
+
} catch {
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
}
|
|
329
386
|
|
|
330
387
|
// src/adapters/claude/sources.ts
|
|
331
388
|
function claudeConfigDir(env) {
|
|
332
|
-
return env.CLAUDE_CONFIG_DIR ??
|
|
389
|
+
return env.CLAUDE_CONFIG_DIR ?? join3(homedir(), ".claude");
|
|
333
390
|
}
|
|
334
391
|
function encodeProjectDir(cwd) {
|
|
335
392
|
return cwd.replace(/[^a-zA-Z0-9]/g, "-");
|
|
@@ -337,11 +394,11 @@ function encodeProjectDir(cwd) {
|
|
|
337
394
|
var TAIL_BYTES = 256 * 1024;
|
|
338
395
|
function resetFromTranscript(env, cwd, sessionId, since) {
|
|
339
396
|
if (!/^[0-9a-zA-Z-]+$/.test(sessionId)) return void 0;
|
|
340
|
-
const projects =
|
|
341
|
-
const candidates = [
|
|
397
|
+
const projects = join3(claudeConfigDir(env), "projects");
|
|
398
|
+
const candidates = [join3(projects, encodeProjectDir(cwd), `${sessionId}.jsonl`)];
|
|
342
399
|
try {
|
|
343
400
|
for (const dir of readdirSync(projects))
|
|
344
|
-
candidates.push(
|
|
401
|
+
candidates.push(join3(projects, dir, `${sessionId}.jsonl`));
|
|
345
402
|
} catch {
|
|
346
403
|
return void 0;
|
|
347
404
|
}
|
|
@@ -398,8 +455,8 @@ function managedSettingsFiles(env, p = platform()) {
|
|
|
398
455
|
function claudeAutoContinueDisabled(env, cwd) {
|
|
399
456
|
const files = [
|
|
400
457
|
...managedSettingsFiles(env),
|
|
401
|
-
|
|
402
|
-
...cwd ? [
|
|
458
|
+
join3(claudeConfigDir(env), "settings.json"),
|
|
459
|
+
...cwd ? [join3(cwd, ".claude", "settings.json"), join3(cwd, ".claude", "settings.local.json")] : []
|
|
403
460
|
];
|
|
404
461
|
return files.some((f) => {
|
|
405
462
|
try {
|
|
@@ -1840,9 +1897,9 @@ function capitalize(s) {
|
|
|
1840
1897
|
|
|
1841
1898
|
// src/core/lock.ts
|
|
1842
1899
|
import { createHash } from "node:crypto";
|
|
1843
|
-
import { closeSync as closeSync3, openSync as openSync3, readFileSync as readFileSync3, rmSync, statSync, writeSync } from "node:fs";
|
|
1900
|
+
import { closeSync as closeSync3, openSync as openSync3, readFileSync as readFileSync3, rmSync as rmSync2, statSync, writeSync as writeSync2 } from "node:fs";
|
|
1844
1901
|
import { hostname } from "node:os";
|
|
1845
|
-
import { join as
|
|
1902
|
+
import { join as join4 } from "node:path";
|
|
1846
1903
|
|
|
1847
1904
|
// src/util/paths.ts
|
|
1848
1905
|
import { existsSync, mkdirSync } from "node:fs";
|
|
@@ -1927,7 +1984,7 @@ function isProcessAlive(pid) {
|
|
|
1927
1984
|
var SessionLock = class {
|
|
1928
1985
|
constructor(stateDir2, alive = isProcessAlive) {
|
|
1929
1986
|
this.alive = alive;
|
|
1930
|
-
this.dir =
|
|
1987
|
+
this.dir = join4(stateDir2, "locks");
|
|
1931
1988
|
}
|
|
1932
1989
|
alive;
|
|
1933
1990
|
dir;
|
|
@@ -1935,7 +1992,7 @@ var SessionLock = class {
|
|
|
1935
1992
|
held = /* @__PURE__ */ new Set();
|
|
1936
1993
|
path(sessionId) {
|
|
1937
1994
|
const h = createHash("sha256").update(sessionId).digest("hex").slice(0, 32);
|
|
1938
|
-
return
|
|
1995
|
+
return join4(this.dir, `${h}.lock`);
|
|
1939
1996
|
}
|
|
1940
1997
|
holds(sessionId) {
|
|
1941
1998
|
return this.held.has(sessionId);
|
|
@@ -1953,7 +2010,7 @@ var SessionLock = class {
|
|
|
1953
2010
|
token: this.token,
|
|
1954
2011
|
createdAt: Date.now()
|
|
1955
2012
|
};
|
|
1956
|
-
|
|
2013
|
+
writeSync2(fd, JSON.stringify(owner));
|
|
1957
2014
|
closeSync3(fd);
|
|
1958
2015
|
this.held.add(sessionId);
|
|
1959
2016
|
return true;
|
|
@@ -1964,7 +2021,7 @@ var SessionLock = class {
|
|
|
1964
2021
|
if (!owner && youngerThan(path, UNREADABLE_GRACE_MS)) return false;
|
|
1965
2022
|
try {
|
|
1966
2023
|
renameWithRetry(path, `${path}.stale.${this.token}`);
|
|
1967
|
-
|
|
2024
|
+
rmSync2(`${path}.stale.${this.token}`, { force: true });
|
|
1968
2025
|
} catch {
|
|
1969
2026
|
return false;
|
|
1970
2027
|
}
|
|
@@ -1975,7 +2032,7 @@ var SessionLock = class {
|
|
|
1975
2032
|
release(sessionId) {
|
|
1976
2033
|
if (!this.held.delete(sessionId)) return;
|
|
1977
2034
|
const path = this.path(sessionId);
|
|
1978
|
-
if (readOwner(path)?.token === this.token)
|
|
2035
|
+
if (readOwner(path)?.token === this.token) rmSync2(path, { force: true });
|
|
1979
2036
|
}
|
|
1980
2037
|
releaseAll() {
|
|
1981
2038
|
for (const s of [...this.held]) this.release(s);
|
|
@@ -2066,8 +2123,8 @@ function withValue(options, id, value) {
|
|
|
2066
2123
|
|
|
2067
2124
|
// src/core/requests.ts
|
|
2068
2125
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
2069
|
-
import { readdirSync as readdirSync3, readFileSync as readFileSync5, rmSync as
|
|
2070
|
-
import { join as
|
|
2126
|
+
import { readdirSync as readdirSync3, readFileSync as readFileSync5, rmSync as rmSync4 } from "node:fs";
|
|
2127
|
+
import { join as join6 } from "node:path";
|
|
2071
2128
|
|
|
2072
2129
|
// src/core/store.ts
|
|
2073
2130
|
import { randomUUID } from "node:crypto";
|
|
@@ -2077,10 +2134,11 @@ import {
|
|
|
2077
2134
|
openSync as openSync4,
|
|
2078
2135
|
readdirSync as readdirSync2,
|
|
2079
2136
|
readFileSync as readFileSync4,
|
|
2080
|
-
rmSync as
|
|
2081
|
-
writeSync as
|
|
2137
|
+
rmSync as rmSync3,
|
|
2138
|
+
writeSync as writeSync3
|
|
2082
2139
|
} from "node:fs";
|
|
2083
|
-
import { join as
|
|
2140
|
+
import { join as join5 } from "node:path";
|
|
2141
|
+
var PAUSE = new Int32Array(new SharedArrayBuffer(4));
|
|
2084
2142
|
var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
2085
2143
|
"sent",
|
|
2086
2144
|
"failed",
|
|
@@ -2131,22 +2189,24 @@ function validateSchedule(value) {
|
|
|
2131
2189
|
return ok ? value : void 0;
|
|
2132
2190
|
}
|
|
2133
2191
|
function writeFileAtomic(dir, name, data) {
|
|
2134
|
-
const tmp =
|
|
2192
|
+
const tmp = join5(dir, `.${name}.${process.pid}.${randomUUID().slice(0, 8)}.tmp`);
|
|
2135
2193
|
const fd = openSync4(tmp, "wx", 384);
|
|
2136
2194
|
try {
|
|
2137
|
-
|
|
2195
|
+
writeSync3(fd, data);
|
|
2138
2196
|
fsyncSync2(fd);
|
|
2139
2197
|
} finally {
|
|
2140
2198
|
closeSync4(fd);
|
|
2141
2199
|
}
|
|
2142
|
-
renameWithRetry(tmp,
|
|
2200
|
+
renameWithRetry(tmp, join5(dir, name));
|
|
2143
2201
|
fsyncDir(dir);
|
|
2144
2202
|
}
|
|
2145
2203
|
var ScheduleStore = class {
|
|
2146
|
-
dir;
|
|
2147
2204
|
constructor(stateDir2) {
|
|
2148
|
-
this.
|
|
2205
|
+
this.stateDir = stateDir2;
|
|
2206
|
+
this.dir = join5(stateDir2, "schedules");
|
|
2149
2207
|
}
|
|
2208
|
+
stateDir;
|
|
2209
|
+
dir;
|
|
2150
2210
|
ensure() {
|
|
2151
2211
|
return ensurePrivateDir(this.dir);
|
|
2152
2212
|
}
|
|
@@ -2184,7 +2244,7 @@ var ScheduleStore = class {
|
|
|
2184
2244
|
if (!/^[0-9a-f-]{36}$/.test(scheduleId)) return void 0;
|
|
2185
2245
|
try {
|
|
2186
2246
|
return validateSchedule(
|
|
2187
|
-
JSON.parse(readFileSync4(
|
|
2247
|
+
JSON.parse(readFileSync4(join5(this.dir, `${scheduleId}.json`), "utf8"))
|
|
2188
2248
|
);
|
|
2189
2249
|
} catch {
|
|
2190
2250
|
return void 0;
|
|
@@ -2216,17 +2276,51 @@ var ScheduleStore = class {
|
|
|
2216
2276
|
}
|
|
2217
2277
|
remove(scheduleId) {
|
|
2218
2278
|
if (!this.get(scheduleId)) return false;
|
|
2219
|
-
|
|
2279
|
+
rmSync3(join5(this.dir, `${scheduleId}.json`), { force: true });
|
|
2220
2280
|
return true;
|
|
2221
2281
|
}
|
|
2222
|
-
/**
|
|
2282
|
+
/**
|
|
2283
|
+
* Update a schedule if it still exists. Returns the updated copy, or the current one when
|
|
2284
|
+
* `change` returns undefined (nothing to change). The read and the write hold a short lock, so a
|
|
2285
|
+
* change made by another process at the same moment (a cancel while `fire` decides) isn't lost.
|
|
2286
|
+
*/
|
|
2223
2287
|
update(scheduleId, change, now) {
|
|
2224
|
-
const
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2288
|
+
const lock = new SessionLock(this.stateDir);
|
|
2289
|
+
const key2 = `write:${scheduleId}`;
|
|
2290
|
+
let held = lock.acquire(key2);
|
|
2291
|
+
for (let i = 0; !held && i < 200; i++) {
|
|
2292
|
+
Atomics.wait(PAUSE, 0, 0, 10);
|
|
2293
|
+
held = lock.acquire(key2);
|
|
2294
|
+
}
|
|
2295
|
+
try {
|
|
2296
|
+
const current = this.get(scheduleId);
|
|
2297
|
+
if (!current) return void 0;
|
|
2298
|
+
const changed = change(current);
|
|
2299
|
+
if (!changed) return current;
|
|
2300
|
+
const next = { ...changed, updatedAt: now };
|
|
2301
|
+
if (!validateSchedule(next)) throw new Error("Invalid scheduled message after update.");
|
|
2302
|
+
this.put(next);
|
|
2303
|
+
return next;
|
|
2304
|
+
} finally {
|
|
2305
|
+
if (held) lock.release(key2);
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
/**
|
|
2309
|
+
* Cancel a planned message. One already being sent, or finished, is left as it is: returns
|
|
2310
|
+
* whether it was cancelled.
|
|
2311
|
+
*/
|
|
2312
|
+
cancel(scheduleId, now) {
|
|
2313
|
+
let done = false;
|
|
2314
|
+
this.update(
|
|
2315
|
+
scheduleId,
|
|
2316
|
+
(x) => {
|
|
2317
|
+
if (x.status === "sending" || TERMINAL_STATUSES.has(x.status)) return void 0;
|
|
2318
|
+
done = true;
|
|
2319
|
+
return { ...x, status: "cancelled" };
|
|
2320
|
+
},
|
|
2321
|
+
now
|
|
2322
|
+
);
|
|
2323
|
+
return done;
|
|
2230
2324
|
}
|
|
2231
2325
|
};
|
|
2232
2326
|
|
|
@@ -2234,7 +2328,7 @@ var ScheduleStore = class {
|
|
|
2234
2328
|
var RequestStore = class {
|
|
2235
2329
|
dir;
|
|
2236
2330
|
constructor(stateDir2) {
|
|
2237
|
-
this.dir =
|
|
2331
|
+
this.dir = join6(stateDir2, "requests");
|
|
2238
2332
|
}
|
|
2239
2333
|
create(input) {
|
|
2240
2334
|
const r = {
|
|
@@ -2256,7 +2350,7 @@ var RequestStore = class {
|
|
|
2256
2350
|
if (!/^[0-9a-f-]{36}$/.test(requestId)) return void 0;
|
|
2257
2351
|
try {
|
|
2258
2352
|
const r = JSON.parse(
|
|
2259
|
-
readFileSync5(
|
|
2353
|
+
readFileSync5(join6(this.dir, `${requestId}.json`), "utf8")
|
|
2260
2354
|
);
|
|
2261
2355
|
return r.schemaVersion === 1 && r.requestId === requestId ? r : void 0;
|
|
2262
2356
|
} catch {
|
|
@@ -2274,13 +2368,13 @@ var RequestStore = class {
|
|
|
2274
2368
|
}
|
|
2275
2369
|
remove(requestId) {
|
|
2276
2370
|
if (/^[0-9a-f-]{36}$/.test(requestId))
|
|
2277
|
-
|
|
2371
|
+
rmSync4(join6(this.dir, `${requestId}.json`), { force: true });
|
|
2278
2372
|
}
|
|
2279
2373
|
};
|
|
2280
2374
|
var LinkStore = class {
|
|
2281
2375
|
dir;
|
|
2282
2376
|
constructor(stateDir2) {
|
|
2283
|
-
this.dir =
|
|
2377
|
+
this.dir = join6(stateDir2, "links");
|
|
2284
2378
|
}
|
|
2285
2379
|
set(token, sessionId, cwd) {
|
|
2286
2380
|
if (!/^[0-9a-f-]{36}$/.test(token)) return;
|
|
@@ -2294,7 +2388,7 @@ var LinkStore = class {
|
|
|
2294
2388
|
get(token) {
|
|
2295
2389
|
if (!/^[0-9a-f-]{36}$/.test(token)) return void 0;
|
|
2296
2390
|
try {
|
|
2297
|
-
const v = JSON.parse(readFileSync5(
|
|
2391
|
+
const v = JSON.parse(readFileSync5(join6(this.dir, `${token}.json`), "utf8"));
|
|
2298
2392
|
return typeof v.sessionId === "string" ? { sessionId: v.sessionId, cwd: String(v.cwd ?? "") } : void 0;
|
|
2299
2393
|
} catch {
|
|
2300
2394
|
return void 0;
|
|
@@ -2344,7 +2438,7 @@ function decideFire(c) {
|
|
|
2344
2438
|
|
|
2345
2439
|
// src/core/settings.ts
|
|
2346
2440
|
import { readFileSync as readFileSync6 } from "node:fs";
|
|
2347
|
-
import { join as
|
|
2441
|
+
import { join as join7 } from "node:path";
|
|
2348
2442
|
var DEFAULT_SETTINGS = {
|
|
2349
2443
|
clock: "12h",
|
|
2350
2444
|
newThreads: "ask",
|
|
@@ -2353,7 +2447,7 @@ var DEFAULT_SETTINGS = {
|
|
|
2353
2447
|
};
|
|
2354
2448
|
function loadSettings(stateDir2) {
|
|
2355
2449
|
try {
|
|
2356
|
-
const raw = JSON.parse(readFileSync6(
|
|
2450
|
+
const raw = JSON.parse(readFileSync6(join7(stateDir2, "settings.json"), "utf8"));
|
|
2357
2451
|
const clock2 = raw.clock === "12h" || raw.clock === "24h" ? raw.clock : DEFAULT_SETTINGS.clock;
|
|
2358
2452
|
const newThreads = raw.newThreads === "on" || raw.newThreads === "off" ? raw.newThreads : "ask";
|
|
2359
2453
|
const resumePrompt = typeof raw.resumePrompt === "string" && raw.resumePrompt.trim() && raw.resumePrompt.length <= 16384 ? raw.resumePrompt : void 0;
|
|
@@ -2386,13 +2480,13 @@ function applySettings(stateDir2) {
|
|
|
2386
2480
|
|
|
2387
2481
|
// src/core/threads.ts
|
|
2388
2482
|
import { createHash as createHash2 } from "node:crypto";
|
|
2389
|
-
import { readdirSync as readdirSync4, readFileSync as readFileSync7, rmSync as
|
|
2390
|
-
import { join as
|
|
2483
|
+
import { readdirSync as readdirSync4, readFileSync as readFileSync7, rmSync as rmSync5 } from "node:fs";
|
|
2484
|
+
import { join as join8 } from "node:path";
|
|
2391
2485
|
var DEFAULT_RESUME_PROMPT = "Resume the work from where you were interrupted. Agent Rewake sent this message after a usage limit reset, and nobody is here to answer questions or confirm anything until the work is done, so don't ask and don't wait: make the decisions yourself and keep going. Review the current state (latest git pull) and continue from the last completed step. Fully finish the task, including any remaining implementation, testing, fixes and verification. When something is unclear, re-read the task and the code first; otherwise choose the option that changes the least and can be undone, or skip that one item and carry on with the rest. Never invent facts or results, and don't take irreversible or outward-facing actions (deleting data, force-pushing, spending money, publishing) that weren't already asked for. Don't stop to announce your next step or to offer to continue; keep working until everything is complete and there are no known remaining issues. At the end, list the decisions you made on your own and any open questions.";
|
|
2392
2486
|
var ThreadStore = class {
|
|
2393
2487
|
dir;
|
|
2394
2488
|
constructor(stateDir2) {
|
|
2395
|
-
this.dir =
|
|
2489
|
+
this.dir = join8(stateDir2, "threads");
|
|
2396
2490
|
}
|
|
2397
2491
|
file(sessionId) {
|
|
2398
2492
|
return `${createHash2("sha256").update(sessionId).digest("hex").slice(0, 32)}.json`;
|
|
@@ -2400,7 +2494,7 @@ var ThreadStore = class {
|
|
|
2400
2494
|
get(sessionId) {
|
|
2401
2495
|
try {
|
|
2402
2496
|
const t = JSON.parse(
|
|
2403
|
-
readFileSync7(
|
|
2497
|
+
readFileSync7(join8(this.dir, this.file(sessionId)), "utf8")
|
|
2404
2498
|
);
|
|
2405
2499
|
const valid2 = t.schemaVersion === 1 && t.sessionId === sessionId && typeof t.autoResume === "boolean" && (t.resumePrompt === void 0 || typeof t.resumePrompt === "string" && Buffer.byteLength(t.resumePrompt) <= MAX_TEXT_BYTES);
|
|
2406
2500
|
return valid2 ? t : void 0;
|
|
@@ -2427,7 +2521,7 @@ var ThreadStore = class {
|
|
|
2427
2521
|
}
|
|
2428
2522
|
/** Forget a thread (it was deleted in Zed). */
|
|
2429
2523
|
remove(sessionId) {
|
|
2430
|
-
|
|
2524
|
+
rmSync5(join8(this.dir, this.file(sessionId)), { force: true });
|
|
2431
2525
|
}
|
|
2432
2526
|
/** Every thread Rewake has seen, most recently updated first. */
|
|
2433
2527
|
list() {
|
|
@@ -2441,7 +2535,7 @@ var ThreadStore = class {
|
|
|
2441
2535
|
for (const name of names) {
|
|
2442
2536
|
if (!name.endsWith(".json") || name.startsWith(".")) continue;
|
|
2443
2537
|
try {
|
|
2444
|
-
const t = JSON.parse(readFileSync7(
|
|
2538
|
+
const t = JSON.parse(readFileSync7(join8(this.dir, name), "utf8"));
|
|
2445
2539
|
const valid2 = typeof t.sessionId === "string" ? this.get(t.sessionId) : void 0;
|
|
2446
2540
|
if (valid2) out.push(valid2);
|
|
2447
2541
|
} catch {
|
|
@@ -2562,20 +2656,9 @@ Everything stays on the user's computer in Rewake's state folder (macOS: ~/Libra
|
|
|
2562
2656
|
`;
|
|
2563
2657
|
|
|
2564
2658
|
// src/install.ts
|
|
2565
|
-
import {
|
|
2566
|
-
chmodSync as chmodSync2,
|
|
2567
|
-
closeSync as closeSync7,
|
|
2568
|
-
copyFileSync,
|
|
2569
|
-
existsSync as existsSync17,
|
|
2570
|
-
fsyncSync as fsyncSync3,
|
|
2571
|
-
openSync as openSync8,
|
|
2572
|
-
readFileSync as readFileSync22,
|
|
2573
|
-
realpathSync as realpathSync5,
|
|
2574
|
-
statSync as statSync4,
|
|
2575
|
-
writeSync as writeSync3
|
|
2576
|
-
} from "node:fs";
|
|
2659
|
+
import { chmodSync as chmodSync2, copyFileSync, existsSync as existsSync18, readFileSync as readFileSync22, realpathSync as realpathSync5, statSync as statSync4 } from "node:fs";
|
|
2577
2660
|
import { homedir as homedir14, platform as platform3 } from "node:os";
|
|
2578
|
-
import {
|
|
2661
|
+
import { delimiter as delimiter2, dirname as dirname6, join as join27, posix as posix3, win32 as win325 } from "node:path";
|
|
2579
2662
|
import { createInterface as createInterface3 } from "node:readline/promises";
|
|
2580
2663
|
|
|
2581
2664
|
// node_modules/jsonc-parser/lib/esm/impl/scanner.js
|
|
@@ -3988,22 +4071,22 @@ function applyEdits(text2, edits) {
|
|
|
3988
4071
|
}
|
|
3989
4072
|
|
|
3990
4073
|
// src/hosts/previews.ts
|
|
3991
|
-
import { existsSync as
|
|
4074
|
+
import { existsSync as existsSync17 } from "node:fs";
|
|
3992
4075
|
|
|
3993
4076
|
// src/hosts/antigravity/install.ts
|
|
3994
|
-
import { existsSync as
|
|
4077
|
+
import { existsSync as existsSync6, rmSync as rmSync6 } from "node:fs";
|
|
3995
4078
|
import { homedir as homedir5 } from "node:os";
|
|
3996
|
-
import { join as
|
|
4079
|
+
import { join as join15 } from "node:path";
|
|
3997
4080
|
|
|
3998
4081
|
// src/install/detect.ts
|
|
3999
4082
|
import { existsSync as existsSync3, readdirSync as readdirSync5, readFileSync as readFileSync9, realpathSync, statSync as statSync2 } from "node:fs";
|
|
4000
|
-
import { delimiter, dirname as
|
|
4083
|
+
import { delimiter, dirname as dirname4, join as join10 } from "node:path";
|
|
4001
4084
|
|
|
4002
4085
|
// src/util/spawn.ts
|
|
4003
4086
|
import { spawnSync } from "node:child_process";
|
|
4004
4087
|
import { existsSync as existsSync2, readFileSync as readFileSync8 } from "node:fs";
|
|
4005
4088
|
import { platform as osPlatform2 } from "node:os";
|
|
4006
|
-
import { dirname as
|
|
4089
|
+
import { dirname as dirname3, join as join9, posix as posix2, win32 as win323 } from "node:path";
|
|
4007
4090
|
var defaultHost = () => ({
|
|
4008
4091
|
platform: osPlatform2(),
|
|
4009
4092
|
exists: existsSync2,
|
|
@@ -4072,8 +4155,8 @@ function npmScript(name, execPath = process.execPath, exists = existsSync2, p =
|
|
|
4072
4155
|
}
|
|
4073
4156
|
function killTree(child, p = osPlatform2(), signal = "SIGTERM") {
|
|
4074
4157
|
if (p === "win32" && child.pid !== void 0) {
|
|
4075
|
-
const taskkill =
|
|
4076
|
-
|
|
4158
|
+
const taskkill = join9(
|
|
4159
|
+
dirname3(process.env.ComSpec ?? "C:\\Windows\\System32\\cmd.exe"),
|
|
4077
4160
|
"taskkill.exe"
|
|
4078
4161
|
);
|
|
4079
4162
|
const r = spawnSync(
|
|
@@ -4134,18 +4217,18 @@ function onPath(command, h) {
|
|
|
4134
4217
|
const path = h.env.PATH ?? "";
|
|
4135
4218
|
return [
|
|
4136
4219
|
...new Set(
|
|
4137
|
-
path.split(delimiter).filter(Boolean).map((dir) =>
|
|
4220
|
+
path.split(delimiter).filter(Boolean).map((dir) => join10(dir, command)).filter(isFile)
|
|
4138
4221
|
)
|
|
4139
4222
|
];
|
|
4140
4223
|
}
|
|
4141
4224
|
function npmVersion(program, name) {
|
|
4142
4225
|
let file = realpath(program);
|
|
4143
4226
|
if (/\.(cmd|bat)$/i.test(file)) file = npmShimTarget(file) ?? file;
|
|
4144
|
-
let dir =
|
|
4227
|
+
let dir = dirname4(file);
|
|
4145
4228
|
for (let i = 0; i < 6; i++) {
|
|
4146
|
-
const pkg2 = readJson(
|
|
4229
|
+
const pkg2 = readJson(join10(dir, "package.json"));
|
|
4147
4230
|
if (pkg2?.name === name && typeof pkg2.version === "string") return pkg2.version;
|
|
4148
|
-
const parent =
|
|
4231
|
+
const parent = dirname4(dir);
|
|
4149
4232
|
if (parent === dir) break;
|
|
4150
4233
|
dir = parent;
|
|
4151
4234
|
}
|
|
@@ -4153,7 +4236,7 @@ function npmVersion(program, name) {
|
|
|
4153
4236
|
}
|
|
4154
4237
|
function appVersion(app) {
|
|
4155
4238
|
try {
|
|
4156
|
-
const plist = readFileSync9(
|
|
4239
|
+
const plist = readFileSync9(join10(app, "Contents", "Info.plist"), "utf8");
|
|
4157
4240
|
return /<key>CFBundleShortVersionString<\/key>\s*<string>([^<]+)<\/string>/.exec(plist)?.[1];
|
|
4158
4241
|
} catch {
|
|
4159
4242
|
return void 0;
|
|
@@ -4161,8 +4244,8 @@ function appVersion(app) {
|
|
|
4161
4244
|
}
|
|
4162
4245
|
function apps(h, name) {
|
|
4163
4246
|
if (h.platform !== "darwin") return [];
|
|
4164
|
-
const dirs = h.appDirs ?? ["/Applications",
|
|
4165
|
-
return dirs.map((d) =>
|
|
4247
|
+
const dirs = h.appDirs ?? ["/Applications", join10(h.home, "Applications")];
|
|
4248
|
+
return dirs.map((d) => join10(d, `${name}.app`)).filter((a) => existsSync3(a));
|
|
4166
4249
|
}
|
|
4167
4250
|
function programs(command, h, extra) {
|
|
4168
4251
|
const exe = h.platform === "win32" ? [".exe", ".cmd"] : [""];
|
|
@@ -4179,7 +4262,7 @@ function versionInPath(program, pattern) {
|
|
|
4179
4262
|
return pattern.exec(realpath(program))?.[1];
|
|
4180
4263
|
}
|
|
4181
4264
|
function claudePrograms(h) {
|
|
4182
|
-
const local =
|
|
4265
|
+
const local = join10(h.home, ".local", "bin", "claude");
|
|
4183
4266
|
return programs("claude", h, [local]).map((path) => {
|
|
4184
4267
|
const version = versionInPath(path, /[\\/]versions[\\/](\d+\.\d+\.\d+)/) ?? npmVersion(path, "@anthropic-ai/claude-code");
|
|
4185
4268
|
return { path, surface: "terminal", ...version && { version } };
|
|
@@ -4187,7 +4270,7 @@ function claudePrograms(h) {
|
|
|
4187
4270
|
}
|
|
4188
4271
|
function claudeDesktopPrograms(h) {
|
|
4189
4272
|
if (h.platform !== "darwin") return [];
|
|
4190
|
-
const root =
|
|
4273
|
+
const root = join10(h.home, "Library", "Application Support", "Claude", "claude-code");
|
|
4191
4274
|
const out = [];
|
|
4192
4275
|
let names = [];
|
|
4193
4276
|
try {
|
|
@@ -4198,13 +4281,13 @@ function claudeDesktopPrograms(h) {
|
|
|
4198
4281
|
for (const version of names) {
|
|
4199
4282
|
let builds = [];
|
|
4200
4283
|
try {
|
|
4201
|
-
builds = readdirSync5(
|
|
4284
|
+
builds = readdirSync5(join10(root, version));
|
|
4202
4285
|
} catch {
|
|
4203
4286
|
continue;
|
|
4204
4287
|
}
|
|
4205
4288
|
for (const b of builds) {
|
|
4206
|
-
const path =
|
|
4207
|
-
if (existsSync3(
|
|
4289
|
+
const path = join10(root, version, b, "claude.app", "Contents", "MacOS", "claude");
|
|
4290
|
+
if (existsSync3(join10(root, version, b, ".verified")) && isFile(path))
|
|
4208
4291
|
out.push({ path, surface: "desktop app", version });
|
|
4209
4292
|
}
|
|
4210
4293
|
}
|
|
@@ -4216,7 +4299,7 @@ function claudeCode(h) {
|
|
|
4216
4299
|
const versions = cli.map((p) => p.version);
|
|
4217
4300
|
const desktop = [];
|
|
4218
4301
|
if (h.platform === "darwin") {
|
|
4219
|
-
const root =
|
|
4302
|
+
const root = join10(h.home, "Library", "Application Support", "Claude", "claude-code");
|
|
4220
4303
|
let names = [];
|
|
4221
4304
|
try {
|
|
4222
4305
|
names = readdirSync5(root).filter((n) => VERSION.test(n));
|
|
@@ -4225,11 +4308,11 @@ function claudeCode(h) {
|
|
|
4225
4308
|
for (const v of names) {
|
|
4226
4309
|
let builds = [];
|
|
4227
4310
|
try {
|
|
4228
|
-
builds = readdirSync5(
|
|
4311
|
+
builds = readdirSync5(join10(root, v));
|
|
4229
4312
|
} catch {
|
|
4230
4313
|
continue;
|
|
4231
4314
|
}
|
|
4232
|
-
if (builds.some((b) => existsSync3(
|
|
4315
|
+
if (builds.some((b) => existsSync3(join10(root, v, b, "claude.app")))) desktop.push(v);
|
|
4233
4316
|
}
|
|
4234
4317
|
}
|
|
4235
4318
|
if (bins.length === 0 && desktop.length === 0) return void 0;
|
|
@@ -4245,22 +4328,22 @@ function claudeCode(h) {
|
|
|
4245
4328
|
};
|
|
4246
4329
|
}
|
|
4247
4330
|
function codexPrograms(h) {
|
|
4248
|
-
const dir = h.env.CODEX_INSTALL_DIR ||
|
|
4331
|
+
const dir = h.env.CODEX_INSTALL_DIR || join10(h.home, ".local", "bin");
|
|
4249
4332
|
const localAppData = h.env.LOCALAPPDATA;
|
|
4250
4333
|
const bins = programs("codex", h, [
|
|
4251
|
-
|
|
4252
|
-
...h.platform === "win32" && localAppData ? [
|
|
4334
|
+
join10(dir, "codex"),
|
|
4335
|
+
...h.platform === "win32" && localAppData ? [join10(localAppData, "Programs", "OpenAI", "Codex", "bin", "codex")] : []
|
|
4253
4336
|
]);
|
|
4254
4337
|
const found = bins.map((path) => {
|
|
4255
4338
|
const version = npmVersion(path, "@openai/codex") ?? versionInPath(path, /[\\/]Caskroom[\\/]codex[\\/]([\d.]+)/);
|
|
4256
4339
|
return { path, surface: "terminal", ...version && { version } };
|
|
4257
4340
|
});
|
|
4258
4341
|
for (const app of apps(h, "ChatGPT")) {
|
|
4259
|
-
const d =
|
|
4342
|
+
const d = join10(app, "Contents", "Resources", "codex-cli");
|
|
4260
4343
|
if (!existsSync3(d)) continue;
|
|
4261
|
-
const v = readJson(
|
|
4344
|
+
const v = readJson(join10(d, "codex-package.json"))?.version;
|
|
4262
4345
|
found.push({
|
|
4263
|
-
path:
|
|
4346
|
+
path: join10(d, "bin", "codex"),
|
|
4264
4347
|
surface: "ChatGPT app",
|
|
4265
4348
|
...typeof v === "string" && { version: v }
|
|
4266
4349
|
});
|
|
@@ -4281,8 +4364,8 @@ function codex(h) {
|
|
|
4281
4364
|
function copilotPrograms(h) {
|
|
4282
4365
|
const appData = h.env.APPDATA;
|
|
4283
4366
|
const extra = [
|
|
4284
|
-
|
|
4285
|
-
...h.platform === "win32" && appData ? [
|
|
4367
|
+
join10(h.home, ".local", "bin", "copilot"),
|
|
4368
|
+
...h.platform === "win32" && appData ? [join10(appData, "npm", "copilot")] : []
|
|
4286
4369
|
];
|
|
4287
4370
|
return programs("copilot", h, extra).map((path) => {
|
|
4288
4371
|
const version = npmVersion(path, "@github/copilot");
|
|
@@ -4290,15 +4373,15 @@ function copilotPrograms(h) {
|
|
|
4290
4373
|
});
|
|
4291
4374
|
}
|
|
4292
4375
|
function grokPrograms(h) {
|
|
4293
|
-
const grokBin = h.env.GROK_BIN_DIR ||
|
|
4294
|
-
return programs("grok", h, [
|
|
4376
|
+
const grokBin = h.env.GROK_BIN_DIR || join10(h.home, ".grok", "bin");
|
|
4377
|
+
return programs("grok", h, [join10(grokBin, "grok")]).map((path) => {
|
|
4295
4378
|
const version = npmVersion(path, "@xai-official/grok") ?? versionInPath(path, /[\\/]grok-(\d+\.\d+\.\d+)/);
|
|
4296
4379
|
return { path, surface: "terminal", ...version && { version } };
|
|
4297
4380
|
});
|
|
4298
4381
|
}
|
|
4299
4382
|
function geminiPrograms(h) {
|
|
4300
4383
|
const appData = h.env.APPDATA;
|
|
4301
|
-
const extra = h.platform === "win32" && appData ? [
|
|
4384
|
+
const extra = h.platform === "win32" && appData ? [join10(appData, "npm", "gemini")] : [];
|
|
4302
4385
|
return programs("gemini", h, extra).map((path) => {
|
|
4303
4386
|
const version = npmVersion(path, "@google/gemini-cli");
|
|
4304
4387
|
return { path, surface: "terminal", ...version && { version } };
|
|
@@ -4307,8 +4390,8 @@ function geminiPrograms(h) {
|
|
|
4307
4390
|
function agyPrograms(h) {
|
|
4308
4391
|
const localAppData = h.env.LOCALAPPDATA;
|
|
4309
4392
|
return programs("agy", h, [
|
|
4310
|
-
|
|
4311
|
-
...h.platform === "win32" && localAppData ? [
|
|
4393
|
+
join10(h.home, ".local", "bin", "agy"),
|
|
4394
|
+
...h.platform === "win32" && localAppData ? [join10(localAppData, "agy", "bin", "agy")] : []
|
|
4312
4395
|
]).map((path) => ({ path, surface: "terminal" }));
|
|
4313
4396
|
}
|
|
4314
4397
|
function simpleCli(h, id, name, command, pkg2, extra, pathVersion) {
|
|
@@ -4324,8 +4407,8 @@ function simpleCli(h, id, name, command, pkg2, extra, pathVersion) {
|
|
|
4324
4407
|
function antigravity(h) {
|
|
4325
4408
|
const localAppData = h.env.LOCALAPPDATA;
|
|
4326
4409
|
const bins = programs("agy", h, [
|
|
4327
|
-
|
|
4328
|
-
...h.platform === "win32" && localAppData ? [
|
|
4410
|
+
join10(h.home, ".local", "bin", "agy"),
|
|
4411
|
+
...h.platform === "win32" && localAppData ? [join10(localAppData, "agy", "bin", "agy")] : []
|
|
4329
4412
|
]);
|
|
4330
4413
|
const app = apps(h, "Antigravity");
|
|
4331
4414
|
const ide = apps(h, "Antigravity IDE");
|
|
@@ -4356,10 +4439,10 @@ function terminalAgents(h) {
|
|
|
4356
4439
|
});
|
|
4357
4440
|
}
|
|
4358
4441
|
function detectAgents(h) {
|
|
4359
|
-
const local = (cmd) =>
|
|
4360
|
-
const grokBin = h.env.GROK_BIN_DIR ||
|
|
4442
|
+
const local = (cmd) => join10(h.home, ".local", "bin", cmd);
|
|
4443
|
+
const grokBin = h.env.GROK_BIN_DIR || join10(h.home, ".grok", "bin");
|
|
4361
4444
|
const appData = h.env.APPDATA;
|
|
4362
|
-
const npmWin = (cmd) => h.platform === "win32" && appData ? [
|
|
4445
|
+
const npmWin = (cmd) => h.platform === "win32" && appData ? [join10(appData, "npm", cmd)] : [];
|
|
4363
4446
|
return [
|
|
4364
4447
|
claudeCode(h),
|
|
4365
4448
|
codex(h),
|
|
@@ -4373,7 +4456,7 @@ function detectAgents(h) {
|
|
|
4373
4456
|
"Grok Build",
|
|
4374
4457
|
"grok",
|
|
4375
4458
|
"@xai-official/grok",
|
|
4376
|
-
[
|
|
4459
|
+
[join10(grokBin, "grok")],
|
|
4377
4460
|
/[\\/]grok-(\d+\.\d+\.\d+)/
|
|
4378
4461
|
),
|
|
4379
4462
|
simpleCli(h, "gemini-cli", "Gemini CLI", "gemini", "@google/gemini-cli", npmWin("gemini")),
|
|
@@ -4394,7 +4477,7 @@ function otherAgentsNote(found, previews = []) {
|
|
|
4394
4477
|
|
|
4395
4478
|
// src/timers/launcher.ts
|
|
4396
4479
|
import { existsSync as existsSync4, readFileSync as readFileSync11, realpathSync as realpathSync2 } from "node:fs";
|
|
4397
|
-
import { join as
|
|
4480
|
+
import { join as join11 } from "node:path";
|
|
4398
4481
|
|
|
4399
4482
|
// src/version.ts
|
|
4400
4483
|
import { readFileSync as readFileSync10 } from "node:fs";
|
|
@@ -4409,12 +4492,12 @@ var pkg = (() => {
|
|
|
4409
4492
|
return {};
|
|
4410
4493
|
}
|
|
4411
4494
|
})();
|
|
4412
|
-
var VERSION2 = pkg.version ?? (true ? "0.3.
|
|
4495
|
+
var VERSION2 = pkg.version ?? (true ? "0.3.1" : "0.0.0");
|
|
4413
4496
|
var PACKAGE_NAME = pkg.name ?? "@codizelabs/agent-rewake";
|
|
4414
4497
|
|
|
4415
4498
|
// src/timers/launcher.ts
|
|
4416
4499
|
function launcherPath(stateDir2) {
|
|
4417
|
-
return
|
|
4500
|
+
return join11(stateDir2, "bin", "agent-rewake.mjs");
|
|
4418
4501
|
}
|
|
4419
4502
|
function ensureLauncher(stateDir2, bundle, version = VERSION2) {
|
|
4420
4503
|
const target = launcherPath(stateDir2);
|
|
@@ -4428,7 +4511,7 @@ function ensureLauncher(stateDir2, bundle, version = VERSION2) {
|
|
|
4428
4511
|
if (existsSync4(target) && realpathSync2(target) === source) return target;
|
|
4429
4512
|
const code = readFileSync11(source, "utf8");
|
|
4430
4513
|
const current = existsSync4(target) ? readFileSync11(target, "utf8") : void 0;
|
|
4431
|
-
const bin = ensurePrivateDir(
|
|
4514
|
+
const bin = ensurePrivateDir(join11(stateDir2, "bin"));
|
|
4432
4515
|
if (current !== code) writeFileAtomic(bin, "agent-rewake.mjs", code);
|
|
4433
4516
|
if (launcherVersion(stateDir2) !== version)
|
|
4434
4517
|
writeFileAtomic(bin, "agent-rewake.version", `${version}
|
|
@@ -4437,7 +4520,7 @@ function ensureLauncher(stateDir2, bundle, version = VERSION2) {
|
|
|
4437
4520
|
}
|
|
4438
4521
|
function launcherVersion(stateDir2) {
|
|
4439
4522
|
try {
|
|
4440
|
-
return readFileSync11(
|
|
4523
|
+
return readFileSync11(join11(stateDir2, "bin", "agent-rewake.version"), "utf8").trim() || void 0;
|
|
4441
4524
|
} catch {
|
|
4442
4525
|
return void 0;
|
|
4443
4526
|
}
|
|
@@ -4464,7 +4547,7 @@ function refreshLauncher(stateDir2, bundle, version) {
|
|
|
4464
4547
|
import { spawn as spawn2, spawnSync as spawnSync3 } from "node:child_process";
|
|
4465
4548
|
import { readFileSync as readFileSync13, writeFileSync } from "node:fs";
|
|
4466
4549
|
import { homedir as homedir4 } from "node:os";
|
|
4467
|
-
import { join as
|
|
4550
|
+
import { join as join14, resolve, sep } from "node:path";
|
|
4468
4551
|
|
|
4469
4552
|
// src/core/limits/agents.ts
|
|
4470
4553
|
var str2 = (v) => typeof v === "string" ? v : "";
|
|
@@ -4651,11 +4734,29 @@ function recogniseForHost(signal, now) {
|
|
|
4651
4734
|
}
|
|
4652
4735
|
|
|
4653
4736
|
// src/hosts/closed.ts
|
|
4654
|
-
import { basename as
|
|
4737
|
+
import { basename as basename3 } from "node:path";
|
|
4738
|
+
|
|
4739
|
+
// src/util/command.ts
|
|
4740
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
4741
|
+
import { join as join12 } from "node:path";
|
|
4742
|
+
var NPX_COMMAND = "npx @codizelabs/agent-rewake";
|
|
4743
|
+
var chosen;
|
|
4744
|
+
function rewakeOnPath(env = process.env, platform4 = process.platform) {
|
|
4745
|
+
const path = env.PATH ?? env.Path ?? "";
|
|
4746
|
+
const names = platform4 === "win32" ? ["agent-rewake.cmd", "agent-rewake.exe", "agent-rewake.ps1"] : ["agent-rewake"];
|
|
4747
|
+
return path.split(platform4 === "win32" ? ";" : ":").filter(Boolean).some((dir) => names.some((n) => existsSync5(join12(dir, n))));
|
|
4748
|
+
}
|
|
4749
|
+
function rewakeCommand() {
|
|
4750
|
+
chosen ??= rewakeOnPath() ? "agent-rewake" : NPX_COMMAND;
|
|
4751
|
+
return chosen;
|
|
4752
|
+
}
|
|
4753
|
+
function rewake(args) {
|
|
4754
|
+
return `${rewakeCommand()} ${args}`;
|
|
4755
|
+
}
|
|
4655
4756
|
|
|
4656
4757
|
// src/util/proc.ts
|
|
4657
4758
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
4658
|
-
import { basename } from "node:path";
|
|
4759
|
+
import { basename as basename2 } from "node:path";
|
|
4659
4760
|
var SHELLS = /* @__PURE__ */ new Set(["sh", "bash", "zsh", "dash", "fish", "ksh", "env", "timeout"]);
|
|
4660
4761
|
var ps = (pid) => {
|
|
4661
4762
|
const r = spawnSync2("ps", ["-o", "ppid=,comm=", "-p", String(pid)], {
|
|
@@ -4663,7 +4764,7 @@ var ps = (pid) => {
|
|
|
4663
4764
|
timeout: 2e3
|
|
4664
4765
|
});
|
|
4665
4766
|
const m = /^\s*(\d+)\s+(.+?)\s*$/.exec(r.stdout ?? "");
|
|
4666
|
-
return m ? { ppid: Number(m[1]), name:
|
|
4767
|
+
return m ? { ppid: Number(m[1]), name: basename2(m[2]).replace(/^-/, "") } : void 0;
|
|
4667
4768
|
};
|
|
4668
4769
|
function agentProcess(start = process.ppid, platform4 = process.platform, run3 = ps) {
|
|
4669
4770
|
if (platform4 === "win32") return void 0;
|
|
@@ -4684,8 +4785,8 @@ function stillRunning(p, alive = isProcessAlive, run3 = ps) {
|
|
|
4684
4785
|
|
|
4685
4786
|
// src/hosts/sessions.ts
|
|
4686
4787
|
import { readdirSync as readdirSync6, readFileSync as readFileSync12 } from "node:fs";
|
|
4687
|
-
import { join as
|
|
4688
|
-
var
|
|
4788
|
+
import { join as join13 } from "node:path";
|
|
4789
|
+
var PAUSE2 = new Int32Array(new SharedArrayBuffer(4));
|
|
4689
4790
|
var safeSessionId = (id) => typeof id === "string" && /^[A-Za-z0-9_-]{1,128}$/.test(id);
|
|
4690
4791
|
function valid(v, host) {
|
|
4691
4792
|
if (typeof v !== "object" || v === null) return false;
|
|
@@ -4696,7 +4797,7 @@ var SessionRecords = class {
|
|
|
4696
4797
|
constructor(stateDir2, host) {
|
|
4697
4798
|
this.stateDir = stateDir2;
|
|
4698
4799
|
this.host = host;
|
|
4699
|
-
this.dir =
|
|
4800
|
+
this.dir = join13(stateDir2, "hosts", host, "sessions");
|
|
4700
4801
|
}
|
|
4701
4802
|
stateDir;
|
|
4702
4803
|
host;
|
|
@@ -4704,7 +4805,7 @@ var SessionRecords = class {
|
|
|
4704
4805
|
get(sessionId) {
|
|
4705
4806
|
if (!safeSessionId(sessionId)) return void 0;
|
|
4706
4807
|
try {
|
|
4707
|
-
const v = JSON.parse(readFileSync12(
|
|
4808
|
+
const v = JSON.parse(readFileSync12(join13(this.dir, `${sessionId}.json`), "utf8"));
|
|
4708
4809
|
return valid(v, this.host) ? v : void 0;
|
|
4709
4810
|
} catch {
|
|
4710
4811
|
return void 0;
|
|
@@ -4725,7 +4826,7 @@ var SessionRecords = class {
|
|
|
4725
4826
|
const lock = new SessionLock(this.stateDir);
|
|
4726
4827
|
const key2 = `record:${this.host}:${sessionId}`;
|
|
4727
4828
|
const until = Date.now() + 2e3;
|
|
4728
|
-
while (!lock.acquire(key2) && Date.now() < until) Atomics.wait(
|
|
4829
|
+
while (!lock.acquire(key2) && Date.now() < until) Atomics.wait(PAUSE2, 0, 0, 20);
|
|
4729
4830
|
try {
|
|
4730
4831
|
return this.updateLocked(sessionId, cwd, now, change);
|
|
4731
4832
|
} finally {
|
|
@@ -4783,7 +4884,7 @@ function stillOpen(r, running = (p) => stillRunning(p)) {
|
|
|
4783
4884
|
return agents.length === 0 || agents.some(running);
|
|
4784
4885
|
}
|
|
4785
4886
|
function placeOf(host, cwd) {
|
|
4786
|
-
const folder = cwd ?
|
|
4887
|
+
const folder = cwd ? basename3(cwd) : "";
|
|
4787
4888
|
return folder ? `${host.name} in the "${folder}" folder` : host.name;
|
|
4788
4889
|
}
|
|
4789
4890
|
function pendingFor(stateDir2, host, sessionId) {
|
|
@@ -4807,7 +4908,7 @@ function autoFor(settings) {
|
|
|
4807
4908
|
function armedText(host, cwd, at, now) {
|
|
4808
4909
|
const keep = host.keepOpen ? ` ${host.keepOpen}` : "";
|
|
4809
4910
|
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.`;
|
|
4810
|
-
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:
|
|
4911
|
+
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")}`;
|
|
4811
4912
|
}
|
|
4812
4913
|
function armClosed(host, r, at, d) {
|
|
4813
4914
|
const store = new ScheduleStore(d.stateDir);
|
|
@@ -4871,8 +4972,7 @@ function onPrompt(host, sessionId, cwd, d) {
|
|
|
4871
4972
|
}));
|
|
4872
4973
|
const store = new ScheduleStore(d.stateDir);
|
|
4873
4974
|
for (const s of pendingFor(d.stateDir, host.id, sessionId)) {
|
|
4874
|
-
store.
|
|
4875
|
-
d.disarm(s.scheduleId);
|
|
4975
|
+
if (store.cancel(s.scheduleId, d.now)) d.disarm(s.scheduleId);
|
|
4876
4976
|
}
|
|
4877
4977
|
}
|
|
4878
4978
|
function onLimit(host, sessionId, cwd, limit, d) {
|
|
@@ -4910,7 +5010,7 @@ function onSessionEnd(host, sessionId, cwd, d) {
|
|
|
4910
5010
|
const how = limit.resetsAt ? `to continue it ${formatAt(limit.resetsAt + RESET_MARGIN_MS, d.now)}, after the limit resets` : "and choose when to continue it";
|
|
4911
5011
|
d.notify(
|
|
4912
5012
|
"Agent Rewake",
|
|
4913
|
-
`${placeOf(host, r.cwd)} hit its usage limit. Run "
|
|
5013
|
+
`${placeOf(host, r.cwd)} hit its usage limit. Run "${rewake("continue")}" ${how}.`
|
|
4914
5014
|
);
|
|
4915
5015
|
}
|
|
4916
5016
|
function followLaterReset(host, r, d) {
|
|
@@ -4921,8 +5021,7 @@ function followLaterReset(host, r, d) {
|
|
|
4921
5021
|
for (const s of pendingFor(d.stateDir, host.id, r.sessionId)) {
|
|
4922
5022
|
if (s.status !== "scheduled" || l.seenAt <= s.createdAt || at <= s.dueAt) continue;
|
|
4923
5023
|
if (l.resetsAt - d.now > FAR_RESET_MS) {
|
|
4924
|
-
store.
|
|
4925
|
-
d.disarm(s.scheduleId);
|
|
5024
|
+
if (store.cancel(s.scheduleId, d.now)) d.disarm(s.scheduleId);
|
|
4926
5025
|
continue;
|
|
4927
5026
|
}
|
|
4928
5027
|
store.update(s.scheduleId, (x) => ({ ...x, dueAt: at }), d.now);
|
|
@@ -5175,16 +5274,22 @@ function resumeDeadline(child, ms = RESUME_TIMEOUT_MS) {
|
|
|
5175
5274
|
child.once("error", () => clearTimeout(timer));
|
|
5176
5275
|
return () => stopped;
|
|
5177
5276
|
}
|
|
5277
|
+
function sendPromptOnStdin(child, text2) {
|
|
5278
|
+
if (!child.stdin) return;
|
|
5279
|
+
child.stdin.on("error", () => {
|
|
5280
|
+
});
|
|
5281
|
+
child.stdin.end(text2);
|
|
5282
|
+
}
|
|
5178
5283
|
|
|
5179
5284
|
// src/hosts/antigravity/host.ts
|
|
5180
5285
|
var ANTIGRAVITY_ID = "antigravity";
|
|
5181
5286
|
function geminiHome(env, home = homedir4()) {
|
|
5182
|
-
return env.GEMINI_HOME ||
|
|
5287
|
+
return env.GEMINI_HOME || join14(home, ".gemini");
|
|
5183
5288
|
}
|
|
5184
5289
|
function surfaceOf(transcriptPath, env, home) {
|
|
5185
5290
|
const g = geminiHome(env, home);
|
|
5186
5291
|
for (const s of ["antigravity-cli", "antigravity-ide", "antigravity-acp", "antigravity"])
|
|
5187
|
-
if (transcriptPath.startsWith(
|
|
5292
|
+
if (transcriptPath.startsWith(join14(g, s) + sep)) return s;
|
|
5188
5293
|
return "unknown";
|
|
5189
5294
|
}
|
|
5190
5295
|
var AGY = /(^|[\\/\s])agy(\.exe)?(\s|$)/i;
|
|
@@ -5259,8 +5364,8 @@ function appNotice(surface, resetsAt, now) {
|
|
|
5259
5364
|
return `Antigravity hit its usage limit in ${where2}.${when2} Rewake can't continue conversations there, so continue yours after the reset.`;
|
|
5260
5365
|
}
|
|
5261
5366
|
function firstNotice(stateDir2, id, resetsAt) {
|
|
5262
|
-
const dir = ensurePrivateDir(
|
|
5263
|
-
const file =
|
|
5367
|
+
const dir = ensurePrivateDir(join14(stateDir2, "hosts", ANTIGRAVITY_ID, "notified"));
|
|
5368
|
+
const file = join14(dir, `${id}.json`);
|
|
5264
5369
|
const key2 = String(resetsAt ?? "unknown");
|
|
5265
5370
|
try {
|
|
5266
5371
|
if (readFileSync13(file, "utf8") === key2) return false;
|
|
@@ -5319,7 +5424,7 @@ function antigravityHooks(deps) {
|
|
|
5319
5424
|
|
|
5320
5425
|
// src/hosts/antigravity/install.ts
|
|
5321
5426
|
function pluginDir(env, home) {
|
|
5322
|
-
return
|
|
5427
|
+
return join15(geminiHome(env, home), "config", "plugins", "agent-rewake");
|
|
5323
5428
|
}
|
|
5324
5429
|
function antigravityHooksJson(node, launcher) {
|
|
5325
5430
|
return `${JSON.stringify(
|
|
@@ -5338,7 +5443,7 @@ function antigravityHooksJson(node, launcher) {
|
|
|
5338
5443
|
async function runAntigravityInstall(o) {
|
|
5339
5444
|
const home = o.env.HOME || o.env.USERPROFILE || homedir5();
|
|
5340
5445
|
const dir = pluginDir(o.env, home);
|
|
5341
|
-
const installed =
|
|
5446
|
+
const installed = existsSync6(dir);
|
|
5342
5447
|
if (o.uninstall) {
|
|
5343
5448
|
if (!installed) {
|
|
5344
5449
|
o.out("Rewake isn't set up in Antigravity: nothing to remove.\n");
|
|
@@ -5384,7 +5489,7 @@ async function runAntigravityInstall(o) {
|
|
|
5384
5489
|
}
|
|
5385
5490
|
}
|
|
5386
5491
|
if (o.uninstall) {
|
|
5387
|
-
|
|
5492
|
+
rmSync6(dir, { recursive: true, force: true });
|
|
5388
5493
|
o.out("Done. Rewake is out of Antigravity.\n");
|
|
5389
5494
|
return 0;
|
|
5390
5495
|
}
|
|
@@ -5415,15 +5520,15 @@ async function runAntigravityInstall(o) {
|
|
|
5415
5520
|
import { execFile as execFile2 } from "node:child_process";
|
|
5416
5521
|
import {
|
|
5417
5522
|
cpSync,
|
|
5418
|
-
existsSync as
|
|
5419
|
-
mkdtempSync,
|
|
5523
|
+
existsSync as existsSync7,
|
|
5524
|
+
mkdtempSync as mkdtempSync2,
|
|
5420
5525
|
readdirSync as readdirSync7,
|
|
5421
5526
|
readFileSync as readFileSync14,
|
|
5422
5527
|
realpathSync as realpathSync4,
|
|
5423
|
-
rmSync as
|
|
5528
|
+
rmSync as rmSync7
|
|
5424
5529
|
} from "node:fs";
|
|
5425
|
-
import { homedir as homedir6, tmpdir } from "node:os";
|
|
5426
|
-
import { dirname as
|
|
5530
|
+
import { homedir as homedir6, tmpdir as tmpdir2 } from "node:os";
|
|
5531
|
+
import { dirname as dirname5, join as join16 } from "node:path";
|
|
5427
5532
|
|
|
5428
5533
|
// src/install/probe.ts
|
|
5429
5534
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
@@ -5456,7 +5561,7 @@ function withVersion(p, probe) {
|
|
|
5456
5561
|
return version ? { ...p, version } : p;
|
|
5457
5562
|
}
|
|
5458
5563
|
function unknownVersionText(agent, min, update, place) {
|
|
5459
|
-
return `Rewake couldn't tell which version of ${agent} you have. It needs ${min} or newer: if Rewake doesn't respond in ${agent}, update it with "${update}", then run "
|
|
5564
|
+
return `Rewake couldn't tell which version of ${agent} you have. It needs ${min} or newer: if Rewake doesn't respond in ${agent}, update it with "${update}", then run "${rewake(`install --only ${place}`)}" again.
|
|
5460
5565
|
`;
|
|
5461
5566
|
}
|
|
5462
5567
|
|
|
@@ -5502,7 +5607,7 @@ function newerThanTested(id, found) {
|
|
|
5502
5607
|
}
|
|
5503
5608
|
function untestedText(id, found) {
|
|
5504
5609
|
const v = versionOf(id);
|
|
5505
|
-
return `${v.name} ${found} is newer than the versions Rewake was tested with (up to ${v.tested}). It should still work; if Rewake misses a usage limit there, report it with
|
|
5610
|
+
return `${v.name} ${found} is newer than the versions Rewake was tested with (up to ${v.tested}). It should still work; if Rewake misses a usage limit there, report it with ${rewake("doctor --details")}.`;
|
|
5506
5611
|
}
|
|
5507
5612
|
|
|
5508
5613
|
// src/hosts/claude-code/install.ts
|
|
@@ -5510,13 +5615,13 @@ function copyMod(source, dir) {
|
|
|
5510
5615
|
ensurePrivateDir(dir);
|
|
5511
5616
|
for (const entry of readdirSync7(source)) {
|
|
5512
5617
|
if (entry === "rewake.json") continue;
|
|
5513
|
-
|
|
5514
|
-
cpSync(
|
|
5618
|
+
rmSync7(join16(dir, entry), { recursive: true, force: true });
|
|
5619
|
+
cpSync(join16(source, entry), join16(dir, entry), { recursive: true });
|
|
5515
5620
|
}
|
|
5516
5621
|
}
|
|
5517
5622
|
function modVersion(dir) {
|
|
5518
5623
|
try {
|
|
5519
|
-
const v = JSON.parse(readFileSync14(
|
|
5624
|
+
const v = JSON.parse(readFileSync14(join16(dir, ".claude-plugin", "plugin.json"), "utf8")).version;
|
|
5520
5625
|
return typeof v === "string" ? v : void 0;
|
|
5521
5626
|
} catch {
|
|
5522
5627
|
return void 0;
|
|
@@ -5544,7 +5649,7 @@ var MIN_CLAUDE_CODE = versionOf("claude-code").min;
|
|
|
5544
5649
|
var PLUGIN = "rewake@agent-rewake";
|
|
5545
5650
|
var MARKETPLACE = "agent-rewake";
|
|
5546
5651
|
function modDir(stateDir2) {
|
|
5547
|
-
return
|
|
5652
|
+
return join16(stateDir2, "hosts", "claude-code");
|
|
5548
5653
|
}
|
|
5549
5654
|
function shippedMod(bundle) {
|
|
5550
5655
|
let real = bundle;
|
|
@@ -5552,15 +5657,15 @@ function shippedMod(bundle) {
|
|
|
5552
5657
|
real = realpathSync4(bundle);
|
|
5553
5658
|
} catch {
|
|
5554
5659
|
}
|
|
5555
|
-
return
|
|
5660
|
+
return join16(dirname5(real), "hosts", "claude-code");
|
|
5556
5661
|
}
|
|
5557
5662
|
function claudeConfigDir2(env, home) {
|
|
5558
|
-
return env.CLAUDE_CONFIG_DIR ||
|
|
5663
|
+
return env.CLAUDE_CONFIG_DIR || join16(home, ".claude");
|
|
5559
5664
|
}
|
|
5560
5665
|
function modInstalled(env, home) {
|
|
5561
5666
|
try {
|
|
5562
5667
|
return readFileSync14(
|
|
5563
|
-
|
|
5668
|
+
join16(claudeConfigDir2(env, home), "plugins", "installed_plugins.json"),
|
|
5564
5669
|
"utf8"
|
|
5565
5670
|
).includes(`"${PLUGIN}"`);
|
|
5566
5671
|
} catch {
|
|
@@ -5595,13 +5700,13 @@ function outcome(stdout) {
|
|
|
5595
5700
|
}
|
|
5596
5701
|
}
|
|
5597
5702
|
async function modsBlocked(run3) {
|
|
5598
|
-
const empty =
|
|
5703
|
+
const empty = mkdtempSync2(join16(tmpdir2(), "rewake-probe-"));
|
|
5599
5704
|
try {
|
|
5600
5705
|
const r = await run3(["plugin", "test", empty]);
|
|
5601
5706
|
return /turned off here/i.test(`${r.stdout}
|
|
5602
5707
|
${r.stderr}`);
|
|
5603
5708
|
} finally {
|
|
5604
|
-
|
|
5709
|
+
rmSync7(empty, { recursive: true, force: true });
|
|
5605
5710
|
}
|
|
5606
5711
|
}
|
|
5607
5712
|
function pickClaude(programs2) {
|
|
@@ -5643,7 +5748,7 @@ async function runClaudeInstall(o) {
|
|
|
5643
5748
|
return 1;
|
|
5644
5749
|
}
|
|
5645
5750
|
const source = shippedMod(o.bundle);
|
|
5646
|
-
if (!
|
|
5751
|
+
if (!existsSync7(join16(source, ".claude-plugin", "plugin.json"))) {
|
|
5647
5752
|
o.out("This copy of Agent Rewake doesn't include its Claude Code plugin.\n");
|
|
5648
5753
|
return 1;
|
|
5649
5754
|
}
|
|
@@ -5694,7 +5799,7 @@ async function runClaudeInstall(o) {
|
|
|
5694
5799
|
if (o.uninstall) {
|
|
5695
5800
|
await run3(["plugin", "uninstall", PLUGIN, "--json"]);
|
|
5696
5801
|
await run3(["plugin", "marketplace", "remove", MARKETPLACE]);
|
|
5697
|
-
|
|
5802
|
+
rmSync7(modDir(o.stateDir), { recursive: true, force: true });
|
|
5698
5803
|
if (modInstalled(o.env, home)) {
|
|
5699
5804
|
o.out(
|
|
5700
5805
|
"Claude Code couldn't remove the plugin. Try: claude plugin uninstall rewake@agent-rewake\n"
|
|
@@ -5705,13 +5810,13 @@ async function runClaudeInstall(o) {
|
|
|
5705
5810
|
return 0;
|
|
5706
5811
|
}
|
|
5707
5812
|
const dir = modDir(o.stateDir);
|
|
5708
|
-
if (installed &&
|
|
5813
|
+
if (installed && existsSync7(join16(dir, ".claude-plugin", "plugin.json"))) {
|
|
5709
5814
|
copyMod(shippedMod(o.bundle), dir);
|
|
5710
5815
|
await run3(["plugin", "update", PLUGIN, "--json"]);
|
|
5711
5816
|
o.out("\nDone. Rewake's plugin in Claude Code is up to date; new sessions use it.\n");
|
|
5712
5817
|
return 0;
|
|
5713
5818
|
}
|
|
5714
|
-
|
|
5819
|
+
rmSync7(dir, { recursive: true, force: true });
|
|
5715
5820
|
cpSync(shippedMod(o.bundle), ensurePrivateDir(dir), { recursive: true });
|
|
5716
5821
|
writeFileAtomic(dir, "rewake.json", `${JSON.stringify({ stateDir: o.stateDir })}
|
|
5717
5822
|
`);
|
|
@@ -5720,7 +5825,7 @@ async function runClaudeInstall(o) {
|
|
|
5720
5825
|
const ok = inst.status === 0 && outcome(inst.stdout).outcome === "ok";
|
|
5721
5826
|
if (!ok) {
|
|
5722
5827
|
if (add.status === 0) await run3(["plugin", "marketplace", "remove", MARKETPLACE]);
|
|
5723
|
-
|
|
5828
|
+
rmSync7(dir, { recursive: true, force: true });
|
|
5724
5829
|
const why = outcome(inst.stdout).message ?? inst.stderr.trim().slice(0, 300);
|
|
5725
5830
|
o.out(`Claude Code couldn't add the plugin, so nothing was changed. ${why}
|
|
5726
5831
|
`);
|
|
@@ -5740,13 +5845,13 @@ async function runClaudeInstall(o) {
|
|
|
5740
5845
|
}
|
|
5741
5846
|
|
|
5742
5847
|
// src/hosts/codex/plugin.ts
|
|
5743
|
-
import { existsSync as
|
|
5744
|
-
import { join as
|
|
5848
|
+
import { existsSync as existsSync8, readFileSync as readFileSync15, rmSync as rmSync8 } from "node:fs";
|
|
5849
|
+
import { join as join17 } from "node:path";
|
|
5745
5850
|
var PLUGIN_ID = "agent-rewake@agent-rewake";
|
|
5746
5851
|
var MARKETPLACE2 = "agent-rewake";
|
|
5747
5852
|
var CODEX_HOOK_EVENTS = ["SessionStart", "UserPromptSubmit", "SessionEnd"];
|
|
5748
5853
|
function marketplaceDir(stateDir2) {
|
|
5749
|
-
return
|
|
5854
|
+
return join17(stateDir2, "hosts", "codex-marketplace");
|
|
5750
5855
|
}
|
|
5751
5856
|
var q = (s) => `"${s}"`;
|
|
5752
5857
|
function hooksJson(node, launcher) {
|
|
@@ -5773,9 +5878,9 @@ function hooksJson(node, launcher) {
|
|
|
5773
5878
|
}
|
|
5774
5879
|
function writeMarketplace(stateDir2, node, launcher) {
|
|
5775
5880
|
const root = ensurePrivateDir(marketplaceDir(stateDir2));
|
|
5776
|
-
const plugin = ensurePrivateDir(
|
|
5881
|
+
const plugin = ensurePrivateDir(join17(root, "plugins", "agent-rewake"));
|
|
5777
5882
|
writeFileAtomic(
|
|
5778
|
-
ensurePrivateDir(
|
|
5883
|
+
ensurePrivateDir(join17(root, ".agents", "plugins")),
|
|
5779
5884
|
"marketplace.json",
|
|
5780
5885
|
`${JSON.stringify(
|
|
5781
5886
|
{
|
|
@@ -5795,7 +5900,7 @@ function writeMarketplace(stateDir2, node, launcher) {
|
|
|
5795
5900
|
`
|
|
5796
5901
|
);
|
|
5797
5902
|
writeFileAtomic(
|
|
5798
|
-
ensurePrivateDir(
|
|
5903
|
+
ensurePrivateDir(join17(plugin, ".codex-plugin")),
|
|
5799
5904
|
"plugin.json",
|
|
5800
5905
|
`${JSON.stringify(
|
|
5801
5906
|
{
|
|
@@ -5816,15 +5921,15 @@ function writeMarketplace(stateDir2, node, launcher) {
|
|
|
5816
5921
|
)}
|
|
5817
5922
|
`
|
|
5818
5923
|
);
|
|
5819
|
-
writeFileAtomic(ensurePrivateDir(
|
|
5924
|
+
writeFileAtomic(ensurePrivateDir(join17(plugin, "hooks")), "hooks.json", hooksJson(node, launcher));
|
|
5820
5925
|
return root;
|
|
5821
5926
|
}
|
|
5822
5927
|
function codexHome(env, home) {
|
|
5823
|
-
return env.CODEX_HOME ||
|
|
5928
|
+
return env.CODEX_HOME || join17(home, ".codex");
|
|
5824
5929
|
}
|
|
5825
5930
|
function pluginInstalled(env, home) {
|
|
5826
|
-
const file =
|
|
5827
|
-
if (!
|
|
5931
|
+
const file = join17(codexHome(env, home), "config.toml");
|
|
5932
|
+
if (!existsSync8(file)) return false;
|
|
5828
5933
|
try {
|
|
5829
5934
|
return readFileSync15(file, "utf8").includes(`[plugins."${PLUGIN_ID}"]`);
|
|
5830
5935
|
} catch {
|
|
@@ -5848,26 +5953,26 @@ async function installPlugin(codex2, dir, env) {
|
|
|
5848
5953
|
async function uninstallPlugin(codex2, stateDir2, env) {
|
|
5849
5954
|
const remove = await codexCommand(codex2, ["plugin", "remove", PLUGIN_ID], env);
|
|
5850
5955
|
const market = await codexCommand(codex2, ["plugin", "marketplace", "remove", MARKETPLACE2], env);
|
|
5851
|
-
|
|
5956
|
+
rmSync8(marketplaceDir(stateDir2), { recursive: true, force: true });
|
|
5852
5957
|
if (remove.status !== 0 && market.status !== 0)
|
|
5853
5958
|
return { ok: false, detail: remove.stderr.trim().slice(0, 300) };
|
|
5854
5959
|
return { ok: true };
|
|
5855
5960
|
}
|
|
5856
5961
|
|
|
5857
5962
|
// src/hosts/copilot/install.ts
|
|
5858
|
-
import { existsSync as
|
|
5963
|
+
import { existsSync as existsSync11, rmSync as rmSync10 } from "node:fs";
|
|
5859
5964
|
import { homedir as homedir9 } from "node:os";
|
|
5860
|
-
import { join as
|
|
5965
|
+
import { join as join21 } from "node:path";
|
|
5861
5966
|
|
|
5862
5967
|
// src/hosts/policy.ts
|
|
5863
5968
|
import { readFileSync as readFileSync18 } from "node:fs";
|
|
5864
|
-
import { join as
|
|
5969
|
+
import { join as join20 } from "node:path";
|
|
5865
5970
|
|
|
5866
5971
|
// src/hosts/gemini/install.ts
|
|
5867
5972
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
5868
|
-
import { existsSync as
|
|
5973
|
+
import { existsSync as existsSync9, readFileSync as readFileSync16, rmSync as rmSync9 } from "node:fs";
|
|
5869
5974
|
import { homedir as homedir7 } from "node:os";
|
|
5870
|
-
import { join as
|
|
5975
|
+
import { join as join18 } from "node:path";
|
|
5871
5976
|
|
|
5872
5977
|
// src/hosts/gemini/host.ts
|
|
5873
5978
|
import { spawn as spawn3 } from "node:child_process";
|
|
@@ -6034,19 +6139,10 @@ function resumeGemini(r, text2, env, node = process.execPath) {
|
|
|
6034
6139
|
let err = "";
|
|
6035
6140
|
const child = spawn3(
|
|
6036
6141
|
program.command,
|
|
6037
|
-
[
|
|
6038
|
-
|
|
6039
|
-
"--resume",
|
|
6040
|
-
r.sessionId,
|
|
6041
|
-
"-p",
|
|
6042
|
-
text2,
|
|
6043
|
-
"--approval-mode",
|
|
6044
|
-
"default",
|
|
6045
|
-
"-o",
|
|
6046
|
-
"json"
|
|
6047
|
-
],
|
|
6048
|
-
{ cwd: r.cwd || void 0, env, stdio: ["ignore", "pipe", "pipe"], windowsHide: true }
|
|
6142
|
+
[...program.args, "--resume", r.sessionId, "--approval-mode", "default", "-o", "json"],
|
|
6143
|
+
{ cwd: r.cwd || void 0, env, stdio: ["pipe", "pipe", "pipe"], windowsHide: true }
|
|
6049
6144
|
);
|
|
6145
|
+
sendPromptOnStdin(child, text2);
|
|
6050
6146
|
child.stdout.on("data", (d) => {
|
|
6051
6147
|
if (out.length < 1 << 20) out += d.toString("utf8");
|
|
6052
6148
|
});
|
|
@@ -6100,7 +6196,7 @@ var REWAKE_MARKER = "[agent-rewake command]";
|
|
|
6100
6196
|
function offerText(resetsAt, now) {
|
|
6101
6197
|
return resetsAt ? `Rewake: Gemini hit its usage limit, which resets ${formatAt(resetsAt, now)}. To continue this conversation then, type /rewake.` : "Rewake: Gemini hit its usage limit. To continue this conversation later, type /rewake with a time, for example /rewake 3:30pm.";
|
|
6102
6198
|
}
|
|
6103
|
-
function
|
|
6199
|
+
function rewakeCommand2(args, id, cwd, d) {
|
|
6104
6200
|
const store = new ScheduleStore(d.stateDir);
|
|
6105
6201
|
const c = continueOnly(GEMINI_PLACE, args, d.now);
|
|
6106
6202
|
if (c.kind === "reply") return c.text;
|
|
@@ -6111,8 +6207,7 @@ function rewakeCommand(args, id, cwd, d) {
|
|
|
6111
6207
|
if (c.kind === "cancel") {
|
|
6112
6208
|
const pending = pendingFor(d.stateDir, GEMINI_ID, id);
|
|
6113
6209
|
for (const s of pending) {
|
|
6114
|
-
store.
|
|
6115
|
-
d.disarm(s.scheduleId);
|
|
6210
|
+
if (store.cancel(s.scheduleId, d.now)) d.disarm(s.scheduleId);
|
|
6116
6211
|
}
|
|
6117
6212
|
return pending.length > 0 ? "Rewake: Cancelled. This conversation won't be continued on its own." : "Rewake: Nothing is scheduled for this conversation.";
|
|
6118
6213
|
}
|
|
@@ -6131,8 +6226,7 @@ function rewakeCommand(args, id, cwd, d) {
|
|
|
6131
6226
|
at = l.resetsAt + RESET_MARGIN_MS;
|
|
6132
6227
|
}
|
|
6133
6228
|
for (const s of pendingFor(d.stateDir, GEMINI_ID, id)) {
|
|
6134
|
-
store.
|
|
6135
|
-
d.disarm(s.scheduleId);
|
|
6229
|
+
if (store.cancel(s.scheduleId, d.now)) d.disarm(s.scheduleId);
|
|
6136
6230
|
}
|
|
6137
6231
|
armClosed(geminiHost, r, at, d);
|
|
6138
6232
|
return `Rewake will continue this conversation ${formatAt(at, d.now)}, if Gemini CLI is closed by then and this computer is awake. To cancel: /rewake cancel`;
|
|
@@ -6154,7 +6248,7 @@ function geminiHooks(deps) {
|
|
|
6154
6248
|
case "BeforeAgent": {
|
|
6155
6249
|
const prompt2 = typeof ctx.input.prompt === "string" ? ctx.input.prompt : "";
|
|
6156
6250
|
if (prompt2.startsWith(REWAKE_MARKER)) {
|
|
6157
|
-
const reason =
|
|
6251
|
+
const reason = rewakeCommand2(prompt2.slice(REWAKE_MARKER.length).trim(), id, cwd, d);
|
|
6158
6252
|
return JSON.stringify({ decision: "deny", reason });
|
|
6159
6253
|
}
|
|
6160
6254
|
onPrompt(geminiHost, id, cwd, d);
|
|
@@ -6186,10 +6280,10 @@ function geminiHooks(deps) {
|
|
|
6186
6280
|
var MIN_GEMINI = versionOf("gemini-cli").min;
|
|
6187
6281
|
var GEMINI_EVENTS = ["SessionStart", "SessionEnd", "BeforeAgent", "AfterAgent"];
|
|
6188
6282
|
function extensionDir(stateDir2) {
|
|
6189
|
-
return
|
|
6283
|
+
return join18(stateDir2, "hosts", "gemini-extension");
|
|
6190
6284
|
}
|
|
6191
6285
|
function geminiSettingsFile(env, home) {
|
|
6192
|
-
return
|
|
6286
|
+
return join18(env.GEMINI_CLI_HOME || home, ".gemini", "settings.json");
|
|
6193
6287
|
}
|
|
6194
6288
|
function readGeminiSettings(env, home) {
|
|
6195
6289
|
try {
|
|
@@ -6241,12 +6335,12 @@ function writeExtension(stateDir2, node, launcher) {
|
|
|
6241
6335
|
`
|
|
6242
6336
|
);
|
|
6243
6337
|
writeFileAtomic(
|
|
6244
|
-
ensurePrivateDir(
|
|
6338
|
+
ensurePrivateDir(join18(dir, "hooks")),
|
|
6245
6339
|
"hooks.json",
|
|
6246
6340
|
geminiHooksJson(node, launcher)
|
|
6247
6341
|
);
|
|
6248
6342
|
writeFileAtomic(
|
|
6249
|
-
ensurePrivateDir(
|
|
6343
|
+
ensurePrivateDir(join18(dir, "commands")),
|
|
6250
6344
|
"rewake.toml",
|
|
6251
6345
|
`description = "Agent Rewake: continue after the usage limit resets. Also: /rewake 3:30pm, /rewake cancel, /rewake help"
|
|
6252
6346
|
prompt = "${REWAKE_MARKER} {{args}}"
|
|
@@ -6266,7 +6360,7 @@ async function runGeminiInstall(o) {
|
|
|
6266
6360
|
const p = codexProgram(program, o.node);
|
|
6267
6361
|
return spawnSync5(p.command, [...p.args, ...args], { stdio: "inherit", env: o.env }).status;
|
|
6268
6362
|
});
|
|
6269
|
-
const installed = o.installed?.() ??
|
|
6363
|
+
const installed = o.installed?.() ?? existsSync9(extensionDir(o.stateDir));
|
|
6270
6364
|
if (!gemini) {
|
|
6271
6365
|
o.out(
|
|
6272
6366
|
o.uninstall ? "Gemini CLI wasn't found on this computer.\n" : "Gemini CLI wasn't found on this computer, so there's nothing to set up for it.\n"
|
|
@@ -6284,14 +6378,14 @@ async function runGeminiInstall(o) {
|
|
|
6284
6378
|
} else {
|
|
6285
6379
|
if (gemini.version && compareVersions(gemini.version, MIN_GEMINI) < 0) {
|
|
6286
6380
|
o.out(
|
|
6287
|
-
`Gemini CLI ${gemini.version} is too old for Rewake (it needs ${MIN_GEMINI} or newer). Update it with "npm install -g @google/gemini-cli@latest", then run "
|
|
6381
|
+
`Gemini CLI ${gemini.version} is too old for Rewake (it needs ${MIN_GEMINI} or newer). Update it with "npm install -g @google/gemini-cli@latest", then run "${rewake("install --only gemini-cli")}" again.
|
|
6288
6382
|
`
|
|
6289
6383
|
);
|
|
6290
6384
|
return 1;
|
|
6291
6385
|
}
|
|
6292
6386
|
if (!geminiHooksOn(o.env, home)) {
|
|
6293
6387
|
o.out(
|
|
6294
|
-
`Gemini CLI's hooks are turned off ("hooksConfig": { "enabled": false } in ${geminiSettingsFile(o.env, home)}), and Rewake needs them. Nothing was changed. To use Rewake, change false to true there (this turns all Gemini CLI hooks back on, including any of your own), then run "
|
|
6388
|
+
`Gemini CLI's hooks are turned off ("hooksConfig": { "enabled": false } in ${geminiSettingsFile(o.env, home)}), and Rewake needs them. Nothing was changed. To use Rewake, change false to true there (this turns all Gemini CLI hooks back on, including any of your own), then run "${rewake("install --only gemini-cli")}" again.
|
|
6295
6389
|
`
|
|
6296
6390
|
);
|
|
6297
6391
|
return 1;
|
|
@@ -6324,7 +6418,7 @@ async function runGeminiInstall(o) {
|
|
|
6324
6418
|
}
|
|
6325
6419
|
if (!o.interactive) {
|
|
6326
6420
|
o.out(
|
|
6327
|
-
o.uninstall ? "Not a terminal, so nothing was changed. Run this in a terminal: gemini extensions uninstall agent-rewake\n" : `Not a terminal, so nothing was changed. Run "
|
|
6421
|
+
o.uninstall ? "Not a terminal, so nothing was changed. Run this in a terminal: gemini extensions uninstall agent-rewake\n" : `Not a terminal, so nothing was changed. Run "${rewake("install --only gemini-cli")}" in a terminal; Gemini CLI asks you to confirm.
|
|
6328
6422
|
`
|
|
6329
6423
|
);
|
|
6330
6424
|
return 1;
|
|
@@ -6335,7 +6429,7 @@ async function runGeminiInstall(o) {
|
|
|
6335
6429
|
}
|
|
6336
6430
|
if (o.uninstall) {
|
|
6337
6431
|
const status2 = run3(gemini.path, ["extensions", "uninstall", "agent-rewake"]);
|
|
6338
|
-
|
|
6432
|
+
rmSync9(extensionDir(o.stateDir), { recursive: true, force: true });
|
|
6339
6433
|
o.out(
|
|
6340
6434
|
status2 === 0 ? "Done. Rewake is out of Gemini CLI.\n" : "Gemini CLI couldn't remove the extension. Try: gemini extensions uninstall agent-rewake\n"
|
|
6341
6435
|
);
|
|
@@ -6345,14 +6439,14 @@ async function runGeminiInstall(o) {
|
|
|
6345
6439
|
const dir = writeExtension(o.stateDir, o.node, launcher);
|
|
6346
6440
|
const status = run3(gemini.path, ["extensions", "link", dir]);
|
|
6347
6441
|
if (status === 41) {
|
|
6348
|
-
|
|
6442
|
+
rmSync9(dir, { recursive: true, force: true });
|
|
6349
6443
|
o.out(
|
|
6350
6444
|
"Sign in to Gemini CLI first (run gemini once), then run this again. Nothing was changed.\n"
|
|
6351
6445
|
);
|
|
6352
6446
|
return 1;
|
|
6353
6447
|
}
|
|
6354
6448
|
if (status !== 0) {
|
|
6355
|
-
|
|
6449
|
+
rmSync9(dir, { recursive: true, force: true });
|
|
6356
6450
|
o.out("Gemini CLI didn't add the extension, so nothing was changed.\n");
|
|
6357
6451
|
return 1;
|
|
6358
6452
|
}
|
|
@@ -6364,12 +6458,12 @@ async function runGeminiInstall(o) {
|
|
|
6364
6458
|
|
|
6365
6459
|
// src/hosts/grok/host.ts
|
|
6366
6460
|
import { spawn as spawn4 } from "node:child_process";
|
|
6367
|
-
import { existsSync as
|
|
6461
|
+
import { existsSync as existsSync10, readFileSync as readFileSync17 } from "node:fs";
|
|
6368
6462
|
import { homedir as homedir8 } from "node:os";
|
|
6369
|
-
import { join as
|
|
6463
|
+
import { join as join19 } from "node:path";
|
|
6370
6464
|
var GROK_ID = "grok";
|
|
6371
6465
|
function grokHome(env, home = homedir8()) {
|
|
6372
|
-
return env.GROK_HOME ||
|
|
6466
|
+
return env.GROK_HOME || join19(home, ".grok");
|
|
6373
6467
|
}
|
|
6374
6468
|
function isGrok(input, env) {
|
|
6375
6469
|
return typeof env.GROK_HOOK_EVENT === "string" || typeof input.hookEventName === "string";
|
|
@@ -6385,8 +6479,8 @@ function lineTime(ts) {
|
|
|
6385
6479
|
return void 0;
|
|
6386
6480
|
}
|
|
6387
6481
|
function billingReset(home, now, sessionId) {
|
|
6388
|
-
const file =
|
|
6389
|
-
if (!
|
|
6482
|
+
const file = join19(home, "logs", "unified.jsonl");
|
|
6483
|
+
if (!existsSync10(file)) return { full: false };
|
|
6390
6484
|
let tail;
|
|
6391
6485
|
try {
|
|
6392
6486
|
tail = readTail2(file, 512 * 1024);
|
|
@@ -6420,7 +6514,7 @@ function billingReset(home, now, sessionId) {
|
|
|
6420
6514
|
}
|
|
6421
6515
|
function grokSessionOpen(home, sessionId) {
|
|
6422
6516
|
try {
|
|
6423
|
-
const list = JSON.parse(readFileSync17(
|
|
6517
|
+
const list = JSON.parse(readFileSync17(join19(home, "active_sessions.json"), "utf8"));
|
|
6424
6518
|
const entries = Array.isArray(list) ? list : Object.values(list);
|
|
6425
6519
|
return entries.some((e) => {
|
|
6426
6520
|
const s = e;
|
|
@@ -6445,14 +6539,15 @@ function resumeGrok(r, text2, env) {
|
|
|
6445
6539
|
if (!r.program)
|
|
6446
6540
|
return Promise.resolve({ ok: false, reason: "unsupported", detail: "no Grok found" });
|
|
6447
6541
|
const program = codexProgram(r.program, process.execPath);
|
|
6542
|
+
const prompt2 = privateTempFile("agent-rewake-grok-", "message.txt", text2);
|
|
6448
6543
|
return new Promise((resolve2) => {
|
|
6449
6544
|
let out = "";
|
|
6450
6545
|
const child = spawn4(
|
|
6451
6546
|
program.command,
|
|
6452
6547
|
[
|
|
6453
6548
|
...program.args,
|
|
6454
|
-
"-
|
|
6455
|
-
|
|
6549
|
+
"--prompt-file",
|
|
6550
|
+
prompt2.path,
|
|
6456
6551
|
"-r",
|
|
6457
6552
|
r.sessionId,
|
|
6458
6553
|
...r.cwd ? ["--cwd", r.cwd] : [],
|
|
@@ -6474,8 +6569,12 @@ function resumeGrok(r, text2, env) {
|
|
|
6474
6569
|
if (out.length < 1 << 20) out += d.toString("utf8");
|
|
6475
6570
|
});
|
|
6476
6571
|
const timedOut = resumeDeadline(child);
|
|
6477
|
-
child.on("error", () =>
|
|
6572
|
+
child.on("error", () => {
|
|
6573
|
+
prompt2.remove();
|
|
6574
|
+
resolve2({ ok: false, reason: "failed", detail: "spawn" });
|
|
6575
|
+
});
|
|
6478
6576
|
child.on("exit", (code) => {
|
|
6577
|
+
prompt2.remove();
|
|
6479
6578
|
if (timedOut()) return resolve2({ ok: false, reason: "failed", detail: "timeout" });
|
|
6480
6579
|
if (code === 0) {
|
|
6481
6580
|
const ran = resultSession(out);
|
|
@@ -6565,7 +6664,7 @@ function grokHooks(deps) {
|
|
|
6565
6664
|
// src/hosts/policy.ts
|
|
6566
6665
|
function hooksTurnedOff(place, env, home) {
|
|
6567
6666
|
if (place === "copilot-cli") {
|
|
6568
|
-
const file =
|
|
6667
|
+
const file = join20(copilotHome(env, home), "settings.json");
|
|
6569
6668
|
try {
|
|
6570
6669
|
const s = parse2(readFileSync18(file, "utf8"));
|
|
6571
6670
|
return s?.disableAllHooks === true ? `"disableAllHooks": true in GitHub Copilot CLI's settings` : void 0;
|
|
@@ -6575,7 +6674,7 @@ function hooksTurnedOff(place, env, home) {
|
|
|
6575
6674
|
}
|
|
6576
6675
|
if (place === "grok") {
|
|
6577
6676
|
try {
|
|
6578
|
-
const text2 = readFileSync18(
|
|
6677
|
+
const text2 = readFileSync18(join20(grokHome(env, home), "disabled-hooks"), "utf8");
|
|
6579
6678
|
return /agent-rewake/.test(text2) ? "Grok Build's list of turned-off hooks" : void 0;
|
|
6580
6679
|
} catch {
|
|
6581
6680
|
return void 0;
|
|
@@ -6595,10 +6694,10 @@ var COPILOT_EVENTS = [
|
|
|
6595
6694
|
"errorOccurred"
|
|
6596
6695
|
];
|
|
6597
6696
|
function copilotHome(env, home) {
|
|
6598
|
-
return env.COPILOT_HOME ||
|
|
6697
|
+
return env.COPILOT_HOME || join21(home, ".copilot");
|
|
6599
6698
|
}
|
|
6600
6699
|
function hooksFile(env, home) {
|
|
6601
|
-
return
|
|
6700
|
+
return join21(copilotHome(env, home), "hooks", "agent-rewake.json");
|
|
6602
6701
|
}
|
|
6603
6702
|
function copilotHooksJson(node, launcher) {
|
|
6604
6703
|
const hooks = Object.fromEntries(
|
|
@@ -6626,7 +6725,7 @@ async function runCopilotInstall(o) {
|
|
|
6626
6725
|
)[0];
|
|
6627
6726
|
const copilot = picked && !o.uninstall ? withVersion(picked, probe) : picked;
|
|
6628
6727
|
const file = hooksFile(o.env, home);
|
|
6629
|
-
const installed =
|
|
6728
|
+
const installed = existsSync11(file);
|
|
6630
6729
|
if (o.uninstall) {
|
|
6631
6730
|
if (!installed) {
|
|
6632
6731
|
o.out("Rewake isn't set up in GitHub Copilot CLI: nothing to remove.\n");
|
|
@@ -6645,7 +6744,7 @@ async function runCopilotInstall(o) {
|
|
|
6645
6744
|
const label2 = `GitHub Copilot CLI${copilot.version ? ` (version ${copilot.version} found)` : ""}`;
|
|
6646
6745
|
if (copilot.version && compareVersions(copilot.version, MIN_COPILOT) < 0) {
|
|
6647
6746
|
o.out(
|
|
6648
|
-
`GitHub Copilot CLI ${copilot.version} is too old for Rewake (it needs ${MIN_COPILOT} or newer). Update it with "copilot update" (or npm install -g @github/copilot@latest), then run "
|
|
6747
|
+
`GitHub Copilot CLI ${copilot.version} is too old for Rewake (it needs ${MIN_COPILOT} or newer). Update it with "copilot update" (or npm install -g @github/copilot@latest), then run "${rewake("install --only copilot-cli")}" again.
|
|
6649
6748
|
`
|
|
6650
6749
|
);
|
|
6651
6750
|
return 1;
|
|
@@ -6680,13 +6779,13 @@ async function runCopilotInstall(o) {
|
|
|
6680
6779
|
}
|
|
6681
6780
|
}
|
|
6682
6781
|
if (o.uninstall) {
|
|
6683
|
-
|
|
6782
|
+
rmSync10(file, { force: true });
|
|
6684
6783
|
o.out("Done. Rewake is out of GitHub Copilot CLI.\n");
|
|
6685
6784
|
return 0;
|
|
6686
6785
|
}
|
|
6687
6786
|
const launcher = ensureLauncher(o.stateDir, o.bundle) ?? launcherPath(o.stateDir);
|
|
6688
6787
|
writeFileAtomic(
|
|
6689
|
-
ensurePrivateDir(
|
|
6788
|
+
ensurePrivateDir(join21(copilotHome(o.env, home), "hooks")),
|
|
6690
6789
|
"agent-rewake.json",
|
|
6691
6790
|
copilotHooksJson(o.node, launcher)
|
|
6692
6791
|
);
|
|
@@ -6707,20 +6806,20 @@ async function runCopilotInstall(o) {
|
|
|
6707
6806
|
}
|
|
6708
6807
|
|
|
6709
6808
|
// src/hosts/cursor/install.ts
|
|
6710
|
-
import { existsSync as
|
|
6809
|
+
import { existsSync as existsSync12, readFileSync as readFileSync19 } from "node:fs";
|
|
6711
6810
|
import { homedir as homedir10 } from "node:os";
|
|
6712
|
-
import { join as
|
|
6811
|
+
import { join as join22 } from "node:path";
|
|
6713
6812
|
var WAIT_SECONDS = 4 * 60 * 60;
|
|
6714
6813
|
var CURSOR_EVENTS = ["beforeSubmitPrompt", "stop"];
|
|
6715
6814
|
function cursorHooksFile(home) {
|
|
6716
|
-
return
|
|
6815
|
+
return join22(home, ".cursor", "hooks.json");
|
|
6717
6816
|
}
|
|
6718
6817
|
function cursorFound(env, home, platform4) {
|
|
6719
|
-
const apps2 = platform4 === "darwin" ? ["/Applications/Cursor.app",
|
|
6720
|
-
if (apps2.some((a) =>
|
|
6818
|
+
const apps2 = platform4 === "darwin" ? ["/Applications/Cursor.app", join22(home, "Applications", "Cursor.app")] : platform4 === "win32" ? env.LOCALAPPDATA ? [join22(env.LOCALAPPDATA, "Programs", "cursor", "Cursor.exe")] : [] : ["/usr/share/cursor", "/opt/Cursor", "/opt/cursor"];
|
|
6819
|
+
if (apps2.some((a) => existsSync12(a))) return true;
|
|
6721
6820
|
const sep2 = platform4 === "win32" ? ";" : ":";
|
|
6722
6821
|
const names = platform4 === "win32" ? ["cursor.cmd", "cursor.exe"] : ["cursor"];
|
|
6723
|
-
return (env.PATH ?? "").split(sep2).filter(Boolean).some((d) => names.some((n) =>
|
|
6822
|
+
return (env.PATH ?? "").split(sep2).filter(Boolean).some((d) => names.some((n) => existsSync12(join22(d, n))));
|
|
6724
6823
|
}
|
|
6725
6824
|
var OURS = /\bhook cursor\b/;
|
|
6726
6825
|
function readHooks(file) {
|
|
@@ -6744,7 +6843,7 @@ function planCursor(file, node, launcher, uninstall) {
|
|
|
6744
6843
|
return {
|
|
6745
6844
|
error: `Rewake couldn't set up Cursor: the path to Node.js or to Rewake contains a double quote (${node}, ${launcher}). Rewake didn't change anything.`
|
|
6746
6845
|
};
|
|
6747
|
-
const existed =
|
|
6846
|
+
const existed = existsSync12(file);
|
|
6748
6847
|
const before = existed ? readFileSync19(file, "utf8") : "";
|
|
6749
6848
|
const parsed = existed ? readHooks(file) : { version: 1, hooks: {} };
|
|
6750
6849
|
if (!parsed)
|
|
@@ -6804,7 +6903,7 @@ Your own hooks stay. Rewake keeps a backup of the file.
|
|
|
6804
6903
|
"Agent Rewake (preview) will add its hooks to Cursor's own agent:",
|
|
6805
6904
|
` ${file}`,
|
|
6806
6905
|
"",
|
|
6807
|
-
|
|
6906
|
+
`When a Cursor chat stops at its usage limit, run "${rewake("continue")}" and pick a time within 4 hours. Rewake then continues that chat, as long as its window stays open. Typing in the chat cancels it. A limit that waiting won't lift (one that needs a paid plan or a new month) gets a notification instead. Your own hooks stay; Rewake keeps a backup of the file.`,
|
|
6808
6907
|
""
|
|
6809
6908
|
].join("\n")
|
|
6810
6909
|
);
|
|
@@ -6833,26 +6932,26 @@ Next, reload Cursor's window so its agent loads the hooks: in Cursor, run "Devel
|
|
|
6833
6932
|
}
|
|
6834
6933
|
|
|
6835
6934
|
// src/hosts/devin/install.ts
|
|
6836
|
-
import { existsSync as
|
|
6935
|
+
import { existsSync as existsSync14, readFileSync as readFileSync20 } from "node:fs";
|
|
6837
6936
|
import { homedir as homedir11 } from "node:os";
|
|
6838
|
-
import { join as
|
|
6937
|
+
import { join as join24 } from "node:path";
|
|
6839
6938
|
|
|
6840
6939
|
// src/wrap.ts
|
|
6841
6940
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
6842
6941
|
import { createHash as createHash3 } from "node:crypto";
|
|
6843
6942
|
import {
|
|
6844
6943
|
chmodSync,
|
|
6845
|
-
existsSync as
|
|
6944
|
+
existsSync as existsSync13,
|
|
6846
6945
|
mkdirSync as mkdirSync2,
|
|
6847
6946
|
openSync as openSync7,
|
|
6848
6947
|
readdirSync as readdirSync8,
|
|
6849
6948
|
renameSync as renameSync2,
|
|
6850
|
-
rmSync as
|
|
6949
|
+
rmSync as rmSync11,
|
|
6851
6950
|
statSync as statSync3,
|
|
6852
6951
|
writeFileSync as writeFileSync2
|
|
6853
6952
|
} from "node:fs";
|
|
6854
6953
|
import { platform as platform2 } from "node:os";
|
|
6855
|
-
import { basename as
|
|
6954
|
+
import { basename as basename4, join as join23, win32 as win324 } from "node:path";
|
|
6856
6955
|
var WRAP_REGISTRY = "--wrap-registry";
|
|
6857
6956
|
var WRAP_COMMAND = "--wrap-command";
|
|
6858
6957
|
var CLAUDE_REGISTRY_ID = "claude-acp";
|
|
@@ -6893,7 +6992,7 @@ function platformKey(env = process.env) {
|
|
|
6893
6992
|
}
|
|
6894
6993
|
var strings = (v) => isRecord(v) ? Object.fromEntries(Object.entries(v).map(([k, x]) => [k, String(x)])) : {};
|
|
6895
6994
|
function registryAgent(id, env = process.env) {
|
|
6896
|
-
const file =
|
|
6995
|
+
const file = join23(zedDataDir(env), "external_agents", "registry", "registry.json");
|
|
6897
6996
|
let agents;
|
|
6898
6997
|
try {
|
|
6899
6998
|
agents = readJsonFile(file).agents;
|
|
@@ -6949,26 +7048,26 @@ function splitPackageSpec(spec) {
|
|
|
6949
7048
|
}
|
|
6950
7049
|
function installedVersion(dir, pkg2) {
|
|
6951
7050
|
try {
|
|
6952
|
-
const json = readJsonFile(
|
|
7051
|
+
const json = readJsonFile(join23(dir, "node_modules", pkg2, "package.json"));
|
|
6953
7052
|
return typeof json.version === "string" ? json.version : void 0;
|
|
6954
7053
|
} catch {
|
|
6955
7054
|
return void 0;
|
|
6956
7055
|
}
|
|
6957
7056
|
}
|
|
6958
7057
|
function packageExecutable(dir, pkg2) {
|
|
6959
|
-
const root =
|
|
7058
|
+
const root = join23(dir, "node_modules", pkg2);
|
|
6960
7059
|
let json;
|
|
6961
7060
|
try {
|
|
6962
|
-
json = readJsonFile(
|
|
7061
|
+
json = readJsonFile(join23(root, "package.json"));
|
|
6963
7062
|
} catch {
|
|
6964
7063
|
return void 0;
|
|
6965
7064
|
}
|
|
6966
7065
|
const bin = json.bin;
|
|
6967
|
-
if (typeof bin === "string") return
|
|
7066
|
+
if (typeof bin === "string") return join23(root, bin);
|
|
6968
7067
|
if (!isRecord(bin)) return void 0;
|
|
6969
7068
|
const short = pkg2.replace(/^@[^/]+\//, "");
|
|
6970
|
-
const
|
|
6971
|
-
return typeof
|
|
7069
|
+
const chosen2 = bin[short] ?? Object.values(bin)[0];
|
|
7070
|
+
return typeof chosen2 === "string" ? join23(root, chosen2) : void 0;
|
|
6972
7071
|
}
|
|
6973
7072
|
function npmCli(args, env) {
|
|
6974
7073
|
const script = npmScript("npm-cli.js");
|
|
@@ -6976,8 +7075,8 @@ function npmCli(args, env) {
|
|
|
6976
7075
|
}
|
|
6977
7076
|
function ensureNpxAgent(id, npx, stateDir2, env, logFile) {
|
|
6978
7077
|
const [pkg2, version] = splitPackageSpec(npx.package);
|
|
6979
|
-
const zedDir =
|
|
6980
|
-
const ownDir =
|
|
7078
|
+
const zedDir = join23(zedDataDir(env), "external_agents", "registry", "npx", safeName(id));
|
|
7079
|
+
const ownDir = join23(stateDir2, "agents", "npx", safeName(id));
|
|
6981
7080
|
for (const dir of [zedDir, ownDir]) if (installedVersion(dir, pkg2)) return dir;
|
|
6982
7081
|
ensurePrivateDir(ownDir);
|
|
6983
7082
|
const spec = version ? `${pkg2}@0.0.0 - ${version}` : pkg2;
|
|
@@ -6998,7 +7097,7 @@ function ensureNpxAgent(id, npx, stateDir2, env, logFile) {
|
|
|
6998
7097
|
function zedBinaryDir(id, version, target, env) {
|
|
6999
7098
|
const sha = (s) => createHash3("sha256").update(s).digest("hex").slice(0, 16);
|
|
7000
7099
|
const archiveKey = target.sha256 ? `${target.archive}\0sha256:${target.sha256.toLowerCase()}` : target.archive;
|
|
7001
|
-
return
|
|
7100
|
+
return join23(
|
|
7002
7101
|
zedDataDir(env),
|
|
7003
7102
|
"external_agents",
|
|
7004
7103
|
"registry",
|
|
@@ -7008,18 +7107,18 @@ function zedBinaryDir(id, version, target, env) {
|
|
|
7008
7107
|
}
|
|
7009
7108
|
function commandIn(dir, cmd) {
|
|
7010
7109
|
if (!/^\.[\\/]/.test(cmd) || cmd.includes("..")) return void 0;
|
|
7011
|
-
const path =
|
|
7012
|
-
return
|
|
7110
|
+
const path = join23(dir, cmd.slice(2));
|
|
7111
|
+
return existsSync13(path) ? path : void 0;
|
|
7013
7112
|
}
|
|
7014
7113
|
function findBinaryAgent(id, version, target, stateDir2, env) {
|
|
7015
7114
|
const exact = commandIn(zedBinaryDir(id, version, target, env), target.cmd);
|
|
7016
7115
|
if (exact) return exact;
|
|
7017
|
-
const zedAgentDir =
|
|
7018
|
-
const own =
|
|
7116
|
+
const zedAgentDir = join23(zedDataDir(env), "external_agents", "registry", zedSafeName(id));
|
|
7117
|
+
const own = join23(stateDir2, "agents", "bin", safeName(id));
|
|
7019
7118
|
for (const base of [zedAgentDir, own]) {
|
|
7020
7119
|
let dirs = [];
|
|
7021
7120
|
try {
|
|
7022
|
-
dirs = readdirSync8(base).filter((d) => d.startsWith("v_")).map((d) =>
|
|
7121
|
+
dirs = readdirSync8(base).filter((d) => d.startsWith("v_")).map((d) => join23(base, d)).sort((a, b) => statSync3(b).mtimeMs - statSync3(a).mtimeMs);
|
|
7023
7122
|
} catch {
|
|
7024
7123
|
continue;
|
|
7025
7124
|
}
|
|
@@ -7031,10 +7130,10 @@ function findBinaryAgent(id, version, target, stateDir2, env) {
|
|
|
7031
7130
|
return void 0;
|
|
7032
7131
|
}
|
|
7033
7132
|
async function downloadBinaryAgent(id, version, target, stateDir2, fetchImpl = fetch) {
|
|
7034
|
-
const base = ensurePrivateDir(
|
|
7035
|
-
const dest =
|
|
7133
|
+
const base = ensurePrivateDir(join23(stateDir2, "agents", "bin", safeName(id)));
|
|
7134
|
+
const dest = join23(base, `v_${safeName(version)}`);
|
|
7036
7135
|
const tmp = `${dest}.partial-${process.pid}`;
|
|
7037
|
-
|
|
7136
|
+
rmSync11(tmp, { recursive: true, force: true });
|
|
7038
7137
|
mkdirSync2(tmp, { recursive: true });
|
|
7039
7138
|
try {
|
|
7040
7139
|
const res = await fetchImpl(target.archive);
|
|
@@ -7045,32 +7144,32 @@ async function downloadBinaryAgent(id, version, target, stateDir2, fetchImpl = f
|
|
|
7045
7144
|
if (got !== target.sha256.toLowerCase())
|
|
7046
7145
|
throw new Error("the download doesn't match the registry's checksum");
|
|
7047
7146
|
}
|
|
7048
|
-
const name =
|
|
7049
|
-
const file =
|
|
7147
|
+
const name = basename4(new URL(target.archive).pathname) || "agent";
|
|
7148
|
+
const file = join23(tmp, name);
|
|
7050
7149
|
writeFileSync2(file, bytes);
|
|
7051
7150
|
const lower = name.toLowerCase();
|
|
7052
7151
|
if (lower.endsWith(".zip")) {
|
|
7053
7152
|
unpack(unpackers("zip", file, tmp));
|
|
7054
|
-
|
|
7153
|
+
rmSync11(file, { force: true });
|
|
7055
7154
|
} else if (/\.(tar\.gz|tgz)$/.test(lower)) {
|
|
7056
7155
|
unpack(unpackers("gz", file, tmp));
|
|
7057
|
-
|
|
7156
|
+
rmSync11(file, { force: true });
|
|
7058
7157
|
} else if (/\.(tar\.bz2|tbz2?)$/.test(lower)) {
|
|
7059
7158
|
unpack(unpackers("bz2", file, tmp));
|
|
7060
|
-
|
|
7159
|
+
rmSync11(file, { force: true });
|
|
7061
7160
|
} else if (target.cmd.replace(/^\.[\\/]/, "") !== name) {
|
|
7062
|
-
renameSync2(file,
|
|
7161
|
+
renameSync2(file, join23(tmp, target.cmd.slice(2)));
|
|
7063
7162
|
}
|
|
7064
7163
|
const cmd = commandIn(tmp, target.cmd);
|
|
7065
7164
|
if (!cmd) throw new Error(`the download has no ${target.cmd}`);
|
|
7066
7165
|
chmodSync(cmd, 493);
|
|
7067
|
-
|
|
7166
|
+
rmSync11(dest, { recursive: true, force: true });
|
|
7068
7167
|
renameWithRetry(tmp, dest);
|
|
7069
|
-
return
|
|
7168
|
+
return join23(dest, target.cmd.slice(2));
|
|
7070
7169
|
} catch (err) {
|
|
7071
|
-
|
|
7170
|
+
rmSync11(tmp, { recursive: true, force: true });
|
|
7072
7171
|
throw new Error(
|
|
7073
|
-
`couldn't set up "${id}" ${version} (${err.message}). Check your network, or open the agent once without Rewake (
|
|
7172
|
+
`couldn't set up "${id}" ${version} (${err.message}). Check your network, or open the agent once without Rewake (${rewake("uninstall")}), then reopen the thread.`
|
|
7074
7173
|
);
|
|
7075
7174
|
}
|
|
7076
7175
|
}
|
|
@@ -7104,7 +7203,7 @@ async function wrappedAgentCommand(target, extra, env, stateDir2, logFile, fetch
|
|
|
7104
7203
|
const agent = registryAgent(target.id, env);
|
|
7105
7204
|
if (!agent)
|
|
7106
7205
|
throw new Error(
|
|
7107
|
-
`"${target.id}" isn't in Zed's copy of the ACP Registry. Open Zed's agent registry once, or run
|
|
7206
|
+
`"${target.id}" isn't in Zed's copy of the ACP Registry. Open Zed's agent registry once, or run "${rewake("uninstall")}" to restore the original entry.`
|
|
7108
7207
|
);
|
|
7109
7208
|
if (agent.kind === "binary") {
|
|
7110
7209
|
const cmd = findBinaryAgent(target.id, agent.version, agent.binary, stateDir2, env) ?? await downloadBinaryAgent(target.id, agent.version, agent.binary, stateDir2, fetchImpl);
|
|
@@ -7116,7 +7215,7 @@ async function wrappedAgentCommand(target, extra, env, stateDir2, logFile, fetch
|
|
|
7116
7215
|
}
|
|
7117
7216
|
if (agent.kind !== "npx")
|
|
7118
7217
|
throw new Error(
|
|
7119
|
-
`"${target.id}" has no build for this computer (${platformKey(env) ?? "unknown platform"}), so Zed can't run it either. Run
|
|
7218
|
+
`"${target.id}" has no build for this computer (${platformKey(env) ?? "unknown platform"}), so Zed can't run it either. Run "${rewake("uninstall")}" to restore it.`
|
|
7120
7219
|
);
|
|
7121
7220
|
const dir = ensureNpxAgent(target.id, agent.npx, stateDir2, env, logFile);
|
|
7122
7221
|
const [pkg2] = splitPackageSpec(agent.npx.package);
|
|
@@ -7145,7 +7244,7 @@ var DEVIN_AGENTS = {
|
|
|
7145
7244
|
};
|
|
7146
7245
|
function devinFile(env, home, platform4) {
|
|
7147
7246
|
if (platform4 === "win32")
|
|
7148
|
-
return
|
|
7247
|
+
return join24(
|
|
7149
7248
|
env.USERPROFILE || home,
|
|
7150
7249
|
"AppData",
|
|
7151
7250
|
"Roaming",
|
|
@@ -7154,12 +7253,12 @@ function devinFile(env, home, platform4) {
|
|
|
7154
7253
|
"acp",
|
|
7155
7254
|
"registry.json"
|
|
7156
7255
|
);
|
|
7157
|
-
const next =
|
|
7158
|
-
const dir =
|
|
7159
|
-
return
|
|
7256
|
+
const next = join24(home, ".windsurf-next");
|
|
7257
|
+
const dir = existsSync14(join24(home, ".windsurf")) || !existsSync14(next) ? ".windsurf" : ".windsurf-next";
|
|
7258
|
+
return join24(home, dir, "acp", "registry.json");
|
|
7160
7259
|
}
|
|
7161
7260
|
function devinFound(home) {
|
|
7162
|
-
return
|
|
7261
|
+
return existsSync14(join24(home, ".windsurf")) || existsSync14(join24(home, ".windsurf-next"));
|
|
7163
7262
|
}
|
|
7164
7263
|
function platformKey2(platform4, arch) {
|
|
7165
7264
|
const os = platform4 === "win32" ? "windows" : platform4 === "darwin" ? "darwin" : "linux";
|
|
@@ -7181,7 +7280,7 @@ function devinInstalled(file) {
|
|
|
7181
7280
|
});
|
|
7182
7281
|
}
|
|
7183
7282
|
function planDevin(file, launch, uninstall, platform4 = process.platform, arch = process.arch) {
|
|
7184
|
-
const existed =
|
|
7283
|
+
const existed = existsSync14(file);
|
|
7185
7284
|
const before = existed ? readFileSync20(file, "utf8") : "";
|
|
7186
7285
|
const parsed = existed ? readJson2(file) : { version: "1.0.0", agents: [], extensions: [] };
|
|
7187
7286
|
if (!parsed)
|
|
@@ -7277,9 +7376,9 @@ async function runDevinInstall(o) {
|
|
|
7277
7376
|
}
|
|
7278
7377
|
|
|
7279
7378
|
// src/hosts/grok/install.ts
|
|
7280
|
-
import { existsSync as
|
|
7379
|
+
import { existsSync as existsSync15, rmSync as rmSync12 } from "node:fs";
|
|
7281
7380
|
import { homedir as homedir12 } from "node:os";
|
|
7282
|
-
import { join as
|
|
7381
|
+
import { join as join25 } from "node:path";
|
|
7283
7382
|
var MIN_GROK = versionOf("grok").min;
|
|
7284
7383
|
var GROK_EVENTS = [
|
|
7285
7384
|
"SessionStart",
|
|
@@ -7288,7 +7387,7 @@ var GROK_EVENTS = [
|
|
|
7288
7387
|
"SessionEnd"
|
|
7289
7388
|
];
|
|
7290
7389
|
function grokHooksFile(env, home) {
|
|
7291
|
-
return
|
|
7390
|
+
return join25(grokHome(env, home), "hooks", "agent-rewake.json");
|
|
7292
7391
|
}
|
|
7293
7392
|
function grokHooksJson(node, launcher) {
|
|
7294
7393
|
const cmd = (event) => `"${node}" "${launcher}" hook grok ${event}`;
|
|
@@ -7317,7 +7416,7 @@ async function runGrokInstall(o) {
|
|
|
7317
7416
|
)[0];
|
|
7318
7417
|
const grok = picked && !o.uninstall ? withVersion(picked, probe) : picked;
|
|
7319
7418
|
const file = grokHooksFile(o.env, home);
|
|
7320
|
-
const installed =
|
|
7419
|
+
const installed = existsSync15(file);
|
|
7321
7420
|
if (o.uninstall) {
|
|
7322
7421
|
if (!installed) {
|
|
7323
7422
|
o.out("Rewake isn't set up in Grok Build: nothing to remove.\n");
|
|
@@ -7333,7 +7432,7 @@ async function runGrokInstall(o) {
|
|
|
7333
7432
|
}
|
|
7334
7433
|
if (grok.version && compareVersions(grok.version, MIN_GROK) < 0) {
|
|
7335
7434
|
o.out(
|
|
7336
|
-
`Grok Build ${grok.version} is too old for Rewake (it needs ${MIN_GROK} or newer). Update it with "grok update", then run "
|
|
7435
|
+
`Grok Build ${grok.version} is too old for Rewake (it needs ${MIN_GROK} or newer). Update it with "grok update", then run "${rewake("install --only grok")}" again.
|
|
7337
7436
|
`
|
|
7338
7437
|
);
|
|
7339
7438
|
return 1;
|
|
@@ -7368,13 +7467,13 @@ async function runGrokInstall(o) {
|
|
|
7368
7467
|
}
|
|
7369
7468
|
}
|
|
7370
7469
|
if (o.uninstall) {
|
|
7371
|
-
|
|
7470
|
+
rmSync12(file, { force: true });
|
|
7372
7471
|
o.out("Done. Rewake is out of Grok Build.\n");
|
|
7373
7472
|
return 0;
|
|
7374
7473
|
}
|
|
7375
7474
|
const launcher = ensureLauncher(o.stateDir, o.bundle) ?? launcherPath(o.stateDir);
|
|
7376
7475
|
writeFileAtomic(
|
|
7377
|
-
ensurePrivateDir(
|
|
7476
|
+
ensurePrivateDir(join25(grokHome(o.env, home), "hooks")),
|
|
7378
7477
|
"agent-rewake.json",
|
|
7379
7478
|
grokHooksJson(o.node, launcher)
|
|
7380
7479
|
);
|
|
@@ -7390,23 +7489,23 @@ async function runGrokInstall(o) {
|
|
|
7390
7489
|
}
|
|
7391
7490
|
|
|
7392
7491
|
// src/hosts/jetbrains/install.ts
|
|
7393
|
-
import { existsSync as
|
|
7492
|
+
import { existsSync as existsSync16, readFileSync as readFileSync21 } from "node:fs";
|
|
7394
7493
|
import { homedir as homedir13 } from "node:os";
|
|
7395
|
-
import { join as
|
|
7494
|
+
import { join as join26 } from "node:path";
|
|
7396
7495
|
var JETBRAINS_AGENTS = {
|
|
7397
7496
|
"Claude Agent (with Rewake)": "claude-acp",
|
|
7398
7497
|
"Codex (with Rewake)": "codex-acp"
|
|
7399
7498
|
};
|
|
7400
7499
|
function jetbrainsFile(env, home = homedir13()) {
|
|
7401
|
-
return
|
|
7500
|
+
return join26(
|
|
7402
7501
|
env.USERPROFILE && process.platform === "win32" ? env.USERPROFILE : home,
|
|
7403
7502
|
".jetbrains",
|
|
7404
7503
|
"acp.json"
|
|
7405
7504
|
);
|
|
7406
7505
|
}
|
|
7407
7506
|
function jetbrainsFound(env, home, platform4) {
|
|
7408
|
-
const dirs = platform4 === "darwin" ? [
|
|
7409
|
-
return dirs.some((d) =>
|
|
7507
|
+
const dirs = platform4 === "darwin" ? [join26(home, "Library", "Application Support", "JetBrains")] : platform4 === "win32" ? env.APPDATA ? [join26(env.APPDATA, "JetBrains")] : [] : [join26(env.XDG_CONFIG_HOME || join26(home, ".config"), "JetBrains")];
|
|
7508
|
+
return dirs.some((d) => existsSync16(d)) || existsSync16(join26(home, ".jetbrains"));
|
|
7410
7509
|
}
|
|
7411
7510
|
function jetbrainsInstalled(env, home) {
|
|
7412
7511
|
const v = readJson3(jetbrainsFile(env, home));
|
|
@@ -7422,7 +7521,7 @@ function readJson3(file) {
|
|
|
7422
7521
|
}
|
|
7423
7522
|
}
|
|
7424
7523
|
function planJetbrains(file, launch, uninstall) {
|
|
7425
|
-
const existed =
|
|
7524
|
+
const existed = existsSync16(file);
|
|
7426
7525
|
const before = existed ? readFileSync21(file, "utf8") : "";
|
|
7427
7526
|
const parsed = existed ? readJson3(file) : {};
|
|
7428
7527
|
if (!parsed)
|
|
@@ -7517,10 +7616,10 @@ function installedPreviews(env, home, stateDir2) {
|
|
|
7517
7616
|
const checks = [
|
|
7518
7617
|
["claude-code", () => modInstalled(env, home)],
|
|
7519
7618
|
["codex", () => pluginInstalled(env, home)],
|
|
7520
|
-
["copilot-cli", () =>
|
|
7521
|
-
["grok", () =>
|
|
7522
|
-
["gemini-cli", () =>
|
|
7523
|
-
["antigravity", () =>
|
|
7619
|
+
["copilot-cli", () => existsSync17(hooksFile(env, home))],
|
|
7620
|
+
["grok", () => existsSync17(grokHooksFile(env, home))],
|
|
7621
|
+
["gemini-cli", () => existsSync17(extensionDir(stateDir2))],
|
|
7622
|
+
["antigravity", () => existsSync17(pluginDir(env, home))],
|
|
7524
7623
|
["jetbrains", () => jetbrainsInstalled(env, home)],
|
|
7525
7624
|
["devin-desktop", () => devinInstalled(devinFile(env, home, process.platform))],
|
|
7526
7625
|
["cursor", () => cursorInstalled(home)]
|
|
@@ -7533,12 +7632,12 @@ var AGENT_NAME = "Agent Rewake";
|
|
|
7533
7632
|
var TASK_LABEL = "Agent Rewake: schedules";
|
|
7534
7633
|
var FORMAT = { insertSpaces: true, tabSize: 2, eol: "\n" };
|
|
7535
7634
|
function launchCommand(execPath = stableNode(), script = process.argv[1] ?? "", npxCli = npmScript("npx-cli.js", execPath)) {
|
|
7536
|
-
const real =
|
|
7635
|
+
const real = existsSync18(script) ? realpathSync5(script) : script;
|
|
7537
7636
|
if (/[\\/]_npx[\\/]/.test(real)) {
|
|
7538
7637
|
const pinned = ["--yes", `${PACKAGE_NAME}@${VERSION2}`];
|
|
7539
7638
|
if (npxCli) return { command: execPath, args: [npxCli, ...pinned] };
|
|
7540
|
-
const npx =
|
|
7541
|
-
return { command:
|
|
7639
|
+
const npx = join27(dirname6(execPath), platform3() === "win32" ? "npx.cmd" : "npx");
|
|
7640
|
+
return { command: existsSync18(npx) ? npx : "npx", args: pinned };
|
|
7542
7641
|
}
|
|
7543
7642
|
return { command: execPath, args: [real] };
|
|
7544
7643
|
}
|
|
@@ -7551,12 +7650,12 @@ function stableNode(execPath = process.execPath, env = process.env, p = platform
|
|
|
7551
7650
|
}
|
|
7552
7651
|
};
|
|
7553
7652
|
const self = real(execPath);
|
|
7554
|
-
const candidates = p === "win32" ? [findOnWindows("node", env,
|
|
7653
|
+
const candidates = p === "win32" ? [findOnWindows("node", env, existsSync18)] : (env.PATH ?? "").split(delimiter2).filter(Boolean).map((d) => join27(d, "node"));
|
|
7555
7654
|
for (const c of candidates) if (c && c !== execPath && self && real(c) === self) return c;
|
|
7556
7655
|
return execPath;
|
|
7557
7656
|
}
|
|
7558
7657
|
function selfCommand(execPath = process.execPath, script = process.argv[1] ?? "") {
|
|
7559
|
-
return { command: execPath, args: [
|
|
7658
|
+
return { command: execPath, args: [existsSync18(script) ? realpathSync5(script) : script] };
|
|
7560
7659
|
}
|
|
7561
7660
|
function wrappedEntry(original, target, launch) {
|
|
7562
7661
|
const { type: _type, command: _command, args: _args, ...rest } = original;
|
|
@@ -7622,7 +7721,7 @@ function keyChord() {
|
|
|
7622
7721
|
}
|
|
7623
7722
|
var KEY_ACTION = ["task::Spawn", { task_name: TASK_LABEL }];
|
|
7624
7723
|
function read(file) {
|
|
7625
|
-
return
|
|
7724
|
+
return existsSync18(file) ? { text: readText(file), existed: true } : { text: "", existed: false };
|
|
7626
7725
|
}
|
|
7627
7726
|
function parseJsonc(text2) {
|
|
7628
7727
|
const errors = [];
|
|
@@ -7631,8 +7730,8 @@ function parseJsonc(text2) {
|
|
|
7631
7730
|
return first ? { value, error: `${printParseErrorCode(first.error)} at offset ${first.offset}` } : { value };
|
|
7632
7731
|
}
|
|
7633
7732
|
function zedAgentSetting(agentId, key2, env = process.env) {
|
|
7634
|
-
const file =
|
|
7635
|
-
if (!
|
|
7733
|
+
const file = join27(zedConfigDir(env), "settings.json");
|
|
7734
|
+
if (!existsSync18(file)) return void 0;
|
|
7636
7735
|
const value = parseJsonc(readText(file)).value;
|
|
7637
7736
|
const servers = value && typeof value === "object" ? value.agent_servers : void 0;
|
|
7638
7737
|
const entry = servers && typeof servers === "object" ? servers[agentId] : void 0;
|
|
@@ -7670,7 +7769,7 @@ function planInstall(opts) {
|
|
|
7670
7769
|
const changes = [];
|
|
7671
7770
|
const notes = [];
|
|
7672
7771
|
const env = opts.env ?? process.env;
|
|
7673
|
-
const settingsFile =
|
|
7772
|
+
const settingsFile = join27(opts.dir, "settings.json");
|
|
7674
7773
|
const settings = read(settingsFile);
|
|
7675
7774
|
const base = settings.text.trim() === "" ? "{}\n" : settings.text;
|
|
7676
7775
|
const parsed = parseJsonc(base);
|
|
@@ -7758,7 +7857,7 @@ function planInstall(opts) {
|
|
|
7758
7857
|
]
|
|
7759
7858
|
});
|
|
7760
7859
|
}
|
|
7761
|
-
const tasksFile =
|
|
7860
|
+
const tasksFile = join27(opts.dir, "tasks.json");
|
|
7762
7861
|
const tasks = read(tasksFile);
|
|
7763
7862
|
const tasksBase = tasks.text.trim() === "" ? "[]\n" : tasks.text;
|
|
7764
7863
|
const tasksParsed = parseJsonc(tasksBase);
|
|
@@ -7784,7 +7883,7 @@ function planInstall(opts) {
|
|
|
7784
7883
|
});
|
|
7785
7884
|
}
|
|
7786
7885
|
if (opts.keybinding) {
|
|
7787
|
-
const keymapFile =
|
|
7886
|
+
const keymapFile = join27(opts.dir, "keymap.json");
|
|
7788
7887
|
const keymap = read(keymapFile);
|
|
7789
7888
|
const keymapBase = keymap.text.trim() === "" ? "[]\n" : keymap.text;
|
|
7790
7889
|
const keymapParsed = parseJsonc(keymapBase);
|
|
@@ -7814,8 +7913,8 @@ function planInstall(opts) {
|
|
|
7814
7913
|
}
|
|
7815
7914
|
return { changes, notes };
|
|
7816
7915
|
}
|
|
7817
|
-
function missingLaunchFiles(dir, exists =
|
|
7818
|
-
const parsed = parseJsonc(read(
|
|
7916
|
+
function missingLaunchFiles(dir, exists = existsSync18) {
|
|
7917
|
+
const parsed = parseJsonc(read(join27(dir, "settings.json")).text || "{}");
|
|
7819
7918
|
const servers = isRecord2(parsed.value) ? parsed.value.agent_servers : void 0;
|
|
7820
7919
|
if (parsed.error || !isRecord2(servers)) return [];
|
|
7821
7920
|
const missing = [];
|
|
@@ -7831,7 +7930,7 @@ function missingLaunchFiles(dir, exists = existsSync17) {
|
|
|
7831
7930
|
function planUninstall(dir) {
|
|
7832
7931
|
const changes = [];
|
|
7833
7932
|
const notes = [];
|
|
7834
|
-
const settingsFile =
|
|
7933
|
+
const settingsFile = join27(dir, "settings.json");
|
|
7835
7934
|
const settings = read(settingsFile);
|
|
7836
7935
|
const parsed = parseJsonc(settings.text || "{}");
|
|
7837
7936
|
const servers = isRecord2(parsed.value) ? parsed.value.agent_servers : void 0;
|
|
@@ -7858,7 +7957,7 @@ function planUninstall(dir) {
|
|
|
7858
7957
|
summary
|
|
7859
7958
|
});
|
|
7860
7959
|
}
|
|
7861
|
-
const tasksFile =
|
|
7960
|
+
const tasksFile = join27(dir, "tasks.json");
|
|
7862
7961
|
const tasks = read(tasksFile);
|
|
7863
7962
|
const taskList = parseJsonc(tasks.text || "[]");
|
|
7864
7963
|
if (!taskList.error && Array.isArray(taskList.value)) {
|
|
@@ -7874,7 +7973,7 @@ function planUninstall(dir) {
|
|
|
7874
7973
|
summary: [`Remove the task "${TASK_LABEL}"`]
|
|
7875
7974
|
});
|
|
7876
7975
|
}
|
|
7877
|
-
const keymapFile =
|
|
7976
|
+
const keymapFile = join27(dir, "keymap.json");
|
|
7878
7977
|
const keymap = read(keymapFile);
|
|
7879
7978
|
const blocks = parseJsonc(keymap.text || "[]");
|
|
7880
7979
|
if (!blocks.error && Array.isArray(blocks.value)) {
|
|
@@ -7910,7 +8009,7 @@ function applyPlan(plan, now = /* @__PURE__ */ new Date()) {
|
|
|
7910
8009
|
const backups = [];
|
|
7911
8010
|
for (const change of plan.changes) {
|
|
7912
8011
|
const target = change.existed ? realpathSync5(change.file) : change.file;
|
|
7913
|
-
const dir =
|
|
8012
|
+
const dir = dirname6(target);
|
|
7914
8013
|
if (!change.existed) ensurePrivateDir(dir);
|
|
7915
8014
|
let mode = 420;
|
|
7916
8015
|
let bom = "";
|
|
@@ -7921,14 +8020,7 @@ function applyPlan(plan, now = /* @__PURE__ */ new Date()) {
|
|
|
7921
8020
|
copyFileSync(target, backup);
|
|
7922
8021
|
backups.push(backup);
|
|
7923
8022
|
}
|
|
7924
|
-
const tmp =
|
|
7925
|
-
const fd = openSync8(tmp, "w", mode);
|
|
7926
|
-
try {
|
|
7927
|
-
writeSync3(fd, bom + change.after);
|
|
7928
|
-
fsyncSync3(fd);
|
|
7929
|
-
} finally {
|
|
7930
|
-
closeSync7(fd);
|
|
7931
|
-
}
|
|
8023
|
+
const tmp = writeTempExclusive(target, bom + change.after, mode);
|
|
7932
8024
|
if (process.platform === "win32" && change.existed && !(mode & 128)) chmodSync2(target, 438);
|
|
7933
8025
|
renameWithRetry(tmp, target);
|
|
7934
8026
|
}
|
|
@@ -8012,7 +8104,8 @@ ${note}
|
|
|
8012
8104
|
for (const b of backups) out(` Backup: ${b}
|
|
8013
8105
|
`);
|
|
8014
8106
|
out(
|
|
8015
|
-
opts.uninstall ?
|
|
8107
|
+
opts.uninstall ? `Rewake is out of Zed. Your threads are untouched, and your scheduled messages are kept; \`${rewake("doctor")}\` shows where.
|
|
8108
|
+
` : nextSteps(note !== void 0)
|
|
8016
8109
|
);
|
|
8017
8110
|
return 0;
|
|
8018
8111
|
}
|
|
@@ -8032,7 +8125,7 @@ function nextSteps(reachShown = false) {
|
|
|
8032
8125
|
`Now ${quitZed()} and open it again.`,
|
|
8033
8126
|
`Then open Zed's Agent Panel (${agentPanelKey()}) and open or start a thread with one of these agents.`,
|
|
8034
8127
|
"Zed starts Rewake when you open a thread with the agent, not when Zed itself starts.",
|
|
8035
|
-
"
|
|
8128
|
+
`\`${rewake("doctor")}\` shows whether it has started.`,
|
|
8036
8129
|
"",
|
|
8037
8130
|
'In the thread, the "Rewake" menu under the message box (next to the model picker) schedules messages.',
|
|
8038
8131
|
"When the agent hits a usage limit, Rewake asks you in the thread with Yes/No buttons.",
|
|
@@ -8237,7 +8330,7 @@ function overviewMarkdown(groups, now, locale) {
|
|
|
8237
8330
|
const lines = [
|
|
8238
8331
|
"# Agent Rewake: scheduled messages",
|
|
8239
8332
|
"",
|
|
8240
|
-
`Snapshot taken ${generated} by Agent Rewake ${VERSION2}. To manage them, run the "Agent Rewake: schedules" task in Zed (
|
|
8333
|
+
`Snapshot taken ${generated} by Agent Rewake ${VERSION2}. To manage them, run the "Agent Rewake: schedules" task in Zed (\`${rewake("ui")}\`), or use \`/rewake list\` in a thread.`,
|
|
8241
8334
|
""
|
|
8242
8335
|
];
|
|
8243
8336
|
if (groups.length === 0) lines.push("No scheduled messages.");
|
|
@@ -8262,7 +8355,7 @@ function overviewMarkdown(groups, now, locale) {
|
|
|
8262
8355
|
|
|
8263
8356
|
// src/util/keep-awake.ts
|
|
8264
8357
|
import { spawn as spawn6 } from "node:child_process";
|
|
8265
|
-
import { existsSync as
|
|
8358
|
+
import { existsSync as existsSync19 } from "node:fs";
|
|
8266
8359
|
import { platform as osPlatform3 } from "node:os";
|
|
8267
8360
|
var CAFFEINATE = "/usr/bin/caffeinate";
|
|
8268
8361
|
var Wakefulness = class {
|
|
@@ -8277,7 +8370,7 @@ var Wakefulness = class {
|
|
|
8277
8370
|
this.pid = opts.pid ?? process.pid;
|
|
8278
8371
|
}
|
|
8279
8372
|
get supported() {
|
|
8280
|
-
return this.platform === "darwin" &&
|
|
8373
|
+
return this.platform === "darwin" && existsSync19(this.program);
|
|
8281
8374
|
}
|
|
8282
8375
|
get holding() {
|
|
8283
8376
|
return this.child !== void 0 && this.child.exitCode === null && this.child.signalCode === null;
|
|
@@ -8318,7 +8411,7 @@ var Wakefulness = class {
|
|
|
8318
8411
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
8319
8412
|
import { readFileSync as readFileSync23 } from "node:fs";
|
|
8320
8413
|
import { homedir as homedir15, platform as osPlatform4 } from "node:os";
|
|
8321
|
-
import { join as
|
|
8414
|
+
import { join as join28 } from "node:path";
|
|
8322
8415
|
var SLEEP_DOCS_URL = "https://codizelabs.github.io/agent-rewake/docs/#keep-your-computer-awake";
|
|
8323
8416
|
var run2 = (command, args) => {
|
|
8324
8417
|
const r = spawnSync7(command, args, { encoding: "utf8", timeout: 3e3, windowsHide: true });
|
|
@@ -8424,7 +8517,7 @@ function linuxSleep(exec, env, home, read2) {
|
|
|
8424
8517
|
out.pluggedInSleepMin = kind === "nothing" || kind === "blank" ? 0 : Math.ceil(seconds / 60);
|
|
8425
8518
|
}
|
|
8426
8519
|
} else if (desktops.includes("kde")) {
|
|
8427
|
-
const rc = read2(
|
|
8520
|
+
const rc = read2(join28(env.XDG_CONFIG_HOME || join28(home, ".config"), "powerdevilrc"));
|
|
8428
8521
|
out.desktop = "kde";
|
|
8429
8522
|
const group = /\[AC\]\[SuspendAndShutdown\]([\s\S]*?)(?:\n\[|$)/.exec(rc ?? "")?.[1] ?? "";
|
|
8430
8523
|
const key2 = (k) => new RegExp(`^${k}=(\\S+)`, "m").exec(group)?.[1];
|
|
@@ -9278,7 +9371,7 @@ var SchedulingAddon = class {
|
|
|
9278
9371
|
}
|
|
9279
9372
|
for (const s of resumes)
|
|
9280
9373
|
if (s.status === "missed" || s.status === "needs_attention")
|
|
9281
|
-
this.store.
|
|
9374
|
+
this.store.cancel(s.scheduleId, now);
|
|
9282
9375
|
const thread = this.threads.get(session.sessionId);
|
|
9283
9376
|
const gate = this.autoGate(session, resetAt);
|
|
9284
9377
|
const delay = thread?.resumeDelayMs ?? DEFAULT_RESUME_DELAY_MS;
|
|
@@ -9531,8 +9624,7 @@ var SchedulingAddon = class {
|
|
|
9531
9624
|
const resumes = this.pending(session).filter(
|
|
9532
9625
|
(s) => s.kind !== "user" && s.status !== "sending" && s.createdAt < session.turnStartedAt
|
|
9533
9626
|
);
|
|
9534
|
-
for (const s of resumes)
|
|
9535
|
-
this.store.update(s.scheduleId, (x) => ({ ...x, status: "cancelled" }), this.now());
|
|
9627
|
+
for (const s of resumes) this.store.cancel(s.scheduleId, this.now());
|
|
9536
9628
|
if (resumes.length > 0) {
|
|
9537
9629
|
const kept = resumes.map((s) => this.keepFollowUps(session, s)).join("");
|
|
9538
9630
|
this.status(
|
|
@@ -10492,11 +10584,11 @@ ${this.listText(session)}`;
|
|
|
10492
10584
|
return command.on ? `Rewake: Automatic resume is on for this thread. After a usage limit, Rewake sends your resume message when the limit resets, follows the new reset time if ${this.agentName} is still limited, and never approves permission requests. Turn it off with /${COMMAND_NAME} auto off.` : "Rewake: Automatic resume is off for this thread. After a usage limit, Rewake will ask first.";
|
|
10493
10585
|
}
|
|
10494
10586
|
case "page": {
|
|
10495
|
-
const file =
|
|
10587
|
+
const file = join29(ensurePrivateDir(this.opts.stateDir), "Schedules.md");
|
|
10496
10588
|
writeFileSync3(file, overviewMarkdown(overview(this.opts.stateDir), now, this.opts.locale), {
|
|
10497
10589
|
mode: 384
|
|
10498
10590
|
});
|
|
10499
|
-
return `Rewake: [Open the overview of all scheduled messages](${pathToFileURL(file).href}) (a snapshot). To manage them, run the "Agent Rewake: schedules" task (
|
|
10591
|
+
return `Rewake: [Open the overview of all scheduled messages](${pathToFileURL(file).href}) (a snapshot). To manage them, run the "Agent Rewake: schedules" task (\`${rewake("setup zed")}\` prints it).`;
|
|
10500
10592
|
}
|
|
10501
10593
|
case "repeat":
|
|
10502
10594
|
return this.cmdRepeat(session, command.sub, command.words);
|
|
@@ -11414,7 +11506,9 @@ async function runContinue(o) {
|
|
|
11414
11506
|
if (o.mode === "always" || o.mode === "ask") {
|
|
11415
11507
|
saveSettings(o.deps.stateDir, { ...settings, newThreads: o.mode === "always" ? "on" : "ask" });
|
|
11416
11508
|
o.out(
|
|
11417
|
-
o.mode === "always" ?
|
|
11509
|
+
o.mode === "always" ? `From now on, when a session stops at a usage limit that resets within a day, Rewake continues it by itself once the session is closed. To be asked again: ${rewake("continue --ask")}
|
|
11510
|
+
` : `Rewake will ask again: after a usage limit, run "${rewake("continue")}" to continue a session.
|
|
11511
|
+
`
|
|
11418
11512
|
);
|
|
11419
11513
|
return 0;
|
|
11420
11514
|
}
|
|
@@ -11427,10 +11521,18 @@ async function runContinue(o) {
|
|
|
11427
11521
|
return 0;
|
|
11428
11522
|
}
|
|
11429
11523
|
for (const s of pending) {
|
|
11430
|
-
store.update(s.scheduleId, (x) => ({ ...x, status: "cancelled" }), now);
|
|
11431
|
-
o.deps.disarm(s.scheduleId);
|
|
11432
11524
|
const host = o.hosts.find((h) => h.id === s.host);
|
|
11433
|
-
|
|
11525
|
+
const place2 = host ? placeOf(host, s.cwd) : "a session";
|
|
11526
|
+
if (!store.cancel(s.scheduleId, now)) {
|
|
11527
|
+
const reopen = host?.reopen ?? `open the session in ${host?.name ?? "its agent"}`;
|
|
11528
|
+
o.out(
|
|
11529
|
+
`Not cancelled: Rewake is already continuing ${place2}. It finishes on its own; ${reopen} afterwards to see what it did.
|
|
11530
|
+
`
|
|
11531
|
+
);
|
|
11532
|
+
continue;
|
|
11533
|
+
}
|
|
11534
|
+
o.deps.disarm(s.scheduleId);
|
|
11535
|
+
o.out(`Cancelled: ${place2} ${formatAt(s.dueAt, now)}.
|
|
11434
11536
|
`);
|
|
11435
11537
|
}
|
|
11436
11538
|
return 0;
|
|
@@ -11448,12 +11550,12 @@ async function runContinue(o) {
|
|
|
11448
11550
|
if (!o.interactive) {
|
|
11449
11551
|
o.out(
|
|
11450
11552
|
`${list.map((c) => ` ${line(c)}`).join("\n")}
|
|
11451
|
-
Run "
|
|
11553
|
+
Run "${rewake("continue")}" in a terminal to choose.${list.some((c) => failedTry(c)) ? " If a try failed, open that session in its agent to continue it yourself." : ""}
|
|
11452
11554
|
`
|
|
11453
11555
|
);
|
|
11454
11556
|
return 1;
|
|
11455
11557
|
}
|
|
11456
|
-
let
|
|
11558
|
+
let chosen2 = list[0];
|
|
11457
11559
|
if (list.length > 1) {
|
|
11458
11560
|
o.out(
|
|
11459
11561
|
`Sessions stopped at a usage limit:
|
|
@@ -11468,22 +11570,22 @@ ${list.map((c, i) => ` ${i + 1}. ${line(c)}`).join("\n")}
|
|
|
11468
11570
|
o.out("Nothing was changed.\n");
|
|
11469
11571
|
return 1;
|
|
11470
11572
|
}
|
|
11471
|
-
|
|
11573
|
+
chosen2 = pick;
|
|
11472
11574
|
}
|
|
11473
|
-
const place = placeOf(
|
|
11474
|
-
const latest =
|
|
11475
|
-
const tooLate = () => `Rewake can continue ${place} only until ${formatWhen(latest ?? now, now)}, 4 hours after its usage limit. Choose an earlier time, or open the ${
|
|
11575
|
+
const place = placeOf(chosen2.host, chosen2.record.cwd);
|
|
11576
|
+
const latest = chosen2.host.maxWaitAfterLimitMs === void 0 ? void 0 : (chosen2.record.limit?.seenAt ?? now) + chosen2.host.maxWaitAfterLimitMs;
|
|
11577
|
+
const tooLate = () => `Rewake can continue ${place} only until ${formatWhen(latest ?? now, now)}, 4 hours after its usage limit. Choose an earlier time, or open the ${chosen2.host.noun ?? "session"} later and continue it yourself.
|
|
11476
11578
|
`;
|
|
11477
11579
|
if (latest !== void 0 && latest - now < 5 * 6e4) {
|
|
11478
11580
|
o.out(
|
|
11479
|
-
`Rewake can continue ${place} only within 4 hours of its usage limit, and that time has passed. Open the ${
|
|
11581
|
+
`Rewake can continue ${place} only within 4 hours of its usage limit, and that time has passed. Open the ${chosen2.host.noun ?? "session"} and continue it yourself.
|
|
11480
11582
|
`
|
|
11481
11583
|
);
|
|
11482
11584
|
return 1;
|
|
11483
11585
|
}
|
|
11484
11586
|
let at;
|
|
11485
|
-
if (
|
|
11486
|
-
at =
|
|
11587
|
+
if (chosen2.resetsAt && chosen2.resetsAt + RESET_MARGIN_MS > now) {
|
|
11588
|
+
at = chosen2.resetsAt + RESET_MARGIN_MS;
|
|
11487
11589
|
} else {
|
|
11488
11590
|
const presets = [1, 3, 5].map((h) => ({ h, at: now + h * 36e5 })).filter((p) => latest === void 0 || p.at <= latest);
|
|
11489
11591
|
o.out(
|
|
@@ -11520,8 +11622,8 @@ ${presets.map(
|
|
|
11520
11622
|
o.out(tooLate());
|
|
11521
11623
|
return 1;
|
|
11522
11624
|
}
|
|
11523
|
-
armClosed(
|
|
11524
|
-
o.out(`${armedText(
|
|
11625
|
+
armClosed(chosen2.host, chosen2.record, at, o.deps);
|
|
11626
|
+
o.out(`${armedText(chosen2.host, chosen2.record.cwd, at, now)}
|
|
11525
11627
|
`);
|
|
11526
11628
|
const risks = o.sleepSettings ? sleepRisks(o.sleepSettings(), "none") : [];
|
|
11527
11629
|
if (risks.length > 0)
|
|
@@ -11531,22 +11633,23 @@ ${presets.map(
|
|
|
11531
11633
|
);
|
|
11532
11634
|
if (settings.newThreads !== "on" && latest === void 0)
|
|
11533
11635
|
o.out(
|
|
11534
|
-
|
|
11636
|
+
`To let Rewake do this by itself next time (when the reset is within a day): ${rewake("continue --always")}
|
|
11637
|
+
`
|
|
11535
11638
|
);
|
|
11536
11639
|
return 0;
|
|
11537
11640
|
}
|
|
11538
11641
|
|
|
11539
11642
|
// src/doctor.ts
|
|
11540
|
-
import { existsSync as
|
|
11643
|
+
import { existsSync as existsSync21, readdirSync as readdirSync10, readFileSync as readFileSync25, rmSync as rmSync13, writeFileSync as writeFileSync4 } from "node:fs";
|
|
11541
11644
|
import { homedir as homedir16 } from "node:os";
|
|
11542
|
-
import { join as
|
|
11645
|
+
import { join as join31 } from "node:path";
|
|
11543
11646
|
|
|
11544
11647
|
// src/setup.ts
|
|
11545
|
-
import { existsSync as
|
|
11546
|
-
import { join as
|
|
11648
|
+
import { existsSync as existsSync20, readdirSync as readdirSync9, readFileSync as readFileSync24 } from "node:fs";
|
|
11649
|
+
import { join as join30 } from "node:path";
|
|
11547
11650
|
var isRecord3 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
11548
11651
|
function detectSetup(zedConfigDir2, stateDir2) {
|
|
11549
|
-
const file =
|
|
11652
|
+
const file = join30(zedConfigDir2, "settings.json");
|
|
11550
11653
|
const setup = {
|
|
11551
11654
|
settings: "missing",
|
|
11552
11655
|
aiOff: false,
|
|
@@ -11557,7 +11660,7 @@ function detectSetup(zedConfigDir2, stateDir2) {
|
|
|
11557
11660
|
};
|
|
11558
11661
|
const started = lastStart(stateDir2);
|
|
11559
11662
|
if (started) setup.lastStart = started;
|
|
11560
|
-
if (!
|
|
11663
|
+
if (!existsSync20(file)) return setup;
|
|
11561
11664
|
const errors = [];
|
|
11562
11665
|
const value = parse2(readText(file) || "{}", errors, { allowTrailingComma: true });
|
|
11563
11666
|
if (errors.length > 0 || !isRecord3(value)) return { ...setup, settings: "invalid" };
|
|
@@ -11580,7 +11683,7 @@ function agentName(id, env = process.env) {
|
|
|
11580
11683
|
return id === CLAUDE_REGISTRY_ID ? "Claude Agent" : id;
|
|
11581
11684
|
}
|
|
11582
11685
|
function lastStart(stateDir2) {
|
|
11583
|
-
const dir =
|
|
11686
|
+
const dir = join30(stateDir2, "logs");
|
|
11584
11687
|
let files;
|
|
11585
11688
|
try {
|
|
11586
11689
|
files = readdirSync9(dir).filter((f) => /^rewake-\d{4}-\d{2}-\d{2}\.jsonl$/.test(f)).sort().reverse();
|
|
@@ -11588,7 +11691,7 @@ function lastStart(stateDir2) {
|
|
|
11588
11691
|
return void 0;
|
|
11589
11692
|
}
|
|
11590
11693
|
for (const f of files) {
|
|
11591
|
-
const lines = readFileSync24(
|
|
11694
|
+
const lines = readFileSync24(join30(dir, f), "utf8").trim().split("\n").reverse();
|
|
11592
11695
|
for (const line of lines) {
|
|
11593
11696
|
try {
|
|
11594
11697
|
const r = JSON.parse(line);
|
|
@@ -11616,10 +11719,10 @@ function findZedApps(platform4 = process.platform, home = homedir16(), env = pro
|
|
|
11616
11719
|
const apps2 = [];
|
|
11617
11720
|
const names = ["Zed", "Zed Preview", "Zed Nightly", "Zed Dev"];
|
|
11618
11721
|
if (platform4 === "darwin") {
|
|
11619
|
-
for (const dir of ["/Applications",
|
|
11722
|
+
for (const dir of ["/Applications", join31(home, "Applications")]) {
|
|
11620
11723
|
for (const name of names) {
|
|
11621
|
-
const plist =
|
|
11622
|
-
if (!
|
|
11724
|
+
const plist = join31(dir, `${name}.app`, "Contents", "Info.plist");
|
|
11725
|
+
if (!existsSync21(plist) || apps2.some((a) => a.name === name)) continue;
|
|
11623
11726
|
const m = /<key>CFBundleShortVersionString<\/key>\s*<string>([^<]+)<\/string>/.exec(
|
|
11624
11727
|
readTextSafe(plist)
|
|
11625
11728
|
);
|
|
@@ -11632,12 +11735,12 @@ function findZedApps(platform4 = process.platform, home = homedir16(), env = pro
|
|
|
11632
11735
|
["Zed Preview", "zed-preview.app"],
|
|
11633
11736
|
["Zed Nightly", "zed-nightly.app"]
|
|
11634
11737
|
];
|
|
11635
|
-
for (const [name, dir] of local) if (
|
|
11636
|
-
if (
|
|
11738
|
+
for (const [name, dir] of local) if (existsSync21(join31(home, ".local", dir))) apps2.push({ name });
|
|
11739
|
+
if (existsSync21(join31(home, ".var", "app", "dev.zed.Zed"))) apps2.push({ name: "Zed (Flatpak)" });
|
|
11637
11740
|
} else if (platform4 === "win32") {
|
|
11638
|
-
const programs2 = env.LOCALAPPDATA ?
|
|
11741
|
+
const programs2 = env.LOCALAPPDATA ? join31(env.LOCALAPPDATA, "Programs") : void 0;
|
|
11639
11742
|
if (programs2) {
|
|
11640
|
-
for (const name of names) if (
|
|
11743
|
+
for (const name of names) if (existsSync21(join31(programs2, name))) apps2.push({ name });
|
|
11641
11744
|
}
|
|
11642
11745
|
}
|
|
11643
11746
|
return apps2;
|
|
@@ -11650,7 +11753,7 @@ function readTextSafe(file) {
|
|
|
11650
11753
|
}
|
|
11651
11754
|
}
|
|
11652
11755
|
function recentLogs(state, now, days = 14) {
|
|
11653
|
-
const dir =
|
|
11756
|
+
const dir = join31(state, "logs");
|
|
11654
11757
|
let files;
|
|
11655
11758
|
try {
|
|
11656
11759
|
files = readdirSync10(dir).filter((f) => /^rewake-\d{4}-\d{2}-\d{2}\.jsonl$/.test(f));
|
|
@@ -11662,7 +11765,7 @@ function recentLogs(state, now, days = 14) {
|
|
|
11662
11765
|
const out = [];
|
|
11663
11766
|
for (const f of files.sort()) {
|
|
11664
11767
|
if (f.slice(7, 17) < cutoff) continue;
|
|
11665
|
-
for (const line of readTextSafe(
|
|
11768
|
+
for (const line of readTextSafe(join31(dir, f)).split("\n")) {
|
|
11666
11769
|
if (!line.startsWith("{")) continue;
|
|
11667
11770
|
try {
|
|
11668
11771
|
const r = JSON.parse(line);
|
|
@@ -11676,7 +11779,7 @@ function recentLogs(state, now, days = 14) {
|
|
|
11676
11779
|
return out.sort((a, b) => a.t - b.t);
|
|
11677
11780
|
}
|
|
11678
11781
|
function readSettings(file) {
|
|
11679
|
-
if (!
|
|
11782
|
+
if (!existsSync21(file)) return { state: "missing", value: {} };
|
|
11680
11783
|
const errors = [];
|
|
11681
11784
|
const value = parse2(readText(file) || "{}", errors, { allowTrailingComma: true });
|
|
11682
11785
|
if (errors.length > 0 || !isRecord4(value)) return { state: "invalid", value: {} };
|
|
@@ -11705,7 +11808,7 @@ function diagnose(ctx) {
|
|
|
11705
11808
|
const reach = otherAgentsNote(ctx.agents?.() ?? [], ctx.previews?.() ?? []);
|
|
11706
11809
|
let reachShown = false;
|
|
11707
11810
|
const apps2 = ctx.zedApps();
|
|
11708
|
-
const settingsFile =
|
|
11811
|
+
const settingsFile = join31(zedDir, "settings.json");
|
|
11709
11812
|
const settings = readSettings(settingsFile);
|
|
11710
11813
|
if (apps2.length > 0) {
|
|
11711
11814
|
const old = apps2.filter((a) => a.version && compareVersions(a.version, MIN_ZED) < 0);
|
|
@@ -11823,8 +11926,8 @@ function diagnose(ctx) {
|
|
|
11823
11926
|
text: `Not on yet for: ${names(addable)}.`,
|
|
11824
11927
|
fix: `Run: ${install}`
|
|
11825
11928
|
});
|
|
11826
|
-
const noRegistry = !
|
|
11827
|
-
|
|
11929
|
+
const noRegistry = !existsSync21(
|
|
11930
|
+
join31(zedDataDir(env), "external_agents", "registry", "registry.json")
|
|
11828
11931
|
);
|
|
11829
11932
|
for (const [id, why] of skipped) {
|
|
11830
11933
|
if (noRegistry && /copy of the ACP Registry/.test(why)) continue;
|
|
@@ -11879,7 +11982,7 @@ function diagnose(ctx) {
|
|
|
11879
11982
|
const registryIds = Object.entries(servers).filter(([id, e]) => isRecord4(e) && id !== CLAUDE_REGISTRY_ID && id !== AGENT_NAME).filter(
|
|
11880
11983
|
([, e]) => isRecord4(e) && (e.type === "registry" || (unwrappedEntry(e)?.type ?? "") === "registry")
|
|
11881
11984
|
).map(([id]) => id);
|
|
11882
|
-
if (registryIds.length > 0 && !
|
|
11985
|
+
if (registryIds.length > 0 && !existsSync21(join31(zedDataDir(env), "external_agents", "registry", "registry.json")))
|
|
11883
11986
|
add({
|
|
11884
11987
|
area: "Zed",
|
|
11885
11988
|
level: "todo",
|
|
@@ -11907,7 +12010,7 @@ function diagnose(ctx) {
|
|
|
11907
12010
|
area: "Sign-in",
|
|
11908
12011
|
level: "todo",
|
|
11909
12012
|
text: "Zed's settings give Claude Agent an Anthropic API key, but Zed clears that key when Claude Agent runs through Rewake, so Claude uses your Claude sign-in instead.",
|
|
11910
|
-
fix:
|
|
12013
|
+
fix: `To keep using your Claude sign-in, remove the key from Claude Agent in Zed's settings. To use the API key instead, Rewake can't pass it on yet: run "${rewake("uninstall")}" for Claude Agent's setup without Rewake.`
|
|
11911
12014
|
});
|
|
11912
12015
|
}
|
|
11913
12016
|
if (env.AGENT_REWAKE_ALLOW_AUTO === "0")
|
|
@@ -12017,7 +12120,7 @@ function diagnose(ctx) {
|
|
|
12017
12120
|
area: "Scheduled messages",
|
|
12018
12121
|
level: "todo",
|
|
12019
12122
|
text: `${count(needsYou.length, "message")} need${needsYou.length === 1 ? "s" : ""} you (for example the reply was cut off, or the next reset is more than a day away).`,
|
|
12020
|
-
fix:
|
|
12123
|
+
fix: `Open the thread and use the Rewake menu, or run: ${rewake("ui")}`
|
|
12021
12124
|
});
|
|
12022
12125
|
if (failed.length > 0)
|
|
12023
12126
|
add({
|
|
@@ -12078,7 +12181,7 @@ function diagnose(ctx) {
|
|
|
12078
12181
|
level: fixed ? "info" : "problem",
|
|
12079
12182
|
text: `${who} couldn't start ${count(v.n, "time")}, last ${when(v.last, now)}${fixed ? "; it has started since" : ""}.`,
|
|
12080
12183
|
...!fixed && {
|
|
12081
|
-
fix: `Reopen the thread. If it keeps failing, run the install command again (${install}), or check that ${who} starts without Rewake (
|
|
12184
|
+
fix: `Reopen the thread. If it keeps failing, run the install command again (${install}), or check that ${who} starts without Rewake (${rewake("uninstall")}).`
|
|
12082
12185
|
}
|
|
12083
12186
|
});
|
|
12084
12187
|
}
|
|
@@ -12106,11 +12209,11 @@ function diagnose(ctx) {
|
|
|
12106
12209
|
return findings;
|
|
12107
12210
|
}
|
|
12108
12211
|
function canWrite(dir) {
|
|
12109
|
-
if (!
|
|
12212
|
+
if (!existsSync21(dir)) return true;
|
|
12110
12213
|
try {
|
|
12111
|
-
const probe =
|
|
12214
|
+
const probe = join31(dir, `.doctor-${process.pid}.tmp`);
|
|
12112
12215
|
writeFileSync4(probe, "");
|
|
12113
|
-
|
|
12216
|
+
rmSync13(probe, { force: true });
|
|
12114
12217
|
return true;
|
|
12115
12218
|
} catch {
|
|
12116
12219
|
return false;
|
|
@@ -12195,7 +12298,7 @@ function render(findings, opts) {
|
|
|
12195
12298
|
].filter(Boolean);
|
|
12196
12299
|
lines.push(`${parts.join(" and ")}.${first?.fix ? ` Start here: ${first.fix}` : ""}`);
|
|
12197
12300
|
}
|
|
12198
|
-
if (!opts.details) lines.push(
|
|
12301
|
+
if (!opts.details) lines.push(`More detail for a bug report: ${rewake("doctor --details")}`);
|
|
12199
12302
|
return `${lines.join("\n")}
|
|
12200
12303
|
`;
|
|
12201
12304
|
}
|
|
@@ -12328,7 +12431,7 @@ async function runCodexInstall(o) {
|
|
|
12328
12431
|
o.out(
|
|
12329
12432
|
[
|
|
12330
12433
|
"",
|
|
12331
|
-
|
|
12434
|
+
`Codex added the plugin but doesn't list Rewake's hooks, so it won't run them. This usually means your organisation's settings allow only hooks it manages (allow_managed_hooks_only). Ask whoever manages Codex for you, or remove the plugin with: ${rewake("uninstall --only codex")}`,
|
|
12332
12435
|
""
|
|
12333
12436
|
].join("\n")
|
|
12334
12437
|
);
|
|
@@ -12347,13 +12450,13 @@ async function runCodexInstall(o) {
|
|
|
12347
12450
|
}
|
|
12348
12451
|
|
|
12349
12452
|
// src/timers/waiter.ts
|
|
12350
|
-
import { readdirSync as readdirSync12, readFileSync as readFileSync27, rmSync as
|
|
12351
|
-
import { join as
|
|
12453
|
+
import { readdirSync as readdirSync12, readFileSync as readFileSync27, rmSync as rmSync15, writeFileSync as writeFileSync6 } from "node:fs";
|
|
12454
|
+
import { join as join33 } from "node:path";
|
|
12352
12455
|
|
|
12353
12456
|
// src/timers/timers.ts
|
|
12354
12457
|
import { spawn as spawn7, spawnSync as spawnSync8 } from "node:child_process";
|
|
12355
|
-
import { existsSync as
|
|
12356
|
-
import { join as
|
|
12458
|
+
import { existsSync as existsSync22, readdirSync as readdirSync11, readFileSync as readFileSync26, rmSync as rmSync14, writeFileSync as writeFileSync5 } from "node:fs";
|
|
12459
|
+
import { join as join32 } from "node:path";
|
|
12357
12460
|
var ID = /^[a-z0-9-]{1,64}$/;
|
|
12358
12461
|
function defaultTimerHost(stateDir2, node, cli) {
|
|
12359
12462
|
return {
|
|
@@ -12376,7 +12479,7 @@ function defaultTimerHost(stateDir2, node, cli) {
|
|
|
12376
12479
|
} catch {
|
|
12377
12480
|
}
|
|
12378
12481
|
},
|
|
12379
|
-
exists:
|
|
12482
|
+
exists: existsSync22,
|
|
12380
12483
|
uid: () => process.getuid?.(),
|
|
12381
12484
|
waiterRunning: (pid) => isWaiter(pid, cli)
|
|
12382
12485
|
};
|
|
@@ -12392,7 +12495,7 @@ function parseTimerName(name) {
|
|
|
12392
12495
|
var unit = (id) => `codizelabs-agent-rewake-${id}`;
|
|
12393
12496
|
var taskName = (id) => `\\AgentRewake\\${id}`;
|
|
12394
12497
|
function timersDir(h) {
|
|
12395
|
-
return ensurePrivateDir(
|
|
12498
|
+
return ensurePrivateDir(join32(h.stateDir, "timers"));
|
|
12396
12499
|
}
|
|
12397
12500
|
function checkId(id) {
|
|
12398
12501
|
if (!ID.test(id)) throw new Error(`invalid timer id: ${id}`);
|
|
@@ -12400,13 +12503,13 @@ function checkId(id) {
|
|
|
12400
12503
|
var MARK = { systemd: ".systemd", schtasks: ".task" };
|
|
12401
12504
|
function mark(name, kind, h) {
|
|
12402
12505
|
const ext = MARK[kind];
|
|
12403
|
-
if (ext) writeFileSync5(
|
|
12506
|
+
if (ext) writeFileSync5(join32(timersDir(h), `${name}${ext}`), "", { mode: 384 });
|
|
12404
12507
|
}
|
|
12405
12508
|
function timerNames(id, h) {
|
|
12406
12509
|
const names = /* @__PURE__ */ new Set([id]);
|
|
12407
12510
|
let files = [];
|
|
12408
12511
|
try {
|
|
12409
|
-
files = readdirSync11(
|
|
12512
|
+
files = readdirSync11(join32(h.stateDir, "timers"));
|
|
12410
12513
|
} catch {
|
|
12411
12514
|
}
|
|
12412
12515
|
for (const f of files) {
|
|
@@ -12443,11 +12546,11 @@ function launchdTarget(h) {
|
|
|
12443
12546
|
function launchdArm(id, at, h) {
|
|
12444
12547
|
const domain = launchdTarget(h);
|
|
12445
12548
|
if (!domain) return { ok: false, reason: "no-scheduler" };
|
|
12446
|
-
const plist =
|
|
12549
|
+
const plist = join32(timersDir(h), `${label(id)}.plist`);
|
|
12447
12550
|
writeFileSync5(plist, launchdPlist(id, at, h.node, h.cli, h.stateDir), { mode: 384 });
|
|
12448
12551
|
const r = h.run("launchctl", ["bootstrap", domain, plist]);
|
|
12449
12552
|
if (r.status === 0) return { ok: true, via: "launchd" };
|
|
12450
|
-
|
|
12553
|
+
rmSync14(plist, { force: true });
|
|
12451
12554
|
return { ok: false, reason: "failed", detail: r.stderr.trim() };
|
|
12452
12555
|
}
|
|
12453
12556
|
function systemdAvailable(h) {
|
|
@@ -12498,15 +12601,15 @@ function atArm(id, at, h) {
|
|
|
12498
12601
|
const n = /job (\d+)/.exec(`${r.stderr}
|
|
12499
12602
|
${r.stdout}`)?.[1];
|
|
12500
12603
|
if (r.status !== 0 || !n) return { ok: false, reason: "failed", detail: r.stderr.trim() };
|
|
12501
|
-
writeFileSync5(
|
|
12502
|
-
writeFileSync5(
|
|
12604
|
+
writeFileSync5(join32(timersDir(h), `${id}.at`), n, { mode: 384 });
|
|
12605
|
+
writeFileSync5(join32(timersDir(h), `${id}.at-time`), `${atTime(at)} ${h.node} ${h.cli}`, {
|
|
12503
12606
|
mode: 384
|
|
12504
12607
|
});
|
|
12505
12608
|
return { ok: true, via: "at" };
|
|
12506
12609
|
}
|
|
12507
12610
|
function atJob(id, h) {
|
|
12508
12611
|
try {
|
|
12509
|
-
const n = readFileSync26(
|
|
12612
|
+
const n = readFileSync26(join32(h.stateDir, "timers", `${id}.at`), "utf8").trim();
|
|
12510
12613
|
return /^\d+$/.test(n) ? n : void 0;
|
|
12511
12614
|
} catch {
|
|
12512
12615
|
return void 0;
|
|
@@ -12515,10 +12618,10 @@ function atJob(id, h) {
|
|
|
12515
12618
|
function atCancel(id, h) {
|
|
12516
12619
|
const n = atJob(id, h);
|
|
12517
12620
|
if (n) h.run("atrm", [n]);
|
|
12518
|
-
|
|
12519
|
-
|
|
12621
|
+
rmSync14(join32(h.stateDir, "timers", `${id}.at`), { force: true });
|
|
12622
|
+
rmSync14(join32(h.stateDir, "timers", `${id}.at-time`), { force: true });
|
|
12520
12623
|
}
|
|
12521
|
-
var waiterPid = (h) =>
|
|
12624
|
+
var waiterPid = (h) => join32(h.stateDir, "timers", "waiter.pid");
|
|
12522
12625
|
function waiterAlive(h) {
|
|
12523
12626
|
try {
|
|
12524
12627
|
const pid = Number(readFileSync26(waiterPid(h), "utf8").trim());
|
|
@@ -12536,12 +12639,12 @@ function isWaiter(pid, cli) {
|
|
|
12536
12639
|
}
|
|
12537
12640
|
}
|
|
12538
12641
|
function waiterArm(id, at, h) {
|
|
12539
|
-
writeFileSync5(
|
|
12642
|
+
writeFileSync5(join32(timersDir(h), `${id}.wait`), String(at), { mode: 384 });
|
|
12540
12643
|
if (waiterAlive(h) === void 0) h.detached(h.node, [h.cli, "wait", "--state-dir", h.stateDir]);
|
|
12541
12644
|
return { ok: true, via: "waiter" };
|
|
12542
12645
|
}
|
|
12543
12646
|
function waiterHas(name, h) {
|
|
12544
|
-
return
|
|
12647
|
+
return existsSync22(join32(h.stateDir, "timers", `${name}.wait`)) && waiterAlive(h) !== void 0;
|
|
12545
12648
|
}
|
|
12546
12649
|
function localIso(at) {
|
|
12547
12650
|
const d = new Date(Math.ceil(at / 1e3) * 1e3);
|
|
@@ -12577,10 +12680,10 @@ function taskXml(id, at, node, cli, stateDir2) {
|
|
|
12577
12680
|
}
|
|
12578
12681
|
function schtasksArm(id, at, h) {
|
|
12579
12682
|
h.run("schtasks", ["/Delete", "/TN", taskName(id), "/F"]);
|
|
12580
|
-
const file =
|
|
12683
|
+
const file = join32(timersDir(h), `${id}.xml`);
|
|
12581
12684
|
writeFileSync5(file, Buffer.from(`\uFEFF${taskXml(id, at, h.node, h.cli, h.stateDir)}`, "utf16le"));
|
|
12582
12685
|
const r = h.run("schtasks", ["/Create", "/TN", taskName(id), "/XML", file]);
|
|
12583
|
-
|
|
12686
|
+
rmSync14(file, { force: true });
|
|
12584
12687
|
if (r.status !== 0) return { ok: false, reason: "failed", detail: r.stderr.trim() };
|
|
12585
12688
|
mark(id, "schtasks", h);
|
|
12586
12689
|
return { ok: true, via: "schtasks" };
|
|
@@ -12629,19 +12732,19 @@ function nameArmed(name, kind, h) {
|
|
|
12629
12732
|
function timerStale(id, at, h) {
|
|
12630
12733
|
checkId(id);
|
|
12631
12734
|
const kind = timerKind(h);
|
|
12632
|
-
const dir =
|
|
12735
|
+
const dir = join32(h.stateDir, "timers");
|
|
12633
12736
|
if (kind === "launchd") {
|
|
12634
|
-
const names = timerNames(id, h).filter((n) =>
|
|
12737
|
+
const names = timerNames(id, h).filter((n) => existsSync22(join32(dir, `${label(n)}.plist`)));
|
|
12635
12738
|
if (names.length === 0) return false;
|
|
12636
12739
|
return !names.some(
|
|
12637
|
-
(n) => readFileSync26(
|
|
12740
|
+
(n) => readFileSync26(join32(dir, `${label(n)}.plist`), "utf8") === launchdPlist(n, at, h.node, h.cli, h.stateDir)
|
|
12638
12741
|
);
|
|
12639
12742
|
}
|
|
12640
12743
|
if (kind === "at") {
|
|
12641
|
-
const marks = timerNames(id, h).filter((n) =>
|
|
12744
|
+
const marks = timerNames(id, h).filter((n) => existsSync22(join32(dir, `${n}.at-time`)));
|
|
12642
12745
|
if (marks.length === 0) return false;
|
|
12643
12746
|
const want = `${atTime(at)} ${h.node} ${h.cli}`;
|
|
12644
|
-
return !marks.some((n) => readFileSync26(
|
|
12747
|
+
return !marks.some((n) => readFileSync26(join32(dir, `${n}.at-time`), "utf8") === want);
|
|
12645
12748
|
}
|
|
12646
12749
|
return false;
|
|
12647
12750
|
}
|
|
@@ -12656,11 +12759,11 @@ function cancelTimer(id, h, fromInsideTimer = false, keep) {
|
|
|
12656
12759
|
const kind = timerKind(h);
|
|
12657
12760
|
for (const name of timerNames(id, h)) {
|
|
12658
12761
|
if (name === keep) continue;
|
|
12659
|
-
const dir =
|
|
12762
|
+
const dir = join32(h.stateDir, "timers");
|
|
12660
12763
|
if (kind === "launchd") {
|
|
12661
|
-
const plist =
|
|
12662
|
-
const had =
|
|
12663
|
-
|
|
12764
|
+
const plist = join32(dir, `${label(name)}.plist`);
|
|
12765
|
+
const had = existsSync22(plist);
|
|
12766
|
+
rmSync14(plist, { force: true });
|
|
12664
12767
|
const domain = launchdTarget(h);
|
|
12665
12768
|
if (!domain || !had && name !== id) continue;
|
|
12666
12769
|
if (fromInsideTimer)
|
|
@@ -12668,12 +12771,12 @@ function cancelTimer(id, h, fromInsideTimer = false, keep) {
|
|
|
12668
12771
|
else h.run("launchctl", ["bootout", `${domain}/${label(name)}`]);
|
|
12669
12772
|
} else if (kind === "systemd") {
|
|
12670
12773
|
h.run("systemctl", ["--user", "stop", `${unit(name)}.timer`]);
|
|
12671
|
-
|
|
12774
|
+
rmSync14(join32(dir, `${name}.systemd`), { force: true });
|
|
12672
12775
|
} else if (kind === "at") atCancel(name, h);
|
|
12673
|
-
else if (kind === "waiter")
|
|
12776
|
+
else if (kind === "waiter") rmSync14(join32(dir, `${name}.wait`), { force: true });
|
|
12674
12777
|
else if (kind === "schtasks") {
|
|
12675
12778
|
h.run("schtasks", ["/Delete", "/TN", taskName(name), "/F"]);
|
|
12676
|
-
|
|
12779
|
+
rmSync14(join32(dir, `${name}.task`), { force: true });
|
|
12677
12780
|
}
|
|
12678
12781
|
}
|
|
12679
12782
|
}
|
|
@@ -12692,7 +12795,7 @@ function due(dir) {
|
|
|
12692
12795
|
const name = WAIT.exec(f)?.[1];
|
|
12693
12796
|
if (!name) return [];
|
|
12694
12797
|
try {
|
|
12695
|
-
const at = Number(readFileSync27(
|
|
12798
|
+
const at = Number(readFileSync27(join33(dir, f), "utf8").trim());
|
|
12696
12799
|
return Number.isFinite(at) ? [{ name, at }] : [];
|
|
12697
12800
|
} catch {
|
|
12698
12801
|
return [];
|
|
@@ -12700,8 +12803,8 @@ function due(dir) {
|
|
|
12700
12803
|
});
|
|
12701
12804
|
}
|
|
12702
12805
|
async function runWaiter(d) {
|
|
12703
|
-
const dir = ensurePrivateDir(
|
|
12704
|
-
const pidFile =
|
|
12806
|
+
const dir = ensurePrivateDir(join33(d.timers.stateDir, "timers"));
|
|
12807
|
+
const pidFile = join33(dir, "waiter.pid");
|
|
12705
12808
|
const other = waiterAlive(d.timers);
|
|
12706
12809
|
if (other !== void 0 && other !== d.pid) return 0;
|
|
12707
12810
|
writeFileSync6(pidFile, String(d.pid), { mode: 384 });
|
|
@@ -12717,12 +12820,12 @@ async function runWaiter(d) {
|
|
|
12717
12820
|
const waits = due(dir);
|
|
12718
12821
|
const now = d.now();
|
|
12719
12822
|
for (const w of waits.filter((x) => x.at <= now)) {
|
|
12720
|
-
|
|
12823
|
+
rmSync15(join33(dir, `${w.name}.wait`), { force: true });
|
|
12721
12824
|
d.fire(w.name);
|
|
12722
12825
|
}
|
|
12723
12826
|
const left = waits.filter((x) => x.at > now);
|
|
12724
12827
|
if (left.length === 0) {
|
|
12725
|
-
|
|
12828
|
+
rmSync15(pidFile, { force: true });
|
|
12726
12829
|
if (due(dir).length === 0) return 0;
|
|
12727
12830
|
writeFileSync6(pidFile, String(d.pid), { mode: 384 });
|
|
12728
12831
|
continue;
|
|
@@ -12750,10 +12853,10 @@ function waiterNote(wsl) {
|
|
|
12750
12853
|
|
|
12751
12854
|
// src/hosts/claude-code/records.ts
|
|
12752
12855
|
import { readdirSync as readdirSync13, readFileSync as readFileSync28 } from "node:fs";
|
|
12753
|
-
import { join as
|
|
12856
|
+
import { join as join34 } from "node:path";
|
|
12754
12857
|
var STALE_MS = 2 * 24 * 60 * 60 * 1e3;
|
|
12755
12858
|
function claudeCodeRecords(stateDir2, now) {
|
|
12756
|
-
const dir =
|
|
12859
|
+
const dir = join34(stateDir2, "hosts", "claude-code", "sessions");
|
|
12757
12860
|
let names;
|
|
12758
12861
|
try {
|
|
12759
12862
|
names = readdirSync13(dir).filter((n) => n.endsWith(".json"));
|
|
@@ -12763,7 +12866,7 @@ function claudeCodeRecords(stateDir2, now) {
|
|
|
12763
12866
|
const out = [];
|
|
12764
12867
|
for (const n of names) {
|
|
12765
12868
|
try {
|
|
12766
|
-
const r = JSON.parse(readFileSync28(
|
|
12869
|
+
const r = JSON.parse(readFileSync28(join34(dir, n), "utf8"));
|
|
12767
12870
|
if (r.host !== "claude-code" || typeof r.sessionId !== "string") continue;
|
|
12768
12871
|
if (typeof r.state !== "string" || typeof r.updatedAt !== "number") continue;
|
|
12769
12872
|
if (now - r.updatedAt > STALE_MS) continue;
|
|
@@ -12795,7 +12898,7 @@ function diagnoseOutside(f) {
|
|
|
12795
12898
|
add({
|
|
12796
12899
|
level: set ? "problem" : "info",
|
|
12797
12900
|
text: `${v.name} ${a.version} is too old for Rewake (it needs ${v.min} or newer), so ${set ? "Rewake may miss its usage limits" : "Rewake isn't set up for it"}.`,
|
|
12798
|
-
fix: `Update it with: ${v.update}${set ? "" : `, then run:
|
|
12901
|
+
fix: `Update it with: ${v.update}${set ? "" : `, then run: ${rewake(`install --only ${a.id}`)}`}`
|
|
12799
12902
|
});
|
|
12800
12903
|
} else if (setUp.has(a.id) && newerThanTested(a.id, a.version))
|
|
12801
12904
|
add({ level: "info", text: untestedText(a.id, a.version) });
|
|
@@ -12807,14 +12910,14 @@ function diagnoseOutside(f) {
|
|
|
12807
12910
|
add({
|
|
12808
12911
|
level: "problem",
|
|
12809
12912
|
text: `${p.name} has its hooks turned off, so Rewake can't see its usage limits.`,
|
|
12810
|
-
fix: `Turn hooks back on in ${p.name}'s settings, or take Rewake out of it:
|
|
12913
|
+
fix: `Turn hooks back on in ${p.name}'s settings, or take Rewake out of it: ${rewake(`uninstall --only ${p.id}`)}`
|
|
12811
12914
|
});
|
|
12812
12915
|
}
|
|
12813
12916
|
if (!f.hasTimer)
|
|
12814
12917
|
add({
|
|
12815
12918
|
level: "problem",
|
|
12816
12919
|
text: "Rewake can't continue sessions outside Zed by itself on this computer: it has no scheduler Rewake can use.",
|
|
12817
|
-
fix: f.platform === "linux" ? "Sign in to a normal desktop session, or install and start the at service." :
|
|
12920
|
+
fix: f.platform === "linux" ? "Sign in to a normal desktop session, or install and start the at service." : `Run ${rewake("doctor")} again after a restart; if it stays, report it with ${rewake("doctor --details")}.`
|
|
12818
12921
|
});
|
|
12819
12922
|
if (f.timerKind === "waiter") add({ level: "info", ...waiterNote(f.wsl ?? false) });
|
|
12820
12923
|
const resumes = new ScheduleStore(f.stateDir).list().filter((s) => s.host !== void 0);
|
|
@@ -12848,7 +12951,7 @@ function diagnoseOutside(f) {
|
|
|
12848
12951
|
add({
|
|
12849
12952
|
level: "todo",
|
|
12850
12953
|
text: `${n(needsYou.length, "resume")} need${needsYou.length === 1 ? "s" : ""} you.`,
|
|
12851
|
-
fix: `Review ${needsYou.length === 1 ? "it" : "them"} with:
|
|
12954
|
+
fix: `Review ${needsYou.length === 1 ? "it" : "them"} with: ${rewake("ui")}`
|
|
12852
12955
|
});
|
|
12853
12956
|
if (missed.length > 0)
|
|
12854
12957
|
add({
|
|
@@ -12860,7 +12963,7 @@ function diagnoseOutside(f) {
|
|
|
12860
12963
|
add({
|
|
12861
12964
|
level: "info",
|
|
12862
12965
|
text: `${n(failed.length, "resume")} failed in the last 7 days.${lastFailed?.failureMessage ? ` The last one, in ${name(lastFailed.host)}, ended with: "${lastFailed.failureMessage}"` : ""}`,
|
|
12863
|
-
fix: lastFailed?.failureMessage ?
|
|
12966
|
+
fix: lastFailed?.failureMessage ? `See all of them with: ${rewake("ui")}` : `See why with: ${rewake("ui")}`
|
|
12864
12967
|
});
|
|
12865
12968
|
if (out.length === 0)
|
|
12866
12969
|
add({
|
|
@@ -13003,14 +13106,13 @@ function codexHooks(deps) {
|
|
|
13003
13106
|
};
|
|
13004
13107
|
store.put(resume);
|
|
13005
13108
|
if (deps.arm(resume.scheduleId, at) !== false) return true;
|
|
13006
|
-
store.
|
|
13109
|
+
store.cancel(resume.scheduleId, ctx.now);
|
|
13007
13110
|
return false;
|
|
13008
13111
|
};
|
|
13009
13112
|
const cancelPending = (ctx, threadId) => {
|
|
13010
13113
|
const store = new ScheduleStore(ctx.stateDir);
|
|
13011
13114
|
for (const s of pendingFor2(store, threadId)) {
|
|
13012
|
-
store.
|
|
13013
|
-
deps.disarm(s.scheduleId);
|
|
13115
|
+
if (store.cancel(s.scheduleId, ctx.now)) deps.disarm(s.scheduleId);
|
|
13014
13116
|
}
|
|
13015
13117
|
};
|
|
13016
13118
|
return {
|
|
@@ -13133,8 +13235,6 @@ function resumeCopilot(r, text2, env, node = process.execPath) {
|
|
|
13133
13235
|
[
|
|
13134
13236
|
...program.args,
|
|
13135
13237
|
`--resume=${r.sessionId}`,
|
|
13136
|
-
"-p",
|
|
13137
|
-
text2,
|
|
13138
13238
|
"--no-ask-user",
|
|
13139
13239
|
"--output-format",
|
|
13140
13240
|
"json",
|
|
@@ -13143,10 +13243,11 @@ function resumeCopilot(r, text2, env, node = process.execPath) {
|
|
|
13143
13243
|
{
|
|
13144
13244
|
cwd: r.cwd || void 0,
|
|
13145
13245
|
env: { ...env, COPILOT_AUTO_UPDATE: "false" },
|
|
13146
|
-
stdio: ["
|
|
13246
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
13147
13247
|
windowsHide: true
|
|
13148
13248
|
}
|
|
13149
13249
|
);
|
|
13250
|
+
sendPromptOnStdin(child, text2);
|
|
13150
13251
|
let err = "";
|
|
13151
13252
|
child.stderr.on("data", (d) => {
|
|
13152
13253
|
if (err.length < 1 << 16) err += d.toString("utf8");
|
|
@@ -13423,7 +13524,7 @@ function defaultChoice(places) {
|
|
|
13423
13524
|
return new Set(places.filter((p) => p.state === "ready").map((p) => p.id));
|
|
13424
13525
|
}
|
|
13425
13526
|
var PREVIEW_NOTE = "Everything except Zed is a preview: new, and may change.";
|
|
13426
|
-
function renderChoice(places,
|
|
13527
|
+
function renderChoice(places, chosen2, cursor, missing) {
|
|
13427
13528
|
const lines = [];
|
|
13428
13529
|
places.forEach((p, i) => {
|
|
13429
13530
|
const pointer = i === cursor ? ">" : " ";
|
|
@@ -13434,7 +13535,7 @@ function renderChoice(places, chosen, cursor, missing) {
|
|
|
13434
13535
|
);
|
|
13435
13536
|
return;
|
|
13436
13537
|
}
|
|
13437
|
-
const box =
|
|
13538
|
+
const box = chosen2.has(p.id) ? "[x]" : "[ ]";
|
|
13438
13539
|
const note = p.state === "installed" ? ": Rewake is set up here (tick to update)" : "";
|
|
13439
13540
|
lines.push(`${pointer} ${box} ${label2}${note}`);
|
|
13440
13541
|
lines.push(` ${p.what}`);
|
|
@@ -13455,16 +13556,16 @@ function keyOf(data) {
|
|
|
13455
13556
|
if (data === "q" || data === "" || data === "\x1B") return "quit";
|
|
13456
13557
|
return "other";
|
|
13457
13558
|
}
|
|
13458
|
-
function press(key2, places,
|
|
13559
|
+
function press(key2, places, chosen2, state) {
|
|
13459
13560
|
const pickable = (i) => places[i]?.state !== "too-old";
|
|
13460
13561
|
if (key2 === "up") state.cursor = Math.max(0, state.cursor - 1);
|
|
13461
13562
|
if (key2 === "down") state.cursor = Math.min(places.length - 1, state.cursor + 1);
|
|
13462
13563
|
if (key2 === "toggle" && pickable(state.cursor)) {
|
|
13463
13564
|
const id = places[state.cursor]?.id;
|
|
13464
|
-
if (id)
|
|
13565
|
+
if (id) chosen2.has(id) ? chosen2.delete(id) : chosen2.add(id);
|
|
13465
13566
|
}
|
|
13466
13567
|
if (key2 === "all") {
|
|
13467
|
-
for (const p of places) if (p.state !== "too-old")
|
|
13568
|
+
for (const p of places) if (p.state !== "too-old") chosen2.add(p.id);
|
|
13468
13569
|
}
|
|
13469
13570
|
if (key2 === "enter") return "done";
|
|
13470
13571
|
if (key2 === "quit") return "quit";
|
|
@@ -13497,14 +13598,14 @@ function placesFrom(found, zed, installed, minimum, older, update = () => void 0
|
|
|
13497
13598
|
return out;
|
|
13498
13599
|
}
|
|
13499
13600
|
async function choosePlaces(places, missing, io) {
|
|
13500
|
-
const
|
|
13601
|
+
const chosen2 = defaultChoice(places);
|
|
13501
13602
|
const state = { cursor: 0 };
|
|
13502
13603
|
let drawn = 0;
|
|
13503
13604
|
const draw = () => {
|
|
13504
13605
|
const lines = [
|
|
13505
|
-
...renderChoice(places,
|
|
13606
|
+
...renderChoice(places, chosen2, state.cursor, missing),
|
|
13506
13607
|
"",
|
|
13507
|
-
keysHelp(
|
|
13608
|
+
keysHelp(chosen2.size)
|
|
13508
13609
|
];
|
|
13509
13610
|
if (drawn > 0) io.write(`\x1B[${drawn}A`);
|
|
13510
13611
|
io.write(`${lines.map((l) => `\x1B[2K${l}`).join("\n")}
|
|
@@ -13513,9 +13614,9 @@ async function choosePlaces(places, missing, io) {
|
|
|
13513
13614
|
};
|
|
13514
13615
|
draw();
|
|
13515
13616
|
for await (const data of io.keys) {
|
|
13516
|
-
const result = press(keyOf(data), places,
|
|
13617
|
+
const result = press(keyOf(data), places, chosen2, state);
|
|
13517
13618
|
if (result === "quit") return void 0;
|
|
13518
|
-
if (result === "done") return places.filter((p) =>
|
|
13619
|
+
if (result === "done") return places.filter((p) => chosen2.has(p.id)).map((p) => p.id);
|
|
13519
13620
|
draw();
|
|
13520
13621
|
}
|
|
13521
13622
|
return void 0;
|
|
@@ -14030,18 +14131,29 @@ async function fire(id, deps) {
|
|
|
14030
14131
|
});
|
|
14031
14132
|
switch (decision.action) {
|
|
14032
14133
|
case "send": {
|
|
14033
|
-
store.update(
|
|
14134
|
+
const claimed = store.update(
|
|
14034
14135
|
id,
|
|
14035
|
-
(x) =>
|
|
14136
|
+
(x) => x.status !== s.status || x.dueAt !== s.dueAt ? void 0 : {
|
|
14036
14137
|
...x,
|
|
14037
14138
|
status: "sending",
|
|
14038
14139
|
attempts: [
|
|
14039
14140
|
...x.attempts,
|
|
14040
|
-
{
|
|
14141
|
+
{
|
|
14142
|
+
n: x.attempts.length + 1,
|
|
14143
|
+
idempotencyKey: key2,
|
|
14144
|
+
startedAt: now,
|
|
14145
|
+
outcome: "sending"
|
|
14146
|
+
}
|
|
14041
14147
|
]
|
|
14042
|
-
}
|
|
14148
|
+
},
|
|
14043
14149
|
now
|
|
14044
14150
|
);
|
|
14151
|
+
if (claimed?.status !== "sending") {
|
|
14152
|
+
log("fire.changed", { status: claimed?.status ?? "gone" });
|
|
14153
|
+
if (!claimed || TERMINAL_STATUSES.has(claimed.status) || claimed.status === "cancelled")
|
|
14154
|
+
removeTimer();
|
|
14155
|
+
return "gone";
|
|
14156
|
+
}
|
|
14045
14157
|
let result;
|
|
14046
14158
|
const wake = deps.wake ?? new Wakefulness();
|
|
14047
14159
|
wake.set(true, settings.keepAwake);
|
|
@@ -14147,8 +14259,8 @@ function settleStale(id, s, host, now, deps, removeTimer) {
|
|
|
14147
14259
|
}
|
|
14148
14260
|
|
|
14149
14261
|
// src/timers/login.ts
|
|
14150
|
-
import { existsSync as
|
|
14151
|
-
import { dirname as
|
|
14262
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync3, readFileSync as readFileSync30, rmSync as rmSync16 } from "node:fs";
|
|
14263
|
+
import { dirname as dirname7, join as join35 } from "node:path";
|
|
14152
14264
|
var LOGIN_LABEL = "codizelabs.agent-rewake.sweep";
|
|
14153
14265
|
var UNIT = "agent-rewake-sweep.service";
|
|
14154
14266
|
var xml2 = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
@@ -14158,7 +14270,7 @@ function loginItem(h) {
|
|
|
14158
14270
|
if (h.platform === "darwin")
|
|
14159
14271
|
return {
|
|
14160
14272
|
kind: "launchd",
|
|
14161
|
-
path:
|
|
14273
|
+
path: join35(h.home, "Library", "LaunchAgents", `${LOGIN_LABEL}.plist`),
|
|
14162
14274
|
text: `<?xml version="1.0" encoding="UTF-8"?>
|
|
14163
14275
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
14164
14276
|
<plist version="1.0">
|
|
@@ -14178,7 +14290,7 @@ function loginItem(h) {
|
|
|
14178
14290
|
if (h.exists("/run/systemd/system"))
|
|
14179
14291
|
return {
|
|
14180
14292
|
kind: "systemd",
|
|
14181
|
-
path:
|
|
14293
|
+
path: join35(h.home, ".config", "systemd", "user", UNIT),
|
|
14182
14294
|
text: `[Unit]
|
|
14183
14295
|
Description=Agent Rewake: set planned resumes again after a restart
|
|
14184
14296
|
|
|
@@ -14192,7 +14304,7 @@ WantedBy=default.target
|
|
|
14192
14304
|
};
|
|
14193
14305
|
return {
|
|
14194
14306
|
kind: "autostart",
|
|
14195
|
-
path:
|
|
14307
|
+
path: join35(h.home, ".config", "autostart", "agent-rewake-sweep.desktop"),
|
|
14196
14308
|
text: `[Desktop Entry]
|
|
14197
14309
|
Type=Application
|
|
14198
14310
|
Name=Agent Rewake
|
|
@@ -14208,12 +14320,12 @@ X-GNOME-Autostart-enabled=true
|
|
|
14208
14320
|
function syncLoginItem(h, wanted) {
|
|
14209
14321
|
const item = loginItem(h);
|
|
14210
14322
|
if (!item) return "unchanged";
|
|
14211
|
-
const had =
|
|
14323
|
+
const had = existsSync23(item.path);
|
|
14212
14324
|
if (wanted) {
|
|
14213
14325
|
const same2 = had && readFileSync30(item.path, "utf8") === item.text;
|
|
14214
14326
|
if (same2) return "unchanged";
|
|
14215
|
-
mkdirSync3(
|
|
14216
|
-
|
|
14327
|
+
mkdirSync3(dirname7(item.path), { recursive: true });
|
|
14328
|
+
replaceFileExclusive(item.path, item.text, 420);
|
|
14217
14329
|
if (item.kind === "systemd") {
|
|
14218
14330
|
h.run("systemctl", ["--user", "daemon-reload"]);
|
|
14219
14331
|
h.run("systemctl", ["--user", "enable", UNIT]);
|
|
@@ -14222,7 +14334,7 @@ function syncLoginItem(h, wanted) {
|
|
|
14222
14334
|
}
|
|
14223
14335
|
if (!had) return "unchanged";
|
|
14224
14336
|
if (item.kind === "systemd") h.run("systemctl", ["--user", "disable", UNIT]);
|
|
14225
|
-
|
|
14337
|
+
rmSync16(item.path, { force: true });
|
|
14226
14338
|
if (item.kind === "systemd") h.run("systemctl", ["--user", "daemon-reload"]);
|
|
14227
14339
|
return "removed";
|
|
14228
14340
|
}
|
|
@@ -14417,15 +14529,15 @@ function textAfterLineBreak(data) {
|
|
|
14417
14529
|
}
|
|
14418
14530
|
|
|
14419
14531
|
// src/ui/page.ts
|
|
14420
|
-
import { readFileSync as readFileSync31, writeFileSync as
|
|
14421
|
-
import { join as
|
|
14532
|
+
import { readFileSync as readFileSync31, writeFileSync as writeFileSync7 } from "node:fs";
|
|
14533
|
+
import { join as join36 } from "node:path";
|
|
14422
14534
|
var TIPS = [
|
|
14423
14535
|
"In any thread, the Rewake menu under the message box does everything this page does.",
|
|
14424
14536
|
"Type /rewake in a thread to open the scheduling form, or /rewake 09:00 Run the tests to skip it.",
|
|
14425
14537
|
"When Claude hits its usage limit, Rewake asks in the thread whether to resume after the reset.",
|
|
14426
14538
|
"Hold Shift while dragging to select text on this page.",
|
|
14427
14539
|
"Messages are sent while Zed is open with that thread's project. Missed ones wait for you here.",
|
|
14428
|
-
"
|
|
14540
|
+
`The command "${rewake("schedules")}" prints this list as plain text, which works well with screen readers.`
|
|
14429
14541
|
];
|
|
14430
14542
|
var TIME_PRESETS = [
|
|
14431
14543
|
{ label: "In 30 min", value: "in 30m" },
|
|
@@ -14558,7 +14670,7 @@ var SchedulesPage = class {
|
|
|
14558
14670
|
return this.rows[this.selected];
|
|
14559
14671
|
}
|
|
14560
14672
|
prefsFile() {
|
|
14561
|
-
return
|
|
14673
|
+
return join36(this.opts.stateDir, "ui.json");
|
|
14562
14674
|
}
|
|
14563
14675
|
prefs() {
|
|
14564
14676
|
try {
|
|
@@ -14570,7 +14682,7 @@ var SchedulesPage = class {
|
|
|
14570
14682
|
savePrefs(p) {
|
|
14571
14683
|
try {
|
|
14572
14684
|
ensurePrivateDir(this.opts.stateDir);
|
|
14573
|
-
|
|
14685
|
+
writeFileSync7(this.prefsFile(), `${JSON.stringify(p)}
|
|
14574
14686
|
`, { mode: 384 });
|
|
14575
14687
|
} catch {
|
|
14576
14688
|
}
|
|
@@ -15370,7 +15482,7 @@ var HELP = [
|
|
|
15370
15482
|
"",
|
|
15371
15483
|
"# Good to know",
|
|
15372
15484
|
"Messages are sent while Zed is open with that thread's project.",
|
|
15373
|
-
|
|
15485
|
+
`Hold Shift while dragging to select text. Plain list: "${rewake("schedules")}"`,
|
|
15374
15486
|
"",
|
|
15375
15487
|
`Open source: ${REPO_URL} (a star there helps others find it)`
|
|
15376
15488
|
];
|
|
@@ -15492,7 +15604,8 @@ async function runTui(stateDir2, opts = {}) {
|
|
|
15492
15604
|
const { stdin, stdout } = process;
|
|
15493
15605
|
if (!stdin.isTTY || !stdout.isTTY) {
|
|
15494
15606
|
process.stderr.write(
|
|
15495
|
-
|
|
15607
|
+
`The schedules page needs an interactive terminal. For plain output, run "${rewake("schedules")}".
|
|
15608
|
+
`
|
|
15496
15609
|
);
|
|
15497
15610
|
return 2;
|
|
15498
15611
|
}
|
|
@@ -15576,7 +15689,7 @@ async function runTui(stateDir2, opts = {}) {
|
|
|
15576
15689
|
|
|
15577
15690
|
// src/util/log.ts
|
|
15578
15691
|
import { appendFileSync } from "node:fs";
|
|
15579
|
-
import { join as
|
|
15692
|
+
import { join as join37 } from "node:path";
|
|
15580
15693
|
var Logger = class {
|
|
15581
15694
|
constructor(env = process.env) {
|
|
15582
15695
|
this.env = env;
|
|
@@ -15598,8 +15711,8 @@ var Logger = class {
|
|
|
15598
15711
|
try {
|
|
15599
15712
|
const day = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
15600
15713
|
if (!this.file?.endsWith(`rewake-${day}.jsonl`)) {
|
|
15601
|
-
const dir = ensurePrivateDir(
|
|
15602
|
-
this.file =
|
|
15714
|
+
const dir = ensurePrivateDir(join37(stateDir(this.env), "logs"));
|
|
15715
|
+
this.file = join37(dir, `rewake-${day}.jsonl`);
|
|
15603
15716
|
}
|
|
15604
15717
|
const record = { t: (/* @__PURE__ */ new Date()).toISOString(), level, event, pid: process.pid, ...fields };
|
|
15605
15718
|
appendFileSync(this.file, `${JSON.stringify(record)}
|
|
@@ -15651,7 +15764,10 @@ Usage:
|
|
|
15651
15764
|
antigravity, jetbrains, devin-desktop. Without a terminal or
|
|
15652
15765
|
with --yes: Zed only
|
|
15653
15766
|
agent-rewake uninstall [--yes] [--dry-run]
|
|
15654
|
-
Take Rewake out of
|
|
15767
|
+
Take Rewake out of every place it's set up in (shows the
|
|
15768
|
+
changes and asks once)
|
|
15769
|
+
agent-rewake uninstall --only <place>[,<place>...] | --skip <place>[,<place>...]
|
|
15770
|
+
Take Rewake out of only the places you name, or all but some
|
|
15655
15771
|
agent-rewake setup zed Print the Zed settings, task and keybinding (to add by hand)
|
|
15656
15772
|
agent-rewake continue [--always | --ask | --cancel]
|
|
15657
15773
|
Continue a closed agent session after its usage limit resets.
|
|
@@ -15749,11 +15865,11 @@ async function main(argv, env = process.env) {
|
|
|
15749
15865
|
}
|
|
15750
15866
|
const yes = argv.includes("--yes") || argv.includes("-y");
|
|
15751
15867
|
const dryRun = argv.includes("--dry-run");
|
|
15752
|
-
let
|
|
15868
|
+
let chosen2;
|
|
15753
15869
|
let picked = false;
|
|
15754
|
-
if (places.length > 0)
|
|
15755
|
-
else if (argv.includes("--all")) {
|
|
15756
|
-
|
|
15870
|
+
if (places.length > 0) chosen2 = [...new Set(places)];
|
|
15871
|
+
else if (argv.includes("--all") || first === "uninstall") {
|
|
15872
|
+
chosen2 = pickablePlaces(env, first === "uninstall");
|
|
15757
15873
|
picked = true;
|
|
15758
15874
|
} else if (first === "install" && only.length === 0 && !yes && process.stdin.isTTY && process.stdout.isTTY) {
|
|
15759
15875
|
const pickedPlaces = await pickPlaces(env);
|
|
@@ -15761,17 +15877,17 @@ async function main(argv, env = process.env) {
|
|
|
15761
15877
|
process.stdout.write("Nothing was changed.\n");
|
|
15762
15878
|
return 1;
|
|
15763
15879
|
}
|
|
15764
|
-
|
|
15880
|
+
chosen2 = pickedPlaces;
|
|
15765
15881
|
picked = true;
|
|
15766
15882
|
} else {
|
|
15767
|
-
|
|
15883
|
+
chosen2 = ["zed"];
|
|
15768
15884
|
if (first === "install" && only.length === 0)
|
|
15769
15885
|
process.stdout.write(
|
|
15770
15886
|
"Setting up Zed (the default). To choose other places, run install in a terminal without --yes, or name them: --only claude-code,codex\n"
|
|
15771
15887
|
);
|
|
15772
15888
|
}
|
|
15773
|
-
|
|
15774
|
-
const bad = [...
|
|
15889
|
+
chosen2 = chosen2.filter((p) => !skip.includes(p));
|
|
15890
|
+
const bad = [...chosen2, ...skip].filter((p) => !INSTALL_PLACES.has(p));
|
|
15775
15891
|
if (bad.length > 0) {
|
|
15776
15892
|
process.stderr.write(
|
|
15777
15893
|
`agent-rewake: ${bad.join(", ")}: not a place Rewake can ${first === "install" ? "install into" : "remove from"}. Choose from: ${[...INSTALL_PLACES].join(", ")}.
|
|
@@ -15779,7 +15895,7 @@ async function main(argv, env = process.env) {
|
|
|
15779
15895
|
);
|
|
15780
15896
|
return 2;
|
|
15781
15897
|
}
|
|
15782
|
-
if (
|
|
15898
|
+
if (chosen2.length === 0) {
|
|
15783
15899
|
process.stdout.write("No places chosen: nothing was changed.\n");
|
|
15784
15900
|
return 0;
|
|
15785
15901
|
}
|
|
@@ -15839,7 +15955,7 @@ async function main(argv, env = process.env) {
|
|
|
15839
15955
|
});
|
|
15840
15956
|
return runAntigravityInstall(common);
|
|
15841
15957
|
};
|
|
15842
|
-
const order = [...INSTALL_PLACES].filter((p) =>
|
|
15958
|
+
const order = [...INSTALL_PLACES].filter((p) => chosen2.includes(p));
|
|
15843
15959
|
const print = (t) => {
|
|
15844
15960
|
process.stdout.write(t);
|
|
15845
15961
|
};
|
|
@@ -15859,10 +15975,18 @@ ${placeName(id)}
|
|
|
15859
15975
|
if (!uninstall && loginWouldAdd(env, order))
|
|
15860
15976
|
print(`
|
|
15861
15977
|
${loginItemPlanText(process.platform)}`);
|
|
15862
|
-
if (!
|
|
15978
|
+
if (!yes) {
|
|
15979
|
+
if (!interactive) {
|
|
15980
|
+
print(
|
|
15981
|
+
"\nNot a terminal, so nothing was changed. Run again with --yes to apply the changes above.\n"
|
|
15982
|
+
);
|
|
15983
|
+
return 1;
|
|
15984
|
+
}
|
|
15985
|
+
if (!await ask(`
|
|
15863
15986
|
Apply these changes to ${order.length} places? [y/N] `)) {
|
|
15864
|
-
|
|
15865
|
-
|
|
15987
|
+
print("Nothing was changed.\n");
|
|
15988
|
+
return 1;
|
|
15989
|
+
}
|
|
15866
15990
|
}
|
|
15867
15991
|
const results = [];
|
|
15868
15992
|
for (const id of order) {
|
|
@@ -15877,13 +16001,19 @@ Apply these changes to ${order.length} places? [y/N] `)) {
|
|
|
15877
16001
|
results.push([id, c, text2]);
|
|
15878
16002
|
code2 = Math.max(code2, c);
|
|
15879
16003
|
}
|
|
15880
|
-
print(summaryText(results));
|
|
16004
|
+
print(summaryText(results, uninstall ? "uninstall" : "install"));
|
|
16005
|
+
if (uninstall && code2 === 0)
|
|
16006
|
+
print(
|
|
16007
|
+
`
|
|
16008
|
+
Rewake's entries and hooks are gone from every place above. Its own folder, with your scheduled messages, is still on disk: "${rewake("doctor --details")}" shows where; delete it to finish.
|
|
16009
|
+
`
|
|
16010
|
+
);
|
|
15881
16011
|
} else {
|
|
15882
16012
|
if (!uninstall && loginWouldAdd(env, order)) print(loginItemPlanText(process.platform));
|
|
15883
16013
|
for (const id of order)
|
|
15884
16014
|
code2 = Math.max(code2, await runPlace(id, { yes, dryRun, out: print }));
|
|
15885
16015
|
}
|
|
15886
|
-
if (uninstall && !dryRun) cancelResumesOf(
|
|
16016
|
+
if (uninstall && !dryRun) cancelResumesOf(chosen2, env);
|
|
15887
16017
|
if (!dryRun) {
|
|
15888
16018
|
const change = syncLogin(env);
|
|
15889
16019
|
if (change !== "unchanged") print(loginItemText(change, process.platform));
|
|
@@ -15942,7 +16072,7 @@ Apply these changes to ${order.length} places? [y/N] `)) {
|
|
|
15942
16072
|
const sep2 = argv.indexOf("--");
|
|
15943
16073
|
if (wrap) {
|
|
15944
16074
|
try {
|
|
15945
|
-
const npmLog =
|
|
16075
|
+
const npmLog = join38(ensurePrivateDir(join38(stateDir(env), "logs")), "npm-install.log");
|
|
15946
16076
|
agent = await wrappedAgentCommand(wrap.target, wrap.extra, env, stateDir(env), npmLog);
|
|
15947
16077
|
} catch (err) {
|
|
15948
16078
|
log.error("agent.resolve_failed", {
|
|
@@ -16068,7 +16198,7 @@ function doctor(env, details) {
|
|
|
16068
16198
|
return findings.some((f) => f.level === "problem") ? 1 : 0;
|
|
16069
16199
|
}
|
|
16070
16200
|
function toolsRefused(state) {
|
|
16071
|
-
const dir =
|
|
16201
|
+
const dir = join38(state, "logs");
|
|
16072
16202
|
const agents = /* @__PURE__ */ new Set();
|
|
16073
16203
|
let files = [];
|
|
16074
16204
|
try {
|
|
@@ -16077,7 +16207,7 @@ function toolsRefused(state) {
|
|
|
16077
16207
|
return [];
|
|
16078
16208
|
}
|
|
16079
16209
|
for (const f of files) {
|
|
16080
|
-
for (const line of readFileSync32(
|
|
16210
|
+
for (const line of readFileSync32(join38(dir, f), "utf8").split("\n")) {
|
|
16081
16211
|
if (!line.includes("agent_tools.refused")) continue;
|
|
16082
16212
|
try {
|
|
16083
16213
|
const r = JSON.parse(line);
|
|
@@ -16098,9 +16228,9 @@ function setupZedText() {
|
|
|
16098
16228
|
const task = [taskEntry(launch)];
|
|
16099
16229
|
const keymap = [{ bindings: { [keyChord()]: ["task::Spawn", { task_name: TASK_LABEL }] } }];
|
|
16100
16230
|
const dir = zedConfigDir();
|
|
16101
|
-
const file = (name) =>
|
|
16231
|
+
const file = (name) => join38(dir, name);
|
|
16102
16232
|
return [
|
|
16103
|
-
|
|
16233
|
+
`Easiest: run \`${rewake("install")}\`, which adds these for you after asking.`,
|
|
16104
16234
|
"To add them by hand instead:",
|
|
16105
16235
|
"",
|
|
16106
16236
|
`1. ${file("settings.json")}: put Rewake in front of an agent you already use, under the`,
|
|
@@ -16189,14 +16319,14 @@ function placeName(id) {
|
|
|
16189
16319
|
};
|
|
16190
16320
|
return names[id] ?? id;
|
|
16191
16321
|
}
|
|
16192
|
-
function summaryText(results) {
|
|
16322
|
+
function summaryText(results, verb = "install") {
|
|
16193
16323
|
const width = Math.max(...results.map(([id]) => placeName(id).length));
|
|
16194
16324
|
const lines = results.map(([id, c, text2]) => {
|
|
16195
|
-
const said = text2.trim().split("\n").map((l) => l.trim()).filter(
|
|
16325
|
+
const said = text2.trim().split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("Backup:"));
|
|
16196
16326
|
const done = said.findIndex((l) => l.startsWith("Done"));
|
|
16197
16327
|
const next = c === 0 ? done >= 0 ? said.slice(done).join(" ").replace(/^Done\.?\s*/, "") : said.at(-1) ?? "" : said.at(-1) ?? "";
|
|
16198
16328
|
const state = c === 0 ? "done" : "not changed";
|
|
16199
|
-
const retry = c === 0 ? "" : ` Try it on its own:
|
|
16329
|
+
const retry = c === 0 ? "" : ` Try it on its own: ${rewake(`${verb} --only ${id}`)}`;
|
|
16200
16330
|
return ` ${placeName(id).padEnd(width)} ${state}${next ? `: ${next}` : ""}${retry}`;
|
|
16201
16331
|
});
|
|
16202
16332
|
return `
|
|
@@ -16205,8 +16335,13 @@ ${lines.join("\n")}
|
|
|
16205
16335
|
`;
|
|
16206
16336
|
}
|
|
16207
16337
|
function pickablePlaces(env, uninstall) {
|
|
16338
|
+
if (uninstall) {
|
|
16339
|
+
const zed = planUninstall(zedConfigDir(env)).changes.length > 0 ? ["zed"] : [];
|
|
16340
|
+
const ids = [...zed, ...installedPreviews(env, homedir19(), stateDir(env))];
|
|
16341
|
+
return ids.length > 0 ? ids : ["zed"];
|
|
16342
|
+
}
|
|
16208
16343
|
const { places } = placesHere(env);
|
|
16209
|
-
return places.filter((p) =>
|
|
16344
|
+
return places.filter((p) => p.state !== "too-old").map((p) => p.id);
|
|
16210
16345
|
}
|
|
16211
16346
|
async function pickPlaces(env) {
|
|
16212
16347
|
const { places, missing } = placesHere(env);
|
|
@@ -16245,7 +16380,7 @@ async function pickPlaces(env) {
|
|
|
16245
16380
|
}
|
|
16246
16381
|
function rewakeCli(state) {
|
|
16247
16382
|
const stable = launcherPath(state);
|
|
16248
|
-
if (
|
|
16383
|
+
if (existsSync24(stable)) return stable;
|
|
16249
16384
|
const bundle = process.argv[1] ?? "";
|
|
16250
16385
|
return bundle && ensureLauncher(state, bundle) || bundle || stable;
|
|
16251
16386
|
}
|
|
@@ -16260,7 +16395,7 @@ function cancelResumesOf(places, env) {
|
|
|
16260
16395
|
let n = 0;
|
|
16261
16396
|
for (const s of store.list()) {
|
|
16262
16397
|
if (s.host !== place || TERMINAL_STATUSES.has(s.status)) continue;
|
|
16263
|
-
store.
|
|
16398
|
+
if (!store.cancel(s.scheduleId, Date.now())) continue;
|
|
16264
16399
|
cancelTimer(s.scheduleId, timers);
|
|
16265
16400
|
n++;
|
|
16266
16401
|
}
|
|
@@ -16297,9 +16432,9 @@ function loginWouldAdd(env, places) {
|
|
|
16297
16432
|
cli: rewakeCli(state),
|
|
16298
16433
|
stateDir: state,
|
|
16299
16434
|
run: () => ({ status: 0 }),
|
|
16300
|
-
exists:
|
|
16435
|
+
exists: existsSync24
|
|
16301
16436
|
});
|
|
16302
|
-
return item !== void 0 && !
|
|
16437
|
+
return item !== void 0 && !existsSync24(item.path);
|
|
16303
16438
|
}
|
|
16304
16439
|
function syncLogin(env) {
|
|
16305
16440
|
try {
|
|
@@ -16314,7 +16449,7 @@ function syncLogin(env) {
|
|
|
16314
16449
|
cli: rewakeCli(state),
|
|
16315
16450
|
stateDir: state,
|
|
16316
16451
|
run: (cmd, args) => timers.run(cmd, args),
|
|
16317
|
-
exists:
|
|
16452
|
+
exists: existsSync24
|
|
16318
16453
|
},
|
|
16319
16454
|
wanted
|
|
16320
16455
|
);
|