@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.
@@ -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 existsSync23, readdirSync as readdirSync14, readFileSync as readFileSync32 } from "node:fs";
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 join36 } from "node:path";
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 join27 } from "node:path";
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 join2, win32 } from "node:path";
290
+ import { join as join3, win32 } from "node:path";
291
291
 
292
292
  // src/util/fs.ts
293
- import { closeSync, fsyncSync, openSync, readFileSync as readFileSync2, renameSync } from "node:fs";
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 ?? join2(homedir(), ".claude");
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 = join2(claudeConfigDir(env), "projects");
341
- const candidates = [join2(projects, encodeProjectDir(cwd), `${sessionId}.jsonl`)];
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(join2(projects, dir, `${sessionId}.jsonl`));
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
- join2(claudeConfigDir(env), "settings.json"),
402
- ...cwd ? [join2(cwd, ".claude", "settings.json"), join2(cwd, ".claude", "settings.local.json")] : []
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 join3 } from "node:path";
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 = join3(stateDir2, "locks");
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 join3(this.dir, `${h}.lock`);
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
- writeSync(fd, JSON.stringify(owner));
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
- rmSync(`${path}.stale.${this.token}`, { force: true });
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) rmSync(path, { force: true });
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 rmSync3 } from "node:fs";
2070
- import { join as join5 } from "node:path";
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 rmSync2,
2081
- writeSync as writeSync2
2137
+ rmSync as rmSync3,
2138
+ writeSync as writeSync3
2082
2139
  } from "node:fs";
