@sanohiro/casty 1.0.0 → 1.1.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.ja.md CHANGED
@@ -21,7 +21,7 @@ casty は w3m や lynx のようなテキストブラウザではありません
21
21
  └──────────────┘ └──────────────┘ └──────────────┘
22
22
  ```
23
23
 
24
- レンダリングはすべて Chrome がやります。casty はフレームをターミナルに流して入力を返すだけのブリッジ(約1200行)。Playwright も puppeteer も使わず、WebSocket で生 CDP を叩いています。
24
+ レンダリングはすべて Chrome がやります。casty はフレームをターミナルに流して入力を返すだけのブリッジ(約2300行)。Playwright も puppeteer も使わず、WebSocket で生 CDP を叩いています。
25
25
 
26
26
  本物の Chrome なので JavaScript, CSS, Canvas, WebGL 全部動きます。ステルスパッチで Google ログインも通ります。マウスのクリック、スクロール、ドラッグ、キーボード入力 — 普通のブラウザと同じ操作ができます。
27
27
 
@@ -52,6 +52,15 @@ cd casty && npm install
52
52
  - Node.js >= 18
53
53
  - `unzip`(Chrome 自動インストールに必要)
54
54
 
55
+ ### tmux
56
+
57
+ tmux 内で casty を使う場合は、Kitty graphics のエスケープシーケンスを
58
+ ターミナルまで通すために passthrough を有効にしてください:
59
+
60
+ ```tmux
61
+ set -g allow-passthrough on
62
+ ```
63
+
55
64
  ## 使い方
56
65
 
57
66
  ```bash
@@ -127,7 +136,7 @@ casty # ホームページを開く
127
136
  <details>
128
137
  <summary>技術詳細</summary>
129
138
 
130
- 全体で約1200行の JavaScript です。中でやっていること:
139
+ 全体で約2300行の JavaScript です。中でやっていること:
131
140
 
132
141
  - chrome-headless-shell を起動して生 CDP WebSocket で通信
133
142
  - `Runtime.enable` は絶対に送らない(Google ログインが壊れる。これは苦労して発見した)
package/README.md CHANGED
@@ -21,7 +21,7 @@ Terminal (you) casty Chrome (headless)
21
21
  └──────────────┘ └──────────────┘ └──────────────┘
22
22
  ```
23
23
 
24
- Chrome does all the rendering. casty is just a bridge (~1200 lines) that streams frames to your terminal and sends input back. No Playwright, no puppeteer — raw CDP over WebSocket.
24
+ Chrome does all the rendering. casty is just a bridge (~2300 lines) that streams frames to your terminal and sends input back. No Playwright, no puppeteer — raw CDP over WebSocket.
25
25
 
26
26
  Since it's real Chrome, JavaScript, CSS, Canvas, and WebGL all work. Google login works too (stealth patches bypass bot detection). Mouse clicks, scrolling, dragging, typing — everything you'd expect.
27
27
 
@@ -52,6 +52,15 @@ Chrome Headless Shell is auto-installed to `~/.casty/browsers/` on first run.
52
52
  - Node.js >= 18
53
53
  - `unzip` (for Chrome auto-install)
54
54
 
55
+ ### tmux
56
+
57
+ If you run casty inside tmux, enable passthrough so Kitty graphics escape
58
+ sequences can reach your terminal:
59
+
60
+ ```tmux
61
+ set -g allow-passthrough on
62
+ ```
63
+
55
64
  ## Usage
56
65
 
57
66
  ```bash
package/lib/kitty.js CHANGED
@@ -62,9 +62,16 @@ export function cursorHome() {
62
62
  process.stdout.write(CURSOR_HOME);
63
63
  }
64
64
 
65
+ // tmux only forwards kitty graphics if they are wrapped in a DCS passthrough
66
+ // envelope. Regular cursor/control sequences must stay outside that wrapper.
67
+ function wrapKitty(seq) {
68
+ if (!process.env.TMUX) return seq;
69
+ return `\x1bPtmux;${seq.replaceAll('\x1b', '\x1b\x1b')}\x1b\\`;
70
+ }
71
+
65
72
  // Clear screen (also delete all Kitty images)
66
73
  export function clearScreen() {
67
- process.stdout.write('\x1b_Ga=d,d=A,q=2;\x1b\\\x1b[2J\x1b[H');
74
+ process.stdout.write(`${wrapKitty('\x1b_Ga=d,d=A,q=2;\x1b\\')}\x1b[2J\x1b[H`);
68
75
  }
69
76
 
70
77
  // Hide cursor
@@ -103,7 +110,8 @@ function sendFrameFile(base64Data) {
103
110
  lastFrameData = base64Data;
104
111
  writeFileSync(tmpFile, Buffer.from(base64Data, 'base64'));
105
112
  const crFile = _cols && _rows ? `,c=${_cols},r=${_rows}` : '';
106
- process.stdout.write(`${CURSOR_HOME}\x1b_Ga=T,f=100,t=f,q=2,C=1,i=1${crFile};${tmpPathB64}\x1b\\`);
113
+ const seq = `\x1b_Ga=T,f=100,t=f,q=2,C=1,i=1${crFile};${tmpPathB64}\x1b\\`;
114
+ process.stdout.write(`${CURSOR_HOME}${wrapKitty(seq)}`);
107
115
  }
108
116
 
109
117
  // Inline mode (4096B chunked, PNG only)
@@ -116,10 +124,11 @@ function sendFrameInline(pngBase64) {
116
124
  const CHUNK = 4096;
117
125
  const crInline = _cols && _rows ? `,c=${_cols},r=${_rows}` : '';
118
126
  if (pngBase64.length <= CHUNK) {
119
- process.stdout.write(`${CURSOR_HOME}\x1b_Ga=T,f=100,q=2,C=1,i=1${crInline};${pngBase64}\x1b\\`);
127
+ const seq = `\x1b_Ga=T,f=100,q=2,C=1,i=1${crInline};${pngBase64}\x1b\\`;
128
+ process.stdout.write(`${CURSOR_HOME}${wrapKitty(seq)}`);
120
129
  return;
121
130
  }
122
- const parts = [CURSOR_HOME];
131
+ const parts = [];
123
132
  let i = 0;
124
133
  while (i < pngBase64.length) {
125
134
  const chunk = pngBase64.slice(i, i + CHUNK);
@@ -131,7 +140,7 @@ function sendFrameInline(pngBase64) {
131
140
  }
132
141
  i += CHUNK;
133
142
  }
134
- process.stdout.write(parts.join(''));
143
+ process.stdout.write(`${CURSOR_HOME}${wrapKitty(parts.join(''))}`);
135
144
  }
136
145
 
137
146
  // Reset dedup state (e.g. after resize)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanohiro/casty",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "TTY web browser using raw CDP and Kitty graphics protocol",
5
5
  "main": "bin/casty.js",
6
6
  "bin": {
@@ -13,6 +13,7 @@
13
13
  ],
14
14
  "scripts": {
15
15
  "start": "./bin/casty",
16
+ "test": "node --test",
16
17
  "postinstall": "echo 'Run casty to auto-install Chrome Headless Shell to ~/.casty/browsers/'"
17
18
  },
18
19
  "keywords": [