claude-cache-keepalive 0.1.7 → 0.1.8

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
@@ -137,6 +137,10 @@ Environment variables (mostly for testing / advanced use):
137
137
 
138
138
  ## Changelog
139
139
 
140
+ ### 0.1.8
141
+ - **Fix:** the keepalive's `Esc`‑prefix (added in 0.1.5) could dismiss Claude Code's **folder‑trust dialog** ("Do you trust the files in this folder?"). Since 0.1.7 dropped the implicit `--continue`, bare `cwarm` starts a *fresh* session, so an untrusted directory shows the trust dialog on launch; if you stepped away past the idle threshold, the keepalive's `Esc` cancelled it — which writes `hasTrustDialogAccepted: false` into `~/.claude.json` and makes that folder's `.claude/settings.local.json` permissions silently ignored (the "Ignoring N permissions.allow entries: this workspace has not been trusted" warning you only see after `/exit` restores the normal screen). The keepalive now detects the trust dialog on screen and **skips the whole tick** (no `Esc`, no message), leaving it for you to answer; all other mandatory prompts keep the 0.1.5 `Esc` behaviour. Adds `looksLikeTrustPrompt`.
142
+ - **修正:** 0.1.5 加入的 keepalive **`Esc` 先行**可能會把 Claude Code 的**資料夾信任對話框**(「Do you trust the files in this folder?」)給收掉。自 0.1.7 拿掉隱含的 `--continue` 後,單獨打 `cwarm` 會開*全新* session,所以進入未信任的資料夾時啟動就會跳信任框;若你人走開、閒置過門檻,keepalive 的 `Esc` 就把它取消掉——這會在 `~/.claude.json` 寫下 `hasTrustDialogAccepted: false`,使該資料夾的 `.claude/settings.local.json` 權限被靜默忽略(就是你 `/exit` 還原一般畫面後才看到的「Ignoring N permissions.allow entries: this workspace has not been trusted」警告)。keepalive 現在會偵測畫面上的信任框並**整輪跳過**(不送 `Esc`、不送訊息),交給你本人回答;其他必答提示維持 0.1.5 的 `Esc` 行為。新增 `looksLikeTrustPrompt`。
143
+
140
144
  ### 0.1.7
141
145
  - **Change:** `cwarm` no longer implicitly adds `--continue`. It is now a fully transparent pass‑through — `cwarm [args]` is exactly `claude [args]`, so bare `cwarm` starts a clean session. To resume your last session, run `cwarm --continue`. (Previously bare `cwarm` auto‑resumed.)
142
146
  - **變更:** `cwarm` 不再隱含補上 `--continue`,改為完全透傳——`cwarm [參數]` 就等於 `claude [參數]`,所以單獨打 `cwarm` 會開全新 session。要接續上次請打 `cwarm --continue`。(先前單獨打 `cwarm` 會自動接續。)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-cache-keepalive",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
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
@@ -5,7 +5,7 @@ import { createRequire } from 'node:module';
5
5
  import fs from 'node:fs';
6
6
  import path from 'node:path';
7
7
  import { spawnSync } from 'node:child_process';
8
- import { defaultClaudeDir, regimeParams, detectTtlRegime, decideInject, transcriptIdleMs } from './keepalive.mjs';
8
+ import { defaultClaudeDir, regimeParams, detectTtlRegime, decideInject, transcriptIdleMs, looksLikeTrustPrompt } from './keepalive.mjs';
9
9
 
10
10
  const require = createRequire(import.meta.url);
11
11
  const isWin = process.platform === 'win32';