2083
- import { join as join4 } from "node:path";
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 = join4(dir, `.${name}.${process.pid}.${randomUUID().slice(0, 8)}.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
- writeSync2(fd, data);
2195
+ writeSync3(fd, data);
2138
2196
  fsyncSync2(fd);
2139
2197
  } finally {
2140
2198
  closeSync4(fd);
2141
2199
  }
2142
- renameWithRetry(tmp, join4(dir, name));
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.dir = join4(stateDir2, "schedules");
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(join4(this.dir, `${scheduleId}.json`), "utf8"))
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
- rmSync2(join4(this.dir, `${scheduleId}.json`), { force: true });
2279
+ rmSync3(join5(this.dir, `${scheduleId}.json`), { force: true });
2220
2280
  return true;
2221
2281
  }
2222
- /** Update a schedule if it still exists. Returns the updated copy. */
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 current = this.get(scheduleId);
2225
- if (!current) return void 0;
2226
- const next = { ...change(current), updatedAt: now };
2227
- if (!validateSchedule(next)) throw new Error("Invalid scheduled message after update.");
2228
- this.put(next);
2229
- return next;
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 = join5(stateDir2, "requests");
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(join5(this.dir, `${requestId}.json`), "utf8")
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
- rmSync3(join5(this.dir, `${requestId}.json`), { force: true });
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 = join5(stateDir2, "links");
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(join5(this.dir, `${token}.json`), "utf8"));
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 join6 } from "node:path";
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(join6(stateDir2, "settings.json"), "utf8"));
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 rmSync4 } from "node:fs";
2390
- import { join as join7 } from "node:path";
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 = join7(stateDir2, "threads");
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(join7(this.dir, this.file(sessionId)), "utf8")
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
- rmSync4(join7(this.dir, this.file(sessionId)), { force: true });
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(join7(this.dir, name), "utf8"));
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 { basename as basename4, delimiter as delimiter2, dirname as dirname5, join as join25, posix as posix3, win32 as win325 } from "node:path";
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 existsSync16 } from "node:fs";
4074
+ import { existsSync as existsSync17 } from "node:fs";
3992
4075
 
3993
4076
  // src/hosts/antigravity/install.ts
3994
- import { existsSync as existsSync5, rmSync as rmSync5 } from "node:fs";
4077
+ import { existsSync as existsSync6, rmSync as rmSync6 } from "node:fs";
3995
4078
  import { homedir as homedir5 } from "node:os";
3996
- import { join as join13 } from "node:path";
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 dirname3, join as join9 } from "node:path";
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 dirname2, join as join8, posix as posix2, win32 as win323 } from "node:path";
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 = join8(
4076
- dirname2(process.env.ComSpec ?? "C:\\Windows\\System32\\cmd.exe"),
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) => join9(dir, command)).filter(isFile)
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 = dirname3(file);
4227
+ let dir = dirname4(file);
4145
4228
  for (let i = 0; i < 6; i++) {
4146
- const pkg2 = readJson(join9(dir, "package.json"));
4229
+ const pkg2 = readJson(join10(dir, "package.json"));
4147
4230
  if (pkg2?.name === name && typeof pkg2.version === "string") return pkg2.version;
4148
- const parent = dirname3(dir);
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(join9(app, "Contents", "Info.plist"), "utf8");
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", join9(h.home, "Applications")];
4165
- return dirs.map((d) => join9(d, `${name}.app`)).filter((a) => existsSync3(a));
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 = join9(h.home, ".local", "bin", "claude");
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 = join9(h.home, "Library", "Application Support", "Claude", "claude-code");
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(join9(root, version));
4284
+ builds = readdirSync5(join10(root, version));
4202
4285
  } catch {
4203
4286
  continue;
4204
4287
  }
4205
4288
  for (const b of builds) {
4206
- const path = join9(root, version, b, "claude.app", "Contents", "MacOS", "claude");
4207
- if (existsSync3(join9(root, version, b, ".verified")) && isFile(path))
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 = join9(h.home, "Library", "Application Support", "Claude", "claude-code");
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(join9(root, v));
4311
+ builds = readdirSync5(join10(root, v));
4229
4312
  } catch {
4230
4313
  continue;
4231
4314
  }
4232
- if (builds.some((b) => existsSync3(join9(root, v, b, "claude.app")))) desktop.push(v);
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 || join9(h.home, ".local", "bin");
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
- join9(dir, "codex"),
4252
- ...h.platform === "win32" && localAppData ? [join9(localAppData, "Programs", "OpenAI", "Codex", "bin", "codex")] : []
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 = join9(app, "Contents", "Resources", "codex-cli");
4342
+ const d = join10(app, "Contents", "Resources", "codex-cli");
4260
4343
  if (!existsSync3(d)) continue;
4261
- const v = readJson(join9(d, "codex-package.json"))?.version;
4344
+ const v = readJson(join10(d, "codex-package.json"))?.version;
4262
4345
  found.push({
4263
- path: join9(d, "bin", "codex"),
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
- join9(h.home, ".local", "bin", "copilot"),
4285
- ...h.platform === "win32" && appData ? [join9(appData, "npm", "copilot")] : []
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 || join9(h.home, ".grok", "bin");
4294
- return programs("grok", h, [join9(grokBin, "grok")]).map((path) => {
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 ? [join9(appData, "npm", "gemini")] : [];
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
- join9(h.home, ".local", "bin", "agy"),
4311
- ...h.platform === "win32" && localAppData ? [join9(localAppData, "agy", "bin", "agy")] : []
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
- join9(h.home, ".local", "bin", "agy"),
4328
- ...h.platform === "win32" && localAppData ? [join9(localAppData, "agy", "bin", "agy")] : []
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) => join9(h.home, ".local", "bin", cmd);
4360
- const grokBin = h.env.GROK_BIN_DIR || join9(h.home, ".grok", "bin");
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 ? [join9(appData, "npm", cmd)] : [];
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
- [join9(grokBin, "grok")],
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 join10 } from "node:path";
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.0" : "0.0.0");
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 join10(stateDir2, "bin", "agent-rewake.mjs");
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(join10(stateDir2, "bin"));
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(join10(stateDir2, "bin", "agent-rewake.version"), "utf8").trim() || void 0;
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 join12, resolve, sep } from "node:path";
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 basename2 } from "node:path";
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: basename(m[2]).replace(/^-/, "") } : void 0;
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 join11 } from "node:path";
4688
- var PAUSE = new Int32Array(new SharedArrayBuffer(4));
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 = join11(stateDir2, "hosts", host, "sessions");
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(join11(this.dir, `${sessionId}.json`), "utf8"));
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(PAUSE, 0, 0, 20);
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 ? basename2(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: agent-rewake continue --cancel`;
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.update(s.scheduleId, (x) => ({ ...x, status: "cancelled" }), d.now);
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 "agent-rewake continue" ${how}.`
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.update(s.scheduleId, (x) => ({ ...x, status: "cancelled" }), d.now);
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 || join12(home, ".gemini");
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(join12(g, s) + sep)) return s;
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(join12(stateDir2, "hosts", ANTIGRAVITY_ID, "notified"));
5263
- const file = join12(dir, `${id}.json`);
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 join13(geminiHome(env, home), "config", "plugins", "agent-rewake");
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 = existsSync5(dir);
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
- rmSync5(dir, { recursive: true, force: true });
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 existsSync6,
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 rmSync6
5528
+ rmSync as rmSync7
5424
5529
  } from "node:fs";
5425
- import { homedir as homedir6, tmpdir } from "node:os";
5426
- import { dirname as dirname4, join as join14 } from "node:path";
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 "agent-rewake install --only ${place}" again.
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 agent-rewake doctor --details.`;
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
- rmSync6(join14(dir, entry), { recursive: true, force: true });
5514
- cpSync(join14(source, entry), join14(dir, entry), { recursive: true });
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(join14(dir, ".claude-plugin", "plugin.json"), "utf8")).version;
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 join14(stateDir2, "hosts", "claude-code");
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 join14(dirname4(real), "hosts", "claude-code");
5660
+ return join16(dirname5(real), "hosts", "claude-code");
5556
5661
  }
