claude-remote-cli 3.0.3 → 3.0.4

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.
@@ -1,93 +1,260 @@
1
+ import pty from 'node-pty';
1
2
  import crypto from 'node:crypto';
2
3
  import fs from 'node:fs';
4
+ import os from 'node:os';
3
5
  import path from 'node:path';
4
6
  import { execFile } from 'node:child_process';
5
7
  import { promisify } from 'node:util';
6
- import { AGENT_COMMANDS, AGENT_CONTINUE_ARGS, AGENT_YOLO_ARGS } from './types.js';
7
- import { createPtySession } from './pty-handler.js';
8
- import { createSdkSession, killSdkSession, sendMessage as sdkSendMessage, handlePermission as sdkHandlePermission, serializeSdkSession, restoreSdkSession } from './sdk-handler.js';
8
+ import { readMeta, writeMeta } from './config.js';
9
9
  const execFileAsync = promisify(execFile);
10
+ const AGENT_COMMANDS = {
11
+ claude: 'claude',
12
+ codex: 'codex',
13
+ };
14
+ const AGENT_CONTINUE_ARGS = {
15
+ claude: ['--continue'],
16
+ codex: ['resume', '--last'],
17
+ };
18
+ const AGENT_YOLO_ARGS = {
19
+ claude: ['--dangerously-skip-permissions'],
20
+ codex: ['--full-auto'],
21
+ };
10
22
  const STALE_THRESHOLD_MS = 5 * 60 * 1000; // 5 minutes
11
- const SDK_IDLE_CHECK_INTERVAL_MS = 60 * 1000; // 60 seconds
12
- const SDK_MAX_IDLE_MS = 30 * 60 * 1000; // 30 minutes
13
- const SDK_MAX_IDLE_SESSIONS = 5;
23
+ function generateTmuxSessionName(displayName, id) {
24
+ const sanitized = displayName.replace(/[^a-zA-Z0-9-]/g, '-').replace(/-+/g, '-').slice(0, 30);
25
+ return `crc-${sanitized}-${id.slice(0, 8)}`;
26
+ }
27
+ function resolveTmuxSpawn(command, args, tmuxSessionName) {
28
+ return {
29
+ command: 'tmux',
30
+ args: [
31
+ '-u', 'new-session', '-s', tmuxSessionName, '--', command, ...args,
32
+ // ';' tokens are tmux command separators — parsed at the top level before
33
+ // dispatching to new-session, not passed as argv to `command`.
34
+ ';', 'set', 'set-clipboard', 'on',
35
+ ';', 'set', 'allow-passthrough', 'on',
36
+ ';', 'set', 'mode-keys', 'vi',
37
+ ],
38
+ };
39
+ }
14
40
  // In-memory registry: id -> Session
15
41
  const sessions = new Map();
42
+ const IDLE_TIMEOUT_MS = 5000;
16
43
  let terminalCounter = 0;
17
44
  const idleChangeCallbacks = [];
18
45
  function onIdleChange(cb) {
19
46
  idleChangeCallbacks.push(cb);
20
47
  }
