claude-auto-continue 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 dakmor
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # claude-auto-continue
2
+
3
+ Automatically resumes Claude Code sessions after usage limits reset — no manual babysitting.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/claude-auto-continue.svg)](https://www.npmjs.com/package/claude-auto-continue)
6
+ [![Node.js >=18](https://img.shields.io/node/v/claude-auto-continue.svg)](https://nodejs.org)
7
+ [![License: ISC](https://img.shields.io/badge/license-ISC-blue.svg)](LICENSE)
8
+
9
+ Claude Code pauses with a "usage limit reached" message and a reset timestamp. Instead of watching and waiting, `claude-auto-continue` wraps Claude Code in a pseudo-terminal, monitors all output for rate-limit messages, parses the exact reset timestamp, shows a live status bar and countdown timer, then sends `continue` automatically at reset time. Leave it running overnight; it resumes by itself.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ npm install -g claude-auto-continue
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ```bash
20
+ claude-auto-continue # start — launches 'claude' automatically
21
+ clac # short alias
22
+ clac -- --continue # pass flags through to Claude Code
23
+ ```
24
+
25
+ All arguments after `--` are forwarded directly to `claude`. For example, `clac -- --resume` passes `--resume` to Claude Code.
26
+
27
+ ## Prerequisites
28
+
29
+ `claude-auto-continue` depends on `node-pty`, a native addon that compiles during install. Build tools must be present.
30
+
31
+ **Linux (Debian/Ubuntu):**
32
+
33
+ ```bash
34
+ sudo apt-get install build-essential python3 make g++
35
+ ```
36
+
37
+ **macOS:** Xcode Command Line Tools are usually pre-installed. If not:
38
+
39
+ ```bash
40
+ xcode-select --install
41
+ ```
42
+
43
+ **Windows:** `windows-build-tools` may be required. Install via an elevated PowerShell:
44
+
45
+ ```bash
46
+ npm install --global windows-build-tools
47
+ ```
48
+
49
+ **Node.js >= 18 is required.**
50
+
51
+ ## How It Works
52
+
53
+ 1. Wraps `claude` in a pseudo-terminal (PTY) so it receives a real TTY — required for interactive operation
54
+ 2. Monitors all output with a regex-based pattern detector that strips ANSI codes and uses a rolling buffer
55
+ 3. Parses the reset timestamp from the rate-limit message when a usage limit is detected
56
+ 4. Displays a status bar and centered countdown card in the terminal while waiting
57
+ 5. Sends `continue` to the PTY at reset time, automatically resuming the session
58
+ 6. Returns to monitoring — handles multiple rate limits in a single session
59
+
60
+ ## License
61
+
62
+ ISC
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ require('../dist/cli.js');
@@ -0,0 +1,27 @@
1
+ export interface CountdownCardOptions {
2
+ cols?: number;
3
+ rows?: number;
4
+ }
5
+ /**
6
+ * CountdownCard — renders a centered countdown box during WAITING state.
7
+ *
8
+ * Pure renderer: produces strings, does NOT write to stdout directly.
9
+ * The caller is responsible for writing the returned strings to the terminal.
10
+ */
11
+ export declare class CountdownCard {
12
+ cols: number;
13
+ rows: number;
14
+ constructor(options?: CountdownCardOptions);
15
+ /**
16
+ * Render the countdown card as a complete ANSI string.
17
+ * Shows a centered box with session name, countdown, and absolute reset time.
18
+ */
19
+ render(opts: {
20
+ resetTime: Date | null;
21
+ cwd: string;
22
+ }): string;
23
+ /**
24
+ * Clear the card area by writing clearLine to each row the card occupied.
25
+ */
26
+ clear(): string;
27
+ }
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CountdownCard = void 0;
4
+ const ansi_js_1 = require("./ansi.js");
5
+ const StatusBar_js_1 = require("./StatusBar.js");
6
+ /** Number of lines the card occupies (border + content + border) */
7
+ const CARD_HEIGHT = 9;
8
+ /**
9
+ * CountdownCard — renders a centered countdown box during WAITING state.
10
+ *
11
+ * Pure renderer: produces strings, does NOT write to stdout directly.
12
+ * The caller is responsible for writing the returned strings to the terminal.
13
+ */
14
+ class CountdownCard {
15
+ cols;
16
+ rows;
17
+ constructor(options = {}) {
18
+ this.cols = options.cols ?? 80;
19
+ this.rows = options.rows ?? 24;
20
+ }
21
+ /**
22
+ * Render the countdown card as a complete ANSI string.
23
+ * Shows a centered box with session name, countdown, and absolute reset time.
24
+ */
25
+ render(opts) {
26
+ const { resetTime, cwd } = opts;
27
+ const countdown = resetTime ? (0, StatusBar_js_1.formatCountdown)(resetTime) : 'Unknown';
28
+ const resetAt = resetTime ? (0, StatusBar_js_1.formatResetTime)(resetTime) : 'Unknown';
29
+ // Build card content lines (without borders)
30
+ const header = 'Waiting for rate limit reset';
31
+ const countdownLine = `${countdown} remaining`;
32
+ const resetLine = `Resets at ${resetAt}`;
33
+ const sessionLine = `Session: ${cwd}`;
34
+ // Calculate box width — fit the longest content line + padding
35
+ const contentLines = [header, countdownLine, resetLine, sessionLine];
36
+ const maxContentWidth = Math.max(...contentLines.map((l) => l.length));
37
+ const boxInnerWidth = Math.min(Math.max(maxContentWidth + 4, 40), this.cols - 4);
38
+ const boxOuterWidth = boxInnerWidth + 2; // +2 for left/right border chars
39
+ // Calculate centering positions
40
+ const startCol = Math.max(1, Math.floor((this.cols - boxOuterWidth) / 2) + 1);
41
+ // Vertical center: account for row 1 (status bar), so usable area is rows 2..this.rows
42
+ const usableRows = this.rows - 1;
43
+ const startRow = Math.max(2, Math.floor((usableRows - CARD_HEIGHT) / 2) + 2);
44
+ // Build the box
45
+ const topBorder = '+' + '-'.repeat(boxInnerWidth) + '+';
46
+ const bottomBorder = topBorder;
47
+ const emptyLine = '|' + ' '.repeat(boxInnerWidth) + '|';
48
+ const centerInBox = (text, visibleLength) => {
49
+ const len = visibleLength ?? text.length;
50
+ const padding = Math.max(0, boxInnerWidth - len);
51
+ const leftPad = Math.floor(padding / 2);
52
+ const rightPad = padding - leftPad;
53
+ return '|' + ' '.repeat(leftPad) + text + ' '.repeat(rightPad) + '|';
54
+ };
55
+ const lines = [
56
+ topBorder,
57
+ emptyLine,
58
+ centerInBox((0, ansi_js_1.bold)(header), header.length),
59
+ emptyLine,
60
+ centerInBox((0, ansi_js_1.yellow)(countdownLine), countdownLine.length),
61
+ centerInBox(resetLine),
62
+ emptyLine,
63
+ centerInBox(sessionLine),
64
+ bottomBorder,
65
+ ];
66
+ // Render each line at the calculated position
67
+ let output = '';
68
+ for (let i = 0; i < lines.length; i++) {
69
+ output += (0, ansi_js_1.moveTo)(startRow + i, startCol) + lines[i];
70
+ }
71
+ return output;
72
+ }
73
+ /**
74
+ * Clear the card area by writing clearLine to each row the card occupied.
75
+ */
76
+ clear() {
77
+ const boxInnerWidth = Math.min(44, this.cols - 4);
78
+ const boxOuterWidth = boxInnerWidth + 2;
79
+ const startCol = Math.max(1, Math.floor((this.cols - boxOuterWidth) / 2) + 1);
80
+ const usableRows = this.rows - 1;
81
+ const startRow = Math.max(2, Math.floor((usableRows - CARD_HEIGHT) / 2) + 2);
82
+ let output = '';
83
+ for (let i = 0; i < CARD_HEIGHT; i++) {
84
+ output += (0, ansi_js_1.moveTo)(startRow + i, startCol) + ansi_js_1.clearLine;
85
+ }
86
+ return output;
87
+ }
88
+ }
89
+ exports.CountdownCard = CountdownCard;
90
+ //# sourceMappingURL=CountdownCard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CountdownCard.js","sourceRoot":"","sources":["../src/CountdownCard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import { EventEmitter } from 'events';
2
+ /**
3
+ * Payload emitted with the 'limit' event.
4
+ */
5
+ export interface LimitEvent {
6
+ /** Parsed reset time as a Date, or null when unparseable */
7
+ resetTime: Date | null;
8
+ /** Last ~500 chars of the buffer at the time of detection */
9
+ rawMatch: string;
10
+ }
11
+ export interface PatternDetectorOptions {
12
+ /** Override default detection pattern */
13
+ pattern?: RegExp;
14
+ /** If true, write buffer snapshots to stderr on each feed() call */
15
+ debug?: boolean;
16
+ }
17
+ /**
18
+ * EventEmitter subclass that detects Claude rate-limit messages in a stream of
19
+ * PTY output chunks. Emits a 'limit' event with a LimitEvent payload.
20
+ */
21
+ export declare class PatternDetector extends EventEmitter {
22
+ #private;
23
+ constructor(options?: PatternDetectorOptions);
24
+ /**
25
+ * Feed a raw PTY output chunk into the detector.
26
+ * Strips ANSI codes, appends to rolling buffer, trims if >4KB, then checks pattern.
27
+ */
28
+ feed(rawChunk: string): void;
29
+ /**
30
+ * Clear the buffer and re-arm detection (allow the next match to fire again).
31
+ */
32
+ reset(): void;
33
+ }
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.PatternDetector = void 0;
7
+ const events_1 = require("events");
8
+ const strip_ansi_1 = __importDefault(require("strip-ansi"));
9
+ const config_js_1 = require("./config.js");
10
+ /**
11
+ * Default regex that matches all three known Claude rate-limit message formats:
12
+ * Format A (legacy): "Claude AI usage limit reached|1760000400"
13
+ * Format B (mid-era): "Claude usage limit reached. Your limit will reset at 3pm (America/Santiago)."
14
+ * Format C (current): "You've hit your limit · resets 4pm (Europe/Berlin)"
15
+ */
16
+ const DEFAULT_PATTERN = /(?:Claude(?:\s+AI)?\s+usage\s+limit\s+reached[|.]|you(?:'ve| have)\s+hit\s+your\s+limit)/i;
17
+ /** Matches a 10+ digit unix timestamp after a pipe: |1760000400 */
18
+ const UNIX_TS_PATTERN = /\|(\d{10,})/;
19
+ /**
20
+ * Matches human-readable reset time in multiple forms:
21
+ * "resets Feb 20, 5pm (Africa/Libreville)"
22
+ * "reset at 3pm (America/Santiago)"
23
+ * "resets 4pm (Europe/Berlin)"
24
+ */
25
+ const HUMAN_TIME_PATTERN = /reset(?:s)?\s+(?:at\s+)?(?:\w+\s+\d{1,2},?\s*)?(\d{1,2}(?::\d{2})?\s*[ap]m)/i;
26
+ /** Maximum rolling buffer size in characters */
27
+ const MAX_BUFFER = 4096;
28
+ /**
29
+ * EventEmitter subclass that detects Claude rate-limit messages in a stream of
30
+ * PTY output chunks. Emits a 'limit' event with a LimitEvent payload.
31
+ */
32
+ class PatternDetector extends events_1.EventEmitter {
33
+ #pattern;
34
+ #debug;
35
+ #buffer = '';
36
+ #detected = false;
37
+ constructor(options = {}) {
38
+ super();
39
+ // Priority: constructor option > config file > default
40
+ const config = (0, config_js_1.loadConfig)();
41
+ this.#pattern = options.pattern ?? config.pattern ?? DEFAULT_PATTERN;
42
+ this.#debug = options.debug ?? false;
43
+ }
44
+ /**
45
+ * Feed a raw PTY output chunk into the detector.
46
+ * Strips ANSI codes, appends to rolling buffer, trims if >4KB, then checks pattern.
47
+ */
48
+ feed(rawChunk) {
49
+ // Already detected — ignore further input until reset()
50
+ if (this.#detected)
51
+ return;
52
+ // Strip ANSI escape codes and append to rolling buffer
53
+ const clean = (0, strip_ansi_1.default)(rawChunk);
54
+ this.#buffer += clean;
55
+ // Trim buffer to last MAX_BUFFER characters to avoid unbounded growth
56
+ if (this.#buffer.length > MAX_BUFFER) {
57
+ this.#buffer = this.#buffer.slice(this.#buffer.length - MAX_BUFFER);
58
+ }
59
+ if (this.#debug) {
60
+ process.stderr.write(`[PatternDetector] buffer(${this.#buffer.length}): ${this.#buffer}\n`);
61
+ }
62
+ // Test the pattern against the current buffer
63
+ if (this.#pattern.test(this.#buffer)) {
64
+ this.#detected = true;
65
+ const rawMatch = this.#buffer.slice(-500);
66
+ const resetTime = this.#parseResetTime(this.#buffer);
67
+ this.emit('limit', { resetTime, rawMatch });
68
+ }
69
+ }
70
+ /**
71
+ * Clear the buffer and re-arm detection (allow the next match to fire again).
72
+ */
73
+ reset() {
74
+ this.#buffer = '';
75
+ this.#detected = false;
76
+ }
77
+ /**
78
+ * Parse a reset timestamp from the buffer text.
79
+ * Tries unix epoch first, then human-readable time expression.
80
+ * Returns null if neither can be parsed.
81
+ */
82
+ #parseResetTime(text) {
83
+ // Try unix timestamp (Format A): |1760000400
84
+ const unixMatch = UNIX_TS_PATTERN.exec(text);
85
+ if (unixMatch) {
86
+ const seconds = parseInt(unixMatch[1], 10);
87
+ return new Date(seconds * 1000);
88
+ }
89
+ // Try human-readable time (Formats B & C)
90
+ return this.#parseHumanTime(text);
91
+ }
92
+ /**
93
+ * Parse a human-readable time expression like "3pm", "4pm", "5:30am"
94
+ * into an absolute Date. Rolls to tomorrow if the time is already past.
95
+ * Returns null if the pattern doesn't match.
96
+ *
97
+ * Note: Does not perform IANA timezone lookup — uses local clock per user decision.
98
+ */
99
+ #parseHumanTime(text) {
100
+ const match = HUMAN_TIME_PATTERN.exec(text);
101
+ if (!match)
102
+ return null;
103
+ const timeStr = match[1].trim(); // e.g. "3pm", "4pm", "5:30am"
104
+ const timeMatch = /^(\d{1,2})(?::(\d{2}))?\s*([ap]m)$/i.exec(timeStr);
105
+ if (!timeMatch)
106
+ return null;
107
+ let hours = parseInt(timeMatch[1], 10);
108
+ const minutes = timeMatch[2] ? parseInt(timeMatch[2], 10) : 0;
109
+ const meridiem = timeMatch[3].toLowerCase();
110
+ if (meridiem === 'am') {
111
+ if (hours === 12)
112
+ hours = 0;
113
+ }
114
+ else {
115
+ if (hours !== 12)
116
+ hours += 12;
117
+ }
118
+ const now = new Date();
119
+ const candidate = new Date(now.getFullYear(), now.getMonth(), now.getDate(), hours, minutes, 0, 0);
120
+ // If the time is in the past (or right now), roll to tomorrow
121
+ if (candidate.getTime() <= now.getTime()) {
122
+ candidate.setDate(candidate.getDate() + 1);
123
+ }
124
+ return candidate;
125
+ }
126
+ }
127
+ exports.PatternDetector = PatternDetector;
128
+ //# sourceMappingURL=PatternDetector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PatternDetector.js","sourceRoot":"","sources":["../src/PatternDetector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ import { EventEmitter } from 'events';
2
+ import * as pty from 'node-pty';
3
+ /**
4
+ * Four-state machine for the PTY session lifecycle:
5
+ *
6
+ * RUNNING — normal operation, forwarding I/O and feeding PatternDetector
7
+ * LIMIT_DETECTED — transient: rate limit seen, calling scheduler.scheduleAt()
8
+ * WAITING — blocked: scheduler is counting down to reset time
9
+ * RESUMING — transient: sending resume sequence to PTY, resetting detector
10
+ *
11
+ * Transitions: RUNNING -> LIMIT_DETECTED -> WAITING -> RESUMING -> RUNNING
12
+ */
13
+ export declare const enum SessionState {
14
+ RUNNING = "RUNNING",
15
+ LIMIT_DETECTED = "LIMIT_DETECTED",
16
+ WAITING = "WAITING",
17
+ RESUMING = "RESUMING"
18
+ }
19
+ /** Payload emitted with the 'stateChange' event */
20
+ export interface StateChangeEvent {
21
+ state: string;
22
+ resetTime: Date | null;
23
+ }
24
+ export interface ProcessSupervisorOptions {
25
+ /** Override node-pty spawn function for testing (dependency injection) */
26
+ spawnFn?: typeof pty.spawn;
27
+ /** Cooldown after resume — suppresses false-positive re-detections. Default: 30000ms */
28
+ cooldownMs?: number;
29
+ /** Safety buffer added to reset time before resuming. Default: 5000ms */
30
+ safetyMs?: number;
31
+ /** Override process.exit for testing. Default: process.exit */
32
+ onExit?: (code: number) => void;
33
+ /** Override PTY output handler. Default: process.stdout.write */
34
+ onOutput?: (data: string) => void;
35
+ }
36
+ /**
37
+ * ProcessSupervisor — the core PTY orchestrator.
38
+ *
39
+ * Spawns Claude Code in a real PTY, passes all I/O transparently, detects
40
+ * usage-limit messages via PatternDetector, waits via Scheduler, and
41
+ * auto-resumes via StdinWriter.
42
+ *
43
+ * Extends EventEmitter to broadcast 'stateChange' events for the display layer.
44
+ */
45
+ export declare class ProcessSupervisor extends EventEmitter {
46
+ #private;
47
+ constructor(options?: ProcessSupervisorOptions);
48
+ /** Current session state — exposed for Phase 3 status display and testing */
49
+ get state(): SessionState;
50
+ /**
51
+ * Spawn the given command in a PTY and wire up all I/O.
52
+ *
53
+ * @param command - executable to run (e.g. 'claude')
54
+ * @param args - CLI arguments (e.g. ['--continue'])
55
+ */
56
+ spawn(command: string, args: string[]): void;
57
+ /**
58
+ * Gracefully shut down: cancel pending timer, mark writer dead, kill PTY.
59
+ */
60
+ shutdown(): void;
61
+ }
@@ -0,0 +1,184 @@
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.ProcessSupervisor = void 0;
37
+ const events_1 = require("events");
38
+ const pty = __importStar(require("node-pty"));
39
+ const PatternDetector_js_1 = require("./PatternDetector.js");
40
+ const Scheduler_js_1 = require("./Scheduler.js");
41
+ const StdinWriter_js_1 = require("./StdinWriter.js");
42
+ /**
43
+ * ProcessSupervisor — the core PTY orchestrator.
44
+ *
45
+ * Spawns Claude Code in a real PTY, passes all I/O transparently, detects
46
+ * usage-limit messages via PatternDetector, waits via Scheduler, and
47
+ * auto-resumes via StdinWriter.
48
+ *
49
+ * Extends EventEmitter to broadcast 'stateChange' events for the display layer.
50
+ */
51
+ class ProcessSupervisor extends events_1.EventEmitter {
52
+ #spawnFn;
53
+ #cooldownMs;
54
+ #detector;
55
+ #scheduler;
56
+ #onExitCallback;
57
+ #onOutput;
58
+ #state = "RUNNING" /* SessionState.RUNNING */;
59
+ #writer = null;
60
+ #cooldownUntil = 0;
61
+ #resetTime = null;
62
+ constructor(options = {}) {
63
+ super();
64
+ this.#spawnFn = options.spawnFn ?? pty.spawn;
65
+ this.#cooldownMs = options.cooldownMs ?? 30_000;
66
+ this.#detector = new PatternDetector_js_1.PatternDetector();
67
+ this.#scheduler = new Scheduler_js_1.Scheduler(options.safetyMs ?? 5_000);
68
+ this.#onExitCallback = options.onExit ?? ((code) => process.exit(code));
69
+ this.#onOutput = options.onOutput ?? ((data) => { process.stdout.write(data); });
70
+ // Listen for rate-limit detections
71
+ this.#detector.on('limit', (event) => this.#onLimitDetected(event));
72
+ }
73
+ /** Current session state — exposed for Phase 3 status display and testing */
74
+ get state() {
75
+ return this.#state;
76
+ }
77
+ /**
78
+ * Set state and emit a 'stateChange' event.
79
+ */
80
+ #setState(newState) {
81
+ if (newState !== 'DEAD') {
82
+ this.#state = newState;
83
+ }
84
+ this.emit('stateChange', {
85
+ state: newState,
86
+ resetTime: this.#resetTime,
87
+ });
88
+ }
89
+ /**
90
+ * Spawn the given command in a PTY and wire up all I/O.
91
+ *
92
+ * @param command - executable to run (e.g. 'claude')
93
+ * @param args - CLI arguments (e.g. ['--continue'])
94
+ */
95
+ spawn(command, args) {
96
+ const ptyProcess = this.#spawnFn(command, args, {
97
+ name: process.env['TERM'] ?? 'xterm-256color',
98
+ cols: process.stdout.columns ?? 80,
99
+ rows: process.stdout.rows ?? 24,
100
+ cwd: process.cwd(),
101
+ env: process.env,
102
+ });
103
+ this.#writer = new StdinWriter_js_1.StdinWriter(ptyProcess);
104
+ // --- PTY output: pass to output handler, optionally feed detector ---
105
+ ptyProcess.onData((data) => {
106
+ this.#onOutput(data);
107
+ // Only feed the detector when RUNNING — ignore output in all other states
108
+ if (this.#state === "RUNNING" /* SessionState.RUNNING */) {
109
+ this.#detector.feed(data);
110
+ }
111
+ });
112
+ // --- PTY exit: clean up and exit ---
113
+ ptyProcess.onExit((e) => {
114
+ this.#writer.markDead();
115
+ this.#scheduler.cancel();
116
+ this.#setState('DEAD');
117
+ // Allow Node.js event loop to drain (stdin will no longer hold the process open)
118
+ if (process.stdin.isTTY) {
119
+ process.stdin.unref();
120
+ }
121
+ this.#onExitCallback(e.exitCode ?? 0);
122
+ });
123
+ // --- Stdin forwarding (only in a real TTY environment) ---
124
+ if (process.stdin.isTTY) {
125
+ process.stdin.setRawMode(true);
126
+ process.stdin.resume();
127
+ process.stdin.on('data', (chunk) => {
128
+ // Forward keystrokes to PTY only during RUNNING state
129
+ if (this.#state === "RUNNING" /* SessionState.RUNNING */) {
130
+ this.#writer.write(chunk.toString('binary'));
131
+ }
132
+ // Silently discard during WAITING / RESUMING / LIMIT_DETECTED
133
+ });
134
+ }
135
+ // --- Terminal resize forwarding ---
136
+ process.stdout.on('resize', () => {
137
+ ptyProcess.resize(process.stdout.columns ?? 80, process.stdout.rows ?? 24);
138
+ });
139
+ }
140
+ /**
141
+ * Called when PatternDetector emits a 'limit' event.
142
+ * Transitions: RUNNING -> LIMIT_DETECTED -> WAITING
143
+ */
144
+ #onLimitDetected(event) {
145
+ // Suppress false positives during post-resume cooldown
146
+ if (Date.now() < this.#cooldownUntil) {
147
+ return;
148
+ }
149
+ this.#resetTime = event.resetTime;
150
+ this.#setState("LIMIT_DETECTED" /* SessionState.LIMIT_DETECTED */);
151
+ // Schedule the resume callback
152
+ this.#scheduler.scheduleAt(event.resetTime, () => this.#onResumeReady());
153
+ this.#setState("WAITING" /* SessionState.WAITING */);
154
+ }
155
+ /**
156
+ * Called by Scheduler when the reset time has elapsed.
157
+ * Transitions: WAITING -> RESUMING -> RUNNING
158
+ */
159
+ #onResumeReady() {
160
+ this.#setState("RESUMING" /* SessionState.RESUMING */);
161
+ // Send Escape to dismiss any rate-limit UI overlay
162
+ this.#writer.write('\x1b');
163
+ // Type "continue" and press Enter to resume the session
164
+ this.#writer.write('continue\r');
165
+ // Arm cooldown to suppress the false-positive re-detection that can occur
166
+ // immediately after resume (Claude Code issue #14129)
167
+ this.#cooldownUntil = Date.now() + this.#cooldownMs;
168
+ // Re-arm the detector for the next potential rate-limit cycle
169
+ this.#detector.reset();
170
+ this.#resetTime = null;
171
+ this.#setState("RUNNING" /* SessionState.RUNNING */);
172
+ }
173
+ /**
174
+ * Gracefully shut down: cancel pending timer, mark writer dead, kill PTY.
175
+ */
176
+ shutdown() {
177
+ this.#scheduler.cancel();
178
+ if (this.#writer) {
179
+ this.#writer.markDead();
180
+ }
181
+ }
182
+ }
183
+ exports.ProcessSupervisor = ProcessSupervisor;
184
+ //# sourceMappingURL=ProcessSupervisor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProcessSupervisor.js","sourceRoot":"","sources":["../src/ProcessSupervisor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ export declare class Scheduler {
2
+ #private;
3
+ constructor(safetyMs?: number);
4
+ /**
5
+ * Schedule callback to fire at resetTime + safetyBuffer milliseconds from now.
6
+ * If resetTime is null → fire immediately (0ms delay) as a fallback.
7
+ * If resetTime is in the past → waitMs clamps to 0 (plus safety buffer).
8
+ * Calling scheduleAt() while a timer is pending cancels the previous timer.
9
+ * Calling scheduleAt() after cancel() is a no-op (cancelled flag stays true).
10
+ */
11
+ scheduleAt(resetTime: Date | null, callback: () => void): void;
12
+ /**
13
+ * Cancel any pending timer. After cancel(), the scheduler is inert —
14
+ * subsequent scheduleAt() calls are ignored.
15
+ * Safe to call when no timer is pending (no-op, no error).
16
+ */
17
+ cancel(): void;
18
+ }
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Scheduler = void 0;
4
+ class Scheduler {
5
+ #timer = null;
6
+ #cancelled = false;
7
+ #safetyMs;
8
+ constructor(safetyMs = 5000) {
9
+ this.#safetyMs = safetyMs;
10
+ }
11
+ /**
12
+ * Schedule callback to fire at resetTime + safetyBuffer milliseconds from now.
13
+ * If resetTime is null → fire immediately (0ms delay) as a fallback.
14
+ * If resetTime is in the past → waitMs clamps to 0 (plus safety buffer).
15
+ * Calling scheduleAt() while a timer is pending cancels the previous timer.
16
+ * Calling scheduleAt() after cancel() is a no-op (cancelled flag stays true).
17
+ */
18
+ scheduleAt(resetTime, callback) {
19
+ if (this.#cancelled)
20
+ return;
21
+ // Clear any existing timer before setting a new one
22
+ if (this.#timer) {
23
+ clearTimeout(this.#timer);
24
+ this.#timer = null;
25
+ }
26
+ const waitMs = resetTime
27
+ ? Math.max(0, resetTime.getTime() - Date.now() + this.#safetyMs)
28
+ : 0;
29
+ this.#timer = setTimeout(() => {
30
+ if (!this.#cancelled)
31
+ callback();
32
+ }, waitMs);
33
+ }
34
+ /**
35
+ * Cancel any pending timer. After cancel(), the scheduler is inert —
36
+ * subsequent scheduleAt() calls are ignored.
37
+ * Safe to call when no timer is pending (no-op, no error).
38
+ */
39
+ cancel() {
40
+ this.#cancelled = true;
41
+ if (this.#timer) {
42
+ clearTimeout(this.#timer);
43
+ this.#timer = null;
44
+ }
45
+ }
46
+ }
47
+ exports.Scheduler = Scheduler;
48
+ //# sourceMappingURL=Scheduler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Scheduler.js","sourceRoot":"","sources":["../src/Scheduler.ts"],"names":[],"mappings":";;;AAAA,MAAa,SAAS;IACpB,MAAM,GAAyC,IAAI,CAAC;IACpD,UAAU,GAAG,KAAK,CAAC;IACV,SAAS,CAAS;IAE3B,YAAY,QAAQ,GAAG,IAAI;QACzB,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;IAC5B,CAAC;IAED;;;;;;OAMG;IACH,UAAU,CAAC,SAAsB,EAAE,QAAoB;QACrD,IAAI,IAAI,CAAC,UAAU;YAAE,OAAO;QAE5B,oDAAoD;QACpD,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC1B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACrB,CAAC;QAED,MAAM,MAAM,GAAG,SAAS;YACtB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC;YAChE,CAAC,CAAC,CAAC,CAAC;QAEN,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,IAAI,CAAC,IAAI,CAAC,UAAU;gBAAE,QAAQ,EAAE,CAAC;QACnC,CAAC,EAAE,MAAM,CAAC,CAAC;IACb,CAAC;IAED;;;;OAIG;IACH,MAAM;QACJ,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC1B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACrB,CAAC;IACH,CAAC;CACF;AA9CD,8BA8CC"}
@@ -0,0 +1,41 @@
1
+ export interface StatusBarOptions {
2
+ cols?: number;
3
+ }
4
+ /**
5
+ * Format a countdown from now until resetTime as a human-readable string.
6
+ * Returns "Xh Xm Xs" for durations over an hour, "Xm Xs" otherwise.
7
+ * Returns "0m 00s" for past or null dates.
8
+ */
9
+ export declare function formatCountdown(resetTime: Date): string;
10
+ /**
11
+ * Format a Date as a human-readable absolute time (e.g., "2:45 PM").
12
+ */
13
+ export declare function formatResetTime(resetTime: Date): string;
14
+ /**
15
+ * StatusBar — renders a fixed top-row status bar with color-coded session state.
16
+ *
17
+ * Pure renderer: produces strings, does NOT write to stdout directly.
18
+ * The caller is responsible for writing the returned strings to the terminal.
19
+ */
20
+ export declare class StatusBar {
21
+ cols: number;
22
+ constructor(options?: StatusBarOptions);
23
+ /**
24
+ * Render the status bar string for the given state.
25
+ * Returns a complete ANSI sequence: save cursor, move to row 1, render bar, restore cursor.
26
+ */
27
+ render(state: string, opts?: {
28
+ resetTime?: Date;
29
+ cwd?: string;
30
+ }): string;
31
+ /**
32
+ * Produce the ANSI sequence to initialize the scroll region.
33
+ * Confines scrolling to rows 2..termRows, leaving row 1 for the status bar.
34
+ */
35
+ initScrollRegion(rows: number): string;
36
+ /**
37
+ * Produce the ANSI cleanup sequence.
38
+ * Resets scroll region, shows cursor, and resets all attributes.
39
+ */
40
+ cleanup(): string;
41
+ }
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StatusBar = void 0;
4
+ exports.formatCountdown = formatCountdown;
5
+ exports.formatResetTime = formatResetTime;
6
+ const ansi_js_1 = require("./ansi.js");
7
+ /**
8
+ * Format a countdown from now until resetTime as a human-readable string.
9
+ * Returns "Xh Xm Xs" for durations over an hour, "Xm Xs" otherwise.
10
+ * Returns "0m 00s" for past or null dates.
11
+ */
12
+ function formatCountdown(resetTime) {
13
+ const remaining = Math.max(0, resetTime.getTime() - Date.now());
14
+ const totalSec = Math.ceil(remaining / 1000);
15
+ const hours = Math.floor(totalSec / 3600);
16
+ const minutes = Math.floor((totalSec % 3600) / 60);
17
+ const seconds = totalSec % 60;
18
+ if (hours > 0) {
19
+ return `${hours}h ${String(minutes).padStart(2, '0')}m ${String(seconds).padStart(2, '0')}s`;
20
+ }
21
+ return `${minutes}m ${String(seconds).padStart(2, '0')}s`;
22
+ }
23
+ /**
24
+ * Format a Date as a human-readable absolute time (e.g., "2:45 PM").
25
+ */
26
+ function formatResetTime(resetTime) {
27
+ return resetTime.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' });
28
+ }
29
+ /**
30
+ * StatusBar — renders a fixed top-row status bar with color-coded session state.
31
+ *
32
+ * Pure renderer: produces strings, does NOT write to stdout directly.
33
+ * The caller is responsible for writing the returned strings to the terminal.
34
+ */
35
+ class StatusBar {
36
+ cols;
37
+ constructor(options = {}) {
38
+ this.cols = options.cols ?? 80;
39
+ }
40
+ /**
41
+ * Render the status bar string for the given state.
42
+ * Returns a complete ANSI sequence: save cursor, move to row 1, render bar, restore cursor.
43
+ */
44
+ render(state, opts = {}) {
45
+ const { resetTime, cwd = '' } = opts;
46
+ let stateText;
47
+ let colorFn;
48
+ switch (state) {
49
+ case 'RUNNING':
50
+ stateText = 'Running';
51
+ colorFn = ansi_js_1.green;
52
+ break;
53
+ case 'WAITING':
54
+ stateText = 'Waiting';
55
+ colorFn = ansi_js_1.yellow;
56
+ break;
57
+ case 'RESUMING':
58
+ stateText = 'Resuming';
59
+ colorFn = ansi_js_1.green;
60
+ break;
61
+ case 'DEAD':
62
+ stateText = 'Dead';
63
+ colorFn = ansi_js_1.red;
64
+ break;
65
+ default:
66
+ stateText = state;
67
+ colorFn = ansi_js_1.green;
68
+ }
69
+ // Build bar content
70
+ const parts = [colorFn(stateText)];
71
+ if (state === 'WAITING' && resetTime) {
72
+ const countdown = formatCountdown(resetTime);
73
+ const resetAt = formatResetTime(resetTime);
74
+ parts.push(`${countdown} (resets ${resetAt})`);
75
+ }
76
+ if (cwd) {
77
+ parts.push(cwd);
78
+ }
79
+ const content = ` ${parts.join(' | ')} `;
80
+ const barContent = (0, ansi_js_1.inverse)(content);
81
+ return `${ansi_js_1.saveCursor}${(0, ansi_js_1.moveTo)(1, 1)}${ansi_js_1.clearLine}${barContent}${ansi_js_1.restoreCursor}`;
82
+ }
83
+ /**
84
+ * Produce the ANSI sequence to initialize the scroll region.
85
+ * Confines scrolling to rows 2..termRows, leaving row 1 for the status bar.
86
+ */
87
+ initScrollRegion(rows) {
88
+ return `${(0, ansi_js_1.setScrollRegion)(2, rows)}${(0, ansi_js_1.moveTo)(2, 1)}`;
89
+ }
90
+ /**
91
+ * Produce the ANSI cleanup sequence.
92
+ * Resets scroll region, shows cursor, and resets all attributes.
93
+ */
94
+ cleanup() {
95
+ return `${ansi_js_1.resetScrollRegion}${ansi_js_1.showCursor}${ansi_js_1.resetAttributes}`;
96
+ }
97
+ }
98
+ exports.StatusBar = StatusBar;
99
+ //# sourceMappingURL=StatusBar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatusBar.js","sourceRoot":"","sources":["../src/StatusBar.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type * as pty from 'node-pty';
2
+ export declare class StdinWriter {
3
+ #private;
4
+ constructor(ptyProcess: pty.IPty);
5
+ write(data: string): void;
6
+ markDead(): void;
7
+ get isDead(): boolean;
8
+ }
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StdinWriter = void 0;
4
+ class StdinWriter {
5
+ #pty;
6
+ #dead = false;
7
+ constructor(ptyProcess) {
8
+ this.#pty = ptyProcess;
9
+ }
10
+ write(data) {
11
+ if (this.#dead)
12
+ return;
13
+ try {
14
+ this.#pty.write(data);
15
+ }
16
+ catch (err) {
17
+ const code = err.code;
18
+ if (code !== 'EPIPE') {
19
+ process.stderr.write(`[StdinWriter] write error: ${code ?? String(err)}\n`);
20
+ }
21
+ // EPIPE = PTY process exited between dead-check and write — silently ignore
22
+ }
23
+ }
24
+ markDead() {
25
+ this.#dead = true;
26
+ }
27
+ get isDead() {
28
+ return this.#dead;
29
+ }
30
+ }
31
+ exports.StdinWriter = StdinWriter;
32
+ //# sourceMappingURL=StdinWriter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StdinWriter.js","sourceRoot":"","sources":["../src/StdinWriter.ts"],"names":[],"mappings":";;;AAEA,MAAa,WAAW;IACb,IAAI,CAAW;IACxB,KAAK,GAAG,KAAK,CAAC;IAEd,YAAY,UAAoB;QAC9B,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,IAAY;QAChB,IAAI,IAAI,CAAC,KAAK;YAAE,OAAO;QACvB,IAAI,CAAC;YACH,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,IAAI,GAAI,GAA6B,CAAC,IAAI,CAAC;YACjD,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;gBACrB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,IAAI,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC9E,CAAC;YACD,4EAA4E;QAC9E,CAAC;IACH,CAAC;IAED,QAAQ;QACN,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACpB,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;CACF;AA5BD,kCA4BC"}
package/dist/ansi.d.ts ADDED
@@ -0,0 +1,18 @@
1
+ /**
2
+ * ANSI escape code helpers for terminal rendering.
3
+ * Pure string functions — no I/O, no dependencies.
4
+ */
5
+ export declare function moveTo(row: number, col: number): string;
6
+ export declare const saveCursor = "\u001B7";
7
+ export declare const restoreCursor = "\u001B8";
8
+ export declare function setScrollRegion(top: number, bottom: number): string;
9
+ export declare const resetScrollRegion = "\u001B[r";
10
+ export declare const clearLine = "\u001B[2K";
11
+ export declare function green(text: string): string;
12
+ export declare function yellow(text: string): string;
13
+ export declare function red(text: string): string;
14
+ export declare function bold(text: string): string;
15
+ export declare function inverse(text: string): string;
16
+ export declare const showCursor = "\u001B[?25h";
17
+ export declare const hideCursor = "\u001B[?25l";
18
+ export declare const resetAttributes = "\u001B[0m";
package/dist/ansi.js ADDED
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ /**
3
+ * ANSI escape code helpers for terminal rendering.
4
+ * Pure string functions — no I/O, no dependencies.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.resetAttributes = exports.hideCursor = exports.showCursor = exports.clearLine = exports.resetScrollRegion = exports.restoreCursor = exports.saveCursor = void 0;
8
+ exports.moveTo = moveTo;
9
+ exports.setScrollRegion = setScrollRegion;
10
+ exports.green = green;
11
+ exports.yellow = yellow;
12
+ exports.red = red;
13
+ exports.bold = bold;
14
+ exports.inverse = inverse;
15
+ const CSI = '\x1b[';
16
+ // --- Cursor positioning ---
17
+ function moveTo(row, col) {
18
+ return `${CSI}${row};${col}H`;
19
+ }
20
+ exports.saveCursor = '\x1b7';
21
+ exports.restoreCursor = '\x1b8';
22
+ // --- Scroll region ---
23
+ function setScrollRegion(top, bottom) {
24
+ return `${CSI}${top};${bottom}r`;
25
+ }
26
+ exports.resetScrollRegion = `${CSI}r`;
27
+ // --- Line operations ---
28
+ exports.clearLine = `${CSI}2K`;
29
+ // --- Colors (foreground) ---
30
+ function green(text) {
31
+ return `${CSI}32m${text}${CSI}0m`;
32
+ }
33
+ function yellow(text) {
34
+ return `${CSI}33m${text}${CSI}0m`;
35
+ }
36
+ function red(text) {
37
+ return `${CSI}31m${text}${CSI}0m`;
38
+ }
39
+ // --- Text attributes ---
40
+ function bold(text) {
41
+ return `${CSI}1m${text}${CSI}0m`;
42
+ }
43
+ function inverse(text) {
44
+ return `${CSI}7m${text}${CSI}0m`;
45
+ }
46
+ // --- Cursor visibility ---
47
+ exports.showCursor = `${CSI}?25h`;
48
+ exports.hideCursor = `${CSI}?25l`;
49
+ // --- Reset ---
50
+ exports.resetAttributes = `${CSI}0m`;
51
+ //# sourceMappingURL=ansi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ansi.js","sourceRoot":"","sources":["../src/ansi.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAMH,wBAEC;AAOD,0CAEC;AAUD,sBAEC;AAED,wBAEC;AAED,kBAEC;AAID,oBAEC;AAED,0BAEC;AA7CD,MAAM,GAAG,GAAG,OAAO,CAAC;AAEpB,6BAA6B;AAE7B,SAAgB,MAAM,CAAC,GAAW,EAAE,GAAW;IAC7C,OAAO,GAAG,GAAG,GAAG,GAAG,IAAI,GAAG,GAAG,CAAC;AAChC,CAAC;AAEY,QAAA,UAAU,GAAG,OAAO,CAAC;AACrB,QAAA,aAAa,GAAG,OAAO,CAAC;AAErC,wBAAwB;AAExB,SAAgB,eAAe,CAAC,GAAW,EAAE,MAAc;IACzD,OAAO,GAAG,GAAG,GAAG,GAAG,IAAI,MAAM,GAAG,CAAC;AACnC,CAAC;AAEY,QAAA,iBAAiB,GAAG,GAAG,GAAG,GAAG,CAAC;AAE3C,0BAA0B;AAEb,QAAA,SAAS,GAAG,GAAG,GAAG,IAAI,CAAC;AAEpC,8BAA8B;AAE9B,SAAgB,KAAK,CAAC,IAAY;IAChC,OAAO,GAAG,GAAG,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC;AACpC,CAAC;AAED,SAAgB,MAAM,CAAC,IAAY;IACjC,OAAO,GAAG,GAAG,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC;AACpC,CAAC;AAED,SAAgB,GAAG,CAAC,IAAY;IAC9B,OAAO,GAAG,GAAG,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC;AACpC,CAAC;AAED,0BAA0B;AAE1B,SAAgB,IAAI,CAAC,IAAY;IAC/B,OAAO,GAAG,GAAG,KAAK,IAAI,GAAG,GAAG,IAAI,CAAC;AACnC,CAAC;AAED,SAAgB,OAAO,CAAC,IAAY;IAClC,OAAO,GAAG,GAAG,KAAK,IAAI,GAAG,GAAG,IAAI,CAAC;AACnC,CAAC;AAED,4BAA4B;AAEf,QAAA,UAAU,GAAG,GAAG,GAAG,MAAM,CAAC;AAC1B,QAAA,UAAU,GAAG,GAAG,GAAG,MAAM,CAAC;AAEvC,gBAAgB;AAEH,QAAA,eAAe,GAAG,GAAG,GAAG,IAAI,CAAC"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const ProcessSupervisor_js_1 = require("./ProcessSupervisor.js");
4
+ const StatusBar_js_1 = require("./StatusBar.js");
5
+ const CountdownCard_js_1 = require("./CountdownCard.js");
6
+ const fs_1 = require("fs");
7
+ const path_1 = require("path");
8
+ /**
9
+ * Read the version string from package.json.
10
+ */
11
+ function getVersion() {
12
+ try {
13
+ const pkgPath = (0, path_1.join)(__dirname, '..', 'package.json');
14
+ const pkg = JSON.parse((0, fs_1.readFileSync)(pkgPath, 'utf8'));
15
+ return pkg.version ?? 'unknown';
16
+ }
17
+ catch {
18
+ return 'unknown';
19
+ }
20
+ }
21
+ /**
22
+ * Print usage instructions to stdout.
23
+ */
24
+ function showHelp() {
25
+ const version = getVersion();
26
+ console.log(`claude-auto-continue v${version}
27
+
28
+ Automatically resumes Claude Code sessions after usage limits reset.
29
+
30
+ USAGE:
31
+ claude-auto-continue [options] [-- claude-code-args...]
32
+ clac [options] [-- claude-code-args...]
33
+
34
+ OPTIONS:
35
+ --help, -h Show this help message
36
+ --version, -v Show version number
37
+
38
+ EXAMPLES:
39
+ claude-auto-continue Start with defaults
40
+ claude-auto-continue -- --continue Pass --continue to Claude Code
41
+ clac -- --resume Short alias, pass --resume to Claude Code
42
+
43
+ WHAT IT DOES:
44
+ Wraps Claude Code in a PTY, monitors for rate-limit messages, waits
45
+ until the reset time, then sends "continue" to resume automatically.
46
+ A status bar and countdown timer show progress while waiting.`);
47
+ }
48
+ /**
49
+ * Parse CLI arguments, extracting Claude Code args after the -- separator.
50
+ */
51
+ function parseArgs(argv) {
52
+ const userArgs = argv.slice(2); // strip 'node' and script path
53
+ const separatorIdx = userArgs.indexOf('--');
54
+ if (separatorIdx === -1) {
55
+ return { claudeArgs: [] };
56
+ }
57
+ return { claudeArgs: userArgs.slice(separatorIdx + 1) };
58
+ }
59
+ /**
60
+ * Main entry point — wires ProcessSupervisor to the status display.
61
+ */
62
+ function main() {
63
+ const args = process.argv.slice(2);
64
+ // Handle --help and --version before anything else
65
+ if (args.includes('--help') || args.includes('-h')) {
66
+ showHelp();
67
+ process.exit(0);
68
+ }
69
+ if (args.includes('--version') || args.includes('-v')) {
70
+ console.log(getVersion());
71
+ process.exit(0);
72
+ }
73
+ const { claudeArgs } = parseArgs(process.argv);
74
+ const cols = () => process.stdout.columns ?? 80;
75
+ const rows = () => process.stdout.rows ?? 24;
76
+ const cwd = process.cwd();
77
+ // Create display components
78
+ const statusBar = new StatusBar_js_1.StatusBar({ cols: cols() });
79
+ const countdownCard = new CountdownCard_js_1.CountdownCard({ cols: cols(), rows: rows() });
80
+ // Set up terminal: scroll region leaves row 1 for status bar
81
+ process.stdout.write(statusBar.initScrollRegion(rows()));
82
+ // Initial status bar render
83
+ process.stdout.write(statusBar.render('RUNNING', { cwd }));
84
+ // Countdown timer handle
85
+ let countdownInterval = null;
86
+ // Create supervisor with output routed through the standard handler
87
+ const supervisor = new ProcessSupervisor_js_1.ProcessSupervisor({
88
+ onOutput: (data) => {
89
+ process.stdout.write(data);
90
+ },
91
+ });
92
+ // Handle state changes from ProcessSupervisor
93
+ supervisor.on('stateChange', (event) => {
94
+ const { state, resetTime } = event;
95
+ // Clear any existing countdown timer
96
+ if (countdownInterval) {
97
+ clearInterval(countdownInterval);
98
+ countdownInterval = null;
99
+ }
100
+ if (state === 'DEAD') {
101
+ // Show dead state in status bar, clear countdown card
102
+ process.stdout.write(statusBar.render('DEAD', { cwd }));
103
+ process.stdout.write(countdownCard.clear());
104
+ // Wait 5 seconds to show "Dead" status, then cleanup and let exit handler run
105
+ setTimeout(() => {
106
+ process.stdout.write(statusBar.cleanup());
107
+ }, 5000);
108
+ return;
109
+ }
110
+ // Re-render status bar for the current state
111
+ process.stdout.write(statusBar.render(state, { resetTime: resetTime ?? undefined, cwd }));
112
+ if (state === 'WAITING' && resetTime) {
113
+ // Show centered countdown card
114
+ process.stdout.write(countdownCard.render({ resetTime, cwd }));
115
+ // Start 1-second countdown tick
116
+ countdownInterval = setInterval(() => {
117
+ // Race protection: if state has moved on, stop ticking
118
+ if (supervisor.state !== 'WAITING') {
119
+ clearInterval(countdownInterval);
120
+ countdownInterval = null;
121
+ return;
122
+ }
123
+ // Recalculate from resetTime - Date.now() each tick (no drift)
124
+ process.stdout.write(statusBar.render('WAITING', { resetTime, cwd }));
125
+ process.stdout.write(countdownCard.render({ resetTime, cwd }));
126
+ }, 1000);
127
+ }
128
+ else {
129
+ // Clear countdown card if it was showing
130
+ process.stdout.write(countdownCard.clear());
131
+ }
132
+ });
133
+ // Handle terminal resize
134
+ process.stdout.on('resize', () => {
135
+ // Update display component dimensions
136
+ statusBar.cols = cols();
137
+ countdownCard.cols = cols();
138
+ countdownCard.rows = rows();
139
+ // Re-initialize scroll region with new dimensions
140
+ process.stdout.write(statusBar.initScrollRegion(rows()));
141
+ // Re-render current state
142
+ const currentState = supervisor.state;
143
+ process.stdout.write(statusBar.render(currentState, { cwd }));
144
+ });
145
+ // Terminal cleanup on all exit paths
146
+ const cleanup = () => {
147
+ if (countdownInterval) {
148
+ clearInterval(countdownInterval);
149
+ countdownInterval = null;
150
+ }
151
+ process.stdout.write(statusBar.cleanup());
152
+ };
153
+ process.on('exit', cleanup);
154
+ process.on('SIGINT', () => {
155
+ cleanup();
156
+ process.exit(130);
157
+ });
158
+ process.on('SIGTERM', () => {
159
+ cleanup();
160
+ process.exit(143);
161
+ });
162
+ // Spawn Claude Code with passed-through arguments
163
+ supervisor.spawn('claude', claudeArgs);
164
+ }
165
+ main();
166
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export interface ToolConfig {
2
+ pattern?: RegExp;
3
+ }
4
+ export declare const CONFIG_PATH: string;
5
+ export declare function loadConfig(): ToolConfig;
package/dist/config.js ADDED
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CONFIG_PATH = void 0;
4
+ exports.loadConfig = loadConfig;
5
+ const fs_1 = require("fs");
6
+ const os_1 = require("os");
7
+ const path_1 = require("path");
8
+ exports.CONFIG_PATH = (0, path_1.join)((0, os_1.homedir)(), '.config', 'claude-auto-continue', 'config.json');
9
+ function loadConfig() {
10
+ try {
11
+ const raw = (0, fs_1.readFileSync)(exports.CONFIG_PATH, 'utf8');
12
+ const parsed = JSON.parse(raw);
13
+ const config = {};
14
+ if (typeof parsed.pattern === 'string') {
15
+ config.pattern = new RegExp(parsed.pattern, 'i');
16
+ }
17
+ return config;
18
+ }
19
+ catch {
20
+ return {};
21
+ }
22
+ }
23
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;;AAUA,gCAYC;AAtBD,2BAAkC;AAClC,2BAA6B;AAC7B,+BAA4B;AAMf,QAAA,WAAW,GAAG,IAAA,WAAI,EAAC,IAAA,YAAO,GAAE,EAAE,SAAS,EAAE,sBAAsB,EAAE,aAAa,CAAC,CAAC;AAE7F,SAAgB,UAAU;IACxB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAA,iBAAY,EAAC,mBAAW,EAAE,MAAM,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,MAAM,MAAM,GAAe,EAAE,CAAC;QAC9B,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;YACvC,MAAM,CAAC,OAAO,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACnD,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "claude-auto-continue",
3
+ "version": "1.0.0",
4
+ "description": "Automatically resumes Claude Code sessions after usage limits reset",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "claude-auto-continue": "bin/claude-auto-continue.js",
8
+ "clac": "bin/claude-auto-continue.js"
9
+ },
10
+ "files": [
11
+ "dist/",
12
+ "bin/"
13
+ ],
14
+ "scripts": {
15
+ "test": "vitest run",
16
+ "test:watch": "vitest",
17
+ "build": "tsc",
18
+ "prepublishOnly": "npm run build"
19
+ },
20
+ "engines": {
21
+ "node": ">=18"
22
+ },
23
+ "keywords": [
24
+ "claude",
25
+ "claude-code",
26
+ "auto-continue",
27
+ "rate-limit",
28
+ "cli"
29
+ ],
30
+ "author": "dakmor",
31
+ "license": "MIT",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "https://github.com/oguztecimer/claude-auto-continue.git"
35
+ },
36
+ "homepage": "https://github.com/oguztecimer/claude-auto-continue#readme",
37
+ "bugs": {
38
+ "url": "https://github.com/oguztecimer/claude-auto-continue/issues"
39
+ },
40
+ "dependencies": {
41
+ "node-pty": "^1.1.0",
42
+ "strip-ansi": "^6.0.1"
43
+ },
44
+ "devDependencies": {
45
+ "@types/node": "^25.3.2",
46
+ "tsx": "^4.21.0",
47
+ "typescript": "^5.9.3",
48
+ "vitest": "^2.1.9"
49
+ }
50
+ }