5557
5662
  function claudeConfigDir2(env, home) {
5558
- return env.CLAUDE_CONFIG_DIR || join14(home, ".claude");
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
- join14(claudeConfigDir2(env, home), "plugins", "installed_plugins.json"),
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 = mkdtempSync(join14(tmpdir(), "rewake-probe-"));
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
- rmSync6(empty, { recursive: true, force: true });
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 (!existsSync6(join14(source, ".claude-plugin", "plugin.json"))) {
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
- rmSync6(modDir(o.stateDir), { recursive: true, force: true });
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 && existsSync6(join14(dir, ".claude-plugin", "plugin.json"))) {
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
- rmSync6(dir, { recursive: true, force: true });
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
- rmSync6(dir, { recursive: true, force: true });
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 existsSync7, readFileSync as readFileSync15, rmSync as rmSync7 } from "node:fs";
5744
- import { join as join15 } from "node:path";
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 join15(stateDir2, "hosts", "codex-marketplace");
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(join15(root, "plugins", "agent-rewake"));
5881
+ const plugin = ensurePrivateDir(join17(root, "plugins", "agent-rewake"));
5777
5882
  writeFileAtomic(
5778
- ensurePrivateDir(join15(root, ".agents", "plugins")),
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(join15(plugin, ".codex-plugin")),
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(join15(plugin, "hooks")), "hooks.json", hooksJson(node, launcher));
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 || join15(home, ".codex");
5928
+ return env.CODEX_HOME || join17(home, ".codex");
5824
5929
  }
5825
5930
  function pluginInstalled(env, home) {
5826
- const file = join15(codexHome(env, home), "config.toml");
5827
- if (!existsSync7(file)) return false;
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
- rmSync7(marketplaceDir(stateDir2), { recursive: true, force: true });
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 existsSync10, rmSync as rmSync9 } from "node:fs";
5963
+ import { existsSync as existsSync11, rmSync as rmSync10 } from "node:fs";
5859
5964
  import { homedir as homedir9 } from "node:os";
5860
- import { join as join19 } from "node:path";
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 join18 } from "node:path";
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 existsSync8, readFileSync as readFileSync16, rmSync as rmSync8 } from "node:fs";
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 join16 } from "node:path";
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
- ...program.args,
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 rewakeCommand(args, id, cwd, d) {
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.update(s.scheduleId, (x) => ({ ...x, status: "cancelled" }), d.now);
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.update(s.scheduleId, (x) => ({ ...x, status: "cancelled" }), d.now);
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 = rewakeCommand(prompt2.slice(REWAKE_MARKER.length).trim(), id, cwd, d);
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 join16(stateDir2, "hosts", "gemini-extension");
6283
+ return join18(stateDir2, "hosts", "gemini-extension");
6190
6284
  }
6191
6285
  function geminiSettingsFile(env, home) {
6192
- return join16(env.GEMINI_CLI_HOME || home, ".gemini", "settings.json");
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(join16(dir, "hooks")),
6338
+ ensurePrivateDir(join18(dir, "hooks")),
6245
6339
  "hooks.json",
6246
6340
  geminiHooksJson(node, launcher)
6247
6341
  );
