storymode-cli 1.3.2 → 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 -13
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "storymode-cli",
3
- "version": "1.3.2",
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,12 +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 (no equivalent of
203
- // Kitty's a=d,d=a — \x1b[2J is intercepted by tmux, not forwarded to iTerm2).
204
- // So HD only works for: Kitty/Ghostty (any context) or iTerm2 (direct, no tmux).
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.
205
205
  const renderMode = detectGraphicsProtocol();
206
- const useHd = renderMode.protocol === 'kitty'
207
- || (renderMode.protocol === 'iterm2' && !renderMode.inTmux);
206
+ const useHd = !!renderMode.protocol;
208
207
  const paneWidth = useHd && size === 'full' ? 80 : size === 'full' ? 62 : size === 'tiny' ? 14 : 22;
209
208
 
210
209
  // If we're already the companion pane (spawned by tmux split), play inline
@@ -241,21 +240,48 @@ export async function run(args) {
241
240
  installHooks({ global: true });
242
241
  }
243
242
 
244
- // Open tmux side pane — install tmux if needed
245
- if (!await ensureTmux()) process.exit(1);
246
- const inTmux = !!process.env.TMUX;
243
+ // Build companion command flags
247
244
  const sextantFlag = flags.sextant ? ' --sextant' : '';
248
245
  const reactiveFlag = reactive ? ' --reactive' : '';
249
246
  const noAiFlag = noAi ? ' --no-ai' : '';
250
247
  const modelFlag = model ? ` --model=${model}` : '';
251
- // Enable tmux passthrough for graphics protocols when HD is active
252
- const passthroughPrefix = useHd ? 'tmux set allow-passthrough on; ' : '';
253
- 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}`;
254
280
 
255
281
  try {
256
282
  if (inTmux) {
257
283
  execSync(
258
- `tmux split-window -h -l ${paneWidth} '${companionCmd}'`,
284
+ `tmux split-window -h -l ${paneWidth} '${tmuxCompanionCmd}'`,
259
285
  { stdio: 'ignore' }
260
286
  );
261
287
  if (!detach) {
@@ -280,7 +306,7 @@ export async function run(args) {
280
306
  process.stderr.write(' Starting tmux session with companion pane...\n');
281
307
  execSync(
282
308
  `tmux new-session -d -s storymode -x 100 -y 30 \\; ` +
283
- `split-window -h -l ${paneWidth} '${companionCmd}' \\; ` +
309
+ `split-window -h -l ${paneWidth} '${tmuxCompanionCmd}' \\; ` +
284
310
  `select-pane -L`,
285
311
  { stdio: 'ignore' }
286
312
  );