@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 +33 -10
- package/dist/commands/default.d.ts +3 -1
- package/dist/commands/default.d.ts.map +1 -1
- package/dist/commands/default.js +25 -0
- package/dist/commands/default.js.map +1 -1
- package/dist/commands/doctor.d.ts +51 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +219 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/logs.d.ts +12 -0
- package/dist/commands/logs.d.ts.map +1 -0
- package/dist/commands/logs.js +27 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/menu.d.ts +52 -0
- package/dist/commands/menu.d.ts.map +1 -0
- package/dist/commands/menu.js +185 -0
- package/dist/commands/menu.js.map +1 -0
- package/dist/commands/status.d.ts +8 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +85 -11
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/test.d.ts.map +1 -1
- package/dist/commands/test.js +25 -4
- package/dist/commands/test.js.map +1 -1
- package/dist/config.d.ts +7 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +21 -0
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +32 -3
- package/dist/index.js.map +1 -1
- package/dist/ui.d.ts +49 -4
- package/dist/ui.d.ts.map +1 -1
- package/dist/ui.js +210 -27
- package/dist/ui.js.map +1 -1
- package/dist/warmup.d.ts +13 -4
- package/dist/warmup.d.ts.map +1 -1
- package/dist/warmup.js +139 -79
- package/dist/warmup.js.map +1 -1
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<div align="center">
|
|
2
|
-
<img src="https://raw.githubusercontent.com/
|
|
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
|
[](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
|
|
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 2–3 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
|
|
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`
|
|
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
|
|
79
|
+
Run `warmup` anywhere in your terminal:
|
|
57
80
|
|
|
58
81
|
```bash
|
|
59
82
|
warmup
|
|
60
83
|
```
|
|
61
84
|
|
|
62
|
-
*
|
|
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
|
-
###
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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;
|
|
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"}
|
package/dist/commands/default.js
CHANGED
|
@@ -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":";;;;;
|
|
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"}
|