6248
6342
  writeFileAtomic(
6249
- ensurePrivateDir(join16(dir, "commands")),
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?.() ?? existsSync8(extensionDir(o.stateDir));
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 "agent-rewake install --only gemini-cli" again.
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 "agent-rewake install --only gemini-cli" again.
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 "agent-rewake install --only gemini-cli" in a terminal; Gemini CLI asks you to confirm.
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
- rmSync8(extensionDir(o.stateDir), { recursive: true, force: true });
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
- rmSync8(dir, { recursive: true, force: true });
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
- rmSync8(dir, { recursive: true, force: true });
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 existsSync9, readFileSync as readFileSync17 } from "node:fs";
6461
+ import { existsSync as existsSync10, readFileSync as readFileSync17 } from "node:fs";
6368
6462
  import { homedir as homedir8 } from "node:os";
6369
- import { join as join17 } from "node:path";
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 || join17(home, ".grok");
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 = join17(home, "logs", "unified.jsonl");
6389
- if (!existsSync9(file)) return { full: false };
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(join17(home, "active_sessions.json"), "utf8"));
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
- "-p",
6455
- text2,
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", () => resolve2({ ok: false, reason: "failed", detail: "spawn" }));
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 = join18(copilotHome(env, home), "settings.json");
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(join18(grokHome(env, home), "disabled-hooks"), "utf8");
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 || join19(home, ".copilot");
6697
+ return env.COPILOT_HOME || join21(home, ".copilot");
6599
6698
  }
6600
6699
  function hooksFile(env, home) {
6601
- return join19(copilotHome(env, home), "hooks", "agent-rewake.json");
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 = existsSync10(file);
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 "agent-rewake install --only copilot-cli" again.
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
- rmSync9(file, { force: true });
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(join19(copilotHome(o.env, home), "hooks")),
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 existsSync11, readFileSync as readFileSync19 } from "node:fs";
6809
+ import { existsSync as existsSync12, readFileSync as readFileSync19 } from "node:fs";
6711
6810
  import { homedir as homedir10 } from "node:os";
6712
- import { join as join20 } from "node:path";
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 join20(home, ".cursor", "hooks.json");
6815
+ return join22(home, ".cursor", "hooks.json");
6717
6816
  }
6718
6817
  function cursorFound(env, home, platform4) {
6719
- const apps2 = platform4 === "darwin" ? ["/Applications/Cursor.app", join20(home, "Applications", "Cursor.app")] : platform4 === "win32" ? env.LOCALAPPDATA ? [join20(env.LOCALAPPDATA, "Programs", "cursor", "Cursor.exe")] : [] : ["/usr/share/cursor", "/opt/Cursor", "/opt/cursor"];
6720
- if (apps2.some((a) => existsSync11(a))) return true;
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) => existsSync11(join20(d, 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 = existsSync11(file);
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
- "When a Cursor chat stops at its usage limit, run agent-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.",
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 existsSync13, readFileSync as readFileSync20 } from "node:fs";
6935
+ import { existsSync as existsSync14, readFileSync as readFileSync20 } from "node:fs";
6837
6936
  import { homedir as homedir11 } from "node:os";
6838
- import { join as join22 } from "node:path";
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 existsSync12,
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 rmSync10,
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 basename3, join as join21, win32 as win324 } from "node:path";
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 = join21(zedDataDir(env), "external_agents", "registry", "registry.json");
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(join21(dir, "node_modules", pkg2, "package.json"));
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 = join21(dir, "node_modules", pkg2);
7058
+ const root = join23(dir, "node_modules", pkg2);
6960
7059
  let json;