@@ -58,7 +58,14 @@ export function startHost(opts = {}) {
58
58
  // 追蹤 claude 最近一次有輸出到畫面的時刻:閒置在輸入框時畫面靜止;提示等待回答時 spinner 在動、
59
59
  // 生成/跑工具時持續輸出。注入前要求畫面已靜止一段時間(見下方 quietMs),就能避開「忙/卡」狀態。
60
60
  let lastOutputMs = Date.now();
61
- ptyProc.onData((d) => { lastOutputMs = Date.now(); process.stdout.write(d); });
61
+ // 保留最近一小段螢幕輸出(含 ANSI),供偵測「資料夾信任」對話框用:那個框被保溫 Esc 掉會留下
62
+ // hasTrustDialogAccepted:false,害該資料夾 settings.local.json 權限整批失效,故它在畫面上時整輪不注入。
63
+ let screenBuf = '';
64
+ ptyProc.onData((d) => {
65
+ lastOutputMs = Date.now();
66
+ process.stdout.write(d);
67
+ screenBuf = (screenBuf + d.toString('utf8')).slice(-8192);
68
+ });
62
69
  process.stdout.on('resize', () => {
63
70
  try { ptyProc.resize(process.stdout.columns || 80, process.stdout.rows || 24); } catch {}
64
71
  });
@@ -75,7 +82,18 @@ export function startHost(opts = {}) {
75
82
  if (ttlO != null) overrides.ttl = Number(ttlO);
76
83
 
77
84
  let lastFire = 0;
85
+ let trustGuardLogged = false;
78
86
  const timer = setInterval(() => {
87
+ // 信任對話框在畫面上時,這輪完全不動作(連 Esc 都不送)——那是使用者本人該回答的框,被保溫
88
+ // Esc 掉會留下 hasTrustDialogAccepted:false,害該資料夾 settings.local.json 權限失效、之後不再跳框。
89
+ if (looksLikeTrustPrompt(screenBuf)) {
90
+ if (!trustGuardLogged) {
91
+ trustGuardLogged = true;
92
+ try { fs.appendFileSync(LOG, `${new Date().toISOString()} skip: trust dialog on screen — left for the user to answer\n`); } catch {}
93
+ }
94
+ return;
95
+ }
96
+ trustGuardLogged = false;
79
97
  const cwd = process.cwd();
80
98
  const regime = detectTtlRegime(claudeDir, cwd); // 從 transcript 實測 1h/5m,不再猜方案
81
99
  const { ttl, idleThreshold } = regimeParams(regime, overrides);
package/src/keepalive.mjs CHANGED
@@ -141,3 +141,19 @@ export function decideInject({ now, idleMs, lastFire, idleThreshold, ttl, disabl
141
141
  if (quietMs != null && screenIdleMs != null && screenIdleMs < quietMs) return false; // 畫面還在動(提示/生成/打字中)
142
142
  return true;
143
143
  }
144
+
145
+ // 畫面上是否正顯示 Claude Code 的「資料夾信任」對話框("Do you trust the files in this folder?")。
146
+ // 保溫的「Esc 先行」是用來收掉一般必答 modal(權限/選單/計畫批准),但信任框特殊:被 Esc 掉會在
147
+ // ~/.claude.json 寫下 hasTrustDialogAccepted:false,使該資料夾的 .claude/settings.local.json 權限
148
+ // 整批失效、且之後不再自動跳框。這種框只能由使用者本人回答——偵測到就整輪跳過注入(連 Esc 都不送)。
149
+ // 傳入的是原始終端輸出(含 ANSI),先剝掉控制序列再比對,避免顏色/游標碼把字拆開。
150
+ const TRUST_PROMPT_RE = /trust\s+the\s+files\s+in\s+this\s+(?:folder|workspace)/i;
151
+ export function looksLikeTrustPrompt(screenText) {
152
+ if (!screenText) return false;
153
+ const plain = String(screenText)
154
+ .replace(/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g, ' ') // OSC …(BEL 或 ST 結尾)
155
+ .replace(/\x1b[@-Z\\-_]/g, ' ') // 兩位元組跳脫
156
+ .replace(/\x1b\[[0-9;?]*[ -\/]*[@-~]/g, ' ') // CSI(顏色/游標)
157
+ .replace(/[\x00-\x08\x0b-\x1f\x7f]/g, ' '); // 其餘控制碼 → 空白
158
+ return TRUST_PROMPT_RE.test(plain);
159
+ }