autonag 0.1.1 → 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 CHANGED
@@ -50,16 +50,8 @@ function createApiClient(baseUrl, defaultToken) {
50
50
  { method: "POST", body: JSON.stringify({ nickname }) },
51
51
  token
52
52
  ),
53
- requestInstanceAccess: (instanceId, token, inviteCode) => apiFetch(
53
+ requestInstanceAccess: (instanceId, token) => apiFetch(
54
54
  `/instances/${instanceId}/access/request`,
55
- { method: "POST", body: JSON.stringify(inviteCode ? { inviteCode } : {}) },
56
- token
57
- ),
58
- getInvite: (code) => apiFetch(
59
- `/invites/${code}`
60
- ),
61
- createInvite: (instanceId, token) => apiFetch(
62
- `/instances/${instanceId}/invites`,
63
55
  { method: "POST", body: JSON.stringify({}) },
64
56
  token
65
57
  ),
@@ -227,7 +219,8 @@ function fmtDate(ms) {
227
219
  function shortId(id) {
228
220
  return id.slice(0, 8);
229
221
  }
230
- function col(s, w) {
222
+ function col(s, w, ellipsis = false) {
223
+ if (ellipsis && s.length > w) return s.slice(0, w - 1) + "\u2026";
231
224
  return s.slice(0, w).padEnd(w);
232
225
  }
233
226
  async function resolveTimerId(prefix, cfg2) {
@@ -353,17 +346,13 @@ async function cmdInstancesSelect(id, cfg2) {
353
346
  saveConfig(cfg2);
354
347
  console.log(`Default instance set to ${instanceId}`);
355
348
  }
356
- async function cmdInstancesJoin(code, cfg2) {
349
+ async function cmdInstancesJoin(instanceId, cfg2) {
357
350
  requireToken(cfg2);
358
351
  const api = createApiClient(cfg2.server, cfg2.token);
359
- const { invite } = await api.getInvite(code);
360
- if (!invite.valid) {
361
- console.error(`Invite is not valid: ${invite.reason ?? "expired or already used"}`);
362
- process.exit(1);
363
- }
364
- await api.requestInstanceAccess(invite.instanceId, cfg2.token, code);
365
- console.log(`Joined instance "${invite.instanceNickname}" (${shortId(invite.instanceId)}\u2026)`);
366
- console.log(`Run: autonag instances select ${invite.instanceId}`);
352
+ await api.requestInstanceAccess(instanceId, cfg2.token);
353
+ console.log(`Access requested for instance ${shortId(instanceId)}\u2026`);
354
+ console.log(`An admin will need to approve your request.`);
355
+ console.log(`Once approved, run: autonag instances select ${instanceId}`);
367
356
  }
368
357
  async function cmdTimersList(cfg2) {
369
358
  requireToken(cfg2);
@@ -381,7 +370,7 @@ async function cmdTimersList(cfg2) {
381
370
  const remaining = t.currentExpiry - now;
382
371
  const label = remaining < 0 ? `OVERDUE ${fmtCountdown(remaining)}` : `in ${fmtCountdown(remaining)}`;
383
372
  const recur = t.recurrence ? "\u21BB" : "";
384
- 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}`);
385
374
  }
386
375
  }
387
376
  console.log();
@@ -466,7 +455,7 @@ async function cmdTimersSnooze(id, expiryStr, cfg2) {
466
455
  await api.updateExpiry(cfg2.instanceId, cfg2.token, timerId, expiry);
467
456
  console.log(`Timer ${shortId(timerId)}\u2026 snoozed until ${fmtDate(expiry)}`);
468
457
  }
469
- async function cmdTimersComplete(id, reason, cfg2) {
458
+ async function cmdTimersComplete(id, reason, cfg2, opts = {}) {
470
459
  requireToken(cfg2);
471
460
  requireInstance(cfg2);
472
461
  const api = createApiClient(cfg2.server, cfg2.token);
@@ -474,7 +463,7 @@ async function cmdTimersComplete(id, reason, cfg2) {
474
463
  const timerId = await resolveTimerId(id, cfg2);
475
464
  const timer = state.timers.find((t) => t.id === timerId);
476
465
  if (timer?.recurrence) {
477
- 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 } : {} }]);
478
467
  const newState = await api.getState(cfg2.instanceId, cfg2.token);
479
468
  const updated = newState.timers.find((t) => t.id === timerId);
480
469
  if (updated) {
@@ -483,17 +472,21 @@ async function cmdTimersComplete(id, reason, cfg2) {
483
472
  console.log(`Timer ${shortId(timerId)}\u2026 recurred`);
484
473
  }
485
474
  } else {
486
- await api.completeTimer(cfg2.instanceId, cfg2.token, timerId, reason);
487
- console.log(`Timer ${shortId(timerId)}\u2026 completed (${reason})`);
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})`);
488
478
  }
489
479
  }
490
480
  async function cmdTimersRemove(id, cfg2) {
491
481
  requireToken(cfg2);
492
482
  requireInstance(cfg2);
493
- const timerId = await resolveTimerId(id, cfg2);
494
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);
495
487
  await api.removeTimer(cfg2.instanceId, cfg2.token, timerId);
496
- console.log(`Timer ${shortId(timerId)}\u2026 removed`);
488
+ const name = timer?.name ?? shortId(timerId);
489
+ console.log(`Timer "${name}" removed`);
497
490
  }
498
491
  async function cmdTimersDescribe(id, text, cfg2) {
499
492
  requireToken(cfg2);
@@ -503,6 +496,23 @@ async function cmdTimersDescribe(id, text, cfg2) {
503
496
  await api.batchActions(cfg2.instanceId, cfg2.token, [{ type: "updateDescription", timerId, description: text }]);
504
497
  console.log(`Timer ${shortId(timerId)}\u2026 description updated`);
505
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
+ }
506
516
  async function cmdTimersRecurrenceSet(id, days, cfg2, opts) {
507
517
  requireToken(cfg2);
508
518
  requireInstance(cfg2);
@@ -536,8 +546,8 @@ async function cmdTimersHistory(id, cfg2) {
536
546
  const { events, nextCursor } = await api.getTimerHistory(cfg2.instanceId, cfg2.token, timerId, { after: cursor });
537
547
  for (const ev of events) {
538
548
  const p = ev.payload;
539
- const date = ev.type === "TimerRecurred" ? p["occurredAt"] ?? ev.timestamp : ev.timestamp;
540
- 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 });
541
551
  }
542
552
  cursor = nextCursor;
543
553
  }
@@ -545,11 +555,26 @@ async function cmdTimersHistory(id, cfg2) {
545
555
  console.log("No history yet.");
546
556
  return;
547
557
  }
548
- console.log(`${"Date".padEnd(22)} Reason`);
549
- console.log("-".repeat(36));
558
+ console.log(`${"Date".padEnd(22)} ${"Reason".padEnd(16)} Type`);
559
+ console.log("-".repeat(56));
550
560
  for (const e of allEntries) {
551
- console.log(`${col(fmtDate(e.date), 22)} ${e.closeReason}`);
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}`);
563
+ }
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);
552
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)}`);
553
578
  }