6961
7060
  try {
6962
- json = readJsonFile(join21(root, "package.json"));
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 join21(root, bin);
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 chosen = bin[short] ?? Object.values(bin)[0];
6971
- return typeof chosen === "string" ? join21(root, chosen) : void 0;
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 = join21(zedDataDir(env), "external_agents", "registry", "npx", safeName(id));
6980
- const ownDir = join21(stateDir2, "agents", "npx", safeName(id));
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 join21(
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 = join21(dir, cmd.slice(2));
7012
- return existsSync12(path) ? path : void 0;
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 = join21(zedDataDir(env), "external_agents", "registry", zedSafeName(id));
7018
- const own = join21(stateDir2, "agents", "bin", safeName(id));
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) => join21(base, d)).sort((a, b) => statSync3(b).mtimeMs - statSync3(a).mtimeMs);
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(join21(stateDir2, "agents", "bin", safeName(id)));
7035
- const dest = join21(base, `v_${safeName(version)}`);
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
- rmSync10(tmp, { recursive: true, force: true });
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 = basename3(new URL(target.archive).pathname) || "agent";
7049
- const file = join21(tmp, name);
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
- rmSync10(file, { force: true });
7153
+ rmSync11(file, { force: true });
7055
7154
  } else if (/\.(tar\.gz|tgz)$/.test(lower)) {
7056
7155
  unpack(unpackers("gz", file, tmp));
7057
- rmSync10(file, { force: true });
7156
+ rmSync11(file, { force: true });
7058
7157
  } else if (/\.(tar\.bz2|tbz2?)$/.test(lower)) {
7059
7158
  unpack(unpackers("bz2", file, tmp));
7060
- rmSync10(file, { force: true });
7159
+ rmSync11(file, { force: true });
7061
7160
  } else if (target.cmd.replace(/^\.[\\/]/, "") !== name) {
7062
- renameSync2(file, join21(tmp, target.cmd.slice(2)));
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
- rmSync10(dest, { recursive: true, force: true });
7166
+ rmSync11(dest, { recursive: true, force: true });
7068
7167
  renameWithRetry(tmp, dest);
7069
- return join21(dest, target.cmd.slice(2));
7168
+ return join23(dest, target.cmd.slice(2));
7070
7169
  } catch (err) {
7071
- rmSync10(tmp, { recursive: true, force: true });
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 (agent-rewake uninstall), then reopen the thread.`
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 agent-rewake uninstall to restore the original entry.`
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 agent-rewake uninstall to restore it.`
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 join22(
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 = join22(home, ".windsurf-next");
7158
- const dir = existsSync13(join22(home, ".windsurf")) || !existsSync13(next) ? ".windsurf" : ".windsurf-next";
7159
- return join22(home, dir, "acp", "registry.json");
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 existsSync13(join22(home, ".windsurf")) || existsSync13(join22(home, ".windsurf-next"));
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 = existsSync13(file);
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 existsSync14, rmSync as rmSync11 } from "node:fs";
7379
+ import { existsSync as existsSync15, rmSync as rmSync12 } from "node:fs";
7281
7380
  import { homedir as homedir12 } from "node:os";
7282
- import { join as join23 } from "node:path";
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 join23(grokHome(env, home), "hooks", "agent-rewake.json");
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 = existsSync14(file);
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 "agent-rewake install --only grok" again.
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
- rmSync11(file, { force: true });
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(join23(grokHome(o.env, home), "hooks")),
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 existsSync15, readFileSync as readFileSync21 } from "node:fs";
7492
+ import { existsSync as existsSync16, readFileSync as readFileSync21 } from "node:fs";
7394
7493
  import { homedir as homedir13 } from "node:os";
7395
- import { join as join24 } from "node:path";
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 join24(
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" ? [join24(home, "Library", "Application Support", "JetBrains")] : platform4 === "win32" ? env.APPDATA ? [join24(env.APPDATA, "JetBrains")] : [] : [join24(env.XDG_CONFIG_HOME || join24(home, ".config"), "JetBrains")];
7409
- return dirs.some((d) => existsSync15(d)) || existsSync15(join24(home, ".jetbrains"));
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 = existsSync15(file);
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", () => existsSync16(hooksFile(env, home))],
7521
- ["grok", () => existsSync16(grokHooksFile(env, home))],
7522
- ["gemini-cli", () => existsSync16(extensionDir(stateDir2))],
7523
- ["antigravity", () => existsSync16(pluginDir(env, home))],
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 = existsSync17(script) ? realpathSync5(script) : script;
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 = join25(dirname5(execPath), platform3() === "win32" ? "npx.cmd" : "npx");
7541
- return { command: existsSync17(npx) ? npx : "npx", args: pinned };
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, existsSync17)] : (env.PATH ?? "").split(delimiter2).filter(Boolean).map((d) => join25(d, "node"));
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: [existsSync17(script) ? realpathSync5(script) : script] };
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 existsSync17(file) ? { text: readText(file), existed: true } : { text: "", existed: false };
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 = join25(zedConfigDir(env), "settings.json");
7635
- if (!existsSync17(file)) return void 0;
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 = join25(opts.dir, "settings.json");
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 = join25(opts.dir, "tasks.json");
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 = join25(opts.dir, "keymap.json");
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 = existsSync17) {
7818
- const parsed = parseJsonc(read(join25(dir, "settings.json")).text || "{}");
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 = join25(dir, "settings.json");
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 = join25(dir, "tasks.json");
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 = join25(dir, "keymap.json");
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 = dirname5(target);
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 = join25(dir, `.${basename4(target)}.agent-rewake.${process.pid}.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 ? "Rewake is out of your agents. Your threads are untouched, and your scheduled messages are kept; `agent-rewake doctor` shows where.\n" : nextSteps(note !== void 0)
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
- "`agent-rewake doctor` shows whether it has started.",
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 (\`agent-rewake ui\`), or use \`/rewake list\` in a thread.`,
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 existsSync18 } from "node:fs";
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" && existsSync18(this.program);
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 join26 } from "node:path";
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(join26(env.XDG_CONFIG_HOME || join26(home, ".config"), "powerdevilrc"));
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.update(s.scheduleId, (x) => ({ ...x, status: "cancelled" }), now);
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 = join27(ensurePrivateDir(this.opts.stateDir), "Schedules.md");
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 (\`agent-rewake setup zed\` prints it).`;
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" ? "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: agent-rewake continue --ask\n" : 'Rewake will ask again: after a usage limit, run "agent-rewake continue" to continue a session.\n'
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
- o.out(`Cancelled: ${host ? placeOf(host, s.cwd) : "a session"} ${formatAt(s.dueAt, now)}.
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 "agent-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." : ""}
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 chosen = list[0];
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
- chosen = pick;
11573
+ chosen2 = pick;
11472
11574
  }
11473
- const place = placeOf(chosen.host, chosen.record.cwd);
11474
- const latest = chosen.host.maxWaitAfterLimitMs === void 0 ? void 0 : (chosen.record.limit?.seenAt ?? now) + chosen.host.maxWaitAfterLimitMs;
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 ${chosen.host.noun ?? "session"} later and continue it yourself.
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 ${chosen.host.noun ?? "session"} and continue it yourself.
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 (chosen.resetsAt && chosen.resetsAt + RESET_MARGIN_MS > now) {
11486
- at = chosen.resetsAt + RESET_MARGIN_MS;
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(chosen.host, chosen.record, at, o.deps);
11524
- o.out(`${armedText(chosen.host, chosen.record.cwd, at, now)}
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
- "To let Rewake do this by itself next time (when the reset is within a day): agent-rewake continue --always\n"
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 existsSync20, readdirSync as readdirSync10, readFileSync as readFileSync25, rmSync as rmSync12, writeFileSync as writeFileSync4 } from "node:fs";
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 join29 } from "node:path";
11645
+ import { join as join31 } from "node:path";
11543
11646
 
