claude-cache-keepalive 0.1.3 → 0.1.4

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
@@ -104,6 +104,9 @@ Environment variables (mostly for testing / advanced use):
104
104
 
105
105
  ## Changelog
106
106
 
107
+ ### 0.1.4
108
+ - **Fix:** the terminal could be left unusable after `/exit` or Ctrl‑C (keystrokes garbled / no usable input). The PTY host now restores the terminal on every exit path: it emits an explicit reset (disabling alt‑screen, bracketed‑paste, mouse, cursor‑hide, and — critically on Windows — `win32‑input‑mode` `?9001` and focus‑reporting `?1004`, which otherwise make the shell receive keystrokes as unparseable `ESC[…_` packets) and flushes stdout before exiting. Adds a `SIGINT` handler that forwards `0x03` to claude instead of letting the host be killed before cleanup, plus `SIGHUP`/`exit` safety restores.
109
+
107
110
  ### 0.1.3
108
111
  - **Change:** the cache TTL is now **measured from the transcript** (`message.usage.cache_creation`'s `ephemeral_1h` / `ephemeral_5m` tokens) instead of being guessed from your subscription plan. A recent 1h write → 1h regime; only 5m writes (or no evidence) → 5m regime (conservative). This drops the `~/.claude/.credentials.json` read entirely and is correct even when a Pro account gets a 1h cache. Adds `transcriptPath` / `readTtlRegime` / `detectTtlRegime` / `regimeParams`; removes `detectPlan` / `planParams`.
109
112
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-cache-keepalive",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Keep Claude Code's prompt cache warm while idle, by running claude inside a PTY host and injecting a tiny keepalive when you step away. Cross-platform, no tmux required.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/host.mjs CHANGED
@@ -83,17 +83,38 @@ export function startHost(opts = {}) {
83
83
  }, tickMs);
84
84
 
85
85
  // ---- 收尾 ----
86
- function restore() {
86
+ // claude(TUI)會開 alt-screen / bracketed-paste / mouse / 隱藏游標等終端模式。正常 /exit 時它自己會還原,
87
+ // 但 (1) 被 Ctrl-C 中斷時來不及還原;(2) 在 onExit 內立刻 process.exit() 會跟 claude 最後一段輸出(含還原
88
+ // 序列)賽跑而把它截斷。任一情況都會讓真終端卡在這些模式 → 回到 shell 後「鍵盤輸入不正常」。
89
+ // 故 shutdown():還原 raw mode + 主動補一份終端還原序列 + 等 stdout flush 再退出。
90
+ // 關鍵(Windows):node-pty 啟動時對真終端開了 ?9001h(win32-input-mode) 與 ?1004h(focus reporting),
91
+ // 若沒關掉,回到 shell 後終端會把每個鍵碼以 ESC[…_ 封包送出,readline 無法解析 → 鍵盤輸入全亂。
92
+ // ?2004=bracketed paste、?1000/1002/1003/1006=mouse、?25=cursor、?1049=alt-screen、?9001=win32-input、?1004=focus。
93
+ const RESET = '\x1b[?2004l\x1b[?1000l\x1b[?1002l\x1b[?1003l\x1b[?1006l\x1b[?25h\x1b[?1049l\x1b[?9001l\x1b[?1004l\x1b[0m';
94
+ let exiting = false;
95
+ function shutdown(code) {
96
+ if (exiting) return;
97
+ exiting = true;
98
+ clearInterval(timer);
87
99
  try { if (process.stdin.isTTY) process.stdin.setRawMode(false); } catch {}
88
100
  try { process.stdin.pause(); } catch {}
101
+ try { process.stdout.write(RESET, () => process.exit(code)); }
102
+ catch { process.exit(code); }
103
+ setTimeout(() => process.exit(code), 200).unref(); // 保險:flush callback 沒回也強制退出
89
104
  }
90
- ptyProc.onExit(({ exitCode }) => {
91
- clearInterval(timer);
92
- restore();
93
- process.exit(exitCode || 0); // node-pty 會卡住 event loop,必須主動退出
105
+ ptyProc.onExit(({ exitCode }) => shutdown(exitCode || 0)); // node-pty 會卡住 event loop,必須主動退出
106
+ // Windows:真主控台的 Ctrl-C 以 SIGINT 送到 host(claude 在獨立 ConPTY、收不到真主控台的 Ctrl-C),
107
+ // 轉成 0x03 寫進 pty 交給 claude 自己處理;不要讓 host 被預設行為直接殺掉(那會跳過終端還原 → 卡 raw mode)。
108
+ // Unix raw mode 下 Ctrl-C 是位元組(0x03)、不觸發 SIGINT,故此 handler 不影響 Unix。
109
+ process.on('SIGINT', () => { try { ptyProc.write('\x03'); } catch {} });
110
+ process.on('SIGTERM', () => shutdown(0));
111
+ process.on('SIGHUP', () => shutdown(0));
112
+ // 任何路徑退出都殺掉 pty,並盡力(同步)還原終端,作為最後保險。
113
+ process.on('exit', () => {
114
+ try { ptyProc.kill(); } catch {}
115
+ try { if (process.stdin.isTTY) process.stdin.setRawMode(false); } catch {}
116
+ try { process.stdout.write(RESET); } catch {}
94
117
  });
95
- process.on('exit', () => { try { ptyProc.kill(); } catch {} });
96
- process.on('SIGTERM', () => { try { ptyProc.kill(); } catch {} process.exit(0); });
97
118
 
98
119
  return ptyProc;
99
120
  }