autonag 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +155 -23
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -219,7 +219,8 @@ function fmtDate(ms) {
|
|
|
219
219
|
function shortId(id) {
|
|
220
220
|
return id.slice(0, 8);
|
|
221
221
|
}
|
|
222
|
-
function col(s, w) {
|
|
222
|
+
function col(s, w, ellipsis = false) {
|
|
223
|
+
if (ellipsis && s.length > w) return s.slice(0, w - 1) + "\u2026";
|
|
223
224
|
return s.slice(0, w).padEnd(w);
|
|
224
225
|
}
|
|
225
226
|
async function resolveTimerId(prefix, cfg2) {
|
|
@@ -369,7 +370,7 @@ async function cmdTimersList(cfg2) {
|
|
|
369
370
|
const remaining = t.currentExpiry - now;
|
|
370
371
|
const label = remaining < 0 ? `OVERDUE ${fmtCountdown(remaining)}` : `in ${fmtCountdown(remaining)}`;
|
|
371
372
|
const recur = t.recurrence ? "\u21BB" : "";
|
|
372
|
-
console.log(`${col(shortId(t.id) + "\u2026", 10)} ${col(t.name, 24)} ${col(label, 16)} ${recur}`);
|
|
373
|
+
console.log(`${col(shortId(t.id) + "\u2026", 10)} ${col(t.name, 24, true)} ${col(label, 16)} ${recur}`);
|
|
373
374
|
}
|
|
374
375
|
}
|
|
375
376
|
console.log();
|
|
@@ -454,7 +455,7 @@ async function cmdTimersSnooze(id, expiryStr, cfg2) {
|
|
|
454
455
|
await api.updateExpiry(cfg2.instanceId, cfg2.token, timerId, expiry);
|
|
455
456
|
console.log(`Timer ${shortId(timerId)}\u2026 snoozed until ${fmtDate(expiry)}`);
|
|
456
457
|
}
|
|
457
|
-
async function cmdTimersComplete(id, reason, cfg2) {
|
|
458
|
+
async function cmdTimersComplete(id, reason, cfg2, opts = {}) {
|
|
458
459
|
requireToken(cfg2);
|
|
459
460
|
requireInstance(cfg2);
|
|
460
461
|
const api = createApiClient(cfg2.server, cfg2.token);
|
|
@@ -462,7 +463,7 @@ async function cmdTimersComplete(id, reason, cfg2) {
|
|
|
462
463
|
const timerId = await resolveTimerId(id, cfg2);
|
|
463
464
|
const timer = state.timers.find((t) => t.id === timerId);
|
|
464
465
|
if (timer?.recurrence) {
|
|
465
|
-
await api.batchActions(cfg2.instanceId, cfg2.token, [{ type: "recurTimer", timerId, closeReason: reason }]);
|
|
466
|
+
await api.batchActions(cfg2.instanceId, cfg2.token, [{ type: "recurTimer", timerId, closeReason: reason, ...opts.at != null ? { occurredAt: opts.at } : {} }]);
|
|
466
467
|
const newState = await api.getState(cfg2.instanceId, cfg2.token);
|
|
467
468
|
const updated = newState.timers.find((t) => t.id === timerId);
|
|
468
469
|
if (updated) {
|
|
@@ -471,17 +472,21 @@ async function cmdTimersComplete(id, reason, cfg2) {
|
|
|
471
472
|
console.log(`Timer ${shortId(timerId)}\u2026 recurred`);
|
|
472
473
|
}
|
|
473
474
|
} else {
|
|
474
|
-
await api.
|
|
475
|
-
|
|
475
|
+
await api.batchActions(cfg2.instanceId, cfg2.token, [{ type: "completeTimer", timerId, closeReason: reason, ...opts.at != null ? { occurredAt: opts.at } : {} }]);
|
|
476
|
+
const name = timer?.name ?? shortId(timerId);
|
|
477
|
+
console.log(`Timer "${name}" completed (${reason})`);
|
|
476
478
|
}
|
|
477
479
|
}
|
|
478
480
|
async function cmdTimersRemove(id, cfg2) {
|
|
479
481
|
requireToken(cfg2);
|
|
480
482
|
requireInstance(cfg2);
|
|
481
|
-
const timerId = await resolveTimerId(id, cfg2);
|
|
482
483
|
const api = createApiClient(cfg2.server, cfg2.token);
|
|
484
|
+
const state = await api.getState(cfg2.instanceId, cfg2.token);
|
|
485
|
+
const timerId = await resolveTimerId(id, cfg2);
|
|
486
|
+
const timer = state.timers.find((t) => t.id === timerId);
|
|
483
487
|
await api.removeTimer(cfg2.instanceId, cfg2.token, timerId);
|
|
484
|
-
|
|
488
|
+
const name = timer?.name ?? shortId(timerId);
|
|
489
|
+
console.log(`Timer "${name}" removed`);
|
|
485
490
|
}
|
|
486
491
|
async function cmdTimersDescribe(id, text, cfg2) {
|
|
487
492
|
requireToken(cfg2);
|
|
@@ -491,6 +496,23 @@ async function cmdTimersDescribe(id, text, cfg2) {
|
|
|
491
496
|
await api.batchActions(cfg2.instanceId, cfg2.token, [{ type: "updateDescription", timerId, description: text }]);
|
|
492
497
|
console.log(`Timer ${shortId(timerId)}\u2026 description updated`);
|
|
493
498
|
}
|
|
499
|
+
async function cmdTimersGetDescription(id, cfg2) {
|
|
500
|
+
requireToken(cfg2);
|
|
501
|
+
requireInstance(cfg2);
|
|
502
|
+
const timerId = await resolveTimerId(id, cfg2);
|
|
503
|
+
const api = createApiClient(cfg2.server, cfg2.token);
|
|
504
|
+
const state = await api.getState(cfg2.instanceId, cfg2.token);
|
|
505
|
+
const timer = state.timers.find((t) => t.id === timerId);
|
|
506
|
+
if (!timer) {
|
|
507
|
+
console.error(`Timer not found: ${timerId}`);
|
|
508
|
+
process.exit(1);
|
|
509
|
+
}
|
|
510
|
+
if (!timer.description) {
|
|
511
|
+
console.log("(no description)");
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
console.log(timer.description);
|
|
515
|
+
}
|
|
494
516
|
async function cmdTimersRecurrenceSet(id, days, cfg2, opts) {
|
|
495
517
|
requireToken(cfg2);
|
|
496
518
|
requireInstance(cfg2);
|
|
@@ -524,8 +546,8 @@ async function cmdTimersHistory(id, cfg2) {
|
|
|
524
546
|
const { events, nextCursor } = await api.getTimerHistory(cfg2.instanceId, cfg2.token, timerId, { after: cursor });
|
|
525
547
|
for (const ev of events) {
|
|
526
548
|
const p = ev.payload;
|
|
527
|
-
const date = ev.type === "TimerRecurred" ? p["occurredAt"] ?? ev.timestamp : ev.timestamp;
|
|
528
|
-
allEntries.push({ date, closeReason: p["closeReason"] });
|
|
549
|
+
const date = ev.type === "TimerRecurred" || ev.type === "TimerCompletionLogged" ? p["occurredAt"] ?? ev.timestamp : ev.timestamp;
|
|
550
|
+
allEntries.push({ date, closeReason: p["closeReason"], type: ev.type });
|
|
529
551
|
}
|
|
530
552
|
cursor = nextCursor;
|
|
531
553
|
}
|
|
@@ -533,12 +555,27 @@ async function cmdTimersHistory(id, cfg2) {
|
|
|
533
555
|
console.log("No history yet.");
|
|
534
556
|
return;
|
|
535
557
|
}
|
|
536
|
-
console.log(`${"Date".padEnd(22)} Reason`);
|
|
537
|
-
console.log("-".repeat(
|
|
558
|
+
console.log(`${"Date".padEnd(22)} ${"Reason".padEnd(16)} Type`);
|
|
559
|
+
console.log("-".repeat(56));
|
|
538
560
|
for (const e of allEntries) {
|
|
539
|
-
|
|
561
|
+
const typeLabel = e.type === "TimerCompletionLogged" ? "logged" : e.type === "TimerRecurred" ? "recurred" : "completed";
|
|
562
|
+
console.log(`${col(fmtDate(e.date), 22)} ${col(e.closeReason, 16)} ${typeLabel}`);
|
|
540
563
|
}
|
|
541
564
|
}
|
|
565
|
+
async function cmdTimersLog(id, reason, at, cfg2) {
|
|
566
|
+
requireToken(cfg2);
|
|
567
|
+
requireInstance(cfg2);
|
|
568
|
+
const api = createApiClient(cfg2.server, cfg2.token);
|
|
569
|
+
const state = await api.getState(cfg2.instanceId, cfg2.token);
|
|
570
|
+
const timerId = await resolveTimerId(id, cfg2);
|
|
571
|
+
const timer = state.timers.find((t) => t.id === timerId);
|
|
572
|
+
if (!timer) {
|
|
573
|
+
console.error(`Timer not found: ${id}`);
|
|
574
|
+
process.exit(1);
|
|
575
|
+
}
|
|
576
|
+
await api.batchActions(cfg2.instanceId, cfg2.token, [{ type: "logCompletion", timerId, closeReason: reason, occurredAt: at }]);
|
|
577
|
+
console.log(`Logged "${reason}" for "${timer.name}" at ${fmtDate(at)}`);
|
|
578
|
+
}
|
|
542
579
|
async function cmdShush(durationStr, cfg2) {
|
|
543
580
|
requireToken(cfg2);
|
|
544
581
|
requireInstance(cfg2);
|
|
@@ -586,7 +623,51 @@ async function cmdEventsUnskip(id, cfg2) {
|
|
|
586
623
|
await api.unskipEvent(cfg2.instanceId, cfg2.token, eventId);
|
|
587
624
|
console.log(`Event ${shortId(eventId)}\u2026 unskipped`);
|
|
588
625
|
}
|
|
589
|
-
async function
|
|
626
|
+
async function cmdTimersView(id, cfg2) {
|
|
627
|
+
requireToken(cfg2);
|
|
628
|
+
requireInstance(cfg2);
|
|
629
|
+
const timerId = await resolveTimerId(id, cfg2);
|
|
630
|
+
const api = createApiClient(cfg2.server, cfg2.token);
|
|
631
|
+
const state = await api.getState(cfg2.instanceId, cfg2.token);
|
|
632
|
+
const timer = state.timers.find((t) => t.id === timerId);
|
|
633
|
+
if (!timer) {
|
|
634
|
+
console.error(`Timer not found: ${timerId}`);
|
|
635
|
+
process.exit(1);
|
|
636
|
+
}
|
|
637
|
+
const now = Date.now();
|
|
638
|
+
const remaining = timer.currentExpiry - now;
|
|
639
|
+
const expiryStr = `${fmtDate(timer.currentExpiry)} (${remaining >= 0 ? "in " : ""}${fmtCountdown(remaining)})`;
|
|
640
|
+
console.log(`ID: ${timer.id}`);
|
|
641
|
+
console.log(`Name: ${timer.name}`);
|
|
642
|
+
if (timer.description) {
|
|
643
|
+
if (timer.description.length > 500) {
|
|
644
|
+
console.log(`Description: ${timer.description.slice(0, 497)}...`);
|
|
645
|
+
console.log(` (${timer.description.length} chars total \u2014 run 'timers description ${shortId(timerId)}' for full text)`);
|
|
646
|
+
} else {
|
|
647
|
+
console.log(`Description: ${timer.description}`);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
console.log(`Expires: ${expiryStr}`);
|
|
651
|
+
console.log(`Created: ${fmtDate(timer.created)}`);
|
|
652
|
+
if (timer.recurrence) {
|
|
653
|
+
const r = timer.recurrence;
|
|
654
|
+
const wknd = r.skipWeekends ? ", skip weekends" : "";
|
|
655
|
+
console.log(`Recurrence: every ${r.periodDays}d at ${r.anchorTime} ${r.timezone}${wknd}`);
|
|
656
|
+
}
|
|
657
|
+
const { comments } = await api.listComments(cfg2.instanceId, cfg2.token, timerId);
|
|
658
|
+
if (comments.length > 0) {
|
|
659
|
+
const PREVIEW = 5;
|
|
660
|
+
const shown = comments.slice(-PREVIEW);
|
|
661
|
+
const hidden = comments.length - shown.length;
|
|
662
|
+
console.log(`
|
|
663
|
+
Comments:${hidden > 0 ? ` (${hidden} older \u2014 run 'comments list ${shortId(timerId)}' to see all)` : ""}`);
|
|
664
|
+
for (const c of shown) {
|
|
665
|
+
const text = c.text.length > 80 ? c.text.slice(0, 77) + "..." : c.text;
|
|
666
|
+
console.log(` ${fmtDate(c.createdAt)} ${text}`);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
async function cmdCommentsList(id, cfg2, opts = {}) {
|
|
590
671
|
requireToken(cfg2);
|
|
591
672
|
requireInstance(cfg2);
|
|
592
673
|
const timerId = await resolveTimerId(id, cfg2);
|
|
@@ -596,7 +677,10 @@ async function cmdCommentsList(id, cfg2) {
|
|
|
596
677
|
console.log("No comments.");
|
|
597
678
|
return;
|
|
598
679
|
}
|
|
599
|
-
|
|
680
|
+
const shown = opts.limit != null ? comments.slice(-opts.limit) : comments;
|
|
681
|
+
const hidden = comments.length - shown.length;
|
|
682
|
+
if (hidden > 0) console.log(`(${hidden} older comments not shown)`);
|
|
683
|
+
for (const c of shown) {
|
|
600
684
|
console.log(`[${fmtDate(c.createdAt)}] ${c.text}`);
|
|
601
685
|
}
|
|
602
686
|
}
|
|
@@ -832,12 +916,17 @@ Timers:
|
|
|
832
916
|
timers add <name> <expiry> [--desc <text>] [--days <n>] [--anchor <HH:MM>] [--tz <tz>] [--skip-weekends]
|
|
833
917
|
timers rename <id> <name>
|
|
834
918
|
timers snooze <id> <expiry> Update expiry: 1d, 30m, 2h, 90s | 2026-05-01T09:00:00Z | unix-ms:<n>
|
|
835
|
-
timers
|
|
919
|
+
timers pass <id> [--at <datetime>] Complete with reason "pass" (preferred)
|
|
920
|
+
timers fail <id> [--at <datetime>] Complete with reason "fail" (preferred)
|
|
921
|
+
timers complete <id> <reason> [--at <datetime>] Complete with a custom reason
|
|
836
922
|
timers remove <id>
|
|
923
|
+
timers view <id> Show full timer details, description, and recent comments
|
|
837
924
|
timers describe <id> <text> Set description
|
|
925
|
+
timers description <id> Print full description
|
|
838
926
|
timers recurrence set <id> <days> [--anchor <HH:MM>] [--tz <tz>] [--skip-weekends]
|
|
839
927
|
timers recurrence remove <id>
|
|
840
928
|
timers history <id> Show completion history
|
|
929
|
+
timers log <id> <reason> --at <datetime> Log a historical completion (no expiry change)
|
|
841
930
|
|
|
842
931
|
Alarm:
|
|
843
932
|
alarm show Show current alarm state
|
|
@@ -852,7 +941,7 @@ Events:
|
|
|
852
941
|
events unskip <id>
|
|
853
942
|
|
|
854
943
|
Comments:
|
|
855
|
-
comments list <timerId>
|
|
944
|
+
comments list <timerId> [--limit N]
|
|
856
945
|
comments add <timerId> <text>
|
|
857
946
|
|
|
858
947
|
Config saved to ~/.config/autonag/client.json5`;
|
|
@@ -1010,13 +1099,30 @@ try {
|
|
|
1010
1099
|
process.exit(1);
|
|
1011
1100
|
}
|
|
1012
1101
|
await cmdTimersSnooze(positional[0], positional[1], cfg);
|
|
1102
|
+
} else if (sub === "pass") {
|
|
1103
|
+
const { positional, flags } = parseFlags(rest, { at: "string" });
|
|
1104
|
+
if (!positional[0]) {
|
|
1105
|
+
console.error("Usage: autonag timers pass <id> [--at <datetime>]");
|
|
1106
|
+
process.exit(1);
|
|
1107
|
+
}
|
|
1108
|
+
const at = flags.at ? parseExpiry(flags.at) : void 0;
|
|
1109
|
+
await cmdTimersComplete(positional[0], "pass", cfg, { at });
|
|
1110
|
+
} else if (sub === "fail") {
|
|
1111
|
+
const { positional, flags } = parseFlags(rest, { at: "string" });
|
|
1112
|
+
if (!positional[0]) {
|
|
1113
|
+
console.error("Usage: autonag timers fail <id> [--at <datetime>]");
|
|
1114
|
+
process.exit(1);
|
|
1115
|
+
}
|
|
1116
|
+
const at = flags.at ? parseExpiry(flags.at) : void 0;
|
|
1117
|
+
await cmdTimersComplete(positional[0], "fail", cfg, { at });
|
|
1013
1118
|
} else if (sub === "complete") {
|
|
1014
|
-
const { positional } = parseFlags(rest, {});
|
|
1119
|
+
const { positional, flags } = parseFlags(rest, { at: "string" });
|
|
1015
1120
|
if (!positional[0] || !positional[1]) {
|
|
1016
|
-
console.error("Usage: autonag timers complete <id> <reason>");
|
|
1121
|
+
console.error("Usage: autonag timers complete <id> <reason> [--at <datetime>]");
|
|
1017
1122
|
process.exit(1);
|
|
1018
1123
|
}
|
|
1019
|
-
|
|
1124
|
+
const at = flags.at ? parseExpiry(flags.at) : void 0;
|
|
1125
|
+
await cmdTimersComplete(positional[0], positional[1], cfg, { at });
|
|
1020
1126
|
} else if (sub === "remove") {
|
|
1021
1127
|
const { positional } = parseFlags(rest, {});
|
|
1022
1128
|
if (!positional[0]) {
|
|
@@ -1031,6 +1137,13 @@ try {
|
|
|
1031
1137
|
process.exit(1);
|
|
1032
1138
|
}
|
|
1033
1139
|
await cmdTimersDescribe(positional[0], positional[1], cfg);
|
|
1140
|
+
} else if (sub === "description") {
|
|
1141
|
+
const { positional } = parseFlags(rest, {});
|
|
1142
|
+
if (!positional[0]) {
|
|
1143
|
+
console.error("Usage: autonag timers description <id>");
|
|
1144
|
+
process.exit(1);
|
|
1145
|
+
}
|
|
1146
|
+
await cmdTimersGetDescription(positional[0], cfg);
|
|
1034
1147
|
} else if (sub === "recurrence") {
|
|
1035
1148
|
const recSub = rest[0];
|
|
1036
1149
|
if (recSub === "set") {
|
|
@@ -1060,6 +1173,13 @@ try {
|
|
|
1060
1173
|
console.error("Usage: autonag timers recurrence set|remove ...");
|
|
1061
1174
|
process.exit(1);
|
|
1062
1175
|
}
|
|
1176
|
+
} else if (sub === "view") {
|
|
1177
|
+
const { positional } = parseFlags(rest, {});
|
|
1178
|
+
if (!positional[0]) {
|
|
1179
|
+
console.error("Usage: autonag timers view <id>");
|
|
1180
|
+
process.exit(1);
|
|
1181
|
+
}
|
|
1182
|
+
await cmdTimersView(positional[0], cfg);
|
|
1063
1183
|
} else if (sub === "history") {
|
|
1064
1184
|
const { positional } = parseFlags(rest, {});
|
|
1065
1185
|
if (!positional[0]) {
|
|
@@ -1067,6 +1187,18 @@ try {
|
|
|
1067
1187
|
process.exit(1);
|
|
1068
1188
|
}
|
|
1069
1189
|
await cmdTimersHistory(positional[0], cfg);
|
|
1190
|
+
} else if (sub === "log") {
|
|
1191
|
+
const { positional, flags } = parseFlags(rest, { at: "string" });
|
|
1192
|
+
if (!positional[0] || !positional[1]) {
|
|
1193
|
+
console.error("Usage: autonag timers log <id> <reason> --at <datetime>");
|
|
1194
|
+
process.exit(1);
|
|
1195
|
+
}
|
|
1196
|
+
if (!flags.at) {
|
|
1197
|
+
console.error("--at <datetime> is required for timers log");
|
|
1198
|
+
process.exit(1);
|
|
1199
|
+
}
|
|
1200
|
+
const at = parseExpiry(flags.at);
|
|
1201
|
+
await cmdTimersLog(positional[0], positional[1], at, cfg);
|
|
1070
1202
|
} else {
|
|
1071
1203
|
console.error(`Unknown subcommand: timers ${sub}`);
|
|
1072
1204
|
process.exit(1);
|
|
@@ -1108,12 +1240,12 @@ try {
|
|
|
1108
1240
|
}
|
|
1109
1241
|
} else if (cmd === "comments") {
|
|
1110
1242
|
if (!sub || sub === "list") {
|
|
1111
|
-
const { positional } = parseFlags(rest, {});
|
|
1243
|
+
const { positional, flags } = parseFlags(rest, { limit: "int" });
|
|
1112
1244
|
if (!positional[0]) {
|
|
1113
|
-
console.error("Usage: autonag comments list <timerId>");
|
|
1245
|
+
console.error("Usage: autonag comments list <timerId> [--limit N]");
|
|
1114
1246
|
process.exit(1);
|
|
1115
1247
|
}
|
|
1116
|
-
await cmdCommentsList(positional[0], cfg);
|
|
1248
|
+
await cmdCommentsList(positional[0], cfg, { limit: flags.limit });
|
|
1117
1249
|
} else if (sub === "add") {
|
|
1118
1250
|
const { positional } = parseFlags(rest, {});
|
|
1119
1251
|
if (!positional[0] || !positional[1]) {
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../cli.ts","../apiClient.ts"],"sourcesContent":["import { join } from \"path\";\nimport { homedir } from \"os\";\nimport { mkdirSync, existsSync, readFileSync, writeFileSync } from \"fs\";\nimport JSON5 from \"json5\";\nimport { createApiClient, ApiError } from \"./apiClient\";\n\n// ---- Config ----\n\ntype Config = {\n server: string;\n token?: string;\n deviceId?: string;\n instanceId?: string;\n};\n\nlet CONFIG_PATH = join(homedir(), \".config\", \"autonag\", \"client.json5\");\n\nfunction loadConfig(): Config {\n if (!existsSync(CONFIG_PATH)) return { server: \"http://localhost:3000\" };\n let raw: string;\n try {\n raw = readFileSync(CONFIG_PATH, \"utf8\");\n } catch (e) {\n console.error(`Cannot read config file ${CONFIG_PATH}: ${e}`);\n process.exit(1);\n }\n try {\n return JSON5.parse(raw) as Config;\n } catch (e) {\n console.error(`Config file ${CONFIG_PATH} is not valid JSON5: ${e}`);\n process.exit(1);\n }\n}\n\nfunction saveConfig(config: Config): void {\n mkdirSync(join(CONFIG_PATH, \"..\"), { recursive: true });\n writeFileSync(CONFIG_PATH, JSON5.stringify(config, null, 2));\n}\n\n// ---- Expiry parsing ----\n\nfunction parseExpiry(input: string): number {\n // Explicit unix milliseconds: unix-ms:<n>\n if (input.startsWith(\"unix-ms:\")) {\n const n = Number(input.slice(8));\n if (!Number.isInteger(n) || n <= 0) {\n console.error(`Invalid expiry \"${input}\". Use unix-ms:<positive-integer>`);\n process.exit(1);\n }\n return n;\n }\n // ISO 8601 with required timezone: 2026-05-01T09:00:00Z or 2026-05-01T09:00:00+05:30\n if (/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(Z|[+-]\\d{2}:\\d{2})$/.test(input)) {\n const ms = Date.parse(input);\n if (isNaN(ms)) {\n console.error(`Invalid datetime \"${input}\"`);\n process.exit(1);\n }\n return ms;\n }\n // Duration: 1d, 30m, 2h, 90s, or combinations like 1d12h\n const match = input.match(/^(?:(\\d+)d)?(?:(\\d+)h)?(?:(\\d+)m)?(?:(\\d+)s)?$/);\n if (match && (match[1] || match[2] || match[3] || match[4])) {\n const d = parseInt(match[1] ?? \"0\");\n const h = parseInt(match[2] ?? \"0\");\n const m = parseInt(match[3] ?? \"0\");\n const s = parseInt(match[4] ?? \"0\");\n return Date.now() + (d * 86400 + h * 3600 + m * 60 + s) * 1000;\n }\n console.error(`Cannot parse expiry \"${input}\". Use: 1d, 30m, 2h, 90s (relative duration), 2026-05-01T09:00:00Z (ISO 8601 with timezone), or unix-ms:<n>`);\n process.exit(1);\n}\n\n// ---- Formatting ----\n\nfunction fmtCountdown(ms: number): string {\n const sign = ms < 0 ? \"-\" : \"\";\n const abs = Math.abs(ms);\n const totalSec = Math.floor(abs / 1000);\n const d = Math.floor(totalSec / 86400);\n const h = Math.floor((totalSec % 86400) / 3600);\n const m = Math.floor((totalSec % 3600) / 60);\n const s = totalSec % 60;\n if (d > 0) return `${sign}${d}d ${h}h`;\n if (h > 0) return `${sign}${h}h ${m}m`;\n if (m > 0) return `${sign}${m}m ${s}s`;\n return `${sign}${s}s`;\n}\n\nfunction fmtDate(ms: number): string {\n return new Date(ms).toLocaleString();\n}\n\nfunction shortId(id: string): string {\n return id.slice(0, 8);\n}\n\nfunction col(s: string, w: number): string {\n return s.slice(0, w).padEnd(w);\n}\n\n// ---- ID resolution ----\n\nasync function resolveTimerId(prefix: string, cfg: Config & { token: string; instanceId: string }): Promise<string> {\n if (/^[0-9a-f-]{36}$/.test(prefix)) return prefix;\n const api = createApiClient(cfg.server, cfg.token);\n const state = await api.getState(cfg.instanceId, cfg.token);\n const matches = state.timers.filter(t => t.id.startsWith(prefix));\n if (matches.length === 0) { console.error(`Timer not found: ${prefix}`); process.exit(1); }\n if (matches.length > 1) {\n console.error(`Ambiguous prefix \"${prefix}\" matches: ${matches.map(t => shortId(t.id) + \"…\").join(\", \")}`);\n process.exit(1);\n }\n return matches[0]!.id;\n}\n\nasync function resolveEventId(prefix: string, cfg: Config & { token: string; instanceId: string }): Promise<string> {\n if (/^[0-9a-f-]{36}$/.test(prefix)) return prefix;\n const api = createApiClient(cfg.server, cfg.token);\n // Fetch all events (paginated default covers most cases)\n const allIds: string[] = [];\n let from = 1;\n while (true) {\n const { events, latestSeq } = await api.listEvents(cfg.instanceId, cfg.token, { from, limit: 200 });\n allIds.push(...events.map(e => e.id));\n if (events.length < 200 || events[events.length - 1]!.seq >= latestSeq) break;\n from = events[events.length - 1]!.seq + 1;\n }\n const matches = allIds.filter(id => id.startsWith(prefix));\n if (matches.length === 0) { console.error(`Event not found: ${prefix}`); process.exit(1); }\n if (matches.length > 1) {\n console.error(`Ambiguous prefix \"${prefix}\" matches: ${matches.map(id => shortId(id) + \"…\").join(\", \")}`);\n process.exit(1);\n }\n return matches[0]!;\n}\n\nasync function resolveInstanceId(prefix: string, cfg: Config & { token: string }): Promise<string> {\n if (/^[0-9a-f-]{36}$/.test(prefix)) return prefix;\n const api = createApiClient(cfg.server, cfg.token);\n const { instances } = await api.listInstances(cfg.token);\n const matches = instances.filter(i => i.id.startsWith(prefix));\n if (matches.length === 0) { console.error(`Instance not found: ${prefix}`); process.exit(1); }\n if (matches.length > 1) {\n console.error(`Ambiguous prefix \"${prefix}\" matches: ${matches.map(i => `\"${i.nickname}\" (${shortId(i.id)}…)`).join(\", \")}`);\n process.exit(1);\n }\n return matches[0]!.id;\n}\n\n// ---- Guards ----\n\nfunction requireToken(cfg: Config): asserts cfg is Config & { token: string } {\n if (!cfg.token) {\n console.error(\"Not registered. Run: autonag register <nickname>\");\n process.exit(1);\n }\n}\n\nfunction requireInstance(cfg: Config): asserts cfg is Config & { instanceId: string } {\n if (!cfg.instanceId) {\n console.error(\"No instance selected. Run: autonag instances select <id>\");\n process.exit(1);\n }\n}\n\n// ---- Commands ----\n\nasync function cmdRegister(nickname: string, cfg: Config): Promise<void> {\n const api = createApiClient(cfg.server);\n const { device, token } = await api.registerDevice(nickname);\n cfg.token = token;\n cfg.deviceId = device.id;\n saveConfig(cfg);\n console.log(`Registered as \"${nickname}\" (${shortId(device.id)}…)`);\n console.log(`Token saved to ${CONFIG_PATH}`);\n console.log(`Waiting for admin approval — run \"autonag status\" to check.`);\n}\n\nasync function cmdStatus(cfg: Config): Promise<void> {\n console.log(`Server: ${cfg.server}`);\n console.log(`Config: ${CONFIG_PATH}`);\n if (!cfg.token) {\n console.log(`Auth: not registered (run: autonag register <nickname>)`);\n return;\n }\n const api = createApiClient(cfg.server, cfg.token);\n try {\n const { device: d } = await api.getMe(cfg.token);\n const status = d.approvedAt ? `approved ${fmtDate(d.approvedAt)}` : \"PENDING APPROVAL\";\n console.log(`Auth: ${d.nickname} (${shortId(d.id)}…) [${status}]`);\n } catch (e) {\n if (e instanceof ApiError && e.status === 401) {\n console.log(`Auth: token invalid or expired`);\n } else throw e;\n }\n console.log(`Instance: ${cfg.instanceId ?? \"none selected (run: autonag instances select <id>)\"}`);\n}\n\nasync function cmdInstancesList(cfg: Config): Promise<void> {\n requireToken(cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const { instances } = await api.listInstances(cfg.token);\n if (instances.length === 0) { console.log(\"No accessible instances.\"); return; }\n for (const i of instances) {\n const status = i.approvedAt ? \"active\" : \"PENDING\";\n const marker = i.id === cfg.instanceId ? \" *\" : \" \";\n console.log(`${marker} ${shortId(i.id)}… \"${i.nickname}\" [${status}]`);\n }\n console.log(`\\n* = current default`);\n}\n\nasync function cmdInstancesRequest(nickname: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const { instance } = await api.requestInstance(nickname, cfg.token);\n console.log(`Requested instance \"${instance.nickname}\" (${shortId(instance.id)}…)`);\n console.log(`Waiting for admin approval.`);\n}\n\nasync function cmdInstancesSelect(id: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n const instanceId = await resolveInstanceId(id, cfg);\n cfg.instanceId = instanceId;\n saveConfig(cfg);\n console.log(`Default instance set to ${instanceId}`);\n}\n\nasync function cmdInstancesJoin(instanceId: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n const api = createApiClient(cfg.server, cfg.token);\n await api.requestInstanceAccess(instanceId, cfg.token);\n console.log(`Access requested for instance ${shortId(instanceId)}…`);\n console.log(`An admin will need to approve your request.`);\n console.log(`Once approved, run: autonag instances select ${instanceId}`);\n}\n\nasync function cmdTimersList(cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const state = await api.getState(cfg.instanceId, cfg.token);\n\n const now = Date.now();\n const timers = [...state.timers].sort((a, b) => a.currentExpiry - b.currentExpiry);\n\n if (timers.length === 0) {\n console.log(\"No active timers.\");\n } else {\n console.log(`${\"ID\".padEnd(10)} ${\"Name\".padEnd(24)} ${\"Remaining\".padEnd(16)} Recur`);\n console.log(\"-\".repeat(60));\n for (const t of timers) {\n const remaining = t.currentExpiry - now;\n const label = remaining < 0\n ? `OVERDUE ${fmtCountdown(remaining)}`\n : `in ${fmtCountdown(remaining)}`;\n const recur = t.recurrence ? \"↻\" : \"\";\n console.log(`${col(shortId(t.id) + \"…\", 10)} ${col(t.name, 24)} ${col(label, 16)} ${recur}`);\n }\n }\n\n console.log();\n printAlarmStatus(state, now);\n}\n\nfunction printAlarmStatus(state: { alarm: { on: boolean; startsAt: number | null; urgentName: string | null; color: string }; shush: { expiry: number } | null }, now: number): void {\n const { alarm, shush } = state;\n const shushed = !!(shush && shush.expiry > now);\n const colorLabel: Record<string, string> = {\n blue: \"off\", green: \"green\", yellow: \"yellow\", red: \"red\", flashing: \"FLASHING\",\n };\n\n // Line 1: color + most urgent timer\n if (alarm.startsAt !== null) {\n const diff = alarm.startsAt - now;\n const colorStr = colorLabel[alarm.color] ?? alarm.color;\n const timeStr = diff <= 0 ? `overdue ${fmtCountdown(diff)}` : `in ${fmtCountdown(diff)}`;\n console.log(`[${colorStr}] \"${alarm.urgentName}\" — ${timeStr}`);\n }\n\n // Line 2: alarm state\n if (alarm.on) {\n console.log(`Alarm: ringing.`);\n } else if (shushed) {\n const overdue = alarm.startsAt !== null && alarm.startsAt <= now;\n // \"necessary\" = shush is actually blocking a ring (timer overdue now, or timer fires before shush ends)\n const shushEndsAfterTimer = alarm.startsAt !== null && shush!.expiry >= alarm.startsAt;\n const necessary = overdue || shushEndsAfterTimer;\n if (necessary) {\n const ringIn = fmtCountdown(shush!.expiry - now);\n console.log(`Alarm: off. Will ring in ${ringIn}: Shush expires: ${alarm.urgentName}.`);\n } else if (alarm.startsAt !== null) {\n // Shush ends before timer fires — timer still drives the ring time\n const ringIn = fmtCountdown(alarm.startsAt - now);\n const remaining = fmtCountdown(shush!.expiry - now);\n console.log(`Alarm: off. Will ring in ${ringIn}: ${alarm.urgentName}. (Shushed unnecessarily for ${remaining}.)`);\n } else {\n const remaining = fmtCountdown(shush!.expiry - now);\n console.log(`Alarm: off. Shushed (unnecessarily) for ${remaining}.`);\n }\n } else if (alarm.startsAt !== null) {\n const ringIn = fmtCountdown(alarm.startsAt - now);\n console.log(`Alarm: off. Will ring in ${ringIn}: ${alarm.urgentName}.`);\n } else {\n console.log(`Alarm: off.`);\n }\n}\n\nasync function cmdAlarm(cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const state = await api.getState(cfg.instanceId, cfg.token);\n printAlarmStatus(state, Date.now());\n}\n\nasync function cmdTimersAdd(\n name: string, expiryStr: string, cfg: Config,\n opts: { desc?: string; days?: number; anchor?: string; tz?: string; skipWeekends?: boolean }\n): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const expiry = parseExpiry(expiryStr);\n const recurrence = opts.days !== undefined ? {\n periodDays: opts.days,\n anchorTime: opts.anchor ?? \"09:00\",\n timezone: opts.tz ?? Intl.DateTimeFormat().resolvedOptions().timeZone,\n skipWeekends: opts.skipWeekends ?? false,\n } : undefined;\n await api.addTimer(cfg.instanceId, cfg.token, name, expiry, recurrence, opts.desc);\n const recurNote = recurrence ? ` (recurs every ${opts.days}d)` : \"\";\n console.log(`Timer \"${name}\" added, expires ${fmtDate(expiry)}${recurNote}`);\n}\n\nasync function cmdTimersRename(id: string, name: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const timerId = await resolveTimerId(id, cfg);\n const api = createApiClient(cfg.server, cfg.token);\n await api.renameTimer(cfg.instanceId, cfg.token, timerId, name);\n console.log(`Timer ${shortId(timerId)}… renamed to \"${name}\"`);\n}\n\nasync function cmdTimersSnooze(id: string, expiryStr: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const timerId = await resolveTimerId(id, cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const expiry = parseExpiry(expiryStr);\n await api.updateExpiry(cfg.instanceId, cfg.token, timerId, expiry);\n console.log(`Timer ${shortId(timerId)}… snoozed until ${fmtDate(expiry)}`);\n}\n\nasync function cmdTimersComplete(id: string, reason: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const state = await api.getState(cfg.instanceId, cfg.token);\n const timerId = await resolveTimerId(id, cfg);\n const timer = state.timers.find(t => t.id === timerId);\n\n if (timer?.recurrence) {\n await api.batchActions(cfg.instanceId, cfg.token, [{ type: \"recurTimer\", timerId, closeReason: reason }]);\n const newState = await api.getState(cfg.instanceId, cfg.token);\n const updated = newState.timers.find(t => t.id === timerId);\n if (updated) {\n console.log(`Timer \"${timer.name}\" recurred — next: ${fmtDate(updated.currentExpiry)}`);\n } else {\n console.log(`Timer ${shortId(timerId)}… recurred`);\n }\n } else {\n await api.completeTimer(cfg.instanceId, cfg.token, timerId, reason);\n console.log(`Timer ${shortId(timerId)}… completed (${reason})`);\n }\n}\n\nasync function cmdTimersRemove(id: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const timerId = await resolveTimerId(id, cfg);\n const api = createApiClient(cfg.server, cfg.token);\n await api.removeTimer(cfg.instanceId, cfg.token, timerId);\n console.log(`Timer ${shortId(timerId)}… removed`);\n}\n\nasync function cmdTimersDescribe(id: string, text: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const timerId = await resolveTimerId(id, cfg);\n const api = createApiClient(cfg.server, cfg.token);\n await api.batchActions(cfg.instanceId, cfg.token, [{ type: \"updateDescription\", timerId, description: text }]);\n console.log(`Timer ${shortId(timerId)}… description updated`);\n}\n\nasync function cmdTimersRecurrenceSet(\n id: string, days: number, cfg: Config,\n opts: { anchor?: string; tz?: string; skipWeekends?: boolean }\n): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const timerId = await resolveTimerId(id, cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const recurrence = {\n periodDays: days,\n anchorTime: opts.anchor ?? \"09:00\",\n timezone: opts.tz ?? Intl.DateTimeFormat().resolvedOptions().timeZone,\n skipWeekends: opts.skipWeekends ?? false,\n };\n await api.batchActions(cfg.instanceId, cfg.token, [{ type: \"updateRecurrence\", timerId, recurrence }]);\n console.log(`Timer ${shortId(timerId)}… recurrence set to every ${days}d at ${recurrence.anchorTime} (${recurrence.timezone})`);\n}\n\nasync function cmdTimersRecurrenceRemove(id: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const timerId = await resolveTimerId(id, cfg);\n const api = createApiClient(cfg.server, cfg.token);\n await api.batchActions(cfg.instanceId, cfg.token, [{ type: \"removeRecurrence\", timerId }]);\n console.log(`Timer ${shortId(timerId)}… recurrence removed`);\n}\n\nasync function cmdTimersHistory(id: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const timerId = await resolveTimerId(id, cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const allEntries: Array<{ date: number; closeReason: string }> = [];\n let cursor: number | null = 0;\n while (cursor !== null) {\n const { events, nextCursor } = await api.getTimerHistory(cfg.instanceId, cfg.token, timerId, { after: cursor });\n for (const ev of events) {\n const p = ev.payload as Record<string, unknown>;\n const date = ev.type === \"TimerRecurred\"\n ? (p[\"occurredAt\"] as number) ?? ev.timestamp\n : ev.timestamp;\n allEntries.push({ date, closeReason: p[\"closeReason\"] as string });\n }\n cursor = nextCursor;\n }\n if (allEntries.length === 0) { console.log(\"No history yet.\"); return; }\n console.log(`${\"Date\".padEnd(22)} Reason`);\n console.log(\"-\".repeat(36));\n for (const e of allEntries) {\n console.log(`${col(fmtDate(e.date), 22)} ${e.closeReason}`);\n }\n}\n\nasync function cmdShush(durationStr: string | undefined, cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const expiry = durationStr ? parseExpiry(durationStr) : Date.now() + 30 * 60 * 1000;\n await api.setShush(cfg.instanceId, cfg.token, expiry);\n console.log(`Alarm silenced until ${fmtDate(expiry)}`);\n}\n\nasync function cmdUnshush(cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const api = createApiClient(cfg.server, cfg.token);\n await api.clearShush(cfg.instanceId, cfg.token);\n console.log(`Shush cleared`);\n}\n\nasync function cmdEventsList(fromSeq: number, cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const { events } = await api.listEvents(cfg.instanceId, cfg.token, { from: fromSeq });\n if (events.length === 0) { console.log(\"No events.\"); return; }\n console.log(`${\"seq\".padEnd(6)} ${\"ID\".padEnd(10)} ${\"Type\".padEnd(28)} ${\"Time\".padEnd(20)} Skipped`);\n console.log(\"-\".repeat(78));\n for (const e of events) {\n const skipped = e.skipped ? \"yes\" : \"\";\n console.log(`${String(e.seq).padEnd(6)} ${col(shortId(e.id) + \"…\", 10)} ${col(e.type, 28)} ${col(fmtDate(e.timestamp), 20)} ${skipped}`);\n }\n}\n\nasync function cmdEventsSkip(id: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const eventId = await resolveEventId(id, cfg);\n const api = createApiClient(cfg.server, cfg.token);\n await api.skipEvent(cfg.instanceId, cfg.token, eventId);\n console.log(`Event ${shortId(eventId)}… skipped`);\n}\n\nasync function cmdEventsUnskip(id: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const eventId = await resolveEventId(id, cfg);\n const api = createApiClient(cfg.server, cfg.token);\n await api.unskipEvent(cfg.instanceId, cfg.token, eventId);\n console.log(`Event ${shortId(eventId)}… unskipped`);\n}\n\nasync function cmdCommentsList(id: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const timerId = await resolveTimerId(id, cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const { comments } = await api.listComments(cfg.instanceId, cfg.token, timerId);\n if (comments.length === 0) { console.log(\"No comments.\"); return; }\n for (const c of comments) {\n console.log(`[${fmtDate(c.createdAt)}] ${c.text}`);\n }\n}\n\nasync function cmdCommentsAdd(id: string, text: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const timerId = await resolveTimerId(id, cfg);\n const api = createApiClient(cfg.server, cfg.token);\n await api.addComment(cfg.instanceId, cfg.token, timerId, text);\n console.log(`Comment added`);\n}\n\n// ---- Tutorial ----\n\nfunction cmdTutorial(): void {\n console.log(`# autonag tutorial\n\nautonag is a recurring-task tracker with an alarm. Timers count down; when\nthey expire, your alarm client starts ringing. You mark them done — if the\ntimer is recurring, the next occurrence is automatically scheduled.\n\n## Config\n\nYour config lives at \\`~/.config/autonag/client.json5\\`. It is a JSON5 file\n(JSON with comments and trailing commas), so you can annotate it. After\nregistration it looks something like:\n\n\\`\\`\\`json5\n{\n server: 'https://your-server.example',\n token: '…',\n deviceId: '…',\n instanceId: '…',\n}\n\\`\\`\\`\n\nEdit it directly in a text editor whenever you need to change the server\nURL or switch instances. To use a different config file:\n\n\\`\\`\\`\nautonag --config /path/to/other.json5 timers list\n\\`\\`\\`\n\n## First-time setup\n\nRegister this device — give it a short nickname so the admin knows who you are:\n\n\\`\\`\\`\nautonag register myphone\n\\`\\`\\`\n\nYour auth token and device ID are saved to the config. The device starts in\nPENDING state until an admin approves it. Check your status:\n\n\\`\\`\\`\nautonag status\n\\`\\`\\`\n\n## Getting an instance\n\nTimers live in an instance. Create a new one:\n\n\\`\\`\\`\nautonag instances request home\n\\`\\`\\`\n\nWhen the admin approves it, it shows up in your list:\n\n\\`\\`\\`\nautonag instances list\n\\`\\`\\`\n\nSet it as your default:\n\n\\`\\`\\`\nautonag instances select <id>\n\\`\\`\\`\n\nTo join an instance someone else owns, ask them for the instance ID. Then\nrequest access:\n\n\\`\\`\\`\nautonag instances join <instance-id>\n\\`\\`\\`\n\nAn admin will approve your request. The instance ID is not advertised\npublicly — you need to know it.\n\n## Adding timers\n\nOne-shot reminder due in 2 days:\n\n\\`\\`\\`\nautonag timers add \"Doctor follow-up\" 2d\n\\`\\`\\`\n\nRecurring task every 7 days at 9 AM:\n\n\\`\\`\\`\nautonag timers add \"Weekly review\" 7d --days 7 --anchor 09:00\n\\`\\`\\`\n\nThe first argument after the name is the initial expiry. \\`--days\\` makes it\nrecurring; \\`--anchor\\` sets the time of day; \\`--tz\\` overrides the timezone.\n\n## Checking timers\n\n\\`\\`\\`\nautonag timers list\n\\`\\`\\`\n\n\\`\\`\\`\nID Name Remaining Recur\n------------------------------------------------------------\na1b2c3d4… Doctor follow-up in 1d 23h\ne5f6a7b8… Weekly review in 6d 23h ↻\n\\`\\`\\`\n\nThe ↻ symbol marks recurring timers.\n\n## Completing a timer\n\nMark a timer done with a reason (pass, fail, or any custom string):\n\n\\`\\`\\`\nautonag timers complete e5f6 pass\n\\`\\`\\`\n\nFor a one-shot timer this removes it. For a recurring timer it schedules\nthe next occurrence and tells you when:\n\n\\`\\`\\`\nTimer \"Weekly review\" recurred — next: 4/24/2026, 9:00:00 AM\n\\`\\`\\`\n\nTo permanently stop a recurring timer, remove the recurrence first:\n\n\\`\\`\\`\nautonag timers recurrence remove e5f6\nautonag timers complete e5f6 done\n\\`\\`\\`\n\n## Snoozing\n\nPush a timer's deadline out:\n\n\\`\\`\\`\nautonag timers snooze e5f6 3d\n\\`\\`\\`\n\n## Silencing the alarm\n\nSilence the alarm for 30 minutes (the default):\n\n\\`\\`\\`\nautonag shush\n\\`\\`\\`\n\nOr for a specific duration:\n\n\\`\\`\\`\nautonag shush 2h\n\\`\\`\\`\n\nResume:\n\n\\`\\`\\`\nautonag unshush\n\\`\\`\\`\n\n## History\n\nSee every time a recurring timer was completed:\n\n\\`\\`\\`\nautonag timers history e5f6\n\\`\\`\\`\n\n## Notes and comments\n\nAttach a description to a timer:\n\n\\`\\`\\`\nautonag timers describe e5f6 \"Prep the agenda before this\"\n\\`\\`\\`\n\nAdd timestamped comments (good for logging what happened):\n\n\\`\\`\\`\nautonag comments add e5f6 \"Completed but flagged the follow-up\"\n\\`\\`\\`\n\n## Event log\n\nEvery action is recorded. View the log:\n\n\\`\\`\\`\nautonag events list\n\\`\\`\\`\n\nYou can skip events to undo them — state is recomputed as if the\nskipped event never happened:\n\n\\`\\`\\`\nautonag events skip <event-id>\nautonag events unskip <event-id>\n\\`\\`\\`\n\n---\nRun \\`autonag --help\\` for a full command reference.`);\n}\n\n// ---- Help ----\n\nconst HELP = `autonag client CLI\n\nUsage: autonag [options] <command> [args]\n\nOptions:\n -h, --help Show this help\n -s, --server <url> Server URL (default: http://localhost:3000)\n -i, --instance <id> Instance ID (overrides saved default)\n -c, --config <path> Config file (default: ~/.config/autonag/client.json5)\n\n tutorial Walk through setup and daily workflow\n\nAuth:\n register <nickname> Register this device and save token\n status Show auth status and saved config\n\nInstances:\n instances list\n instances request <nickname> Create a new instance\n instances join <instance-id> Request access to an existing instance\n instances select <id>\n\nTimers:\n timers list\n timers add <name> <expiry> [--desc <text>] [--days <n>] [--anchor <HH:MM>] [--tz <tz>] [--skip-weekends]\n timers rename <id> <name>\n timers snooze <id> <expiry> Update expiry: 1d, 30m, 2h, 90s | 2026-05-01T09:00:00Z | unix-ms:<n>\n timers complete <id> <reason> Complete or recur (reason: pass, fail, or custom)\n timers remove <id>\n timers describe <id> <text> Set description\n timers recurrence set <id> <days> [--anchor <HH:MM>] [--tz <tz>] [--skip-weekends]\n timers recurrence remove <id>\n timers history <id> Show completion history\n\nAlarm:\n alarm show Show current alarm state\n\nShush:\n shush [duration] Silence alarm (default: 30m)\n unshush Clear shush\n\nEvents:\n events list [--from <seq>]\n events skip <id>\n events unskip <id>\n\nComments:\n comments list <timerId>\n comments add <timerId> <text>\n\nConfig saved to ~/.config/autonag/client.json5`;\n\n// ---- Flag parsing ----\n\ntype FlagSchema = Record<string, \"string\" | \"int\" | \"boolean\">;\ntype ParsedFlags = { positional: string[]; flags: Record<string, string | number | boolean> };\n\nfunction parseFlags(args: string[], schema: FlagSchema): ParsedFlags {\n const positional: string[] = [];\n const flags: Record<string, string | number | boolean> = {};\n for (let i = 0; i < args.length; i++) {\n const a = args[i]!;\n if (a.startsWith(\"--\")) {\n const key = a.slice(2);\n if (!(key in schema)) {\n console.error(`Unknown flag: --${key}`);\n process.exit(1);\n }\n const type = schema[key]!;\n if (type === \"boolean\") {\n flags[key] = true;\n } else {\n const next = args[i + 1];\n if (!next || next.startsWith(\"--\")) {\n console.error(`Flag --${key} requires a value`);\n process.exit(1);\n }\n if (type === \"int\") {\n const n = Number(next);\n if (!Number.isInteger(n)) {\n console.error(`Flag --${key} must be an integer, got: \"${next}\"`);\n process.exit(1);\n }\n flags[key] = n;\n } else {\n flags[key] = next;\n }\n i++;\n }\n } else {\n positional.push(a);\n }\n }\n return { positional, flags };\n}\n\n// ---- Arg parsing & dispatch ----\n\nconst rawArgs = process.argv.slice(2);\nconst topArgs: string[] = [];\nlet serverOverride: string | undefined;\nlet instanceOverride: string | undefined;\n\nfor (let i = 0; i < rawArgs.length; i++) {\n const a = rawArgs[i]!;\n if (a === \"-h\" || a === \"--help\") { console.log(HELP); process.exit(0); }\n else if (a === \"-s\" || a === \"--server\") {\n if (!rawArgs[i + 1] || rawArgs[i + 1]!.startsWith(\"-\")) { console.error(\"Flag -s/--server requires a URL\"); process.exit(1); }\n serverOverride = rawArgs[++i];\n }\n else if (a === \"-i\" || a === \"--instance\") {\n if (!rawArgs[i + 1] || rawArgs[i + 1]!.startsWith(\"-\")) { console.error(\"Flag -i/--instance requires an ID\"); process.exit(1); }\n instanceOverride = rawArgs[++i];\n }\n else if (a === \"-c\" || a === \"--config\") {\n if (!rawArgs[i + 1] || rawArgs[i + 1]!.startsWith(\"-\")) { console.error(\"Flag -c/--config requires a path\"); process.exit(1); }\n CONFIG_PATH = rawArgs[++i]!;\n }\n else topArgs.push(a);\n}\n\nconst cfg = loadConfig();\nif (serverOverride) cfg.server = serverOverride;\nif (instanceOverride) cfg.instanceId = instanceOverride;\n\nconst [cmd, sub, ...rest] = topArgs;\n\ntry {\n if (!cmd || cmd === \"help\") {\n parseFlags(rest, {});\n console.log(HELP);\n } else if (cmd === \"tutorial\") {\n parseFlags(rest, {});\n cmdTutorial();\n\n } else if (cmd === \"register\") {\n parseFlags(rest, {});\n if (!sub) { console.error(\"Usage: autonag register <nickname>\"); process.exit(1); }\n await cmdRegister(sub, cfg);\n\n } else if (cmd === \"status\") {\n parseFlags(rest, {});\n await cmdStatus(cfg);\n\n } else if (cmd === \"instances\") {\n if (!sub || sub === \"list\") {\n parseFlags(rest, {});\n await cmdInstancesList(cfg);\n } else if (sub === \"request\") {\n const { positional } = parseFlags(rest, {});\n if (!positional[0]) { console.error(\"Usage: autonag instances request <nickname>\"); process.exit(1); }\n await cmdInstancesRequest(positional[0], cfg);\n } else if (sub === \"join\") {\n const { positional } = parseFlags(rest, {});\n if (!positional[0]) { console.error(\"Usage: autonag instances join <instance-id>\"); process.exit(1); }\n await cmdInstancesJoin(positional[0], cfg);\n } else if (sub === \"select\") {\n const { positional } = parseFlags(rest, {});\n if (!positional[0]) { console.error(\"Usage: autonag instances select <id>\"); process.exit(1); }\n await cmdInstancesSelect(positional[0], cfg);\n } else {\n console.error(`Unknown subcommand: instances ${sub}`); process.exit(1);\n }\n\n } else if (cmd === \"timers\") {\n if (!sub || sub === \"list\") {\n parseFlags(rest, {});\n await cmdTimersList(cfg);\n } else if (sub === \"add\") {\n const { positional, flags } = parseFlags(rest, {\n desc: \"string\", days: \"int\", anchor: \"string\", tz: \"string\", \"skip-weekends\": \"boolean\",\n });\n if (!positional[0] || !positional[1]) { console.error(\"Usage: autonag timers add <name> <expiry> [--desc <text>] [--days <n>] [--anchor <HH:MM>] [--tz <tz>] [--skip-weekends]\"); process.exit(1); }\n await cmdTimersAdd(positional[0], positional[1], cfg, {\n desc: flags.desc as string | undefined,\n days: flags.days as number | undefined,\n anchor: flags.anchor as string | undefined,\n tz: flags.tz as string | undefined,\n skipWeekends: flags[\"skip-weekends\"] === true,\n });\n } else if (sub === \"rename\") {\n const { positional } = parseFlags(rest, {});\n if (!positional[0] || !positional[1]) { console.error(\"Usage: autonag timers rename <id> <name>\"); process.exit(1); }\n await cmdTimersRename(positional[0], positional[1], cfg);\n } else if (sub === \"snooze\") {\n const { positional } = parseFlags(rest, {});\n if (!positional[0] || !positional[1]) { console.error(\"Usage: autonag timers snooze <id> <expiry>\"); process.exit(1); }\n await cmdTimersSnooze(positional[0], positional[1], cfg);\n } else if (sub === \"complete\") {\n const { positional } = parseFlags(rest, {});\n if (!positional[0] || !positional[1]) { console.error(\"Usage: autonag timers complete <id> <reason>\"); process.exit(1); }\n await cmdTimersComplete(positional[0], positional[1], cfg);\n } else if (sub === \"remove\") {\n const { positional } = parseFlags(rest, {});\n if (!positional[0]) { console.error(\"Usage: autonag timers remove <id>\"); process.exit(1); }\n await cmdTimersRemove(positional[0], cfg);\n } else if (sub === \"describe\") {\n const { positional } = parseFlags(rest, {});\n if (!positional[0] || !positional[1]) { console.error(\"Usage: autonag timers describe <id> <text>\"); process.exit(1); }\n await cmdTimersDescribe(positional[0], positional[1], cfg);\n } else if (sub === \"recurrence\") {\n const recSub = rest[0];\n if (recSub === \"set\") {\n const { positional, flags } = parseFlags(rest, { anchor: \"string\", tz: \"string\", \"skip-weekends\": \"boolean\" });\n // positional = [\"set\", id, days]\n if (!positional[1] || !positional[2]) { console.error(\"Usage: autonag timers recurrence set <id> <days> [--anchor <HH:MM>] [--tz <tz>] [--skip-weekends]\"); process.exit(1); }\n const days = Number(positional[2]);\n if (!Number.isInteger(days) || days <= 0) { console.error(`<days> must be a positive integer, got: \"${positional[2]}\"`); process.exit(1); }\n await cmdTimersRecurrenceSet(positional[1], days, cfg, {\n anchor: flags.anchor as string | undefined,\n tz: flags.tz as string | undefined,\n skipWeekends: flags[\"skip-weekends\"] === true,\n });\n } else if (recSub === \"remove\") {\n const { positional } = parseFlags(rest, {});\n // positional = [\"remove\", id]\n if (!positional[1]) { console.error(\"Usage: autonag timers recurrence remove <id>\"); process.exit(1); }\n await cmdTimersRecurrenceRemove(positional[1], cfg);\n } else {\n console.error(\"Usage: autonag timers recurrence set|remove ...\"); process.exit(1);\n }\n } else if (sub === \"history\") {\n const { positional } = parseFlags(rest, {});\n if (!positional[0]) { console.error(\"Usage: autonag timers history <id>\"); process.exit(1); }\n await cmdTimersHistory(positional[0], cfg);\n } else {\n console.error(`Unknown subcommand: timers ${sub}`); process.exit(1);\n }\n\n } else if (cmd === \"alarm\") {\n if (sub !== \"show\") { console.error(\"Usage: autonag alarm show\"); process.exit(1); }\n parseFlags(rest, {});\n await cmdAlarm(cfg);\n\n } else if (cmd === \"shush\") {\n parseFlags(rest, {});\n await cmdShush(sub, cfg);\n } else if (cmd === \"unshush\") {\n parseFlags(rest, {});\n await cmdUnshush(cfg);\n\n } else if (cmd === \"events\") {\n if (!sub || sub === \"list\") {\n const { flags } = parseFlags(rest, { from: \"int\" });\n await cmdEventsList((flags.from as number | undefined) ?? 1, cfg);\n } else if (sub === \"skip\") {\n const { positional } = parseFlags(rest, {});\n if (!positional[0]) { console.error(\"Usage: autonag events skip <id>\"); process.exit(1); }\n await cmdEventsSkip(positional[0], cfg);\n } else if (sub === \"unskip\") {\n const { positional } = parseFlags(rest, {});\n if (!positional[0]) { console.error(\"Usage: autonag events unskip <id>\"); process.exit(1); }\n await cmdEventsUnskip(positional[0], cfg);\n } else {\n console.error(`Unknown subcommand: events ${sub}`); process.exit(1);\n }\n\n } else if (cmd === \"comments\") {\n if (!sub || sub === \"list\") {\n const { positional } = parseFlags(rest, {});\n if (!positional[0]) { console.error(\"Usage: autonag comments list <timerId>\"); process.exit(1); }\n await cmdCommentsList(positional[0], cfg);\n } else if (sub === \"add\") {\n const { positional } = parseFlags(rest, {});\n if (!positional[0] || !positional[1]) { console.error(\"Usage: autonag comments add <timerId> <text>\"); process.exit(1); }\n await cmdCommentsAdd(positional[0], positional[1], cfg);\n } else {\n console.error(`Unknown subcommand: comments ${sub}`); process.exit(1);\n }\n\n } else {\n console.error(`Unknown command: ${cmd}`);\n console.error(`Run \"autonag --help\" for usage.`);\n process.exit(1);\n }\n} catch (e) {\n if (e instanceof ApiError) {\n console.error(`Error: ${e.message}`);\n process.exit(1);\n }\n throw e;\n}\n","import type { RecurrenceSpec, StoredEvent, Comment, InstanceState } from \"./types\";\n\nexport class ApiError extends Error {\n constructor(public status: number, message: string) {\n super(message);\n this.name = \"ApiError\";\n }\n}\n\nexport type BatchActionItem =\n | { type: \"addTimer\"; name: string; description?: string; expiry: number; recurrence?: RecurrenceSpec }\n | { type: \"updateExpiry\"; timerId: string; expiry: number }\n | { type: \"completeTimer\"; timerId: string; closeReason: string }\n | { type: \"removeTimer\"; timerId: string }\n | { type: \"shush\"; expiry: number }\n | { type: \"clearShush\" }\n | { type: \"recurTimer\"; timerId: string; closeReason: string }\n | { type: \"updateRecurrence\"; timerId: string; recurrence: RecurrenceSpec }\n | { type: \"removeRecurrence\"; timerId: string }\n | { type: \"updateDescription\"; timerId: string; description: string }\n | { type: \"assert\"; path: string; expectStatus?: number; expect?: unknown };\n\nexport function createApiClient(baseUrl: string, defaultToken?: string) {\n async function apiFetch<T>(\n path: string,\n options: RequestInit = {},\n token?: string,\n ): Promise<T> {\n const tok = token ?? defaultToken;\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...(options.headers as Record<string, string>),\n };\n if (tok) headers[\"Authorization\"] = `Bearer ${tok}`;\n\n const res = await fetch(`${baseUrl}${path}`, { ...options, headers });\n if (!res.ok) {\n let message = `HTTP ${res.status}`;\n try {\n const body = await res.json() as { error?: string };\n if (body.error) message = body.error;\n } catch { /* ignore */ }\n throw new ApiError(res.status, message);\n }\n return res.json() as Promise<T>;\n }\n\n return {\n registerDevice: (nickname: string) =>\n apiFetch<{ device: { id: string; nickname: string }; token: string }>(\n \"/devices/request\", { method: \"POST\", body: JSON.stringify({ nickname }) }\n ),\n\n getMe: (token: string) =>\n apiFetch<{ device: { id: string; nickname: string; approvedAt: number | null } }>(\n \"/devices/me\", {}, token\n ),\n\n requestInstance: (nickname: string, token: string) =>\n apiFetch<{ instance: { id: string; nickname: string } }>(\n \"/instances/request\", { method: \"POST\", body: JSON.stringify({ nickname }) }, token\n ),\n\n requestInstanceAccess: (instanceId: string, token: string) =>\n apiFetch<{ request?: { id: string; status: string }; status?: string }>(\n `/instances/${instanceId}/access/request`,\n { method: \"POST\", body: JSON.stringify({}) },\n token\n ),\n\n listInstances: (token: string) =>\n apiFetch<{ instances: { id: string; nickname: string; approvedAt: number | null }[] }>(\n \"/instances\", {}, token\n ),\n\n addTimer: (instanceId: string, token: string, name: string, expiry: number, recurrence?: RecurrenceSpec, description?: string) =>\n apiFetch<{ timer: { id: string }; event: { id: string; seq: number } }>(\n `/instances/${instanceId}/timers`,\n { method: \"POST\", body: JSON.stringify({ name, expiry, ...(description ? { description } : {}), ...(recurrence ? { recurrence } : {}) }) },\n token\n ),\n\n renameTimer: (instanceId: string, token: string, timerId: string, name: string) =>\n apiFetch<{ event: { id: string; seq: number } }>(\n `/instances/${instanceId}/timers/${timerId}/name`,\n { method: \"PATCH\", body: JSON.stringify({ name }) },\n token\n ),\n\n updateExpiry: (instanceId: string, token: string, timerId: string, expiry: number) =>\n apiFetch<{ event: { id: string; seq: number } }>(\n `/instances/${instanceId}/timers/${timerId}/expiry`,\n { method: \"PATCH\", body: JSON.stringify({ expiry }) },\n token\n ),\n\n completeTimer: (instanceId: string, token: string, timerId: string, closeReason: string) =>\n apiFetch<{ event: { id: string; seq: number } }>(\n `/instances/${instanceId}/timers/${timerId}/complete`,\n { method: \"POST\", body: JSON.stringify({ closeReason }) },\n token\n ),\n\n removeTimer: (instanceId: string, token: string, timerId: string) =>\n apiFetch<{ event: { id: string; seq: number } }>(\n `/instances/${instanceId}/timers/${timerId}`,\n { method: \"DELETE\" },\n token\n ),\n\n setShush: (instanceId: string, token: string, expiry: number) =>\n apiFetch<{ event: { id: string; seq: number } }>(\n `/instances/${instanceId}/shush`,\n { method: \"POST\", body: JSON.stringify({ expiry }) },\n token\n ),\n\n clearShush: (instanceId: string, token: string) =>\n apiFetch<{ event: { id: string; seq: number } }>(\n `/instances/${instanceId}/shush`,\n { method: \"DELETE\" },\n token\n ),\n\n listEvents: (instanceId: string, token: string, opts: { from?: number; before?: number; limit?: number } = {}) => {\n const { from = 1, before, limit = 200 } = opts;\n const params = before !== undefined\n ? `before=${before}&limit=${limit}`\n : `from=${from}&limit=${limit}`;\n return apiFetch<{ events: StoredEvent[]; latestSeq: number; prevCursor?: number | null }>(\n `/instances/${instanceId}/events?${params}`, {}, token\n );\n },\n\n getTimerHistory: (instanceId: string, token: string, timerId: string, opts: {\n after?: number; limit?: number; from?: number; to?: number;\n } = {}) => {\n const params = new URLSearchParams();\n if (opts.after !== undefined) params.set(\"after\", String(opts.after));\n if (opts.limit !== undefined) params.set(\"limit\", String(opts.limit));\n if (opts.from !== undefined) params.set(\"from\", String(opts.from));\n if (opts.to !== undefined) params.set(\"to\", String(opts.to));\n const qs = params.toString();\n return apiFetch<{ events: StoredEvent[]; nextCursor: number | null }>(\n `/instances/${instanceId}/timers/${timerId}/history${qs ? `?${qs}` : \"\"}`, {}, token\n );\n },\n\n skipEvent: (instanceId: string, token: string, eventId: string) =>\n apiFetch<{ ok: boolean }>(\n `/instances/${instanceId}/events/${eventId}/skip`, { method: \"POST\" }, token\n ),\n\n unskipEvent: (instanceId: string, token: string, eventId: string) =>\n apiFetch<{ ok: boolean }>(\n `/instances/${instanceId}/events/${eventId}/skip`, { method: \"DELETE\" }, token\n ),\n\n listComments: (instanceId: string, token: string, threadId: string) =>\n apiFetch<{ comments: Comment[] }>(\n `/instances/${instanceId}/threads/${threadId}/comments`, {}, token\n ),\n\n addComment: (instanceId: string, token: string, threadId: string, text: string) =>\n apiFetch<{ comment: Comment }>(\n `/instances/${instanceId}/threads/${threadId}/comments`,\n { method: \"POST\", body: JSON.stringify({ text }) },\n token\n ),\n\n getState: (instanceId: string, token: string) =>\n apiFetch<InstanceState>(\n `/instances/${instanceId}/state`, {}, token\n ),\n\n batchActions: (instanceId: string, token: string, actions: BatchActionItem[]) =>\n apiFetch<{ events: { id: string; seq: number; type: string }[] }>(\n `/instances/${instanceId}/actions`,\n { method: \"POST\", body: JSON.stringify({ actions }) },\n token\n ),\n };\n}\n"],"mappings":"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","names":["cfg"]}
|
|
1
|
+
{"version":3,"sources":["../cli.ts","../apiClient.ts"],"sourcesContent":["import { join } from \"path\";\nimport { homedir } from \"os\";\nimport { mkdirSync, existsSync, readFileSync, writeFileSync } from \"fs\";\nimport JSON5 from \"json5\";\nimport { createApiClient, ApiError } from \"./apiClient\";\n\n// ---- Config ----\n\ntype Config = {\n server: string;\n token?: string;\n deviceId?: string;\n instanceId?: string;\n};\n\nlet CONFIG_PATH = join(homedir(), \".config\", \"autonag\", \"client.json5\");\n\nfunction loadConfig(): Config {\n if (!existsSync(CONFIG_PATH)) return { server: \"http://localhost:3000\" };\n let raw: string;\n try {\n raw = readFileSync(CONFIG_PATH, \"utf8\");\n } catch (e) {\n console.error(`Cannot read config file ${CONFIG_PATH}: ${e}`);\n process.exit(1);\n }\n try {\n return JSON5.parse(raw) as Config;\n } catch (e) {\n console.error(`Config file ${CONFIG_PATH} is not valid JSON5: ${e}`);\n process.exit(1);\n }\n}\n\nfunction saveConfig(config: Config): void {\n mkdirSync(join(CONFIG_PATH, \"..\"), { recursive: true });\n writeFileSync(CONFIG_PATH, JSON5.stringify(config, null, 2));\n}\n\n// ---- Expiry parsing ----\n\nfunction parseExpiry(input: string): number {\n // Explicit unix milliseconds: unix-ms:<n>\n if (input.startsWith(\"unix-ms:\")) {\n const n = Number(input.slice(8));\n if (!Number.isInteger(n) || n <= 0) {\n console.error(`Invalid expiry \"${input}\". Use unix-ms:<positive-integer>`);\n process.exit(1);\n }\n return n;\n }\n // ISO 8601 with required timezone: 2026-05-01T09:00:00Z or 2026-05-01T09:00:00+05:30\n if (/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(Z|[+-]\\d{2}:\\d{2})$/.test(input)) {\n const ms = Date.parse(input);\n if (isNaN(ms)) {\n console.error(`Invalid datetime \"${input}\"`);\n process.exit(1);\n }\n return ms;\n }\n // Duration: 1d, 30m, 2h, 90s, or combinations like 1d12h\n const match = input.match(/^(?:(\\d+)d)?(?:(\\d+)h)?(?:(\\d+)m)?(?:(\\d+)s)?$/);\n if (match && (match[1] || match[2] || match[3] || match[4])) {\n const d = parseInt(match[1] ?? \"0\");\n const h = parseInt(match[2] ?? \"0\");\n const m = parseInt(match[3] ?? \"0\");\n const s = parseInt(match[4] ?? \"0\");\n return Date.now() + (d * 86400 + h * 3600 + m * 60 + s) * 1000;\n }\n console.error(`Cannot parse expiry \"${input}\". Use: 1d, 30m, 2h, 90s (relative duration), 2026-05-01T09:00:00Z (ISO 8601 with timezone), or unix-ms:<n>`);\n process.exit(1);\n}\n\n// ---- Formatting ----\n\nfunction fmtCountdown(ms: number): string {\n const sign = ms < 0 ? \"-\" : \"\";\n const abs = Math.abs(ms);\n const totalSec = Math.floor(abs / 1000);\n const d = Math.floor(totalSec / 86400);\n const h = Math.floor((totalSec % 86400) / 3600);\n const m = Math.floor((totalSec % 3600) / 60);\n const s = totalSec % 60;\n if (d > 0) return `${sign}${d}d ${h}h`;\n if (h > 0) return `${sign}${h}h ${m}m`;\n if (m > 0) return `${sign}${m}m ${s}s`;\n return `${sign}${s}s`;\n}\n\nfunction fmtDate(ms: number): string {\n return new Date(ms).toLocaleString();\n}\n\nfunction shortId(id: string): string {\n return id.slice(0, 8);\n}\n\nfunction col(s: string, w: number, ellipsis = false): string {\n if (ellipsis && s.length > w) return s.slice(0, w - 1) + \"…\";\n return s.slice(0, w).padEnd(w);\n}\n\n// ---- ID resolution ----\n\nasync function resolveTimerId(prefix: string, cfg: Config & { token: string; instanceId: string }): Promise<string> {\n if (/^[0-9a-f-]{36}$/.test(prefix)) return prefix;\n const api = createApiClient(cfg.server, cfg.token);\n const state = await api.getState(cfg.instanceId, cfg.token);\n const matches = state.timers.filter(t => t.id.startsWith(prefix));\n if (matches.length === 0) { console.error(`Timer not found: ${prefix}`); process.exit(1); }\n if (matches.length > 1) {\n console.error(`Ambiguous prefix \"${prefix}\" matches: ${matches.map(t => shortId(t.id) + \"…\").join(\", \")}`);\n process.exit(1);\n }\n return matches[0]!.id;\n}\n\nasync function resolveEventId(prefix: string, cfg: Config & { token: string; instanceId: string }): Promise<string> {\n if (/^[0-9a-f-]{36}$/.test(prefix)) return prefix;\n const api = createApiClient(cfg.server, cfg.token);\n // Fetch all events (paginated default covers most cases)\n const allIds: string[] = [];\n let from = 1;\n while (true) {\n const { events, latestSeq } = await api.listEvents(cfg.instanceId, cfg.token, { from, limit: 200 });\n allIds.push(...events.map(e => e.id));\n if (events.length < 200 || events[events.length - 1]!.seq >= latestSeq) break;\n from = events[events.length - 1]!.seq + 1;\n }\n const matches = allIds.filter(id => id.startsWith(prefix));\n if (matches.length === 0) { console.error(`Event not found: ${prefix}`); process.exit(1); }\n if (matches.length > 1) {\n console.error(`Ambiguous prefix \"${prefix}\" matches: ${matches.map(id => shortId(id) + \"…\").join(\", \")}`);\n process.exit(1);\n }\n return matches[0]!;\n}\n\nasync function resolveInstanceId(prefix: string, cfg: Config & { token: string }): Promise<string> {\n if (/^[0-9a-f-]{36}$/.test(prefix)) return prefix;\n const api = createApiClient(cfg.server, cfg.token);\n const { instances } = await api.listInstances(cfg.token);\n const matches = instances.filter(i => i.id.startsWith(prefix));\n if (matches.length === 0) { console.error(`Instance not found: ${prefix}`); process.exit(1); }\n if (matches.length > 1) {\n console.error(`Ambiguous prefix \"${prefix}\" matches: ${matches.map(i => `\"${i.nickname}\" (${shortId(i.id)}…)`).join(\", \")}`);\n process.exit(1);\n }\n return matches[0]!.id;\n}\n\n// ---- Guards ----\n\nfunction requireToken(cfg: Config): asserts cfg is Config & { token: string } {\n if (!cfg.token) {\n console.error(\"Not registered. Run: autonag register <nickname>\");\n process.exit(1);\n }\n}\n\nfunction requireInstance(cfg: Config): asserts cfg is Config & { instanceId: string } {\n if (!cfg.instanceId) {\n console.error(\"No instance selected. Run: autonag instances select <id>\");\n process.exit(1);\n }\n}\n\n// ---- Commands ----\n\nasync function cmdRegister(nickname: string, cfg: Config): Promise<void> {\n const api = createApiClient(cfg.server);\n const { device, token } = await api.registerDevice(nickname);\n cfg.token = token;\n cfg.deviceId = device.id;\n saveConfig(cfg);\n console.log(`Registered as \"${nickname}\" (${shortId(device.id)}…)`);\n console.log(`Token saved to ${CONFIG_PATH}`);\n console.log(`Waiting for admin approval — run \"autonag status\" to check.`);\n}\n\nasync function cmdStatus(cfg: Config): Promise<void> {\n console.log(`Server: ${cfg.server}`);\n console.log(`Config: ${CONFIG_PATH}`);\n if (!cfg.token) {\n console.log(`Auth: not registered (run: autonag register <nickname>)`);\n return;\n }\n const api = createApiClient(cfg.server, cfg.token);\n try {\n const { device: d } = await api.getMe(cfg.token);\n const status = d.approvedAt ? `approved ${fmtDate(d.approvedAt)}` : \"PENDING APPROVAL\";\n console.log(`Auth: ${d.nickname} (${shortId(d.id)}…) [${status}]`);\n } catch (e) {\n if (e instanceof ApiError && e.status === 401) {\n console.log(`Auth: token invalid or expired`);\n } else throw e;\n }\n console.log(`Instance: ${cfg.instanceId ?? \"none selected (run: autonag instances select <id>)\"}`);\n}\n\nasync function cmdInstancesList(cfg: Config): Promise<void> {\n requireToken(cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const { instances } = await api.listInstances(cfg.token);\n if (instances.length === 0) { console.log(\"No accessible instances.\"); return; }\n for (const i of instances) {\n const status = i.approvedAt ? \"active\" : \"PENDING\";\n const marker = i.id === cfg.instanceId ? \" *\" : \" \";\n console.log(`${marker} ${shortId(i.id)}… \"${i.nickname}\" [${status}]`);\n }\n console.log(`\\n* = current default`);\n}\n\nasync function cmdInstancesRequest(nickname: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const { instance } = await api.requestInstance(nickname, cfg.token);\n console.log(`Requested instance \"${instance.nickname}\" (${shortId(instance.id)}…)`);\n console.log(`Waiting for admin approval.`);\n}\n\nasync function cmdInstancesSelect(id: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n const instanceId = await resolveInstanceId(id, cfg);\n cfg.instanceId = instanceId;\n saveConfig(cfg);\n console.log(`Default instance set to ${instanceId}`);\n}\n\nasync function cmdInstancesJoin(instanceId: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n const api = createApiClient(cfg.server, cfg.token);\n await api.requestInstanceAccess(instanceId, cfg.token);\n console.log(`Access requested for instance ${shortId(instanceId)}…`);\n console.log(`An admin will need to approve your request.`);\n console.log(`Once approved, run: autonag instances select ${instanceId}`);\n}\n\nasync function cmdTimersList(cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const state = await api.getState(cfg.instanceId, cfg.token);\n\n const now = Date.now();\n const timers = [...state.timers].sort((a, b) => a.currentExpiry - b.currentExpiry);\n\n if (timers.length === 0) {\n console.log(\"No active timers.\");\n } else {\n console.log(`${\"ID\".padEnd(10)} ${\"Name\".padEnd(24)} ${\"Remaining\".padEnd(16)} Recur`);\n console.log(\"-\".repeat(60));\n for (const t of timers) {\n const remaining = t.currentExpiry - now;\n const label = remaining < 0\n ? `OVERDUE ${fmtCountdown(remaining)}`\n : `in ${fmtCountdown(remaining)}`;\n const recur = t.recurrence ? \"↻\" : \"\";\n console.log(`${col(shortId(t.id) + \"…\", 10)} ${col(t.name, 24, true)} ${col(label, 16)} ${recur}`);\n }\n }\n\n console.log();\n printAlarmStatus(state, now);\n}\n\nfunction printAlarmStatus(state: { alarm: { on: boolean; startsAt: number | null; urgentName: string | null; color: string }; shush: { expiry: number } | null }, now: number): void {\n const { alarm, shush } = state;\n const shushed = !!(shush && shush.expiry > now);\n const colorLabel: Record<string, string> = {\n blue: \"off\", green: \"green\", yellow: \"yellow\", red: \"red\", flashing: \"FLASHING\",\n };\n\n // Line 1: color + most urgent timer\n if (alarm.startsAt !== null) {\n const diff = alarm.startsAt - now;\n const colorStr = colorLabel[alarm.color] ?? alarm.color;\n const timeStr = diff <= 0 ? `overdue ${fmtCountdown(diff)}` : `in ${fmtCountdown(diff)}`;\n console.log(`[${colorStr}] \"${alarm.urgentName}\" — ${timeStr}`);\n }\n\n // Line 2: alarm state\n if (alarm.on) {\n console.log(`Alarm: ringing.`);\n } else if (shushed) {\n const overdue = alarm.startsAt !== null && alarm.startsAt <= now;\n // \"necessary\" = shush is actually blocking a ring (timer overdue now, or timer fires before shush ends)\n const shushEndsAfterTimer = alarm.startsAt !== null && shush!.expiry >= alarm.startsAt;\n const necessary = overdue || shushEndsAfterTimer;\n if (necessary) {\n const ringIn = fmtCountdown(shush!.expiry - now);\n console.log(`Alarm: off. Will ring in ${ringIn}: Shush expires: ${alarm.urgentName}.`);\n } else if (alarm.startsAt !== null) {\n // Shush ends before timer fires — timer still drives the ring time\n const ringIn = fmtCountdown(alarm.startsAt - now);\n const remaining = fmtCountdown(shush!.expiry - now);\n console.log(`Alarm: off. Will ring in ${ringIn}: ${alarm.urgentName}. (Shushed unnecessarily for ${remaining}.)`);\n } else {\n const remaining = fmtCountdown(shush!.expiry - now);\n console.log(`Alarm: off. Shushed (unnecessarily) for ${remaining}.`);\n }\n } else if (alarm.startsAt !== null) {\n const ringIn = fmtCountdown(alarm.startsAt - now);\n console.log(`Alarm: off. Will ring in ${ringIn}: ${alarm.urgentName}.`);\n } else {\n console.log(`Alarm: off.`);\n }\n}\n\nasync function cmdAlarm(cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const state = await api.getState(cfg.instanceId, cfg.token);\n printAlarmStatus(state, Date.now());\n}\n\nasync function cmdTimersAdd(\n name: string, expiryStr: string, cfg: Config,\n opts: { desc?: string; days?: number; anchor?: string; tz?: string; skipWeekends?: boolean }\n): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const expiry = parseExpiry(expiryStr);\n const recurrence = opts.days !== undefined ? {\n periodDays: opts.days,\n anchorTime: opts.anchor ?? \"09:00\",\n timezone: opts.tz ?? Intl.DateTimeFormat().resolvedOptions().timeZone,\n skipWeekends: opts.skipWeekends ?? false,\n } : undefined;\n await api.addTimer(cfg.instanceId, cfg.token, name, expiry, recurrence, opts.desc);\n const recurNote = recurrence ? ` (recurs every ${opts.days}d)` : \"\";\n console.log(`Timer \"${name}\" added, expires ${fmtDate(expiry)}${recurNote}`);\n}\n\nasync function cmdTimersRename(id: string, name: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const timerId = await resolveTimerId(id, cfg);\n const api = createApiClient(cfg.server, cfg.token);\n await api.renameTimer(cfg.instanceId, cfg.token, timerId, name);\n console.log(`Timer ${shortId(timerId)}… renamed to \"${name}\"`);\n}\n\nasync function cmdTimersSnooze(id: string, expiryStr: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const timerId = await resolveTimerId(id, cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const expiry = parseExpiry(expiryStr);\n await api.updateExpiry(cfg.instanceId, cfg.token, timerId, expiry);\n console.log(`Timer ${shortId(timerId)}… snoozed until ${fmtDate(expiry)}`);\n}\n\nasync function cmdTimersComplete(id: string, reason: string, cfg: Config, opts: { at?: number } = {}): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const state = await api.getState(cfg.instanceId, cfg.token);\n const timerId = await resolveTimerId(id, cfg);\n const timer = state.timers.find(t => t.id === timerId);\n\n if (timer?.recurrence) {\n await api.batchActions(cfg.instanceId, cfg.token, [{ type: \"recurTimer\", timerId, closeReason: reason, ...(opts.at != null ? { occurredAt: opts.at } : {}) }]);\n const newState = await api.getState(cfg.instanceId, cfg.token);\n const updated = newState.timers.find(t => t.id === timerId);\n if (updated) {\n console.log(`Timer \"${timer.name}\" recurred — next: ${fmtDate(updated.currentExpiry)}`);\n } else {\n console.log(`Timer ${shortId(timerId)}… recurred`);\n }\n } else {\n await api.batchActions(cfg.instanceId, cfg.token, [{ type: \"completeTimer\", timerId, closeReason: reason, ...(opts.at != null ? { occurredAt: opts.at } : {}) }]);\n const name = timer?.name ?? shortId(timerId);\n console.log(`Timer \"${name}\" completed (${reason})`);\n }\n}\n\nasync function cmdTimersRemove(id: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const state = await api.getState(cfg.instanceId, cfg.token);\n const timerId = await resolveTimerId(id, cfg);\n const timer = state.timers.find(t => t.id === timerId);\n await api.removeTimer(cfg.instanceId, cfg.token, timerId);\n const name = timer?.name ?? shortId(timerId);\n console.log(`Timer \"${name}\" removed`);\n}\n\nasync function cmdTimersDescribe(id: string, text: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const timerId = await resolveTimerId(id, cfg);\n const api = createApiClient(cfg.server, cfg.token);\n await api.batchActions(cfg.instanceId, cfg.token, [{ type: \"updateDescription\", timerId, description: text }]);\n console.log(`Timer ${shortId(timerId)}… description updated`);\n}\n\nasync function cmdTimersGetDescription(id: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const timerId = await resolveTimerId(id, cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const state = await api.getState(cfg.instanceId, cfg.token);\n const timer = state.timers.find(t => t.id === timerId);\n if (!timer) { console.error(`Timer not found: ${timerId}`); process.exit(1); }\n if (!timer.description) { console.log(\"(no description)\"); return; }\n console.log(timer.description);\n}\n\nasync function cmdTimersRecurrenceSet(\n id: string, days: number, cfg: Config,\n opts: { anchor?: string; tz?: string; skipWeekends?: boolean }\n): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const timerId = await resolveTimerId(id, cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const recurrence = {\n periodDays: days,\n anchorTime: opts.anchor ?? \"09:00\",\n timezone: opts.tz ?? Intl.DateTimeFormat().resolvedOptions().timeZone,\n skipWeekends: opts.skipWeekends ?? false,\n };\n await api.batchActions(cfg.instanceId, cfg.token, [{ type: \"updateRecurrence\", timerId, recurrence }]);\n console.log(`Timer ${shortId(timerId)}… recurrence set to every ${days}d at ${recurrence.anchorTime} (${recurrence.timezone})`);\n}\n\nasync function cmdTimersRecurrenceRemove(id: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const timerId = await resolveTimerId(id, cfg);\n const api = createApiClient(cfg.server, cfg.token);\n await api.batchActions(cfg.instanceId, cfg.token, [{ type: \"removeRecurrence\", timerId }]);\n console.log(`Timer ${shortId(timerId)}… recurrence removed`);\n}\n\nasync function cmdTimersHistory(id: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const timerId = await resolveTimerId(id, cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const allEntries: Array<{ date: number; closeReason: string; type: string }> = [];\n let cursor: number | null = 0;\n while (cursor !== null) {\n const { events, nextCursor } = await api.getTimerHistory(cfg.instanceId, cfg.token, timerId, { after: cursor });\n for (const ev of events) {\n const p = ev.payload as Record<string, unknown>;\n const date = (ev.type === \"TimerRecurred\" || ev.type === \"TimerCompletionLogged\")\n ? (p[\"occurredAt\"] as number) ?? ev.timestamp\n : ev.timestamp;\n allEntries.push({ date, closeReason: p[\"closeReason\"] as string, type: ev.type });\n }\n cursor = nextCursor;\n }\n if (allEntries.length === 0) { console.log(\"No history yet.\"); return; }\n console.log(`${\"Date\".padEnd(22)} ${\"Reason\".padEnd(16)} Type`);\n console.log(\"-\".repeat(56));\n for (const e of allEntries) {\n const typeLabel = e.type === \"TimerCompletionLogged\" ? \"logged\" : e.type === \"TimerRecurred\" ? \"recurred\" : \"completed\";\n console.log(`${col(fmtDate(e.date), 22)} ${col(e.closeReason, 16)} ${typeLabel}`);\n }\n}\n\nasync function cmdTimersLog(id: string, reason: string, at: number, cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const state = await api.getState(cfg.instanceId, cfg.token);\n const timerId = await resolveTimerId(id, cfg);\n const timer = state.timers.find(t => t.id === timerId);\n if (!timer) { console.error(`Timer not found: ${id}`); process.exit(1); }\n await api.batchActions(cfg.instanceId, cfg.token, [{ type: \"logCompletion\", timerId, closeReason: reason, occurredAt: at }]);\n console.log(`Logged \"${reason}\" for \"${timer.name}\" at ${fmtDate(at)}`);\n}\n\nasync function cmdShush(durationStr: string | undefined, cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const expiry = durationStr ? parseExpiry(durationStr) : Date.now() + 30 * 60 * 1000;\n await api.setShush(cfg.instanceId, cfg.token, expiry);\n console.log(`Alarm silenced until ${fmtDate(expiry)}`);\n}\n\nasync function cmdUnshush(cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const api = createApiClient(cfg.server, cfg.token);\n await api.clearShush(cfg.instanceId, cfg.token);\n console.log(`Shush cleared`);\n}\n\nasync function cmdEventsList(fromSeq: number, cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const { events } = await api.listEvents(cfg.instanceId, cfg.token, { from: fromSeq });\n if (events.length === 0) { console.log(\"No events.\"); return; }\n console.log(`${\"seq\".padEnd(6)} ${\"ID\".padEnd(10)} ${\"Type\".padEnd(28)} ${\"Time\".padEnd(20)} Skipped`);\n console.log(\"-\".repeat(78));\n for (const e of events) {\n const skipped = e.skipped ? \"yes\" : \"\";\n console.log(`${String(e.seq).padEnd(6)} ${col(shortId(e.id) + \"…\", 10)} ${col(e.type, 28)} ${col(fmtDate(e.timestamp), 20)} ${skipped}`);\n }\n}\n\nasync function cmdEventsSkip(id: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const eventId = await resolveEventId(id, cfg);\n const api = createApiClient(cfg.server, cfg.token);\n await api.skipEvent(cfg.instanceId, cfg.token, eventId);\n console.log(`Event ${shortId(eventId)}… skipped`);\n}\n\nasync function cmdEventsUnskip(id: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const eventId = await resolveEventId(id, cfg);\n const api = createApiClient(cfg.server, cfg.token);\n await api.unskipEvent(cfg.instanceId, cfg.token, eventId);\n console.log(`Event ${shortId(eventId)}… unskipped`);\n}\n\nasync function cmdTimersView(id: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const timerId = await resolveTimerId(id, cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const state = await api.getState(cfg.instanceId, cfg.token);\n const timer = state.timers.find(t => t.id === timerId);\n if (!timer) { console.error(`Timer not found: ${timerId}`); process.exit(1); }\n\n const now = Date.now();\n const remaining = timer.currentExpiry - now;\n const expiryStr = `${fmtDate(timer.currentExpiry)} (${remaining >= 0 ? \"in \" : \"\"}${fmtCountdown(remaining)})`;\n\n console.log(`ID: ${timer.id}`);\n console.log(`Name: ${timer.name}`);\n if (timer.description) {\n if (timer.description.length > 500) {\n console.log(`Description: ${timer.description.slice(0, 497)}...`);\n console.log(` (${timer.description.length} chars total — run 'timers description ${shortId(timerId)}' for full text)`);\n } else {\n console.log(`Description: ${timer.description}`);\n }\n }\n console.log(`Expires: ${expiryStr}`);\n console.log(`Created: ${fmtDate(timer.created)}`);\n if (timer.recurrence) {\n const r = timer.recurrence;\n const wknd = r.skipWeekends ? \", skip weekends\" : \"\";\n console.log(`Recurrence: every ${r.periodDays}d at ${r.anchorTime} ${r.timezone}${wknd}`);\n }\n\n const { comments } = await api.listComments(cfg.instanceId, cfg.token, timerId);\n if (comments.length > 0) {\n const PREVIEW = 5;\n const shown = comments.slice(-PREVIEW);\n const hidden = comments.length - shown.length;\n console.log(`\\nComments:${hidden > 0 ? ` (${hidden} older — run 'comments list ${shortId(timerId)}' to see all)` : \"\"}`);\n for (const c of shown) {\n const text = c.text.length > 80 ? c.text.slice(0, 77) + \"...\" : c.text;\n console.log(` ${fmtDate(c.createdAt)} ${text}`);\n }\n }\n}\n\nasync function cmdCommentsList(id: string, cfg: Config, opts: { limit?: number } = {}): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const timerId = await resolveTimerId(id, cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const { comments } = await api.listComments(cfg.instanceId, cfg.token, timerId);\n if (comments.length === 0) { console.log(\"No comments.\"); return; }\n const shown = opts.limit != null ? comments.slice(-opts.limit) : comments;\n const hidden = comments.length - shown.length;\n if (hidden > 0) console.log(`(${hidden} older comments not shown)`);\n for (const c of shown) {\n console.log(`[${fmtDate(c.createdAt)}] ${c.text}`);\n }\n}\n\nasync function cmdCommentsAdd(id: string, text: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n requireInstance(cfg);\n const timerId = await resolveTimerId(id, cfg);\n const api = createApiClient(cfg.server, cfg.token);\n await api.addComment(cfg.instanceId, cfg.token, timerId, text);\n console.log(`Comment added`);\n}\n\n// ---- Tutorial ----\n\nfunction cmdTutorial(): void {\n console.log(`# autonag tutorial\n\nautonag is a recurring-task tracker with an alarm. Timers count down; when\nthey expire, your alarm client starts ringing. You mark them done — if the\ntimer is recurring, the next occurrence is automatically scheduled.\n\n## Config\n\nYour config lives at \\`~/.config/autonag/client.json5\\`. It is a JSON5 file\n(JSON with comments and trailing commas), so you can annotate it. After\nregistration it looks something like:\n\n\\`\\`\\`json5\n{\n server: 'https://your-server.example',\n token: '…',\n deviceId: '…',\n instanceId: '…',\n}\n\\`\\`\\`\n\nEdit it directly in a text editor whenever you need to change the server\nURL or switch instances. To use a different config file:\n\n\\`\\`\\`\nautonag --config /path/to/other.json5 timers list\n\\`\\`\\`\n\n## First-time setup\n\nRegister this device — give it a short nickname so the admin knows who you are:\n\n\\`\\`\\`\nautonag register myphone\n\\`\\`\\`\n\nYour auth token and device ID are saved to the config. The device starts in\nPENDING state until an admin approves it. Check your status:\n\n\\`\\`\\`\nautonag status\n\\`\\`\\`\n\n## Getting an instance\n\nTimers live in an instance. Create a new one:\n\n\\`\\`\\`\nautonag instances request home\n\\`\\`\\`\n\nWhen the admin approves it, it shows up in your list:\n\n\\`\\`\\`\nautonag instances list\n\\`\\`\\`\n\nSet it as your default:\n\n\\`\\`\\`\nautonag instances select <id>\n\\`\\`\\`\n\nTo join an instance someone else owns, ask them for the instance ID. Then\nrequest access:\n\n\\`\\`\\`\nautonag instances join <instance-id>\n\\`\\`\\`\n\nAn admin will approve your request. The instance ID is not advertised\npublicly — you need to know it.\n\n## Adding timers\n\nOne-shot reminder due in 2 days:\n\n\\`\\`\\`\nautonag timers add \"Doctor follow-up\" 2d\n\\`\\`\\`\n\nRecurring task every 7 days at 9 AM:\n\n\\`\\`\\`\nautonag timers add \"Weekly review\" 7d --days 7 --anchor 09:00\n\\`\\`\\`\n\nThe first argument after the name is the initial expiry. \\`--days\\` makes it\nrecurring; \\`--anchor\\` sets the time of day; \\`--tz\\` overrides the timezone.\n\n## Checking timers\n\n\\`\\`\\`\nautonag timers list\n\\`\\`\\`\n\n\\`\\`\\`\nID Name Remaining Recur\n------------------------------------------------------------\na1b2c3d4… Doctor follow-up in 1d 23h\ne5f6a7b8… Weekly review in 6d 23h ↻\n\\`\\`\\`\n\nThe ↻ symbol marks recurring timers.\n\n## Completing a timer\n\nMark a timer done with a reason (pass, fail, or any custom string):\n\n\\`\\`\\`\nautonag timers complete e5f6 pass\n\\`\\`\\`\n\nFor a one-shot timer this removes it. For a recurring timer it schedules\nthe next occurrence and tells you when:\n\n\\`\\`\\`\nTimer \"Weekly review\" recurred — next: 4/24/2026, 9:00:00 AM\n\\`\\`\\`\n\nTo permanently stop a recurring timer, remove the recurrence first:\n\n\\`\\`\\`\nautonag timers recurrence remove e5f6\nautonag timers complete e5f6 done\n\\`\\`\\`\n\n## Snoozing\n\nPush a timer's deadline out:\n\n\\`\\`\\`\nautonag timers snooze e5f6 3d\n\\`\\`\\`\n\n## Silencing the alarm\n\nSilence the alarm for 30 minutes (the default):\n\n\\`\\`\\`\nautonag shush\n\\`\\`\\`\n\nOr for a specific duration:\n\n\\`\\`\\`\nautonag shush 2h\n\\`\\`\\`\n\nResume:\n\n\\`\\`\\`\nautonag unshush\n\\`\\`\\`\n\n## History\n\nSee every time a recurring timer was completed:\n\n\\`\\`\\`\nautonag timers history e5f6\n\\`\\`\\`\n\n## Notes and comments\n\nAttach a description to a timer:\n\n\\`\\`\\`\nautonag timers describe e5f6 \"Prep the agenda before this\"\n\\`\\`\\`\n\nAdd timestamped comments (good for logging what happened):\n\n\\`\\`\\`\nautonag comments add e5f6 \"Completed but flagged the follow-up\"\n\\`\\`\\`\n\n## Event log\n\nEvery action is recorded. View the log:\n\n\\`\\`\\`\nautonag events list\n\\`\\`\\`\n\nYou can skip events to undo them — state is recomputed as if the\nskipped event never happened:\n\n\\`\\`\\`\nautonag events skip <event-id>\nautonag events unskip <event-id>\n\\`\\`\\`\n\n---\nRun \\`autonag --help\\` for a full command reference.`);\n}\n\n// ---- Help ----\n\nconst HELP = `autonag client CLI\n\nUsage: autonag [options] <command> [args]\n\nOptions:\n -h, --help Show this help\n -s, --server <url> Server URL (default: http://localhost:3000)\n -i, --instance <id> Instance ID (overrides saved default)\n -c, --config <path> Config file (default: ~/.config/autonag/client.json5)\n\n tutorial Walk through setup and daily workflow\n\nAuth:\n register <nickname> Register this device and save token\n status Show auth status and saved config\n\nInstances:\n instances list\n instances request <nickname> Create a new instance\n instances join <instance-id> Request access to an existing instance\n instances select <id>\n\nTimers:\n timers list\n timers add <name> <expiry> [--desc <text>] [--days <n>] [--anchor <HH:MM>] [--tz <tz>] [--skip-weekends]\n timers rename <id> <name>\n timers snooze <id> <expiry> Update expiry: 1d, 30m, 2h, 90s | 2026-05-01T09:00:00Z | unix-ms:<n>\n timers pass <id> [--at <datetime>] Complete with reason \"pass\" (preferred)\n timers fail <id> [--at <datetime>] Complete with reason \"fail\" (preferred)\n timers complete <id> <reason> [--at <datetime>] Complete with a custom reason\n timers remove <id>\n timers view <id> Show full timer details, description, and recent comments\n timers describe <id> <text> Set description\n timers description <id> Print full description\n timers recurrence set <id> <days> [--anchor <HH:MM>] [--tz <tz>] [--skip-weekends]\n timers recurrence remove <id>\n timers history <id> Show completion history\n timers log <id> <reason> --at <datetime> Log a historical completion (no expiry change)\n\nAlarm:\n alarm show Show current alarm state\n\nShush:\n shush [duration] Silence alarm (default: 30m)\n unshush Clear shush\n\nEvents:\n events list [--from <seq>]\n events skip <id>\n events unskip <id>\n\nComments:\n comments list <timerId> [--limit N]\n comments add <timerId> <text>\n\nConfig saved to ~/.config/autonag/client.json5`;\n\n// ---- Flag parsing ----\n\ntype FlagSchema = Record<string, \"string\" | \"int\" | \"boolean\">;\ntype ParsedFlags = { positional: string[]; flags: Record<string, string | number | boolean> };\n\nfunction parseFlags(args: string[], schema: FlagSchema): ParsedFlags {\n const positional: string[] = [];\n const flags: Record<string, string | number | boolean> = {};\n for (let i = 0; i < args.length; i++) {\n const a = args[i]!;\n if (a.startsWith(\"--\")) {\n const key = a.slice(2);\n if (!(key in schema)) {\n console.error(`Unknown flag: --${key}`);\n process.exit(1);\n }\n const type = schema[key]!;\n if (type === \"boolean\") {\n flags[key] = true;\n } else {\n const next = args[i + 1];\n if (!next || next.startsWith(\"--\")) {\n console.error(`Flag --${key} requires a value`);\n process.exit(1);\n }\n if (type === \"int\") {\n const n = Number(next);\n if (!Number.isInteger(n)) {\n console.error(`Flag --${key} must be an integer, got: \"${next}\"`);\n process.exit(1);\n }\n flags[key] = n;\n } else {\n flags[key] = next;\n }\n i++;\n }\n } else {\n positional.push(a);\n }\n }\n return { positional, flags };\n}\n\n// ---- Arg parsing & dispatch ----\n\nconst rawArgs = process.argv.slice(2);\nconst topArgs: string[] = [];\nlet serverOverride: string | undefined;\nlet instanceOverride: string | undefined;\n\nfor (let i = 0; i < rawArgs.length; i++) {\n const a = rawArgs[i]!;\n if (a === \"-h\" || a === \"--help\") { console.log(HELP); process.exit(0); }\n else if (a === \"-s\" || a === \"--server\") {\n if (!rawArgs[i + 1] || rawArgs[i + 1]!.startsWith(\"-\")) { console.error(\"Flag -s/--server requires a URL\"); process.exit(1); }\n serverOverride = rawArgs[++i];\n }\n else if (a === \"-i\" || a === \"--instance\") {\n if (!rawArgs[i + 1] || rawArgs[i + 1]!.startsWith(\"-\")) { console.error(\"Flag -i/--instance requires an ID\"); process.exit(1); }\n instanceOverride = rawArgs[++i];\n }\n else if (a === \"-c\" || a === \"--config\") {\n if (!rawArgs[i + 1] || rawArgs[i + 1]!.startsWith(\"-\")) { console.error(\"Flag -c/--config requires a path\"); process.exit(1); }\n CONFIG_PATH = rawArgs[++i]!;\n }\n else topArgs.push(a);\n}\n\nconst cfg = loadConfig();\nif (serverOverride) cfg.server = serverOverride;\nif (instanceOverride) cfg.instanceId = instanceOverride;\n\nconst [cmd, sub, ...rest] = topArgs;\n\ntry {\n if (!cmd || cmd === \"help\") {\n parseFlags(rest, {});\n console.log(HELP);\n } else if (cmd === \"tutorial\") {\n parseFlags(rest, {});\n cmdTutorial();\n\n } else if (cmd === \"register\") {\n parseFlags(rest, {});\n if (!sub) { console.error(\"Usage: autonag register <nickname>\"); process.exit(1); }\n await cmdRegister(sub, cfg);\n\n } else if (cmd === \"status\") {\n parseFlags(rest, {});\n await cmdStatus(cfg);\n\n } else if (cmd === \"instances\") {\n if (!sub || sub === \"list\") {\n parseFlags(rest, {});\n await cmdInstancesList(cfg);\n } else if (sub === \"request\") {\n const { positional } = parseFlags(rest, {});\n if (!positional[0]) { console.error(\"Usage: autonag instances request <nickname>\"); process.exit(1); }\n await cmdInstancesRequest(positional[0], cfg);\n } else if (sub === \"join\") {\n const { positional } = parseFlags(rest, {});\n if (!positional[0]) { console.error(\"Usage: autonag instances join <instance-id>\"); process.exit(1); }\n await cmdInstancesJoin(positional[0], cfg);\n } else if (sub === \"select\") {\n const { positional } = parseFlags(rest, {});\n if (!positional[0]) { console.error(\"Usage: autonag instances select <id>\"); process.exit(1); }\n await cmdInstancesSelect(positional[0], cfg);\n } else {\n console.error(`Unknown subcommand: instances ${sub}`); process.exit(1);\n }\n\n } else if (cmd === \"timers\") {\n if (!sub || sub === \"list\") {\n parseFlags(rest, {});\n await cmdTimersList(cfg);\n } else if (sub === \"add\") {\n const { positional, flags } = parseFlags(rest, {\n desc: \"string\", days: \"int\", anchor: \"string\", tz: \"string\", \"skip-weekends\": \"boolean\",\n });\n if (!positional[0] || !positional[1]) { console.error(\"Usage: autonag timers add <name> <expiry> [--desc <text>] [--days <n>] [--anchor <HH:MM>] [--tz <tz>] [--skip-weekends]\"); process.exit(1); }\n await cmdTimersAdd(positional[0], positional[1], cfg, {\n desc: flags.desc as string | undefined,\n days: flags.days as number | undefined,\n anchor: flags.anchor as string | undefined,\n tz: flags.tz as string | undefined,\n skipWeekends: flags[\"skip-weekends\"] === true,\n });\n } else if (sub === \"rename\") {\n const { positional } = parseFlags(rest, {});\n if (!positional[0] || !positional[1]) { console.error(\"Usage: autonag timers rename <id> <name>\"); process.exit(1); }\n await cmdTimersRename(positional[0], positional[1], cfg);\n } else if (sub === \"snooze\") {\n const { positional } = parseFlags(rest, {});\n if (!positional[0] || !positional[1]) { console.error(\"Usage: autonag timers snooze <id> <expiry>\"); process.exit(1); }\n await cmdTimersSnooze(positional[0], positional[1], cfg);\n } else if (sub === \"pass\") {\n const { positional, flags } = parseFlags(rest, { at: \"string\" });\n if (!positional[0]) { console.error(\"Usage: autonag timers pass <id> [--at <datetime>]\"); process.exit(1); }\n const at = flags.at ? parseExpiry(flags.at as string) : undefined;\n await cmdTimersComplete(positional[0], \"pass\", cfg, { at });\n } else if (sub === \"fail\") {\n const { positional, flags } = parseFlags(rest, { at: \"string\" });\n if (!positional[0]) { console.error(\"Usage: autonag timers fail <id> [--at <datetime>]\"); process.exit(1); }\n const at = flags.at ? parseExpiry(flags.at as string) : undefined;\n await cmdTimersComplete(positional[0], \"fail\", cfg, { at });\n } else if (sub === \"complete\") {\n const { positional, flags } = parseFlags(rest, { at: \"string\" });\n if (!positional[0] || !positional[1]) { console.error(\"Usage: autonag timers complete <id> <reason> [--at <datetime>]\"); process.exit(1); }\n const at = flags.at ? parseExpiry(flags.at as string) : undefined;\n await cmdTimersComplete(positional[0], positional[1], cfg, { at });\n } else if (sub === \"remove\") {\n const { positional } = parseFlags(rest, {});\n if (!positional[0]) { console.error(\"Usage: autonag timers remove <id>\"); process.exit(1); }\n await cmdTimersRemove(positional[0], cfg);\n } else if (sub === \"describe\") {\n const { positional } = parseFlags(rest, {});\n if (!positional[0] || !positional[1]) { console.error(\"Usage: autonag timers describe <id> <text>\"); process.exit(1); }\n await cmdTimersDescribe(positional[0], positional[1], cfg);\n } else if (sub === \"description\") {\n const { positional } = parseFlags(rest, {});\n if (!positional[0]) { console.error(\"Usage: autonag timers description <id>\"); process.exit(1); }\n await cmdTimersGetDescription(positional[0], cfg);\n } else if (sub === \"recurrence\") {\n const recSub = rest[0];\n if (recSub === \"set\") {\n const { positional, flags } = parseFlags(rest, { anchor: \"string\", tz: \"string\", \"skip-weekends\": \"boolean\" });\n // positional = [\"set\", id, days]\n if (!positional[1] || !positional[2]) { console.error(\"Usage: autonag timers recurrence set <id> <days> [--anchor <HH:MM>] [--tz <tz>] [--skip-weekends]\"); process.exit(1); }\n const days = Number(positional[2]);\n if (!Number.isInteger(days) || days <= 0) { console.error(`<days> must be a positive integer, got: \"${positional[2]}\"`); process.exit(1); }\n await cmdTimersRecurrenceSet(positional[1], days, cfg, {\n anchor: flags.anchor as string | undefined,\n tz: flags.tz as string | undefined,\n skipWeekends: flags[\"skip-weekends\"] === true,\n });\n } else if (recSub === \"remove\") {\n const { positional } = parseFlags(rest, {});\n // positional = [\"remove\", id]\n if (!positional[1]) { console.error(\"Usage: autonag timers recurrence remove <id>\"); process.exit(1); }\n await cmdTimersRecurrenceRemove(positional[1], cfg);\n } else {\n console.error(\"Usage: autonag timers recurrence set|remove ...\"); process.exit(1);\n }\n } else if (sub === \"view\") {\n const { positional } = parseFlags(rest, {});\n if (!positional[0]) { console.error(\"Usage: autonag timers view <id>\"); process.exit(1); }\n await cmdTimersView(positional[0], cfg);\n } else if (sub === \"history\") {\n const { positional } = parseFlags(rest, {});\n if (!positional[0]) { console.error(\"Usage: autonag timers history <id>\"); process.exit(1); }\n await cmdTimersHistory(positional[0], cfg);\n } else if (sub === \"log\") {\n const { positional, flags } = parseFlags(rest, { at: \"string\" });\n if (!positional[0] || !positional[1]) { console.error(\"Usage: autonag timers log <id> <reason> --at <datetime>\"); process.exit(1); }\n if (!flags.at) { console.error(\"--at <datetime> is required for timers log\"); process.exit(1); }\n const at = parseExpiry(flags.at as string);\n await cmdTimersLog(positional[0], positional[1], at, cfg);\n } else {\n console.error(`Unknown subcommand: timers ${sub}`); process.exit(1);\n }\n\n } else if (cmd === \"alarm\") {\n if (sub !== \"show\") { console.error(\"Usage: autonag alarm show\"); process.exit(1); }\n parseFlags(rest, {});\n await cmdAlarm(cfg);\n\n } else if (cmd === \"shush\") {\n parseFlags(rest, {});\n await cmdShush(sub, cfg);\n } else if (cmd === \"unshush\") {\n parseFlags(rest, {});\n await cmdUnshush(cfg);\n\n } else if (cmd === \"events\") {\n if (!sub || sub === \"list\") {\n const { flags } = parseFlags(rest, { from: \"int\" });\n await cmdEventsList((flags.from as number | undefined) ?? 1, cfg);\n } else if (sub === \"skip\") {\n const { positional } = parseFlags(rest, {});\n if (!positional[0]) { console.error(\"Usage: autonag events skip <id>\"); process.exit(1); }\n await cmdEventsSkip(positional[0], cfg);\n } else if (sub === \"unskip\") {\n const { positional } = parseFlags(rest, {});\n if (!positional[0]) { console.error(\"Usage: autonag events unskip <id>\"); process.exit(1); }\n await cmdEventsUnskip(positional[0], cfg);\n } else {\n console.error(`Unknown subcommand: events ${sub}`); process.exit(1);\n }\n\n } else if (cmd === \"comments\") {\n if (!sub || sub === \"list\") {\n const { positional, flags } = parseFlags(rest, { limit: \"int\" });\n if (!positional[0]) { console.error(\"Usage: autonag comments list <timerId> [--limit N]\"); process.exit(1); }\n await cmdCommentsList(positional[0], cfg, { limit: flags.limit as number | undefined });\n } else if (sub === \"add\") {\n const { positional } = parseFlags(rest, {});\n if (!positional[0] || !positional[1]) { console.error(\"Usage: autonag comments add <timerId> <text>\"); process.exit(1); }\n await cmdCommentsAdd(positional[0], positional[1], cfg);\n } else {\n console.error(`Unknown subcommand: comments ${sub}`); process.exit(1);\n }\n\n } else {\n console.error(`Unknown command: ${cmd}`);\n console.error(`Run \"autonag --help\" for usage.`);\n process.exit(1);\n }\n} catch (e) {\n if (e instanceof ApiError) {\n console.error(`Error: ${e.message}`);\n process.exit(1);\n }\n throw e;\n}\n","import type { RecurrenceSpec, StoredEvent, Comment, InstanceState } from \"./types\";\n\nexport class ApiError extends Error {\n constructor(public status: number, message: string) {\n super(message);\n this.name = \"ApiError\";\n }\n}\n\nexport type BatchActionItem =\n | { type: \"addTimer\"; name: string; description?: string; expiry: number; recurrence?: RecurrenceSpec }\n | { type: \"updateExpiry\"; timerId: string; expiry: number }\n | { type: \"completeTimer\"; timerId: string; closeReason: string; occurredAt?: number }\n | { type: \"removeTimer\"; timerId: string }\n | { type: \"shush\"; expiry: number }\n | { type: \"clearShush\" }\n | { type: \"recurTimer\"; timerId: string; closeReason: string; occurredAt?: number }\n | { type: \"updateRecurrence\"; timerId: string; recurrence: RecurrenceSpec }\n | { type: \"removeRecurrence\"; timerId: string }\n | { type: \"updateDescription\"; timerId: string; description: string }\n | { type: \"logCompletion\"; timerId: string; closeReason: string; occurredAt: number }\n | { type: \"assert\"; path: string; expectStatus?: number; expect?: unknown };\n\nexport function createApiClient(baseUrl: string, defaultToken?: string) {\n async function apiFetch<T>(\n path: string,\n options: RequestInit = {},\n token?: string,\n ): Promise<T> {\n const tok = token ?? defaultToken;\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...(options.headers as Record<string, string>),\n };\n if (tok) headers[\"Authorization\"] = `Bearer ${tok}`;\n\n const res = await fetch(`${baseUrl}${path}`, { ...options, headers });\n if (!res.ok) {\n let message = `HTTP ${res.status}`;\n try {\n const body = await res.json() as { error?: string };\n if (body.error) message = body.error;\n } catch { /* ignore */ }\n throw new ApiError(res.status, message);\n }\n return res.json() as Promise<T>;\n }\n\n return {\n registerDevice: (nickname: string) =>\n apiFetch<{ device: { id: string; nickname: string }; token: string }>(\n \"/devices/request\", { method: \"POST\", body: JSON.stringify({ nickname }) }\n ),\n\n getMe: (token: string) =>\n apiFetch<{ device: { id: string; nickname: string; approvedAt: number | null } }>(\n \"/devices/me\", {}, token\n ),\n\n requestInstance: (nickname: string, token: string) =>\n apiFetch<{ instance: { id: string; nickname: string } }>(\n \"/instances/request\", { method: \"POST\", body: JSON.stringify({ nickname }) }, token\n ),\n\n requestInstanceAccess: (instanceId: string, token: string) =>\n apiFetch<{ request?: { id: string; status: string }; status?: string }>(\n `/instances/${instanceId}/access/request`,\n { method: \"POST\", body: JSON.stringify({}) },\n token\n ),\n\n listInstances: (token: string) =>\n apiFetch<{ instances: { id: string; nickname: string; approvedAt: number | null }[] }>(\n \"/instances\", {}, token\n ),\n\n addTimer: (instanceId: string, token: string, name: string, expiry: number, recurrence?: RecurrenceSpec, description?: string) =>\n apiFetch<{ timer: { id: string }; event: { id: string; seq: number } }>(\n `/instances/${instanceId}/timers`,\n { method: \"POST\", body: JSON.stringify({ name, expiry, ...(description ? { description } : {}), ...(recurrence ? { recurrence } : {}) }) },\n token\n ),\n\n renameTimer: (instanceId: string, token: string, timerId: string, name: string) =>\n apiFetch<{ event: { id: string; seq: number } }>(\n `/instances/${instanceId}/timers/${timerId}/name`,\n { method: \"PATCH\", body: JSON.stringify({ name }) },\n token\n ),\n\n updateExpiry: (instanceId: string, token: string, timerId: string, expiry: number) =>\n apiFetch<{ event: { id: string; seq: number } }>(\n `/instances/${instanceId}/timers/${timerId}/expiry`,\n { method: \"PATCH\", body: JSON.stringify({ expiry }) },\n token\n ),\n\n completeTimer: (instanceId: string, token: string, timerId: string, closeReason: string) =>\n apiFetch<{ event: { id: string; seq: number } }>(\n `/instances/${instanceId}/timers/${timerId}/complete`,\n { method: \"POST\", body: JSON.stringify({ closeReason }) },\n token\n ),\n\n removeTimer: (instanceId: string, token: string, timerId: string) =>\n apiFetch<{ event: { id: string; seq: number } }>(\n `/instances/${instanceId}/timers/${timerId}`,\n { method: \"DELETE\" },\n token\n ),\n\n setShush: (instanceId: string, token: string, expiry: number) =>\n apiFetch<{ event: { id: string; seq: number } }>(\n `/instances/${instanceId}/shush`,\n { method: \"POST\", body: JSON.stringify({ expiry }) },\n token\n ),\n\n clearShush: (instanceId: string, token: string) =>\n apiFetch<{ event: { id: string; seq: number } }>(\n `/instances/${instanceId}/shush`,\n { method: \"DELETE\" },\n token\n ),\n\n listEvents: (instanceId: string, token: string, opts: { from?: number; before?: number; limit?: number } = {}) => {\n const { from = 1, before, limit = 200 } = opts;\n const params = before !== undefined\n ? `before=${before}&limit=${limit}`\n : `from=${from}&limit=${limit}`;\n return apiFetch<{ events: StoredEvent[]; latestSeq: number; prevCursor?: number | null }>(\n `/instances/${instanceId}/events?${params}`, {}, token\n );\n },\n\n getTimerHistory: (instanceId: string, token: string, timerId: string, opts: {\n after?: number; limit?: number; from?: number; to?: number;\n } = {}) => {\n const params = new URLSearchParams();\n if (opts.after !== undefined) params.set(\"after\", String(opts.after));\n if (opts.limit !== undefined) params.set(\"limit\", String(opts.limit));\n if (opts.from !== undefined) params.set(\"from\", String(opts.from));\n if (opts.to !== undefined) params.set(\"to\", String(opts.to));\n const qs = params.toString();\n return apiFetch<{ events: StoredEvent[]; nextCursor: number | null }>(\n `/instances/${instanceId}/timers/${timerId}/history${qs ? `?${qs}` : \"\"}`, {}, token\n );\n },\n\n skipEvent: (instanceId: string, token: string, eventId: string) =>\n apiFetch<{ ok: boolean }>(\n `/instances/${instanceId}/events/${eventId}/skip`, { method: \"POST\" }, token\n ),\n\n unskipEvent: (instanceId: string, token: string, eventId: string) =>\n apiFetch<{ ok: boolean }>(\n `/instances/${instanceId}/events/${eventId}/skip`, { method: \"DELETE\" }, token\n ),\n\n listComments: (instanceId: string, token: string, threadId: string) =>\n apiFetch<{ comments: Comment[] }>(\n `/instances/${instanceId}/threads/${threadId}/comments`, {}, token\n ),\n\n addComment: (instanceId: string, token: string, threadId: string, text: string) =>\n apiFetch<{ comment: Comment }>(\n `/instances/${instanceId}/threads/${threadId}/comments`,\n { method: \"POST\", body: JSON.stringify({ text }) },\n token\n ),\n\n getState: (instanceId: string, token: string) =>\n apiFetch<InstanceState>(\n `/instances/${instanceId}/state`, {}, token\n ),\n\n batchActions: (instanceId: string, token: string, actions: BatchActionItem[]) =>\n apiFetch<{ events: { id: string; seq: number; type: string }[] }>(\n `/instances/${instanceId}/actions`,\n { method: \"POST\", body: JSON.stringify({ actions }) },\n token\n ),\n };\n}\n"],"mappings":"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","names":["cfg"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -97,6 +97,7 @@ type BatchActionItem = {
|
|
|
97
97
|
type: "completeTimer";
|
|
98
98
|
timerId: string;
|
|
99
99
|
closeReason: string;
|
|
100
|
+
occurredAt?: number;
|
|
100
101
|
} | {
|
|
101
102
|
type: "removeTimer";
|
|
102
103
|
timerId: string;
|
|
@@ -109,6 +110,7 @@ type BatchActionItem = {
|
|
|
109
110
|
type: "recurTimer";
|
|
110
111
|
timerId: string;
|
|
111
112
|
closeReason: string;
|
|
113
|
+
occurredAt?: number;
|
|
112
114
|
} | {
|
|
113
115
|
type: "updateRecurrence";
|
|
114
116
|
timerId: string;
|
|
@@ -120,6 +122,11 @@ type BatchActionItem = {
|
|
|
120
122
|
type: "updateDescription";
|
|
121
123
|
timerId: string;
|
|
122
124
|
description: string;
|
|
125
|
+
} | {
|
|
126
|
+
type: "logCompletion";
|
|
127
|
+
timerId: string;
|
|
128
|
+
closeReason: string;
|
|
129
|
+
occurredAt: number;
|
|
123
130
|
} | {
|
|
124
131
|
type: "assert";
|
|
125
132
|
path: string;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../apiClient.ts"],"sourcesContent":["import type { RecurrenceSpec, StoredEvent, Comment, InstanceState } from \"./types\";\n\nexport class ApiError extends Error {\n constructor(public status: number, message: string) {\n super(message);\n this.name = \"ApiError\";\n }\n}\n\nexport type BatchActionItem =\n | { type: \"addTimer\"; name: string; description?: string; expiry: number; recurrence?: RecurrenceSpec }\n | { type: \"updateExpiry\"; timerId: string; expiry: number }\n | { type: \"completeTimer\"; timerId: string; closeReason: string }\n | { type: \"removeTimer\"; timerId: string }\n | { type: \"shush\"; expiry: number }\n | { type: \"clearShush\" }\n | { type: \"recurTimer\"; timerId: string; closeReason: string }\n | { type: \"updateRecurrence\"; timerId: string; recurrence: RecurrenceSpec }\n | { type: \"removeRecurrence\"; timerId: string }\n | { type: \"updateDescription\"; timerId: string; description: string }\n | { type: \"assert\"; path: string; expectStatus?: number; expect?: unknown };\n\nexport function createApiClient(baseUrl: string, defaultToken?: string) {\n async function apiFetch<T>(\n path: string,\n options: RequestInit = {},\n token?: string,\n ): Promise<T> {\n const tok = token ?? defaultToken;\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...(options.headers as Record<string, string>),\n };\n if (tok) headers[\"Authorization\"] = `Bearer ${tok}`;\n\n const res = await fetch(`${baseUrl}${path}`, { ...options, headers });\n if (!res.ok) {\n let message = `HTTP ${res.status}`;\n try {\n const body = await res.json() as { error?: string };\n if (body.error) message = body.error;\n } catch { /* ignore */ }\n throw new ApiError(res.status, message);\n }\n return res.json() as Promise<T>;\n }\n\n return {\n registerDevice: (nickname: string) =>\n apiFetch<{ device: { id: string; nickname: string }; token: string }>(\n \"/devices/request\", { method: \"POST\", body: JSON.stringify({ nickname }) }\n ),\n\n getMe: (token: string) =>\n apiFetch<{ device: { id: string; nickname: string; approvedAt: number | null } }>(\n \"/devices/me\", {}, token\n ),\n\n requestInstance: (nickname: string, token: string) =>\n apiFetch<{ instance: { id: string; nickname: string } }>(\n \"/instances/request\", { method: \"POST\", body: JSON.stringify({ nickname }) }, token\n ),\n\n requestInstanceAccess: (instanceId: string, token: string) =>\n apiFetch<{ request?: { id: string; status: string }; status?: string }>(\n `/instances/${instanceId}/access/request`,\n { method: \"POST\", body: JSON.stringify({}) },\n token\n ),\n\n listInstances: (token: string) =>\n apiFetch<{ instances: { id: string; nickname: string; approvedAt: number | null }[] }>(\n \"/instances\", {}, token\n ),\n\n addTimer: (instanceId: string, token: string, name: string, expiry: number, recurrence?: RecurrenceSpec, description?: string) =>\n apiFetch<{ timer: { id: string }; event: { id: string; seq: number } }>(\n `/instances/${instanceId}/timers`,\n { method: \"POST\", body: JSON.stringify({ name, expiry, ...(description ? { description } : {}), ...(recurrence ? { recurrence } : {}) }) },\n token\n ),\n\n renameTimer: (instanceId: string, token: string, timerId: string, name: string) =>\n apiFetch<{ event: { id: string; seq: number } }>(\n `/instances/${instanceId}/timers/${timerId}/name`,\n { method: \"PATCH\", body: JSON.stringify({ name }) },\n token\n ),\n\n updateExpiry: (instanceId: string, token: string, timerId: string, expiry: number) =>\n apiFetch<{ event: { id: string; seq: number } }>(\n `/instances/${instanceId}/timers/${timerId}/expiry`,\n { method: \"PATCH\", body: JSON.stringify({ expiry }) },\n token\n ),\n\n completeTimer: (instanceId: string, token: string, timerId: string, closeReason: string) =>\n apiFetch<{ event: { id: string; seq: number } }>(\n `/instances/${instanceId}/timers/${timerId}/complete`,\n { method: \"POST\", body: JSON.stringify({ closeReason }) },\n token\n ),\n\n removeTimer: (instanceId: string, token: string, timerId: string) =>\n apiFetch<{ event: { id: string; seq: number } }>(\n `/instances/${instanceId}/timers/${timerId}`,\n { method: \"DELETE\" },\n token\n ),\n\n setShush: (instanceId: string, token: string, expiry: number) =>\n apiFetch<{ event: { id: string; seq: number } }>(\n `/instances/${instanceId}/shush`,\n { method: \"POST\", body: JSON.stringify({ expiry }) },\n token\n ),\n\n clearShush: (instanceId: string, token: string) =>\n apiFetch<{ event: { id: string; seq: number } }>(\n `/instances/${instanceId}/shush`,\n { method: \"DELETE\" },\n token\n ),\n\n listEvents: (instanceId: string, token: string, opts: { from?: number; before?: number; limit?: number } = {}) => {\n const { from = 1, before, limit = 200 } = opts;\n const params = before !== undefined\n ? `before=${before}&limit=${limit}`\n : `from=${from}&limit=${limit}`;\n return apiFetch<{ events: StoredEvent[]; latestSeq: number; prevCursor?: number | null }>(\n `/instances/${instanceId}/events?${params}`, {}, token\n );\n },\n\n getTimerHistory: (instanceId: string, token: string, timerId: string, opts: {\n after?: number; limit?: number; from?: number; to?: number;\n } = {}) => {\n const params = new URLSearchParams();\n if (opts.after !== undefined) params.set(\"after\", String(opts.after));\n if (opts.limit !== undefined) params.set(\"limit\", String(opts.limit));\n if (opts.from !== undefined) params.set(\"from\", String(opts.from));\n if (opts.to !== undefined) params.set(\"to\", String(opts.to));\n const qs = params.toString();\n return apiFetch<{ events: StoredEvent[]; nextCursor: number | null }>(\n `/instances/${instanceId}/timers/${timerId}/history${qs ? `?${qs}` : \"\"}`, {}, token\n );\n },\n\n skipEvent: (instanceId: string, token: string, eventId: string) =>\n apiFetch<{ ok: boolean }>(\n `/instances/${instanceId}/events/${eventId}/skip`, { method: \"POST\" }, token\n ),\n\n unskipEvent: (instanceId: string, token: string, eventId: string) =>\n apiFetch<{ ok: boolean }>(\n `/instances/${instanceId}/events/${eventId}/skip`, { method: \"DELETE\" }, token\n ),\n\n listComments: (instanceId: string, token: string, threadId: string) =>\n apiFetch<{ comments: Comment[] }>(\n `/instances/${instanceId}/threads/${threadId}/comments`, {}, token\n ),\n\n addComment: (instanceId: string, token: string, threadId: string, text: string) =>\n apiFetch<{ comment: Comment }>(\n `/instances/${instanceId}/threads/${threadId}/comments`,\n { method: \"POST\", body: JSON.stringify({ text }) },\n token\n ),\n\n getState: (instanceId: string, token: string) =>\n apiFetch<InstanceState>(\n `/instances/${instanceId}/state`, {}, token\n ),\n\n batchActions: (instanceId: string, token: string, actions: BatchActionItem[]) =>\n apiFetch<{ events: { id: string; seq: number; type: string }[] }>(\n `/instances/${instanceId}/actions`,\n { method: \"POST\", body: JSON.stringify({ actions }) },\n token\n ),\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../apiClient.ts"],"sourcesContent":["import type { RecurrenceSpec, StoredEvent, Comment, InstanceState } from \"./types\";\n\nexport class ApiError extends Error {\n constructor(public status: number, message: string) {\n super(message);\n this.name = \"ApiError\";\n }\n}\n\nexport type BatchActionItem =\n | { type: \"addTimer\"; name: string; description?: string; expiry: number; recurrence?: RecurrenceSpec }\n | { type: \"updateExpiry\"; timerId: string; expiry: number }\n | { type: \"completeTimer\"; timerId: string; closeReason: string; occurredAt?: number }\n | { type: \"removeTimer\"; timerId: string }\n | { type: \"shush\"; expiry: number }\n | { type: \"clearShush\" }\n | { type: \"recurTimer\"; timerId: string; closeReason: string; occurredAt?: number }\n | { type: \"updateRecurrence\"; timerId: string; recurrence: RecurrenceSpec }\n | { type: \"removeRecurrence\"; timerId: string }\n | { type: \"updateDescription\"; timerId: string; description: string }\n | { type: \"logCompletion\"; timerId: string; closeReason: string; occurredAt: number }\n | { type: \"assert\"; path: string; expectStatus?: number; expect?: unknown };\n\nexport function createApiClient(baseUrl: string, defaultToken?: string) {\n async function apiFetch<T>(\n path: string,\n options: RequestInit = {},\n token?: string,\n ): Promise<T> {\n const tok = token ?? defaultToken;\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...(options.headers as Record<string, string>),\n };\n if (tok) headers[\"Authorization\"] = `Bearer ${tok}`;\n\n const res = await fetch(`${baseUrl}${path}`, { ...options, headers });\n if (!res.ok) {\n let message = `HTTP ${res.status}`;\n try {\n const body = await res.json() as { error?: string };\n if (body.error) message = body.error;\n } catch { /* ignore */ }\n throw new ApiError(res.status, message);\n }\n return res.json() as Promise<T>;\n }\n\n return {\n registerDevice: (nickname: string) =>\n apiFetch<{ device: { id: string; nickname: string }; token: string }>(\n \"/devices/request\", { method: \"POST\", body: JSON.stringify({ nickname }) }\n ),\n\n getMe: (token: string) =>\n apiFetch<{ device: { id: string; nickname: string; approvedAt: number | null } }>(\n \"/devices/me\", {}, token\n ),\n\n requestInstance: (nickname: string, token: string) =>\n apiFetch<{ instance: { id: string; nickname: string } }>(\n \"/instances/request\", { method: \"POST\", body: JSON.stringify({ nickname }) }, token\n ),\n\n requestInstanceAccess: (instanceId: string, token: string) =>\n apiFetch<{ request?: { id: string; status: string }; status?: string }>(\n `/instances/${instanceId}/access/request`,\n { method: \"POST\", body: JSON.stringify({}) },\n token\n ),\n\n listInstances: (token: string) =>\n apiFetch<{ instances: { id: string; nickname: string; approvedAt: number | null }[] }>(\n \"/instances\", {}, token\n ),\n\n addTimer: (instanceId: string, token: string, name: string, expiry: number, recurrence?: RecurrenceSpec, description?: string) =>\n apiFetch<{ timer: { id: string }; event: { id: string; seq: number } }>(\n `/instances/${instanceId}/timers`,\n { method: \"POST\", body: JSON.stringify({ name, expiry, ...(description ? { description } : {}), ...(recurrence ? { recurrence } : {}) }) },\n token\n ),\n\n renameTimer: (instanceId: string, token: string, timerId: string, name: string) =>\n apiFetch<{ event: { id: string; seq: number } }>(\n `/instances/${instanceId}/timers/${timerId}/name`,\n { method: \"PATCH\", body: JSON.stringify({ name }) },\n token\n ),\n\n updateExpiry: (instanceId: string, token: string, timerId: string, expiry: number) =>\n apiFetch<{ event: { id: string; seq: number } }>(\n `/instances/${instanceId}/timers/${timerId}/expiry`,\n { method: \"PATCH\", body: JSON.stringify({ expiry }) },\n token\n ),\n\n completeTimer: (instanceId: string, token: string, timerId: string, closeReason: string) =>\n apiFetch<{ event: { id: string; seq: number } }>(\n `/instances/${instanceId}/timers/${timerId}/complete`,\n { method: \"POST\", body: JSON.stringify({ closeReason }) },\n token\n ),\n\n removeTimer: (instanceId: string, token: string, timerId: string) =>\n apiFetch<{ event: { id: string; seq: number } }>(\n `/instances/${instanceId}/timers/${timerId}`,\n { method: \"DELETE\" },\n token\n ),\n\n setShush: (instanceId: string, token: string, expiry: number) =>\n apiFetch<{ event: { id: string; seq: number } }>(\n `/instances/${instanceId}/shush`,\n { method: \"POST\", body: JSON.stringify({ expiry }) },\n token\n ),\n\n clearShush: (instanceId: string, token: string) =>\n apiFetch<{ event: { id: string; seq: number } }>(\n `/instances/${instanceId}/shush`,\n { method: \"DELETE\" },\n token\n ),\n\n listEvents: (instanceId: string, token: string, opts: { from?: number; before?: number; limit?: number } = {}) => {\n const { from = 1, before, limit = 200 } = opts;\n const params = before !== undefined\n ? `before=${before}&limit=${limit}`\n : `from=${from}&limit=${limit}`;\n return apiFetch<{ events: StoredEvent[]; latestSeq: number; prevCursor?: number | null }>(\n `/instances/${instanceId}/events?${params}`, {}, token\n );\n },\n\n getTimerHistory: (instanceId: string, token: string, timerId: string, opts: {\n after?: number; limit?: number; from?: number; to?: number;\n } = {}) => {\n const params = new URLSearchParams();\n if (opts.after !== undefined) params.set(\"after\", String(opts.after));\n if (opts.limit !== undefined) params.set(\"limit\", String(opts.limit));\n if (opts.from !== undefined) params.set(\"from\", String(opts.from));\n if (opts.to !== undefined) params.set(\"to\", String(opts.to));\n const qs = params.toString();\n return apiFetch<{ events: StoredEvent[]; nextCursor: number | null }>(\n `/instances/${instanceId}/timers/${timerId}/history${qs ? `?${qs}` : \"\"}`, {}, token\n );\n },\n\n skipEvent: (instanceId: string, token: string, eventId: string) =>\n apiFetch<{ ok: boolean }>(\n `/instances/${instanceId}/events/${eventId}/skip`, { method: \"POST\" }, token\n ),\n\n unskipEvent: (instanceId: string, token: string, eventId: string) =>\n apiFetch<{ ok: boolean }>(\n `/instances/${instanceId}/events/${eventId}/skip`, { method: \"DELETE\" }, token\n ),\n\n listComments: (instanceId: string, token: string, threadId: string) =>\n apiFetch<{ comments: Comment[] }>(\n `/instances/${instanceId}/threads/${threadId}/comments`, {}, token\n ),\n\n addComment: (instanceId: string, token: string, threadId: string, text: string) =>\n apiFetch<{ comment: Comment }>(\n `/instances/${instanceId}/threads/${threadId}/comments`,\n { method: \"POST\", body: JSON.stringify({ text }) },\n token\n ),\n\n getState: (instanceId: string, token: string) =>\n apiFetch<InstanceState>(\n `/instances/${instanceId}/state`, {}, token\n ),\n\n batchActions: (instanceId: string, token: string, actions: BatchActionItem[]) =>\n apiFetch<{ events: { id: string; seq: number; type: string }[] }>(\n `/instances/${instanceId}/actions`,\n { method: \"POST\", body: JSON.stringify({ actions }) },\n token\n ),\n };\n}\n"],"mappings":"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","names":[]}
|