11544
11647
  // src/setup.ts
11545
- import { existsSync as existsSync19, readdirSync as readdirSync9, readFileSync as readFileSync24 } from "node:fs";
11546
- import { join as join28 } from "node:path";
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 = join28(zedConfigDir2, "settings.json");
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 (!existsSync19(file)) return setup;
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 = join28(stateDir2, "logs");
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(join28(dir, f), "utf8").trim().split("\n").reverse();
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", join29(home, "Applications")]) {
11722
+ for (const dir of ["/Applications", join31(home, "Applications")]) {
11620
11723
  for (const name of names) {
11621
- const plist = join29(dir, `${name}.app`, "Contents", "Info.plist");
11622
- if (!existsSync20(plist) || apps2.some((a) => a.name === name)) continue;
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 (existsSync20(join29(home, ".local", dir))) apps2.push({ name });
11636
- if (existsSync20(join29(home, ".var", "app", "dev.zed.Zed"))) apps2.push({ name: "Zed (Flatpak)" });
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 ? join29(env.LOCALAPPDATA, "Programs") : void 0;
11741
+ const programs2 = env.LOCALAPPDATA ? join31(env.LOCALAPPDATA, "Programs") : void 0;
11639
11742
  if (programs2) {
11640
- for (const name of names) if (existsSync20(join29(programs2, name))) apps2.push({ name });
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 = join29(state, "logs");
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(join29(dir, f)).split("\n")) {
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 (!existsSync20(file)) return { state: "missing", value: {} };
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 = join29(zedDir, "settings.json");
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 = !existsSync20(
11827
- join29(zedDataDir(env), "external_agents", "registry", "registry.json")
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 && !existsSync20(join29(zedDataDir(env), "external_agents", "registry", "registry.json")))
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: "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 agent-rewake uninstall for Claude Agent's setup without Rewake."
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: "Open the thread and use the Rewake menu, or run: agent-rewake ui"
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 (agent-rewake uninstall).`
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 (!existsSync20(dir)) return true;
12212
+ if (!existsSync21(dir)) return true;
12110
12213
  try {
12111
- const probe = join29(dir, `.doctor-${process.pid}.tmp`);
12214
+ const probe = join31(dir, `.doctor-${process.pid}.tmp`);
12112
12215
  writeFileSync4(probe, "");
12113
- rmSync12(probe, { force: true });
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("More detail for a bug report: agent-rewake doctor --details");
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
- "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: agent-rewake uninstall --only codex",
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 rmSync14, writeFileSync as writeFileSync6 } from "node:fs";
12351
- import { join as join31 } from "node:path";
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 existsSync21, readdirSync as readdirSync11, readFileSync as readFileSync26, rmSync as rmSync13, writeFileSync as writeFileSync5 } from "node:fs";
12356
- import { join as join30 } from "node:path";
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: existsSync21,
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(join30(h.stateDir, "timers"));
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(join30(timersDir(h), `${name}${ext}`), "", { mode: 384 });
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(join30(h.stateDir, "timers"));
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 = join30(timersDir(h), `${label(id)}.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
- rmSync13(plist, { force: true });
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(join30(timersDir(h), `${id}.at`), n, { mode: 384 });
12502
- writeFileSync5(join30(timersDir(h), `${id}.at-time`), `${atTime(at)} ${h.node} ${h.cli}`, {
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(join30(h.stateDir, "timers", `${id}.at`), "utf8").trim();
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
- rmSync13(join30(h.stateDir, "timers", `${id}.at`), { force: true });
12519
- rmSync13(join30(h.stateDir, "timers", `${id}.at-time`), { force: true });
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) => join30(h.stateDir, "timers", "waiter.pid");
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(join30(timersDir(h), `${id}.wait`), String(at), { mode: 384 });
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 existsSync21(join30(h.stateDir, "timers", `${name}.wait`)) && waiterAlive(h) !== void 0;
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 = join30(timersDir(h), `${id}.xml`);
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
- rmSync13(file, { force: true });
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 = join30(h.stateDir, "timers");
12735
+ const dir = join32(h.stateDir, "timers");
12633
12736
  if (kind === "launchd") {
12634
- const names = timerNames(id, h).filter((n) => existsSync21(join30(dir, `${label(n)}.plist`)));
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(join30(dir, `${label(n)}.plist`), "utf8") === launchdPlist(n, at, h.node, h.cli, h.stateDir)
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) => existsSync21(join30(dir, `${n}.at-time`)));
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(join30(dir, `${n}.at-time`), "utf8") === want);
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 = join30(h.stateDir, "timers");
12762
+ const dir = join32(h.stateDir, "timers");
12660
12763
  if (kind === "launchd") {
12661
- const plist = join30(dir, `${label(name)}.plist`);
12662
- const had = existsSync21(plist);
12663
- rmSync13(plist, { force: true });
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
- rmSync13(join30(dir, `${name}.systemd`), { force: true });
12774
+ rmSync14(join32(dir, `${name}.systemd`), { force: true });
12672
12775
  } else if (kind === "at") atCancel(name, h);
12673
- else if (kind === "waiter") rmSync13(join30(dir, `${name}.wait`), { force: true });
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
- rmSync13(join30(dir, `${name}.task`), { force: true });
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(join31(dir, f), "utf8").trim());
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(join31(d.timers.stateDir, "timers"));
12704
- const pidFile = join31(dir, "waiter.pid");
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
- rmSync14(join31(dir, `${w.name}.wait`), { force: true });
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
- rmSync14(pidFile, { force: true });
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 join32 } from "node:path";
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 = join32(stateDir2, "hosts", "claude-code", "sessions");
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(join32(dir, n), "utf8"));
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: agent-rewake install --only ${a.id}`}`
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: agent-rewake uninstall --only ${p.id}`
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." : "Run agent-rewake doctor again after a restart; if it stays, report it with agent-rewake doctor --details."
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: agent-rewake ui`
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 ? "See all of them with: agent-rewake ui" : "See why with: agent-rewake ui"
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.update(resume.scheduleId, (x) => ({ ...x, status: "cancelled" }), ctx.now);
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.update(s.scheduleId, (x) => ({ ...x, status: "cancelled" }), ctx.now);
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: ["ignore", "pipe", "pipe"],
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, chosen, cursor, missing) {
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 = chosen.has(p.id) ? "[x]" : "[ ]";
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, chosen, state) {
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) chosen.has(id) ? chosen.delete(id) : chosen.add(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") chosen.add(p.id);
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 chosen = defaultChoice(places);
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, chosen, state.cursor, missing),
13606
+ ...renderChoice(places, chosen2, state.cursor, missing),
13506
13607
  "",