21
- function create({ id: providedId, type, agent = 'claude', repoName, repoPath, cwd, root, worktreeName, branchName, displayName, command, args = [], cols = 80, rows = 24, configPath, useTmux: paramUseTmux, tmuxSessionName: paramTmuxSessionName, initialScrollback, restored: paramRestored }) {
48
+ function create({ id: providedId, type, agent = 'claude', repoName, repoPath, cwd, root, worktreeName, branchName, displayName, command, args = [], cols = 80, rows = 24, configPath, useTmux: paramUseTmux, tmuxSessionName: paramTmuxSessionName, initialScrollback, restored: paramRestored, needsBranchRename: paramNeedsBranchRename, branchRenamePrompt: paramBranchRenamePrompt }) {
22
49
  const id = providedId || crypto.randomBytes(8).toString('hex');
23
- // Dispatch: if agent is claude, no custom command, try SDK first
24
- if (agent === 'claude' && !command) {
25
- const sdkResult = createSdkSession({
26
- id,
27
- type,
28
- agent,
29
- repoName,
30
- repoPath,
31
- cwd,
32
- root,
33
- worktreeName,
34
- branchName,
35
- displayName,
36
- }, sessions, idleChangeCallbacks);
37
- if (!('fallback' in sdkResult)) {
38
- return { ...sdkResult.result, pid: undefined };
39
- }
40
- // SDK init failed — fall through to PTY
50
+ const createdAt = new Date().toISOString();
51
+ const resolvedCommand = command || AGENT_COMMANDS[agent];
52
+ // Strip CLAUDECODE env var to allow spawning claude inside a claude-managed server
53
+ const env = Object.assign({}, process.env);
54
+ delete env.CLAUDECODE;
55
+ const useTmux = !command && !!paramUseTmux;
56
+ let spawnCommand = resolvedCommand;
57
+ let spawnArgs = args;
58
+ const tmuxSessionName = paramTmuxSessionName || (useTmux ? generateTmuxSessionName(displayName || repoName || 'session', id) : '');
59
+ if (useTmux) {
60
+ const tmux = resolveTmuxSpawn(resolvedCommand, args, tmuxSessionName);
61
+ spawnCommand = tmux.command;
62
+ spawnArgs = tmux.args;
41
63
  }
42
- // PTY path: codex, terminal, custom command, or SDK fallback
43
- const ptyParams = {
64
+ // Wrap the spawn command to trap SIGPIPE in the child shell.
65
+ // Without this, piped bash commands (e.g. `cmd | grep | tail`) run by
66
+ // Claude Code inside the PTY can generate SIGPIPE when the reading end
67
+ // of the pipe closes, which propagates up and kills the PTY session.
68
+ // Wrapping with `trap '' PIPE; exec ...` makes the shell ignore SIGPIPE
69
+ // before exec'ing the agent, so the agent inherits SIG_IGN for PIPE.
70
+ const wrappedCommand = '/bin/bash';
71
+ const wrappedArgs = ['-c', `trap '' PIPE; exec ${spawnCommand} ${spawnArgs.map(a => `'${a.replace(/'/g, "'\\''")}'`).join(' ')}`];
72
+ const ptyProcess = pty.spawn(wrappedCommand, wrappedArgs, {
73
+ name: 'xterm-256color',
74
+ cols,
75
+ rows,
76
+ cwd: cwd || repoPath,
77
+ env,
78
+ });
79
+ // Scrollback buffer: stores all PTY output so we can replay on WebSocket (re)connect
80
+ const scrollback = initialScrollback ? [...initialScrollback] : [];
81
+ let scrollbackBytes = initialScrollback ? initialScrollback.reduce((sum, s) => sum + s.length, 0) : 0;
82
+ const MAX_SCROLLBACK = 256 * 1024; // 256KB max
83
+ const resolvedCwd = cwd || repoPath;
84
+ const session = {
44
85
  id,
45
- type,
86
+ type: type || 'worktree',
46
87
  agent,
47
- repoName,
88
+ root: root || '',
89
+ repoName: repoName || '',
48
90
  repoPath,
49
- cwd,
50
- root,
51
- worktreeName,
52
- branchName,
53
- displayName,
54
- command,
55
- args,
56
- cols,
57
- rows,
58
- configPath,
59
- useTmux: paramUseTmux,
60
- tmuxSessionName: paramTmuxSessionName,
61
- initialScrollback,
62
- restored: paramRestored,
91
+ worktreeName: worktreeName || '',
92
+ branchName: branchName || worktreeName || '',
93
+ displayName: displayName || worktreeName || repoName || '',
94
+ pty: ptyProcess,
95
+ createdAt,
96
+ lastActivity: createdAt,
97
+ scrollback,
98
+ idle: false,
99
+ cwd: resolvedCwd,
100
+ customCommand: command || null,
101
+ useTmux,
102
+ tmuxSessionName,
103
+ onPtyReplacedCallbacks: [],
104
+ status: 'active',
105
+ restored: paramRestored || false,
106
+ needsBranchRename: paramNeedsBranchRename || false,
107
+ branchRenamePrompt: paramBranchRenamePrompt || '',
63
108
  };
64
- const { result } = createPtySession(ptyParams, sessions, idleChangeCallbacks);
65
- return result;
109
+ sessions.set(id, session);
110
+ // Load existing metadata to preserve a previously-set displayName
111
+ if (configPath && worktreeName) {
112
+ const existing = readMeta(configPath, repoPath);
113
+ if (existing && existing.displayName) {
114
+ session.displayName = existing.displayName;
115
+ }
116
+ writeMeta(configPath, { worktreePath: repoPath, displayName: session.displayName, lastActivity: createdAt });
117
+ }
118
+ let metaFlushTimer = null;
119
+ let idleTimer = null;
120
+ function resetIdleTimer() {
121
+ if (session.idle) {
122
+ session.idle = false;
123
+ for (const cb of idleChangeCallbacks)
124
+ cb(session.id, false);
125
+ }
126
+ if (idleTimer)
127
+ clearTimeout(idleTimer);
128
+ idleTimer = setTimeout(() => {
129
+ if (!session.idle) {
130
+ session.idle = true;
131
+ for (const cb of idleChangeCallbacks)
132
+ cb(session.id, true);
133
+ }
134
+ }, IDLE_TIMEOUT_MS);
135
+ }
136
+ const continueArgs = AGENT_CONTINUE_ARGS[agent];
137
+ function attachHandlers(proc, canRetry) {
138
+ const spawnTime = Date.now();
139
+ // Clear restored flag after 3s of running — means the PTY is healthy
140
+ const restoredClearTimer = session.restored ? setTimeout(() => { session.restored = false; }, 3000) : null;
141
+ proc.onData((data) => {
142
+ session.lastActivity = new Date().toISOString();
143
+ resetIdleTimer();
144
+ scrollback.push(data);
145
+ scrollbackBytes += data.length;
146
+ // Trim oldest entries if over limit
147
+ while (scrollbackBytes > MAX_SCROLLBACK && scrollback.length > 1) {
148
+ scrollbackBytes -= scrollback.shift().length;
149
+ }
150
+ if (configPath && worktreeName && !metaFlushTimer) {
151
+ metaFlushTimer = setTimeout(() => {
152
+ metaFlushTimer = null;
153
+ writeMeta(configPath, { worktreePath: repoPath, displayName: session.displayName, lastActivity: session.lastActivity });
154
+ }, 5000);
155
+ }
156
+ });
157
+ proc.onExit(() => {
158
+ // If continue args failed quickly, retry without them.
159
+ // Exit code is intentionally not checked: tmux wrapping exits 0 even
160
+ // when the inner command (e.g. claude --continue) fails, because the
161
+ // tmux client doesn't propagate inner exit codes. The 3-second window
162
+ // is the primary heuristic — no user quits a session that fast.
163
+ if (canRetry && (Date.now() - spawnTime) < 3000) {
164
+ const retryArgs = args.filter(a => !continueArgs.includes(a));
165
+ const retryNotice = '\r\n[claude-remote-cli] --continue not available; starting new session...\r\n';
166
+ scrollback.length = 0;
167
+ scrollbackBytes = 0;
168
+ scrollback.push(retryNotice);
169
+ scrollbackBytes = retryNotice.length;
170
+ let retryCommand = resolvedCommand;
171
+ let retrySpawnArgs = retryArgs;
172
+ if (useTmux && tmuxSessionName) {
173
+ const retryTmuxName = tmuxSessionName + '-retry';
174
+ session.tmuxSessionName = retryTmuxName;
175
+ const tmux = resolveTmuxSpawn(resolvedCommand, retryArgs, retryTmuxName);
176
+ retryCommand = tmux.command;
177
+ retrySpawnArgs = tmux.args;
178
+ }
179
+ let retryPty;
180
+ try {
181
+ // Wrap retry spawn with SIGPIPE trap (same as initial spawn)
182
+ const retryWrapped = ['-c', `trap '' PIPE; exec ${retryCommand} ${retrySpawnArgs.map(a => `'${a.replace(/'/g, "'\\''")}'`).join(' ')}`];
183
+ retryPty = pty.spawn('/bin/bash', retryWrapped, {
184
+ name: 'xterm-256color',
185
+ cols,
186
+ rows,
187
+ cwd: cwd || repoPath,
188
+ env,
189
+ });
190
+ }
191
+ catch {
192
+ // Retry spawn failed — fall through to normal exit cleanup
193
+ if (restoredClearTimer)
194
+ clearTimeout(restoredClearTimer);
195
+ if (idleTimer)
196
+ clearTimeout(idleTimer);
197
+ if (metaFlushTimer)
198
+ clearTimeout(metaFlushTimer);
199
+ sessions.delete(id);
200
+ return;
201
+ }
202
+ session.pty = retryPty;
203
+ for (const cb of session.onPtyReplacedCallbacks)
204
+ cb(retryPty);
205
+ attachHandlers(retryPty, false);
206
+ return;
207
+ }
208
+ if (restoredClearTimer)
209
+ clearTimeout(restoredClearTimer);
210
+ // If PTY exited and this is a restored session, mark disconnected rather than delete
211
+ if (session.restored) {
212
+ session.status = 'disconnected';
213
+ session.restored = false; // clear so user-initiated kills can delete normally
214
+ if (idleTimer)
215
+ clearTimeout(idleTimer);
216
+ if (metaFlushTimer)
217
+ clearTimeout(metaFlushTimer);
218
+ return;
219
+ }
220
+ if (idleTimer)
221
+ clearTimeout(idleTimer);
222
+ if (metaFlushTimer)
223
+ clearTimeout(metaFlushTimer);
224
+ if (configPath && worktreeName) {
225
+ writeMeta(configPath, { worktreePath: repoPath, displayName: session.displayName, lastActivity: session.lastActivity });
226
+ }
227
+ sessions.delete(id);
228
+ const tmpDir = path.join(os.tmpdir(), 'claude-remote-cli', id);
229
+ fs.rm(tmpDir, { recursive: true, force: true }, () => { });
230
+ });
231
+ }
232
+ attachHandlers(ptyProcess, continueArgs.some(a => args.includes(a)));
233
+ return { id, type: session.type, agent: session.agent, root: session.root, repoName: session.repoName, repoPath, worktreeName: session.worktreeName, branchName: session.branchName, displayName: session.displayName, pid: ptyProcess.pid, createdAt, lastActivity: createdAt, idle: false, cwd: resolvedCwd, customCommand: command || null, useTmux, tmuxSessionName, status: 'active' };
66
234
  }
67
235
  function get(id) {
68
236
  return sessions.get(id);
69
237
  }
70
238
  function list() {
71
239
  return Array.from(sessions.values())
72
- .map((s) => ({
73
- id: s.id,
74
- type: s.type,
75
- agent: s.agent,
76
- mode: s.mode,
77
- root: s.root,
78
- repoName: s.repoName,
79
- repoPath: s.repoPath,
80
- worktreeName: s.worktreeName,
81
- branchName: s.branchName,
82
- displayName: s.displayName,
83
- createdAt: s.createdAt,
84
- lastActivity: s.lastActivity,
85
- idle: s.idle,
86
- cwd: s.cwd,
87
- customCommand: s.customCommand,
88
- useTmux: s.mode === 'pty' ? s.useTmux : false,
89
- tmuxSessionName: s.mode === 'pty' ? s.tmuxSessionName : '',
90
- status: s.status,
240
+ .map(({ id, type, agent, root, repoName, repoPath, worktreeName, branchName, displayName, createdAt, lastActivity, idle, cwd, customCommand, useTmux, tmuxSessionName, status }) => ({
241
+ id,
242
+ type,
243
+ agent,
244
+ root,
245
+ repoName,
246
+ repoPath,
247
+ worktreeName,
248
+ branchName,
249
+ displayName,
250
+ createdAt,
251
+ lastActivity,
252
+ idle,
253
+ cwd,
254
+ customCommand,
255
+ useTmux,
256
+ tmuxSessionName,
257
+ status,
91
258
  }))
92
259
  .sort((a, b) => b.lastActivity.localeCompare(a.lastActivity));
93
260
  }
@@ -103,25 +270,20 @@ function kill(id) {
103
270
  if (!session) {
104
271
  throw new Error(`Session not found: ${id}`);
105
272
  }
106
- if (session.mode === 'pty') {
107
- try {
108
- session.pty.kill('SIGTERM');
109
- }
110
- catch {
111
- // PTY may already be dead (e.g. disconnected sessions) — still delete from registry
112
- }
113
- if (session.tmuxSessionName) {
114
- execFile('tmux', ['kill-session', '-t', session.tmuxSessionName], () => { });
115
- }
273
+ try {
274
+ session.pty.kill('SIGTERM');
116
275
  }
117
- else if (session.mode === 'sdk') {
118
- killSdkSession(id);
276
+ catch {
277
+ // PTY may already be dead (e.g. disconnected sessions) — still delete from registry
278
+ }
279
+ if (session.tmuxSessionName) {
280
+ execFile('tmux', ['kill-session', '-t', session.tmuxSessionName], () => { });
119
281
  }
120
282
  sessions.delete(id);
121
283
  }
122
284
  function killAllTmuxSessions() {
123
285
  for (const session of sessions.values()) {
124
- if (session.mode === 'pty' && session.tmuxSessionName) {
286
+ if (session.tmuxSessionName) {
125
287
  execFile('tmux', ['kill-session', '-t', session.tmuxSessionName], () => { });
126
288
  }
127
289
  }
@@ -131,25 +293,14 @@ function resize(id, cols, rows) {
131
293
  if (!session) {
132
294
  throw new Error(`Session not found: ${id}`);
133
295
  }
134
- if (session.mode === 'pty') {
135
- session.pty.resize(cols, rows);
136
- }
137
- // SDK sessions don't support resize (no PTY)
296
+ session.pty.resize(cols, rows);
138
297
  }
139
298
  function write(id, data) {
140
299
  const session = sessions.get(id);
141
300
  if (!session) {
142
301
  throw new Error(`Session not found: ${id}`);
143
302
  }
144
- if (session.mode === 'pty') {
145
- session.pty.write(data);
146
- }
147
- else if (session.mode === 'sdk') {
148
- sdkSendMessage(id, data);
149
- }
150
- }
151
- function handlePermission(id, requestId, approved) {
152
- sdkHandlePermission(id, requestId, approved);
303
+ session.pty.write(data);
153
304
  }
154
305
  function findRepoSession(repoPath) {
155
306
  return list().find((s) => s.type === 'repo' && s.repoPath === repoPath);
@@ -160,40 +311,33 @@ function nextTerminalName() {
160
311
  function serializeAll(configDir) {
161
312
  const scrollbackDirPath = path.join(configDir, 'scrollback');
162
313
  fs.mkdirSync(scrollbackDirPath, { recursive: true });
163
- const serializedPty = [];
164
- const serializedSdk = [];
314
+ const serialized = [];
165
315
  for (const session of sessions.values()) {
166
- if (session.mode === 'pty') {
167
- // Write scrollback to disk
168
- const scrollbackPath = path.join(scrollbackDirPath, session.id + '.buf');
169
- fs.writeFileSync(scrollbackPath, session.scrollback.join(''), 'utf-8');
170
- serializedPty.push({
171
- id: session.id,
172
- type: session.type,
173
- agent: session.agent,
174
- root: session.root,
175
- repoName: session.repoName,
176
- repoPath: session.repoPath,
177
- worktreeName: session.worktreeName,
178
- branchName: session.branchName,
179
- displayName: session.displayName,
180
- createdAt: session.createdAt,
181
- lastActivity: session.lastActivity,
182
- useTmux: session.useTmux,
183
- tmuxSessionName: session.tmuxSessionName,
184
- customCommand: session.customCommand,
185
- cwd: session.cwd,
186
- });
187
- }
188
- else if (session.mode === 'sdk') {
189
- serializedSdk.push(serializeSdkSession(session));
190
- }
316
+ // Write scrollback to disk
317
+ const scrollbackPath = path.join(scrollbackDirPath, session.id + '.buf');
318
+ fs.writeFileSync(scrollbackPath, session.scrollback.join(''), 'utf-8');
319
+ serialized.push({
320
+ id: session.id,
321
+ type: session.type,
322
+ agent: session.agent,
323
+ root: session.root,
324
+ repoName: session.repoName,
325
+ repoPath: session.repoPath,
326
+ worktreeName: session.worktreeName,
327
+ branchName: session.branchName,
328
+ displayName: session.displayName,
329
+ createdAt: session.createdAt,
330
+ lastActivity: session.lastActivity,
331
+ useTmux: session.useTmux,
332
+ tmuxSessionName: session.tmuxSessionName,
333
+ customCommand: session.customCommand,
334
+ cwd: session.cwd,
335
+ });
191
336
  }
192
337
  const pending = {
193
338
  version: 1,
194
339
  timestamp: new Date().toISOString(),
195
- sessions: serializedPty,
196
- sdkSessions: serializedSdk.length > 0 ? serializedSdk : undefined,
340
+ sessions: serialized,
197
341
  };
198
342
  fs.writeFileSync(path.join(configDir, 'pending-sessions.json'), JSON.stringify(pending, null, 2), 'utf-8');
199
343
  }
@@ -216,7 +360,6 @@ async function restoreFromDisk(configDir) {
216
360
  }
217
361
  const scrollbackDirPath = path.join(configDir, 'scrollback');
218
362
  let restored = 0;
219
- // Restore PTY sessions
220
363
  for (const s of pending.sessions) {
221
364
  // Load scrollback from disk
222
365
  let initialScrollback;
@@ -293,18 +436,6 @@ async function restoreFromDisk(configDir) {
293
436
  }
294
437
  catch { /* ignore */ }
295
438
  }
296
- // Restore SDK sessions (as disconnected — they can't resume a live process)
297
- if (pending.sdkSessions) {
298
- for (const sdkData of pending.sdkSessions) {
299
- try {
300
- restoreSdkSession(sdkData, sessions);
301
- restored++;
302
- }
303
- catch {
304
- console.error(`Failed to restore SDK session ${sdkData.id} (${sdkData.displayName})`);
305
- }
306
- }
307
- }
308
439
  // Clean up
309
440
  try {
310
441
  fs.unlinkSync(pendingPath);
@@ -320,55 +451,9 @@ async function restoreFromDisk(configDir) {
320
451
  function activeTmuxSessionNames() {
321
452
  const names = new Set();
322
453
  for (const session of sessions.values()) {
323
- if (session.mode === 'pty' && session.tmuxSessionName)
454
+ if (session.tmuxSessionName)
324
455
  names.add(session.tmuxSessionName);
325
456
  }
326
457
  return names;
327
458
  }
328
- // SDK idle sweep: check every 60s, terminate SDK sessions idle > 30min, max 5 idle
329
- let sdkIdleSweepTimer = null;
330
- function startSdkIdleSweep() {
331
- if (sdkIdleSweepTimer)
332
- return;
333
- sdkIdleSweepTimer = setInterval(() => {
334
- const now = Date.now();
335
- const sdkSessions = [];
336
- for (const session of sessions.values()) {
337
- if (session.mode === 'sdk') {
338
- sdkSessions.push(session);
339
- }
340
- }
341
- // Terminate sessions idle > 30 minutes
342
- for (const session of sdkSessions) {
343
- const lastActivity = new Date(session.lastActivity).getTime();
344
- if (session.idle && (now - lastActivity) > SDK_MAX_IDLE_MS) {
345
- console.log(`SDK idle sweep: terminating session ${session.id} (${session.displayName}) — idle for ${Math.round((now - lastActivity) / 60000)}min`);
346
- try {
347
- kill(session.id);
348
- }
349
- catch { /* already dead */ }
350
- }
351
- }
352
- // LRU eviction: if more than 5 idle SDK sessions remain, evict oldest
353
- const idleSdkSessions = Array.from(sessions.values())
354
- .filter((s) => s.mode === 'sdk' && s.idle)
355
- .sort((a, b) => a.lastActivity.localeCompare(b.lastActivity));
356
- while (idleSdkSessions.length > SDK_MAX_IDLE_SESSIONS) {
357
- const oldest = idleSdkSessions.shift();
358
- console.log(`SDK idle sweep: evicting session ${oldest.id} (${oldest.displayName}) — LRU`);
359
- try {
360
- kill(oldest.id);
361
- }
362
- catch { /* already dead */ }
363
- }
364
- }, SDK_IDLE_CHECK_INTERVAL_MS);
365
- }
366
- function stopSdkIdleSweep() {
367
- if (sdkIdleSweepTimer) {
368
- clearInterval(sdkIdleSweepTimer);
369
- sdkIdleSweepTimer = null;
370
- }
371
- }
372
- // Re-export pty-handler utilities for backward compatibility
373
- export { generateTmuxSessionName, resolveTmuxSpawn } from './pty-handler.js';
374
- export { create, get, list, kill, killAllTmuxSessions, resize, updateDisplayName, write, handlePermission, onIdleChange, findRepoSession, nextTerminalName, serializeAll, restoreFromDisk, activeTmuxSessionNames, startSdkIdleSweep, stopSdkIdleSweep, AGENT_COMMANDS, AGENT_CONTINUE_ARGS, AGENT_YOLO_ARGS };
459
+ export { create, get, list, kill, killAllTmuxSessions, resize, updateDisplayName, write, onIdleChange, findRepoSession, nextTerminalName, serializeAll, restoreFromDisk, activeTmuxSessionNames, AGENT_COMMANDS, AGENT_CONTINUE_ARGS, AGENT_YOLO_ARGS, resolveTmuxSpawn, generateTmuxSessionName };
@@ -1,13 +1,7 @@
1
- // Agent command records (shared by PTY and SDK handlers)
2
- export const AGENT_COMMANDS = {
3
- claude: 'claude',
4
- codex: 'codex',
5
- };
6
- export const AGENT_CONTINUE_ARGS = {
7
- claude: ['--continue'],
8
- codex: ['resume', '--last'],
9
- };
10
- export const AGENT_YOLO_ARGS = {
11
- claude: ['--dangerously-skip-permissions'],
12
- codex: ['--full-auto'],
13
- };
1
+ export const MOUNTAIN_NAMES = [
2
+ 'everest', 'kilimanjaro', 'denali', 'fuji', 'rainier', 'matterhorn',
3
+ 'elbrus', 'aconcagua', 'kangchenjunga', 'lhotse', 'makalu', 'cho-oyu',
4
+ 'dhaulagiri', 'manaslu', 'annapurna', 'nanga-parbat', 'olympus',
5
+ 'mont-blanc', 'k2', 'vinson', 'erebus', 'logan', 'puncak-jaya',
6
+ 'wilhelm', 'cook', 'ararat', 'etna', 'shasta', 'whitney', 'hood',
7
+ ];