554
579
  async function cmdShush(durationStr, cfg2) {
555
580
  requireToken(cfg2);
@@ -598,7 +623,51 @@ async function cmdEventsUnskip(id, cfg2) {
598
623
  await api.unskipEvent(cfg2.instanceId, cfg2.token, eventId);
599
624
  console.log(`Event ${shortId(eventId)}\u2026 unskipped`);
600
625
  }
601
- async function cmdCommentsList(id, cfg2) {
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 = {}) {
602
671
  requireToken(cfg2);
603
672
  requireInstance(cfg2);
604
673
  const timerId = await resolveTimerId(id, cfg2);
@@ -608,7 +677,10 @@ async function cmdCommentsList(id, cfg2) {
608
677
  console.log("No comments.");
609
678
  return;
610
679
  }
611
- for (const c of comments) {
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) {
612
684
  console.log(`[${fmtDate(c.createdAt)}] ${c.text}`);
613
685
  }
614
686
  }
@@ -684,21 +756,15 @@ Set it as your default:
684
756
  autonag instances select <id>
685
757
  \`\`\`
686
758
 
687
- To join an instance someone else owns, ask them for an invite code. They
688
- generate one with:
689
-
690
- \`\`\`
691
- autonag instances invite
692
- \`\`\`
693
-
694
- Then you join with the code they share:
759
+ To join an instance someone else owns, ask them for the instance ID. Then
760
+ request access:
695
761
 
696
762
  \`\`\`
697
- autonag instances join <code>
763
+ autonag instances join <instance-id>
698
764
  \`\`\`
699
765
 
700
- Invite codes are single-use and expire after 7 days. The instance is not
701
- discoverable by name \u2014 you need the code.
766
+ An admin will approve your request. The instance ID is not advertised
767
+ publicly \u2014 you need to know it.
702
768
 
703
769
  ## Adding timers
704
770
 
@@ -842,8 +908,7 @@ Auth:
842
908
  Instances:
843
909
  instances list
844
910
  instances request <nickname> Create a new instance
845
- instances join <code> Join an existing instance via invite code
846
- instances invite Create an invite code for this instance
911
+ instances join <instance-id> Request access to an existing instance
847
912
  instances select <id>
848
913
 
849
914
  Timers:
@@ -851,12 +916,17 @@ Timers:
851
916
  timers add <name> <expiry> [--desc <text>] [--days <n>] [--anchor <HH:MM>] [--tz <tz>] [--skip-weekends]
852
917
  timers rename <id> <name>
853
918
  timers snooze <id> <expiry> Update expiry: 1d, 30m, 2h, 90s | 2026-05-01T09:00:00Z | unix-ms:<n>
854
- timers complete <id> <reason> Complete or recur (reason: pass, fail, or custom)
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
855
922
  timers remove <id>
923
+ timers view <id> Show full timer details, description, and recent comments
856
924
  timers describe <id> <text> Set description
925
+ timers description <id> Print full description
857
926
  timers recurrence set <id> <days> [--anchor <HH:MM>] [--tz <tz>] [--skip-weekends]
858
927
  timers recurrence remove <id>
859
928
  timers history <id> Show completion history
929
+ timers log <id> <reason> --at <datetime> Log a historical completion (no expiry change)
860
930
 
861
931
  Alarm:
862
932
  alarm show Show current alarm state
@@ -871,7 +941,7 @@ Events:
871
941
  events unskip <id>
872
942
 
873
943
  Comments:
874
- comments list <timerId>
944
+ comments list <timerId> [--limit N]
875
945
  comments add <timerId> <text>
876
946
 
877
947
  Config saved to ~/.config/autonag/client.json5`;
@@ -977,19 +1047,10 @@ try {
977
1047
  } else if (sub === "join") {
978
1048
  const { positional } = parseFlags(rest, {});
979
1049
  if (!positional[0]) {
980
- console.error("Usage: autonag instances join <code>");
1050
+ console.error("Usage: autonag instances join <instance-id>");
981
1051
  process.exit(1);
982
1052
  }
983
1053
  await cmdInstancesJoin(positional[0], cfg);
984
- } else if (sub === "invite") {
985
- parseFlags(rest, {});
986
- requireToken(cfg);
987
- requireInstance(cfg);
988
- const api = createApiClient(cfg.server, cfg.token);
989
- const { invite } = await api.createInvite(cfg.instanceId, cfg.token);
990
- console.log(`Invite code: ${invite.code}`);
991
- console.log(`Expires: ${fmtDate(invite.expiresAt)}`);
992
- console.log(`Share this code \u2014 it can only be used once.`);
993
1054
  } else if (sub === "select") {
994
1055
  const { positional } = parseFlags(rest, {});
995
1056
  if (!positional[0]) {
@@ -1038,13 +1099,30 @@ try {
1038
1099
  process.exit(1);
1039
1100
  }
1040
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 });
1041
1118
  } else if (sub === "complete") {
1042
- const { positional } = parseFlags(rest, {});
1119
+ const { positional, flags } = parseFlags(rest, { at: "string" });
1043
1120
  if (!positional[0] || !positional[1]) {
1044
- console.error("Usage: autonag timers complete <id> <reason>");
1121
+ console.error("Usage: autonag timers complete <id> <reason> [--at <datetime>]");
1045
1122
  process.exit(1);
1046
1123
  }
1047
- await cmdTimersComplete(positional[0], positional[1], cfg);
1124
+ const at = flags.at ? parseExpiry(flags.at) : void 0;
1125
+ await cmdTimersComplete(positional[0], positional[1], cfg, { at });
1048
1126
  } else if (sub === "remove") {
1049
1127
  const { positional } = parseFlags(rest, {});
1050
1128
  if (!positional[0]) {
@@ -1059,6 +1137,13 @@ try {
1059
1137
  process.exit(1);
1060
1138
  }
1061
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);
1062
1147
  } else if (sub === "recurrence") {
1063
1148
  const recSub = rest[0];
1064
1149
  if (recSub === "set") {
@@ -1088,6 +1173,13 @@ try {
1088
1173
  console.error("Usage: autonag timers recurrence set|remove ...");
1089
1174
  process.exit(1);
1090
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);
1091
1183
  } else if (sub === "history") {
1092
1184
  const { positional } = parseFlags(rest, {});
1093
1185
  if (!positional[0]) {
@@ -1095,6 +1187,18 @@ try {
1095
1187
  process.exit(1);
1096
1188
  }
1097
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);
1098
1202
  } else {
1099
1203
  console.error(`Unknown subcommand: timers ${sub}`);
1100
1204
  process.exit(1);
@@ -1136,12 +1240,12 @@ try {
1136
1240
  }
1137
1241
  } else if (cmd === "comments") {
1138
1242
  if (!sub || sub === "list") {
1139
- const { positional } = parseFlags(rest, {});
1243
+ const { positional, flags } = parseFlags(rest, { limit: "int" });
1140
1244
  if (!positional[0]) {
1141
- console.error("Usage: autonag comments list <timerId>");
1245
+ console.error("Usage: autonag comments list <timerId> [--limit N]");
1142
1246
  process.exit(1);
1143
1247
  }
1144
- await cmdCommentsList(positional[0], cfg);
1248
+ await cmdCommentsList(positional[0], cfg, { limit: flags.limit });
1145
1249
  } else if (sub === "add") {
1146
1250
  const { positional } = parseFlags(rest, {});
1147
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(code: string, cfg: Config): Promise<void> {\n requireToken(cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const { invite } = await api.getInvite(code);\n if (!invite.valid) {\n console.error(`Invite is not valid: ${invite.reason ?? \"expired or already used\"}`);\n process.exit(1);\n }\n await api.requestInstanceAccess(invite.instanceId, cfg.token, code);\n console.log(`Joined instance \"${invite.instanceNickname}\" (${shortId(invite.instanceId)}…)`);\n console.log(`Run: autonag instances select ${invite.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 an invite code. They\ngenerate one with:\n\n\\`\\`\\`\nautonag instances invite\n\\`\\`\\`\n\nThen you join with the code they share:\n\n\\`\\`\\`\nautonag instances join <code>\n\\`\\`\\`\n\nInvite codes are single-use and expire after 7 days. The instance is not\ndiscoverable by name — you need the code.\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 <code> Join an existing instance via invite code\n instances invite Create an invite code for this 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 <code>\"); process.exit(1); }\n await cmdInstancesJoin(positional[0], cfg);\n } else if (sub === \"invite\") {\n parseFlags(rest, {});\n requireToken(cfg);\n requireInstance(cfg);\n const api = createApiClient(cfg.server, cfg.token);\n const { invite } = await api.createInvite(cfg.instanceId, cfg.token);\n console.log(`Invite code: ${invite.code}`);\n console.log(`Expires: ${fmtDate(invite.expiresAt)}`);\n console.log(`Share this code — it can only be used once.`);\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, inviteCode?: string) =>\n apiFetch<{ request?: { id: string; status: string }; status?: string }>(\n `/instances/${instanceId}/access/request`,\n { method: \"POST\", body: JSON.stringify(inviteCode ? { inviteCode } : {}) },\n token\n ),\n\n getInvite: (code: string) =>\n apiFetch<{ invite: { code: string; instanceId: string; instanceNickname: string; expiresAt: number; valid: boolean; reason?: string } }>(\n `/invites/${code}`\n ),\n\n createInvite: (instanceId: string, token: string) =>\n apiFetch<{ invite: { code: string; expiresAt: number } }>(\n `/instances/${instanceId}/invites`, { method: \"POST\", body: JSON.stringify({}) }, 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;
@@ -147,29 +154,13 @@ declare function createApiClient(baseUrl: string, defaultToken?: string): {
147
154
  nickname: string;
148
155
  };
149
156
  }>;
150
- requestInstanceAccess: (instanceId: string, token: string, inviteCode?: string) => Promise<{
157
+ requestInstanceAccess: (instanceId: string, token: string) => Promise<{
151
158
  request?: {
152
159
  id: string;
153
160
  status: string;
154
161
  };
155
162
  status?: string;
156
163
  }>;
157
- getInvite: (code: string) => Promise<{
158
- invite: {
159
- code: string;
160
- instanceId: string;
161
- instanceNickname: string;
162
- expiresAt: number;
163
- valid: boolean;
164
- reason?: string;
165
- };
166
- }>;
167
- createInvite: (instanceId: string, token: string) => Promise<{
168
- invite: {
169
- code: string;
170
- expiresAt: number;
171
- };
172
- }>;
173
164
  listInstances: (token: string) => Promise<{
174
165
  instances: {
175
166
  id: string;
package/dist/index.js CHANGED
@@ -42,16 +42,8 @@ function createApiClient(baseUrl, defaultToken) {
42
42
  { method: "POST", body: JSON.stringify({ nickname }) },
43
43
  token
44
44
  ),
45
- requestInstanceAccess: (instanceId, token, inviteCode) => apiFetch(
45
+ requestInstanceAccess: (instanceId, token) => apiFetch(
46
46
  `/instances/${instanceId}/access/request`,
47
- { method: "POST", body: JSON.stringify(inviteCode ? { inviteCode } : {}) },
48
- token
49
- ),
50
- getInvite: (code) => apiFetch(
51
- `/invites/${code}`
52
- ),
53
- createInvite: (instanceId, token) => apiFetch(
54
- `/instances/${instanceId}/invites`,
55
47
  { method: "POST", body: JSON.stringify({}) },
56
48
  token
57
49
  ),
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, inviteCode?: string) =>\n apiFetch<{ request?: { id: string; status: string }; status?: string }>(\n `/instances/${instanceId}/access/request`,\n { method: \"POST\", body: JSON.stringify(inviteCode ? { inviteCode } : {}) },\n token\n ),\n\n getInvite: (code: string) =>\n apiFetch<{ invite: { code: string; instanceId: string; instanceNickname: string; expiresAt: number; valid: boolean; reason?: string } }>(\n `/invites/${code}`\n ),\n\n createInvite: (instanceId: string, token: string) =>\n apiFetch<{ invite: { code: string; expiresAt: number } }>(\n `/instances/${instanceId}/invites`, { method: \"POST\", body: JSON.stringify({}) }, 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":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autonag",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "description": "Autonag API client and CLI — recurring-task tracker with a persistent alarm",
6
6
  "exports": {