13507
- keysHelp(chosen.size)
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, chosen, state);
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) => chosen.has(p.id)).map((p) => p.id);
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
- { n: x.attempts.length + 1, idempotencyKey: key2, startedAt: now, outcome: "sending" }
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 existsSync22, mkdirSync as mkdirSync3, readFileSync as readFileSync30, rmSync as rmSync15, writeFileSync as writeFileSync7 } from "node:fs";
14151
- import { dirname as dirname6, join as join33 } from "node:path";
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, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
@@ -14158,7 +14270,7 @@ function loginItem(h) {
14158
14270
  if (h.platform === "darwin")
14159
14271
  return {
14160
14272
  kind: "launchd",
14161
- path: join33(h.home, "Library", "LaunchAgents", `${LOGIN_LABEL}.plist`),
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: join33(h.home, ".config", "systemd", "user", UNIT),
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: join33(h.home, ".config", "autostart", "agent-rewake-sweep.desktop"),
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 = existsSync22(item.path);
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(dirname6(item.path), { recursive: true });
14216
- writeFileSync7(item.path, item.text, { mode: 420 });
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
- rmSync15(item.path, { force: true });
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 writeFileSync8 } from "node:fs";
14421
- import { join as join34 } from "node:path";
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
- "agent-rewake schedules prints this list as plain text, which works well with screen readers."
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 join34(this.opts.stateDir, "ui.json");
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
- writeFileSync8(this.prefsFile(), `${JSON.stringify(p)}
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
- "Hold Shift while dragging to select text. Plain list: agent-rewake schedules",
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
- "agent-rewake ui needs an interactive terminal. Use `agent-rewake schedules` for plain output.\n"
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 join35 } from "node:path";
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(join35(stateDir(this.env), "logs"));
15602
- this.file = join35(dir, `rewake-${day}.jsonl`);
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 your agents and remove its Zed entries
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 chosen;
15868
+ let chosen2;
15753
15869
  let picked = false;
15754
- if (places.length > 0) chosen = [...new Set(places)];
15755
- else if (argv.includes("--all")) {
15756
- chosen = pickablePlaces(env, first === "uninstall");
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
- chosen = pickedPlaces;
15880
+ chosen2 = pickedPlaces;
15765
15881
  picked = true;
15766
15882
  } else {
15767
- chosen = ["zed"];
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
- chosen = chosen.filter((p) => !skip.includes(p));
15774
- const bad = [...chosen, ...skip].filter((p) => !INSTALL_PLACES.has(p));
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 (chosen.length === 0) {
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) => chosen.includes(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 (!await ask(`
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
- print("Nothing was changed.\n");
15865
- return 1;
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(chosen, env);
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 = join36(ensurePrivateDir(join36(stateDir(env), "logs")), "npm-install.log");
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 = join36(state, "logs");
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(join36(dir, f), "utf8").split("\n")) {
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) => join36(dir, name);
16231
+ const file = (name) => join38(dir, name);
16102
16232
  return [
16103
- "Easiest: run `agent-rewake install`, which adds these for you after asking.",
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(Boolean);
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: agent-rewake install --only ${id}`;
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) => uninstall ? p.state === "installed" || p.id === "zed" : p.state !== "too-old").map((p) => p.id);
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 (existsSync23(stable)) return stable;
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.update(s.scheduleId, (x) => ({ ...x, status: "cancelled" }), Date.now());
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: existsSync23
16435
+ exists: existsSync24
16301
16436
  });
16302
- return item !== void 0 && !existsSync23(item.path);
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: existsSync23
16452
+ exists: existsSync24
16318
16453
  },
16319
16454
  wanted
16320
16455
  );