compact-agent 1.31.2 → 1.32.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.
@@ -0,0 +1,44 @@
1
+ /**
2
+ * OpenRouter model catalog fetcher.
3
+ *
4
+ * GET https://openrouter.ai/api/v1/models returns the full catalog
5
+ * (300+ entries) with per-token pricing in USD. We cache the result
6
+ * for the duration of the process — the catalog only changes when
7
+ * OpenRouter adds/removes models, which is rare enough that one
8
+ * fetch per REPL session is the right trade-off.
9
+ *
10
+ * Pricing in the response is per-token; we convert to per-1M tokens
11
+ * for display because that's how everyone quotes LLM costs.
12
+ *
13
+ * No auth required for /models (it's public). We hit it without the
14
+ * user's API key so it works even before the user has finished
15
+ * configuring their key.
16
+ */
17
+ export interface OpenRouterModel {
18
+ /** Canonical model ID, e.g. "anthropic/claude-sonnet-4". */
19
+ id: string;
20
+ /** Display name, e.g. "Claude Sonnet 4". */
21
+ name: string;
22
+ /** Context window in tokens, or null if unknown. */
23
+ contextLength: number | null;
24
+ /** USD per million input tokens. */
25
+ promptPerM: number;
26
+ /** USD per million output tokens. */
27
+ completionPerM: number;
28
+ /** True when the model is free (both prompt + completion = 0). */
29
+ isFree: boolean;
30
+ }
31
+ /**
32
+ * Fetch the OpenRouter model catalog, normalized + sorted (free
33
+ * models first, then alphabetical by ID).
34
+ *
35
+ * Returns an empty array on any network / parse failure instead of
36
+ * throwing — the caller is typically the model-picker, which can
37
+ * gracefully say "couldn't fetch models" without aborting the REPL.
38
+ */
39
+ export declare function fetchOpenRouterModels(): Promise<OpenRouterModel[]>;
40
+ /**
41
+ * Format the per-million pricing as a compact column for use in
42
+ * the picker's hint field. "in:$0.14 out:$0.28 · 128k" style.
43
+ */
44
+ export declare function formatPricing(m: OpenRouterModel): string;
@@ -0,0 +1,112 @@
1
+ /**
2
+ * OpenRouter model catalog fetcher.
3
+ *
4
+ * GET https://openrouter.ai/api/v1/models returns the full catalog
5
+ * (300+ entries) with per-token pricing in USD. We cache the result
6
+ * for the duration of the process — the catalog only changes when
7
+ * OpenRouter adds/removes models, which is rare enough that one
8
+ * fetch per REPL session is the right trade-off.
9
+ *
10
+ * Pricing in the response is per-token; we convert to per-1M tokens
11
+ * for display because that's how everyone quotes LLM costs.
12
+ *
13
+ * No auth required for /models (it's public). We hit it without the
14
+ * user's API key so it works even before the user has finished
15
+ * configuring their key.
16
+ */
17
+ let _cache = null;
18
+ let _cacheAt = 0;
19
+ const CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour
20
+ /**
21
+ * Fetch the OpenRouter model catalog, normalized + sorted (free
22
+ * models first, then alphabetical by ID).
23
+ *
24
+ * Returns an empty array on any network / parse failure instead of
25
+ * throwing — the caller is typically the model-picker, which can
26
+ * gracefully say "couldn't fetch models" without aborting the REPL.
27
+ */
28
+ export async function fetchOpenRouterModels() {
29
+ // Cache hit?
30
+ if (_cache && (Date.now() - _cacheAt) < CACHE_TTL_MS) {
31
+ return _cache;
32
+ }
33
+ try {
34
+ const resp = await fetch('https://openrouter.ai/api/v1/models', {
35
+ // Quick timeout — picker is interactive, can't sit on a stuck
36
+ // request. If the network is slow the user can use /model <id>
37
+ // directly.
38
+ signal: AbortSignal.timeout(8000),
39
+ headers: { 'User-Agent': 'compact-agent/1.x' },
40
+ });
41
+ if (!resp.ok)
42
+ return [];
43
+ const json = await resp.json();
44
+ const raw = json.data ?? [];
45
+ const models = [];
46
+ for (const r of raw) {
47
+ if (!r.id)
48
+ continue;
49
+ const prompt = parsePrice(r.pricing?.prompt);
50
+ const completion = parsePrice(r.pricing?.completion);
51
+ models.push({
52
+ id: r.id,
53
+ name: r.name ?? r.id,
54
+ contextLength: typeof r.context_length === 'number' ? r.context_length : null,
55
+ promptPerM: prompt * 1_000_000,
56
+ completionPerM: completion * 1_000_000,
57
+ isFree: prompt === 0 && completion === 0,
58
+ });
59
+ }
60
+ // Sort: free first, then alphabetical by ID. Cheaper paid
61
+ // models float to the top within each group implicitly because
62
+ // ID alphabetical happens to put well-known cheap-tier vendors
63
+ // (anthropic, deepseek, google) near the top.
64
+ models.sort((a, b) => {
65
+ if (a.isFree !== b.isFree)
66
+ return a.isFree ? -1 : 1;
67
+ return a.id.localeCompare(b.id);
68
+ });
69
+ _cache = models;
70
+ _cacheAt = Date.now();
71
+ return models;
72
+ }
73
+ catch {
74
+ return [];
75
+ }
76
+ }
77
+ function parsePrice(p) {
78
+ if (p === undefined || p === null)
79
+ return 0;
80
+ if (typeof p === 'number')
81
+ return p;
82
+ const n = parseFloat(p);
83
+ return Number.isFinite(n) ? n : 0;
84
+ }
85
+ /**
86
+ * Format the per-million pricing as a compact column for use in
87
+ * the picker's hint field. "in:$0.14 out:$0.28 · 128k" style.
88
+ */
89
+ export function formatPricing(m) {
90
+ if (m.isFree) {
91
+ return `FREE · ${formatCtx(m.contextLength)}`;
92
+ }
93
+ return `in:$${formatPrice(m.promptPerM)} out:$${formatPrice(m.completionPerM)} · ${formatCtx(m.contextLength)}`;
94
+ }
95
+ function formatPrice(n) {
96
+ // Sub-$1: show two decimals. $1+: show one or whole-dollar.
97
+ if (n < 1)
98
+ return n.toFixed(2);
99
+ if (n < 10)
100
+ return n.toFixed(1);
101
+ return n.toFixed(0);
102
+ }
103
+ function formatCtx(ctx) {
104
+ if (!ctx)
105
+ return '?';
106
+ if (ctx >= 1_000_000)
107
+ return `${(ctx / 1_000_000).toFixed(1)}M`;
108
+ if (ctx >= 1_000)
109
+ return `${Math.round(ctx / 1_000)}k`;
110
+ return String(ctx);
111
+ }
112
+ //# sourceMappingURL=openrouter-models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openrouter-models.js","sourceRoot":"","sources":["../src/openrouter-models.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ export interface PickerItem<T = string> {
2
+ /** The line shown to the user. Plain text — no ANSI codes. */
3
+ label: string;
4
+ /** Optional right-aligned hint (e.g. pricing, key combo). */
5
+ hint?: string;
6
+ /** Optional second line under the label (e.g. description). */
7
+ description?: string;
8
+ /** The value returned when this item is selected. */
9
+ value: T;
10
+ }
11
+ export interface PickerOptions {
12
+ /** Title shown at the top of the picker. */
13
+ title?: string;
14
+ /** Footer hint about what's happening (overrides default). */
15
+ footer?: string;
16
+ /**
17
+ * Filtering: when true (default), the user can type to narrow the
18
+ * list. Set to false for pickers where you want pure navigation
19
+ * (rare).
20
+ */
21
+ filterable?: boolean;
22
+ }
23
+ /**
24
+ * Show the picker and resolve with the user's selection (or null
25
+ * on cancel). Restores terminal state cleanly on either path.
26
+ */
27
+ export declare function pick<T>(items: PickerItem<T>[], opts?: PickerOptions): Promise<T | null>;
package/dist/picker.js ADDED
@@ -0,0 +1,225 @@
1
+ /**
2
+ * Terminal list picker — an interactive arrow-key navigation widget
3
+ * that takes over the screen briefly, lets the user filter + select
4
+ * from a list, and returns the chosen value (or null on cancel).
5
+ *
6
+ * Design choice: alt-screen, not inline.
7
+ *
8
+ * Inline pickers (write a list below the cursor, redraw on each
9
+ * keystroke) are simpler to implement but fragile — they break when
10
+ * the terminal scrolls, when the live-queue scroll-region is active,
11
+ * or when items overflow the visible rows. The alt-screen pattern
12
+ * (`\x1b[?1049h` / `\x1b[?1049l`) is what `git diff --interactive`,
13
+ * `less`, `vim`, and `fzf` all use: switch to a fresh screen buffer,
14
+ * render the picker as a full-screen widget, exit back to the normal
15
+ * screen with the original contents intact.
16
+ *
17
+ * Trade-off: the user briefly loses sight of the surrounding REPL
18
+ * output during selection. In exchange, the picker is robust against
19
+ * any terminal state — it can be invoked from any point in the chat
20
+ * without coordinating with the live queue, current prompt, scroll
21
+ * position, etc.
22
+ *
23
+ * Key handling: bytes parsed from raw stdin. Recognized:
24
+ * Arrow Up / Down move selection
25
+ * Page Up / Down move 10 at a time
26
+ * Home / End jump to first / last
27
+ * Enter select current item
28
+ * Esc cancel (returns null)
29
+ * Ctrl+C cancel (returns null)
30
+ * Backspace delete last filter char
31
+ * Printable ASCII append to filter, reset selection to 0
32
+ *
33
+ * Returns the `value` field of the chosen item, or null if cancelled.
34
+ */
35
+ import { stdin, stdout } from 'node:process';
36
+ // ANSI control sequences. Centralized so the rendering loop stays
37
+ // readable.
38
+ const ANSI = {
39
+ altScreenOn: '\x1b[?1049h',
40
+ altScreenOff: '\x1b[?1049l',
41
+ cursorHide: '\x1b[?25l',
42
+ cursorShow: '\x1b[?25h',
43
+ clearScreen: '\x1b[2J\x1b[H',
44
+ reverse: '\x1b[7m',
45
+ dim: '\x1b[2m',
46
+ bold: '\x1b[1m',
47
+ reset: '\x1b[0m',
48
+ };
49
+ /**
50
+ * Show the picker and resolve with the user's selection (or null
51
+ * on cancel). Restores terminal state cleanly on either path.
52
+ */
53
+ export async function pick(items, opts = {}) {
54
+ if (items.length === 0)
55
+ return null;
56
+ return new Promise((resolve) => {
57
+ let filter = '';
58
+ let selected = 0;
59
+ const wasRaw = stdin.isRaw;
60
+ const filterable = opts.filterable !== false;
61
+ function visibleItems() {
62
+ if (!filter)
63
+ return items;
64
+ const f = filter.toLowerCase();
65
+ return items.filter((i) => i.label.toLowerCase().includes(f) ||
66
+ (i.description ?? '').toLowerCase().includes(f) ||
67
+ (i.hint ?? '').toLowerCase().includes(f));
68
+ }
69
+ function render() {
70
+ const visible = visibleItems();
71
+ if (visible.length === 0) {
72
+ selected = 0;
73
+ }
74
+ else if (selected >= visible.length) {
75
+ selected = visible.length - 1;
76
+ }
77
+ stdout.write(ANSI.clearScreen);
78
+ // Title row.
79
+ if (opts.title) {
80
+ stdout.write(`${ANSI.bold} ${opts.title}${ANSI.reset}\n`);
81
+ }
82
+ // Filter row. The trailing ▮ is a visible cursor since we hid
83
+ // the real one (reduces flicker on each render).
84
+ if (filterable) {
85
+ stdout.write(` ${ANSI.dim}filter:${ANSI.reset} ${filter}${ANSI.dim}▮${ANSI.reset}\n`);
86
+ }
87
+ stdout.write('\n');
88
+ // Item list. Window around the selection so we always show
89
+ // the selected row even with hundreds of items. Reserve ~5
90
+ // rows for header + footer.
91
+ const termRows = stdout.rows || 24;
92
+ const itemSlot = Math.max(5, termRows - 7);
93
+ const startIdx = Math.max(0, selected - Math.floor(itemSlot / 2));
94
+ const endIdx = Math.min(visible.length, startIdx + itemSlot);
95
+ for (let i = startIdx; i < endIdx; i++) {
96
+ const item = visible[i];
97
+ const isSel = i === selected;
98
+ const hint = item.hint ? ` ${ANSI.dim}${item.hint}${ANSI.reset}` : '';
99
+ const prefix = isSel ? `${ANSI.reverse} ▸ ` : ' ';
100
+ const suffix = isSel ? `${ANSI.reset}` : '';
101
+ stdout.write(`${prefix}${item.label}${suffix}${hint}\n`);
102
+ if (item.description) {
103
+ const descPrefix = isSel ? `${ANSI.reverse} ` : ' ';
104
+ stdout.write(`${descPrefix}${ANSI.dim}${item.description}${ANSI.reset}${suffix}\n`);
105
+ }
106
+ }
107
+ if (visible.length === 0) {
108
+ stdout.write(` ${ANSI.dim}(no matches — Backspace to clear filter, Esc to cancel)${ANSI.reset}\n`);
109
+ }
110
+ // Footer.
111
+ stdout.write('\n');
112
+ const footerText = opts.footer ??
113
+ `${visible.length}/${items.length} • ↑↓ navigate • Enter select • Esc cancel${filterable ? ' • type to filter' : ''}`;
114
+ stdout.write(` ${ANSI.dim}${footerText}${ANSI.reset}\n`);
115
+ }
116
+ function cleanup() {
117
+ stdin.removeListener('data', onData);
118
+ try {
119
+ stdin.setRawMode(wasRaw);
120
+ }
121
+ catch { /* noop */ }
122
+ stdout.write(ANSI.cursorShow);
123
+ stdout.write(ANSI.altScreenOff);
124
+ }
125
+ function onData(buf) {
126
+ const visible = visibleItems();
127
+ // Ctrl+C — cancel. Has to win over everything else.
128
+ if (buf.length === 1 && buf[0] === 0x03) {
129
+ cleanup();
130
+ resolve(null);
131
+ return;
132
+ }
133
+ // Esc — cancel. But Esc is also the start byte of ANSI escape
134
+ // sequences (arrows, function keys), so only bare Esc (single
135
+ // byte) counts as a cancel. Arrows arrive as a 3+ byte chunk.
136
+ if (buf.length === 1 && buf[0] === 0x1B) {
137
+ cleanup();
138
+ resolve(null);
139
+ return;
140
+ }
141
+ // Enter (CR or LF).
142
+ if (buf.length === 1 && (buf[0] === 0x0D || buf[0] === 0x0A)) {
143
+ if (visible.length === 0)
144
+ return;
145
+ const chosen = visible[selected];
146
+ cleanup();
147
+ resolve(chosen ? chosen.value : null);
148
+ return;
149
+ }
150
+ // Backspace (DEL 0x7F on POSIX, BS 0x08 on Windows).
151
+ if (buf.length === 1 && (buf[0] === 0x7F || buf[0] === 0x08)) {
152
+ if (filterable && filter.length > 0) {
153
+ filter = filter.slice(0, -1);
154
+ selected = 0;
155
+ render();
156
+ }
157
+ return;
158
+ }
159
+ // Arrow keys arrive as `Esc [ <code>` (typically 3 bytes).
160
+ // Page Up / Down arrive as `Esc [ 5 ~` / `Esc [ 6 ~`.
161
+ // Home / End vary: `Esc [ H`, `Esc [ F`, or `Esc [ 1 ~` / `Esc [ 4 ~`.
162
+ if (buf.length >= 3 && buf[0] === 0x1B && buf[1] === 0x5B) {
163
+ const code = buf[2];
164
+ if (code === 0x41) { // Up
165
+ if (visible.length > 0)
166
+ selected = (selected - 1 + visible.length) % visible.length;
167
+ render();
168
+ return;
169
+ }
170
+ if (code === 0x42) { // Down
171
+ if (visible.length > 0)
172
+ selected = (selected + 1) % visible.length;
173
+ render();
174
+ return;
175
+ }
176
+ if (code === 0x48) { // Home
177
+ selected = 0;
178
+ render();
179
+ return;
180
+ }
181
+ if (code === 0x46) { // End
182
+ selected = Math.max(0, visible.length - 1);
183
+ render();
184
+ return;
185
+ }
186
+ if (buf.length >= 4 && (code === 0x35 || code === 0x36) && buf[3] === 0x7E) {
187
+ // Page Up (5~) / Page Down (6~) — move by 10.
188
+ const step = code === 0x35 ? -10 : 10;
189
+ if (visible.length > 0) {
190
+ selected = Math.max(0, Math.min(visible.length - 1, selected + step));
191
+ }
192
+ render();
193
+ return;
194
+ }
195
+ // Unknown escape sequence — ignore.
196
+ return;
197
+ }
198
+ // Otherwise: treat as filter input, but only printable ASCII.
199
+ // Multi-byte UTF-8 entry (e.g. paste) gets appended as the
200
+ // string it represents; the regex check keeps control bytes
201
+ // out.
202
+ if (filterable) {
203
+ const s = buf.toString('utf-8');
204
+ // Allow printable ASCII + extended ranges; reject control
205
+ // chars + the escape we already handled.
206
+ if (/^[\x20-\x7E -￿]+$/.test(s)) {
207
+ filter += s;
208
+ selected = 0;
209
+ render();
210
+ }
211
+ }
212
+ }
213
+ // Enter the picker.
214
+ stdout.write(ANSI.altScreenOn);
215
+ stdout.write(ANSI.cursorHide);
216
+ try {
217
+ stdin.setRawMode(true);
218
+ }
219
+ catch { /* noop */ }
220
+ stdin.on('data', onData);
221
+ stdin.resume();
222
+ render();
223
+ });
224
+ }
225
+ //# sourceMappingURL=picker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"picker.js","sourceRoot":"","sources":["../src/picker.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "compact-agent",
3
- "version": "1.31.2",
3
+ "version": "1.32.0",
4
4
  "description": "Terminal AI coding CLI. Speaks any OpenAI-compatible API (OpenRouter, OpenAI, NVIDIA, Ollama, LM Studio, DeepSeek). Modes, slash commands, multi-agent swarming, key-rotation pool, optional voice + screen-reader, sandbox + permission gates, persistent input box, bundled everything-claude-code skills.",
5
5
  "type": "module",
6
6
  "license": "MIT",