storymode-cli 1.3.1 → 1.3.3

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/cli.mjs +39 -9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "storymode-cli",
3
- "version": "1.3.1",
3
+ "version": "1.3.3",
4
4
  "description": "Play AI-animated pixel art characters in your terminal",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli.mjs CHANGED
@@ -199,8 +199,11 @@ export async function run(args) {
199
199
  const reactive = !flags['no-reactive'];
200
200
 
201
201
  // Auto-detect graphics protocol for HD rendering
202
+ // iTerm2 inside tmux can't clear previous inline images (Kitty has a=d,d=a
203
+ // but iTerm2's \x1b[2J is intercepted by tmux). So for iTerm2 we use native
204
+ // splits (AppleScript) instead of tmux, keeping the companion process direct.
202
205
  const renderMode = detectGraphicsProtocol();
203
- const useHd = !!renderMode.protocol; // auto-detect only
206
+ const useHd = !!renderMode.protocol;
204
207
  const paneWidth = useHd && size === 'full' ? 80 : size === 'full' ? 62 : size === 'tiny' ? 14 : 22;
205
208
 
206
209
  // If we're already the companion pane (spawned by tmux split), play inline
@@ -237,21 +240,48 @@ export async function run(args) {
237
240
  installHooks({ global: true });
238
241
  }
239
242
 
240
- // Open tmux side pane — install tmux if needed
241
- if (!await ensureTmux()) process.exit(1);
242
- const inTmux = !!process.env.TMUX;
243
+ // Build companion command flags
243
244
  const sextantFlag = flags.sextant ? ' --sextant' : '';
244
245
  const reactiveFlag = reactive ? ' --reactive' : '';
245
246
  const noAiFlag = noAi ? ' --no-ai' : '';
246
247
  const modelFlag = model ? ` --model=${model}` : '';
247
- // Enable tmux passthrough for graphics protocols when HD is active
248
- const passthroughPrefix = useHd ? 'tmux set allow-passthrough on; ' : '';
249
- const companionCmd = `${passthroughPrefix}STORYMODE_COMPANION=1 npx storymode-cli play ${id} --size=${size}${sextantFlag}${reactiveFlag}${noAiFlag}${modelFlag}`;
248
+ const companionCmd = `STORYMODE_COMPANION=1 npx storymode-cli play ${id} --size=${size}${sextantFlag}${reactiveFlag}${noAiFlag}${modelFlag}`;
249
+
250
+ // iTerm2 (not in tmux): use native split to keep HD working.
251
+ // iTerm2 inline images can't be cleared through tmux passthrough,
252
+ // so we avoid tmux entirely and use AppleScript to split the pane.
253
+ if (renderMode.protocol === 'iterm2' && !renderMode.inTmux) {
254
+ try {
255
+ const escapedCmd = companionCmd.replace(/"/g, '\\"');
256
+ execSync(`osascript -e '
257
+ tell application "iTerm2"
258
+ tell current session of current tab of current window
259
+ set newSession to split vertically with default profile command "${escapedCmd}"
260
+ end tell
261
+ end tell
262
+ '`, { stdio: 'ignore' });
263
+ process.stderr.write(` Companion opened in iTerm2 pane (${size} HD/${renderMode.protocol}).\n`);
264
+ process.stderr.write(' Close the pane or press q in it to stop.\n');
265
+ } catch (err) {
266
+ console.error(` iTerm2 split failed: ${err.message}`);
267
+ console.error(' Falling back to tmux...');
268
+ // Fall through to tmux path below
269
+ renderMode.protocol = null;
270
+ }
271
+ if (renderMode.protocol) break;
272
+ }
273
+
274
+ // Open tmux side pane — install tmux if needed
275
+ if (!await ensureTmux()) process.exit(1);
276
+ const inTmux = !!process.env.TMUX;
277
+ // Enable tmux passthrough for Kitty/Ghostty graphics protocols
278
+ const passthroughPrefix = renderMode.protocol === 'kitty' ? 'tmux set allow-passthrough on; ' : '';
279
+ const tmuxCompanionCmd = `${passthroughPrefix}${companionCmd}`;
250
280
 
251
281
  try {
252
282
  if (inTmux) {
253
283
  execSync(
254
- `tmux split-window -h -l ${paneWidth} '${companionCmd}'`,
284
+ `tmux split-window -h -l ${paneWidth} '${tmuxCompanionCmd}'`,
255
285
  { stdio: 'ignore' }
256
286
  );
257
287
  if (!detach) {
@@ -276,7 +306,7 @@ export async function run(args) {
276
306
  process.stderr.write(' Starting tmux session with companion pane...\n');
277
307
  execSync(
278
308
  `tmux new-session -d -s storymode -x 100 -y 30 \\; ` +
279
- `split-window -h -l ${paneWidth} '${companionCmd}' \\; ` +
309
+ `split-window -h -l ${paneWidth} '${tmuxCompanionCmd}' \\; ` +
280
310
  `select-pane -L`,
281
311
  { stdio: 'ignore' }
282
312
  );