storymode-cli 1.3.0 → 1.3.1
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/package.json +1 -1
- package/src/api.mjs +3 -1
- package/src/browse.mjs +2 -1
- package/src/cli.mjs +35 -3
- package/src/mcp.mjs +2 -1
- package/src/player.mjs +4 -4
package/package.json
CHANGED
package/src/api.mjs
CHANGED
|
@@ -25,7 +25,9 @@ function request(url) {
|
|
|
25
25
|
|
|
26
26
|
export async function fetchGallery() {
|
|
27
27
|
const { buffer } = await request(`${BASE}/gallery`);
|
|
28
|
-
|
|
28
|
+
const data = JSON.parse(buffer.toString('utf-8'));
|
|
29
|
+
// Handle both new {featured_id, curated_ids, items} and legacy bare array
|
|
30
|
+
return Array.isArray(data) ? { featured_id: null, curated_ids: null, items: data } : data;
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
export async function fetchFrames(galleryId, { size, mode, animId } = {}) {
|
package/src/browse.mjs
CHANGED
package/src/cli.mjs
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { execSync } from 'node:child_process';
|
|
2
2
|
import { createInterface } from 'node:readline';
|
|
3
|
-
import {
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { homedir } from 'node:os';
|
|
6
|
+
import { fetchFrames, fetchCharacter, fetchPngFrames, fetchGallery } from './api.mjs';
|
|
4
7
|
import { playAnimation, playCompanion, playReactiveCompanion, showFrame, playHdAnimation, detectGraphicsProtocol } from './player.mjs';
|
|
5
8
|
import { browse } from './browse.mjs';
|
|
6
9
|
import { startMcpServer } from './mcp.mjs';
|
|
@@ -111,12 +114,41 @@ function parseFlags(args) {
|
|
|
111
114
|
return { flags, positional };
|
|
112
115
|
}
|
|
113
116
|
|
|
114
|
-
const DEFAULT_CHARACTER = 3; // Zephyr
|
|
117
|
+
const DEFAULT_CHARACTER = 3; // Zephyr (fallback if server has no featured_id)
|
|
118
|
+
const CONFIG_CACHE_PATH = join(homedir(), '.storymode', 'cache', 'gallery-config.json');
|
|
119
|
+
|
|
120
|
+
/** Get the featured character ID: positional arg > cached config > fetch from server > fallback */
|
|
121
|
+
async function resolveFeaturedId() {
|
|
122
|
+
// Try cached config first
|
|
123
|
+
try {
|
|
124
|
+
if (existsSync(CONFIG_CACHE_PATH)) {
|
|
125
|
+
const cached = JSON.parse(readFileSync(CONFIG_CACHE_PATH, 'utf-8'));
|
|
126
|
+
if (cached.featured_id != null) return cached.featured_id;
|
|
127
|
+
}
|
|
128
|
+
} catch { /* ignore corrupt cache */ }
|
|
129
|
+
|
|
130
|
+
// Fetch from server and cache
|
|
131
|
+
try {
|
|
132
|
+
const gallery = await fetchGallery();
|
|
133
|
+
const cacheDir = join(homedir(), '.storymode', 'cache');
|
|
134
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
135
|
+
writeFileSync(CONFIG_CACHE_PATH, JSON.stringify({
|
|
136
|
+
featured_id: gallery.featured_id,
|
|
137
|
+
curated_ids: gallery.curated_ids,
|
|
138
|
+
}));
|
|
139
|
+
if (gallery.featured_id != null) return gallery.featured_id;
|
|
140
|
+
} catch { /* network failure — fall through */ }
|
|
141
|
+
|
|
142
|
+
return DEFAULT_CHARACTER;
|
|
143
|
+
}
|
|
115
144
|
|
|
116
145
|
export async function run(args) {
|
|
117
146
|
const cmd = args[0];
|
|
118
147
|
const { flags, positional } = parseFlags(args.slice(1));
|
|
119
|
-
|
|
148
|
+
let id = positional[0];
|
|
149
|
+
if (!id && (cmd === 'play' || cmd === 'companion')) {
|
|
150
|
+
id = await resolveFeaturedId();
|
|
151
|
+
}
|
|
120
152
|
|
|
121
153
|
switch (cmd) {
|
|
122
154
|
// --- Main command: reactive companion ---
|
package/src/mcp.mjs
CHANGED
|
@@ -47,7 +47,8 @@ function findAnimation(animations, query) {
|
|
|
47
47
|
async function handleToolCall(name, args) {
|
|
48
48
|
switch (name) {
|
|
49
49
|
case 'list_characters': {
|
|
50
|
-
const
|
|
50
|
+
const gallery = await fetchGallery();
|
|
51
|
+
const items = gallery.items;
|
|
51
52
|
if (!items.length) return 'Gallery is empty.';
|
|
52
53
|
const chars = await Promise.all(
|
|
53
54
|
items.map(item => fetchCharacter(item.id).catch(() => null))
|
package/src/player.mjs
CHANGED
|
@@ -751,10 +751,10 @@ export function detectGraphicsProtocol() {
|
|
|
751
751
|
// Map client_termname back to protocol
|
|
752
752
|
if (clientTerm === 'xterm-ghostty') return { protocol: 'kitty', inTmux };
|
|
753
753
|
if (clientTerm.includes('kitty')) return { protocol: 'kitty', inTmux };
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
754
|
+
} catch { /* tmux command failed — fall through */ }
|
|
755
|
+
// LC_TERMINAL survives tmux env overwriting (iTerm2 sets it)
|
|
756
|
+
const lcTerminal = process.env.LC_TERMINAL || '';
|
|
757
|
+
if (lcTerminal === 'iTerm2') return { protocol: 'iterm2', inTmux };
|
|
758
758
|
}
|
|
759
759
|
|
|
760
760
|
if (kittyId) return { protocol: 'kitty', inTmux };
|