@mohitkumawat/warmup-cli 1.2.16 → 1.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/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <div align="center">
2
- <img src="https://raw.githubusercontent.com/Tarikul-Islam-Anik/Animated-Fluent-Emojis/master/Emojis/Food/Hot%20Beverage.png" alt="WarmUp Logo" width="100" />
2
+ <img src="https://raw.githubusercontent.com/mohit-kumawat/warmup/main/assets/logo.png" alt="WarmUp Logo" width="100" />
3
3
 
4
4
  # ☕ WarmUp
5
5
 
@@ -14,23 +14,44 @@
14
14
  [![Stars](https://img.shields.io/github/stars/mohit-kumawat/warmup?style=for-the-badge&color=6C5CE7&logo=github)](https://github.com/mohit-kumawat/warmup)
15
15
 
16
16
  <br />
17
+
18
+ `npm install -g @mohitkumawat/warmup-cli`
19
+
20
+ <br />
17
21
  </div>
18
22
 
19
23
  ---
20
24
 
25
+ ```console
26
+ $ warmup
27
+
28
+ warmup v1.3.0
29
+
30
+ Schedule: 7:00 AM daily (America/New_York) active
31
+ Wake: scheduled (runs while asleep)
32
+ Last run: 7:00 AM ✔ success
33
+ Window: [████████████▓░░░░░░░░░░░░░░░░░] 45% elapsed
34
+ start now reset
35
+ 7:00 AM 9:15 AM 12:00 PM
36
+
37
+ ✔ Window resets in ~2h 45m. Full capacity at 12:00 PM.
38
+ ```
39
+
40
+ ---
41
+
21
42
  ## 🛑 The Problem
22
43
 
23
- Claude Pro and Max subscribers share a **5-hour rolling rate limit window** across Claude Code, Cowork, and claude.ai. When you start an intensive coding session, you burn through your allocation quickly and are forced to wait 2-3 hours for the window to reset.
44
+ Claude Pro and Max subscribers share a **5-hour rolling rate limit window** across Claude Code, Cowork, and claude.ai. When you start an intensive coding session, you burn through your messages fast then sit idle for 23 hours waiting for the window to reset.
24
45
 
25
46
  ## 🟢 The Solution
26
47
 
27
48
  **`warmup`** starts your rate limit window *before* you wake up by scheduling one tiny Claude Code ping (~10 tokens) at the exact right time.
28
49
 
29
- By the time you sit down to work, the window is perfectly timed to expire exactly when you need it, granting you a **100% fresh allocation** right in the middle of your workday.
50
+ By the time you sit down to work, the window is timed to **reset exactly when you'd otherwise hit the limit** — handing you **100% fresh capacity** in the middle of your workday.
30
51
 
31
52
  ### ⏱️ Side-by-Side Comparison
32
53
 
33
- | ❌ Without `warmup` | ✅ With `warmup` (2-hour exhaustion) |
54
+ | ❌ Without `warmup` | ✅ With `warmup` |
34
55
  | :--- | :--- |
35
56
  | **10:00 AM** → You start working, window starts. | **7:00 AM** → `warmup` sends one tiny ping (window starts). |
36
57
  | **12:00 PM** → **Rate limited!** 🛑 Must wait until 3:00 PM. | **10:00 AM** → You start working using the active window. |
@@ -39,6 +60,8 @@ By the time you sit down to work, the window is perfectly timed to expire exactl
39
60
 
40
61
  > ***You just saved over 3 hours of waiting.***
41
62
 
63
+ <sub>Times are illustrative — this example assumes ~2 hours of heavy use before you hit the limit.</sub>
64
+
42
65
  ---
43
66
 
44
67
  ## ⚡ Installation
@@ -53,13 +76,13 @@ npm install -g @mohitkumawat/warmup-cli
53
76
 
54
77
  ## 🚀 Quick Start
55
78
 
56
- Run the following command anywhere in your terminal:
79
+ Run `warmup` anywhere in your terminal:
57
80
 
58
81
  ```bash
59
82
  warmup
60
83
  ```
61
84
 
62
- *Fresh installs open a **guided onboarding wizard**.*
85
+ *First run? It opens a **guided setup wizard** — no flags to memorize.*
63
86
 
64
87
  ### 🔍 What happens behind the scenes?
65
88
 
@@ -68,10 +91,10 @@ warmup
68
91
  - 📊 Shows a detailed geometric preview of the scheduled timeline before explicitly asking for confirmation.
69
92
  - 💾 Stores config and logs purely locally in `~/.warmup/`.
70
93
 
71
- ### 🛡 What DOES NOT happen?
94
+ ### 🛡️ What DOES NOT happen?
72
95
 
73
96
  - ❌ Setup does **not** send a live Claude request or burn any limits.
74
- - ❌ `warmup` does **not** proxy your session, extract tokens, or phone home to any backend API. Privacy first.
97
+ - ❌ `warmup` does **not** proxy your session, extract tokens, or phone home to any server. Privacy first.
75
98
 
76
99
  ---
77
100
 
@@ -90,9 +113,9 @@ It then automatically calculates the **exact optimal pre-warm time** to ensure y
90
113
 
91
114
  **What if my computer is off or asleep at the scheduled pre-warm time?**
92
115
 
93
- `warmup` handles this automatically using native OS features. It schedules a **real system wake a few minutes before** your pre-warm time, so the ping fires **while the machine is still asleep** — ahead of your workday instead of waiting until you open the lid. If a wake can't be armed (or the machine was fully powered off), it falls back to firing on the next boot/wake, with deduplication so a late catch-up never double-consumes your window.
116
+ **`warmup` wakes your machine a few minutes early and fires the ping while you're still asleep** — so your fresh window is ready before you sit down, not hours later when you open the lid. If the machine was fully powered off, it catches up on the next boot.
94
117
 
95
- It has built-in deduplication guards: it will *never* double-fire or accidentally consume a second rate-limit window, even if you restart your computer 10 times a day.
118
+ Either way, built-in deduplication guards mean it will *never* double-fire or burn a second rate-limit window even if you restart your computer 10 times a day.
96
119
 
97
120
  | OS | Wake & Background Mechanism |
98
121
  | :--- | :--- |
@@ -12,8 +12,10 @@ interface DefaultCommandDependencies {
12
12
  readConfig: typeof readConfig;
13
13
  runStatus: () => Promise<void>;
14
14
  runFirstRunOnboarding: () => Promise<void>;
15
+ runInteractiveHome: () => Promise<void>;
16
+ isInteractive: () => boolean;
15
17
  }
16
18
  export declare function runFirstRunOnboarding(deps?: Partial<OnboardingDependencies>): Promise<void>;
17
- export declare function defaultCommand(deps?: Partial<DefaultCommandDependencies>): Promise<'status' | 'onboarding'>;
19
+ export declare function defaultCommand(deps?: Partial<DefaultCommandDependencies>): Promise<'status' | 'onboarding' | 'home'>;
18
20
  export {};
19
21
  //# sourceMappingURL=default.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"default.d.ts","sourceRoot":"","sources":["../../src/commands/default.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAOvC,OAAO,EAAgB,KAAK,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAGjE,UAAU,sBAAsB;IAC9B,iBAAiB,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,sBAAsB,EAAE,MAAM,IAAI,CAAC;IACnC,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5D;AAED,UAAU,0BAA0B;IAClC,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,qBAAqB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5C;AAaD,wBAAsB,qBAAqB,CACzC,IAAI,GAAE,OAAO,CAAC,sBAAsB,CAAM,GACzC,OAAO,CAAC,IAAI,CAAC,CAkBf;AAED,wBAAsB,cAAc,CAClC,IAAI,GAAE,OAAO,CAAC,0BAA0B,CAAM,GAC7C,OAAO,CAAC,QAAQ,GAAG,YAAY,CAAC,CAYlC"}
1
+ {"version":3,"file":"default.d.ts","sourceRoot":"","sources":["../../src/commands/default.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAOvC,OAAO,EAAgB,KAAK,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAajE,UAAU,sBAAsB;IAC9B,iBAAiB,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,sBAAsB,EAAE,MAAM,IAAI,CAAC;IACnC,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5D;AAED,UAAU,0BAA0B;IAClC,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,qBAAqB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,kBAAkB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,aAAa,EAAE,MAAM,OAAO,CAAC;CAC9B;AAaD,wBAAsB,qBAAqB,CACzC,IAAI,GAAE,OAAO,CAAC,sBAAsB,CAAM,GACzC,OAAO,CAAC,IAAI,CAAC,CAkBf;AAED,wBAAsB,cAAc,CAClC,IAAI,GAAE,OAAO,CAAC,0BAA0B,CAAM,GAC7C,OAAO,CAAC,QAAQ,GAAG,YAAY,GAAG,MAAM,CAAC,CA8B3C"}
@@ -10,6 +10,15 @@ const config_1 = require("../config");
10
10
  const ui_1 = require("../ui");
11
11
  const setup_1 = require("./setup");
12
12
  const status_1 = require("./status");
13
+ const menu_1 = require("./menu");
14
+ /**
15
+ * Bare `warmup` becomes an interactive hub only in a real terminal. Anywhere
16
+ * input/output is not a TTY (pipes, CI, the OS scheduler), it must stay a
17
+ * one-shot status print so it never blocks on a prompt.
18
+ */
19
+ function terminalIsInteractive() {
20
+ return Boolean(process.stdin.isTTY && process.stdout.isTTY);
21
+ }
13
22
  async function promptToStartSetup() {
14
23
  const { startSetup } = await inquirer_1.default.prompt([{
15
24
  type: 'confirm',
@@ -39,11 +48,27 @@ async function defaultCommand(deps = {}) {
39
48
  const loadConfig = deps.readConfig ?? config_1.readConfig;
40
49
  const runStatus = deps.runStatus ?? status_1.statusCommand;
41
50
  const runOnboarding = deps.runFirstRunOnboarding ?? runFirstRunOnboarding;
51
+ const runHome = deps.runInteractiveHome ?? menu_1.runInteractiveHome;
52
+ const isInteractive = deps.isInteractive ?? terminalIsInteractive;
42
53
  if (loadConfig()) {
54
+ // In a terminal, drop into the navigable hub; otherwise stay a scriptable
55
+ // one-shot status print.
56
+ if (isInteractive()) {
57
+ await runHome();
58
+ return 'home';
59
+ }
43
60
  await runStatus();
44
61
  return 'status';
45
62
  }
46
63
  await runOnboarding();
64
+ // If onboarding actually completed setup (config now exists) and we're in a
65
+ // terminal, drop straight into the hub — so a first-time user discovers it
66
+ // immediately instead of dead-ending on a success message. If setup was
67
+ // deferred (still no config), leave them at the deferred notice.
68
+ if (isInteractive() && loadConfig()) {
69
+ await runHome();
70
+ return 'home';
71
+ }
47
72
  return 'onboarding';
48
73
  }
49
74
  //# sourceMappingURL=default.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"default.js","sourceRoot":"","sources":["../../src/commands/default.ts"],"names":[],"mappings":";;;;;AAqCA,sDAoBC;AAED,wCAcC;AAzED,wDAAgC;AAChC,sCAAuC;AACvC,8BAKe;AACf,mCAAiE;AACjE,qCAAyC;AAiBzC,KAAK,UAAU,kBAAkB;IAC/B,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,kBAAQ,CAAC,MAAM,CAAC,CAAC;YAC5C,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,YAAY;YAClB,OAAO,EAAE,kBAAkB;YAC3B,OAAO,EAAE,IAAI;SACd,CAAC,CAAC,CAAC;IAEJ,OAAO,UAAU,CAAC;AACpB,CAAC;AAEM,KAAK,UAAU,qBAAqB,CACzC,OAAwC,EAAE;IAE1C,MAAM,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,IAAI,kBAAkB,CAAC;IACvE,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,IAAI,cAAS,CAAC;IAC7C,MAAM,iBAAiB,GAAG,IAAI,CAAC,kBAAkB,IAAI,uBAAkB,CAAC;IACxE,MAAM,qBAAqB,GAAG,IAAI,CAAC,sBAAsB,IAAI,2BAAsB,CAAC;IACpF,MAAM,iBAAiB,GAAG,IAAI,CAAC,kBAAkB,IAAI,uBAAkB,CAAC;IACxE,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,oBAAY,CAAC;IAE/C,QAAQ,EAAE,CAAC;IACX,iBAAiB,EAAE,CAAC;IACpB,qBAAqB,EAAE,CAAC;IAExB,IAAI,CAAC,CAAC,MAAM,iBAAiB,EAAE,CAAC,EAAE,CAAC;QACjC,iBAAiB,EAAE,CAAC;QACpB,OAAO;IACT,CAAC;IAED,MAAM,QAAQ,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;AACrC,CAAC;AAEM,KAAK,UAAU,cAAc,CAClC,OAA4C,EAAE;IAE9C,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,mBAAU,CAAC;IACjD,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,sBAAa,CAAC;IAClD,MAAM,aAAa,GAAG,IAAI,CAAC,qBAAqB,IAAI,qBAAqB,CAAC;IAE1E,IAAI,UAAU,EAAE,EAAE,CAAC;QACjB,MAAM,SAAS,EAAE,CAAC;QAClB,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,MAAM,aAAa,EAAE,CAAC;IACtB,OAAO,YAAY,CAAC;AACtB,CAAC"}
1
+ {"version":3,"file":"default.js","sourceRoot":"","sources":["../../src/commands/default.ts"],"names":[],"mappings":";;;;;AAiDA,sDAoBC;AAED,wCAgCC;AAvGD,wDAAgC;AAChC,sCAAuC;AACvC,8BAKe;AACf,mCAAiE;AACjE,qCAAyC;AACzC,iCAA4C;AAE5C;;;;GAIG;AACH,SAAS,qBAAqB;IAC5B,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC9D,CAAC;AAmBD,KAAK,UAAU,kBAAkB;IAC/B,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,kBAAQ,CAAC,MAAM,CAAC,CAAC;YAC5C,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,YAAY;YAClB,OAAO,EAAE,kBAAkB;YAC3B,OAAO,EAAE,IAAI;SACd,CAAC,CAAC,CAAC;IAEJ,OAAO,UAAU,CAAC;AACpB,CAAC;AAEM,KAAK,UAAU,qBAAqB,CACzC,OAAwC,EAAE;IAE1C,MAAM,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,IAAI,kBAAkB,CAAC;IACvE,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,IAAI,cAAS,CAAC;IAC7C,MAAM,iBAAiB,GAAG,IAAI,CAAC,kBAAkB,IAAI,uBAAkB,CAAC;IACxE,MAAM,qBAAqB,GAAG,IAAI,CAAC,sBAAsB,IAAI,2BAAsB,CAAC;IACpF,MAAM,iBAAiB,GAAG,IAAI,CAAC,kBAAkB,IAAI,uBAAkB,CAAC;IACxE,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,oBAAY,CAAC;IAE/C,QAAQ,EAAE,CAAC;IACX,iBAAiB,EAAE,CAAC;IACpB,qBAAqB,EAAE,CAAC;IAExB,IAAI,CAAC,CAAC,MAAM,iBAAiB,EAAE,CAAC,EAAE,CAAC;QACjC,iBAAiB,EAAE,CAAC;QACpB,OAAO;IACT,CAAC;IAED,MAAM,QAAQ,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;AACrC,CAAC;AAEM,KAAK,UAAU,cAAc,CAClC,OAA4C,EAAE;IAE9C,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,mBAAU,CAAC;IACjD,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,sBAAa,CAAC;IAClD,MAAM,aAAa,GAAG,IAAI,CAAC,qBAAqB,IAAI,qBAAqB,CAAC;IAC1E,MAAM,OAAO,GAAG,IAAI,CAAC,kBAAkB,IAAI,yBAAkB,CAAC;IAC9D,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,IAAI,qBAAqB,CAAC;IAElE,IAAI,UAAU,EAAE,EAAE,CAAC;QACjB,0EAA0E;QAC1E,yBAAyB;QACzB,IAAI,aAAa,EAAE,EAAE,CAAC;YACpB,MAAM,OAAO,EAAE,CAAC;YAChB,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,MAAM,SAAS,EAAE,CAAC;QAClB,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,MAAM,aAAa,EAAE,CAAC;IAEtB,4EAA4E;IAC5E,2EAA2E;IAC3E,wEAAwE;IACxE,iEAAiE;IACjE,IAAI,aAAa,EAAE,IAAI,UAAU,EAAE,EAAE,CAAC;QACpC,MAAM,OAAO,EAAE,CAAC;QAChB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC"}
@@ -0,0 +1,51 @@
1
+ import { type WarmupConfig, type LogEntry } from '../config';
2
+ export type DiagnosticStatus = 'ok' | 'warn' | 'fail';
3
+ export interface DiagnosticCheck {
4
+ label: string;
5
+ status: DiagnosticStatus;
6
+ detail: string;
7
+ fix?: string;
8
+ }
9
+ /** Raw, already-resolved inputs for {@link collectDiagnostics}. */
10
+ export interface DiagnosticInput {
11
+ claudeInstalled: boolean;
12
+ claudeAuthenticated: boolean;
13
+ claudeVersion: string | null;
14
+ config: WarmupConfig | null;
15
+ platform: string;
16
+ scheduleInstalled: boolean;
17
+ wakeActive: boolean;
18
+ /** Whether the cached runtime node/claude paths still exist on disk. */
19
+ runtimeValid: boolean;
20
+ lastLog: LogEntry | null;
21
+ }
22
+ /**
23
+ * Turn resolved environment facts into an ordered list of health checks.
24
+ * Pure and synchronous: no I/O, no process spawning — so the exact status/fix
25
+ * routing is unit-testable. `doctorCommand` resolves the real facts and feeds
26
+ * them in. Checks short-circuit sensibly (no auth check if Claude is missing;
27
+ * no schedule checks if warmup isn't set up).
28
+ */
29
+ export declare function collectDiagnostics(input: DiagnosticInput): DiagnosticCheck[];
30
+ export interface DoctorDependencies {
31
+ isClaudeInstalled: (binary?: string) => boolean;
32
+ isClaudeAuthenticated: (binary?: string) => boolean;
33
+ getClaudeVersion: (binary?: string) => string | null;
34
+ readConfig: () => WarmupConfig | null;
35
+ detectPlatform: () => string;
36
+ isScheduleInstalled: () => boolean;
37
+ isWakeScheduleActive: () => boolean;
38
+ getLatestLog: () => LogEntry | null;
39
+ }
40
+ /**
41
+ * `warmup doctor` — a one-shot self-diagnostic (à la `claude doctor`): is Claude
42
+ * Code installed & authed, is the schedule registered/active, is a wake armed,
43
+ * did the last run succeed, are runtime paths cached — each with a concrete fix.
44
+ * Scriptable and non-blocking; safe in non-TTY contexts. `--json` emits the
45
+ * structured checks (no chrome) and sets a health-based exit code (non-zero
46
+ * when any check fails) so it composes into scripts and CI.
47
+ */
48
+ export declare function doctorCommand(options?: {
49
+ json?: boolean;
50
+ }, deps?: Partial<DoctorDependencies>): Promise<void>;
51
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,QAAQ,EACd,MAAM,WAAW,CAAC;AAanB,MAAM,MAAM,gBAAgB,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;AAEtD,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,gBAAgB,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,mEAAmE;AACnE,MAAM,WAAW,eAAe;IAC9B,eAAe,EAAE,OAAO,CAAC;IACzB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,UAAU,EAAE,OAAO,CAAC;IACpB,wEAAwE;IACxE,YAAY,EAAE,OAAO,CAAC;IACtB,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,eAAe,GAAG,eAAe,EAAE,CA+G5E;AAED,MAAM,WAAW,kBAAkB;IACjC,iBAAiB,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IAChD,qBAAqB,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IACpD,gBAAgB,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IACrD,UAAU,EAAE,MAAM,YAAY,GAAG,IAAI,CAAC;IACtC,cAAc,EAAE,MAAM,MAAM,CAAC;IAC7B,mBAAmB,EAAE,MAAM,OAAO,CAAC;IACnC,oBAAoB,EAAE,MAAM,OAAO,CAAC;IACpC,YAAY,EAAE,MAAM,QAAQ,GAAG,IAAI,CAAC;CACrC;AAYD;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAO,EAChC,IAAI,GAAE,OAAO,CAAC,kBAAkB,CAAM,GACrC,OAAO,CAAC,IAAI,CAAC,CA+Cf"}
@@ -0,0 +1,219 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.collectDiagnostics = collectDiagnostics;
37
+ exports.doctorCommand = doctorCommand;
38
+ const fs = __importStar(require("fs"));
39
+ const config_1 = require("../config");
40
+ const warmup_1 = require("../warmup");
41
+ const scheduler_1 = require("../scheduler");
42
+ const ui_1 = require("../ui");
43
+ /**
44
+ * Turn resolved environment facts into an ordered list of health checks.
45
+ * Pure and synchronous: no I/O, no process spawning — so the exact status/fix
46
+ * routing is unit-testable. `doctorCommand` resolves the real facts and feeds
47
+ * them in. Checks short-circuit sensibly (no auth check if Claude is missing;
48
+ * no schedule checks if warmup isn't set up).
49
+ */
50
+ function collectDiagnostics(input) {
51
+ const checks = [];
52
+ checks.push(input.claudeInstalled
53
+ ? {
54
+ label: 'Claude Code',
55
+ status: 'ok',
56
+ detail: input.claudeVersion ? `installed (${input.claudeVersion})` : 'installed',
57
+ }
58
+ : {
59
+ label: 'Claude Code',
60
+ status: 'fail',
61
+ detail: 'not found in PATH',
62
+ fix: 'Install Claude Code: https://code.claude.com',
63
+ });
64
+ if (input.claudeInstalled) {
65
+ checks.push(input.claudeAuthenticated
66
+ ? { label: 'Authentication', status: 'ok', detail: 'logged in' }
67
+ : {
68
+ label: 'Authentication',
69
+ status: 'fail',
70
+ detail: 'not authenticated',
71
+ fix: 'Run `claude` once and complete login',
72
+ });
73
+ }
74
+ if (!input.config) {
75
+ checks.push({
76
+ label: 'Setup',
77
+ status: 'warn',
78
+ detail: 'not set up yet',
79
+ fix: 'Run `warmup` to start the guided setup',
80
+ });
81
+ return checks;
82
+ }
83
+ checks.push({
84
+ label: 'Setup',
85
+ status: 'ok',
86
+ detail: `pre-warm at ${input.config.schedule.time} (${input.config.schedule.timezone})`,
87
+ });
88
+ checks.push(input.scheduleInstalled
89
+ ? { label: 'Scheduled task', status: 'ok', detail: 'registered with the OS scheduler' }
90
+ : {
91
+ label: 'Scheduled task',
92
+ status: 'fail',
93
+ detail: 'not registered with the OS scheduler',
94
+ fix: 'Run `warmup setup` to (re)install it',
95
+ });
96
+ checks.push(input.config.schedule.enabled
97
+ ? { label: 'Schedule', status: 'ok', detail: 'active' }
98
+ : {
99
+ label: 'Schedule',
100
+ status: 'warn',
101
+ detail: 'paused',
102
+ fix: 'Run `warmup resume` to reactivate',
103
+ });
104
+ if (input.platform === 'macos') {
105
+ checks.push(input.wakeActive
106
+ ? { label: 'Wake', status: 'ok', detail: 'scheduled — runs while asleep' }
107
+ : {
108
+ label: 'Wake',
109
+ status: 'warn',
110
+ detail: "not scheduled — won't fire while the Mac is asleep",
111
+ fix: 'Run `warmup setup` to arm a system wake',
112
+ });
113
+ }
114
+ const last = input.lastLog;
115
+ if (!last) {
116
+ checks.push({ label: 'Last run', status: 'warn', detail: 'no runs recorded yet' });
117
+ }
118
+ else if (last.status === 'success' || last.status === 'boot-recovery') {
119
+ checks.push({ label: 'Last run', status: 'ok', detail: last.status });
120
+ }
121
+ else if (last.status === 'skipped') {
122
+ checks.push({
123
+ label: 'Last run',
124
+ status: 'warn',
125
+ detail: 'last scheduled window was missed (skipped)',
126
+ });
127
+ }
128
+ else {
129
+ checks.push({
130
+ label: 'Last run',
131
+ status: 'fail',
132
+ detail: 'last run failed',
133
+ fix: 'Run `warmup test` to retry and surface the error',
134
+ });
135
+ }
136
+ if (!input.config.runtime) {
137
+ checks.push({
138
+ label: 'Runtime',
139
+ status: 'warn',
140
+ detail: 'runtime paths not cached',
141
+ fix: 'Run `warmup update` to refresh them',
142
+ });
143
+ }
144
+ else if (input.runtimeValid) {
145
+ checks.push({ label: 'Runtime', status: 'ok', detail: 'node + claude paths resolved' });
146
+ }
147
+ else {
148
+ checks.push({
149
+ label: 'Runtime',
150
+ status: 'warn',
151
+ detail: 'cached node/claude path no longer exists',
152
+ fix: 'Run `warmup update` to refresh the paths the scheduler uses',
153
+ });
154
+ }
155
+ return checks;
156
+ }
157
+ /** Whether the cached runtime node + claude paths still exist on disk. */
158
+ function runtimePathsExist(runtime) {
159
+ if (!runtime)
160
+ return false;
161
+ try {
162
+ return fs.existsSync(runtime.nodePath) && fs.existsSync(runtime.claudePath);
163
+ }
164
+ catch {
165
+ return false;
166
+ }
167
+ }
168
+ /**
169
+ * `warmup doctor` — a one-shot self-diagnostic (à la `claude doctor`): is Claude
170
+ * Code installed & authed, is the schedule registered/active, is a wake armed,
171
+ * did the last run succeed, are runtime paths cached — each with a concrete fix.
172
+ * Scriptable and non-blocking; safe in non-TTY contexts. `--json` emits the
173
+ * structured checks (no chrome) and sets a health-based exit code (non-zero
174
+ * when any check fails) so it composes into scripts and CI.
175
+ */
176
+ async function doctorCommand(options = {}, deps = {}) {
177
+ const claudeInstalledFn = deps.isClaudeInstalled ?? warmup_1.isClaudeInstalled;
178
+ const claudeAuthedFn = deps.isClaudeAuthenticated ?? warmup_1.isClaudeAuthenticated;
179
+ const claudeVersionFn = deps.getClaudeVersion ?? warmup_1.getClaudeVersion;
180
+ const loadConfig = deps.readConfig ?? config_1.readConfig;
181
+ const platformFn = deps.detectPlatform ?? scheduler_1.detectPlatform;
182
+ const scheduleInstalledFn = deps.isScheduleInstalled ?? scheduler_1.isScheduleInstalled;
183
+ const wakeActiveFn = deps.isWakeScheduleActive ?? scheduler_1.isWakeScheduleActive;
184
+ const latestLogFn = deps.getLatestLog ?? config_1.getLatestLog;
185
+ const config = loadConfig();
186
+ const platform = platformFn();
187
+ // Probe the SAME binary the scheduler runs, not bare `claude`.
188
+ const claudeBinary = config?.runtime?.claudePath || 'claude';
189
+ const claudeInstalled = claudeInstalledFn(claudeBinary);
190
+ const input = {
191
+ claudeInstalled,
192
+ claudeAuthenticated: claudeInstalled ? claudeAuthedFn(claudeBinary) : false,
193
+ claudeVersion: claudeInstalled ? claudeVersionFn(claudeBinary) : null,
194
+ config,
195
+ platform,
196
+ scheduleInstalled: config ? scheduleInstalledFn() : false,
197
+ wakeActive: config && platform === 'macos' ? Boolean(config.wake) && wakeActiveFn() : false,
198
+ runtimeValid: config?.runtime ? runtimePathsExist(config.runtime) : false,
199
+ lastLog: config ? latestLogFn() : null,
200
+ };
201
+ const checks = collectDiagnostics(input);
202
+ if (options.json) {
203
+ const failures = checks.filter(c => c.status === 'fail').length;
204
+ const warnings = checks.filter(c => c.status === 'warn').length;
205
+ process.stdout.write(`${JSON.stringify({
206
+ healthy: failures === 0 && warnings === 0,
207
+ failures,
208
+ warnings,
209
+ checks,
210
+ }, null, 2)}\n`);
211
+ // Non-zero only on hard failures, so `warmup doctor --json` is usable as a
212
+ // health gate; warnings (e.g. paused, no wake) are advisory and exit 0.
213
+ process.exitCode = failures > 0 ? 1 : 0;
214
+ return;
215
+ }
216
+ (0, ui_1.printMiniLogo)();
217
+ (0, ui_1.printDiagnostics)(checks);
218
+ }
219
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export interface LogsCommandOptions {
2
+ limit?: number;
3
+ json?: boolean;
4
+ }
5
+ /**
6
+ * `warmup logs` — show recent pre-warm run history (newest first). Also reused
7
+ * by the interactive hub's "View recent runs". Scriptable: `--json` emits the
8
+ * raw entries (no chrome) for piping; otherwise a pretty list. In a non-TTY
9
+ * context it just prints and exits.
10
+ */
11
+ export declare function logsCommand(options?: LogsCommandOptions): Promise<void>;
12
+ //# sourceMappingURL=logs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBjF"}
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.logsCommand = logsCommand;
4
+ const config_1 = require("../config");
5
+ const ui_1 = require("../ui");
6
+ /**
7
+ * `warmup logs` — show recent pre-warm run history (newest first). Also reused
8
+ * by the interactive hub's "View recent runs". Scriptable: `--json` emits the
9
+ * raw entries (no chrome) for piping; otherwise a pretty list. In a non-TTY
10
+ * context it just prints and exits.
11
+ */
12
+ async function logsCommand(options = {}) {
13
+ const config = (0, config_1.readConfig)();
14
+ const limit = options.limit && options.limit > 0 ? options.limit : 10;
15
+ if (options.json) {
16
+ const entries = config ? (0, config_1.getRecentLogs)(limit) : [];
17
+ process.stdout.write(`${JSON.stringify(entries, null, 2)}\n`);
18
+ return;
19
+ }
20
+ (0, ui_1.printMiniLogo)();
21
+ if (!config) {
22
+ (0, ui_1.printNotSetup)();
23
+ return;
24
+ }
25
+ (0, ui_1.printRecentRuns)((0, config_1.getRecentLogs)(limit), config.schedule.timezone);
26
+ }
27
+ //# sourceMappingURL=logs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs.js","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":";;AAcA,kCAgBC;AA9BD,sCAAsD;AACtD,8BAAsE;AAOtE;;;;;GAKG;AACI,KAAK,UAAU,WAAW,CAAC,UAA8B,EAAE;IAChE,MAAM,MAAM,GAAG,IAAA,mBAAU,GAAE,CAAC;IAC5B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IAEtE,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,IAAA,sBAAa,EAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QAC9D,OAAO;IACT,CAAC;IAED,IAAA,kBAAa,GAAE,CAAC;IAChB,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,IAAA,kBAAa,GAAE,CAAC;QAChB,OAAO;IACT,CAAC;IACD,IAAA,oBAAe,EAAC,IAAA,sBAAa,EAAC,KAAK,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAClE,CAAC"}
@@ -0,0 +1,52 @@
1
+ import { readConfig, type WarmupConfig } from '../config';
2
+ export type MenuAction = 'status' | 'logs' | 'doctor' | 'update' | 'test' | 'toggle' | 'help' | 'uninstall' | 'exit';
3
+ export interface MenuChoice {
4
+ name: string;
5
+ value: MenuAction;
6
+ }
7
+ /**
8
+ * Build the interactive home-menu choices for the current config state.
9
+ * Pure and synchronous so the menu contents can be unit-tested without a TTY.
10
+ * The pause/resume entry flips to match whether the schedule is enabled.
11
+ */
12
+ export declare function buildMenuChoices(config: WarmupConfig): MenuChoice[];
13
+ /**
14
+ * Autocomplete source: substring-filter the menu by what the user types (case-
15
+ * insensitive). Empty input shows everything. Returned as a factory so the
16
+ * choices are captured per frame.
17
+ */
18
+ export declare function filterMenuChoices(choices: MenuChoice[]): (_answers: unknown, input?: string) => Promise<MenuChoice[]>;
19
+ export interface InteractiveHomeActions {
20
+ status: () => Promise<void>;
21
+ logs: () => Promise<void>;
22
+ doctor: () => Promise<void>;
23
+ update: () => Promise<void>;
24
+ test: () => Promise<void>;
25
+ pause: () => Promise<void>;
26
+ resume: () => Promise<void>;
27
+ help: () => Promise<void>;
28
+ uninstall: () => Promise<void>;
29
+ }
30
+ export interface InteractiveHomeDependencies {
31
+ prompt: (questions: unknown) => Promise<Record<string, unknown>>;
32
+ readConfig: typeof readConfig;
33
+ actions: InteractiveHomeActions;
34
+ /** Clear+repaint the frame. No-op in non-TTY (and in tests). */
35
+ clearScreen: () => void;
36
+ /** Pause so the user can read an action's output before the next repaint. */
37
+ waitForKey: () => Promise<void>;
38
+ }
39
+ /**
40
+ * Interactive "home" hub shown when a configured user runs bare `warmup` in a
41
+ * terminal. Each frame repaints from a clean screen: the status dashboard
42
+ * (persistent header + live context), a keyboard-hint footer, then an arrow-key
43
+ * menu. Selecting an action runs it, pauses so the output is readable, then
44
+ * returns to a fresh frame — so the whole tool is browsable without retyping
45
+ * subcommands, until the user picks Exit (or confirms Uninstall).
46
+ *
47
+ * The caller gates this on an interactive TTY; non-interactive contexts keep
48
+ * the one-shot status print, so `warmup` stays scriptable and never blocks on a
49
+ * prompt (launchd/systemd/CI/pipes). The cursor is always restored on exit.
50
+ */
51
+ export declare function runInteractiveHome(deps?: Partial<InteractiveHomeDependencies>): Promise<void>;
52
+ //# sourceMappingURL=menu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"menu.d.ts","sourceRoot":"","sources":["../../src/commands/menu.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAiB,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAoBzE,MAAM,MAAM,UAAU,GAClB,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;AAEhG,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,UAAU,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,GAAG,UAAU,EAAE,CAenE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,UAAU,EAAE,IACvC,UAAU,OAAO,EAAE,QAAQ,MAAM,KAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAKxE;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,2BAA2B;IAC1C,MAAM,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACjE,UAAU,EAAE,OAAO,UAAU,CAAC;IAC9B,OAAO,EAAE,sBAAsB,CAAC;IAChC,gEAAgE;IAChE,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,6EAA6E;IAC7E,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC;AA2BD;;;;;;;;;;;GAWG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,GAAE,OAAO,CAAC,2BAA2B,CAAM,GAC9C,OAAO,CAAC,IAAI,CAAC,CA+Ff"}